Quinoa all test code coverage report
Current view: top level - Inciter - Discretization.cpp (source / functions) Hit Total Coverage
Commit: -128-NOTFOUND Lines: 367 386 95.1 %
Date: 2024-11-22 09:12:55 Functions: 41 43 95.3 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 350 890 39.3 %

           Branch data     Line data    Source code
       1                 :            : // *****************************************************************************
       2                 :            : /*!
       3                 :            :   \file      src/Inciter/Discretization.cpp
       4                 :            :   \copyright 2012-2015 J. Bakosi,
       5                 :            :              2016-2018 Los Alamos National Security, LLC.,
       6                 :            :              2019-2021 Triad National Security, LLC.
       7                 :            :              All rights reserved. See the LICENSE file for details.
       8                 :            :   \details   Data and functionality common to all discretization schemes
       9                 :            :   \see       Discretization.h and Discretization.C for more info.
      10                 :            : */
      11                 :            : // *****************************************************************************
      12                 :            : 
      13                 :            : #include "Tags.hpp"
      14                 :            : #include "Reorder.hpp"
      15                 :            : #include "Vector.hpp"
      16                 :            : #include "DerivedData.hpp"
      17                 :            : #include "Discretization.hpp"
      18                 :            : #include "MeshWriter.hpp"
      19                 :            : #include "DiagWriter.hpp"
      20                 :            : #include "Inciter/InputDeck/InputDeck.hpp"
      21                 :            : #include "Inciter/Options/Scheme.hpp"
      22                 :            : #include "Print.hpp"
      23                 :            : #include "Around.hpp"
      24                 :            : #include "QuinoaBuildConfig.hpp"
      25                 :            : #include "ConjugateGradients.hpp"
      26                 :            : #include "ALE.hpp"
      27                 :            : 
      28                 :            : #include "M2MTransfer.hpp"
      29                 :            : 
      30                 :            : namespace inciter {
      31                 :            : 
      32                 :            : static CkReduction::reducerType PDFMerger;
      33                 :            : extern ctr::InputDeck g_inputdeck;
      34                 :            : extern ctr::InputDeck g_inputdeck_defaults;
      35                 :            : 
      36                 :            : } // inciter::
      37                 :            : 
      38                 :            : using inciter::Discretization;
      39                 :            : 
      40                 :       1943 : Discretization::Discretization(
      41                 :            :   std::size_t meshid,
      42                 :            :   const std::vector< CProxy_Discretization >& disc,
      43                 :            :   const CProxy_ALE& aleproxy,
      44                 :            :   const tk::CProxy_ConjugateGradients& conjugategradientsproxy,
      45                 :            :   const CProxy_Transporter& transporter,
      46                 :            :   const tk::CProxy_MeshWriter& meshwriter,
      47                 :            :   const tk::UnsMesh::CoordMap& coordmap,
      48                 :            :   const tk::UnsMesh::Chunk& el,
      49                 :            :   const tk::CommMaps& msum,
      50                 :            :   const std::map< int, std::vector< std::size_t > >& bface,
      51                 :            :   const std::vector< std::size_t >& triinpoel,
      52                 :            :   const std::unordered_map< std::size_t, std::set< std::size_t > >& elemblockid,
      53                 :       1943 :   int nc ) :
      54                 :            :   m_meshid( meshid ),
      55                 :            :   m_transfer( g_inputdeck.get< tag::transfer >() ),
      56                 :            :   m_disc( disc ),
      57                 :            :   m_nchare( nc ),
      58                 :            :   m_it( 0 ),
      59                 :            :   m_itr( 0 ),
      60                 :            :   m_itf( 0 ),
      61                 :            :   m_initial( 1 ),
      62                 :       1943 :   m_t( g_inputdeck.get< tag::t0 >() ),
      63                 :            :   m_lastDumpTime( -std::numeric_limits< tk::real >::max() ),
      64                 :            :   m_physFieldFloor( 0.0 ),
      65                 :            :   m_physHistFloor( 0.0 ),
      66                 :            :   m_rangeFieldFloor( 0.0 ),
      67                 :            :   m_rangeHistFloor( 0.0 ),
      68                 :       1943 :   m_dt( g_inputdeck.get< tag::dt >() ),
      69                 :            :   m_dtn( m_dt ),
      70                 :            :   m_nvol( 0 ),
      71                 :            :   m_nxfer( 0 ),
      72                 :            :   m_ale( aleproxy ),
      73                 :            :   m_transporter( transporter ),
      74                 :            :   m_meshwriter( meshwriter ),
      75                 :            :   m_el( el ),     // fills m_inpoel, m_gid, m_lid
      76                 :            :   m_coord( setCoord( coordmap ) ),
      77                 :       1943 :   m_coordn( m_coord ),
      78                 :            :   m_nodeCommMap(),
      79                 :            :   m_edgeCommMap(),
      80                 :            :   m_meshvol( 0.0 ),
      81         [ +  - ]:       1943 :   m_v( m_gid.size(), 0.0 ),
      82                 :       3886 :   m_vol( m_gid.size(), 0.0 ),
      83                 :            :   m_volc(),
      84                 :            :   m_voln( m_vol ),
      85                 :       3886 :   m_vol0( m_inpoel.size()/4, 0.0 ),
      86                 :            :   m_bid(),
      87                 :            :   m_timer(),
      88                 :            :   m_refined( 0 ),
      89                 :       1943 :   m_prevstatus( std::chrono::high_resolution_clock::now() ),
      90                 :            :   m_nrestart( 0 ),
      91                 :            :   m_histdata(),
      92                 :            :   m_nsrc( 0 ),
      93                 :            :   m_ndst( 0 ),
      94                 :            :   m_meshvel( 0, 3 ),
      95                 :            :   m_meshvel_converged( true ),
      96                 :            :   m_bface( bface ),
      97                 :            :   m_triinpoel( triinpoel ),
      98 [ +  - ][ +  - ]:       3886 :   m_elemblockid( elemblockid )
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ -  - ][ -  - ]
      99                 :            : // *****************************************************************************
     100                 :            : //  Constructor
     101                 :            : //! \param[in] meshid Mesh ID
     102                 :            : //! \param[in] disc All Discretization proxies (one per mesh)
     103                 :            : //! \param[in] aleproxy Distributed ALE proxy
     104                 :            : //! \param[in] conjugategradientsproxy Distributed Conjugrate Gradients linear
     105                 :            : //!   solver proxy
     106                 :            : //! \param[in] transporter Host (Transporter) proxy
     107                 :            : //! \param[in] meshwriter Mesh writer proxy
     108                 :            : //! \param[in] coordmap Coordinates of mesh nodes and their global IDs
     109                 :            : //! \param[in] el Elements of the mesh chunk we operate on
     110                 :            : //! \param[in] msum Communication maps associated to chare IDs bordering the
     111                 :            : //!   mesh chunk we operate on
     112                 :            : //! \param[in] bface Face lists mapped to side set ids
     113                 :            : //! \param[in] triinpoel Interconnectivity of points and boundary-faces
     114                 :            : //! \param[in] elemblockid Local tet ids associated with mesh block ids
     115                 :            : //! \param[in] nc Total number of Discretization chares
     116                 :            : // *****************************************************************************
     117                 :            : {
     118                 :            :   Assert( !m_inpoel.empty(), "No elements assigned to Discretization chare" );
     119                 :            :   Assert( tk::positiveJacobians( m_inpoel, m_coord ),
     120                 :            :           "Jacobian in input mesh to Discretization non-positive" );
     121                 :            :   #if not defined(__INTEL_COMPILER) || defined(NDEBUG)
     122                 :            :   // The above ifdef skips running the conformity test with the intel compiler
     123                 :            :   // in debug mode only. This is necessary because in tk::conforming(), filling
     124                 :            :   // up the map can fail with some meshes (only in parallel), e.g., tube.exo,
     125                 :            :   // used by some regression tests, due to the intel compiler generating some
     126                 :            :   // garbage incorrect code - only in debug, only in parallel, only with that
     127                 :            :   // mesh.
     128                 :            :   Assert( tk::conforming( m_inpoel, m_coord ),
     129                 :            :           "Input mesh to Discretization not conforming" );
     130                 :            :   #endif
     131                 :            : 
     132                 :            :   // Store communication maps
     133         [ +  + ]:      21595 :   for (const auto& [ c, maps ] : msum) {
     134                 :            :     m_nodeCommMap[c] = maps.get< tag::node >();
     135                 :            :     m_edgeCommMap[c] = maps.get< tag::edge >();
     136                 :            :   }
     137                 :            : 
     138                 :            :   // Get ready for computing/communicating nodal volumes
     139         [ +  - ]:       1943 :   startvol();
     140                 :            : 
     141                 :            :   // Get chare-boundary node-id map
     142         [ +  - ]:       3886 :   m_bid = genBid();
     143                 :            : 
     144                 :            :   // Find host elements of user-specified points where time histories are
     145                 :            :   // saved, and save the shape functions evaluated at the point locations
     146                 :            :   const auto& pt = g_inputdeck.get< tag::history_output, tag::point >();
     147         [ +  + ]:       1995 :   for (std::size_t p=0; p<pt.size(); ++p) {
     148                 :            :     std::array< tk::real, 4 > N;
     149                 :            :     const auto& l = pt[p].get< tag::coord >();
     150                 :            :     const auto& id = pt[p].get< tag::id >();
     151         [ +  + ]:      25021 :     for (std::size_t e=0; e<m_inpoel.size()/4; ++e) {
     152 [ +  - ][ +  + ]:      24979 :       if (tk::intet( m_coord, m_inpoel, l, e, N )) {
     153 [ +  - ][ -  + ]:         20 :         m_histdata.push_back( HistData{{ id, e, {l[0],l[1],l[2]}, N }} );
                 [ -  - ]
     154                 :         10 :         break;
     155                 :            :       }
     156                 :            :     }
     157                 :            :   }
     158                 :            : 
     159                 :            :   // Insert ConjugrateGradients solver chare array element if needed
     160         [ +  + ]:       1943 :   if (g_inputdeck.get< tag::ale, tag::ale >()) {
     161         [ +  - ]:         62 :     m_ale[ thisIndex ].insert( conjugategradientsproxy,
     162                 :         31 :                                m_coord, m_inpoel,
     163         [ +  - ]:         31 :                                m_gid, m_lid, m_nodeCommMap );
     164                 :            :   } else {
     165         [ +  - ]:       1912 :     m_meshvel.resize( m_gid.size() );
     166                 :            :   }
     167                 :            : 
     168                 :            :   // Register mesh with mesh-transfer lib
     169 [ +  + ][ -  + ]:       1943 :   if (m_disc.size() == 1 || m_transfer.empty()) {
     170                 :            :     // skip transfer if single mesh or if not involved in coupling
     171         [ +  - ]:       1929 :     transferInit();
     172                 :            :   } else {
     173         [ +  + ]:         14 :     if (thisIndex == 0) {
     174         [ +  - ]:          4 :       exam2m::addMesh( thisProxy, m_nchare,
     175                 :          4 :         CkCallback( CkIndex_Discretization::transferInit(), thisProxy ) );
     176                 :            :       //std::cout << "Disc: " << m_meshid << " m2m::addMesh()\n";
     177                 :            :     }
     178                 :            :   }
     179                 :       1943 : }
     180                 :            : 
     181                 :            : std::unordered_map< std::size_t, std::size_t >
     182                 :       1943 : Discretization::genBid()
     183                 :            : // *****************************************************************************
     184                 :            : // Generate the Bid data-structure based on the node communication-map
     185                 :            : // *****************************************************************************
     186                 :            : {
     187                 :            :   // Count the number of mesh nodes at which we receive data from other chares
     188                 :            :   // and compute map associating boundary-chare node ID to global node ID
     189                 :       1943 :   std::vector< std::size_t > c( tk::sumvalsize( m_nodeCommMap ) );
     190                 :            :   std::size_t j = 0;
     191 [ +  + ][ +  + ]:     167871 :   for (const auto& [ch,n] : m_nodeCommMap) for (auto i : n) c[j++] = i;
     192         [ +  - ]:       1943 :   tk::unique( c );
     193         [ +  - ]:       3886 :   return tk::assignLid( c );
     194                 :            : }
     195                 :            : 
     196                 :            : void
     197                 :       1943 : Discretization::transferInit()
     198                 :            : // *****************************************************************************
     199                 :            : // Our mesh has been registered with the mesh-to-mesh transfer library (if
     200                 :            : // coupled to other solver)
     201                 :            : // *****************************************************************************
     202                 :            : {
     203                 :            :   // Compute number of mesh points owned
     204                 :       1943 :   std::size_t npoin = m_gid.size();
     205 [ +  + ][ +  + ]:     187866 :   for (auto g : m_gid) if (tk::slave(m_nodeCommMap,g,thisIndex)) --npoin;
     206                 :            : 
     207                 :            :   // Tell the RTS that the Discretization chares have been created and compute
     208                 :            :   // the total number of mesh points across the distributed mesh
     209                 :       1943 :   std::vector< std::size_t > meshdata{ m_meshid, npoin };
     210         [ +  - ]:       1943 :   contribute( meshdata, CkReduction::sum_ulong,
     211 [ +  - ][ +  - ]:       3886 :     CkCallback( CkReductionTarget(Transporter,disccreated), m_transporter ) );
                 [ -  - ]
     212                 :       1943 : }
     213                 :            : 
     214                 :            : void
     215                 :      43686 : Discretization::meshvelStart(
     216                 :            :   const tk::UnsMesh::Coords vel,
     217                 :            :   const std::vector< tk::real >& soundspeed,
     218                 :            :   const std::unordered_map< int,
     219                 :            :     std::unordered_map< std::size_t, std::array< tk::real, 4 > > >& bnorm,
     220                 :            :   tk::real adt,
     221                 :            :   CkCallback done ) const
     222                 :            : // *****************************************************************************
     223                 :            : // Start computing new mesh velocity for ALE mesh motion
     224                 :            : //! \param[in] vel Fluid velocity at mesh nodes
     225                 :            : //! \param[in] soundspeed Speed of sound at mesh nodes
     226                 :            : //! \param[in] bnorm Face normals in boundary points associated to side sets
     227                 :            : //! \param[in] adt alpha*dt of the RK time step
     228                 :            : //! \param[in] done Function to continue with when mesh velocity has been
     229                 :            : //!   computed
     230                 :            : // *****************************************************************************
     231                 :            : {
     232         [ +  + ]:      43686 :   if (g_inputdeck.get< tag::ale, tag::ale >())
     233 [ +  - ][ -  + ]:       4444 :     m_ale[ thisIndex ].ckLocal()->start( vel, soundspeed, done,
         [ -  - ][ -  - ]
     234 [ +  - ][ +  - ]:       1111 :       m_coord, m_coordn, m_vol0, m_vol, bnorm, m_initial, m_it, m_t, adt );
     235                 :            :   else
     236                 :      42575 :     done.send();
     237                 :      43686 : }
     238                 :            : 
     239                 :            : const tk::Fields&
     240                 :      44304 : Discretization::meshvel() const
     241                 :            : // *****************************************************************************
     242                 :            : //! Query the mesh velocity
     243                 :            : //! \return Mesh velocity
     244                 :            : // *****************************************************************************
     245                 :            : {
     246         [ +  + ]:      44304 :   if (g_inputdeck.get< tag::ale, tag::ale >())
     247                 :       4470 :     return m_ale[ thisIndex ].ckLocal()->meshvel();
     248                 :            :   else
     249                 :      42069 :     return m_meshvel;
     250                 :            : }
     251                 :            : 
     252                 :            : void
     253                 :      43686 : Discretization::meshvelBnd(
     254                 :            :   const std::map< int, std::vector< std::size_t > >& bface,
     255                 :            :   const std::map< int, std::vector< std::size_t > >& bnode,
     256                 :            :   const std::vector< std::size_t >& triinpoel) const
     257                 :            : // *****************************************************************************
     258                 :            : // Query ALE mesh velocity boundary condition node lists and node lists at
     259                 :            : // which ALE moves boundaries
     260                 :            : // *****************************************************************************
     261                 :            : {
     262         [ +  + ]:      43686 :   if (g_inputdeck.get< tag::ale, tag::ale >())
     263         [ +  - ]:       3333 :     m_ale[ thisIndex ].ckLocal()->meshvelBnd( bface, bnode, triinpoel );
     264                 :      43686 : }
     265                 :            : 
     266                 :            : void
     267                 :      43686 : Discretization::meshvelConv()
     268                 :            : // *****************************************************************************
     269                 :            : //! Assess and record mesh velocity linear solver convergence
     270                 :            : // *****************************************************************************
     271                 :            : {
     272                 :      43686 :   auto smoother = g_inputdeck.get< tag::ale, tag::smoother >();
     273                 :            : 
     274         [ +  + ]:      43686 :   if (g_inputdeck.get< tag::ale, tag::ale >() &&
     275         [ +  + ]:       1111 :       (smoother == ctr::MeshVelocitySmootherType::LAPLACE or
     276                 :            :        smoother == ctr::MeshVelocitySmootherType::HELMHOLTZ))
     277                 :            :   {
     278 [ +  - ][ -  + ]:       1602 :     m_meshvel_converged &= m_ale[ thisIndex ].ckLocal()->converged();
     279                 :            :   }
     280                 :      43686 : }
     281                 :            : 
     282                 :            : void
     283                 :        844 : Discretization::comfinal()
     284                 :            : // *****************************************************************************
     285                 :            : // Finish setting up communication maps and solution transfer callbacks
     286                 :            : // *****************************************************************************
     287                 :            : {
     288                 :            :   // Generate own subset of solver/mesh transfer list
     289         [ +  + ]:        858 :   for (const auto& t : m_transfer) {
     290 [ +  + ][ +  - ]:         14 :     if (t.src == m_meshid || t.dst == m_meshid) {
     291                 :         14 :       m_mytransfer.push_back( t );
     292                 :            :     }
     293                 :            :   }
     294                 :            : 
     295                 :            :   // Signal the runtime system that the workers have been created
     296                 :        844 :   std::vector< std::size_t > meshdata{ /* initial = */ 1, m_meshid };
     297         [ +  - ]:        844 :   contribute( meshdata, CkReduction::sum_ulong,
     298 [ +  - ][ +  - ]:       1688 :     CkCallback(CkReductionTarget(Transporter,comfinal), m_transporter) );
                 [ -  - ]
     299                 :        844 : }
     300                 :            : 
     301                 :            : void
     302         [ +  + ]:      12264 : Discretization::transfer(
     303                 :            :   tk::Fields& u,
     304                 :            :   std::size_t dirn,
     305                 :            :   CkCallback cb )
     306                 :            : // *****************************************************************************
     307                 :            : //  Start solution transfer (if coupled)
     308                 :            : //! \param[in,out] u Solution to transfer from/to
     309                 :            : //! \param[in] dirn Direction of solution transfer. 0: from background to
     310                 :            : //!   overset, 1: from overset to background
     311                 :            : //! \param[in] cb Callback to call when back and forth transfers complete.
     312                 :            : //! \details This function initiates the solution transfer (direction dependent
     313                 :            : //!   on 'dirn') between meshes. It invokes a reduction to Transporter when the
     314                 :            : //!   transfer in one direction is complete (dirn == 0), or calls back the
     315                 :            : //!   'cb' function in Scheme when transfers both directions are complete.
     316                 :            : //!   The function relies on 'dirn' to make this decision.
     317                 :            : // *****************************************************************************
     318                 :            : {
     319         [ +  + ]:      12264 :   if (m_mytransfer.empty()) {   // skip transfer if not involved in coupling
     320                 :            : 
     321                 :       9800 :     cb.send();
     322                 :            : 
     323                 :            :   } else {
     324                 :            : 
     325         [ +  + ]:       2464 :     m_transfer_complete = cb;
     326                 :            : 
     327                 :            :     // determine source and destination mesh depending on direction of transfer
     328                 :            :     std::size_t fromMesh(0), toMesh(0);
     329                 :            :     CkCallback cb_xfer;
     330         [ +  + ]:       2464 :     if (dirn == 0) {
     331         [ +  - ]:       1232 :       fromMesh = m_mytransfer[m_nsrc].src;
     332                 :       1232 :       toMesh = m_mytransfer[m_ndst].dst;
     333 [ +  - ][ +  - ]:       2464 :       cb_xfer = CkCallback( CkIndex_Discretization::to_complete(), thisProxy[thisIndex] );
                 [ -  + ]
     334                 :            :     }
     335                 :            :     else {
     336         [ +  - ]:       1232 :       fromMesh = m_mytransfer[m_nsrc].dst;
     337                 :       1232 :       toMesh = m_mytransfer[m_ndst].src;
     338 [ +  - ][ +  - ]:       2464 :       cb_xfer = CkCallback( CkIndex_Discretization::from_complete(), thisProxy[thisIndex] );
                 [ -  + ]
     339                 :            :     }
     340                 :            : 
     341                 :            :     // Pass source and destination meshes to mesh transfer lib (if coupled)
     342                 :            :     Assert( m_nsrc < m_mytransfer.size(), "Indexing out of mytransfer[src]" );
     343         [ +  + ]:       2464 :     if (fromMesh == m_meshid) {
     344         [ +  - ]:       1232 :       exam2m::setSourceTets( thisProxy, thisIndex, &m_inpoel, &m_coord, u );
     345                 :       1232 :       ++m_nsrc;
     346                 :            :     } else {
     347                 :       1232 :       m_nsrc = 0;
     348                 :            :     }
     349                 :            :     Assert( m_ndst < m_mytransfer.size(), "Indexing out of mytransfer[dst]" );
     350         [ +  + ]:       2464 :     if (toMesh == m_meshid) {
     351         [ +  - ]:       1232 :       exam2m::setDestPoints( thisProxy, thisIndex, &m_coord, u,
     352                 :            :         cb_xfer );
     353                 :       1232 :       ++m_ndst;
     354                 :            :     } else {
     355                 :       1232 :       m_ndst = 0;
     356                 :            :     }
     357                 :            : 
     358                 :            :   }
     359                 :            : 
     360                 :      12264 :   m_nsrc = 0;
     361                 :      12264 :   m_ndst = 0;
     362                 :      12264 : }
     363                 :            : 
     364                 :        616 : void Discretization::to_complete()
     365                 :            : // *****************************************************************************
     366                 :            : //! Solution transfer from background to overset mesh completed (from ExaM2M)
     367                 :            : //! \brief This is called by ExaM2M on the destination mesh when the
     368                 :            : //!   transfer completes. Since this is called only on the destination, we find
     369                 :            : //!   and notify the corresponding source of the completion.
     370                 :            : // *****************************************************************************
     371                 :            : {
     372                 :            :   // Lookup the source disc and notify it of completion
     373         [ +  + ]:       1232 :   for (auto& t : m_transfer) {
     374         [ +  - ]:        616 :     if (m_meshid == t.dst) {
     375         [ +  - ]:       1232 :       m_disc[ t.src ][ thisIndex ].transfer_complete();
     376                 :            :     }
     377                 :            :   }
     378                 :            : 
     379         [ +  - ]:        616 :   thisProxy[ thisIndex ].transfer_complete();
     380                 :        616 : }
     381                 :            : 
     382                 :        616 : void Discretization::from_complete()
     383                 :            : // *****************************************************************************
     384                 :            : //! Solution transfer from overset to background mesh completed (from ExaM2M)
     385                 :            : //! \brief This is called by ExaM2M on the destination mesh when the
     386                 :            : //!   transfer completes. Since this is called only on the destination, we find
     387                 :            : //!   and notify the corresponding source of the completion.
     388                 :            : // *****************************************************************************
     389                 :            : {
     390                 :            :   // Lookup the source disc and notify it of completion
     391         [ +  + ]:       1232 :   for (auto& t : m_transfer) {
     392         [ +  - ]:        616 :     if (m_meshid == t.src) {
     393         [ +  - ]:       1232 :       m_disc[ t.dst ][ thisIndex ].transfer_complete_from_dest();
     394                 :            :     }
     395                 :            :   }
     396                 :            : 
     397                 :        616 :   m_transfer_complete.send();
     398                 :        616 : }
     399                 :            : 
     400                 :        616 : void Discretization::transfer_complete_from_dest()
     401                 :            : // *****************************************************************************
     402                 :            : //! Solution transfer completed (from dest Discretization)
     403                 :            : //! \details Called on the source only by the destination when a back and forth
     404                 :            : //!   transfer step completes.
     405                 :            : // *****************************************************************************
     406                 :            : {
     407                 :        616 :   m_transfer_complete.send();
     408                 :        616 : }
     409                 :            : 
     410                 :       1232 : void Discretization::transfer_complete()
     411                 :            : // *****************************************************************************
     412                 :            : //! Solution transfer completed (one-way)
     413                 :            : //! \note Single exit point after solution transfer between meshes
     414                 :            : // *****************************************************************************
     415                 :            : {
     416         [ +  - ]:       2464 :   contribute( sizeof(nullptr), nullptr, CkReduction::nop,
     417                 :       1232 :     CkCallback(CkReductionTarget(Transporter,solutionTransferred),
     418                 :            :     m_transporter) );
     419                 :       1232 : }
     420                 :            : 
     421                 :            : std::vector< std::size_t >
     422                 :       8329 : Discretization::bndel() const
     423                 :            : // *****************************************************************************
     424                 :            : // Find elements along our mesh chunk boundary
     425                 :            : //! \return List of local element ids that have at least a single node
     426                 :            : //!   contributing to a chare boundary
     427                 :            : // *****************************************************************************
     428                 :            : {
     429                 :            :   // Lambda to find out if a mesh node is shared with another chare
     430                 :   10327604 :   auto shared = [this]( std::size_t i ){
     431         [ +  + ]:   29288081 :     for (const auto& [c,n] : m_nodeCommMap)
     432         [ +  + ]:   21040683 :       if (n.find(i) != end(n)) return true;
     433                 :            :     return false;
     434                 :            :   };
     435                 :            : 
     436                 :            :   // Find elements along our mesh chunk boundary
     437                 :            :   std::vector< std::size_t > e;
     438         [ +  + ]:   10335933 :   for (std::size_t n=0; n<m_inpoel.size(); ++n)
     439 [ +  + ][ +  - ]:   10327604 :     if (shared( m_gid[ m_inpoel[n] ] )) e.push_back( n/4 );
                 [ -  - ]
     440         [ +  - ]:       8329 :   tk::unique( e );
     441                 :            : 
     442                 :       8329 :   return e;
     443                 :            : }
     444                 :            : 
     445                 :            : void
     446                 :          0 : Discretization::resizePostAMR(
     447                 :            :   const tk::UnsMesh::Chunk& chunk,
     448                 :            :   const tk::UnsMesh::Coords& coord,
     449                 :            :   const std::unordered_map< std::size_t, std::size_t >& /*amrNodeMap*/,
     450                 :            :   const tk::NodeCommMap& nodeCommMap,
     451                 :            :   const std::set< std::size_t >& /*removedNodes*/,
     452                 :            :   const std::unordered_map< std::size_t, std::set< std::size_t > >& elemblockid )
     453                 :            : // *****************************************************************************
     454                 :            : //  Resize mesh data structures after mesh refinement
     455                 :            : //! \param[in] chunk New mesh chunk (connectivity and global<->local id maps)
     456                 :            : //! \param[in] coord New mesh node coordinates
     457                 :            : //! \param[in] amrNodeMap Node id map after amr (local ids)
     458                 :            : //! \param[in] nodeCommMap New node communication map
     459                 :            : //! \param[in] removedNodes Newly removed mesh node local ids
     460                 :            : //! \param[in] elemblockid New local tet ids associated with mesh block ids
     461                 :            : // *****************************************************************************
     462                 :            : {
     463                 :            :   m_el = chunk;         // updates m_inpoel, m_gid, m_lid
     464                 :            :   m_nodeCommMap.clear();
     465                 :            :   m_nodeCommMap = nodeCommMap;        // update node communication map
     466                 :            :   m_elemblockid.clear();
     467                 :            :   m_elemblockid = elemblockid;
     468                 :            : 
     469                 :            :   // Update mesh volume container size
     470         [ -  - ]:          0 :   m_vol.resize( m_gid.size(), 0.0 );
     471         [ -  - ]:          0 :   if (!m_voln.empty()) m_voln.resize( m_gid.size(), 0.0 );
     472                 :            : 
     473                 :            :   // Regenerate bid data
     474                 :          0 :   tk::destroy(m_bid);
     475                 :          0 :   m_bid = genBid();
     476                 :            : 
     477                 :            :   // update mesh node coordinates
     478                 :            :   m_coord = coord;
     479                 :            : 
     480                 :            :   // we are no longer during setup
     481                 :          0 :   m_initial = 0;
     482                 :          0 : }
     483                 :            : 
     484                 :            : void
     485                 :       3023 : Discretization::startvol()
     486                 :            : // *****************************************************************************
     487                 :            : //  Get ready for (re-)computing/communicating nodal volumes
     488                 :            : // *****************************************************************************
     489                 :            : {
     490                 :       3023 :   m_nvol = 0;
     491         [ +  - ]:       6046 :   thisProxy[ thisIndex ].wait4vol();
     492                 :            : 
     493                 :            :   // Zero out mesh volume container
     494                 :            :   std::fill( begin(m_vol), end(m_vol), 0.0 );
     495                 :            : 
     496                 :            :   // Clear receive buffer that will be used for collecting nodal volumes
     497                 :            :   m_volc.clear();
     498                 :       3023 : }
     499                 :            : 
     500                 :            : void
     501                 :        572 : Discretization::registerReducers()
     502                 :            : // *****************************************************************************
     503                 :            : //  Configure Charm++ reduction types
     504                 :            : //!  \details Since this is a [initnode] routine, see the .ci file, the
     505                 :            : //!   Charm++ runtime system executes the routine exactly once on every
     506                 :            : //!   logical node early on in the Charm++ init sequence. Must be static as
     507                 :            : //!   it is called without an object. See also: Section "Initializations at
     508                 :            : //!   Program Startup" at in the Charm++ manual
     509                 :            : //!   http://charm.cs.illinois.edu/manuals/html/charm++/manual.html.
     510                 :            : // *****************************************************************************
     511                 :            : {
     512                 :        572 :   PDFMerger = CkReduction::addReducer( tk::mergeUniPDFs );
     513                 :        572 : }
     514                 :            : 
     515                 :            : tk::UnsMesh::Coords
     516                 :       1943 : Discretization::setCoord( const tk::UnsMesh::CoordMap& coordmap )
     517                 :            : // *****************************************************************************
     518                 :            : // Set mesh coordinates based on coordinates map
     519                 :            : // *****************************************************************************
     520                 :            : {
     521                 :            :   Assert( coordmap.size() == m_gid.size(), "Size mismatch" );
     522                 :            :   Assert( coordmap.size() == m_lid.size(), "Size mismatch" );
     523                 :            : 
     524                 :            :   tk::UnsMesh::Coords coord;
     525         [ +  - ]:       1943 :   coord[0].resize( coordmap.size() );
     526         [ +  - ]:       1943 :   coord[1].resize( coordmap.size() );
     527         [ +  - ]:       1943 :   coord[2].resize( coordmap.size() );
     528                 :            : 
     529         [ +  + ]:     187866 :   for (const auto& [ gid, coords ] : coordmap) {
     530                 :     185923 :     auto i = tk::cref_find( m_lid, gid );
     531                 :     185923 :     coord[0][i] = coords[0];
     532                 :     185923 :     coord[1][i] = coords[1];
     533                 :     185923 :     coord[2][i] = coords[2];
     534                 :            :   }
     535                 :            : 
     536                 :       1943 :   return coord;
     537                 :            : }
     538                 :            : 
     539                 :            : void
     540                 :         10 : Discretization::remap(
     541                 :            :   const std::unordered_map< std::size_t, std::size_t >& map )
     542                 :            : // *****************************************************************************
     543                 :            : //  Remap mesh data based on new local ids
     544                 :            : //! \param[in] map Mapping of old->new local ids
     545                 :            : // *****************************************************************************
     546                 :            : {
     547                 :            :   // Remap connectivity containing local IDs
     548         [ +  + ]:      11914 :   for (auto& l : m_inpoel) l = tk::cref_find(map,l);
     549                 :            : 
     550                 :            :   // Remap global->local id map
     551         [ +  + ]:       1104 :   for (auto& [g,l] : m_lid) l = tk::cref_find(map,l);
     552                 :            : 
     553                 :            :   // Remap global->local id map
     554                 :         10 :   auto maxid = std::numeric_limits< std::size_t >::max();
     555                 :         10 :   std::vector< std::size_t > newgid( m_gid.size(), maxid );
     556         [ +  + ]:       1104 :   for (const auto& [o,n] : map) newgid[n] = m_gid[o];
     557         [ +  - ]:         10 :   m_gid = std::move( newgid );
     558                 :            : 
     559                 :            :   Assert( std::all_of( m_gid.cbegin(), m_gid.cend(),
     560                 :            :             [=](std::size_t i){ return i < maxid; } ),
     561                 :            :           "Not all gid have been remapped" );
     562                 :            : 
     563                 :            :   // Remap nodal volumes (with contributions along chare-boundaries)
     564 [ +  - ][ -  - ]:         10 :   std::vector< tk::real > newvol( m_vol.size(), 0.0 );
     565         [ +  + ]:       1104 :   for (const auto& [o,n] : map) newvol[n] = m_vol[o];
     566                 :            :   m_vol = std::move( newvol );
     567                 :            : 
     568                 :            :   // Remap nodal volumes (without contributions along chare-boundaries)
     569 [ +  - ][ -  - ]:         10 :   std::vector< tk::real > newv( m_v.size(), 0.0 );
     570         [ +  + ]:       1104 :   for (const auto& [o,n] : map) newv[n] = m_v[o];
     571                 :            :   m_v = std::move( newv );
     572                 :            : 
     573                 :            :   // Remap locations of node coordinates
     574                 :            :   tk::UnsMesh::Coords newcoord;
     575         [ +  - ]:         10 :   auto npoin = m_coord[0].size();
     576         [ +  - ]:         10 :   newcoord[0].resize( npoin );
     577         [ +  - ]:         10 :   newcoord[1].resize( npoin );
     578         [ +  - ]:         10 :   newcoord[2].resize( npoin );
     579         [ +  + ]:       1104 :   for (const auto& [o,n] : map) {
     580                 :       1094 :     newcoord[0][n] = m_coord[0][o];
     581                 :       1094 :     newcoord[1][n] = m_coord[1][o];
     582                 :       1094 :     newcoord[2][n] = m_coord[2][o];
     583                 :            :   }
     584                 :         10 :   m_coord = std::move( newcoord );
     585                 :         10 : }
     586                 :            : 
     587                 :            : void
     588                 :       1943 : Discretization::setRefiner( const CProxy_Refiner& ref )
     589                 :            : // *****************************************************************************
     590                 :            : //  Set Refiner Charm++ proxy
     591                 :            : //! \param[in] ref Incoming refiner proxy to store
     592                 :            : // *****************************************************************************
     593                 :            : {
     594                 :            :   m_refiner = ref;
     595                 :       1943 : }
     596                 :            : 
     597                 :            : void
     598                 :       3023 : Discretization::vol()
     599                 :            : // *****************************************************************************
     600                 :            : // Sum mesh volumes to nodes, start communicating them on chare-boundaries
     601                 :            : // *****************************************************************************
     602                 :            : {
     603                 :            :   const auto& x = m_coord[0];
     604                 :            :   const auto& y = m_coord[1];
     605                 :            :   const auto& z = m_coord[2];
     606                 :            : 
     607                 :            :   // Compute nodal volumes on our chunk of the mesh
     608         [ +  + ]:    5555430 :   for (std::size_t e=0; e<m_inpoel.size()/4; ++e) {
     609         [ -  + ]:    5552407 :     const std::array< std::size_t, 4 > N{{ m_inpoel[e*4+0], m_inpoel[e*4+1],
     610                 :    5552407 :                                            m_inpoel[e*4+2], m_inpoel[e*4+3] }};
     611                 :            :     // compute element Jacobi determinant * 5/120 = element volume / 4
     612                 :            :     const std::array< tk::real, 3 >
     613         [ -  + ]:    5552407 :       ba{{ x[N[1]]-x[N[0]], y[N[1]]-y[N[0]], z[N[1]]-z[N[0]] }},
     614                 :    5552407 :       ca{{ x[N[2]]-x[N[0]], y[N[2]]-y[N[0]], z[N[2]]-z[N[0]] }},
     615         [ -  + ]:    5552407 :       da{{ x[N[3]]-x[N[0]], y[N[3]]-y[N[0]], z[N[3]]-z[N[0]] }};
     616                 :    5552407 :     const auto J = tk::triple( ba, ca, da ) * 5.0 / 120.0;
     617 [ -  + ][ -  - ]:    5552407 :     ErrChk( J > 0, "Element Jacobian non-positive: PE:" +
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
                 [ -  - ]
     618                 :            :                    std::to_string(CkMyPe()) + ", node IDs: " +
     619                 :            :                    std::to_string(m_gid[N[0]]) + ',' +
     620                 :            :                    std::to_string(m_gid[N[1]]) + ',' +
     621                 :            :                    std::to_string(m_gid[N[2]]) + ',' +
     622                 :            :                    std::to_string(m_gid[N[3]]) + ", coords: (" +
     623                 :            :                    std::to_string(x[N[0]]) + ", " +
     624                 :            :                    std::to_string(y[N[0]]) + ", " +
     625                 :            :                    std::to_string(z[N[0]]) + "), (" +
     626                 :            :                    std::to_string(x[N[1]]) + ", " +
     627                 :            :                    std::to_string(y[N[1]]) + ", " +
     628                 :            :                    std::to_string(z[N[1]]) + "), (" +
     629                 :            :                    std::to_string(x[N[2]]) + ", " +
     630                 :            :                    std::to_string(y[N[2]]) + ", " +
     631                 :            :                    std::to_string(z[N[2]]) + "), (" +
     632                 :            :                    std::to_string(x[N[3]]) + ", " +
     633                 :            :                    std::to_string(y[N[3]]) + ", " +
     634                 :            :                    std::to_string(z[N[3]]) + ')' );
     635                 :            :     // scatter add V/4 to nodes
     636         [ +  + ]:   27762035 :     for (std::size_t j=0; j<4; ++j) m_vol[N[j]] += J;
     637                 :            : 
     638                 :            :     // save element volumes at t=t0
     639         [ +  + ]:    5552407 :     if (m_it == 0) m_vol0[e] = J * 4.0;
     640                 :            :   }
     641                 :            : 
     642                 :            :   // Store nodal volumes without contributions from other chares on
     643                 :            :   // chare-boundaries
     644                 :       3023 :   m_v = m_vol;
     645                 :            : 
     646                 :            :   // Send our nodal volume contributions to neighbor chares
     647         [ +  + ]:       3023 :   if (m_nodeCommMap.empty())
     648                 :        214 :    totalvol();
     649                 :            :   else
     650         [ +  + ]:      25341 :     for (const auto& [c,n] : m_nodeCommMap) {
     651         [ +  - ]:      22532 :       std::vector< tk::real > v( n.size() );
     652                 :            :       std::size_t j = 0;
     653         [ +  + ]:     437036 :       for (auto i : n) v[ j++ ] = m_vol[ tk::cref_find(m_lid,i) ];
     654 [ +  - ][ +  - ]:      45064 :       thisProxy[c].comvol( std::vector<std::size_t>(begin(n), end(n)), v );
         [ +  - ][ -  + ]
         [ +  - ][ -  - ]
     655                 :            :     }
     656                 :            : 
     657                 :       3023 :   ownvol_complete();
     658                 :       3023 : }
     659                 :            : 
     660                 :            : void
     661                 :      22532 : Discretization::comvol( const std::vector< std::size_t >& gid,
     662                 :            :                         const std::vector< tk::real >& nodevol )
     663                 :            : // *****************************************************************************
     664                 :            : //  Receive nodal volumes on chare-boundaries
     665                 :            : //! \param[in] gid Global mesh node IDs at which we receive volume contributions
     666                 :            : //! \param[in] nodevol Partial sums of nodal volume contributions to
     667                 :            : //!    chare-boundary nodes
     668                 :            : //! \details This function receives contributions to m_vol, which stores the
     669                 :            : //!   nodal volumes. While m_vol stores own contributions, m_volc collects the
     670                 :            : //!   neighbor chare contributions during communication. This way work on m_vol
     671                 :            : //!   and m_volc is overlapped. The contributions are applied in totalvol().
     672                 :            : // *****************************************************************************
     673                 :            : {
     674                 :            :   Assert( nodevol.size() == gid.size(), "Size mismatch" );
     675                 :            : 
     676         [ +  + ]:     437036 :   for (std::size_t i=0; i<gid.size(); ++i)
     677                 :     414504 :     m_volc[ gid[i] ] += nodevol[i];
     678                 :            : 
     679         [ +  + ]:      22532 :   if (++m_nvol == m_nodeCommMap.size()) {
     680                 :       2809 :     m_nvol = 0;
     681                 :       2809 :     comvol_complete();
     682                 :            :   }
     683                 :      22532 : }
     684                 :            : 
     685                 :            : void
     686                 :       3023 : Discretization::totalvol()
     687                 :            : // *****************************************************************************
     688                 :            : // Sum mesh volumes and contribute own mesh volume to total volume
     689                 :            : // *****************************************************************************
     690                 :            : {
     691                 :            :   // Add received contributions to nodal volumes
     692         [ +  + ]:     318860 :   for (const auto& [gid, vol] : m_volc)
     693                 :     631674 :     m_vol[ tk::cref_find(m_lid,gid) ] += vol;
     694                 :            : 
     695                 :            :   // Clear receive buffer
     696                 :       3023 :   tk::destroy(m_volc);
     697                 :            : 
     698                 :            :   // Sum mesh volume to host
     699                 :            :   std::vector< tk::real > tvol{ 0.0,
     700                 :       3023 :                                 static_cast<tk::real>(m_initial),
     701                 :       3023 :                                 static_cast<tk::real>(m_meshid) };
     702         [ +  + ]:    1484616 :   for (auto v : m_v) tvol[0] += v;
     703         [ +  - ]:       3023 :   contribute( tvol, CkReduction::sum_double,
     704 [ +  - ][ +  - ]:       6046 :     CkCallback(CkReductionTarget(Transporter,totalvol), m_transporter) );
                 [ -  - ]
     705                 :       3023 : }
     706                 :            : 
     707                 :            : void
     708                 :       1943 : Discretization::stat( tk::real mesh_volume )
     709                 :            : // *****************************************************************************
     710                 :            : // Compute mesh cell statistics
     711                 :            : //! \param[in] mesh_volume Total mesh volume
     712                 :            : // *****************************************************************************
     713                 :            : {
     714                 :            :   // Store total mesh volume
     715                 :       1943 :   m_meshvol = mesh_volume;
     716                 :            : 
     717                 :            :   const auto& x = m_coord[0];
     718                 :            :   const auto& y = m_coord[1];
     719                 :            :   const auto& z = m_coord[2];
     720                 :            : 
     721                 :            :   auto MIN = -std::numeric_limits< tk::real >::max();
     722                 :            :   auto MAX = std::numeric_limits< tk::real >::max();
     723                 :       1943 :   std::vector< tk::real > min{ MAX, MAX, MAX };
     724 [ +  - ][ -  - ]:       1943 :   std::vector< tk::real > max{ MIN, MIN, MIN };
     725 [ +  - ][ +  - ]:       1943 :   std::vector< tk::real > sum{ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
                 [ -  - ]
     726                 :            :   tk::UniPDF edgePDF( 1e-4 );
     727                 :            :   tk::UniPDF volPDF( 1e-4 );
     728                 :            :   tk::UniPDF ntetPDF( 1e-4 );
     729                 :            : 
     730                 :            :   // Compute points surrounding points
     731 [ +  - ][ +  - ]:       5829 :   auto psup = tk::genPsup( m_inpoel, 4, tk::genEsup(m_inpoel,4) );
     732                 :            :   Assert( psup.second.size()-1 == m_gid.size(),
     733                 :            :           "Number of mesh points and number of global IDs unequal" );
     734                 :            : 
     735                 :            :   // Compute edge length statistics
     736                 :            :   // Note that while the min and max edge lengths are independent of the number
     737                 :            :   // of CPUs (by the time they are aggregated across all chares), the sum of
     738                 :            :   // the edge lengths and the edge length PDF are not. This is because the
     739                 :            :   // edges on the chare-boundary are counted multiple times and we
     740                 :            :   // conscientiously do not make an effort to precisely compute this, because
     741                 :            :   // that would require communication and more complex logic. Since these
     742                 :            :   // statistics are intended as simple average diagnostics, we ignore these
     743                 :            :   // small differences. For reproducible average edge lengths and edge length
     744                 :            :   // PDFs, run the mesh in serial.
     745         [ +  + ]:     187866 :   for (std::size_t p=0; p<m_gid.size(); ++p)
     746         [ +  + ]:    1949919 :     for (auto i : tk::Around(psup,p)) {
     747         [ +  + ]:    1763996 :        const auto dx = x[ i ] - x[ p ];
     748                 :    1763996 :        const auto dy = y[ i ] - y[ p ];
     749                 :    1763996 :        const auto dz = z[ i ] - z[ p ];
     750                 :    1763996 :        const auto length = std::sqrt( dx*dx + dy*dy + dz*dz );
     751         [ +  + ]:    1763996 :        if (length < min[0]) min[0] = length;
     752         [ +  + ]:    1763996 :        if (length > max[0]) max[0] = length;
     753                 :    1763996 :        sum[0] += 1.0;
     754                 :    1763996 :        sum[1] += length;
     755         [ +  - ]:    1763996 :        edgePDF.add( length );
     756                 :            :     }
     757                 :            : 
     758                 :            :   // Compute mesh cell volume statistics
     759         [ +  + ]:     546990 :   for (std::size_t e=0; e<m_inpoel.size()/4; ++e) {
     760         [ +  + ]:     545047 :     const std::array< std::size_t, 4 > N{{ m_inpoel[e*4+0], m_inpoel[e*4+1],
     761                 :     545047 :                                            m_inpoel[e*4+2], m_inpoel[e*4+3] }};
     762                 :            :     const std::array< tk::real, 3 >
     763         [ +  + ]:     545047 :       ba{{ x[N[1]]-x[N[0]], y[N[1]]-y[N[0]], z[N[1]]-z[N[0]] }},
     764                 :     545047 :       ca{{ x[N[2]]-x[N[0]], y[N[2]]-y[N[0]], z[N[2]]-z[N[0]] }},
     765         [ +  + ]:     545047 :       da{{ x[N[3]]-x[N[0]], y[N[3]]-y[N[0]], z[N[3]]-z[N[0]] }};
     766                 :     545047 :     const auto L = std::cbrt( tk::triple( ba, ca, da ) / 6.0 );
     767         [ +  + ]:     545047 :     if (L < min[1]) min[1] = L;
     768         [ +  + ]:     545047 :     if (L > max[1]) max[1] = L;
     769                 :     545047 :     sum[2] += 1.0;
     770                 :     545047 :     sum[3] += L;
     771         [ +  - ]:     545047 :     volPDF.add( L );
     772                 :            :   }
     773                 :            : 
     774                 :            :   // Contribute stats of number of tetrahedra (ntets)
     775                 :       1943 :   sum[4] = 1.0;
     776                 :       1943 :   min[2] = max[2] = sum[5] = static_cast< tk::real >( m_inpoel.size() / 4 );
     777         [ +  - ]:       1943 :   ntetPDF.add( min[2] );
     778                 :            : 
     779         [ +  - ]:       1943 :   min.push_back( static_cast<tk::real>(m_meshid) );
     780         [ +  - ]:       1943 :   max.push_back( static_cast<tk::real>(m_meshid) );
     781         [ +  - ]:       1943 :   sum.push_back( static_cast<tk::real>(m_meshid) );
     782                 :            : 
     783                 :            :   // Contribute to mesh statistics across all Discretization chares
     784         [ +  - ]:       1943 :   contribute( min, CkReduction::min_double,
     785 [ +  - ][ +  - ]:       3886 :     CkCallback(CkReductionTarget(Transporter,minstat), m_transporter) );
     786                 :            :   contribute( max, CkReduction::max_double,
     787 [ +  - ][ +  - ]:       3886 :     CkCallback(CkReductionTarget(Transporter,maxstat), m_transporter) );
     788                 :            :   contribute( sum, CkReduction::sum_double,
     789         [ +  - ]:       1943 :     CkCallback(CkReductionTarget(Transporter,sumstat), m_transporter) );
     790                 :            : 
     791                 :            :   // Serialize PDFs to raw stream
     792 [ +  - ][ +  - ]:       5829 :   auto stream = tk::serialize( m_meshid, { edgePDF, volPDF, ntetPDF } );
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     793                 :            :   // Create Charm++ callback function for reduction of PDFs with
     794                 :            :   // Transporter::pdfstat() as the final target where the results will appear.
     795         [ +  - ]:       1943 :   CkCallback cb( CkIndex_Transporter::pdfstat(nullptr), m_transporter );
     796                 :            :   // Contribute serialized PDF of partial sums to host via Charm++ reduction
     797         [ +  - ]:       1943 :   contribute( stream.first, stream.second.get(), PDFMerger, cb );
     798                 :       1943 : }
     799                 :            : 
     800                 :            : void
     801                 :       1943 : Discretization::boxvol(
     802                 :            :   const std::vector< std::unordered_set< std::size_t > >& nodes,
     803                 :            :   const std::unordered_map< std::size_t, std::set< std::size_t > >& nodeblk,
     804                 :            :   std::size_t nuserblk )
     805                 :            : // *****************************************************************************
     806                 :            : // Compute total box IC volume
     807                 :            : //! \param[in] nodes Node list contributing to box IC volume (for each IC box)
     808                 :            : //! \param[in] nodeblk Node list associated to mesh blocks contributing to block
     809                 :            : //!   volumes (for each IC box)
     810                 :            : //! \param[in] nuserblk Number of user IC mesh blocks
     811                 :            : // *****************************************************************************
     812                 :            : {
     813                 :            :   // Compute partial box IC volume (just add up all boxes)
     814                 :       1943 :   tk::real boxvol = 0.0;
     815 [ +  + ][ +  + ]:       4499 :   for (const auto& b : nodes) for (auto i : b) boxvol += m_v[i];
     816                 :            : 
     817                 :            :   // Compute partial IC mesh block volume
     818                 :            :   std::vector< tk::real > blockvols;
     819         [ -  + ]:       1943 :   if (nuserblk > 0) {
     820 [ -  - ][ -  - ]:          0 :     blockvols.resize(nuserblk,0.0);
     821         [ -  - ]:          0 :     for (const auto& [blid, ndset] : nodeblk) {
     822                 :            :       // The following if-test makes sure we access volumes only of mesh blocks
     823                 :            :       // with user-specified ICs
     824         [ -  - ]:          0 :       if (blid < nuserblk) {
     825         [ -  - ]:          0 :         for (const auto& n : ndset) blockvols[blid] += m_v[n];
     826                 :            :       }
     827                 :            :     }
     828                 :            :   }
     829                 :            : 
     830                 :            :   // Sum up box IC volume across all chares
     831         [ +  - ]:       1943 :   auto meshdata = blockvols;
     832         [ +  - ]:       1943 :   meshdata.push_back(boxvol);
     833         [ +  - ]:       1943 :   meshdata.push_back(static_cast<tk::real>(m_meshid));
     834         [ +  - ]:       1943 :   contribute( meshdata, CkReduction::sum_double,
     835 [ +  - ][ +  - ]:       3886 :     CkCallback(CkReductionTarget(Transporter,boxvol), m_transporter) );
                 [ -  - ]
     836                 :       1943 : }
     837                 :            : 
     838                 :            : void
     839                 :       3557 : Discretization::write(
     840                 :            :   const std::vector< std::size_t >& inpoel,
     841                 :            :   const tk::UnsMesh::Coords& coord,
     842                 :            :   const std::map< int, std::vector< std::size_t > >& bface,
     843                 :            :   const std::map< int, std::vector< std::size_t > >& bnode,
     844                 :            :   const std::vector< std::size_t >& triinpoel,
     845                 :            :   const std::vector< std::string>& elemfieldnames,
     846                 :            :   const std::vector< std::string>& nodefieldnames,
     847                 :            :   const std::vector< std::string>& elemsurfnames,
     848                 :            :   const std::vector< std::string>& nodesurfnames,
     849                 :            :   const std::vector< std::vector< tk::real > >& elemfields,
     850                 :            :   const std::vector< std::vector< tk::real > >& nodefields,
     851                 :            :   const std::vector< std::vector< tk::real > >& elemsurfs,
     852                 :            :   const std::vector< std::vector< tk::real > >& nodesurfs,
     853                 :            :   CkCallback c )
     854                 :            : // *****************************************************************************
     855                 :            : //  Output mesh and fields data (solution dump) to file(s)
     856                 :            : //! \param[in] inpoel Mesh connectivity for the mesh chunk to be written
     857                 :            : //! \param[in] coord Node coordinates of the mesh chunk to be written
     858                 :            : //! \param[in] bface Map of boundary-face lists mapped to corresponding side set
     859                 :            : //!   ids for this mesh chunk
     860                 :            : //! \param[in] bnode Map of boundary-node lists mapped to corresponding side set
     861                 :            : //!   ids for this mesh chunk
     862                 :            : //! \param[in] triinpoel Interconnectivity of points and boundary-face in this
     863                 :            : //!   mesh chunk
     864                 :            : //! \param[in] elemfieldnames Names of element fields to be output to file
     865                 :            : //! \param[in] nodefieldnames Names of node fields to be output to file
     866                 :            : //! \param[in] elemsurfnames Names of elemental surface fields to be output to
     867                 :            : //!   file
     868                 :            : //! \param[in] nodesurfnames Names of node surface fields to be output to file
     869                 :            : //! \param[in] elemfields Field data in mesh elements to output to file
     870                 :            : //! \param[in] nodefields Field data in mesh nodes to output to file
     871                 :            : //! \param[in] elemsurfs Surface field data in mesh elements to output to file
     872                 :            : //! \param[in] nodesurfs Surface field data in mesh nodes to output to file
     873                 :            : //! \param[in] c Function to continue with after the write
     874                 :            : //! \details Since m_meshwriter is a Charm++ chare group, it never migrates and
     875                 :            : //!   an instance is guaranteed on every PE. We index the first PE on every
     876                 :            : //!   logical compute node. In Charm++'s non-SMP mode, a node is the same as a
     877                 :            : //!   PE, so the index is the same as CkMyPe(). In SMP mode the index is the
     878                 :            : //!   first PE on every logical node. In non-SMP mode this yields one or more
     879                 :            : //!   output files per PE with zero or non-zero virtualization, respectively. If
     880                 :            : //!   there are multiple chares on a PE, the writes are serialized per PE, since
     881                 :            : //!   only a single entry method call can be executed at any given time. In SMP
     882                 :            : //!   mode, still the same number of files are output (one per chare), but the
     883                 :            : //!   output is serialized through the first PE of each compute node. In SMP
     884                 :            : //!   mode, channeling multiple files via a single PE on each node is required
     885                 :            : //!   by NetCDF and HDF5, as well as ExodusII, since none of these libraries are
     886                 :            : //!   thread-safe.
     887                 :            : // *****************************************************************************
     888                 :            : {
     889                 :            :   // If the previous iteration refined (or moved) the mesh or this is called
     890                 :            :   // before the first time step, we also output the mesh.
     891                 :       3557 :   bool meshoutput = m_itf == 0 ? true : false;
     892                 :            : 
     893                 :            :   auto eps = std::numeric_limits< tk::real >::epsilon();
     894                 :       3557 :   bool fieldoutput = false;
     895                 :            : 
     896                 :            :   // Output field data only if there is no dump at this physical time yet
     897         [ +  - ]:       3557 :   if (std::abs(m_lastDumpTime - m_t) > eps ) {
     898                 :       3557 :     m_lastDumpTime = m_t;
     899                 :       3557 :     ++m_itf;
     900                 :       3557 :     fieldoutput = true;
     901                 :            :   }
     902                 :            : 
     903                 :            :   // set of sidesets where fieldoutput is required
     904                 :            :   std::set< int > outsets;
     905                 :            :   const auto& osv = g_inputdeck.get< tag::field_output, tag::sideset >();
     906                 :       3557 :   outsets.insert(osv.begin(), osv.end());
     907                 :            : 
     908                 :            :   m_meshwriter[ CkNodeFirst( CkMyNode() ) ].
     909 [ +  - ][ +  - ]:      10671 :     write( m_meshid, meshoutput, fieldoutput, m_itr, m_itf, m_t, thisIndex,
     910                 :            :            g_inputdeck.get< tag::cmd, tag::io, tag::output >(),
     911                 :            :            inpoel, coord, bface, bnode, triinpoel, elemfieldnames,
     912                 :            :            nodefieldnames, elemsurfnames, nodesurfnames, elemfields, nodefields,
     913                 :            :            elemsurfs, nodesurfs, outsets, c );
     914                 :       3557 : }
     915                 :            : 
     916                 :            : void
     917                 :      40348 : Discretization::setdt( tk::real newdt )
     918                 :            : // *****************************************************************************
     919                 :            : // Set time step size
     920                 :            : //! \param[in] newdt Size of the new time step
     921                 :            : // *****************************************************************************
     922                 :            : {
     923                 :      40348 :   m_dtn = m_dt;
     924                 :      40348 :   m_dt = newdt;
     925                 :            : 
     926                 :            :   // Truncate the size of last time step
     927                 :      40348 :   const auto term = g_inputdeck.get< tag::term >();
     928         [ +  + ]:      40348 :   if (m_t+m_dt > term) m_dt = term - m_t;
     929                 :      40348 : }
     930                 :            : 
     931                 :            : void
     932                 :      40348 : Discretization::next()
     933                 :            : // *****************************************************************************
     934                 :            : // Prepare for next step
     935                 :            : // *****************************************************************************
     936                 :            : {
     937                 :            :   // Update floor of physics time divided by output interval times
     938                 :            :   const auto eps = std::numeric_limits< tk::real >::epsilon();
     939                 :      40348 :   const auto ft = g_inputdeck.get< tag::field_output, tag::time_interval >();
     940         [ +  - ]:      40348 :   if (ft > eps) m_physFieldFloor = std::floor( m_t / ft );
     941                 :      40348 :   const auto ht = g_inputdeck.get< tag::history_output, tag::time_interval >();
     942         [ +  - ]:      40348 :   if (ht > eps) m_physHistFloor = std::floor( m_t / ht );
     943                 :            : 
     944                 :            :   // Update floors of physics time divided by output interval times for ranges
     945                 :            :   const auto& rf = g_inputdeck.get< tag::field_output, tag::time_range >();
     946         [ -  + ]:      40348 :   if (!rf.empty()) {
     947 [ -  - ][ -  - ]:          0 :     if (m_t > rf[0] and m_t < rf[1])
     948                 :          0 :       m_rangeFieldFloor = std::floor( m_t / rf[2] );
     949                 :            :   }
     950                 :            :   const auto& rh = g_inputdeck.get< tag::history_output, tag::time_range >();
     951         [ -  + ]:      40348 :   if (!rh.empty()) {
     952 [ -  - ][ -  - ]:          0 :     if (m_t > rh[0] and m_t < rh[1])
     953                 :          0 :       m_rangeHistFloor = std::floor( m_t / rh[2] );
     954                 :            :   }
     955                 :            : 
     956                 :      40348 :   ++m_it;
     957                 :      40348 :   m_t += m_dt;
     958                 :      40348 : }
     959                 :            : 
     960                 :            : void
     961                 :       1948 : Discretization::grindZero()
     962                 :            : // *****************************************************************************
     963                 :            : //  Zero grind-time
     964                 :            : // *****************************************************************************
     965                 :            : {
     966                 :       1948 :   m_prevstatus = std::chrono::high_resolution_clock::now();
     967                 :            : 
     968 [ +  + ][ +  + ]:       1948 :   if (thisIndex == 0 && m_meshid == 0) {
     969                 :        189 :     const auto verbose = g_inputdeck.get< tag::cmd, tag::verbose >();
     970                 :            :     const auto& def =
     971                 :            :       g_inputdeck_defaults.get< tag::cmd, tag::io, tag::screen >();
     972                 :        189 :     tk::Print print( g_inputdeck.get< tag::cmd >().logname( def, m_nrestart ),
     973                 :            :                      verbose ? std::cout : std::clog,
     974 [ -  + ][ +  - ]:        378 :                      std::ios_base::app );
     975 [ +  - ][ +  - ]:        378 :     print.diag( "Starting time stepping ..." );
     976                 :            :   }
     977                 :       1948 : }
     978                 :            : 
     979                 :            : bool
     980                 :      38405 : Discretization::restarted( int nrestart )
     981                 :            : // *****************************************************************************
     982                 :            : //  Detect if just returned from a checkpoint and if so, zero timers
     983                 :            : //! \param[in] nrestart Number of times restarted
     984                 :            : //! \return True if restart detected
     985                 :            : // *****************************************************************************
     986                 :            : {
     987                 :            :   // Detect if just restarted from checkpoint:
     988                 :            :   //   nrestart == -1 if there was no checkpoint this step
     989                 :            :   //   d->Nrestart() == nrestart if there was a checkpoint this step
     990                 :            :   //   if both false, just restarted from a checkpoint
     991 [ +  + ][ +  - ]:      38405 :   bool restarted = nrestart != -1 and m_nrestart != nrestart;
     992                 :            : 
     993                 :            :    // If just restarted from checkpoint
     994                 :            :   if (restarted) {
     995                 :            :     // Update number of restarts
     996                 :          5 :     m_nrestart = nrestart;
     997                 :            :     // Start timer measuring time stepping wall clock time
     998                 :          5 :     m_timer.zero();
     999                 :            :     // Zero grind-timer
    1000                 :          5 :     grindZero();
    1001                 :            :   }
    1002                 :            : 
    1003                 :      38405 :   return restarted;
    1004                 :            : }
    1005                 :            : 
    1006                 :            : std::string
    1007                 :         88 : Discretization::histfilename( const std::string& id,
    1008                 :            :                               std::streamsize precision )
    1009                 :            : // *****************************************************************************
    1010                 :            : //  Construct history output filename
    1011                 :            : //! \param[in] id History point id
    1012                 :            : //! \param[in] precision Floating point precision to use for output
    1013                 :            : //! \return History file name
    1014                 :            : // *****************************************************************************
    1015                 :            : {
    1016                 :            :   auto of = g_inputdeck.get< tag::cmd, tag::io, tag::output >();
    1017         [ +  - ]:        176 :   std::stringstream ss;
    1018                 :            : 
    1019                 :            :   auto mid =
    1020 [ +  + ][ +  - ]:         88 :     m_disc.size() > 1 ? std::string( '.' + std::to_string(m_meshid) ) : "";
         [ +  - ][ -  + ]
         [ +  - ][ -  - ]
    1021         [ +  - ]:         88 :   ss << std::setprecision(static_cast<int>(precision)) << of << mid << ".hist." << id;
    1022                 :            : 
    1023                 :         88 :   return ss.str();
    1024                 :            : }
    1025                 :            : 
    1026                 :            : void
    1027                 :         30 : Discretization::histheader( std::vector< std::string >&& names )
    1028                 :            : // *****************************************************************************
    1029                 :            : //  Output headers for time history files (one for each point)
    1030                 :            : //! \param[in] names History output variable names
    1031                 :            : // *****************************************************************************
    1032                 :            : {
    1033         [ +  + ]:         40 :   for (const auto& h : m_histdata) {
    1034                 :         10 :     auto prec = g_inputdeck.get< tag::history_output, tag::precision >();
    1035         [ +  - ]:         10 :     tk::DiagWriter hw( histfilename( h.get< tag::id >(), prec ),
    1036                 :            :                        g_inputdeck.get< tag::history_output, tag::format >(),
    1037 [ +  - ][ +  - ]:         10 :                        prec );
    1038         [ +  - ]:         10 :     hw.header( names );
    1039                 :            :   }
    1040                 :         30 : }
    1041                 :            : 
    1042                 :            : void
    1043                 :        254 : Discretization::history( std::vector< std::vector< tk::real > >&& data )
    1044                 :            : // *****************************************************************************
    1045                 :            : //  Output time history for a time step
    1046                 :            : //! \param[in] data Time history data for all variables and equations integrated
    1047                 :            : // *****************************************************************************
    1048                 :            : {
    1049                 :            :   Assert( data.size() == m_histdata.size(), "Size mismatch" );
    1050                 :            : 
    1051                 :            :   std::size_t i = 0;
    1052         [ +  + ]:        332 :   for (const auto& h : m_histdata) {
    1053                 :         78 :     auto prec = g_inputdeck.get< tag::history_output, tag::precision >();
    1054         [ +  - ]:         78 :     tk::DiagWriter hw( histfilename( h.get< tag::id >(), prec ),
    1055                 :            :                        g_inputdeck.get< tag::history_output, tag::format >(),
    1056                 :            :                        prec,
    1057 [ +  - ][ +  - ]:         78 :                        std::ios_base::app );
    1058         [ +  - ]:         78 :     hw.diag( m_it, m_t, m_dt, data[i] );
    1059                 :         78 :     ++i;
    1060                 :            :   }
    1061                 :        254 : }
    1062                 :            : 
    1063                 :            : bool
    1064                 :      39573 : Discretization::fielditer() const
    1065                 :            : // *****************************************************************************
    1066                 :            : //  Decide if field output iteration count interval is hit
    1067                 :            : //! \return True if field output iteration count interval is hit
    1068                 :            : // *****************************************************************************
    1069                 :            : {
    1070         [ +  + ]:      39573 :   if (g_inputdeck.get< tag::cmd, tag::benchmark >()) return false;
    1071                 :            : 
    1072                 :      33157 :   return m_it % g_inputdeck.get< tag::field_output, tag::interval >() == 0;
    1073                 :            : }
    1074                 :            : 
    1075                 :            : bool
    1076                 :      36028 : Discretization::fieldtime() const
    1077                 :            : // *****************************************************************************
    1078                 :            : //  Decide if field output physics time interval is hit
    1079                 :            : //! \return True if field output physics time interval is hit
    1080                 :            : // *****************************************************************************
    1081                 :            : {
    1082         [ +  + ]:      36028 :   if (g_inputdeck.get< tag::cmd, tag::benchmark >()) return false;
    1083                 :            : 
    1084                 :            :   const auto eps = std::numeric_limits< tk::real >::epsilon();
    1085                 :      29612 :   const auto ft = g_inputdeck.get< tag::field_output, tag::time_interval >();
    1086                 :            : 
    1087         [ +  - ]:      29612 :   if (ft < eps) return false;
    1088                 :            : 
    1089                 :      29612 :   return std::floor(m_t/ft) - m_physFieldFloor > eps;
    1090                 :            : }
    1091                 :            : 
    1092                 :            : bool
    1093                 :      36006 : Discretization::fieldrange() const
    1094                 :            : // *****************************************************************************
    1095                 :            : //  Decide if physics time falls into a field output time range
    1096                 :            : //! \return True if physics time falls into a field output time range
    1097                 :            : // *****************************************************************************
    1098                 :            : {
    1099         [ +  + ]:      36006 :   if (g_inputdeck.get< tag::cmd, tag::benchmark >()) return false;
    1100                 :            : 
    1101                 :            :   const auto eps = std::numeric_limits< tk::real >::epsilon();
    1102                 :            : 
    1103                 :            :   bool output = false;
    1104                 :            : 
    1105                 :            :   const auto& rf = g_inputdeck.get< tag::field_output, tag::time_range >();
    1106         [ -  + ]:      29590 :   if (!rf.empty()) {
    1107 [ -  - ][ -  - ]:          0 :     if (m_t > rf[0] and m_t < rf[1])
    1108                 :          0 :       output |= std::floor(m_t/rf[2]) - m_rangeFieldFloor > eps;
    1109                 :            :   }
    1110                 :            : 
    1111                 :            :   return output;
    1112                 :            : }
    1113                 :            : 
    1114                 :            : bool
    1115                 :      42562 : Discretization::histiter() const
    1116                 :            : // *****************************************************************************
    1117                 :            : //  Decide if history output iteration count interval is hit
    1118                 :            : //! \return True if history output iteration count interval is hit
    1119                 :            : // *****************************************************************************
    1120                 :            : {
    1121                 :      42562 :   const auto hist = g_inputdeck.get< tag::history_output, tag::interval >();
    1122                 :            :   const auto& hist_points = g_inputdeck.get< tag::history_output, tag::point >();
    1123                 :            : 
    1124 [ +  + ][ -  + ]:      42562 :   return m_it % hist == 0 and not hist_points.empty();
    1125                 :            : }
    1126                 :            : 
    1127                 :            : bool
    1128                 :      42275 : Discretization::histtime() const
    1129                 :            : // *****************************************************************************
    1130                 :            : //  Decide if history output physics time interval is hit
    1131                 :            : //! \return True if history output physics time interval is hit
    1132                 :            : // *****************************************************************************
    1133                 :            : {
    1134         [ +  + ]:      42275 :   if (g_inputdeck.get< tag::cmd, tag::benchmark >()) return false;
    1135                 :            : 
    1136                 :            :   const auto eps = std::numeric_limits< tk::real >::epsilon();
    1137                 :      32355 :   const auto ht = g_inputdeck.get< tag::history_output, tag::time_interval >();
    1138                 :            : 
    1139         [ +  - ]:      32355 :   if (ht < eps) return false;
    1140                 :            : 
    1141                 :      32355 :   return std::floor(m_t/ht) - m_physHistFloor > eps;
    1142                 :            : }
    1143                 :            : 
    1144                 :            : bool
    1145                 :      42269 : Discretization::histrange() const
    1146                 :            : // *****************************************************************************
    1147                 :            : //  Decide if physics time falls into a history output time range
    1148                 :            : //! \return True if physics time falls into a history output time range
    1149                 :            : // *****************************************************************************
    1150                 :            : {
    1151         [ +  + ]:      42269 :   if (g_inputdeck.get< tag::cmd, tag::benchmark >()) return false;
    1152                 :            : 
    1153                 :            :   const auto eps = std::numeric_limits< tk::real >::epsilon();
    1154                 :            : 
    1155                 :            :   bool output = false;
    1156                 :            : 
    1157                 :            :   const auto& rh = g_inputdeck.get< tag::history_output, tag::time_range >();
    1158         [ -  + ]:      32349 :   if (!rh.empty()) {
    1159 [ -  - ][ -  - ]:          0 :     if (m_t > rh[0] and m_t < rh[1])
    1160                 :          0 :       output |= std::floor(m_t/rh[2]) - m_rangeHistFloor > eps;
    1161                 :            :   }
    1162                 :            : 
    1163                 :            :   return output;
    1164                 :            : }
    1165                 :            : 
    1166                 :            : bool
    1167                 :      50124 : Discretization::finished() const
    1168                 :            : // *****************************************************************************
    1169                 :            : //  Decide if this is the last time step
    1170                 :            : //! \return True if this is the last time step
    1171                 :            : // *****************************************************************************
    1172                 :            : {
    1173                 :            :   const auto eps = std::numeric_limits< tk::real >::epsilon();
    1174                 :      50124 :   const auto nstep = g_inputdeck.get< tag::nstep >();
    1175                 :      50124 :   const auto term = g_inputdeck.get< tag::term >();
    1176                 :            : 
    1177 [ +  + ][ +  + ]:      50124 :   return std::abs(m_t-term) < eps or m_it >= nstep;
    1178                 :            : }
    1179                 :            : 
    1180                 :            : void
    1181                 :      40348 : Discretization::status()
    1182                 :            : // *****************************************************************************
    1183                 :            : // Output one-liner status report
    1184                 :            : // *****************************************************************************
    1185                 :            : {
    1186                 :            :   // Query after how many time steps user wants TTY dump
    1187                 :      40348 :   const auto tty = g_inputdeck.get< tag::ttyi >();
    1188                 :            : 
    1189                 :            :   // estimate grind time (taken between this and the previous time step)
    1190                 :            :   using std::chrono::duration_cast;
    1191                 :            :   using ms = std::chrono::milliseconds;
    1192                 :            :   using clock = std::chrono::high_resolution_clock;
    1193                 :      40348 :   auto grind_time = duration_cast< ms >(clock::now() - m_prevstatus).count();
    1194                 :      40348 :   m_prevstatus = clock::now();
    1195                 :            : 
    1196 [ +  + ][ +  + ]:      40348 :   if (thisIndex==0 and m_meshid == 0 and not (m_it%tty)) {
                 [ +  + ]
    1197                 :            : 
    1198                 :       2214 :     const auto term = g_inputdeck.get< tag::term >();
    1199                 :       2214 :     const auto t0 = g_inputdeck.get< tag::t0 >();
    1200                 :       2214 :     const auto nstep = g_inputdeck.get< tag::nstep >();
    1201                 :       2214 :     const auto diag = g_inputdeck.get< tag::diagnostics, tag::interval >();
    1202                 :       2214 :     const auto lbfreq = g_inputdeck.get< tag::cmd, tag::lbfreq >();
    1203                 :       2214 :     const auto rsfreq = g_inputdeck.get< tag::cmd, tag::rsfreq >();
    1204                 :       2214 :     const auto verbose = g_inputdeck.get< tag::cmd, tag::verbose >();
    1205                 :       2214 :     const auto benchmark = g_inputdeck.get< tag::cmd, tag::benchmark >();
    1206         [ +  + ]:       2214 :     const auto steady = g_inputdeck.get< tag::steady_state >();
    1207                 :            : 
    1208                 :            :     // estimate time elapsed and time for accomplishment
    1209                 :            :     tk::Timer::Watch ete, eta;
    1210         [ +  + ]:       2214 :     if (not steady) m_timer.eta( term-t0, m_t-t0, nstep, m_it, ete, eta );
    1211                 :            : 
    1212                 :            :     const auto& def =
    1213                 :            :       g_inputdeck_defaults.get< tag::cmd, tag::io, tag::screen >();
    1214         [ +  - ]:       4428 :     tk::Print print( g_inputdeck.get< tag::cmd >().logname( def, m_nrestart ),
    1215                 :            :                      verbose ? std::cout : std::clog,
    1216 [ -  + ][ +  - ]:       6642 :                      std::ios_base::app );
    1217                 :            : 
    1218                 :            :     // Output one-liner
    1219                 :            :     print << std::setfill(' ') << std::setw(8) << m_it << "  "
    1220                 :            :           << std::scientific << std::setprecision(6)
    1221                 :            :           << std::setw(12) << m_t << "  "
    1222                 :            :           << m_dt << "  "
    1223                 :            :           << std::setfill('0')
    1224         [ +  - ]:       2214 :           << std::setw(3) << ete.hrs.count() << ":"
    1225         [ +  - ]:       2214 :           << std::setw(2) << ete.min.count() << ":"
    1226         [ +  - ]:       2214 :           << std::setw(2) << ete.sec.count() << "  "
    1227         [ +  - ]:       2214 :           << std::setw(3) << eta.hrs.count() << ":"
    1228         [ +  - ]:       2214 :           << std::setw(2) << eta.min.count() << ":"
    1229         [ +  - ]:       2214 :           << std::setw(2) << eta.sec.count() << "  "
    1230                 :            :           << std::scientific << std::setprecision(6) << std::setfill(' ')
    1231 [ +  - ][ +  - ]:       6642 :           << std::setw(9) << grind_time << "  ";
                 [ +  - ]
    1232                 :            : 
    1233                 :            :     // Augment one-liner status with output indicators
    1234 [ +  - ][ +  + ]:       2214 :     if (fielditer() or fieldtime() or fieldrange()) print << 'f';
         [ +  - ][ +  + ]
         [ +  - ][ -  + ]
    1235         [ +  + ]:       2214 :     if (not (m_it % diag)) print << 'd';
    1236 [ +  - ][ +  + ]:       2214 :     if (histiter() or histtime() or histrange()) print << 't';
         [ +  - ][ +  + ]
         [ +  - ][ -  + ]
    1237         [ -  + ]:       2214 :     if (m_refined) print << 'h';
    1238 [ +  + ][ +  - ]:       2214 :     if (not (m_it % lbfreq) && not finished()) print << 'l';
                 [ +  + ]
    1239 [ +  + ][ +  - ]:       2214 :     if (not benchmark && (not (m_it % rsfreq) || finished())) print << 'r';
         [ +  - ][ +  + ]
    1240                 :            : 
    1241         [ +  + ]:       2214 :     if (not m_meshvel_converged) print << 'a';
    1242         [ +  - ]:       2214 :     m_meshvel_converged = true; // get ready for next time step
    1243                 :            : 
    1244                 :            :     print << std::endl;
    1245                 :            :   }
    1246                 :      40348 : }
    1247                 :            : 
    1248                 :            : #include "NoWarning/discretization.def.h"

Generated by: LCOV version 1.14