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:
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^*\):
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:
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:
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 lawvon_mises
: computes Von Mises stressesdeviatoric
: computes the deviatoric part of a stress tensoreigenvalues
: 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
model.addDumper(H5Dumper('rough_contact_archive', all_fields=True))
model.addDumper(uvw_dumper)
model.dump()
The last model.dump()
call will trigger all dumpers. The resulting files will have the following hierachy:
./paraview/rough_contact_example_0000.vtr
./paraview/rough_contact_example_0001.vtr
./hdf5/rough_contact_archive_0000.h5
Important
Currently, only H5Dumper
and
NetCDFDumper
support
parallel output with MPI.