Source code for gemseo.mda.sequential_mda

# -*- coding: utf-8 -*-
# Copyright 2021 IRT Saint Exupéry, https://www.irt-saintexupery.com
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License version 3 as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

# Contributors:
#    INITIAL AUTHORS - API and implementation and/or documentation
#        :author: Charlie Vanaret
#    OTHER AUTHORS   - MACROSCOPIC CHANGES
"""
A chain of MDAs to build hybrids of MDA algorithms sequentially
***************************************************************
"""
from __future__ import division, unicode_literals

from gemseo.core.discipline import MDODiscipline
from gemseo.mda.gauss_seidel import MDAGaussSeidel
from gemseo.mda.mda import MDA
from gemseo.mda.newton import MDANewtonRaphson


[docs]class MDASequential(MDA): """Perform a MDA defined as a sequence of elementary MDAs.""" def __init__( self, disciplines, mda_sequence, name=None, grammar_type=MDODiscipline.JSON_GRAMMAR_TYPE, max_mda_iter=10, tolerance=1e-6, linear_solver_tolerance=1e-12, warm_start=False, use_lu_fact=False, ): """Constructor. :param disciplines: the disciplines list :type disciplines: list(MDODiscipline) :param mda_sequence: sequence of MDAs :type mda_sequence: list(MDA) :param max_mda_iter: maximum number of iterations :type max_mda_iter: int :param name: name :type name: str :param grammar_type: the type of grammar to use for IO declaration either JSON_GRAMMAR_TYPE or SIMPLE_GRAMMAR_TYPE :type grammar_type: str :param tolerance: tolerance of the iterative direct coupling solver, norm of the current residuals divided by initial residuals norm shall be lower than the tolerance to stop iterating :type tolerance: float :param warm_start: if True, the second iteration and ongoing start from the previous coupling solution :type warm_start: bool :param linear_solver_tolerance: Tolerance of the linear solver in the adjoint equation :type linear_solver_tolerance: float :param use_lu_fact: use LU factorization :type use_lu_fact: bool """ super(MDASequential, self).__init__( disciplines, name=name, grammar_type=grammar_type, max_mda_iter=max_mda_iter, tolerance=tolerance, linear_solver_tolerance=linear_solver_tolerance, warm_start=warm_start, ) self._initialize_grammars() self._set_default_inputs() self._compute_input_couplings() self.mda_sequence = mda_sequence for mda in self.mda_sequence: mda.reset_history_each_run = True def _initialize_grammars(self): """Defines all inputs and outputs.""" for discipline in self.disciplines: self.input_grammar.update_from(discipline.input_grammar) self.output_grammar.update_from(discipline.output_grammar) def _run(self): """Runs the MDAs in a sequential way. :returns: the local data """ self._couplings_warm_start() # execute MDAs in sequence if self.reset_history_each_run: self.residual_history = [] for mda_i in self.mda_sequence: mda_i.reset_statuses_for_run() self.local_data = mda_i.execute(self.local_data) self.residual_history += mda_i.residual_history if mda_i.normed_residual < self.tolerance: break
[docs]class GSNewtonMDA(MDASequential): """Perform some GaussSeidel iterations and then NewtonRaphson iterations.""" def __init__( self, disciplines, name=None, grammar_type=MDODiscipline.JSON_GRAMMAR_TYPE, tolerance=1e-6, max_mda_iter=10, relax_factor=0.99, linear_solver="lgmres", max_mda_iter_gs=3, linear_solver_tolerance=1e-12, warm_start=False, use_lu_fact=False, **newton_mda_options ): """Constructor. :param disciplines: the disciplines list :type disciplines: list(MDODiscipline) :param name: name :type name: str :param grammar_type: the type of grammar to use for IO declaration either JSON_GRAMMAR_TYPE or SIMPLE_GRAMMAR_TYPE :type grammar_type: str :param tolerance: tolerance of the iterative direct coupling solver, norm of the current residuals divided by initial residuals norm shall be lower than the tolerance to stop iterating :type tolerance: float :param max_mda_iter: maximum number of iterations :type max_mda_iter: int :param relax_factor: relaxation factor :type relax_factor: float :param linear_solver: type of linear solver to be used to solve the Newton problem :type linear_solver: str :param max_mda_iter_gs: maximum number of iterations of the GaussSeidel solver :type max_mda_iter_gs: int :param warm_start: if True, the second iteration and ongoing start from the previous coupling solution :type warm_start: bool :param linear_solver_tolerance: Tolerance of the linear solver in the adjoint equation :type linear_solver_tolerance: float :param use_lu_fact: if True, when using adjoint/forward differenciation, store a LU factorization of the matrix to solve faster multiple RHS problem :type use_lu_fact: bool :param newton_mda_options: options passed to the MDANewtonRaphson :type newton_mda_options: dict """ mda_gs = MDAGaussSeidel(disciplines, max_mda_iter=max_mda_iter_gs, name=None) mda_gs.tolerance = tolerance mda_newton = MDANewtonRaphson( disciplines, max_mda_iter, relax_factor, name=None, grammar_type=grammar_type, linear_solver=linear_solver, use_lu_fact=use_lu_fact, **newton_mda_options ) sequence = [mda_gs, mda_newton] super(GSNewtonMDA, self).__init__( disciplines, sequence, name=name, grammar_type=grammar_type, max_mda_iter=max_mda_iter, tolerance=tolerance, linear_solver_tolerance=linear_solver_tolerance, warm_start=warm_start, )