# -*- coding: utf-8 -*-
import os
from mpi4py import MPI
if MPI.COMM_WORLD.Get_size() > 1: # pragma: no cover
    os.environ["OMP_NUM_THREADS"] = "1"
    os.environ["OPENBLAS_NUM_THREADS"] = "1"
    os.environ["MKL_NUM_THREADS"] = "1"
    os.environ["VECLIB_MAXIMUM_THREADS"] = "1"
    os.environ["NUMEXPR_NUM_THREADS"] = "1"
import numpy as np
from Mordicus.Core.Containers.ConstitutiveLaws.ConstitutiveLawBase import ConstitutiveLawBase
[docs]class MfrontConstitutiveLaw(ConstitutiveLawBase):
    """
    Class containing a MfrontConstitutiveLaw
    Attributes
    ----------
    b : mgis.behaviour.Behaviour
        mfront behaviour
    m : mgis.behaviour.MaterialDataManager
        mfront material data manager
    density : float
        density of the material
    constitutiveLawVariables : dict
        dictionary with variable names (str) as keys and variables as type
    """
    def __init__(self, set):
        assert isinstance(set, str)
        super(MfrontConstitutiveLaw, self).__init__(set, "mechanical")
        self.b       = None
        self.m       = None
        self.density = None
        self.constitutiveLawVariables = {}
        self.constitutiveLawVariables['var'] = ['eto11', 'eto22', 'eto33', 'eto12', 'eto23', 'eto31', 'sig11', 'sig22', 'sig33', 'sig12', 'sig23', 'sig31']
[docs]    def SetConstitutiveLawVariables(self, constitutiveLawVariables):
        """
        Sets the constitutiveLawVariables dictionary
        Parameters
        ----------
        constitutiveLawVariables : dict
            dictionary with variable names (str) as keys and variables as type
        """
        self.constitutiveLawVariables = constitutiveLawVariables 
[docs]    def SetOneConstitutiveLawVariable(self, var, value):
        """
        Sets one variable of the constitutive law
        Parameters
        ----------
        var : str
            name of the variable
        value : custom_data_structure
            variable of the constitutive law
        """
        self.constitutiveLawVariables[var] = value 
[docs]    def SetDensity(self, density):
        """
        Sets the density of the constitutive law
        Parameters
        ----------
        density : float
            density of the material
        """
        self.density = density 
[docs]    def GetDensity(self):
        """
        Returns the density of the material
        Returns
        -------
        float
            density
        """
        return self.density 
[docs]    def GetConstitutiveLawVariables(self):
        """
        Returns
        -------
        dict
            complete dictionary defining the constitutive law variables
        """
        return self.constitutiveLawVariables 
[docs]    def GetOneConstitutiveLawVariable(self, var):
        """
        Returns one variable of the constitutive law
        Parameters
        ----------
        var : str
            key of the dictionnary for storing the variable (e.g. name of the variable)
        Returns
        -------
        custom_data_structure
            variable of the constitutive law
        """
        return self.constitutiveLawVariables[var] 
[docs]    def SetLawModelling(self, hypothesis, behavior, behaviorFile, internalVariables, nbIntPoints):
        """
        Sets the density of the constitutive law
        Parameters
        ----------
        hypothesis : mgis_bv.Hypothesis
            mfront hypothesis
        behavior : mgis.behaviour.Behaviour
            mfront behaviour
        behaviorFile : string
            path to compiled mfront behavior file (.so)
        internalVariables : list of strings
            list of the name of the internal variables modeling the constitutive law
        nbIntPoints : int
            number of integration points, where the constitutive law is modeled
        """
        import mgis.behaviour as mgis_bv
        availableHypothesis = {'Tridimensional': mgis_bv.Hypothesis.TRIDIMENSIONAL}
        assert hypothesis in availableHypothesis, "hypothesis '"+hypothesis+"' not available"
        h = availableHypothesis[hypothesis]
        self.b = mgis_bv.load(behaviorFile, behavior, h)
        self.m = mgis_bv.MaterialDataManager(self.b, nbIntPoints)
        self.constitutiveLawVariables['var'] += internalVariables
        self.constitutiveLawVariables['nstatv'] = len(internalVariables) 
[docs]    def ComputeConstitutiveLaw(self, temperature, dtemp, stran, dstran, statev):
        """
        Main function of the class: computes a new material state using a constitutive law
        solver from a previous material state and variations of temperature and strain
        Parameters
        ----------
        temperature : np.ndarray or list
            temperature at the previous state, at integration points (np.ndarray of size (nbIntPoints) or list of length nbIntPoints)
        dtemp : np.ndarray or list
            variations of temperature between the previous state and the new state to compute,
            at integration points (np.ndarray of size (nbIntPoints) or list of length nbIntPoints)
        stran : np.ndarray
            strain at the previous state, at integration points (np.ndarray of size (nbIntPoints,nbeOfDualComponents))
        dstran : np.ndarray
            variations of strain between the previous state and the new state to compute,
            at integration points (np.ndarray of size (nbIntPoints,nbeOfDualComponents))
        statev : np.ndarray
            internal state variables at the previous state, at integration points (np.ndarray of size (nbIntPoints,nbeOfStateVariables))
        Returns
        -------
        np.ndarray
            of size (nbIntPoints, nbeOfDualComponents, nbeOfDualComponents) ddsdde: local tangent matrix at the new state
        np.ndarray
            of size (nbIntPoints, nbeOfDualComponents) stress: stress at the new state
        np.ndarray
            of size (nbIntPoints, nbeOfStateVariables) statev: internal state variables at the new state
        """
        import mgis.behaviour as mgis_bv
        mgis_bv.setExternalStateVariable(self.m.s0, "Temperature", temperature, mgis_bv.MaterialStateManagerStorageMode.LocalStorage)
        mgis_bv.setExternalStateVariable(self.m.s1, "Temperature", temperature + dtemp, mgis_bv.MaterialStateManagerStorageMode.LocalStorage)
        self.m.s0.gradients[:,:] = stran
        self.m.s1.gradients[:,:] = stran + dstran
        self.m.s0.gradients[:,3:] /= np.sqrt(2.)
        self.m.s1.gradients[:,3:] /= np.sqrt(2.)
        it = mgis_bv.IntegrationType.IntegrationWithConsistentTangentOperator
        mgis_bv.integrate(self.m, it, 0, 0, self.m.n)
        stress = self.m.s1.thermodynamic_forces
        ddsdde = self.m.K
        stress[:,3:]   /= np.sqrt(2.)
        ddsdde[:,3:,:] /= np.sqrt(2.)
        ddsdde[:,:,3:] /= np.sqrt(2.)
        statev = self.m.s1.internal_state_variables
        return ddsdde, stress, statev 
[docs]    def UpdateInternalState(self):
        """
        Updates the state of the internal variables
        """
        import mgis.behaviour as mgis_bv
        mgis_bv.update(self.m) 
    def __str__(self):
        res = "Mechanical MfrontConstitutiveLaw on set "+self.set
        return res 
if __name__ == "__main__":# pragma: no cover
    from Mordicus import RunTestFile
    RunTestFile(__file__)