def IsConverged(self): new_data = self.interface_data.GetData() residual = new_data - self.prev_data res_norm = la.norm(residual) norm_new_data = la.norm(new_data) if norm_new_data < 1e-15: norm_new_data = 1.0 # to avoid division by zero abs_norm = res_norm / np.sqrt(residual.size) rel_norm = res_norm / norm_new_data is_converged = abs_norm < self.abs_tolerance or rel_norm < self.rel_tolerance if self.echo_level > 1: info_msg = 'Convergence for "' + colors.bold( self.interface_data.variable.Name()) + '": ' if is_converged: info_msg += colors.green("ACHIEVED") else: info_msg += colors.red("NOT ACHIEVED") cs_tools.cs_print_info(self._Name(), info_msg) if self.echo_level > 2: info_msg = colors.bold("abs_norm") + " = " + str(abs_norm) + " | " info_msg += colors.bold("abs_tol") + " = " + str( self.abs_tolerance) + " || " info_msg += colors.bold("rel_norm") + " = " + str(rel_norm) + " | " info_msg += colors.bold("rel_tol") + " = " + str( self.rel_tolerance) cs_tools.cs_print_info(self._Name(), info_msg) return is_converged
def IsConverged(self): new_data = self.interface_data.GetData() residual = new_data - self.prev_data abs_norm = la.norm(residual) / np.sqrt(residual.size) if self.initial_iteration: self.initial_iteration = False self.initial_norm = abs_norm rel_norm = abs_norm / self.initial_norm is_converged = abs_norm < self.abs_tolerance or rel_norm < self.rel_tolerance if self.echo_level > 1: info_msg = 'Convergence for "' + colors.bold( self.interface_data.variable.Name()) + '": ' if is_converged: info_msg += colors.green("ACHIEVED") else: info_msg += colors.red("NOT ACHIEVED") cs_tools.cs_print_info(self._ClassName(), info_msg) if self.echo_level > 2: info_msg = colors.bold("abs_norm") + " = " + str(abs_norm) + " | " info_msg += colors.bold("abs_tol") + " = " + str( self.abs_tolerance) + " || " info_msg += colors.bold("rel_norm") + " = " + str(rel_norm) + " | " info_msg += colors.bold("rel_tol") + " = " + str( self.rel_tolerance) cs_tools.cs_print_info(self._ClassName(), info_msg) return is_converged
def _ExecuteTransferData(self, from_solver_data, to_solver_data, transfer_options): model_part_origin = from_solver_data.GetModelPart() model_part_origin_name = from_solver_data.model_part_name variable_origin = from_solver_data.variable identifier_origin = from_solver_data.solver_name + "." + model_part_origin_name model_part_destination = to_solver_data.GetModelPart() model_part_destination_name = to_solver_data.model_part_name variable_destination = to_solver_data.variable identifier_destination = to_solver_data.solver_name + "." + model_part_destination_name mapper_flags = self.__GetMapperFlags(transfer_options) # TODO in the future automatically add the flags if the values are non-historical identifier_tuple = (identifier_origin, identifier_destination) inverse_identifier_tuple = (identifier_destination, identifier_origin) if identifier_tuple in self.__mappers: self.__mappers[identifier_tuple].Map(variable_origin, variable_destination, mapper_flags) elif inverse_identifier_tuple in self.__mappers: self.__mappers[inverse_identifier_tuple].InverseMap( variable_destination, variable_origin, mapper_flags) else: if model_part_origin.IsDistributed( ) or model_part_destination.IsDistributed(): mapper_create_fct = python_mapper_factory.CreateMPIMapper else: mapper_create_fct = python_mapper_factory.CreateMapper if self.echo_level > 0: info_msg = "Creating Mapper:\n" info_msg += ' Origin: ModelPart "{}" of solver "{}"\n'.format( model_part_origin_name, from_solver_data.solver_name) info_msg += ' Destination: ModelPart "{}" of solver "{}"'.format( model_part_destination_name, to_solver_data.solver_name) cs_tools.cs_print_info(colors.bold(self._ClassName()), info_msg) mapper_creation_start_time = time() self.__mappers[identifier_tuple] = mapper_create_fct( model_part_origin, model_part_destination, self.settings["mapper_settings"].Clone() ) # Clone is necessary because the settings are validated and defaults assigned, which could influence the creation of other mappers if self.echo_level > 2: cs_tools.cs_print_info( colors.bold(self._ClassName()), "Creating Mapper took: {0:.{1}f} [s]".format( time() - mapper_creation_start_time, 2)) self.__mappers[identifier_tuple].Map(variable_origin, variable_destination, mapper_flags)
def InitializeSolutionStep(self): self.step += 1 cs_tools.cs_print_info( colors.bold("\ntime={0:.12g}".format(self.time) + " | step=" + str(self.step))) self._GetSolver().InitializeSolutionStep()
def SolveSolutionStep(self): for k in range(self.num_coupling_iterations): if self.echo_level > 0: cs_tools.cs_print_info( self._ClassName(), colors.cyan("Coupling iteration:"), colors.bold( str(k + 1) + " / " + str(self.num_coupling_iterations))) for coupling_op in self.coupling_operations_dict.values(): coupling_op.InitializeCouplingIteration() for conv_acc in self.convergence_accelerators_list: conv_acc.InitializeNonLinearIteration() for conv_crit in self.convergence_criteria_list: conv_crit.InitializeNonLinearIteration() for solver_name, solver in self.solver_wrappers.items(): self._SynchronizeInputData(solver_name) solver.SolveSolutionStep() self._SynchronizeOutputData(solver_name) for coupling_op in self.coupling_operations_dict.values(): coupling_op.FinalizeCouplingIteration() for conv_acc in self.convergence_accelerators_list: conv_acc.FinalizeNonLinearIteration() for conv_crit in self.convergence_criteria_list: conv_crit.FinalizeNonLinearIteration() is_converged = all([ conv_crit.IsConverged() for conv_crit in self.convergence_criteria_list ]) if is_converged: if self.echo_level > 0: cs_tools.cs_print_info( self._ClassName(), colors.green("### CONVERGENCE WAS ACHIEVED ###")) self.__CommunicateStateOfConvergence(True) return True if k + 1 >= self.num_coupling_iterations and self.echo_level > 0: cs_tools.cs_print_info( self._ClassName(), colors.red("XXX CONVERGENCE WAS NOT ACHIEVED XXX")) self.__CommunicateStateOfConvergence( True ) # True because max number of iterations is achieved. Otherwise external solver is stuck in time return False # if it reaches here it means that the coupling has not converged and this was not the last coupling iteration self.__CommunicateStateOfConvergence(False) # do relaxation only if this iteration is not the last iteration of this timestep for conv_acc in self.convergence_accelerators_list: conv_acc.ComputeAndApplyUpdate()
def Run(self): num_coupling_interfaces = self.settings["coupling_interfaces"].size() self.__CustomPrint( 1, colors.cyan("Starting export") + " of CouplingInterfaces ...") for i in range(num_coupling_interfaces): coupling_interface_settings = self.settings["coupling_interfaces"][ i] sub_model_part_name = coupling_interface_settings[ "sub_model_part_name"].GetString() comm_name = coupling_interface_settings["comm_name"].GetString() receive_interface = False operation = "Exporting" if coupling_interface_settings.Has("receive_interface"): receive_interface = coupling_interface_settings[ "receive_interface"].GetBool() operation = "Importing" self.__CustomPrint( 2, colors.cyan(operation) + ' coupling-interface "{}" on ModelPart "{}"'.format( comm_name, sub_model_part_name)) if not self.dry_run: if receive_interface: # use an aux-modelpart, which will not be used again KratosCoSim.EMPIRE_API.EMPIRE_API_recvMesh( self.model.CreateModelPart(sub_model_part_name), comm_name) # TODO maybe restructure and do all receives after all sends else: KratosCoSim.EMPIRE_API.EMPIRE_API_sendMesh( self.model["ExtSolver." + sub_model_part_name], comm_name) else: self.__CustomPrint(2, colors.magenta('... skipped')) self.__CustomPrint( 1, colors.cyan("Finished " + operation) + " of CouplingInterfaces") # time loop self.__CustomPrint(1, "Starting Solution Loop") for i in range(self.settings["num_steps"].GetInt()): if self.echo_level > 0: print() # newline self.__CustomPrint( 1, colors.bold('Step: {}/{}'.format( i + 1, self.settings["num_steps"].GetInt()))) self.SolveSolutionStep() self.__CustomPrint(1, "Finished")
def SolveSolutionStep(self): for k in range(self.num_coupling_iterations): if self.echo_level > 0: cs_tools.cs_print_info( self._ClassName(), colors.cyan("Coupling iteration:"), colors.bold( str(k + 1) + " / " + str(self.num_coupling_iterations))) for coupling_op in self.coupling_operations_dict.values(): coupling_op.InitializeCouplingIteration() for conv_acc in self.convergence_accelerators_list: conv_acc.InitializeNonLinearIteration() for conv_crit in self.convergence_criteria_list: conv_crit.InitializeNonLinearIteration() for solver_name, solver in self.solver_wrappers.items(): self._SynchronizeInputData(solver_name) solver.SolveSolutionStep() self._SynchronizeOutputData(solver_name) for coupling_op in self.coupling_operations_dict.values(): coupling_op.FinalizeCouplingIteration() for conv_acc in self.convergence_accelerators_list: conv_acc.FinalizeNonLinearIteration() for conv_crit in self.convergence_criteria_list: conv_crit.FinalizeNonLinearIteration() is_converged = all([ conv_crit.IsConverged() for conv_crit in self.convergence_criteria_list ]) self.__CommunicateStateOfConvergence(is_converged) if is_converged: if self.echo_level > 0: cs_tools.cs_print_info( self._ClassName(), colors.green("### CONVERGENCE WAS ACHIEVED ###")) return True else: # TODO I think this should not be done in the last iterations if the solution does not converge in this timestep for conv_acc in self.convergence_accelerators_list: conv_acc.ComputeAndApplyUpdate() if k + 1 >= self.num_coupling_iterations and self.echo_level > 0: cs_tools.cs_print_info( self._ClassName(), colors.red("XXX CONVERGENCE WAS NOT ACHIEVED XXX")) return False
def __init__(self, settings, solver_wrapper): self.interface_data = solver_wrapper.GetInterfaceData( settings["data_name"].GetString()) settings.RemoveValue("data_name") settings.RemoveValue("solver") if not settings.Has("label"): settings.AddEmptyValue("label").SetString( colors.bold('{}.{}'.format(self.interface_data.solver_name, self.interface_data.name))) self.conv_crit = CreateConvergenceCriterion(settings)
def TransferData(self, from_solver_data, to_solver_data, transfer_options): # TODO check location of data => should coincide with the one for the mapper # or throw if it is not in a suitable location (e.g. on the ProcessInfo) self._CheckAvailabilityTransferOptions(transfer_options) model_part_origin = from_solver_data.GetModelPart() model_part_origin_name = from_solver_data.model_part_name variable_origin = from_solver_data.variable identifier_origin = from_solver_data.solver_name + "." + model_part_origin_name model_part_destination = to_solver_data.GetModelPart() model_part_destination_name = to_solver_data.model_part_name variable_destination = to_solver_data.variable identifier_destination = to_solver_data.solver_name + "." + model_part_destination_name mapper_flags = self.__GetMapperFlags(transfer_options) identifier_tuple = (identifier_origin, identifier_destination) inverse_identifier_tuple = (identifier_destination, identifier_origin) if identifier_tuple in self.__mappers: self.__mappers[identifier_tuple].Map(variable_origin, variable_destination, mapper_flags) elif inverse_identifier_tuple in self.__mappers: self.__mappers[inverse_identifier_tuple].InverseMap( variable_destination, variable_origin, mapper_flags) else: # CheckIfInterfaceDataIsSuitable() # TODO if model_part_origin.IsDistributed( ) or model_part_destination.IsDistributed(): mapper_create_fct = KratosMapping.MapperFactory.CreateMPIMapper else: mapper_create_fct = KratosMapping.MapperFactory.CreateMapper if self.echo_level > 0: info_msg = "Creating Mapper:\n" info_msg += ' Origin: ModePart "{}" of solver "{}"\n'.format( model_part_origin_name, from_solver_data.solver_name) info_msg += ' Destination: ModePart "{}" of solver "{}"'.format( model_part_destination_name, to_solver_data.solver_name) cs_tools.cs_print_info(colors.bold(self._ClassName()), info_msg) self.__mappers[identifier_tuple] = mapper_create_fct( model_part_origin, model_part_destination, self.settings["mapper_settings"].Clone() ) # Clone is necessary here bcs settings are influenced among mappers otherwise. TODO check in the MapperFactory how to solve this better self.__mappers[identifier_tuple].Map(variable_origin, variable_destination, mapper_flags)
def PrintInfo(self): cs_tools.cs_print_info("Convergence Criteria", colors.bold(self._ClassName()))
def cs_print_warning(label, *args): KM.Logger.PrintWarning( colors.red("Warning: ") + colors.bold(label), " ".join(map(str, args)))
def cs_print_info(label, *args): KM.Logger.PrintInfo(colors.bold(label), " ".join(map(str, args)))
def PrintInfo(self): '''Function to print Info abt the Object Can be overridden in derived classes to print more information ''' cs_tools.cs_print_info("Convergence Accelerator", colors.bold(self._Name()))
def __init__(self, settings, solvers): super().__init__(settings) if self.settings["criteria_composition"].GetString( ) != "energy_conjugate": self.__RaiseException( 'Energy conjugate criteria composition requires energy conjugate variables to be specified in "data_name" and "conjugate_data_name".' ) self.iteration = 1 self.abs_tolerance = self.settings["abs_tolerance"].GetDouble() self.ignore_first_convergence = self.settings[ "ignore_first_convergence"].GetBool() # Determine if we are looking at the energy difference between two domains (solvers), or just one self.solver_vec = [solvers[settings["solver"].GetString()]] is_dual_domain = False for criteria_option in settings["criteria_options"]: if criteria_option.GetString() == "domain_difference": is_dual_domain = True break if is_dual_domain: is_error = False if settings.Has("solver_domain_two"): solver_domain_two = settings["solver_domain_two"].GetString() if solver_domain_two == "UNSPECIFIED": is_error = True else: self.solver_vec.append(solvers[solver_domain_two]) else: is_error = True if is_error: self.__RaiseException( 'Domain difference requires "solver_domain_two" to be set to the second domain.' ) # Setup interface data matrix (general form) self.interface_data = [None] * len(solvers) for solver_index in range(0, len(self.interface_data)): self.interface_data[solver_index] = [ self.solver_vec[solver_index].GetInterfaceData( settings["data_name"].GetString()) ] self.interface_data[solver_index].append( self.solver_vec[solver_index].GetInterfaceData( settings["conjugate_data_name"].GetString())) self.second_domain_data_sign = 1.0 if "swap_second_domain_data_sign" in settings[ "criteria_options"].GetStringArray(): self.second_domain_data_sign = -1.0 settings.RemoveValue("data_name") settings.RemoveValue("solver") if not settings.Has("label"): settings.AddEmptyValue("label").SetString( colors.bold('{}.{}'.format( self.interface_data[0][0].solver_name, self.interface_data[0][0].name))) self.label = self.settings["label"].GetString()
def Check(self): cs_tools.cs_print_warning("Convergence Criteria", colors.bold(self._ClassName()), 'does not implement "Check"')
def PrintInfo(self): '''Function to print Info abt the Object Can be overridden in derived classes to print more information ''' cs_tools.cs_print_info("Predictor", colors.bold(self._ClassName()))