def main(self, return_flow=False): """s Migrates seismic data to generate sensitivity kernels :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. """ flow = ( self.setup, self.generate_synthetics, self.backproject, self.process_kernels, self.finalize, ) if return_flow: return flow # Allow workflow resume from and stop after given flow functions start, stop = self.check_stop_resume_cond(flow) # Run each argument in flow self.logger.info(msg.mjr("STARTING MIGRATION WORKFLOW")) for func in flow[start:stop]: func() self.logger.info(msg.mjr("FINISHED MIGRATION WORKFLOW"))
def finalize(self): """ Saves results from current model update iteration and increment the iteration number to set up for the next iteration. Finalization is expected to the be LAST function in workflow.main()'s flow list. """ self.logger.info(msg.mjr(f"FINALIZING ITERATION {optimize.iter}")) self.checkpoint() preprocess.finalize() # Save files from scratch before discarding if PAR.SAVEMODEL: self.save_model() if PAR.SAVEGRADIENT: self.save_gradient() if PAR.SAVEKERNELS: self.save_kernels() if PAR.SAVETRACES: self.save_traces() if PAR.SAVERESIDUALS: self.save_residuals()
def initialize(self): """ Generates synthetics via a forward simulation, calculates misfits for the forward simulation. Writes misfit for use in optimization. """ self.logger.info(msg.mjr("INITIALIZING INVERSION")) self.evaluate_function(path=PATH.GRAD, suffix="new")
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"))
def initialize(self): """ If line search can be carried over, skip initialization step Or if manually starting a new run, start with normal inversion init """ if not self.thrifty or optimize.iter == PAR.BEGIN: super().initialize() else: self.logger.info(msg.mjr("INITIALIZING THRIFTY INVERSION"))
def main(self, return_flow=False): """ Execution of a workflow is equal to stepping through workflow.main() An example main() script is provided below which details the requisite parts. This function will NOT execute as it is written in pseudocode. :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. """ self.logger.warning("The current definition of workflow.main() will " "NOT execute, it must be overwritten by a " "subclass") # The FLOW function defines a list of functions to execute IN ORDER flow = ( self.func1, self.func2, # ... self.funcN) # REQUIRED: CLI command `seisflows print flow` needs this for output if return_flow: return flow # Allow User to start the workflow mid-FLOW, 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 start, stop = self.check_stop_resume_cond(flow) self.logger.info(msg.mjr("BEGINNING EXAMPLE WORKFLOW")) # Iterate through the `FLOW` to step through workflow.main() for func in flow[start:stop]: func() # If an multi-iteration workflow is run, `FLOW` will be executed # repeatedly, so reset start and stop for subsequent iterations start, stop = 0, -1 self.logger.info(msg.mjr("FINISHED EXAMPLE WORKFLOW"))
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)