[cig-commits] [commit] devel: Adds initial files for SEP models (f17ddfa)
cig_noreply at geodynamics.org
cig_noreply at geodynamics.org
Thu Oct 2 14:07:04 PDT 2014
Repository : https://github.com/geodynamics/specfem3d
On branch : devel
Link : https://github.com/geodynamics/specfem3d/compare/858a86e5e8e4c076696d24c8c9942e93d3d663cb...7ef78c5b45b052afca446255945d0c62788f8e93
>---------------------------------------------------------------
commit f17ddfaeed212cd20989b072efd71b4a2e4daa3d
Author: Matthieu Lefebvre <ml15 at princeton.edu>
Date: Mon Sep 22 08:59:19 2014 -0400
Adds initial files for SEP models
>---------------------------------------------------------------
f17ddfaeed212cd20989b072efd71b4a2e4daa3d
src/generate_databases/model_sep.f90 | 183 +++++++++++++++++++++++++++++++++++
src/generate_databases/parse_sep.c | 119 +++++++++++++++++++++++
2 files changed, 302 insertions(+)
diff --git a/src/generate_databases/model_sep.f90 b/src/generate_databases/model_sep.f90
new file mode 100644
index 0000000..9601d62
--- /dev/null
+++ b/src/generate_databases/model_sep.f90
@@ -0,0 +1,183 @@
+module model_sep_mode
+ implicit none
+contains
+
+!==============================================================================
+subroutine model_sep()
+ use create_regions_mesh_ext_par, only rhostore, rho_vp, rho_vs
+
+ real(kind=4), allocatable, dimension(:,:,:) :: vp_sep, vs_sep, rho_sep
+ integer :: NX, NY, NZ
+ real :: OX, OY, OZ, DX, DY, DZ
+ character(len=512) :: sep_bin_vp
+ real :: xmin, ymin
+ integer :: imin, jmin, kmin, ni, nj, nk
+
+ ! Read SEP header for each SEP file
+ ! -> n1 (NX), n2 (NY), n3 (NZ)
+ ! -> o1 (O1), o2 (O2), o3 (O3)
+ ! -> d1 (D1), d2 (D2), d3 (D3)
+ ! -> in (filename)
+ ! -> Check for unit* to be meter
+ ! Parse only one of the header, vp is the most likely to be present
+ ! It might be useful to make sure that all SEP files have coherent dimensions.
+ parse_sep_vs_header(sep_header_name_vp, &
+ NX, NY, NZ, OX, OY, OZ, D1, D2, D3, &
+ sep_bin_vp)
+
+ ! Match slice topography and parts of the SEP file.
+ call find_slice_bounds_sep(NX, NY, NZ, OX, OY, OZ, DX, DY, DZ, &
+ xmin, ymin, imin, jmin, kmin, ni, nj, nk)
+
+ ! Read available SEP files, assign default values for unfound files.
+ allocate(vp_sep(ni, nj, NZ))
+ allocate(vs_sep(ni, nj, NZ))
+ allocate(rho_sep(ni, nj, NZ))
+
+ call read_sep_binary_mpiio(FILE_VP, NX, NY, NZ, ni, nj, NZ, vp_sep)
+ call read_sep_binary_mpiio(FILE_VS, NX, NY, NZ, ni, nj, NZ, vs_sep)
+ call read_sep_binary_mpiio(FILE_RHO, NX, NY, NZ, ni, nj, NZ, rho_sep)
+
+ ! Interpolate SEP values on meshfem mesh.
+ call interpolate_sep_on_mesh(rho_sep, xmin, ymin, ni, nj, NZ, &
+ DX, DY, DZ, rhostore)
+ call interpolate_sep_on_mesh(vp_sep, xmin, ymin, ni, nj, NZ, &
+ DX, DY, DZ, rho_vp)
+ call interpolate_sep_on_mesh(vs_sep, xmin, ymin, ni, nj, NZ, &
+ DX, DY, DZ, rho_vs)
+ ! SPECFEM expects rho*velocity
+ rho_vp = rho_vp * rhostore
+ rho_vs = rho_vs * rhostore
+
+ deallocate(vp_sep)
+ deallocate(vs_sep)
+ deallocate(rho_sep)
+end subroutine model_sep
+
+
+!==============================================================================
+!> \brief Parallel read of a SEP file.
+!!
+!! \param filename Name of the SEP file to read
+!! \param NX Dimension in x for the SEP file (n1 in SEP header)
+!! \param NY Dimension in y for the SEP file (n1 in SEP header)
+!! \param NZ Dimension in z for the SEP file (n1 in SEP header)
+!! \param ni Dimension in x for a process.
+!! \param nj Dimension in y for a process.
+!! \param nk Dimension in z for a process -- usually equal to NZ.
+!!
+!! \note xyz SEP organized files are expected.
+subroutine read_sep_binary_mpiio(filename, NX, NY, NZ, ni, nj, nk, var)
+ use mpi
+ ! Parameters
+ character(len=*), intent(in) :: filename
+ integer, intent(in) :: NX, NY, NZ, ni, nj, nk
+ real(kind =4), dimension(:, :, :), intent(inout) :: var
+
+ !Variables
+ integer :: fh
+ integer, dimension(3) :: global_sizes, local_sizes, starting_idx
+ integer(kind=MPI_OFFSET_KIND) :: displ
+ integer :: subarray_type
+ integer :: mpi_status, ier
+
+ ! Sizes for the subarrays
+ global_sizes = (/ NX, NY, NZ /)
+ local_sizes = (/ ni, nj, nk /)
+ starting_idx = (/ imin-1, jmin-1, kmin-1 /)
+
+ ! Create the 3D stencil for values consecutive in X but disjoint in Y and Z.
+ call MPI_Type_create_subarray(3, global_sizes, local_sizes, starting_idx, &
+ MPI_ORDER_FORTRAN, MPI_REAL, subarray_type, ier)
+ call MPI_Type_commit(subarray_type, ier)
+
+ call MPI_File_open(MPI_COMM_WORLD, trim(adjustl(filename)), &
+ MPI_MODE_RDONLY, MPI_INFO_NULL, fh, ier)
+ ! View is set to match the stencil
+ displ = 0
+ call MPI_File_set_view(fh, displ, MPI_REAL, subarray_type, "native", &
+ MPI_INFO_NULL, ier)
+ ! Number of element is equal to the local size
+ call MPI_File_read_all(fh, var, ni * nj * nk, &
+ MPI_REAL, mpi_status, ier)
+ call MPI_File_close(fh, ier)
+end subroutine read_sep_binary_mpiio
+
+!==============================================================================
+!> \brief Assign values read from SEP files to GLL points
+!!
+!! \note from Yang Luo's external routines. Actually finds a nearby point.
+subroutine interpolate_sep_on_mesh(sep_var, xmin, ymin, ni, nj, NZ, &
+ DX, DY, DZ, var)
+ use generate_database_par, only: NGLLX, NGLLY, NGLLZ, NSPEC=>NSPEC_AB &
+ ibool
+ !--- Parameters
+ real(kind=4), dimension(:,:,:), intent(in) :: sep_var
+ real, intent(in) :: xmin, ymin, DX, DY, DZ
+ integer, intent(in) :: ni, nj, NZ
+ real, dimension(:,:,:,:) :: var
+ !--- Variables
+ integer :: iglob, i_target, j_target, k_target
+ integer :: ispec, i, j, k
+
+ do ispec=1,NSPEC
+ do i=1,NGLLX
+ do j=1,NGLLY
+ do k=1,NGLLZ
+ iglob=ibool(i,j,k,ispec);
+ i_target=NINT((xstore(iglob)-xmin)/DX)+1
+ j_target=NINT((ystore(iglob)-ymin)/DY)+1
+ ! in SEP, z-axis is downward; in SPECFEM, z-axis is upward
+ k_target=NINT(-zstore(iglob)/DZ)+1; !NOT using (z_temp-zmin)
+ ! Stay in the computational domain
+ if(i_target< 1) i_target= 1
+ if(j_target< 1) j_target= 1
+ if(k_target< 1) k_target= 1
+ if(i_target>ni) i_target= ni
+ if(j_target>nj) j_target= nj
+ if(k_target>NZ) k_target= NZ
+
+ var(i,j,k,ispec) = sep_var(i_target,j_target,k_target)
+ enddo
+ enddo
+ enddo
+ enddo
+end subroutine interpolate_sep_on_mesh
+
+!==============================================================================
+!>
+subroutine find_slice_bounds_sep(NX, NY, NZ, OX, OY, OZ, DX, DY, DZ, &
+ xmin, ymin, imin, jmin, kmin, ni, nj, nk)
+ use generate_database_par, only: xstor, ystore, zstore
+ ! Parameters
+ integer, intent(in) :: NX, NY, NZ
+ real, intent(in) :: OX, OY, OZ, DX, DY, DZ
+ real, intent(out) :: xmin, ymin
+ integer, intent(out) :: imin, jmin, kmin, ni, nj, nk
+
+ ! Actual bounds for the current slice mesh
+ xmin=minval(xstore); xmax=maxval(xstore);
+ ymin=minval(ystore); ymax=maxval(ystore);
+ ! in SEP, z-axis is downward; in SPECFEM, z-axis is upward
+ zmin=minval(-zstore); zmax=maxval(-zstore);
+
+ ! Bounds for the SEP model
+ imin=floor((xmin-OX)/DX+1); imax=ceiling((xmax-OX)/DX+1);
+ jmin=floor((ymin-OY)/DY+1); jmax=ceiling((ymax-OY)/DY+1);
+ kmin=floor((zmin-OZ)/DZ+1); kmax=ceiling((zmax-OZ)/DZ+1);
+ if(imin<1) imin= 1; if(jmin<1) jmin= 1; if(kmin<1) kmin= 1;
+ if(imax>NX) imin=NX; if(jmax>NY) jmax=NY; if(kmax>NZ) kmax=NZ;
+ ! Number of SEP indexes for the current slice
+ ni=imax-imin+1
+ nj=jmax-jmin+1
+ nk=kmax-kmin+1
+
+ ! Corrected bounds for the current slice when looking for SEP indexes
+ xmin=DX*(imin-1)+OX; xmax=DX*(imax-1)+OX;
+ ymin=DY*(jmin-1)+OY; ymax=DY*(jmax-1)+OY;
+ zmin=DZ*(kmin-1)+OZ; zmax=DZ*(kmax-1)+OZ;
+
+end subroutine find_slice_bounds_sep
+
+end module model_sep_mode
+
diff --git a/src/generate_databases/parse_sep.c b/src/generate_databases/parse_sep.c
new file mode 100644
index 0000000..744910b
--- /dev/null
+++ b/src/generate_databases/parse_sep.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright [2014] [Matthieu Lefebvre]
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*****************************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <regex.h>
+#include "err.h"
+
+#define EXIT_ON_ERR(msg) \
+ err(1, "%s(%d) -- %s: %s", __FILE__, __LINE__, __func__, msg);
+
+
+/*****************************************************************************/
+void parse_sep_vs_header(char *header_name,
+ int *n1, int *n2, int *n3,
+ int *o1, int *o2, int *o3,
+ float *d1, float *d2, float *d3,
+ char *in) {
+ char *line = NULL;
+ size_t len = 0;
+
+ FILE *fd = fopen(header_name, "r");
+ if (fd == NULL)
+ EXIT_ON_ERR("fopen");
+
+ /* Build regex mathing "name=value" with optional spaces*/
+ regex_t re;
+ if(regcomp(&re, "^[ \t]*\\(.*\\)[ \t]*=[ \t]*\\(.*\\)[ \t]*",
+ REG_ICASE | REG_NEWLINE))
+ EXIT_ON_ERR("regcomp");
+
+ /* Apply the regex to every line of the sep header */
+ while(getline(&line, &len, fd) != -1) {
+
+ char name[512], value[512];
+ size_t nmatch = 3;
+ regmatch_t pmatch[3];
+ if(REG_NOMATCH == regexec(&re, line, nmatch, pmatch, 0)) {
+ continue; /* These files are usually quite messy... */
+ } else {
+ size_t name_len = pmatch[1].rm_eo - pmatch[1].rm_so;
+ strncpy(name, &line[pmatch[1].rm_so], name_len);
+ name[name_len] = '\0';
+
+ size_t value_len = pmatch[2].rm_eo - pmatch[2].rm_so;
+ strncpy(value, &line[pmatch[2].rm_so], pmatch[2].rm_eo - pmatch[2].rm_so);
+ value[value_len] = '\0';
+
+ if (!strcmp(name, "n1")) {
+ *n1 = atoi(value);
+ } else if (!strcmp(name, "n2")) {
+ *n2 = atoi(value);
+ } else if (!strcmp(name, "n3")) {
+ *n3 = atoi(value);
+ } else if (!strcmp(name, "o1")) {
+ *o1 = atoi(value);
+ } else if (!strcmp(name, "o2")) {
+ *o2 = atoi(value);
+ } else if (!strcmp(name, "o3")) {
+ *o3 = atoi(value);
+ } else if (!strcmp(name, "d1")) {
+ *d1 = atof(value);
+ } else if (!strcmp(name, "d2")) {
+ *d2 = atof(value);
+ } else if (!strcmp(name, "d3")) {
+ *d3 = atof(value);
+ /*} else if (!strcmp(name, "label1")) {
+ strncpy(*label1, value, value_len+1);
+ } else if (!strcmp(name, "label2")) {
+ strncpy(*label2, value, value_len+1);
+ } else if (!strcmp(name, "label3")) {
+ strncpy(*label3, value, value_len+1);
+ } else if (!strcmp(name, "unit1")) {
+ strncpy(*unit1, value, value_len+1);
+ } else if (!strcmp(name, "unit2")) {
+ strncpy(*unit2, value, value_len+1);
+ } else if (!strcmp(name, "unit3")) {
+ strncpy(*unit3, value, value_len+1);
+ } else if (!strcmp(name, "data_format")) {
+ strncpy(*data_format, value, value_len+1);*/
+ } else if (!strcmp(name, "in")) {
+ strncpy(*in, value, value_len+1);
+ }
+ }
+
+ if (line)
+ free(line);
+ len = 0;
+ }
+ fclose(fd);
+ regfree(&re);
+}
+
+
+/*****************************************************************************/
+/*** Aliases for Fortran bindings ***/
+
+void parse_sep_vs_header_(char *header_name,
+ int *n1, int *n2, int *n3,
+ int *o1, int *o2, int *o3,
+ float *f1, float *f2, float *f3,
+ char *in)
+ __attribute__((alias("parse_sep_vs_header")));
+/*****************************************************************************/
More information about the CIG-COMMITS
mailing list