def ComputeUpdate( self, r, x ): self.R.appendleft( deepcopy(r) ) k = len( self.R ) - 1 ## For the first iteration, do relaxation only if k == 0: alpha = min( self.alpha_old, self.init_alpha_max ) if self.echo_level > 3: cs_tools.cs_print_info(self._Name(), ": Doing relaxation in the first iteration with initial factor = " + "{0:.1g}".format(alpha)) return alpha * r else: r_diff = self.R[0] - self.R[1] numerator = np.inner( self.R[1], r_diff ) denominator = np.inner( r_diff, r_diff ) alpha = -self.alpha_old * numerator/denominator if self.echo_level > 3: cs_tools.cs_print_info(self._Name(), ": Doing relaxation with factor = " + "{0:.1g}".format(alpha)) if alpha > 20: alpha = 20 if self.echo_level > 0: cs_tools.cs_print_warning(self._Name(), "dynamic relaxation factor reaches upper bound: 20") elif alpha < -2: alpha = -2 if self.echo_level > 0: cs_tools.cs_print_warning(self._Name(), "dynamic relaxation factor reaches lower bound: -2") delta_x = alpha * self.R[0] self.alpha_old = alpha return delta_x
def UpdateSolution( self, r, x ): self.R.appendleft( deepcopy(r) ) ## For the first iteration, do relaxation only if self.initial_iteration: self.initial_iteration = False alpha = min( self.alpha_old, self.init_alpha_max ) if self.echo_level > 3: cs_tools.cs_print_info(self._ClassName(), ": Doing relaxation in the first iteration with initial factor = {}".format(alpha)) return alpha * r else: r_diff = self.R[0] - self.R[1] numerator = np.inner( self.R[1], r_diff ) denominator = np.inner( r_diff, r_diff ) alpha = -self.alpha_old * numerator/denominator if self.echo_level > 3: cs_tools.cs_print_info(self._ClassName(), ": Doing relaxation with factor = {}".format(alpha)) if alpha > self.alpha_max: alpha = self.alpha_max if self.echo_level > 0: cs_tools.cs_print_warning(self._ClassName(), "dynamic relaxation factor reaches upper bound: {}".format(self.alpha_max)) elif alpha < self.alpha_min: alpha = self.alpha_min if self.echo_level > 0: cs_tools.cs_print_warning(self._ClassName(), "dynamic relaxation factor reaches lower bound: {}".format(self.alpha_min)) delta_x = alpha * self.R[0] self.alpha_old = alpha return delta_x
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, residual, current_data): res_norm = la.norm(residual) norm_new_data = la.norm(current_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 info_msg = "" if self.echo_level > 1: info_msg = 'Convergence ' if self.label != "": info_msg += 'for "{}": '.format(self.label) if is_converged: info_msg += colors.green("ACHIEVED") else: info_msg += colors.red("NOT ACHIEVED") if self.echo_level > 2: info_msg += '\n\t abs-norm = {:.2e} | abs-tol = {} || rel-norm = {:.2e} | rel-tol = {}'.format( abs_norm, self.abs_tolerance, rel_norm, self.rel_tolerance) if info_msg != "": cs_tools.cs_print_info(self._ClassName(), 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 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 IsConverged(self, residual, current_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 info_msg = "" if self.echo_level > 1: info_msg = 'Convergence ' if self.label != "": info_msg += 'for "{}": '.format(self.label) if is_converged: info_msg += colors.green("ACHIEVED") else: info_msg += colors.red("NOT ACHIEVED") if self.echo_level > 2: info_msg += '\n\t abs-norm = {:.2e} | abs-tol = {} || rel-norm = {:.2e} | rel-tol = {}'.format( abs_norm, self.abs_tolerance, rel_norm, self.rel_tolerance) if info_msg != "": cs_tools.cs_print_info(self._ClassName(), info_msg) return is_converged
def Execute(self): process_info = self.interface_data.GetModelPart().ProcessInfo time = process_info[KM.TIME] step = process_info[KM.STEP] if not KM.IntervalUtility(self.settings).IsInInterval(time): if self.echo_level > 0: cs_tools.cs_print_info("ScalingOperation", "Skipped, not in interval") return if isinstance(self.scaling_factor, str): # TODO maybe make this to use COSIM_TIME and COSIM_STEP, such that it is generic for all solvers scope_vars = { 't': time, 'step': step } # make time and step useable in function current_scaling_factor = GenericCallFunction( self.scaling_factor, scope_vars, check=False) # evaluating function string else: current_scaling_factor = self.scaling_factor if self.echo_level > 0: cs_tools.cs_print_info("ScalingOperation", "Scaling-Factor", current_scaling_factor) self.interface_data.SetData( current_scaling_factor * self.interface_data.GetData()) # setting the scaled data
def PrintInfo(self): cs_tools.cs_print_info("KratosSolver", self._ClassName()) cs_tools.cs_print_info( "KratosSolver", 'Using AnalysisStage "{}", defined in module "{}'.format( self._analysis_stage.__class__.__name__, self._analysis_stage.__class__.__module__))
def AllocateHistoricalVariablesFromCouplingDataSettings( data_settings_list, model, solver_name): '''This function allocates historical variables for the Modelparts It retrieves the historical variables that are needed for the ModelParts from the specified CouplingInterfaceData-settings and allocates them on the ModelParts Note that it can only be called after the (Main-)ModelParts are created ''' data_settings_list = data_settings_list.Clone( ) # clone to not mess with the following validation for data_settings in data_settings_list.values(): CouplingInterfaceData.GetDefaultParameters() data_settings.ValidateAndAssignDefaults( CouplingInterfaceData.GetDefaultParameters()) if data_settings["location"].GetString() == "node_historical": variable = KM.KratosGlobals.GetVariable( data_settings["variable_name"].GetString()) main_model_part_name = data_settings["model_part_name"].GetString( ).split(".")[0] if not model.HasModelPart(main_model_part_name): raise Exception( 'ModelPart "{}" does not exist in solver "{}"!'.format( main_model_part_name, solver_name)) main_model_part = model[main_model_part_name] if not main_model_part.HasNodalSolutionStepVariable(variable): cs_print_info( "CoSimTools", 'Allocating historical variable "{}" in ModelPart "{}" for solver "{}"' .format(variable.Name(), main_model_part_name, solver_name)) main_model_part.AddNodalSolutionStepVariable(variable)
def ExportData(self, data_config): if self.echo_level > 2: cs_tools.cs_print_info( "CoSimulationSolverWrapper", 'Exporting data of solver: "{}" with type: "{}"'.format( colors.blue(self.name), data_config["type"])) self.__GetIO().ExportData(data_config)
def __del__(self): # make sure no communication files are left even if simulation is terminated prematurely if os.path.isdir(communication_folder): kratos_utilities.DeleteDirectoryIfExisting(communication_folder) if self.echo_level > 0: cs_tools.cs_print_info( self._ClassName(), "Deleting Communication folder in destructor")
def ExportCouplingInterface(self, interface_config): if self.echo_level > 2: cs_tools.cs_print_info( "CoSimulationSolverWrapper", 'Exporting coupling interface "{}" of solver: "{}"'.format( colors.magenta(interface_config["model_part_name"]), colors.blue(self.name))) self.__GetIO().ExportCouplingInterface(interface_config)
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 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 RecursiveCreateModelParts(model_part, model_part_name): '''This function creates a hierarchy of SubModelParts on a given ModelPart''' model_part_name, *sub_model_part_names = model_part_name.split(".") if model_part.HasSubModelPart(model_part_name): model_part = model_part.GetSubModelPart(model_part_name) else: cs_print_info( "CoSimTools", 'Created "{}" as SubModelPart of "{}"'.format( model_part_name, model_part.Name)) model_part = model_part.CreateSubModelPart(model_part_name) if len(sub_model_part_names) > 0: RecursiveCreateModelParts(model_part, ".".join(sub_model_part_names))
def PrintInfo(self): super(CoSimulationCoupledSolver, self).PrintInfo() cs_tools.cs_print_info(self._ClassName(), "Has the following components:") for solver in self.solver_wrappers.values(): solver.PrintInfo() for predictor in self.predictors_list: predictor.PrintInfo() for coupling_operation in self.coupling_operations_dict.values(): coupling_operation.PrintInfo()
def IsConverged(self): # Compute energy scalar on interface current_data = 0.0 for solver_index in range(0, len(self.interface_data)): #check length of data vectors are the same interface_energy = 0.0 data_1 = self.interface_data[solver_index][0].GetData() data_2 = self.interface_data[solver_index][1].GetData() if len(data_1) != len(data_2): self.__RaiseException( 'Data vector lengths for conjugate criteria composition must be identical, but they are different!' ) else: for i in range(0, len(data_1)): interface_energy += data_1[i] * data_2[i] if solver_index == 0: current_data = interface_energy else: current_data -= self.second_domain_data_sign * interface_energy #assumes domain_difference abs_norm = la.norm(current_data) if self.ignore_first_convergence and self.iteration == 1: is_converged = False else: is_converged = abs_norm < self.abs_tolerance self.iteration += 1 info_msg = "" if self.echo_level > 1: info_msg = 'Convergence ' if self.label != "": info_msg += 'for "{}": '.format(self.label) if is_converged: info_msg += colors.green("ACHIEVED") else: info_msg += colors.red("NOT ACHIEVED") if self.echo_level > 2: info_msg += '\n\t abs-norm = {:.2e} | abs-tol = {}'.format( abs_norm, self.abs_tolerance) if info_msg != "": cs_tools.cs_print_info(self._ClassName(), info_msg) return is_converged
def __ApplyScaling(self, interface_data, data_configuration): # perform scaling of data if specified if data_configuration["scaling_factor"].IsString(): from KratosMultiphysics.CoSimulationApplication.function_callback_utility import GenericCallFunction scaling_function_string = data_configuration["scaling_factor"].GetString() scope_vars = {'t' : self.time} # make time useable in function scaling_factor = GenericCallFunction(scaling_function_string, scope_vars) # evaluating function string else: scaling_factor = data_configuration["scaling_factor"].GetDouble() if abs(scaling_factor-1.0) > 1E-15: if self.echo_level > 2: cs_tools.cs_print_info(" Scaling-Factor", scaling_factor) interface_data.InplaceMultiply(scaling_factor)
def _SynchronizeOutputData(self, solver_name): from_solver = self.solver_wrappers[solver_name] output_data_list = self.coupling_sequence[solver_name][ "output_data_list"] if self.echo_level > 2: cs_tools.cs_print_info( self._ClassName(), 'Start Synchronizing Output for "{}"'.format( colors.blue(solver_name))) for i in range(output_data_list.size()): i_output_data = output_data_list[i] data_name = i_output_data["data"].GetString() to_solver_name = i_output_data["to_solver"].GetString() to_solver_data_name = i_output_data["to_solver_data"].GetString() if self.echo_level > 2: cs_tools.cs_print_info( " Data", '"{}" | to solver: "{}": "{}"'.format( colors.magenta(data_name), colors.blue(to_solver_name), colors.magenta(to_solver_data_name))) # check if data-exchange is specified for current time if not KM.IntervalUtility(i_output_data).IsInInterval(self.time): if self.echo_level > 2: cs_tools.cs_print_info(" Skipped", 'not in interval') continue # from solver from_solver_data = from_solver.GetInterfaceData(data_name) # to solver to_solver = self.solver_wrappers[to_solver_name] to_solver_data = to_solver.GetInterfaceData(to_solver_data_name) # perform the data transfer self.__ExecuteCouplingOperations( i_output_data["before_data_transfer_operations"]) data_transfer_operator_name = i_output_data[ "data_transfer_operator"].GetString() # TODO check the order of solvers! self.__GetDataTransferOperator( data_transfer_operator_name).TransferData( from_solver_data, to_solver_data, i_output_data["data_transfer_operator_options"]) self.__ExecuteCouplingOperations( i_output_data["after_data_transfer_operations"]) self.__ApplyScaling(to_solver_data, i_output_data) # Exporting data to external solvers from_solver.ExportCouplingInterfaceData(from_solver_data) if self.echo_level > 2: cs_tools.cs_print_info( self._ClassName(), 'End Synchronizing Output for "{}"'.format( colors.blue(solver_name)))
def FinalizeSolutionStep(self): if self.V_new != [] and self.W_new != []: self.v_old_matrices.appendleft(self.V_new) self.w_old_matrices.appendleft(self.W_new) if self.v_old_matrices and self.w_old_matrices: self.V_old = np.concatenate(self.v_old_matrices, 1) self.W_old = np.concatenate(self.w_old_matrices, 1) ## Clear the buffer if self.R and self.X: if self.echo_level > 3: cs_print_info(self._ClassName(), "Cleaning") self.R.clear() self.X.clear() self.V_new = [] self.W_new = []
def FinalizeSolutionStep( self ): if self.J == []: return row = self.J.shape[0] col = self.J.shape[1] ## Assign J=J_hat for i in range(0, row): for j in range(0, col): self.J[i][j] = self.J_hat[i][j] if self.echo_level > 3: cs_tools.cs_print_info(self._Name(), "Jacobian matrix updated!") ## Clear the buffer if self.R and self.X: self.R.clear() self.X.clear()
def UpdateSolution(self, r, x): self.R.appendleft(deepcopy(r)) self.X.appendleft(deepcopy(x)) col = len(self.R) - 1 row = len(r) k = col if self.echo_level > 3: cs_tools.cs_print_info(self._ClassName(), "Number of new modes: ", col) ## For the first iteration if k == 0: if self.J == []: return self.alpha * r # if no Jacobian, do relaxation else: return np.linalg.solve( self.J, -r) # use the Jacobian from previous step ## Let the initial Jacobian correspond to a constant relaxation if self.J == []: self.J = -np.identity( row) / self.alpha # correspongding to constant relaxation ## Construct matrix V (differences of residuals) V = np.empty(shape=(col, row)) # will be transposed later for i in range(0, col): V[i] = self.R[i] - self.R[i + 1] V = V.T ## Construct matrix W(differences of intermediate solutions x) W = np.empty(shape=(col, row)) # will be transposed later for i in range(0, col): W[i] = self.X[i] - self.X[i + 1] W = W.T ## Solve least norm problem rhs = V - np.dot(self.J, W) b = np.identity(row) W_right_inverse = np.linalg.lstsq(W, b)[0] J_tilde = np.dot(rhs, W_right_inverse) self.J_hat = self.J + J_tilde delta_r = -self.R[0] delta_x = np.linalg.solve(self.J_hat, delta_r) return delta_x
def Execute(self): process_info = self.interface_data.GetModelPart().ProcessInfo time = process_info[KM.TIME] if not KM.IntervalUtility(self.settings).IsInInterval(time): if self.echo_level > 0: cs_tools.cs_print_info("Elemental_data_to_Nodal_data", "Skipped, not in interval") return model_part_interface = self.interface_data.GetModelPart() #ConversionUtilities.ConvertElementalDataToNodalData(model_part_interface) ConversionUtilities.ConvertElementalDataToNodalData( model_part_interface, KM.FORCE, KM.FORCE) if self.echo_level > 0: cs_tools.cs_print_info("Elemental_data_to_Nodal_data", "Done")
def __ApplyScaling(self, interface_data, data_configuration): # perform scaling of data if specified if data_configuration["scaling_factor"].IsString(): scaling_function_string = data_configuration[ "scaling_factor"].GetString() scope_vars = {'t': self.time} # make time useable in function scaling_factor = GenericCallFunction( scaling_function_string, scope_vars) # evaluating function string else: scaling_factor = data_configuration["scaling_factor"].GetDouble() if abs(scaling_factor - 1.0) > 1E-15: if self.echo_level > 2: cs_tools.cs_print_info(" Scaling-Factor", scaling_factor) interface_data.SetData( scaling_factor * interface_data.GetData()) # setting the scaled data
def CreateMainModelPartsFromCouplingDataSettings(data_settings_list, model, solver_name): '''This function creates the Main-ModelParts that are used in the specified CouplingInterfaceData-settings''' data_settings_list = data_settings_list.Clone( ) # clone to not mess with the following validation for data_settings in data_settings_list.values(): CouplingInterfaceData.GetDefaultParameters() data_settings.ValidateAndAssignDefaults( CouplingInterfaceData.GetDefaultParameters()) main_model_part_name = data_settings["model_part_name"].GetString( ).split(".")[0] if not model.HasModelPart(main_model_part_name): model.CreateModelPart(main_model_part_name) cs_print_info( "CoSimTools", 'Created ModelPart "{}" for solver "{}"'.format( main_model_part_name, solver_name))
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 __SynchronizeData(self, i_data, from_solver, from_solver_data, to_solver, to_solver_data): # check if data-exchange is specified for current time if not KM.IntervalUtility(i_data).IsInInterval(self.time): if self.echo_level > 2: cs_tools.cs_print_info(" Skipped", 'not in interval') return if from_solver_data.is_outdated: # Importing data from external solvers (if it is outdated) from_solver_data_config = { "type": "coupling_interface_data", "interface_data": from_solver_data } from_solver.ImportData(from_solver_data_config) from_solver_data.is_outdated = False # perform the data transfer self.__ExecuteCouplingOperations( i_data["before_data_transfer_operations"]) data_transfer_operator_name = i_data[ "data_transfer_operator"].GetString() # TODO check the order of solvers! self.__GetDataTransferOperator( data_transfer_operator_name).TransferData( from_solver_data, to_solver_data, i_data["data_transfer_operator_options"]) self.__ExecuteCouplingOperations( i_data["after_data_transfer_operations"]) self.__ApplyScaling(to_solver_data, i_data) # Exporting data to external solvers to_solver_data_config = { "type": "coupling_interface_data", "interface_data": to_solver_data } to_solver.ExportData(to_solver_data_config)
def __SynchronizeData(self, i_data, from_solver, from_solver_data, to_solver, to_solver_data): # check if data-exchange is specified for current time if not KM.IntervalUtility(i_data).IsInInterval(self.time): if self.echo_level > 2: cs_tools.cs_print_info(" Skipped", 'not in interval') return # perform the data transfer self.__ExecuteCouplingOperations( i_data["before_data_transfer_operations"]) data_transfer_operator_name = i_data[ "data_transfer_operator"].GetString() # TODO check the order of solvers! self.__GetDataTransferOperator( data_transfer_operator_name).TransferData( from_solver_data, to_solver_data, i_data["data_transfer_operator_options"]) self.__ExecuteCouplingOperations( i_data["after_data_transfer_operations"])
def _AllocateHistoricalVariablesFromCouplingData(self): '''This function retrieves the historical variables that are needed for the ModelParts from the specified CouplingInterfaceDatas and allocates them on the ModelParts Note that it can only be called after the (Main-)ModelParts are created ''' for data in self.data_dict.values(): hist_var_dict = data.GetHistoricalVariableDict() for full_model_part_name, variable in hist_var_dict.items(): main_model_part_name = full_model_part_name.split(".")[0] if not self.model.HasModelPart(main_model_part_name): raise Exception( 'ModelPart "{}" does not exist in solver "{}"!'.format( main_model_part_name, self.name)) main_model_part = self.model[main_model_part_name] if not main_model_part.HasNodalSolutionStepVariable(variable): if self.echo_level > 0: cs_tools.cs_print_info( "CoSimulationSolverWrapper", 'Allocating historical variable "{}" in ModelPart "{}" for solver "{}"' .format(variable.Name(), main_model_part_name, self.name)) main_model_part.AddNodalSolutionStepVariable(variable) self.__allocate_hist_vars_called = True