# OPTUMCompute

(Redirected from OPTUM Compute)
Jump to navigation Jump to search

## 1 Getting started

When OPTUM Compute has been installed, open the application and login using your e-mail and password. You will then be greeted by a minimalistic console, geometry window, and visualization window.

Direct interaction with the application is very limited, and all commands for modelling, analyzing, and viewing results are issued using Python. OPTUM Compute comes with a Python API (`OptumCompute.py`) and several examples. If the default directory was chosen for the installation, the Python scripts can be found here: `C:\Program Files\OPTUM CE\OPTUM C 2020\Python` In the current directory, the files are read-only. In order to edit them, copy the code to a new Python script (`.py`) in a new folder. To run the appended examples:

1. Open them up in a Python environment (Spyder, PyCharm, Visual Studio Code or similar)
2. Run OPTUM Compute
3. Press `Run` in the Python environment

### 1.1 OptumCompute.py

The OPTUM Compute Python API should be imported to the Python script:

` import OptumCompute as oc `

With this, all the different functions and methods for building a model, running calculations, and viewing results are available within the script. The file contains all the methods available for OPTUM Compute. The input to most of the methods is shown in the file as well, with the exception of the materials, where the material parameters are defined by calling the appropriate names. For example, the method for creating an N-prism as seen in `OptumCompute.py`:

The method has a total of 4 inputs, and the 4th input is a location, which can be specified using `oc.axis` as follows:

which creates vertical 16-sided n-prism with a height of 59.5 metres and a radius of 3.9 metres with the base center located at (0, 0, 20.5 m).

## 2 Working with OPTUM Compute

Before building a model, specifying materials, etc. a Python script has to be created and the OPTUM Compute Python API imported as shown above. The workflow in OPTUM Compute then follows a few general steps as outlined below:

1. Creating a material A material is created by specifying the material type and parameters as shown in Section 5. OPTUM Compute comes with two basic categories of materials, Solids and Shells. These are listed in Sections 6 and 7. A Shear Joint material can also be specified for interfaces.
2. Create stages, analysis type and meshing The `oc.setStageProperties` method specifies the stage name, analysis type, number of elements and the element type to be used in the analysis. Mesh options can also be specified within the method as shown in Section 11.1. Similarly, the `oc.newStage` command is used to create a new stage. It also allow for specifying from which previous stage the analysis should be carried out from. Section 11 outlines the methods for creating stages.
3. Creating a geometry For 3D volumes, the geometry of a material can be specified via the `oc.makeBox` or `oc.makeNprism` methods. More complex shapes can be created with the `oc.makeFace`, `oc.makeWire` and `oc.extrude` commands. For 2D faces, the `oc.makeRect` methods can be used to specify a planar geometry. Geometries can be edited or deleted with the `oc.removeInterior`, `oc.partition` and `oc.DeleteShape` commands.
4. Assigning a geometry to a material A geometry is assigned a material via the `oc.assignSolid` method for Solids, `oc.assignShell` for Shells and `oc.assignShearJoint` for Shear Joints.
5. Specify boundary conditions A face or a boundary on a geometry is assigned supports with the `oc.assignSupport` method. Other methods are also available to directly specify full, normal or tangential supports.
6. Assign loads The `oc.assignLoad` method is used to assign a loading vector to a selected face of a geometry. The loading can be non-fixed for limit analysis and multiplier elastoplastic (MEP) problems or fixed for a standard single-step elastoplastic (EP) analysis.
7. Running the analysis and viewing results After completing the above steps, the analysis is run and the results stored in a list by e.g. writing `results = oc.runAnalysis`. The analysis progress can be monitored in the Console window of OPTUM Compute. When the analysis is completed the results can be accessed in the `results` list as shown in Section 13. Section 12 specifies which plotting options are available via the `os.plot` function for visualization.

### 2.1 Functions Overview

An overview of the available methods and functions in OPTUM Compute is given below.

Function Description
`oc.assignFullSupport` Assign full supports to the given shapes
`oc.assignLoad` Assign the given load to the given shapes
`oc.assignNormalSupport` Assign normal supports to the given shapes
`oc.assignShearJoint` Assign the given shear joint material to the given shapes
`oc.assignShell` Assign the given shell material to the given (surface) shapes
`oc.assignSolid` Assign a solid material to a geometry in the current stage
`oc.assignSupport` Assign the given support to the given shapes
`oc.assignTangentialSupport` Assign tangential supports to the given shapes
`oc.axis` Axis with given point, normal vector (local Z) and primary vector (local X)
`oc.boundBox` Bounding box to test against
`oc.camera` Camera settings
`oc.clear` Clear everything the current project
`oc.currentStage` Access current stage information
`oc.deleteShape` Delete a signel selected object in the current stage
`oc.deleteShapes` Delete multipile selected objects in the current stage
`oc.extractEdges` List all edge shapes in current stage
`oc.extractFaces` List all surface shapes in current stage
`oc.extractVertices` List all vertex shapes in current stage
`oc.extrude` Extrude the given 2D shape to a 3D geometry
`oc.linear` Specify a linearly varying field
`oc.loads` List of all defined load attributes in current stage
`oc.makeBox` Bounding box to test against
`oc.makeFace` Create a 2D face in the current stage
`oc.makeMaterial` Create a new material in the current stage
`oc.makeNprism` Create a N-prism in the current stage
`oc.makeRect` Create a 2D rectangle in the current stage
`oc.makeVertex` Create a vertex point in the current stage
`oc.makeWire` Create a wire object in the current stage
`oc.material` Write out the material with the given id
`oc.materials` Write out all materials
`oc.newStage` Create a new stage
`oc.partition` Parition the selected geometries
`oc.plane` Plane containing global point (x, y, z) with normal vector (nx, ny, nz)
`oc.plot` Plot a specific result of the analysis
`oc.profile` Specify a piecewise linearly varying field
`oc.project` Access current project information
`oc.removeInterior` Remove the interior of the selected object
`oc.runAnalysis` Run the analysis using the stage parameters
`oc.select` Select objects within the specified domain
`oc.selectAll` Select all objects in the current stage
`oc.setCamera` Set the projection of the camera in the current stage
`oc.setStageProperties` Set the current stage properties
`oc.shapes` List all shapes in current stage
`oc.shearJoints` List of all defined solid attributes in current stage
`oc.shells` List of all defined shell attributes in current stage
`oc.solids` List of all defined solid attributes in current stage
`oc.stages` Access all stages information
`oc.supports` List of all defined support attributes in current stage
`oc.vector` Vector in global coordinates

## 3 Coordinate system

OPTUM Compute uses a standard Cartesian coordinate system. The directions of the global coordinate system are shown upon startup in the lower left corner of the Geometry window. This along with the naming conventions used for the global and local coordinate systems is shown below.

### 3.1 Local axis

The `oc.axis` method specifies the location and orientation of a local coordinate system relative to the global origo:

`oc.axis(P, normal, primary)`
 `P` Point of local csys origo, , relative to the global csys, default is or global origo `normal` Normal vector, N, of the local csys, default is N = , i.e. local normal is in the direction of global coordinate `primary` Primary vector, V , specifying the direction of the local csys, default is V , i.e. local -direction is in the global -direction

A local coordinate system with origo at , a normal in the direction of global and V pointing along global is defined as:

`at = oc.axis(P=[1, 1, 15], normal=[0, 1, 0], primary=[0, 0, 1])`

The above method is for example used to specify a reference point for geometries.

### 3.2 Defining a plane

The `oc.plane` method defines a local plane containing the global point with a normal vector :

`oc.plane(P=[0,0,0], normal = [0,0,1])`
 `P` Point of local csys origo, , relative to the global csys, default is or global origo `normal` Normal vector, N, of the local csys, default is N = , i.e. local normal is in the direction of global -coordinate

Similar as to the `oc.axis` method, a local plane with origo at and a normal in the direction of global can be specified as:

`oc.plane(P=[1, 1, 15], normal = [0, -1, 0])`

### 3.3 Defining a vector

The `oc.vector` method defines a vector in the global coordinate system:

`oc.vector(x, y, z)`
 `x` magnitude of vector in global direction, default is 0 `y` magnitude of vector in global direction, default is 0 `z` magnitude of vector in global direction, default is 0

Defining a vector is required as an input to methods that e.g. specify the magnitude and direction of loading or extrusion of a 2D surface into a 3D volume.

## 4 Analysis Types

OPTUM Compute comes with four types of analyses: Limit Analysis, Initial Stress, Elastoplastic and Multiplier Elastoplastic analysis. Additionally, a Mesh analysis type is also available. In this section an overview of the different analysis types is given. A complete list of the available options for the different analysis types is found in a section on Stage Options.

### 4.1 Mesh

This analysis type is atypical in that it involves no physics but only generates a mesh for the current stage. Mesh analysis can be specified through the `oc.setStageProperties` method by specifying `"analysisType": oc.AnalysisType.Mesh` as given in a section on Stage Options:

```oc.setStageProperties({
"name": "Mesh",
"analysisType": oc.AnalysisType.Mesh,
"meshTargetCount": 1000,
"elementFamily": 'mixed'
})```

The desired number of elements is here set to 1000 and a mixed element is used in the discretization.

Note: all analyses involve the automatic generation of a mesh. As such the Mesh analysis type is meant only to gauge the eventual mesh that would be used in an analysis with the same mesh settings.

### 4.2 Limit Analysis

The most basic analysis type in OPTUM Compute is Limit Analysis. This allows for the robust assessment of the stability or bearing capacity of geostructures without having to perform an exhaustive step-by-step elastoplastic analysis.

Both Fixed and Multiplier loads are applicable. In Limit Analysis, the former are kept constant while the latter are amplified until a state of incipient collapse is attained. The factor by which the multiplier loads need to be amplified in order to cause collapse is also referred to as the collapse multiplier.

The solution to a given Limit Analysis problem can be bracketed by using lower bound, upper bound and mixed elements. Using the lower bound element in Limit Analysis gives a solution which fulfills equilibrium and the yield conditions. To identify the upper bound a material specific flow rule and stress-strain relation is used. The mixed element type then implements a combination of the two.

A Limit Analysis stage can e.g. be specified as:

```oc.setStageProperties({
"name": "LA",
"analysisType": oc.AnalysisType.LimitAnalysis,
"meshTargetCount": 5000,
"adaptIterations": 3,
"meshStartCount": 1000,
"elementFamily": 'mixed'
})```

where a mixed upper and lower bound solution is specified via the `"elementFamily": 'mixed'` and three mesh adaptation iterations are used.

Before running a Limit Analysis stage with the `oc.runAnalysis()` method, a multiplier loading must be specified:

`oc.assignLoad(shape, oc.vector(0,0,-1), isFixed=False)`

where the `isFixed=False` input denotes a multiplier loading. The Limit Analysis will then give as an output a collapse multiplier on the -1 kN loading in the -direction corresponding to a mixed upper and lower bound solution. Furthermore, a failure mechanism can be identified from the analysis. It should be noted that fixed loads and gravity are also included in the Limit Analysis but are not assigned a multiplier, i.e. they are held constant.

### 4.3 Initial Stress

The initial stresses in the ground are in many cases an important aspect of strength and deformation analysis. In problems involving complex geometries and/or constitutive models, a complete description of the initial stress state may be unavailable by simple methods.

The Initial Stress analysis ( analysis) in OPTUM Compute determines a stress field which satisfies the equilibrium and boundary conditions specified while also complying with the yield conditions of the materials and the earth pressure condition.

It is recommended to perform a Initial Stress analysis in an initial stage before proceeding to do an elastoplastic analysis. Initial stress analysis can be specified as:

```oc.setStageProperties({
"name": "InitialStress",
"analysisType": oc.AnalysisType.InitialStress,
"meshTargetCount": 1000,
"elementFamily": "mixed"
})```

Note: Usually, the number of elements is not particularly critical and the computed stress fields will rarely improve significantly by increasing the number of elements above 1000. The mixed element type is recommended for this type of analysis.

### 4.4 Elastoplastic

A single-step Elastoplastic analysis entails that the failure criteria for all solid and structural elements are included in the analysis. Only fixed loads are processed while multiplier loads are ignored. Gravity is automatically included.

Elastoplastic is the appropriate analysis for both the situation where the deformations in response to a load of a given magnitude are to be computed and in the case where the analysis involves several linked stages in a staged construction scenario (e.g. excavation, embankment construction, etc). For example, after performing a analysis a new stage can be conducted as an elastoplastic analysis:

```    oc.newStage({
"name": "EP",
"analysisType": oc.AnalysisType.ElastoPlastic,
"meshTargetCount": 1000,
"fromStage": "K0",
"elementFamily": 'mixed'
})```

where `"fromStage": "K0"` specifies that the analysis should continue from an initial stress analysis stage named `"K0"`.

In Elastoplastic analysis the mixed element is usually an appropriate choice. However, the elements Lower and Upper may also be used to compute a response that underestimates (Lower) or overestimates (Upper) the true strength as well as stiffness.

### 4.5 Multiplier Elastoplastic

Multiplier Elastoplastic (MEP) analysis may be seen as combining the Limit Analysis and Elastoplastic analysis types. As in Limit Analysis, the Multiplier loads are amplified until collapse while Fixed loads and gravity are kept constant. This is done in a step-by-step elastoplastic manner with deformations computed at each load step.

Multiplier Elastoplastic analysis is for example useful in determining a Load-Displacement curve as shown in an example in [sec:MonopileTrescaMEP]. Before running a Multiplier Elastoplastic analysis stage with, a multiplier loading must be specified similarly as for Limit Analysis. An example of specifying a MEP stage starting from an Initial Stress analysis is given below:

```oc.newStage({
"name": "MEP",
"analysisType": oc.AnalysisType.MultiplierEP,
"meshStartCount": 1500,
"steps": 6,
"w": 20,
"adaptSteps" : [[0, 1, 1500], [1, 1, 1750], [2, 1, 2000], [3, 1, 2500],
[4, 1, 3000], [5, 1, 5000]],
"fromStage": "K0"
})```

In the above `"analysisType": oc.AnalysisType.MultiplierEP` specifies that the analysis should be conducted as MEP type. The `"meshStartCount": 1500` input sets the starting number of elements in the mesh to 1500. Unique to the MEP analysis is the number of load steps to be run, `"steps": 6`, and the prescribed work for each step, `"w": 20`, here set at 6 and 20 kJ respectively. Using `"fromStage": "K0"` ensures that the analysis is to continue from an Initial Stress stage which has been run beforehand. For the MEP analysis, it is possible to select precisely which steps should be used for mesh adaptivity using the option `adaptSteps`, which is an array of lists containing step number, number of adaptations, and the target number of elements.

## 5 Creating a material

A new material is added using the following command:

`oc.makeMaterial({...})`

All materials are created with the same command, and the type of material is specified in the input.

### 5.1 Linearly varying material parameters

Linearly varying fields can be defined using the `linear` method, e.g.:

`oc.linear(48, z=-6.4, zref=40.0)`

which defines a field which takes the value of 48 at and decrease with the -coordinate, e.g. at the field will evaluate to 304. This field can be assigned to a material parameter, e.g. as the shear strength of a Tresca material for limit analysis:

```soil = oc.makeMaterial({
'type': 'Tresca',
'specificWeight': 20.5,
'su': oc.linear(48, z=-6.4, zref=40),
'color': '#ff0000'
})```

where `'color': '#ff0000'` defined the color of the Tresca material in HEX format, i.e. the chosen color corresponds to bright red in this case.

The `linear` method can vary in all three directions. The full list of input can be seen below:

 `constant` Value at reference point `x` Gradient in the -direction `y` Gradient in the -direction `z` Gradient in the -direction `xref` Reference coordinate `yref` Reference coordinate `zref` Reference coordinate

### 5.2 Material parameter profile

Piece-wise linearly varying fields can be defined using the `profile` method which takes two lists as input, e.g.:

`oc.profile([5, 15, 40, 50], [1.5, 1.0, 1.0, 0.5])`

which defines a field that takes the value of 1.5 at , decrease linearly to 1.0 at , stays constant between and , and decrease to 0.5 at . For -coordinates lower than 5 or higher than 50, the nearest value will be used, i.e. 1.5 for and 0.5 for . Defining a profile with a single point is equivalent to a constant field.

The profile can be assigned to material parameters, e.g. the cohesion of a Mohr-Coulomb material or as for an AUS material:

```soil = oc.makeMaterial({
'type': 'AUS',
'specificWeight': 18,
'suc': 30,
'sue': 18,
'K0': oc.profile([5, 15, 40, 50], [1.5, 1.0, 1.0, 0.5]),
'color': '#100010'
})```

The full list of input can be seen below:

 `z` -coordinates `values` Values at each -coordinate

Both `z` and `values` are lists, i.e. defined using square brackets as seen above. The number of coordinates and values must be identical otherwise an error message will be shown.

#### 5.2.1 Solids

##### 5.2.1.1 Rigid solid

In order to define a rigid material, the type must be defined as “RigidSolid”:

`oc.makeMaterial({'type': 'RigidSolid', ...})`

The only parameter that can be defined for a rigid material is the unit weight:

`specificWeight` Unit weight [kN/m³, default = 0 kN/m³]

##### 5.2.1.2 Mohr-Coulomb

Currently, only Mohr-Coulomb materials with associated flow rule are available. In order to define a Mohr-Coulomb material, the type must be defined as “MohrCoulomb”:

`oc.makeMaterial({'type': 'MohrCoulomb', ...})`

Strength related parameters (for Limit Analysis):

 `specificWeight` Unit weight [kN/m³, default = 18 kN/m³] `c` Cohesion [kPa, default = 5 kPa] `phi` Friction angle [°, default = 25°]

Stiffness related parameters (for Elastoplastic Analysis):

 `E` Young’s modulus [MPa, default = 30 MPa] `nu` Poisson’s ratio [-, default = 0.25] `K0` K0 for initial stress analysis [-, default = 0.5]

Optional parameters:

 `ft` Tension cut-off [kPa] (included only if “ft” is defined) Default is no tension cut-off.
##### 5.2.1.3 Drucker-Prager

In order to define a Drucker-Prager material, the type must be defined as “DruckerPrager”:

`oc.makeMaterial({'type': 'DruckerPrager', ...})`

Strength related parameters (for Limit Analysis):

 `specificWeight` Unit weight [kN/m³, default = 18 kN/m³] `k` Cohesion [kPa, default = 5 kPa] `M` Friction coefficient [-, default = 0.7]

Stiffness related parameters (for Elastoplastic Analysis):

 `E` Young’s modulus [MPa, default = 30 MPa] `nu` Poisson’s ratio [-, default = 0.25] `K0` K0 for initial stress analysis [-, default = 0.5]
##### 5.2.1.4 Tresca

In order to define a Tresca material, the type must be defined as “Tresca”:

`oc.makeMaterial({'type': 'Tresca', ...})`

Strength related parameters (for Limit Analysis):

 `specificWeight` Unit weight [kN/m³, default = 18 kN/m³] `su` Shear strength [kPa, default = 30 kPa]

Stiffness related parameters (for Elastoplastic Analysis):

 `E` Young’s modulus [MPa, default = 30 MPa] `nu` Poisson’s ratio [-, default = 0.25] `K0` K0 for initial stress analysis [-, default = 0.5]

Optional parameters:

 `ft` Tension cut-off [kPa] (included only if “ft” is defined) Default is no tension cut-off.
##### 5.2.1.5 AUS

In order to define a AUS material, the type must be defined as “AUS”:

`oc.makeMaterial({'type': 'AUS', ...})`

Strength related parameters (for Limit Analysis):

 `specificWeight` Unit weight [kN/m³, default = 18 kN/m³] `suc` Undrained shear strength in triaxial compression [kPa, default = 30 kPa] `sue` Undrained shear strength in triaxial extension [kPa, default = 18 kPa]

Stiffness and hardening related parameters (for Elastoplastic Analysis):

 `Eur` Initial undrained Young’s modulus [MPa, default = 30 MPa] `epsilonC50` Axial plastic strains halfway to failure in triaxial compression [-, default = 0.005] `epsilonE50` Axial plastic strains halfway to failure in triaxial extension [-, default = 0.020] `alpha` Fitting parameter for small strain stiffness, typically [-, default = 0.6] `K0` K0 for initial stress analysis [-, default = 0.5]

Optional parameters:

 `resetParameter` Defines the degree of small strain stiffness reset: Value between 0 and 1 where 1: Full stiffness used. Independent of initial stress state 0: Stiffness reduced accordingly. Dependent on the intial stress state A value of 1 is used per default if `resetParameter` is not given. `ft` Tension cut-off [kPa] (included only if “ft” is defined) Default is no tension cut-off.
##### 5.2.1.6 Hardening Mohr-Coulomb (HMC)

The Hardening Mohr-Coulomb material includes small strain stiffness and a non-associated flow rule. For elastoplastic analysis, several parameters must therefore be defined.
In order to define a Hardening Mohr-Coulomb material, the type must be defined as “HMC”:

`oc.makeMaterial({'type': 'HMC', ...})`

Strength related parameters (for Limit Analysis):

 `specificWeight` Unit weight [kN/m³, default = 18 kN/m³] `c` Cohesion [kPa, default = 0 kPa] `phi` Friction angle [°>, default = 35°]

Stiffness and hardening related parameters (for Elastoplastic Analysis):

 `E0ref` Initial stiffness at reference pressure [MPa, default = 200 MPa] `E50ref` Stiffness halfway to failure at reference pressure [MPa, default = 34 MPa] `nu` Poisson’s ratio [-, default = 0.25] `dilationRule` Either “Taylor” or “Constant”. Use the provided class for setting the flow rule (Default is “Taylor”): `'dilationRule': oc.HMCdilationRule.Taylor` `'dilationRule': oc.HMCdilationRule.Constant` `psi` Dilation angle [°, default = 5°] `epsilonvcr` Volumetric dilation cap [-, default = 0.01] `pressureDependency` Defines how and depend on the pressure. Use the provided class for setting the pressure dependency (Default is "MinorPrincipal"): `'pressureDepedency': oc.HMCpressureDependency.MinorPrincipal` `'pressureDepedency': oc.HMCpressureDependency.MeanStress` `'pressureDepedency': oc.HMCpressureDependency.Triaxial` `referencePressure` Reference pressure for elastic moduli [kPa, default = 100 kPa] `m` Exponent for the pressure dependency, [-, default = 0.5] `alpha` Fitting parameter for small strain stiffness, typically [-, default = 0.6] `K0` K0 for initial stress analysis [-, default = 0.5]

Optional parameters:

 `resetParameter` Defines the degree of small strain stiffness reset: Value between 0 and 1 where 1: Full stiffness used. Independent of initial stress state 0: Stiffness reduced accordingly. Dependent on the initial stress state A value of 1 is used per default if `resetParameter` is not given. `ft` Tension cut-off [kPa] (included only if “ft” is defined) Default is no tension cut-off.

### 5.3 Shells

Shell materials are defined using the same basic `makeMaterial`-command as for Solids.

#### 5.3.1 Rigid shell

In order to define a rigid shell material, the type must be defined as “RigidShell”:

`oc.makeMaterial({'type': 'RigidShell', ...})`

The only parameters that can be defined for a rigid shell material are the thickness and density:

 `thickness` Thickness of shell [m, default = 0.1 m] `specificWeight` Unit weight [kN/m³, default = 0 kN/m³]

#### 5.3.2 Von Mises shell

In order to define a Von Mises shell material, the type must be defined as “VonMisesShell”:

`oc.makeMaterial({'type': 'VonMisesShell', ...})`

Strength related parameters (for Limit Analysis):

 `thickness` Thickness of shell [m, default = 0.1 m] `specificWeight` Unit weight [kN/m³, default = 0 kN/m³] `fy` Yield strength [MPa, default = 300 MPa] `mp` Yield moment [kNm/m, default = 100 kNm/m]

Stiffness related parameters (for Elastoplastic Analysis):

 `E` Young’s modulus [MPa, default = 210,000 MPa] `nu` Poisson’s ratio [-, default = 0.3]

## 6 Creating a geometry

Three basic types of shapes are available in OPTUM Compute: wires, 2D faces and 3D volumes. Furthermore, 2D geometries can be extruded to create more complex 3D volume shapes.

The following methods for creating a geometry all return a Python dictionary which can be stored as a variable or passed on to other functions to edit the shapes, assign materials, load specification etc.

Additionally, vertices can be added to faces for application of point loads. Partition is necessary for the added vertex to be a part of face and thereby be included in the meshing. In general, point loads should only be used on rigid shells or rigid solids. An example of this is given in a section on Load Specification.

### 6.1 3D Box

The `oc.makeBox` method creates a rectangular box in the current stage:

`oc.makeBox(dx, dy, dz, at)`
 `dx,dy,dz` dimensions of rectangle [m, default is ] `at` Axis location of first corner and orientation of box, default means origo and global axis

The `at` input attribute specifies the location and orientation of the object (see section on Coordinate System):

`at = oc.axis(P, normal, primary)`

By e.g. writing:

`oc.makeBox(dx=30, dy=30, dz=10, at=oc.axis(P=[-15, -15, 0]))`

a 3D box is created with depth and width of 30 m and a height of 10 m. Using `at=oc.axis(P=[-15,-15,0])` in the input places the box with it’s center coinciding with the global origo. If no input for `at` is provided, the lower left corner of the box is by default placed at the global origo with its sides coinciding with the global coordinate system.

### 6.2 3D N-prism

The `oc.makeNprism` method creates and returns a N-prism volume shape in the current stage:

`oc.makeNprism(n, radius, height, at)`
 `n` number of prism sides, [-, default is ] `radius` outer radius of prism, [m, default is m] `height` height of prism from base to top, [m, default is m] `at` location and orientation of base point, default global origo and global axis. The reference point is set at the prism center.

For example, the above method can be called as:

`oc.makeNprism(n=16, radius=3.9, height=59.5, at=oc.axis(P=[0, 0, 20.5]))`

to create a vertical solid cylinder with a radius of 3.9 m and a height of 59.5 m, with its center located at m.

### 6.3 2D Rectangle

The `oc.makeRect` method creates and returns a rectangular surface shape in the current stage:

`oc.makeRect(width, height, at) `
 `width` width of rectangle in primary direction, [m, default is 10 m] `height` height of rectangle in secondary direction, [m, default is 10 m] `at` axis location and orientation of base point, default is origo and global axis

To create a 30 m wide and 20 m high 2D rectangular face, with a plane-normal coinciding with the global -direction, the above can be used as:

`oc.makeRect(width=30, height=20, at=oc.plane(P=[10, 20, 30], normal=[0, -1, 0]))`

where the location of the lower left corner of the rectangle is set at m.

### 6.4 2D Face

The `oc.makeFace` method generates a planar face shape:

`oc.makeFace(pathData, at) `
 `pathData` 2D points in the given planar coordinate system `at` axis location and orientation of base point, default origo and global axis

For example, to create a 30-by-30 m rectangle with a 20 m indentation on one side, the coordinates of the corners are specified as:

`oc.makeFace([[0,0], [10,0], [10,20], [20,20], [20,0], [30,0], [30,30], [0,30]])`

Notice that the planar coordinates, , should be placed inside brackets to ensure that the `pathData` input is given as a Python list. As nothing is specified for `at` the coordinates are in the global coordinate system.

### 6.5 Wire

The `oc.makeWire` method creates a wire object:

`oc.makeWire(pathData, at) `
 `pathData` 2D points in the given planar coordinate system, default is the global -plane `at` axis location and orientation of base point, default origo and global axis

The `pathData` input is specified in the same way as for the `oc.makeFace` method. To create a 30-by-30 m hollow rectangle with a 10 m indentation on one side:

`oc.makeWire([[0,0], [10,0], [10,20], [20,20], [20,0], [30,0], [30,30], [0,30], [0,0]])`

### 6.6 Extrude a 2D face or wire

he `oc.extrude` method extrudes a 2D face or wire:

`oc.extrude(shapes, vector) `
 `shapes` instance or collection of shape dictionaries, each with attribute id identifying the shape (output from e.g. `oc.makeFace` or `oc.makeWire`) `vector` vector in global coordinates specifying the direction and magnitude of the extrusion (use `oc.vector`)

The input attribute `oc.vector` specifies a vector in the global coordinate system. This controls the direction of extrusion for the object. The `oc.extrude` and `vector` methods are illustrated in the figure below.

The `shapes` input specifies the geometrical object to be extruded. For example, to create a 30-by-30 m box of height 20 m, the `oc.makeFace` method is fed into the `shapes` input:

`oc.extrude(oc.makeFace( [[0,0],[10,0],[10,20],[20,20], [20,0],[30,0],[30,30],[0,30]]), oc.vector(z=20))`

For more complex shapes, the `oc.extrude` method along with the `oc.makeWire` and `oc.makeFace` provide an easy way to first create the planar layout and then extruding the 2D face to make a 3D volume object.

### 6.7 Partition shapes

Partitioning shapes in the current stage into a new set of non-overlapping shapes is done via the `oc.partition` method:

`oc.partition(shapes)   `

where `shapes` is an instance or collection of shape dictionaries, each with an attribute id identifying the shape. The method is illustrated below.

For example, a 30x30x20 m box can be partitioned into two parts by using a 2D plane:

```s1 = oc.makeBox(dx=30, dy=30, dz=20)
s2 = oc.makeRect(30, 30, at=oc.axis(P=[0, 0, 10]))
oc.partition([s1, s2])
oc.deleteShapes(s2)```

where after partitioning, the 2D plane used to cut the 3D volume is deleted via the `oc.deleteShapes(s2)` method.

After partitioning, OPTUM Compute generates new object id’s for the geometries in the current stage. Therefore, a dictionary with the pre-partitioned shape which is stored in a variable cannot be used as a reference after performing the partitioning.

### 6.8 Create a vertex

The `oc.makeVertex` method creates a vertex at given location:

`oc.makeVertex(x, y, z)`
 `x,y,z` Vertex location in global coordinates

The vertex method is for example used to ensure that a node is placed at a specific point on a geometry. This must be the case for point loads as shown in an example in a section on Load Specification.

### 6.9 Selecting shapes

electing shapes in the current stage is done via the `oc.select` method:

`oc.select(bound, level, partials)`
 `bound` Bounding box to test against `level` The (combination) of parts to select, i.e. Edge, Face etc. as: Edge : `oc.Level.Edge` Face : `oc.Level.Face` Shell : `oc.Level.Shell` Solid : `oc.Level.Solid` Vertex : `oc.Level.Vertex` Wire : `oc.Level.Wire` `partials` Include shapes that overlaps the bounding box. If false, only include shapes fully contained in box. Default is `partials=True` .

The `bound` input attribute is specified via the `oc.boundBox(x, y, z, dx, dy, dz)` command where give the reference location of the bounding volume dimensions to be selected. Selecting a face within a bounding box is illustrated in the figure below.

To specify which type of geometry to select, the `level` input is given as e.g. `oc.Level.Solid` to select all solids within the domain.

For selecting only 2D faces within a 30 m wide, 30 m deep and 10 m high box, with its center at global origo:

```oc.select(oc.boundBox(x=-15, y=-15, z=0, dx=30, dy=30, dz=10),
oc.Level.Face,
partials=False)```

If multiple 2D faces are present within the bounding box, the method returns a list of dictionaries containing the description of the shapes. This includes the dimensions and reference point of the object along with its id and object type.

All shapes in the stage can be selected using the following method:

`shapes = oc.selectAll()  `

where `shapes` will be a list of all shapes in the current stage.

### 6.10 Replace shapes

To replace a given (volume) shapes in the current stage with their corresponding surface shell shapes the following method can be used:

`oc.removeInterior(shapes)     `

where `shapes` is a dictionary containing the volume to be replaced.

For example, to create a circular hollow section the `oc.makeNprism` method along with `oc.removeInterior`, `oc.select` and `oc.deleteShapes` can be used to create a hollow shell object as:

```oc.removeInterior(oc.makeNprism(n=16, radius=3.9, height=59.9))
oc.deleteShapes(oc.select(oc.boundBox(z=59.9), oc.Level.Face) +
oc.select(oc.boundBox(z=0.0), oc.Level.Face))```

In the above the 16-side prism with a radius of 3.9 m and height of 59.9 m is first created and then hollowed out/replaced by a shell object. Then, the top and bottom faces are selected and subsequently deleted.

### 6.11 Delete a single shape

Deleting a shape from the current stage is done with the following method:

`oc.deleteShape(shape) `

The input `shape` can be a single object such as the rectangular face stored as a dictionary in `s2` in the partitioning example above:

```s2 = oc.makeRect(30, 30, at=oc.axis(P=[0, 0, 15]))
oc.deleteShape(s2)```

Another example for the use of the above command is when having selected multiple shapes but only a single shape in the list is to be deleted:

```sel = oc.select(oc.boundBox(x=-15, y=-15, z=0, dx=30, dy=30, dz=10),
oc.Level.Face,
partials=False)
oc.deleteShapes(sel)```

Note in the above the the index in `sel` refers to the first element in the list, `sel` to the second etc.

### 6.12 Delete multiple shapes

Deleting multiple shapes is done via the `oc.deleteShapes(shapes)` method as:

`oc.deleteShapes(shapes) `

If for example, all faces within a certain volume are to be deleted, the above method can be used in combination with the `oc.select` method as:

```sel = oc.select(oc.boundBox(x=-15, y=-15, z=0, dx=30, dy=30, dz=10),
oc.Level.Face,
partials=False)
oc.deleteShapes(sel)```

To delete only certain shapes within the list of selected shapes:

`oc.deleteShapes(sel+sel+sel)`

can be used to remove the first, fourth and sixth shape in the list respectively.

## 7 Boundary conditions

### 7.1 Assign supports

A general way to specify boundary conditions is via the `oc.assignSupport` method as:

`assignSupport(shapes, x, y, z, rotation, isLocal)`
 `shapes` Instance or list of shape dictionaries, each with attribute id identifying the shape. `x, y, z, rotation` Degree of freedom for each global or local axis `isLocal` Degrees of freedom parameters are consider in the canonical local coordinate system for the shapes, default is False.

It is considered good practice to always use symmetry in a model to reduce the computational cost. For example, a model including both solid and shell materials can be reduced to half by using one axis of symmetry. The shell boundary conditions can then be specified in the following way:

```oc.assignSupport(shellEdge,
x = oc.Support.Free,
y = oc.Support.Fixed,
z = oc.Support.Free,
rotation = oc.Support.Fixed)```

corresponding to symmetry about the global -direction, where displacement in the -direction and rotation is fixed.

### 7.2 Assign full supports

Boundary conditions can be directly assigned as fully fixed (global fixed) as follows:

` oc.assignFullSupport(shapes)    `

where `shapes` is a list containing the dictionaries holding the object description.

### 7.3 Assign normal supports

To specify a boundary condition directly with local and free but local fixed:

` oc.assignNormalSupport(shapes)  `

where `shapes` is a list containing the dictionaries holding the object description.

### 7.4 Assign tangential supports

To specify a boundary condition directly with local and fixed and local free:

` oc.assignTangentialSupport(shapes)  `

where `shapes` is a list containing the dictionaries holding the object description.

### 7.5 Standard fixities

Specifying the boundary conditions of the computational domain is essential when carrying out an analysis with a soil volume which is practically infinite. For example, the figure below shows a soil domain with standard fixities where the displacement normal to the plane is restricted for the sides of the soil domain whereas both normal and in-plane displacements are restricted for the bottom face.

A general approach to add standard fixities to a model is shown in the Python code below:

```tol = 1E-5
sel = oc.select(oc.boundBox(-15-1, -15-1, 0, 30+2, 30+2, 10+1), oc.Level.Face)
bottoms = []
sides = []
for i in sel:
b = i['bound']
x, y, z, dx, dy, dz = [b[c] for c in ['x', 'y', 'z', 'dx', 'dy', 'dz']]
if abs(z) < tol and dz < tol:
bottoms.append(i)
elif abs(x) - foundation_w/2 < tol and dx < tol:
sides.append(i)
elif abs(y) - foundation_w/2 < tol and dy < tol:
sides.append(i)
elif abs(y) < tol and dy < tol:
sides.append(i)
oc.assignFullSupport(bottoms)
oc.assignNormalSupport(sides)```

This can be broken down in a few steps:

• Firstly, all 2D faces within a e.g. 30x30x10 volume are selected and a list for storing the faces representing the bottom and sides of the domain is initialized
• A loop is used to iterate through all the 2D faces in the selected volume and a nested conditional if-elif statement used to check whether a face corresponds to a side or a bottom
• Finally, the bottom faces are assigned full supports (global fixed) and the sides assigned normal supports (local free, global fixed)

Note that in the above a tolerance variable is introduced as `tol=1E-5`. This is to allow for conditional statements on the dimensions of the faces, which are stored as floating point numbers with double precision.

## 8 Load specification

To assign a given load to specific shapes the `oc.assignLoad` method is used as:

` assignLoad(shapes, vector, isFixed)  `
 `shapes` Instance or collection of shape dictionaries, each with attribute id identifying the shape `vector` Load vector in global coordinates specified via `oc.vector()` `isFixed` Load is to be considered a fixed (non-multiplier) load, default is False

The units of the load vector depends on the shape to which it is applied: If the shape is a solid a volume load is applied (kN/m³), if the shape is a face a surface load is applied (kN/m²), if the shape is an edge an edge load is applied (kN/m), and, finally, if the shape is a vertex a point load is applied (kN).

Arrows are used to denote assigned loads in the Geometry window as shown in the figure below.

To apply a vertical multiplier load to a rectangular face stored in `rect` (for e.g. Limit Analysis), the above method can be used as:

`oc.assignLoad(rect, oc.vector(0,0,-1), isFixed=False)`

As the given `shape` is a 2D face, the loading type is a surface load in units of kN/m .

For point loading, a node must be placed where the loading is assigned. This can be ensured by creating a vertex via the `oc.makeVertex` method on the geometry. For example, to assign a 25 kN vertical point loading on the middle upper face of a 10x10x10 m box:

```s1 = oc.makeBox(10,10,10,at=oc.axis([-5,-5,-10]))
v = oc.makeVertex()
oc.partition([s1, v])
oc.assignLoad(v, oc.vector(0,0,-25))```

Generally, the `s1` shape in this example is assigned a rigid solid or shell material. Note that the box and vertex must be partitioned via the `oc.partition([s1, v])` method.

## 9 Stage options

The stage options define the calculations to be run. The following options are available:

 `analysisType` Use the provided `analysisType` class (Default analysis type is meshing): `oc.AnalysisType.Mesh`: Meshing `oc.AnalysisType.LimitAnalysis`: Limit analysis `oc.AnalysisType.ElastoPlastic`: Single-step elastoplastic analysis `oc.AnalysisType.InitialStress`: Initial stress analysis `oc.AnalysisType.MultiplierEP`: Multiplier elastoplastic analysis `elementFamily` Use the provided `elementFamily` class: `oc.AnalysisType.Upper`: Upper bound elements `oc.AnalysisType.Mixed`: Mixed elements `oc.AnalysisType.Lower`: Lower bound elements (Currently not available) `name` Unique name for the stage (standard string) `fromStage` Defines previous stage: Results are carried over and analysis continues with e.g. additional loads. The previous stage is referenced using the name.

When using the AUS or HMC materials, so-called iterations are needed to ensure convergence for each step. Tolerances and maximum number of iterations can be provided:

 `tol` Defines the acceptance criterion for the multiplier, i.e. , default is tol = 0.01 `iterations` Defines the maximum number of iterations, default is 15

For the multiplier elastoplastic (MEP) analysis additional parameters can be given:

 `steps` Number of load steps to be run, default is 1 `w` Prescribed work (kJ) for each step. Input can be either a single double or a list of doubles. Default value is 1.0. `tol2` Defines the acceptance criterion for the dampening and step length

### 9.1 Mesh options

When defining a stage, several options for the mesh and mesh adaptivity can be defined. Generally, the following options are available:

 `meshTargetCount` Desired number of elements [integer] `meshStartCount` Initial number of elements when using mesh adaptivity [integer] `adaptIterations` Number of mesh adaptations [integer] `refinementFactor` Defines the degree of refinement, i.e. the minimum size of new elements compared to the old size [double, default = 0.25] `coarseningFactor` Defines the degree of coarsening, i.e. the maximum size of new elements compared to the old size [double, default = 1.50] `targetLowerBound` Defines the lowest number of elements accepted relative to the target number [double, default = 0.90] `targetUpperBound` Defines the highest number of elements accepted relative to the target number [double, default = 1.10]

For multiplier elastoplastic analysis, mesh adaptivity can be chosen for any number of steps:

 `adaptSteps` List of triplets [3 integers]: Each triplet specifies the step number (starting from 0), the number of adaptivity iterations, and the target number of elements.

An example of performing initial stress analysis, creating a new stage with MEP analysis and using mesh adaptivity is given in the Examples section.

## 10 Plotting options

The results can be visualised in OPTUM Compute using the `oc.plot` method. The following input parameters are available:

 `fieldSetName` Field to be plotted, e.g. stresses, displacements and so on `layer` Toggle between regular elements and (collapsed) interface elements. Default: Regular elements are shown. `include` Toggle between solids and shells. Default: Both are shown. `displacementScale` Factor for the displacements (or normalized velocities for Limit Analysis) for better visualization. Default: 0. `rangeMax` Maximum for shown values. Default: No maximum is used. `rangeMin` Minimum for shown values. Default: No minimum is used. `step` Display the MEP results for specified step. Default: Last step is shown. `camera` Specify initial view using `oc.camera`, e.g. `camera=oc.camera(location=oc.vector(100,100,50))`. Default: Top-down view is used. `clipPlane` Allow cutting through the model for better visualization, e.g. `clipPlane=oc.plane(0,0,0,1,0,0)`, where the first three inputs to `plane` specify a point and the next three specify the normal vector. Default: No clipping plane is used. `slicePlane` Similar to `clipPlane`, but only the intersection of the plane and elements is shown. Default: No slice plane is used. `filename` File name for export of view. Default: No file name is specified, thus, no image is exported. `renderAttributes` Renders the boundary conditions on the result set. Default: `False`, i.e. not shown.

The result fields can be plotted by specifying the correct `fieldSetName`:

 u| Euclidian norm of the displacements (or normalized velocities for Limit Analysis). `ux` Displacement in the -direction. Not available for Limit Analysis. `uy` Displacement in the -direction. Not available for Limit Analysis. `uz` Displacement in the -direction. Not available for Limit Analysis. `sx` `sy` `sz` `sxy` `syz` `szx` `s1` , largest principal stress, i.e. `s2` , middle principal stress `s3` , smallest principal stress `mx` , moment in the -direction (shells) `my` , moment in the -direction (shells) `mxy` , twisting moment (shells) `m1` , largest principal moment, (shells) `m2` , smallest principal moment (shells) `td` Total dissipation (solids) `td` Shear dissipation (solids)

Strains will be added to the result set in the nearest future.

The `layer` input takes a string as input:

 `layer=` Default option, solids and shells are shown. `layer='volumes'` Same as default option, solids and shells are shown. `layer='interfaces'` Interface elements are shown.

The `include` input takes a string as input:

 `include=` Default option, solids and shells are shown. `include='solids'` Solids shown. `include='shells'` Shells are shown.

## 11 Accessing the results

The result set is the output when an analysis is run:

`results = oc.runAnalysis()`

Displacements and strains are currently not made available in the result structure, but it will be added in the nearest future. Resulting nodal forces for each element will likewise be added soon.

### 11.1 Limit analysis

The results of a limit analysis run can be accessed as follows:

 `results.limitAnalysis.volumes.elements[EL #].points` Location of the solid or shell element `results.limitAnalysis.volumes.elements[EL #].displacements` Displacement of the solid or shell element `results.limitAnalysis.volumes.elements[EL #].stresses` Stresses of the solid or shell element `results.limitAnalysis.volumes.elements[EL #].moments` Moments of the shell element

### 11.2 Initial stress analysis

The results of an initial stress analysis run can be accessed as follows:

 `results.initialStress.volumes.elements[EL #].points` Location of the solid or shell element `results.initialStress.volumes.elements[EL #].displacements` Displacement of the solid or shell element `results.initialStress.volumes.elements[EL #].stresses` Stresses of the solid or shell element `results.initialStress.volumes.elements[EL #].moments` Moments of the shell element

### 11.3 Elastoplastic analysis

The results of an elastoplastic analysis run can be accessed as follows:

 `results.ep.volumes.elements[EL #].points` Location of the solid or shell element `results.ep.volumes.elements[EL #].displacements` Displacement of the solid or shell element `results.ep.volumes.elements[EL #].stresses` Stresses of the solid or shell element `results.ep.volumes.elements[EL #].moments` Moments of the shell element

### 11.4 Multiplier elastoplastic analysis

The multiplier elastoplastic analysis may contain several steps. The results for each step can be assessed using the first index (counting from zero):

 First step: `results.ep.volumes.elements[EL #].points` Location of the solid or shell element `results.ep.volumes.elements[EL #].displacements` Displacement of the solid or shell element `results.ep.volumes.elements[EL #].stresses` Stresses of the solid or shell element `results.ep.volumes.elements[EL #].moments` Moments of the shell element Second step: `results.ep.volumes.elements[EL #].points` Location of the solid or shell element Nth step: `results[N-1].ep.volumes.elements[EL #].points` Location of the solid or shell element

## 12 Examples

### 12.1 Monopile with Tresca material

In this section, we will go through an example script for modelling and analysing a monopile. The script is included as an example in the installed version of OPTUM Compute as well.

First and foremost, we import `OptumCompute` and set the camera to perspective. Moreover, several variables are defined to make the model parametric:

```import OptumCompute as oc

oc.setCamera(oc.CameraOption.Perspective)
oc.clear()
foundation_w = 50.0
foundation_h = 40.0

d = 19.5
pile_z = foundation_h - d
pile_h = 40.0 + d
pile_r = 3.9

tol = 1E-5```

Next, the materials are defined: The soil is modelled as a Tresca material with a shear strength, which increase with the depth and has the value of 48 kPa at ground level, while the monopile is modelled as a rigid shell.

```solid1 = oc.makeMaterial({
'type': 'Tresca',
'specificWeight': 20.5,
'su': oc.linear(48, z=-6.4, zref=foundation_h),
'E': 50,
'nu': 0.0,
'K0': 0.5,
'color': '#ff0000'
})

shellMaterial = oc.makeMaterial({
'type': 'RigidShell',
'thickness': 0.080,
'color': '#60ff00'
})
```

The model is encapsulated in a small method, as it needs to be defined twice; once for the initial stress analysis and once for the multiplier elastoplastic analysis. The geometry of the soil is created using the `makeBox` method, while the monopile is created using the `makeNprism` method. Due to the symmetry of the model, half is removed using a box to partition, and finally, the interior of the pile is removed above ground level.

```def create_geometry():
shift = foundation_w/2
s1 = oc.makeBox(foundation_w, foundation_w, foundation_h,
at=oc.axis(P=[-shift, -shift, 0]))
s2 = oc.makeNprism(16, pile_r, pile_h, at=oc.axis(P=[0, 0, pile_z]))
s3 = oc.makeBox(foundation_w+2, foundation_w/2+1,
foundation_h+pile_h+1, at=oc.axis(P=[-shift-1, 0, 0]))
oc.partition([s1, s2, s3])

# Remove half:
sel = oc.select(oc.boundBox(-shift+2, 1, 1, foundation_w+2,
foundation_w/2+2, foundation_h+pile_h ),
oc.Level.Solid)
oc.deleteShapes(sel)

# Hollow out pile above ground and delete face:
sel = oc.select(oc.boundBox(z=pile_h + pile_z/2), oc.Level.Solid)
oc.removeInterior(sel)
sel = oc.select(oc.boundBox(z=pile_h + pile_z/2), oc.Level.Face)
oc.deleteShapes(sel)```

With the geometry in place, materials can be assigned to the shapes. This is done by selecting a shape in the model using the `select` method and then assigning materials. For the shells, two selections are used to be able to define interfaces between the pile and the soil. These interfaces means that a displacement discontinuity can occur. Finally, a shear joint is assigned at pile bottom, which again enables a displacement discontinuity.

```    # solid
sel = oc.select(oc.boundBox(-shift-1, -shift-1, 0, foundation_w+2,
foundation_w+2, foundation_h+1), oc.Level.Solid)
oc.assignSolid(sel, solid1)

# shell
sel = oc.select(oc.boundBox(x = -pile_r-1, y=-pile_r-1, z=pile_z+1,
dx=2*pile_r+2, dy=pile_r, dz=foundation_h-pile_z-2), oc.Level.Face)
sel = list(filter(lambda s:s['bound']['dy'] > 1e-5, sel))
oc.assignShell(sel, shellMaterial, plusMaterial=solid1, minusMaterial=solid1)

sel = oc.select(oc.boundBox(-pile_r-1, -pile_r-1, foundation_h+1,
2*pile_r+2, pile_r+2, pile_h), oc.Level.Face)
oc.assignShell(sel, shellMaterial)

# shear joint at pile bottom:
sel = oc.select(oc.boundBox(0, -1, pile_z), oc.Level.Face)
oc.assignShearJoint(sel, solid1)
```

For the soil, standard fixities are used. This is done by selecting the faces of the soil domain and assigning full support for the bottom and normal supports for the sides. When using either the `assignNormalSupport` or `assignTangentialSupport` methods, the local coordinate system of the face is used.

```    # standard fixities
sel = oc.select(oc.boundBox(-shift-1, -shift-1, 0, foundation_w+2,
foundation_w+2, foundation_h+1), oc.Level.Face)
bottoms = []
sides = []
for i in sel:
b = i['bound']
x, y, z, dx, dy, dz = [b[c] for c in ['x', 'y', 'z', 'dx', 'dy', 'dz']]
if abs(z) < tol and dz < tol:
bottoms.append(i)
elif abs(x) - foundation_w/2 < tol and dx < tol:
sides.append(i)
elif abs(y) - foundation_w/2 < tol and dy < tol:
sides.append(i)
elif abs(y) < tol and dy < tol:
sides.append(i)
oc.assignFullSupport(bottoms)
oc.assignNormalSupport(sides)```

Symmetry conditions must be applied to the pile itself. Again, this is done by selecting the relevant edges and applying supports using the `assignSupport` method.

```    # shell BCs
edges = []
edges.extend(oc.select(oc.boundBox(x = -pile_r, y = 0,
z = pile_z/2+foundation_h/2), oc.Level.Edge))
edges.extend(oc.select(oc.boundBox(x = pile_r, y = 0,
z = pile_z/2+foundation_h/2), oc.Level.Edge))

edges.extend(oc.select(oc.boundBox(x = -pile_r, y = 0,
z = pile_z/2+foundation_h), oc.Level.Edge))
edges.extend(oc.select(oc.boundBox(x = pile_r, y = 0,
z = pile_z/2+foundation_h), oc.Level.Edge))

edges.extend(oc.select(oc.boundBox(x = 0, y = 0, z = pile_z+foundation_h),
oc.Level.Edge))

oc.assignSupport(edges, x=oc.Support.Free, y=oc.Support.Fixed,
z=oc.Support.Free, rotation=oc.Support.Fixed)

return```

An initial stress stage is required when doing a multiplier elastoplastic analysis. A stage name is needed as reference for following stage. The analysis type is set to `oc.AnalysisType.InitialStress`, and we will be using approximately 1500 mixed elements. The stage is run using `oc.runAnalysis()`.

```# STAGE 1
oc.setStageProperties({
"name": "K0",
"analysisType": oc.AnalysisType.InitialStress,
"meshTargetCount": 1500,
"elementFamily": 'mixed'
})
create_geometry()
result = oc.runAnalysis()```

With the initial stresses computed, we can create a new stage for the multiplier elastoplastic (MEP) analysis. With the new stage initiated, we recreate the geometry and define the load acting horizontally at the pile top. For the analysis, we want to run six steps starting at 1500 elements and adapt the mesh every step increasing the element count to 4000 for the final step.

For the MEP analysis, it is possible to select precisely which steps should be used for mesh adaptivity using the option `adaptSteps`, which is an array of lists containing step number, number of adaptations, and the target number of elements.

```# STAGE 2
oc.newStage({
"name": "MEP",
"analysisType": oc.AnalysisType.MultiplierEP,
"meshStartCount": 1500,
"steps": 6,
"w": 20,
"adaptSteps" : [[0, 1, 1500], [1, 1, 1750], [2, 1, 2000], [3, 1, 2500],
[4, 1, 3000], [5, 1, 5000]],
"fromStage": "K0"
})
create_geometry()
sel = oc.select(oc.boundBox(0,0,pile_z+pile_h), oc.Level.Face)
oc.assignLoad(sel, oc.vector(10,0,0), isFixed = False)

result = oc.runAnalysis()

oc.plot('|U|', displacementScale = 10)```

The six steps of the MEP analysis yield the following load multipliers and maximum displacements:

```MEP step 1 concluded: Multiplier = 11.2121, max displacement = 0.0862609 m
MEP step 2 concluded: Multiplier = 17.3423, max displacement = 0.172418 m
MEP step 3 concluded: Multiplier = 20.8508, max displacement = 0.258606 m
MEP step 4 concluded: Multiplier = 22.9506, max displacement = 0.344827 m
MEP step 5 concluded: Multiplier = 24.064, max displacement = 0.431041 m
MEP step 6 concluded: Multiplier = 24.672, max displacement = 0.517284 m```

Multiplying with the applied load of 10 kN/m² and the area of the pile top (23.282 m²), we get the following load displacement curve for the top of the pile:

```Return to Main Page
```