Skip to content

Commit

Permalink
addressing adjtomo#138 broke out 'Model' class from the specfem tools…
Browse files Browse the repository at this point in the history
… into its own tool for faster imports

SeisFlows command line tool moved heavier imports into functions to speed up call times for other functions that don't need it
fixed import statements and all tests pass
  • Loading branch information
bch0w committed Oct 15, 2022
1 parent f97c008 commit f5d0dcd
Show file tree
Hide file tree
Showing 10 changed files with 719 additions and 619 deletions.
2 changes: 1 addition & 1 deletion seisflows/optimize/gradient.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
from seisflows.tools import msg, unix
from seisflows.tools.config import Dict
from seisflows.tools.math import angle, dot
from seisflows.tools.specfem import Model
from seisflows.tools.model import Model
from seisflows.plugins import line_search as line_search_dir


Expand Down
39 changes: 21 additions & 18 deletions seisflows/seisflows.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,19 @@
- Write a new function within the SeisFlows class
- Add a new subparser with optional arguments to sfparser()
- Add subparser to subparser dict at the end of sfparser()
In-function import statements are used to reduce call-time for simpler fx's
"""
import os
import sys
# import warnings
import argparse
# import traceback
# from glob import glob
# from IPython import embed
# from obspy import Stream, read
from glob import glob
from inspect import getmro
#
# from seisflows import logger, ROOT_DIR, NAMES
# from seisflows.preprocess.default import Default
# from seisflows.tools import unix, msg
# from seisflows.tools.config import load_yaml, custom_import, import_seisflows
# from seisflows.tools.specfem import (getpar, setpar, getpar_vel_model,
# setpar_vel_model, Model)
from seisflows import logger, ROOT_DIR, NAMES
from seisflows.tools import unix, msg
from seisflows.tools.config import load_yaml, custom_import, import_seisflows
from seisflows.tools.specfem import (getpar, setpar, getpar_vel_model,
setpar_vel_model)



def sfparser():
Expand Down Expand Up @@ -521,6 +517,8 @@ def configure(self, absolute_paths=False, **kwargs):
else if False, use path names relative to the working directory.
Defaults to False, uses relative paths.
"""
from traceback import format_exc

print("configuring SeisFlows parameter file")

def split_module_docstring(mod, idx):
Expand Down Expand Up @@ -600,7 +598,7 @@ def split_module_docstring(mod, idx):
logger.critical(
msg.cli(text="seisflows configure traceback", header="error")
)
print(traceback.format_exc())
print(format_exc())
raise
else:
unix.rm(temp_par_file)
Expand Down Expand Up @@ -712,6 +710,7 @@ def clean(self, force=False, **kwargs):
:param force: ignore the warning check that precedes the clean()
function, useful if you don't want any input messages popping up
"""

# Check if the filepaths exist
if not os.path.exists(self._args.parameter_file):
print(msg.cli(f"SeisFlows parameter file not found: "
Expand Down Expand Up @@ -750,6 +749,8 @@ def debug(self, **kwargs):
interactive environment allowing exploration of the package space.
Does not allow stepping through of code (not a breakpoint).
"""
from IPython import embed

workflow = import_seisflows(workdir=self._args.workdir,
parameter_file=self._args.parameter_file)

Expand Down Expand Up @@ -822,8 +823,6 @@ def sempar(self, parameter, value=None, skip_print=False,
:param skip_print: skip the print statement which is typically sent
to stdout after changing parameters.
"""
from seisflows.tools.specfem import getpar, setpar, getpar_vel_model

if not os.path.exists(par_file):
sys.exit(f"\n\tparameter file '{par_file}' does not exist\n")
if parameter is None:
Expand Down Expand Up @@ -897,7 +896,7 @@ def par(self, parameter, value=None, skip_print=False, **kwargs):
:param skip_print: skip the print statement which is typically sent
to stdout after changing parameters.
"""
from seisflows.tools.specfem import getpar
from warnings import warn

if not os.path.exists(self._args.parameter_file):
sys.exit(f"\n\tparameter file '{self._args.parameter_file}' "
Expand All @@ -910,8 +909,7 @@ def par(self, parameter, value=None, skip_print=False, **kwargs):
# SeisFlows parameter file dictates upper-case parameters
parameter = parameter.upper()
if isinstance(value, str) and value.lower() == "none":
warnings.warn("to set values to NoneType, use 'null' not 'none'",
UserWarning)
warn("to set values NoneType, use 'null' not 'none'", UserWarning)

# Use the specfem tool to grab related information
try:
Expand Down Expand Up @@ -1055,6 +1053,9 @@ def plotst(self, fids, data_format="ASCII", savefig=None, **kwargs):
:param savefig: full path and filename to save the output figure. If
NoneType, will not save the figure
"""
from obspy import Stream
from seisflows.preprocess.default import Default

# Take advantage of the Default Preprocessing module's read() function
plotter = Default(data_format=data_format)
assert(data_format.upper() in plotter._acceptable_data_formats), \
Expand Down Expand Up @@ -1082,6 +1083,8 @@ def plot2d(self, name=None, parameter=None, cmap=None, savefig=None,
:param savefig: optional name and path of filename to save figure
to disk
"""
from seisflows.tools.model import Model

# Figure out which models/gradients/kernels we can actually plot
_, output_dir, _ = getpar(key="path_output",
file=self._args.parameter_file,
Expand Down
85 changes: 85 additions & 0 deletions seisflows/solver/specfem3d_chinook.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#!/usr/bin/env python3
"""
This class provides utilities for the Seisflows solver interactions with
Specfem3D Cartesian, specifically to run on Chinook.
"""
import sys
import subprocess
from seisflows import logger
from seisflows.tools import unix, msg
from seisflows.solver.specfem3d import Specfem3D


class Specfem3D_Chinook(Specfem3D):
"""
Solver SPECFEM3D
----------------
SPECFEM3D-specific alterations to the base SPECFEM module
Parameters
----------
Paths
-----
***
"""
__doc__ = Specfem3D.__doc__ + __doc__

def _run_binary(self, executable, stdout="solver.log", with_mpi=True):
"""
Calls MPI solver executable to run solver binaries, used by individual
processes to run the solver on system. If the external solver returns a
non-zero exit code (failure), this function will return a negative
boolean.
.. note::
This function ASSUMES it is being run from a SPECFEM working
directory, i.e., that the executables are located in ./bin/
.. note::
This is essentially an error-catching wrapper of subprocess.run()
:type executable: str
:param executable: executable function to call. May or may not start
E.g., acceptable calls for the solver would './bin/xspecfem2D'.
Also accepts additional command line arguments such as:
'xcombine_sem alpha_kernel kernel_paths...'
:type stdout: str
:param stdout: where to redirect stdout
:type with_mpi: bool
:param with_mpi: If `mpiexec` is given, use MPI to run the executable.
Some executables (e.g., combine_vol_data_vtk) must be run in
serial so this flag allows them to turn off MPI running.
:raises SystemExit: If external numerical solver return any failure
code while running
"""
# Executable may come with additional sub arguments, we only need to
# check that the actually executable exists
if not unix.which(executable.split(" ")[0]):
logger.critical(msg.cli(f"executable '{executable}' does not exist",
header="external solver error", border="="))
sys.exit(-1)

# Prepend with `mpiexec` if we are running with MPI
# looks something like: `mpirun -n 4 ./bin/xspecfem2d`
if self._mpiexec and with_mpi:
executable = f"{self._mpiexec} -n {self.nproc} {executable}"
logger.debug(f"running executable with cmd: '{executable}'")

try:
with open(stdout, "w") as f:
subprocess.run(executable, shell=True, check=True, stdout=f,
stderr=f)
except (subprocess.CalledProcessError, OSError) as e:
logger.critical(
msg.cli("The external numerical solver has returned a "
"nonzero exit code (failure). Consider stopping any "
"currently running jobs to avoid wasted "
"computational resources. Check 'scratch/solver/"
f"mainsolver/{stdout}' for the solvers stdout log "
"message. The failing command and error message are:",
items=[f"exc: {executable}", f"err: {e}"],
header="external solver error",
border="=")
)
sys.exit(-1)
2 changes: 1 addition & 1 deletion seisflows/tests/test_optimize.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import numpy as np
import matplotlib.pyplot as plt
from seisflows.tools.config import Dict
from seisflows.tools.specfem import Model
from seisflows.tools.model import Model
from seisflows.tools.math import angle
from seisflows.optimize.gradient import Gradient
from seisflows.optimize.LBFGS import LBFGS
Expand Down
2 changes: 1 addition & 1 deletion seisflows/tests/test_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from glob import glob
from seisflows import ROOT_DIR
from seisflows.tools.config import Dict
from seisflows.tools.specfem import Model
from seisflows.tools.model import Model
from seisflows.tools.config import custom_import


Expand Down
Loading

0 comments on commit f5d0dcd

Please sign in to comment.