# Model and integral operators

The class tamaas::Model (and its counterpart Model) is both a central class in Tamaas and one of the simplest. It mostly serves as holder for material properties, fields and integral operators, and apart from a linear elastic behavior does not perform any computation on its own.

## Units in Tamaas

All quantities in Tamaas are unitless. To put real units onto them, one can use the following equation, which must have a consistent set of units:

$\frac{u}{L} = \frac{\pi}{k} \frac{p}{\frac{E}{1-\nu^2}}.$

It relates the surface displacement $$u$$ to the pressure $$p$$, with the Young’s modulus $$E$$, the Poisson coefficient $$\nu$$ and the horizontal physical size of the system $$L$$ (i.e. the horizontal period of the system). The wavenumber $$k$$ is adimensional. This means that $$L$$ is the natural unit for lengths (which can be specified when creating the Model object), and $$E^* := E / (1 - \nu^2)$$ is the natural unit for pressures (which can be accessed with model.E_star). All other units (areas, forces, energies, etc.) are derived from these two units.

In general, it is a good idea to work with a unit set that gives numerical values of the same order of magnitude to minimize floating point errors in algebraic operations. While this is not always possible, because in elastic contact we have $$u \sim h_\mathrm{rms}$$ and $$p \sim h'_\mathrm{rms} E^*$$, which are dependent, one should avoid using meters if expected lengths are nanometers for example.

## Model types

tamaas::Model has a concrete subclass tamaas::ModelTemplate which implements the model function for a given tamaas::model_type:

tamaas::basic_2d

Model type used in normal frictionless contact: traction and displacement are 2D fields with only one component.

tamaas::surface_2d

Model type used in frictional contact: traction and displacement are 2D fields with three components.

tamaas::volume_2d

Model type used in elastoplastic contact: tractions are the same as with tamaas::surface_2d but the displacement is a 3D field.

The enumeration values suffixed with _1d are the one dimensional (line contact) counterparts of the above model types. The domain physical dimension and number of components are encoded in the class tamaas::model_type_traits.

## Model creation and basic functionality

The instanciation of a Model requires the model type, the physical size of the system, and the number of points in each direction:

physical_size = [1., 1.]
discretization = [512, 512]
model = tm.Model(tm.model_type.basic_2d, physical_size, discretization)


Warning

For models of type volume_*d, the first component of the physical_size and discretization arrays corresponds to the depth dimension ($$z$$ in most cases). For example:

tm.Model(tm.model_type.basic_2d, [0.3, 1, 1], [64, 81, 81])


creates a model of depth 0.3 and surface size 12, while the number of points is 64 in depth and 812 on the surface. This is done for data contiguity reasons, as we do discrete Fourier transforms in the horizontal plane.

Note

If ran in an MPI context, the constructor to Model expects the global system sizes and discretization of the model.

Tip

Deep copies of model objects can be done with the copy.deepcopy() function:

import copy

model_copy = copy.deepcopy(model)


Note that it only copies fields, not operators or dumpers.

### Model properties

The properties E and nu can be used to set the Young’s modulus and Poisson ratio respectively:

model.E = 1
model.nu = 0.3


Tip

The Greenwood–Tripp equivalence, sometimes called Johnson equivalence, allows one to model a normal, frictionless contact between two homogeneous linear, isotropic, elastic materials with rough surfaces $$h_\alpha$$ and $$h_\beta$$ as the contact of a rigid-rough surface $$h_\beta - h_\alpha$$ and a flat elastic solid with an equivalent contact modulus $$E^*$$:

$\frac{1}{E^*} = \frac{1 - \nu_\alpha^2}{E_\alpha^2} + \frac{1 - \nu_\beta^2}{E_\beta^2} = \frac{1}{E^*_\alpha} + \frac{1}{E^*_\beta}$

Since a model only defines a single set of elastic properties $$(E, \nu)$$, one can model contact between two different elastic materials by computing $$E^*$$ a priori, and setting $$(E, \nu) = (E^*, 0)$$. The total displacement $$u$$ computed by, for example, a contact solver can then be redistributed in proportion according to:

$\frac{1}{E^*}u = \frac{1}{E_\alpha^*}u_\alpha + \frac{1}{E_\beta^*}u_\beta$

Note that is equivalence breaks down with friction, plasticity, heterogeneities, anisotropy, etc.

### Fields

Fields can be easlily accessed with the [] operator, similar to Python’s dictionaries:

surface_traction = model['traction']
# surface_traction is a numpy array


To know what fields are available, you can call the list function on a model (list(model)). You can add new fields to a model object with the [] operator:model['new_field'] = new_field, which is convenient for dumping fields that are computed outside of Tamaas.

Note

The fields traction and displacement are always registered in models, and are accessible via model.traction and model.displacement.

A model can also be used to compute stresses from a strain field:

import numpy

strain = numpy.zeros(model.shape + [6])  # Mandel--Voigt notation
stress = numpy.zeros_like(strain)

model.applyElasticity(stress, strain)


Tip

print(model) gives a lot of information about the model: the model type, shape, registered fields, and more!

#### Manipulating fields

Fields are stored in C-contiguous order. The last dimension of any field is always the vector/tensor components, if the number of components is greater than one. The other dimensions are the space dimensions, in z, x, (y) order for volumetric quantities and x, (y) for boundary quantities.

Tip

To select normal component of the surface displacement of a volume_2d model, one can write:

model.displacement[0, ..., 2]


Symmetric tensors are stored in Mandel–Voigt notation as vectors in the form:

$\underline \sigma = (\sigma_{11}, \sigma_{22}, \sigma_{33}, \sqrt{2}\sigma_{12}, \sqrt{2}\sigma_{13}, \sqrt{2}\sigma_{23}).$

## Integral operators

Integral operators are a central part of Tamaas: they are carefully designed for performance in periodic system. When a Model object is used with contact solvers or with a residual object (for plasticty), the objects using the model register integral operators with the model, so the user typically does not have to worry about creating integral operators.

Integral operators are accessed through the operators property of a model object. The [] operator gives access to the operators, and list(model.operators) gives the list of registered operators:

# Accessing operator
elasticity = model.operators['hooke']

# Applying operator
elasticity(strain, stress)

# Print all registered operators
print(list(model.operators))


Note

At model creation, these operators are automatically registered:

• hooke: Hooke’s elasticity law

• von_mises: computes Von Mises stresses

• deviatoric: computes the deviatoric part of a stress tensor

• eigenvalues: computes the eigenvalues of a symetric tensor field

Westergaard operators are automatically registered when solveNeumann or solveDirichlet are called.

## Model dumpers

The submodule tamaas.dumpers contains a number of classes to save model data into different formats:

UVWDumper

Dumps a model to VTK format. Requires the UVW python package which you can install with pip:

pip install uvw


This dumper is made for visualization with VTK based software like Paraview.

NumpyDumper

Dumps a model to a compressed Numpy file.

H5Dumper

Dumps a model to a compressed HDF5 file. Requires the h5py package. Saves separate files for each dump of a model.

NetCDFDumper

Dumps a model to a compressed NetCDF file. Requires the netCDF4 package. Saves sequential dumps of a model into a single file, with the frame dimension containing the model dumps.

The dumpers are initialzed with a basename and the fields that you wish to write to file (optionally you can set all_fields to True to dump all fields in the model). By default, each write operation creates a new file in a separate directory (e.g. UVWDumper creates a paraview directory). To write to a specific file you can use the dump_to_file method. Here is a usage example:

from tamaas.dumpers import UVWDumper, H5Dumper

# Create dumper
uvw_dumper = UVWDumper('rough_contact_example', 'stress', 'plastic_strain')

# Dump model
uvw_dumper << model

# Or alternatively

The last model.dump() call will trigger all dumpers. The resulting files will have the following hierachy:
./paraview/rough_contact_example_0000.vtr

Currently, only H5Dumper and NetCDFDumper support parallel output with MPI.