コード例 #1
0
 def setup(self):
     """
     Sets up the SeisFlows3 modules for the Migration
     """
     # Set up all the requisite modules from the master job
     self.logger.info(msg.mnr("PERFORMING MODULE SETUP"))
     preprocess.setup()
     postprocess.setup()
     system.run("solver", "setup")
コード例 #2
0
    def clean(self):
        """
        Cleans directories in which function and gradient evaluations were
        carried out
        """
        self.logger.info(msg.mnr("CLEANING WORKDIR FOR NEXT ITERATION"))

        unix.rm(PATH.GRAD)
        unix.rm(PATH.FUNC)
        unix.mkdir(PATH.GRAD)
        unix.mkdir(PATH.FUNC)
コード例 #3
0
    def evaluate_gradient(self, path=None):
        """
        Performs adjoint simulation to retrieve the gradient of the objective 
        """
        self.logger.info(msg.mnr("EVALUATING GRADIENT"))

        self.logger.debug(
            f"evaluating gradient {PAR.NTASK} times on system...")
        system.run("solver",
                   "eval_grad",
                   path=path or PATH.GRAD,
                   export_traces=PAR.SAVETRACES)
コード例 #4
0
    def finalize(self):
        """
        Saves results from current model update iteration
        """
        self.logger.info(msg.mnr("FINALIZING MIGRATION WORKFLOW"))

        if PAR.SAVETRACES:
            self.save_traces()
        if PAR.SAVEKERNELS:
            self.save_kernels()
        else:
            self.save_kernels_sum()
コード例 #5
0
    def write_gradient(self):
        """
        Writes gradient in format expected by non-linear optimization library.
        Calls the postprocess module, which will smooth/precondition gradient.
        """
        self.logger.info(msg.mnr("POSTPROCESSING KERNELS"))
        src = os.path.join(PATH.GRAD, "gradient")
        dst = f"g_new"

        postprocess.write_gradient(PATH.GRAD)
        parts = solver.load(src, suffix="_kernel")

        optimize.save(dst, solver.merge(parts))
コード例 #6
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()
コード例 #7
0
    def main(self, return_flow=False):
        """
        This function controls the main SeisFlows3 workflow, and is submitted
        to system by the call `seisflows submit` or `seisflows resume`. It
        proceeds to evaluate a list of functions in order until a User defined
        stop criteria is met.

        :type return_flow: bool
        :param return_flow: for CLI tool, simply returns the flow function
            rather than running the workflow. Used for print statements etc.
        """
        # The workFLOW is a tuple of functions that can be called dynamic ally
        flow = (self.setup, self.initialize, self.evaluate_gradient,
                self.write_gradient, self.compute_direction, self.line_search,
                self.finalize, self.clean)
        if return_flow:
            return flow

        # Allow workflow resume from and stop after given flow functions
        start, stop = self.check_stop_resume_cond(flow)

        # Run the workflow until from the current iteration until PAR.END
        optimize.iter = PAR.BEGIN
        self.logger.info(msg.mjr("STARTING INVERSION WORKFLOW"))
        while True:
            self.logger.info(msg.mnr(f"ITERATION {optimize.iter} / {PAR.END}"))

            # Execute the functions within the flow
            for func in flow[start:stop]:
                func()

            # Finish. Assuming completion of all arguments in flow()
            self.logger.info(msg.mjr(f"FINISHED FLOW EXECUTION"))

            # Reset flow for subsequent iterations
            start, stop = None, None

            if optimize.iter >= PAR.END:
                break

            optimize.iter += 1
            self.logger.info(
                msg.sub(f"INCREMENT ITERATION TO {optimize.iter}"))

        self.logger.info(msg.mjr("FINISHED INVERSION WORKFLOW"))
コード例 #8
0
    def line_search(self):
        """
        Conducts line search in given search direction

        Status codes:
            status > 0  : finished
            status == 0 : not finished
            status < 0  : failed
        """
        # Calculate the initial step length based on optimization algorithm
        if optimize.line_search.step_count == 0:
            self.logger.info(
                msg.mjr(f"CONDUCTING LINE SEARCH "
                        f"({optimize.eval_str})"))
            optimize.initialize_search()

        # Attempt a new trial step with the given step length
        optimize.line_search.step_count += 1
        self.logger.info(msg.mnr(f"TRIAL STEP COUNT: {optimize.eval_str}"))
        self.evaluate_function(path=PATH.FUNC, suffix="try")

        # Check the function evaluation against line search history
        status = optimize.update_search()

        # Proceed based on the outcome of the line search
        if status > 0:
            self.logger.info("trial step successful")
            # Save outcome of line search to disk; reset step to 0 for next iter
            optimize.finalize_search()
            return
        elif status == 0:
            self.logger.info("retrying with new trial step")
            # Recursively call this function to attempt another trial step
            self.line_search()
        elif status < 0:
            if optimize.retry_status():
                self.logger.info("line search failed. restarting line search")
                # Reset the line search machinery; set step count to 0
                optimize.restart()
                self.line_search()
            else:
                self.logger.info("line search failed. aborting inversion.")
                sys.exit(-1)
コード例 #9
0
    def setup(self):
        """
        Lays groundwork for inversion by running setup() functions for the 
        involved sub-modules, generating True model synthetic data if necessary,
        and generating the pre-requisite database files.

        .. note::
            This function should only be run one time, at the start of iter 1
        """
        # Iter check is done inside setup() so that we can include fx in FLOW
        if optimize.iter == 1:
            # Set up all the requisite modules from the master job
            self.logger.info(msg.mnr("PERFORMING MODULE SETUP"))
            preprocess.setup()
            postprocess.setup()
            optimize.setup()

            # Run solver.setup() in parallel
            self.logger.info("setting up solver on system...")
            system.run("solver", "setup")
コード例 #10
0
 def compute_direction(self):
     """
     Computes search direction
     """
     self.logger.info(msg.mnr("COMPUTING SEARCH DIRECTION"))
     optimize.compute_direction()
コード例 #11
0
ファイル: base.py プロジェクト: bch0w/seisflows
    def check_stop_resume_cond(self, flow):
        """
        Chek the stop after and resume from conditions

        Allow the main() function to resume a workflow from a given flow
        argument, or stop the workflow after a given argument. In the event
        that a previous workflow errored, or if the User had previously
        stopped a workflow to look at results and they want to pick up where
        they left off.

        Late check: Exits the workflow if RESUME_FROM or STOP_AFTER arguments
        do not match any of the given flow arguments.

        :type flow: tuple of functions
        :param flow: an ordered list of functions that will be
        :rtype: tuple of int
        :return: (start, stop) indices of the `flow` input dictating where the
            list should be begun and ended. If RESUME_FROM and STOP_AFTER
            conditions are NOT given by the user, start and stop will be 0 and
            -1 respectively, meaning we should execute the ENTIRE list
        """
        fxnames = [func.__name__ for func in flow]

        # Default values which dictate that flow will execute in its entirety
        start_idx = None
        stop_idx = None

        # Overwrite start_idx if RESUME_FROM given, exit condition if no match
        if PAR.RESUME_FROM:
            try:
                start_idx = fxnames.index(PAR.RESUME_FROM)
                fx_name = flow[start_idx].__name__
                self.logger.info(
                    msg.mnr(f"WORKFLOW WILL RESUME FROM FUNC: '{fx_name}'"))
            except ValueError:
                self.logger.info(
                    msg.cli(
                        f"{PAR.RESUME_FROM} does not correspond to any FLOW "
                        f"functions. Please check that PAR.RESUME_FROM "
                        f"matches one of the functions listed out in "
                        f"`seisflows print flow`.",
                        header="error",
                        border="="))
                sys.exit(-1)

        # Overwrite stop_idx if STOP_AFTER provided, exit condition if no match
        if PAR.STOP_AFTER:
            try:
                stop_idx = fxnames.index(PAR.STOP_AFTER)
                fx_name = flow[stop_idx].__name__
                stop_idx += 1  # increment to stop AFTER, due to python indexing
                self.logger.info(
                    msg.mnr(f"WORKFLOW WILL STOP AFTER FUNC: '{fx_name}'"))
            except ValueError:
                self.logger.info(
                    msg.cli(
                        f"{PAR.STOP_AFTER} does not correspond to any FLOW "
                        f"functions. Please check that PAR.STOP_AFTER "
                        f"matches one of the functions listed out in "
                        f"`seisflows print flow`.",
                        header="error",
                        border="="))
                sys.exit(-1)

        # Make sure stop after doesn't come before resume_from, otherwise none
        # of the flow will execute
        if PAR.STOP_AFTER and PAR.RESUME_FROM:
            if stop_idx <= start_idx:
                self.logger.info(
                    msg.cli(
                        f"PAR.STOP_AFTER=='{PAR.STOP_AFTER}' is called "
                        f"before PAR.RESUME_FROM=='{PAR.RESUME_FROM}' in "
                        f"the FLOW functions. Please adjust accordingly "
                        f"and rerun.",
                        header="error",
                        border="="))
                sys.exit(-1)

        return start_idx, stop_idx