Basic maths#

Note

This tutorial requires DPF 9.1 or above (2025 R1).

This tutorial explains how to perform some basic mathematical operations with PyDPF-Core.

DPF exposes data through Field objects (or other specialized kinds of fields). A Field is a homogeneous array of floats.

A FieldsContainer is a labeled collection of Field objects that most operators can use, allowing you to operate on several fields at once.

To perform mathematical operations, use the operators available in the math operators module. First create an instance of the operator of interest, then use the .eval() method to compute and retrieve the first output.

Most operators for mathematical operations can take in a Field or a FieldsContainer.

Most mathematical operators have a separate implementation for handling FieldsContainer objects as input, and are recognizable by the suffix _fc appended to their name.

This tutorial first shows in Create fields and field collections how to create the custom fields and field containers it uses.

It then provides a focus on the effect of the scoping of the fields on the result in Effect of the scoping, as well as a focus on the treatment of collections in Handling of collections.

It then explains how to use several of the mathematical operators available, both with fields and with field containers.

Download tutorial as Python script Download tutorial as Jupyter notebook

Create fields and field collections#

DPF exposes mathematical fields of floats through Field and FieldsContainer objects. The Field is a homogeneous array of floats and a FieldsContainer is a labeled collection of Field objects.

Here, fields and field collections created from scratch are used to show how the mathematical operators work.

For more information on creating a Field from scratch, see DPF data structures.

Create the fields based on:

  • A number of entities

  • A list of IDs and a location, which together define the scoping of the field

The location defines the type of entity the IDs refer to. It defaults to nodal, in which case the scoping is understood as a list of node IDs, and the field is a nodal field.

For a more detailed explanation about the influence of the Scoping on the operations, see the Effect of the scoping section of this tutorial.

First import the necessary DPF modules.

# Import the ``ansys.dpf.core`` module
from ansys.dpf import core as dpf
# Import the math operators module
from ansys.dpf.core.operators import math as maths

Create the fields with the Field class constructor.

Helpers are also available in fields_factory for easier creation of fields from scratch.

# Create four nodal 3D vector fields of size 2
num_entities = 2
field1 = dpf.Field(nentities=num_entities)
field2 = dpf.Field(nentities=num_entities)
field3 = dpf.Field(nentities=num_entities)
field4 = dpf.Field(nentities=num_entities)

# Set the scoping IDs
field1.scoping.ids = field2.scoping.ids = field3.scoping.ids = field4.scoping.ids = range(num_entities)

# Set the data for each field using flat lists (of size = num_entities * num_components)
field1.data = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0]
field2.data = [7.0, 3.0, 5.0, 8.0, 1.0, 2.0]
field3.data = [6.0, 5.0, 4.0, 3.0, 2.0, 1.0]
field4.data = [4.0, 1.0, 8.0, 5.0, 7.0, 9.0]

# Print the fields
print("Field 1","\n", field1, "\n"); print("Field 2","\n", field2, "\n");
print("Field 3","\n", field3, "\n"); print("Field 4","\n", field4, "\n")
Field 1 
 DPF  Field
  Location: Nodal
  Unit: 
  2 entities 
  Data: 3 components and 2 elementary data 

  IDs                   data
  ------------          ----------
  0                     1.000000e+00   2.000000e+00   3.000000e+00   
                        
  1                     4.000000e+00   5.000000e+00   6.000000e+00   
                        

 

Field 2 
 DPF  Field
  Location: Nodal
  Unit: 
  2 entities 
  Data: 3 components and 2 elementary data 

  IDs                   data
  ------------          ----------
  0                     7.000000e+00   3.000000e+00   5.000000e+00   
                        
  1                     8.000000e+00   1.000000e+00   2.000000e+00   
                        

 

Field 3 
 DPF  Field
  Location: Nodal
  Unit: 
  2 entities 
  Data: 3 components and 2 elementary data 

  IDs                   data
  ------------          ----------
  0                     6.000000e+00   5.000000e+00   4.000000e+00   
                        
  1                     3.000000e+00   2.000000e+00   1.000000e+00   
                        

 

Field 4 
 DPF  Field
  Location: Nodal
  Unit: 
  2 entities 
  Data: 3 components and 2 elementary data 

  IDs                   data
  ------------          ----------
  0                     4.000000e+00   1.000000e+00   8.000000e+00   
                        
  1                     5.000000e+00   7.000000e+00   9.000000e+00   
                        

 

Create the collections of fields (called “field containers”) using the fields_container_factory. Here, we use the over_time_freq_fields_container() helper to generate a FieldsContainer with ‘time’ labels.

# Create the field containers
fc1 = dpf.fields_container_factory.over_time_freq_fields_container(fields=[field1, field2])
fc2 = dpf.fields_container_factory.over_time_freq_fields_container(fields=[field3, field4])

# Print the field containers
print("FieldsContainer1","\n", fc1, "\n")
print("FieldsContainer2","\n", fc2, "\n")
FieldsContainer1 
 DPF  Fields Container
  with 2 field(s)
  defined on labels: time 

  with:
  - field 0 {time:  1} with Nodal location, 3 components and 2 entities.
  - field 1 {time:  2} with Nodal location, 3 components and 2 entities.
 

FieldsContainer2 
 DPF  Fields Container
  with 2 field(s)
  defined on labels: time 

  with:
  - field 0 {time:  1} with Nodal location, 3 components and 2 entities.
  - field 1 {time:  2} with Nodal location, 3 components and 2 entities.
 

Effect of the scoping#

The scoping of a DPF field stores information about which entity the data is associated to. A scalar field containing data for three entities is, for example, linked to a scoping defining three entity IDs. The location of the scoping defines the type of entity the IDs refer to. This allows DPF to know what each data point of a field is associated to.

Operators such as mathematical operators usually perform operations between corresponding entities of fields.

For example, the addition of two scalar fields does not just add the two data arrays, which may not be of the same length or may not be ordered the same way. Instead it uses the scoping of each field to find corresponding entities, their data in each field, and perform the addition on those.

This means that the operation is usually performed for entities in the intersection of the two field scopings.

Some operators provide options to handle data for entities outside of this intersection, but most simply ignore the data for these entities not in the intersection of the scopings.

The following examples illustrate this behavior.

# Instantiate two nodal 3D vector fields of length 3
field5 = dpf.Field(nentities=3)
field6 = dpf.Field(nentities=3)

# Set the data for each field
field5.data = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]
field6.data = [5.0, 1.0, 6.0, 3.0, 8.0, 9.0, 7.0, 2.0, 4.0]

# Set the scoping IDs (here node IDs)
field5.scoping.ids = [1, 2, 3]
field6.scoping.ids = [3, 4, 5]

# Print the fields
print("Field 5", "\n", field5, "\n")
print("Field 6", "\n", field6, "\n")
Field 5 
 DPF  Field
  Location: Nodal
  Unit: 
  3 entities 
  Data: 3 components and 3 elementary data 

  IDs                   data
  ------------          ----------
  1                     1.000000e+00   2.000000e+00   3.000000e+00   
                        
  2                     4.000000e+00   5.000000e+00   6.000000e+00   
                        
  3                     7.000000e+00   8.000000e+00   9.000000e+00   
                        

 

Field 6 
 DPF  Field
  Location: Nodal
  Unit: 
  3 entities 
  Data: 3 components and 3 elementary data 

  IDs                   data
  ------------          ----------
  3                     5.000000e+00   1.000000e+00   6.000000e+00   
                        
  4                     3.000000e+00   8.000000e+00   9.000000e+00   
                        
  5                     7.000000e+00   2.000000e+00   4.000000e+00   
                        

 

Here the only entities with matching IDs between the two fields are:

  • The third entity in field5 (ID=3)

  • The first entity in field6 (ID=3)

Other entities are not taken into account when using an operator that needs two operands.

For example the add operator:

# Use the add operator
add_scop = dpf.operators.math.add(fieldA=field5, fieldB=field6).eval()

# Print the result
# The resulting field only contains data for entities where a match is found in the other field.
# It has the size of the intersection of the two scopings.
# Here this means the addition returns a field with data only for the node with ID=3.
# This behavior is specific to each operator.
print(add_scop, "\n")
DPF  Field
  Location: Nodal
  Unit: 
  5 entities 
  Data: 3 components and 5 elementary data 

  IDs                   data
  ------------          ----------
  1                     1.000000e+00   2.000000e+00   3.000000e+00   
                        
  2                     4.000000e+00   5.000000e+00   6.000000e+00   
                        
  3                     1.200000e+01   9.000000e+00   1.500000e+01   
                        
  ...

 

Or the generalized_inner_product operator:

# Use the dot product operator
dot_scop = dpf.operators.math.generalized_inner_product(fieldA=field5, fieldB=field6).eval()
# ID 3: (7. * 5.) + (8. * 1.) + (9. * 6.)

# Print the result
# The operator returns zero for entities where no match is found in the other field.
# The resulting field is the size of the union of the two scopings.
# This behavior is specific to each operator.
print(dot_scop,"\n")
print(dot_scop.data,"\n")
DPF  Field
  Location: Nodal
  Unit: 
  5 entities 
  Data: 1 components and 5 elementary data 

  IDs                   data
  ------------          ----------
  1                     0.000000e+00   
                        
  2                     0.000000e+00   
                        
  3                     9.700000e+01   
                        
  ...

 

[ 0.  0. 97.  0.  0.] 

Handling of collections#

Most mathematical operators have a separate implementation for handling FieldsContainer objects as input, and are recognizable by the suffix _fc appended to their name.

These operator operate on fields with the same label space.

Using the two collections of fields built previously, both have a time label with an associated value for each field.

Operators working with FieldsContainer inputs match fields from each collection with the same value for all labels.

In this case, field 0 of fc1 with label space {"time": 1} gets matched up with field 0 of fc2 also with label space {"time": 1}. Then field 1 of fc1 with label space {"time": 2} gets matched up with field 1 of fc2 also with label space {"time": 2}.

Addition#

Use:

  • the add operator to compute the element-wise addition for each component of two fields

  • the accumulate operator to compute the overall sum of data for each component of a field

Element-wise addition#

This operator computes the element-wise sum of two fields for each component.

# Add the fields
add_field = maths.add(fieldA=field1, fieldB=field2).eval()
# id 0: [1.+7. 2.+3. 3.+5.] = [ 8.  5.  8.]
# id 1: [4.+8. 5.+1. 6.+2.] = [12.  6.  8.]

# Print the results
print("Addition field ", add_field , "\n")
Addition field  DPF  Field
  Location: Nodal
  Unit: 
  2 entities 
  Data: 3 components and 2 elementary data 

  IDs                   data
  ------------          ----------
  0                     8.000000e+00   5.000000e+00   8.000000e+00   
                        
  1                     1.200000e+01   6.000000e+00   8.000000e+00   
                        

 

# Add the two field collections
add_fc = maths.add_fc(fields_container1=fc1, fields_container2=fc2).eval()
# {time: 1}: field1 + field3
#           -->      id 0: [1.+6. 2.+5. 3.+4.] = [7. 7. 7.]
#                    id 1: [4.+3. 5.+2. 6.+1.] = [7. 7. 7.]
#
# {time: 2}: field2 + field4
#           -->      id 0: [7.+4. 3.+1. 5.+8.] = [11. 4. 13.]
#                    id 1: [8.+5. 1.+7. 2.+9.] = [13. 8. 11.]

# Print the results
print("Addition FieldsContainers","\n", add_fc , "\n")
print(add_fc.get_field({"time":1}), "\n")
print(add_fc.get_field({"time":2}), "\n")
Addition FieldsContainers 
 DPF  Fields Container
  with 2 field(s)
  defined on labels: time 

  with:
  - field 0 {time:  1} with Nodal location, 3 components and 2 entities.
  - field 1 {time:  2} with Nodal location, 3 components and 2 entities.
 

DPF  Field
  Location: Nodal
  Unit: 
  2 entities 
  Data: 3 components and 2 elementary data 

  IDs                   data
  ------------          ----------
  0                     7.000000e+00   7.000000e+00   7.000000e+00   
                        
  1                     7.000000e+00   7.000000e+00   7.000000e+00   
                        

 

DPF  Field
  Location: Nodal
  Unit: 
  2 entities 
  Data: 3 components and 2 elementary data 

  IDs                   data
  ------------          ----------
  0                     1.100000e+01   4.000000e+00   1.300000e+01   
                        
  1                     1.300000e+01   8.000000e+00   1.100000e+01   
                        

 

Overall sum#

This operator computes the total sum of elementary data of a field, for each component of the field. You can give a scaling (“weights”) argument.

Keep in mind the Field dimension. The Field represents 3D vectors, so each elementary data is a 3D vector. The optional “weights” Field attribute is a scaling factor for each entity when performing the sum, so you must provide a 1D field.

Compute the total sum (accumulate) for each component of a given Field.

# Compute the total sum of a field
tot_sum_field = maths.accumulate(fieldA=field1).eval()
# vector component 0 = 1. + 4. = 5.
# vector component 1 = 2. + 5. = 7.
# vector component 2 = 3. + 6. = 9.

# Print the results
print("Total sum fields","\n", tot_sum_field, "\n")
Total sum fields 
 DPF  Field
  Location: overall
  Unit: 
  1 entities 
  Data: 3 components and 1 elementary data 

  overall
  IDs                   data
  ------------          ----------
  0                     5.000000e+00   7.000000e+00   9.000000e+00   
                        

 

# Find the total sum of the two field collections
tot_sum_fc = maths.accumulate_fc(fields_container=fc1).eval()
# {time: 1}: field1
#           -->      vector component 0 = 1.+ 4. = 5.
#                    vector component 1 = 2.+ 5. = 7.
#                    vector component 2 = 3.+ 6. = 9.
#
# {time: 2}: field2
#           -->      vector component 0 = 7.+ 8. = 15.
#                    vector component 1 = 3.+ 1. = 4.
#                    vector component 2 = 5.+ 2. = 7.

# Print the results
print("Total sum FieldsContainers","\n", tot_sum_fc , "\n")
print(tot_sum_fc.get_field({"time":1}), "\n")
print(tot_sum_fc.get_field({"time":2}), "\n")
Total sum FieldsContainers 
 DPF  Fields Container
  with 2 field(s)
  defined on labels: time 

  with:
  - field 0 {time:  1} with overall location, 3 components and 1 entities.
  - field 1 {time:  2} with overall location, 3 components and 1 entities.
 

DPF  Field
  Location: overall
  Unit: 
  1 entities 
  Data: 3 components and 1 elementary data 

  overall
  IDs                   data
  ------------          ----------
  0                     5.000000e+00   7.000000e+00   9.000000e+00   
                        

 

DPF  Field
  Location: overall
  Unit: 
  1 entities 
  Data: 3 components and 1 elementary data 

  overall
  IDs                   data
  ------------          ----------
  0                     1.500000e+01   4.000000e+00   7.000000e+00   
                        

 

Compute the total sum (accumulate) for each component of a given Field using a scale factor field.

# Define the scale factor field
scale_vect = dpf.Field(nentities=num_entities, nature=dpf.natures.scalar)
# Set the scale factor field scoping IDs
scale_vect.scoping.ids = range(num_entities)
# Set the scale factor field data
scale_vect.data = [5., 2.]

# Compute the total sum of the field using a scaling field
tot_sum_field_scale = maths.accumulate(fieldA=field1, weights=scale_vect).eval()
# vector component 0 = (1.0 * 5.0) + (4.0 * 2.0) = 13.
# vector component 1 = (2.0 * 5.0) + (5.0 * 2.0) = 20.
# vector component 2 = (3.0 * 5.0) + (6.0 * 2.0) = 27.

# Print the results
print("Total weighted sum:","\n", tot_sum_field_scale, "\n")
Total weighted sum: 
 DPF  Field
  Location: overall
  Unit: 
  1 entities 
  Data: 3 components and 1 elementary data 

  overall
  IDs                   data
  ------------          ----------
  0                     1.300000e+01   2.000000e+01   2.700000e+01   
                        

 

# Total scaled sum of the two field collections (accumulate)
tot_sum_fc_scale = maths.accumulate_fc(fields_container=fc1, weights=scale_vect).eval()
# {time: 1}: field1
#           -->      vector component 0 = (1.0 * 5.0) + (4.0 * 2.0) = 13.
#                    vector component 1 = (2.0 * 5.0) + (5.0 * 2.0) = 20.
#                    vector component 2 = (3.0 * 5.0) + (6.0 * 2.0) = 27.
#
# {time: 2}: field2
#           -->      vector component 0 = (7.0 * 5.0) + (8.0 * 2.0) = 51.
#                    vector component 1 = (3.0 * 5.0) + (1.0 * 2.0) = 17.
#                    vector component 2 = (5.0 * 5.0) + (2.0 * 2.0) = 29.

# Print the results
print("Total sum FieldsContainers scale","\n", tot_sum_fc_scale , "\n")
print(tot_sum_fc_scale.get_field({"time":1}), "\n")
print(tot_sum_fc_scale.get_field({"time":2}), "\n")
Total sum FieldsContainers scale 
 DPF  Fields Container
  with 2 field(s)
  defined on labels: time 

  with:
  - field 0 {time:  1} with overall location, 3 components and 1 entities.
  - field 1 {time:  2} with overall location, 3 components and 1 entities.
 

DPF  Field
  Location: overall
  Unit: 
  1 entities 
  Data: 3 components and 1 elementary data 

  overall
  IDs                   data
  ------------          ----------
  0                     1.300000e+01   2.000000e+01   2.700000e+01   
                        

 

DPF  Field
  Location: overall
  Unit: 
  1 entities 
  Data: 3 components and 1 elementary data 

  overall
  IDs                   data
  ------------          ----------
  0                     5.100000e+01   1.700000e+01   2.900000e+01   
                        

 

Subtraction#

Use the minus operator to compute the element-wise difference between each component of two fields.

# Subtraction of two 3D vector fields
minus_field = maths.minus(fieldA=field1, fieldB=field2).eval()
# id 0: [1.-7. 2.-3. 3.-5.] = [-6. -1. -2.]
# id 1: [4.-8. 5.-1. 6.-2.] = [-4. 4. 4.]

# Print the results
print("Subtraction field","\n", minus_field , "\n")
Subtraction field 
 DPF  Field
  Location: Nodal
  Unit: 
  2 entities 
  Data: 3 components and 2 elementary data 

  IDs                   data
  ------------          ----------
  0                     -6.000000e+00  -1.000000e+00  -2.000000e+00  
                        
  1                     -4.000000e+00  4.000000e+00   4.000000e+00   
                        

 

# Subtraction of two field collections
minus_fc = maths.minus_fc(
    field_or_fields_container_A=fc1,
    field_or_fields_container_B=fc2
).eval()
# {time: 1}: field1 - field3
#           -->      id 0: [1.-6. 2.-5. 3.-4.] = [-5. -3. -1.]
#                    id 1: [4.-3. 5.-2. 6.-1.] = [1. 3. 5.]
#
# {time: 2}: field2 - field4
#           -->      id 0: [7.-4. 3.-1. 5.-8.] = [3. 2. -3.]
#                    id 1: [8.-5. 1.-7. 2.-9.] = [3. -6. -7.]

# Print the results
print("Subtraction field collection","\n", minus_fc , "\n")
print(minus_fc.get_field({"time":1}), "\n")
print(minus_fc.get_field({"time":2}), "\n")
Subtraction field collection 
 DPF  Fields Container
  with 2 field(s)
  defined on labels: time 

  with:
  - field 0 {time:  1} with Nodal location, 3 components and 2 entities.
  - field 1 {time:  2} with Nodal location, 3 components and 2 entities.
 

DPF  Field
  Location: Nodal
  Unit: 
  2 entities 
  Data: 3 components and 2 elementary data 

  IDs                   data
  ------------          ----------
  0                     -5.000000e+00  -3.000000e+00  -1.000000e+00  
                        
  1                     1.000000e+00   3.000000e+00   5.000000e+00   
                        

 

DPF  Field
  Location: Nodal
  Unit: 
  2 entities 
  Data: 3 components and 2 elementary data 

  IDs                   data
  ------------          ----------
  0                     3.000000e+00   2.000000e+00   -3.000000e+00  
                        
  1                     3.000000e+00   -6.000000e+00  -7.000000e+00  
                        

 

Element-wise product#

Use the component_wise_product operator to compute the element-wise product between each component of two fields. Also known as the Hadamard product, the entrywise product or Schur product.

# Compute the Hadamard product of two fields
element_prod_field = maths.component_wise_product(fieldA=field1, fieldB=field2).eval()
# id 0: [1.*7. 2.*3. 3.*5.] = [7. 6. 15.]
# id 1: [4.*8. 5.*1. 6.*2.] = [32. 5. 12.]

# Print the results
print("Element-wise product field","\n", element_prod_field , "\n")
Element-wise product field 
 DPF  Field
  Location: Nodal
  Unit: 
  2 entities 
  Data: 3 components and 2 elementary data 

  IDs                   data
  ------------          ----------
  0                     7.000000e+00   6.000000e+00   1.500000e+01   
                        
  1                     3.200000e+01   5.000000e+00   1.200000e+01   
                        

 

The current implementation of component_wise_product_fc only performs the Hadamard product for each field in a collection with a distinct unique field.

The element-wise product between two field collections is not implemented.

# Cross product of each field in a collection and a single unique field
element_prod_fc = maths.component_wise_product_fc(fields_container=fc1, fieldB=field3).eval()
# {time: 1}: field1 and field3
#           -->      id 0: [1.*6. 2.*5. 3.*4.] = [6. 10. 12.]
#                    id 1: [4.*3. 5.*2. 6.*1.] = [12. 10. 6.]
#
# {time: 2}: field2 and field3
#           -->      id 0: [7.*6. 3.*5. 5.*4.] = [42. 15. 20.]
#                    id 1: [8.*3. 1.*2. 2.*1.] = [24. 2. 2.]

# Print the results
print("Element product FieldsContainer","\n", element_prod_fc , "\n")
print(element_prod_fc.get_field({"time":1}), "\n")
print(element_prod_fc.get_field({"time":2}), "\n")
Element product FieldsContainer 
 DPF  Fields Container
  with 2 field(s)
  defined on labels: time 

  with:
  - field 0 {time:  1} with Nodal location, 3 components and 2 entities.
  - field 1 {time:  2} with Nodal location, 3 components and 2 entities.
 

DPF  Field
  Location: Nodal
  Unit: 
  2 entities 
  Data: 3 components and 2 elementary data 

  IDs                   data
  ------------          ----------
  0                     6.000000e+00   1.000000e+01   1.200000e+01   
                        
  1                     1.200000e+01   1.000000e+01   6.000000e+00   
                        

 

DPF  Field
  Location: Nodal
  Unit: 
  2 entities 
  Data: 3 components and 2 elementary data 

  IDs                   data
  ------------          ----------
  0                     4.200000e+01   1.500000e+01   2.000000e+01   
                        
  1                     2.400000e+01   2.000000e+00   2.000000e+00   
                        

 

Cross product#

Use the cross_product operator to compute the cross product between two vector fields.

# Compute the cross product
cross_prod_field = maths.cross_product(fieldA=field1, fieldB=field2).eval()
# id 0: [(2.*5. - 3.*3.)  (3.*7. - 1.*5.)  (1.*3. - 2.*7.)] = [1. 16. -11.]
# id 1: [(5.*2. - 6.*1.)  (6.*8. - 4.*2.)  (4.*1. - 5.*8.)] = [4. 40. -36.]

# Print the results
print("Cross product field","\n", cross_prod_field , "\n")
Cross product field 
 DPF  Field
  Location: Nodal
  Unit: 
  2 entities 
  Data: 3 components and 2 elementary data 

  IDs                   data
  ------------          ----------
  0                     1.000000e+00   1.600000e+01   -1.100000e+01  
                        
  1                     4.000000e+00   4.000000e+01   -3.600000e+01  
                        

 

# Cross product of two field collections
cross_prod_fc = maths.cross_product_fc(field_or_fields_container_A=fc1,field_or_fields_container_B=fc2).eval()
# {time: 1}: field1 X field3
#           -->      id 0: [(2.*4. - 3.*5.)  (3.*6. - 1.*4.)  (1.*5. - 2.*6.)] = [-7. 14. -7.]
#                    id 1: [(5.*1. - 6.*2.)  (6.*3. - 4.*1.)  (4.*2. - 5.*3.)] = [-7. 14. -7.]
#
# {time: 2}: field2 X field4
#           -->      id 0: [(3.*8. - 5.*1.)  (5.*4. - 7.*8.)  (7.*1. - 3.*4.)] = [19. -36. -5]
#                    id 1: [(1.*9. - 2.*7.)  (2.*5. - 8.*9.)  (8.*7. - 1.*5.)] = [-5. -62. 51.]

# Print the results
print("Cross product FieldsContainer","\n", cross_prod_fc , "\n")
print(cross_prod_fc.get_field({"time":1}), "\n")
print(cross_prod_fc.get_field({"time":2}), "\n")
Cross product FieldsContainer 
 DPF  Fields Container
  with 2 field(s)
  defined on labels: time 

  with:
  - field 0 {time:  1} with Nodal location, 3 components and 2 entities.
  - field 1 {time:  2} with Nodal location, 3 components and 2 entities.
 

DPF  Field
  Location: Nodal
  Unit: 
  2 entities 
  Data: 3 components and 2 elementary data 

  IDs                   data
  ------------          ----------
  0                     -7.000000e+00  1.400000e+01   -7.000000e+00  
                        
  1                     -7.000000e+00  1.400000e+01   -7.000000e+00  
                        

 

DPF  Field
  Location: Nodal
  Unit: 
  2 entities 
  Data: 3 components and 2 elementary data 

  IDs                   data
  ------------          ----------
  0                     1.900000e+01   -3.600000e+01  -5.000000e+00  
                        
  1                     -5.000000e+00  -6.200000e+01  5.100000e+01   
                        

 

Dot product#

Here, DPF provides two operations:

  • Use the generalized_inner_product operator to compute the inner product (also known as dot product or scalar product) between vector data of entities in two fields

  • Use the overall_dot operator to compute the sum over all entities of the inner product of two vector fields

Inner product#

The generalized_inner_product operator computes a general notion of inner product between two vector fields. In Cartesian coordinates it is equivalent to the dot/scalar product.

# Generalized inner product of two fields
dot_prod_field = maths.generalized_inner_product(fieldA=field1, fieldB=field2).eval()
# id 0: (1. * 7.) + (2. * 3.) + (3. * 5.) = 28.
# id 1: (4. * 8.) + (5. * 1.) + (6. * 2.) = 49.

# Print the results
print("Dot product field","\n", dot_prod_field , "\n")
Dot product field 
 DPF  Field
  Location: Nodal
  Unit: 
  2 entities 
  Data: 1 components and 2 elementary data 

  IDs                   data
  ------------          ----------
  0                     2.800000e+01   
                        
  1                     4.900000e+01   
                        

 

# Generalized inner product of two field collections
dot_prod_fc = maths.generalized_inner_product_fc(field_or_fields_container_A=fc1, field_or_fields_container_B=fc2).eval()
# {time: 1}: field1 X field3
#           -->      id 0: (1. * 6.) + (2. * 5.) + (3. * 4.) = 28.
#                    id 1: (4. * 3.) + (5. * 2.) + (6. * 1.) = 28.
#
# {time: 2}: field2 X field4
#           -->      id 0: (7. * 4.) + (3. * 1.) + (5. * 8.) = 71.
#                    id 1: (8. * 5.) + (1. * 7.) + (2. * 9.) = 65.

# Print the results
print("Dot product FieldsContainer","\n", dot_prod_fc , "\n")
print(dot_prod_fc.get_field({"time":1}), "\n")
print(dot_prod_fc.get_field({"time":2}), "\n")
Dot product FieldsContainer 
 DPF  Fields Container
  with 2 field(s)
  defined on labels: time 

  with:
  - field 0 {time:  1} with Nodal location, 1 components and 2 entities.
  - field 1 {time:  2} with Nodal location, 1 components and 2 entities.
 

DPF  Field
  Location: Nodal
  Unit: 
  2 entities 
  Data: 1 components and 2 elementary data 

  IDs                   data
  ------------          ----------
  0                     2.800000e+01   
                        
  1                     2.800000e+01   
                        

 

DPF  Field
  Location: Nodal
  Unit: 
  2 entities 
  Data: 1 components and 2 elementary data 

  IDs                   data
  ------------          ----------
  0                     7.100000e+01   
                        
  1                     6.500000e+01   
                        

 

Overall dot product#

The overall_dot operator creates two manipulations to give the result:

  1. it first computes a dot product between data of corresponding entities for two vector fields, resulting in a scalar field

  2. it then sums the result obtained previously over all entities to return a scalar

# Overall dot product of two fields
overall_dot = maths.overall_dot(fieldA=field1, fieldB=field2).eval()
# id 1: (1. * 7.) + (2. * 3.) + (3. * 5.) + (4. * 8.) + (5. * 1.) + (6. * 2.) = 77.

# Print the results
print("Overall dot","\n", overall_dot , "\n")
Overall dot 
 DPF  Field
  Location: overall
  Unit: 
  1 entities 
  Data: 1 components and 1 elementary data 

  IDs                   data
  ------------          ----------
  1                     7.700000e+01   
                        

 

The overall_dot_fc operator is not available.

Division#

Use the component_wise_divide operator to compute the Hadamard division between each component of two fields.

# Divide a field by another field
comp_wise_div = maths.component_wise_divide(fieldA=field1, fieldB=field2).eval()
# id 0: [1./7. 2./3. 3./5.] = [0.143 0.667 0.6]
# id 1: [4./8. 5./1. 6./2.] = [0.5 5. 3.]

# Print the results
print("Component-wise division field","\n", comp_wise_div , "\n")
Component-wise division field 
 DPF  Field
  Location: Nodal
  Unit: 
  2 entities 
  Data: 3 components and 2 elementary data 

  IDs                   data
  ------------          ----------
  0                     1.428571e-01   6.666667e-01   6.000000e-01   
                        
  1                     5.000000e-01   5.000000e+00   3.000000e+00   
                        

 

# Component-wise division between two field collections
comp_wise_div_fc = maths.component_wise_divide_fc(fields_containerA=fc1, fields_containerB=fc2).eval()
# {time: 1}: field1 - field3
#           -->      id 0: [1./6. 2./5. 3./4.] = [0.167 0.4 0.75]
#                    id 1: [4./3. 5./2. 6./1.] = [1.333 2.5 6.]
#
# {time: 2}: field2 - field4
#           -->      id 0: [7./4. 3./1. 5./8.] = [1.75 3. 0.625]
#                    id 1: [8./5. 1./7. 2./9.] = [1.6 0.143 0.222]

# Print the results
print("Component-wise division FieldsContainer","\n", comp_wise_div_fc , "\n")
print(comp_wise_div_fc.get_field({"time":1}), "\n")
print(comp_wise_div_fc.get_field({"time":2}), "\n")
Component-wise division FieldsContainer 
 DPF  Fields Container
  with 2 field(s)
  defined on labels: time 

  with:
  - field 0 {time:  1} with Nodal location, 3 components and 2 entities.
  - field 1 {time:  2} with Nodal location, 3 components and 2 entities.
 

DPF  Field
  Location: Nodal
  Unit: 
  2 entities 
  Data: 3 components and 2 elementary data 

  IDs                   data
  ------------          ----------
  0                     1.666667e-01   4.000000e-01   7.500000e-01   
                        
  1                     1.333333e+00   2.500000e+00   6.000000e+00   
                        

 

DPF  Field
  Location: Nodal
  Unit: 
  2 entities 
  Data: 3 components and 2 elementary data 

  IDs                   data
  ------------          ----------
  0                     1.750000e+00   3.000000e+00   6.250000e-01   
                        
  1                     1.600000e+00   1.428571e-01   2.222222e-01   
                        

 

Power#

Use:

pow operator#

The pow operator computes the element-wise power of each component of a Field to a given factor.

This example computes the power of three.

# Define the power factor
pow_factor = 3.0
# Compute the power of three of a field
pow_field = maths.pow(field=field1, factor=pow_factor).eval()
# id 0: [(1.^3.) (2.^3.) (3.^3.)] = [1. 8. 27.]
# id 1: [(4.^3.) (5.^3.) (6.^3.)] = [64. 125. 216.]

# Print the results
print("Power field","\n", pow_field , "\n")
Power field 
 DPF  Field
  Location: Nodal
  Unit: 
  2 entities 
  Data: 3 components and 2 elementary data 

  IDs                   data
  ------------          ----------
  0                     1.000000e+00   8.000000e+00   2.700000e+01   
                        
  1                     6.400000e+01   1.250000e+02   2.160000e+02   
                        

 

# Compute the power of three of a field collection
pow_fc = maths.pow_fc(fields_container=fc1, factor=pow_factor).eval()
# {time: 1}: field1
#           -->      id 0: [(1.^3.) (2.^3.) (3.^3.)] = [1. 8. 27.]
#                    id 1: [(4.^3.) (5.^3.) (6.^3.)] = [64. 125. 216.]
#
# {time: 2}: field2
#           -->      id 0: [(7.^3.) (3.^3.) (5.^3.)] = [343. 27. 125.]
#                    id 1: [(8.^3.) (1.^3.) (2.^3.)] = [512. 1. 8.]

# Print the results
print("Power FieldsContainer","\n", pow_fc , "\n")
print(pow_fc.get_field({"time":1}), "\n")
print(pow_fc.get_field({"time":2}), "\n")
Power FieldsContainer 
 DPF  Fields Container
  with 2 field(s)
  defined on labels: time 

  with:
  - field 0 {time:  1} with Nodal location, 3 components and 2 entities.
  - field 1 {time:  2} with Nodal location, 3 components and 2 entities.
 

DPF  Field
  Location: Nodal
  Unit: 
  2 entities 
  Data: 3 components and 2 elementary data 

  IDs                   data
  ------------          ----------
  0                     1.000000e+00   8.000000e+00   2.700000e+01   
                        
  1                     6.400000e+01   1.250000e+02   2.160000e+02   
                        

 

DPF  Field
  Location: Nodal
  Unit: 
  2 entities 
  Data: 3 components and 2 elementary data 

  IDs                   data
  ------------          ----------
  0                     3.430000e+02   2.700000e+01   1.250000e+02   
                        
  1                     5.120000e+02   1.000000e+00   8.000000e+00   
                        

 

sqr operator#

The sqr operator computes the element-wise power of two (Hadamard power) for each component of a Field. It is a shortcut for the pow operator with factor 2.

# Compute the power of two of a field
sqr_field = maths.sqr(field=field1).eval()
# id 0: [(1.^2.) (2.^2.) (3.^2.)] = [1. 4. 9.]
# id 1: [(4.^2.) (5.^2.) (6.^2.)] = [16. 25. 36.]

print("^2 field","\n", sqr_field , "\n")
^2 field 
 DPF  Field
  Location: Nodal
  Unit: 
  2 entities 
  Data: 3 components and 2 elementary data 

  IDs                   data
  ------------          ----------
  0                     1.000000e+00   4.000000e+00   9.000000e+00   
                        
  1                     1.600000e+01   2.500000e+01   3.600000e+01   
                        

 

# Compute the power of two of a field collection
sqr_fc = maths.sqr_fc(fields_container=fc1).eval()
# {time: 1}: field1
#           -->      id 0: [(1.^2.) (2.^2.) (3.^2.)] = [1. 4. 9.]
#                    id 1: [(4.^2.) (5.^2.) (6.^2.)] = [16. 25. 36.]
#
# {time: 2}: field2
#           -->      id 0: [(7.^2.) (3.^2.) (5.^2.)] = [49. 9. 25.]
#                    id 1: [(8.^2.) (1.^2.) (2.^2.)] = [64. 1. 4.]

# Print the results
print("^2 FieldsContainer","\n", sqr_fc , "\n")
print(sqr_fc.get_field({"time":1}), "\n")
print(sqr_fc.get_field({"time":2}), "\n")
^2 FieldsContainer 
 DPF  Fields Container
  with 2 field(s)
  defined on labels: time 

  with:
  - field 0 {time:  1} with Nodal location, 3 components and 2 entities.
  - field 1 {time:  2} with Nodal location, 3 components and 2 entities.
 

DPF  Field
  Location: Nodal
  Unit: 
  2 entities 
  Data: 3 components and 2 elementary data 

  IDs                   data
  ------------          ----------
  0                     1.000000e+00   4.000000e+00   9.000000e+00   
                        
  1                     1.600000e+01   2.500000e+01   3.600000e+01   
                        

 

DPF  Field
  Location: Nodal
  Unit: 
  2 entities 
  Data: 3 components and 2 elementary data 

  IDs                   data
  ------------          ----------
  0                     4.900000e+01   9.000000e+00   2.500000e+01   
                        
  1                     6.400000e+01   1.000000e+00   4.000000e+00   
                        

 

sqrt operator#

The sqr operator computes the element-wise square-root (Hadamard root) for each component of a Field. It is a shortcut for the pow operator with factor 0.5.

# Compute the square-root of a field
sqrt_field = maths.sqrt(field=field1).eval()
# id 0: [(1.^0.5) (2.^0.5) (3.^0.5)] = [1. 1.414 1.732]
# id 1: [(4.^0.5) (5.^0.5) (6.^0.5)] = [2. 2.236 2.449]

print("^0.5 field","\n", sqrt_field , "\n")
^0.5 field 
 DPF  Field
  Location: Nodal
  Unit: 
  2 entities 
  Data: 3 components and 2 elementary data 

  IDs                   data
  ------------          ----------
  0                     1.000000e+00   1.414214e+00   1.732051e+00   
                        
  1                     2.000000e+00   2.236068e+00   2.449490e+00   
                        

 

# Compute the square-root of a field collection
sqrt_fc = maths.sqrt_fc(fields_container=fc1).eval()
# {time: 1}: field1
#           -->      id 0: [(1.^.5) (2.^.5) (3.^.5)] = [1. 1.414 1.732]
#                    id 1: [(4.^.5) (5.^.5) (6.^.5)] = [2. 2.236 2.449]
#
# {time: 2}: field2
#           -->      id 0: [(7.^.5) (3.^.5) (5.^.5)] = [2.645 1.732 2.236]
#                    id 1: [(8.^.5) (1.^.5) (2.^.5)] = [2.828 1. 1.414]

# Print the results
print("Sqrt FieldsContainer","\n", sqrt_fc , "\n")
print(sqrt_fc.get_field({"time":1}), "\n")
print(sqrt_fc.get_field({"time":2}), "\n")
Sqrt FieldsContainer 
 DPF  Fields Container
  with 2 field(s)
  defined on labels: time 

  with:
  - field 0 {time:  1} with Nodal location, 3 components and 2 entities.
  - field 1 {time:  2} with Nodal location, 3 components and 2 entities.
 

DPF  Field
  Location: Nodal
  Unit: 
  2 entities 
  Data: 3 components and 2 elementary data 

  IDs                   data
  ------------          ----------
  0                     1.000000e+00   1.414214e+00   1.732051e+00   
                        
  1                     2.000000e+00   2.236068e+00   2.449490e+00   
                        

 

DPF  Field
  Location: Nodal
  Unit: 
  2 entities 
  Data: 3 components and 2 elementary data 

  IDs                   data
  ------------          ----------
  0                     2.645751e+00   1.732051e+00   2.236068e+00   
                        
  1                     2.828427e+00   1.000000e+00   1.414214e+00   
                        

 

Norm#

Use the norm operator to compute the Lp norm of the elementary data for each entity of a Field.

The default Lp norm is Lp=L2.

# Compute the L2 norm of a field
norm_field = maths.norm(field=field1, scalar_int=2).eval()
# id 0: [(1.^2.) + (2.^2.) + (3.^2.)] ^1/2 = 3.742
# id 1: [(4.^2.) + (5.^2.) + (6.^2.)] ^1/2 = 8.775

# Print the results
print("Norm field","\n", norm_field , "\n")
Norm field 
 DPF  Field
  Location: Nodal
  Unit: 
  2 entities 
  Data: 1 components and 2 elementary data 

  IDs                   data
  ------------          ----------
  0                     3.741657e+00   
                        
  1                     8.774964e+00   
                        

 

# Define the L2 norm of a field collection
norm_fc = maths.norm_fc(fields_container=fc1).eval()
# {time: 1}: field1
#           -->      id 0: [(1.^2.) + (2.^2.) + (3.^2.)] ^1/2 = 3.742
#                    id 1: [(4.^2.) + (5.^2.) + (6.^2.)] ^1/2 = 8.775
#
# {time: 2}: field2
#           -->      id 0: [(7.^2.) + (3.^2.) + (5.^2.)] ^1/2 = 9.110
#                    id 1: [(8.^2.) + (1.^2.) + (2.^2.)] ^1/2 = 8.307

# Print the results
print("Norm FieldsContainer","\n", norm_fc , "\n")
print(norm_fc.get_field({"time":1}), "\n")
print(norm_fc.get_field({"time":2}), "\n")
Norm FieldsContainer
 
 
DPF  Fields Container
  with 2 field(s)
  defined on labels: time 

  with:
  - field 0 {time:  1} with Nodal location, 1 components and 2 entities.
  - field 1 {time:  2} with Nodal location, 1 components and 2 entities.
 

DPF  Field
  Location: Nodal
  Unit: 
  2 entities 
  Data: 1 components and 2 elementary data 

  IDs                   data
  ------------          ----------
  0                     3.741657e+00   
                        
  1                     8.774964e+00   
                        

 

DPF  Field
  Location: Nodal
  Unit: 
  2 entities 
  Data: 1 components and 2 elementary data 

  IDs                   data
  ------------          ----------
  0                     9.110434e+00   
                        
  1                     8.306624e+00