Commit 92d6a6e6 authored by Mathieu Courtois's avatar Mathieu Courtois
Browse files

Merge branch 'mc/mnl' into 'main'

#34400: refactoring of meca_non_line

See merge request codeaster/src!568
parents 60f41f0d 3bf74572
Loading
Loading
Loading
Loading
+1 −115
Original line number Diff line number Diff line
# coding=utf-8
# --------------------------------------------------------------------
# Copyright (C) 1991 - 2024 - EDF R&D - www.code-aster.org
# Copyright (C) 1991 - 2025 - EDF R&D - www.code-aster.org
# This file is part of code_aster.
#
# code_aster is free software: you can redistribute it and/or modify
@@ -18,14 +18,12 @@
# --------------------------------------------------------------------

import unittest
from enum import IntFlag, auto
from unittest.mock import MagicMock


from code_aster.Commands import *
from code_aster import CA
from code_aster.Solvers import (
    BaseFeature,
    ConvergenceManager,
    PhysicalState,
    ProblemType,
@@ -39,118 +37,6 @@ list0 = DEFI_LIST_REEL(VALE=0.0)
listr = DEFI_LIST_REEL(DEBUT=0.0, INTERVALLE=_F(JUSQU_A=10.0, PAS=1.0))


class UnittestOptions(IntFlag):
    """Enumeration of options for unittest."""

    System = auto()
    Storage = auto()
    State = auto()
    Unused = auto()
    Contact = auto()


class SystemDefinition(BaseFeature):
    """Object that stores the definition of the system to be solved."""

    provide = UnittestOptions.System


class Storage(BaseFeature):
    """Object that provides the archiving feature."""

    provide = UnittestOptions.Storage


class Anonymous:
    """Non-Feature object"""


class BasicTest(unittest.TestCase):
    """Check for Feature object."""

    def test01_basics(self):
        FOP = UnittestOptions
        opt = FOP.Storage
        self.assertEqual(str(opt), "UnittestOptions.Storage")
        opt |= FOP.System
        self.assertEqual(str(opt), "UnittestOptions.Storage|System", str(opt))

        syst = SystemDefinition()
        stor = Storage()
        # object that provides services for System + Storage
        syssto = SystemDefinition()
        anonym = Anonymous()

        class TestFeature(BaseFeature):
            required_features = [FOP.System, FOP.State]
            optional_features = [FOP.Storage]

        op = TestFeature()
        self.assertEqual(len(op._use), 0)
        op.use(syst)
        op.use(stor)
        op.use(syssto, FOP.Storage)
        with self.assertRaisesRegex(TypeError, "not support.*UnittestOptions.Unused"):
            op.use(anonym, FOP.Unused)
        op.use(anonym, FOP.State)
        self.assertEqual(len(op._use), 4)
        op.use(syst)
        self.assertEqual(len(op._use), 4)

        self.assertCountEqual(op.get_features(FOP.System), [syst, syssto])
        self.assertCountEqual(op.get_features(FOP.Storage), [stor, syssto])
        self.assertCountEqual(op.get_features(FOP.System | FOP.Storage), [syssto])

        op.discard(syssto)
        self.assertCountEqual(op.get_features(FOP.System), [syst])
        self.assertCountEqual(op.get_features(FOP.Storage), [stor])
        self.assertCountEqual(op.get_features(FOP.System | FOP.Storage), [])

    def test02_nonl(self):
        FOP = UnittestOptions

        class TestFeature(BaseFeature):
            provide = FOP.System
            required_features = [FOP.System, FOP.Storage]
            optional_features = [FOP.Contact]

        op = TestFeature()
        op.use(object(), FOP.System)
        with self.assertRaisesRegex(TypeError, "not support.*UnittestOptions.Unused"):
            op.use(object(), FOP.Unused)
        self.assertSequenceEqual(op.undefined(), [(FOP.Storage, True), (FOP.Contact, False)])

        self.assertEqual(len(op.required_features), 2)
        self.assertEqual(len(op.optional_features), 1)

        class InheritedFeature(TestFeature):
            provide = FOP.System
            optional_features = TestFeature.optional_features + [FOP.State]

        inherit = InheritedFeature()
        self.assertEqual(len(inherit.required_features), 2)
        self.assertEqual(len(inherit.optional_features), 2)

    def test03_child(self):
        FOP = UnittestOptions

        class Main(BaseFeature):
            provide = FOP.System
            required_features = [FOP.Storage]

        class SubFeat(BaseFeature):
            provide = FOP.Storage
            required_features = [FOP.Contact]

        op = Main()
        sub = SubFeat()
        sub.use(object(), FOP.Contact)
        op.use(sub)
        self.assertEqual(len(op.get_features(FOP.Contact)), 0)
        self.assertEqual(len(sub.get_features(FOP.Contact)), 1)
        self.assertEqual(len(op.get_childs(FOP.Contact)), 1)


class TestTimeStepper(unittest.TestCase):
    """Check for TimeStepper."""

+22 −23
Original line number Diff line number Diff line
@@ -17,11 +17,10 @@
# along with code_aster.  If not, see <http://www.gnu.org/licenses/>.
# --------------------------------------------------------------------


from code_aster.Commands import *
from code_aster import CA
from code_aster.Solvers import NonLinearSolver, ProblemSolver
from code_aster.Solvers import SolverOptions as SOP
from code_aster.Solvers import TimeStepper, ProblemType
from code_aster.Solvers import BaseHook, NonLinearOperator, TimeStepper
from code_aster.Solvers.StepSolvers import MecaStatStepSolver

DEBUT(
@@ -86,40 +85,40 @@ class CustomStepSolver(MecaStatStepSolver):
            print("+++ CustomStepSolver ends successfully, time:", self.phys_state.time_curr)


def post_hook(nl_solver):
def post_hook(nl_oper):
    """Example of hook function.

    Arguments:
        phys_state (PhysicalState): Current physical state.
        nl_oper (NonLinearOperator): Caller operator.
    """
    print(f"calling hook at time = {nl_solver.phys_state.time_curr}...", flush=True)
    print(f"calling hook at time = {nl_oper.state.time_curr}...", flush=True)


class PostHook:
class PostHook(BaseHook):
    """User object to be used as a PostStepHook."""

    provide = SOP.PostStepHook

    def __call__(self, nl_solver):
    def run(self, nl_oper):
        """Example of hook."""
        nl_solver.phys_state.debugPrint()
        nl_oper.state.debugPrint()


problem = CA.PhysicalProblem(model, mater)
problem.addLoadFromDict({"CHARGE": encast, "FONC_MULT": RAMPE, "TYPE_CHARGE": "FIXE_CSTE"})
problem.addLoadFromDict({"CHARGE": depl, "FONC_MULT": RAMPE, "TYPE_CHARGE": "FIXE_CSTE"})

snl = ProblemSolver(NonLinearSolver(), CA.NonLinearResult(), pb_type=ProblemType.MecaStat)
snl.use(CA.PhysicalProblem(model, mater))
snl.use(CA.LinearSolver.factory(METHODE="MUMPS"))
snl.phys_pb.addLoadFromDict({"CHARGE": encast, "FONC_MULT": RAMPE, "TYPE_CHARGE": "FIXE_CSTE"})
snl.phys_pb.addLoadFromDict({"CHARGE": depl, "FONC_MULT": RAMPE, "TYPE_CHARGE": "FIXE_CSTE"})
snl.setKeywords(
keywords = _F(
    SOLVEUR=_F(METHODE="MUMPS"),
    CONVERGENCE={"RESI_GLOB_RELA": 1.0e-6, "ITER_GLOB_MAXI": 20},
    NEWTON={"PREDICTION": "ELASTIQUE"},
    COMPORTEMENT={"RELATION": "VMIS_ISOT_LINE"},
    INFO=1,
)
snl.use(CustomStepSolver())
snl.use(TimeStepper([0.5, 1.0]))
snl.use(post_hook, provide=SOP.PostStepHook)
snl.use(PostHook())
snl = NonLinearOperator.factory(problem, **keywords)
snl.context.stepper = TimeStepper([0.5, 1.0])
# TODO
# snl.context.step_solver = CustomStepSolver()
snl.register_hook(PostHook())
snl.register_hook(post_hook)
snl.run()

# =========================================================
@@ -136,8 +135,8 @@ VARI_REF = CREA_CHAMP(
)


SIGMA = snl.phys_state.stress
VARI = snl.phys_state.internVar
SIGMA = snl.state.stress
VARI = snl.state.internVar


# =========================================================
+10 −10
Original line number Diff line number Diff line
@@ -19,7 +19,7 @@

from code_aster.Commands import *
from code_aster import CA
from code_aster.Solvers import NonLinearSolver, ProblemSolver, TimeStepper, ProblemType
from code_aster.Solvers import NonLinearOperator, TimeStepper

DEBUT(
    CODE=_F(NIV_PUB_WEB="INTERNET"), ERREUR=_F(ALARME="EXCEPTION"), DEBUG=_F(SDVERI="OUI"), INFO=1
@@ -63,20 +63,20 @@ SOLUT = STAT_NON_LINE(
    INFO=1,
)

problem = CA.PhysicalProblem(model, mater)
problem.addLoadFromDict({"CHARGE": encast, "FONC_MULT": RAMPE, "TYPE_CHARGE": "FIXE_CSTE"})
problem.addLoadFromDict({"CHARGE": depl, "FONC_MULT": RAMPE, "TYPE_CHARGE": "FIXE_CSTE"})

snl = ProblemSolver(NonLinearSolver(), CA.NonLinearResult(), pb_type=ProblemType.MecaStat)
snl.use(CA.PhysicalProblem(model, mater))
snl.use(CA.LinearSolver.factory(METHODE="MUMPS", RENUM="METIS", NPREC=8))
snl.phys_pb.addLoadFromDict({"CHARGE": encast, "FONC_MULT": RAMPE, "TYPE_CHARGE": "FIXE_CSTE"})
snl.phys_pb.addLoadFromDict({"CHARGE": depl, "FONC_MULT": RAMPE, "TYPE_CHARGE": "FIXE_CSTE"})
snl.setKeywords(
keywords = _F(
    METHODE="NEWTON",
    CONVERGENCE={"RESI_GLOB_MAXI": 1.0e-8, "ITER_GLOB_MAXI": 20},
    NEWTON={"PREDICTION": "ELASTIQUE"},
    COMPORTEMENT={"RELATION": "VMIS_ISOT_LINE"},
    INFO=1,
)
snl.use(TimeStepper([0.5, 1.0]))
snl = NonLinearOperator.factory(problem, **keywords)
snl.context.linear_solver = CA.LinearSolver.factory(METHODE="MUMPS", RENUM="METIS", NPREC=8)
snl.context.stepper = TimeStepper([0.5, 1.0])
snl.run()

# =========================================================
@@ -93,8 +93,8 @@ VARI_REF = CREA_CHAMP(
)


SIGMA = snl.phys_state.stress
VARI = snl.phys_state.internVar
SIGMA = snl.state.stress
VARI = snl.state.internVar


# =========================================================
+11 −10
Original line number Diff line number Diff line
@@ -19,7 +19,7 @@

from code_aster.Commands import *
from code_aster import CA
from code_aster.Solvers import NonLinearSolver, ProblemSolver, TimeStepper, ProblemType
from code_aster.Solvers import NonLinearOperator, TimeStepper
from code_aster.Utilities import haveMPI

DEBUT(CODE=_F(NIV_PUB_WEB="INTERNET"), DEBUG=_F(SDVERI="OUI"), INFO=1)
@@ -70,19 +70,20 @@ SOLUT = STAT_NON_LINE(
    INFO=1,
)

snl = ProblemSolver(NonLinearSolver(), CA.NonLinearResult(), pb_type=ProblemType.MecaStat)
snl.use(CA.PhysicalProblem(model, mater))
snl.use(CA.LinearSolver.factory(**linear_solver))
snl.phys_pb.addLoadFromDict({"CHARGE": encast, "FONC_MULT": RAMPE, "TYPE_CHARGE": "FIXE_CSTE"})
snl.phys_pb.addLoadFromDict({"CHARGE": depl, "FONC_MULT": RAMPE, "TYPE_CHARGE": "FIXE_CSTE"})
snl.setKeywords(
problem = CA.PhysicalProblem(model, mater)
problem.addLoadFromDict({"CHARGE": encast, "FONC_MULT": RAMPE, "TYPE_CHARGE": "FIXE_CSTE"})
problem.addLoadFromDict({"CHARGE": depl, "FONC_MULT": RAMPE, "TYPE_CHARGE": "FIXE_CSTE"})

keywords = _F(
    METHODE="NEWTON",
    CONVERGENCE={"RESI_GLOB_MAXI": 1.0e-8, "ITER_GLOB_MAXI": 20},
    NEWTON={"PREDICTION": "ELASTIQUE"},
    COMPORTEMENT={"RELATION": "VMIS_ISOT_LINE"},
)
snl.use(TimeStepper([0.5, 1.0]))

snl = NonLinearOperator.factory(problem, **keywords)
snl.context.linear_solver = CA.LinearSolver.factory(**linear_solver)
snl.context.stepper = TimeStepper([0.5, 1.0])
snl.run()

# =========================================================
@@ -99,8 +100,8 @@ VARI_REF = CREA_CHAMP(
)


SIGMA = snl.phys_state.stress
VARI = snl.phys_state.internVar
SIGMA = snl.state.stress
VARI = snl.state.internVar


# =========================================================
+2 −3
Original line number Diff line number Diff line
# coding=utf-8
# --------------------------------------------------------------------
# Copyright (C) 1991 - 2024 - EDF R&D - www.code-aster.org
# Copyright (C) 1991 - 2025 - EDF R&D - www.code-aster.org
# This file is part of code_aster.
#
# code_aster is free software: you can redistribute it and/or modify
@@ -96,7 +96,7 @@ maxSteps = 5
timeStepper = DEFI_LIST_INST(
    METHODE="AUTO",
    DEFI_LIST=_F(LIST_INST=LI1, NB_PAS_MAXI=maxSteps),
    ECHEC=_F(ACTION="DECOUPE", SUBD_METHODE="MANUEL", SUBD_PAS=2, SUBD_NIVEAU=4),
    ECHEC=_F(ACTION="DECOUPE", SUBD_METHODE="MANUEL", SUBD_PAS=2, SUBD_NIVEAU=6),
)

### >>>>>>>>>>>>>>>>>>>
@@ -283,7 +283,6 @@ CHA_DEPL2 = AFFE_CHAR_MECA(MODELE=MODELE, DDL_IMPO=(_F(GROUP_MA=("BAS",), DX=0,

LI1 = DEFI_LIST_REEL(DEBUT=0.0, INTERVALLE=(_F(JUSQU_A=1.0, NOMBRE=10), _F(JUSQU_A=2.0, NOMBRE=10)))

maxSteps = 6
maxSteps = 9
timeStepper = DEFI_LIST_INST(
    METHODE="AUTO",
Loading