def generate_data(self, **model_kwargs): """ Generates data using the True model, exports traces to `traces/obs` :param model_kwargs: keyword arguments to pass to `generate_mesh` """ self.generate_mesh(**model_kwargs) unix.cd(self.cwd) setpar(key="SIMULATION_TYPE", val="1", file="DATA/Par_file") setpar(key="SAVE_FORWARD", val=".true.", file="DATA/Par_file") call_solver(PAR.MPIEXEC, "bin/xmeshfem2D", output="mesher.log") call_solver(PAR.MPIEXEC, "bin/xspecfem2D", output="solver.log") if PAR.FORMAT.upper() == "SU": # Work around SPECFEM2D's version dependent file names for tag in ["d", "v", "a", "p"]: unix.rename(old=f"single_{tag}.su", new="single.su", names=glob(os.path.join("OUTPUT_FILES", "*.su"))) unix.mv(src=glob(os.path.join("OUTPUT_FILES", self.data_wildcard)), dst=os.path.join("traces", "obs")) if PAR.SAVETRACES: self.export_traces(os.path.join(PATH.OUTPUT, "traces", "obs"))
def write_receivers(self): """ Write a list of receivers into a text file !!! This calls on plugins.solver.specfem3d.write_receivers() but incorrect number of parameters is forwarded !!! """ unix.cd(self.cwd) setpar(key="use_existing_STATIONS", val=".true", file="DATA/Par_file") _, h = preprocess.load("traces/obs") solvertools.write_receivers(h.nr, h.rx, h.rz)
def generate_data(self, **model_kwargs): """ Generates data using the True model, exports traces to `traces/obs` :param model_kwargs: keyword arguments to pass to `generate_mesh` """ # Create the mesh self.generate_mesh(**model_kwargs) # Run the Forward simulation unix.cd(self.cwd) setpar(key="SIMULATION_TYPE", val="1", file="DATA/Par_file") setpar(key="SAVE_FORWARD", val=".true.", file="DATA/Par_file") if PAR.ATTENUATION: setpar(key="ATTENUATION", val=".true.", file="DATA/Par_file") else: setpar(key="ATTENUATION", val=".false.", file="DATA/Par_file") call_solver(mpiexec=PAR.MPIEXEC, executable="bin/xspecfem3D") unix.mv(src=glob(os.path.join("OUTPUT_FILES", self.data_wildcard)), dst=os.path.join("traces", "obs")) # Export traces to disk for permanent storage if PAR.SAVETRACES: self.export_traces(os.path.join(PATH.OUTPUT, "traces", "obs"))
def generate_data(self): """ Overload seisflows.solver.base.generate_data. To be run in parallel Not used if PAR.CASE == "Data" Generates data in the synthetic-synthetic comparison case. Automatically calls generate mesh for the true model, rather than passing them in as kwargs. Also turns on attenuation for the forward model !!! attenuation could be moved into parameters.yaml? !!! """ unix.cd(self.cwd) setpar(key="SIMULATION_TYPE", val="1", file="DATA/Par_file") setpar(key="SAVE_FORWARD", val=".true.", file="DATA/Par_file") if PAR.ATTENUATION: setpar(key="ATTENUATION ", val=".true.", file="DATA/Par_file") else: setpar(key="ATTENUATION ", val=".false.", file="DATA/Par_file") call_solver(mpiexec=PAR.MPIEXEC, executable="bin/xspecfem3D") # move ASCII .sem? files into appropriate directory unix.mv(src=glob(os.path.join("OUTPUT_FILES", self.data_wildcard)), dst=os.path.join("traces", "obs")) # Export traces to permanent storage on disk if PAR.SAVETRACES: self.export_traces(os.path.join(PATH.OUTPUT, "traces", "obs"))
def write_sources(par, h, path="."): """ Writes FORCESOLUTION source information to text file :type par: dict :param par: seisflows.PAR :type h: :param h: :type path: str :param path: path to write sources to """ file = os.path.join(findpath("seisflows.plugins"), "specfem3d", "FORCESOLUTION") with open(file, "r") as f: lines = f.readlines() file = "DATA/FORCESOURCE" with open(file, "w") as f: f.writelines(lines) # adjust coordinates setpar("xs", h.sx[0], file) setpar("zs", h.sz[0], file) setpar("ts", h.ts, file) # adjust wavelet setpar("f0", par["F0"], file)
def adjoint(self): """ Calls SPECFEM2D adjoint solver, creates the `SEM` folder with adjoint traces which is required by the adjoint solver """ setpar(key="SIMULATION_TYPE", val="3", file="DATA/Par_file") setpar(key="SAVE_FORWARD", val=".false.", file="DATA/Par_file") unix.rm("SEM") unix.ln("traces/adj", "SEM") # Deal with different SPECFEM2D name conventions for regular traces and # "adjoint" traces if PAR.FORMAT.upper == "SU": unix.rename(old=".su", new=".su.adj", names=glob(os.path.join("traces", "adj", "*.su"))) call_solver(mpiexec=PAR.MPIEXEC, executable="bin/xmeshfem2D") call_solver(mpiexec=PAR.MPIEXEC, executable="bin/xspecfem2D")
def forward(self, path='traces/syn'): """ Calls SPECFEM2D forward solver, exports solver outputs to traces dir :type path: str :param path: path to export traces to after completion of simulation """ setpar(key="SIMULATION_TYPE", val="1", file="DATA/Par_file") setpar(key="SAVE_FORWARD", val=".true.", file="DATA/Par_file") call_solver(mpiexec=PAR.MPIEXEC, executable="bin/xmeshfem2D") call_solver(mpiexec=PAR.MPIEXEC, executable="bin/xspecfem2D") if PAR.FORMAT.upper() == "SU": # Work around SPECFEM2D's version dependent file names for tag in ["d", "v", "a", "p"]: unix.rename(old=f"single_{tag}.su", new="single.su", names=glob(os.path.join("OUTPUT_FILES", "*.su"))) unix.mv(src=glob(os.path.join("OUTPUT_FILES", self.data_wildcard)), dst=path)
def check_solver_parameter_files(self): """ Checks solver parameters. Only slightly different to Specfem3D as it is run by the main task, not be an array process, so no need to check task_id """ nt = getpar(key="NSTEP", cast=int) dt = getpar(key="DT", cast=float) if nt != PAR.NT: warnings.warn("Specfem3D NSTEP != PAR.NT\n" "overwriting Specfem3D with Seisflows parameter") setpar(key="NSTEP", val=PAR.NT) if dt != PAR.DT: warnings.warn("Specfem3D DT != PAR.DT\n" "overwriting Specfem3D with Seisflows parameter") setpar(key="DT", val=PAR.DT) if self.mesh_properties.nproc != PAR.NPROC: warnings.warn("Specfem3D mesh nproc != PAR.NPROC") if "MULTIPLES" in PAR: raise NotImplementedError
def write_sources(PAR, h, path='.'): """ Writes source information to text file """ filename = findpath('seisflows.plugins') + '/' + 'specfem3d/SOURCE' with open(filename, 'r') as f: lines = f.readlines() filename = 'DATA/SOURCE' with open(filename, 'w') as f: f.writelines(lines) # adjust coordinates setpar('xs', h.sx[0], filename) setpar('zs', h.sz[0], filename) setpar('ts', h.ts, filename) # adjust wavelet setpar('f0', PAR['F0'], filename)
def adjoint(self): """ Calls SPECFEM3D adjoint solver, creates the `SEM` folder with adjoint traces which is required by the adjoint solver """ setpar(key="SIMULATION_TYPE", val="3", file="DATA/Par_file") setpar(key="SAVE_FORWARD", val=".false.", file="DATA/Par_file") setpar(key="ATTENUATION", val=".false.", file="DATA/Par_file") unix.rm("SEM") unix.ln("traces/adj", "SEM") call_solver(mpiexec=PAR.MPIEXEC, executable="bin/xspecfem3D")
def forward(self, path="traces/syn"): """ Calls SPECFEM3D forward solver, exports solver outputs to traces dir :type path: str :param path: path to export traces to after completion of simulation """ # Set parameters and run forward simulation setpar(key="SIMULATION_TYPE", val="1", file="DATA/Par_file") setpar(key="SAVE_FORWARD", val=".true.", file="DATA/Par_file") if PAR.ATTENUATION: setpar(key="ATTENUATION", val=".true.", file="DATA/Par_file") else: setpar(key="ATTENUATION", val=".false`.", file="DATA/Par_file") call_solver(mpiexec=PAR.MPIEXEC, executable="bin/xgenerate_databases") call_solver(mpiexec=PAR.MPIEXEC, executable="bin/xspecfem3D") # Find and move output traces, by default to synthetic traces dir unix.mv(src=glob(os.path.join("OUTPUT_FILES", self.data_wildcard)), dst=path)
def check_solver_parameter_files(self): """ Checks SPECFEM2D Par_file for acceptable parameters and matches with the internally set parameters """ # Check the number of steps in the SPECFEM2D Par_file nt_str, nt, nt_i = getpar(key="NSTEP", file="DATA/Par_file") if int(nt) != PAR.NT: if self.taskid == 0: print( msg.cli( f"SPECFEM2D {nt_str}=={nt} is not equal " f"SeisFlows3 PAR.NT=={PAR.NT}. Please ensure " f"that these values match in both files.", header="parameter match error", border="=")) sys.exit(-1) dt_str, dt, dt_i = getpar(key="DT", file="DATA/Par_file") if float(dt) != PAR.DT: if self.taskid == 0: print( msg.cli( f"SPECFEM2D {dt_str}=={dt} is not equal " f"SeisFlows3 PAR.DT=={PAR.DT}. Please ensure " f"that these values match in both files.", header="parameter match error", border="=")) sys.exit(-1) # Check the central frequency in the SPECFEM2D SOURCE file f0_str, f0, f0_i = getpar(key="f0", file="DATA/SOURCE") if float(f0) != PAR.F0: if self.taskid == 0: print( msg.cli( f"SPECFEM2D {f0_str}=={f0} is not equal " f"SeisFlows3 PAR.F0=={PAR.F0}. Please ensure " f"that these values match the DATA/SOURCE file.", header="parameter match error", border="=")) sys.exit(-1) # Ensure that NPROC matches the MESH values nproc = self.mesh_properties.nproc if nproc != PAR.NPROC: if self.taskid == 0: print( msg.cli( f"SPECFEM2D mesh NPROC=={nproc} is not equal" f"SeisFlows3 PAR.NPROC=={PAR.NPROC}. " f"Please check that your mesh matches this val.", header="parameter match error", border="=")) sys.exit(-1) if "MULTIPLES" in PAR: if PAR.MULTIPLES: setpar(key="absorbtop", val=".false.", file="DATA/Par_file") else: setpar(key="absorbtop", val=".true.", file="DATA/Par_file")
def write_sources(coords, path='.', ws=1., suffix=''): """ Writes source information to text file TODO this has to be adapted for new versions of specfem because the source file format has changed """ sx, sy, sz = coords filename = findpath('seisflows.plugins') + '/' + 'solver/specfem2d/SOURCE' with open(filename, 'r') as f: lines = f.readlines() filename = 'DATA/SOURCE' + suffix with open(filename, 'w') as f: f.writelines(lines) # adjust source coordinates setpar('xs', sx, filename) setpar('zs', sy, filename) # setpar('ts', ts[0], filename) # adjust source amplitude try: fs = float(getpar('factor', filename)) fs *= ws setpar('factor', str(fs), filename) except: pass # adjust source wavelet if 1: # Ricker wavelet setpar('time_function_type', 1, filename) elif 0: # first derivative of Gaussian setpar('time_function_type', 2, filename) elif 0: # Gaussian setpar('time_function_type', 3, filename) elif 0: # Dirac setpar('time_function_type', 4, filename) elif 0: # Heaviside setpar('time_function_type', 5, filename)