Skip to content

Commit

Permalink
Merge pull request #11990 from KratosMultiphysics/docs/expression_doc…
Browse files Browse the repository at this point in the history
…umentation

[Docs] Add user level documentation for Expressions
  • Loading branch information
sunethwarna authored Feb 6, 2024
2 parents 1b36c25 + 2d43e74 commit b963521
Show file tree
Hide file tree
Showing 30 changed files with 2,256 additions and 3 deletions.
4 changes: 2 additions & 2 deletions docs/pages/Kratos/Documentation_Guide/How_Tos/Testing.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
---
title: Documentation testing and updating
keywords:
keywords:
tags: [Testing.md]
sidebar: documentation_guide
summary:
summary:
---


Expand Down
69 changes: 69 additions & 0 deletions docs/pages/Kratos/Expressions/General/Expression_Arithmetics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
title: Expression Arithmetics
keywords:
tags: [expression, arithmetics]
sidebar: kratos_expressions
summary:
---

## Introduction

The ```Expressions``` of type ```NodalExpression```, ```ConditionExpression```, ```ElementExpression``` and their underlying ```Expression``` can be used in arithmetic formulations.

Following operations are supported:
* Addition ```+``` or ```+=```
* Subtraction ```-``` or ```-=```
* Multiplication ```*``` or ```*=```
* Division ```/``` or ```/=```
* Power ```**``` or ```**=```

These operations are carried out only when their results are required ([lazy evaluation](https://en.wikipedia.org/wiki/Lazy_evaluation)).

## Example usage
Here is an example for using ```NodalExpression``` (other expression types can be used in a similar fashion).
```python
import KratosMultiphysics as Kratos
model = Kratos.Model()
model_part = model.CreateModelPart("test")
node_1 = model_part.CreateNewNode(1, 0, 0, 0)
node_2 = model_part.CreateNewNode(2, 1, 0, 0)
node_3 = model_part.CreateNewNode(3, 1, 1, 0)

# setting VELOCITY of each node
node_1.SetValue(Kratos.VELOCITY, Kratos.Array3([1,2,3]))
node_2.SetValue(Kratos.VELOCITY, Kratos.Array3([4,5,6]))
node_3.SetValue(Kratos.VELOCITY, Kratos.Array3([7,8,9]))

# create nodal expression
nodal_expression = Kratos.Expression.NodalExpression(model_part)

# read non-historical nodal VELOCITY to expression
Kratos.Expression.VariableExpressionIO.Read(nodal_expression, Kratos.VELOCITY, False)

# now we can do arithmetics.
nodal_expression += 1 # Adds 1 to all the components of VELOCITY in all the entities
nodal_expression *= 2 # Multiplies by 2, the all the components of VELOCITY in all the entities
nodal_expression /= 3 # Divides by 2, the all the components of VELOCITY in all the entities
nodal_expression -= 0.5 # Subtract by 2, the all the components of VELOCITY in all the entities

# writing the result to the ACCELERATION variable
Kratos.Expression.VariableExpressionIO.Write(nodal_expression, Kratos.ACCELERATION, False)

for node in model_part.Nodes:
print(node.GetValue(Kratos.ACCELERATION))
```
Expected output:
```console
| / |
' / __| _` | __| _ \ __|
. \ | ( | | ( |\__ \
_|\_\_| \__,_|\__|\___/ ____/
Multi-Physics 9.4."3"-docs/expression_documentation-156476ea1c-Release-x86_64
Compiled for GNU/Linux and Python3.11 with GCC-13.2
Compiled with threading and MPI support.
Maximum number of threads: 30.
Running without MPI.
[3](0.833333,1.5,2.16667)
[3](2.83333,3.5,4.16667)
[3](4.83333,5.5,6.16667)
```
11 changes: 11 additions & 0 deletions docs/pages/Kratos/Expressions/General/Expression_Interface.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
title: Expression Interface
keywords:
tags: [Expression_Interface.md]
sidebar: kratos_expressions
summary:
---

## Introduction

TODO: Link this page to the doxygen page once it is properly online.
87 changes: 87 additions & 0 deletions docs/pages/Kratos/Expressions/General/Expression_Types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
---
title: Expression Types
keywords:
tags: [Expression_Types.md]
sidebar: kratos_expressions
summary:
---

## Introduction

There are four types of expressions.
* `Expression`
* `NodalExpression`
* `ConditionExpression`
* `ElementExpression`

## `Expression`

`Expression` is the lowest level class that everything else is built on top of. It models an array of numeric values (scalars, vectors, matrices, etc.), supports arithmetic operations, but is not related to any container in Kratos. To create an `Expression` or write an existing one, you can use one of the derived classes of `ExpressionIO`.

TODO: add an example (@matekelemen) - requires exposing the `Input` and `Output` nested classes of `VariableExpressionIO` to python.


## Nodal Expression

Nodal expressions are used to store data related to nodal quantities. They may be historical or non-historical. Following code snippet illustrtes creating a nodal expression
and reading ```VELOCITY``` from non-historical nodal container.
```python
import KratosMultiphysics as Kratos
model = Kratos.Model()
model_part = model.CreateModelPart("test")
node_1 = model_part.CreateNewNode(1, 0.0, 0.0, 0.0)
node_2 = model_part.CreateNewNode(2, 0.0, 1.0, 0.0)
node_1.SetValue(Kratos.VELOCITY, Kratos.Array3([1,2,3]))
node_2.SetValue(Kratos.VELOCITY, Kratos.Array3([3,4,5]))

# now create the expression:
nodal_expression = Kratos.Expression.NodalExpression(model_part)

# now read the VELOCITY from the non-historical container
Kratos.Expression.VariableExpressionIO.Read(nodal_expression, Kratos.VELOCITY, False)
```

## Condition Expression

Condition expressions are used to store data related to condition quantities. Following code snippet illustrtes creating a condition expression
and reading ```VELOCITY``` from the conditions' container.
```python
import KratosMultiphysics as Kratos
model = Kratos.Model()
model_part = model.CreateModelPart("test")
node_1 = model_part.CreateNewNode(1, 0.0, 0.0, 0.0)
node_2 = model_part.CreateNewNode(2, 0.0, 1.0, 0.0)

prop = model_part.CreateNewProperties(1)
cond_1 = model_part.CreateNewCondition("LineCondition2D2N", 1, [1, 2], prop)
cond_1.SetValue(Kratos.VELOCITY, Kratos.Array3([1,2,3]))

# now create the expression:
condition_expression = Kratos.Expression.ConditionExpression(model_part)

# now read the VELOCITY from the condition data value container
Kratos.Expression.VariableExpressionIO.Read(condition_expression, Kratos.VELOCITY)
```

## Element Expression

Element expressions are used to store data related to element quantities. Following code snippet illustrtes creating a element expression
and reading ```VELOCITY``` from the elements' container.
```python
import KratosMultiphysics as Kratos
model = Kratos.Model()
model_part = model.CreateModelPart("test")
node_1 = model_part.CreateNewNode(1, 0.0, 0.0, 0.0)
node_2 = model_part.CreateNewNode(2, 0.0, 1.0, 0.0)
node_3 = model_part.CreateNewNode(3, 0.0, 1.0, 0.0)

prop = model_part.CreateNewProperties(1)
elem_1 = model_part.CreateNewElement("Element2D3N", 1, [1, 2, 3], prop)
elem_1.SetValue(Kratos.VELOCITY, Kratos.Array3([1,2,3]))

# now create the expression:
element_expression = Kratos.Expression.ElementExpression(model_part)

# now read the VELOCITY from the condition data value container
Kratos.Expression.VariableExpressionIO.Read(element_expression, Kratos.VELOCITY)
```
15 changes: 15 additions & 0 deletions docs/pages/Kratos/Expressions/General/Notes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
title: Notes
keywords:
tags: [notes, warnings, expression]
sidebar: kratos_expressions
summary:
---

## Introduction

The use of ```Expression```, ```NodalExpression```, ```ConditionExpression``` or ```ElementExpression``` should be done carefully for the following reasons.

1. If it is possible to implement the arithmetics or opertations you do in ```C++``` level, then it is encouraged.
2. Use arithmetic operators (`+=`, `-=`, `*=`, `/=`, `**=`, `+`, `-`, `*`, `/`) carefully. Operators keep their operands in memory, which means that if you chain operations for long enough, at some point you will run out of RAM. In such cases, `Kratos.Expression.Utils.Collpase` to forcefully evaluate an expression and discard the hierarchy of operands it stored. An example use case would be updating the same expression with new data in every time step of an analysis.
3. Expressions have significant memory and performance overhead due to dynamic polymorphism. If it becomes a bottleneck, move your calculations to `C++`.
50 changes: 50 additions & 0 deletions docs/pages/Kratos/Expressions/General/Overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
title: Overview
keywords:
tags: [overview.md]
sidebar: kratos_expressions
summary:
---
## Introduction

An expression represents a mechanism where a given mathematical expression is evaluated when actual value of that expression in required. One can compare these
expressions to lazy expressions (expression templates) in [Eigen](https://eigen.tuxfamily.org/dox/TopicLazyEvaluation.html) or in [Boost](https://www.boost.org/doc/libs/1_82_0/doc/html/boost_yap/manual.html). The main difference being, Kratos expressions are **dynamic** lazy expressions (evaluated on demand, not automatically) whose type is evaluated at runtime, whereas Eigen and Boost has **static** lazy expressions whose type is known at compile-time. Few of the main advantages of these lazy expressions are:
* May reduce memory footprint.
* May reduce computational cost.

KratosMultiphysics stores its data in different containers depending on what kind of geometry that data is associated with (node, element, condition, etc.) and what that data represents. Each container requires a ```Kratos::Variable``` to access its underlying data. This requires defining the variable beforehand, and then using it to store and retrieve its value. Expressions allow users/developers to access and manipulate the data within these containers regardless of what `Kratos::Variable` they belong to. All expressions support **shared memory** and **distributed memory** parallelism. Though implemented in C++, expressions are meant to be used mainly in python.

## Supported data containers

The following data containers are supported:
* NodalExpression - data related to nodes (with historical or non-historical variables).
* ConditionExpression - data related to conditions.
* ElementExpression - data related to elements.

## Supported data types

Expressions are compatible with most main variable types in Kratos:

* ```int```
* ```double```
* ```array_1d<double, 3>```
* ```array_1d<double, 4>```
* ```array_1d<double, 6>```
* ```array_1d<double, 9>```
* ```Vector```
* ```Matrix```

## Use cases

Expressions are useful in following scenarios:
1. Transferring data between Kratos and other libraries - third-party libraries may be developed in other languages like Fortran as well.
2. Transferring data between Kratos and numpy/scipy.
3. Storing and fetching Kratos data in HDF5.
4. Non performance-critical intermediate calculations in python.
5. Transerring data back and forth within Kratos without variables such as in OptimizationApplication.
6. Quick and convenient prototyping of research code in python while using **shared memory** and **distributed memory** paralellism.





Loading

0 comments on commit b963521

Please sign in to comment.