Mesh Oriented datABase  (version 5.5.0)
An array-based unstructured mesh library
TempestLinearRemap.cpp
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////////
2 ///
3 /// \file TempestLinearRemap.cpp
4 /// \author Vijay Mahadevan
5 /// \version Mar 08, 2017
6 ///
7 
8 #ifdef WIN32 /* windows */
9 #define _USE_MATH_DEFINES // For M_PI
10 #endif
11 #include "Announce.h"
12 #include "DataArray3D.h"
13 #include "FiniteElementTools.h"
14 #include "FiniteVolumeTools.h"
15 #include "GaussLobattoQuadrature.h"
16 #include "TriangularQuadrature.h"
17 #include "MeshUtilitiesFuzzy.h"
18 #include "MeshUtilitiesExact.h"
19 #include "MathHelper.h"
20 #include "SparseMatrix.h"
21 #include "OverlapMesh.h"
22 
23 #include "DebugOutput.hpp"
24 #include "moab/AdaptiveKDTree.hpp"
25 
27 #include "moab/TupleList.hpp"
28 
29 #ifdef MOAB_HAVE_EIGEN3
30 #include <Eigen/Dense>
31 #endif
32 
33 #include <fstream>
34 #include <cmath>
35 #include <cstdlib>
36 #include <sstream>
37 
38 // #define VERBOSE
39 
40 /// <summary>
41 /// Face index and distance metric pair.
42 /// </summary>
43 typedef std::pair< int, int > FaceDistancePair;
44 
45 /// <summary>
46 /// Vector storing adjacent Faces.
47 /// </summary>
48 typedef std::vector< FaceDistancePair > AdjacentFaceVector;
49 
50 ///////////////////////////////////////////////////////////////////////////////
51 
52 moab::ErrorCode moab::TempestOnlineMap::LinearRemapNN_MOAB( bool use_GID_matching, bool strict_check )
53 {
54  /* m_mapRemap size = (m_nTotDofs_Dest X m_nTotDofs_SrcCov) */
55 
56 #ifdef VVERBOSE
57  {
58  std::ofstream output_file( "rowcolindices.txt", std::ios::out );
59  output_file << m_nTotDofs_Dest << " " << m_nTotDofs_SrcCov << " " << row_gdofmap.size() << " "
60  << row_ldofmap.size() << " " << col_gdofmap.size() << " " << col_ldofmap.size() << "\n";
61  output_file << "Rows \n";
62  for( unsigned iv = 0; iv < row_gdofmap.size(); iv++ )
63  output_file << row_gdofmap[iv] << " " << row_dofmap[iv] << "\n";
64  output_file << "Cols \n";
65  for( unsigned iv = 0; iv < col_gdofmap.size(); iv++ )
66  output_file << col_gdofmap[iv] << " " << col_dofmap[iv] << "\n";
67  output_file.flush(); // required here
68  output_file.close();
69  }
70 #endif
71 
72  if( use_GID_matching )
73  {
74  std::map< unsigned, unsigned > src_gl;
75  for( unsigned it = 0; it < col_gdofmap.size(); ++it )
76  src_gl[col_gdofmap[it]] = it;
77 
78  std::map< unsigned, unsigned >::iterator iter;
79  for( unsigned it = 0; it < row_gdofmap.size(); ++it )
80  {
81  unsigned row = row_gdofmap[it];
82  iter = src_gl.find( row );
83  if( strict_check && iter == src_gl.end() )
84  {
85  std::cout << "Searching for global target DOF " << row
86  << " but could not find correspondence in source mesh.\n";
87  assert( false );
88  }
89  else if( iter == src_gl.end() )
90  {
91  continue;
92  }
93  else
94  {
95  unsigned icol = src_gl[row];
96  unsigned irow = it;
97 
98  // Set the permutation matrix in local space
99  m_mapRemap( irow, icol ) = 1.0;
100  }
101  }
102 
103  return moab::MB_SUCCESS;
104  }
105  else
106  {
107  /* Create a Kd-tree to perform local queries to find nearest neighbors */
108 
109  return moab::MB_SUCCESS;
110  }
111 }
112 
113 ///////////////////////////////////////////////////////////////////////////////
114 
116 {
117  // Order of triangular quadrature rule
118  const int TriQuadRuleOrder = 4;
119 
120  // Verify ReverseNodeArray has been calculated
121  if( m_meshInputCov->faces.size() > 0 && m_meshInputCov->revnodearray.size() == 0 )
122  {
123  _EXCEPTIONT( "ReverseNodeArray has not been calculated for m_meshInput" );
124  }
125 
126  // Triangular quadrature rule
127  TriangularQuadratureRule triquadrule( TriQuadRuleOrder );
128 
129  // Number of coefficients needed at this order
130 #ifdef RECTANGULAR_TRUNCATION
131  int nCoefficients = nOrder * nOrder;
132 #endif
133 #ifdef TRIANGULAR_TRUNCATION
134  int nCoefficients = nOrder * ( nOrder + 1 ) / 2;
135 #endif
136 
137  // Number of faces you need
138  const int nRequiredFaceSetSize = nCoefficients;
139 
140  // Fit weight exponent
141  const int nFitWeightsExponent = nOrder + 2;
142 
143  // Announcemnets
144  moab::DebugOutput dbgprint( std::cout, this->rank, 0 );
145  dbgprint.set_prefix( "[LinearRemapFVtoFV_Tempest_MOAB]: " );
146  if( is_root )
147  {
148  dbgprint.printf( 0, "Finite Volume to Finite Volume Projection\n" );
149  dbgprint.printf( 0, "Triangular quadrature rule order %i\n", TriQuadRuleOrder );
150  dbgprint.printf( 0, "Number of coefficients: %i\n", nCoefficients );
151  dbgprint.printf( 0, "Required adjacency set size: %i\n", nRequiredFaceSetSize );
152  dbgprint.printf( 0, "Fit weights exponent: %i\n", nFitWeightsExponent );
153  }
154 
155  // Current overlap face
156  int ixOverlap = 0;
157 #ifdef VERBOSE
158  const unsigned outputFrequency = ( m_meshInputCov->faces.size() / 10 ) + 1;
159 #endif
160  DataArray2D< double > dIntArray;
161  DataArray1D< double > dConstraint( nCoefficients );
162 
163  // Loop through all faces on m_meshInput
164  for( size_t ixFirst = 0; ixFirst < m_meshInputCov->faces.size(); ixFirst++ )
165  {
166  // Output every 1000 elements
167 #ifdef VERBOSE
168  if( ixFirst % outputFrequency == 0 && is_root )
169  {
170  dbgprint.printf( 0, "Element %zu/%lu\n", ixFirst, m_meshInputCov->faces.size() );
171  }
172 #endif
173  // Find the set of Faces that overlap faceFirst
174  int ixOverlapBegin = ixOverlap;
175  unsigned ixOverlapEnd = ixOverlapBegin;
176 
177  for( ; ixOverlapEnd < m_meshOverlap->faces.size(); ixOverlapEnd++ )
178  {
179  if( ixFirst - m_meshOverlap->vecSourceFaceIx[ixOverlapEnd] != 0 ) break;
180  }
181 
182  unsigned nOverlapFaces = ixOverlapEnd - ixOverlapBegin;
183 
184  if( nOverlapFaces == 0 ) continue;
185 
186  // Build integration array
187  BuildIntegrationArray( *m_meshInputCov, *m_meshOverlap, triquadrule, ixFirst, ixOverlapBegin, ixOverlapEnd,
188  nOrder, dIntArray );
189 
190  // Set of Faces to use in building the reconstruction and associated
191  // distance metric.
192  AdjacentFaceVector vecAdjFaces;
193 
194  GetAdjacentFaceVectorByEdge( *m_meshInputCov, ixFirst, nRequiredFaceSetSize, vecAdjFaces );
195 
196  // Number of adjacent Faces
197  int nAdjFaces = vecAdjFaces.size();
198 
199  // Determine the conservative constraint equation
200  double dFirstArea = m_meshInputCov->vecFaceArea[ixFirst];
201  dConstraint.Zero();
202  for( int p = 0; p < nCoefficients; p++ )
203  {
204  for( unsigned j = 0; j < nOverlapFaces; j++ )
205  {
206  dConstraint[p] += dIntArray[p][j];
207  }
208  dConstraint[p] /= dFirstArea;
209  }
210 
211  // Build the fit array from the integration operator
212  DataArray2D< double > dFitArray;
213  DataArray1D< double > dFitWeights;
214  DataArray2D< double > dFitArrayPlus;
215 
216  BuildFitArray( *m_meshInputCov, triquadrule, ixFirst, vecAdjFaces, nOrder, nFitWeightsExponent, dConstraint,
217  dFitArray, dFitWeights );
218 
219  // Compute the inverse fit array
220  bool fSuccess = InvertFitArray_Corrected( dConstraint, dFitArray, dFitWeights, dFitArrayPlus );
221 
222  // Multiply integration array and fit array
223  DataArray2D< double > dComposedArray( nAdjFaces, nOverlapFaces );
224  if( fSuccess )
225  {
226  // Multiply integration array and inverse fit array
227  for( int i = 0; i < nAdjFaces; i++ )
228  {
229  for( size_t j = 0; j < nOverlapFaces; j++ )
230  {
231  for( int k = 0; k < nCoefficients; k++ )
232  {
233  dComposedArray( i, j ) += dIntArray( k, j ) * dFitArrayPlus( i, k );
234  }
235  }
236  }
237 
238  // Unable to invert fit array, drop to 1st order. In this case
239  // dFitArrayPlus(0,0) = 1 and all other entries are zero.
240  }
241  else
242  {
243  dComposedArray.Zero();
244  for( size_t j = 0; j < nOverlapFaces; j++ )
245  {
246  dComposedArray( 0, j ) += dIntArray( 0, j );
247  }
248  }
249 
250  // Put composed array into map
251  for( unsigned i = 0; i < vecAdjFaces.size(); i++ )
252  {
253  for( unsigned j = 0; j < nOverlapFaces; j++ )
254  {
255  int& ixFirstFaceLoc = vecAdjFaces[i].first;
256  int& ixSecondFaceLoc = m_meshOverlap->vecTargetFaceIx[ixOverlap + j];
257  // int ixFirstFaceGlob = m_remapper->GetGlobalID(moab::Remapper::SourceMesh,
258  // ixFirstFaceLoc); int ixSecondFaceGlob =
259  // m_remapper->GetGlobalID(moab::Remapper::TargetMesh, ixSecondFaceLoc);
260 
261  // signal to not participate, because it is a ghost target
262  if( ixSecondFaceLoc < 0 ) continue; // do not do anything
263 
264  m_mapRemap( ixSecondFaceLoc, ixFirstFaceLoc ) +=
265  dComposedArray[i][j] / m_meshOutput->vecFaceArea[ixSecondFaceLoc];
266  }
267  }
268 
269  // Increment the current overlap index
270  ixOverlap += nOverlapFaces;
271  }
272 
273  return;
274 }
275 
276 ///////////////////////////////////////////////////////////////////////////////
277 
278 #ifdef MOAB_HAVE_EIGEN3
279 void moab::TempestOnlineMap::copy_tempest_sparsemat_to_eigen3()
280 {
281 #ifndef VERBOSE
282 #define VERBOSE_ACTIVATED
283 // #define VERBOSE
284 #endif
285  if( m_nTotDofs_Dest <= 0 || m_nTotDofs_SrcCov <= 0 )
286  {
287  // std::cout << rank << ": rowsize = " << m_nTotDofs_Dest << ", colsize = " <<
288  // m_nTotDofs_SrcCov << "\n";
289  // return; // No need to allocate if either rows or cols size are zero
290  }
291 
292  /* Should the columns be the global size of the matrix ? */
293  m_weightMatrix.resize( m_nTotDofs_Dest, m_nTotDofs_SrcCov );
294  m_rowVector.resize( m_weightMatrix.rows() );
295  m_colVector.resize( m_weightMatrix.cols() );
296 
297 #ifdef VERBOSE
298  int locrows = std::max( m_mapRemap.GetRows(), m_nTotDofs_Dest );
299  int loccols = std::max( m_mapRemap.GetColumns(), m_nTotDofs_SrcCov );
300 
301  std::cout << m_weightMatrix.rows() << ", " << locrows << ", " << m_weightMatrix.cols() << ", " << loccols << "\n";
302  // assert(m_weightMatrix.rows() == locrows && m_weightMatrix.cols() == loccols);
303 #endif
304 
305  DataArray1D< int > lrows;
306  DataArray1D< int > lcols;
307  DataArray1D< double > lvals;
308  m_mapRemap.GetEntries( lrows, lcols, lvals );
309  size_t locvals = lvals.GetRows();
310 
311  // first matrix
312  typedef Eigen::Triplet< double > Triplet;
313  std::vector< Triplet > tripletList;
314  tripletList.reserve( locvals );
315  for( size_t iv = 0; iv < locvals; iv++ )
316  {
317  tripletList.push_back( Triplet( lrows[iv], lcols[iv], lvals[iv] ) );
318  }
319 
320  m_weightMatrix.setFromTriplets( tripletList.begin(), tripletList.end() );
321  m_weightMatrix.makeCompressed();
322 
323  int nrows = m_weightMatrix.rows(); // Number of rows
324  int ncols = m_weightMatrix.cols(); // Number of columns
325  int NNZ = m_weightMatrix.nonZeros(); // Number of non zero values
326 #ifdef MOAB_HAVE_MPI
327  // find out min/max for NNZ, ncols, nrows
328  // should work on std c++ 11
329  int arr3[6] = { NNZ, nrows, ncols, -NNZ, -nrows, -ncols };
330  int rarr3[6];
331  MPI_Reduce( arr3, rarr3, 6, MPI_INT, MPI_MIN, 0, m_pcomm->comm() );
332 
333  int total[2];
334  MPI_Reduce( arr3, total, 2, MPI_INT, MPI_SUM, 0, m_pcomm->comm() );
335  if( !rank )
336  std::cout << " Rows:(" << rarr3[1] << ", " << -rarr3[4] << "), Cols:(" << rarr3[2] << ", " << -rarr3[5]
337  << "), NNZ:(" << rarr3[0] << ", " << -rarr3[3] << "), total NNZ:" << total[0]
338  << " total rows:" << total[1] << "\n";
339 #else
340  std::cout << "nr rows: " << nrows << " cols: " << ncols << " non-zeros: " << NNZ << "\n";
341 #endif
342 
343 #ifdef VERBOSE
344  std::stringstream sstr;
345  sstr << "tempestmatrix.txt.0000" << rank;
346  std::ofstream output_file( sstr.str(), std::ios::out );
347  output_file << "0 " << locrows << " 0 " << loccols << "\n";
348  for( unsigned iv = 0; iv < locvals; iv++ )
349  {
350  // output_file << lrows[iv] << " " << row_ldofmap[lrows[iv]] << " " <<
351  // row_gdofmap[row_ldofmap[lrows[iv]]] << " " << col_gdofmap[col_ldofmap[lcols[iv]]] << " "
352  // << lvals[iv] << "\n";
353  output_file << row_gdofmap[row_ldofmap[lrows[iv]]] << " " << col_gdofmap[col_ldofmap[lcols[iv]]] << " "
354  << lvals[iv] << "\n";
355  }
356  output_file.flush(); // required here
357  output_file.close();
358 #endif
359 
360 #ifdef VERBOSE_ACTIVATED
361 #undef VERBOSE_ACTIVATED
362 #undef VERBOSE
363 #endif
364  return;
365 }
366 
367 ///////////////////////////////////////////////////////////////////////////////
368 //#define VERBOSE
369 moab::ErrorCode moab::TempestOnlineMap::ApplyWeights( std::vector< double >& srcVals,
370  std::vector< double >& tgtVals,
371  bool transpose )
372 {
373  // Reset the source and target data first
374  m_rowVector.setZero();
375  m_colVector.setZero();
376 
377 #ifdef VERBOSE
378  std::stringstream sstr;
379  static int callId = 0;
380  callId++;
381  sstr << "projection_id_" << callId << "_s_" << size << "_rk_" << rank << ".txt";
382  std::ofstream output_file( sstr.str() );
383 #endif
384  // Perform the actual projection of weights: application of weight matrix onto the source
385  // solution vector
386  if( transpose )
387  {
388  // Permute the source data first
389  for( unsigned i = 0; i < srcVals.size(); ++i )
390  {
391  if( row_dtoc_dofmap[i] >= 0 )
392  m_rowVector( row_dtoc_dofmap[i] ) = srcVals[i]; // permute and set the row (source) vector properly
393  }
394 
395  m_colVector = m_weightMatrix.adjoint() * m_rowVector;
396 
397  // Permute the resulting target data back
398  for( unsigned i = 0; i < tgtVals.size(); ++i )
399  {
400  if( col_dtoc_dofmap[i] >= 0 )
401  tgtVals[i] = m_colVector( col_dtoc_dofmap[i] ); // permute and set the row (source) vector properly
402  }
403  }
404  else
405  {
406  // Permute the source data first
407 #ifdef VERBOSE
408  output_file << "ColVector: " << m_colVector.size() << ", SrcVals: " << srcVals.size()
409  << ", Sizes: " << m_nTotDofs_SrcCov << ", " << col_dtoc_dofmap.size() << "\n";
410 #endif
411  for( unsigned i = 0; i < srcVals.size(); ++i )
412  {
413  if( col_dtoc_dofmap[i] >= 0 )
414  {
415  m_colVector( col_dtoc_dofmap[i] ) = srcVals[i]; // permute and set the row (source) vector properly
416 #ifdef VERBOSE
417  output_file << i << " " << col_gdofmap[col_dtoc_dofmap[i]] + 1 << " " << srcVals[i] << "\n";
418 #endif
419  }
420  }
421 
422  m_rowVector = m_weightMatrix * m_colVector;
423 
424  // Permute the resulting target data back
425 #ifdef VERBOSE
426  output_file << "RowVector: " << m_rowVector.size() << ", TgtVals:" << tgtVals.size()
427  << ", Sizes: " << m_nTotDofs_Dest << ", " << row_gdofmap.size() << "\n";
428 #endif
429  for( unsigned i = 0; i < tgtVals.size(); ++i )
430  {
431  if( row_dtoc_dofmap[i] >= 0 )
432  {
433  tgtVals[i] = m_rowVector( row_dtoc_dofmap[i] ); // permute and set the row (source) vector properly
434 #ifdef VERBOSE
435  output_file << i << " " << row_gdofmap[row_dtoc_dofmap[i]] + 1 << " " << tgtVals[i] << "\n";
436 #endif
437  }
438  }
439  }
440 
441 #ifdef VERBOSE
442  output_file.flush(); // required here
443  output_file.close();
444 #endif
445 
446  // All done with matvec application
447  return moab::MB_SUCCESS;
448 }
449 
450 #endif
451 //#undef VERBOSE
452 ///////////////////////////////////////////////////////////////////////////////
453 
454 extern void ForceConsistencyConservation3( const DataArray1D< double >& vecSourceArea,
455  const DataArray1D< double >& vecTargetArea,
456  DataArray2D< double >& dCoeff,
457  bool fMonotone,
458  bool fSparseConstraints = false );
459 
460 ///////////////////////////////////////////////////////////////////////////////
461 
462 extern void ForceIntArrayConsistencyConservation( const DataArray1D< double >& vecSourceArea,
463  const DataArray1D< double >& vecTargetArea,
464  DataArray2D< double >& dCoeff,
465  bool fMonotone );
466 
467 ///////////////////////////////////////////////////////////////////////////////
468 
469 void moab::TempestOnlineMap::LinearRemapSE4_Tempest_MOAB( const DataArray3D< int >& dataGLLNodes,
470  const DataArray3D< double >& dataGLLJacobian,
471  int nMonotoneType,
472  bool fContinuousIn,
473  bool fNoConservation )
474 {
475  // Order of the polynomial interpolant
476  int nP = dataGLLNodes.GetRows();
477 
478  // Order of triangular quadrature rule
479  const int TriQuadRuleOrder = 4;
480 
481  // Triangular quadrature rule
482  TriangularQuadratureRule triquadrule( TriQuadRuleOrder );
483 
484  int TriQuadraturePoints = triquadrule.GetPoints();
485 
486  const DataArray2D< double >& TriQuadratureG = triquadrule.GetG();
487 
488  const DataArray1D< double >& TriQuadratureW = triquadrule.GetW();
489 
490  // Sample coefficients
491  DataArray2D< double > dSampleCoeff( nP, nP );
492 
493  // GLL Quadrature nodes on quadrilateral elements
494  DataArray1D< double > dG;
495  DataArray1D< double > dW;
496  GaussLobattoQuadrature::GetPoints( nP, 0.0, 1.0, dG, dW );
497 
498  // Announcements
499  moab::DebugOutput dbgprint( std::cout, this->rank, 0 );
500  dbgprint.set_prefix( "[LinearRemapSE4_Tempest_MOAB]: " );
501  if( is_root )
502  {
503  dbgprint.printf( 0, "Finite Element to Finite Volume Projection\n" );
504  dbgprint.printf( 0, "Triangular quadrature rule order %i\n", TriQuadRuleOrder );
505  dbgprint.printf( 0, "Order of the FE polynomial interpolant: %i\n", nP );
506  }
507 
508  // Get SparseMatrix represntation of the OfflineMap
509  SparseMatrix< double >& smatMap = this->GetSparseMatrix();
510 
511  // NodeVector from m_meshOverlap
512  const NodeVector& nodesOverlap = m_meshOverlap->nodes;
513  const NodeVector& nodesFirst = m_meshInputCov->nodes;
514 
515  // Vector of source areas
516  DataArray1D< double > vecSourceArea( nP * nP );
517 
518  DataArray1D< double > vecTargetArea;
519  DataArray2D< double > dCoeff;
520 
521 #ifdef VERBOSE
522  std::stringstream sstr;
523  sstr << "remapdata_" << rank << ".txt";
524  std::ofstream output_file( sstr.str() );
525 #endif
526 
527  // Current Overlap Face
528  int ixOverlap = 0;
529 #ifdef VERBOSE
530  const unsigned outputFrequency = ( m_meshInputCov->faces.size() / 10 ) + 1;
531 #endif
532  // generic triangle used for area computation, for triangles around the center of overlap face;
533  // used for overlap faces with more than 4 edges;
534  // nodes array will be set for each triangle;
535  // these triangles are not part of the mesh structure, they are just temporary during
536  // aforementioned decomposition.
537  Face faceTri( 3 );
538  NodeVector nodes( 3 );
539  faceTri.SetNode( 0, 0 );
540  faceTri.SetNode( 1, 1 );
541  faceTri.SetNode( 2, 2 );
542 
543  // Loop over all input Faces
544  for( size_t ixFirst = 0; ixFirst < m_meshInputCov->faces.size(); ixFirst++ )
545  {
546  const Face& faceFirst = m_meshInputCov->faces[ixFirst];
547 
548  if( faceFirst.edges.size() != 4 )
549  {
550  _EXCEPTIONT( "Only quadrilateral elements allowed for SE remapping" );
551  }
552 #ifdef VERBOSE
553  // Announce computation progress
554  if( ixFirst % outputFrequency == 0 && is_root )
555  {
556  dbgprint.printf( 0, "Element %zu/%lu\n", ixFirst, m_meshInputCov->faces.size() );
557  }
558 #endif
559  // Need to re-number the overlap elements such that vecSourceFaceIx[a:b] = 0, then 1 and so
560  // on wrt the input mesh data Then the overlap_end and overlap_begin will be correct.
561  // However, the relation with MOAB and Tempest will go out of the roof
562 
563  // Determine how many overlap Faces and triangles are present
564  int nOverlapFaces = 0;
565  size_t ixOverlapTemp = ixOverlap;
566  for( ; ixOverlapTemp < m_meshOverlap->faces.size(); ixOverlapTemp++ )
567  {
568  // const Face & faceOverlap = m_meshOverlap->faces[ixOverlapTemp];
569  if( ixFirst - m_meshOverlap->vecSourceFaceIx[ixOverlapTemp] != 0 )
570  {
571  break;
572  }
573 
574  nOverlapFaces++;
575  }
576 
577  // No overlaps
578  if( nOverlapFaces == 0 )
579  {
580  continue;
581  }
582 
583  // Allocate remap coefficients array for meshFirst Face
584  DataArray3D< double > dRemapCoeff( nP, nP, nOverlapFaces );
585 
586  // Find the local remap coefficients
587  for( int j = 0; j < nOverlapFaces; j++ )
588  {
589  const Face& faceOverlap = m_meshOverlap->faces[ixOverlap + j];
590  if( m_meshOverlap->vecFaceArea[ixOverlap + j] < 1.e-16 ) // machine precision
591  {
592  Announce( "Very small overlap at index %i area polygon: (%1.10e )", ixOverlap + j,
593  m_meshOverlap->vecFaceArea[ixOverlap + j] );
594  int n = faceOverlap.edges.size();
595  Announce( "Number nodes: %d", n );
596  for( int k = 0; k < n; k++ )
597  {
598  Node nd = nodesOverlap[faceOverlap[k]];
599  Announce( "Node %d %d : %1.10e %1.10e %1.10e ", k, faceOverlap[k], nd.x, nd.y, nd.z );
600  }
601  continue;
602  }
603 
604  // #ifdef VERBOSE
605  // if ( is_root )
606  // Announce ( "\tLocal ID: %i/%i = %i, areas = %2.8e", j + ixOverlap, nOverlapFaces,
607  // m_remapper->lid_to_gid_covsrc[m_meshOverlap->vecSourceFaceIx[ixOverlap + j]],
608  // m_meshOverlap->vecFaceArea[ixOverlap + j] );
609  // #endif
610 
611  int nbEdges = faceOverlap.edges.size();
612  int nOverlapTriangles = 1;
613  Node center; // not used if nbEdges == 3
614  if( nbEdges > 3 )
615  { // decompose from center in this case
616  nOverlapTriangles = nbEdges;
617  for( int k = 0; k < nbEdges; k++ )
618  {
619  const Node& node = nodesOverlap[faceOverlap[k]];
620  center = center + node;
621  }
622  center = center / nbEdges;
623  center = center.Normalized(); // project back on sphere of radius 1
624  }
625 
626  Node node0, node1, node2;
627  double dTriangleArea;
628 
629  // Loop over all sub-triangles of this Overlap Face
630  for( int k = 0; k < nOverlapTriangles; k++ )
631  {
632  if( nbEdges == 3 ) // will come here only once, nOverlapTriangles == 1 in this case
633  {
634  node0 = nodesOverlap[faceOverlap[0]];
635  node1 = nodesOverlap[faceOverlap[1]];
636  node2 = nodesOverlap[faceOverlap[2]];
637  dTriangleArea = CalculateFaceArea( faceOverlap, nodesOverlap );
638  }
639  else // decompose polygon in triangles around the center
640  {
641  node0 = center;
642  node1 = nodesOverlap[faceOverlap[k]];
643  int k1 = ( k + 1 ) % nbEdges;
644  node2 = nodesOverlap[faceOverlap[k1]];
645  nodes[0] = center;
646  nodes[1] = node1;
647  nodes[2] = node2;
648  dTriangleArea = CalculateFaceArea( faceTri, nodes );
649  }
650  // Coordinates of quadrature Node
651  for( int l = 0; l < TriQuadraturePoints; l++ )
652  {
653  Node nodeQuadrature;
654  nodeQuadrature.x = TriQuadratureG[l][0] * node0.x + TriQuadratureG[l][1] * node1.x +
655  TriQuadratureG[l][2] * node2.x;
656 
657  nodeQuadrature.y = TriQuadratureG[l][0] * node0.y + TriQuadratureG[l][1] * node1.y +
658  TriQuadratureG[l][2] * node2.y;
659 
660  nodeQuadrature.z = TriQuadratureG[l][0] * node0.z + TriQuadratureG[l][1] * node1.z +
661  TriQuadratureG[l][2] * node2.z;
662 
663  nodeQuadrature = nodeQuadrature.Normalized();
664 
665  // Find components of quadrature point in basis
666  // of the first Face
667  double dAlpha;
668  double dBeta;
669 
670  ApplyInverseMap( faceFirst, nodesFirst, nodeQuadrature, dAlpha, dBeta );
671 
672  // Check inverse map value
673  if( ( dAlpha < -1.0e-13 ) || ( dAlpha > 1.0 + 1.0e-13 ) || ( dBeta < -1.0e-13 ) ||
674  ( dBeta > 1.0 + 1.0e-13 ) )
675  {
676  _EXCEPTION4( "Inverse Map for element %d and subtriangle %d out of range "
677  "(%1.5e %1.5e)",
678  j, l, dAlpha, dBeta );
679  }
680 
681  // Sample the finite element at this point
682  SampleGLLFiniteElement( nMonotoneType, nP, dAlpha, dBeta, dSampleCoeff );
683 
684  // Add sample coefficients to the map if m_meshOverlap->vecFaceArea[ixOverlap + j] > 0
685  for( int p = 0; p < nP; p++ )
686  {
687  for( int q = 0; q < nP; q++ )
688  {
689  dRemapCoeff[p][q][j] += TriQuadratureW[l] * dTriangleArea * dSampleCoeff[p][q] /
690  m_meshOverlap->vecFaceArea[ixOverlap + j];
691  }
692  }
693  }
694  }
695  }
696 
697 #ifdef VERBOSE
698  output_file << "[" << m_remapper->lid_to_gid_covsrc[ixFirst] << "] \t";
699  for( int j = 0; j < nOverlapFaces; j++ )
700  {
701  for( int p = 0; p < nP; p++ )
702  {
703  for( int q = 0; q < nP; q++ )
704  {
705  output_file << dRemapCoeff[p][q][j] << " ";
706  }
707  }
708  }
709  output_file << std::endl;
710 #endif
711 
712  // Force consistency and conservation
713  if( !fNoConservation )
714  {
715  double dTargetArea = 0.0;
716  for( int j = 0; j < nOverlapFaces; j++ )
717  {
718  dTargetArea += m_meshOverlap->vecFaceArea[ixOverlap + j];
719  }
720 
721  for( int p = 0; p < nP; p++ )
722  {
723  for( int q = 0; q < nP; q++ )
724  {
725  vecSourceArea[p * nP + q] = dataGLLJacobian[p][q][ixFirst];
726  }
727  }
728 
729  const double areaTolerance = 1e-10;
730  // Source elements are completely covered by target volumes
731  if( fabs( m_meshInputCov->vecFaceArea[ixFirst] - dTargetArea ) <= areaTolerance )
732  {
733  vecTargetArea.Allocate( nOverlapFaces );
734  for( int j = 0; j < nOverlapFaces; j++ )
735  {
736  vecTargetArea[j] = m_meshOverlap->vecFaceArea[ixOverlap + j];
737  }
738 
739  dCoeff.Allocate( nOverlapFaces, nP * nP );
740 
741  for( int j = 0; j < nOverlapFaces; j++ )
742  {
743  for( int p = 0; p < nP; p++ )
744  {
745  for( int q = 0; q < nP; q++ )
746  {
747  dCoeff[j][p * nP + q] = dRemapCoeff[p][q][j];
748  }
749  }
750  }
751 
752  // Target volumes only partially cover source elements
753  }
754  else if( m_meshInputCov->vecFaceArea[ixFirst] - dTargetArea > areaTolerance )
755  {
756  double dExtraneousArea = m_meshInputCov->vecFaceArea[ixFirst] - dTargetArea;
757 
758  vecTargetArea.Allocate( nOverlapFaces + 1 );
759  for( int j = 0; j < nOverlapFaces; j++ )
760  {
761  vecTargetArea[j] = m_meshOverlap->vecFaceArea[ixOverlap + j];
762  }
763  vecTargetArea[nOverlapFaces] = dExtraneousArea;
764 
765 #ifdef VERBOSE
766  Announce( "Partial volume: %i (%1.10e / %1.10e)", ixFirst, dTargetArea,
767  m_meshInputCov->vecFaceArea[ixFirst] );
768 #endif
769  if( dTargetArea > m_meshInputCov->vecFaceArea[ixFirst] )
770  {
771  _EXCEPTIONT( "Partial element area exceeds total element area" );
772  }
773 
774  dCoeff.Allocate( nOverlapFaces + 1, nP * nP );
775 
776  for( int j = 0; j < nOverlapFaces; j++ )
777  {
778  for( int p = 0; p < nP; p++ )
779  {
780  for( int q = 0; q < nP; q++ )
781  {
782  dCoeff[j][p * nP + q] = dRemapCoeff[p][q][j];
783  }
784  }
785  }
786  for( int p = 0; p < nP; p++ )
787  {
788  for( int q = 0; q < nP; q++ )
789  {
790  dCoeff[nOverlapFaces][p * nP + q] = dataGLLJacobian[p][q][ixFirst];
791  }
792  }
793  for( int j = 0; j < nOverlapFaces; j++ )
794  {
795  for( int p = 0; p < nP; p++ )
796  {
797  for( int q = 0; q < nP; q++ )
798  {
799  dCoeff[nOverlapFaces][p * nP + q] -=
800  dRemapCoeff[p][q][j] * m_meshOverlap->vecFaceArea[ixOverlap + j];
801  }
802  }
803  }
804  for( int p = 0; p < nP; p++ )
805  {
806  for( int q = 0; q < nP; q++ )
807  {
808  dCoeff[nOverlapFaces][p * nP + q] /= dExtraneousArea;
809  }
810  }
811 
812  // Source elements only partially cover target volumes
813  }
814  else
815  {
816  Announce( "Coverage area: %1.10e, and target element area: %1.10e)", ixFirst,
817  m_meshInputCov->vecFaceArea[ixFirst], dTargetArea );
818  _EXCEPTIONT( "Target grid must be a subset of source grid" );
819  }
820 
821  ForceConsistencyConservation3( vecSourceArea, vecTargetArea, dCoeff, ( nMonotoneType > 0 )
822  /*, m_remapper->lid_to_gid_covsrc[ixFirst]*/ );
823 
824  for( int j = 0; j < nOverlapFaces; j++ )
825  {
826  for( int p = 0; p < nP; p++ )
827  {
828  for( int q = 0; q < nP; q++ )
829  {
830  dRemapCoeff[p][q][j] = dCoeff[j][p * nP + q];
831  }
832  }
833  }
834  }
835 
836 #ifdef VERBOSE
837  // output_file << "[" << m_remapper->lid_to_gid_covsrc[ixFirst] << "] \t";
838  // for ( int j = 0; j < nOverlapFaces; j++ )
839  // {
840  // for ( int p = 0; p < nP; p++ )
841  // {
842  // for ( int q = 0; q < nP; q++ )
843  // {
844  // output_file << dRemapCoeff[p][q][j] << " ";
845  // }
846  // }
847  // }
848  // output_file << std::endl;
849 #endif
850 
851  // Put these remap coefficients into the SparseMatrix map
852  for( int j = 0; j < nOverlapFaces; j++ )
853  {
854  int ixSecondFace = m_meshOverlap->vecTargetFaceIx[ixOverlap + j];
855 
856  // signal to not participate, because it is a ghost target
857  if( ixSecondFace < 0 ) continue; // do not do anything
858 
859  for( int p = 0; p < nP; p++ )
860  {
861  for( int q = 0; q < nP; q++ )
862  {
863  if( fContinuousIn )
864  {
865  int ixFirstNode = dataGLLNodes[p][q][ixFirst] - 1;
866 
867  smatMap( ixSecondFace, ixFirstNode ) += dRemapCoeff[p][q][j] *
868  m_meshOverlap->vecFaceArea[ixOverlap + j] /
869  m_meshOutput->vecFaceArea[ixSecondFace];
870  }
871  else
872  {
873  int ixFirstNode = ixFirst * nP * nP + p * nP + q;
874 
875  smatMap( ixSecondFace, ixFirstNode ) += dRemapCoeff[p][q][j] *
876  m_meshOverlap->vecFaceArea[ixOverlap + j] /
877  m_meshOutput->vecFaceArea[ixSecondFace];
878  }
879  }
880  }
881  }
882  // Increment the current overlap index
883  ixOverlap += nOverlapFaces;
884  }
885 #ifdef VERBOSE
886  output_file.flush(); // required here
887  output_file.close();
888 #endif
889 
890  return;
891 }
892 
893 ///////////////////////////////////////////////////////////////////////////////
894 
895 void moab::TempestOnlineMap::LinearRemapGLLtoGLL2_MOAB( const DataArray3D< int >& dataGLLNodesIn,
896  const DataArray3D< double >& dataGLLJacobianIn,
897  const DataArray3D< int >& dataGLLNodesOut,
898  const DataArray3D< double >& dataGLLJacobianOut,
899  const DataArray1D< double >& dataNodalAreaOut,
900  int nPin,
901  int nPout,
902  int nMonotoneType,
903  bool fContinuousIn,
904  bool fContinuousOut,
905  bool fNoConservation )
906 {
907  // Triangular quadrature rule
908  TriangularQuadratureRule triquadrule( 8 );
909 
910  const DataArray2D< double >& dG = triquadrule.GetG();
911  const DataArray1D< double >& dW = triquadrule.GetW();
912 
913  // Get SparseMatrix represntation of the OfflineMap
914  SparseMatrix< double >& smatMap = this->GetSparseMatrix();
915 
916  // Sample coefficients
917  DataArray2D< double > dSampleCoeffIn( nPin, nPin );
918  DataArray2D< double > dSampleCoeffOut( nPout, nPout );
919 
920  // Announcemnets
921  moab::DebugOutput dbgprint( std::cout, this->rank, 0 );
922  dbgprint.set_prefix( "[LinearRemapGLLtoGLL2_MOAB]: " );
923  if( is_root )
924  {
925  dbgprint.printf( 0, "Finite Element to Finite Element Projection\n" );
926  dbgprint.printf( 0, "Order of the input FE polynomial interpolant: %i\n", nPin );
927  dbgprint.printf( 0, "Order of the output FE polynomial interpolant: %i\n", nPout );
928  }
929 
930  // Build the integration array for each element on m_meshOverlap
931  DataArray3D< double > dGlobalIntArray( nPin * nPin, m_meshOverlap->faces.size(), nPout * nPout );
932 
933  // Number of overlap Faces per source Face
934  DataArray1D< int > nAllOverlapFaces( m_meshInputCov->faces.size() );
935 
936  int ixOverlap = 0;
937  for( size_t ixFirst = 0; ixFirst < m_meshInputCov->faces.size(); ixFirst++ )
938  {
939  // Determine how many overlap Faces and triangles are present
940  int nOverlapFaces = 0;
941  size_t ixOverlapTemp = ixOverlap;
942  for( ; ixOverlapTemp < m_meshOverlap->faces.size(); ixOverlapTemp++ )
943  {
944  // const Face & faceOverlap = m_meshOverlap->faces[ixOverlapTemp];
945  if( ixFirst - m_meshOverlap->vecSourceFaceIx[ixOverlapTemp] != 0 )
946  {
947  break;
948  }
949 
950  nOverlapFaces++;
951  }
952 
953  nAllOverlapFaces[ixFirst] = nOverlapFaces;
954 
955  // Increment the current overlap index
956  ixOverlap += nAllOverlapFaces[ixFirst];
957  }
958 
959  // Geometric area of each output node
960  DataArray2D< double > dGeometricOutputArea( m_meshOutput->faces.size(), nPout * nPout );
961 
962  // Area of each overlap element in the output basis
963  DataArray2D< double > dOverlapOutputArea( m_meshOverlap->faces.size(), nPout * nPout );
964 
965  // Loop through all faces on m_meshInput
966  ixOverlap = 0;
967 #ifdef VERBOSE
968  const unsigned outputFrequency = ( m_meshInputCov->faces.size() / 10 ) + 1;
969 #endif
970  if( is_root ) dbgprint.printf( 0, "Building conservative distribution maps\n" );
971 
972  // generic triangle used for area computation, for triangles around the center of overlap face;
973  // used for overlap faces with more than 4 edges;
974  // nodes array will be set for each triangle;
975  // these triangles are not part of the mesh structure, they are just temporary during
976  // aforementioned decomposition.
977  Face faceTri( 3 );
978  NodeVector nodes( 3 );
979  faceTri.SetNode( 0, 0 );
980  faceTri.SetNode( 1, 1 );
981  faceTri.SetNode( 2, 2 );
982 
983  for( size_t ixFirst = 0; ixFirst < m_meshInputCov->faces.size(); ixFirst++ )
984  {
985 #ifdef VERBOSE
986  // Announce computation progress
987  if( ixFirst % outputFrequency == 0 && is_root )
988  {
989  dbgprint.printf( 0, "Element %zu/%lu\n", ixFirst, m_meshInputCov->faces.size() );
990  }
991 #endif
992  // Quantities from the First Mesh
993  const Face& faceFirst = m_meshInputCov->faces[ixFirst];
994 
995  const NodeVector& nodesFirst = m_meshInputCov->nodes;
996 
997  // Number of overlapping Faces and triangles
998  int nOverlapFaces = nAllOverlapFaces[ixFirst];
999 
1000  if( !nOverlapFaces ) continue;
1001 
1002  // // Calculate total element Jacobian
1003  // double dTotalJacobian = 0.0;
1004  // for (int s = 0; s < nPin; s++) {
1005  // for (int t = 0; t < nPin; t++) {
1006  // dTotalJacobian += dataGLLJacobianIn[s][t][ixFirst];
1007  // }
1008  // }
1009 
1010  // Loop through all Overlap Faces
1011  for( int i = 0; i < nOverlapFaces; i++ )
1012  {
1013  // Quantities from the overlap Mesh
1014  const Face& faceOverlap = m_meshOverlap->faces[ixOverlap + i];
1015 
1016  const NodeVector& nodesOverlap = m_meshOverlap->nodes;
1017 
1018  // Quantities from the Second Mesh
1019  int ixSecond = m_meshOverlap->vecTargetFaceIx[ixOverlap + i];
1020 
1021  // signal to not participate, because it is a ghost target
1022  if( ixSecond < 0 ) continue; // do not do anything
1023 
1024  const NodeVector& nodesSecond = m_meshOutput->nodes;
1025 
1026  const Face& faceSecond = m_meshOutput->faces[ixSecond];
1027 
1028  int nbEdges = faceOverlap.edges.size();
1029  int nOverlapTriangles = 1;
1030  Node center; // not used if nbEdges == 3
1031  if( nbEdges > 3 )
1032  { // decompose from center in this case
1033  nOverlapTriangles = nbEdges;
1034  for( int k = 0; k < nbEdges; k++ )
1035  {
1036  const Node& node = nodesOverlap[faceOverlap[k]];
1037  center = center + node;
1038  }
1039  center = center / nbEdges;
1040  center = center.Normalized(); // project back on sphere of radius 1
1041  }
1042 
1043  Node node0, node1, node2;
1044  double dTriArea;
1045 
1046  // Loop over all sub-triangles of this Overlap Face
1047  for( int j = 0; j < nOverlapTriangles; j++ )
1048  {
1049  if( nbEdges == 3 ) // will come here only once, nOverlapTriangles == 1 in this case
1050  {
1051  node0 = nodesOverlap[faceOverlap[0]];
1052  node1 = nodesOverlap[faceOverlap[1]];
1053  node2 = nodesOverlap[faceOverlap[2]];
1054  dTriArea = CalculateFaceArea( faceOverlap, nodesOverlap );
1055  }
1056  else // decompose polygon in triangles around the center
1057  {
1058  node0 = center;
1059  node1 = nodesOverlap[faceOverlap[j]];
1060  int j1 = ( j + 1 ) % nbEdges;
1061  node2 = nodesOverlap[faceOverlap[j1]];
1062  nodes[0] = center;
1063  nodes[1] = node1;
1064  nodes[2] = node2;
1065  dTriArea = CalculateFaceArea( faceTri, nodes );
1066  }
1067 
1068  for( int k = 0; k < triquadrule.GetPoints(); k++ )
1069  {
1070  // Get the nodal location of this point
1071  double dX[3];
1072 
1073  dX[0] = dG( k, 0 ) * node0.x + dG( k, 1 ) * node1.x + dG( k, 2 ) * node2.x;
1074  dX[1] = dG( k, 0 ) * node0.y + dG( k, 1 ) * node1.y + dG( k, 2 ) * node2.y;
1075  dX[2] = dG( k, 0 ) * node0.z + dG( k, 1 ) * node1.z + dG( k, 2 ) * node2.z;
1076 
1077  double dMag = sqrt( dX[0] * dX[0] + dX[1] * dX[1] + dX[2] * dX[2] );
1078 
1079  dX[0] /= dMag;
1080  dX[1] /= dMag;
1081  dX[2] /= dMag;
1082 
1083  Node nodeQuadrature( dX[0], dX[1], dX[2] );
1084 
1085  // Find the components of this quadrature point in the basis
1086  // of the first Face.
1087  double dAlphaIn;
1088  double dBetaIn;
1089 
1090  ApplyInverseMap( faceFirst, nodesFirst, nodeQuadrature, dAlphaIn, dBetaIn );
1091 
1092  // Find the components of this quadrature point in the basis
1093  // of the second Face.
1094  double dAlphaOut;
1095  double dBetaOut;
1096 
1097  ApplyInverseMap( faceSecond, nodesSecond, nodeQuadrature, dAlphaOut, dBetaOut );
1098 
1099  /*
1100  // Check inverse map value
1101  if ((dAlphaIn < 0.0) || (dAlphaIn > 1.0) ||
1102  (dBetaIn < 0.0) || (dBetaIn > 1.0)
1103  ) {
1104  _EXCEPTION2("Inverse Map out of range (%1.5e %1.5e)",
1105  dAlphaIn, dBetaIn);
1106  }
1107 
1108  // Check inverse map value
1109  if ((dAlphaOut < 0.0) || (dAlphaOut > 1.0) ||
1110  (dBetaOut < 0.0) || (dBetaOut > 1.0)
1111  ) {
1112  _EXCEPTION2("Inverse Map out of range (%1.5e %1.5e)",
1113  dAlphaOut, dBetaOut);
1114  }
1115  */
1116  // Sample the First finite element at this point
1117  SampleGLLFiniteElement( nMonotoneType, nPin, dAlphaIn, dBetaIn, dSampleCoeffIn );
1118 
1119  // Sample the Second finite element at this point
1120  SampleGLLFiniteElement( nMonotoneType, nPout, dAlphaOut, dBetaOut, dSampleCoeffOut );
1121 
1122  // Overlap output area
1123  for( int s = 0; s < nPout; s++ )
1124  {
1125  for( int t = 0; t < nPout; t++ )
1126  {
1127  double dNodeArea = dSampleCoeffOut[s][t] * dW[k] * dTriArea;
1128 
1129  dOverlapOutputArea[ixOverlap + i][s * nPout + t] += dNodeArea;
1130 
1131  dGeometricOutputArea[ixSecond][s * nPout + t] += dNodeArea;
1132  }
1133  }
1134 
1135  // Compute overlap integral
1136  int ixp = 0;
1137  for( int p = 0; p < nPin; p++ )
1138  {
1139  for( int q = 0; q < nPin; q++ )
1140  {
1141  int ixs = 0;
1142  for( int s = 0; s < nPout; s++ )
1143  {
1144  for( int t = 0; t < nPout; t++ )
1145  {
1146  // Sample the Second finite element at this point
1147  dGlobalIntArray[ixp][ixOverlap + i][ixs] +=
1148  dSampleCoeffOut[s][t] * dSampleCoeffIn[p][q] * dW[k] * dTriArea;
1149 
1150  ixs++;
1151  }
1152  }
1153 
1154  ixp++;
1155  }
1156  }
1157  }
1158  }
1159  }
1160 
1161  // Coefficients
1162  DataArray2D< double > dCoeff( nOverlapFaces * nPout * nPout, nPin * nPin );
1163 
1164  for( int i = 0; i < nOverlapFaces; i++ )
1165  {
1166  // int ixSecondFace = m_meshOverlap->vecTargetFaceIx[ixOverlap + i];
1167 
1168  int ixp = 0;
1169  for( int p = 0; p < nPin; p++ )
1170  {
1171  for( int q = 0; q < nPin; q++ )
1172  {
1173  int ixs = 0;
1174  for( int s = 0; s < nPout; s++ )
1175  {
1176  for( int t = 0; t < nPout; t++ )
1177  {
1178  dCoeff[i * nPout * nPout + ixs][ixp] = dGlobalIntArray[ixp][ixOverlap + i][ixs] /
1179  dOverlapOutputArea[ixOverlap + i][s * nPout + t];
1180 
1181  ixs++;
1182  }
1183  }
1184 
1185  ixp++;
1186  }
1187  }
1188  }
1189 
1190  // Source areas
1191  DataArray1D< double > vecSourceArea( nPin * nPin );
1192 
1193  for( int p = 0; p < nPin; p++ )
1194  {
1195  for( int q = 0; q < nPin; q++ )
1196  {
1197  vecSourceArea[p * nPin + q] = dataGLLJacobianIn[p][q][ixFirst];
1198  }
1199  }
1200 
1201  // Target areas
1202  DataArray1D< double > vecTargetArea( nOverlapFaces * nPout * nPout );
1203 
1204  for( int i = 0; i < nOverlapFaces; i++ )
1205  {
1206  // int ixSecond = m_meshOverlap->vecTargetFaceIx[ixOverlap + i];
1207  int ixs = 0;
1208  for( int s = 0; s < nPout; s++ )
1209  {
1210  for( int t = 0; t < nPout; t++ )
1211  {
1212  vecTargetArea[i * nPout * nPout + ixs] = dOverlapOutputArea[ixOverlap + i][nPout * s + t];
1213 
1214  ixs++;
1215  }
1216  }
1217  }
1218 
1219  // Force consistency and conservation
1220  if( !fNoConservation )
1221  {
1222  ForceIntArrayConsistencyConservation( vecSourceArea, vecTargetArea, dCoeff, ( nMonotoneType != 0 ) );
1223  }
1224 
1225  // Update global coefficients
1226  for( int i = 0; i < nOverlapFaces; i++ )
1227  {
1228  int ixp = 0;
1229  for( int p = 0; p < nPin; p++ )
1230  {
1231  for( int q = 0; q < nPin; q++ )
1232  {
1233  int ixs = 0;
1234  for( int s = 0; s < nPout; s++ )
1235  {
1236  for( int t = 0; t < nPout; t++ )
1237  {
1238  dGlobalIntArray[ixp][ixOverlap + i][ixs] =
1239  dCoeff[i * nPout * nPout + ixs][ixp] * dOverlapOutputArea[ixOverlap + i][s * nPout + t];
1240 
1241  ixs++;
1242  }
1243  }
1244 
1245  ixp++;
1246  }
1247  }
1248  }
1249 
1250 #ifdef VVERBOSE
1251  // Check column sums (conservation)
1252  for( int i = 0; i < nPin * nPin; i++ )
1253  {
1254  double dColSum = 0.0;
1255  for( int j = 0; j < nOverlapFaces * nPout * nPout; j++ )
1256  {
1257  dColSum += dCoeff[j][i] * vecTargetArea[j];
1258  }
1259  printf( "Col %i: %1.15e\n", i, dColSum / vecSourceArea[i] );
1260  }
1261 
1262  // Check row sums (consistency)
1263  for( int j = 0; j < nOverlapFaces * nPout * nPout; j++ )
1264  {
1265  double dRowSum = 0.0;
1266  for( int i = 0; i < nPin * nPin; i++ )
1267  {
1268  dRowSum += dCoeff[j][i];
1269  }
1270  printf( "Row %i: %1.15e\n", j, dRowSum );
1271  }
1272 #endif
1273 
1274  // Increment the current overlap index
1275  ixOverlap += nOverlapFaces;
1276  }
1277 
1278  // Build redistribution map within target element
1279  if( is_root ) dbgprint.printf( 0, "Building redistribution maps on target mesh\n" );
1280  DataArray1D< double > dRedistSourceArea( nPout * nPout );
1281  DataArray1D< double > dRedistTargetArea( nPout * nPout );
1282  std::vector< DataArray2D< double > > dRedistributionMaps;
1283  dRedistributionMaps.resize( m_meshOutput->faces.size() );
1284 
1285  for( size_t ixSecond = 0; ixSecond < m_meshOutput->faces.size(); ixSecond++ )
1286  {
1287  dRedistributionMaps[ixSecond].Allocate( nPout * nPout, nPout * nPout );
1288 
1289  for( int i = 0; i < nPout * nPout; i++ )
1290  {
1291  dRedistributionMaps[ixSecond][i][i] = 1.0;
1292  }
1293 
1294  for( int s = 0; s < nPout * nPout; s++ )
1295  {
1296  dRedistSourceArea[s] = dGeometricOutputArea[ixSecond][s];
1297  }
1298 
1299  for( int s = 0; s < nPout * nPout; s++ )
1300  {
1301  dRedistTargetArea[s] = dataGLLJacobianOut[s / nPout][s % nPout][ixSecond];
1302  }
1303 
1304  if( !fNoConservation )
1305  {
1306  ForceIntArrayConsistencyConservation( dRedistSourceArea, dRedistTargetArea, dRedistributionMaps[ixSecond],
1307  ( nMonotoneType != 0 ) );
1308 
1309  for( int s = 0; s < nPout * nPout; s++ )
1310  {
1311  for( int t = 0; t < nPout * nPout; t++ )
1312  {
1313  dRedistributionMaps[ixSecond][s][t] *= dRedistTargetArea[s] / dRedistSourceArea[t];
1314  }
1315  }
1316  }
1317  }
1318 
1319  // Construct the total geometric area
1320  DataArray1D< double > dTotalGeometricArea( dataNodalAreaOut.GetRows() );
1321  for( size_t ixSecond = 0; ixSecond < m_meshOutput->faces.size(); ixSecond++ )
1322  {
1323  for( int s = 0; s < nPout; s++ )
1324  {
1325  for( int t = 0; t < nPout; t++ )
1326  {
1327  dTotalGeometricArea[dataGLLNodesOut[s][t][ixSecond] - 1] +=
1328  dGeometricOutputArea[ixSecond][s * nPout + t];
1329  }
1330  }
1331  }
1332 
1333  // Compose the integration operator with the output map
1334  ixOverlap = 0;
1335 
1336  if( is_root ) dbgprint.printf( 0, "Assembling map\n" );
1337 
1338  // Map from source DOFs to target DOFs with redistribution applied
1339  DataArray2D< double > dRedistributedOp( nPin * nPin, nPout * nPout );
1340 
1341  for( size_t ixFirst = 0; ixFirst < m_meshInputCov->faces.size(); ixFirst++ )
1342  {
1343 #ifdef VERBOSE
1344  // Announce computation progress
1345  if( ixFirst % outputFrequency == 0 && is_root )
1346  {
1347  dbgprint.printf( 0, "Element %zu/%lu\n", ixFirst, m_meshInputCov->faces.size() );
1348  }
1349 #endif
1350  // Number of overlapping Faces and triangles
1351  int nOverlapFaces = nAllOverlapFaces[ixFirst];
1352 
1353  if( !nOverlapFaces ) continue;
1354 
1355  // Put composed array into map
1356  for( int j = 0; j < nOverlapFaces; j++ )
1357  {
1358  int ixSecondFace = m_meshOverlap->vecTargetFaceIx[ixOverlap + j];
1359 
1360  // signal to not participate, because it is a ghost target
1361  if( ixSecondFace < 0 ) continue; // do not do anything
1362 
1363  dRedistributedOp.Zero();
1364  for( int p = 0; p < nPin * nPin; p++ )
1365  {
1366  for( int s = 0; s < nPout * nPout; s++ )
1367  {
1368  for( int t = 0; t < nPout * nPout; t++ )
1369  {
1370  dRedistributedOp[p][s] +=
1371  dRedistributionMaps[ixSecondFace][s][t] * dGlobalIntArray[p][ixOverlap + j][t];
1372  }
1373  }
1374  }
1375 
1376  int ixp = 0;
1377  for( int p = 0; p < nPin; p++ )
1378  {
1379  for( int q = 0; q < nPin; q++ )
1380  {
1381  int ixFirstNode;
1382  if( fContinuousIn )
1383  {
1384  ixFirstNode = dataGLLNodesIn[p][q][ixFirst] - 1;
1385  }
1386  else
1387  {
1388  ixFirstNode = ixFirst * nPin * nPin + p * nPin + q;
1389  }
1390 
1391  int ixs = 0;
1392  for( int s = 0; s < nPout; s++ )
1393  {
1394  for( int t = 0; t < nPout; t++ )
1395  {
1396  int ixSecondNode;
1397  if( fContinuousOut )
1398  {
1399  ixSecondNode = dataGLLNodesOut[s][t][ixSecondFace] - 1;
1400 
1401  if( !fNoConservation )
1402  {
1403  smatMap( ixSecondNode, ixFirstNode ) +=
1404  dRedistributedOp[ixp][ixs] / dataNodalAreaOut[ixSecondNode];
1405  }
1406  else
1407  {
1408  smatMap( ixSecondNode, ixFirstNode ) +=
1409  dRedistributedOp[ixp][ixs] / dTotalGeometricArea[ixSecondNode];
1410  }
1411  }
1412  else
1413  {
1414  ixSecondNode = ixSecondFace * nPout * nPout + s * nPout + t;
1415 
1416  if( !fNoConservation )
1417  {
1418  smatMap( ixSecondNode, ixFirstNode ) +=
1419  dRedistributedOp[ixp][ixs] / dataGLLJacobianOut[s][t][ixSecondFace];
1420  }
1421  else
1422  {
1423  smatMap( ixSecondNode, ixFirstNode ) +=
1424  dRedistributedOp[ixp][ixs] / dGeometricOutputArea[ixSecondFace][s * nPout + t];
1425  }
1426  }
1427 
1428  ixs++;
1429  }
1430  }
1431 
1432  ixp++;
1433  }
1434  }
1435  }
1436 
1437  // Increment the current overlap index
1438  ixOverlap += nOverlapFaces;
1439  }
1440 
1441  return;
1442 }
1443 
1444 ///////////////////////////////////////////////////////////////////////////////
1445 
1446 void moab::TempestOnlineMap::LinearRemapGLLtoGLL2_Pointwise_MOAB( const DataArray3D< int >& dataGLLNodesIn,
1447  const DataArray3D< double >& /*dataGLLJacobianIn*/,
1448  const DataArray3D< int >& dataGLLNodesOut,
1449  const DataArray3D< double >& /*dataGLLJacobianOut*/,
1450  const DataArray1D< double >& dataNodalAreaOut,
1451  int nPin,
1452  int nPout,
1453  int nMonotoneType,
1454  bool fContinuousIn,
1455  bool fContinuousOut )
1456 {
1457  // Gauss-Lobatto quadrature within Faces
1458  DataArray1D< double > dGL;
1459  DataArray1D< double > dWL;
1460 
1461  GaussLobattoQuadrature::GetPoints( nPout, 0.0, 1.0, dGL, dWL );
1462 
1463  // Get SparseMatrix represntation of the OfflineMap
1464  SparseMatrix< double >& smatMap = this->GetSparseMatrix();
1465 
1466  // Sample coefficients
1467  DataArray2D< double > dSampleCoeffIn( nPin, nPin );
1468 
1469  // Announcemnets
1470  moab::DebugOutput dbgprint( std::cout, this->rank, 0 );
1471  dbgprint.set_prefix( "[LinearRemapGLLtoGLL2_Pointwise_MOAB]: " );
1472  if( is_root )
1473  {
1474  dbgprint.printf( 0, "Finite Element to Finite Element (Pointwise) Projection\n" );
1475  dbgprint.printf( 0, "Order of the input FE polynomial interpolant: %i\n", nPin );
1476  dbgprint.printf( 0, "Order of the output FE polynomial interpolant: %i\n", nPout );
1477  }
1478 
1479  // Number of overlap Faces per source Face
1480  DataArray1D< int > nAllOverlapFaces( m_meshInputCov->faces.size() );
1481 
1482  int ixOverlap = 0;
1483 
1484  for( size_t ixFirst = 0; ixFirst < m_meshInputCov->faces.size(); ixFirst++ )
1485  {
1486  size_t ixOverlapTemp = ixOverlap;
1487  for( ; ixOverlapTemp < m_meshOverlap->faces.size(); ixOverlapTemp++ )
1488  {
1489  // const Face & faceOverlap = m_meshOverlap->faces[ixOverlapTemp];
1490 
1491  if( ixFirst - m_meshOverlap->vecSourceFaceIx[ixOverlapTemp] != 0 ) break;
1492 
1493  nAllOverlapFaces[ixFirst]++;
1494  }
1495 
1496  // Increment the current overlap index
1497  ixOverlap += nAllOverlapFaces[ixFirst];
1498  }
1499 
1500  // Number of times this point was found
1501  DataArray1D< bool > fSecondNodeFound( dataNodalAreaOut.GetRows() );
1502 
1503  ixOverlap = 0;
1504 #ifdef VERBOSE
1505  const unsigned outputFrequency = ( m_meshInputCov->faces.size() / 10 ) + 1;
1506 #endif
1507  // Loop through all faces on m_meshInputCov
1508  for( size_t ixFirst = 0; ixFirst < m_meshInputCov->faces.size(); ixFirst++ )
1509  {
1510 #ifdef VERBOSE
1511  // Announce computation progress
1512  if( ixFirst % outputFrequency == 0 && is_root )
1513  {
1514  dbgprint.printf( 0, "Element %zu/%lu\n", ixFirst, m_meshInputCov->faces.size() );
1515  }
1516 #endif
1517  // Quantities from the First Mesh
1518  const Face& faceFirst = m_meshInputCov->faces[ixFirst];
1519 
1520  const NodeVector& nodesFirst = m_meshInputCov->nodes;
1521 
1522  // Number of overlapping Faces and triangles
1523  int nOverlapFaces = nAllOverlapFaces[ixFirst];
1524 
1525  // Loop through all Overlap Faces
1526  for( int i = 0; i < nOverlapFaces; i++ )
1527  {
1528  // Quantities from the Second Mesh
1529  int ixSecond = m_meshOverlap->vecTargetFaceIx[ixOverlap + i];
1530 
1531  // signal to not participate, because it is a ghost target
1532  if( ixSecond < 0 ) continue; // do not do anything
1533 
1534  const NodeVector& nodesSecond = m_meshOutput->nodes;
1535  const Face& faceSecond = m_meshOutput->faces[ixSecond];
1536 
1537  // Loop through all nodes on the second face
1538  for( int s = 0; s < nPout; s++ )
1539  {
1540  for( int t = 0; t < nPout; t++ )
1541  {
1542  size_t ixSecondNode;
1543  if( fContinuousOut )
1544  {
1545  ixSecondNode = dataGLLNodesOut[s][t][ixSecond] - 1;
1546  }
1547  else
1548  {
1549  ixSecondNode = ixSecond * nPout * nPout + s * nPout + t;
1550  }
1551 
1552  if( ixSecondNode >= fSecondNodeFound.GetRows() ) _EXCEPTIONT( "Logic error" );
1553 
1554  // Check if this node has been found already
1555  if( fSecondNodeFound[ixSecondNode] ) continue;
1556 
1557  // Check this node
1558  Node node;
1559  Node dDx1G;
1560  Node dDx2G;
1561 
1562  ApplyLocalMap( faceSecond, nodesSecond, dGL[t], dGL[s], node, dDx1G, dDx2G );
1563 
1564  // Find the components of this quadrature point in the basis
1565  // of the first Face.
1566  double dAlphaIn;
1567  double dBetaIn;
1568 
1569  ApplyInverseMap( faceFirst, nodesFirst, node, dAlphaIn, dBetaIn );
1570 
1571  // Check if this node is within the first Face
1572  if( ( dAlphaIn < -1.0e-10 ) || ( dAlphaIn > 1.0 + 1.0e-10 ) || ( dBetaIn < -1.0e-10 ) ||
1573  ( dBetaIn > 1.0 + 1.0e-10 ) )
1574  continue;
1575 
1576  // Node is within the overlap region, mark as found
1577  fSecondNodeFound[ixSecondNode] = true;
1578 
1579  // Sample the First finite element at this point
1580  SampleGLLFiniteElement( nMonotoneType, nPin, dAlphaIn, dBetaIn, dSampleCoeffIn );
1581 
1582  // Add to map
1583  for( int p = 0; p < nPin; p++ )
1584  {
1585  for( int q = 0; q < nPin; q++ )
1586  {
1587  int ixFirstNode;
1588  if( fContinuousIn )
1589  {
1590  ixFirstNode = dataGLLNodesIn[p][q][ixFirst] - 1;
1591  }
1592  else
1593  {
1594  ixFirstNode = ixFirst * nPin * nPin + p * nPin + q;
1595  }
1596 
1597  smatMap( ixSecondNode, ixFirstNode ) += dSampleCoeffIn[p][q];
1598  }
1599  }
1600  }
1601  }
1602  }
1603 
1604  // Increment the current overlap index
1605  ixOverlap += nOverlapFaces;
1606  }
1607 
1608  // Check for missing samples
1609  for( size_t i = 0; i < fSecondNodeFound.GetRows(); i++ )
1610  {
1611  if( !fSecondNodeFound[i] )
1612  {
1613  _EXCEPTION1( "Can't sample point %i", i );
1614  }
1615  }
1616 
1617  return;
1618 }
1619 
1620 ///////////////////////////////////////////////////////////////////////////////