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))


Last Run: 2016-07-27 09:23:59

In [2]:
# Run this cell only once
from IPython.display import clear_output

%cd ../
clear_output()

Writing Custom Models

Writing custom theoretical models is a powerful, extensible option of the LamAna package.

Authoring Custom Models

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.

  1. Implement a _use_model_() hook that returns (at minimum) an updated DataFrame.
  2. If using the class-style models, implement _use_model_() hook within a class that inherits from theories.BaseModel.

Exceptions for specific models are maintained by the models author.

Which style do I implement?

  • For beginners, function-style models are the best way to start making custom models.
  • We recommend class-style models, which use object-oriented principles such as inheritance. This is best suited for intermediate Pythonistas, which we encourage everyone to consider acheiving. :)

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

What are Defaults?

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
        )
Handling Model Exceptions (0.4.3c6)

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.

Modified Classical Laminate Theory - Wilson_LT

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}$$