Quinoa all test code coverage report
Current view: top level - Inciter - Transporter.cpp (source / functions) Hit Total Coverage
Commit: -128-NOTFOUND Lines: 702 756 92.9 %
Date: 2025-12-08 20:34:58 Functions: 44 46 95.7 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 822 1652 49.8 %

           Branch data     Line data    Source code
       1                 :            : // *****************************************************************************
       2                 :            : /*!
       3                 :            :   \file      src/Inciter/Transporter.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                 :            :   \brief     Transporter drives the time integration of transport equations
       9                 :            :   \details   Transporter drives the time integration of transport equations.
      10                 :            :     The implementation uses the Charm++ runtime system and is fully asynchronous,
      11                 :            :     overlapping computation, communication as well as I/O. The algorithm
      12                 :            :     utilizes the structured dagger (SDAG) Charm++ functionality. The high-level
      13                 :            :     overview of the algorithm structure and how it interfaces with Charm++ is
      14                 :            :     discussed in the Charm++ interface file src/Inciter/transporter.ci.
      15                 :            : */
      16                 :            : // *****************************************************************************
      17                 :            : 
      18                 :            : #include <string>
      19                 :            : #include <iostream>
      20                 :            : #include <cstddef>
      21                 :            : #include <unordered_set>
      22                 :            : #include <limits>
      23                 :            : #include <cmath>
      24                 :            : 
      25                 :            : #include <brigand/algorithms/for_each.hpp>
      26                 :            : 
      27                 :            : #include "Macro.hpp"
      28                 :            : #include "Transporter.hpp"
      29                 :            : #include "Fields.hpp"
      30                 :            : #include "PDEStack.hpp"
      31                 :            : #include "UniPDF.hpp"
      32                 :            : #include "PDFWriter.hpp"
      33                 :            : #include "ContainerUtil.hpp"
      34                 :            : #include "LoadDistributor.hpp"
      35                 :            : #include "MeshReader.hpp"
      36                 :            : #include "Inciter/InputDeck/InputDeck.hpp"
      37                 :            : #include "NodeDiagnostics.hpp"
      38                 :            : #include "ElemDiagnostics.hpp"
      39                 :            : #include "DiagWriter.hpp"
      40                 :            : #include "Callback.hpp"
      41                 :            : #include "CartesianProduct.hpp"
      42                 :            : 
      43                 :            : #include "NoWarning/inciter.decl.h"
      44                 :            : #include "NoWarning/partitioner.decl.h"
      45                 :            : 
      46                 :            : extern CProxy_Main mainProxy;
      47                 :            : 
      48                 :            : namespace inciter {
      49                 :            : 
      50                 :            : extern ctr::InputDeck g_inputdeck_defaults;
      51                 :            : extern ctr::InputDeck g_inputdeck;
      52                 :            : extern std::vector< CGPDE > g_cgpde;
      53                 :            : extern std::vector< DGPDE > g_dgpde;
      54                 :            : extern std::vector< FVPDE > g_fvpde;
      55                 :            : 
      56                 :            : }
      57                 :            : 
      58                 :            : using inciter::Transporter;
      59                 :            : 
      60                 :        171 : Transporter::Transporter() :
      61                 :            :   m_input( input() ),
      62                 :            :   m_nchare( m_input.size() ),
      63                 :            :   m_meshid(),
      64                 :          0 :   m_ncit( m_nchare.size(), 0 ),
      65                 :            :   m_nload( 0 ),
      66                 :            :   m_ntrans( 0 ),
      67                 :            :   m_ndtmsh( 0 ),
      68                 :            :   m_dtmsh(),
      69                 :            :   m_npart( 0 ),
      70                 :            :   m_nstat( 0 ),
      71                 :            :   m_ndisc( 0 ),
      72                 :            :   m_nchk( 0 ),
      73                 :            :   m_ncom( 0 ),
      74                 :          0 :   m_nt0refit( m_nchare.size(), 0 ),
      75                 :          0 :   m_ndtrefit( m_nchare.size(), 0 ),
      76                 :          0 :   m_noutrefit( m_nchare.size(), 0 ),
      77                 :          0 :   m_noutderefit( m_nchare.size(), 0 ),
      78                 :            :   m_scheme(),
      79                 :            :   m_partitioner(),
      80                 :            :   m_refiner(),
      81                 :            :   m_meshwriter(),
      82                 :            :   m_sorter(),
      83                 :            :   m_nelem( m_nchare.size() ),
      84                 :            :   m_npoin(),
      85                 :          0 :   m_finished( m_nchare.size(), 0 ),
      86                 :            :   m_meshvol( m_nchare.size() ),
      87                 :            :   m_minstat( m_nchare.size() ),
      88                 :            :   m_maxstat( m_nchare.size() ),
      89                 :            :   m_avgstat( m_nchare.size() ),
      90                 :            :   m_timer(),
      91                 :        342 :   m_progMesh( g_inputdeck.get< tag::cmd, tag::feedback >(),
      92                 :            :               ProgMeshPrefix, ProgMeshLegend ),
      93                 :        171 :   m_progWork( g_inputdeck.get< tag::cmd, tag::feedback >(),
      94 [ +  - ][ +  - ]:       1026 :               ProgWorkPrefix, ProgWorkLegend )
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  + ][ +  - ]
      95                 :            : // *****************************************************************************
      96                 :            : //  Constructor
      97                 :            : // *****************************************************************************
      98                 :            : {
      99                 :            :   // Echo configuration to screen
     100 [ +  - ][ +  - ]:        171 :   info( printer() );
     101                 :            : 
     102                 :        171 :   const auto nstep = g_inputdeck.get< tag::nstep >();
     103                 :        171 :   const auto t0 = g_inputdeck.get< tag::t0 >();
     104                 :        171 :   const auto term = g_inputdeck.get< tag::term >();
     105                 :        171 :   const auto constdt = g_inputdeck.get< tag::dt >();
     106                 :            : 
     107                 :            :   // If the desired max number of time steps is larger than zero, and the
     108                 :            :   // termination time is larger than the initial time, and the constant time
     109                 :            :   // step size (if that is used) is smaller than the duration of the time to be
     110                 :            :   // simulated, we have work to do, otherwise, finish right away. If a constant
     111                 :            :   // dt is not used, that part of the logic is always true as the default
     112                 :            :   // constdt is zero, see inciter::ctr::InputDeck::InputDeck().
     113 [ +  - ][ +  - ]:        171 :   if ( nstep != 0 && term > t0 && constdt < term-t0 ) {
                 [ +  - ]
     114                 :            : 
     115                 :            :     // Enable SDAG waits for collecting mesh statistics
     116         [ +  - ]:        171 :     thisProxy.wait4stat();
     117                 :            : 
     118                 :            :     // Configure and write diagnostics file header
     119         [ +  - ]:        171 :     diagHeader();
     120                 :            : 
     121                 :            :     // Create mesh partitioner AND boundary condition object group
     122         [ +  - ]:        171 :     createPartitioner();
     123                 :            : 
     124         [ -  - ]:          0 :   } else finish();      // stop if no time stepping requested
     125                 :        171 : }
     126                 :            : 
     127                 :          2 : Transporter::Transporter( CkMigrateMessage* m ) :
     128                 :            :   CBase_Transporter( m ),
     129                 :          4 :   m_progMesh( g_inputdeck.get< tag::cmd, tag::feedback >(),
     130                 :            :               ProgMeshPrefix, ProgMeshLegend ),
     131                 :          2 :   m_progWork( g_inputdeck.get< tag::cmd, tag::feedback >(),
     132 [ +  - ][ +  + ]:         12 :               ProgWorkPrefix, ProgWorkLegend )
                 [ +  - ]
     133                 :            : // *****************************************************************************
     134                 :            : //  Migrate constructor: returning from a checkpoint
     135                 :            : //! \param[in] m Charm++ migrate message
     136                 :            : // *****************************************************************************
     137                 :            : {
     138         [ +  - ]:          4 :    auto print = printer();
     139 [ +  - ][ +  - ]:          2 :    print.diag( "Restarted from checkpoint" );
     140         [ +  - ]:          2 :    info( print );
     141         [ +  - ]:          2 :    inthead( print );
     142                 :          2 : }
     143                 :            : 
     144                 :            : std::vector< std::string >
     145                 :        171 : Transporter::input()
     146                 :            : // *****************************************************************************
     147                 :            : // Generate list of input mesh filenames configured by the user
     148                 :            : //! \return List of input mesh filenames configured by the user
     149                 :            : //! \details If the input file is given on the command line, a single solver
     150                 :            : //!   will be instantiated on the single mesh, solving potentially multiple
     151                 :            : //!   systems of (potentially coupled) equations. If the input file is not given
     152                 :            : //!   on the command line, the mesh files are expected to be configured in the
     153                 :            : //!   control/input file, associating a potentially different mesh to each
     154                 :            : //!   solver. Both configurations allow the solution of coupled systems, but the
     155                 :            : //!   first one solves all equations on the same mesh, while the latter can
     156                 :            : //!   couple solutions computed on multiple different meshes.
     157                 :            : // *****************************************************************************
     158                 :            : {
     159                 :            :   // Query input mesh filename specified on the command line
     160                 :        171 :   const auto& cmdinput = g_inputdeck.get< tag::cmd, tag::io, tag::input >();
     161                 :            : 
     162                 :            :   // Extract mesh filenames specified in the control file (assigned to solvers)
     163                 :        342 :   std::vector< std::string > ctrinput;
     164         [ +  + ]:        343 :   for (const auto& im : g_inputdeck.get< tag::mesh >()) {
     165         [ +  - ]:        172 :     ctrinput.push_back(im.get< tag::filename >());
     166                 :            :   }
     167                 :            : 
     168 [ +  + ][ -  + ]:        171 :   ErrChk( not cmdinput.empty() or not ctrinput.empty(),
         [ -  - ][ -  - ]
                 [ -  - ]
     169                 :            :     "Either a single input mesh must be given on the command line or multiple "
     170                 :            :     "meshes must be configured in the control file." );
     171                 :            : 
     172                 :            :    // Prepend control file path to mesh filenames in given in control file
     173         [ +  - ]:        171 :   if (not ctrinput.empty()) {
     174                 :        171 :      const auto& ctr = g_inputdeck.get< tag::cmd, tag::io, tag::control >();
     175         [ +  - ]:        342 :      auto path = ctr.substr( 0, ctr.find_last_of("/")+1 );
     176 [ +  + ][ +  - ]:        343 :      for (auto& f : ctrinput) f = path + f;
     177                 :            :   }
     178                 :            : 
     179 [ +  + ][ +  - ]:        333 :   if (cmdinput.empty()) return ctrinput; else return { cmdinput };
         [ +  - ][ +  + ]
                 [ -  - ]
     180                 :            : }
     181                 :            : 
     182                 :            : void
     183                 :        173 : Transporter::info( const InciterPrint& print )
     184                 :            : // *****************************************************************************
     185                 :            : // Echo configuration to screen
     186                 :            : //! \param[in] print Pretty printer object to use for printing
     187                 :            : // *****************************************************************************
     188                 :            : {
     189 [ +  - ][ +  - ]:        173 :   print.part( "Factory" );
     190                 :            : 
     191                 :            :   // Print out info data layout
     192 [ +  - ][ +  - ]:        173 :   print.list( "Unknowns data layout (CMake: FIELD_DATA_LAYOUT)",
     193 [ +  - ][ +  - ]:        519 :               std::list< std::string >{ tk::Fields::layout() } );
         [ +  + ][ -  - ]
     194                 :            : 
     195                 :            :   // Re-create partial differential equations stack for output
     196         [ +  - ]:        346 :   PDEStack stack;
     197                 :            : 
     198                 :            :   // Print out information on PDE factories
     199 [ +  - ][ +  - ]:        346 :   print.eqlist( "Registered PDEs using continuous Galerkin (CG) methods",
     200                 :        173 :                 stack.cgfactory(), stack.cgntypes() );
     201 [ +  - ][ +  - ]:        346 :   print.eqlist( "Registered PDEs using discontinuous Galerkin (DG) methods",
     202                 :        173 :                 stack.dgfactory(), stack.dgntypes() );
     203 [ +  - ][ +  - ]:        346 :   print.eqlist( "Registered PDEs using finite volume (DG) methods",
     204                 :        173 :                 stack.fvfactory(), stack.fvntypes() );
     205         [ +  - ]:        173 :   print.endpart();
     206                 :            : 
     207                 :            :   // Print out information on problem
     208 [ +  - ][ +  - ]:        173 :   print.part( "Problem" );
     209                 :            : 
     210                 :            :   // Print out info on problem title
     211         [ +  - ]:        173 :   if ( !g_inputdeck.get< tag::title >().empty() )
     212         [ +  - ]:        173 :     print.title( g_inputdeck.get< tag::title >() );
     213                 :            : 
     214                 :        173 :   const auto nstep = g_inputdeck.get< tag::nstep >();
     215                 :        173 :   const auto t0 = g_inputdeck.get< tag::t0 >();
     216                 :        173 :   const auto term = g_inputdeck.get< tag::term >();
     217                 :        173 :   const auto constdt = g_inputdeck.get< tag::dt >();
     218                 :        173 :   const auto cfl = g_inputdeck.get< tag::cfl >();
     219                 :        173 :   const auto scheme = g_inputdeck.get< tag::scheme >();
     220                 :            : 
     221                 :            :   // Print discretization parameters
     222 [ +  - ][ +  - ]:        173 :   print.section( "Discretization parameters" );
     223         [ +  - ]:        173 :   print.Item< ctr::Scheme, tag::scheme >();
     224 [ +  - ][ +  - ]:        173 :   print.item( "Implicit-Explicit Runge-Kutta",
     225                 :        173 :               g_inputdeck.get< tag::imex_runge_kutta >() );
     226                 :            : 
     227 [ +  - ][ +  + ]:        173 :   if (g_inputdeck.centering() == tk::Centering::ELEM)
     228                 :            :   {
     229         [ +  - ]:         97 :     print.Item< ctr::Limiter, tag::limiter >();
     230                 :            : 
     231 [ +  - ][ +  - ]:         97 :     print.item("Shock detection based limiting",
     232                 :         97 :       g_inputdeck.get< tag::shock_detector_coeff >());
     233                 :            : 
     234         [ -  + ]:         97 :     if (g_inputdeck.get< tag::accuracy_test >())
     235                 :            :     {
     236 [ -  - ][ -  - ]:          0 :       print.item("WARNING: order-of-accuracy testing enabled",
     237                 :            :         "robustness corrections inactive");
     238                 :            :     }
     239                 :            : 
     240 [ +  - ][ +  - ]:         97 :     print.item("Limited solution projection",
     241                 :         97 :       g_inputdeck.get< tag::limsol_projection >());
     242                 :            :   }
     243 [ +  - ][ +  - ]:        173 :   print.item( "PE-locality mesh reordering",
     244                 :        173 :               g_inputdeck.get< tag::pelocal_reorder >() );
     245 [ +  - ][ +  - ]:        173 :   print.item( "Operator-access mesh reordering",
     246                 :        173 :               g_inputdeck.get< tag::operator_reorder >() );
     247                 :        173 :   auto steady = g_inputdeck.get< tag::steady_state >();
     248 [ +  - ][ +  - ]:        173 :   print.item( "Local time stepping", steady );
     249                 :        173 :   auto implicitts = g_inputdeck.get< tag::implicit_timestepping >();
     250 [ +  - ][ +  - ]:        173 :   print.item( "Implicit time stepping", implicitts );
     251 [ +  + ][ -  + ]:        173 :   if (steady || implicitts) {
     252 [ +  - ][ +  - ]:          2 :     print.item( "L2-norm residual convergence criterion",
     253                 :          2 :                 g_inputdeck.get< tag::residual >() );
     254 [ +  - ][ +  - ]:          2 :     print.item( "Convergence criterion component index",
     255                 :          2 :                 g_inputdeck.get< tag::rescomp >() );
     256                 :            :   }
     257 [ +  - ][ +  - ]:        173 :   print.item( "Number of time steps", nstep );
     258 [ +  - ][ +  - ]:        173 :   print.item( "Start time", t0 );
     259 [ +  - ][ +  - ]:        173 :   print.item( "Terminate time", term );
     260                 :            : 
     261         [ +  + ]:        173 :   if (constdt > std::numeric_limits< tk::real >::epsilon())
     262 [ +  - ][ +  - ]:        106 :     print.item( "Constant time step size", constdt );
     263         [ +  - ]:         67 :   else if (cfl > std::numeric_limits< tk::real >::epsilon())
     264                 :            :   {
     265 [ +  - ][ +  - ]:         67 :     print.item( "CFL coefficient", cfl );
     266                 :            :   }
     267                 :            : 
     268                 :        173 :   const auto& meshes = g_inputdeck.get< tag::mesh >();
     269                 :        173 :   const auto& depvars = g_inputdeck.get< tag::depvar >();
     270         [ +  + ]:        347 :   for (std::size_t i=0; i<meshes.size(); ++i) {
     271 [ +  - ][ +  - ]:        522 :     print.item( "Dependent var name and assoc. mesh", std::string{depvars[i]}
                 [ +  - ]
     272 [ +  - ][ +  - ]:        522 :       + " - " + meshes[i].get< tag::filename >() );
     273                 :            :   }
     274                 :            : 
     275                 :        173 :   const auto& rbmotion = g_inputdeck.get< tag::rigid_body_motion >();
     276         [ -  + ]:        173 :   if (rbmotion.get< tag::rigid_body_movt >()) {
     277                 :          0 :     const auto& rbdof = rbmotion.get< tag::rigid_body_dof >();
     278 [ -  - ][ -  - ]:          0 :     print.item( "Rigid body motion DOF", rbdof );
     279         [ -  - ]:          0 :     if (rbdof == 3)
     280 [ -  - ][ -  - ]:          0 :       print.item( "Rigid body 3-DOF symmetry plane",
     281                 :            :         rbmotion.get< tag::symmetry_plane >() );
     282                 :            :   }
     283                 :            : 
     284                 :            :   // Print out info on settings of selected partial differential equations
     285 [ +  - ][ +  - ]:        173 :   print.pdes( "Partial differential equations integrated", stack.info() );
                 [ +  - ]
     286                 :            : 
     287                 :            :   // Print out adaptive polynomial refinement configuration
     288         [ +  + ]:        173 :   if (scheme == ctr::SchemeType::PDG) {
     289 [ +  - ][ +  - ]:         12 :     print.section( "Polynomial refinement (p-ref)" );
     290 [ +  - ][ +  - ]:         12 :     print.item( "p-refinement",
     291                 :         12 :                 g_inputdeck.get< tag::pref, tag::pref >() );
     292         [ +  - ]:         12 :     print.Item< ctr::PrefIndicator, tag::pref, tag::indicator >();
     293 [ +  - ][ +  - ]:         12 :     print.item( "Max degrees of freedom",
     294                 :         12 :                 g_inputdeck.get< tag::pref, tag::ndofmax >() );
     295 [ +  - ][ +  - ]:         12 :     print.item( "Tolerance",
     296                 :         12 :                 g_inputdeck.get< tag::pref, tag::tolref >() );
     297                 :            :   }
     298                 :            : 
     299                 :            :   // Print out adaptive mesh refinement configuration
     300                 :        173 :   const auto amr = g_inputdeck.get< tag::amr, tag::amr >();
     301         [ +  + ]:        173 :   if (amr) {
     302 [ +  - ][ +  - ]:         20 :     print.section( "Mesh refinement (h-ref)" );
     303                 :         20 :     auto maxlevels = g_inputdeck.get< tag::amr, tag::maxlevels >();
     304 [ +  - ][ +  - ]:         20 :     print.item( "Maximum mesh refinement levels", maxlevels );
     305         [ +  - ]:         20 :     print.Item< ctr::AMRError, tag::amr, tag::error >();
     306                 :         20 :     auto t0ref = g_inputdeck.get< tag::amr, tag::t0ref >();
     307 [ +  - ][ +  - ]:         20 :     print.item( "Refinement at t<0 (t0ref)", t0ref );
     308         [ +  - ]:         20 :     if (t0ref) {
     309                 :         20 :       const auto& initref = g_inputdeck.get< tag::amr, tag::initial >();
     310 [ +  - ][ +  - ]:         20 :       print.item( "Initial refinement steps", initref.size() );
     311                 :            : 
     312                 :         20 :       auto eps = std::numeric_limits< tk::real >::epsilon();
     313                 :            : 
     314                 :         20 :       const auto& amr_coord = g_inputdeck.get< tag::amr, tag::coords >();
     315                 :         20 :       const auto& amr_defcoord = g_inputdeck_defaults.get< tag::amr, tag::coords >();
     316                 :            : 
     317                 :         20 :       auto xminus = amr_coord.get< tag::xminus >();
     318                 :         20 :       auto xminus_default = amr_defcoord.get< tag::xminus >();
     319         [ +  + ]:         20 :       if (std::abs( xminus - xminus_default ) > eps)
     320 [ +  - ][ +  - ]:          1 :         print.item( "Initial refinement x-", xminus );
     321                 :         20 :       auto xplus = amr_coord.get< tag::xplus >();
     322                 :         20 :       auto xplus_default = amr_defcoord.get< tag::xplus >();
     323         [ -  + ]:         20 :       if (std::abs( xplus - xplus_default ) > eps)
     324 [ -  - ][ -  - ]:          0 :         print.item( "Initial refinement x+", xplus );
     325                 :            : 
     326                 :         20 :       auto yminus = amr_coord.get< tag::yminus >();
     327                 :         20 :       auto yminus_default = amr_defcoord.get< tag::yminus >();
     328         [ -  + ]:         20 :       if (std::abs( yminus - yminus_default ) > eps)
     329 [ -  - ][ -  - ]:          0 :         print.item( "Initial refinement y-", yminus );
     330                 :         20 :       auto yplus = amr_coord.get< tag::yplus >();
     331                 :         20 :       auto yplus_default = amr_defcoord.get< tag::yplus >();
     332         [ -  + ]:         20 :       if (std::abs( yplus - yplus_default ) > eps)
     333 [ -  - ][ -  - ]:          0 :         print.item( "Initial refinement y+", yplus );
     334                 :            : 
     335                 :         20 :       auto zminus = amr_coord.get< tag::zminus >();
     336                 :         20 :       auto zminus_default = amr_defcoord.get< tag::zminus >();
     337         [ -  + ]:         20 :       if (std::abs( zminus - zminus_default ) > eps)
     338 [ -  - ][ -  - ]:          0 :         print.item( "Initial refinement z-", zminus );
     339                 :         20 :       auto zplus = amr_coord.get< tag::zplus >();
     340                 :         20 :       auto zplus_default = amr_defcoord.get< tag::zplus >();
     341         [ -  + ]:         20 :       if (std::abs( zplus - zplus_default ) > eps)
     342 [ -  - ][ -  - ]:          0 :         print.item( "Initial refinement z+", zplus );
     343                 :            :     }
     344                 :         20 :     auto dtref = g_inputdeck.get< tag::amr, tag::dtref >();
     345 [ +  - ][ +  - ]:         20 :     print.item( "Refinement at t>0 (dtref)", dtref );
     346         [ -  + ]:         20 :     if (dtref) {
     347                 :          0 :       auto dtfreq = g_inputdeck.get< tag::amr, tag::dtfreq >();
     348 [ -  - ][ -  - ]:          0 :       print.item( "Mesh refinement frequency, t>0", dtfreq );
     349 [ -  - ][ -  - ]:          0 :       print.item( "Uniform-only mesh refinement, t>0",
     350                 :          0 :                   g_inputdeck.get< tag::amr, tag::dtref_uniform >() );
     351                 :            :     }
     352 [ +  - ][ +  - ]:         20 :     print.item( "Refinement tolerance",
     353                 :         20 :                 g_inputdeck.get< tag::amr, tag::tol_refine >() );
     354 [ +  - ][ +  - ]:         20 :     print.item( "De-refinement tolerance",
     355                 :         20 :                 g_inputdeck.get< tag::amr, tag::tol_derefine >() );
     356                 :            :   }
     357                 :            : 
     358                 :            :   // Print out ALE configuration
     359                 :        173 :   const auto ale = g_inputdeck.get< tag::ale, tag::ale >();
     360         [ +  + ]:        173 :   if (ale) {
     361 [ +  - ][ +  - ]:         10 :     print.section( "Arbitrary Lagrangian-Eulerian (ALE) mesh motion" );
     362                 :         10 :     auto dvcfl = g_inputdeck.get< tag::ale, tag::dvcfl >();
     363 [ +  - ][ +  - ]:         10 :     print.item( "Volume-change CFL coefficient", dvcfl );
     364         [ +  - ]:         10 :     print.Item< ctr::MeshVelocity, tag::ale, tag::mesh_velocity >();
     365         [ +  - ]:         10 :     print.Item< ctr::MeshVelocitySmoother, tag::ale, tag::smoother >();
     366 [ +  - ][ +  - ]:         10 :     print.item( "Mesh motion dimensions", tk::parameters(
                 [ +  - ]
     367                 :         10 :                 g_inputdeck.get< tag::ale, tag::mesh_motion >() ) );
     368                 :         10 :     const auto& meshforce = g_inputdeck.get< tag::ale, tag::meshforce >();
     369 [ +  - ][ +  - ]:         10 :     print.item( "Mesh velocity force coefficients", tk::parameters(meshforce) );
                 [ +  - ]
     370 [ +  - ][ +  - ]:         10 :     print.item( "Vorticity multiplier",
     371                 :         10 :                 g_inputdeck.get< tag::ale, tag::vortmult >() );
     372 [ +  - ][ +  - ]:         10 :     print.item( "Mesh velocity linear solver tolerance",
     373                 :         10 :                 g_inputdeck.get< tag::ale, tag::tolerance >() );
     374 [ +  - ][ +  - ]:         10 :     print.item( "Mesh velocity linear solver maxit",
     375                 :         10 :                 g_inputdeck.get< tag::ale, tag::maxit >() );
     376                 :         10 :     const auto& dir = g_inputdeck.get< tag::ale, tag::dirichlet >();
     377         [ +  + ]:         10 :     if (not dir.empty())
     378 [ +  - ][ +  - ]:          5 :       print.item( "Mesh velocity Dirichlet BC sideset(s)",
     379         [ +  - ]:         10 :                   tk::parameters( dir ) );
     380                 :         10 :     const auto& sym = g_inputdeck.get< tag::ale, tag::symmetry >();
     381         [ +  + ]:         10 :     if (not sym.empty())
     382 [ +  - ][ +  - ]:          3 :       print.item( "Mesh velocity symmetry BC sideset(s)",
     383         [ +  - ]:          6 :                   tk::parameters( sym ) );
     384                 :         10 :     std::size_t i = 1;
     385         [ +  + ]:         12 :     for (const auto& m : g_inputdeck.get< tag::ale, tag::move >()) {
     386         [ +  - ]:          2 :        tk::ctr::UserTable opt;
     387 [ +  - ][ +  - ]:          2 :        print.item( opt.group() + ' ' + std::to_string(i) + " interpreted as",
         [ +  - ][ +  - ]
     388 [ +  - ][ +  - ]:          2 :                    opt.name( m.get< tag::fntype >() ) );
     389                 :          2 :        const auto& s = m.get< tag::sideset >();
     390         [ +  - ]:          2 :        if (not s.empty())
     391 [ +  - ][ +  - ]:          2 :          print.item( "Moving sideset(s) with table " + std::to_string(i),
                 [ +  - ]
     392         [ +  - ]:          4 :                      tk::parameters(s));
     393                 :          2 :        ++i;
     394                 :            :     }
     395                 :            :   }
     396                 :            : 
     397                 :            :   // Print I/O filenames
     398 [ +  - ][ +  - ]:        173 :   print.section( "Input/Output filenames and directories" );
     399 [ +  - ][ +  - ]:        173 :   print.item( "Input mesh(es)", tk::parameters( m_input ) );
                 [ +  - ]
     400                 :        173 :   const auto& of = g_inputdeck.get< tag::cmd, tag::io, tag::output >();
     401 [ +  - ][ +  - ]:        173 :   print.item( "Volume field output file(s)",
     402         [ +  - ]:        346 :               of + ".e-s.<meshid>.<numchares>.<chareid>" );
     403 [ +  - ][ +  - ]:        173 :   print.item( "Surface field output file(s)",
     404         [ +  - ]:        346 :               of + "-surf.<surfid>.e-s.<meshid>.<numchares>.<chareid>" );
     405 [ +  - ][ +  - ]:        173 :   print.item( "History output file(s)", of + ".hist.{pointid}" );
                 [ +  - ]
     406 [ +  - ][ +  - ]:        173 :   print.item( "Diagnostics file",
     407                 :        173 :               g_inputdeck.get< tag::cmd, tag::io, tag::diag >() );
     408 [ +  - ][ +  - ]:        173 :   print.item( "Checkpoint/restart directory",
     409         [ +  - ]:        346 :               g_inputdeck.get< tag::cmd, tag::io, tag::restart >() + '/' );
     410                 :            : 
     411                 :            :   // Print output intervals
     412 [ +  - ][ +  - ]:        173 :   print.section( "Output intervals (in units of iteration count)" );
     413 [ +  - ][ +  - ]:        173 :   print.item( "TTY", g_inputdeck.get< tag::ttyi>() );
     414 [ +  - ][ +  - ]:        173 :   print.item( "Field and surface",
     415                 :        173 :               g_inputdeck.get< tag::field_output, tag::interval >() );
     416 [ +  - ][ +  - ]:        173 :   print.item( "History",
     417                 :        173 :               g_inputdeck.get< tag::history_output, tag::interval >() );
     418 [ +  - ][ +  - ]:        173 :   print.item( "Diagnostics",
     419                 :        173 :               g_inputdeck.get< tag::diagnostics, tag::interval >() );
     420 [ +  - ][ +  - ]:        173 :   print.item( "Checkpoint/restart",
     421                 :        173 :               g_inputdeck.get< tag::cmd, tag::rsfreq >() );
     422                 :        173 :   auto tf = g_inputdeck.get< tag::field_output, tag::time_interval >();
     423                 :        173 :   auto th = g_inputdeck.get< tag::history_output, tag::time_interval >();
     424 [ -  + ][ -  - ]:        173 :   if (tf>0.0 || th>0.0) {
     425 [ +  - ][ +  - ]:        173 :     print.section( "Output intervals (in units of physics time)" );
     426 [ +  - ][ +  - ]:        173 :     if (tf > 0.0) print.item( "Field and surface", tf );
                 [ +  - ]
     427 [ +  - ][ +  - ]:        173 :     if (th > 0.0) print.item( "History", th );
                 [ +  - ]
     428                 :            :   }
     429                 :        173 :   const auto& rf = g_inputdeck.get< tag::field_output, tag::time_range >();
     430                 :        173 :   const auto& rh = g_inputdeck.get< tag::history_output, tag::time_range >();
     431 [ +  - ][ -  + ]:        173 :   if (not rf.empty() or not rh.empty()) {
                 [ -  + ]
     432 [ -  - ][ -  - ]:          0 :     print.section( "Output time ranges (in units of physics time)" );
     433 [ -  - ][ -  - ]:          0 :     print.item("Field output { mintime, maxtime, dt }", tk::parameters(rf));
                 [ -  - ]
     434 [ -  - ][ -  - ]:          0 :     print.item("History output { mintime, maxtime, dt }", tk::parameters(rh));
                 [ -  - ]
     435                 :            :   }
     436                 :            : 
     437                 :            :   //// Print output variables: fields and surfaces
     438                 :            :   //const auto nodeoutvars = g_inputdeck.outvars( tk::Centering::NODE );
     439                 :            :   //const auto elemoutvars = g_inputdeck.outvars( tk::Centering::ELEM );
     440                 :            :   //const auto outsets = g_inputdeck.outsets();
     441                 :            :   //if (!nodeoutvars.empty() || !elemoutvars.empty() || !outsets.empty())
     442                 :            :   //   print.section( "Output fields" );
     443                 :            :   //if (!nodeoutvars.empty())
     444                 :            :   //  print.item( "Node field(s)", tk::parameters(nodeoutvars) );
     445                 :            :   //if (!elemoutvars.empty())
     446                 :            :   //  print.item( "Elem field(s)", tk::parameters(elemoutvars) );
     447                 :            :   //if (!aliases.empty())
     448                 :            :   //  print.item( "Alias(es)", tk::parameters(aliases) );
     449                 :            :   //if (!outsets.empty())
     450                 :            :   //  print.item( "Surface side set(s)", tk::parameters(outsets) );
     451                 :            : 
     452                 :            :   // Print output variables: history
     453                 :        173 :   const auto& pt = g_inputdeck.get< tag::history_output, tag::point >();
     454         [ +  + ]:        173 :   if (!pt.empty()) {
     455 [ +  - ][ +  - ]:          4 :     print.section( "Output time history" );
     456         [ +  + ]:         12 :     for (std::size_t p=0; p<pt.size(); ++p) {
     457                 :          8 :       const auto& id = pt[p].get< tag::id >();
     458         [ +  - ]:          8 :       std::stringstream ss;
     459                 :          8 :       auto prec = g_inputdeck.get< tag::history_output, tag::precision >();
     460         [ +  - ]:          8 :       ss << std::setprecision( static_cast<int>(prec) );
     461 [ +  - ][ +  - ]:          8 :       ss << of << ".hist." << id;
                 [ +  - ]
     462 [ +  - ][ +  - ]:          8 :       print.longitem( "At point " + id + ' ' +
         [ +  - ][ +  - ]
     463 [ +  - ][ +  - ]:         16 :         tk::parameters(pt[p].get<tag::coord>()), ss.str() );
     464                 :            :     }
     465                 :            :   }
     466                 :            : 
     467         [ +  - ]:        173 :   print.endsubsection();
     468                 :        173 : }
     469                 :            : 
     470                 :            : bool
     471                 :        249 : Transporter::matchBCs( std::map< int, std::vector< std::size_t > >& bnd )
     472                 :            : // *****************************************************************************
     473                 :            :  // Verify that side sets specified in the control file exist in mesh file
     474                 :            :  //! \details This function does two things: (1) it verifies that the side
     475                 :            :  //!   sets used in the input file (either to which boundary conditions (BC)
     476                 :            :  //!   are assigned or listed as field output by the user in the
     477                 :            :  //!   input file) all exist among the side sets read from the input mesh
     478                 :            :  //!   file and errors out if at least one does not, and (2) it matches the
     479                 :            :  //!   side set ids at which the user has configured BCs (or listed as an output
     480                 :            :  //!   surface) to side set ids read from the mesh file and removes those face
     481                 :            :  //!   and node lists associated to side sets that the user did not set BCs or
     482                 :            :  //!   listed as field output on (as they will not need processing further since
     483                 :            :  //!   they will not be used).
     484                 :            :  //! \param[in,out] bnd Node or face lists mapped to side set ids
     485                 :            :  //! \return True if sidesets have been used and found in mesh
     486                 :            : // *****************************************************************************
     487                 :            : {
     488                 :            :   // Query side set ids at which BCs assigned for all BC types for all PDEs
     489                 :        498 :   std::unordered_set< int > usedsets;
     490                 :            : 
     491                 :            :   using bclist = ctr::bclist::Keys;
     492                 :        249 :   const auto& bcs = g_inputdeck.get< tag::bc >();
     493         [ +  - ]:        249 :   brigand::for_each< bclist >( UserBC( g_inputdeck, usedsets ) );
     494                 :            : 
     495                 :            :   // Query side sets of time dependent and inlet BCs (since these are not a part
     496                 :            :   // of tag::bc)
     497         [ +  + ]:        502 :   for (const auto& bci : bcs) {
     498         [ +  + ]:        260 :     for (const auto& b : bci.get< tag::inlet >()) {
     499         [ +  + ]:         14 :       for (auto i : b.get< tag::sideset >())
     500         [ +  - ]:          7 :         usedsets.insert(static_cast<int>(i));
     501                 :            :     }
     502         [ +  + ]:        257 :     for (const auto& b : bci.get< tag::timedep >()) {
     503         [ +  + ]:          8 :       for (auto i : b.get< tag::sideset >())
     504         [ +  - ]:          4 :         usedsets.insert(static_cast<int>(i));
     505                 :            :     }
     506                 :        253 :     const auto& bp = bci.get< tag::back_pressure >();
     507         [ -  + ]:        253 :     for (auto i : bp.get< tag::sideset >())
     508         [ -  - ]:          0 :       usedsets.insert(static_cast<int>(i));
     509                 :            :   }
     510                 :            : 
     511                 :            :   // Query side sets of boundaries prescribed as moving with ALE
     512         [ +  + ]:        253 :   for (const auto& move : g_inputdeck.get< tag::ale, tag::move >())
     513         [ +  + ]:          8 :     for (auto i : move.get< tag::sideset >())
     514         [ +  - ]:          4 :       usedsets.insert(static_cast<int>(i));
     515                 :            : 
     516                 :            :   // Add sidesets requested for field output
     517                 :        249 :   const auto& ss = g_inputdeck.get< tag::cmd, tag::io, tag::surface >();
     518         [ -  + ]:        249 :   for (const auto& s : ss) {
     519         [ -  - ]:          0 :     std::stringstream conv( s );
     520                 :            :     int num;
     521         [ -  - ]:          0 :     conv >> num;
     522         [ -  - ]:          0 :     usedsets.insert( num );
     523                 :            :   }
     524                 :            : 
     525                 :            :   // Find user-configured side set ids among side sets read from mesh file
     526                 :        249 :   std::unordered_set< int > sidesets_used;
     527         [ +  + ]:       1506 :   for (auto i : usedsets) {       // for all side sets used in control file
     528 [ +  - ][ +  + ]:       1257 :     if (bnd.find(i) != end(bnd))  // used set found among side sets in file
     529         [ +  - ]:       1243 :       sidesets_used.insert( i );  // store side set id configured as BC
     530                 :            :     //else {
     531                 :            :     //  Throw( "Boundary conditions specified on side set " +
     532                 :            :     //    std::to_string(i) + " which does not exist in mesh file" );
     533                 :            :     //}
     534                 :            :   }
     535                 :            : 
     536                 :            :   // Remove sidesets not used (will not process those further)
     537         [ +  - ]:        249 :   tk::erase_if( bnd, [&]( auto& item ) {
     538         [ +  - ]:       1293 :     return sidesets_used.find( item.first ) == end(sidesets_used);
     539                 :            :   });
     540                 :            : 
     541                 :        498 :   return !bnd.empty();
     542                 :            : }
     543                 :            : 
     544                 :            : void
     545                 :        171 : Transporter::createPartitioner()
     546                 :            : // *****************************************************************************
     547                 :            : // Create mesh partitioner AND boundary conditions group
     548                 :            : // *****************************************************************************
     549                 :            : {
     550                 :        171 :   auto scheme = g_inputdeck.get< tag::scheme >();
     551 [ +  - ][ +  - ]:        171 :   auto centering = ctr::Scheme().centering( scheme );
     552         [ +  - ]:        342 :   auto print = printer();
     553                 :            : 
     554                 :            :   // Create partitioner callbacks (order important)
     555                 :            :   tk::PartitionerCallback cbp {{
     556 [ +  - ][ +  - ]:        171 :       CkCallback( CkReductionTarget(Transporter,load), thisProxy )
     557 [ +  - ][ +  - ]:        342 :     , CkCallback( CkReductionTarget(Transporter,partitioned), thisProxy )
     558 [ +  - ][ +  - ]:        342 :     , CkCallback( CkReductionTarget(Transporter,distributed), thisProxy )
     559 [ +  - ][ +  - ]:        342 :     , CkCallback( CkReductionTarget(Transporter,refinserted), thisProxy )
     560 [ +  - ][ +  - ]:        342 :     , CkCallback( CkReductionTarget(Transporter,refined), thisProxy )
     561         [ +  - ]:        513 :   }};
     562                 :            : 
     563                 :            :   // Create refiner callbacks (order important)
     564                 :            :   tk::RefinerCallback cbr {{
     565 [ +  - ][ +  - ]:        171 :       CkCallback( CkReductionTarget(Transporter,queriedRef), thisProxy )
     566 [ +  - ][ +  - ]:        342 :     , CkCallback( CkReductionTarget(Transporter,respondedRef), thisProxy )
     567 [ +  - ][ +  - ]:        342 :     , CkCallback( CkReductionTarget(Transporter,compatibility), thisProxy )
     568 [ +  - ][ +  - ]:        342 :     , CkCallback( CkReductionTarget(Transporter,bndint), thisProxy )
     569 [ +  - ][ +  - ]:        342 :     , CkCallback( CkReductionTarget(Transporter,matched), thisProxy )
     570 [ +  - ][ +  - ]:        342 :     , CkCallback( CkReductionTarget(Transporter,refined), thisProxy )
     571         [ +  - ]:        513 :   }};
     572                 :            : 
     573                 :            :   // Create sorter callbacks (order important)
     574                 :            :   tk::SorterCallback cbs {{
     575 [ +  - ][ +  - ]:        171 :       CkCallback( CkReductionTarget(Transporter,queried), thisProxy )
     576 [ +  - ][ +  - ]:        342 :     , CkCallback( CkReductionTarget(Transporter,responded), thisProxy )
     577 [ +  - ][ +  - ]:        342 :     , CkCallback( CkReductionTarget(Transporter,discinserted), thisProxy )
     578 [ +  - ][ +  - ]:        342 :     , CkCallback( CkReductionTarget(Transporter,workinserted), thisProxy )
     579         [ +  - ]:        513 :   }};
     580                 :            : 
     581                 :            :   // Start timer measuring preparation of mesh(es) for partitioning
     582         [ +  - ]:        171 :   m_timer[ TimerTag::MESH_READ ];
     583                 :            : 
     584                 :            :   // Start preparing mesh(es)
     585 [ +  - ][ +  - ]:        171 :   print.diag( "Reading mesh(es)" );
     586                 :            : 
     587                 :            :   // Create (discretization) Scheme chare worker arrays for all meshes
     588         [ +  + ]:        343 :   for ([[maybe_unused]] const auto& filename : m_input)
     589                 :            :     m_scheme.emplace_back( g_inputdeck.get< tag::scheme >(),
     590                 :            :                            g_inputdeck.get< tag::ale, tag::ale >(),
     591         [ +  - ]:        344 :                            need_linearsolver(),
     592                 :            :                            g_inputdeck.get< tag::implicit_timestepping >(),
     593         [ +  - ]:        344 :                            centering );
     594                 :            : 
     595 [ -  + ][ -  - ]:        171 :   ErrChk( !m_input.empty(), "No input mesh" );
         [ -  - ][ -  - ]
     596                 :            : 
     597                 :            :   // Read boundary (side set) data from a list of input mesh files
     598                 :        171 :   std::size_t meshid = 0;
     599         [ +  + ]:        343 :   for (const auto& filename : m_input) {
     600                 :            :     // Create mesh reader for reading side sets from file
     601         [ +  - ]:        344 :     tk::MeshReader mr( filename );
     602                 :            : 
     603                 :            :     // Read out total number of mesh points from mesh file
     604 [ +  - ][ +  - ]:        172 :     m_npoin.push_back( mr.npoin() );
     605                 :            : 
     606                 :        344 :     std::map< int, std::vector< std::size_t > > bface;
     607                 :        344 :     std::map< int, std::vector< std::size_t > > faces;
     608                 :        344 :     std::map< int, std::vector< std::size_t > > bnode;
     609                 :            : 
     610                 :            :     // Read boundary-face connectivity on side sets
     611         [ +  - ]:        172 :     mr.readSidesetFaces( bface, faces );
     612                 :            : 
     613                 :        172 :     bool bcs_set = false;
     614         [ +  + ]:        172 :     if (centering == tk::Centering::ELEM) {
     615                 :            : 
     616                 :            :       // Verify boundarty condition (BC) side sets used exist in mesh file
     617         [ +  - ]:         95 :       bcs_set = matchBCs( bface );
     618                 :            : 
     619         [ +  - ]:         77 :     } else if (centering == tk::Centering::NODE) {
     620                 :            : 
     621                 :            :       // Read node lists on side sets
     622         [ +  - ]:         77 :       bnode = mr.readSidesetNodes();
     623                 :            :       // Verify boundarty condition (BC) side sets used exist in mesh file
     624         [ +  - ]:         77 :       bool bcnode_set = matchBCs( bnode );
     625         [ +  - ]:         77 :       bool bcface_set = matchBCs( bface );
     626 [ +  + ][ -  + ]:         77 :       bcs_set = bcface_set or bcnode_set;
     627                 :            :     }
     628                 :            : 
     629                 :            :     // Warn on no BCs
     630 [ +  + ][ +  - ]:        172 :     if (!bcs_set) print << "\n>>> WARNING: No boundary conditions set\n\n";
     631                 :            : 
     632         [ +  - ]:        172 :     auto opt = m_scheme[meshid].arrayoptions();
     633                 :            :     // Create empty mesh refiner chare array (bound to workers)
     634 [ +  - ][ +  - ]:        172 :     m_refiner.push_back( CProxy_Refiner::ckNew(opt) );
                 [ +  - ]
     635                 :            :     // Create empty mesh sorter Charm++ chare array (bound to workers)
     636 [ +  - ][ +  - ]:        172 :     m_sorter.push_back( CProxy_Sorter::ckNew(opt) );
                 [ +  - ]
     637                 :            : 
     638                 :            :     // Create MeshWriter chare group for mesh
     639 [ +  - ][ +  - ]:        172 :     m_meshwriter.push_back(
     640                 :            :       tk::CProxy_MeshWriter::ckNew(
     641                 :        172 :         g_inputdeck.get< tag::field_output, tag::filetype >(),
     642                 :            :         centering,
     643                 :        172 :         g_inputdeck.get< tag::cmd, tag::benchmark >(),
     644                 :        172 :         m_input.size() ) );
     645                 :            : 
     646                 :            :     // Create mesh partitioner Charm++ chare nodegroup for all meshes
     647         [ +  - ]:        172 :     m_partitioner.push_back(
     648                 :            :       CProxy_Partitioner::ckNew( meshid, filename, cbp, cbr, cbs,
     649         [ +  - ]:        172 :         thisProxy, m_refiner.back(), m_sorter.back(), m_meshwriter.back(),
     650                 :        172 :         m_scheme, bface, faces, bnode ) );
     651                 :            : 
     652                 :        172 :     ++meshid;
     653                 :            :   }
     654                 :        171 : }
     655                 :            : 
     656                 :            : void
     657                 :        172 : Transporter::load( std::size_t meshid, std::size_t nelem )
     658                 :            : // *****************************************************************************
     659                 :            : // Reduction target: the mesh has been read from file on all PEs
     660                 :            : //! \param[in] meshid Mesh id (summed accross all compute nodes)
     661                 :            : //! \param[in] nelem Number of mesh elements per mesh (summed across all
     662                 :            : //!    compute nodes)
     663                 :            : // *****************************************************************************
     664                 :            : {
     665                 :        172 :   meshid /= static_cast< std::size_t >( CkNumNodes() );
     666 [ -  + ][ -  - ]:        172 :   Assert( meshid < m_nelem.size(), "MeshId indexing out" );
         [ -  - ][ -  - ]
     667                 :        172 :   m_nelem[meshid] = nelem;
     668                 :            : 
     669                 :            :   // Compute load distribution given total work (nelem) and user-specified
     670                 :            :   // virtualization
     671                 :            :   uint64_t chunksize, remainder;
     672                 :        344 :   m_nchare[meshid] = static_cast<int>(
     673         [ +  - ]:        344 :     tk::linearLoadDistributor(
     674                 :        172 :        g_inputdeck.get< tag::cmd, tag::virtualization >(),
     675                 :        172 :        m_nelem[meshid], CkNumPes(), chunksize, remainder ) );
     676                 :            : 
     677                 :            :   // Store sum of meshids (across all chares, key) for each meshid (value).
     678                 :            :   // This is used to look up the mesh id after collectives that sum their data.
     679         [ +  - ]:        172 :   m_meshid[ static_cast<std::size_t>(m_nchare[meshid])*meshid ] = meshid;
     680 [ -  + ][ -  - ]:        172 :   Assert( meshid < m_nelem.size(), "MeshId indexing out" );
         [ -  - ][ -  - ]
     681                 :            : 
     682                 :            :   // Tell the meshwriter for this mesh the total number of its chares
     683         [ +  - ]:        172 :   m_meshwriter[meshid].nchare( meshid, m_nchare[meshid] );
     684                 :            : 
     685         [ +  + ]:        172 :   if (++m_nload == m_nelem.size()) {     // all meshes have been loaded
     686                 :        171 :     m_nload = 0;
     687         [ +  - ]:        342 :     auto print = printer();
     688                 :            : 
     689                 :            :     // Start timer measuring preparation of the mesh for partitioning
     690                 :        171 :     const auto itTimer = TimerTag::MESH_READ;
     691         [ +  - ]:        171 :     const auto& timer = tk::cref_find( m_timer, itTimer );
     692 [ +  - ][ +  - ]:        171 :     print.diag( "Mesh read time: " + std::to_string( timer.dsec() ) + " sec" );
         [ +  - ][ +  - ]
                 [ +  - ]
     693                 :            : 
     694                 :            :     // Print out mesh partitioning configuration
     695 [ +  - ][ +  - ]:        171 :     print.section( "Mesh partitioning" );
     696         [ +  - ]:        171 :     print.Item< tk::ctr::PartitioningAlgorithm, tag::partitioning >();
     697 [ +  - ][ +  - ]:        171 :     print.item( "Virtualization [0.0...1.0]",
     698                 :        171 :                 g_inputdeck.get< tag::cmd, tag::virtualization >() );
     699                 :            :     // Print out initial mesh statistics
     700 [ +  - ][ +  - ]:        171 :     meshstat( "Initial load distribution" );
     701                 :            : 
     702                 :            :     // Query number of initial mesh refinement steps
     703                 :        171 :     int nref = 0;
     704         [ +  + ]:        171 :     if (g_inputdeck.get< tag::amr, tag::t0ref >())
     705                 :         20 :       nref = static_cast<int>(g_inputdeck.get< tag::amr,
     706                 :         20 :         tag::initial >().size());
     707                 :            : 
     708 [ +  - ][ +  - ]:        342 :     m_progMesh.start( print, "Preparing mesh", {{ CkNumPes(), CkNumPes(), nref,
     709                 :        171 :       m_nchare[0], m_nchare[0], m_nchare[0], m_nchare[0] }} );
     710                 :            : 
     711                 :            :     // Partition first mesh
     712         [ +  - ]:        171 :     m_partitioner[0].partition( m_nchare[0] );
     713                 :            :   }
     714                 :        172 : }
     715                 :            : 
     716                 :            : void
     717                 :        172 : Transporter::partitioned( std::size_t meshid )
     718                 :            : // *****************************************************************************
     719                 :            : // Reduction target: a mesh has been partitioned
     720                 :            : //! \param[in] meshid Mesh id
     721                 :            : // *****************************************************************************
     722                 :            : {
     723         [ +  + ]:        172 :   if (++m_npart == m_nelem.size()) {     // all meshes have been partitioned
     724                 :        171 :     m_npart = 0;
     725                 :            :   } else { // partition next mesh
     726                 :          1 :     m_partitioner[meshid+1].partition( m_nchare[meshid+1] );
     727                 :            :   }
     728                 :        172 : }
     729                 :            : 
     730                 :            : void
     731                 :        172 : Transporter::distributed( std::size_t meshid )
     732                 :            : // *****************************************************************************
     733                 :            : // Reduction target: all compute nodes have distributed their mesh after
     734                 :            : // partitioning
     735                 :            : //! \param[in] meshid Mesh id
     736                 :            : // *****************************************************************************
     737                 :            : {
     738                 :        172 :   m_partitioner[meshid].refine();
     739                 :        172 : }
     740                 :            : 
     741                 :            : void
     742                 :        172 : Transporter::refinserted( std::size_t meshid, std::size_t error )
     743                 :            : // *****************************************************************************
     744                 :            : // Reduction target: all compute nodes have created the mesh refiners
     745                 :            : //! \param[in] meshid Mesh id (aggregated across all compute nodes with operator
     746                 :            : //!   max)
     747                 :            : //! \param[in] error Error code (aggregated across all compute nodes with
     748                 :            : //!   operator max)
     749                 :            : // *****************************************************************************
     750                 :            : {
     751         [ -  + ]:        172 :   if (error) {
     752                 :            : 
     753                 :          0 :     printer() << "\n>>> ERROR: A worker chare was not assigned any mesh "
     754 [ -  - ][ -  - ]:          0 :               "elements after distributing mesh " + std::to_string(meshid) +
                 [ -  - ]
     755                 :            :               ". This can happen in SMP-mode with a large +ppn "
     756                 :            :               "parameter (number of worker threads per logical node) and is "
     757                 :            :               "most likely the fault of the mesh partitioning algorithm not "
     758                 :            :               "tolerating the case when it is asked to divide the "
     759                 :            :               "computational domain into a number of partitions different "
     760                 :            :               "than the number of ranks it is called on, i.e., in case of "
     761                 :            :               "overdecomposition and/or calling the partitioner in SMP mode "
     762                 :            :               "with +ppn larger than 1. Solution 1: Try a different "
     763                 :            :               "partitioning algorithm (e.g., rcb instead of mj). Solution 2: "
     764         [ -  - ]:          0 :               "Decrease +ppn.";
     765                 :          0 :     finish( meshid );
     766                 :            : 
     767                 :            :   } else {
     768                 :            : 
     769                 :        172 :      m_refiner[meshid].doneInserting();
     770                 :            : 
     771                 :            :   }
     772                 :        172 : }
     773                 :            : 
     774                 :            : void
     775                 :         87 : Transporter::queriedRef( std::size_t meshid )
     776                 :            : // *****************************************************************************
     777                 :            : // Reduction target: all Refiner chares have queried their boundary edges
     778                 :            : //! \param[in] meshid Mesh id
     779                 :            : // *****************************************************************************
     780                 :            : {
     781                 :         87 :   m_refiner[meshid].response();
     782                 :         87 : }
     783                 :            : 
     784                 :            : void
     785                 :         87 : Transporter::respondedRef( std::size_t meshid )
     786                 :            : // *****************************************************************************
     787                 :            : // Reduction target: all Refiner chares have setup their boundary edges
     788                 :            : //! \param[in] meshid Mesh id
     789                 :            : // *****************************************************************************
     790                 :            : {
     791                 :         87 :   m_refiner[meshid].refine();
     792                 :         87 : }
     793                 :            : 
     794                 :            : void
     795                 :         48 : Transporter::compatibility( std::size_t meshid )
     796                 :            : // *****************************************************************************
     797                 :            : // Reduction target: all Refiner chares have received a round of edges,
     798                 :            : // and have run their compatibility algorithm
     799                 :            : //! \param[in] meshid Mesh id (aggregated across all chares using operator max)
     800                 :            : //! \details This is called iteratively, until convergence by Refiner. At this
     801                 :            : //!   point all Refiner chares have received a round of edge data (tags whether
     802                 :            : //!   an edge needs to be refined, etc.), and applied the compatibility
     803                 :            : //!   algorithm independent of other Refiner chares. We keep going until the
     804                 :            : //!   mesh is no longer modified by the compatibility algorithm, based on a new
     805                 :            : //!   round of edge data communication started in Refiner::comExtra().
     806                 :            : // *****************************************************************************
     807                 :            : {
     808                 :         48 :   m_refiner[meshid].correctref();
     809                 :         48 : }
     810                 :            : 
     811                 :            : void
     812                 :         89 : Transporter::matched( std::size_t summeshid,
     813                 :            :                       std::size_t nextra,
     814                 :            :                       std::size_t nref,
     815                 :            :                       std::size_t nderef,
     816                 :            :                       std::size_t sumrefmode )
     817                 :            : // *****************************************************************************
     818                 :            : // Reduction target: all Refiner chares have matched/corrected the tagging
     819                 :            : // of chare-boundary edges, all chares are ready to perform refinement.
     820                 :            : //! \param[in] summeshid Mesh id (summed across all chares)
     821                 :            : //! \param[in] nextra Sum (across all chares) of the number of edges on each
     822                 :            : //!   chare that need correction along chare boundaries
     823                 :            : //! \param[in] nref Sum of number of refined tetrahedra across all chares.
     824                 :            : //! \param[in] nderef Sum of number of derefined tetrahedra across all chares.
     825                 :            : //! \param[in] sumrefmode Sum of contributions from all chares, encoding
     826                 :            : //!   refinement mode of operation.
     827                 :            : // *****************************************************************************
     828                 :            : {
     829                 :         89 :   auto meshid = tk::cref_find( m_meshid, summeshid );
     830                 :            : 
     831                 :            :   // If at least a single edge on a chare still needs correction, do correction,
     832                 :            :   // otherwise, this mesh refinement step is complete
     833         [ +  + ]:         89 :   if (nextra > 0) {
     834                 :            : 
     835                 :          2 :     ++m_ncit[meshid];
     836                 :          2 :     m_refiner[meshid].comExtra();
     837                 :            : 
     838                 :            :   } else {
     839                 :            : 
     840         [ +  - ]:        174 :     auto print = printer();
     841                 :            : 
     842                 :            :     // decode refmode
     843                 :            :     auto refmode = static_cast< Refiner::RefMode >(
     844                 :         87 :                      sumrefmode / static_cast<std::size_t>(m_nchare[meshid]) );
     845                 :            : 
     846         [ +  + ]:         87 :     if (refmode == Refiner::RefMode::T0REF) {
     847                 :            : 
     848         [ +  - ]:         57 :       if (!g_inputdeck.get< tag::cmd, tag::feedback >()) {
     849         [ +  - ]:         57 :         ctr::AMRInitial opt;
     850 [ +  - ][ +  - ]:        855 :         print.diag( { "meshid", "t0ref", "type", "nref", "nderef", "ncorr" },
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  + ]
         [ +  + ][ -  - ]
                 [ -  - ]
     851                 :            :                     { std::to_string(meshid),
     852                 :         57 :                       std::to_string(m_nt0refit[meshid]),
     853                 :            :                       "initial",
     854                 :            :                       std::to_string(nref),
     855                 :            :                       std::to_string(nderef),
     856                 :        741 :                       std::to_string(m_ncit[meshid]) } );
     857                 :         57 :         ++m_nt0refit[meshid];
     858                 :            :       }
     859         [ +  - ]:         57 :       m_progMesh.inc< REFINE >( print );
     860                 :            : 
     861         [ -  + ]:         30 :     } else if (refmode == Refiner::RefMode::DTREF) {
     862                 :            : 
     863                 :          0 :       auto dtref_uni = g_inputdeck.get< tag::amr, tag::dtref_uniform >();
     864 [ -  - ][ -  - ]:          0 :       print.diag( { "meshid", "dtref", "type", "nref", "nderef", "ncorr" },
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
     865                 :            :                   { std::to_string(meshid),
     866                 :          0 :                     std::to_string(++m_ndtrefit[meshid]),
     867                 :            :                     (dtref_uni?"uniform":"error"),
     868                 :            :                     std::to_string(nref),
     869                 :            :                     std::to_string(nderef),
     870                 :          0 :                     std::to_string(m_ncit[meshid]) },
     871                 :          0 :                   false );
     872                 :            : 
     873         [ +  + ]:         30 :     } else if (refmode == Refiner::RefMode::OUTREF) {
     874                 :            : 
     875 [ +  - ][ +  - ]:        195 :       print.diag( { "meshid", "outref", "nref", "nderef", "ncorr" },
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  + ]
         [ +  + ][ -  - ]
                 [ -  - ]
     876                 :            :                   { std::to_string(meshid),
     877                 :         15 :                     std::to_string(++m_noutrefit[meshid]),
     878                 :            :                     std::to_string(nref),
     879                 :            :                     std::to_string(nderef),
     880                 :        165 :                     std::to_string(m_ncit[meshid]) }, false );
     881                 :            : 
     882         [ +  - ]:         15 :     } else if (refmode == Refiner::RefMode::OUTDEREF) {
     883                 :            : 
     884 [ +  - ][ +  - ]:        195 :       print.diag( { "meshid", "outderef", "nref", "nderef", "ncorr" },
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  + ]
         [ +  + ][ -  - ]
                 [ -  - ]
     885                 :            :                   { std::to_string(meshid),
     886                 :         15 :                     std::to_string(++m_noutderefit[meshid]),
     887                 :            :                     std::to_string(nref),
     888                 :            :                     std::to_string(nderef),
     889                 :         15 :                     std::to_string(m_ncit[meshid]) },
     890                 :        150 :                   false );
     891                 :            : 
     892 [ -  - ][ -  - ]:          0 :     } else Throw( "RefMode not implemented" );
                 [ -  - ]
     893                 :            : 
     894                 :         87 :     m_ncit[meshid] = 0;
     895         [ +  - ]:         87 :     m_refiner[meshid].perform();
     896                 :            : 
     897                 :            :   }
     898                 :         89 : }
     899                 :            : 
     900                 :            : void
     901                 :        182 : Transporter::bndint( tk::real sx, tk::real sy, tk::real sz, tk::real cb,
     902                 :            :                      tk::real summeshid )
     903                 :            : // *****************************************************************************
     904                 :            : // Compute surface integral across the whole problem and perform leak-test
     905                 :            : //! \param[in] sx X component of vector summed
     906                 :            : //! \param[in] sy Y component of vector summed
     907                 :            : //! \param[in] sz Z component of vector summed
     908                 :            : //! \param[in] cb Invoke callback if positive
     909                 :            : //! \param[in] summeshid Mesh id (summed accross all chares)
     910                 :            : //! \details This function aggregates partial surface integrals across the
     911                 :            : //!   boundary faces of the whole problem. After this global sum a
     912                 :            : //!   non-zero vector result indicates a leak, e.g., a hole in the boundary,
     913                 :            : //!   which indicates an error in the boundary face data structures used to
     914                 :            : //!   compute the partial surface integrals.
     915                 :            : // *****************************************************************************
     916                 :            : {
     917         [ +  - ]:        182 :   auto meshid = tk::cref_find( m_meshid, static_cast<std::size_t>(summeshid) );
     918                 :            : 
     919         [ +  - ]:        364 :   std::stringstream err;
     920         [ +  + ]:        182 :   if (cb < 0.0) {
     921                 :            :     err << "Mesh boundary leaky after mesh refinement step; this is due to a "
     922                 :            :      "problem with updating the side sets used to specify boundary conditions "
     923         [ +  - ]:         87 :      "on faces: ";
     924         [ +  - ]:         95 :   } else if (cb > 0.0) {
     925                 :            :     err << "Mesh boundary leaky during initialization; this is due to "
     926                 :            :     "incorrect or incompletely specified boundary conditions for a given input "
     927         [ +  - ]:         95 :     "mesh: ";
     928                 :            :   }
     929                 :            : 
     930                 :        182 :   auto eps = 1.0e-10;
     931 [ +  - ][ +  - ]:        182 :   if (std::abs(sx) > eps || std::abs(sy) > eps || std::abs(sz) > eps) {
         [ -  + ][ -  + ]
     932 [ -  - ][ -  - ]:          0 :     err << "Integral result must be a zero vector: " << std::setprecision(12) <<
     933 [ -  - ][ -  - ]:          0 :            std::abs(sx) << ", " << std::abs(sy) << ", " << std::abs(sz) <<
         [ -  - ][ -  - ]
                 [ -  - ]
     934 [ -  - ][ -  - ]:          0 :            ", eps = " << eps;
     935 [ -  - ][ -  - ]:          0 :     Throw( err.str() );
                 [ -  - ]
     936                 :            :   }
     937                 :            : 
     938 [ +  + ][ +  - ]:        182 :   if (cb > 0.0) m_scheme[meshid].ghosts().resizeComm();
     939                 :        182 : }
     940                 :            : 
     941                 :            : void
     942                 :        172 : Transporter::refined( std::size_t summeshid,
     943                 :            :                       std::size_t nelem,
     944                 :            :                       std::size_t npoin )
     945                 :            : // *****************************************************************************
     946                 :            : // Reduction target: all chares have refined their mesh
     947                 :            : //! \param[in] summeshid Mesh id (summed accross all Refiner chares)
     948                 :            : //! \param[in] nelem Total number of elements in mesh summed across the
     949                 :            : //!   distributed mesh
     950                 :            : //! \param[in] npoin Total number of mesh points summed across the distributed
     951                 :            : //!   mesh. Note that in parallel this is larger than the number of points in
     952                 :            : //!   the mesh, because the boundary nodes are multi-counted. But we only need
     953                 :            : //!   an equal or larger than npoin for Sorter::setup, so this is okay.
     954                 :            : // *****************************************************************************
     955                 :            : {
     956                 :        172 :   auto meshid = tk::cref_find( m_meshid, summeshid );
     957                 :            : 
     958                 :            :   // Store new number of elements for initially refined mesh
     959                 :        172 :   m_nelem[meshid] = nelem;
     960                 :            : 
     961                 :        172 :   m_sorter[meshid].doneInserting();
     962                 :        172 :   m_sorter[meshid].setup( npoin );
     963                 :        172 : }
     964                 :            : 
     965                 :            : void
     966                 :        172 : Transporter::queried( std::size_t meshid )
     967                 :            : // *****************************************************************************
     968                 :            : // Reduction target: all Sorter chares have queried their boundary edges
     969                 :            : //! \param[in] meshid Mesh id
     970                 :            : // *****************************************************************************
     971                 :            : {
     972                 :        172 :   m_sorter[meshid].response();
     973                 :        172 : }
     974                 :            : 
     975                 :            : void
     976                 :        172 : Transporter::responded( std::size_t meshid )
     977                 :            : // *****************************************************************************
     978                 :            : // Reduction target: all Sorter chares have responded with their boundary edges
     979                 :            : //! \param[in] meshid Mesh id
     980                 :            : // *****************************************************************************
     981                 :            : {
     982                 :        172 :   m_sorter[meshid].start();
     983                 :        172 : }
     984                 :            : 
     985                 :            : void
     986                 :        360 : Transporter::resized( std::size_t meshid )
     987                 :            : // *****************************************************************************
     988                 :            : // Reduction target: all worker chares have resized their own mesh data after
     989                 :            : // AMR or ALE
     990                 :            : //! \param[in] meshid Mesh id
     991                 :            : //! \note Only used for nodal schemes
     992                 :            : // *****************************************************************************
     993                 :            : {
     994                 :        360 :   m_scheme[meshid].disc().vol();
     995                 :        360 :   m_scheme[meshid].bcast< Scheme::lhs >();
     996                 :        360 : }
     997                 :            : 
     998                 :            : void
     999                 :         95 : Transporter::startEsup( std::size_t meshid )
    1000                 :            : // *****************************************************************************
    1001                 :            : // Reduction target: all worker chares have generated their own esup
    1002                 :            : //! \param[in] meshid Mesh id
    1003                 :            : //! \note Only used for cell-centered schemes
    1004                 :            : // *****************************************************************************
    1005                 :            : {
    1006                 :         95 :   m_scheme[meshid].ghosts().nodeNeighSetup();
    1007                 :         95 : }
    1008                 :            : 
    1009                 :            : void
    1010                 :        172 : Transporter::discinserted( std::size_t meshid )
    1011                 :            : // *****************************************************************************
    1012                 :            : // Reduction target: all Discretization chares have been inserted
    1013                 :            : //! \param[in] meshid Mesh id
    1014                 :            : // *****************************************************************************
    1015                 :            : {
    1016                 :        172 :   m_scheme[meshid].disc().doneInserting();
    1017                 :        172 : }
    1018                 :            : 
    1019                 :            : void
    1020                 :        191 : Transporter::meshstat( const std::string& header ) const
    1021                 :            : // *****************************************************************************
    1022                 :            : // Print out mesh statistics
    1023                 :            : //! \param[in] header Section header
    1024                 :            : // *****************************************************************************
    1025                 :            : {
    1026         [ +  - ]:        382 :   auto print = printer();
    1027                 :            : 
    1028         [ +  - ]:        191 :   print.section( header );
    1029                 :            : 
    1030         [ +  + ]:        191 :   if (m_nelem.size() > 1) {
    1031 [ +  - ][ +  - ]:          1 :     print.item( "Number of tetrahedra (per mesh)",tk::parameters(m_nelem) );
                 [ +  - ]
    1032 [ +  - ][ +  - ]:          1 :     print.item( "Number of points (per mesh)", tk::parameters(m_npoin) );
                 [ +  - ]
    1033 [ +  - ][ +  - ]:          1 :     print.item( "Number of work units (per mesh)", tk::parameters(m_nchare) );
                 [ +  - ]
    1034                 :            :   }
    1035                 :            : 
    1036 [ +  - ][ +  - ]:        191 :   print.item( "Total number of tetrahedra",
    1037                 :        191 :               std::accumulate( begin(m_nelem), end(m_nelem), 0UL ) );
    1038 [ +  - ][ +  - ]:        191 :   print.item( "Total number of points",
    1039                 :        191 :               std::accumulate( begin(m_npoin), end(m_npoin), 0UL ) );
    1040 [ +  - ][ +  - ]:        191 :   print.item( "Total number of work units",
    1041                 :        191 :               std::accumulate( begin(m_nchare), end(m_nchare), 0 ) );
    1042                 :            : 
    1043         [ +  - ]:        191 :   print.endsubsection();
    1044                 :        191 : }
    1045                 :            : 
    1046                 :            : bool
    1047                 :        344 : Transporter::need_linearsolver() const
    1048                 :            : // *****************************************************************************
    1049                 :            : //  Decide if we need a linear solver for ALE
    1050                 :            : //! \return True if ALE will neeed a linear solver
    1051                 :            : // *****************************************************************************
    1052                 :            : {
    1053                 :        344 :   auto smoother = g_inputdeck.get< tag::ale, tag::smoother >();
    1054                 :            : 
    1055 [ +  + ][ +  + ]:        354 :   if ( g_inputdeck.get< tag::ale, tag::ale >() and
                 [ +  + ]
    1056         [ +  + ]:         10 :        (smoother == ctr::MeshVelocitySmootherType::LAPLACE ||
    1057                 :            :         smoother == ctr::MeshVelocitySmootherType::HELMHOLTZ) )
    1058                 :            :   {
    1059                 :         12 :      return true;
    1060                 :            :   } else {
    1061                 :        332 :      return false;
    1062                 :            :   }
    1063                 :            : }
    1064                 :            : 
    1065                 :            : void
    1066                 :        172 : Transporter::disccreated( std::size_t summeshid, std::size_t npoin )
    1067                 :            : // *****************************************************************************
    1068                 :            : // Reduction target: all Discretization constructors have been called
    1069                 :            : //! \param[in] summeshid Mesh id (summed accross all chares)
    1070                 :            : //! \param[in] npoin Total number of mesh points (summed across all chares)
    1071                 :            : //!  Note that as opposed to npoin in refined(), this npoin is not
    1072                 :            : //!  multi-counted, and thus should be correct in parallel.
    1073                 :            : // *****************************************************************************
    1074                 :            : {
    1075                 :        172 :   auto meshid = tk::cref_find( m_meshid, summeshid );
    1076                 :            :   //std::cout << "Trans: " << meshid << " Transporter::disccreated()\n";
    1077                 :            : 
    1078                 :            :   // Update number of mesh points for mesh, since it may have been refined
    1079         [ +  + ]:        172 :   if (g_inputdeck.get< tag::amr, tag::t0ref >()) m_npoin[meshid] = npoin;
    1080                 :            : 
    1081         [ +  + ]:        172 :   if (++m_ndisc == m_nelem.size()) { // all Disc arrays have been created
    1082                 :        171 :     m_ndisc = 0;
    1083         [ +  - ]:        342 :     auto print = printer();
    1084         [ +  - ]:        171 :     m_progMesh.end( print );
    1085         [ +  + ]:        171 :     if (g_inputdeck.get< tag::amr, tag::t0ref >())
    1086 [ +  - ][ +  - ]:         20 :       meshstat( "Initially (t<0) refined mesh graph statistics" );
    1087                 :            :   }
    1088                 :            : 
    1089                 :        172 :   m_refiner[meshid].sendProxy();
    1090                 :            : 
    1091         [ +  + ]:        172 :   if (g_inputdeck.get< tag::ale, tag::ale >())
    1092                 :         10 :     m_scheme[meshid].ale().doneInserting();
    1093                 :            : 
    1094         [ +  + ]:        172 :   if (need_linearsolver())
    1095                 :          6 :     m_scheme[meshid].conjugategradients().doneInserting();
    1096                 :            : 
    1097                 :        172 :   m_scheme[meshid].disc().vol();
    1098                 :        172 : }
    1099                 :            : 
    1100                 :            : void
    1101                 :        172 : Transporter::workinserted( std::size_t meshid )
    1102                 :            : // *****************************************************************************
    1103                 :            : // Reduction target: all worker (derived discretization) chares have been
    1104                 :            : // inserted
    1105                 :            : //! \param[in] meshid Mesh id
    1106                 :            : // *****************************************************************************
    1107                 :            : {
    1108                 :        172 :   m_scheme[meshid].bcast< Scheme::doneInserting >();
    1109                 :        172 : }
    1110                 :            : 
    1111                 :            : void
    1112                 :        171 : Transporter::diagHeader()
    1113                 :            : // *****************************************************************************
    1114                 :            : // Configure and write diagnostics file header
    1115                 :            : // *****************************************************************************
    1116                 :            : {
    1117         [ +  + ]:        343 :   for (std::size_t m=0; m<m_input.size(); ++m) {
    1118                 :            : 
    1119                 :            :    // Output header for diagnostics output file
    1120 [ +  + ][ +  - ]:        514 :     auto mid = m_input.size() > 1 ? std::string( '.' + std::to_string(m) ) : "";
         [ +  - ][ +  - ]
         [ +  + ][ +  + ]
         [ -  - ][ -  - ]
    1121         [ +  - ]:        172 :     tk::DiagWriter dw( g_inputdeck.get< tag::cmd, tag::io, tag::diag >() + mid,
    1122                 :        172 :       g_inputdeck.get< tag::diagnostics, tag::format >(),
    1123         [ +  - ]:        516 :       g_inputdeck.get< tag::diagnostics, tag::precision >() );
    1124                 :            : 
    1125                 :            :     // Collect variables names for integral/diagnostics output
    1126                 :        344 :     std::vector< std::string > var;
    1127                 :        172 :     const auto scheme = g_inputdeck.get< tag::scheme >();
    1128 [ +  + ][ +  + ]:        172 :     if ( scheme == ctr::SchemeType::ALECG ||
    1129                 :            :          scheme == ctr::SchemeType::OversetFE )
    1130 [ +  + ][ +  - ]:        156 :       for (const auto& eq : g_cgpde) varnames( eq, var );
    1131 [ +  + ][ +  + ]:         95 :     else if ( scheme == ctr::SchemeType::DGP0 ||
    1132         [ +  + ]:         49 :               scheme == ctr::SchemeType::P0P1 ||
    1133         [ +  + ]:         38 :               scheme == ctr::SchemeType::DGP1 ||
    1134         [ +  + ]:         34 :               scheme == ctr::SchemeType::DGP2 ||
    1135                 :            :               scheme == ctr::SchemeType::PDG )
    1136 [ +  + ][ +  - ]:        146 :       for (const auto& eq : g_dgpde) varnames( eq, var );
    1137         [ +  - ]:         22 :     else if (scheme == ctr::SchemeType::FV)
    1138 [ +  + ][ +  - ]:         44 :       for (const auto& eq : g_fvpde) varnames( eq, var );
    1139 [ -  - ][ -  - ]:          0 :     else Throw( "Diagnostics header not handled for discretization scheme" );
                 [ -  - ]
    1140                 :            : 
    1141         [ +  - ]:        344 :     const tk::ctr::Error opt;
    1142                 :        172 :     auto nv = var.size() / m_input.size();
    1143                 :        344 :     std::vector< std::string > d;
    1144                 :            : 
    1145                 :            :     // Add 'L2(var)' for all variables as those are always computed
    1146         [ +  - ]:        172 :     const auto& l2name = opt.name( tk::ctr::ErrorType::L2 );
    1147 [ +  + ][ +  - ]:       1163 :     for (std::size_t i=0; i<nv; ++i) d.push_back( l2name + '(' + var[i] + ')' );
         [ +  - ][ +  - ]
                 [ +  - ]
    1148                 :            : 
    1149                 :            :     // Query user-requested diagnostics and augment diagnostics file header by
    1150                 :            :     // 'err(var)', where 'err' is the error type  configured, and var is the
    1151                 :            :     // variable computed, for all variables and all error types configured.
    1152                 :        172 :     const auto& err = g_inputdeck.get< tag::diagnostics, tag::error >();
    1153         [ +  - ]:        172 :     const auto& errname = opt.name( err );
    1154         [ +  + ]:       1163 :     for (std::size_t i=0; i<nv; ++i)
    1155 [ +  - ][ +  - ]:        991 :       d.push_back( errname + '(' + var[i] + "-IC)" );
         [ +  - ][ +  - ]
    1156                 :            : 
    1157                 :            :     // Augment diagnostics variables by L2-norm of the residual and total energy
    1158 [ +  + ][ +  + ]:        172 :     if ( scheme == ctr::SchemeType::ALECG ||
    1159         [ +  + ]:         95 :          scheme == ctr::SchemeType::OversetFE ||
    1160         [ +  + ]:         73 :          scheme == ctr::SchemeType::FV ||
    1161         [ +  + ]:         36 :          scheme == ctr::SchemeType::DGP0 ||
    1162         [ +  + ]:         25 :          scheme == ctr::SchemeType::DGP1 ||
    1163         [ +  + ]:         21 :          scheme == ctr::SchemeType::DGP2 ||
    1164         [ +  - ]:         12 :          scheme == ctr::SchemeType::P0P1 ||
    1165                 :            :          scheme == ctr::SchemeType::PDG
    1166                 :            :        )
    1167                 :            :     {
    1168 [ +  + ][ +  - ]:       1163 :       for (std::size_t i=0; i<nv; ++i) d.push_back( "L2(d" + var[i] + ')' );
         [ +  - ][ +  - ]
    1169                 :            :     }
    1170 [ +  - ][ +  - ]:        172 :     d.push_back( "mE" );
    1171                 :            : 
    1172                 :            :     // Augment diagnostics variables with the following:
    1173                 :            :     // 1. resultant force vector on mesh boundaries that is used for rigid body
    1174                 :            :     //    motion of overset mesh ('Fi')
    1175                 :            :     // 2. resultant torque vector on mesh boundaries that is used for rigid body
    1176                 :            :     //    motion of overset mesh ('Ti')
    1177                 :            :     // 3. total displacement of rigid body center-of-mass ('Di')
    1178                 :            :     // 4. total rotation of rigid body ('Ri')
    1179         [ +  + ]:        172 :     if ( scheme == ctr::SchemeType::OversetFE )
    1180                 :            :     {
    1181 [ +  + ][ +  - ]:         84 :       for (std::size_t i=0; i<3; ++i) d.push_back( "F" + std::to_string(i+1) );
         [ +  - ][ +  - ]
    1182 [ +  + ][ +  - ]:         84 :       for (std::size_t i=0; i<3; ++i) d.push_back( "T" + std::to_string(i+1) );
         [ +  - ][ +  - ]
    1183 [ +  + ][ +  - ]:         84 :       for (std::size_t i=0; i<3; ++i) d.push_back( "D" + std::to_string(i+1) );
         [ +  - ][ +  - ]
    1184 [ +  + ][ +  - ]:         84 :       for (std::size_t i=0; i<3; ++i) d.push_back( "R" + std::to_string(i+1) );
         [ +  - ][ +  - ]
    1185                 :            :     }
    1186                 :            : 
    1187                 :            :     // Write diagnostics header
    1188         [ +  - ]:        172 :     dw.header( d );
    1189                 :            : 
    1190                 :            :   }
    1191                 :        171 : }
    1192                 :            : 
    1193                 :            : void
    1194                 :         95 : Transporter::doneInsertingGhosts(std::size_t meshid)
    1195                 :            : // *****************************************************************************
    1196                 :            : // Reduction target indicating all "ghosts" insertions are done
    1197                 :            : //! \param[in] meshid Mesh id
    1198                 :            : // *****************************************************************************
    1199                 :            : {
    1200         [ -  + ]:         95 :   if (g_inputdeck.get< tag::implicit_timestepping >())
    1201                 :          0 :     m_scheme[meshid].implicitsolver().doneInserting();
    1202                 :            : 
    1203                 :         95 :   m_scheme[meshid].ghosts().doneInserting();
    1204                 :         95 :   m_scheme[meshid].ghosts().startCommSetup();
    1205                 :         95 : }
    1206                 :            : 
    1207                 :            : void
    1208                 :        172 : Transporter::comfinal( std::size_t initial, std::size_t summeshid )
    1209                 :            : // *****************************************************************************
    1210                 :            : // Reduction target indicating that communication maps have been setup
    1211                 :            : //! \param[in] initial Sum of contributions from all chares. If larger than
    1212                 :            : //!    zero, we are during time stepping and if zero we are during setup.
    1213                 :            : //! \param[in] summeshid Mesh id (summed accross the distributed mesh)
    1214                 :            : // *****************************************************************************
    1215                 :            : // [Discretization-specific communication maps]
    1216                 :            : {
    1217         [ +  - ]:        172 :   auto meshid = tk::cref_find( m_meshid, static_cast<std::size_t>(summeshid) );
    1218                 :            : 
    1219         [ +  - ]:        172 :   if (initial > 0) {
    1220                 :        172 :     m_scheme[meshid].bcast< Scheme::setup >();
    1221                 :            :     // Turn on automatic load balancing
    1222         [ +  + ]:        172 :     if (++m_ncom == m_nelem.size()) { // all worker arrays have finished
    1223                 :        171 :       m_ncom = 0;
    1224         [ +  - ]:        171 :       auto print = printer();
    1225         [ +  - ]:        171 :       m_progWork.end( print );
    1226         [ +  - ]:        171 :       tk::CProxy_LBSwitch::ckNew();
    1227 [ +  - ][ +  - ]:        171 :       print.diag( "Load balancing on (if enabled in Charm++)" );
    1228                 :            :     }
    1229                 :            :   } else {
    1230                 :          0 :     m_scheme[meshid].bcast< Scheme::lhs >();
    1231                 :            :   }
    1232                 :        172 : }
    1233                 :            : // [Discretization-specific communication maps]
    1234                 :            : 
    1235                 :            : void
    1236                 :        532 : Transporter::totalvol( tk::real v, tk::real initial, tk::real summeshid )
    1237                 :            : // *****************************************************************************
    1238                 :            : // Reduction target summing total mesh volume across all workers
    1239                 :            : //! \param[in] v Mesh volume summed across the distributed mesh
    1240                 :            : //! \param[in] initial Sum of contributions from all chares. If larger than
    1241                 :            : //!    zero, we are during setup, if zero, during time stepping.
    1242                 :            : //! \param[in] summeshid Mesh id (summed accross the distributed mesh)
    1243                 :            : // *****************************************************************************
    1244                 :            : {
    1245         [ +  - ]:        532 :   auto meshid = tk::cref_find( m_meshid, static_cast<std::size_t>(summeshid) );
    1246                 :            : 
    1247                 :        532 :   m_meshvol[meshid] = v;
    1248                 :            : 
    1249         [ +  + ]:        532 :   if (initial > 0.0)   // during initialization
    1250                 :        172 :     m_scheme[meshid].disc().stat( v );
    1251                 :            :   else                  // during ALE or AMR
    1252                 :        360 :     m_scheme[meshid].bcast< Scheme::resized >();
    1253                 :        532 : }
    1254                 :            : 
    1255                 :            : void
    1256                 :        172 : Transporter::minstat( tk::real d0, tk::real d1, tk::real d2, tk::real rmeshid )
    1257                 :            : // *****************************************************************************
    1258                 :            : // Reduction target yielding minimum mesh statistcs across all workers
    1259                 :            : //! \param[in] d0 Minimum mesh statistics collected over all chares
    1260                 :            : //! \param[in] d1 Minimum mesh statistics collected over all chares
    1261                 :            : //! \param[in] d2 Minimum mesh statistics collected over all chares
    1262                 :            : //! \param[in] rmeshid Mesh id as a real
    1263                 :            : // *****************************************************************************
    1264                 :            : {
    1265                 :        172 :   auto meshid = static_cast<std::size_t>(rmeshid);
    1266                 :            : 
    1267                 :        172 :   m_minstat[meshid][0] = d0;  // minimum edge length
    1268                 :        172 :   m_minstat[meshid][1] = d1;  // minimum cell volume cubic root
    1269                 :        172 :   m_minstat[meshid][2] = d2;  // minimum number of cells on chare
    1270                 :            : 
    1271                 :        172 :   minstat_complete(meshid);
    1272                 :        172 : }
    1273                 :            : 
    1274                 :            : void
    1275                 :        172 : Transporter::maxstat( tk::real d0, tk::real d1, tk::real d2, tk::real rmeshid )
    1276                 :            : // *****************************************************************************
    1277                 :            : // Reduction target yielding the maximum mesh statistics across all workers
    1278                 :            : //! \param[in] d0 Maximum mesh statistics collected over all chares
    1279                 :            : //! \param[in] d1 Maximum mesh statistics collected over all chares
    1280                 :            : //! \param[in] d2 Maximum mesh statistics collected over all chares
    1281                 :            : //! \param[in] rmeshid Mesh id as a real
    1282                 :            : // *****************************************************************************
    1283                 :            : {
    1284                 :        172 :   auto meshid = static_cast<std::size_t>(rmeshid);
    1285                 :            : 
    1286                 :        172 :   m_maxstat[meshid][0] = d0;  // maximum edge length
    1287                 :        172 :   m_maxstat[meshid][1] = d1;  // maximum cell volume cubic root
    1288                 :        172 :   m_maxstat[meshid][2] = d2;  // maximum number of cells on chare
    1289                 :            : 
    1290                 :        172 :   maxstat_complete(meshid);
    1291                 :        172 : }
    1292                 :            : 
    1293                 :            : void
    1294                 :        172 : Transporter::sumstat( tk::real d0, tk::real d1, tk::real d2, tk::real d3,
    1295                 :            :                       tk::real d4, tk::real d5, tk::real summeshid )
    1296                 :            : // *****************************************************************************
    1297                 :            : // Reduction target yielding the sum mesh statistics across all workers
    1298                 :            : //! \param[in] d0 Sum mesh statistics collected over all chares
    1299                 :            : //! \param[in] d1 Sum mesh statistics collected over all chares
    1300                 :            : //! \param[in] d2 Sum mesh statistics collected over all chares
    1301                 :            : //! \param[in] d3 Sum mesh statistics collected over all chares
    1302                 :            : //! \param[in] d4 Sum mesh statistics collected over all chares
    1303                 :            : //! \param[in] d5 Sum mesh statistics collected over all chares
    1304                 :            : //! \param[in] summeshid Mesh id (summed accross the distributed mesh)
    1305                 :            : // *****************************************************************************
    1306                 :            : {
    1307         [ +  - ]:        172 :   auto meshid = tk::cref_find( m_meshid, static_cast<std::size_t>(summeshid) );
    1308                 :            : 
    1309                 :        172 :   m_avgstat[meshid][0] = d1 / d0;      // average edge length
    1310                 :        172 :   m_avgstat[meshid][1] = d3 / d2;      // average cell volume cubic root
    1311                 :        172 :   m_avgstat[meshid][2] = d5 / d4;      // average number of cells per chare
    1312                 :            : 
    1313                 :        172 :   sumstat_complete(meshid);
    1314                 :        172 : }
    1315                 :            : 
    1316                 :            : void
    1317                 :        172 : Transporter::pdfstat( CkReductionMsg* msg )
    1318                 :            : // *****************************************************************************
    1319                 :            : // Reduction target yielding PDF of mesh statistics across all workers
    1320                 :            : //! \param[in] msg Serialized PDF
    1321                 :            : // *****************************************************************************
    1322                 :            : {
    1323                 :            :   std::size_t meshid;
    1324                 :        344 :   std::vector< tk::UniPDF > pdf;
    1325                 :            : 
    1326                 :            :   // Deserialize final PDF
    1327         [ +  - ]:        344 :   PUP::fromMem creator( msg->getData() );
    1328         [ +  - ]:        172 :   creator | meshid;
    1329         [ +  - ]:        172 :   creator | pdf;
    1330 [ +  - ][ +  - ]:        172 :   delete msg;
    1331                 :            : 
    1332         [ +  - ]:        344 :   auto id = std::to_string(meshid);
    1333                 :            : 
    1334                 :            :   // Create new PDF file (overwrite if exists)
    1335 [ +  - ][ +  - ]:        516 :   tk::PDFWriter pdfe( "mesh_edge_pdf." + id + ".txt" );
                 [ +  - ]
    1336                 :            :   // Output edgelength PDF
    1337                 :            :   // cppcheck-suppress containerOutOfBounds
    1338         [ +  - ]:        172 :   pdfe.writeTxt( pdf[0],
    1339 [ +  - ][ +  - ]:        516 :                  tk::ctr::PDFInfo{ {"PDF"}, {}, {"edgelength"}, 0, 0.0 } );
         [ +  - ][ +  + ]
                 [ -  - ]
    1340                 :            : 
    1341                 :            :   // Create new PDF file (overwrite if exists)
    1342 [ +  - ][ +  - ]:        516 :   tk::PDFWriter pdfv( "mesh_vol_pdf." + id + ".txt" );
                 [ +  - ]
    1343                 :            :   // Output cell volume cubic root PDF
    1344         [ +  - ]:        172 :   pdfv.writeTxt( pdf[1],
    1345 [ +  - ][ +  - ]:        516 :                  tk::ctr::PDFInfo{ {"PDF"}, {}, {"V^{1/3}"}, 0, 0.0 } );
         [ +  - ][ +  + ]
                 [ -  - ]
    1346                 :            : 
    1347                 :            :   // Create new PDF file (overwrite if exists)
    1348 [ +  - ][ +  - ]:        516 :   tk::PDFWriter pdfn( "mesh_ntet_pdf." + id + ".txt" );
                 [ +  - ]
    1349                 :            :   // Output number of cells PDF
    1350         [ +  - ]:        172 :   pdfn.writeTxt( pdf[2],
    1351 [ +  - ][ +  - ]:        516 :                  tk::ctr::PDFInfo{ {"PDF"}, {}, {"ntets"}, 0, 0.0 } );
         [ +  - ][ +  + ]
                 [ -  - ]
    1352                 :            : 
    1353         [ +  - ]:        172 :   pdfstat_complete(meshid);
    1354                 :        172 : }
    1355                 :            : 
    1356                 :            : void
    1357                 :        172 : Transporter::stat()
    1358                 :            : // *****************************************************************************
    1359                 :            : // Echo diagnostics on mesh statistics
    1360                 :            : // *****************************************************************************
    1361                 :            : {
    1362         [ +  - ]:        344 :   auto print = printer();
    1363                 :            : 
    1364         [ +  + ]:        172 :   if (++m_nstat == m_nelem.size()) {     // stats from all meshes have arrived
    1365                 :        171 :     m_nstat = 0;
    1366         [ +  + ]:        343 :     for (std::size_t i=0; i<m_nelem.size(); ++i) {
    1367         [ +  - ]:        172 :       print.diag(
    1368 [ +  - ][ +  - ]:        344 :         "Mesh " + std::to_string(i) +
                 [ +  - ]
    1369         [ +  - ]:        344 :         " distribution statistics: min/max/avg(edgelength) = " +
    1370 [ +  - ][ +  - ]:        688 :         std::to_string( m_minstat[i][0] ) + " / " +
                 [ +  - ]
    1371 [ +  - ][ +  - ]:        688 :         std::to_string( m_maxstat[i][0] ) + " / " +
                 [ +  - ]
    1372 [ +  - ][ +  - ]:        688 :         std::to_string( m_avgstat[i][0] ) + ", " +
                 [ +  - ]
    1373         [ +  - ]:        344 :         "min/max/avg(V^{1/3}) = " +
    1374 [ +  - ][ +  - ]:        688 :         std::to_string( m_minstat[i][1] ) + " / " +
                 [ +  - ]
    1375 [ +  - ][ +  - ]:        688 :         std::to_string( m_maxstat[i][1] ) + " / " +
                 [ +  - ]
    1376 [ +  - ][ +  - ]:        688 :         std::to_string( m_avgstat[i][1] ) + ", " +
                 [ +  - ]
    1377         [ +  - ]:        344 :         "min/max/avg(ntets) = " +
    1378 [ +  - ][ +  - ]:        688 :         std::to_string( static_cast<std::size_t>(m_minstat[i][2]) ) + " / " +
                 [ +  - ]
    1379 [ +  - ][ +  - ]:        688 :         std::to_string( static_cast<std::size_t>(m_maxstat[i][2]) ) + " / " +
                 [ +  - ]
    1380         [ +  - ]:        344 :         std::to_string( static_cast<std::size_t>(m_avgstat[i][2]) ) );
    1381                 :            :     }
    1382                 :            : 
    1383                 :            :     // Print out time integration header to screen
    1384         [ +  - ]:        171 :     inthead( print );
    1385                 :            : 
    1386 [ +  - ][ +  - ]:        171 :     m_progWork.start( print, "Preparing workers",
    1387                 :        171 :       {{ m_nchare[0], m_nchare[0], m_nchare[0], m_nchare[0], m_nchare[0] }} );
    1388                 :            : 
    1389                 :            :     // Create "derived-class" workers
    1390 [ +  + ][ +  - ]:        343 :     for (std::size_t i=0; i<m_nelem.size(); ++i) m_sorter[i].createWorkers();
    1391                 :            :   }
    1392                 :        172 : }
    1393                 :            : 
    1394                 :            : void
    1395                 :        172 : Transporter::boxvol( tk::real* meshdata, int n )
    1396                 :            : // *****************************************************************************
    1397                 :            : // Reduction target computing total volume of IC mesh blocks and box
    1398                 :            : //! \param[in] meshdata Vector containing volumes of all IC mesh blocks,
    1399                 :            : //!   volume of IC box, and mesh id as a real summed across the distributed mesh
    1400                 :            : //! \param[in] n Size of vector, automatically computed by Charm
    1401                 :            : // *****************************************************************************
    1402                 :            : {
    1403 [ -  + ][ -  - ]:        172 :   Assert(n>=2, "mesh data size incorrect");
         [ -  - ][ -  - ]
    1404                 :            : 
    1405                 :            :   // extract summed mesh id from vector
    1406                 :        172 :   tk::real summeshid = meshdata[n-1];
    1407         [ +  - ]:        172 :   auto meshid = tk::cref_find( m_meshid, static_cast<std::size_t>(summeshid) );
    1408                 :            : 
    1409                 :            :   // extract summed box volume from vector
    1410                 :        172 :   tk::real v = meshdata[n-2];
    1411 [ +  + ][ +  - ]:        172 :   if (v > 0.0) printer().diag( "Box IC volume: " + std::to_string(v) );
         [ +  - ][ +  - ]
                 [ +  - ]
    1412                 :            : 
    1413                 :            :   // extract summed mesh block volumes from the vector
    1414                 :        344 :   std::vector< tk::real > blockvols;
    1415         [ -  + ]:        172 :   for (std::size_t blid=0; blid<(static_cast<std::size_t>(n)-2); ++blid) {
    1416         [ -  - ]:          0 :     blockvols.push_back(meshdata[blid]);
    1417         [ -  - ]:          0 :     if (blockvols[blid] > 0.0)
    1418 [ -  - ][ -  - ]:          0 :       printer().diag( "Mesh block " + std::to_string(blid) +
         [ -  - ][ -  - ]
                 [ -  - ]
    1419 [ -  - ][ -  - ]:          0 :         " discrete volume: " + std::to_string(blockvols[blid]) );
    1420                 :            :   }
    1421                 :            : 
    1422         [ +  - ]:        172 :   m_scheme[meshid].bcast< Scheme::box >( v, blockvols );
    1423                 :        172 : }
    1424                 :            : 
    1425                 :            : void
    1426                 :          8 : Transporter::solutionTransferred()
    1427                 :            : // *****************************************************************************
    1428                 :            : // Reduction target broadcasting to Schemes after mesh transfer
    1429                 :            : // *****************************************************************************
    1430                 :            : {
    1431         [ +  + ]:          8 :   if (++m_ntrans == m_nelem.size()) {    // all meshes have been loaded
    1432                 :          4 :     m_ntrans = 0;
    1433 [ +  + ][ +  - ]:         12 :     for (auto& m : m_scheme) m.bcast< Scheme::transferSol >();
    1434                 :            :   }
    1435                 :          8 : }
    1436                 :            : 
    1437                 :            : void
    1438                 :        252 : Transporter::collectDtAndForces( CkReductionMsg* advMsg )
    1439                 :            : // *****************************************************************************
    1440                 :            : // \brief Reduction target that computes minimum timestep across all meshes and
    1441                 :            : //    sums up the forces on each mesh
    1442                 :            : //! \param[in] advMsg Reduction msg containing minimum timestep and total
    1443                 :            : //!   surface force information
    1444                 :            : // *****************************************************************************
    1445                 :            : {
    1446                 :            :   // obtain results of reduction from reduction-msg
    1447                 :        252 :   CkReduction::tupleElement* results = nullptr;
    1448                 :        252 :   int num_reductions = 0;
    1449         [ +  - ]:        252 :   advMsg->toTuple(&results, &num_reductions);
    1450                 :            : 
    1451                 :            : // ignore the old-style-cast warning from clang for this code
    1452                 :            : #if defined(__clang__)
    1453                 :            :   #pragma clang diagnostic push
    1454                 :            :   #pragma clang diagnostic ignored "-Wold-style-cast"
    1455                 :            :   #pragma clang diagnostic ignored "-Wcast-align"
    1456                 :            : #endif
    1457                 :            : 
    1458                 :        252 :   tk::real mindt = *(tk::real*)results[0].data;
    1459                 :            :   std::array< tk::real, 6 > F;
    1460                 :        252 :   F[0] = *(tk::real*)results[1].data;
    1461                 :        252 :   F[1] = *(tk::real*)results[2].data;
    1462                 :        252 :   F[2] = *(tk::real*)results[3].data;
    1463                 :        252 :   F[3] = *(tk::real*)results[4].data;
    1464                 :        252 :   F[4] = *(tk::real*)results[5].data;
    1465                 :        252 :   F[5] = *(tk::real*)results[6].data;
    1466                 :            : 
    1467                 :            : #if defined(__clang__)
    1468                 :            :   #pragma clang diagnostic pop
    1469                 :            : #endif
    1470                 :            : 
    1471         [ +  - ]:        252 :   m_dtmsh.push_back(mindt);
    1472                 :            : 
    1473         [ +  + ]:        252 :   if (++m_ndtmsh == m_nelem.size()) {    // all meshes have been loaded
    1474 [ -  + ][ -  - ]:        251 :     Assert(m_dtmsh.size() == m_nelem.size(), "Incorrect size of dtmsh");
         [ -  - ][ -  - ]
    1475                 :            : 
    1476                 :            :     // compute minimum dt across meshes
    1477                 :        251 :     tk::real dt = std::numeric_limits< tk::real >::max();
    1478         [ +  + ]:        503 :     for (auto idt : m_dtmsh) dt = std::min(dt, idt);
    1479                 :            : 
    1480                 :            :     // clear dt-vector and counter
    1481                 :        251 :     m_dtmsh.clear();
    1482                 :        251 :     m_ndtmsh = 0;
    1483                 :            : 
    1484                 :            :     // broadcast to advance time step
    1485         [ +  + ]:        503 :     for (auto& m : m_scheme) {
    1486         [ +  - ]:        252 :       m.bcast< Scheme::advance >( dt, F );
    1487                 :            :     }
    1488                 :            :   }
    1489                 :        252 : }
    1490                 :            : 
    1491                 :            : void
    1492                 :        173 : Transporter::inthead( const InciterPrint& print )
    1493                 :            : // *****************************************************************************
    1494                 :            : // Print out time integration header to screen
    1495                 :            : //! \param[in] print Pretty printer object to use for printing
    1496                 :            : // *****************************************************************************
    1497                 :            : {
    1498                 :        173 :   auto refined = g_inputdeck.get< tag::field_output, tag::refined >();
    1499                 :        173 :   const auto scheme = g_inputdeck.get< tag::scheme >();
    1500 [ +  + ][ -  + ]:        173 :   if (refined && scheme == ctr::SchemeType::DGP0) {
    1501         [ -  - ]:          0 :     printer() << "\n>>> WARNING: Ignoring refined field output for DG(P0)\n\n";
    1502                 :          0 :     refined = false;
    1503                 :            :   }
    1504                 :            : 
    1505 [ +  - ][ +  - ]:        519 :   print.inthead( "Time integration", "Euler/Navier-Stokes solver",
         [ +  - ][ +  - ]
    1506                 :            :   "Legend: it - iteration count\n"
    1507                 :            :   "         t - physics time\n"
    1508                 :            :   "        dt - physics time step size\n"
    1509                 :            :   "       ETE - estimated wall-clock time elapsed (h:m:s)\n"
    1510                 :            :   "       ETA - estimated wall-clock time for accomplishment (h:m:s)\n"
    1511                 :            :   "       EGT - estimated grind wall-clock time (ms/timestep)\n"
    1512                 :            :   "       flg - status flags, legend:\n"
    1513 [ +  + ][ +  - ]:        346 :   "             f - " + std::string(refined ? "refined " : "")
                 [ +  - ]
    1514         [ +  - ]:        346 :                       + "field (volume and surface)\n"
    1515                 :            :   "             d - diagnostics\n"
    1516                 :            :   "             t - physics time history\n"
    1517                 :            :   "             h - h-refinement\n"
    1518                 :            :   "             l - load balancing\n"
    1519                 :            :   "             r - checkpoint\n"
    1520                 :            :   "             a - ALE mesh velocity linear solver did not converge\n",
    1521                 :            :   "\n      it             t            dt        ETE        ETA        EGT  flg\n"
    1522                 :            :     " -------------------------------------------------------------------------\n" );
    1523                 :        173 : }
    1524                 :            : 
    1525                 :            : void
    1526                 :       2805 : Transporter::diagnostics( CkReductionMsg* msg )
    1527                 :            : // *****************************************************************************
    1528                 :            : // Reduction target optionally collecting diagnostics, e.g., residuals
    1529                 :            : //! \param[in] msg Serialized diagnostics vector aggregated across all PEs
    1530                 :            : //! \note Only used for nodal schemes
    1531                 :            : // *****************************************************************************
    1532                 :            : {
    1533                 :            :   std::size_t meshid, ncomp;
    1534                 :       5610 :   std::vector< std::vector< tk::real > > d;
    1535                 :            : 
    1536                 :            :   // Deserialize diagnostics vector
    1537         [ +  - ]:       5610 :   PUP::fromMem creator( msg->getData() );
    1538         [ +  - ]:       2805 :   creator | meshid;
    1539         [ +  - ]:       2805 :   creator | ncomp;
    1540         [ +  - ]:       2805 :   creator | d;
    1541 [ +  - ][ +  - ]:       2805 :   delete msg;
    1542                 :            : 
    1543         [ +  - ]:       5610 :   auto id = std::to_string(meshid);
    1544                 :            : 
    1545 [ -  + ][ -  - ]:       2805 :   Assert( ncomp > 0, "Number of scalar components must be positive");
         [ -  - ][ -  - ]
    1546 [ -  + ][ -  - ]:       2805 :   Assert( d.size() == NUMDIAG, "Diagnostics vector size mismatch" );
         [ -  - ][ -  - ]
    1547                 :            : 
    1548         [ +  + ]:      36465 :   for (std::size_t i=0; i<d.size(); ++i)
    1549 [ -  + ][ -  - ]:      33660 :      Assert( d[i].size() == ncomp, "Size mismatch at final stage of "
         [ -  - ][ -  - ]
    1550                 :            :              "diagnostics aggregation for mesh " + id );
    1551                 :            : 
    1552                 :            :   // Allocate storage for those diagnostics that are always computed
    1553         [ +  - ]:       5610 :   std::vector< tk::real > diag( ncomp, 0.0 );
    1554                 :            : 
    1555                 :            :   // Finish computing diagnostics
    1556         [ +  + ]:      18697 :   for (std::size_t i=0; i<d[L2SOL].size(); ++i)
    1557                 :      15892 :     diag[i] = sqrt( d[L2SOL][i] / m_meshvol[meshid] );
    1558                 :            :   
    1559                 :            :   // Query user-requested error types to output
    1560                 :       2805 :   const auto& error = g_inputdeck.get< tag::diagnostics, tag::error >();
    1561                 :            : 
    1562                 :       2805 :   decltype(ncomp) n = 0;
    1563                 :       2805 :   n += ncomp;
    1564         [ +  - ]:       2805 :   if (error == tk::ctr::ErrorType::L2) {
    1565                 :            :    // Finish computing the L2 norm of the numerical - analytical solution
    1566         [ +  + ]:      18697 :    for (std::size_t i=0; i<d[L2ERR].size(); ++i)
    1567         [ +  - ]:      15892 :      diag.push_back( sqrt( d[L2ERR][i] / m_meshvol[meshid] ) );
    1568         [ -  - ]:          0 :   } else if (error == tk::ctr::ErrorType::LINF) {
    1569                 :            :     // Finish computing the Linf norm of the numerical - analytical solution
    1570         [ -  - ]:          0 :     for (std::size_t i=0; i<d[LINFERR].size(); ++i)
    1571         [ -  - ]:          0 :       diag.push_back( d[LINFERR][i] );
    1572                 :            :   }
    1573                 :            : 
    1574                 :            :   // Finish computing the L2 norm of the residual and append
    1575                 :       2805 :   const auto scheme = g_inputdeck.get< tag::scheme >();
    1576         [ +  - ]:       5610 :   std::vector< tk::real > l2res( d[L2RES].size(), 0.0 );
    1577 [ +  + ][ +  + ]:       2805 :   if (scheme == ctr::SchemeType::ALECG || scheme == ctr::SchemeType::OversetFE) {
    1578         [ +  + ]:       6920 :     for (std::size_t i=0; i<d[L2RES].size(); ++i) {
    1579                 :       5754 :       l2res[i] = std::sqrt( d[L2RES][i] / m_meshvol[meshid] );
    1580         [ +  - ]:       5754 :       diag.push_back( l2res[i] );
    1581                 :       1166 :     }
    1582                 :            :   }
    1583 [ +  + ][ +  + ]:       1639 :   else if ( scheme == ctr::SchemeType::FV ||
    1584         [ +  + ]:        635 :             scheme == ctr::SchemeType::DGP0 ||
    1585         [ +  + ]:        305 :             scheme == ctr::SchemeType::DGP1 ||
    1586         [ +  + ]:        269 :             scheme == ctr::SchemeType::DGP2 ||
    1587         [ +  - ]:         44 :             scheme == ctr::SchemeType::P0P1 ||
    1588                 :            :             scheme == ctr::SchemeType::PDG
    1589                 :            :           ) {
    1590         [ +  + ]:      11777 :     for (std::size_t i=0; i<d[L2RES].size(); ++i) {
    1591                 :      10138 :       l2res[i] = std::sqrt( d[L2RES][i] );
    1592         [ +  - ]:      10138 :       diag.push_back( l2res[i] );
    1593                 :            :     }
    1594                 :            :   }
    1595                 :            : 
    1596                 :            :   // Append total energy
    1597         [ +  - ]:       2805 :   diag.push_back( d[TOTALSOL][0] );
    1598                 :            : 
    1599                 :            :   // Append resultant force, torque, displacement, and rotation vector
    1600         [ +  + ]:       2805 :   if (scheme == ctr::SchemeType::OversetFE) {
    1601         [ +  + ]:        756 :     for (std::size_t i=0; i<3; ++i)
    1602         [ +  - ]:        567 :       diag.push_back( d[RESFORCE][i] );
    1603         [ +  + ]:        756 :     for (std::size_t i=0; i<3; ++i)
    1604         [ +  - ]:        567 :       diag.push_back( d[RESTORQUE][i] );
    1605         [ +  + ]:        756 :     for (std::size_t i=0; i<3; ++i)
    1606         [ +  - ]:        567 :       diag.push_back( d[DISPLACEMNT][i] );
    1607         [ +  + ]:        756 :     for (std::size_t i=0; i<3; ++i)
    1608         [ +  - ]:        567 :       diag.push_back( d[ROTATION][i] );
    1609                 :            :   }
    1610                 :            : 
    1611                 :            :   // Append diagnostics file at selected times
    1612         [ +  - ]:       5610 :   auto filename = g_inputdeck.get< tag::cmd, tag::io, tag::diag >();
    1613 [ +  + ][ +  - ]:       2805 :   if (m_nelem.size() > 1) filename += '.' + id;
                 [ +  - ]
    1614                 :            :   tk::DiagWriter dw( filename,
    1615                 :       2805 :     g_inputdeck.get< tag::diagnostics, tag::format >(),
    1616                 :       2805 :     g_inputdeck.get< tag::diagnostics, tag::precision >(),
    1617         [ +  - ]:       5610 :     std::ios_base::app );
    1618         [ +  - ]:       2805 :   dw.diag( static_cast<uint64_t>(d[ITER][0]), d[TIME][0], d[DT][0], diag );
    1619                 :            : 
    1620                 :            :   // Continue time step
    1621         [ +  - ]:       2805 :   m_scheme[meshid].bcast< Scheme::refine >( l2res );
    1622                 :       2805 : }
    1623                 :            : 
    1624                 :            : void
    1625                 :        175 : Transporter::resume()
    1626                 :            : // *****************************************************************************
    1627                 :            : // Resume execution from checkpoint/restart files
    1628                 :            : //! \details This is invoked by Charm++ after the checkpoint is done, as well as
    1629                 :            : //!   when the restart (returning from a checkpoint) is complete
    1630                 :            : // *****************************************************************************
    1631                 :            : {
    1632         [ +  + ]:        351 :   if (std::any_of(begin(m_finished), end(m_finished), [](auto f){return !f;})) {
    1633                 :            :     // If just restarted from a checkpoint, Main( CkMigrateMessage* msg ) has
    1634                 :            :     // increased nrestart in g_inputdeck, but only on PE 0, so broadcast.
    1635                 :          2 :     auto nrestart = g_inputdeck.get< tag::cmd, tag::io, tag::nrestart >();
    1636         [ +  + ]:          4 :     for (std::size_t i=0; i<m_nelem.size(); ++i)
    1637         [ +  - ]:          2 :       m_scheme[i].bcast< Scheme::evalLB >( nrestart );
    1638                 :            :   } else
    1639                 :        173 :     mainProxy.finalize();
    1640                 :        175 : }
    1641                 :            : 
    1642                 :            : void
    1643                 :        174 : Transporter::checkpoint( std::size_t finished, std::size_t meshid )
    1644                 :            : // *****************************************************************************
    1645                 :            : // Save checkpoint/restart files
    1646                 :            : //! \param[in] finished Nonzero if finished with time stepping
    1647                 :            : //! \param[in] meshid Mesh id
    1648                 :            : // *****************************************************************************
    1649                 :            : {
    1650                 :        174 :   m_finished[meshid] = finished;
    1651                 :            : 
    1652         [ +  + ]:        174 :   if (++m_nchk == m_nelem.size()) { // all worker arrays have checkpointed
    1653                 :        173 :     m_nchk = 0;
    1654         [ +  + ]:        173 :     if (not g_inputdeck.get< tag::cmd, tag::benchmark >()) {
    1655                 :        101 :       const auto& restart = g_inputdeck.get< tag::cmd, tag::io, tag::restart >();
    1656 [ +  - ][ +  - ]:        202 :       CkCallback res( CkIndex_Transporter::resume(), thisProxy );
    1657         [ +  - ]:        101 :       CkStartCheckpoint( restart.c_str(), res );
    1658                 :            :     } else {
    1659                 :         72 :       resume();
    1660                 :            :     }
    1661                 :            :   }
    1662                 :        174 : }
    1663                 :            : 
    1664                 :            : void
    1665                 :        174 : Transporter::finish( std::size_t meshid )
    1666                 :            : // *****************************************************************************
    1667                 :            : // Normal finish of time stepping
    1668                 :            : //! \param[in] meshid Mesh id
    1669                 :            : // *****************************************************************************
    1670                 :            : {
    1671                 :        174 :   checkpoint( /* finished = */ 1, meshid );
    1672                 :        174 : }
    1673                 :            : 
    1674                 :            : #include "NoWarning/transporter.def.h"

Generated by: LCOV version 1.14