88
99from types import ModuleType
1010
11+ import gt4py .next .typing as gtx_typing
1112import numpy as np
1213from gt4py import next as gtx
1314from gt4py .next import sin , where
1718from icon4py .model .common .math .helpers import (
1819 arc_length_on_edges ,
1920 cross_product_on_edges ,
21+ diff_on_edges_torus ,
22+ distance_on_edges_torus ,
2023 geographical_to_cartesian_on_edges ,
2124 geographical_to_cartesian_on_vertices ,
2225 normalize_cartesian_vector_on_edges ,
2326 zonal_and_meridional_components_on_edges ,
2427)
25- from icon4py .model .common .utils import data_allocation as alloc
28+ from icon4py .model .common .utils import data_allocation as data_alloc
2629
2730
2831@gtx .field_operator (grid_type = gtx .GridType .UNSTRUCTURED )
@@ -56,6 +59,51 @@ def cartesian_coordinates_of_edge_tangent(
5659 return normalize_cartesian_vector_on_edges (x , y , z )
5760
5861
62+ @gtx .field_operator (grid_type = gtx .GridType .UNSTRUCTURED )
63+ def cartesian_coordinates_of_edge_tangent_torus (
64+ vertex_x : fa .VertexField [ta .wpfloat ],
65+ vertex_y : fa .VertexField [ta .wpfloat ],
66+ edge_orientation : fa .EdgeField [ta .wpfloat ],
67+ domain_length : ta .wpfloat ,
68+ domain_height : ta .wpfloat ,
69+ ) -> tuple [
70+ fa .EdgeField [ta .wpfloat ],
71+ fa .EdgeField [ta .wpfloat ],
72+ fa .EdgeField [ta .wpfloat ],
73+ ]:
74+ """
75+ Compute normalized cartesian vector tangential to an edge on a torus grid.
76+
77+ This is done by taking the difference between the two vertices adjacent to the edge
78+ t = d(v1, v2)
79+
80+ Args:
81+ vertex_x: x coordinates of vertices
82+ vertex_y: y coordinates of vertices
83+ edge_orientation: encoding of the edge orientation: (-1, +1) depending on whether the
84+ edge is directed from first to second neighbor of vice versa.
85+ Returns:
86+ x: x coordinate of normalized tangent vector
87+ y: y coordinate of normalized tangent vector
88+ z: z coordinate of normalized tangent vector
89+ """
90+ xdiff , ydiff = diff_on_edges_torus (
91+ vertex_x (E2V [0 ]),
92+ vertex_x (E2V [1 ]),
93+ vertex_y (E2V [0 ]),
94+ vertex_y (E2V [1 ]),
95+ domain_length ,
96+ domain_height ,
97+ )
98+ x = edge_orientation * xdiff
99+ y = edge_orientation * ydiff
100+ z = 0.0 * x
101+ # TODO(msimberg): This should use something like numpy.zeros_like if and
102+ # when that becomes available in gt4py.
103+
104+ return normalize_cartesian_vector_on_edges (x , y , z )
105+
106+
59107@gtx .field_operator
60108def cartesian_coordinates_of_edge_normal (
61109 edge_lat : fa .EdgeField [ta .wpfloat ],
@@ -93,6 +141,32 @@ def cartesian_coordinates_of_edge_normal(
93141 return normalize_cartesian_vector_on_edges (x , y , z )
94142
95143
144+ @gtx .field_operator
145+ def cartesian_coordinates_of_edge_normal_torus (
146+ edge_tangent_x : fa .EdgeField [ta .wpfloat ],
147+ edge_tangent_y : fa .EdgeField [ta .wpfloat ],
148+ ) -> tuple [
149+ fa .EdgeField [ta .wpfloat ],
150+ fa .EdgeField [ta .wpfloat ],
151+ fa .EdgeField [ta .wpfloat ],
152+ ]:
153+ """
154+ Compute the normal to the edge tangent vector on a torus grid.
155+
156+ Args:
157+ edge_tangent_x: x coordinate of the tangent
158+ edge_tangent_y: y coordinate of the tangent
159+ Returns:
160+ edge_normal_x: x coordinate of the normal
161+ edge_normal_y: y coordinate of the normal
162+ edge_normal_z: y coordinate of the normal
163+ """
164+ z = 0.0 * edge_tangent_x
165+ # TODO(msimberg): This should use something like numpy.zeros_like if and
166+ # when that becomes available in gt4py.
167+ return normalize_cartesian_vector_on_edges (- edge_tangent_y , edge_tangent_x , z )
168+
169+
96170@gtx .field_operator
97171def cartesian_coordinates_edge_tangent_and_normal (
98172 vertex_lat : fa .VertexField [ta .wpfloat ],
@@ -123,6 +197,59 @@ def cartesian_coordinates_edge_tangent_and_normal(
123197 return tangent_x , tangent_y , tangent_z , normal_x , normal_y , normal_z
124198
125199
200+ @gtx .field_operator
201+ def cartesian_coordinates_edge_tangent_and_normal_torus (
202+ vertex_x : fa .VertexField [ta .wpfloat ],
203+ vertex_y : fa .VertexField [ta .wpfloat ],
204+ edge_x : fa .EdgeField [ta .wpfloat ],
205+ edge_y : fa .EdgeField [ta .wpfloat ],
206+ edge_orientation : fa .EdgeField [ta .wpfloat ],
207+ domain_length : ta .wpfloat ,
208+ domain_height : ta .wpfloat ,
209+ ) -> tuple [
210+ fa .EdgeField [ta .wpfloat ],
211+ fa .EdgeField [ta .wpfloat ],
212+ fa .EdgeField [ta .wpfloat ],
213+ fa .EdgeField [ta .wpfloat ],
214+ fa .EdgeField [ta .wpfloat ],
215+ fa .EdgeField [ta .wpfloat ],
216+ fa .EdgeField [ta .wpfloat ],
217+ fa .EdgeField [ta .wpfloat ],
218+ fa .EdgeField [ta .wpfloat ],
219+ fa .EdgeField [ta .wpfloat ],
220+ ]:
221+ """Compute normalized cartesian vectors of edge tangent and edge normal."""
222+ tangent_x , tangent_y , tangent_z = cartesian_coordinates_of_edge_tangent_torus (
223+ vertex_x ,
224+ vertex_y ,
225+ edge_orientation ,
226+ domain_length ,
227+ domain_height ,
228+ )
229+ tangent_u = tangent_x
230+ tangent_v = tangent_y
231+
232+ normal_x , normal_y , normal_z = cartesian_coordinates_of_edge_normal_torus (
233+ tangent_x ,
234+ tangent_y ,
235+ )
236+ normal_u = normal_x
237+ normal_v = normal_y
238+
239+ return (
240+ tangent_x ,
241+ tangent_y ,
242+ tangent_z ,
243+ tangent_u ,
244+ tangent_v ,
245+ normal_x ,
246+ normal_y ,
247+ normal_z ,
248+ normal_u ,
249+ normal_v ,
250+ )
251+
252+
126253@gtx .program (grid_type = gtx .GridType .UNSTRUCTURED )
127254def compute_cartesian_coordinates_of_edge_tangent_and_normal (
128255 vertex_lat : fa .VertexField [ta .wpfloat ],
@@ -150,6 +277,52 @@ def compute_cartesian_coordinates_of_edge_tangent_and_normal(
150277 )
151278
152279
280+ @gtx .program (grid_type = gtx .GridType .UNSTRUCTURED )
281+ def compute_cartesian_coordinates_of_edge_tangent_and_normal_torus (
282+ vertex_x : fa .VertexField [ta .wpfloat ],
283+ vertex_y : fa .VertexField [ta .wpfloat ],
284+ edge_x : fa .EdgeField [ta .wpfloat ],
285+ edge_y : fa .EdgeField [ta .wpfloat ],
286+ edge_orientation : fa .EdgeField [ta .wpfloat ],
287+ tangent_x : fa .EdgeField [ta .wpfloat ],
288+ tangent_y : fa .EdgeField [ta .wpfloat ],
289+ tangent_z : fa .EdgeField [ta .wpfloat ],
290+ tangent_u : fa .EdgeField [ta .wpfloat ],
291+ tangent_v : fa .EdgeField [ta .wpfloat ],
292+ normal_x : fa .EdgeField [ta .wpfloat ],
293+ normal_y : fa .EdgeField [ta .wpfloat ],
294+ normal_z : fa .EdgeField [ta .wpfloat ],
295+ normal_u : fa .EdgeField [ta .wpfloat ],
296+ normal_v : fa .EdgeField [ta .wpfloat ],
297+ domain_length : ta .wpfloat ,
298+ domain_height : ta .wpfloat ,
299+ horizontal_start : gtx .int32 ,
300+ horizontal_end : gtx .int32 ,
301+ ):
302+ cartesian_coordinates_edge_tangent_and_normal_torus (
303+ vertex_x ,
304+ vertex_y ,
305+ edge_x ,
306+ edge_y ,
307+ edge_orientation ,
308+ domain_length ,
309+ domain_height ,
310+ out = (
311+ tangent_x ,
312+ tangent_y ,
313+ tangent_z ,
314+ tangent_u ,
315+ tangent_v ,
316+ normal_x ,
317+ normal_y ,
318+ normal_z ,
319+ normal_u ,
320+ normal_v ,
321+ ),
322+ domain = {dims .EdgeDim : (horizontal_start , horizontal_end )},
323+ )
324+
325+
153326@gtx .field_operator (grid_type = gtx .GridType .UNSTRUCTURED )
154327def zonal_and_meridional_component_of_edge_field_at_vertex (
155328 vertex_lat : fa .VertexField [ta .wpfloat ],
@@ -377,14 +550,14 @@ def arc_distance_of_far_edges_in_diamond(
377550
378551 Neighboring edges of an edge span up a diamond with 4 edges (E2C2E) and 4 vertices (E2C2V). Here we compute the
379552 arc length between the two vertices in this diamond that are not directly connected to the edge:
380- between d(v1 , v3)
381- v1 -------v4
553+ between d(v2 , v3)
554+ v2 -------v1
382555 | /|
383556 | / |
384557 | e |
385558 | / |
386559 |/ |
387- v2 ------v3
560+ v0 ------v3
388561
389562
390563
@@ -398,16 +571,47 @@ def arc_distance_of_far_edges_in_diamond(
398571
399572 """
400573 x , y , z = geographical_to_cartesian_on_vertices (vertex_lat , vertex_lon )
401- x2 = x (E2C2V [2 ])
402- x3 = x (E2C2V [3 ])
403- y2 = y (E2C2V [2 ])
404- y3 = y (E2C2V [3 ])
405- z2 = z (E2C2V [2 ])
406- z3 = z (E2C2V [3 ])
407- # (xi, yi, zi) are normalized by construction
574+ return arc_length_on_edges (
575+ x (E2C2V [2 ]),
576+ x (E2C2V [3 ]),
577+ y (E2C2V [2 ]),
578+ y (E2C2V [3 ]),
579+ z (E2C2V [2 ]),
580+ z (E2C2V [3 ]),
581+ radius ,
582+ )
408583
409- far_vertex_vertex_length = arc_length_on_edges (x2 , x3 , y2 , y3 , z2 , z3 , radius )
410- return far_vertex_vertex_length
584+
585+ @gtx .field_operator
586+ def distance_of_far_edges_in_diamond_torus (
587+ vertex_x : fa .VertexField [ta .wpfloat ],
588+ vertex_y : fa .VertexField [ta .wpfloat ],
589+ domain_length : ta .wpfloat ,
590+ domain_height : ta .wpfloat ,
591+ ) -> fa .EdgeField [ta .wpfloat ]:
592+ """
593+ Compute the distance between the "far" vertices of an edge on a torus grid.
594+
595+ See arc_distance_of_far_edges_in_diamond for details.
596+
597+ Args:
598+ vertex_x: x coordinate of vertices
599+ vertex_y: y coordinate of vertices
600+ domain_length: length of the domain
601+ domain_height: height of the domain
602+
603+ Returns:
604+ distance between the "far" vertices in the diamond.
605+
606+ """
607+ return distance_on_edges_torus (
608+ vertex_x (E2C2V [2 ]),
609+ vertex_x (E2C2V [3 ]),
610+ vertex_y (E2C2V [2 ]),
611+ vertex_y (E2C2V [3 ]),
612+ domain_length ,
613+ domain_height ,
614+ )
411615
412616
413617@gtx .field_operator
@@ -502,6 +706,26 @@ def compute_arc_distance_of_far_edges_in_diamond(
502706 )
503707
504708
709+ @gtx .program (grid_type = gtx .GridType .UNSTRUCTURED )
710+ def compute_distance_of_far_edges_in_diamond_torus (
711+ vertex_x : fa .VertexField [ta .wpfloat ],
712+ vertex_y : fa .VertexField [ta .wpfloat ],
713+ domain_length : ta .wpfloat ,
714+ domain_height : ta .wpfloat ,
715+ far_vertex_distance : fa .EdgeField [ta .wpfloat ],
716+ horizontal_start : gtx .int32 ,
717+ horizontal_end : gtx .int32 ,
718+ ):
719+ distance_of_far_edges_in_diamond_torus (
720+ vertex_x ,
721+ vertex_y ,
722+ domain_length ,
723+ domain_height ,
724+ out = far_vertex_distance ,
725+ domain = {dims .EdgeDim : (horizontal_start , horizontal_end )},
726+ )
727+
728+
505729@gtx .field_operator
506730def edge_area (
507731 owner_mask : fa .EdgeField [bool ],
@@ -557,6 +781,29 @@ def coriolis_parameter_on_edges(
557781 return 2.0 * angular_velocity * sin (edge_center_lat )
558782
559783
784+ def coriolis_parameter_on_edges_torus (
785+ coriolis_coefficient : float ,
786+ num_edges : int ,
787+ backend : gtx_typing .Backend ,
788+ ) -> fa .EdgeField [ta .wpfloat ]:
789+ """
790+ Create a coriolis parameter field on edges for a torus grid.
791+ Args:
792+ coriolis_coefficient: coriolis coefficient
793+
794+ Returns:
795+ coriolis parameter
796+ """
797+ xp = data_alloc .import_array_ns (backend )
798+ coriolis_parameter = gtx .as_field (
799+ (dims .EdgeDim ,),
800+ coriolis_coefficient * xp .ones (num_edges ),
801+ dtype = ta .wpfloat ,
802+ allocator = backend ,
803+ )
804+ return coriolis_parameter
805+
806+
560807@gtx .program (grid_type = gtx .GridType .UNSTRUCTURED )
561808def compute_coriolis_parameter_on_edges (
562809 edge_center_lat : fa .EdgeField [ta .wpfloat ],
@@ -574,11 +821,11 @@ def compute_coriolis_parameter_on_edges(
574821
575822
576823def compute_primal_cart_normal (
577- primal_cart_normal_x : alloc .NDArray ,
578- primal_cart_normal_y : alloc .NDArray ,
579- primal_cart_normal_z : alloc .NDArray ,
824+ primal_cart_normal_x : data_alloc .NDArray ,
825+ primal_cart_normal_y : data_alloc .NDArray ,
826+ primal_cart_normal_z : data_alloc .NDArray ,
580827 array_ns : ModuleType = np ,
581- ) -> alloc .NDArray :
828+ ) -> data_alloc .NDArray :
582829 primal_cart_normal = array_ns .transpose (
583830 array_ns .stack (
584831 (
0 commit comments