2323
2424import numpy as np
2525import numpy .linalg as la
26+ from meshmode .discretization .connection .direct import InterpolationBatch
2627
2728import logging
2829logger = logging .getLogger (__name__ )
@@ -43,15 +44,13 @@ def _make_cross_face_batches(actx,
4344 i_tgt_grp , i_src_grp ,
4445 tgt_bdry_element_indices , src_bdry_element_indices ):
4546
46- from meshmode .discretization .connection .direct import InterpolationBatch
4747 if tgt_bdry_discr .dim == 0 :
48- yield InterpolationBatch (
48+ return [ InterpolationBatch (
4949 from_group_index = i_src_grp ,
5050 from_element_indices = freeze_from_numpy (actx , src_bdry_element_indices ),
5151 to_element_indices = freeze_from_numpy (actx , tgt_bdry_element_indices ),
5252 result_unit_nodes = src_bdry_discr .groups [i_src_grp ].unit_nodes ,
53- to_element_face = None )
54- return
53+ to_element_face = None )]
5554
5655 tgt_bdry_nodes = np .array ([
5756 thaw_to_numpy (actx , ary [i_tgt_grp ])[tgt_bdry_element_indices ]
@@ -68,11 +67,74 @@ def _make_cross_face_batches(actx,
6867 src_mesh_grp = src_bdry_discr .mesh .groups [i_src_grp ]
6968 src_grp = src_bdry_discr .groups [i_src_grp ]
7069
70+ src_unit_nodes = _find_src_unit_nodes_by_matching (
71+ tgt_bdry_nodes = tgt_bdry_nodes ,
72+ src_bdry_nodes = src_bdry_nodes ,
73+ src_grp = src_grp , tol = tol )
74+ if src_unit_nodes is None :
75+ src_unit_nodes = _find_src_unit_nodes_via_gauss_newton (
76+ tgt_bdry_nodes = tgt_bdry_nodes ,
77+ src_bdry_nodes = src_bdry_nodes ,
78+ src_grp = src_grp , src_mesh_grp = src_mesh_grp ,
79+ tgt_bdry_discr = tgt_bdry_discr , src_bdry_discr = src_bdry_discr ,
80+ tol = tol )
81+
82+ return list (_find_src_unit_nodes_batches (
83+ actx = actx , src_unit_nodes = src_unit_nodes ,
84+ i_src_grp = i_src_grp ,
85+ tgt_bdry_element_indices = tgt_bdry_element_indices ,
86+ src_bdry_element_indices = src_bdry_element_indices ,
87+ tol = tol ))
88+
89+ # }}}
90+
91+
92+ # {{{ _find_src_unit_nodes_by_matching
93+
94+ def _find_src_unit_nodes_by_matching (
95+ tgt_bdry_nodes ,
96+ src_bdry_nodes ,
97+ src_grp , tol ):
98+ ambient_dim , nelements , ntgt_unit_nodes = tgt_bdry_nodes .shape
99+
100+ dist_vecs = (tgt_bdry_nodes .reshape (ambient_dim , nelements , - 1 , 1 )
101+ - src_bdry_nodes .reshape (ambient_dim , nelements , 1 , - 1 ))
102+
103+ # shape: (nelements, num_tgt_nodes, num_source_nodes)
104+ is_close = np .sqrt (np .sum (dist_vecs ** 2 , axis = 0 )) < tol
105+
106+ num_close_vertices = np .sum (is_close .astype (np .int32 ), axis = - 1 )
107+ if not (num_close_vertices == 1 ).all ():
108+ return None
109+
110+ # Success: it's just a permutation
111+ idx = np .empty_like (is_close , dtype = np .int32 )
112+ idx [:] = np .arange (src_grp .nunit_dofs ).reshape (1 , 1 , - 1 )
113+ source_indices = idx [is_close ].reshape (nelements , ntgt_unit_nodes )
114+
115+ # check
116+ matched_src_bdry_nodes = src_bdry_nodes [
117+ :, np .arange (nelements ).reshape (- 1 , 1 ), source_indices ]
118+ dist_vecs = tgt_bdry_nodes - matched_src_bdry_nodes
119+ is_close = np .sqrt (np .sum (dist_vecs ** 2 , axis = 0 )) < tol
120+ assert is_close .all ()
121+
122+ return src_grp .unit_nodes [:, source_indices ]
123+
124+ # }}}
125+
126+
127+ # {{{ _find_src_unit_nodes_via_gauss_newton
128+
129+ def _find_src_unit_nodes_via_gauss_newton (
130+ tgt_bdry_nodes ,
131+ src_bdry_nodes ,
132+ src_grp , src_mesh_grp ,
133+ tgt_bdry_discr , src_bdry_discr ,
134+ tol ):
71135 dim = src_grp .dim
72136 _ , nelements , ntgt_unit_nodes = tgt_bdry_nodes .shape
73137
74- # {{{ invert face map (using Gauss-Newton)
75-
76138 initial_guess = np .mean (src_mesh_grp .vertex_unit_coordinates (), axis = 0 )
77139 src_unit_nodes = np .empty ((dim , nelements , ntgt_unit_nodes ))
78140 src_unit_nodes [:] = initial_guess .reshape (- 1 , 1 , 1 )
@@ -162,7 +224,7 @@ def get_map_jacobian(unit_nodes):
162224
163225 # }}}
164226
165- logger .debug ("_make_cross_face_batches : begin gauss-newton " )
227+ logger .debug ("_find_src_unit_nodes_via_gauss_newton : begin" )
166228
167229 niter = 0
168230 while True :
@@ -223,18 +285,27 @@ def get_map_jacobian(unit_nodes):
223285 max_resid = np .max (np .abs (resid ))
224286
225287 if max_resid < tol :
226- logger .debug ("_make_cross_face_batches: gauss-newton : done, "
288+ logger .debug ("_find_src_unit_nodes_via_gauss_newton : done, "
227289 "final residual: %g" , max_resid )
228- break
290+ return src_unit_nodes
229291
230292 niter += 1
231293 if niter > 10 :
232294 raise RuntimeError ("Gauss-Newton (for finding opposite-face reference "
233295 "coordinates) did not converge (residual: %g)" % max_resid )
234296
235- # }}}
297+ raise AssertionError ()
236298
237- # {{{ find batches of src_unit_nodes
299+ # }}}
300+
301+
302+ # {{{ _find_src_unit_nodes_batches
303+
304+ def _find_src_unit_nodes_batches (
305+ actx , src_unit_nodes , i_src_grp ,
306+ tgt_bdry_element_indices , src_bdry_element_indices ,
307+ tol ):
308+ dim , nelements , _ = src_unit_nodes .shape
238309
239310 done_elements = np .zeros (nelements , dtype = bool )
240311 while True :
@@ -261,7 +332,7 @@ def get_map_jacobian(unit_nodes):
261332 result_unit_nodes = template_unit_nodes ,
262333 to_element_face = None )
263334
264- # }}}
335+ # }}}
265336
266337
267338def _find_ibatch_for_face (vbc_tgt_grp_batches , iface ):
0 commit comments