Skip to content

Isotropic 3 Dimensional Elasticity

Bases: ConstitutiveModel

A constitutive model for a 3D isotropic material

Inherits

ConstitutiveModel : FEMpy.Constitutive.ConstitutiveModel The base class for FEMpy constitutive models

Source code in FEMpy/Constitutive/Iso3D.py
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
class Iso3D(ConstitutiveModel):
    """A constitutive model for a 3D isotropic material

    Inherits
    ----------
    ConstitutiveModel : FEMpy.Constitutive.ConstitutiveModel
        The base class for FEMpy constitutive models
    """

    def __init__(self, E, nu, rho, linear=True):
        """Create an isotropic plane stress constitutive model

        Parameters
        ----------
        E : float
            Elastic Modulus
        nu : float
            Poisson's ratio
        rho : float
            Density
        linear : bool, optional
            Whether to use the linear kinematic equations for strains, by default True
        """
        # --- Design variables ---
        # This model has no design variables
        designVars = {}

        # --- States ---
        stateNames = ["X-Displacement", "Y-Displacement", "Z-Displacement"]

        # --- Strains ---
        strainNames = ["e_xx", "e_yy", "e_zz", "gamma_xy", "gamma_xz", "gamma_yz"]

        # --- Stresses ---
        stressNames = ["sigma_xx", "sigma_yy", "sigma_zz", "tau_xy", "tau_xz", "tau_yz"]

        # --- Functions ---
        functionNames = ["Mass", "Von-Mises-Stress"]

        # --- Material properties ---
        self.E = E
        self.nu = nu
        self.rho = rho

        numDim = 3

        super().__init__(numDim, stateNames, strainNames, stressNames, designVars, functionNames, linear)

    def computeStrains(self, states, stateGradients, coords, dvs):
        """Given the coordinates, state value, state gradient, and design variables at a bunch of points, compute the strains at each one

        Parameters
        ----------
        states : numPoints x numStates array
            State values at each point
        stateGradients : numPoints x numStates x numDim array
            State gradients at each point
        coords : numPoints x numDim array
            Coordinates of each point
        dvs : dict of arrays of length numPoints
            Design variable values at each point

        Returns
        -------
        numPoints x numStrains array
            Strain components at each point
        """
        return strain3D(UPrime=stateGradients, nonlinear=not self.isLinear)

    def computeStrainStateGradSens(self, states, stateGradients, coords, dvs):
        """Given the coordinates, state value, state gradient, and design variables at a bunch of points, compute the
        sensitivity of the strains to the state gradient at each one



        Parameters
        ----------
        states : numPoints x numStates array
            State values at each point
        stateGradients : numPoints x numStates x numDim array
            State gradients at each point
        coords : numPoints x numDim array
            Coordinates of each point
        dvs : dict of arrays of length numPoints
            Design variable values at each point

        Returns
        -------
        numPoints x numStrains x numStates x numDim array
            Strain sensitivities, sens[i,j,k,l] is the sensitivity of strain component j at point i to state gradient du_k/dx_l
        """
        return strain3DSens(UPrime=stateGradients, nonlinear=not self.isLinear)

    def computeStresses(self, strains, dvs):
        """Given the strains and design variables at a bunch of points, compute the stresses at each one



        Parameters
        ----------
        strains : numPoints x numStrains array
            Strain components at each point
        dvs : dict of arrays of length numPoints
            Design variable values at each point

        Returns
        -------
        numPoints x numStresses array
            Stress components at each point
        """
        return iso3DStress(strains, E=self.E, nu=self.nu)

    def computeStressStrainSens(self, strains, dvs):
        """Given the strains and design variables at a bunch of points, compute the sensitivity of the stresses to the strains at each one



        Parameters
        ----------
        strains : numPoints x numStrains array
            Strain components at each point
        dvs : dict of arrays of length numPoints
            Design variable values at each point

        Returns
        -------
        sens : numPoints x numStrains x numStates x numDim array
            Strain sensitivities, sens[i,j,k,l] is the sensitivity of strain component j at point i to state gradient du_k/dx_l
        """
        return iso3DStressStrainSens(strains, E=self.E, nu=self.nu)

    def computeVolumeScaling(self, coords, dvs):
        """Given the coordinates and design variables at a bunch of points, compute the volume scaling parameter at each one

        For this 2D model, the volume scaling is just the thickness

        Parameters
        ----------
        coords : numPoints x numDim array
            Coordinates of each point
        dvs : dict of arrays of length numPoints
            Design variable values at each point

        Returns
        -------
        numPoints length array
            Volume scaling parameter at each point
        """
        return np.ones(coords.shape[0])

    def getFunction(self, name):
        """Return a function that can be computed for this constitutive model

        Parameters
        ----------
        name : str
            Name of the function to compute

        Returns
        -------
        callable
            A function that can be called to compute the desired function at a bunch of points with the signature, f(states, stateGradients, coords, dvs)
            where:
            states is a numPoints x numStates array
            stateGradients is a numPoints x numStates x numDim array
            coords is a numPoints x numDim array
            dvs is a dictionary of numPoints length arrays
        """
        if name.lower() not in self.lowerCaseFuncNames:
            raise ValueError(
                f"{name} is not a valid function name for this constitutive model, valid choices are {self.functionNames}"
            )

        if name.lower() == "mass":

            def massFunc(states, stateGradients, coords, dvs):
                return np.ones(states.shape[0]) * self.rho

            func = massFunc

        if name.lower() == "von-mises-stress":

            def vmStressFunc(states, stateGradients, coords, dvs):
                strains = self.computeStrains(states, stateGradients, coords, dvs)
                stresses = self.computeStresses(strains, dvs)
                return vonMises3D(stresses)

            func = vmStressFunc

        return func

__init__(E, nu, rho, linear=True)

Create an isotropic plane stress constitutive model

Parameters

E : float Elastic Modulus nu : float Poisson's ratio rho : float Density linear : bool, optional Whether to use the linear kinematic equations for strains, by default True

Source code in FEMpy/Constitutive/Iso3D.py
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
def __init__(self, E, nu, rho, linear=True):
    """Create an isotropic plane stress constitutive model

    Parameters
    ----------
    E : float
        Elastic Modulus
    nu : float
        Poisson's ratio
    rho : float
        Density
    linear : bool, optional
        Whether to use the linear kinematic equations for strains, by default True
    """
    # --- Design variables ---
    # This model has no design variables
    designVars = {}

    # --- States ---
    stateNames = ["X-Displacement", "Y-Displacement", "Z-Displacement"]

    # --- Strains ---
    strainNames = ["e_xx", "e_yy", "e_zz", "gamma_xy", "gamma_xz", "gamma_yz"]

    # --- Stresses ---
    stressNames = ["sigma_xx", "sigma_yy", "sigma_zz", "tau_xy", "tau_xz", "tau_yz"]

    # --- Functions ---
    functionNames = ["Mass", "Von-Mises-Stress"]

    # --- Material properties ---
    self.E = E
    self.nu = nu
    self.rho = rho

    numDim = 3

    super().__init__(numDim, stateNames, strainNames, stressNames, designVars, functionNames, linear)

computeStrainStateGradSens(states, stateGradients, coords, dvs)

Given the coordinates, state value, state gradient, and design variables at a bunch of points, compute the sensitivity of the strains to the state gradient at each one

Parameters

states : numPoints x numStates array State values at each point stateGradients : numPoints x numStates x numDim array State gradients at each point coords : numPoints x numDim array Coordinates of each point dvs : dict of arrays of length numPoints Design variable values at each point

Returns

numPoints x numStrains x numStates x numDim array Strain sensitivities, sens[i,j,k,l] is the sensitivity of strain component j at point i to state gradient du_k/dx_l

Source code in FEMpy/Constitutive/Iso3D.py
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
def computeStrainStateGradSens(self, states, stateGradients, coords, dvs):
    """Given the coordinates, state value, state gradient, and design variables at a bunch of points, compute the
    sensitivity of the strains to the state gradient at each one



    Parameters
    ----------
    states : numPoints x numStates array
        State values at each point
    stateGradients : numPoints x numStates x numDim array
        State gradients at each point
    coords : numPoints x numDim array
        Coordinates of each point
    dvs : dict of arrays of length numPoints
        Design variable values at each point

    Returns
    -------
    numPoints x numStrains x numStates x numDim array
        Strain sensitivities, sens[i,j,k,l] is the sensitivity of strain component j at point i to state gradient du_k/dx_l
    """
    return strain3DSens(UPrime=stateGradients, nonlinear=not self.isLinear)

computeStrains(states, stateGradients, coords, dvs)

Given the coordinates, state value, state gradient, and design variables at a bunch of points, compute the strains at each one

Parameters

states : numPoints x numStates array State values at each point stateGradients : numPoints x numStates x numDim array State gradients at each point coords : numPoints x numDim array Coordinates of each point dvs : dict of arrays of length numPoints Design variable values at each point

Returns

numPoints x numStrains array Strain components at each point

Source code in FEMpy/Constitutive/Iso3D.py
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
def computeStrains(self, states, stateGradients, coords, dvs):
    """Given the coordinates, state value, state gradient, and design variables at a bunch of points, compute the strains at each one

    Parameters
    ----------
    states : numPoints x numStates array
        State values at each point
    stateGradients : numPoints x numStates x numDim array
        State gradients at each point
    coords : numPoints x numDim array
        Coordinates of each point
    dvs : dict of arrays of length numPoints
        Design variable values at each point

    Returns
    -------
    numPoints x numStrains array
        Strain components at each point
    """
    return strain3D(UPrime=stateGradients, nonlinear=not self.isLinear)

computeStressStrainSens(strains, dvs)

Given the strains and design variables at a bunch of points, compute the sensitivity of the stresses to the strains at each one

Parameters

strains : numPoints x numStrains array Strain components at each point dvs : dict of arrays of length numPoints Design variable values at each point

Returns

sens : numPoints x numStrains x numStates x numDim array Strain sensitivities, sens[i,j,k,l] is the sensitivity of strain component j at point i to state gradient du_k/dx_l

Source code in FEMpy/Constitutive/Iso3D.py
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
def computeStressStrainSens(self, strains, dvs):
    """Given the strains and design variables at a bunch of points, compute the sensitivity of the stresses to the strains at each one



    Parameters
    ----------
    strains : numPoints x numStrains array
        Strain components at each point
    dvs : dict of arrays of length numPoints
        Design variable values at each point

    Returns
    -------
    sens : numPoints x numStrains x numStates x numDim array
        Strain sensitivities, sens[i,j,k,l] is the sensitivity of strain component j at point i to state gradient du_k/dx_l
    """
    return iso3DStressStrainSens(strains, E=self.E, nu=self.nu)

computeStresses(strains, dvs)

Given the strains and design variables at a bunch of points, compute the stresses at each one

Parameters

strains : numPoints x numStrains array Strain components at each point dvs : dict of arrays of length numPoints Design variable values at each point

Returns

numPoints x numStresses array Stress components at each point

Source code in FEMpy/Constitutive/Iso3D.py
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
def computeStresses(self, strains, dvs):
    """Given the strains and design variables at a bunch of points, compute the stresses at each one



    Parameters
    ----------
    strains : numPoints x numStrains array
        Strain components at each point
    dvs : dict of arrays of length numPoints
        Design variable values at each point

    Returns
    -------
    numPoints x numStresses array
        Stress components at each point
    """
    return iso3DStress(strains, E=self.E, nu=self.nu)

computeVolumeScaling(coords, dvs)

Given the coordinates and design variables at a bunch of points, compute the volume scaling parameter at each one

For this 2D model, the volume scaling is just the thickness

Parameters

coords : numPoints x numDim array Coordinates of each point dvs : dict of arrays of length numPoints Design variable values at each point

Returns

numPoints length array Volume scaling parameter at each point

Source code in FEMpy/Constitutive/Iso3D.py
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
def computeVolumeScaling(self, coords, dvs):
    """Given the coordinates and design variables at a bunch of points, compute the volume scaling parameter at each one

    For this 2D model, the volume scaling is just the thickness

    Parameters
    ----------
    coords : numPoints x numDim array
        Coordinates of each point
    dvs : dict of arrays of length numPoints
        Design variable values at each point

    Returns
    -------
    numPoints length array
        Volume scaling parameter at each point
    """
    return np.ones(coords.shape[0])

getFunction(name)

Return a function that can be computed for this constitutive model

Parameters

name : str Name of the function to compute

Returns

callable A function that can be called to compute the desired function at a bunch of points with the signature, f(states, stateGradients, coords, dvs) where: states is a numPoints x numStates array stateGradients is a numPoints x numStates x numDim array coords is a numPoints x numDim array dvs is a dictionary of numPoints length arrays

Source code in FEMpy/Constitutive/Iso3D.py
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
def getFunction(self, name):
    """Return a function that can be computed for this constitutive model

    Parameters
    ----------
    name : str
        Name of the function to compute

    Returns
    -------
    callable
        A function that can be called to compute the desired function at a bunch of points with the signature, f(states, stateGradients, coords, dvs)
        where:
        states is a numPoints x numStates array
        stateGradients is a numPoints x numStates x numDim array
        coords is a numPoints x numDim array
        dvs is a dictionary of numPoints length arrays
    """
    if name.lower() not in self.lowerCaseFuncNames:
        raise ValueError(
            f"{name} is not a valid function name for this constitutive model, valid choices are {self.functionNames}"
        )

    if name.lower() == "mass":

        def massFunc(states, stateGradients, coords, dvs):
            return np.ones(states.shape[0]) * self.rho

        func = massFunc

    if name.lower() == "von-mises-stress":

        def vmStressFunc(states, stateGradients, coords, dvs):
            strains = self.computeStrains(states, stateGradients, coords, dvs)
            stresses = self.computeStresses(strains, dvs)
            return vonMises3D(stresses)

        func = vmStressFunc

    return func