@@ -71,22 +71,39 @@ problemData problemOptions[] = {
7171// Auxiliary function to determine if nodes belong to cube faces (panels)
7272// -----------------------------------------------------------------------------
7373
74- PetscErrorCode FindPanelEdgeNodes (DM dm , PetscInt ncomp , PetscInt * nedgenodes ,
75- EdgeNode * edgenodes ) {
74+ PetscErrorCode FindPanelEdgeNodes (DM dm , PhysicsContext phys_ctx ,
75+ PetscInt ncomp , Mat * T ) {
7676
77- PetscInt ierr ;
78- PetscInt cstart , cend , nstart , nend , nnodes , depth , edgenode = 0 ;
77+ PetscInt ierr , rankid ;
78+ MPI_Comm comm ;
79+ PetscInt cstart , cend , nstart , nend , lnodes , gdofs , depth , edgenodecnt = 0 ;
7980 PetscSection section ;
81+ EdgeNode edgenodes ;
82+
8083 PetscFunctionBeginUser ;
8184 // Get Nelem
82- ierr = DMGetSection (dm , & section ); CHKERRQ (ierr );
85+ ierr = DMGetLocalSection (dm , & section ); CHKERRQ (ierr );
8386 ierr = DMPlexGetHeightStratum (dm , 0 , & cstart , & cend ); CHKERRQ (ierr );
8487 ierr = DMPlexGetDepth (dm , & depth ); CHKERRQ (ierr );
8588 ierr = DMPlexGetHeightStratum (dm , depth , & nstart , & nend ); CHKERRQ (ierr );
86- nnodes = nend - nstart ;
87- unsigned int bitmap [nnodes ];
89+ lnodes = nend - nstart ;
90+
91+ PetscSF sf ;
92+ Vec bitmapVec ;
93+ ierr = DMGetSectionSF (dm , & sf ); CHKERRQ (ierr );
94+ ierr = DMCreateGlobalVector (dm , & bitmapVec ); CHKERRQ (ierr );
95+ ierr = VecGetSize (bitmapVec , & gdofs ); CHKERRQ (ierr );
96+ ierr = VecDestroy (& bitmapVec );
97+
98+ // Arrays for local and global bitmaps
99+ unsigned int bitmaploc [lnodes * ncomp ];
100+ unsigned int bitmap [gdofs ];
88101 ierr = PetscMemzero (bitmap , sizeof (bitmap )); CHKERRQ (ierr );
89102
103+ // Broadcast bitmap values to all ranks
104+ ierr = PetscSFBcastBegin (sf , MPI_UNSIGNED , bitmap , bitmaploc ); CHKERRQ (ierr );
105+ ierr = PetscSFBcastEnd (sf , MPI_UNSIGNED , bitmap , bitmaploc ); CHKERRQ (ierr );
106+
90107 // Get indices
91108 for (PetscInt c = cstart ; c < cend ; c ++ ) { // Traverse elements
92109 PetscInt numindices , * indices , n , panel ;
@@ -96,49 +113,220 @@ PetscErrorCode FindPanelEdgeNodes(DM dm, PetscInt ncomp, PetscInt *nedgenodes,
96113 & numindices , & indices , NULL , NULL );
97114 CHKERRQ (ierr );
98115 for (n = 0 ; n < numindices ; n += ncomp ) { // Traverse nodes per element
99- PetscInt bitmapidx = indices [n ] / ncomp ;
100- bitmap [bitmapidx ] |= (1 << panel );
116+ PetscInt bitmapidx = indices [n ];
117+ bitmaploc [bitmapidx ] |= (1 << panel );
101118 }
102119 ierr = DMPlexRestoreClosureIndices (dm , section , section , c , PETSC_TRUE ,
103120 & numindices , & indices , NULL , NULL );
104121 CHKERRQ (ierr );
105122 }
106- // Read the 1's in the resulting bitmap and extract edge nodes only
107- ierr = PetscMalloc1 (nnodes + 24 , edgenodes ); CHKERRQ (ierr );
108- for (PetscInt i = 0 ; i < nnodes ; i ++ ) {
109- PetscInt ones = 0 , panels [3 ];
110- for (PetscInt p = 0 ; p < 6 ; p ++ ) {
111- if (bitmap [i ] & 1 )
112- panels [ones ++ ] = p ;
113- bitmap [i ] >>= 1 ;
114- }
115- if (ones == 2 ) {
116- (* edgenodes )[edgenode ].idx = i ;
117- (* edgenodes )[edgenode ].panelA = panels [0 ];
118- (* edgenodes )[edgenode ].panelB = panels [1 ];
119- edgenode ++ ;
123+
124+ // Reduce on all ranks
125+ ierr = PetscSFReduceBegin (sf , MPI_UNSIGNED , bitmaploc , bitmap , MPI_BOR );
126+ CHKERRQ (ierr );
127+ ierr = PetscSFReduceEnd (sf , MPI_UNSIGNED , bitmaploc , bitmap , MPI_BOR );
128+ CHKERRQ (ierr );
129+
130+ // Rank 0 reads the 1's in the resulting bitmap and extracts edge nodes only
131+ PetscObjectGetComm ((PetscObject )dm , & comm ); CHKERRQ (ierr );
132+ MPI_Comm_rank (comm , & rankid );
133+ if (rankid == 0 ) {
134+ ierr = PetscMalloc1 (gdofs + 24 * ncomp , & edgenodes ); CHKERRQ (ierr );
135+ for (PetscInt i = 0 ; i < gdofs ; i += ncomp ) {
136+ PetscInt ones = 0 , panels [3 ];
137+ for (PetscInt p = 0 ; p < 6 ; p ++ ) {
138+ if (bitmap [i ] & 1 )
139+ panels [ones ++ ] = p ;
140+ bitmap [i ] >>= 1 ;
141+ }
142+ if (ones == 2 ) {
143+ edgenodes [edgenodecnt ].idx = i ;
144+ edgenodes [edgenodecnt ].panelA = panels [0 ];
145+ edgenodes [edgenodecnt ].panelB = panels [1 ];
146+ edgenodecnt ++ ;
147+ }
148+ else if (ones == 3 ) {
149+ edgenodes [edgenodecnt ].idx = i ;
150+ edgenodes [edgenodecnt ].panelA = panels [0 ];
151+ edgenodes [edgenodecnt ].panelB = panels [1 ];
152+ edgenodecnt ++ ;
153+ edgenodes [edgenodecnt ].idx = i ;
154+ edgenodes [edgenodecnt ].panelA = panels [0 ];
155+ edgenodes [edgenodecnt ].panelB = panels [2 ];
156+ edgenodecnt ++ ;
157+ edgenodes [edgenodecnt ].idx = i ;
158+ edgenodes [edgenodecnt ].panelA = panels [1 ];
159+ edgenodes [edgenodecnt ].panelB = panels [2 ];
160+ edgenodecnt ++ ;
161+ }
120162 }
121- else if (ones == 3 ) {
122- (* edgenodes )[edgenode ].idx = i ;
123- (* edgenodes )[edgenode ].panelA = panels [0 ];
124- (* edgenodes )[edgenode ].panelB = panels [1 ];
125- edgenode ++ ;
126- (* edgenodes )[edgenode ].idx = i ;
127- (* edgenodes )[edgenode ].panelA = panels [0 ];
128- (* edgenodes )[edgenode ].panelB = panels [2 ];
129- edgenode ++ ;
130- (* edgenodes )[edgenode ].idx = i ;
131- (* edgenodes )[edgenode ].panelA = panels [1 ];
132- (* edgenodes )[edgenode ].panelB = panels [2 ];
133- edgenode ++ ;
163+ ierr = SetupPanelCoordTransformations (dm , phys_ctx , ncomp , edgenodes ,
164+ edgenodecnt , T ); CHKERRQ (ierr );
165+ // Free edgenodes structure array
166+ ierr = PetscFree (edgenodes ); CHKERRQ (ierr );
167+ }
168+
169+ PetscFunctionReturn (0 );
170+ }
171+
172+ // -----------------------------------------------------------------------------
173+ // Auxiliary function that sets up all corrdinate transformations between panels
174+ // -----------------------------------------------------------------------------
175+ PetscErrorCode SetupPanelCoordTransformations (DM dm , PhysicsContext phys_ctx ,
176+ PetscInt ncomp ,
177+ EdgeNode edgenodes ,
178+ PetscInt nedgenodes , Mat * T ) {
179+ PetscInt ierr ;
180+ MPI_Comm comm ;
181+ Vec X ;
182+ PetscInt gdofs ;
183+ const PetscScalar * xarray ;
184+
185+ PetscFunctionBeginUser ;
186+ ierr = PetscObjectGetComm ((PetscObject )dm , & comm ); CHKERRQ (ierr );
187+
188+ ierr = DMGetCoordinates (dm , & X ); CHKERRQ (ierr );
189+ ierr = VecGetSize (X , & gdofs ); CHKERRQ (ierr );
190+
191+ // Preallocate sparse matrix
192+ ierr = MatCreateBAIJ (comm , 2 , PETSC_DECIDE , PETSC_DECIDE , 4 * gdofs /ncomp ,
193+ 4 * gdofs /ncomp , 2 , NULL , 0 , NULL , T ); CHKERRQ (ierr );
194+ for (PetscInt i = 0 ; i < 4 * gdofs /ncomp ; i ++ ) {
195+ ierr = MatSetValue (* T , i , i , 1. , INSERT_VALUES ); CHKERRQ (ierr );
196+ }
197+
198+ ierr = VecGetArrayRead (X , & xarray ); CHKERRQ (ierr );
199+ PetscScalar R = phys_ctx -> R ;
200+ // Nodes loop
201+ for (PetscInt i = 0 ; i < gdofs ; i += ncomp ) {
202+ // Read global Cartesian coordinates
203+ PetscScalar x [3 ] = {xarray [i * ncomp + 0 ],
204+ xarray [i * ncomp + 1 ],
205+ xarray [i * ncomp + 2 ]
206+ };
207+ // Normalize quadrature point coordinates to sphere
208+ PetscScalar rad = sqrt (x [0 ]* x [0 ] + x [1 ]* x [1 ] + x [2 ]* x [2 ]);
209+ x [0 ] *= R / rad ;
210+ x [1 ] *= R / rad ;
211+ x [2 ] *= R / rad ;
212+ // Compute latitude and longitude
213+ const PetscScalar theta = asin (x [2 ] / R ); // latitude
214+ const PetscScalar lambda = atan2 (x [1 ], x [0 ]); // longitude
215+
216+ // For P_1 (east), P_3 (front), P_4 (west), P_5 (back):
217+ PetscScalar T00 = cos (theta )* cos (lambda ) * cos (lambda );
218+ PetscScalar T01 = cos (theta )* cos (lambda ) * 0. ;
219+ PetscScalar T10 = cos (theta )* cos (lambda ) * - sin (theta )* sin (lambda );
220+ PetscScalar T11 = cos (theta )* cos (lambda ) * cos (theta );
221+ const PetscScalar T_lateral [2 ][2 ] = {{T00 ,
222+ T01 },
223+ {T10 ,
224+ T11 }
225+ };
226+ PetscScalar Tinv00 = 1. /(cos (theta )* cos (lambda )) * (1. /cos (lambda ));
227+ PetscScalar Tinv01 = 1. /(cos (theta )* cos (lambda )) * 0. ;
228+ PetscScalar Tinv10 = 1. /(cos (theta )* cos (lambda )) * tan (theta )* tan (lambda );
229+ PetscScalar Tinv11 = 1. /(cos (theta )* cos (lambda )) * (1. /cos (theta ));
230+ const PetscScalar T_lateralinv [2 ][2 ] = {{Tinv00 ,
231+ Tinv01 },
232+ {Tinv10 ,
233+ Tinv11 }
234+ };
235+ // For P2 (north):
236+ T00 = sin (theta ) * cos (lambda );
237+ T01 = sin (theta ) * sin (lambda );
238+ T10 = sin (theta ) * - sin (theta )* sin (lambda );
239+ T11 = sin (theta ) * sin (theta )* cos (lambda );
240+ const PetscScalar T_top [2 ][2 ] = {{T00 ,
241+ T01 },
242+ {T10 ,
243+ T11 }
244+ };
245+ Tinv00 = 1. /(sin (theta )* sin (theta )) * sin (theta )* cos (lambda );
246+ Tinv01 = 1. /(sin (theta )* sin (theta )) * (- sin (lambda ));
247+ Tinv10 = 1. /(sin (theta )* sin (theta )) * sin (theta )* sin (lambda );
248+ Tinv11 = 1. /(sin (theta )* sin (theta )) * cos (lambda );
249+ const PetscScalar T_topinv [2 ][2 ] = {{Tinv00 ,
250+ Tinv01 },
251+ {Tinv10 ,
252+ Tinv11 }
253+ };
254+
255+ // For P0 (south):
256+ T00 = sin (theta ) * (- cos (theta ));
257+ T01 = sin (theta ) * sin (lambda );
258+ T10 = sin (theta ) * sin (theta )* sin (lambda );
259+ T11 = sin (theta ) * sin (theta )* cos (lambda );
260+ const PetscScalar T_bottom [2 ][2 ] = {{T00 ,
261+ T01 },
262+ {T10 ,
263+ T11 }
264+ };
265+ Tinv00 = 1. /(sin (theta )* sin (theta )) * (- sin (theta )* cos (lambda ));
266+ Tinv01 = 1. /(sin (theta )* sin (theta )) * sin (lambda );
267+ Tinv10 = 1. /(sin (theta )* sin (theta )) * sin (theta )* sin (lambda );
268+ Tinv11 = 1. /(sin (theta )* sin (theta )) * cos (lambda );
269+ const PetscScalar T_bottominv [2 ][2 ] = {{Tinv00 ,
270+ Tinv01 },
271+ {Tinv10 ,
272+ Tinv11 }
273+ };
274+
275+ const PetscScalar (* transforms [6 ])[2 ][2 ] = {& T_bottom ,
276+ & T_lateral ,
277+ & T_top ,
278+ & T_lateral ,
279+ & T_lateral ,
280+ & T_lateral
281+ };
282+
283+ const PetscScalar (* inv_transforms [6 ])[2 ][2 ] = {& T_bottominv ,
284+ & T_lateralinv ,
285+ & T_topinv ,
286+ & T_lateralinv ,
287+ & T_lateralinv ,
288+ & T_lateralinv
289+ };
290+
291+ for (PetscInt e = 0 ; e < nedgenodes ; e ++ ) {
292+ if (edgenodes [e ].idx == i ) {
293+ const PetscScalar (* matrixA )[2 ][2 ] = inv_transforms [edgenodes [e ].panelA ];
294+ const PetscScalar (* matrixB )[2 ][2 ] = transforms [edgenodes [e ].panelB ];
295+
296+ // inv_transform * transform (A^{-1}*B)
297+ // This product represents the mapping from coordinate system A
298+ // to spherical coordinates and then to coordinate system B. Vice versa
299+ // for transform * inv_transform (B^{-1}*A)
300+ PetscScalar matrixAB [2 ][2 ], matrixBA [2 ][2 ];
301+ for (int j = 0 ; j < 2 ; j ++ ) {
302+ for (int k = 0 ; k < 2 ; k ++ ) {
303+ matrixAB [j ][k ] = matrixBA [j ][k ] = 0 ;
304+ for (int l = 0 ; l < 2 ; l ++ ) {
305+ matrixAB [j ][k ] += (* matrixA )[j ][l ] * (* matrixB )[l ][k ];
306+ matrixBA [j ][k ] += (* matrixB )[j ][l ] * (* matrixA )[l ][k ];
307+ }
308+ }
309+ }
310+ PetscInt idxAB [2 ] = {4 * i /ncomp + 0 , 4 * i /ncomp + 1 };
311+ PetscInt idxBA [2 ] = {4 * i /ncomp + 2 , 4 * i /ncomp + 3 };
312+ ierr = MatSetValues (* T , 2 , idxAB , 2 , idxAB , (PetscScalar * )matrixAB ,
313+ INSERT_VALUES ); CHKERRQ (ierr );
314+ ierr = MatSetValues (* T , 2 , idxBA , 2 , idxBA , (PetscScalar * )matrixBA ,
315+ INSERT_VALUES ); CHKERRQ (ierr );
316+ }
134317 }
135318 }
136- ierr = PetscRealloc (edgenode , edgenodes ); CHKERRQ (ierr );
137- * nedgenodes = edgenode ;
319+ // Assemble matrix for all node transformations
320+ ierr = MatAssemblyBegin (* T , MAT_FINAL_ASSEMBLY ); CHKERRQ (ierr );
321+ ierr = MatAssemblyEnd (* T , MAT_FINAL_ASSEMBLY ); CHKERRQ (ierr );
322+
323+ // Restore array read
324+ ierr = VecRestoreArrayRead (X , & xarray ); CHKERRQ (ierr );
138325
139326 PetscFunctionReturn (0 );
140327}
141328
329+
142330// -----------------------------------------------------------------------------
143331// Auxiliary function to create PETSc FE space for a given degree
144332// -----------------------------------------------------------------------------
0 commit comments