-
Notifications
You must be signed in to change notification settings - Fork 79
Old data from the Discontinuous Galerkin page...
This is documentation/design information that was written previously. I don't want to lose it just yet, so stored here. Some/All of this may be invalid;
DoF | DoF definition | ||||||
---|---|---|---|---|---|---|---|
ordinal | subc dim | subc ordinal | subc DoF ord | subc num DoF | ξ | η | ζ |
0 | 0 | 0 | 0 | 1 | -1.0 | -1.0 | 0.0 |
1 | 0 | 1 | 0 | 1 | 1.0 | -1.0 | 0.0 |
2 | 0 | 2 | 0 | 1 | 1.0 | 1.0 | 0.0 |
3 | 0 | 3 | 0 | 1 | -1.0 | 1.0 | 0.0 |
4 | 1 | 0 | 0 | 1 | 0.0 | -1.0 | 0.0 |
5 | 1 | 1 | 0 | 1 | 1.0 | 0.0 | 0.0 |
6 | 1 | 2 | 0 | 1 | 0.0 | 1.0 | 0.0 |
7 | 1 | 3 | 0 | 1 | -1.0 | 0.0 | 0.0 |
8 | 2 | 0 | 0 | 1 | 0.0 | 0.0 | 0.0 |
MAX | maxScDim=2 | maxScOrd=3 | maxDfOrd=0 | - |
- Based on https://docs.trilinos.org/dev/packages/intrepid/doc/html/classIntrepid_1_1Basis.html
-
DoF ordinal
is not stored -- implicit numbering [Range: unlimited] -
subc dim
: dimension of the subcell associated with the specified DoF ordinal -- 0 node, 1 edge, 2 face, 3 volume [Range: 0..3] -
subc ordinal
: ordinal of the subcell relative to its parent cell -- 0..n for each ordinal with the samesubc dim
[Range: <= DoF ordinal] -
subc DoF ordinal
: ordinal of the DoF relative to the subcell -
subc num DoF
: cardinality of the DoF set associated with this subcell. - ξ, η, ζ -- Parametric coordinate location of the DoF (Only first
ndim
values are valid)
-
Entity attribute on an element block:
-
Basis@name
, text [HGRAD_QUAD_C2_FEM in example above] -
Basis@cardinality
, scalar [9 in example above] -
Basis@subc_dim
, vector of sizecardinality
integers -
Basis@subc_ordinal
, vector of sizecardinality
integers -
Basis@subc_dof_ordinal
, vector of sizecardinality
integers -
Basis@subc_num_dof
, vector of sizecardinality
integers -
Basis@xi
, vector of sizecardinality
doubles -
Basis@eta
(if 2D/3D), vector of sizecardinality
doubles -
Basis@zeta
(if 3D), vector of sizecardinality
doubles - Do we need
type
ordegree
or parse from name:-
HCURL_TRI_I1_FEM
-- type=FEM, degree=1 -
HGRAD_WEDGE_C2_FEM
-- type=FEM, degree=2
-
-
As an example, assume HCURL_TRI_I1_FEM
basis being used on an element block of triangles:
int64 connect1(num_el_in_blk1, num_nod_per_el1) ;
connect1:elem_type = "tri4" ; // Current Exodus
connect1:Basis@name = "HCURL_TRI_I1_FEM" ;
connect1:Basis@cardinality = 3 ;
connect1:Basis@subc_dim = 1, 1, 1 ;
connect1:Basis@subc_ordinal = 0, 1, 2 ;
connect1:Basis@subc_dof_ordinal = 0, 0, 0 ;
connect1:Basis@subc_num_dof = 1, 1, 1 ;
connect1:Basis@xi = 0.5, 0.5, 0.0 ;
connect1:Basis@eta = 0.0, 0.5, 0.5 ;
-
Need to support representing fields of size
Basis@cardinality
bynum_element_in_block
at each timestep.- The
Basis@cardinality
will be consistent for a block, but can be different for different blocks.
- The
-
Can also use this concept to store fields at quadrature points?
-
Easiest modification is to store
Basis@cardinality
separate fields as normal element fields.- This has problems of ordering -- which field corresponds to which basis point
- can use convention of field name suffix [0..Basis@cardinality)
- Relates back to the
Basis
entity attributes stored on the element block (or assembly?).- This will give the ordering and the parametric location of the field component within the element.
- This has problems of ordering -- which field corresponds to which basis point
-
There is additional metadata which groups field components together and indicates how fields relate to each other.
-
For example, for a scalar field
Temperature
with basis cardinality 3, we would storeTemperature_0
,Temperature_1
, andTemperature_2
as normal fields.- Each field would have metadata or attribute which indicates the "base name" (Temperature), cardinality, and which component this field is. E.g.,
Temperature_0
would have attributesbase_name: Temperature
,cardinality: 3
,component_index: 0
- Field probably needs a reference to the basis if it is a "basis-type" field...
- The parametric location of this degree of freedom could be determined by referencing the Basis definition on the element block.
- There would be an API function which would return this information for each entity.
- Number of
fields
(Temperature_0, Temperature_1, Temperature_2 would be 1 field) - For each field, return a structure defining:
- Base field name
- Number of components
- Name of each component field in correct order (Is storage allocated by callee, or by api function...)
- Number of
- How are "composite fields" handled -- 3D vector at each basis point or quadrature point:
- A vector field
Velocity
with component fieldsVelocity_X
,Velocity_Y
, andVelocity_Z
- This field exists at each of 3 basis points...
Velocity_X_0
,Velocity_Y_0
,Velocity_Z_0
, ...,Velocity_Z_2
- Does the
Velocity_X_0
field return a component count of 3 or 9 and is the base nameVelocity
orVelocity_X
- If the base name is
Velocity_X
, then there is no place to store an attribute to recover theVelocity
field unless there is additional metadata stored somewhere for that purpose. - Maybe there is something similar to the assembly structure which stores the field hierarchy. Disadvantage is that it needs to be done for each entity, so lots of metadata.
- If the base name is
- A vector field
- Each field would have metadata or attribute which indicates the "base name" (Temperature), cardinality, and which component this field is. E.g.,
# Temperature field on HCURL_TRI_I1_FEM Basis -- Temperature_0, Temperature_1, Temperature_2
double vals_elem_var7eb1(time_step, num_el_in_blk1) ;
vals_elem_var7eb1:name = "Temperature_2" ; // Not sure this is needed since it duplicates existing element variable names...
vals_elem_var7eb1:base_name = "Temperature" ;
vals_elem_var7eb1:component_count = 3 ;
vals_elem_var7eb1:component_index = 2 ;
vals_elem_var7eb1:storage_type = "Basis3" ; // Tensor, SymTensor, Quaternion, Count, Quadrature, ...
vals_elem_var7eb1:storage_type = "EX_BASIS" ; // Alternative with pre-defined types...
# Velocity_X_0, Velocity_Y_0, Velocity_Z_0, Velocity_X_1, ..., Velocity_Z_2
double vals_elem_var7eb1(time_step, num_el_in_blk1) ;
vals_elem_var7eb1:name = "Velocity_X_0" ; // Not sure this should be there since duplicates existing element variable names...
vals_elem_var7eb1:base_name = "Velocity" ;
vals_elem_var7eb1:component_count = 3, 3 ; // First is X,Y,Z second is the 0,1,2
vals_elem_var7eb1:component_index = 0, 0 ; // How do we know composite cardinality (2 in this case)
vals_elem_var7eb1:storage_type = "Vector3D, Basis3" ; // Tensor, SymTensor, Quaternion, Count, Quadrature, ...
vals_elem_var7eb1:storage_type = "EX_VECTOR_3D, EX_BASIS" ; // Alternative with pre-defined types...
There can be an API function which will return the number of "top-level" fields on the entity. (The current API will still return all of the low-level fields and their names). A second API function will return either an array of structures describing each top-level field or an individual top-level field. Structure will be something like:
typedef struct ex_field
{
int offset; // 0-based, gives the offset to the first component in this field in all the fields on this entity
char *field_name; // Memory provided by application or by library?
int component_count[MAX_FIELD_DEPTH];
int storage_type[MAX_FIELD_DEPTH]; // EX_VECTOR_3D, EX_TENSOR33, EX_BASIS, EX_QUADRATURE, EX_USER
} ex_field;
Internally, the exodus library will maintain a mapping which lets it efficiently access the fields corresponding to each component of the "top-level" field.
- This could probably be provided in the
ex_field
struct, but then that would mean the user would have to allocate additional memory for that storage. - The library could build that structure internally and then return a pointer to it for use by the application which would eliminate all memory allocation issues... (This looks like a good idea; investigate further)
- Is there a way to indicate any common fields across different entities (The same top-level field exists on element blocks 1, 3, 5, 9)...
- API Function will permit accessing all data in the field, or a particular component.
- Interleave would be all of each component (all X, all Y, all Z; not x1, y1, z1, x2, y2, z2, ..., xn, yn, zn)
- Could add dimension and units to the ex_field struct. Avoids multiple API functions... (Although API function could just query the internal ex_field storage)
Internals On file open, or lazily, (or via specific API call), the Exodus library could parse all fields on all (or specified) entities and keep that storage internally for faster query from application. The library could then return a pointer to either the entire field data for a specific entity or to a specific entry on that specific entity. The internal storage would use an allocated array of ex_field
structs. This would remove some issues with memory allocation ownership and might make it easier on the client as they don't need to do queries and then memory allocations... Makes it easier to modify the ex_field structure if needed...
API
int ex_get_field_param(int exoid, ex_entity_type obj_type, int obj_id, ex_field *field_data[]); // Get all
int ex_get_field_param(int exoid, ex_entity_type obj_type, int obj_id, int entry, ex_field *field_data); // Get one
void ex_put_field_param(int exoid, ex_entity_type obj_type, int obj_id, int num_entry, ex_field* const field_data[]);
- Note the use of
field
instead ofvar
-- Maybe use that convention to distinguish between new/old API? - If
field_data
is NULL, then just return the count; otherwise setfield_data
to point to exodus internal data. - Returns the number of "high-level" fields on this object.
- Is it an error to mix old/new API (var vs field) on an entity type?
- OK on read, but old api will just have access to scalar fields.
- Predefined symbols
EX_FIELD_VECTOR
orEX_FIELD_VECTOR_3D
that indicate which field is being stored. - Do we need the component count
VECTOR_3D
vsVECTOR
. Can possibly get the information from the component count, but may be ambiguous in the symmetric or anti-symmetric tensor cases. - Probably best to fully specify field names --
EX_VECTOR_3D
- Alternative is to just use strings. Easier to extend, but also ambiguous...
- Need description of what the basis functions are...
- Order may be important (maybe guess from count)
- Describe type for interpolation -- lagrange/bezier/legendre polynomials/
- Describe what this type of function means...
- Example: https://docs.trilinos.org/dev/packages/intrepid/doc/html/classIntrepid_1_1Basis__HCURL__HEX__I1__FEM.html, https://docs.trilinos.org/dev/packages/intrepid/doc/html/classIntrepid_1_1Basis.html, https://docs.trilinos.org/dev/packages/intrepid/doc/html/basis_page.html
- The above is complete, but very verbose
- Each variable (field) has several entries:
double vals_elem_var7eb1(time_step, num_el_in_blk1) ;
vals_elem_var7eb1:name = "Velocity_X_0" ; // Not sure this should be there since duplicates existing element variable names...
vals_elem_var7eb1:base_name = "Velocity" ;
vals_elem_var7eb1:component_count = 3, 3 ; // First is X,Y,Z second is the 0,1,2
vals_elem_var7eb1:component_index = 0, 0 ; // How do we know composite cardinality (2 in this case)
vals_elem_var7eb1:storage_type = "Vector3D, Basis3" ; // Tensor, SymTensor, Quaternion, Count, Quadrature, ...
vals_elem_var7eb1:storage_type = "EX_VECTOR_3D, EX_BASIS" ; // Alternative with pre-defined types...
- Several of these are repeated for each component of each
variable
. For example, if there is a Velocity vector field of type "Basis3", there would be nine individual field components each with the above information (or slight modification)... - Would it be better to leave the variables alone. Keep the CDF representation as it currently exists.
- The element block(s) (for example) would have:
- Basis information would be stored at
global
level - Information about each Basis (or higher-order) variable:
- Base field name "Velocity" in this case
- Storage Type -- Either "Vector3D, Basis3" or
EX_VECTOR_3D, EX_BASIS
- From this information, it is possible to generate the names of the variable components ("Velocity_X_0", "Velocity_Y_0", "Velocity_Z_0", ..., "Velocity_Z_2")
- A non-basis higher-order field would be something like:
- Base field name "Stress"
- Storage Type -- "EX_SYM_TENSOR_3D"
- Optional
COMPONENT_SEPARATOR = "_"
- Basis information would be stored at
This has some advantages and some disadvantages over the scheme above:
- less verbose
- can parse the information once on the element block instead of on each variable
- If a variable is deleted or renamed and the corresponding information on the element block is not modified, will be out of sync
- Although, if a single variable component is deleted in original scheme, would also have problems)
- More disconnected -- information about variables is stored somewhere else instead of on variable itself.
- A
Variable
is the current exodus transient data type. - A
Field
is a collection of 1 or more scalar variables. For example a Field of typeEX_VECTOR_3D
would be a collection of 3 variables. - A
Composite Field
is a Field consisting of 2 or moreFields
. For example, a composite field representing a symmetric stress tensor at each of 8 integration points. - The
nesting
of a Field is the number of Fields in the Composite Field. In the above example, the nesting would be 2; a "normal" Field would have a nesting of 1. - The
component count
is the number of variables contained in a field.- For example, a
EX_VECTOR_3D
(three-dimensional vector) would have a component count of 3. - The tensor at integration point example would have a component count of [6,4] -- 6 components for each symmetric tensor (
EX_SYM_TENSOR_33
) and 4 for the integration points.
- For example, a
- The
component separator
is zero-or-one characters which separate the Field name from the individual component names.- For example, if the separator is
_
, the field name isVelocity
, and the field type isEX_VECTOR_3D
, then the names of the variables that are collected in the field areVelocity_X
,Velocity_Y
, andVelocity_Z
(orVelocity_x
,Velocity_y
, andVelocity_z
) - If the separator is empty (char 0), then the variables would be
VelocityX
,VelocityY
, andVelocityZ
or the lower-case alternative.
- For example, if the separator is
- A
Sequence
field type is a collection ofN
variables with suffices 1..N.- For example, a sequence field
Temperature
of size 4 would collect the variablesTemperature_1
,Temperature_2
,Temperature_3
, andTemperature_4
.
- For example, a sequence field
The following field types are predefined:
Enum | Component Count | Suffices |
---|---|---|
EX_FIELD_TYPE_UNKNOWN | invalid | |
EX_FIELD_TYPE_USER_DEFINED | variable | |
EX_FIELD_TYPE_SEQUENCE | variable | 1, 2, ..., N |
EX_BASIS | specified by basis | 1, 2, 3, ..., N ? |
EX_QUADRATURE | specified by quadrature | 1, 2, 3, ..., N? |
EX_SCALAR | 1 | -none- |
EX_VECTOR_1D | 1 | x |
EX_VECTOR_2D | 2 | x, y |
EX_VECTOR_3D | 3 | x, y, z |
EX_QUATERNION_2D | 2 | s, q |
EX_QUATERNION_3D | 4 | x, y, z, q |
EX_FULL_TENSOR_36 | 9 | xx, yy, zz, xy, yz, zx, yx, zy, xz |
EX_FULL_TENSOR_32 | 5 | xx, yy, zz, xy, yx |
EX_FULL_TENSOR_22 | 4 | xx, yy, xy, yx |
EX_FULL_TENSOR_16 | 7 | xx, xy, yz, zx, yx, zy, xz |
EX_FULL_TENSOR_12 | 3 | xx, xy, yx |
EX_SYM_TENSOR_33 | 6 | xx, yy, zz, xy, yz, zx |
EX_SYM_TENSOR_31 | 4 | xx, yy, zz, xy |
EX_SYM_TENSOR_21 | 3 | xx, yy, xy |
EX_SYM_TENSOR_13 | 4 | xx, xy, yz, zx |
EX_SYM_TENSOR_11 | 2 | xx, xy |
EX_SYM_TENSOR_10 | 1 | xx |
EX_ASYM_TENSOR_03 | 3 | xy, yz, zx |
EX_ASYM_TENSOR_02 | 2 | xy, yz |
EX_ASYM_TENSOR_01 | 1 | xy |
EX_MATRIX_22 | 4 | 11, 12, 21, 22 |
EX_MATRIX_33 | 9 | 11, 12, 13, 21, 22, 23, 31, 32, 33 |
EX_FIELD_TYPE_INVALID | invalid |
As an example, assume HCURL_TRI_I1_FEM
basis being used on an element block of triangles and there are 2 basis fields Velocity
and Displacement
one non-basis tensor field Stress
int64 connect1(num_el_in_blk1, num_nod_per_el1) ;
connect1:elem_type = "tri3" ; // Current Exodus
connect1:Basis@name = "HCURL_TRI_I1_FEM" ;
connect1:Basis@cardinality = 3 ;
connect1:Basis@subc_dim = 1, 1, 1 ;
connect1:Basis@subc_ordinal = 0, 1, 2 ;
connect1:Basis@subc_dof_ordinal = 0, 0, 0 ;
connect1:Basis@subc_num_dof = 1, 1, 1 ;
connect1:Basis@xi = 0.5, 0.5, 0.0 ;
connect1:Basis@eta = 0.0, 0.5, 0.5 ;
connect1:Field_1@name = "Velocity" ;
connect1:Field_1@storage_type = EX_VECTOR_3D, EX_BASIS ;
connect1:Field_2@name = "Displacement" ;
connect1:Field_2@component_separator = "_$" ;
connect1:Field_2@storage_type = EX_VECTOR_3D, EX_BASIS ;
connect1:Field_3@name = "Stress" ;
connect1:Field_3@storage_type = EX_SYM_TENSOR_3D ;
connect1:Field_3@component_separator = "%" ;
This would result in the client code "looking for" the following variables:
- Field 1 -- Variables "Velocity_X_0, Velocity_Y_0, Velocity_Z_0, ..., Velocity_Z_2"
- Field 2 -- Variables "Displacement_X$0, ... , Displacement_Z$2"
- Field 3 -- Variables "Stress%XX, Stress%YY, Stress%ZZ, Stress%XY, Stress%YZ, Stress%ZX"
- [Either look for both upppercase and lowercase suffices or have a default and an option to specify different than default]
- A "non-predefined-field-type" could list the component count and optionally the suffix list.
- Maybe a predefined type of "EX_SEQUENCE" for "field_1, field_2, field_3, ..., field_n"
- An "EX_USER_DEFINED" which requires component count and list of that many suffices.
Scalar basis field Temperature
int64 connect1(num_el_in_blk1, num_nod_per_el1) ;
connect1:elem_type = "tri3" ; // Current Exodus
connect1:Basis@name = "HGRAD_TRI_C1_FEM" ;
connect1:Basis@cardinality = 3 ;
connect1:Basis@subc_dim = 0, 0, 0 ;
connect1:Basis@subc_ordinal = 0, 1, 2 ;
connect1:Basis@subc_dof_ordinal = 0, 0, 0 ;
connect1:Basis@subc_num_dof = 1, 1, 1 ;
connect1:Basis@xi = 0, 1, 0 ;
connect1:Basis@eta = 0, 0, 1 ;
connect1:Field_1@name = "Temperature" ;
connect1:Field_1@storage_type = EX_BASIS ;
- From
Basis@cardinality = 3
, we know theTemperature
field will have 3 components.- The first field component is variable
Temperature_0
and is located at the node (subc_dim = 0) at location 0, 0 - The second field component is variable
Temperature_1
and is located at the node (subc_dim = 0) at location 1, 0 - The third field component is variable
Temperature_2
and is located at the node (subc_dim = 0) at location 0, 1 - QUESTION: Current IOSS uses 1-based suffices for the "sequence" type fields. Should the "basis" fields also use 1-based, or switch to 0-based to match intrepid...
- The first field component is variable
If the application does not want to store all the information about the basis, the minimal information needed would be:
int64 connect1(num_el_in_blk1, num_nod_per_el1) ;
connect1:elem_type = "tri3" ; // Current Exodus
connect1:Basis@cardinality = 3 ;
connect1:Field_1@name = "Temperature" ;
connect1:Field_1@storage_type = EX_BASIS ;
Which would enable a consumer of the database to map the Temperature
field to its 3 variable components. The location of the variable components would be ambiguous without additional information. If producers and consumers are using a common library, for example, Intrepid; it would be possible to specify the basis name, for example connect1:Basis@name = "HGRAD_TRI_C1_FEM" ;
which would give enough information to query the location information from the Intrepid library.
This mechanism could also be used to specify the locaitions of quadrature points in an element. In the example below, we have an example of a beam which uses nonstandard integration point locations, as both the top and bottom surfaces have an integration point in order to immediately detect the onset of the nonlinear effects.
Scalar basis field Force
int64 connect1(num_el_in_blk1, num_nod_per_el1) ;
connect1:elem_type = "beam2" ; // Current Exodus
connect1:Quadrature@Name = "Optional Name of this quadrature scheme" ;
connect1:Quadrature@cardinality = 5 ;
connect1:Quadrature@dimension = 1 ;
connect1:Quadrature@xi = -1, -0.6, 0, 0.6, 1.0 ; // Do we need to specify an extent? -1..1 or -0.5..0.5
connect1:Quadrature@weight = 0.125, 0.5787036, 0.5925926, 0.5787036, 0.125
connect1:Field_1@name = "Force" ;
connect1:Field_1@storage_type = EX_QUADRATURE ;
The xi
specifies the through-thickness location of the quadrature points (in a valid range of -1.0 .. 1.0) and weight
specifies the weight at each quadrature point. There would be 5 scalar variables that are the components of the Force
field Force_1
, Force_2
, Force_3
, Force_4
, Force_5
.
Minimally, this could be specified as:
int64 connect1(num_el_in_blk1, num_nod_per_el1) ;
connect1:elem_type = "beam2" ; // Current Exodus
connect1:Quadrature@cardinality = 5 ;
connect1:Field_1@name = "Force" ;
connect1:Field_1@storage_type = EX_QUADRATURE ;
Where only the number of components (Quadrature@cardinality
) is specified. This would be enough information to map the field Force
to the 5 variables that are its components.
This should hopefully solve or address some of the needs raised in #185.