OOF2: The Manual

Name

Field — Base class for fields

Synopses

Only those methods useful when extending OOF2 are listed here.

C++ Synopsis

#include "engine/field.h"
class Field {
  const std::string& name() const;
  int ndof() const;
  bool is_defined(const CSubProblem* subproblem) const;
  bool is_active(const CSubProblem* subproblem) const;
  virtual DegreeOfFreedom* operator()(const FuncNode* node,
                                      int component) const;

  virtual DegreeOfFreedom* operator()(const ElementFuncNodeIterator& node,
                                      int component) const;

  DegreeOfFreedom* operator()(const FuncNode& node,
                              int component) const;

  DegreeOfFreedom* operator()(const ElementFuncNodeIterator& node,
                              const IndexP& component) const;

  double value(const FEMesh* mesh,
               const FuncNode* node,
               int component) const;

  double value(const FEmesh* mesh,
               const ElementFuncNodeIterator& node,
               int component) const;

  virtual double value(const FEmesh* mesh,
                       const Element* element,
                       const MasterPosition& position,
                       const FieldIndex& component) const;

  virtual double gradient(const FEmesh* mesh,
                          const Element* element,
                          const MasterPosition& position,
                          const FieldIndex& component,
                          SpaceIndex index) const;

  virtual ArithmeticOutputValue output(const FEMesh* mesh,
                                       const ElementFuncNodeIterator& node) const;

  virtual ArithmeticOutputValue output(const FEMesh* mesh,
                                       const FuncNode& node) const;

  virtual Components* components(Planarity planarity= ALL_INDICES) const;
  virtual Components* outOfPlaneComponents() const;
  virtual FieldIndex* getIndex(const std::string& name) const;
}

Python Synopsis

from ooflib.SWIG.engine.field import Field
class Field:
  def ndof(self)
  def is_defined(self, mesh)
  def is_active(self, mesh)
  def value(self, mesh, node, component)
  def components(self, planarity= ALL_INDICES)
  def outOfPlaneComponents(self)
  def getIndex(self, name)

Source Files

  • SRC/engine/field.h: C++ header
  • SRC/engine/field.C: C++ code
  • SRC/engine/field.swg: SWIG source code
  • SRC/engine/field.spy: python code included in field.swg.

Description

Field is an abstract base class for all types of fields in OOF2. The role of fields is described in Section 2.5.3. Like Fluxes and Equations, Field instances are global objects — there is one instance for each physical field and it is shared by all Meshes that use it. Fields store information about the physical field (such as its name and dimension), but do not store the actual values of the Field. That's done by a Mesh, by using bookkeeping data from a Field.

Most of the programming interface for Fields is defined in the base class, which is an abstract C++ class. Most of the API is available from both C++ and Python.

Most of the Field objects encountered by OOF2 users and extenders are actually instances of the CompoundField class, which groups the in-plane and out-of-plane parts of a Field, along with their time derivatives, all of which are Fields themselves.

Field objects should only be created by calling the Python constructors of the CompoundField subclasses. See CompoundField for the details. After a Field has been created, it can be retrieved in C++ or Python via the getField function. It is not necessary to keep an explicit Python reference to a newly created Field. For convenience in scripts, a variable with the Field's name referring to the Field is defined in the main OOF2 namespace, which is aslo used in text mode and the Console Window.

Several methods are available for computing the values of Fields at points within an FEMesh.

  • Various versions of Field::value() return the value of a component of a Field at a given Node.

  • Versions of Field::value() with Element and position arguments return the value of a field component interpolated within the given Element.

  • Field::value() returns the value of a Field component at an arbitrary position within an Element. ScalarField has a version that doesn't require a component argument.

  • Each concrete non-scalar subclass of Field has a values() method that returns all of the Field components at an arbitrary point within an Element, and a gradients() method that returns the gradient components. These non-virtual methods return different types of objects for different types of Fields.

  • The virtual Field::output() methods return generic Output objects meant for transferring data and modifying it for output, although they can be useful in other situations.

  • Various forms of Field::operator() return a pointer to the low-level DegreeOfFreedom objects that store Field values in an FEMesh.

See the documentation of each subclass for the details.

Methods

std::string& name() const

name() returns the name assigned to the Field when it was created.

int ndof() const

ndof() returns the number of degrees of freedom in the Field. This is the number of data values that must be allocated to store the Field at each Node of the Mesh. For CompoundFields, ndof returns the size of the in-plane part.

bool is_defined(const CSubProblem* subp) const

is_defined() indicates whether the Field has been defined on the given CSubProblem. Defined Fields have been assigned values on Nodes.

bool is_active(const CSubProblem *subp) const

is_active() indicates whether the Field has been activated on the given CSubProblem. Active Fields are being solved for.

DegreeOfFreedom* operator()(...) const

DegreeOfFreedom* operator()(const FuncNode*, int component) const;
DegreeOfFreedom* operator()(const FuncNode&, int component) const;
DegreeOfFreedom* operator()(const ElementFuncNodeIterator&, int component) const;
DegreeOfFreedom* operator()(const ElementFuncNodeIterator&, const IndexP&) const; 

This family of methods are all ways of obtaining the value of a Field at a given FuncNode. (FuncNode is the subclass of Node for Nodes that store Field data.) The different methods are provided for convenience, to allow different representations of Nodes or Field components. All of these methods return a pointer to a DegreeOfFreedom object, which wraps the actual Field component value and is stored at the Node.

DegreeOfFreedoms are low-level, fairly primitive objects, so these methods cannot be used to extract aggregate values, such as all of the components of a multicomponent Field. To do that, or to interpolate a Field value at an arbitrary point within an Element, see Field::value() or Field::output().

double value(...) const

double value(const FEMesh*, const FuncNode*, int component) const;
double value(const FEMesh*, const ElementFuncNodeIterator&, int component) const;
double value(const FEMesh*, const Element*, const MasterPosition&, const FieldIndex& component) const; 

The first two forms of value() evaluate a component of a Field at a Node. In C++, the given node must be a FuncNode pointer or a ElementFuncNodeIterator reference. In Python, it must be a FuncNode object.

The third form of value() returns the value of a component of a Field interpolated at an arbitrary point within an Element. The point is given in the Element's master coordinate space. (This version is currently only available in C++.)

double gradient(...) const

double gradient(const FEMesh*, const Element*, const MasterPosition& position,
                const FieldIndex& component, SpaceIndex direction) const; 

gradient() returns the gradient in direction dir of the given component of the Field at the given position inside an Element. The position is given in the Element's master coordinate space. The direction is 0, 1, or 2, for 𝐱^ , 𝐲^ , and 𝐳^ , respectively.

ArithmeticOutputvalue output(...)

ArithmeticOutputValue output(const FEMesh*, const ElementFuncNodeIterator&) const;
ArithmeticOutputValue output(const FEMesh*, const FuncNode&) const; 

These functions return an OutputValue object which wraps an OutputVal object which contains the value of the Field at the given Node. These calls are mostly used as a mechanism for generically transferring Field values to Python when plotting data, but they can also be useful when writing Field-dependent Propertys.

The output functions differ from Field::operator() and Field::value() by returning all of the components of a multi-dimensional Field in one call.

Components* components(Planarity planarity) const;

components() returns a container-like object that can be iterated over to obtain the indices of a Field. The optional Planarity argument determines which Field components are included. If it is omitted, ALL_INDICES is assumed.

For example, in C++ you can write

Field *displacement = Field::getField("Displacement");
for(IndexP index : *displacement->components()) { // ALL_INDICES is implicit
    ...                                           //  Do something with IndexP index
} 

or, equivalently,

Components* comps = Field::getField("Displacement")->components(ALL_INDICES);
for(ComponentIteratorP i=comps->begin(); i!=comps->end(); i++) {
   IndexP index = *i;                        // Dereference ComponentIterator to get IndexP
   ...                                       // Do something with IndexP index
} 

to loop over all components of the displacement field. The equivalent in Python is

for index in displacement.components():
    ...                                       # Do something with FieldIndex index 

Note that the index object returned in C++ is an IndexP, which is a wrapper around a FieldIndex pointer. In Python the wrapping is unnecessary and the index object is a FieldIndex.

See Section 8.4 for an overview, and Components for the details.

Components* outOfPlaneComponents() const;

Like components, outOfPlaneComponents returns a container that can be iterated over. However, iterating only returns the out-of-plane components of the Field.

[Caution] A Possible Source of Confusion

Field::components(OUT_OF_PLANE) and Field::outOfPlaneComponents() are similar but not identical. They both refer to the same components of a Field and iterate over them in the same order. But the first is used to locate the out-of-plane components in a list that contains all of the components, while the second is used to iterate over a list that contains only the out-of-plane components. The difference is illustrated by using the FieldIndex::integer method to examine the list indices of the components.

For example, the out-of-plane part of the Displacement field is a 3-vector, with indices 0, 1, and 2 obtained from its components() method:

>>> list(Displacement.out_of_plane().components())
[VectorFieldIndex(0), VectorFieldIndex(1), VectorFieldIndex(2)]
>>> list(i.integer() for i in Displacement.out_of_plane().components())
[0, 1, 2] 

On the other hand, outOfPlaneComponents() returns only the z component, but gives it integer index 0, because it's the first and only out-of-plane component:

>>> list(Displacement.out_of_plane().outOfPlaneComponents())
[OutOfPlaneVectorFieldIndex(2)]
>>> list(i.integer() for i in Displacement.out_of_plane().outOfPlaneComponents())
[0] 

A similar issue arises with Fluxes.

FieldIndex* getIndex(std::string& name) const;

getIndex() returns a FieldIndex object, given the name of the desired index. Different Field subclasses expect different strings, and return different subclasses of FieldIndex. For example, a TwoVectorField expects the name to be "x" or "y", and returns a VectorFieldIndex.

In C++ the returned value is a pointer to a newly allocated object. The caller is responsible for deleting it. An easy way to do that is to wrap it in an IndexP, which will delete the pointer in the IndexP's destructor:

Field *field = ...;
IndexP index = IndexP(field->getIndex("x"));