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
+164-9Lines changed: 164 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,161 @@ 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
+
195
+
```@setup 2
196
+
using ClimaCore.CommonSpaces
197
+
using ClimaCore.Geometry
198
+
using ClimaCore.Fields
199
+
import ClimaCore: MatrixFields
200
+
import ClimaCore.MatrixFields: @name
201
+
FT = Float64
202
+
space = ColumnSpace(FT ;
203
+
z_elem = 6,
204
+
z_min = 0,
205
+
z_max = 10,
206
+
staggering = CellCenter()
207
+
)
208
+
f = map(x -> rand(Geometry.Covariant12Vector{Float64}), Fields.local_geometry_field(space))
209
+
g = map(x -> rand(Geometry.Covariant12Vector{Float64}), Fields.local_geometry_field(space))
Consider the case where $b_1 = 0$ and $b_2 = 0$, i.e $M$ is a diagonal matrix, and
242
+
where $M = k * I$, and $k$ is of type `T_k`. This would happen if
243
+
$\frac{\partial f_i}{\partial g_j} = [i=j] * k$. Instead of storing
244
+
each element on the diagonal, less memory can be used by storing a single value that represents a scaling of the identity. This reduces memory usage by a factor of $N_v$.
245
+
246
+
```julia
247
+
entry =fill(DiagonalMatrixRow(k), space)
248
+
```
249
+
250
+
can also be represented by
251
+
252
+
```julia
253
+
entry =DiagonalMatrixRow(k)
254
+
```
255
+
256
+
or, if `T_k` is a scalar, then
257
+
258
+
```julia
259
+
entry = I * k
260
+
```
261
+
262
+
### Implicit Tensor Structure Optimization
263
+
264
+
The functions that index an entry with an internal key assume the implicit tensor structure optimization is being used
265
+
when all of the following are true for `entry` where `T_k` is the element type of each band, and
266
+
`(internal_key_1, internal_key_2)` is the internal key indexing `entry`.
267
+
268
+
- the first key in the `internal_key_1` name chain is not a fieldname of `T_k`
269
+
- the first key in the `internal_key_2` name chain is not a fieldname of `T_k`
270
+
-`internal_key_1` and `internal_key_2` are both not empty
271
+
272
+
For most use cases, `T_k` is a scalar.
273
+
274
+
If the above conditions are met, the optimization assumes that the user intends the
275
+
entry to have an implicit tensor structure, with the values of type `T_k` representing a scaling of the
276
+
tensor identity. If both the first and second name in the name pair are equivalent, then they index onto the diagonal,
277
+
and the value is returned. Otherwise, they index off the diagonal, and a zero value
278
+
is returned.
279
+
280
+
This optimization is intended to be used when `T_f = T_g`, and they are both `AxisVectors`
281
+
The notation $f_{n}[i]$ where $0 < n \leq N_v$ refers to the $i$ component of the element
282
+
at the $n$ vertical level of $f$. In the following example, `T_f=T_g=Covariant12Vector`, and
0 commit comments