You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/src/matrix_fields.md
+144-9Lines changed: 144 additions & 9 deletions
Original file line number
Diff line number
Diff line change
@@ -108,8 +108,8 @@ scalar_field_matrix
108
108
A FieldMatrix entry can be:
109
109
110
110
- An `UniformScaling`, which contains a `Number`
111
-
- A `DiagonalMatrixRow`, which can contain aything
112
-
- A `ColumnwiseBandMatrixField`, where each row is a [`BandMatrixRow`](@ref)where the band element type is representable with the space's base number type.
111
+
- A `DiagonalMatrixRow`, which can contain either a `Number` or a tensor (represented as a `Geometry.Axis2Tensor`)
112
+
- A `ColumnwiseBandMatrixField`, where each value is a [`BandMatrixRow`](@ref)with entries of any type that can be represented using the field's base number type.
113
113
114
114
If an entry contains a composite type, the fields of that type can be extracted.
115
115
This is also true for nested composite types.
@@ -164,10 +164,7 @@ An example of this is:
164
164
165
165
Now consider what happens indexing `A` with the key `(@name(name1.foo.bar.buz), @name(name2.biz.bop.fud))`.
166
166
167
-
First, a function searches the keys of `A` for a key that `(@name(foo.bar.buz), @name(biz.bop.fud))`
168
-
is a child of. In this example, `(@name(foo.bar.buz), @name(biz.bop.fud))` is a child of
169
-
the key `(@name(name1), @name(name2))`, and
170
-
`(@name(foo.bar.buz), @name(biz.bop.fud))` is referred to as the internal key.
167
+
First, `getindex` finds a key in `A` that contains the key being indexed. In this example, `(@name(name1.foo.bar.buz), @name(name2.biz.bop.fud))` is contained within `(@name(name1), @name(name2))`, so `(@name(name1), @name(name2))` is called the "parent key" and `(@name(foo.bar.buz), @name(biz.bop.fud))` is referred to as the "internal key".
171
168
172
169
Next, the entry that `(@name(name1), @name(name2))` is paired with is recursively indexed
173
170
by the internal key.
@@ -181,9 +178,9 @@ works as follows:
181
178
then extract the specified component, and recurse on it with the remaining `internal_name_pair`.
182
179
3. If the element type of each band of `entry` is a `Geometry.AdjointAxisVector`, then recurse on the parent of the adjoint.
183
180
4. If `internal_name_pair[1]` is not empty, and the first name in it is a field of the element type of each band of `entry`,
184
-
extract that field from `entry`, and recurse on the it with the remaining names of `internal_name_pair[1]` and all of `internal_name_pair[2]`
185
-
5. If `internal_name_pair[2]` is not empty, and the first name in it is a field of the element type of each row of `entry`,
186
-
extract that field from `entry`, and recurse on the it with all of `internal_name_pair[1]` and the remaining names of `internal_name_pair[2]`
181
+
extract that field from `entry`, and recurse into it with the remaining names of `internal_name_pair[1]` and all of `internal_name_pair[2]`
182
+
5. If `internal_name_pair[2]` is not empty, and the first name in it is a field of the element type of each band of `entry`,
183
+
extract that field from `entry`, and recurse into it with all of `internal_name_pair[1]` and the remaining names of `internal_name_pair[2]`
187
184
6. At this point, if none of the previous cases are true, both `internal_name_pair[1]` and `internal_name_pair[2]` should be
188
185
non-empty, and it is assumed that `entry` is being used to implicitly represent some tensor structure. If the first name in
189
186
`internal_name_pair[1]` is equivalent to `internal_name_pair[2]`, then both the first names are dropped, and entry is recursed onto.
@@ -194,3 +191,141 @@ the following situations:
194
191
195
192
1. The internal key indexes to a type different than the basetype of the entry
196
193
2. The internal key indexes to a zero-ed value
194
+
3. The internal key slices an `AxisTensor`
195
+
196
+
### Implicit Tensor Structure Optimization
197
+
198
+
```@setup 2
199
+
using ClimaCore.CommonSpaces
200
+
using ClimaCore.Geometry
201
+
using ClimaCore.Fields
202
+
import ClimaCore: MatrixFields
203
+
import ClimaCore.MatrixFields: @name
204
+
FT = Float64
205
+
space = ColumnSpace(FT ;
206
+
z_elem = 6,
207
+
z_min = 0,
208
+
z_max = 10,
209
+
staggering = CellCenter()
210
+
)
211
+
```
212
+
213
+
If using a `FieldMatrix` to represent a jacobian, entries with certain structures
214
+
can be stored in an optimized manner.
215
+
216
+
The optimization assumes that if indexing into an entry of scalars, the user intends the
217
+
entry to have an implicit tensor structure, with the scalar values representing a scaling of the
218
+
tensor identity. If both the first and second name in the name pair are equivalent, then they index onto the diagonal,
219
+
and the scalar value is returned. Otherwise, they index off the diagonal, and a zero value
220
+
is returned.
221
+
222
+
The following sections refer the `Field`s
223
+
$f$ and $g$, which both have values of type `Covariant12Vector` and are defined on a column domain, which is discretized with $N_v$ layers.
224
+
The notation $f_{n}[i]$ where $ 0 < n \leq N_v$ and $i \in (1,2)$ refers to the $i$ component of the element of $f$
225
+
at the $i$ vertical level. $g$ is indexed similarly. Although $f$ and $g$ have values of type
226
+
`Covariant12Vector`, this optimization works for any two `Field`s of `AxisVector`s
227
+
228
+
```@example 2
229
+
f = map(x -> rand(Geometry.Covariant12Vector{Float64}), Fields.local_geometry_field(space))
230
+
g = map(x -> rand(Geometry.Covariant12Vector{Float64}), Fields.local_geometry_field(space))
231
+
```
232
+
233
+
#### Uniform Scaling Case
234
+
235
+
If $\frac{\partial f_n[i]}{\partial g_n[j]} = [i = j]$ for some scalar $k$, then the
236
+
non-optimized entry would be represented by a diagonal matrix with values of an identity 2d tensor. If $k=2$, then
0 commit comments