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
Also add support for tensor slicing and
improved docs
wip
finish docs
minor formatting fix
another minor docs formatting fix
Make suggested docs changes
- 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.
110
+
-A`UniformScaling`, which contains a `Number`
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.
@@ -162,35 +162,172 @@ An example of this is:
162
162
A = MatrixFields.FieldMatrix((@name(name1), @name(name2)) => sample_entry)
163
163
```
164
164
165
-
Now consider what happens indexing `A` with the key `(@name(name1.foo.bar.buz), @name(name2.biz.bop.fud))`.
165
+
Now consider what happens when 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.
174
171
175
-
The recursive indexing of an internal entry given some entry `entry` and internal_key`internal_name_pair`
172
+
The recursive indexing of an internal entry given some entry `entry` and internal key`internal_name_pair`
176
173
works as follows:
177
174
178
175
1. If the `internal_name_pair` is blank, return `entry`
179
-
2. If the element type of each band of `entry` is an `Axis2Tensor`, and `internal_name_pair` is of the form
180
-
`(@name(components.data.1...), @name(components.data.2...))` (potentially with different numbers),
181
-
then extract the specified component, and recurse on it with the remaining `internal_name_pair`.
176
+
2. If the element type of each band of `entry` is an `Axis2Tensor`, and `internal_name_pair` is of the form `(@name(components.data.1...), @name(components.data.2...))` (potentially with different numbers), then extract the specified component, and recurse on it with the remaining `internal_name_pair`.
182
177
3. If the element type of each band of `entry` is a `Geometry.AdjointAxisVector`, then recurse on the parent of the adjoint.
183
-
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]`
187
-
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
-
non-empty, and it is assumed that `entry` is being used to implicitly represent some tensor structure. If the first name in
189
-
`internal_name_pair[1]` is equivalent to `internal_name_pair[2]`, then both the first names are dropped, and entry is recursed onto.
190
-
If the first names are different, both the first names are dropped, and the zero of entry is recursed onto.
178
+
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`, 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]`
179
+
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`, 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]`
180
+
6. At this point, if none of the previous cases are true, both `internal_name_pair[1]` and `internal_name_pair[2]` should be non-empty, and it is assumed that `entry` is being used to implicitly represent some tensor structure. If the first name in `internal_name_pair[1]` is equivalent to `internal_name_pair[2]`, then both the first names are dropped, and entry is recursed onto. If the first names are different, both the first names are dropped, and the zero of entry is recursed onto.
191
181
192
182
When the entry is a `ColumnWiseBandMatrixField`, indexing it will return a broadcasted object in
193
183
the following situations:
194
184
195
185
1. The internal key indexes to a type different than the basetype of the entry
196
186
2. The internal key indexes to a zero-ed value
187
+
188
+
```@setup 2
189
+
using ClimaCore.CommonSpaces
190
+
using ClimaCore.Geometry
191
+
using ClimaCore.Fields
192
+
import ClimaCore: MatrixFields
193
+
import ClimaCore.MatrixFields: @name
194
+
FT = Float64
195
+
space = ColumnSpace(FT ;
196
+
z_elem = 6,
197
+
z_min = 0,
198
+
z_max = 10,
199
+
staggering = CellCenter()
200
+
)
201
+
f = map(x -> rand(Geometry.Covariant12Vector{Float64}), Fields.local_geometry_field(space))
202
+
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
235
+
where $M = k * I$, and $k$ is of type `T_k`. This would happen if
236
+
$\frac{\partial f_i}{\partial g_j} = \delta_{ij} * k$. Instead of storing
237
+
each element on the diagonal, the `FieldMatrix` can store a single value that represents a scaling of the identity matrix, reducing memory usage by a factor of $N_v$:
238
+
239
+
```julia
240
+
entry =fill(DiagonalMatrixRow(k), space)
241
+
```
242
+
243
+
can also be represented by
244
+
245
+
```julia
246
+
entry =DiagonalMatrixRow(k)
247
+
```
248
+
249
+
or, if `T_k` is a scalar, then
250
+
251
+
```julia
252
+
entry = I * k
253
+
```
254
+
255
+
### Implicit Tensor Structure Optimization
256
+
257
+
The functions that index an entry with an internal key assume the implicit tensor structure optimization is being used
258
+
when all of the following are true for `entry` where `T_k` is the element type of each band, and
259
+
`(internal_key_1, internal_key_2)` is the internal key indexing `entry`.
260
+
261
+
- the `internal_key_1` name chain is not empty and its first name is not a field of `T_k`
262
+
- the `internal_key_2` name chain is not empty and its first name is not a field of `T_k`
263
+
264
+
For most use cases, `T_k` is a scalar.
265
+
266
+
If the above conditions are met, the optimization assumes that the user intends the
267
+
entry to have an implicit tensor structure, with the values of type `T_k` representing a scaling of the
268
+
identity tensor. If both the first and second names in the name pair are equivalent, then they index onto the diagonal,
269
+
and the scalar value of `k` is returned. Otherwise, they index off the diagonal, and a zero value
270
+
is returned.
271
+
272
+
This optimization is intended to be used when `T_f = T_g`.
273
+
The notation $f_{n}[i]$ where $0 < n \leq N_v$ refers to the $i$-th component of the element
274
+
at the $n$-th vertical level of $f$. In the following example, `T_f` and `T_g` are both `Covariant12Vector`s, and
0 commit comments