1
2
3
4
5
6
7
8 #ifdef WIN32
9 #define _USE_MATH_DEFINES
10 #endif
11
12 #pragma GCC diagnostic push
13 #pragma GCC diagnostic ignored "-Wdeprecated-copy-with-user-provided-copy"
14 #pragma GCC diagnostic ignored "-Wsign-compare"
15
16 #include "Announce.h"
17 #include "DataArray3D.h"
18 #include "FiniteElementTools.h"
19 #include "FiniteVolumeTools.h"
20 #include "GaussLobattoQuadrature.h"
21 #include "TriangularQuadrature.h"
22 #include "MathHelper.h"
23 #include "SparseMatrix.h"
24 #include "OverlapMesh.h"
25
26 #include "DebugOutput.hpp"
27 #include "moab/AdaptiveKDTree.hpp"
28
29 #include "moab/Remapping/TempestOnlineMap.hpp"
30 #include "moab/TupleList.hpp"
31 #include "moab/MeshTopoUtil.hpp"
32
33 #pragma GCC diagnostic pop
34
35 #include <fstream>
36 #include <cmath>
37 #include <cstdlib>
38 #include <sstream>
39 #include <numeric>
40 #include <algorithm>
41 #include <unordered_set>
42
43
44 #define USE_ComputeAdjacencyRelations
45
46
47
48
49 typedef std::pair< int, int > FaceDistancePair;
50
51
52
53
54 typedef std::vector< FaceDistancePair > AdjacentFaceVector;
55
56
57
58 moab::ErrorCode moab::TempestOnlineMap::LinearRemapNN_MOAB( bool use_GID_matching, bool strict_check )
59 {
60
61
62 #ifdef VVERBOSE
63 {
64 std::ofstream output_file( "rowcolindices.txt", std::ios::out );
65 output_file << m_nTotDofs_Dest << " " << m_nTotDofs_SrcCov << " " << row_gdofmap.size() << " "
66 << row_ldofmap.size() << " " << col_gdofmap.size() << " " << col_ldofmap.size() << "\n";
67 output_file << "Rows \n";
68 for( unsigned iv = 0; iv < row_gdofmap.size(); iv++ )
69 output_file << row_gdofmap[iv] << " " << row_dofmap[iv] << "\n";
70 output_file << "Cols \n";
71 for( unsigned iv = 0; iv < col_gdofmap.size(); iv++ )
72 output_file << col_gdofmap[iv] << " " << col_dofmap[iv] << "\n";
73 output_file.flush();
74 output_file.close();
75 }
76 #endif
77
78 if( use_GID_matching )
79 {
80 std::map< unsigned, unsigned > src_gl;
81 for( unsigned it = 0; it < col_gdofmap.size(); ++it )
82 src_gl[col_gdofmap[it]] = it;
83
84 std::map< unsigned, unsigned >::iterator iter;
85 for( unsigned it = 0; it < row_gdofmap.size(); ++it )
86 {
87 unsigned row = row_gdofmap[it];
88 iter = src_gl.find( row );
89 if( strict_check && iter == src_gl.end() )
90 {
91 std::cout << "Searching for global target DOF " << row
92 << " but could not find correspondence in source mesh.\n";
93 assert( false );
94 }
95 else if( iter == src_gl.end() )
96 {
97 continue;
98 }
99 else
100 {
101 unsigned icol = src_gl[row];
102 unsigned irow = it;
103
104
105 m_mapRemap( irow, icol ) = 1.0;
106 }
107 }
108
109 return moab::MB_SUCCESS;
110 }
111 else
112 {
113
114
115 return moab::MB_FAILURE;
116 }
117 }
118
119
120
121 void moab::TempestOnlineMap::LinearRemapFVtoFV_Tempest_MOAB( int nOrder )
122 {
123
124 const int TriQuadRuleOrder = 4;
125
126
127 if( m_meshInputCov->faces.size() > 0 && m_meshInputCov->revnodearray.size() == 0 )
128 {
129 _EXCEPTIONT( "ReverseNodeArray has not been calculated for m_meshInputCov" );
130 }
131
132
133 TriangularQuadratureRule triquadrule( TriQuadRuleOrder );
134
135
136 #ifdef RECTANGULAR_TRUNCATION
137 int nCoefficients = nOrder * nOrder;
138 #endif
139 #ifdef TRIANGULAR_TRUNCATION
140 int nCoefficients = nOrder * ( nOrder + 1 ) / 2;
141 #endif
142
143
144 const int nRequiredFaceSetSize = nCoefficients;
145
146
147 const int nFitWeightsExponent = nOrder + 2;
148
149
150 moab::DebugOutput dbgprint( std::cout, this->rank, 0 );
151 dbgprint.set_prefix( "[LinearRemapFVtoFV_Tempest_MOAB]: " );
152 if( is_root )
153 {
154 dbgprint.printf( 0, "Finite Volume to Finite Volume Projection\n" );
155 dbgprint.printf( 0, "Triangular quadrature rule order %i\n", TriQuadRuleOrder );
156 dbgprint.printf( 0, "Number of coefficients: %i\n", nCoefficients );
157 dbgprint.printf( 0, "Required adjacency set size: %i\n", nRequiredFaceSetSize );
158 dbgprint.printf( 0, "Fit weights exponent: %i\n", nFitWeightsExponent );
159 }
160
161
162 int ixOverlap = 0;
163 #ifdef VERBOSE
164 const unsigned outputFrequency = ( m_meshInputCov->faces.size() / 10 ) + 1;
165 #endif
166 DataArray2D< double > dIntArray;
167 DataArray1D< double > dConstraint( nCoefficients );
168
169
170 for( size_t ixFirst = 0; ixFirst < m_meshInputCov->faces.size(); ixFirst++ )
171 {
172
173 #ifdef VERBOSE
174 if( ixFirst % outputFrequency == 0 && is_root )
175 {
176 dbgprint.printf( 0, "Element %zu/%lu\n", ixFirst, m_meshInputCov->faces.size() );
177 }
178 #endif
179
180 int ixOverlapBegin = ixOverlap;
181 unsigned ixOverlapEnd = ixOverlapBegin;
182
183 for( ; ixOverlapEnd < m_meshOverlap->faces.size(); ixOverlapEnd++ )
184 {
185 if( ixFirst - m_meshOverlap->vecSourceFaceIx[ixOverlapEnd] != 0 ) break;
186 }
187
188 unsigned nOverlapFaces = ixOverlapEnd - ixOverlapBegin;
189
190 if( nOverlapFaces == 0 ) continue;
191
192
193 BuildIntegrationArray( *m_meshInputCov, *m_meshOverlap, triquadrule, ixFirst, ixOverlapBegin, ixOverlapEnd,
194 nOrder, dIntArray );
195
196
197
198 AdjacentFaceVector vecAdjFaces;
199
200 GetAdjacentFaceVectorByEdge( *m_meshInputCov, ixFirst, nRequiredFaceSetSize, vecAdjFaces );
201
202
203 int nAdjFaces = vecAdjFaces.size();
204
205
206 double dFirstArea = m_meshInputCov->vecFaceArea[ixFirst];
207 dConstraint.Zero();
208 for( int p = 0; p < nCoefficients; p++ )
209 {
210 for( unsigned j = 0; j < nOverlapFaces; j++ )
211 {
212 dConstraint[p] += dIntArray[p][j];
213 }
214 dConstraint[p] /= dFirstArea;
215 }
216
217
218 DataArray2D< double > dFitArray;
219 DataArray1D< double > dFitWeights;
220 DataArray2D< double > dFitArrayPlus;
221
222 BuildFitArray( *m_meshInputCov, triquadrule, ixFirst, vecAdjFaces, nOrder, nFitWeightsExponent, dConstraint,
223 dFitArray, dFitWeights );
224
225
226 bool fSuccess = InvertFitArray_Corrected( dConstraint, dFitArray, dFitWeights, dFitArrayPlus );
227
228
229 DataArray2D< double > dComposedArray( nAdjFaces, nOverlapFaces );
230 if( fSuccess )
231 {
232
233 for( int i = 0; i < nAdjFaces; i++ )
234 {
235 for( size_t j = 0; j < nOverlapFaces; j++ )
236 {
237 for( int k = 0; k < nCoefficients; k++ )
238 {
239 dComposedArray( i, j ) += dIntArray( k, j ) * dFitArrayPlus( i, k );
240 }
241 }
242 }
243
244
245
246 }
247 else
248 {
249 dComposedArray.Zero();
250 for( size_t j = 0; j < nOverlapFaces; j++ )
251 {
252 dComposedArray( 0, j ) += dIntArray( 0, j );
253 }
254 }
255
256
257 for( unsigned i = 0; i < vecAdjFaces.size(); i++ )
258 {
259 for( unsigned j = 0; j < nOverlapFaces; j++ )
260 {
261 int& ixFirstFaceLoc = vecAdjFaces[i].first;
262 int& ixSecondFaceLoc = m_meshOverlap->vecTargetFaceIx[ixOverlap + j];
263
264
265
266
267
268 if( ixSecondFaceLoc < 0 ) continue;
269
270 m_mapRemap( ixSecondFaceLoc, ixFirstFaceLoc ) +=
271 dComposedArray[i][j] / m_meshOutput->vecFaceArea[ixSecondFaceLoc];
272 }
273 }
274
275
276 ixOverlap += nOverlapFaces;
277 }
278
279 return;
280 }
281
282
283
284 void moab::TempestOnlineMap::PrintMapStatistics()
285 {
286 int nrows = m_weightMatrix.rows();
287 int ncols = m_weightMatrix.cols();
288 int NNZ = m_weightMatrix.nonZeros();
289 #ifdef MOAB_HAVE_MPI
290
291
292 int arr3[6] = { NNZ, nrows, ncols, -NNZ, -nrows, -ncols };
293 int rarr3[6];
294 MPI_Reduce( arr3, rarr3, 6, MPI_INT, MPI_MIN, 0, m_pcomm->comm() );
295
296 int total[3];
297 MPI_Reduce( arr3, total, 3, MPI_INT, MPI_SUM, 0, m_pcomm->comm() );
298 if( !rank )
299 std::cout << "-> Rows (min/max/sum): (" << rarr3[1] << " / " << -rarr3[4] << " / " << total[1] << "), "
300 << " Cols (min/max/sum): (" << rarr3[2] << " / " << -rarr3[5] << " / " << total[2] << "), "
301 << " NNZ (min/max/sum): (" << rarr3[0] << " / " << -rarr3[3] << " / " << total[0] << ")\n";
302 #else
303 std::cout << "-> Rows: " << nrows << ", Cols: " << ncols << ", NNZ: " << NNZ << "\n";
304 #endif
305 }
306
307 #ifdef MOAB_HAVE_EIGEN3
308 void moab::TempestOnlineMap::copy_tempest_sparsemat_to_eigen3()
309 {
310 #ifndef VERBOSE
311 #define VERBOSE_ACTIVATED
312
313 #endif
314
315
316 m_weightMatrix.resize( m_nTotDofs_Dest, m_nTotDofs_SrcCov );
317 m_rowVector.resize( m_weightMatrix.rows() );
318 m_colVector.resize( m_weightMatrix.cols() );
319
320 #ifdef VERBOSE
321 int locrows = std::max( m_mapRemap.GetRows(), m_nTotDofs_Dest );
322 int loccols = std::max( m_mapRemap.GetColumns(), m_nTotDofs_SrcCov );
323
324 std::cout << m_weightMatrix.rows() << ", " << locrows << ", " << m_weightMatrix.cols() << ", " << loccols << "\n";
325
326 #endif
327
328 DataArray1D< int > lrows;
329 DataArray1D< int > lcols;
330 DataArray1D< double > lvals;
331 m_mapRemap.GetEntries( lrows, lcols, lvals );
332 size_t locvals = lvals.GetRows();
333
334
335 typedef Eigen::Triplet< double > Triplet;
336 std::vector< Triplet > tripletList;
337 tripletList.reserve( locvals );
338 for( size_t iv = 0; iv < locvals; iv++ )
339 {
340 tripletList.push_back( Triplet( lrows[iv], lcols[iv], lvals[iv] ) );
341 }
342 m_weightMatrix.setFromTriplets( tripletList.begin(), tripletList.end() );
343 m_weightMatrix.makeCompressed();
344
345 #ifdef VERBOSE
346 std::stringstream sstr;
347 sstr << "tempestmatrix.txt.0000" << rank;
348 std::ofstream output_file( sstr.str(), std::ios::out );
349 output_file << "0 " << locrows << " 0 " << loccols << "\n";
350 for( unsigned iv = 0; iv < locvals; iv++ )
351 {
352
353
354
355 output_file << row_gdofmap[row_ldofmap[lrows[iv]]] << " " << col_gdofmap[col_ldofmap[lcols[iv]]] << " "
356 << lvals[iv] << "\n";
357 }
358 output_file.flush();
359 output_file.close();
360 #endif
361
362 #ifdef VERBOSE_ACTIVATED
363 #undef VERBOSE_ACTIVATED
364 #undef VERBOSE
365 #endif
366 return;
367 }
368
369
370
371 template < typename T >
372 static std::vector< size_t > sort_indexes( const std::vector< T >& v )
373 {
374
375 std::vector< size_t > idx( v.size() );
376 std::iota( idx.begin(), idx.end(), 0 );
377
378
379
380
381
382 std::stable_sort( idx.begin(), idx.end(), [&v]( size_t i1, size_t i2 ) { return fabs( v[i1] ) > fabs( v[i2] ); } );
383
384 return idx;
385 }
386
387 double moab::TempestOnlineMap::QLTLimiter( int caasIteration,
388 std::vector< double >& dataCorrectedField,
389 std::vector< double >& dataLowerBound,
390 std::vector< double >& dataUpperBound,
391 std::vector< double >& dMassDefect )
392 {
393 const size_t nrows = dataCorrectedField.size();
394 double dMassL = 0.0;
395 double dMassU = 0.0;
396 std::vector< double > dataCorrection( nrows );
397 double dMassDiffCum = 0.0;
398 double dLMinusU = fabs( dataUpperBound[0] - dataLowerBound[0] );
399 const DataArray1D< double >& dTargetAreas = this->m_remapper->m_target->vecFaceArea;
400
401
402 std::vector< std::unordered_set< int > > vecAdjTargetFaces( nrows );
403 constexpr bool useMOABAdjacencies = true;
404 #ifdef USE_ComputeAdjacencyRelations
405 if( useMOABAdjacencies )
406 ComputeAdjacencyRelations( vecAdjTargetFaces, caasIteration, m_remapper->m_target_entities,
407 useMOABAdjacencies );
408 else
409 ComputeAdjacencyRelations( vecAdjTargetFaces, caasIteration, m_remapper->m_target_entities, useMOABAdjacencies,
410 this->m_remapper->m_target );
411 #else
412 moab::MeshTopoUtil mtu( m_interface );
413 ;
414 #endif
415
416 for( size_t i = 0; i < nrows; i++ )
417 {
418
419 size_t index = i;
420 dataCorrection[index] = fmax( dataLowerBound[index], fmin( dataUpperBound[index], 0.0 ) );
421
422
423
424 dMassL += dTargetAreas[index] * dataLowerBound[index];
425 dMassU += dTargetAreas[index] * dataUpperBound[index];
426 dLMinusU = fmax( dLMinusU, fabs( dataUpperBound[index] - dataLowerBound[index] ) );
427 dMassDiffCum += dMassDefect[index] - dTargetAreas[index] * dataCorrection[index];
428
429 #ifndef USE_ComputeAdjacencyRelations
430 vecAdjTargetFaces[index].insert( index );
431 {
432
433 if( useMOABAdjacencies )
434 {
435 moab::Range ents;
436
437 ents.insert( m_remapper->m_target_entities[index] );
438 moab::Range adjEnts;
439 moab::ErrorCode rval = mtu.get_bridge_adjacencies( ents, 0, 2, adjEnts, caasIteration );MB_CHK_SET_ERR_CONT( rval, "Failed to get adjacent faces" );
440 for( moab::Range::iterator it = adjEnts.begin(); it != adjEnts.end(); ++it )
441 {
442
443 int adjIndex = m_remapper->m_target_entities.index( *it );
444
445 if( adjIndex >= 0 ) vecAdjTargetFaces[index].insert( adjIndex );
446 }
447 }
448 else
449 {
450 AdjacentFaceVector vecAdjFaces;
451 GetAdjacentFaceVectorByEdge( *this->m_remapper->m_target, index,
452 ( m_output_order + 1 ) * ( m_output_order + 1 ) * ( m_output_order + 1 ),
453
454
455 vecAdjFaces );
456
457
458 for( auto adjFace : vecAdjFaces )
459 if( adjFace.first >= 0 )
460 vecAdjTargetFaces[index].insert( adjFace.first );
461 }
462 }
463 #endif
464 }
465
466 #ifdef MOAB_HAVE_MPI
467 std::vector< double > localDefects( 5, 0.0 ), globalDefects( 5, 0.0 );
468 localDefects[0] = dMassL;
469 localDefects[1] = dMassU;
470 localDefects[2] = dMassDiffCum;
471 localDefects[3] = dLMinusU;
472
473
474 MPI_Allreduce( localDefects.data(), globalDefects.data(), 4, MPI_DOUBLE, MPI_SUM, m_pcomm->comm() );
475
476 dMassL = globalDefects[0];
477 dMassU = globalDefects[1];
478 dMassDiffCum = globalDefects[2];
479 dLMinusU = globalDefects[3];
480
481 #endif
482
483
484 if( fabs( dMassDiffCum ) < 1e-15 || dLMinusU < 1e-15 )
485 {
486 for( size_t i = 0; i < nrows; i++ )
487 dataCorrectedField[i] += dataCorrection[i];
488 return dMassDiffCum;
489 }
490 else
491 {
492 if( dMassL > dMassDiffCum )
493 {
494 Announce( "Lower bound mass exceeds target mass by %1.15e: CAAS will need another iteration",
495 dMassL - dMassDiffCum );
496 dMassDiffCum = dMassL;
497
498 }
499 else if( dMassU < dMassDiffCum )
500 {
501 Announce( "Target mass exceeds upper bound mass by %1.15e: CAAS will need another iteration",
502 dMassDiffCum - dMassU );
503 dMassDiffCum = dMassU;
504
505 }
506
507
508
509 for( size_t i = 0; i < nrows; i++ )
510 {
511
512 size_t index = i;
513 const std::unordered_set< int >& neighbors = vecAdjTargetFaces[index];
514 if( dMassDefect[index] > 0.0 )
515 {
516 double dMassCorrectU = 0.0;
517 for( auto it : neighbors )
518 dMassCorrectU += dTargetAreas[it] * ( dataUpperBound[it] - dataCorrection[it] );
519
520
521 for( auto it : neighbors )
522 dataCorrection[it] +=
523 dMassDefect[index] * ( dataUpperBound[it] - dataCorrection[it] ) / dMassCorrectU;
524 }
525 else
526 {
527 double dMassCorrectL = 0.0;
528 for( auto it : neighbors )
529 dMassCorrectL += dTargetAreas[it] * ( dataCorrection[it] - dataLowerBound[it] );
530
531
532 for( auto it : neighbors )
533 dataCorrection[it] +=
534 dMassDefect[index] * ( dataCorrection[it] - dataLowerBound[it] ) / dMassCorrectL;
535 }
536 }
537
538 for( size_t i = 0; i < nrows; i++ )
539 dataCorrectedField[i] += dataCorrection[i];
540 }
541
542 return dMassDiffCum;
543 }
544
545 void moab::TempestOnlineMap::CAASLimiter( std::vector< double >& dataCorrectedField,
546 std::vector< double >& dataLowerBound,
547 std::vector< double >& dataUpperBound,
548 double& dMass )
549 {
550 const size_t nrows = dataCorrectedField.size();
551 double dMassL = 0.0;
552 double dMassU = 0.0;
553 std::vector< double > dataCorrection( nrows );
554 const DataArray1D< double >& dTargetAreas = this->m_remapper->m_target->vecFaceArea;
555 double dMassDiff = dMass;
556 double dLMinusU = fabs( dataUpperBound[0] - dataLowerBound[0] );
557 double dMassCorrectU = 0.0;
558 double dMassCorrectL = 0.0;
559 for( size_t i = 0; i < nrows; i++ )
560 {
561 dataCorrection[i] = fmax( dataLowerBound[i], fmin( dataUpperBound[i], 0.0 ) );
562 dMassL += dTargetAreas[i] * dataLowerBound[i];
563 dMassU += dTargetAreas[i] * dataUpperBound[i];
564 dMassDiff -= dTargetAreas[i] * dataCorrection[i];
565 dLMinusU = fmax( dLMinusU, fabs( dataUpperBound[i] - dataLowerBound[i] ) );
566 dMassCorrectL += dTargetAreas[i] * ( dataCorrection[i] - dataLowerBound[i] );
567 dMassCorrectU += dTargetAreas[i] * ( dataUpperBound[i] - dataCorrection[i] );
568 }
569
570 #ifdef MOAB_HAVE_MPI
571 std::vector< double > localDefects( 5, 0.0 ), globalDefects( 5, 0.0 );
572 localDefects[0] = dMassL;
573 localDefects[1] = dMassU;
574 localDefects[2] = dMassDiff;
575 localDefects[3] = dMassCorrectL;
576 localDefects[4] = dMassCorrectU;
577
578 MPI_Allreduce( localDefects.data(), globalDefects.data(), 5, MPI_DOUBLE, MPI_SUM, m_pcomm->comm() );
579
580 dMassL = globalDefects[0];
581 dMassU = globalDefects[1];
582 dMassDiff = globalDefects[2];
583 dMassCorrectL = globalDefects[3];
584 dMassCorrectU = globalDefects[4];
585 #endif
586
587
588 if( fabs( dMassDiff ) < 1e-15 || fabs( dLMinusU ) < 1e-15 )
589 {
590 for( size_t i = 0; i < nrows; i++ )
591 dataCorrectedField[i] += dataCorrection[i];
592 return;
593 }
594 else
595 {
596 if( dMassL > dMassDiff )
597 {
598 Announce( "%d: Lower bound mass exceeds target mass by %1.15e: CAAS will need another iteration", rank,
599 dMassL - dMassDiff );
600 dMassDiff = dMassL;
601 dMass -= dMassL;
602 }
603 else if( dMassU < dMassDiff )
604 {
605 Announce( "%d: Target mass exceeds upper bound mass by %1.15e: CAAS will need another iteration", rank,
606 dMassDiff - dMassU );
607 dMassDiff = dMassU;
608 dMass -= dMassU;
609 }
610
611
612 DataArray1D< double > dataMassVec( nrows );
613 if( dMassDiff > 0.0 )
614 {
615 for( size_t i = 0; i < nrows; i++ )
616 {
617 dataMassVec[i] = ( dataUpperBound[i] - dataCorrection[i] ) / dMassCorrectU;
618 dataCorrection[i] += dMassDiff * dataMassVec[i];
619 }
620 }
621 else
622 {
623 for( size_t i = 0; i < nrows; i++ )
624 {
625 dataMassVec[i] = ( dataCorrection[i] - dataLowerBound[i] ) / dMassCorrectL;
626 dataCorrection[i] += dMassDiff * dataMassVec[i];
627 }
628 }
629
630 for( size_t i = 0; i < nrows; i++ )
631 dataCorrectedField[i] += dataCorrection[i];
632 }
633
634 return;
635 }
636
637 std::pair< double, double > moab::TempestOnlineMap::ApplyBoundsLimiting( std::vector< double >& dataInDouble,
638 std::vector< double >& dataOutDouble,
639 CAASType caasType,
640 int caasIteration,
641 double mismatch )
642 {
643
644
645 assert( !dataGLLNodesSrcCov.IsAttached() && !dataGLLNodesDest.IsAttached() );
646
647 std::pair< double, double > massDefect( 0.0, 0.0 );
648
649
650 const size_t nTargetCount = dataOutDouble.size();
651 const DataArray1D< double >& m_dOverlapAreas = this->m_remapper->m_overlap->vecFaceArea;
652
653
654 double dMassDiff = 0.0;
655 std::vector< double > x( nTargetCount );
656 std::vector< double > dataLowerBound( nTargetCount );
657 std::vector< double > dataUpperBound( nTargetCount );
658 std::vector< double > massVector( nTargetCount );
659 std::vector< std::unordered_set< int > > vecSourceOvTarget( nTargetCount );
660
661 #undef USE_ComputeAdjacencyRelations
662 constexpr bool useMOABAdjacencies = true;
663 #ifdef USE_ComputeAdjacencyRelations
664
665
666
667 if( caasType == CAAS_QLT || caasType == CAAS_LOCAL_ADJACENT )
668 {
669 if( useMOABAdjacencies )
670 {
671 moab::ErrorCode rval =
672 ComputeAdjacencyRelations( vecSourceOvTarget, caasIteration, m_remapper->m_covering_source_entities,
673 useMOABAdjacencies );MB_CHK_SET_ERR_CONT( rval, "Failed to get adjacent faces" );
674 }
675 else
676 {
677 moab::ErrorCode rval =
678 ComputeAdjacencyRelations( vecSourceOvTarget, caasIteration, m_remapper->m_covering_source_entities,
679 useMOABAdjacencies, m_meshInputCov );MB_CHK_SET_ERR_CONT( rval, "Failed to get adjacent faces" );
680 }
681 }
682 #else
683 moab::MeshTopoUtil mtu( m_interface );
684 #endif
685
686
687 double dSourceMin = dataInDouble[0];
688 double dSourceMax = dataInDouble[0];
689 double dTargetMin = dataOutDouble[0];
690 double dTargetMax = dataOutDouble[0];
691 for( size_t i = 0; i < m_meshOverlap->faces.size(); i++ )
692 {
693 const int ixS = m_meshOverlap->vecSourceFaceIx[i];
694 const int ixT = m_meshOverlap->vecTargetFaceIx[i];
695
696 if( ixT < 0 ) continue;
697
698 assert( m_dOverlapAreas[i] > 0.0 );
699 assert( ixS >= 0 );
700 assert( ixT >= 0 );
701
702 #ifndef USE_ComputeAdjacencyRelations
703
704 vecSourceOvTarget[ixT].insert( ixS );
705 if( ( caasType == CAAS_QLT || caasType == CAAS_LOCAL_ADJACENT ) )
706 {
707 if( useMOABAdjacencies )
708 {
709 moab::Range ents;
710 ents.insert( m_remapper->m_covering_source_entities[ixS] );
711 moab::Range adjEnts;
712 moab::ErrorCode rval = mtu.get_bridge_adjacencies( ents, 0, 2, adjEnts, caasIteration );MB_CHK_SET_ERR_CONT( rval, "Failed to get adjacent faces" );
713 for( moab::Range::iterator it = adjEnts.begin(); it != adjEnts.end(); ++it )
714 {
715 int adjIndex = m_remapper->m_covering_source_entities.index( *it );
716 if( adjIndex >= 0 ) vecSourceOvTarget[ixT].insert( adjIndex );
717 }
718 }
719 else
720 {
721
722 AdjacentFaceVector vecAdjFaces;
723 GetAdjacentFaceVectorByEdge( *m_meshInputCov, ixS,
724 ( caasIteration ) * ( m_input_order + 1 ) * ( m_input_order + 1 ),
725 vecAdjFaces );
726
727
728 for( size_t iadj = 0; iadj < vecAdjFaces.size(); iadj++ )
729 vecSourceOvTarget[ixT].insert( vecAdjFaces[iadj].first );
730 }
731 }
732 #endif
733
734
735 dSourceMax = fmax( dSourceMax, dataInDouble[ixS] );
736 dSourceMin = fmin( dSourceMin, dataInDouble[ixS] );
737
738
739 dTargetMin = fmin( dTargetMin, dataOutDouble[ixT] );
740 dTargetMax = fmax( dTargetMax, dataOutDouble[ixT] );
741
742 const double locMassDiff = ( dataInDouble[ixS] * m_dOverlapAreas[i] ) -
743 ( dataOutDouble[ixT] * m_dOverlapAreas[i] );
744
745
746
747 dMassDiff += locMassDiff;
748 massVector[ixT] += locMassDiff;
749 }
750
751 #ifdef MOAB_HAVE_MPI
752 std::vector< double > localMinMaxDefects( 5, 0.0 ), globalMinMaxDefects( 5, 0.0 );
753 localMinMaxDefects[0] = dSourceMin;
754 localMinMaxDefects[1] = dTargetMin;
755 localMinMaxDefects[2] = dSourceMax;
756 localMinMaxDefects[3] = dTargetMax;
757 localMinMaxDefects[4] = dMassDiff;
758
759 if( caasType == CAAS_GLOBAL )
760 {
761 MPI_Allreduce( localMinMaxDefects.data(), globalMinMaxDefects.data(), 2, MPI_DOUBLE, MPI_MIN, m_pcomm->comm() );
762 MPI_Allreduce( localMinMaxDefects.data() + 2, globalMinMaxDefects.data() + 2, 2, MPI_DOUBLE, MPI_MAX,
763 m_pcomm->comm() );
764 dSourceMin = globalMinMaxDefects[0];
765 dSourceMax = globalMinMaxDefects[2];
766 dTargetMin = globalMinMaxDefects[1];
767 dTargetMax = globalMinMaxDefects[3];
768 }
769 if( caasIteration == 1 )
770 MPI_Allreduce( localMinMaxDefects.data() + 4, globalMinMaxDefects.data() + 4, 1, MPI_DOUBLE, MPI_SUM,
771 m_pcomm->comm() );
772 else
773 globalMinMaxDefects[4] = mismatch;
774
775 dMassDiff = localMinMaxDefects[4];
776
777 massDefect.first = globalMinMaxDefects[4];
778 #else
779
780
781 massDefect.first = dMassDiff;
782 #endif
783
784
785
786 if( fabs( massDefect.first ) > 1e-20 )
787 {
788 if( caasType == CAAS_GLOBAL )
789 {
790 for( size_t i = 0; i < nTargetCount; i++ )
791 {
792 dataLowerBound[i] = dSourceMin - dataOutDouble[i];
793 dataUpperBound[i] = dSourceMax - dataOutDouble[i];
794 }
795 }
796 else
797 {
798
799 std::vector< double > vecLocalUpperBound( nTargetCount );
800 std::vector< double > vecLocalLowerBound( nTargetCount );
801
802
803 for( size_t i = 0; i < nTargetCount; i++ )
804 {
805 assert( vecSourceOvTarget[i].size() );
806
807 double dMinI = 1E10;
808 double dMaxI = -1E10;
809
810
811 for( const auto& srcElem : vecSourceOvTarget[i] )
812 {
813 dMinI = fmin( dMinI, dataInDouble[srcElem] );
814 dMaxI = fmax( dMaxI, dataInDouble[srcElem] );
815 }
816
817
818 vecLocalLowerBound[i] = dMinI;
819 vecLocalUpperBound[i] = dMaxI;
820 }
821
822 for( size_t i = 0; i < nTargetCount; i++ )
823 {
824 dataLowerBound[i] = vecLocalLowerBound[i] - dataOutDouble[i];
825 dataUpperBound[i] = vecLocalUpperBound[i] - dataOutDouble[i];
826 }
827 }
828
829
830 if( fabs( dMassDiff ) > 1e-20 )
831 {
832 if( caasType == CAAS_QLT )
833 dMassDiff = QLTLimiter( caasIteration, dataOutDouble, dataLowerBound, dataUpperBound, massVector );
834 else
835 CAASLimiter( dataOutDouble, dataLowerBound, dataUpperBound, dMassDiff );
836 }
837
838
839 double dMassDiffPost = 0.0;
840 for( size_t i = 0; i < m_meshOverlap->faces.size(); i++ )
841 {
842 const int ixS = m_meshOverlap->vecSourceFaceIx[i];
843 const int ixT = m_meshOverlap->vecTargetFaceIx[i];
844
845 if( ixT < 0 ) continue;
846
847
848
849 dMassDiffPost += ( dataInDouble[ixS] * m_dOverlapAreas[i] ) -
850 ( dataOutDouble[ixT] * m_dOverlapAreas[i] );
851 }
852
853 massDefect.second = dMassDiffPost;
854 }
855
856
857
858 return massDefect;
859 }
860
861
862
863
864 struct KahanSum
865 {
866 double sum = 0.0;
867 double correction = 0.0;
868
869 void add( double value )
870 {
871 double y = value - correction;
872 double t = sum + y;
873 correction = ( t - sum ) - y;
874 sum = t;
875 }
876
877 double result() const
878 {
879 return sum;
880 }
881 };
882
883
884 inline double pairwiseSum( const std::set< double >& sorted )
885 {
886 if( sorted.empty() ) return 0.0;
887 if( sorted.size() == 1 ) return *sorted.begin();
888
889
890 double sum = 0.0;
891 for( double val : sorted )
892 sum += val;
893 return sum;
894 }
895
896
897 inline double pairwiseKahanSum( const std::set< double >& sorted )
898 {
899 if( sorted.empty() ) return 0.0;
900 if( sorted.size() == 1 ) return *sorted.begin();
901
902
903
904 KahanSum kahan;
905 for( double val : sorted )
906 kahan.add( val );
907 return kahan.result();
908 }
909
910
911 inline void deterministicSparseMatVecMul( const typename moab::TempestOnlineMap::WeightMatrix& A,
912 const typename moab::TempestOnlineMap::WeightColVector& x,
913 typename moab::TempestOnlineMap::WeightRowVector& result )
914 {
915 constexpr bool useKahanSum = false;
916 constexpr bool usePairwiseSum = false;
917
918 result.setZero();
919
920
921 for( int row = 0; row < A.outerSize(); ++row )
922 {
923 std::set< double > accumulators;
924 for( typename moab::TempestOnlineMap::WeightMatrix::InnerIterator it( A, row ); it; ++it )
925 {
926
927 accumulators.insert( it.value() * x( it.col() ) );
928 }
929 if( usePairwiseSum ) result( row ) = pairwiseSum( accumulators );
930 if( useKahanSum ) result( row ) = pairwiseKahanSum( accumulators );
931
932 if( !usePairwiseSum && !useKahanSum )
933 {
934 double sum = 0.0;
935 for( double val : accumulators )
936 sum += val;
937 result( row ) = sum;
938 }
939 }
940 }
941
942
943
944 inline void deterministicSparseMatVecMulKahan( const typename moab::TempestOnlineMap::WeightMatrix& A,
945 const typename moab::TempestOnlineMap::WeightColVector& x,
946 typename moab::TempestOnlineMap::WeightRowVector& result )
947 {
948 result.setZero();
949
950
951 for( int row = 0; row < A.outerSize(); ++row )
952 {
953 KahanSum kahan;
954 for( typename moab::TempestOnlineMap::WeightMatrix::InnerIterator it( A, row ); it; ++it )
955 {
956 double product = it.value() * x( it.col() );
957 kahan.add( product );
958 }
959
960 result( row ) = kahan.result();
961 }
962 }
963
964
965 inline void deterministicSparseMatVecMulClean( const typename moab::TempestOnlineMap::WeightMatrix& A,
966 const typename moab::TempestOnlineMap::WeightColVector& x,
967 typename moab::TempestOnlineMap::WeightRowVector& result )
968 {
969 result.setZero();
970
971
972 for( int row = 0; row < A.outerSize(); ++row )
973 {
974 for( typename moab::TempestOnlineMap::WeightMatrix::InnerIterator it( A, row ); it; ++it )
975 {
976 const double product = it.value() * x( it.col() );
977 result( it.row() ) += product;
978 }
979 }
980 }
981
982 inline void deterministicSparseMatVecMulNative( const typename moab::TempestOnlineMap::WeightMatrix& A,
983 const typename moab::TempestOnlineMap::WeightColVector& x,
984 typename moab::TempestOnlineMap::WeightRowVector& result )
985 {
986 result = A * x;
987 }
988
989
990 inline void deterministicSparseMatTransposeVecMul( const typename moab::TempestOnlineMap::WeightMatrix& A,
991 const typename moab::TempestOnlineMap::WeightRowVector& x,
992 typename moab::TempestOnlineMap::WeightColVector& result )
993 {
994 result.setZero();
995
996
997 std::vector< std::set< double > > accumulators( A.cols() );
998
999
1000 for( int row = 0; row < A.outerSize(); ++row )
1001 {
1002 for( typename moab::TempestOnlineMap::WeightMatrix::InnerIterator it( A, row ); it; ++it )
1003 {
1004 accumulators[it.col()].insert( it.value() * x( row ) );
1005 }
1006 }
1007
1008
1009 for( int col = 0; col < A.cols(); ++col )
1010 {
1011
1012 result( col ) = pairwiseKahanSum( accumulators[col] );
1013 }
1014 }
1015
1016
1017 inline void deterministicSparseMatTransposeVecMulClean( const typename moab::TempestOnlineMap::WeightMatrix& A,
1018 const typename moab::TempestOnlineMap::WeightRowVector& x,
1019 typename moab::TempestOnlineMap::WeightColVector& result )
1020 {
1021 result.setZero();
1022
1023
1024 for( int row = 0; row < A.outerSize(); ++row )
1025 {
1026 for( typename moab::TempestOnlineMap::WeightMatrix::InnerIterator it( A, row ); it; ++it )
1027 {
1028 const double product = it.value() * x( row );
1029 result( it.col() ) += product;
1030 }
1031 }
1032 }
1033
1034
1035 inline void deterministicSparseMatTransposeVecMulNative( const typename moab::TempestOnlineMap::WeightMatrix& A,
1036 const typename moab::TempestOnlineMap::WeightRowVector& x,
1037 typename moab::TempestOnlineMap::WeightColVector& result )
1038 {
1039 result = A.adjoint() * x;
1040 }
1041
1042
1043 moab::ErrorCode moab::TempestOnlineMap::ApplyWeights( std::vector< double >& srcVals,
1044 std::vector< double >& tgtVals,
1045 bool transpose )
1046 {
1047
1048 m_rowVector.setZero();
1049 m_colVector.setZero();
1050 #ifdef VERBOSE
1051 std::stringstream sstr;
1052 static int callId = 0;
1053 callId++;
1054 sstr << "projection_id_" << callId << "_s_" << size << "_rk_" << rank << ".txt";
1055 std::ofstream output_file( sstr.str() );
1056 #endif
1057
1058
1059 if( transpose )
1060 {
1061
1062 for( unsigned i = 0; i < srcVals.size(); ++i )
1063 {
1064 if( row_dtoc_dofmap[i] >= 0 && row_dtoc_dofmap[i] < m_rowVector.size() )
1065 m_rowVector( row_dtoc_dofmap[i] ) = srcVals[i];
1066 }
1067
1068
1069 deterministicSparseMatTransposeVecMul( m_weightMatrix, m_rowVector, m_colVector );
1070
1071
1072
1073 for( unsigned i = 0; i < tgtVals.size(); ++i )
1074 {
1075 if( col_dtoc_dofmap[i] >= 0 && col_dtoc_dofmap[i] < m_colVector.size() )
1076 tgtVals[i] = m_colVector( col_dtoc_dofmap[i] );
1077 }
1078 }
1079 else
1080 {
1081
1082 #ifdef VERBOSE
1083 output_file << "ColVector: " << m_colVector.size() << ", SrcVals: " << srcVals.size()
1084 << ", Sizes: " << m_nTotDofs_SrcCov << ", " << col_dtoc_dofmap.size() << "\n";
1085 #endif
1086 for( unsigned i = 0; i < srcVals.size(); ++i )
1087 {
1088 if( col_dtoc_dofmap[i] >= 0 && col_dtoc_dofmap[i] < m_colVector.size() )
1089 {
1090 m_colVector( col_dtoc_dofmap[i] ) = srcVals[i];
1091 #ifdef VERBOSE
1092 output_file << i << " " << col_gdofmap[col_dtoc_dofmap[i]] + 1 << " " << srcVals[i] << "\n";
1093 #endif
1094 }
1095 }
1096
1097
1098 deterministicSparseMatVecMul( m_weightMatrix, m_colVector, m_rowVector );
1099
1100
1101
1102
1103 #ifdef VERBOSE
1104 output_file
1105 << "RowVector: " << m_rowVector.size() << ", TgtVals:" << tgtVals.size() << ", Sizes: " << m_nTotDofs_Dest
1106 << ", " << row_gdofmap.size() << "\n";
1107 #endif
1108 for( unsigned i = 0; i < tgtVals.size(); ++i )
1109 {
1110 if( row_dtoc_dofmap[i] >= 0 && row_dtoc_dofmap[i] < m_rowVector.size() )
1111 {
1112 tgtVals[i] = m_rowVector( row_dtoc_dofmap[i] );
1113 #ifdef VERBOSE
1114 output_file << i << " " << row_gdofmap[row_dtoc_dofmap[i]] + 1 << " " << tgtVals[i] << "\n";
1115 #endif
1116 }
1117 }
1118 }
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136 #ifdef VERBOSE
1137 output_file.flush();
1138 output_file.close();
1139 #endif
1140
1141
1142 return moab::MB_SUCCESS;
1143 }
1144
1145 #endif
1146
1147
1148
1149 extern void ForceConsistencyConservation3( const DataArray1D< double >& vecSourceArea,
1150 const DataArray1D< double >& vecTargetArea,
1151 DataArray2D< double >& dCoeff,
1152 bool fMonotone,
1153 bool fSparseConstraints = false );
1154
1155
1156
1157 extern void ForceIntArrayConsistencyConservation( const DataArray1D< double >& vecSourceArea,
1158 const DataArray1D< double >& vecTargetArea,
1159 DataArray2D< double >& dCoeff,
1160 bool fMonotone );
1161
1162
1163
1164 void moab::TempestOnlineMap::LinearRemapSE4_Tempest_MOAB( const DataArray3D< int >& dataGLLNodes,
1165 const DataArray3D< double >& dataGLLJacobian,
1166 int nMonotoneType,
1167 bool fContinuousIn,
1168 bool fNoConservation )
1169 {
1170
1171 int nP = dataGLLNodes.GetRows();
1172
1173
1174 const int TriQuadRuleOrder = 4;
1175
1176
1177 TriangularQuadratureRule triquadrule( TriQuadRuleOrder );
1178
1179 int TriQuadraturePoints = triquadrule.GetPoints();
1180
1181 const DataArray2D< double >& TriQuadratureG = triquadrule.GetG();
1182
1183 const DataArray1D< double >& TriQuadratureW = triquadrule.GetW();
1184
1185
1186 DataArray2D< double > dSampleCoeff( nP, nP );
1187
1188
1189 DataArray1D< double > dG;
1190 DataArray1D< double > dW;
1191 GaussLobattoQuadrature::GetPoints( nP, 0.0, 1.0, dG, dW );
1192
1193
1194 moab::DebugOutput dbgprint( std::cout, this->rank, 0 );
1195 dbgprint.set_prefix( "[LinearRemapSE4_Tempest_MOAB]: " );
1196 if( is_root )
1197 {
1198 dbgprint.printf( 0, "Finite Element to Finite Volume Projection\n" );
1199 dbgprint.printf( 0, "Triangular quadrature rule order %i\n", TriQuadRuleOrder );
1200 dbgprint.printf( 0, "Order of the FE polynomial interpolant: %i\n", nP );
1201 }
1202
1203
1204 SparseMatrix< double >& smatMap = this->GetSparseMatrix();
1205
1206
1207 const NodeVector& nodesOverlap = m_meshOverlap->nodes;
1208 const NodeVector& nodesFirst = m_meshInputCov->nodes;
1209
1210
1211 DataArray1D< double > vecSourceArea( nP * nP );
1212
1213 DataArray1D< double > vecTargetArea;
1214 DataArray2D< double > dCoeff;
1215
1216 #ifdef VERBOSE
1217 std::stringstream sstr;
1218 sstr << "remapdata_" << rank << ".txt";
1219 std::ofstream output_file( sstr.str() );
1220 #endif
1221
1222
1223 int ixOverlap = 0;
1224 #ifdef VERBOSE
1225 const unsigned outputFrequency = ( m_meshInputCov->faces.size() / 10 ) + 1;
1226 #endif
1227
1228
1229
1230
1231
1232 Face faceTri( 3 );
1233 NodeVector nodes( 3 );
1234 faceTri.SetNode( 0, 0 );
1235 faceTri.SetNode( 1, 1 );
1236 faceTri.SetNode( 2, 2 );
1237
1238
1239 for( size_t ixFirst = 0; ixFirst < m_meshInputCov->faces.size(); ixFirst++ )
1240 {
1241 const Face& faceFirst = m_meshInputCov->faces[ixFirst];
1242
1243 if( faceFirst.edges.size() != 4 )
1244 {
1245 _EXCEPTIONT( "Only quadrilateral elements allowed for SE remapping" );
1246 }
1247 #ifdef VERBOSE
1248
1249 if( ixFirst % outputFrequency == 0 && is_root )
1250 {
1251 dbgprint.printf( 0, "Element %zu/%lu\n", ixFirst, m_meshInputCov->faces.size() );
1252 }
1253 #endif
1254
1255
1256
1257
1258
1259 int nOverlapFaces = 0;
1260 size_t ixOverlapTemp = ixOverlap;
1261 for( ; ixOverlapTemp < m_meshOverlap->faces.size(); ixOverlapTemp++ )
1262 {
1263
1264
1265 if( ixFirst - m_meshOverlap->vecSourceFaceIx[ixOverlapTemp] != 0 ) break;
1266
1267 nOverlapFaces++;
1268 }
1269
1270
1271 if( nOverlapFaces == 0 )
1272 {
1273 continue;
1274 }
1275
1276
1277 DataArray3D< double > dRemapCoeff( nP, nP, nOverlapFaces );
1278
1279
1280 for( int j = 0; j < nOverlapFaces; j++ )
1281 {
1282 const Face& faceOverlap = m_meshOverlap->faces[ixOverlap + j];
1283 if( m_meshOverlap->vecFaceArea[ixOverlap + j] < 1.e-16 )
1284 {
1285 Announce( "Very small overlap at index %i area polygon: (%1.10e )", ixOverlap + j,
1286 m_meshOverlap->vecFaceArea[ixOverlap + j] );
1287 int n = faceOverlap.edges.size();
1288 Announce( "Number nodes: %d", n );
1289 for( int k = 0; k < n; k++ )
1290 {
1291 Node nd = nodesOverlap[faceOverlap[k]];
1292 Announce( "Node %d %d : %1.10e %1.10e %1.10e ", k, faceOverlap[k], nd.x, nd.y, nd.z );
1293 }
1294 continue;
1295 }
1296
1297
1298
1299
1300
1301
1302
1303
1304 int nbEdges = faceOverlap.edges.size();
1305 int nOverlapTriangles = 1;
1306 Node center;
1307 if( nbEdges > 3 )
1308 {
1309 nOverlapTriangles = nbEdges;
1310 for( int k = 0; k < nbEdges; k++ )
1311 {
1312 const Node& node = nodesOverlap[faceOverlap[k]];
1313 center = center + node;
1314 }
1315 center = center / nbEdges;
1316 center = center.Normalized();
1317 }
1318
1319 Node node0, node1, node2;
1320 double dTriangleArea;
1321
1322
1323 for( int k = 0; k < nOverlapTriangles; k++ )
1324 {
1325 if( nbEdges == 3 )
1326 {
1327 node0 = nodesOverlap[faceOverlap[0]];
1328 node1 = nodesOverlap[faceOverlap[1]];
1329 node2 = nodesOverlap[faceOverlap[2]];
1330 dTriangleArea = CalculateFaceArea( faceOverlap, nodesOverlap );
1331 }
1332 else
1333 {
1334 node0 = center;
1335 node1 = nodesOverlap[faceOverlap[k]];
1336 int k1 = ( k + 1 ) % nbEdges;
1337 node2 = nodesOverlap[faceOverlap[k1]];
1338 nodes[0] = center;
1339 nodes[1] = node1;
1340 nodes[2] = node2;
1341 dTriangleArea = CalculateFaceArea( faceTri, nodes );
1342 }
1343
1344 for( int l = 0; l < TriQuadraturePoints; l++ )
1345 {
1346 Node nodeQuadrature;
1347 nodeQuadrature.x = TriQuadratureG[l][0] * node0.x + TriQuadratureG[l][1] * node1.x +
1348 TriQuadratureG[l][2] * node2.x;
1349
1350 nodeQuadrature.y = TriQuadratureG[l][0] * node0.y + TriQuadratureG[l][1] * node1.y +
1351 TriQuadratureG[l][2] * node2.y;
1352
1353 nodeQuadrature.z = TriQuadratureG[l][0] * node0.z + TriQuadratureG[l][1] * node1.z +
1354 TriQuadratureG[l][2] * node2.z;
1355
1356 nodeQuadrature = nodeQuadrature.Normalized();
1357
1358
1359
1360 double dAlpha;
1361 double dBeta;
1362
1363 ApplyInverseMap( faceFirst, nodesFirst, nodeQuadrature, dAlpha, dBeta );
1364
1365
1366 if( ( dAlpha < -1.0e-13 ) || ( dAlpha > 1.0 + 1.0e-13 ) || ( dBeta < -1.0e-13 ) ||
1367 ( dBeta > 1.0 + 1.0e-13 ) )
1368 {
1369 _EXCEPTION4( "Inverse Map for element %d and subtriangle %d out of range "
1370 "(%1.5e %1.5e)",
1371 j, l, dAlpha, dBeta );
1372 }
1373
1374
1375 SampleGLLFiniteElement( nMonotoneType, nP, dAlpha, dBeta, dSampleCoeff );
1376
1377
1378 for( int p = 0; p < nP; p++ )
1379 {
1380 for( int q = 0; q < nP; q++ )
1381 {
1382 dRemapCoeff[p][q][j] += TriQuadratureW[l] * dTriangleArea * dSampleCoeff[p][q] /
1383 m_meshOverlap->vecFaceArea[ixOverlap + j];
1384 }
1385 }
1386 }
1387 }
1388 }
1389
1390 #ifdef VERBOSE
1391 output_file << "[" << m_remapper->lid_to_gid_covsrc[ixFirst] << "] \t";
1392 for( int j = 0; j < nOverlapFaces; j++ )
1393 {
1394 for( int p = 0; p < nP; p++ )
1395 {
1396 for( int q = 0; q < nP; q++ )
1397 {
1398 output_file << dRemapCoeff[p][q][j] << " ";
1399 }
1400 }
1401 }
1402 output_file << std::endl;
1403 #endif
1404
1405
1406 if( !fNoConservation )
1407 {
1408 double dTargetArea = 0.0;
1409 for( int j = 0; j < nOverlapFaces; j++ )
1410 {
1411 dTargetArea += m_meshOverlap->vecFaceArea[ixOverlap + j];
1412 }
1413
1414 for( int p = 0; p < nP; p++ )
1415 {
1416 for( int q = 0; q < nP; q++ )
1417 {
1418 vecSourceArea[p * nP + q] = dataGLLJacobian[p][q][ixFirst];
1419 }
1420 }
1421
1422 const double areaTolerance = 1e-10;
1423
1424 if( fabs( m_meshInputCov->vecFaceArea[ixFirst] - dTargetArea ) <= areaTolerance )
1425 {
1426 vecTargetArea.Allocate( nOverlapFaces );
1427 for( int j = 0; j < nOverlapFaces; j++ )
1428 {
1429 vecTargetArea[j] = m_meshOverlap->vecFaceArea[ixOverlap + j];
1430 }
1431
1432 dCoeff.Allocate( nOverlapFaces, nP * nP );
1433
1434 for( int j = 0; j < nOverlapFaces; j++ )
1435 {
1436 for( int p = 0; p < nP; p++ )
1437 {
1438 for( int q = 0; q < nP; q++ )
1439 {
1440 dCoeff[j][p * nP + q] = dRemapCoeff[p][q][j];
1441 }
1442 }
1443 }
1444
1445
1446 }
1447 else if( m_meshInputCov->vecFaceArea[ixFirst] - dTargetArea > areaTolerance )
1448 {
1449 double dExtraneousArea = m_meshInputCov->vecFaceArea[ixFirst] - dTargetArea;
1450
1451 vecTargetArea.Allocate( nOverlapFaces + 1 );
1452 for( int j = 0; j < nOverlapFaces; j++ )
1453 {
1454 vecTargetArea[j] = m_meshOverlap->vecFaceArea[ixOverlap + j];
1455 }
1456 vecTargetArea[nOverlapFaces] = dExtraneousArea;
1457
1458 #ifdef VERBOSE
1459 Announce( "Partial volume: %i (%1.10e / %1.10e)", ixFirst, dTargetArea,
1460 m_meshInputCov->vecFaceArea[ixFirst] );
1461 #endif
1462 if( dTargetArea > m_meshInputCov->vecFaceArea[ixFirst] )
1463 {
1464 _EXCEPTIONT( "Partial element area exceeds total element area" );
1465 }
1466
1467 dCoeff.Allocate( nOverlapFaces + 1, nP * nP );
1468
1469 for( int j = 0; j < nOverlapFaces; j++ )
1470 {
1471 for( int p = 0; p < nP; p++ )
1472 {
1473 for( int q = 0; q < nP; q++ )
1474 {
1475 dCoeff[j][p * nP + q] = dRemapCoeff[p][q][j];
1476 }
1477 }
1478 }
1479 for( int p = 0; p < nP; p++ )
1480 {
1481 for( int q = 0; q < nP; q++ )
1482 {
1483 dCoeff[nOverlapFaces][p * nP + q] = dataGLLJacobian[p][q][ixFirst];
1484 }
1485 }
1486 for( int j = 0; j < nOverlapFaces; j++ )
1487 {
1488 for( int p = 0; p < nP; p++ )
1489 {
1490 for( int q = 0; q < nP; q++ )
1491 {
1492 dCoeff[nOverlapFaces][p * nP + q] -=
1493 dRemapCoeff[p][q][j] * m_meshOverlap->vecFaceArea[ixOverlap + j];
1494 }
1495 }
1496 }
1497 for( int p = 0; p < nP; p++ )
1498 {
1499 for( int q = 0; q < nP; q++ )
1500 {
1501 dCoeff[nOverlapFaces][p * nP + q] /= dExtraneousArea;
1502 }
1503 }
1504
1505
1506 }
1507 else
1508 {
1509 Announce( "Coverage area: %1.10e, and target element area: %1.10e)", ixFirst,
1510 m_meshInputCov->vecFaceArea[ixFirst], dTargetArea );
1511 _EXCEPTIONT( "Target grid must be a subset of source grid" );
1512 }
1513
1514 ForceConsistencyConservation3( vecSourceArea, vecTargetArea, dCoeff, ( nMonotoneType > 0 )
1515 );
1516
1517 for( int j = 0; j < nOverlapFaces; j++ )
1518 {
1519 for( int p = 0; p < nP; p++ )
1520 {
1521 for( int q = 0; q < nP; q++ )
1522 {
1523 dRemapCoeff[p][q][j] = dCoeff[j][p * nP + q];
1524 }
1525 }
1526 }
1527 }
1528
1529 #ifdef VERBOSE
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542 #endif
1543
1544
1545 for( int j = 0; j < nOverlapFaces; j++ )
1546 {
1547 int ixSecondFace = m_meshOverlap->vecTargetFaceIx[ixOverlap + j];
1548
1549
1550 if( ixSecondFace < 0 ) continue;
1551
1552 for( int p = 0; p < nP; p++ )
1553 {
1554 for( int q = 0; q < nP; q++ )
1555 {
1556 if( fContinuousIn )
1557 {
1558 int ixFirstNode = dataGLLNodes[p][q][ixFirst] - 1;
1559
1560 smatMap( ixSecondFace, ixFirstNode ) += dRemapCoeff[p][q][j] *
1561 m_meshOverlap->vecFaceArea[ixOverlap + j] /
1562 m_meshOutput->vecFaceArea[ixSecondFace];
1563 }
1564 else
1565 {
1566 int ixFirstNode = ixFirst * nP * nP + p * nP + q;
1567
1568 smatMap( ixSecondFace, ixFirstNode ) += dRemapCoeff[p][q][j] *
1569 m_meshOverlap->vecFaceArea[ixOverlap + j] /
1570 m_meshOutput->vecFaceArea[ixSecondFace];
1571 }
1572 }
1573 }
1574 }
1575
1576 ixOverlap += nOverlapFaces;
1577 }
1578 #ifdef VERBOSE
1579 output_file.flush();
1580 output_file.close();
1581 #endif
1582
1583 return;
1584 }
1585
1586
1587
1588 void moab::TempestOnlineMap::LinearRemapGLLtoGLL2_MOAB( const DataArray3D< int >& dataGLLNodesIn,
1589 const DataArray3D< double >& dataGLLJacobianIn,
1590 const DataArray3D< int >& dataGLLNodesOut,
1591 const DataArray3D< double >& dataGLLJacobianOut,
1592 const DataArray1D< double >& dataNodalAreaOut,
1593 int nPin,
1594 int nPout,
1595 int nMonotoneType,
1596 bool fContinuousIn,
1597 bool fContinuousOut,
1598 bool fNoConservation )
1599 {
1600
1601 TriangularQuadratureRule triquadrule( 8 );
1602
1603 const DataArray2D< double >& dG = triquadrule.GetG();
1604 const DataArray1D< double >& dW = triquadrule.GetW();
1605
1606
1607 SparseMatrix< double >& smatMap = this->GetSparseMatrix();
1608
1609
1610 DataArray2D< double > dSampleCoeffIn( nPin, nPin );
1611 DataArray2D< double > dSampleCoeffOut( nPout, nPout );
1612
1613
1614 moab::DebugOutput dbgprint( std::cout, this->rank, 0 );
1615 dbgprint.set_prefix( "[LinearRemapGLLtoGLL2_MOAB]: " );
1616 if( is_root )
1617 {
1618 dbgprint.printf( 0, "Finite Element to Finite Element Projection\n" );
1619 dbgprint.printf( 0, "Order of the input FE polynomial interpolant: %i\n", nPin );
1620 dbgprint.printf( 0, "Order of the output FE polynomial interpolant: %i\n", nPout );
1621 }
1622
1623
1624 DataArray3D< double > dGlobalIntArray( nPin * nPin, m_meshOverlap->faces.size(), nPout * nPout );
1625
1626
1627 DataArray1D< int > nAllOverlapFaces( m_meshInputCov->faces.size() );
1628
1629 int ixOverlap = 0;
1630 for( size_t ixFirst = 0; ixFirst < m_meshInputCov->faces.size(); ixFirst++ )
1631 {
1632
1633 int nOverlapFaces = 0;
1634 size_t ixOverlapTemp = ixOverlap;
1635 for( ; ixOverlapTemp < m_meshOverlap->faces.size(); ixOverlapTemp++ )
1636 {
1637
1638 if( ixFirst - m_meshOverlap->vecSourceFaceIx[ixOverlapTemp] != 0 )
1639 {
1640 break;
1641 }
1642
1643 nOverlapFaces++;
1644 }
1645
1646 nAllOverlapFaces[ixFirst] = nOverlapFaces;
1647
1648
1649 ixOverlap += nAllOverlapFaces[ixFirst];
1650 }
1651
1652
1653 DataArray2D< double > dGeometricOutputArea( m_meshOutput->faces.size(), nPout * nPout );
1654
1655
1656 DataArray2D< double > dOverlapOutputArea( m_meshOverlap->faces.size(), nPout * nPout );
1657
1658
1659 ixOverlap = 0;
1660 #ifdef VERBOSE
1661 const unsigned outputFrequency = ( m_meshInputCov->faces.size() / 10 ) + 1;
1662 #endif
1663 if( is_root ) dbgprint.printf( 0, "Building conservative distribution maps\n" );
1664
1665
1666
1667
1668
1669
1670 Face faceTri( 3 );
1671 NodeVector nodes( 3 );
1672 faceTri.SetNode( 0, 0 );
1673 faceTri.SetNode( 1, 1 );
1674 faceTri.SetNode( 2, 2 );
1675
1676 for( size_t ixFirst = 0; ixFirst < m_meshInputCov->faces.size(); ixFirst++ )
1677 {
1678 #ifdef VERBOSE
1679
1680 if( ixFirst % outputFrequency == 0 && is_root )
1681 {
1682 dbgprint.printf( 0, "Element %zu/%lu\n", ixFirst, m_meshInputCov->faces.size() );
1683 }
1684 #endif
1685
1686 const Face& faceFirst = m_meshInputCov->faces[ixFirst];
1687
1688 const NodeVector& nodesFirst = m_meshInputCov->nodes;
1689
1690
1691 int nOverlapFaces = nAllOverlapFaces[ixFirst];
1692
1693 if( !nOverlapFaces ) continue;
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704 for( int i = 0; i < nOverlapFaces; i++ )
1705 {
1706
1707 const Face& faceOverlap = m_meshOverlap->faces[ixOverlap + i];
1708
1709 const NodeVector& nodesOverlap = m_meshOverlap->nodes;
1710
1711
1712 int ixSecond = m_meshOverlap->vecTargetFaceIx[ixOverlap + i];
1713
1714
1715 if( ixSecond < 0 ) continue;
1716
1717 const NodeVector& nodesSecond = m_meshOutput->nodes;
1718
1719 const Face& faceSecond = m_meshOutput->faces[ixSecond];
1720
1721 int nbEdges = faceOverlap.edges.size();
1722 int nOverlapTriangles = 1;
1723 Node center;
1724 if( nbEdges > 3 )
1725 {
1726 nOverlapTriangles = nbEdges;
1727 for( int k = 0; k < nbEdges; k++ )
1728 {
1729 const Node& node = nodesOverlap[faceOverlap[k]];
1730 center = center + node;
1731 }
1732 center = center / nbEdges;
1733 center = center.Normalized();
1734 }
1735
1736 Node node0, node1, node2;
1737 double dTriArea;
1738
1739
1740 for( int j = 0; j < nOverlapTriangles; j++ )
1741 {
1742 if( nbEdges == 3 )
1743 {
1744 node0 = nodesOverlap[faceOverlap[0]];
1745 node1 = nodesOverlap[faceOverlap[1]];
1746 node2 = nodesOverlap[faceOverlap[2]];
1747 dTriArea = CalculateFaceArea( faceOverlap, nodesOverlap );
1748 }
1749 else
1750 {
1751 node0 = center;
1752 node1 = nodesOverlap[faceOverlap[j]];
1753 int j1 = ( j + 1 ) % nbEdges;
1754 node2 = nodesOverlap[faceOverlap[j1]];
1755 nodes[0] = center;
1756 nodes[1] = node1;
1757 nodes[2] = node2;
1758 dTriArea = CalculateFaceArea( faceTri, nodes );
1759 }
1760
1761 for( int k = 0; k < triquadrule.GetPoints(); k++ )
1762 {
1763
1764 double dX[3];
1765
1766 dX[0] = dG( k, 0 ) * node0.x + dG( k, 1 ) * node1.x + dG( k, 2 ) * node2.x;
1767 dX[1] = dG( k, 0 ) * node0.y + dG( k, 1 ) * node1.y + dG( k, 2 ) * node2.y;
1768 dX[2] = dG( k, 0 ) * node0.z + dG( k, 1 ) * node1.z + dG( k, 2 ) * node2.z;
1769
1770 double dMag = sqrt( dX[0] * dX[0] + dX[1] * dX[1] + dX[2] * dX[2] );
1771
1772 dX[0] /= dMag;
1773 dX[1] /= dMag;
1774 dX[2] /= dMag;
1775
1776 Node nodeQuadrature( dX[0], dX[1], dX[2] );
1777
1778
1779
1780 double dAlphaIn;
1781 double dBetaIn;
1782
1783 ApplyInverseMap( faceFirst, nodesFirst, nodeQuadrature, dAlphaIn, dBetaIn );
1784
1785
1786
1787 double dAlphaOut;
1788 double dBetaOut;
1789
1790 ApplyInverseMap( faceSecond, nodesSecond, nodeQuadrature, dAlphaOut, dBetaOut );
1791
1792
1809
1810 SampleGLLFiniteElement( nMonotoneType, nPin, dAlphaIn, dBetaIn, dSampleCoeffIn );
1811
1812
1813 SampleGLLFiniteElement( nMonotoneType, nPout, dAlphaOut, dBetaOut, dSampleCoeffOut );
1814
1815
1816 for( int s = 0; s < nPout; s++ )
1817 {
1818 for( int t = 0; t < nPout; t++ )
1819 {
1820 double dNodeArea = dSampleCoeffOut[s][t] * dW[k] * dTriArea;
1821
1822 dOverlapOutputArea[ixOverlap + i][s * nPout + t] += dNodeArea;
1823
1824 dGeometricOutputArea[ixSecond][s * nPout + t] += dNodeArea;
1825 }
1826 }
1827
1828
1829 int ixp = 0;
1830 for( int p = 0; p < nPin; p++ )
1831 {
1832 for( int q = 0; q < nPin; q++ )
1833 {
1834 int ixs = 0;
1835 for( int s = 0; s < nPout; s++ )
1836 {
1837 for( int t = 0; t < nPout; t++ )
1838 {
1839
1840 dGlobalIntArray[ixp][ixOverlap + i][ixs] +=
1841 dSampleCoeffOut[s][t] * dSampleCoeffIn[p][q] * dW[k] * dTriArea;
1842
1843 ixs++;
1844 }
1845 }
1846
1847 ixp++;
1848 }
1849 }
1850 }
1851 }
1852 }
1853
1854
1855 DataArray2D< double > dCoeff( nOverlapFaces * nPout * nPout, nPin * nPin );
1856
1857 for( int i = 0; i < nOverlapFaces; i++ )
1858 {
1859
1860
1861 int ixp = 0;
1862 for( int p = 0; p < nPin; p++ )
1863 {
1864 for( int q = 0; q < nPin; q++ )
1865 {
1866 int ixs = 0;
1867 for( int s = 0; s < nPout; s++ )
1868 {
1869 for( int t = 0; t < nPout; t++ )
1870 {
1871 dCoeff[i * nPout * nPout + ixs][ixp] = dGlobalIntArray[ixp][ixOverlap + i][ixs] /
1872 dOverlapOutputArea[ixOverlap + i][s * nPout + t];
1873
1874 ixs++;
1875 }
1876 }
1877
1878 ixp++;
1879 }
1880 }
1881 }
1882
1883
1884 DataArray1D< double > vecSourceArea( nPin * nPin );
1885
1886 for( int p = 0; p < nPin; p++ )
1887 {
1888 for( int q = 0; q < nPin; q++ )
1889 {
1890 vecSourceArea[p * nPin + q] = dataGLLJacobianIn[p][q][ixFirst];
1891 }
1892 }
1893
1894
1895 DataArray1D< double > vecTargetArea( nOverlapFaces * nPout * nPout );
1896
1897 for( int i = 0; i < nOverlapFaces; i++ )
1898 {
1899
1900 int ixs = 0;
1901 for( int s = 0; s < nPout; s++ )
1902 {
1903 for( int t = 0; t < nPout; t++ )
1904 {
1905 vecTargetArea[i * nPout * nPout + ixs] = dOverlapOutputArea[ixOverlap + i][nPout * s + t];
1906
1907 ixs++;
1908 }
1909 }
1910 }
1911
1912
1913 if( !fNoConservation )
1914 {
1915 ForceIntArrayConsistencyConservation( vecSourceArea, vecTargetArea, dCoeff, ( nMonotoneType != 0 ) );
1916 }
1917
1918
1919 for( int i = 0; i < nOverlapFaces; i++ )
1920 {
1921 int ixp = 0;
1922 for( int p = 0; p < nPin; p++ )
1923 {
1924 for( int q = 0; q < nPin; q++ )
1925 {
1926 int ixs = 0;
1927 for( int s = 0; s < nPout; s++ )
1928 {
1929 for( int t = 0; t < nPout; t++ )
1930 {
1931 dGlobalIntArray[ixp][ixOverlap + i][ixs] =
1932 dCoeff[i * nPout * nPout + ixs][ixp] * dOverlapOutputArea[ixOverlap + i][s * nPout + t];
1933
1934 ixs++;
1935 }
1936 }
1937
1938 ixp++;
1939 }
1940 }
1941 }
1942
1943 #ifdef VVERBOSE
1944
1945 for( int i = 0; i < nPin * nPin; i++ )
1946 {
1947 double dColSum = 0.0;
1948 for( int j = 0; j < nOverlapFaces * nPout * nPout; j++ )
1949 {
1950 dColSum += dCoeff[j][i] * vecTargetArea[j];
1951 }
1952 printf( "Col %i: %1.15e\n", i, dColSum / vecSourceArea[i] );
1953 }
1954
1955
1956 for( int j = 0; j < nOverlapFaces * nPout * nPout; j++ )
1957 {
1958 double dRowSum = 0.0;
1959 for( int i = 0; i < nPin * nPin; i++ )
1960 {
1961 dRowSum += dCoeff[j][i];
1962 }
1963 printf( "Row %i: %1.15e\n", j, dRowSum );
1964 }
1965 #endif
1966
1967
1968 ixOverlap += nOverlapFaces;
1969 }
1970
1971
1972 if( is_root ) dbgprint.printf( 0, "Building redistribution maps on target mesh\n" );
1973 DataArray1D< double > dRedistSourceArea( nPout * nPout );
1974 DataArray1D< double > dRedistTargetArea( nPout * nPout );
1975 std::vector< DataArray2D< double > > dRedistributionMaps;
1976 dRedistributionMaps.resize( m_meshOutput->faces.size() );
1977
1978 for( size_t ixSecond = 0; ixSecond < m_meshOutput->faces.size(); ixSecond++ )
1979 {
1980 dRedistributionMaps[ixSecond].Allocate( nPout * nPout, nPout * nPout );
1981
1982 for( int i = 0; i < nPout * nPout; i++ )
1983 {
1984 dRedistributionMaps[ixSecond][i][i] = 1.0;
1985 }
1986
1987 for( int s = 0; s < nPout * nPout; s++ )
1988 {
1989 dRedistSourceArea[s] = dGeometricOutputArea[ixSecond][s];
1990 }
1991
1992 for( int s = 0; s < nPout * nPout; s++ )
1993 {
1994 dRedistTargetArea[s] = dataGLLJacobianOut[s / nPout][s % nPout][ixSecond];
1995 }
1996
1997 if( !fNoConservation )
1998 {
1999 ForceIntArrayConsistencyConservation( dRedistSourceArea, dRedistTargetArea, dRedistributionMaps[ixSecond],
2000 ( nMonotoneType != 0 ) );
2001
2002 for( int s = 0; s < nPout * nPout; s++ )
2003 {
2004 for( int t = 0; t < nPout * nPout; t++ )
2005 {
2006 dRedistributionMaps[ixSecond][s][t] *= dRedistTargetArea[s] / dRedistSourceArea[t];
2007 }
2008 }
2009 }
2010 }
2011
2012
2013 DataArray1D< double > dTotalGeometricArea( dataNodalAreaOut.GetRows() );
2014 for( size_t ixSecond = 0; ixSecond < m_meshOutput->faces.size(); ixSecond++ )
2015 {
2016 for( int s = 0; s < nPout; s++ )
2017 {
2018 for( int t = 0; t < nPout; t++ )
2019 {
2020 dTotalGeometricArea[dataGLLNodesOut[s][t][ixSecond] - 1] +=
2021 dGeometricOutputArea[ixSecond][s * nPout + t];
2022 }
2023 }
2024 }
2025
2026
2027 ixOverlap = 0;
2028
2029 if( is_root ) dbgprint.printf( 0, "Assembling map\n" );
2030
2031
2032 DataArray2D< double > dRedistributedOp( nPin * nPin, nPout * nPout );
2033
2034 for( size_t ixFirst = 0; ixFirst < m_meshInputCov->faces.size(); ixFirst++ )
2035 {
2036 #ifdef VERBOSE
2037
2038 if( ixFirst % outputFrequency == 0 && is_root )
2039 {
2040 dbgprint.printf( 0, "Element %zu/%lu\n", ixFirst, m_meshInputCov->faces.size() );
2041 }
2042 #endif
2043
2044 int nOverlapFaces = nAllOverlapFaces[ixFirst];
2045
2046 if( !nOverlapFaces ) continue;
2047
2048
2049 for( int j = 0; j < nOverlapFaces; j++ )
2050 {
2051 int ixSecondFace = m_meshOverlap->vecTargetFaceIx[ixOverlap + j];
2052
2053
2054 if( ixSecondFace < 0 ) continue;
2055
2056 dRedistributedOp.Zero();
2057 for( int p = 0; p < nPin * nPin; p++ )
2058 {
2059 for( int s = 0; s < nPout * nPout; s++ )
2060 {
2061 for( int t = 0; t < nPout * nPout; t++ )
2062 {
2063 dRedistributedOp[p][s] +=
2064 dRedistributionMaps[ixSecondFace][s][t] * dGlobalIntArray[p][ixOverlap + j][t];
2065 }
2066 }
2067 }
2068
2069 int ixp = 0;
2070 for( int p = 0; p < nPin; p++ )
2071 {
2072 for( int q = 0; q < nPin; q++ )
2073 {
2074 int ixFirstNode;
2075 if( fContinuousIn )
2076 {
2077 ixFirstNode = dataGLLNodesIn[p][q][ixFirst] - 1;
2078 }
2079 else
2080 {
2081 ixFirstNode = ixFirst * nPin * nPin + p * nPin + q;
2082 }
2083
2084 int ixs = 0;
2085 for( int s = 0; s < nPout; s++ )
2086 {
2087 for( int t = 0; t < nPout; t++ )
2088 {
2089 int ixSecondNode;
2090 if( fContinuousOut )
2091 {
2092 ixSecondNode = dataGLLNodesOut[s][t][ixSecondFace] - 1;
2093
2094 if( !fNoConservation )
2095 {
2096 smatMap( ixSecondNode, ixFirstNode ) +=
2097 dRedistributedOp[ixp][ixs] / dataNodalAreaOut[ixSecondNode];
2098 }
2099 else
2100 {
2101 smatMap( ixSecondNode, ixFirstNode ) +=
2102 dRedistributedOp[ixp][ixs] / dTotalGeometricArea[ixSecondNode];
2103 }
2104 }
2105 else
2106 {
2107 ixSecondNode = ixSecondFace * nPout * nPout + s * nPout + t;
2108
2109 if( !fNoConservation )
2110 {
2111 smatMap( ixSecondNode, ixFirstNode ) +=
2112 dRedistributedOp[ixp][ixs] / dataGLLJacobianOut[s][t][ixSecondFace];
2113 }
2114 else
2115 {
2116 smatMap( ixSecondNode, ixFirstNode ) +=
2117 dRedistributedOp[ixp][ixs] / dGeometricOutputArea[ixSecondFace][s * nPout + t];
2118 }
2119 }
2120
2121 ixs++;
2122 }
2123 }
2124
2125 ixp++;
2126 }
2127 }
2128 }
2129
2130
2131 ixOverlap += nOverlapFaces;
2132 }
2133
2134 return;
2135 }
2136
2137
2138
2139 void moab::TempestOnlineMap::LinearRemapGLLtoGLL2_Pointwise_MOAB( const DataArray3D< int >& dataGLLNodesIn,
2140 const DataArray3D< double >& ,
2141 const DataArray3D< int >& dataGLLNodesOut,
2142 const DataArray3D< double >& ,
2143 const DataArray1D< double >& dataNodalAreaOut,
2144 int nPin,
2145 int nPout,
2146 int nMonotoneType,
2147 bool fContinuousIn,
2148 bool fContinuousOut )
2149 {
2150
2151 DataArray1D< double > dGL;
2152 DataArray1D< double > dWL;
2153
2154 GaussLobattoQuadrature::GetPoints( nPout, 0.0, 1.0, dGL, dWL );
2155
2156
2157 SparseMatrix< double >& smatMap = this->GetSparseMatrix();
2158
2159
2160 DataArray2D< double > dSampleCoeffIn( nPin, nPin );
2161
2162
2163 moab::DebugOutput dbgprint( std::cout, this->rank, 0 );
2164 dbgprint.set_prefix( "[LinearRemapGLLtoGLL2_Pointwise_MOAB]: " );
2165 if( is_root )
2166 {
2167 dbgprint.printf( 0, "Finite Element to Finite Element (Pointwise) Projection\n" );
2168 dbgprint.printf( 0, "Order of the input FE polynomial interpolant: %i\n", nPin );
2169 dbgprint.printf( 0, "Order of the output FE polynomial interpolant: %i\n", nPout );
2170 }
2171
2172
2173 DataArray1D< int > nAllOverlapFaces( m_meshInputCov->faces.size() );
2174
2175 int ixOverlap = 0;
2176
2177 for( size_t ixFirst = 0; ixFirst < m_meshInputCov->faces.size(); ixFirst++ )
2178 {
2179 size_t ixOverlapTemp = ixOverlap;
2180 for( ; ixOverlapTemp < m_meshOverlap->faces.size(); ixOverlapTemp++ )
2181 {
2182
2183
2184 if( ixFirst - m_meshOverlap->vecSourceFaceIx[ixOverlapTemp] != 0 ) break;
2185
2186 nAllOverlapFaces[ixFirst]++;
2187 }
2188
2189
2190 ixOverlap += nAllOverlapFaces[ixFirst];
2191 }
2192
2193
2194 DataArray1D< bool > fSecondNodeFound( dataNodalAreaOut.GetRows() );
2195
2196 ixOverlap = 0;
2197 #ifdef VERBOSE
2198 const unsigned outputFrequency = ( m_meshInputCov->faces.size() / 10 ) + 1;
2199 #endif
2200
2201 for( size_t ixFirst = 0; ixFirst < m_meshInputCov->faces.size(); ixFirst++ )
2202 {
2203 #ifdef VERBOSE
2204
2205 if( ixFirst % outputFrequency == 0 && is_root )
2206 {
2207 dbgprint.printf( 0, "Element %zu/%lu\n", ixFirst, m_meshInputCov->faces.size() );
2208 }
2209 #endif
2210
2211 const Face& faceFirst = m_meshInputCov->faces[ixFirst];
2212
2213 const NodeVector& nodesFirst = m_meshInputCov->nodes;
2214
2215
2216 int nOverlapFaces = nAllOverlapFaces[ixFirst];
2217
2218
2219 for( int i = 0; i < nOverlapFaces; i++ )
2220 {
2221
2222 int ixSecond = m_meshOverlap->vecTargetFaceIx[ixOverlap + i];
2223
2224
2225 if( ixSecond < 0 ) continue;
2226
2227 const NodeVector& nodesSecond = m_meshOutput->nodes;
2228 const Face& faceSecond = m_meshOutput->faces[ixSecond];
2229
2230
2231 for( int s = 0; s < nPout; s++ )
2232 {
2233 for( int t = 0; t < nPout; t++ )
2234 {
2235 size_t ixSecondNode;
2236 if( fContinuousOut )
2237 {
2238 ixSecondNode = dataGLLNodesOut[s][t][ixSecond] - 1;
2239 }
2240 else
2241 {
2242 ixSecondNode = ixSecond * nPout * nPout + s * nPout + t;
2243 }
2244
2245 if( ixSecondNode >= fSecondNodeFound.GetRows() ) _EXCEPTIONT( "Logic error" );
2246
2247
2248 if( fSecondNodeFound[ixSecondNode] ) continue;
2249
2250
2251 Node node;
2252 Node dDx1G;
2253 Node dDx2G;
2254
2255 ApplyLocalMap( faceSecond, nodesSecond, dGL[t], dGL[s], node, dDx1G, dDx2G );
2256
2257
2258
2259 double dAlphaIn;
2260 double dBetaIn;
2261
2262 ApplyInverseMap( faceFirst, nodesFirst, node, dAlphaIn, dBetaIn );
2263
2264
2265 if( ( dAlphaIn < -1.0e-10 ) || ( dAlphaIn > 1.0 + 1.0e-10 ) || ( dBetaIn < -1.0e-10 ) ||
2266 ( dBetaIn > 1.0 + 1.0e-10 ) )
2267 continue;
2268
2269
2270 fSecondNodeFound[ixSecondNode] = true;
2271
2272
2273 SampleGLLFiniteElement( nMonotoneType, nPin, dAlphaIn, dBetaIn, dSampleCoeffIn );
2274
2275
2276 for( int p = 0; p < nPin; p++ )
2277 {
2278 for( int q = 0; q < nPin; q++ )
2279 {
2280 int ixFirstNode;
2281 if( fContinuousIn )
2282 {
2283 ixFirstNode = dataGLLNodesIn[p][q][ixFirst] - 1;
2284 }
2285 else
2286 {
2287 ixFirstNode = ixFirst * nPin * nPin + p * nPin + q;
2288 }
2289
2290 smatMap( ixSecondNode, ixFirstNode ) += dSampleCoeffIn[p][q];
2291 }
2292 }
2293 }
2294 }
2295 }
2296
2297
2298 ixOverlap += nOverlapFaces;
2299 }
2300
2301
2302 for( size_t i = 0; i < fSecondNodeFound.GetRows(); i++ )
2303 {
2304 if( !fSecondNodeFound[i] )
2305 {
2306 _EXCEPTION1( "Can't sample point %i", i );
2307 }
2308 }
2309
2310 return;
2311 }
2312
2313