Xyst test code coverage report
Current view: top level - Inciter - Refiner.cpp (source / functions) Hit Total Coverage
Commit: 5689ba12dc66a776d3d75f1ee48cc7d78eaa18dc Lines: 508 642 79.1 %
Date: 2024-11-22 19:02:53 Functions: 39 44 88.6 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 404 908 44.5 %

           Branch data     Line data    Source code
       1                 :            : // *****************************************************************************
       2                 :            : /*!
       3                 :            :   \file      src/Inciter/Refiner.cpp
       4                 :            :   \copyright 2012-2015 J. Bakosi,
       5                 :            :              2016-2018 Los Alamos National Security, LLC.,
       6                 :            :              2019-2021 Triad National Security, LLC.,
       7                 :            :              2022-2024 J. Bakosi
       8                 :            :              All rights reserved. See the LICENSE file for details.
       9                 :            :   \brief     Mesh refiner for interfacing the mesh refinement library
      10                 :            :   \see       Refiner.h for more info.
      11                 :            : */
      12                 :            : // *****************************************************************************
      13                 :            : 
      14                 :            : #include <vector>
      15                 :            : #include <algorithm>
      16                 :            : 
      17                 :            : #include "Refiner.hpp"
      18                 :            : #include "Reorder.hpp"
      19                 :            : #include "AMR/mesh_adapter.hpp"
      20                 :            : #include "AMR/Error.hpp"
      21                 :            : #include "InciterConfig.hpp"
      22                 :            : #include "DerivedData.hpp"
      23                 :            : #include "UnsMesh.hpp"
      24                 :            : #include "Centering.hpp"
      25                 :            : #include "Around.hpp"
      26                 :            : #include "Sorter.hpp"
      27                 :            : #include "Discretization.hpp"
      28                 :            : #include "Problems.hpp"
      29                 :            : #include "Vector.hpp"
      30                 :            : 
      31                 :            : namespace inciter {
      32                 :            : 
      33                 :            : extern ctr::Config g_cfg;
      34                 :            : 
      35                 :            : } // inciter::
      36                 :            : 
      37                 :            : using inciter::Refiner;
      38                 :            : 
      39                 :       2459 : Refiner::Refiner( std::size_t meshid,
      40                 :            :                   const CProxy_Transporter& transporter,
      41                 :            :                   const CProxy_Sorter& sorter,
      42                 :            :                   const tk::CProxy_MeshWriter& meshwriter,
      43                 :            :                   const CProxy_Discretization& discretization,
      44                 :            :                   const CProxy_RieCG& riecg,
      45                 :            :                   const CProxy_LaxCG& laxcg,
      46                 :            :                   const CProxy_ZalCG& zalcg,
      47                 :            :                   const CProxy_KozCG& kozcg,
      48                 :            :                   const CProxy_ChoCG& chocg,
      49                 :            :                   const CProxy_LohCG& lohcg,
      50                 :            :                   const tk::CProxy_ConjugateGradients& cgpre,
      51                 :            :                   const tk::CProxy_ConjugateGradients& cgmom,
      52                 :            :                   const tk::RefinerCallback& cbr,
      53                 :            :                   const tk::SorterCallback& cbs,
      54                 :            :                   const std::vector< std::size_t >& ginpoel,
      55                 :            :                   const tk::UnsMesh::CoordMap& coordmap,
      56                 :            :                   const std::map< int, std::vector< std::size_t > >& bface,
      57                 :            :                   const std::vector< std::size_t >& triinpoel,
      58                 :            :                   const std::map< int, std::vector< std::size_t > >& bnode,
      59                 :       2459 :                   int nchare ) :
      60                 :       2459 :   m_meshid( meshid ),
      61                 :       2459 :   m_ncit(0),
      62                 :            :   m_host( transporter ),
      63                 :            :   m_sorter( sorter ),
      64                 :            :   m_meshwriter( meshwriter ),
      65                 :            :   m_disc( discretization ),
      66                 :            :   m_riecg( riecg ),
      67                 :            :   m_laxcg( laxcg ),
      68                 :            :   m_zalcg( zalcg ),
      69                 :            :   m_kozcg( kozcg ),
      70                 :            :   m_chocg( chocg ),
      71                 :            :   m_lohcg( lohcg ),
      72                 :            :   m_cgpre( cgpre ),
      73                 :            :   m_cgmom( cgmom ),
      74                 :       2459 :   m_cbr( cbr ),
      75                 :       2459 :   m_cbs( cbs ),
      76         [ +  - ]:       2459 :   m_ginpoel( ginpoel ),
      77         [ +  - ]:       2459 :   m_el( tk::global2local( ginpoel ) ),     // fills m_inpoel, m_gid, m_lid
      78                 :            :   m_coordmap( coordmap ),
      79         [ +  - ]:       2459 :   m_coord( flatcoord(coordmap) ),
      80                 :            :   m_bface( bface ),
      81                 :            :   m_bnode( bnode ),
      82         [ +  - ]:       2459 :   m_triinpoel( triinpoel ),
      83                 :       2459 :   m_nchare( nchare ),
      84                 :       2459 :   m_mode( RefMode::T0REF ),
      85         [ +  - ]:       2459 :   m_initref( g_cfg.get< tag::href_init >() ),
      86                 :       2459 :   m_ninitref( m_initref.size() ),
      87         [ +  - ]:       2459 :   m_refiner( g_cfg.get< tag::href_maxlevels >(), m_inpoel ),
      88                 :       2459 :   m_nref( 0 ),
      89                 :       2459 :   m_nbnd( 0 ),
      90         [ +  - ]:       2459 :   m_extra( 0 ),
      91                 :       2459 :   m_oldntets( 0 ),
      92 [ +  - ][ +  - ]:       2459 :   m_rid( m_coord[0].size() ),
      93                 :            : //  m_oldrid(),
      94         [ -  - ]:          0 :   m_lref( m_rid.size() ),
      95                 :            : //  m_oldparent(),
      96 [ +  - ][ +  - ]:       7377 :   m_writeCallback()
                 [ +  - ]
      97                 :            : // *****************************************************************************
      98                 :            : //  Constructor
      99                 :            : //! \param[in] meshid Mesh ID
     100                 :            : //! \param[in] transporter Transporter (host) proxy
     101                 :            : //! \param[in] sorter Mesh reordering (sorter) proxy
     102                 :            : //! \param[in] meshwriter Mesh writer proxy
     103                 :            : //! \param[in] discretization Discretization base proxy
     104                 :            : //! \param[in] riecg Discretization scheme proxy
     105                 :            : //! \param[in] laxcg Discretization scheme proxy
     106                 :            : //! \param[in] zalcg Discretization scheme proxy
     107                 :            : //! \param[in] kozcg Discretization scheme proxy
     108                 :            : //! \param[in] chocg Discretization scheme proxy
     109                 :            : //! \param[in] lohcg Discretization scheme proxy
     110                 :            : //! \param[in] cgpre ConjugateGradients Charm++ proxy for pressure solve
     111                 :            : //! \param[in] cgmom ConjugateGradients Charm++ proxy for momentum solve
     112                 :            : //! \param[in] cbr Charm++ callbacks for Refiner
     113                 :            : //! \param[in] cbs Charm++ callbacks for Sorter
     114                 :            : //! \param[in] ginpoel Mesh connectivity (this chare) using global node IDs
     115                 :            : //! \param[in] coordmap Mesh node coordinates (this chare) for global node IDs
     116                 :            : //! \param[in] bface File-internal elem ids of side sets
     117                 :            : //! \param[in] triinpoel Triangle face connectivity with global IDs
     118                 :            : //! \param[in] bnode Node lists of side sets
     119                 :            : //! \param[in] nchare Total number of refiner chares (chare array elements)
     120                 :            : // *****************************************************************************
     121                 :            : {
     122                 :            :   Assert( !m_ginpoel.empty(), "No elements assigned to refiner chare" );
     123                 :            :   Assert( tk::positiveJacobians( m_inpoel, m_coord ),
     124                 :            :           "Input mesh to Refiner Jacobian non-positive" );
     125                 :            :   Assert( !tk::leakyPartition(
     126                 :            :             tk::genEsuelTet( m_inpoel, tk::genEsup(m_inpoel,4) ),
     127                 :            :             m_inpoel, m_coord ),
     128                 :            :           "Input mesh to Refiner leaky" );
     129                 :            : 
     130                 :            :   #if not defined(__INTEL_COMPILER) || defined(NDEBUG)
     131                 :            :   // The above ifdef skips running the conformity test with the intel compiler
     132                 :            :   // in debug mode only. This is necessary because in tk::conforming(), filling
     133                 :            :   // up the map can fail with some meshes (only in parallel), e.g., tube.exo,
     134                 :            :   // used by some regression tests, due to the intel compiler generating some
     135                 :            :   // garbage incorrect code - only in debug, only in parallel, only with that
     136                 :            :   // mesh.
     137                 :            :   Assert( tk::conforming( m_inpoel, m_coord, true, m_rid ),
     138                 :            :           "Input mesh to Refiner not conforming" );
     139                 :            :   #endif
     140                 :            : 
     141                 :            :   // Generate local -> refiner lib node id map and its inverse
     142         [ +  - ]:       2459 :   libmap();
     143                 :            : 
     144                 :            :   // Reverse initial mesh refinement type list (will pop from back)
     145                 :            :   std::reverse( begin(m_initref), end(m_initref) );
     146                 :            : 
     147                 :            :   // Generate boundary data structures for coarse mesh
     148         [ +  - ]:       2459 :   coarseMesh();
     149                 :            : 
     150                 :            :   // If initial mesh refinement is configured, start initial mesh refinement.
     151 [ +  + ][ +  - ]:       2459 :   if (g_cfg.get< tag::href_t0 >() && m_ninitref > 0) {
     152         [ +  - ]:         27 :     t0ref();
     153                 :            :   } else {
     154         [ +  - ]:       2432 :     endt0ref();
     155                 :            :   }
     156                 :       2459 : }
     157                 :            : 
     158                 :            : void
     159                 :       2459 : Refiner::libmap()
     160                 :            : // *****************************************************************************
     161                 :            : // (Re-)generate local -> refiner lib node id map and its inverse
     162                 :            : // *****************************************************************************
     163                 :            : {
     164                 :            :   // Fill initial (matching) mapping between local and refiner node ids
     165                 :            :   std::iota( begin(m_rid), end(m_rid), 0 );
     166                 :            : 
     167                 :            :   // Fill in inverse, mapping refiner to local node ids
     168                 :            :   std::size_t i = 0;
     169         [ +  + ]:     265280 :   for (auto r : m_rid) m_lref[r] = i++;
     170                 :       2459 : }
     171                 :            : 
     172                 :            : void
     173                 :       2468 : Refiner::coarseMesh()
     174                 :            : // *****************************************************************************
     175                 :            : // (Re-)generate side set and block data structures for coarse mesh
     176                 :            : // *****************************************************************************
     177                 :            : {
     178                 :            :   // Generate unique set of faces for each side set of the input (coarsest) mesh
     179                 :            :   m_coarseBndFaces.clear();
     180         [ +  + ]:       8210 :   for (const auto& [ setid, faceids ] : m_bface) {
     181                 :            :     auto& faces = m_coarseBndFaces[ setid ];
     182         [ +  + ]:     231580 :     for (auto f : faceids) {
     183                 :     225838 :       faces.insert(
     184                 :     225838 :         {{{ m_triinpoel[f*3+0], m_triinpoel[f*3+1], m_triinpoel[f*3+2] }}} );
     185                 :            :     }
     186                 :            :   }
     187                 :            : 
     188                 :            :   // Generate unique set of nodes for each side set of the input (coarsest) mesh
     189                 :            :   m_coarseBndNodes.clear();
     190         [ +  + ]:       5074 :   for (const auto& [ setid, nodes ] : m_bnode) {
     191                 :            :     m_coarseBndNodes[ setid ].insert( begin(nodes), end(nodes) );
     192                 :            :   }
     193                 :       2468 : }
     194                 :            : 
     195                 :            : void
     196                 :       2459 : Refiner::sendProxy()
     197                 :            : // *****************************************************************************
     198                 :            : // Send Refiner proxy to Discretization objects
     199                 :            : //! \details This should be called when bound Discretization chare array
     200                 :            : //!   elements have already been created.
     201                 :            : // *****************************************************************************
     202                 :            : {
     203                 :            :   // Make sure (bound) Discretization chare is already created and accessible
     204                 :            :   Assert( m_disc[ thisIndex ].ckLocal() != nullptr,
     205                 :            :           "About to dereference nullptr" );
     206                 :            : 
     207                 :            :   // Pass Refiner Charm++ chare proxy to fellow (bound) Discretization object
     208         [ +  - ]:       4918 :   m_disc[ thisIndex ].ckLocal()->setRefiner( thisProxy );
     209                 :       2459 : }
     210                 :            : 
     211                 :            : void
     212                 :          9 : Refiner::reorder()
     213                 :            : // *****************************************************************************
     214                 :            : // Query Sorter and update local mesh with the reordered one
     215                 :            : // *****************************************************************************
     216                 :            : {
     217                 :          9 :   m_sorter[thisIndex].ckLocal()->
     218         [ +  - ]:         18 :     mesh( m_ginpoel, m_coordmap, m_triinpoel, m_bnode );
     219                 :            : 
     220                 :            :   // Update local mesh data based on data just received from Sorter
     221                 :          9 :   m_el = tk::global2local( m_ginpoel );     // fills m_inpoel, m_gid, m_lid
     222                 :         18 :   m_coord = flatcoord( m_coordmap );
     223                 :            : 
     224                 :            :   // Re-generate boundary data structures for coarse mesh
     225                 :          9 :   coarseMesh();
     226                 :            : 
     227                 :            :   // WARNING: This re-creates the AMR lib which is probably not what we
     228                 :            :   // ultimately want, beacuse this deletes its history recorded during initial
     229                 :            :   // (t<0) refinement. However, this appears to correctly update the local mesh
     230                 :            :   // based on the reordered one (from Sorter) at least when t0ref is off.
     231                 :          9 :   m_refiner = AMR::mesh_adapter_t(
     232                 :          9 :     g_cfg.get< tag::href_maxlevels >(), m_inpoel );
     233                 :          9 : }
     234                 :            : 
     235                 :            : tk::UnsMesh::Coords
     236                 :       2468 : Refiner::flatcoord( const tk::UnsMesh::CoordMap& coordmap )
     237                 :            : // *****************************************************************************
     238                 :            : // Generate flat coordinate data from coordinate map
     239                 :            : //! \param[in] coordmap Coordinates associated to global node IDs of mesh chunk
     240                 :            : //! \return Flat coordinate data
     241                 :            : // *****************************************************************************
     242                 :            : {
     243                 :            :   tk::UnsMesh::Coords coord;
     244                 :            : 
     245                 :            :   // Convert node coordinates associated to global node IDs to a flat vector
     246                 :            :   auto npoin = coordmap.size();
     247                 :            :   Assert( m_gid.size() == npoin, "Size mismatch" );
     248         [ +  - ]:       2468 :   coord[0].resize( npoin );
     249         [ +  - ]:       2468 :   coord[1].resize( npoin );
     250         [ +  - ]:       2468 :   coord[2].resize( npoin );
     251         [ +  + ]:     267599 :   for (const auto& [ gid, coords ] : coordmap) {
     252                 :     265131 :     auto i = tk::cref_find( m_lid, gid );
     253                 :            :     Assert( i < npoin, "Indexing out of coordinate map" );
     254                 :     265131 :     coord[0][i] = coords[0];
     255                 :     265131 :     coord[1][i] = coords[1];
     256                 :     265131 :     coord[2][i] = coords[2];
     257                 :            :   }
     258                 :            : 
     259                 :       2468 :   return coord;
     260                 :          0 : }
     261                 :            : 
     262                 :            : void
     263                 :          0 : Refiner::dtref( const std::map< int, std::vector< std::size_t > >& bface,
     264                 :            :                 const std::map< int, std::vector< std::size_t > >& bnode,
     265                 :            :                 const std::vector< std::size_t >& triinpoel )
     266                 :            : // *****************************************************************************
     267                 :            : // Start mesh refinement (during time stepping, t>0)
     268                 :            : //! \param[in] bface Boundary-faces mapped to side set ids
     269                 :            : //! \param[in] bnode Boundary-node lists mapped to side set ids
     270                 :            : //! \param[in] triinpoel Boundary-face connectivity
     271                 :            : // *****************************************************************************
     272                 :            : {
     273                 :          0 :   m_mode = RefMode::DTREF;
     274                 :            : 
     275                 :            :   // Update boundary node lists
     276                 :            :   m_bface = bface;
     277                 :            :   m_bnode = bnode;
     278                 :          0 :   m_triinpoel = tk::remap(triinpoel, m_gid);
     279                 :            : 
     280                 :          0 :   start();
     281                 :          0 : }
     282                 :            : 
     283                 :            : void
     284                 :         71 : Refiner::t0ref()
     285                 :            : // *****************************************************************************
     286                 :            : // Output mesh to file before a new step mesh refinement
     287                 :            : // *****************************************************************************
     288                 :            : {
     289                 :            :   Assert( m_ninitref > 0, "No initial mesh refinement steps configured" );
     290                 :            :   // Output initial mesh to file
     291         [ +  + ]:         71 :   auto l = m_ninitref - m_initref.size();  // num initref steps completed
     292                 :         71 :   auto t0 = g_cfg.get< tag::t0 >();
     293         [ +  + ]:         71 :   if (l == 0) {
     294 [ +  - ][ +  - ]:         54 :     writeMesh( "t0ref", l, t0-1.0,
     295         [ +  - ]:         81 :       CkCallback( CkIndex_Refiner::start(), thisProxy[thisIndex] ) );
     296                 :            :   } else {
     297                 :         44 :     start();
     298                 :            :   }
     299                 :         71 : }
     300                 :            : 
     301                 :            : void
     302                 :         71 : Refiner::start()
     303                 :            : // *****************************************************************************
     304                 :            : //  Start new step of mesh refinement
     305                 :            : // *****************************************************************************
     306                 :            : {
     307                 :         71 :   m_extra = 0;
     308                 :            :   m_ch.clear();
     309                 :            :   m_remoteEdgeData.clear();
     310                 :            :   m_remoteEdges.clear();
     311                 :            : 
     312                 :         71 :   updateEdgeData();
     313                 :            : 
     314                 :            :   // Generate and communicate boundary edges
     315                 :         71 :   bndEdges();
     316                 :         71 : }
     317                 :            : 
     318                 :            : void
     319                 :         71 : Refiner::bndEdges()
     320                 :            : // *****************************************************************************
     321                 :            : // Generate boundary edges and send them to all chares
     322                 :            : //! \details Extract edges on the boundary only. The boundary edges (shared by
     323                 :            : //!   multiple chares) will be agreed on a refinement that yields a conforming
     324                 :            : //!   mesh across chares boundaries.
     325                 :            : // *****************************************************************************
     326                 :            : {
     327                 :            :   // Compute the number of edges (chunksize) a chare will respond to when
     328                 :            :   // computing shared edges
     329                 :         71 :   auto N = static_cast< std::size_t >( m_nchare );
     330                 :            :   // cppcheck-suppress unreadVariable
     331         [ +  - ]:         71 :   std::size_t chunksize = std::numeric_limits< std::size_t >::max() / N;
     332                 :            : 
     333                 :            :   // Generate boundary edges of our mesh chunk
     334                 :            :   std::unordered_map< int, EdgeSet > chbedges;
     335         [ +  - ]:         71 :   auto esup = tk::genEsup( m_inpoel, 4 );         // elements surrounding points
     336         [ +  - ]:         71 :   auto esuel = tk::genEsuelTet( m_inpoel, esup ); // elems surrounding elements
     337         [ +  + ]:      72875 :   for (std::size_t e=0; e<esuel.size()/4; ++e) {
     338                 :      72804 :     auto mark = e*4;
     339         [ +  + ]:     364020 :     for (std::size_t f=0; f<4; ++f) {
     340         [ +  + ]:     291216 :       if (esuel[mark+f] == -1) {
     341         [ +  - ]:      22868 :         auto A = m_ginpoel[ mark+tk::lpofa[f][0] ];
     342                 :            :         // cppcheck-suppress unreadVariable
     343                 :      22868 :         auto B = m_ginpoel[ mark+tk::lpofa[f][1] ];
     344                 :            :         // cppcheck-suppress unreadVariable
     345                 :      22868 :         auto C = m_ginpoel[ mark+tk::lpofa[f][2] ];
     346                 :            :         Assert( m_lid.find( A ) != end(m_lid), "Local node ID not found" );
     347                 :            :         Assert( m_lid.find( B ) != end(m_lid), "Local node ID not found" );
     348                 :            :         Assert( m_lid.find( C ) != end(m_lid), "Local node ID not found" );
     349                 :            :         // assign edges to bins a single chare will respond to when computing
     350                 :            :         // shared edges
     351                 :      22868 :         auto bin = A / chunksize;
     352                 :            :         Assert( bin < N, "Will index out of number of chares" );
     353 [ +  - ][ +  - ]:      22868 :         chbedges[ static_cast<int>(bin) ].insert( {A,B} );
     354                 :      22868 :         bin = B / chunksize;
     355                 :            :         Assert( bin < N, "Will index out of number of chares" );
     356 [ +  - ][ +  - ]:      22868 :         chbedges[ static_cast<int>(bin) ].insert( {B,C} );
     357                 :      22868 :         bin = C / chunksize;
     358                 :            :         Assert( bin < N, "Will index out of number of chares" );
     359 [ +  - ][ +  - ]:      22868 :         chbedges[ static_cast<int>(bin) ].insert( {C,A} );
     360                 :            :       }
     361                 :            :     }
     362                 :            :   }
     363                 :            : 
     364                 :            :   // Send edges in bins to chares that will compute shared edges
     365                 :         71 :   m_nbnd = chbedges.size();
     366         [ -  + ]:         71 :   if (m_nbnd == 0)
     367         [ -  - ]:          0 :     contribute( sizeof(std::size_t), &m_meshid, CkReduction::nop,
     368                 :            :                 m_cbr.get< tag::queried >() );
     369                 :            :   else
     370         [ +  + ]:        168 :     for (const auto& [ targetchare, bndedges ] : chbedges)
     371 [ +  - ][ +  - ]:        194 :       thisProxy[ targetchare ].query( thisIndex, bndedges );
                 [ -  - ]
     372                 :        142 : }
     373                 :            : 
     374                 :            : void
     375                 :         97 : Refiner::query( int fromch, const EdgeSet& edges )
     376                 :            : // *****************************************************************************
     377                 :            : // Incoming query for a list boundary edges for which this chare compiles
     378                 :            : // shared edges
     379                 :            : //! \param[in] fromch Sender chare ID
     380                 :            : //! \param[in] edges Chare-boundary edge list from another chare
     381                 :            : // *****************************************************************************
     382                 :            : {
     383                 :            :   // Store incoming edges in edge->chare and its inverse, chare->edge, maps
     384         [ +  + ]:      88075 :   for (const auto& e : edges) m_edgech[ e ].push_back( fromch );
     385                 :            :   m_chedge[ fromch ].insert( begin(edges), end(edges) );
     386                 :            :   // Report back to chare message received from
     387         [ +  - ]:         97 :   thisProxy[ fromch ].recvquery();
     388                 :         97 : }
     389                 :            : 
     390                 :            : void
     391                 :         97 : Refiner::recvquery()
     392                 :            : // *****************************************************************************
     393                 :            : // Receive receipt of boundary edge lists to query
     394                 :            : // *****************************************************************************
     395                 :            : {
     396         [ +  + ]:         97 :   if (--m_nbnd == 0)
     397                 :         71 :     contribute( sizeof(std::size_t), &m_meshid, CkReduction::nop,
     398                 :            :                 m_cbr.get< tag::queried >() );
     399                 :         97 : }
     400                 :            : 
     401                 :            : void
     402                 :         71 : Refiner::response()
     403                 :            : // *****************************************************************************
     404                 :            : //  Respond to boundary edge list queries
     405                 :            : // *****************************************************************************
     406                 :            : {
     407                 :            :   std::unordered_map< int, std::vector< int > > exp;
     408                 :            : 
     409                 :            :   // Compute shared edges whose chare ids will be sent back to querying chares
     410         [ +  + ]:        168 :   for (const auto& [ neighborchare, bndedges ] : m_chedge) {
     411                 :            :     auto& e = exp[ neighborchare ];
     412         [ +  + ]:      44086 :     for (const auto& ed : bndedges)
     413         [ +  + ]:      94126 :       for (auto d : tk::cref_find(m_edgech,ed))
     414         [ +  + ]:      50137 :         if (d != neighborchare)
     415                 :            :           // cppcheck-suppress useStlAlgorithm
     416         [ +  - ]:       6148 :           e.push_back( d );
     417                 :            :   }
     418                 :            : 
     419                 :            :   // Send chare ids of shared edges to chares that issued a query to us. Shared
     420                 :            :   // boundary edges assigned to chare ids sharing the boundary edge were
     421                 :            :   // computed above for those chares that queried this map from us. These
     422                 :            :   // boundary edges form a distributed table and we only work on a chunk of it.
     423                 :            :   // Note that we only send data back to those chares that have queried us. The
     424                 :            :   // receiving sides do not know in advance if they receive messages or not.
     425                 :            :   // Completion is detected by having the receiver respond back and counting
     426                 :            :   // the responses on the sender side, i.e., this chare.
     427                 :         71 :   m_nbnd = exp.size();
     428         [ +  + ]:         71 :   if (m_nbnd == 0)
     429         [ +  - ]:         20 :     contribute( sizeof(std::size_t), &m_meshid, CkReduction::nop,
     430                 :            :                 m_cbr.get< tag::responded >() );
     431                 :            :   else
     432         [ +  + ]:        148 :     for (const auto& [ targetchare, bndedges ] : exp)
     433 [ +  - ][ +  - ]:        194 :       thisProxy[ targetchare ].bnd( thisIndex, bndedges );
     434                 :         71 : }
     435                 :            : 
     436                 :            : void
     437                 :         97 : Refiner::bnd( int fromch, const std::vector< int >& chares )
     438                 :            : // *****************************************************************************
     439                 :            : // Receive shared boundary edges for our mesh chunk
     440                 :            : //! \param[in] fromch Sender chare ID
     441                 :            : //! \param[in] chares Chare ids we share edges with
     442                 :            : // *****************************************************************************
     443                 :            : {
     444                 :            :   // Store chare ids we share edges with
     445                 :            :   m_ch.insert( begin(chares), end(chares) );
     446                 :            : 
     447                 :            :   // Report back to chare message received from
     448         [ +  - ]:         97 :   thisProxy[ fromch ].recvbnd();
     449                 :         97 : }
     450                 :            : 
     451                 :            : void
     452                 :         97 : Refiner::recvbnd()
     453                 :            : // *****************************************************************************
     454                 :            : // Receive receipt of shared boundary edges
     455                 :            : // *****************************************************************************
     456                 :            : {
     457         [ +  + ]:         97 :   if (--m_nbnd == 0)
     458                 :         51 :     contribute( sizeof(std::size_t), &m_meshid, CkReduction::nop,
     459                 :            :                 m_cbr.get< tag::responded >() );
     460                 :         97 : }
     461                 :            : 
     462                 :            : void
     463                 :         71 : Refiner::refine()
     464                 :            : // *****************************************************************************
     465                 :            : //  Do a single step of mesh refinement (really, only tag edges)
     466                 :            : //! \details During initial (t<0, t0ref) mesh refinement, this is a single step
     467                 :            : //!   in a potentially multiple-entry list of initial adaptive mesh refinement
     468                 :            : //!   steps. Distribution of the chare-boundary edges must have preceded this
     469                 :            : //!   step, so that boundary edges (shared by multiple chares) can agree on a
     470                 :            : //!   refinement that yields a conforming mesh across chare boundaries.
     471                 :            : //!
     472                 :            : //!   During-timestepping (t>0, dtref) mesh refinement this is called once, as
     473                 :            : //!   we only do a single step during time stepping.
     474                 :            : // *****************************************************************************
     475                 :            : {
     476                 :            :   // Free memory used for computing shared boundary edges
     477                 :         71 :   tk::destroy( m_edgech );
     478                 :         71 :   tk::destroy( m_chedge );
     479                 :            : 
     480                 :            :   // Perform leak test on old mesh
     481                 :            :   Assert( !tk::leakyPartition(
     482                 :            :             tk::genEsuelTet( m_inpoel, tk::genEsup(m_inpoel,4) ),
     483                 :            :             m_inpoel, m_coord ),
     484                 :            :           "Mesh partition before refinement leaky" );
     485                 :            : 
     486         [ +  - ]:         71 :   if (m_mode == RefMode::T0REF) {
     487                 :            : 
     488                 :            :     // Refine mesh based on next initial refinement type
     489         [ +  - ]:         71 :     if (!m_initref.empty()) {
     490                 :            :       auto r = m_initref.back();    // consume (reversed) list from its back
     491         [ +  + ]:         71 :       if (r == "uniform")
     492         [ +  - ]:         31 :         uniformRefine();
     493         [ +  + ]:         40 :       else if (r == "uniform_deref")
     494         [ +  - ]:         24 :         uniformDeRefine();
     495         [ +  - ]:         16 :       else if (r == "ic")
     496         [ +  - ]:         16 :         errorRefine();
     497         [ -  - ]:          0 :       else if (r == "coord")
     498         [ -  - ]:          0 :         coordRefine();
     499         [ -  - ]:          0 :       else if (r == "edges")
     500         [ -  - ]:          0 :         edgelistRefine();
     501 [ -  - ][ -  - ]:          0 :       else Throw( "Initial AMR type not implemented" );
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
                 [ -  - ]
     502                 :            :     }
     503                 :            : 
     504         [ -  - ]:          0 :   } else if (m_mode == RefMode::DTREF) {
     505                 :            : 
     506                 :            :     //if (true)//g_cfg.get< tag::amr, tag::dtref_uniform >())
     507                 :          0 :       uniformRefine();
     508                 :            :     //else
     509                 :            :       //errorRefine();
     510                 :            : 
     511 [ -  - ][ -  - ]:          0 :   } else Throw( "RefMode not implemented" );
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
                 [ -  - ]
     512                 :            : 
     513                 :            :   // Communicate extra edges
     514                 :         71 :   comExtra();
     515                 :         71 : }
     516                 :            : 
     517                 :            : void
     518         [ +  + ]:         71 : Refiner::comExtra()
     519                 :            : // *****************************************************************************
     520                 :            : // Communicate extra edges along chare boundaries
     521                 :            : // *****************************************************************************
     522                 :            : {
     523                 :            :   // Export extra added nodes on our mesh chunk boundary to other chares
     524         [ +  + ]:         71 :   if (m_ch.empty()) {
     525                 :         13 :     correctref();
     526                 :            :   } else {
     527         [ +  + ]:        146 :     for (auto c : m_ch) {  // for all chares we share at least an edge with
     528 [ +  - ][ -  + ]:        264 :       thisProxy[c].addRefBndEdges(thisIndex, m_localEdgeData, m_intermediates);
                 [ -  - ]
     529                 :            :     }
     530                 :            :   }
     531                 :         71 : }
     532                 :            : 
     533                 :            : void
     534                 :         88 : Refiner::addRefBndEdges(
     535                 :            :   int fromch,
     536                 :            :   const AMR::EdgeData& ed,
     537                 :            :   const std::unordered_set< std::size_t >& intermediates )
     538                 :            : // *****************************************************************************
     539                 :            : //! Receive edges on our chare boundary from other chares
     540                 :            : //! \param[in] fromch Chare call coming from
     541                 :            : //! \param[in] ed Edges on chare boundary
     542                 :            : //! \param[in] intermediates Intermediate nodes
     543                 :            : //! \details Other than update remoteEdge data, this function also updates
     544                 :            : //!   locking information for such edges whos nodes are marked as intermediate
     545                 :            : //!   by neighboring chares.
     546                 :            : // *****************************************************************************
     547                 :            : {
     548                 :            :   // Save/augment buffers of edge data for each sender chare
     549                 :            :   auto& red = m_remoteEdgeData[ fromch ];
     550                 :            :   auto& re = m_remoteEdges[ fromch ];
     551                 :            :   using edge_data_t = std::tuple< Edge, int, int, AMR::Edge_Lock_Case >;
     552         [ +  + ]:      77072 :   for (const auto& [ edge, data ] : ed) {
     553                 :      76984 :     red.push_back( edge_data_t{ edge, std::get<0>(data), std::get<1>(data),
     554                 :            :       std::get<2>(data) } );
     555                 :      76984 :     re.push_back( edge );
     556                 :            :   }
     557                 :            : 
     558                 :            :   // Add intermediates to mesh refiner lib
     559                 :            :   // needs to be done only when mesh has been actually updated, i.e. first iter
     560         [ +  - ]:         88 :   if (m_ncit == 0) {
     561                 :         88 :     auto esup = tk::genEsup( m_inpoel, 4 );
     562         [ +  - ]:         88 :     auto psup = tk::genPsup( m_inpoel, 4, esup );
     563         [ +  + ]:        239 :     for (const auto g : intermediates) {
     564         [ -  + ]:        151 :       auto l = m_lid.find( g ); // convert to local node ids
     565         [ -  + ]:        151 :       if (l != end(m_lid)) {
     566                 :            :         // lock all edges connected to intermediate node
     567                 :          0 :         auto p = l->second;
     568 [ -  - ][ -  - ]:          0 :         for (auto q : tk::Around(psup,p)) {
     569         [ -  - ]:          0 :           AMR::edge_t e(m_rid[p], m_rid[q]);
     570         [ -  - ]:          0 :           auto& refedge = m_refiner.tet_store.edge_store.get(e);
     571         [ -  - ]:          0 :           if (refedge.lock_case == AMR::Edge_Lock_Case::unlocked) {
     572                 :          0 :             refedge.lock_case = AMR::Edge_Lock_Case::temporary; //intermediate;
     573                 :          0 :             refedge.needs_refining = 0;
     574                 :            :           }
     575                 :            :         }
     576                 :            :       }
     577                 :            :     }
     578                 :         88 :   }
     579                 :            : 
     580                 :            :   // Heard from every worker we share at least a single edge with
     581         [ +  + ]:         88 :   if (++m_nref == m_ch.size()) {
     582                 :         58 :     m_nref = 0;
     583                 :            : 
     584                 :         58 :     updateBndEdgeData();
     585                 :            : 
     586                 :         58 :     std::vector< std::size_t > meshdata{ m_meshid };
     587         [ +  - ]:         58 :     contribute( meshdata, CkReduction::max_ulong,
     588                 :            :                 m_cbr.get< tag::compatibility >() );
     589                 :            :   }
     590                 :         88 : }
     591                 :            : 
     592                 :            : void
     593                 :         71 : Refiner::correctref()
     594                 :            : // *****************************************************************************
     595                 :            : //  Correct extra edges to arrive at conforming mesh across chare boundaries
     596                 :            : //! \details This function is called repeatedly until there is not a a single
     597                 :            : //!    edge that needs correction for the whole distributed problem to arrive at
     598                 :            : //!    a conforming mesh across chare boundaries during a mesh refinement step.
     599                 :            : // *****************************************************************************
     600                 :            : {
     601                 :            :   auto unlocked = AMR::Edge_Lock_Case::unlocked;
     602                 :            : 
     603                 :            :   // Storage for edge data that need correction to yield a conforming mesh
     604                 :            :   AMR::EdgeData extra;
     605                 :            :   std::size_t neigh_extra(0);
     606                 :            : 
     607                 :            :   // Vars for debugging purposes
     608                 :            :   // cppcheck-suppress unreadVariable
     609                 :            :   std::size_t nlocked(0);
     610                 :            :   std::array< std::size_t, 4 > ncorrcase{{0,0,0,0}};
     611                 :            : 
     612                 :            :   // loop through all edges shared with other chares
     613         [ +  + ]:        159 :   for (const auto& [ neighborchare, edgedata ] : m_remoteEdgeData) {
     614                 :         88 :     for (const auto& [edge,remote_needs_refining,remote_needs_derefining,
     615         [ +  + ]:      77072 :       remote_lock_case] : edgedata) {
     616                 :            :       // find local data of remote edge
     617                 :            :       auto it = m_localEdgeData.find( edge );
     618         [ +  + ]:      76984 :       if (it != end(m_localEdgeData)) {
     619                 :            :         auto& local = it->second;
     620                 :            :         auto& local_needs_refining = std::get<0>(local);
     621                 :            :         auto& local_needs_derefining = std::get<1>(local);
     622                 :            :         auto& local_lock_case = std::get<2>(local);
     623                 :            : 
     624                 :            :         // cppcheck-suppress unreadVariable
     625                 :       4484 :         auto local_needs_refining_orig = local_needs_refining;
     626                 :            :         // cppcheck-suppress unreadVariable
     627                 :       4484 :         auto local_needs_derefining_orig = local_needs_derefining;
     628                 :            :         // cppcheck-suppress unreadVariable
     629         [ -  + ]:       4484 :         auto local_lock_case_orig = local_lock_case;
     630                 :            : 
     631                 :            :         Assert( !(local_lock_case > unlocked && local_needs_refining),
     632                 :            :                 "Invalid local edge: locked & needs refining" );
     633                 :            :         Assert( !(remote_lock_case > unlocked && remote_needs_refining),
     634                 :            :                 "Invalid remote edge: locked & needs refining" );
     635                 :            :         Assert( !(local_needs_derefining == 1 && local_needs_refining > 0),
     636                 :            :                 "Invalid local edge: needs refining and derefining" );
     637                 :            : 
     638                 :            :         // The parallel compatibility (par-compat) algorithm
     639                 :            : 
     640                 :            :         // compute lock from local and remote locks as most restrictive
     641                 :       4484 :         local_lock_case = std::max( local_lock_case, remote_lock_case );
     642                 :            : 
     643         [ +  - ]:       4484 :         if (local_lock_case > unlocked) {
     644                 :          0 :           local_needs_refining = 0;
     645                 :            :           if (local_needs_refining != local_needs_refining_orig ||
     646                 :            :             local_lock_case != local_lock_case_orig)
     647                 :            :             ++ncorrcase[0];
     648                 :            :         }
     649                 :            : 
     650                 :            :         // Possible combinations of remote-local ref-deref decisions
     651                 :            :         // rows 1, 5, 9: no action needed.
     652                 :            :         // rows 4, 7, 8: no action on local-side; comm needed.
     653                 :            :         //
     654                 :            :         //    LOCAL          |        REMOTE    |  Result
     655                 :            :         // 1  d              |        d         |  d
     656                 :            :         // 2  d              |        -         |  -
     657                 :            :         // 3  d              |        r         |  r
     658                 :            :         // 4  -              |        d         |  -
     659                 :            :         // 5  -              |        -         |  -
     660                 :            :         // 6  -              |        r         |  r
     661                 :            :         // 7  r              |        d         |  r
     662                 :            :         // 8  r              |        -         |  r
     663                 :            :         // 9  r              |        r         |  r
     664                 :            : 
     665                 :            :         // Rows 3, 6
     666                 :            :         // If remote wants to refine
     667         [ +  + ]:       4484 :         if (remote_needs_refining == 1) {
     668         [ +  - ]:       2198 :           if (local_lock_case == unlocked) {
     669                 :       2198 :             local_needs_refining = 1;
     670                 :       2198 :             local_needs_derefining = false;
     671                 :            :             if (local_needs_refining != local_needs_refining_orig ||
     672                 :            :               local_needs_derefining != local_needs_derefining_orig)
     673                 :            :               ++ncorrcase[1];
     674                 :            :           }
     675                 :            :           else {
     676                 :            :            ++nlocked;
     677                 :            :           }
     678                 :            :         }
     679                 :            : 
     680                 :            :         // Row 2
     681                 :            :         // If remote neither wants to refine nor derefine
     682 [ +  + ][ +  + ]:       4484 :         if (remote_needs_refining == 0 && remote_needs_derefining == false) {
     683                 :        126 :           local_needs_derefining = false;
     684                 :            :           if (local_needs_derefining != local_needs_derefining_orig)
     685                 :            :             ++ncorrcase[2];
     686                 :            :         }
     687                 :            : 
     688                 :            :         // Row 1: special case
     689                 :            :         // If remote wants to deref-ref (either of 8:4, 8:2, 4:2)
     690                 :            :         // and local does not want to refine (neither pure ref nor deref-ref)
     691 [ -  + ][ -  - ]:       4484 :         if (remote_needs_refining == 2 && local_needs_refining == 0) {
     692         [ -  - ]:          0 :           if (local_lock_case == unlocked) {
     693                 :          0 :             local_needs_refining = 1;
     694                 :          0 :             local_needs_derefining = false;
     695                 :            :             if (local_needs_refining != local_needs_refining_orig ||
     696                 :            :               local_needs_derefining != local_needs_derefining_orig)
     697                 :            :               ++ncorrcase[3];
     698                 :            :           }
     699                 :            :           else {
     700                 :            :             // cppcheck-suppress unreadVariable
     701                 :            :             ++nlocked;
     702                 :            :           }
     703                 :            :         }
     704                 :            : 
     705                 :            :         // Rows 4, 7, 8
     706                 :            : 
     707                 :            :         // if the remote sent us data that makes us change our local state,
     708                 :            :         // e.g., local{-,0} + remote{r,0} -> local{r,0}, i.e., I changed my
     709                 :            :         // state I need to tell the world about it
     710         [ +  - ]:       4484 :         if (local_lock_case != local_lock_case_orig ||
     711         [ +  - ]:       4484 :             local_needs_refining != local_needs_refining_orig ||
     712         [ -  + ]:       4484 :             local_needs_derefining != local_needs_derefining_orig)
     713                 :            :         {
     714         [ -  - ]:          0 :           auto l1 = tk::cref_find( m_lid, edge[0] );
     715         [ -  - ]:          0 :           auto l2 = tk::cref_find( m_lid, edge[1] );
     716                 :            :           Assert( l1 != l2, "Edge end-points local ids are the same" );
     717                 :          0 :           auto r1 = m_rid[ l1 ];
     718         [ -  - ]:          0 :           auto r2 = m_rid[ l2 ];
     719                 :            :           Assert( r1 != r2, "Edge end-points refiner ids are the same" );
     720                 :            :           //std::cout << thisIndex << ": " << r1 << ", " << r2 << std::endl;
     721                 :            :           //if (m_refiner.tet_store.edge_store.get(AMR::edge_t(r1,r2)).lock_case > local_lock_case) {
     722                 :            :           //  std::cout << thisIndex << ": edge " << r1 << "-" << r2 <<
     723                 :            :           //    "; prev=" << local_lock_case_orig <<
     724                 :            :           //    "; new=" << local_lock_case <<
     725                 :            :           //    "; amr-lib=" << m_refiner.tet_store.edge_store.get(AMR::edge_t(r1,r2)).lock_case <<
     726                 :            :           //    " | parcompatiter " << m_ncit << std::endl;
     727                 :            :           //}
     728 [ -  - ][ -  - ]:          0 :            extra[ {{ std::min(r1,r2), std::max(r1,r2) }} ] =
     729                 :            :              { local_needs_refining, local_needs_derefining, local_lock_case };
     730                 :          0 :         }
     731                 :            :         // or if the remote data is inconsistent with what I think, e.g.,
     732                 :            :         // local{r,0} + remote{-,0} -> local{r,0}, i.e., the remote does not
     733                 :            :         // yet agree, so another par-compat iteration will be pursued. but
     734                 :            :         // I do not have to locally run ref-compat.
     735         [ +  - ]:       4484 :         else if (local_lock_case != remote_lock_case ||
     736         [ +  - ]:       4484 :           local_needs_refining != remote_needs_refining ||
     737         [ +  - ]:       4484 :           local_needs_derefining != remote_needs_derefining)
     738                 :            :         {
     739                 :          0 :           ++neigh_extra;
     740                 :            :         }
     741                 :            :       }
     742                 :            :     }
     743                 :            :   }
     744                 :            : 
     745                 :            :   m_remoteEdgeData.clear();
     746                 :         71 :   m_extra = extra.size();
     747                 :            :   //std::cout << thisIndex << ": amr correction reqd for nedge: " << m_extra << std::endl;
     748                 :            :   //std::cout << thisIndex << ": amr correction reqd for neighbor edges: " << neigh_extra << std::endl;
     749                 :            :   //std::cout << thisIndex << ": edge counts by correction case: " << ncorrcase[0]
     750                 :            :   //  << ", " << ncorrcase[1] << ", " << ncorrcase[2] << ", " << ncorrcase[3] << std::endl;
     751                 :            :   //std::cout << thisIndex << ": locked edges that req corr: " << nlocked << std::endl;
     752                 :            : 
     753         [ -  + ]:         71 :   if (!extra.empty()) {
     754                 :            :     //std::cout << thisIndex << ": redoing markings" << std::endl;
     755                 :            :     // Do refinement compatibility (ref-compat) for edges that need correction
     756         [ -  - ]:          0 :     m_refiner.mark_error_refinement_corr( extra );
     757                 :          0 :     ++m_ncit;
     758                 :            :     // Update our extra-edge store based on refiner
     759         [ -  - ]:          0 :     updateEdgeData();
     760                 :            :     m_remoteEdges.clear();
     761                 :            :   }
     762         [ +  - ]:         71 :   else if (neigh_extra == 0) {
     763                 :         71 :     m_ncit = 0;
     764                 :            :   }
     765                 :            : 
     766                 :            :   // Aggregate number of extra edges that still need correction and some
     767                 :            :   // refinement/derefinement statistics
     768                 :            :   const auto& tet_store = m_refiner.tet_store;
     769                 :            :   std::vector< std::size_t >
     770                 :         71 :     m{ m_meshid,
     771                 :         71 :        m_extra,
     772                 :            :        tet_store.marked_refinements.size(),
     773                 :            :        tet_store.marked_derefinements.size(),
     774         [ +  - ]:         71 :        static_cast< std::underlying_type_t< RefMode > >( m_mode ) };
     775         [ +  - ]:         71 :   contribute( m, CkReduction::sum_ulong, m_cbr.get< tag::matched >() );
     776                 :         71 : }
     777                 :            : 
     778                 :            : void
     779                 :        142 : Refiner::updateEdgeData()
     780                 :            : // *****************************************************************************
     781                 :            : // Query AMR lib and update our local store of edge data
     782                 :            : // *****************************************************************************
     783                 :            : {
     784                 :            :   m_localEdgeData.clear();
     785                 :            :   m_intermediates.clear();
     786                 :            : 
     787                 :            :   // This currently takes ALL edges from the AMR lib, i.e., on the whole
     788                 :            :   // domain. We should eventually only collect edges here that are shared with
     789                 :            :   // other chares.
     790                 :            :   const auto& ref_edges = m_refiner.tet_store.edge_store.edges;
     791                 :        142 :   const auto& refinpoel = m_refiner.tet_store.get_active_inpoel();
     792                 :            : 
     793         [ +  + ]:     145750 :   for (std::size_t e=0; e<refinpoel.size()/4; ++e) {
     794                 :     145608 :     auto A = refinpoel[e*4+0];
     795                 :     145608 :     auto B = refinpoel[e*4+1];
     796                 :     145608 :     auto C = refinpoel[e*4+2];
     797                 :     145608 :     auto D = refinpoel[e*4+3];
     798                 :            :     std::array<Edge,6> edges{{ {{A,B}}, {{B,C}}, {{A,C}},
     799                 :     145608 :                                {{A,D}}, {{B,D}}, {{C,D}} }};
     800         [ +  + ]:    1019256 :     for (const auto& ed : edges) {
     801         [ +  + ]:    1422078 :       auto ae = AMR::edge_t{{{ std::min(ed[0],ed[1]), std::max(ed[0],ed[1]) }}};
     802                 :     873648 :       auto r = tk::cref_find( ref_edges, ae );
     803                 :     873648 :       const auto ged = Edge{{ m_gid[ tk::cref_find( m_lref, ed[0] ) ],
     804                 :     873648 :                               m_gid[ tk::cref_find( m_lref, ed[1] ) ] }};
     805                 :            :       m_localEdgeData[ ged ] =
     806                 :            :         { r.needs_refining, r.needs_derefining, r.lock_case };
     807                 :            :     }
     808                 :            :   }
     809                 :            : 
     810                 :            :   // Build intermediates to send. This currently takes ALL intermediates from
     811                 :            :   // the AMR lib, i.e., on the whole domain. We should eventually only collect
     812                 :            :   // edges here that are shared with other chares.
     813         [ +  + ]:        746 :   for (const auto& r : m_refiner.tet_store.intermediate_list) {
     814                 :        604 :     m_intermediates.insert( m_gid[ tk::cref_find( m_lref, r ) ] );
     815                 :            :   }
     816                 :        142 : }
     817                 :            : 
     818                 :            : void
     819                 :         58 : Refiner::updateBndEdgeData()
     820                 :            : // *****************************************************************************
     821                 :            : // Query AMR lib and update our local store of boundary edge data
     822                 :            : // *****************************************************************************
     823                 :            : {
     824                 :            :   // This currently takes ALL edges from the AMR lib, i.e., on the whole
     825                 :            :   // domain. We should eventually only collect edges here that are shared with
     826                 :            :   // other chares.
     827                 :            :   const auto& ref_edges = m_refiner.tet_store.edge_store.edges;
     828                 :         58 :   const auto& refinpoel = m_refiner.tet_store.get_active_inpoel();
     829                 :            : 
     830         [ +  + ]:      48163 :   for (std::size_t e=0; e<refinpoel.size()/4; ++e) {
     831                 :      48105 :     auto A = refinpoel[e*4+0];
     832                 :      48105 :     auto B = refinpoel[e*4+1];
     833                 :      48105 :     auto C = refinpoel[e*4+2];
     834                 :      48105 :     auto D = refinpoel[e*4+3];
     835                 :            :     std::array<Edge,6> edges{{ {{A,B}}, {{B,C}}, {{A,C}},
     836                 :      48105 :                                {{A,D}}, {{B,D}}, {{C,D}} }};
     837         [ +  + ]:     336735 :     for (const auto& ed : edges) {
     838         [ +  + ]:     471418 :       auto ae = AMR::edge_t{{{ std::min(ed[0],ed[1]), std::max(ed[0],ed[1]) }}};
     839                 :     288630 :       auto r = tk::cref_find( ref_edges, ae );
     840                 :     288630 :       const auto ged = Edge{{ m_gid[ tk::cref_find( m_lref, ed[0] ) ],
     841                 :     288630 :                               m_gid[ tk::cref_find( m_lref, ed[1] ) ] }};
     842                 :            :       // only update edges that are on chare boundary OR unlocked
     843         [ +  - ]:     288630 :       if (m_localEdgeData.find(ged) == m_localEdgeData.end() ||
     844         [ +  - ]:     288630 :         std::get<2>(m_localEdgeData[ged]) == AMR::Edge_Lock_Case::unlocked) {
     845                 :            :         m_localEdgeData[ ged ] = { r.needs_refining, r.needs_derefining,
     846                 :            :           r.lock_case };
     847                 :            :       }
     848                 :            :     }
     849                 :            :   }
     850                 :         58 : }
     851                 :            : 
     852                 :            : std::tuple< std::vector< std::string >,
     853                 :            :             std::vector< std::vector< tk::real > >,
     854                 :            :             std::vector< std::string >,
     855                 :            :             std::vector< std::vector< tk::real > > >
     856                 :         98 : Refiner::refinementFields() const
     857                 :            : // *****************************************************************************
     858                 :            : //  Collect mesh output fields from refiner lib
     859                 :            : //! \return Names and fields of mesh refinement data in mesh cells and nodes
     860                 :            : // *****************************************************************************
     861                 :            : {
     862                 :            :   // Find number of nodes in current mesh
     863                 :         98 :   auto npoin = tk::npoin_in_graph( m_inpoel );
     864                 :            :   // Generate edges surrounding points in current mesh
     865                 :         98 :   auto esup = tk::genEsup( m_inpoel, 4 );
     866                 :            : 
     867                 :            :   // Update solution on current mesh
     868         [ +  - ]:         98 :   const auto& u = solution( npoin, esup );
     869                 :            :   Assert( u.nunk() == npoin, "Solution uninitialized or wrong size" );
     870                 :            : 
     871                 :            :   // Compute error in edges on current mesh
     872         [ +  - ]:         98 :   auto edgeError = errorsInEdges( npoin, esup, u );
     873                 :            : 
     874                 :            :   // Transfer error from edges to cells for field output
     875         [ +  - ]:         98 :   std::vector< tk::real > error( m_inpoel.size()/4, 0.0 );
     876         [ +  + ]:     133213 :   for (std::size_t e=0; e<m_inpoel.size()/4; ++e) {
     877                 :     133115 :     auto A = m_inpoel[e*4+0];
     878                 :     133115 :     auto B = m_inpoel[e*4+1];
     879                 :     133115 :     auto C = m_inpoel[e*4+2];
     880                 :     133115 :     auto D = m_inpoel[e*4+3];
     881                 :            :     std::array<Edge,6> edges{{ {{A,B}}, {{B,C}}, {{A,C}},
     882                 :     133115 :                                {{A,D}}, {{B,D}}, {{C,D}} }};
     883                 :            :     // sum error from edges to elements
     884         [ +  + ]:     931805 :     for (const auto& ed : edges) error[e] += tk::cref_find( edgeError, ed );
     885                 :     133115 :     error[e] /= 6.0;    // assign edge-average error to element
     886                 :            :   }
     887                 :            : 
     888                 :            :   // Prepare element fields with mesh refinement data
     889                 :            :   std::vector< std::string >
     890 [ -  + ][ +  + ]:        392 :     elemfieldnames{ "refinement level", "cell type", "error" };
         [ +  + ][ -  - ]
         [ -  - ][ -  - ]
     891                 :         98 :   auto& tet_store = m_refiner.tet_store;
     892                 :            :   std::vector< std::vector< tk::real > > elemfields{
     893                 :            :     tet_store.get_refinement_level_list(),
     894                 :            :     tet_store.get_cell_type_list(),
     895 [ -  + ][ +  + ]:        392 :     error };
         [ +  - ][ +  - ]
         [ -  - ][ -  - ]
     896                 :            : 
     897                 :            :   using tuple_t = std::tuple< std::vector< std::string >,
     898                 :            :                               std::vector< std::vector< tk::real > >,
     899                 :            :                               std::vector< std::string >,
     900                 :            :                               std::vector< std::vector< tk::real > > >;
     901                 :        196 :   return tuple_t{ elemfieldnames, elemfields, {}, {} };
     902 [ +  - ][ +  - ]:        392 : }
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
     903                 :            : 
     904                 :            : void
     905                 :         98 : Refiner::writeMesh( const std::string& basefilename,
     906                 :            :                     uint64_t itr,
     907                 :            :                     tk::real t,
     908                 :            :                     CkCallback c ) const
     909                 :            : // *****************************************************************************
     910                 :            : //  Output mesh to file(s)
     911                 :            : //! \param[in] basefilename File name to append to
     912                 :            : //! \param[in] itr Iteration count since a new mesh
     913                 :            : //! \param[in] t "Physical time" to write to file. "Time" here is used to
     914                 :            : //!   designate a new time step at which the mesh is saved.
     915                 :            : //! \param[in] c Function to continue with after the write
     916                 :            : // *****************************************************************************
     917                 :            : {
     918                 :         98 :   auto r = refinementFields();
     919                 :            :   auto& elemfieldnames = std::get< 0 >( r );
     920                 :            :   auto& elemfields = std::get< 1 >( r );
     921                 :            :   auto& nodefieldnames = std::get< 2 >( r );
     922                 :            :   auto& nodefields = std::get< 3 >( r );
     923                 :            : 
     924                 :            :   // Prepare solution field names: depvar + component id for all eqs
     925                 :         98 :   auto ncomp = g_cfg.get< tag::problem_ncomp >();
     926 [ +  - ][ +  - ]:         98 :   std::vector< std::string > solfieldnames( ncomp, "u" );
     927                 :            :   Assert( solfieldnames.size() == ncomp, "Size mismatch" );
     928                 :            : 
     929                 :         98 :   auto t0 = g_cfg.get< tag::t0 >();
     930                 :            : 
     931                 :            :   // Augment element field names with solution variable names + field ids
     932                 :            :   //nodefieldnames.insert( end(nodefieldnames),
     933                 :            :   //                       begin(solfieldnames), end(solfieldnames) );
     934 [ +  - ][ +  - ]:        196 :   nodefieldnames.push_back( "c1" );
     935                 :            : 
     936                 :            :   // Evaluate initial conditions on current mesh at t0
     937                 :            :   tk::Fields u( m_coord[0].size(), ncomp );
     938         [ +  - ]:         98 :   problems::initialize( m_coord, u, t0 );
     939                 :            : 
     940                 :            :   // Extract all scalar components from solution for output to file
     941                 :            :   //for (std::size_t i=0; i<ncomp; ++i)
     942         [ +  - ]:         98 :   nodefields.push_back( u.extract( 5 ) );
     943                 :            : 
     944                 :            :   // Output mesh
     945                 :            :   m_meshwriter[ CkNodeFirst( CkMyNode() ) ].
     946 [ +  - ][ -  + ]:        294 :     write( m_meshid, /*meshoutput = */ true, /*fieldoutput = */ true, itr, 1, t,
         [ +  - ][ -  - ]
                 [ -  - ]
     947         [ +  - ]:         98 :            thisIndex, basefilename, m_inpoel, m_coord, m_bface,
     948 [ +  - ][ +  - ]:        294 :            tk::remap(m_bnode,m_lid), tk::remap(m_triinpoel,m_lid),
         [ +  - ][ -  - ]
     949                 :            :            elemfieldnames, nodefieldnames, {}, {}, elemfields, nodefields, {},
     950                 :            :            {}, {}, c );
     951                 :        196 : }
     952                 :            : 
     953                 :            : void
     954                 :         71 : Refiner::perform()
     955                 :            : // *****************************************************************************
     956                 :            : // Perform mesh refinement and decide how to continue
     957                 :            : //! \details First the mesh refiner object is called to perform a single step
     958                 :            : //!   of mesh refinement. Then, if this function is called during a step
     959                 :            : //!   (potentially multiple levels of) initial AMR, it evaluates whether to do
     960                 :            : //!   another one. If it is called during time stepping, this concludes the
     961                 :            : //!   single mesh refinement step and the new mesh is sent to the PDE worker
     962                 :            : //!   (Discretization).
     963                 :            : // *****************************************************************************
     964                 :            : {
     965                 :            :   // Save old tets and their ids before performing refinement. Outref is always
     966                 :            :   // followed by outderef, so to the outside world, the mesh is uchanged, thus
     967                 :            :   // no update.
     968                 :            :   m_oldTets.clear();
     969         [ +  + ]:      82257 :   for (const auto& [ id, tet ] : m_refiner.tet_store.tets) {
     970                 :            :     m_oldTets.insert( tet );
     971                 :            :   }
     972                 :         71 :   m_oldntets = m_oldTets.size();
     973                 :            : 
     974         [ +  - ]:         71 :   if (m_mode == RefMode::T0REF) {
     975                 :            : 
     976                 :            :     // Refine mesh based on next initial refinement type
     977         [ +  - ]:         71 :     if (!m_initref.empty()) {
     978                 :            :       auto r = m_initref.back();    // consume (reversed) list from its back
     979         [ +  + ]:         71 :       if (r == "uniform_deref")
     980         [ +  - ]:         24 :         m_refiner.perform_derefinement();
     981                 :            :       else
     982         [ +  - ]:         47 :         m_refiner.perform_refinement();
     983                 :            :     }
     984                 :            : 
     985                 :            :   } else {
     986                 :            : 
     987                 :            :     // TODO: does not work yet, fix as above
     988                 :          0 :     m_refiner.perform_refinement();
     989                 :          0 :     m_refiner.perform_derefinement();
     990                 :            :   }
     991                 :            : 
     992                 :            :   // Remove temporary edge-locks resulting from the parallel compatibility
     993                 :         71 :   m_refiner.remove_edge_locks(1);
     994                 :         71 :   m_refiner.remove_edge_temp_locks();
     995                 :            : 
     996                 :            :   //auto& tet_store = m_refiner.tet_store;
     997                 :            :   //std::cout << "before ref: " << tet_store.marked_refinements.size() << ", " << tet_store.marked_derefinements.size() << ", " << tet_store.size() << ", " << tet_store.get_active_inpoel().size() << '\n';
     998                 :            :   //std::cout << "after ref: " << tet_store.marked_refinements.size() << ", " << tet_store.marked_derefinements.size() << ", " << tet_store.size() << ", " << tet_store.get_active_inpoel().size() << '\n';
     999                 :            :   //std::cout << "after deref: " << tet_store.marked_refinements.size() << ", " << tet_store.marked_derefinements.size() << ", " << tet_store.size() << ", " << tet_store.get_active_inpoel().size() << '\n';
    1000                 :            : 
    1001                 :            :   // Update volume and boundary mesh
    1002                 :         71 :   updateMesh();
    1003                 :            : 
    1004                 :            :   // Save mesh at every initial refinement step (mainly for debugging). Will
    1005                 :            :   // replace with just a 'next()' in production.
    1006         [ +  - ]:         71 :   if (m_mode == RefMode::T0REF) {
    1007                 :            : 
    1008                 :         71 :     auto l = m_ninitref - m_initref.size() + 1;  // num initref steps completed
    1009                 :         71 :     auto t0 = g_cfg.get< tag::t0 >();
    1010                 :            :     // Generate times equally subdividing t0-1...t0 to ninitref steps
    1011                 :         71 :     auto t =
    1012                 :         71 :       t0 - 1.0 + static_cast<tk::real>(l)/static_cast<tk::real>(m_ninitref);
    1013                 :            :     auto itr = l;
    1014                 :            :     // Output mesh after refinement step
    1015 [ +  - ][ +  - ]:        142 :     writeMesh( "t0ref", itr, t,
    1016         [ +  - ]:        213 :                CkCallback( CkIndex_Refiner::next(), thisProxy[thisIndex] ) );
    1017                 :            : 
    1018                 :            :   } else {
    1019                 :            : 
    1020                 :          0 :     next();
    1021                 :            : 
    1022                 :            :   }
    1023                 :         71 : }
    1024                 :            : 
    1025                 :            : void
    1026                 :         71 : Refiner::next()
    1027                 :            : // *****************************************************************************
    1028                 :            : // Continue after finishing a refinement step
    1029                 :            : // *****************************************************************************
    1030                 :            : {
    1031         [ +  - ]:         71 :   if (m_mode == RefMode::T0REF) {
    1032                 :            : 
    1033                 :            :     // Remove initial mesh refinement step from list
    1034         [ +  - ]:         71 :     if (!m_initref.empty()) m_initref.pop_back();
    1035                 :            :     // Continue to next initial AMR step or finish
    1036         [ +  + ]:         71 :     if (!m_initref.empty()) t0ref(); else endt0ref();
    1037                 :            : 
    1038         [ -  - ]:          0 :   } else if (m_mode == RefMode::DTREF) {
    1039                 :            : 
    1040                 :            :     // Send new mesh, solution, and communication data back to PDE worker
    1041                 :            :     const auto& solver = g_cfg.get< tag::solver >();
    1042         [ -  - ]:          0 :     if (solver == "riecg") {
    1043                 :          0 :       m_riecg[ thisIndex ].ckLocal()->resizePostAMR( m_ginpoel,
    1044                 :          0 :         m_el, m_coord, m_addedNodes, m_addedTets, m_removedNodes,
    1045         [ -  - ]:          0 :         m_nodeCommMap, m_bface, m_bnode, m_triinpoel );
    1046                 :            :     }
    1047         [ -  - ]:          0 :     else if (solver == "laxcg") {
    1048                 :          0 :       m_laxcg[ thisIndex ].ckLocal()->resizePostAMR( m_ginpoel,
    1049                 :          0 :         m_el, m_coord, m_addedNodes, m_addedTets, m_removedNodes,
    1050         [ -  - ]:          0 :         m_nodeCommMap, m_bface, m_bnode, m_triinpoel );
    1051                 :            :     }
    1052         [ -  - ]:          0 :     else if (solver == "zalcg") {
    1053                 :          0 :       m_zalcg[ thisIndex ].ckLocal()->resizePostAMR( m_ginpoel,
    1054                 :          0 :         m_el, m_coord, m_addedNodes, m_addedTets, m_removedNodes,
    1055         [ -  - ]:          0 :         m_nodeCommMap, m_bface, m_bnode, m_triinpoel );
    1056                 :            :     }
    1057         [ -  - ]:          0 :     else if (solver == "kozcg") {
    1058                 :          0 :       m_kozcg[ thisIndex ].ckLocal()->resizePostAMR( m_ginpoel,
    1059                 :          0 :         m_el, m_coord, m_addedNodes, m_addedTets, m_removedNodes,
    1060         [ -  - ]:          0 :         m_nodeCommMap, m_bface, m_bnode, m_triinpoel );
    1061                 :            :     }
    1062         [ -  - ]:          0 :     else if (solver == "chocg") {
    1063                 :          0 :       m_chocg[ thisIndex ].ckLocal()->resizePostAMR( m_ginpoel,
    1064                 :          0 :         m_el, m_coord, m_addedNodes, m_addedTets, m_removedNodes,
    1065         [ -  - ]:          0 :         m_nodeCommMap, m_bface, m_bnode, m_triinpoel );
    1066                 :            :     }
    1067         [ -  - ]:          0 :     else if (solver == "lohcg") {
    1068                 :          0 :       m_lohcg[ thisIndex ].ckLocal()->resizePostAMR( m_ginpoel,
    1069                 :          0 :         m_el, m_coord, m_addedNodes, m_addedTets, m_removedNodes,
    1070         [ -  - ]:          0 :         m_nodeCommMap, m_bface, m_bnode, m_triinpoel );
    1071                 :            :     }
    1072                 :            :     else {
    1073 [ -  - ][ -  - ]:          0 :       Throw( "Unknown solver: " + solver );
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
                 [ -  - ]
    1074                 :            :     }
    1075                 :            : 
    1076 [ -  - ][ -  - ]:          0 :   } else Throw( "RefMode not implemented" );
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
                 [ -  - ]
    1077                 :         71 : }
    1078                 :            : 
    1079                 :            : void
    1080                 :       2459 : Refiner::endt0ref()
    1081                 :            : // *****************************************************************************
    1082                 :            : // Finish initial mesh refinement
    1083                 :            : //! \details This function is called as after initial mesh refinement has
    1084                 :            : //!   finished. If initial mesh reifnement was not configured by the user, this
    1085                 :            : //!   is the point where we continue after the constructor, by computing the
    1086                 :            : //!   total number of elements across the whole problem.
    1087                 :            : // *****************************************************************************
    1088                 :            : {
    1089                 :            :   // create sorter Charm++ chare array elements using dynamic insertion
    1090                 :       2459 :   m_sorter[ thisIndex ].insert( m_meshid, m_host, m_meshwriter, m_cbs,
    1091                 :       2459 :     m_disc, m_riecg, m_laxcg, m_zalcg, m_kozcg, m_chocg, m_lohcg, m_cgpre,
    1092         [ +  - ]:       2459 :     m_cgmom,
    1093 [ +  - ][ -  + ]:       4918 :     CkCallback(CkIndex_Refiner::reorder(), thisProxy[thisIndex]), m_ginpoel,
                 [ -  - ]
    1094         [ +  - ]:       2459 :     m_coordmap, m_el, m_bface, m_triinpoel, m_bnode, m_nchare );
    1095                 :            : 
    1096                 :            :   // Compute final number of cells across whole problem
    1097                 :            :   std::vector< std::size_t >
    1098                 :       2459 :     meshdata{ m_meshid, m_ginpoel.size()/4, m_coord[0].size() };
    1099         [ +  - ]:       2459 :   contribute( meshdata, CkReduction::sum_ulong, m_cbr.get< tag::refined >() );
    1100                 :            : 
    1101                 :            :   // Free up memory if no dtref
    1102         [ +  - ]:       2459 :   if (!g_cfg.get< tag::href_dt >()) {
    1103                 :            :     tk::destroy( m_ginpoel );
    1104                 :       2459 :     tk::destroy( m_el );
    1105                 :       2459 :     tk::destroy( m_coordmap );
    1106                 :       2459 :     tk::destroy( m_coord );
    1107                 :       2459 :     tk::destroy( m_bface );
    1108                 :       2459 :     tk::destroy( m_bnode );
    1109                 :            :     tk::destroy( m_triinpoel );
    1110                 :            :     tk::destroy( m_initref );
    1111                 :       2459 :     tk::destroy( m_ch );
    1112                 :       2459 :     tk::destroy( m_edgech );
    1113                 :       2459 :     tk::destroy( m_chedge );
    1114                 :       2459 :     tk::destroy( m_localEdgeData );
    1115                 :       2459 :     tk::destroy( m_remoteEdgeData );
    1116                 :       2459 :     tk::destroy( m_remoteEdges );
    1117                 :       2459 :     tk::destroy( m_intermediates );
    1118                 :       2459 :     tk::destroy( m_nodeCommMap );
    1119                 :       2459 :     tk::destroy( m_oldTets );
    1120                 :       2459 :     tk::destroy( m_addedNodes );
    1121                 :       2459 :     tk::destroy( m_addedTets );
    1122                 :       2459 :     tk::destroy( m_coarseBndFaces );
    1123                 :       2459 :     tk::destroy( m_coarseBndNodes );
    1124                 :            :     tk::destroy( m_rid );
    1125                 :            :     //tk::destroy( m_oldrid );
    1126                 :       2459 :     tk::destroy( m_lref );
    1127                 :            :   }
    1128                 :       2459 : }
    1129                 :            : 
    1130                 :            : void
    1131                 :         31 : Refiner::uniformRefine()
    1132                 :            : // *****************************************************************************
    1133                 :            : // Do uniform mesh refinement
    1134                 :            : // *****************************************************************************
    1135                 :            : {
    1136                 :            :   // Do uniform refinement
    1137                 :         31 :   m_refiner.mark_uniform_refinement();
    1138                 :            : 
    1139                 :            :   // Update our extra-edge store based on refiner
    1140                 :         31 :   updateEdgeData();
    1141                 :            : 
    1142                 :            :   // Set number of extra edges to be zero, skipping correction (if this is the
    1143                 :            :   // only step in this refinement step)
    1144                 :         31 :   m_extra = 0;
    1145                 :         31 : }
    1146                 :            : 
    1147                 :            : void
    1148                 :         24 : Refiner::uniformDeRefine()
    1149                 :            : // *****************************************************************************
    1150                 :            : // Do uniform mesh derefinement
    1151                 :            : // *****************************************************************************
    1152                 :            : {
    1153                 :            :   // Do uniform derefinement
    1154                 :         24 :   m_refiner.mark_uniform_derefinement();
    1155                 :            : 
    1156                 :            :   // Update our extra-edge store based on refiner
    1157                 :         24 :   updateEdgeData();
    1158                 :            : 
    1159                 :            :   // Set number of extra edges to be zero, skipping correction (if this is the
    1160                 :            :   // only step in this refinement step)
    1161                 :         24 :   m_extra = 0;
    1162                 :         24 : }
    1163                 :            : 
    1164                 :            : Refiner::EdgeError
    1165                 :        114 : Refiner::errorsInEdges(
    1166                 :            :   std::size_t npoin,
    1167                 :            :   const std::pair< std::vector<std::size_t>, std::vector<std::size_t> >& esup,
    1168                 :            :   const tk::Fields& u ) const
    1169                 :            : // *****************************************************************************
    1170                 :            : //  Compute errors in edges
    1171                 :            : //! \param[in] npoin Number nodes in current mesh (partition)
    1172                 :            : //! \param[in] esup Elements surrounding points linked vectors
    1173                 :            : //! \param[in] u Solution evaluated at mesh nodes for all scalar components
    1174                 :            : //! \return A map associating errors (real values between 0.0 and 1.0 incusive)
    1175                 :            : //!   to edges (2 local node IDs)
    1176                 :            : // *****************************************************************************
    1177                 :            : {
    1178                 :            :   auto errtype = g_cfg.get< tag::href_error >();
    1179                 :            :   const auto& refvar = g_cfg.get< tag::href_refvar >();
    1180         [ +  - ]:        114 :   auto psup = tk::genPsup( m_inpoel, 4, esup );
    1181                 :            : 
    1182                 :            :   // Compute errors in ICs and define refinement criteria for edges
    1183                 :            :   AMR::Error error;
    1184                 :            :   EdgeError edgeError;
    1185                 :            : 
    1186         [ +  + ]:      35211 :   for (std::size_t p=0; p<npoin; ++p) { // for all mesh nodes on this chare
    1187 [ +  + ][ +  + ]:     422029 :     for (auto q : tk::Around(psup,p)) { // for all nodes surrounding p
    1188                 :            :       tk::real cmax = 0.0;
    1189                 :     386932 :       AMR::edge_t e(p,q);
    1190         [ +  + ]:     549892 :       for (auto i : refvar) {          // for all refinement variables
    1191         [ +  - ]:     162960 :         auto c = error.scalar( u, e, i-1, m_coord, m_inpoel, esup, errtype );
    1192         [ +  + ]:     162960 :         if (c > cmax) cmax = c;        // find max error at edge
    1193                 :            :       }
    1194         [ +  - ]:     386932 :       edgeError[ {{p,q}} ] = cmax;       // associate error to edge
    1195                 :            :     }
    1196                 :            :   }
    1197                 :            : 
    1198                 :        114 :   return edgeError;
    1199                 :        114 : }
    1200                 :            : 
    1201                 :            : tk::Fields
    1202         [ +  - ]:        114 : Refiner::solution( std::size_t npoin,
    1203                 :            :                    const std::pair< std::vector< std::size_t >,
    1204                 :            :                                     std::vector< std::size_t > >& esup ) const
    1205                 :            : // *****************************************************************************
    1206                 :            : //  Update (or evaluate) solution on current mesh
    1207                 :            : //! \param[in] npoin Number nodes in current mesh (partition)
    1208                 :            : //! \param[in] esup Elements surrounding points linked vectors
    1209                 :            : //! \return Solution updated/evaluated for all scalar components
    1210                 :            : // *****************************************************************************
    1211                 :            : {
    1212                 :            :   // Get solution whose error to evaluate
    1213                 :            :   tk::Fields u;
    1214                 :            : 
    1215         [ +  - ]:        114 :   if (m_mode == RefMode::T0REF) {
    1216                 :            : 
    1217                 :            :     // Evaluate initial conditions at mesh nodes
    1218         [ +  - ]:        228 :     u = nodeinit( npoin, esup );
    1219                 :            : 
    1220         [ -  - ]:          0 :   } else if (m_mode == RefMode::DTREF) {
    1221                 :            : 
    1222                 :            :     // Query current solution
    1223                 :            :     const auto& solver = g_cfg.get< tag::solver >();
    1224         [ -  - ]:          0 :     if (solver == "riecg") {
    1225         [ -  - ]:          0 :       u = m_riecg[ thisIndex ].ckLocal()->solution();
    1226                 :            :     }
    1227         [ -  - ]:          0 :     else if (solver == "laxcg") {
    1228         [ -  - ]:          0 :       u = m_laxcg[ thisIndex ].ckLocal()->solution();
    1229                 :            :     }
    1230         [ -  - ]:          0 :     else if (solver == "zalcg") {
    1231         [ -  - ]:          0 :       u = m_zalcg[ thisIndex ].ckLocal()->solution();
    1232                 :            :     }
    1233         [ -  - ]:          0 :     else if (solver == "kozcg") {
    1234         [ -  - ]:          0 :       u = m_kozcg[ thisIndex ].ckLocal()->solution();
    1235                 :            :     }
    1236         [ -  - ]:          0 :     else if (solver == "chocg") {
    1237         [ -  - ]:          0 :       u = m_chocg[ thisIndex ].ckLocal()->solution();
    1238                 :            :     }
    1239         [ -  - ]:          0 :     else if (solver == "lohcg") {
    1240 [ -  - ][ -  - ]:          0 :       u = m_lohcg[ thisIndex ].ckLocal()->solution();
    1241                 :            :     }
    1242                 :            :     else {
    1243 [ -  - ][ -  - ]:          0 :       Throw( "Unknown solver: " + solver );
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
                 [ -  - ]
    1244                 :            :     }
    1245                 :            :  
    1246 [ -  - ][ -  - ]:          0 :   } else Throw( "RefMode not implemented" );
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
                 [ -  - ]
    1247                 :            : 
    1248                 :        114 :   return u;
    1249                 :            : }
    1250                 :            : 
    1251                 :            : void
    1252                 :         16 : Refiner::errorRefine()
    1253                 :            : // *****************************************************************************
    1254                 :            : // Do error-based mesh refinement and derefinement
    1255                 :            : // *****************************************************************************
    1256                 :            : {
    1257                 :            :   // Find number of nodes in old mesh
    1258                 :         16 :   auto npoin = tk::npoin_in_graph( m_inpoel );
    1259                 :            :   // Generate edges surrounding points in old mesh
    1260                 :         16 :   auto esup = tk::genEsup( m_inpoel, 4 );
    1261                 :            : 
    1262                 :            :   // Update solution on current mesh
    1263         [ +  - ]:         16 :   const auto& u = solution( npoin, esup );
    1264                 :            :   Assert( u.nunk() == npoin, "Solution uninitialized or wrong size" );
    1265                 :            : 
    1266                 :            :   using AMR::edge_t;
    1267                 :            :   using AMR::edge_tag;
    1268                 :            : 
    1269                 :            :   // Compute error in edges. Tag edge for refinement if error exceeds
    1270                 :            :   // refinement tolerance, tag edge for derefinement if error is below
    1271                 :            :   // derefinement tolerance.
    1272                 :            :   auto tolref = 0.2;//g_cfg.get< tag::amr, tag::tolref >();
    1273                 :            :   auto tolderef = 0.05;//g_cfg.get< tag::amr, tag::tolderef >();
    1274                 :            :   std::vector< std::pair< edge_t, edge_tag > > tagged_edges;
    1275 [ +  - ][ +  + ]:       5551 :   for (const auto& e : errorsInEdges(npoin,esup,u)) {
    1276         [ +  + ]:       5535 :     if (e.second > tolref) {
    1277 [ +  + ][ +  - ]:       7224 :       tagged_edges.push_back( { edge_t( m_rid[e.first[0]], m_rid[e.first[1]] ),
    1278                 :            :                                 edge_tag::REFINE } );
    1279         [ +  + ]:       1923 :     } else if (e.second < tolderef) {
    1280 [ +  + ][ +  - ]:       3464 :       tagged_edges.push_back( { edge_t( m_rid[e.first[0]], m_rid[e.first[1]] ),
    1281                 :            :                                 edge_tag::DEREFINE } );
    1282                 :            :     }
    1283                 :            :   }
    1284                 :            : 
    1285                 :            :   // Do error-based refinement
    1286         [ +  - ]:         16 :   m_refiner.mark_error_refinement( tagged_edges );
    1287                 :            : 
    1288                 :            :   // Update our extra-edge store based on refiner
    1289         [ +  - ]:         16 :   updateEdgeData();
    1290                 :            : 
    1291                 :            :   // Set number of extra edges to a nonzero number, triggering correction
    1292         [ +  - ]:         16 :   m_extra = 1;
    1293                 :         16 : }
    1294                 :            : 
    1295                 :            : void
    1296                 :          0 : Refiner::edgelistRefine()
    1297                 :            : // *****************************************************************************
    1298                 :            : // Do mesh refinement based on user explicitly tagging edges
    1299                 :            : // *****************************************************************************
    1300                 :            : {
    1301                 :            :   // Get user-defined node-pairs (edges) to tag for refinement
    1302         [ -  - ]:          0 :   const auto& edgenodelist = std::vector<uint64_t>{0,1};//g_cfg.get< tag::amr, tag::edge >();
    1303                 :            : 
    1304         [ -  - ]:          0 :   if (!edgenodelist.empty()) {  // if user explicitly tagged edges
    1305                 :            :     // Find number of nodes in old mesh
    1306         [ -  - ]:          0 :     auto npoin = tk::npoin_in_graph( m_inpoel );
    1307                 :            :     // Generate edges surrounding points in old mesh
    1308         [ -  - ]:          0 :     auto esup = tk::genEsup( m_inpoel, 4 );
    1309         [ -  - ]:          0 :     auto psup = tk::genPsup( m_inpoel, 4, esup );
    1310                 :            : 
    1311                 :            :     EdgeSet useredges;
    1312         [ -  - ]:          0 :     for (std::size_t i=0; i<edgenodelist.size()/2; ++i)
    1313         [ -  - ]:          0 :       useredges.insert( {{ {edgenodelist[i*2+0], edgenodelist[i*2+1]} }} );
    1314                 :            : 
    1315                 :            :     using AMR::edge_t;
    1316                 :            :     using AMR::edge_tag;
    1317                 :            : 
    1318                 :            :     // Tag edges the user configured
    1319                 :            :     std::vector< std::pair< edge_t, edge_tag > > tagged_edges;
    1320         [ -  - ]:          0 :     for (std::size_t p=0; p<npoin; ++p)        // for all mesh nodes on this chare
    1321         [ -  - ]:          0 :       for (auto q : tk::Around(psup,p)) {      // for all nodes surrounding p
    1322                 :          0 :         Edge e{{ m_gid[p], m_gid[q] }};
    1323                 :            :         auto f = useredges.find(e);
    1324         [ -  - ]:          0 :         if (f != end(useredges)) { // tag edge if on user's list
    1325 [ -  - ][ -  - ]:          0 :           tagged_edges.push_back( { edge_t( m_rid[p], m_rid[q] ),
                 [ -  - ]
    1326                 :            :                                     edge_tag::REFINE } );
    1327                 :            :           useredges.erase( f );
    1328                 :            :         }
    1329                 :            :       }
    1330                 :            : 
    1331                 :            :     // Do error-based refinement
    1332         [ -  - ]:          0 :     m_refiner.mark_error_refinement( tagged_edges );
    1333                 :            : 
    1334                 :            :     // Update our extra-edge store based on refiner
    1335         [ -  - ]:          0 :     updateEdgeData();
    1336                 :            : 
    1337                 :            :     // Set number of extra edges to a nonzero number, triggering correction
    1338         [ -  - ]:          0 :     m_extra = 1;
    1339                 :          0 :   }
    1340                 :          0 : }
    1341                 :            : 
    1342                 :            : void
    1343                 :          0 : Refiner::coordRefine()
    1344                 :            : // *****************************************************************************
    1345                 :            : // Do mesh refinement based on tagging edges based on end-point coordinates
    1346                 :            : // *****************************************************************************
    1347                 :            : {
    1348                 :            :   // Get user-defined half-world coordinates
    1349                 :            :   auto xminus = 0.0;
    1350                 :            :   auto xplus = 0.0;
    1351                 :            :   auto yminus = 0.0;
    1352                 :            :   auto yplus = 0.0;
    1353                 :            :   auto zminus = 0.0;
    1354                 :            :   auto zplus = 0.0;
    1355                 :            : 
    1356                 :            :   // The default is the largest representable double
    1357                 :            :   auto eps = 1.0e-12;
    1358                 :            :   auto xminus_default = 0.0;
    1359                 :            :   auto xplus_default = 0.0;
    1360                 :            :   auto yminus_default = 0.0;
    1361                 :            :   auto yplus_default = 0.0;
    1362                 :            :   auto zminus_default = 0.0;
    1363                 :            :   auto zplus_default = 0.0;
    1364                 :            : 
    1365                 :            :   // Decide if user has configured the half-world
    1366                 :            :   bool xm = std::abs(xminus - xminus_default) > eps ? true : false;
    1367                 :            :   bool xp = std::abs(xplus - xplus_default) > eps ? true : false;
    1368                 :            :   bool ym = std::abs(yminus - yminus_default) > eps ? true : false;
    1369                 :            :   bool yp = std::abs(yplus - yplus_default) > eps ? true : false;
    1370                 :            :   bool zm = std::abs(zminus - zminus_default) > eps ? true : false;
    1371                 :            :   bool zp = std::abs(zplus - zplus_default) > eps ? true : false;
    1372                 :            : 
    1373                 :            :   using AMR::edge_t;
    1374                 :            :   using AMR::edge_tag;
    1375                 :            : 
    1376                 :            :   if (xm || xp || ym || yp || zm || zp) {       // if any half-world configured
    1377                 :            :     // Find number of nodes in old mesh
    1378                 :            :     auto npoin = tk::npoin_in_graph( m_inpoel );
    1379                 :            :     // Generate edges surrounding points in old mesh
    1380                 :            :     auto esup = tk::genEsup( m_inpoel, 4 );
    1381                 :            :     auto psup = tk::genPsup( m_inpoel, 4, esup );
    1382                 :            :     // Get access to node coordinates
    1383                 :            :     const auto& x = m_coord[0];
    1384                 :            :     const auto& y = m_coord[1];
    1385                 :            :     const auto& z = m_coord[2];
    1386                 :            :     // Compute edges to be tagged for refinement
    1387                 :            :     std::vector< std::pair< edge_t, edge_tag > > tagged_edges;
    1388                 :            :     for (std::size_t p=0; p<npoin; ++p)    // for all mesh nodes on this chare
    1389                 :            :       for (auto q : tk::Around(psup,p)) {  // for all nodes surrounding p
    1390                 :            :         Edge e{{p,q}};
    1391                 :            : 
    1392                 :            :         bool t = true;
    1393                 :            :         if (xm) { if (x[p]>xminus && x[q]>xminus) t = false; }
    1394                 :            :         if (xp) { if (x[p]<xplus && x[q]<xplus) t = false; }
    1395                 :            :         if (ym) { if (y[p]>yminus && y[q]>yminus) t = false; }
    1396                 :            :         if (yp) { if (y[p]<yplus && y[q]<yplus) t = false; }
    1397                 :            :         if (zm) { if (z[p]>zminus && z[q]>zminus) t = false; }
    1398                 :            :         if (zp) { if (z[p]<zplus && z[q]<zplus) t = false; }
    1399                 :            : 
    1400                 :            :         if (t) {
    1401                 :            :           tagged_edges.push_back( { edge_t( m_rid[e[0]], m_rid[e[1]] ),
    1402                 :            :                                     edge_tag::REFINE } );
    1403                 :            :         }
    1404                 :            :       }
    1405                 :            : 
    1406                 :            :     // Do error-based refinement
    1407                 :            :     m_refiner.mark_error_refinement( tagged_edges );
    1408                 :            : 
    1409                 :            :     // Update our extra-edge store based on refiner
    1410                 :            :     updateEdgeData();
    1411                 :            : 
    1412                 :            :     // Set number of extra edges to a nonzero number, triggering correction
    1413                 :            :     m_extra = 1;
    1414                 :            :   }
    1415                 :          0 : }
    1416                 :            : 
    1417                 :            : tk::Fields
    1418                 :        114 : Refiner::nodeinit( std::size_t /*npoin*/,
    1419                 :            :                    const std::pair< std::vector< std::size_t >,
    1420                 :            :                                     std::vector< std::size_t > >& /*esup*/ ) const
    1421                 :            : // *****************************************************************************
    1422                 :            : // Evaluate initial conditions (IC) at mesh nodes
    1423                 :            : // //! \param[in] npoin Number points in mesh (on this chare)
    1424                 :            : // //! \param[in] esup Elements surrounding points as linked lists, see tk::genEsup
    1425                 :            : //! \return Initial conditions (evaluated at t0) at nodes
    1426                 :            : // *****************************************************************************
    1427                 :            : {
    1428                 :        114 :   auto t0 = g_cfg.get< tag::t0 >();
    1429                 :        114 :   auto nprop = g_cfg.get< tag::problem_ncomp >();
    1430                 :            : 
    1431                 :            :   // Will store nodal ICs
    1432                 :            :   tk::Fields u( m_coord[0].size(), nprop );
    1433                 :            : 
    1434                 :            :   // Evaluate ICs
    1435                 :            : 
    1436                 :            :   // Evaluate ICs for all scalar components integrated
    1437 [ +  - ][ -  - ]:        114 :   problems::initialize( m_coord, u, t0 );
    1438                 :            : 
    1439                 :            :   Assert( u.nunk() == m_coord[0].size(), "Size mismatch" );
    1440                 :            :   Assert( u.nprop() == nprop, "Size mismatch" );
    1441                 :            : 
    1442                 :        114 :   return u;
    1443                 :            : }
    1444                 :            : 
    1445                 :            : void
    1446                 :         71 : Refiner::updateMesh()
    1447                 :            : // *****************************************************************************
    1448                 :            : // Update old mesh after refinement
    1449                 :            : // *****************************************************************************
    1450                 :            : {
    1451                 :            :   // Get refined mesh connectivity
    1452                 :         71 :   const auto& refinpoel = m_refiner.tet_store.get_active_inpoel();
    1453                 :            :   Assert( refinpoel.size()%4 == 0, "Inconsistent refined mesh connectivity" );
    1454                 :            : 
    1455                 :            :   // Generate unique node lists of old and refined mesh using local ids
    1456                 :         71 :   auto rinpoel = m_inpoel;
    1457         [ +  - ]:         71 :   tk::remap( rinpoel, m_rid );
    1458 [ +  - ][ -  - ]:         71 :   std::unordered_set< std::size_t > old( begin(rinpoel), end(rinpoel) );
    1459                 :         71 :   std::unordered_set< std::size_t > ref( begin(refinpoel), end(refinpoel) );
    1460                 :            : 
    1461                 :            :   // Augment refiner id -> local node id map with newly added nodes
    1462                 :            :   std::size_t l = m_lref.size();
    1463 [ +  + ][ +  - ]:      31966 :   for (auto r : ref) if (old.find(r) == end(old)) m_lref[r] = l++;
                 [ +  + ]
    1464                 :            : 
    1465                 :            :   // Get nodal communication map from Discretization worker
    1466         [ -  + ]:         71 :   if ( m_mode == RefMode::DTREF) {
    1467         [ -  - ]:          0 :     m_nodeCommMap = m_disc[ thisIndex ].ckLocal()->NodeCommMap();
    1468                 :            :   }
    1469                 :            : 
    1470                 :            :   // Update mesh and solution after refinement
    1471         [ +  - ]:         71 :   newVolMesh( old, ref );
    1472                 :            : 
    1473                 :            :   // Update mesh connectivity from refiner lib, remapping refiner to local ids
    1474 [ +  - ][ +  - ]:         71 :   m_inpoel = m_refiner.tet_store.get_active_inpoel();
    1475                 :            : 
    1476         [ +  - ]:         71 :   tk::remap( m_inpoel, m_lref );
    1477                 :            : 
    1478                 :            :   // Update mesh connectivity with new global node ids
    1479         [ +  - ]:         71 :   m_ginpoel = m_inpoel;
    1480                 :            :   Assert( tk::uniquecopy(m_ginpoel).size() == m_coord[0].size(),
    1481                 :            :           "Size mismatch" );
    1482         [ +  - ]:         71 :   tk::remap( m_ginpoel, m_gid );
    1483                 :            : 
    1484                 :            :   // Update boundary face and node information
    1485         [ +  - ]:         71 :   newBndMesh( ref );
    1486                 :            : 
    1487                 :            :   // Augment node communication map with newly added nodes on chare-boundary
    1488         [ -  + ]:         71 :   if (m_mode == RefMode::DTREF) {
    1489         [ -  - ]:          0 :     for (const auto& [ neighborchare, edges ] : m_remoteEdges) {
    1490                 :            :       auto& nodes = tk::ref_find( m_nodeCommMap, neighborchare );
    1491         [ -  - ]:          0 :       for (const auto& e : edges) {
    1492                 :            :         // If parent nodes were part of the node communication map for chare
    1493 [ -  - ][ -  - ]:          0 :         if (nodes.find(e[0]) != end(nodes) && nodes.find(e[1]) != end(nodes)) {
    1494                 :            :           // Add new node if local id was generated for it
    1495                 :          0 :           auto n = Hash<2>()( e );
    1496         [ -  - ]:          0 :           if (m_lid.find(n) != end(m_lid)) nodes.insert( n );
    1497                 :            :         }
    1498                 :            :       }
    1499                 :            :     }
    1500                 :            :   }
    1501                 :            : 
    1502                 :            :   // Ensure valid mesh after refinement
    1503                 :            :   Assert( tk::positiveJacobians( m_inpoel, m_coord ),
    1504                 :            :           "Refined mesh cell Jacobian non-positive" );
    1505                 :            : 
    1506                 :            :   Assert( tk::conforming( m_inpoel, m_coord, true, m_rid ),
    1507                 :            :           "Chare-"+std::to_string(thisIndex)+
    1508                 :            :           " mesh not conforming after updating mesh after mesh refinement" );
    1509                 :            : 
    1510                 :            :   // Perform leak test on new mesh
    1511                 :            :   Assert( !tk::leakyPartition(
    1512                 :            :             tk::genEsuelTet( m_inpoel, tk::genEsup(m_inpoel,4) ),
    1513                 :            :             m_inpoel, m_coord ),
    1514                 :            :           "Refined mesh partition leaky" );
    1515                 :         71 : }
    1516                 :            : 
    1517                 :            : void
    1518                 :         71 : Refiner::newVolMesh( const std::unordered_set< std::size_t >& old,
    1519                 :            :                      const std::unordered_set< std::size_t >& ref )
    1520                 :            : // *****************************************************************************
    1521                 :            : //  Compute new volume mesh after mesh refinement
    1522                 :            : //! \param[in] old Unique nodes of the old (unrefined) mesh using
    1523                 :            : //!   refiner-lib ids
    1524                 :            : //! \param[in] ref Unique nodes of the refined mesh using refiner-lib ids
    1525                 :            : // *****************************************************************************
    1526                 :            : {
    1527                 :            :   const auto& x = m_coord[0];
    1528                 :            :   const auto& y = m_coord[1];
    1529                 :            :   const auto& z = m_coord[2];
    1530                 :            : 
    1531                 :            :   // Generate coordinates and ids to newly added nodes after refinement
    1532                 :            :   std::unordered_map< std::size_t, std::size_t > gid_add;
    1533                 :         71 :   tk::destroy( m_addedNodes );
    1534                 :         71 :   tk::destroy( m_removedNodes );
    1535                 :         71 :   tk::destroy( m_amrNodeMap );
    1536 [ +  + ][ +  + ]:      31966 :   for (auto r : ref) {               // for all unique nodes of the refined mesh
    1537         [ +  + ]:      31895 :     if (old.find(r) == end(old)) {   // if node is newly added
    1538                 :            :       // get (local) parent ids of newly added node
    1539                 :      22670 :       auto p = m_refiner.node_connectivity.get( r );
    1540                 :            :       Assert(p[0] != p[1], "Node without parent edge in newVolMesh");
    1541                 :            :       Assert( old.find(p[0]) != end(old) && old.find(p[1]) != end(old),
    1542                 :            :               "Parent(s) not in old mesh" );
    1543                 :            :       // local parent ids
    1544                 :      22670 :       decltype(p) lp{{tk::cref_find(m_lref,p[0]), tk::cref_find(m_lref,p[1])}};
    1545                 :            :       // global parent ids
    1546                 :      22670 :       decltype(p) gp{{m_gid[lp[0]], m_gid[lp[1]]}};
    1547                 :            :       // generate new global ID for newly added node
    1548         [ +  - ]:      22670 :       auto g = Hash<2>()( gp );
    1549                 :            : 
    1550                 :            :       // if node added by AMR lib has not yet been added to Refiner's new mesh
    1551         [ +  - ]:      22670 :       if (m_coordmap.find(g) == end(m_coordmap)) {
    1552                 :            :         Assert( g >= old.size(), "Hashed id overwriting old id" );
    1553                 :            :         Assert( m_lid.find(g) == end(m_lid),
    1554                 :            :                 "Overwriting entry global->local node ID map" );
    1555         [ +  - ]:      22670 :         auto l = tk::cref_find( m_lref, r );
    1556                 :            :         // store newly added node id and their parent ids (local ids)
    1557         [ +  - ]:      22670 :         m_addedNodes[r] = lp;   // key = r for later update to local
    1558                 :            :         // assign new node to refiner->global map
    1559                 :      22670 :         gid_add[r] = g; // key = r for later search
    1560                 :            :         // assign new node to global->local map
    1561 [ +  - ][ +  - ]:      22670 :         m_lid[g] = l;
    1562                 :            :         // generate and store coordinates for newly added node
    1563                 :      22670 :         m_coordmap.insert( {g, {{ (x[lp[0]] + x[lp[1]])/2.0,
    1564                 :      22670 :                                   (y[lp[0]] + y[lp[1]])/2.0,
    1565         [ +  - ]:      22670 :                                   (z[lp[0]] + z[lp[1]])/2.0 }} } );
    1566                 :            :       }
    1567                 :            :     }
    1568                 :            :   }
    1569                 :         71 :   tk::destroy( m_coord );
    1570                 :            : 
    1571                 :            :   // generate a node map based on oldnodes+addednodes
    1572         [ +  - ]:         71 :   std::vector< size_t > nodeVec(m_coordmap.size());
    1573         [ +  + ]:      41397 :   for (size_t j=0; j<nodeVec.size(); ++j) {
    1574                 :      41326 :     nodeVec[j] = j;
    1575                 :            :   }
    1576                 :            : 
    1577                 :            :   // Remove coordinates and ids of removed nodes due to derefinement
    1578                 :            :   std::unordered_map< std::size_t, std::size_t > gid_rem;
    1579 [ +  + ][ +  + ]:      18727 :   for (auto o : old) {               // for all unique nodes of the old mesh
    1580         [ +  + ]:      18656 :     if (ref.find(o) == end(ref)) {   // if node is no longer in new mesh
    1581                 :       9431 :       auto l = tk::cref_find( m_lref, o );
    1582         [ +  - ]:       9431 :       auto g = m_gid[l];
    1583                 :            :       // store local-ids of removed nodes
    1584                 :            :       m_removedNodes.insert(l);
    1585                 :            :       // remove derefined nodes from node comm map
    1586         [ -  + ]:       9431 :       for (auto& [neighborchare, sharednodes] : m_nodeCommMap) {
    1587         [ -  - ]:          0 :         if (sharednodes.find(g) != sharednodes.end()) {
    1588                 :            :           sharednodes.erase(g);
    1589                 :            :         }
    1590                 :            :       }
    1591                 :       9431 :       gid_rem[l] = g;
    1592                 :       9431 :       m_lid.erase( g );
    1593                 :            :       m_coordmap.erase( g );
    1594                 :            :     }
    1595                 :            :   }
    1596                 :            : 
    1597                 :            :   // update the node map by removing the derefined nodes
    1598 [ -  + ][ -  - ]:         71 :   if (m_mode == RefMode::DTREF && m_removedNodes.size() > 0) {
    1599                 :            :     // remove derefined nodes
    1600                 :            :     size_t remCount = 0;
    1601                 :            :     size_t origSize = nodeVec.size();
    1602         [ -  - ]:          0 :     for (size_t j=0; j<origSize; ++j) {
    1603                 :          0 :       auto nd = nodeVec[j-remCount];
    1604                 :            : 
    1605                 :            :       bool no_change = false;
    1606                 :            :       size_t nodeidx = 0;
    1607         [ -  - ]:          0 :       for (const auto& rn : m_removedNodes) {
    1608         [ -  - ]:          0 :         if (nd < *m_removedNodes.cbegin()) {
    1609                 :            :           no_change = true;
    1610                 :            :           break;
    1611                 :            :         }
    1612         [ -  - ]:          0 :         else if (nd <= rn) {
    1613                 :            :           nodeidx = rn;
    1614                 :            :           break;
    1615                 :            :         }
    1616                 :            :       }
    1617                 :            : 
    1618                 :            :       // if node is out-or-range of removed nodes list, continue with next entry
    1619         [ -  - ]:          0 :       if (no_change)
    1620                 :          0 :         continue;
    1621                 :            :       // if not is within range of removed nodes list, erase node appropriately
    1622         [ -  - ]:          0 :       else if (nodeidx == nd) {
    1623                 :            :         //! Difference type for iterator/pointer arithmetics
    1624                 :            :         using diff_type = std::vector< std::size_t >::difference_type;
    1625                 :            :         nodeVec.erase(nodeVec.begin()+static_cast< diff_type >(j-remCount));
    1626                 :          0 :         ++remCount;
    1627                 :            :       }
    1628                 :            :     }
    1629                 :            : 
    1630                 :            :     Assert(remCount == m_removedNodes.size(), "Incorrect number of nodes removed "
    1631                 :            :       "from node map.");
    1632                 :            :   }
    1633                 :            : 
    1634                 :            :   // invert node vector to get node map
    1635         [ +  + ]:      41397 :   for (size_t i=0; i<nodeVec.size(); ++i) {
    1636                 :      41326 :     m_amrNodeMap[nodeVec[i]] = i;
    1637                 :            :   }
    1638                 :            : 
    1639                 :            :   //// Save previous states of refiner-local node id maps before update
    1640                 :            :   //m_oldrid = m_rid;
    1641                 :            :   //m_oldlref = m_lref;
    1642                 :            : 
    1643                 :            :   // Generate new node id maps for nodes kept
    1644                 :         71 :   tk::destroy( m_lref );
    1645 [ +  - ][ +  - ]:         71 :   std::vector< std::size_t > rid( ref.size() );
    1646 [ +  - ][ -  - ]:         71 :   std::vector< std::size_t > gid( ref.size() );
    1647                 :         71 :   std::size_t l = 0;    // will generate new local node id
    1648         [ +  + ]:      18727 :   for (std::size_t i=0; i<m_gid.size(); ++i) {
    1649         [ +  + ]:      18656 :     if (gid_rem.find(i) == end(gid_rem)) {
    1650                 :       9225 :       gid[l] = m_gid[i];
    1651                 :       9225 :       rid[l] = m_rid[i];
    1652         [ +  - ]:       9225 :       m_lref[ m_rid[i] ] = l;
    1653                 :       9225 :       ++l;
    1654                 :            :     }
    1655                 :            :   }
    1656                 :            :   // Add newly added nodes due to refinement to node id maps
    1657                 :            :   // cppcheck-suppress unreadVariable
    1658         [ -  - ]:         71 :   decltype(m_addedNodes) addedNodes( m_addedNodes.size() );
    1659         [ +  + ]:      22741 :   for (const auto& n : gid_add) {
    1660                 :      22670 :     auto r = n.first;
    1661                 :      22670 :     auto g = n.second;
    1662         [ +  - ]:      22670 :     gid[l] = g;
    1663                 :            :     // cppcheck-suppress unreadVariable
    1664                 :      22670 :     rid[l] = r;
    1665                 :            :     Assert(m_lref.find(r) == m_lref.end(), "Overwriting lref");
    1666 [ +  - ][ +  - ]:      22670 :     m_lref[r] = l;
    1667                 :            :     auto it = m_addedNodes.find( r );
    1668                 :            :     Assert( it != end(m_addedNodes), "Cannot find added node" );
    1669         [ +  - ]:      22670 :     addedNodes[l] = std::move(it->second);
    1670 [ +  - ][ +  - ]:      22670 :     addedNodes.at(l)[0] = m_amrNodeMap[addedNodes.at(l)[0]];
    1671         [ +  - ]:      22670 :     addedNodes.at(l)[1] = m_amrNodeMap[addedNodes.at(l)[1]];
    1672                 :      22670 :     ++l;
    1673                 :            :   }
    1674                 :            :   Assert( m_lref.size() == ref.size(), "Size mismatch" );
    1675                 :            :   //for (auto r : ref) {
    1676                 :            :   //  Assert(m_lref.find(r) != m_lref.end(), "Node missing in lref");
    1677                 :            :   //}
    1678                 :            :   //const auto& int_list = m_refiner.tet_store.intermediate_list;
    1679                 :            :   //for (auto in : int_list) {
    1680                 :            :   //  Assert(m_lref.find(in) != m_lref.end(), "Interm node missing in lref: "
    1681                 :            :   //    + std::to_string(in));
    1682                 :            :   //}
    1683                 :         71 :   m_rid = std::move( rid );
    1684                 :            :   Assert( m_rid.size() == ref.size(), "Size mismatch" );
    1685                 :            :   m_addedNodes = std::move( addedNodes );
    1686                 :            : 
    1687                 :            :   // Update node coordinates, ids, and id maps
    1688                 :            :   auto& rx = m_coord[0];
    1689                 :            :   auto& ry = m_coord[1];
    1690                 :            :   auto& rz = m_coord[2];
    1691         [ +  - ]:         71 :   rx.resize( ref.size() );
    1692         [ +  - ]:         71 :   ry.resize( ref.size() );
    1693         [ +  - ]:         71 :   rz.resize( ref.size() );
    1694         [ +  + ]:      31966 :   for (std::size_t i=0; i<gid.size(); ++i) {
    1695                 :      31895 :     tk::ref_find( m_lid, gid[i] ) = i;
    1696                 :            :     const auto& c = tk::cref_find( m_coordmap, gid[i] );
    1697                 :      31895 :     rx[i] = c[0];
    1698                 :      31895 :     ry[i] = c[1];
    1699                 :      31895 :     rz[i] = c[2];
    1700                 :            :   }
    1701                 :         71 :   m_gid = std::move( gid );
    1702                 :            :   Assert( m_gid.size() == m_lid.size() && m_gid.size() == ref.size(),
    1703                 :            :     "Size mismatch" );
    1704                 :         71 : }
    1705                 :            : 
    1706                 :            : std::unordered_set< std::size_t >
    1707         [ +  + ]:    2552108 : Refiner::ancestors( std::size_t n )
    1708                 :            : // *****************************************************************************
    1709                 :            : // Find the oldest parents of a mesh node in the AMR hierarchy
    1710                 :            : //! \param[in] n Local node id whose ancestors to search
    1711                 :            : //! \return Parents of local node id from the coarsest (original) mesh
    1712                 :            : // *****************************************************************************
    1713                 :            : {
    1714 [ +  + ][ +  + ]:    3478338 :   auto d = m_refiner.node_connectivity.get( m_rid[n] );
    1715                 :    2552108 :   decltype(d) p{{ tk::cref_find( m_lref, d[0] ),
    1716         [ +  + ]:    2552108 :                   tk::cref_find( m_lref, d[1] ) }};
    1717                 :            : 
    1718                 :            :   std::unordered_set< std::size_t > s;
    1719                 :            : 
    1720         [ +  + ]:    2552108 :   if (p != AMR::node_pair_t{{n,n}}) {
    1721         [ +  - ]:     926230 :     auto q = ancestors( p[0] );
    1722                 :            :     s.insert( begin(q), end(q) );
    1723         [ +  - ]:     926230 :     auto r = ancestors( p[1] );
    1724                 :            :     s.insert( begin(r), end(r) );
    1725                 :            :   } else {
    1726                 :            :     s.insert( begin(p), end(p) );
    1727                 :            :   }
    1728                 :            : 
    1729                 :    2552108 :   return s;
    1730                 :            : }
    1731                 :            : 
    1732                 :            : Refiner::BndFaceData
    1733                 :         71 : Refiner::boundary()
    1734                 :            : // *****************************************************************************
    1735                 :            : //  Generate boundary data structures used to update refined/derefined boundary
    1736                 :            : //  faces and nodes of side sets
    1737                 :            : //! \return A tuple of boundary face data
    1738                 :            : //! \details The output of this function is used to regenerate physical boundary
    1739                 :            : //!   face and node data structures after refinement, see updateBndData().
    1740                 :            : // *****************************************************************************
    1741                 :            : {
    1742                 :            :   // Generate the inverse of AMR's tet store
    1743                 :            :   std::unordered_map< Tet, std::size_t, Hash<4>, Eq<4> > invtets;
    1744         [ +  + ]:     145529 :   for (const auto& [key, tet] : m_refiner.tet_store.tets)
    1745         [ +  - ]:     145458 :     invtets[ tet ] = key;
    1746                 :            : 
    1747                 :            :   //std::cout << thisIndex << " invt: " << invtets.size() << '\n';
    1748                 :            :   //std::cout << thisIndex << " active inpoel size: " << m_refiner.tet_store.get_active_inpoel().size() << '\n';
    1749                 :            :   //std::cout << thisIndex << " marked derefinement size: " << m_refiner.tet_store.marked_derefinements.size() << '\n';
    1750                 :            : 
    1751                 :            :   // Generate data structure pcFaceTets for the new (post-AMR) mesh:
    1752                 :            :   // pcFaceTets is a map that associates all triangle boundary faces (physical
    1753                 :            :   // and chare) to the id of the tet adjacent to the said face.
    1754                 :            :   // Key: Face-nodes' global id; Value: tet-id.
    1755                 :            :   std::unordered_map< Face, std::size_t, Hash<3>, Eq<3> > pcFaceTets;
    1756 [ +  - ][ +  - ]:         71 :   auto esuel = tk::genEsuelTet( m_inpoel, tk::genEsup(m_inpoel,4) );
    1757         [ +  + ]:     128238 :   for (std::size_t e=0; e<esuel.size()/4; ++e) {
    1758                 :     128167 :     auto m = e*4;
    1759         [ +  + ]:     640835 :     for (std::size_t f=0; f<4; ++f) {
    1760         [ +  + ]:     512668 :       if (esuel[m+f] == -1) {  // if a face does not have an adjacent tet
    1761                 :      38060 :         Face b{{ m_ginpoel[ m+tk::lpofa[f][0] ],
    1762                 :      38060 :                  m_ginpoel[ m+tk::lpofa[f][1] ],
    1763                 :      38060 :                  m_ginpoel[ m+tk::lpofa[f][2] ] }};
    1764                 :            :         Assert( m_inpoel[m+0] < m_rid.size() &&
    1765                 :            :                 m_inpoel[m+1] < m_rid.size() &&
    1766                 :            :                 m_inpoel[m+2] < m_rid.size() &&
    1767                 :            :                 m_inpoel[m+3] < m_rid.size(), "Indexing out of rid" );
    1768                 :      38060 :         Tet t{{ m_rid[ m_inpoel[m+0] ], m_rid[ m_inpoel[m+1] ],
    1769                 :      38060 :                 m_rid[ m_inpoel[m+2] ], m_rid[ m_inpoel[m+3] ] }};
    1770                 :            :         //Tet t{{ m_inpoel[m+0], m_inpoel[m+1],
    1771                 :            :         //        m_inpoel[m+2], m_inpoel[m+3] }};
    1772                 :            :         // associate tet id to adjacent (physical or chare) boundary face
    1773                 :            :         auto i = invtets.find( t );
    1774                 :            :         Assert(m_refiner.tet_store.is_active(i->second),
    1775                 :            :           "Inactive element while regenerating boundary data");
    1776         [ +  - ]:      38060 :         if (i != end(invtets)) {
    1777                 :            :           //std::cout << "refacetets: " <<
    1778                 :            :           //  b[0] << "-" << b[1] << "-" << b[2] << std::endl;
    1779         [ +  - ]:      38060 :           pcFaceTets[ b ] = i->second;
    1780                 :            :         } else {
    1781 [ -  - ][ -  - ]:          0 :           Throw("Active element not found in tet_store");
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
                 [ -  - ]
    1782                 :            :         }
    1783                 :            :       }
    1784                 :            :     }
    1785                 :            :   }
    1786                 :            : 
    1787                 :            :   // Generate child->parent tet and id maps after refinement/derefinement step
    1788                 :            : //  tk::destroy( m_oldparent );
    1789                 :            :   m_addedTets.clear();
    1790                 :            :   std::size_t p = 0;
    1791                 :            :   // cppcheck-suppress unreadVariable
    1792                 :            :   std::size_t c = 0;
    1793                 :            :   const auto& tet_store = m_refiner.tet_store;
    1794         [ +  + ]:     145529 :   for (const auto& t : tet_store.tets) {
    1795                 :            :     // query number of children of tet
    1796         [ +  - ]:     145458 :     auto nc = tet_store.data( t.first ).children.size();
    1797         [ +  + ]:     282302 :     for (decltype(nc) i=0; i<nc; ++i ) {      // for all child tets
    1798                 :            :       // get child tet id
    1799         [ +  - ]:     136844 :       auto childtet = tet_store.get_child_id( t.first, i );
    1800                 :            :       auto ct = tet_store.tets.find( childtet );
    1801                 :            :       Assert(ct != tet_store.tets.end(), "Child not found in tet store");
    1802                 :            : //      //auto cA = tk::cref_find( m_lref, ct->second[0] );
    1803                 :            : //      //auto cB = tk::cref_find( m_lref, ct->second[1] );
    1804                 :            : //      //auto cC = tk::cref_find( m_lref, ct->second[2] );
    1805                 :            : //      //auto cD = tk::cref_find( m_lref, ct->second[3] );
    1806                 :            : //      // get nodes of parent tet
    1807                 :            : //      //auto pA = tk::cref_find( m_lref, t.second[0] );
    1808                 :            : //      //auto pB = tk::cref_find( m_lref, t.second[1] );
    1809                 :            : //      //auto pC = tk::cref_find( m_lref, t.second[2] );
    1810                 :            : //      //auto pD = tk::cref_find( m_lref, t.second[3] );
    1811                 :            : //      // assign parent tet to child tet
    1812                 :            : //      //m_oldparent[ {{cA,cB,cC,cD}} ] = {{pA,pB,pC,pD}};
    1813                 :            : //      m_oldparent[ ct->second ] = t.second; //{{pA,pB,pC,pD}};
    1814         [ +  + ]:     136844 :       if (m_oldTets.find(ct->second) == end(m_oldTets)) {
    1815                 :            :         // TODO: the following code can assign negative ids to newly added tets.
    1816                 :            :         // This needs to be corrected before applying to cell-based schemes.
    1817                 :            :         //Assert((p-m_oldntets) > 0, "Negative id assigned to added tet");
    1818 [ +  - ][ -  - ]:     112028 :         m_addedTets[ c++ ] = p - m_oldntets;
    1819                 :            :       }
    1820                 :            :     }
    1821                 :     145458 :     ++p;
    1822                 :            :   }
    1823                 :            : 
    1824                 :            :   //std::cout << thisIndex << " added: " << m_addedTets.size() << '\n';
    1825                 :            :   //std::cout << thisIndex << " parent: " << m_oldparent.size() << '\n';
    1826                 :            :   //std::cout << thisIndex << " pcret: " << pcFaceTets.size() << '\n';
    1827                 :            : 
    1828                 :            :   //for (std::size_t f=0; f<m_triinpoel.size()/3; ++f) {
    1829                 :            :   //  std::cout << "triinpoel: " <<
    1830                 :            :   //    m_triinpoel[f*3+0] << "-" << m_triinpoel[f*3+1] << "-" <<
    1831                 :            :   //    m_triinpoel[f*3+2] << std::endl;
    1832                 :            :   //}
    1833                 :            : 
    1834                 :         71 :   return pcFaceTets;
    1835                 :            : }
    1836                 :            : 
    1837                 :            : void
    1838                 :         71 : Refiner::newBndMesh( const std::unordered_set< std::size_t >& ref )
    1839                 :            : // *****************************************************************************
    1840                 :            : // Update boundary data structures after mesh refinement
    1841                 :            : //! \param[in] ref Unique nodes of the refined mesh using refiner-lib ids
    1842                 :            : // *****************************************************************************
    1843                 :            : {
    1844                 :            :   // Generate boundary face data structures used to regenerate boundary face
    1845                 :            :   // and node data after mesh refinement
    1846                 :         71 :   auto pcFaceTets = boundary();
    1847                 :            : 
    1848                 :            :   // Regerate boundary faces and nodes after AMR step
    1849         [ +  - ]:         71 :   updateBndData( ref, pcFaceTets );
    1850                 :         71 : }
    1851                 :            : 
    1852                 :            : void
    1853                 :         71 : Refiner::updateBndData(
    1854                 :            :   [[maybe_unused]] const std::unordered_set< std::size_t >& ref,
    1855                 :            :   const BndFaceData& pcFaceTets )
    1856                 :            : // *****************************************************************************
    1857                 :            : // Regenerate boundary faces and nodes after AMR step
    1858                 :            : //! \param[in] ref Unique nodes of the refined mesh using refiner-lib ids
    1859                 :            : //! \param[in] pcFaceTets Boundary face data
    1860                 :            : // *****************************************************************************
    1861                 :            : {
    1862                 :            :   // storage for boundary faces associated to side-set IDs of the refined mesh
    1863                 :         71 :   tk::destroy( m_bface );
    1864                 :            :   // storage for boundary faces-node connectivity of the refined mesh
    1865                 :            :   tk::destroy( m_triinpoel );
    1866                 :            :   // storage for boundary nodes associated to side-set IDs of the refined mesh
    1867                 :         71 :   tk::destroy( m_bnode );
    1868                 :            : 
    1869                 :            :   // will collect unique faces added for each side set
    1870                 :            :   std::unordered_map< int, FaceSet > bf;
    1871                 :            : 
    1872                 :            :   // Lambda to search the parents in the coarsest mesh of a mesh node and if
    1873                 :            :   // found, add its global id to boundary node lists associated to the side
    1874                 :            :   // set(s) of its parents. Argument 'n' is the local id of the mesh node id
    1875                 :            :   // whose parents to search.
    1876                 :     585468 :   auto addBndNodes = [&]( std::size_t n ){
    1877                 :     585468 :     auto a = ancestors( n );  // find parents of n in coarse mesh
    1878         [ +  + ]:     585468 :     if (a.size() == 1) {
    1879                 :            :       // node was part of the coarse mesh
    1880                 :            :       Assert(*a.cbegin() == n, "Single ancestor not self");
    1881         [ +  - ]:     109874 :       auto ss = keys( m_coarseBndNodes, m_gid[*a.cbegin()] );
    1882         [ +  + ]:     269898 :       for (auto s : ss)
    1883 [ +  - ][ +  - ]:     160024 :         m_bnode[ s ].push_back( m_gid[n] );
    1884         [ +  + ]:     475594 :     } else if (a.size() == 2) {
    1885                 :            :       // node was added to an edge of a coarse face
    1886         [ +  - ]:     374802 :       std::vector< std::size_t > p( begin(a), end(a) );
    1887         [ +  - ]:     374802 :       auto ss1 = keys( m_coarseBndNodes, m_gid[p[0]] );
    1888         [ +  - ]:     374802 :       auto ss2 = keys( m_coarseBndNodes, m_gid[p[1]] );
    1889 [ +  + ][ +  + ]:     891908 :       for (auto s : ss1) {
    1890                 :            :         // only add 'n' to bnode if all parent nodes are in same side set, else
    1891                 :            :         // 'n' is not a boundary node
    1892         [ +  + ]:     517106 :         if (ss2.find(s) != end(ss2)) {
    1893 [ +  - ][ +  - ]:     404902 :           m_bnode[ s ].push_back( m_gid[n] );
    1894                 :            :         }
    1895                 :            :       }
    1896         [ +  - ]:     100792 :     } else if (a.size() == 3) {
    1897                 :            :       // node was added inside of a coarse face
    1898         [ +  - ]:     100792 :       std::vector< std::size_t > p( begin(a), end(a) );
    1899         [ +  - ]:     100792 :       auto ss1 = keys( m_coarseBndNodes, m_gid[p[0]] );
    1900         [ +  - ]:     100792 :       auto ss2 = keys( m_coarseBndNodes, m_gid[p[1]] );
    1901         [ +  - ]:     100792 :       auto ss3 = keys( m_coarseBndNodes, m_gid[p[2]] );
    1902 [ +  + ][ +  + ]:     275845 :       for (auto s : ss1) {
    1903                 :            :         // only add 'n' to bnode if all parent nodes are in same side set, else
    1904                 :            :         // 'n' is not a boundary node
    1905 [ +  + ][ +  + ]:     175053 :         if (ss2.find(s) != end(ss2) && ss3.find(s) != end(ss3)) {
    1906 [ +  - ][ +  - ]:      89992 :           m_bnode[ s ].push_back( m_gid[n] );
    1907                 :            :         }
    1908                 :            :       }
    1909                 :            :     }
    1910                 :     585468 :   };
    1911                 :            : 
    1912                 :            :   // face id counter
    1913                 :         71 :   std::size_t facecnt = 0;
    1914                 :            : 
    1915                 :            :   // Lambda to associate a boundary face and connectivity to a side set.
    1916                 :            :   // Argument 's' is the list of faces (ids) to add the new face to. Argument
    1917                 :            :   // 'ss' is the side set id to which the face is added. Argument 'f' is the
    1918                 :            :   // triangle face connectivity to add.
    1919                 :      33968 :   auto addBndFace = [&]( std::vector< std::size_t >& s, int ss, const Face& f )
    1920                 :            :   {
    1921                 :            :     // only add face if it has not yet been aded to this side set
    1922         [ +  - ]:      67936 :     if (bf[ ss ].insert( f ).second) {
    1923                 :      33968 :       s.push_back( facecnt++ );
    1924                 :      33968 :       m_triinpoel.insert( end(m_triinpoel), begin(f), end(f) );
    1925                 :            :       Assert(m_triinpoel.size()/3 == facecnt, "Incorrect size of triinpoel");
    1926                 :            :     }
    1927                 :         71 :   };
    1928                 :            : 
    1929                 :            :   // Regenerate boundary faces for new mesh along side sets. For all faces
    1930                 :            :   // associated to side sets, we find the ancestors (parents of nodes in the
    1931                 :            :   // original/coarsest mesh) of the nodes comprising the physical and chare
    1932                 :            :   // boundary faces of the new mesh.
    1933                 :            :   //bool faceNoSs = false;
    1934                 :            :   // for all P/C faces in current (post-AMR) mesh
    1935         [ +  + ]:      38131 :   for (const auto& [ face, tetid ] : pcFaceTets) {
    1936                 :            :     // find ancestors of face
    1937                 :            :     std::unordered_set< std::size_t > ans;
    1938         [ +  + ]:     152240 :     for (std::size_t i=0; i<3; ++i) {
    1939         [ +  - ]:     114180 :       auto ai = ancestors(tk::cref_find(m_lid, face[i]));
    1940                 :            :       ans.insert(ai.begin(), ai.end());
    1941                 :            :     }
    1942                 :            :     Assert(ans.size() == 3, "Incorrect number of ancestors in refined face");
    1943                 :            :     Face af;
    1944                 :            :     std::size_t i = 0;
    1945         [ +  + ]:     152240 :     for (auto ai:ans) {
    1946                 :     114180 :       af[i] = m_gid[ai];
    1947                 :     114180 :       ++i;
    1948                 :            :     }
    1949                 :            :     // for all boundary faces in original mesh
    1950                 :            :     //std::size_t fss = 0;
    1951         [ +  + ]:     233216 :     for (const auto& [ss, cfaceset] : m_coarseBndFaces) {
    1952         [ +  + ]:     195156 :       if (cfaceset.find(af) != cfaceset.end()) {
    1953 [ +  - ][ +  - ]:      33968 :         addBndFace(m_bface[ss], ss, face);
    1954                 :            :         //++fss;
    1955                 :            :       }
    1956         [ +  + ]:     780624 :       for (auto j : face) {
    1957         [ +  - ]:     585468 :         addBndNodes(tk::cref_find(m_lid, j));
    1958                 :            :       }
    1959                 :            :     }
    1960                 :            :     //if (fss==0) {
    1961                 :            :     //  std::cout << "Face added to no/multiple side sets; " << fss << std::endl;
    1962                 :            :     //  faceNoSs = true;
    1963                 :            :     //}
    1964                 :            :   }
    1965                 :            : 
    1966                 :            :   // Commented code below, since diagcg can work without sideset/bcs
    1967                 :            :   //Assert(!faceNoSs, "Face/s added to incorrect number of side sets");
    1968                 :            : 
    1969                 :            :   // Make boundary node IDs unique for each physical boundary (side set)
    1970 [ +  - ][ +  + ]:        423 :   for (auto& s : m_bnode) tk::unique( s.second );
    1971                 :            : 
    1972                 :            :   //for (const auto& [ setid, faceids ] : m_bface) {
    1973                 :            :   //  std::cout << "sset: " << setid << std::endl;
    1974                 :            :   //  for (auto f : faceids) {
    1975                 :            :   //    Assert(f<m_triinpoel.size()/3, "Out of bounds access into triinpoel");
    1976                 :            :   //    std::cout << "new bndfaces: " <<
    1977                 :            :   //      m_triinpoel[f*3+0] << "-" << m_triinpoel[f*3+1] << "-" <<
    1978                 :            :   //      m_triinpoel[f*3+2] << std::endl;
    1979                 :            :   //  }
    1980                 :            :   //}
    1981                 :            : 
    1982                 :            :   //for (std::size_t f=0; f<m_triinpoel.size()/3; ++f) {
    1983                 :            :   //  std::cout << "new triinpoel: " <<
    1984                 :            :   //    m_triinpoel[f*3+0] << "-" << m_triinpoel[f*3+1] << "-" <<
    1985                 :            :   //    m_triinpoel[f*3+2] << std::endl;
    1986                 :            :   //}
    1987                 :            : 
    1988                 :            :   //std::cout << thisIndex << " bf: " << tk::sumvalsize( m_bface ) << '\n';
    1989                 :            : 
    1990                 :            :   //std::cout << thisIndex << " bn: " << tk::sumvalsize( m_bnode ) << '\n';
    1991                 :            : 
    1992                 :            :   // Perform leak-test on boundary face data just updated (only in DEBUG)
    1993                 :            :   Assert( bndIntegral(), "Partial boundary integral" );
    1994                 :         71 : }
    1995                 :            : 
    1996                 :            : bool
    1997                 :          0 : Refiner::bndIntegral()
    1998                 :            : // *****************************************************************************
    1999                 :            : //  Compute partial boundary surface integral and sum across all chares
    2000                 :            : //! \return true so we don't trigger assert in client code
    2001                 :            : //! \details This function computes a partial surface integral over the boundary
    2002                 :            : //!   of the faces of this mesh partition then sends its contribution to perform
    2003                 :            : //!   the integral acorss the total problem boundary. After the global sum a
    2004                 :            : //!   non-zero vector result indicates a leak, e.g., a hole in the boundary
    2005                 :            : //!   which indicates an error in the boundary face data structures used to
    2006                 :            : //!   compute the partial surface integrals.
    2007                 :            : // *****************************************************************************
    2008                 :            : {
    2009                 :            :   const auto& x = m_coord[0];
    2010                 :            :   const auto& y = m_coord[1];
    2011                 :            :   const auto& z = m_coord[2];
    2012                 :            : 
    2013                 :          0 :   std::vector< tk::real > s{{ 0.0, 0.0, 0.0 }};
    2014                 :            : 
    2015         [ -  - ]:          0 :   for (const auto& [ setid, faceids ] : m_bface) {
    2016         [ -  - ]:          0 :     for (auto f : faceids) {
    2017                 :          0 :       auto A = tk::cref_find( m_lid, m_triinpoel[f*3+0] );
    2018                 :          0 :       auto B = tk::cref_find( m_lid, m_triinpoel[f*3+1] );
    2019                 :          0 :       auto C = tk::cref_find( m_lid, m_triinpoel[f*3+2] );
    2020                 :            :       // Compute face area and normal
    2021                 :            :       tk::real nx, ny, nz;
    2022                 :          0 :       auto a = tk::normal( x[A],x[B],x[C], y[A],y[B],y[C], z[A],z[B],z[C],
    2023                 :            :                            nx, ny, nz );
    2024                 :            :       // Sum up face area * face unit-normal
    2025                 :          0 :       s[0] += a * nx;
    2026                 :          0 :       s[1] += a * ny;
    2027                 :          0 :       s[2] += a * nz;
    2028                 :            :     }
    2029                 :            :   }
    2030                 :            : 
    2031         [ -  - ]:          0 :   s.push_back( -1.0 );  // negative: no call-back after reduction
    2032 [ -  - ][ -  - ]:          0 :   s.push_back( static_cast< tk::real >( m_meshid ) );
    2033                 :            : 
    2034                 :            :   // Send contribution to host summing partial surface integrals
    2035         [ -  - ]:          0 :   contribute( s, CkReduction::sum_double, m_cbr.get< tag::bndint >() );
    2036                 :            : 
    2037                 :          0 :   return true;  // don't trigger the assert in client code
    2038                 :            : }
    2039                 :            : 
    2040                 :            : #include "NoWarning/refiner.def.h"

Generated by: LCOV version 1.16