# Fields

From the beginning of a project we had a clear concept in our mind: "everything is a field". That is, everything can vary temporally and spatially. We think that constant is just a special case of field which does not vary in temporal nor spatial direction. Fields can vary in spatial direction, i.e. can be either constant or variable, and in temporal direction, i.e. can be time variant or time invariant. From this pondering we can think that there exists four kind of (discrete) fields:

- discrete, constant, time invariant (DCTI)
- discrete, variable, time invariant (DVTI)
- discrete, constant, time variant (DCTV)
- discrete, variable, time variant (DVTV)

Discrete, in this context, means that field is defined in point-wise in $1 \ldots n$ locations, from where it is then interpolated to whole domain using some interpolation polynomials, i.e.

math where $N_{i}(\xi, t)$ is the basis function or interpolation polymial corresponding to $i$^{th} discrete value and $u_{i}$ is the discrete value.

Then we have continuous fields, which are defined in whole domain, or at least not point-wise. By following the already used abbreviations, we have four more fields:

- continuous, constant, time invariant (CCTI)
- continuous, variable, time invariant (CVTI)
- continuous, constant, time variant (DCTV)
- continuous, variable, time variant (CVTV)

Continuous, again in this context, does not mean that field has to be defined everywhere. It's enough that it's defined in function of spatial and/or temporal coordinates, i.e. we have $u \equiv u(\xi, t)$, without a some spesific basis needed to interpolate from discrete values.

Field itself can be in principle anything. However, usually either scalar, vector or tensor (matrix). Time does not to have be real, it can be for example angle of some rotating machine or even complex value.

From these starting points, we assume that the mentioned field system can describe all imaginable situations.

## Creating new fields

For discrete fields that are varying in spatial direction, value for each discrete point is defined using NTuple. The order of points is implicitly assumed to be same than node ordering in ABAQUS. That is, first corner nodes in anti-clockwise direction and after that middle nodes.

For example, `(1, 2, 3, 4)`

is a scalar field having length of 4 and `([1,2],[2,3],[3,4],[4,5])`

is a vector field having length of 4.

For fields that are varying in temporal direction, `time => value`

syntax is used. The first item in pair is time (or similar) and second item is value assigned to that time. For example, `0.0 => 1.0`

is a time-dependent scalar field having value 1.0 at time 0.0.

The most simple field is a field that is constant in both time and spatial direction. Discrete, constant, time invariant `DCTI`

:

```
julia> a = DCTI(1.0)
ERROR: UndefVarError: DCTI not defined
```

Then we have discrete, variable, time invariant fields `DVTI`

. Notice the use of `Tuple`

when defining field.

```
julia> b = DVTI( (1.0, 2.0) )
ERROR: UndefVarError: DVTI not defined
```

Discrete, constant, time variant field `DCTV`

is constant in spatial direction $\partial u/\partial x = 0$ but can vary in temporal direction, $\partial u/\partial t\neq 0$. Here, `=>`

syntax is used. New values can be added to field using function `update!`

. If there already exists a value for that particular time, it will be overridden. It is assumed that content of field in time direction is monotonically increasing, i.e.

For the sake of clarity let's also mention that `update!`

works for time invariant fields as well if content needs to be updated.

```
julia> c = DCTV(0.0 => 1.0, 1.0 => 2.0)
ERROR: UndefVarError: DCTV not defined
julia> update!(c, 2.0 => 3.0)
ERROR: UndefVarError: update! not defined
```

Discrete, variable, time variant `DVTV`

field is the most general one, allowing values of field to vary in both spatial and time direction.

```
julia> d = DVTV(0.0 => (1.0, 2.0), 1.0 => (2.0, 3.0))
ERROR: UndefVarError: DVTV not defined
julia> update!(d, 2.0 => (3.0, 4.0))
ERROR: UndefVarError: update! not defined
```

In examples above, all fields defined was scalar fields. Defining vector or tensor fields goes in the same way. The only difference is that now we define vectors and tensors instead of a single scalar value. They can vary in spatial and time direction in the same way than scalar fields. Here is example of defining the abovementioned vector fields:

```
julia> a = DCTI([1.0, 2.0])
ERROR: UndefVarError: DCTI not defined
julia> b = DVTI(([1.0, 2.0], [2.0, 3.0]))
ERROR: UndefVarError: DVTI not defined
julia> c = DCTV(0.0 => [1.0, 2.0], 1.0 => [2.0, 3.0])
ERROR: UndefVarError: DCTV not defined
julia> d = DVTV(0.0 => ([1.0, 2.0], [2.0, 3.0]), 1.0 => ([2.0, 3.0], [3.0, 4.0]))
ERROR: UndefVarError: DVTV not defined
```

## Accessing fields

Accessing fields in time direction is done using a function `interpolate`

. For example, if we have (constant) $[1,2]$ at time $t=0.0$ and $[3,4]$ at time $t=1.0$, linear interpolation in time direction yields

```
julia> c = DCTV(0.0 => [1.0,2.0], 1.0 => [3.0,4.0])
ERROR: UndefVarError: DCTV not defined
julia> interpolate(c, 0.5)
ERROR: UndefVarError: interpolate not defined
```

If field is spatially varying, a `Tuple`

will be returned, having one value for each "node". This can then be interpolated in spatial direction, typically using basis functions defined on element, i.e. $u = N_{i} u_{i}$:

```
julia> d = DVTV(0.0 => (1.0,2.0), 1.0 => (3.0,4.0))
ERROR: UndefVarError: DVTV not defined
julia> interpolate(d, 0.5)
ERROR: UndefVarError: interpolate not defined
```

Although the two fields above looks quite same, the key difference is that in DCTV field we have a constant vectorial value (defined using square brackets []) and in latter DVTV field we have a scalar value (defined using round brackets) changing in spatial direction from 1.0 to 2.0 at time $t=0.0$ and changing from 3.0 to 4.0 at time $t=1.0$.

If a field is time invariant, interpolation in time direction returns a trivial solution:

```
julia> interpolate(DCTI(1.0), 0.5)
ERROR: UndefVarError: DCTI not defined
julia> interpolate(DVTI((1.0,2.0)), 0.5)
ERROR: UndefVarError: DVTI not defined
```

For spatially varying fields, one can access to ith element using getindex:

```
julia> a = DVTI((1.0,2.0))
ERROR: UndefVarError: DVTI not defined
julia> getindex(a, 1)
ERROR: UndefVarError: a not defined
```

For field varying both temporally and spatially, one has first to interpolate in time direction to get iterable tuple:

```
julia> d = DVTV(0.0 => (1.0,2.0), 1.0 => (3.0,4.0))
ERROR: UndefVarError: DVTV not defined
julia> result = interpolate(d, 0.5)
ERROR: UndefVarError: interpolate not defined
julia> getindex(result, 1)
ERROR: UndefVarError: result not defined
```

Internally, each field is a subtype of `AbstractField`

having a field `data`

, which be accessed directly for hacking purposes.

```
julia> d.data
ERROR: UndefVarError: d not defined
```

## Continuous fields

Continuous fields may be useful when defining analytical boundary conditions. For that we have `CVTV`

, where "C" stands for continuous.

```
julia> f(xi,t) = xi[1]*xi[2]*t
f (generic function with 1 method)
julia> g = CVTV(f)
ERROR: UndefVarError: CVTV not defined
julia> g((1.0,2.0), 3.0)
ERROR: UndefVarError: g not defined
```

## Dictionary fields

Usually it is assumed that size of length of discrete field matches to the number of basis functions of a single element, typically something small like 1-10.

However, there might be cases where it is more practical to define field in a sense that indexing is not continuous or starting from 1. For example, we might want to define field common for a set of elements. In that case it's natural to think that each index in field corresponds to the certain id-number of node. For example, if we have a triangle element connecting nodes 1, 1000 and 100000, we still want to access that field naturally using `getindex`

, e.g. `f[1]`

, `f[1000]`

and `f[100000]`

. In that case, more appropriate internal structure for field is based on a dictionary, not tuple.

It only makes sense to define dictionary fields for spatially varying fields. Two new fields are introduced: `DVTId`

and `DVTVd`

, where the last character "d" stands for "dictionary".

Keep on mind, that this type of field has one restriction. If and when this field is typically defined on nodes of several elements, field must be continuous between elements. That is, if field value in node 1000 is for example 1.0, then it's 1.0 in all elements connecting to that node. To define jumps on field, one must define field element-wise.

Define eg. "geometry" for nodes 1,1000,100000:

```
julia> X = Dict(1=>[0.0,0.0], 1000=>[1.0,0.0], 100000=>[1.0,1.0])
Dict{Int64,Array{Float64,1}} with 3 entries:
100000 => [1.0, 1.0]
1000 => [1.0, 0.0]
1 => [0.0, 0.0]
julia> G = DVTId(X)
ERROR: UndefVarError: DVTId not defined
julia> G[1], G[1000], G[100000]
ERROR: UndefVarError: G not defined
```

Interpolation in time directions works in a same way than with other fields depends from time.

```
julia> Y = Dict(1=>[1.0,1.0], 1000=>[2.0,1.0], 100000=>[2.0,2.0])
Dict{Int64,Array{Float64,1}} with 3 entries:
100000 => [2.0, 2.0]
1000 => [2.0, 1.0]
1 => [1.0, 1.0]
julia> F = DVTVd(0.0 => X, 1.0 => Y)
ERROR: UndefVarError: DVTVd not defined
julia> interpolate(F,0.5)[100000]
ERROR: UndefVarError: interpolate not defined
```

## Using common constructor `field`

Now we have introduced total of 7 fields: DCTI, DCTV, DVTI, DVTV, CVTV, DVTId, DVTVd. A good question arises that how to remember all this stuff and is it even necessary? Luckily not, because one can use a single constructor called `field`

to create all kind of fields. Type of field is inspected from data type. It's not necessary to remember all this technical stuff, just declare new field using more of less intuitive syntax and `field`

-function.

```
julia> f1 = field(1)
ERROR: UndefVarError: field not defined
julia> f2 = field(1, 2)
ERROR: UndefVarError: field not defined
julia> f3 = field(0.0 => 1)
ERROR: UndefVarError: field not defined
julia> f4 = field(0.0 => (1, 2), 1.0 => (2, 3))
ERROR: UndefVarError: field not defined
julia> f5 = field((xi,t) -> xi[1]*t)
ERROR: UndefVarError: field not defined
julia> f6 = field(1 => 1, 2 => 2)
ERROR: UndefVarError: field not defined
julia> f7 = field(0.0 => (1=>1, 10=>2), 1.0 => (1=>2,10=>3))
ERROR: UndefVarError: field not defined
```

## Developing new fields

If the FEMBase ones are not enough, it's always possible to define new ones. Minimum requirements is that field is a subtype of `AbstractField`

and `interpolate`

, `getindex`

, has been defined to it. Field can, for example fetch data from random.org or market stocks, read data from hard drive or add some stochastics behavior to it.

## Functions and types related to fields

### Types

Missing docstring for `AbstractField`

. Check Documenter's build log for details.

Missing docstring for `DCTI`

. Check Documenter's build log for details.

Missing docstring for `DVTI`

. Check Documenter's build log for details.

Missing docstring for `DCTV`

. Check Documenter's build log for details.

Missing docstring for `DVTV`

. Check Documenter's build log for details.

Missing docstring for `CVTV`

. Check Documenter's build log for details.

Missing docstring for `DVTId`

. Check Documenter's build log for details.

Missing docstring for `DVTVd`

. Check Documenter's build log for details.

### Functions (internal)

These functions needs to be defined when developing new fields:

Missing docstring for `new_field`

. Check Documenter's build log for details.

Missing docstring for `update_field!`

. Check Documenter's build log for details.

Missing docstring for `interpolate_field`

. Check Documenter's build log for details.

### Functions (public)

Missing docstring for `field(x)`

. Check Documenter's build log for details.

Missing docstring for `update!(field::F, data) where {F<:AbstractField}`

. Check Documenter's build log for details.

Missing docstring for `interpolate(field::F, time) where {F<:AbstractField}`

. Check Documenter's build log for details.