In [1]:
# Hidden TimeStamp
import time, datetime
st = datetime.datetime.fromtimestamp(time.time()).strftime('%Y-%m-%d %H:%M:%S')
print('Last Run: {}'.format(st))
In [2]:
# Run this cell only once
from IPython.display import clear_output
%cd ../
clear_output()
Writing custom theoretical models is a powerful, extensible option of the LamAna package.
Custom models are simple .py
files that can be locally placed by the user into the models directory. The API finds these selected files from the apply(model='<name>')
method in the distributions.Case
class. In order for these processes to work smoothly, the following essentials are needed to "handshake" with theories
module.
_use_model_()
hook that returns (at minimum) an updated DataFrame._use_model_()
hook within a class that inherits from theories.BaseModel
.Exceptions for specific models are maintained by the models author.
Examples of both function-style and class-style models are found in the "examples" folder of the repository.
The following cell shows an excerpt of the class-style model.
#------------------------------------------------------------------------------
# Class-style model
# ...
class Model(BaseModel):
'''A custom CLT model.
A modified laminate theory for circular biaxial flexure disks,
loaded with a flat piston punch on 3-ball support having two distinct
materials (polymer and ceramic).
'''
def __init__(self):
self.Laminate = None
self.FeatureInput = None
self.LaminateModel = None
def _use_model_(self, Laminate, adjusted_z=False):
'''Return updated DataFrame and FeatureInput.
...
Returns
-------
tuple
The updated calculations and parameters stored in a tuple
`(LaminateModel, FeatureInput)``.
df : DataFrame
LaminateModel with IDs and Dimensional Variables.
FeatureInut : dict
Geometry, laminate parameters and more. Updates Globals dict for
parameters in the dashboard output.
'''
...
return (df, FeatureInput)
# Add Defaults here
Recall there are a set of geometric, loading and material parameters that are required to run LT calculations. During analysis, retyping these parameters may become tedious each time you wish to run a simple plot or test parallel case. Therefore, you can prepare variables that store default parameters with specific values.
LamAna eases this process by simply inheriting from BaseDefaults
. The BaseDefaults
class stores a number of common geometry strings, Geometry objects and arbitrary loading parameters/material properties. These values are intended to get you started, but you can alter to fit your better suit model. In addition, this class has methods for easily building formatted FeatureInput objects.
class Defaults(BaseDefaults):
'''Return parameters for building distributions cases. Useful for consistent
testing.
Dimensional defaults are inherited from utils.BaseDefaults().
Material-specific parameters are defined here by he user.
- Default geometric parameters
- Default material properties
- Default FeatureInput
Examples
========
>>> dft = Defaults()
>>> dft.load_params
{'R' : 12e-3, 'a' : 7.5e-3, 'p' : 1, 'P_a' : 1, 'r' : 2e-4,}
>>> dft.mat_props
{'Modulus': {'HA': 5.2e10, 'PSu': 2.7e9},
'Poissons': {'HA': 0.25, 'PSu': 0.33}}
>>> dft.FeatureInput
{'Geometry' : '400-[200]-800',
'Geometric' : {'R' : 12e-3, 'a' : 7.5e-3, 'p' : 1, 'P_a' : 1, 'r' : 2e-4,},
'Materials' : {'HA' : [5.2e10, 0.25], 'PSu' : [2.7e9, 0.33],},
'Custom' : None,
'Model' : Wilson_LT}
'''
def __init__(self):
BaseDefaults.__init__(self)
'''DEV: Add defaults first. Then adjust attributes.'''
# DEFAULTS ------------------------------------------------------------
# Build dicts of geometric and material parameters
self.load_params = {
'R': 12e-3, # specimen radius
'a': 7.5e-3, # support ring radius
'p': 5, # points/layer
'P_a': 1, # applied load
'r': 2e-4, # radial distance from center loading
}
self.mat_props = {
'Modulus': {'HA': 5.2e10, 'PSu': 2.7e9},
'Poissons': {'HA': 0.25, 'PSu': 0.33}
}
# ATTRIBUTES ----------------------------------------------------------
# FeatureInput
self.FeatureInput = self.get_FeatureInput(
self.Geo_objects['standard'][0],
load_params=self.load_params,
mat_props=self.mat_props,
model='Wilson_LT',
global_vars=None
)
The oneous of exception handling is maintained by the model's author.
Since users can create their own models and use them in LamAna
, it becomes important to handle erroroneous code. There is some basic handling is implement to prevent erroroneous code from halting LamAna. Generally, if an error occurs during the handshaking period, a ModelError
is raised. Provision is taken to rollback the object back to the Lamainate
percursor. A traceback will still print even though the exception was caught, allowing the author to improve their code and prevent breakage.
Here is a sample model that comes with LamAna. It applies Classical Laminate Theory (CLT) to circular-disk laminates with alternating ceramic-polymer materials. CLT was modified for disks loaded in biaxial flexure.
Stiffness Matrix: $E$ is elastic modulus, $\nu$ is Poisson's ratio.
$$|Q| = \begin{vmatrix} Q_{11}& Q_{12}\\ Q_{21}& Q_{22} \end{vmatrix}$$$$Q_{11}=Q_{22}=E/(1-\nu^2)$$$$Q_{12}=Q_{21}=\nu E/(1-\nu^2)$$Bending : $k$ is essentially the enumerated interface where $k=0$ is tensile surface. $h$ is the layer thickness relative to the neutral axis where $t_{middle} = h_{middle}/2$. $z$ (lower case) is the relative distance betweeen the neuatral axis and a lamina centroid.
$$|D| = \begin{vmatrix} D_{11}& D_{12}\\ D_{21}& D_{22} \end{vmatrix}$$$$D_{11}=D_{22}=\Sigma_{k=1}^N Q_{11(k)}((h_{(k)}^3/12)+h_{(k)}z_{(k)}^2)$$$$D_{12}=D_{21}=\Sigma_{k=1}^N Q_{12(k)}((h_{(k)}^3/12)+h_{(k)}z_{(k)}^2)$$Equivalent Poisson's Ratio
$$\nu_{eq} = D_{12}/D_{11}$$Moments: radial and tangential bending moments. The tangential stress is used for the failure stress.
$$M_r = (P/4\pi)[(1+\nu_{eq})\log(a/r)]$$$$M_t = (P/4\pi)[(1+\nu_{eq})\log(a/r)+(1-\nu_{eq})]$$Curvature
$$ \begin{Bmatrix} K_r \\ K_t \end{Bmatrix} = [D]^{-1} \begin{Bmatrix} M_r \\ M_t \end{Bmatrix}$$Strain: $Z$ (caplital) is the distance betwen the neutral axis and the lamina interface.
$$ \begin{Bmatrix} \epsilon_r \\ \epsilon_t \end{Bmatrix} = Z_k \begin{Bmatrix} K_r \\ K_t \end{Bmatrix}$$Stress
$$ \begin{Bmatrix} \sigma_r \\ \sigma_t \end{Bmatrix} = [Q] \begin{Bmatrix} \epsilon_r \\ \epsilon_t \end{Bmatrix}$$