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 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, **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 smooth(self, input_path, output_path, parameters=None, span_h=0., span_v=0., output="solver.log"): """ Postprocessing wrapper: xsmooth_sem Smooths kernels by convolving them with a Gaussian. .. note:: paths require a trailing `/` character when calling xsmooth_sem .. note:: It is ASSUMED that this function is being called by system.run(single=True) so that we can use the main solver directory to perform the kernel smooth task :type input_path: str :param input_path: path to data :type output_path: str :param output_path: path to export the outputs of xcombine_sem :type parameters: list :param parameters: optional list of parameters, defaults to `self.parameters` :type span_h: float :param span_h: horizontal smoothing length in meters :type span_v: float :param span_v: vertical smoothing length in meters :type output: str :param output: file to output stdout to """ if parameters is None: parameters = self.parameters if not exists(output_path): unix.mkdir(output_path) # Apply smoothing operator inside scratch/solver/* unix.cd(self.cwd) # mpiexec ./bin/xsmooth_sem SMOOTH_H SMOOTH_V name input output use_gpu for name in parameters: call_solver(mpiexec=PAR.MPIEXEC, executable=" ".join([ "bin/xsmooth_sem", str(span_h), str(span_v), f"{name}_kernel", os.path.join(input_path, ""), os.path.join(output_path, ""), ".false" ]), output=output) # Rename output files files = glob(os.path.join(output_path, "*")) unix.rename(old="_smooth", new="", names=files)
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 generate_mesh(self, model_path, model_name, model_type='gll'): """ Performs meshing and database generation as a serial task. Differs slightly from specfem3d class as it only creates database files for the main solver, which are then copied in serial by the function distribute_databases() :type model_path: str :param model_path: path to the model to be used for mesh generation :type model_name: str :param model_name: name of the model to be used as identification :type model_type: str :param model_type: available model types to be passed to the Specfem3D Par_file. See Specfem3D Par_file for available options. """ available_model_types = ["gll"] assert (exists(model_path)), f"model {model_path} does not exist" model_type = model_type or getpar(key="MODEL", file="DATA/Par_file") assert(model_type in available_model_types), \ f"{model_type} not in available types {available_model_types}" # Ensure that we're running on the main solver only assert (self.taskid == 0) unix.cd(self.cwd) # Check that the model parameter falls into the acceptable types par = getpar("MODEL").strip() assert(par in available_model_types), \ f"Par_file {par} not in available types {available_model_types}" if par == "gll": self.check_mesh_properties(model_path) # Copy model files and then run xgenerate databases src = glob(os.path.join(model_path, "*")) dst = self.model_databases unix.cp(src, dst) call_solver(mpiexec=PAR.MPIEXEC, executable="bin/xgenerate_databases") self.export_model(os.path.join(PATH.OUTPUT, model_name))
def combine(self, input_path, output_path, parameters=None): """ Postprocessing wrapper: xcombine_sem Sums kernels from individual source contributions to create gradient. .. note:: The binary xcombine_sem simply sums matching databases (.bin) .. note:: It is ASSUMED that this function is being called by system.run(single=True) so that we can use the main solver directory to perform the kernel summation task :type input_path: str :param input_path: path to data :type output_path: str :param output_path: path to export the outputs of xcombine_sem :type parameters: list :param parameters: optional list of parameters, defaults to `self.parameters` """ if parameters is None: parameters = self.parameters if not exists(output_path): unix.mkdir(output_path) unix.cd(self.cwd) # Write the source names into the kernel paths file for SEM/ directory with open("kernel_paths", "w") as f: f.writelines([ os.path.join(input_path, f"{name}\n") for name in self.source_names ]) # Call on xcombine_sem to combine kernels into a single file for name in self.parameters: # e.g.: mpiexec ./bin/xcombine_sem alpha_kernel kernel_paths output call_solver(mpiexec=PAR.MPIEXEC, executable=" ".join([ f"bin/xcombine_sem", f"{name}_kernel", "kernel_paths", output_path ]))
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 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 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 generate_mesh(self, model_path, model_name, model_type=None): """ Performs meshing with internal mesher Meshfem3D and database generation :type model_path: str :param model_path: path to the model to be used for mesh generation :type model_name: str :param model_name: name of the model to be used as identification :type model_type: str :param model_type: available model types to be passed to the Specfem3D Par_file. See Specfem3D Par_file for available options. """ available_model_types = ["gll"] assert (exists(model_path)), f"model {model_path} does not exist" model_type = model_type or getpar(key="MODEL", file="DATA/Par_file") assert(model_type in available_model_types), \ f"{model_type} not in available types {available_model_types}" unix.cd(self.cwd) # Run mesh generation if model_type == "gll": self.check_mesh_properties(model_path) src = glob(os.path.join(model_path, "*")) dst = self.model_databases unix.cp(src, dst) call_solver(mpiexec=PAR.MPIEXEC, executable="bin/xmeshfem3D") call_solver(mpiexec=PAR.MPIEXEC, executable="bin/xgenerate_databases") # Export the model for future use in the workflow if self.taskid == 0: self.export_model(os.path.join(PATH.OUTPUT, model_name))