def Check(self): is_distributed = co_simulation_tools.COSIM_SPACE.IsDistributed() solver_parallel_type = self._GetParallelType() if is_distributed and not solver_parallel_type == "MPI": warning_msg = 'WARNING: Global "parallel_type" (MPI) is different ' warning_msg += 'from local one (' + solver_parallel_type + ')!' solverprint(self.lvl, self._Name(), ": " + red(warning_msg)) elif not is_distributed and not solver_parallel_type == "OpenMP": warning_msg = 'WARNING: Global "parallel_type" (OpenMP) is different ' warning_msg += 'from local one (' + solver_parallel_type + ')!' solverprint(self.lvl, self._Name(), ": " + red(warning_msg))
def SolveSolutionStep(self): for k in range(self.num_coupling_iterations): if self.echo_level > 0: couplingsolverprint(self.lvl, self._Name(), cyan("Coupling iteration:"), bold(str(k+1)+" / " + str(self.num_coupling_iterations))) self.convergence_accelerator.InitializeNonLinearIteration() self.convergence_criteria.InitializeNonLinearIteration() for solver_name in self.solver_names: solver = self.solvers[solver_name] self._SynchronizeInputData(solver, solver_name) solver.SolveSolutionStep() self._SynchronizeOutputData(solver, solver_name) self.convergence_accelerator.FinalizeNonLinearIteration() self.convergence_criteria.FinalizeNonLinearIteration() if self.convergence_criteria.IsConverged(): if self.echo_level > 0: couplingsolverprint(self.lvl, self._Name(), green("### CONVERGENCE WAS ACHIEVED ###")) break else: self.convergence_accelerator.ComputeUpdate() if k+1 >= self.num_coupling_iterations and self.echo_level > 0: couplingsolverprint(self.lvl, self._Name(), red("XXX CONVERGENCE WAS NOT ACHIEVED XXX"))
def IsConverged(self): convergence_list = [] for i, data_entry in enumerate(self.settings["data_list"]): solver = self.solvers[data_entry["solver"]] data_name = data_entry["data_name"] cs_tools.ImportArrayFromSolver(solver, data_name, self.new_data) residual = self.new_data - self.old_data[i] res_norm = la.norm(residual) norm_new_data = la.norm(self.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 convergence_list.append(abs_norm < self.abs_tolerances[i] or rel_norm < self.rel_tolerances[i]) if self.echo_level > 1: info_msg = 'Convergence for "'+bold(data_entry["data_name"])+'": ' if convergence_list[i]: info_msg += green("ACHIEVED") else: info_msg += red("NOT ACHIEVED") classprint(self.lvl, self._Name(), info_msg) if self.echo_level > 2: info_msg = bold("abs_norm")+" = " + str(abs_norm) + " | " info_msg += bold("abs_tol")+" = " + str(self.abs_tolerances[i]) info_msg += " || "+bold("rel_norm")+" = " + str(rel_norm) + " | " info_msg += bold("rel_tol") +" = " + str(self.rel_tolerances[i]) classprint(self.lvl, self._Name(), info_msg) return min(convergence_list) # return false if any of them did not converge!
def __init__(self, cosim_settings): if (type(cosim_settings) != dict): raise Exception( "Input is expected to be provided as a python dictionary") CheckCoSimulationSettingsAndAssignDefaults(cosim_settings) problem_data = cosim_settings["problem_data"] self.cosim_settings = cosim_settings cs_tools.PRINT_COLORS = problem_data["print_colors"] parallel_type = problem_data["parallel_type"] if parallel_type == "OpenMP": self.flush_stdout = True cs_tools.PRINTING_RANK = True elif parallel_type == "MPI": from co_simulation_mpi_space import CoSimulationMPISpace cs_tools.COSIM_SPACE = CoSimulationMPISpace() cs_tools.PRINTING_RANK = (cs_tools.COSIM_SPACE.Rank() == 0) else: raise Exception('"parallel_type" can only be "OpenMP" or "MPI"!') self.flush_stdout = problem_data["flush_stdout"] self.echo_level = problem_data["echo_level"] print( red("DEPRECATION-WARNING:"), "The CoSimulation-features in the EmpireApplication have been moved to the CoSimulationApplication.\nThe EmpireApplication-CoSimulation will be supported for some time, but it will be removed eventually.\nPlease update your code." )
def _ComputeUpdate(self, r, x): self.V.appendleft(deepcopy(r)) self.W.appendleft(deepcopy(x)) row = len(r) col = len(self.V) - 1 k = col if k == 0: ## For the first iteration, do relaxation only if self.echo_level > 3: classprint( self.lvl, self._Name(), "Doing relaxation in the first iteration with factor = ", "{0:.1g}".format(self.alpha)) return self.alpha * r else: self.F = np.empty(shape=(col, row)) # will be transposed later self.X = np.empty(shape=(col, row)) # will be transposed later for i in range(0, col): self.F[i] = self.V[i] - self.V[i + 1] self.X[i] = self.W[i] - self.W[i + 1] self.F = self.F.T self.X = self.X.T #compute Moore-Penrose inverse of F^T F A = np.linalg.pinv(self.F.T @ self.F) switch = (self.iteration_counter + 1) / self.p classprint(self.lvl, magenta(self.iteration_counter)) if switch.is_integer() == True: B = self.beta * np.identity(row) - ( self.X + self.beta * self.F) @ A @ self.F.T if self.echo_level > 3: classprint(self.lvl, self._Name(), blue("Compute B with Anderson")) else: B = self.alpha * np.identity(row) if self.echo_level > 3: classprint(self.lvl, self._Name(), red("Constant underrelaxtion")) delta_x = B @ r self.iteration_counter += 1 return delta_x def FinalizeSolutionStep(self): self.V.clear() self.W.clear() def _Name(self): return self.__class__.__name__
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: classprint( self.lvl, 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: classprint( self.lvl, self._Name(), ": Doing relaxation with factor = " + "{0:.1g}".format(alpha)) if alpha > 20: alpha = 20 if self.echo_level > 0: classprint( self.lvl, self._Name(), ": " + red("WARNING: dynamic relaxation factor reaches upper bound: 20" )) elif alpha < -2: alpha = -2 if self.echo_level > 0: classprint( self.lvl, self._Name(), ": " + red("WARNING: dynamic relaxation factor reaches lower bound: -2" )) delta_x = alpha * self.R[0] self.alpha_old = alpha return delta_x