Esempio n. 1
0
    def export_residuals(self, path):
        """
        File transfer utility. Export residuals to disk.

        :type path: str
        :param path: path to save residuals
        """
        if self.taskid == 0:
            self.logger.debug(f"exporting residuals to:\n{path}")

        unix.mkdir(os.path.join(path, "residuals"))
        src = os.path.join(self.cwd, "residuals")

        # If this residuals directory has not been created, something
        # has gone wrong with the preprocessing and workflow cannot proceed
        if not os.path.exists(src):
            print(
                msg.cli(
                    "The Solver function 'export_residuals' expected "
                    "'residuals' directories to be created but could not "
                    "find them and cannot continue the workflow. Please "
                    "check the preprocess.prepare_eval_grad() function",
                    header="preprocess error",
                    border="="))
            sys.exit(-1)

        dst = os.path.join(path, "residuals", self.source_name)
        unix.mv(src, dst)
Esempio n. 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`
        """
        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"))
Esempio n. 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`
        """
        # 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"))
Esempio n. 4
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"))
Esempio n. 5
0
    def save_residuals(self):
        """
        Save the residuals to disk
        """
        src = os.path.join(PATH.GRAD, "residuals")
        dst = os.path.join(PATH.OUTPUT, f"residuals_{optimize.iter:04d}")

        self.logger.debug(f"saving residuals to path:\n{dst}")

        unix.mv(src, dst)
Esempio n. 6
0
    def save_kernels(self):
        """
        Save the kernel vector as a Fortran binary file on disk
        """
        src = os.path.join(PATH.GRAD, "kernels")
        dst = os.path.join(PATH.OUTPUT, f"kernels_{optimize.iter:04d}")

        self.logger.debug(f"saving kernels to path:\n{dst}")

        unix.mv(src, dst)
Esempio n. 7
0
    def finalize_search(self):
        """
        Prepares algorithm machinery and scratch directory for next model update

        Removes old model/search parameters, moves current parameters to old,
        sets up new current parameters and writes statistic outputs
        """
        self.logger.info(msg.sub("FINALIZING LINE SEARCH"))

        g = self.load(self.g_new)
        p = self.load(self.p_new)
        x = self.line_search.search_history()[0]
        f = self.line_search.search_history()[1]

        # Clean scratch directory
        unix.cd(PATH.OPTIMIZE)

        # Remove the old model parameters
        if self.iter > 1:
            self.logger.info("removing previously accepted model files (old)")
            for fid in [self.m_old, self.f_old, self.g_old, self.p_old]:
                unix.rm(fid)

        self.logger.info(
            "shifting current model (new) to previous model (old)")
        unix.mv(self.m_new, self.m_old)
        unix.mv(self.f_new, self.f_old)
        unix.mv(self.g_new, self.g_old)
        unix.mv(self.p_new, self.p_old)

        self.logger.info("setting accepted line search model as current model")
        unix.mv(self.m_try, self.m_new)
        self.savetxt(self.f_new, f.min())
        self.logger.info(f"current misfit is {self.f_new}={f.min():.3E}")

        # !!! TODO Describe what stats are being written here
        self.logger.info(f"writing optimization stats to: {CFGPATHS.STATSDIR}")
        self.write_stats(self.log_factor,
                         value=-dot(g, g)**-0.5 * (f[1] - f[0]) /
                         (x[1] - x[0]))
        self.write_stats(self.log_gradient_norm_L1, value=np.linalg.norm(g, 1))
        self.write_stats(self.log_gradient_norm_L2, value=np.linalg.norm(g, 2))
        self.write_stats(self.log_misfit, value=f[0])
        self.write_stats(self.log_restarted, value=self.restarted)
        self.write_stats(self.log_slope, value=(f[1] - f[0]) / (x[1] - x[0]))
        self.write_stats(self.log_step_count,
                         value=self.line_search.step_count)
        self.write_stats(self.log_step_length, value=x[f.argmin()])
        self.write_stats(self.log_theta, value=180. * np.pi**-1 * angle(p, -g))

        self.logger.info("resetting line search step count to 0")
        self.line_search.step_count = 0
Esempio n. 8
0
    def save_traces(self):
        """
        Save the waveform traces to disk.

        !!! This doesn't work? Traces are not saved to PATH.GRAD so src does
        !!! not exist
        """
        src = os.path.join(PATH.GRAD, "traces")
        dst = os.path.join(PATH.OUTPUT, f"traces_{optimize.iter:04d}")

        self.logger.debug(f"saving traces to path:\n{dst}")

        unix.mv(src, dst)
Esempio n. 9
0
    def clean(self):
        """
        Determine if forward simulation from line search can be carried over.
        We assume clean() is the final flow() argument so that we can update
        the thrifty status here.
        """
        self.update_status()

        if self.thrifty:
            self.logger.info(
                msg.mnr("THRIFTY CLEANING  WORKDIR FOR NEXT "
                        "ITERATION"))
            unix.rm(PATH.GRAD)
            unix.mv(PATH.FUNC, PATH.GRAD)
            unix.mkdir(PATH.FUNC)
        else:
            super().clean()
Esempio n. 10
0
    def save_gradient(self):
        """
        Save the gradient vector. Allows saving numpy array or standard
        Fortran .bin files

        Saving as a vector saves on file count, but requires numpy and seisflows
        functions to read
        """
        dst = os.path.join(PATH.OUTPUT, f"gradient_{optimize.iter:04d}")

        if PAR.SAVEAS in ["binary", "both"]:
            src = os.path.join(PATH.GRAD, "gradient")
            unix.mv(src, dst)
        if PAR.SAVEAS in ["vector", "both"]:
            src = os.path.join(PATH.OPTIMIZE, optimize.g_old)
            unix.cp(src, dst + ".npy")

        self.logger.debug(f"saving gradient to path:\n{dst}")
Esempio n. 11
0
    def export_kernels(self, path):
        """
        File transfer utility. Export kernels to disk

        :type path: str
        :param path: path to save kernels
        """
        if self.taskid == 0:
            self.logger.debug(f"exporting kernels to:\n{path}")

        unix.cd(self.kernel_databases)

        # Work around conflicting name conventions
        self.rename_kernels()

        src = glob("*_kernel.bin")
        dst = os.path.join(path, "kernels", self.source_name)
        unix.mkdir(dst)
        unix.mv(src, dst)
Esempio n. 12
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)
Esempio n. 13
0
    def cleanup_xspecfem2d_run(self, choice=None):
        """
        Do some cleanup after running the SPECFEM2D binaries to make sure files
        are in the correct locations, and rename the OUTPUT_FILES directory so
        that it does not get overwritten by subsequent runs

        :type choice: str
        :param choice: Rename the OUTPUT_FILES directory with a suffix tag
            msut be 'INIT' or 'TRUE'. If None, will not rename but the
        """
        cd(self.workdir_paths.workdir)
        print("> Cleaning up after xspecfem2d, setting up for new run")

        # SPECFEM2D outputs its models in the DATA/ directory by default,
        # while SeisFlows3 expects this in the OUTPUT_FILES/ directory (which is
        # the default in SPECFEM3D)
        mv(glob.glob("DATA/*bin"), self.workdir_paths.output)

        if choice == "INIT":
            mv(self.workdir_paths.output, self.workdir_paths.model_init)
            # Create a new OUTPUT_FILES/ directory for TRUE run
            rm(self.workdir_paths.output)
            mkdir(self.workdir_paths.output)
        elif choice == "TRUE":
            mv(self.workdir_paths.output, self.workdir_paths.model_true)
Esempio n. 14
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)
Esempio n. 15
0
# ==============================================================================
print("Generating initial model from Tape 2007 example")
os.chdir(SPECFEM3D_WORKDIR)

cmd = f"./bin/xdecompose_mesh 4 ./MESH-default {SPECFEM3D_OUTPUT}/DATABASES_MPI"
with open("xdecompose_mesh.out", "w") as f:
    subprocess.run(cmd.split(), shell=True, stdout=f)

cmd = f"mpirun -np 4 ./bin/xgenerate_databases"
with open("xgenerate_databases.out", "w") as f:
    subprocess.run("mpiexec ./bin/xSPECFEM3D", shell=True, stdout=f)

# Move the model files (*.bin) into the OUTPUT_FILES directory,
# where SeisFlows3 expects them
unix.mv(glob.glob("DATA/*bin"), "OUTPUT_FILES")

# Make sure we don't overwrite this initial model when creating our target model in the next step
unix.mv("OUTPUT_FILES", "OUTPUT_FILES_INIT")

# ==============================================================================
print("Modifying Tape 2007 example for target model")
# GENERATE MODEL_TRUE
os.chdir(SPECFEM3D_DATA)

# Edit the Par_file by increasing velocities by ~10%
sf.sempar("velocity_model",
          "1 1 2600.d0 5900.d0 3550.0d0 0 0 10.d0 10.d0 0 0 0 0 0 0",
          skip_print=True)

# ==============================================================================