Skip to content

Constitutive Model Base Class

The base class for all FEMpy constitutive models

The constitutive model defines the underlying PDE being solved. Currently, this base class is defined for solid mechanics problems, but in future it may be extended for other PDE types.

It contains information on:

  • The number of spatial dimensions the model is valid for
  • The number and names of the PDE states
  • The number and names of the stresses and strains for this model
  • The number and names of the design variables associated with the PDE
  • The names of functions which can be computed for this constitutive model (e.g mass, Von Mises stress etc)

And contains methods to:

  • Given the coordinates, state value, state gradient, and design variables at a point, compute:
    • The strain components
    • The sensitivities of the strain components
    • The stress components
    • The sensitivities of the stress components
    • The pointwise mass
    • The volume integral scaling parameter (e.g thickness for 2D plane models or \(2 \pi r\) for 2D axisymmetric problems)
    • The weak form residual
    • The weak form residual Jacobian
    • Other arbitrary output values (e.g failure criterion)
Source code in FEMpy/Constitutive/ConstitutiveModel.py
 27
 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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
class ConstitutiveModel:
    """The base class for all FEMpy constitutive models

    The constitutive model defines the underlying PDE being solved. Currently, this base class is defined for
    solid mechanics problems, but in future it may be extended for other PDE types.

    It contains information on:

    - The number of spatial dimensions the model is valid for
    - The number and names of the PDE states
    - The number and names of the stresses and strains for this model
    - The number and names of the design variables associated with the PDE
    - The names of functions which can be computed for this constitutive model (e.g mass, Von Mises stress etc)

    And contains methods to:

    - Given the coordinates, state value, state gradient, and design variables at a point, compute:
        - The strain components
        - The sensitivities of the strain components
        - The stress components
        - The sensitivities of the stress components
        - The pointwise mass
        - The volume integral scaling parameter (e.g thickness for 2D plane models or $2 \pi r$ for 2D axisymmetric problems)
        - The weak form residual
        - The weak form residual Jacobian
        - Other arbitrary output values (e.g failure criterion)
    """

    def __init__(self, numDim, stateNames, strainNames, stressNames, designVars, functionNames, linear=True) -> None:
        """_summary_



        Parameters
        ----------
        numDim : int
            Number of spatial dimensions the model is valid for
        stateNames : list of str
            Names for each state variable
        strainNames : list of str
            Names for each strain component
        stressNames : list of str
            Names for each stress component
        designVars : dict
            A nested dictionary of design variables, with the key being the name of the design variable and the value
            being a dictionary that contains various pieces of information about that DV, including:
                - "defaultValue" : The default value of that DV
        functionNames : list of str
            The names of functions that can be computed with this constitutive model
        linear : bool, optional
            Whether the constitutive model is linear or not, a.k.a whether the weak residual is a linear function of the states/state gradients, by default True
        """
        self.numDim = numDim

        self.stateNames = stateNames
        self.numStates = len(stateNames)

        self.strainNames = strainNames
        self.numStrains = len(strainNames)
        if len(stressNames) != self.numStrains:
            raise ValueError("Number of strains must equal number of stresses")
        self.stressNames = stressNames

        self.designVariables = designVars
        self.numDesignVariables = len(designVars)

        self.functionNames = functionNames

        self.lowerCaseFuncNames = [func.lower() for func in self.functionNames]

        self.isLinear = linear

    # ==============================================================================
    # Abstract methods: To be implemented by derived classes
    # ==============================================================================
    @abc.abstractmethod
    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 : dictionary of len(numpoints) array
            design variable values at each point

        Returns
        -------
        numPoints x numStrains array
            Strain components at each point
        """
        raise NotImplementedError

    @abc.abstractmethod
    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 : dictionary of len(numpoints) array
            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
        """
        raise NotImplementedError

    @abc.abstractmethod
    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 : dictionary of len(numpoints) array
            design variable values at each point

        Returns
        -------
        numPoints x numStresses array
            Stress components at each point
        """
        raise NotImplementedError

    @abc.abstractmethod
    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 : dictionary of len(numpoints) array
            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
        """
        raise NotImplementedError

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

        The volume scaling parameter is used to scale functions that are integrated over the element to get a true
        volume integral. For example, in a 2D plane stress model, we need to multiply by the thickness of the element
        to get a true volume integral. In a 2D axisymmetric model, we need to multiply by 2*pi*r to get a true volume
        integral.

        Parameters
        ----------
        coords : numPoints x numDim array
            Coordinates of each point
        dvs : dictionary of len(numpoints) array
            design variable values at each point

        Returns
        -------
        numPoints length array
            Volume scaling parameter at each point
        """
        raise NotImplementedError

    @abc.abstractmethod
    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
        """

        raise NotImplementedError

    # ==============================================================================
    # Public methods
    # ==============================================================================
    def computeWeakResiduals(self, states, stateGradients, coords, dvs):
        """Given the coordinates, state value, state gradient, and design variables at a bunch of points, compute the weak residual integrand

        For a solid mechanics problem, the weak residual, derived from the virtual work principle is:

        $R = \int r dV = \int (du'/dq)^T  (d\epsilon/du')^T  \sigma  \\theta d\Omega$

        Where:

        - $du'/dq$ is the sensitivity of the state gradient to the nodal state values, this is handled by the element
        - $d\epsilon/du'$ is the sensitivity of the strain to the state gradient
        - $\sigma$ are the stresses
        - $\\theta$ is the volume scaling parameter
        - $\Omega$ is the element

        This function computes $(de/du')^T * \sigma * \\theta$ at each point

        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 : dictionary of len(numpoints) array
            design variable values at each point

        Returns
        -------
        residuals : numPoints x self.numDim x self.numStates array
            Weak residual integrand at each point
        """
        numPoints = coords.shape[0]
        strain = self.computeStrains(states, stateGradients, coords, dvs)
        stress = self.computeStresses(strain, dvs)
        scale = self.computeVolumeScaling(coords, dvs)

        strainSens = self.computeStrainStateGradSens(states, stateGradients, coords, dvs)

        residuals = np.zeros((numPoints, self.numDim, self.numStates))
        _computeWeakResidualProduct(strainSens, stress, scale, residuals)
        return residuals

        # return np.einsum("pesd,pe,p->pds", strainSens, stress, scale, optimize=["einsum_path", (0, 1), (0, 1)])

    def computeWeakResidualJacobian(self, states, stateGradients, coords, dvs):
        """Given the coordinates, state value, state gradient, and design variables at a bunch of points, compute the
        weak residual jacobian integrand

        $j = (d\epsilon/du')^T \\times d\sigma/d\epsilon \\times d\epsilon/du'$

        Where:

        - $d\epsilon/du'$ is the sensitivity of the strain to the state gradient
        - $d\sigma/d\epsilon$ the sensitivity of the stress to the strain gradient

        This function computes `de/du'^T * sigma * scale` at each point

        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 : dictionary of len(numpoints) array
            design variable values at each point

        Returns
        -------
        Jacobians : numPoints x numDim x numStates x numStates x numDim array
            The sensibility of the weak residual integrand components to the state gradients at each point
        """
        strainSens = self.computeStrainStateGradSens(states, stateGradients, coords, dvs)
        strain = self.computeStrains(states, stateGradients, coords, dvs)
        stressSens = self.computeStressStrainSens(strain, dvs)
        scale = self.computeVolumeScaling(coords, dvs)
        numPoints = states.shape[0]
        # strainSens = strainSens.reshape(numPoints, self.numStrains, self.numStates * self.numDim)
        # Jacobian = _computeWeakJacobianProduct(strainSens, stressSens, scale)
        # points = p
        # strains = e
        # stress = o
        # states = s
        # dim = d
        # Jacobians = np.einsum(
        #     "posd,poe,peSD,p->pdsSD",
        #     strainSens,
        #     stressSens,
        #     strainSens,
        #     scale,
        #     optimize=["einsum_path", (1, 3), (0, 2), (0, 1)],
        # )
        Jacobians = np.zeros((numPoints, self.numDim, self.numStates, self.numStates, self.numDim))
        _computeWeakJacobianProduct(strainSens, stressSens, scale, Jacobians)

        return Jacobians

__init__(numDim, stateNames, strainNames, stressNames, designVars, functionNames, linear=True)

summary

Parameters

numDim : int Number of spatial dimensions the model is valid for stateNames : list of str Names for each state variable strainNames : list of str Names for each strain component stressNames : list of str Names for each stress component designVars : dict A nested dictionary of design variables, with the key being the name of the design variable and the value being a dictionary that contains various pieces of information about that DV, including: - "defaultValue" : The default value of that DV functionNames : list of str The names of functions that can be computed with this constitutive model linear : bool, optional Whether the constitutive model is linear or not, a.k.a whether the weak residual is a linear function of the states/state gradients, by default True

Source code in FEMpy/Constitutive/ConstitutiveModel.py
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
def __init__(self, numDim, stateNames, strainNames, stressNames, designVars, functionNames, linear=True) -> None:
    """_summary_



    Parameters
    ----------
    numDim : int
        Number of spatial dimensions the model is valid for
    stateNames : list of str
        Names for each state variable
    strainNames : list of str
        Names for each strain component
    stressNames : list of str
        Names for each stress component
    designVars : dict
        A nested dictionary of design variables, with the key being the name of the design variable and the value
        being a dictionary that contains various pieces of information about that DV, including:
            - "defaultValue" : The default value of that DV
    functionNames : list of str
        The names of functions that can be computed with this constitutive model
    linear : bool, optional
        Whether the constitutive model is linear or not, a.k.a whether the weak residual is a linear function of the states/state gradients, by default True
    """
    self.numDim = numDim

    self.stateNames = stateNames
    self.numStates = len(stateNames)

    self.strainNames = strainNames
    self.numStrains = len(strainNames)
    if len(stressNames) != self.numStrains:
        raise ValueError("Number of strains must equal number of stresses")
    self.stressNames = stressNames

    self.designVariables = designVars
    self.numDesignVariables = len(designVars)

    self.functionNames = functionNames

    self.lowerCaseFuncNames = [func.lower() for func in self.functionNames]

    self.isLinear = linear

computeStrainStateGradSens(states, stateGradients, coords, dvs) abstractmethod

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 : dictionary of len(numpoints) array 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/ConstitutiveModel.py
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
@abc.abstractmethod
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 : dictionary of len(numpoints) array
        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
    """
    raise NotImplementedError

computeStrains(states, stateGradients, coords, dvs) abstractmethod

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 : dictionary of len(numpoints) array design variable values at each point

Returns

numPoints x numStrains array Strain components at each point

Source code in FEMpy/Constitutive/ConstitutiveModel.py
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
@abc.abstractmethod
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 : dictionary of len(numpoints) array
        design variable values at each point

    Returns
    -------
    numPoints x numStrains array
        Strain components at each point
    """
    raise NotImplementedError

computeStressStrainSens(strains, dvs) abstractmethod

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 : dictionary of len(numpoints) array 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/ConstitutiveModel.py
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
@abc.abstractmethod
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 : dictionary of len(numpoints) array
        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
    """
    raise NotImplementedError

computeStresses(strains, dvs) abstractmethod

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 : dictionary of len(numpoints) array design variable values at each point

Returns

numPoints x numStresses array Stress components at each point

Source code in FEMpy/Constitutive/ConstitutiveModel.py
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
@abc.abstractmethod
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 : dictionary of len(numpoints) array
        design variable values at each point

    Returns
    -------
    numPoints x numStresses array
        Stress components at each point
    """
    raise NotImplementedError

computeVolumeScaling(coords, dvs) abstractmethod

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

The volume scaling parameter is used to scale functions that are integrated over the element to get a true volume integral. For example, in a 2D plane stress model, we need to multiply by the thickness of the element to get a true volume integral. In a 2D axisymmetric model, we need to multiply by 2pir to get a true volume integral.

Parameters

coords : numPoints x numDim array Coordinates of each point dvs : dictionary of len(numpoints) array design variable values at each point

Returns

numPoints length array Volume scaling parameter at each point

Source code in FEMpy/Constitutive/ConstitutiveModel.py
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
@abc.abstractmethod
def computeVolumeScaling(self, coords, dvs):
    """Given the coordinates and design variables at a bunch of points, compute the volume scaling parameter at each one

    The volume scaling parameter is used to scale functions that are integrated over the element to get a true
    volume integral. For example, in a 2D plane stress model, we need to multiply by the thickness of the element
    to get a true volume integral. In a 2D axisymmetric model, we need to multiply by 2*pi*r to get a true volume
    integral.

    Parameters
    ----------
    coords : numPoints x numDim array
        Coordinates of each point
    dvs : dictionary of len(numpoints) array
        design variable values at each point

    Returns
    -------
    numPoints length array
        Volume scaling parameter at each point
    """
    raise NotImplementedError

computeWeakResidualJacobian(states, stateGradients, coords, dvs)

Given the coordinates, state value, state gradient, and design variables at a bunch of points, compute the weak residual jacobian integrand

\(j = (d\epsilon/du')^T \times d\sigma/d\epsilon \times d\epsilon/du'\)

Where:

  • \(d\epsilon/du'\) is the sensitivity of the strain to the state gradient
  • \(d\sigma/d\epsilon\) the sensitivity of the stress to the strain gradient

This function computes de/du'^T * sigma * scale at each point

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 : dictionary of len(numpoints) array design variable values at each point

Returns

Jacobians : numPoints x numDim x numStates x numStates x numDim array The sensibility of the weak residual integrand components to the state gradients at each point

Source code in FEMpy/Constitutive/ConstitutiveModel.py
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
def computeWeakResidualJacobian(self, states, stateGradients, coords, dvs):
    """Given the coordinates, state value, state gradient, and design variables at a bunch of points, compute the
    weak residual jacobian integrand

    $j = (d\epsilon/du')^T \\times d\sigma/d\epsilon \\times d\epsilon/du'$

    Where:

    - $d\epsilon/du'$ is the sensitivity of the strain to the state gradient
    - $d\sigma/d\epsilon$ the sensitivity of the stress to the strain gradient

    This function computes `de/du'^T * sigma * scale` at each point

    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 : dictionary of len(numpoints) array
        design variable values at each point

    Returns
    -------
    Jacobians : numPoints x numDim x numStates x numStates x numDim array
        The sensibility of the weak residual integrand components to the state gradients at each point
    """
    strainSens = self.computeStrainStateGradSens(states, stateGradients, coords, dvs)
    strain = self.computeStrains(states, stateGradients, coords, dvs)
    stressSens = self.computeStressStrainSens(strain, dvs)
    scale = self.computeVolumeScaling(coords, dvs)
    numPoints = states.shape[0]
    # strainSens = strainSens.reshape(numPoints, self.numStrains, self.numStates * self.numDim)
    # Jacobian = _computeWeakJacobianProduct(strainSens, stressSens, scale)
    # points = p
    # strains = e
    # stress = o
    # states = s
    # dim = d
    # Jacobians = np.einsum(
    #     "posd,poe,peSD,p->pdsSD",
    #     strainSens,
    #     stressSens,
    #     strainSens,
    #     scale,
    #     optimize=["einsum_path", (1, 3), (0, 2), (0, 1)],
    # )
    Jacobians = np.zeros((numPoints, self.numDim, self.numStates, self.numStates, self.numDim))
    _computeWeakJacobianProduct(strainSens, stressSens, scale, Jacobians)

    return Jacobians

computeWeakResiduals(states, stateGradients, coords, dvs)

Given the coordinates, state value, state gradient, and design variables at a bunch of points, compute the weak residual integrand

For a solid mechanics problem, the weak residual, derived from the virtual work principle is:

\(R = \int r dV = \int (du'/dq)^T (d\epsilon/du')^T \sigma \theta d\Omega\)

Where:

  • \(du'/dq\) is the sensitivity of the state gradient to the nodal state values, this is handled by the element
  • \(d\epsilon/du'\) is the sensitivity of the strain to the state gradient
  • \(\sigma\) are the stresses
  • \(\theta\) is the volume scaling parameter
  • \(\Omega\) is the element

This function computes \((de/du')^T * \sigma * \theta\) at each point

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 : dictionary of len(numpoints) array design variable values at each point

Returns

residuals : numPoints x self.numDim x self.numStates array Weak residual integrand at each point

Source code in FEMpy/Constitutive/ConstitutiveModel.py
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
def computeWeakResiduals(self, states, stateGradients, coords, dvs):
    """Given the coordinates, state value, state gradient, and design variables at a bunch of points, compute the weak residual integrand

    For a solid mechanics problem, the weak residual, derived from the virtual work principle is:

    $R = \int r dV = \int (du'/dq)^T  (d\epsilon/du')^T  \sigma  \\theta d\Omega$

    Where:

    - $du'/dq$ is the sensitivity of the state gradient to the nodal state values, this is handled by the element
    - $d\epsilon/du'$ is the sensitivity of the strain to the state gradient
    - $\sigma$ are the stresses
    - $\\theta$ is the volume scaling parameter
    - $\Omega$ is the element

    This function computes $(de/du')^T * \sigma * \\theta$ at each point

    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 : dictionary of len(numpoints) array
        design variable values at each point

    Returns
    -------
    residuals : numPoints x self.numDim x self.numStates array
        Weak residual integrand at each point
    """
    numPoints = coords.shape[0]
    strain = self.computeStrains(states, stateGradients, coords, dvs)
    stress = self.computeStresses(strain, dvs)
    scale = self.computeVolumeScaling(coords, dvs)

    strainSens = self.computeStrainStateGradSens(states, stateGradients, coords, dvs)

    residuals = np.zeros((numPoints, self.numDim, self.numStates))
    _computeWeakResidualProduct(strainSens, stress, scale, residuals)
    return residuals

getFunction(name) abstractmethod

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/ConstitutiveModel.py
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
@abc.abstractmethod
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
    """

    raise NotImplementedError