Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
pyicon
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Fraser William Goldsworth
pyicon
Commits
4f40ca56
Commit
4f40ca56
authored
2 years ago
by
Fraser William Goldsworth
Browse files
Options
Downloads
Patches
Plain Diff
starting to look at divergence at dual edges
parent
9a1eabc5
No related branches found
No related tags found
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
pyicon/pyicon_calc_xr.py
+135
-46
135 additions, 46 deletions
pyicon/pyicon_calc_xr.py
pyicon/tests/test_pyicon_calc_xr.py
+9
-0
9 additions, 0 deletions
pyicon/tests/test_pyicon_calc_xr.py
with
144 additions
and
46 deletions
pyicon/pyicon_calc_xr.py
+
135
−
46
View file @
4f40ca56
import
warnings
print
(
'
numpy
'
)
import
numpy
as
np
print
(
'
xarray
'
)
...
...
@@ -418,18 +419,92 @@ def xr_edges2edges_via_cell(ds_IcD, vn_e, scalar, dze='const'):
## Mapping between cells and vertices
def
xr_calc_cell2vertex_coeff
(
ds_IcD
):
raise
(
NotImplementedError
)
dist_vector
=
ds_IcD
.
vert_cart_vec
-
ds_IcD
.
cell_cart_vec
.
isel
(
cell
=
ds_IcD
.
cells_of_vertex
)
orientation
=
(
dist_vector
*
ds_IcD
.
edge_prim_norm
).
sum
(
dim
=
'
cart
'
)
dist_vector
*=
np
.
sign
(
orientation
)
edge2cell_coeff_cc
=
(
ds_IcD
.
edge_prim_norm
*
ds_IcD
.
grid_sphere_radius
*
np
.
sqrt
((
dist_vector
**
2
).
sum
(
dim
=
'
cart
'
))
/
ds_IcD
.
dual_edge_length
)
edge2cell_coeff_cc
=
edge2cell_coeff_cc
.
transpose
(
'
edge
'
,
'
nc
'
,
'
cart
'
)
return
edge2cell_coeff_cc
def
xr_calc_cell2vertex_coeff
(
ds_IcD
,
method
=
None
):
"""
Calculates cell2vertex coefficients for scalars
Parameters
----------
ds_IcD : xr.Dataset
A converted tgrid dataset
method : [
"
equal
"
,
"
sector_area
"
,
"
distance
"
,
"
area_dist
"
]
Method used for weighting
Returns
-------
cell2vertex_coeff : xr.DataArray
Array of coefficients for mapping cells to vertices, with dimensions
(
"
vertex
"
,
"
ne
"
). Note that technically
"
ne
"
should be replaced by
"
nc
"
Notes
-----
Hexagonal barycentric interpolants are not uniquely defined. This function
offers several different options, and a user may even choose their own.
The sole constraint on the interpolants is that they sum to one; however,
it is advisable to use physical arguments when determining the
coefficients. For instance, we would expect points to be more influenced by
points nearer to them or representing a greater fraction of the hexagon our
point is in. If our hexagon has symmetry, we may want weights which reflect
these symmetries, be this inversion, rotation or reflection.
"""
if
method
is
None
:
warnings
.
warn
(
"
No cell2vertex method specified, falling back on
'
equal
'"
)
method
=
"
equal
"
cells_of_vertex
=
ds_IcD
[
"
cells_of_vertex
"
]
cell_cart_vec_of_vertex
=
ds_IcD
[
"
cell_cart_vec
"
].
isel
(
cell
=
cells_of_vertex
)
if
method
==
"
equal
"
:
cell2vertex_coeff
=
1
/
6
*
xr
.
ones_like
(
ds_IcD
[
"
cells_of_vertex
"
])
elif
method
==
"
sector_area
"
:
# This method is almost conservative.
vecAP
=
-
cell_cart_vec_of_vertex
+
ds_IcD
[
"
vert_cart_vec
"
]
vecAFp
=
0.5
*
(
-
cell_cart_vec_of_vertex
+
cell_cart_vec_of_vertex
.
roll
(
ne
=-
1
))
vec_areaFpAP
=
xr
.
cross
(
vecAP
,
vecAFp
,
dim
=
"
cart
"
)
areaFpAP
=
0.5
*
np
.
sqrt
(
xr
.
dot
(
vec_areaFpAP
,
vec_areaFpAP
,
dims
=
"
cart
"
))
vecABp
=
0.5
*
(
-
cell_cart_vec_of_vertex
+
cell_cart_vec_of_vertex
.
roll
(
ne
=
1
))
vec_areaABpP
=
xr
.
cross
(
vecAP
,
vecABp
,
dim
=
"
cart
"
)
areaABpP
=
0.5
*
np
.
sqrt
(
xr
.
dot
(
vec_areaABpP
,
vec_areaABpP
,
dims
=
"
cart
"
))
areaFpABpP
=
areaFpAP
+
areaABpP
cell2vertex_coeff
=
areaFpABpP
/
areaFpABpP
.
sum
(
dim
=
"
ne
"
)
elif
method
==
"
distance
"
:
vecPA
=
(
ds_IcD
[
"
vert_cart_vec
"
]
-
cell_cart_vec_of_vertex
)
distPA
=
np
.
sqrt
(
xr
.
dot
(
vecPA
,
vecPA
,
dims
=
"
cart
"
))
cell2vertex_coeff
=
(
1
/
distPA
)
/
(
1
/
distPA
).
sum
(
dim
=
"
ne
"
)
elif
method
==
"
area_dist
"
:
# First do the sector area
vecAP
=
-
cell_cart_vec_of_vertex
+
ds_IcD
[
"
vert_cart_vec
"
]
vecAFp
=
0.5
*
(
-
cell_cart_vec_of_vertex
+
cell_cart_vec_of_vertex
.
roll
(
ne
=-
1
))
vec_areaFpAP
=
xr
.
cross
(
vecAP
,
vecAFp
,
dim
=
"
cart
"
)
areaFpAP
=
0.5
*
np
.
sqrt
(
xr
.
dot
(
vec_areaFpAP
,
vec_areaFpAP
,
dims
=
"
cart
"
))
vecABp
=
0.5
*
(
-
cell_cart_vec_of_vertex
+
cell_cart_vec_of_vertex
.
roll
(
ne
=
1
))
vec_areaABpP
=
xr
.
cross
(
vecAP
,
vecABp
,
dim
=
"
cart
"
)
areaABpP
=
0.5
*
np
.
sqrt
(
xr
.
dot
(
vec_areaABpP
,
vec_areaABpP
,
dims
=
"
cart
"
))
areaFpABpP
=
areaFpAP
+
areaABpP
# Now do the distance
vecPA
=
(
ds_IcD
[
"
vert_cart_vec
"
]
-
cell_cart_vec_of_vertex
)
distPA
=
np
.
sqrt
(
xr
.
dot
(
vecPA
,
vecPA
,
dims
=
"
cart
"
))
def
xr_cell2vertex
(
ds_IcD
,
da_b
,
cell2vertex_coeff_cc
=
None
,
fixed_vol_norm
=
None
):
# Now calculate the coefficients
cell2vertex_coeff
=
(
areaFpABpP
/
distPA
)
cell2vertex_coeff
=
cell2vertex_coeff
/
cell2vertex_coeff
.
sum
(
dim
=
"
ne
"
)
else
:
raise
ValueError
(
"
Selected method cannot be found
"
)
return
cell2vertex_coeff
def
xr_cell2vertex
(
ds_IcD
,
da_b
,
cell2vertex_coeff
=
None
,
fixed_vol_norm
=
None
):
"""
Interpolate cell variables on to vertices
Parameters
----------
...
...
@@ -439,29 +514,22 @@ def xr_cell2vertex(ds_IcD, da_b, cell2vertex_coeff_cc=None, fixed_vol_norm=None)
da_b : xr.DataArray
The data to be mapped onto cell vertices. This should be a scalar.
cell2vertex_coeff : xr.DataArray or string
This gives the weightings to be used during interpolation. If an array,
it should have the dimensions (
"
vertex
"
,
"
ne
"
) <<NEED TO FIX SO NE IS NC>>
If a string it should take a valid method argument for xr_calc_cell2vertex_coeff
Returns
-------
d
s_icd
: xr.Data
set
A tgrid dataset compatible with pyicon function
s
d
a_b_vert
: xr.Data
Array
The array da_b interpolated onto vertice
s
Notes
-----
This function uses hexagonal barycentric interpolation. Each vertex is
(normally) surrounded by 6 cell centres. The value at the vertex should
depend only upon these vertices. We express the position of the cell centre
as a sum of contributions from each point of the hexagon. We then use these
weights to interpolate. Hexagonal barycentric interpolant coefficients
aren
'
t uniquely defined. Here, for the hexagon ABCDEF and point P, we
choose coefficients
x_A = [ABC]/[PBC]
y_B = [BCD]/[PCD]
z_C = [CDE]/[PDE]
u_D = [DEF]/[PEF]
v_E = [EFA]/[PFA]
w_F = [FAB]/[PAB]
where [xyz] represents the area of triangle xyz. We can then interpolate
a function f onto the point P using
f(P) = x_A f(A) + y_B f(B) + z_C f(C) + u_D f(D) + v_E f(E) + w_F f(F)
This function is useful for calculating potential vorticity using it
'
s
C-grid divergence form (see for instance Morel et al. 2019:
https://doi.org/10.1016/j.ocemod.2019.04.004). In this form we require
cell centre scalars (such as density) on vertices (vorticity points).
What isn
'
t immediately clear to me is what happens at edge points where
there may be less valid centres surrounding the vertex? Perhaps we need to
...
...
@@ -469,23 +537,12 @@ def xr_cell2vertex(ds_IcD, da_b, cell2vertex_coeff_cc=None, fixed_vol_norm=None)
Furthermore, do we need to apply any volume normalisation?
"""
raise
(
NotImplementedError
)
if
cell2vertex_coeff_cc
is
None
:
cell2vertex_coeff_cc
=
xr_calc_cell2vertex_coeff
(
ds_IcD
)
ic0
=
ds_IcD
.
adjacent_cell_of_edge
.
isel
(
nc
=
0
).
data
ic1
=
ds_IcD
.
adjacent_cell_of_edge
.
isel
(
nc
=
1
).
data
ptp_vn
=
(
(
p_vn_c
.
isel
(
cell
=
ic0
).
rename
({
'
cell
'
:
'
edge
'
})
#.chunk(dict(edge=ic0.size))
*
edge2cell_coeff_cc_t
.
isel
(
nc
=
0
)
).
sum
(
dim
=
'
cart
'
)
+
(
p_vn_c
.
isel
(
cell
=
ic1
).
rename
({
'
cell
'
:
'
edge
'
})
#.chunk(dict(edge=ic0.size))
*
edge2cell_coeff_cc_t
.
isel
(
nc
=
1
)
).
sum
(
dim
=
'
cart
'
)
)
return
ptp_vn
if
type
(
cell2vertex_coeff
)
!=
xr
.
DataArray
:
# Calculate the coefficients
cell2vertex_coeff
=
xr_calc_cell2vertex_coeff
(
ds_IcD
,
method
=
cell2vertex_coeff
)
da_b_vert
=
(
da_b
*
cell2vertex_coeff
).
sum
(
dim
=
"
ne
"
)
return
da_b_vert
## Divergence
...
...
@@ -504,6 +561,38 @@ def xr_calc_div(ds_IcD, vector, div_coeff=None):
).
sum
(
dim
=
'
nv
'
)
return
div_of_vector
def
xr_calc_div_dual_coeff
():
pass
def
xr_calc_div_dual
(
ds_IcD
,
vector
,
div_dual_coeff
=
None
):
"""
Calculates the divergence of vectors on dual edges
Parameters
----------
ds_IcD : xr.Dataset
vector : xr.DataArray
A vector defined on dual edge points (i.e. pointing towards vertices)
div_dual_coeff : None or xr.DataArray
Returns
-------
div_of_vector : xr.DataArray
The divergence of the dual-edge vector, defined on vertices
"""
if
div_dual_coeff
is
None
:
div_dual_coeff
=
xr
.
calc_div_dual_coeff
()
div_of_vector
=
(
vector
.
isel
(
edge
=
ds_IcD
[
"
edges_of_vertex
"
])
*
div_dual_coeff
).
sum
(
dim
=
"
nv
"
)
# Strictly speaking this should be ne...
return
div_of_vector
## Gradient
def
xr_calc_grad_coeff
(
ds_IcD
):
...
...
This diff is collapsed.
Click to expand it.
pyicon/tests/test_pyicon_calc_xr.py
+
9
−
0
View file @
4f40ca56
...
...
@@ -95,3 +95,12 @@ def test_nabla_funcs(processed_tgrid):
assert
np
.
allclose
(
curl_of_grad
,
0
)
# Should include other tests in the future if any refactoring is done
@pytest.mark.parametrize
(
"
method
"
,
[
None
,
"
equal
"
,
"
sector_area
"
,
"
distance
"
,
"
area_dist
"
])
def
test_cell2vertex
(
processed_tgrid
,
method
):
# Check the cell2vertex coefficients sum to one or nan.
weights
=
pyic
.
xr_calc_cell2vertex_coeff
(
processed_tgrid
,
method
=
method
)
sums_to_1
=
np
.
isclose
(
weights
.
sum
(
dim
=
"
ne
"
,
skipna
=
False
),
1
)
sums_to_nan
=
np
.
isnan
(
weights
.
sum
(
dim
=
"
ne
"
,
skipna
=
False
))
assert
np
.
all
(
sums_to_nan
|
sums_to_1
)
\ No newline at end of file
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment