Beispiel #1
0
    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"))
Beispiel #2
0
    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"))
Beispiel #3
0
    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"))
Beispiel #4
0
    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)
Beispiel #5
0
    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")
Beispiel #6
0
    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))
Beispiel #7
0
    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
                        ]))
Beispiel #8
0
    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")
Beispiel #9
0
    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)
Beispiel #10
0
    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)
Beispiel #11
0
    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))