# Step by step example
A simple mechanical example.
## Import
Let us start by importing the basic input classes
```py
from amitex.input import (
Input,
Grid,
AlgorithmParameters,
Materials,
LoadingOutput
)
```
`Input` contains all parameters, `Grid` specify the grid dimensions, the last three correspond to
the root nodes of AMITEX XML input files.
If not specified, all classes introduces below come from `amitex.input`.
## Grid
Let us make a cell of 32x32x32, with voxels of side 1
```py
grid = Grid([32, 32, 32], [1.0, 1.0, 1.0])
```
## Algorithm
The basic algorithm parameters are defined in "node" Algorithm (importable from amitex.input), we need to set up the algorithm type and the convergence acceleration.
```py
algorithm = Algorithm(type="Basic_Scheme", convergenceAcceleration=True)
```
Parameters can be set, for example to set the maximum number of iterations:
```py
algorithm.nitermax = 3000
```
Most parameters can be set in the constructor, like:
```py
algorithm = Algorithm(type="Basic_Scheme", convergenceAcceleration=True, nitermax=3000)
```
To set up a mechanical resolution, we nee to specify the filter and small perturbations of the Mechanics node:
```py
mechanics = Mechanics(filter="Default", smallPerturbations=True)
```
Then, we gather all algorithm parameters:
```
algorithmParameters = AlgorithmParameters(algorithm, mechanics=mechanics)
```
Alternatively, one could write
```py
algorithmParameters = AlgorithmParameters(algorithm)
algorithmParameters.mechanics = mechanics
```
The corresponding XML is
```xml
```
## Materials
Fist we need to instantiate the `Materials` class regrouping all material specification.
```py
materials = Materials()
```
We have one isotropic elastic material
```py
material = Material()
material.setLaw("elasiso")
```
We need to set the 2 coefficients for this material:
```py
material.setCoeffs([1.0e9, 1.5e9])
```
To place a material, one has to define its zones, which are no more than a list of positions.
Here a zone is defined on the whole cell:
```python3
zone = Zone(grid.dims())
for p in grid.allPoints():
zone.add(p)
```
A zone is initialized with the dimensions of the grid (we use here `grid.dims()` with `grid` defined above). `grid.allPoints()` iterates over all points in the cell, each point is added.
A zone can be added to the material with
```py
material.addZone(zone)
```
Note that `addZone` accepts more parameters to associate coefficients to a zone, for example:
```py
material.addZone(zone, coeffs=[1.0e9, 1.5e9])
```
We can now add the material to the list of materials:
```py
materials.add(material)
```
Finally, we need to set up the reference material:
```py
materials.referenceMaterial = ReferenceMaterial(1.0e9, 1.5e9)
```
The resulting XML is
```xml
```
## Loading & Outputs
```py
loadingOutput = LoadingOutput()
```
### Output
Le us just switch on stress and strain VTK outputs
```py
output = Output()
output.setVtkStressStrain(1, 1)
loadingOutput.output = output
```
### Loading(s)
We will set up a loading ending at time 1.0 with 2 steps, with the ZZ component of the finite strain set to 0.01, and all other components will be relaxed
```py
loading = Loading()
loading.setTimeDiscretizationLinear(2, 1.0)
```
The evolution of the strain component ZZ towards 0.01 can be set with:
```
loading.setEvolution(Component.ZZ, MechanicDriving.Strain, Evolution.Linear, 0.01)
```
Component contains values XX, YY, ZZ, XY… . These are tuples (I. J) where I or J are equal to 0,1,2, `XX = (0, 0)`, `XX = (0, 1)` etc…
MechanicDriving is an enum of values `Strain` and `Stress`, `Evolution` can be `Linear` or `Constant` (in the constant case, specifying a value as last parameter is not needed).
This allow to set component from loops:
```py
for i in range(3):
for j in range(i, 3):
if i != Component.Z or j != Component.Z:
loading.setEvolution((i, j), MechanicDriving.Stress, Evolution.Linear, 0.0)
```
Here only (i,j) != ZZ and with j >= i are considered, because we are in small perturbations (for more on this the reader is referred to the official AMITEX documentation).
Then we add the loading to `loadingOutput`:
```py
loadingOutput.add(loading)
```
### Corresponding XML
The resulting XML is
```xml
```
## Input
It is now time to gather all pieces of input parameters wih the `Input` class
```py
input = Input(grid, algorithmParameters, materials, loadingOutput)
```
This library puts all generated files to a directory (by default "amitex_dir"), it can be set with:
```py
input.resultsDir = "my_amitex_dir"
```
Output files in a subdirectory `output` in this directory. Moreover all output filenames will
have the prefix `output`. The total prefix can be queried with:
```py
input.outputPrefix()
```
## Run simulation
We can now run a simulation with AMITEX-FFTP
```py
from amitex.simulation import runSimulationExternal
runSimulationExternal(input, numberProcs=2)
```
This will generate the necessary files and execute `amitex_fftp`.
The second optional parameter sets the number of MPI processes used for `amitex_fftp`. By default it is set at 0, which (likely) means the number of cores on your machine will be used (`mpirun` is executed without `-n`.)
### Separate generation and running steps
One could decompose the steps by first generating the input files and then generate a script from
the command that would be called by `runSimulationExternal`.
```py
from amitex.simulation import getSimulationShellCommand
input.generateFiles()
with open("run.sh", "w", encoding="utf-8") as file:
file.write("#!/bin/sh\n")
file.write(getSimulationShellCommand(input, numberProcs=2) + "\n")
```
## Full example
```{literalinclude} ../examples/Input/minimal.py
```