Xyst test code coverage report
Current view: top level - Inciter - Transporter.cpp (source / functions) Hit Total Coverage
Commit: 7512f2d92be539d3e2bf801c81cb357720d8ffd7 Lines: 733 842 87.1 %
Date: 2025-04-27 10:04:21 Functions: 42 47 89.4 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 840 1922 43.7 %

           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                 :            :              2022-2025 J. Bakosi
       8                 :            :              All rights reserved. See the LICENSE file for details.
       9                 :            :   \brief     Transporter drives the time integration of transport equations
      10                 :            :   \details   Transporter drives the time integration of transport equations.
      11                 :            :     The implementation uses the Charm++ runtime system and is fully asynchronous,
      12                 :            :     overlapping computation, communication as well as I/O. The algorithm
      13                 :            :     utilizes the structured dagger (SDAG) Charm++ functionality. The high-level
      14                 :            :     overview of the algorithm structure and how it interfaces with Charm++ is
      15                 :            :     discussed in the Charm++ interface file src/Inciter/transporter.ci.
      16                 :            : */
      17                 :            : // *****************************************************************************
      18                 :            : 
      19                 :            : #include <string>
      20                 :            : #include <iomanip>
      21                 :            : #include <cstddef>
      22                 :            : #include <unordered_set>
      23                 :            : 
      24                 :            : #include "Transporter.hpp"
      25                 :            : #include "Fields.hpp"
      26                 :            : #include "UniPDF.hpp"
      27                 :            : #include "PDFWriter.hpp"
      28                 :            : #include "ContainerUtil.hpp"
      29                 :            : #include "LoadDistributor.hpp"
      30                 :            : #include "ExodusIIMeshReader.hpp"
      31                 :            : #include "InciterConfig.hpp"
      32                 :            : #include "DiagWriter.hpp"
      33                 :            : #include "Diagnostics.hpp"
      34                 :            : #include "Integrals.hpp"
      35                 :            : #include "Callback.hpp"
      36                 :            : #include "Problems.hpp"
      37                 :            : 
      38                 :            : #include "NoWarning/inciter.decl.h"
      39                 :            : #include "NoWarning/partitioner.decl.h"
      40                 :            : #include "NoWarning/transfer.decl.h"
      41                 :            : 
      42                 :            : extern CProxy_Main mainProxy;
      43                 :            : 
      44                 :            : namespace inciter {
      45                 :            : 
      46                 :            : extern ctr::Config g_cfg;
      47                 :            : extern int g_nrestart;
      48                 :            : 
      49                 :            : }
      50                 :            : 
      51                 :            : using inciter::Transporter;
      52                 :            : 
      53                 :        256 : Transporter::Transporter() :
      54         [ +  - ]:        256 :   m_input{ g_cfg.get< tag::input >() },
      55         [ +  - ]:        256 :   m_nchare( m_input.size() ),
      56         [ +  - ]:        256 :   m_ncit( m_nchare.size(), 0 ),
      57                 :        256 :   m_ndt( 0 ),
      58                 :        256 :   m_mindt( std::numeric_limits< tk::real >::max() ),
      59                 :        256 :   m_nload( 0 ),
      60                 :        256 :   m_npart( 0 ),
      61                 :        256 :   m_nstat( 0 ),
      62                 :        256 :   m_ndisc( 0 ),
      63                 :        256 :   m_nchk( 0 ),
      64                 :        256 :   m_ncom( 0 ),
      65         [ +  - ]:        256 :   m_nt0refit( m_nchare.size(), 0 ),
      66         [ +  - ]:        256 :   m_ndtrefit( m_nchare.size(), 0 ),
      67         [ +  - ]:        256 :   m_noutrefit( m_nchare.size(), 0 ),
      68         [ +  - ]:        256 :   m_noutderefit( m_nchare.size(), 0 ),
      69         [ +  - ]:        256 :   m_nelem( m_nchare.size() ),
      70         [ +  - ]:        256 :   m_finished( m_nchare.size(), 0 ),
      71         [ +  - ]:        256 :   m_meshvol( m_nchare.size() ),
      72         [ +  - ]:        256 :   m_minstat( m_nchare.size() ),
      73         [ +  - ]:        256 :   m_maxstat( m_nchare.size() ),
      74         [ +  - ]:        256 :   m_avgstat( m_nchare.size() ),
      75         [ +  - ]:        256 :   m_progMesh( g_cfg.get< tag::feedback >(), ProgMeshPrefix, ProgMeshLegend ),
      76         [ +  - ]:       1536 :   m_progWork( g_cfg.get< tag::feedback >(), ProgWorkPrefix, ProgWorkLegend )
      77                 :            : // *****************************************************************************
      78                 :            : //  Constructor
      79                 :            : // *****************************************************************************
      80                 :            : {
      81                 :        256 :   const auto nstep = g_cfg.get< tag::nstep >();
      82                 :        256 :   const auto t0 = g_cfg.get< tag::t0 >();
      83                 :        256 :   const auto term = g_cfg.get< tag::term >();
      84                 :        256 :   const auto constdt = g_cfg.get< tag::dt >();
      85                 :            : 
      86                 :            :   // If the desired max number of time steps is larger than zero, and the
      87                 :            :   // termination time is larger than the initial time, and the constant time
      88                 :            :   // step size (if that is used) is smaller than the duration of the time to be
      89                 :            :   // simulated, we have work to do, otherwise, finish right away. If a constant
      90                 :            :   // dt is not used, that part of the logic is always true as the default
      91                 :            :   // constdt is zero.
      92 [ +  - ][ +  - ]:        256 :   if ( nstep != 0 && term > t0 && constdt < term-t0 ) {
                 [ +  - ]
      93                 :            : 
      94                 :            :     // Enable SDAG waits
      95         [ +  - ]:        256 :     thisProxy.wait4stat();
      96         [ +  - ]:        256 :     thisProxy.wait4part();
      97                 :            : 
      98                 :            :     // Configure and write diagnostics file header
      99         [ +  - ]:        256 :     diagHeader();
     100                 :            : 
     101                 :            :     // Configure and write integrals file header
     102         [ +  - ]:        256 :     integralsHeader();
     103                 :            : 
     104                 :            :     // Create mesh partitioner AND boundary condition object group
     105         [ +  - ]:        256 :     createPartitioner();
     106                 :            : 
     107         [ -  - ]:          0 :   } else finish();      // stop if no time stepping requested
     108                 :        255 : }
     109                 :            : 
     110                 :         12 : Transporter::Transporter( CkMigrateMessage* m ) :
     111                 :            :   CBase_Transporter( m ),
     112         [ +  - ]:         12 :   m_progMesh( g_cfg.get< tag::feedback >(), ProgMeshPrefix, ProgMeshLegend ),
     113         [ +  - ]:         24 :   m_progWork( g_cfg.get< tag::feedback >(), ProgWorkPrefix, ProgWorkLegend )
     114                 :            : // *****************************************************************************
     115                 :            : //  Migrate constructor: returning from a checkpoint
     116                 :            : //! \param[in] m Charm++ migrate message
     117                 :            : // *****************************************************************************
     118                 :            : {
     119                 :         12 :   auto print = tk::Print();
     120         [ +  - ]:         12 :   print << "\nXyst> Restarted from checkpoint\n";
     121         [ +  - ]:         12 :   inthead( print );
     122                 :         12 : }
     123                 :            : 
     124                 :            : bool
     125                 :        255 : Transporter::matchsets( std::map< int, std::vector< std::size_t > >& bnd,
     126                 :            :                         const std::string& filename )
     127                 :            : // *****************************************************************************
     128                 :            : // Verify that side sets referred to in the control file exist in mesh file
     129                 :            : //! \param[in,out] bnd Node or face lists mapped to side set ids
     130                 :            : //! \param[in] filename Mesh file name whose BCs are processed
     131                 :            : //! \details This function does two things: (1) it verifies that the side
     132                 :            : //!   sets used in the input file (either to which boundary conditions (BC)
     133                 :            : //!   are assigned or listed as field output by the user in the
     134                 :            : //!   input file) all exist among the side sets read from the input mesh
     135                 :            : //!   file and errors out if at least one does not, and (2) it matches the
     136                 :            : //!   side set ids at which the user has configured BCs (or listed as an output
     137                 :            : //!   surface) to side set ids read from the mesh file and removes those face
     138                 :            : //!   and node lists associated to side sets that the user did not set BCs or
     139                 :            : //!   listed as field output on (as they will not need processing further since
     140                 :            : //!   they will not be used).
     141                 :            : //! \return True if sidesets have been used and found in mesh
     142                 :            : // *****************************************************************************
     143                 :            : {
     144                 :        255 :   std::unordered_set< int > usersets;
     145                 :            : 
     146                 :            :   // Collect side sets referred to
     147                 :            : 
     148         [ +  + ]:        674 :   for (const auto& s : g_cfg.get< tag::bc_dir >()) {
     149 [ +  - ][ +  - ]:        419 :     if (!s.empty()) usersets.insert(s[0]);
     150                 :            :   }
     151                 :            : 
     152 [ +  - ][ +  + ]:        510 :   for (auto s : g_cfg.get< tag::bc_sym >()) usersets.insert(s);
     153                 :            : 
     154 [ +  - ][ +  + ]:        265 :   for (auto s : g_cfg.get< tag::bc_far, tag::sidesets >()) usersets.insert(s);
     155                 :            : 
     156         [ +  + ]:        267 :   for (const auto& s : g_cfg.get< tag::bc_pre, tag::sidesets >()) {
     157 [ +  - ][ +  - ]:         12 :     if (!s.empty()) usersets.insert(s[0]);
     158                 :            :   }
     159                 :            : 
     160         [ +  + ]:        328 :   for (const auto& s : g_cfg.get< tag::pressure, tag::bc_dir >()) {
     161 [ +  - ][ +  - ]:         73 :     if (!s.empty()) usersets.insert(s[0]);
     162                 :            :   }
     163                 :            : 
     164 [ +  - ][ +  + ]:        258 :   for (auto s : g_cfg.get< tag::pressure, tag::bc_sym >()) usersets.insert(s);
     165                 :            : 
     166 [ +  - ][ +  + ]:        289 :   for (auto s : g_cfg.get< tag::fieldout, tag::sidesets >()) usersets.insert(s);
     167 [ +  - ][ +  + ]:        268 :   for (auto s : g_cfg.get< tag::integout, tag::sidesets >()) usersets.insert(s);
     168                 :            : 
     169                 :            :   // Find user-configured side set ids among side sets read from mesh file
     170                 :        255 :   std::unordered_set< int > sidesets_used;
     171         [ +  + ]:       1020 :   for (auto i : usersets) {       // for all side sets used in control file
     172 [ +  - ][ +  - ]:        765 :     if (bnd.find(i) != end(bnd))  // used set found among side sets in file
     173         [ +  - ]:        765 :       sidesets_used.insert( i );  // store side set id configured as BC
     174                 :            :     else {
     175 [ -  - ][ -  - ]:          0 :       Throw( "Side set " + std::to_string(i) + " referred to in control file "
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
     176                 :            :              " but does not exist in mesh file '" + filename + "'" );
     177                 :            :     }
     178                 :            :   }
     179                 :            :  
     180                 :            :   // Remove sidesets not used (will not process those further)
     181         [ +  - ]:        255 :   tk::erase_if( bnd, [&]( auto& item ) {
     182         [ +  - ]:       1388 :     return sidesets_used.find( item.first ) == end(sidesets_used);
     183                 :            :   });
     184                 :            : 
     185                 :        510 :   return not bnd.empty();
     186                 :        255 : }
     187                 :            : 
     188                 :            : bool
     189                 :          0 : Transporter::matchsets_multi( std::map< int, std::vector< std::size_t > >& bnd,
     190                 :            :                               const std::string& filename,
     191                 :            :                               std::size_t meshid )
     192                 :            : // *****************************************************************************
     193                 :            : // Verify that side sets referred to in the control file exist in mesh file
     194                 :            : //! \note Multi-mesh version, used with overset methods.
     195                 :            : //! \param[in,out] bnd Node or face lists mapped to side set ids
     196                 :            : //! \param[in] filename Mesh file name whose BCs are processed
     197                 :            : //! \details This function does two things: (1) it verifies that the side
     198                 :            : //!   sets used in the input file (either to which boundary conditions (BC)
     199                 :            : //!   are assigned or listed as field output by the user in the
     200                 :            : //!   input file) all exist among the side sets read from the input mesh
     201                 :            : //!   file and errors out if at least one does not, and (2) it matches the
     202                 :            : //!   side set ids at which the user has configured BCs (or listed as an output
     203                 :            : //!   surface) to side set ids read from the mesh file and removes those face
     204                 :            : //!   and node lists associated to side sets that the user did not set BCs or
     205                 :            : //!   listed as field output on (as they will not need processing further since
     206                 :            : //!   they will not be used).
     207                 :            : //! \param[in] meshid Mesh id whose side sets are interrogated
     208                 :            : //! \return True if sidesets have been used and found in mesh
     209                 :            : // *****************************************************************************
     210                 :            : {
     211                 :          0 :   std::unordered_set< int > usersets;
     212                 :            : 
     213                 :            :   // Collect side sets referred to
     214                 :            : 
     215         [ -  - ]:          0 :   for (const auto& s : g_cfg.get< tag::bc_dir_ >()[ meshid ]) {
     216 [ -  - ][ -  - ]:          0 :     if (!s.empty()) usersets.insert(s[0]);
     217                 :            :   }
     218                 :            : 
     219 [ -  - ][ -  - ]:          0 :   for (auto s : g_cfg.get< tag::bc_sym_ >()[ meshid ]) usersets.insert(s);
     220                 :            : 
     221         [ -  - ]:          0 :   for (auto s : g_cfg.get< tag::bc_far_ >()[ meshid ].get< tag::sidesets >()) {
     222         [ -  - ]:          0 :     usersets.insert(s);
     223                 :            :   }
     224                 :            : 
     225                 :          0 :   for (const auto& s :
     226         [ -  - ]:          0 :          g_cfg.get< tag::bc_pre_ >()[ meshid ].get< tag::sidesets >())
     227                 :            :   {
     228 [ -  - ][ -  - ]:          0 :     if (!s.empty()) usersets.insert(s[0]);
     229                 :            :   }
     230                 :            : 
     231                 :          0 :   const auto& tp = g_cfg.get< tag::pressure_ >()[ meshid ];
     232         [ -  - ]:          0 :   for (const auto& s : tp.get< tag::bc_dir >()) {
     233 [ -  - ][ -  - ]:          0 :     if (!s.empty()) usersets.insert(s[0]);
     234                 :            :   }
     235         [ -  - ]:          0 :   for (auto s : tp.get< tag::bc_sym >()) {
     236         [ -  - ]:          0 :     usersets.insert(s);
     237                 :            :   }
     238                 :            : 
     239         [ -  - ]:          0 :   for (auto s : g_cfg.get< tag::fieldout_ >()[ meshid ].get< tag::sidesets >()){
     240         [ -  - ]:          0 :     usersets.insert(s);
     241                 :            :   }
     242         [ -  - ]:          0 :   for (auto s : g_cfg.get< tag::integout_ >()[ meshid ].get< tag::sidesets >()){
     243         [ -  - ]:          0 :     usersets.insert(s);
     244                 :            :   }
     245         [ -  - ]:          0 :   for (auto s : g_cfg.get< tag::overset, tag::intergrid_ >()[ meshid ]){
     246         [ -  - ]:          0 :     usersets.insert(s);
     247                 :            :   }
     248                 :            : 
     249                 :            :   // Find user-configured side set ids among side sets read from mesh file
     250                 :          0 :   std::unordered_set< int > sidesets_used;
     251         [ -  - ]:          0 :   for (auto i : usersets) {       // for all side sets used in control file
     252 [ -  - ][ -  - ]:          0 :     if (bnd.find(i) != end(bnd))  // used set found among side sets in file
     253         [ -  - ]:          0 :       sidesets_used.insert( i );  // store side set id configured as BC
     254                 :            :     else {
     255 [ -  - ][ -  - ]:          0 :       Throw( "Side set " + std::to_string(i) + " referred to in control file "
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
     256                 :            :              " but does not exist in mesh file '" + filename + "'" );
     257                 :            :     }
     258                 :            :   }
     259                 :            : 
     260                 :            :   // Remove sidesets not used (will not process those further)
     261         [ -  - ]:          0 :   tk::erase_if( bnd, [&]( auto& item ) {
     262         [ -  - ]:          0 :     return sidesets_used.find( item.first ) == end(sidesets_used);
     263                 :            :   });
     264                 :            : 
     265                 :          0 :   return not bnd.empty();
     266                 :          0 : }
     267                 :            : 
     268                 :            : void
     269                 :        256 : Transporter::createPartitioner()
     270                 :            : // *****************************************************************************
     271                 :            : // Create mesh partitioner AND boundary conditions group
     272                 :            : // *****************************************************************************
     273                 :            : {
     274                 :            :   // cppcheck-suppress unreadVariable
     275                 :        256 :   auto print = tk::Print();
     276                 :            : 
     277                 :            :   // Create partitioner callbacks (order important)
     278                 :            :   tk::PartitionerCallback cbp {{
     279 [ +  - ][ +  - ]:        256 :       CkCallback( CkReductionTarget(Transporter,queriedPart), thisProxy )
     280 [ +  - ][ +  - ]:        512 :     , CkCallback( CkReductionTarget(Transporter,respondedPart), thisProxy )
     281 [ +  - ][ +  - ]:        512 :     , CkCallback( CkReductionTarget(Transporter,load), thisProxy )
     282 [ +  - ][ +  - ]:        512 :     , CkCallback( CkReductionTarget(Transporter,partitioned), thisProxy )
     283 [ +  - ][ +  - ]:        512 :     , CkCallback( CkReductionTarget(Transporter,distributed), thisProxy )
     284 [ +  - ][ +  - ]:        512 :     , CkCallback( CkReductionTarget(Transporter,refinserted), thisProxy )
     285                 :        256 :   }};
     286                 :            : 
     287                 :            :   // Create refiner callbacks (order important)
     288                 :            :   tk::RefinerCallback cbr {{
     289 [ +  - ][ +  - ]:        256 :       CkCallback( CkReductionTarget(Transporter,queriedRef), thisProxy )
     290 [ +  - ][ +  - ]:        512 :     , CkCallback( CkReductionTarget(Transporter,respondedRef), thisProxy )
     291 [ +  - ][ +  - ]:        512 :     , CkCallback( CkReductionTarget(Transporter,compatibility), thisProxy )
     292 [ +  - ][ +  - ]:        512 :     , CkCallback( CkReductionTarget(Transporter,bndint), thisProxy )
     293 [ +  - ][ +  - ]:        512 :     , CkCallback( CkReductionTarget(Transporter,matched), thisProxy )
     294 [ +  - ][ +  - ]:        512 :     , CkCallback( CkReductionTarget(Transporter,refined), thisProxy )
     295                 :        256 :   }};
     296                 :            : 
     297                 :            :   // Create sorter callbacks (order important)
     298                 :            :   tk::SorterCallback cbs {{
     299 [ +  - ][ +  - ]:        256 :       CkCallback( CkReductionTarget(Transporter,queried), thisProxy )
     300 [ +  - ][ +  - ]:        512 :     , CkCallback( CkReductionTarget(Transporter,responded), thisProxy )
     301 [ +  - ][ +  - ]:        512 :     , CkCallback( CkReductionTarget(Transporter,discinserted), thisProxy )
     302 [ +  - ][ +  - ]:        512 :     , CkCallback( CkReductionTarget(Transporter,workinserted), thisProxy )
     303                 :        256 :   }};
     304                 :            : 
     305                 :            :   // Start timer measuring preparation of mesh(es) for partitioning
     306         [ +  - ]:        256 :   m_timer[ TimerTag::MESH_READ ];
     307                 :            : 
     308 [ -  + ][ -  - ]:        256 :   ErrChk( !m_input.empty(), "No input mesh" );
         [ -  - ][ -  - ]
     309                 :            : 
     310                 :            :   // Start preparing mesh(es)
     311 [ -  + ][ +  - ]:        256 :   print.section( "Reading mesh" + std::string(m_input.size()>1?"es":"") );
         [ +  - ][ +  - ]
     312                 :            : 
     313                 :        256 :   std::size_t meshid = 0;
     314                 :        256 :   bool multi = m_input.size() > 1;
     315                 :            : 
     316                 :            :   // Create empty discretization chare array for all meshes
     317                 :        256 :   std::vector< CkArrayOptions > opt;
     318         [ +  + ]:        512 :   for (std::size_t i=0; i<m_input.size(); ++i) {
     319 [ +  - ][ +  - ]:        256 :     m_discretization.push_back( CProxy_Discretization::ckNew() );
                 [ +  - ]
     320         [ +  - ]:        256 :     opt.emplace_back();
     321 [ +  - ][ +  - ]:        256 :     opt.back().bindTo( m_discretization.back() );
     322                 :            :   }
     323                 :            : 
     324                 :            :   // Create Partitioner Charm++ chare nodegroup for all meshes
     325         [ +  + ]:        511 :   for (const auto& filename : m_input) {
     326                 :            :     // Create mesh reader for reading side sets from file
     327         [ +  - ]:        256 :     tk::ExodusIIMeshReader mr( filename );
     328                 :            : 
     329                 :            :     // Read out total number of mesh points from mesh file
     330 [ +  - ][ +  - ]:        256 :     m_npoin.push_back( mr.npoin() );
     331                 :            : 
     332                 :        256 :     std::map< int, std::vector< std::size_t > > bface;
     333                 :        256 :     std::map< int, std::vector< std::size_t > > faces;
     334                 :        256 :     std::map< int, std::vector< std::size_t > > bnode;
     335                 :            : 
     336                 :            :     // Read boundary-face connectivity on side sets
     337         [ +  - ]:        256 :     mr.readSidesetFaces( bface, faces );
     338                 :            : 
     339                 :        255 :     bool bcs_set = false;
     340                 :            :     // Read node lists on side sets
     341         [ +  - ]:        255 :     bnode = mr.readSidesetNodes();
     342                 :            :     // Verify that side sets referred to in the control file exist in mesh file
     343         [ -  + ]:        255 :     if (multi) {
     344         [ -  - ]:          0 :       bcs_set = matchsets_multi( bnode, filename, meshid );
     345 [ -  - ][ -  - ]:          0 :       bcs_set = bcs_set || matchsets_multi( bface, filename, meshid );
                 [ -  - ]
     346                 :            :     }
     347                 :            :     else {
     348         [ +  - ]:        255 :       bcs_set = matchsets( bnode, filename );
     349 [ -  + ][ -  - ]:        255 :       bcs_set = bcs_set || matchsets( bface, filename );
                 [ -  - ]
     350                 :            :     }
     351                 :            : 
     352                 :            :     // Warn on no BCs
     353         [ -  + ]:        255 :     if (!bcs_set) {
     354                 :            :       print << "\n>>> WARNING: No boundary conditions set for mesh "
     355 [ -  - ][ -  - ]:          0 :                 + std::to_string(meshid) + ": " + filename + "\n\n";
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
     356                 :            :     }
     357                 :            : 
     358                 :            :     // Create empty discretization scheme chare array (bound to discretization)
     359                 :        255 :     CProxy_RieCG riecg;
     360                 :        255 :     CProxy_LaxCG laxcg;
     361                 :        255 :     CProxy_ZalCG zalcg;
     362                 :        255 :     CProxy_KozCG kozcg;
     363                 :        255 :     CProxy_ChoCG chocg;
     364                 :        255 :     CProxy_LohCG lohcg;
     365                 :        255 :     tk::CProxy_ConjugateGradients cgpre, cgmom;
     366                 :        255 :     const auto& mopt = opt[ meshid ];
     367                 :        255 :     const auto& solver = g_cfg.get< tag::solver >();
     368         [ +  + ]:        255 :     if (solver == "riecg") {
     369 [ +  - ][ +  - ]:         73 :       m_riecg.push_back( CProxy_RieCG::ckNew(mopt) );
                 [ +  - ]
     370         [ +  - ]:         73 :       riecg = m_riecg.back();
     371                 :            :     }
     372         [ +  + ]:        182 :     else if (solver == "laxcg") {
     373 [ +  - ][ +  - ]:         23 :       m_laxcg.push_back( CProxy_LaxCG::ckNew(mopt) );
                 [ +  - ]
     374         [ +  - ]:         23 :       laxcg = m_laxcg.back();
     375                 :            :     }
     376         [ +  + ]:        159 :     else if (solver == "zalcg") {
     377 [ +  - ][ +  - ]:         36 :       m_zalcg.push_back( CProxy_ZalCG::ckNew(mopt) );
                 [ +  - ]
     378         [ +  - ]:         36 :       zalcg = m_zalcg.back();
     379                 :            :     }
     380         [ +  + ]:        123 :     else if (solver == "kozcg") {
     381 [ +  - ][ +  - ]:         44 :       m_kozcg.push_back( CProxy_KozCG::ckNew(mopt) );
                 [ +  - ]
     382         [ +  - ]:         44 :       kozcg = m_kozcg.back();
     383                 :            :     }
     384         [ +  + ]:         79 :     else if (solver == "chocg") {
     385 [ +  - ][ +  - ]:         46 :       m_chocg.push_back( CProxy_ChoCG::ckNew(mopt) );
                 [ +  - ]
     386         [ +  - ]:         46 :       chocg = m_chocg.back();
     387 [ +  - ][ +  - ]:         46 :       m_cgpre.push_back( tk::CProxy_ConjugateGradients::ckNew(mopt) );
                 [ +  - ]
     388         [ +  - ]:         46 :       cgpre = m_cgpre.back();
     389 [ +  - ][ +  - ]:         46 :       m_cgmom.push_back( tk::CProxy_ConjugateGradients::ckNew(mopt) );
                 [ +  - ]
     390         [ +  - ]:         46 :       cgmom = m_cgmom.back();
     391                 :            :     }
     392         [ +  - ]:         33 :     else if (solver == "lohcg") {
     393 [ +  - ][ +  - ]:         33 :       m_lohcg.push_back( CProxy_LohCG::ckNew(mopt) );
                 [ +  - ]
     394         [ +  - ]:         33 :       lohcg = m_lohcg.back();
     395 [ +  - ][ +  - ]:         33 :       m_cgpre.push_back( tk::CProxy_ConjugateGradients::ckNew(mopt) );
                 [ +  - ]
     396         [ +  - ]:         33 :       cgpre = m_cgpre.back();
     397                 :            :     }
     398                 :            :     else {
     399 [ -  - ][ -  - ]:          0 :       Throw( "Unknown solver: " + solver );
                 [ -  - ]
     400                 :            :     }
     401                 :            : 
     402                 :            :     // Create empty mesh refiner chare array (bound to discretization)
     403 [ +  - ][ +  - ]:        255 :     m_refiner.push_back( CProxy_Refiner::ckNew(mopt) );
                 [ +  - ]
     404                 :            :     // Create empty mesh sorter Charm++ chare array (bound to discretization)
     405 [ +  - ][ +  - ]:        255 :     m_sorter.push_back( CProxy_Sorter::ckNew(mopt) );
                 [ +  - ]
     406                 :            : 
     407                 :            :     // Create MeshWriter chare group for mesh
     408 [ +  - ][ +  - ]:        255 :     m_meshwriter.push_back(
     409                 :            :       tk::CProxy_MeshWriter::ckNew(
     410                 :        255 :         g_cfg.get< tag::benchmark >(), m_input.size() ) );
     411                 :            : 
     412                 :            :     // Create mesh partitioner Charm++ chare nodegroup for all meshes
     413         [ +  - ]:        255 :     m_partitioner.push_back(
     414                 :            :       CProxy_Partitioner::ckNew( meshid, filename, cbp, cbr, cbs,
     415         [ +  - ]:        255 :         thisProxy, m_refiner.back(), m_sorter.back(), m_meshwriter.back(),
     416                 :        255 :         m_discretization, riecg, laxcg, zalcg, kozcg, chocg, lohcg,
     417                 :            :         cgpre, cgmom, bface, faces, bnode ) );
     418                 :            : 
     419                 :        255 :     ++meshid;
     420                 :        255 :   }
     421                 :        255 : }
     422                 :            : 
     423                 :            : void
     424                 :        255 : Transporter::load( std::size_t meshid, std::size_t nelem )
     425                 :            : // *****************************************************************************
     426                 :            : // Reduction target: the mesh has been read from file on all PEs
     427                 :            : //! \param[in] meshid Mesh id (summed accross all compute nodes)
     428                 :            : //! \param[in] nelem Number of mesh elements per mesh (summed across all
     429                 :            : //!    compute nodes)
     430                 :            : // *****************************************************************************
     431                 :            : {
     432                 :        255 :   meshid /= static_cast< std::size_t >( CkNumNodes() );
     433 [ -  + ][ -  - ]:        255 :   Assert( meshid < m_nelem.size(), "MeshId indexing out" );
         [ -  - ][ -  - ]
     434                 :        255 :   m_nelem[meshid] = nelem;
     435                 :            : 
     436                 :            :   // Compute load distribution given total work (nelem) and user-specified
     437                 :            :   // virtualization
     438                 :            :   uint64_t chunksize, remainder;
     439                 :        510 :   m_nchare[ meshid ] = static_cast<int>(
     440         [ +  - ]:        510 :     tk::linearLoadDistributor(
     441                 :        255 :        g_cfg.get< tag::virt >()[ meshid ],
     442                 :        255 :        m_nelem[meshid], CkNumPes(), chunksize, remainder ) );
     443                 :            : 
     444                 :            :   // Tell meshwriter the total number of chares
     445         [ +  - ]:        255 :   m_meshwriter[meshid].nchare( meshid, m_nchare[meshid] );
     446                 :            : 
     447                 :            :   // Store sum of meshids (across all chares, key) for each meshid (value).
     448                 :            :   // This is used to look up the mesh id after collectives that sum their data.
     449         [ +  - ]:        255 :   m_meshid[ static_cast<std::size_t>(m_nchare[meshid])*meshid ] = meshid;
     450 [ -  + ][ -  - ]:        255 :   Assert( meshid < m_nelem.size(), "MeshId indexing out" );
         [ -  - ][ -  - ]
     451                 :            : 
     452         [ +  - ]:        255 :   if (++m_nload == m_nelem.size()) {     // all meshes have been loaded
     453         [ +  - ]:        255 :     m_timer[ TimerTag::MESH_PART ];  // start timer measuring mesh partitioning
     454                 :            : 
     455                 :            :     // Start partitioning all meshes
     456         [ +  + ]:        510 :     for (std::size_t p=0; p<m_partitioner.size(); ++p) {
     457         [ +  - ]:        255 :       m_partitioner[p].partition( m_nchare[p] );
     458                 :            :     }
     459                 :            : 
     460                 :        255 :     m_nload = 0;
     461                 :        255 :     auto print = tk::Print();
     462                 :        255 :     bool multi = m_input.size() > 1;
     463 [ -  + ][ +  - ]:        255 :     std::string es = multi ? "es" : "";
     464                 :            : 
     465         [ +  - ]:        255 :     auto& timer = tk::ref_find( m_timer, TimerTag::MESH_READ );
     466         [ +  - ]:        255 :     timer.second = timer.first.dsec();
     467 [ +  - ][ +  - ]:        255 :     print << "Mesh read time: " + std::to_string( timer.second ) + " sec\n";
         [ +  - ][ +  - ]
     468                 :            : 
     469                 :            :     // Print out mesh partitioning configuration
     470 [ +  - ][ +  - ]:        255 :     print.section( "Partitioning mesh"+es );
     471                 :            : 
     472         [ -  + ]:        255 :     if (multi) {
     473 [ -  - ][ -  - ]:          0 :       print.item( "Partitioner (per mesh)",
     474         [ -  - ]:          0 :                   tk::parameters( g_cfg.get< tag::part_ >() ) );
     475 [ -  - ][ -  - ]:          0 :       print.item( "Virtualization (per mesh)",
     476         [ -  - ]:          0 :                   tk::parameters( g_cfg.get< tag::virt >() ) );
     477                 :            :     }
     478                 :            :     else {
     479 [ +  - ][ +  - ]:        255 :       print.item( "Partitioner", g_cfg.get< tag::part >() );
     480 [ +  - ][ +  - ]:        255 :       print.item( "Virtualization", g_cfg.get< tag::virt >()[ 0 ] );
     481                 :            :     }
     482                 :            : 
     483                 :            :     // Print out initial mesh statistics
     484 [ +  - ][ +  - ]:        255 :     meshstat( "Mesh"+es+" read from file" );
                 [ +  - ]
     485                 :            : 
     486                 :            :     // Query number of initial mesh refinement steps
     487                 :        255 :     int nref = 0;
     488         [ -  + ]:        255 :     const auto& ht = multi ? g_cfg.get< tag::href_ >()[ meshid ]
     489                 :        255 :                            : g_cfg.get< tag::href >();
     490         [ +  + ]:        255 :     if (ht.get< tag::t0 >()) {
     491                 :         12 :       nref = static_cast<int>( ht.get< tag::init >().size() );
     492                 :            :     }
     493                 :            : 
     494                 :            :     // Query if PE-local reorder is configured
     495                 :        255 :     int nreord = 0;
     496         [ +  + ]:        255 :     if (g_cfg.get< tag::reorder >()) nreord = m_nchare[0];
     497                 :            : 
     498         [ +  - ]:        255 :     print << '\n';
     499 [ +  - ][ +  - ]:        510 :     m_progMesh.start( print, "Preparing mesh"+es, {{ CkNumPes(), CkNumPes(),
     500                 :        255 :       nref, m_nchare[0], m_nchare[0], nreord, nreord }} );
     501                 :        255 :   }
     502                 :        255 : }
     503                 :            : 
     504                 :            : void
     505                 :        255 : Transporter::partitioned()
     506                 :            : // *****************************************************************************
     507                 :            : // Reduction target: all meshes have been partitioned
     508                 :            : // *****************************************************************************
     509                 :            : {
     510         [ +  - ]:        255 :   if (++m_npart == m_nelem.size()) {     // all meshes have been partitioned
     511                 :        255 :     m_npart = 0;
     512         [ +  - ]:        255 :     auto& timer = tk::ref_find( m_timer, TimerTag::MESH_PART );
     513                 :        255 :     timer.second = timer.first.dsec();
     514                 :            :   }
     515                 :        255 : }
     516                 :            : 
     517                 :            : void
     518                 :        255 : Transporter::distributed( std::size_t meshid )
     519                 :            : // *****************************************************************************
     520                 :            : // Reduction target: all compute nodes have distributed their mesh after
     521                 :            : // partitioning
     522                 :            : //! \param[in] meshid Mesh id
     523                 :            : // *****************************************************************************
     524                 :            : {
     525                 :        255 :   m_partitioner[meshid].refine();
     526                 :        255 : }
     527                 :            : 
     528                 :            : void
     529                 :        255 : Transporter::refinserted( std::size_t meshid, std::size_t error )
     530                 :            : // *****************************************************************************
     531                 :            : // Reduction target: all compute nodes have created the mesh refiners
     532                 :            : //! \param[in] meshid Mesh id (aggregated across all compute nodes with operator
     533                 :            : //!   max)
     534                 :            : //! \param[in] error Error code (aggregated across all compute nodes with
     535                 :            : //!   operator max)
     536                 :            : // *****************************************************************************
     537                 :            : {
     538         [ -  + ]:        255 :   if (error) {
     539                 :            : 
     540                 :          0 :     tk::Print() <<
     541                 :            :         "\n>>> ERROR: A worker chare was not assigned any mesh "
     542 [ -  - ][ -  - ]:          0 :         "elements after distributing mesh " + std::to_string(meshid) +
                 [ -  - ]
     543                 :            :         ". This can happen in SMP-mode with a large +ppn parameter (number "
     544                 :            :         "of worker threads per logical node) or using zoltan's hypergraph "
     545                 :            :         "partitioning (phg), which is non-determinsitic. Solution 1: In SMP "
     546                 :            :         "mode decrease +ppn. Solution 2: Try a different partitioning "
     547                 :            :         "algorithm, e.g., rcb, rib, or hsfc, or configure phg differently by "
     548                 :            :         "passing extra zoltan parameters in the control file. To learn how, "
     549         [ -  - ]:          0 :         "grep tests/ for 'zoltan_params'.";
     550                 :          0 :     finish( meshid );
     551                 :            : 
     552                 :            :   } else {
     553                 :            : 
     554                 :        255 :     m_refiner[meshid].doneInserting();
     555                 :            : 
     556                 :            :   }
     557                 :        255 : }
     558                 :            : 
     559                 :            : void
     560                 :         38 : Transporter::queriedRef( std::size_t meshid )
     561                 :            : // *****************************************************************************
     562                 :            : // Reduction target: all Refiner chares have queried their boundary edges
     563                 :            : //! \param[in] meshid Mesh id
     564                 :            : // *****************************************************************************
     565                 :            : {
     566                 :         38 :   m_refiner[meshid].response();
     567                 :         38 : }
     568                 :            : 
     569                 :            : void
     570                 :         38 : Transporter::respondedRef( std::size_t meshid )
     571                 :            : // *****************************************************************************
     572                 :            : // Reduction target: all Refiner chares have setup their boundary edges
     573                 :            : //! \param[in] meshid Mesh id
     574                 :            : // *****************************************************************************
     575                 :            : {
     576                 :         38 :   m_refiner[meshid].refine();
     577                 :         38 : }
     578                 :            : 
     579                 :            : void
     580                 :         25 : Transporter::compatibility( std::size_t meshid )
     581                 :            : // *****************************************************************************
     582                 :            : // Reduction target: all Refiner chares have received a round of edges,
     583                 :            : // and have run their compatibility algorithm
     584                 :            : //! \param[in] meshid Mesh id (aggregated across all chares using operator max)
     585                 :            : //! \details This is called iteratively, until convergence by Refiner. At this
     586                 :            : //!   point all Refiner chares have received a round of edge data (tags whether
     587                 :            : //!   an edge needs to be refined, etc.), and applied the compatibility
     588                 :            : //!   algorithm independent of other Refiner chares. We keep going until the
     589                 :            : //!   mesh is no longer modified by the compatibility algorithm, based on a new
     590                 :            : //!   round of edge data communication started in Refiner::comExtra().
     591                 :            : // *****************************************************************************
     592                 :            : {
     593                 :         25 :   m_refiner[meshid].correctref();
     594                 :         25 : }
     595                 :            : 
     596                 :            : void
     597                 :         38 : Transporter::matched( std::size_t summeshid,
     598                 :            :                       std::size_t nextra,
     599                 :            :                       std::size_t nref,
     600                 :            :                       std::size_t nderef,
     601                 :            :                       std::size_t sumrefmode )
     602                 :            : // *****************************************************************************
     603                 :            : // Reduction target: all Refiner chares have matched/corrected the tagging
     604                 :            : // of chare-boundary edges, all chares are ready to perform refinement.
     605                 :            : //! \param[in] summeshid Mesh id (summed across all chares)
     606                 :            : //! \param[in] nextra Sum (across all chares) of the number of edges on each
     607                 :            : //!   chare that need correction along chare boundaries
     608                 :            : //! \param[in] nref Sum of number of refined tetrahedra across all chares.
     609                 :            : //! \param[in] nderef Sum of number of derefined tetrahedra across all chares.
     610                 :            : //! \param[in] sumrefmode Sum of contributions from all chares, encoding
     611                 :            : //!   refinement mode of operation.
     612                 :            : // *****************************************************************************
     613                 :            : {
     614                 :         38 :   auto meshid = tk::cref_find( m_meshid, summeshid );
     615                 :            : 
     616                 :            :   // If at least a single edge on a chare still needs correction, do correction,
     617                 :            :   // otherwise, this mesh refinement step is complete
     618         [ -  + ]:         38 :   if (nextra > 0) {
     619                 :            : 
     620                 :          0 :     ++m_ncit[meshid];
     621                 :          0 :     m_refiner[meshid].comExtra();
     622                 :            : 
     623                 :            :   } else {
     624                 :            : 
     625                 :         38 :     tk::Print print;
     626                 :            : 
     627                 :            :     // decode refmode
     628                 :            :     auto refmode = static_cast< Refiner::RefMode >(
     629                 :         38 :                      sumrefmode / static_cast<std::size_t>(m_nchare[meshid]) );
     630                 :            : 
     631         [ +  - ]:         38 :     if (refmode == Refiner::RefMode::T0REF) {
     632                 :            : 
     633         [ +  + ]:         38 :       if (!g_cfg.get< tag::feedback >()) {
     634                 :         35 :         bool multi = m_input.size() > 1;
     635         [ -  + ]:         35 :         const auto& ht = multi ? g_cfg.get< tag::href_ >()[ meshid ]
     636                 :         35 :                                : g_cfg.get< tag::href >();
     637                 :         35 :         const auto& initref = ht.get< tag::init >();
     638         [ +  - ]:         35 :         print << '\n';
     639 [ +  - ][ +  - ]:        525 :         print.diag( { "meshid", "t0ref", "type", "nref", "nderef", "ncorr" },
         [ +  - ][ +  + ]
         [ +  + ][ -  - ]
                 [ -  - ]
     640                 :            :                     { std::to_string(meshid),
     641                 :         35 :                       std::to_string(m_nt0refit[meshid]),
     642                 :         35 :                       initref[ m_nt0refit[ meshid ] ],
     643                 :            :                       std::to_string(nref),
     644                 :            :                       std::to_string(nderef),
     645                 :         35 :                       std::to_string(m_ncit[meshid]) } );
     646                 :         35 :         ++m_nt0refit[meshid];
     647 [ +  + ][ +  - ]:         35 :         if (m_nt0refit[meshid] == initref.size()) print << '\n';
     648                 :            :       }
     649         [ +  - ]:         38 :       m_progMesh.inc< REFINE >( print );
     650                 :            : 
     651         [ -  - ]:          0 :     } else if (refmode == Refiner::RefMode::DTREF) {
     652                 :            : 
     653 [ -  - ][ -  - ]:          0 :       print.diag( { "meshid", "dtref", "type", "nref", "nderef", "ncorr" },
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
                 [ -  - ]
     654                 :            :                   { std::to_string(meshid),
     655                 :          0 :                     std::to_string(++m_ndtrefit[meshid]),
     656                 :            :                     "error",
     657                 :            :                     std::to_string(nref),
     658                 :            :                     std::to_string(nderef),
     659                 :          0 :                     std::to_string(m_ncit[meshid]) } );
     660                 :            : 
     661 [ -  - ][ -  - ]:          0 :     } else Throw( "RefMode not implemented" );
                 [ -  - ]
     662                 :            : 
     663                 :         38 :     m_ncit[meshid] = 0;
     664         [ +  - ]:         38 :     m_refiner[meshid].perform();
     665                 :            : 
     666                 :            :   }
     667 [ +  - ][ +  - ]:        178 : }
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
     668                 :            : 
     669                 :            : void
     670                 :         38 : Transporter::bndint( tk::real sx, tk::real sy, tk::real sz, tk::real cb,
     671                 :            :                      tk::real summeshid )
     672                 :            : // *****************************************************************************
     673                 :            : // Compute surface integral across the whole problem and perform leak-test
     674                 :            : //! \param[in] sx X component of vector summed
     675                 :            : //! \param[in] sy Y component of vector summed
     676                 :            : //! \param[in] sz Z component of vector summed
     677                 :            : //! \param[in] cb Invoke callback if positive
     678                 :            : //! \param[in] summeshid Mesh id (summed accross all chares)
     679                 :            : //! \details This function aggregates partial surface integrals across the
     680                 :            : //!   boundary faces of the whole problem. After this global sum a
     681                 :            : //!   non-zero vector result indicates a leak, e.g., a hole in the boundary,
     682                 :            : //!   which indicates an error in the boundary face data structures used to
     683                 :            : //!   compute the partial surface integrals.
     684                 :            : // *****************************************************************************
     685                 :            : {
     686         [ +  - ]:         38 :   /*auto meshid =*/tk::cref_find( m_meshid, static_cast<std::size_t>(summeshid) );
     687                 :            : 
     688         [ +  - ]:         38 :   std::stringstream err;
     689         [ +  - ]:         38 :   if (cb < 0.0) {
     690                 :            :     err << "Mesh boundary leaky after mesh refinement step; this is due to a "
     691                 :            :      "problem with updating the side sets used to specify boundary conditions "
     692         [ +  - ]:         38 :      "on faces: ";
     693         [ -  - ]:          0 :   } else if (cb > 0.0) {
     694                 :            :     err << "Mesh boundary leaky during initialization; this is due to "
     695                 :            :     "incorrect or incompletely specified boundary conditions for a given input "
     696         [ -  - ]:          0 :     "mesh: ";
     697                 :            :   }
     698                 :            : 
     699                 :         38 :   auto eps = 1.0e-10;
     700 [ +  - ][ +  - ]:         38 :   if (std::abs(sx) > eps || std::abs(sy) > eps || std::abs(sz) > eps) {
         [ -  + ][ -  + ]
     701         [ -  - ]:          0 :     err << "Integral result must be a zero vector: " << std::setprecision(12) <<
     702 [ -  - ][ -  - ]:          0 :            std::abs(sx) << ", " << std::abs(sy) << ", " << std::abs(sz) <<
         [ -  - ][ -  - ]
                 [ -  - ]
     703 [ -  - ][ -  - ]:          0 :            ", eps = " << eps;
     704 [ -  - ][ -  - ]:          0 :     Throw( err.str() );
                 [ -  - ]
     705                 :            :   }
     706                 :         38 : }
     707                 :            : 
     708                 :            : void
     709                 :        255 : Transporter::refined( std::size_t summeshid,
     710                 :            :                       std::size_t nelem,
     711                 :            :                       std::size_t npoin )
     712                 :            : // *****************************************************************************
     713                 :            : // Reduction target: all chares have refined their mesh
     714                 :            : //! \param[in] summeshid Mesh id (summed accross all Refiner chares)
     715                 :            : //! \param[in] nelem Total number of elements in mesh summed across the
     716                 :            : //!   distributed mesh
     717                 :            : //! \param[in] npoin Total number of mesh points summed across the distributed
     718                 :            : //!   mesh. Note that in parallel this is larger than the number of points in
     719                 :            : //!   the mesh, because the boundary nodes are multi-counted. But we only need
     720                 :            : //!   an equal or larger than npoin for Sorter::setup, so this is okay.
     721                 :            : // *****************************************************************************
     722                 :            : {
     723                 :        255 :   auto meshid = tk::cref_find( m_meshid, summeshid );
     724                 :            : 
     725                 :            :   // Store new number of elements for initially refined mesh
     726                 :        255 :   m_nelem[meshid] = nelem;
     727                 :            : 
     728                 :        255 :   m_sorter[meshid].doneInserting();
     729                 :        255 :   m_sorter[meshid].setup( npoin );
     730                 :        255 : }
     731                 :            : 
     732                 :            : void
     733                 :        255 : Transporter::queriedPart( std::size_t meshid )
     734                 :            : // *****************************************************************************
     735                 :            : // Reduction target: all Partitioner nodes have queried their mesh graphs
     736                 :            : //! \param[in] meshid Mesh id
     737                 :            : // *****************************************************************************
     738                 :            : {
     739                 :        255 :   m_partitioner[meshid].response();
     740                 :        255 : }
     741                 :            : 
     742                 :            : void
     743                 :        255 : Transporter::respondedPart( std::size_t meshid )
     744                 :            : // *****************************************************************************
     745                 :            : // Reduction target: all Partitioner nodes have responded with their mesh graphs
     746                 :            : //! \param[in] meshid Mesh id
     747                 :            : // *****************************************************************************
     748                 :            : {
     749                 :        255 :   m_partitioner[meshid].load();
     750                 :        255 : }
     751                 :            : 
     752                 :            : void
     753                 :        255 : Transporter::queried( std::size_t meshid )
     754                 :            : // *****************************************************************************
     755                 :            : // Reduction target: all Sorter chares have queried their boundary edges
     756                 :            : //! \param[in] meshid Mesh id
     757                 :            : // *****************************************************************************
     758                 :            : {
     759                 :        255 :   m_sorter[meshid].response();
     760                 :        255 : }
     761                 :            : 
     762                 :            : void
     763                 :        255 : Transporter::responded( std::size_t meshid )
     764                 :            : // *****************************************************************************
     765                 :            : // Reduction target: all Sorter chares have responded with their boundary edges
     766                 :            : //! \param[in] meshid Mesh id
     767                 :            : // *****************************************************************************
     768                 :            : {
     769                 :        255 :   m_sorter[meshid].start();
     770                 :        255 : }
     771                 :            : 
     772                 :            : void
     773                 :          0 : Transporter::resized( std::size_t meshid )
     774                 :            : // *****************************************************************************
     775                 :            : // Reduction target: all worker chares have resized their own mesh data after
     776                 :            : //! \param[in] meshid Mesh id
     777                 :            : //! \note Only used for nodal schemes
     778                 :            : // *****************************************************************************
     779                 :            : {
     780                 :          0 :   m_discretization[ meshid ].vol();
     781                 :            : 
     782                 :          0 :   const auto& solver = g_cfg.get< tag::solver >();
     783         [ -  - ]:          0 :   if (solver == "riecg") {
     784                 :          0 :     m_riecg[ meshid ].feop();
     785                 :            :   }
     786         [ -  - ]:          0 :   else if (solver == "laxcg") {
     787                 :          0 :     m_laxcg[ meshid ].feop();
     788                 :            :   }
     789         [ -  - ]:          0 :   else if (solver == "zalcg") {
     790                 :          0 :     m_zalcg[ meshid ].feop();
     791                 :            :   }
     792         [ -  - ]:          0 :   else if (solver == "kozcg") {
     793                 :          0 :     m_kozcg[ meshid ].feop();
     794                 :            :   }
     795         [ -  - ]:          0 :   else if (solver == "chocg") {
     796                 :          0 :     m_chocg[ meshid ].feop();
     797                 :            :   }
     798         [ -  - ]:          0 :   else if (solver == "lohcg") {
     799                 :          0 :     m_lohcg[ meshid ].feop();
     800                 :            :   }
     801                 :            :   else {
     802 [ -  - ][ -  - ]:          0 :     Throw( "Unknown solver: " + solver  );
                 [ -  - ]
     803                 :            :   }
     804                 :          0 : }
     805                 :            : 
     806                 :            : void
     807                 :        255 : Transporter::discinserted( std::size_t meshid )
     808                 :            : // *****************************************************************************
     809                 :            : // Reduction target: all Discretization chares have been inserted
     810                 :            : //! \param[in] meshid Mesh id
     811                 :            : // *****************************************************************************
     812                 :            : {
     813                 :        255 :   m_discretization[ meshid ].doneInserting();
     814                 :        255 : }
     815                 :            : 
     816                 :            : void
     817                 :        267 : Transporter::meshstat( const std::string& header ) const
     818                 :            : // *****************************************************************************
     819                 :            : // Print out mesh statistics
     820                 :            : //! \param[in] header Section header
     821                 :            : // *****************************************************************************
     822                 :            : {
     823                 :        267 :   tk::Print print;
     824                 :            : 
     825         [ +  - ]:        267 :   print.section( header );
     826                 :            : 
     827         [ -  + ]:        267 :   if (m_nelem.size() > 1) {
     828 [ -  - ][ -  - ]:          0 :     print.item( "Number of tetrahedra (per mesh)",tk::parameters(m_nelem) );
                 [ -  - ]
     829 [ -  - ][ -  - ]:          0 :     print.item( "Number of points (per mesh)", tk::parameters(m_npoin) );
                 [ -  - ]
     830 [ -  - ][ -  - ]:          0 :     print.item( "Number of work units (per mesh)", tk::parameters(m_nchare) );
                 [ -  - ]
     831                 :            :   }
     832                 :            : 
     833 [ +  - ][ +  - ]:        267 :   print.item( "Total number of tetrahedra",
     834                 :        267 :               std::accumulate( begin(m_nelem), end(m_nelem), 0UL ) );
     835 [ +  - ][ +  - ]:        267 :   print.item( "Total number of points",
     836                 :        267 :               std::accumulate( begin(m_npoin), end(m_npoin), 0UL ) );
     837 [ +  - ][ +  - ]:        267 :   print.item( "Total number of work units",
     838                 :        267 :               std::accumulate( begin(m_nchare), end(m_nchare), 0 ) );
     839                 :        267 : }
     840                 :            : 
     841                 :            : void
     842                 :        255 : Transporter::disccreated( std::size_t summeshid, std::size_t npoin )
     843                 :            : // *****************************************************************************
     844                 :            : // Reduction target: all Discretization constructors have been called
     845                 :            : //! \param[in] summeshid Mesh id (summed accross all chares)
     846                 :            : //! \param[in] npoin Total number of mesh points (summed across all chares)
     847                 :            : //!  Note that as opposed to npoin in refined(), this npoin is not
     848                 :            : //!  multi-counted, and thus should be correct in parallel.
     849                 :            : // *****************************************************************************
     850                 :            : {
     851                 :        255 :   auto meshid = tk::cref_find( m_meshid, summeshid );
     852                 :        255 :   bool multi = m_input.size() > 1;
     853         [ -  + ]:        255 :   const auto& ht = multi ? g_cfg.get< tag::href_ >()[ meshid ]
     854                 :        255 :                          : g_cfg.get< tag::href >();
     855                 :            : 
     856                 :            :   // Update number of mesh points for mesh, since it may have been refined
     857         [ +  + ]:        255 :   if (ht.get< tag::t0 >()) m_npoin[meshid] = npoin;
     858                 :            : 
     859         [ +  - ]:        255 :   if (++m_ndisc == m_nelem.size()) { // all Disc arrays have been created
     860                 :        255 :     m_ndisc = 0;
     861                 :        255 :     tk::Print print;
     862         [ +  - ]:        255 :     m_progMesh.end( print );
     863 [ +  + ][ +  - ]:        255 :     if (ht.get< tag::t0 >()) meshstat( "Mesh initially refined" );
                 [ +  - ]
     864                 :            :   }
     865                 :            : 
     866                 :        255 :   m_refiner[ meshid ].sendProxy();
     867                 :        255 :   m_discretization[ meshid ].vol();
     868                 :            : 
     869         [ +  - ]:        255 :   m_discretization[0][0].npoin(
     870         [ +  - ]:        255 :     std::accumulate( begin(m_npoin), end(m_npoin), 0UL ) );
     871                 :        255 : }
     872                 :            : 
     873                 :            : void
     874                 :        255 : Transporter::workinserted( std::size_t meshid )
     875                 :            : // *****************************************************************************
     876                 :            : // Reduction target: all worker (derived discretization) chares have been
     877                 :            : // inserted
     878                 :            : //! \param[in] meshid Mesh id
     879                 :            : // *****************************************************************************
     880                 :            : {
     881                 :        255 :   const auto& solver = g_cfg.get< tag::solver >();
     882         [ +  + ]:        255 :   if (solver == "riecg") {
     883                 :         73 :     m_riecg[ meshid ].doneInserting();
     884                 :            :   }
     885         [ +  + ]:        182 :   else if (solver == "laxcg") {
     886                 :         23 :     m_laxcg[ meshid ].doneInserting();
     887                 :            :   }
     888         [ +  + ]:        159 :   else if (solver == "zalcg") {
     889                 :         36 :     m_zalcg[ meshid ].doneInserting();
     890                 :            :   }
     891         [ +  + ]:        123 :   else if (solver == "kozcg") {
     892                 :         44 :     m_kozcg[ meshid ].doneInserting();
     893                 :            :   }
     894         [ +  + ]:         79 :   else if (solver == "chocg") {
     895                 :         46 :     m_chocg[ meshid ].doneInserting();
     896                 :         46 :     m_cgpre[ meshid ].doneInserting();
     897                 :         46 :     m_cgmom[ meshid ].doneInserting();
     898                 :            :   }
     899         [ +  - ]:         33 :   else if (solver == "lohcg") {
     900                 :         33 :     m_lohcg[ meshid ].doneInserting();
     901                 :         33 :     m_cgpre[ meshid ].doneInserting();
     902                 :            :   }
     903                 :            :   else {
     904 [ -  - ][ -  - ]:          0 :     Throw( "Unknown solver: " + solver );
                 [ -  - ]
     905                 :            :   }
     906                 :        255 : }
     907                 :            : 
     908                 :            : void
     909                 :        256 : Transporter::diagHeader()
     910                 :            : // *****************************************************************************
     911                 :            : // Configure and write diagnostics file header
     912                 :            : // *****************************************************************************
     913                 :            : {
     914                 :            :   // Construct header for diagnostics file output
     915                 :            : 
     916                 :        256 :   std::vector< std::string > d;
     917                 :            : 
     918                 :        256 :   const auto& solver = g_cfg.get< tag::solver >();
     919         [ +  + ]:        439 :   if (solver == "riecg" ||
     920         [ +  + ]:        343 :       solver == "laxcg" ||
     921 [ +  + ][ +  + ]:        599 :       solver == "zalcg" ||
                 [ +  + ]
     922                 :        124 :       solver == "kozcg")
     923                 :            :   {
     924                 :            : 
     925                 :            :     // Collect variables names for integral/diagnostics output
     926 [ +  - ][ +  + ]:       1056 :     std::vector< std::string > var{ "r", "ru", "rv", "rw", "rE" };
                 [ -  - ]
     927                 :        352 :     auto ncomp = g_cfg.get< tag::problem_ncomp >();
     928         [ +  + ]:        200 :     for (std::size_t c=5; c<ncomp; ++c)
     929 [ +  - ][ +  - ]:         24 :       var.push_back( "c" + std::to_string(c-5) );
                 [ +  - ]
     930                 :            : 
     931                 :        176 :     auto nv = var.size();
     932                 :            : 
     933                 :            :     // Add 'L2(var)' for all variables
     934 [ +  - ][ +  - ]:       1080 :     for (std::size_t i=0; i<nv; ++i) d.push_back( "L2(" + var[i] + ')' );
         [ +  - ][ +  + ]
     935                 :            : 
     936                 :            :     // Add L2-norm of the residuals
     937 [ +  - ][ +  - ]:       1080 :     for (std::size_t i=0; i<nv; ++i) d.push_back( "L2(d" + var[i] + ')' );
         [ +  - ][ +  + ]
     938                 :            : 
     939                 :            :     // Add total energy
     940 [ +  - ][ +  - ]:        176 :     d.push_back( "mE" );
     941                 :            : 
     942                 :            :     // Augment diagnostics variables by error norms (if computed)
     943 [ +  - ][ +  + ]:        176 :     if (problems::SOL()) {
     944 [ +  - ][ +  - ]:         62 :       d.push_back( "L2(err:r)" );
     945 [ +  - ][ +  - ]:         62 :       d.push_back( "L2(err:u)" );
     946 [ +  - ][ +  - ]:         62 :       d.push_back( "L2(err:v)" );
     947 [ +  - ][ +  - ]:         62 :       d.push_back( "L2(err:w)" );
     948 [ +  - ][ +  - ]:         62 :       d.push_back( "L2(err:e)" );
     949 [ +  - ][ +  - ]:         84 :       for (std::size_t i=5; i<nv; ++i) d.push_back( "L2(err:" + var[i] + ')' );
         [ +  - ][ +  + ]
     950 [ +  - ][ +  - ]:         62 :       d.push_back( "L1(err:r)" );
     951 [ +  - ][ +  - ]:         62 :       d.push_back( "L1(err:u)" );
     952 [ +  - ][ +  - ]:         62 :       d.push_back( "L1(err:v)" );
     953 [ +  - ][ +  - ]:         62 :       d.push_back( "L1(err:w)" );
     954 [ +  - ][ +  - ]:         62 :       d.push_back( "L1(err:e)" );
     955 [ +  - ][ +  - ]:         84 :       for (std::size_t i=5; i<nv; ++i) d.push_back( "L1(err:" + var[i] + ')' );
         [ +  - ][ +  + ]
     956                 :            :     }
     957                 :            : 
     958                 :        176 :   }
     959         [ +  + ]:         80 :   else if (solver == "chocg") {
     960                 :            : 
     961                 :            :     // query function to evaluate analytic solution (if defined)
     962         [ +  - ]:         47 :     auto pressure_sol = problems::PRESSURE_SOL();
     963                 :            : 
     964                 :            :     // Collect variables names for integral/diagnostics output
     965 [ +  - ][ +  + ]:         94 :     std::vector< std::string > var{ "p" };
                 [ -  - ]
     966         [ +  + ]:         47 :     if (!pressure_sol) {
     967 [ +  - ][ +  - ]:         40 :       var.push_back( "u" );
     968 [ +  - ][ +  - ]:         40 :       var.push_back( "v" );
     969 [ +  - ][ +  - ]:         40 :       var.push_back( "w" );
     970                 :            :     }
     971                 :            : 
     972                 :         47 :     auto ncomp = g_cfg.get< tag::problem_ncomp >();
     973         [ +  + ]:         53 :     for (std::size_t c=3; c<ncomp; ++c) {
     974 [ +  - ][ +  - ]:          6 :       var.push_back( "c" + std::to_string(c-3) );
                 [ +  - ]
     975                 :            :     }
     976                 :            : 
     977                 :         47 :     auto nv = var.size();
     978                 :            : 
     979                 :            :     // Add 'L2(var)' for all variables
     980 [ +  - ][ +  - ]:        220 :     for (std::size_t i=0; i<nv; ++i) d.push_back( "L2(" + var[i] + ')' );
         [ +  - ][ +  + ]
     981                 :            : 
     982                 :            :     // Add L2-norm of the residuals
     983 [ +  - ][ +  - ]:        220 :     for (std::size_t i=0; i<nv; ++i) d.push_back( "L2(d" + var[i] + ')' );
         [ +  - ][ +  + ]
     984                 :            : 
     985                 :            :     // Augment diagnostics variables by error norms of pressure (if computed)
     986         [ +  + ]:         47 :     if (pressure_sol) {
     987 [ +  - ][ +  - ]:          7 :       d.push_back( "L2(err:p)" );
     988 [ +  - ][ +  - ]:          7 :       d.push_back( "L1(err:p)" );
     989                 :            :     }
     990                 :            :     // Augment diagnostics variables by error norms of adv/diff (if computed)
     991 [ +  - ][ +  + ]:         40 :     else if (problems::SOL()) {
     992 [ +  - ][ +  - ]:          5 :       d.push_back( "L2(err:u)" );
     993 [ +  - ][ +  - ]:          5 :       d.push_back( "L2(err:v)" );
     994 [ +  - ][ +  - ]:          5 :       d.push_back( "L2(err:w)" );
     995 [ +  - ][ +  - ]:         10 :       for (std::size_t i=4; i<nv; ++i) d.push_back( "L2(err:" + var[i] + ')' );
         [ +  - ][ +  + ]
     996 [ +  - ][ +  - ]:          5 :       d.push_back( "L1(err:u)" );
     997 [ +  - ][ +  - ]:          5 :       d.push_back( "L1(err:v)" );
     998 [ +  - ][ +  - ]:          5 :       d.push_back( "L1(err:w)" );
     999 [ +  - ][ +  - ]:         10 :       for (std::size_t i=4; i<nv; ++i) d.push_back( "L1(err:" + var[i] + ')' );
         [ +  - ][ +  + ]
    1000                 :            :     }
    1001                 :            : 
    1002                 :         47 :   }
    1003         [ +  - ]:         33 :   else if (solver == "lohcg") {
    1004                 :            : 
    1005                 :            :     // Collect variables names for integral/diagnostics output
    1006 [ +  - ][ +  + ]:         66 :     std::vector< std::string > var{ "p" };
                 [ -  - ]
    1007 [ +  - ][ +  - ]:         33 :     var.push_back( "u" );
    1008 [ +  - ][ +  - ]:         33 :     var.push_back( "v" );
    1009 [ +  - ][ +  - ]:         33 :     var.push_back( "w" );
    1010                 :            : 
    1011                 :         33 :     auto ncomp = g_cfg.get< tag::problem_ncomp >();
    1012         [ +  + ]:         37 :     for (std::size_t c=4; c<ncomp; ++c) {
    1013 [ +  - ][ +  - ]:          4 :       var.push_back( "c" + std::to_string(c-4) );
                 [ +  - ]
    1014                 :            :     }
    1015                 :            : 
    1016                 :         33 :     auto nv = var.size();
    1017                 :            : 
    1018                 :            :     // Add 'L2(var)' for all variables
    1019 [ +  - ][ +  - ]:        169 :     for (std::size_t i=0; i<nv; ++i) d.push_back( "L2(" + var[i] + ')' );
         [ +  - ][ +  + ]
    1020                 :            : 
    1021                 :            :     // Add L2-norm of the residuals
    1022 [ +  - ][ +  - ]:        169 :     for (std::size_t i=0; i<nv; ++i) d.push_back( "L2(d" + var[i] + ')' );
         [ +  - ][ +  + ]
    1023                 :            : 
    1024                 :            :     // Augment diagnostics variables by error norms of adv/diff (if computed)
    1025 [ +  - ][ +  + ]:         33 :     if (problems::SOL()) {
    1026 [ +  - ][ +  - ]:          4 :       d.push_back( "L2(err:u)" );
    1027 [ +  - ][ +  - ]:          4 :       d.push_back( "L2(err:v)" );
    1028 [ +  - ][ +  - ]:          4 :       d.push_back( "L2(err:w)" );
    1029 [ +  - ][ +  - ]:          8 :       for (std::size_t i=4; i<nv; ++i) d.push_back( "L2(err:" + var[i] + ')' );
         [ +  - ][ +  + ]
    1030 [ +  - ][ +  - ]:          4 :       d.push_back( "L1(err:u)" );
    1031 [ +  - ][ +  - ]:          4 :       d.push_back( "L1(err:v)" );
    1032 [ +  - ][ +  - ]:          4 :       d.push_back( "L1(err:w)" );
    1033 [ +  - ][ +  - ]:          8 :       for (std::size_t i=4; i<nv; ++i) d.push_back( "L1(err:" + var[i] + ')' );
         [ +  - ][ +  + ]
    1034                 :            :     }
    1035                 :            : 
    1036                 :         33 :   }
    1037                 :            :   else {
    1038 [ -  - ][ -  - ]:          0 :     Throw( "Unknown solver: " + solver );
                 [ -  - ]
    1039                 :            :   }
    1040                 :            : 
    1041                 :            :   // Output header for diagnostics output file(s)
    1042         [ +  - ]:        256 :   auto basename = g_cfg.get< tag::diag >();
    1043         [ +  - ]:        256 :   auto format = g_cfg.get< tag::diag_format >();
    1044                 :        256 :   auto precision = g_cfg.get< tag::diag_precision >();
    1045                 :        256 :   bool multi = m_input.size() > 1;
    1046         [ -  + ]:        256 :   if (multi) {
    1047         [ -  - ]:          0 :     for (std::size_t k=0; k<m_input.size(); ++k) {
    1048 [ -  - ][ -  - ]:          0 :       std::string name = basename + '.' + std::to_string(k);
                 [ -  - ]
    1049         [ -  - ]:          0 :       tk::DiagWriter dw( name, format, precision );
    1050         [ -  - ]:          0 :       dw.header( d );
    1051                 :          0 :     }
    1052                 :            :   }
    1053                 :            :   else {
    1054         [ +  - ]:        256 :     tk::DiagWriter dw( basename, format, precision );
    1055         [ +  - ]:        256 :     dw.header( d );
    1056                 :        256 :   }
    1057 [ +  - ][ +  - ]:        768 : }
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
                 [ -  - ]
    1058                 :            : 
    1059                 :            : void
    1060                 :        256 : Transporter::integralsHeader()
    1061                 :            : // *****************************************************************************
    1062                 :            : // Configure and write integrals file header
    1063                 :            : // *****************************************************************************
    1064                 :            : {
    1065                 :        256 :   const auto& ti = g_cfg.get< tag::integout >();
    1066                 :        256 :   const auto& sidesets_integral = ti.get< tag::sidesets  >();
    1067                 :            : 
    1068         [ +  + ]:        256 :   if (sidesets_integral.empty()) return;
    1069                 :            : 
    1070         [ +  - ]:          8 :   auto filename = g_cfg.get< tag::output >() + ".int";
    1071                 :            :   tk::DiagWriter dw( filename,
    1072                 :          8 :                      ti.get< tag::format >(),
    1073         [ +  - ]:          8 :                      ti.get< tag::precision >() );
    1074                 :            : 
    1075                 :            :   // Collect variables names for integral output
    1076                 :          8 :   std::vector< std::string > var;
    1077                 :          8 :   const auto& reqv = ti.get< tag::integrals >();
    1078         [ +  - ]:          8 :   std::unordered_set< std::string > req( begin(reqv), end(reqv) );
    1079         [ +  + ]:         21 :   for (auto s : sidesets_integral) {
    1080 [ +  - ][ +  - ]:         13 :     if (req.count( "mass_flow_rate" )) {
                 [ +  + ]
    1081 [ +  - ][ +  - ]:         10 :       var.push_back( "mass_flow_rate:" + std::to_string(s) );
    1082                 :            :     }
    1083 [ +  - ][ +  - ]:         13 :     if (req.count( "force" )) {
                 [ +  + ]
    1084                 :          3 :       auto si = std::to_string( s );
    1085 [ +  - ][ +  - ]:          3 :       var.push_back( "force_x:" + si );
    1086 [ +  - ][ +  - ]:          3 :       var.push_back( "force_y:" + si );
    1087 [ +  - ][ +  - ]:          3 :       var.push_back( "force_z:" + si );
    1088                 :          3 :     }
    1089                 :            :   }
    1090                 :            : 
    1091                 :            :   // Write integrals header
    1092         [ +  - ]:          8 :   dw.header( var );
    1093                 :          8 : }
    1094                 :            : 
    1095                 :            : void
    1096                 :        255 : Transporter::totalvol( tk::real v, tk::real initial, tk::real summeshid )
    1097                 :            : // *****************************************************************************
    1098                 :            : // Reduction target summing total mesh volume across all workers
    1099                 :            : //! \param[in] v Mesh volume summed across the distributed mesh
    1100                 :            : //! \param[in] initial Sum of contributions from all chares. If larger than
    1101                 :            : //!    zero, we are during setup, if zero, during time stepping.
    1102                 :            : //! \param[in] summeshid Mesh id (summed accross the distributed mesh)
    1103                 :            : // *****************************************************************************
    1104                 :            : {
    1105         [ +  - ]:        255 :   auto meshid = tk::cref_find( m_meshid, static_cast<std::size_t>(summeshid) );
    1106                 :            : 
    1107                 :        255 :   m_meshvol[meshid] = v;
    1108                 :            : 
    1109         [ +  - ]:        255 :   if (initial > 0.0) {   // during initialization
    1110                 :            : 
    1111                 :        255 :     m_discretization[ meshid ].stat( v );
    1112                 :            : 
    1113                 :            :   } else {               // during AMR
    1114                 :            : 
    1115                 :          0 :     const auto& solver = g_cfg.get< tag::solver >();
    1116         [ -  - ]:          0 :     if (solver == "riecg") {
    1117                 :          0 :       m_riecg[ meshid ].resize_complete();
    1118                 :            :     }
    1119         [ -  - ]:          0 :     else if (solver == "laxcg") {
    1120                 :          0 :       m_laxcg[ meshid ].resize_complete();
    1121                 :            :     }
    1122         [ -  - ]:          0 :     else if (solver == "zalcg") {
    1123                 :          0 :       m_zalcg[ meshid ].resize_complete();
    1124                 :            :     }
    1125         [ -  - ]:          0 :     else if (solver == "kozcg") {
    1126                 :          0 :       m_kozcg[ meshid ].resize_complete();
    1127                 :            :     }
    1128         [ -  - ]:          0 :     else if (solver == "chocg") {
    1129                 :          0 :       m_chocg[ meshid ].resize_complete();
    1130                 :            :     }
    1131         [ -  - ]:          0 :     else if (solver == "lohcg") {
    1132                 :          0 :       m_lohcg[ meshid ].resize_complete();
    1133                 :            :     }
    1134                 :            :     else {
    1135 [ -  - ][ -  - ]:          0 :       Throw( "Unknown solver: " + solver );
                 [ -  - ]
    1136                 :            :     }
    1137                 :            : 
    1138                 :            :   }
    1139                 :        255 : }
    1140                 :            : 
    1141                 :            : void
    1142                 :        255 : Transporter::minstat( tk::real d0, tk::real d1, tk::real d2, tk::real d3,
    1143                 :            :                       tk::real d4, tk::real d5, tk::real rmeshid )
    1144                 :            : // *****************************************************************************
    1145                 :            : // Reduction target yielding minimum mesh statistcs across all workers
    1146                 :            : //! \param[in] d0 Minimum mesh statistics collected over all chares
    1147                 :            : //! \param[in] d1 Minimum mesh statistics collected over all chares
    1148                 :            : //! \param[in] d2 Minimum mesh statistics collected over all chares
    1149                 :            : //! \param[in] d3 Minimum mesh statistics collected over all chares
    1150                 :            : //! \param[in] d4 Minimum mesh statistics collected over all chares
    1151                 :            : //! \param[in] d5 Minimum mesh statistics collected over all chares
    1152                 :            : //! \param[in] rmeshid Mesh id as a real
    1153                 :            : // *****************************************************************************
    1154                 :            : {
    1155                 :        255 :   auto meshid = static_cast<std::size_t>(rmeshid);
    1156                 :            : 
    1157                 :        255 :   m_minstat[meshid][0] = d0;  // minimum edge length
    1158                 :        255 :   m_minstat[meshid][1] = d1;  // minimum cell volume cubic root
    1159                 :        255 :   m_minstat[meshid][2] = d2;  // minimum number of elements on chare
    1160                 :        255 :   m_minstat[meshid][3] = d3;  // minimum number of points on chare
    1161                 :        255 :   m_minstat[meshid][4] = d4;  // minimum number of edges on chare
    1162                 :        255 :   m_minstat[meshid][5] = d5;  // minimum number of comm/total points on chare
    1163                 :            : 
    1164                 :        255 :   minstat_complete(meshid);
    1165                 :        255 : }
    1166                 :            : 
    1167                 :            : void
    1168                 :        255 : Transporter::maxstat( tk::real d0, tk::real d1, tk::real d2, tk::real d3,
    1169                 :            :                       tk::real d4, tk::real d5, tk::real rmeshid )
    1170                 :            : // *****************************************************************************
    1171                 :            : // Reduction target yielding the maximum mesh statistics across all workers
    1172                 :            : //! \param[in] d0 Maximum mesh statistics collected over all chares
    1173                 :            : //! \param[in] d1 Maximum mesh statistics collected over all chares
    1174                 :            : //! \param[in] d2 Maximum mesh statistics collected over all chares
    1175                 :            : //! \param[in] d3 Maximum mesh statistics collected over all chares
    1176                 :            : //! \param[in] d4 Minimum mesh statistics collected over all chares
    1177                 :            : //! \param[in] d5 Minimum mesh statistics collected over all chares
    1178                 :            : //! \param[in] rmeshid Mesh id as a real
    1179                 :            : // *****************************************************************************
    1180                 :            : {
    1181                 :        255 :   auto meshid = static_cast<std::size_t>(rmeshid);
    1182                 :            : 
    1183                 :        255 :   m_maxstat[meshid][0] = d0;  // maximum edge length
    1184                 :        255 :   m_maxstat[meshid][1] = d1;  // maximum cell volume cubic root
    1185                 :        255 :   m_maxstat[meshid][2] = d2;  // maximum number of elements on chare
    1186                 :        255 :   m_maxstat[meshid][3] = d3;  // maximum number of points on chare
    1187                 :        255 :   m_maxstat[meshid][4] = d4;  // maximum number of edges on chare
    1188                 :        255 :   m_maxstat[meshid][5] = d5;  // maximum number of comm/total points on chare
    1189                 :            : 
    1190                 :        255 :   maxstat_complete(meshid);
    1191                 :        255 : }
    1192                 :            : 
    1193                 :            : void
    1194                 :        255 : Transporter::sumstat( tk::real d0, tk::real d1, tk::real d2, tk::real d3,
    1195                 :            :                       tk::real d4, tk::real d5, tk::real d6, tk::real d7,
    1196                 :            :                       tk::real d8, tk::real summeshid )
    1197                 :            : // *****************************************************************************
    1198                 :            : // Reduction target yielding the sum mesh statistics across all workers
    1199                 :            : //! \param[in] d0 Sum mesh statistics collected over all chares
    1200                 :            : //! \param[in] d1 Sum mesh statistics collected over all chares
    1201                 :            : //! \param[in] d2 Sum mesh statistics collected over all chares
    1202                 :            : //! \param[in] d3 Sum mesh statistics collected over all chares
    1203                 :            : //! \param[in] d4 Sum mesh statistics collected over all chares
    1204                 :            : //! \param[in] d5 Sum mesh statistics collected over all chares
    1205                 :            : //! \param[in] d6 Sum mesh statistics collected over all chares
    1206                 :            : //! \param[in] d7 Sum mesh statistics collected over all chares
    1207                 :            : //! \param[in] d8 Sum mesh statistics collected over all chares
    1208                 :            : //! \param[in] summeshid Mesh id (summed accross the distributed mesh)
    1209                 :            : // *****************************************************************************
    1210                 :            : {
    1211         [ +  - ]:        255 :   auto meshid = tk::cref_find( m_meshid, static_cast<std::size_t>(summeshid) );
    1212                 :            : 
    1213                 :        255 :   m_avgstat[meshid][0] = d1 / d0;  // avg edge length
    1214                 :        255 :   m_avgstat[meshid][1] = d3 / d2;  // avg cell volume cubic root
    1215                 :        255 :   m_avgstat[meshid][2] = d5 / d4;  // avg number of elements per chare
    1216                 :        255 :   m_avgstat[meshid][3] = d6 / d4;  // avg number of points per chare
    1217                 :        255 :   m_avgstat[meshid][4] = d7 / d4;  // avg number of edges per chare
    1218                 :        255 :   m_avgstat[meshid][5] = d8 / d4;  // avg number of comm/total points per chare
    1219                 :            : 
    1220                 :        255 :   sumstat_complete(meshid);
    1221                 :        255 : }
    1222                 :            : 
    1223                 :            : void
    1224                 :        255 : Transporter::pdfstat( CkReductionMsg* msg )
    1225                 :            : // *****************************************************************************
    1226                 :            : // Reduction target yielding PDF of mesh statistics across all workers
    1227                 :            : //! \param[in] msg Serialized PDF
    1228                 :            : // *****************************************************************************
    1229                 :            : {
    1230                 :            :   std::size_t meshid;
    1231                 :        255 :   std::vector< tk::UniPDF > pdf;
    1232                 :            : 
    1233                 :            :   // Deserialize final PDF
    1234                 :        255 :   PUP::fromMem creator( msg->getData() );
    1235                 :            :   // cppcheck-suppress uninitvar
    1236         [ +  - ]:        255 :   creator | meshid;
    1237         [ +  - ]:        255 :   creator | pdf;
    1238 [ +  - ][ +  - ]:        255 :   delete msg;
    1239                 :            : 
    1240                 :            :   // cppcheck-suppress uninitvar
    1241         [ +  - ]:        255 :   auto id = std::to_string(meshid);
    1242                 :            : 
    1243                 :            :   // Create new PDF file (overwrite if exists)
    1244 [ +  - ][ +  - ]:        255 :   tk::PDFWriter pdfe( "mesh_edge_pdf." + id + ".txt" );
         [ +  - ][ +  - ]
    1245                 :            :   // Output edgelength PDF
    1246                 :            :   // cppcheck-suppress containerOutOfBounds
    1247         [ +  - ]:        255 :   pdfe.writeTxt( pdf[0],
    1248                 :        510 :                  tk::ctr::PDFInfo{ {"PDF"}, {}, {"edgelength"}, 0, 0.0 } );
    1249                 :            : 
    1250                 :            :   // Create new PDF file (overwrite if exists)
    1251 [ +  - ][ +  - ]:        255 :   tk::PDFWriter pdfv( "mesh_vol_pdf." + id + ".txt" );
         [ +  - ][ +  - ]
    1252                 :            :   // Output cell volume cubic root PDF
    1253                 :            :   // cppcheck-suppress containerOutOfBounds
    1254         [ +  - ]:        255 :   pdfv.writeTxt( pdf[1],
    1255                 :        510 :                  tk::ctr::PDFInfo{ {"PDF"}, {}, {"V^{1/3}"}, 0, 0.0 } );
    1256                 :            : 
    1257                 :            :   // Create new PDF file (overwrite if exists)
    1258 [ +  - ][ +  - ]:        255 :   tk::PDFWriter pdfn( "mesh_ntet_pdf." + id + ".txt" );
         [ +  - ][ +  - ]
    1259                 :            :   // Output number of cells PDF
    1260                 :            :   // cppcheck-suppress containerOutOfBounds
    1261         [ +  - ]:        255 :   pdfn.writeTxt( pdf[2],
    1262                 :        510 :                  tk::ctr::PDFInfo{ {"PDF"}, {}, {"ntets"}, 0, 0.0 } );
    1263                 :            : 
    1264                 :        255 :   pdfstat_complete(meshid);
    1265 [ +  - ][ +  - ]:       2295 : }
         [ +  - ][ +  + ]
         [ +  - ][ +  - ]
         [ +  - ][ +  + ]
         [ +  - ][ +  - ]
         [ +  - ][ +  + ]
         [ +  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
         [ -  - ][ -  - ]
                 [ -  - ]
    1266                 :            : 
    1267                 :            : void
    1268                 :        255 : Transporter::stat()
    1269                 :            : // *****************************************************************************
    1270                 :            : // Echo diagnostics on mesh statistics
    1271                 :            : // *****************************************************************************
    1272                 :            : {
    1273                 :        255 :   tk::Print print;
    1274                 :            : 
    1275         [ +  - ]:        255 :   if (++m_nstat == m_nelem.size()) {     // stats from all meshes have arrived
    1276                 :        255 :     m_nstat = 0;
    1277                 :            : 
    1278         [ +  - ]:        255 :     auto& t = tk::ref_find( m_timer, TimerTag::MESH_PART );
    1279         [ +  - ]:        255 :     print << '\n';
    1280 [ +  - ][ +  - ]:        255 :     print << "Mesh partitioning time: " + std::to_string(t.second) + " sec\n";
         [ +  - ][ +  - ]
    1281                 :            : 
    1282         [ +  + ]:        510 :     for (std::size_t i=0; i<m_nelem.size(); ++i) {
    1283         [ -  + ]:        255 :       if (m_nelem.size() > 1) {
    1284 [ -  - ][ -  - ]:          0 :         print.section("Mesh " + std::to_string(i) + " distribution statistics");
         [ -  - ][ -  - ]
    1285                 :            :       } else {
    1286 [ +  - ][ +  - ]:        255 :         print.section( "Mesh distribution statistics" );
    1287                 :            :       }
    1288                 :            :       print <<
    1289         [ +  - ]:        510 :         "min/max/avg edgelength = " +
    1290 [ +  - ][ +  - ]:       1020 :         std::to_string( m_minstat[i][0] ) + " / " +
                 [ +  - ]
    1291 [ +  - ][ +  - ]:       1020 :         std::to_string( m_maxstat[i][0] ) + " / " +
                 [ +  - ]
    1292 [ +  - ][ +  - ]:       1020 :         std::to_string( m_avgstat[i][0] ) + "\n" +
                 [ +  - ]
    1293         [ +  - ]:        510 :         "min/max/avg V^(1/3) = " +
    1294 [ +  - ][ +  - ]:       1020 :         std::to_string( m_minstat[i][1] ) + " / " +
                 [ +  - ]
    1295 [ +  - ][ +  - ]:       1020 :         std::to_string( m_maxstat[i][1] ) + " / " +
                 [ +  - ]
    1296 [ +  - ][ +  - ]:       1020 :         std::to_string( m_avgstat[i][1] ) + "\n" +
                 [ +  - ]
    1297         [ +  - ]:        510 :         "min/max/avg nelem = " +
    1298 [ +  - ][ +  - ]:       1020 :         std::to_string( static_cast<std::size_t>(m_minstat[i][2]) ) + " / " +
                 [ +  - ]
    1299 [ +  - ][ +  - ]:       1020 :         std::to_string( static_cast<std::size_t>(m_maxstat[i][2]) ) + " / " +
                 [ +  - ]
    1300 [ +  - ][ +  - ]:       1020 :         std::to_string( static_cast<std::size_t>(m_avgstat[i][2]) ) + "\n" +
                 [ +  - ]
    1301         [ +  - ]:        510 :         "min/max/avg npoin = " +
    1302 [ +  - ][ +  - ]:       1020 :         std::to_string( static_cast<std::size_t>(m_minstat[i][3]) ) + " / " +
                 [ +  - ]
    1303 [ +  - ][ +  - ]:       1020 :         std::to_string( static_cast<std::size_t>(m_maxstat[i][3]) ) + " / " +
                 [ +  - ]
    1304 [ +  - ][ +  - ]:       1020 :         std::to_string( static_cast<std::size_t>(m_avgstat[i][3]) ) + "\n" +
                 [ +  - ]
    1305         [ +  - ]:        510 :         "min/max/avg nedge = " +
    1306 [ +  - ][ +  - ]:       1020 :         std::to_string( static_cast<std::size_t>(m_minstat[i][4]) ) + " / " +
                 [ +  - ]
    1307 [ +  - ][ +  - ]:       1020 :         std::to_string( static_cast<std::size_t>(m_maxstat[i][4]) ) + " / " +
                 [ +  - ]
    1308 [ +  - ][ +  - ]:       1020 :         std::to_string( static_cast<std::size_t>(m_avgstat[i][4]) ) + '\n' +
                 [ +  - ]
    1309         [ +  - ]:        510 :         "min/max/avg ncompoin/npoin = " +
    1310 [ +  - ][ +  - ]:       1020 :         std::to_string( m_minstat[i][5] ) + " / " +
                 [ +  - ]
    1311 [ +  - ][ +  - ]:       1020 :         std::to_string( m_maxstat[i][5] ) + " / " +
                 [ +  - ]
    1312 [ +  - ][ +  - ]:        765 :         std::to_string( m_avgstat[i][5] ) + '\n';
                 [ +  - ]
    1313                 :            :     }
    1314                 :            : 
    1315                 :            :     // Print out time integration header to screen
    1316         [ +  - ]:        255 :     inthead( print );
    1317                 :            : 
    1318 [ +  - ][ +  - ]:        255 :     m_progWork.start( print, "Preparing workers", {{ m_nchare[0] }} );
    1319                 :            : 
    1320                 :            :     // Create "derived-class" workers
    1321 [ +  - ][ +  + ]:        510 :     for (std::size_t i=0; i<m_nelem.size(); ++i) m_sorter[i].createWorkers();
    1322                 :            :   }
    1323                 :        255 : }
    1324                 :            : 
    1325                 :            : void
    1326                 :        460 : Transporter::transfer_dt( tk::real dt )
    1327                 :            : // *****************************************************************************
    1328                 :            : //  Reduction target computing the minimum dt for coupled problems
    1329                 :            : //! \param[in] dt Minimum dt collected over all chares and coupled meshes
    1330                 :            : // *****************************************************************************
    1331                 :            : {
    1332         [ +  + ]:        460 :   if (dt < m_mindt) m_mindt = dt;
    1333                 :            : 
    1334         [ +  - ]:        460 :   if (++m_ndt == m_nelem.size()) {    // all meshes have contributed
    1335                 :        460 :     m_ndt = 0;
    1336                 :            : 
    1337                 :            :     // continue timestep on all meshes
    1338                 :        460 :     const auto& solver = g_cfg.get< tag::solver >();
    1339         [ +  - ]:        460 :     if (solver == "lohcg") {
    1340 [ +  - ][ +  + ]:        920 :       for (auto& w : m_lohcg) w.advance( m_mindt );
    1341                 :            :     }
    1342                 :            :     else {
    1343 [ -  - ][ -  - ]:          0 :       Throw( "Unknown solver: " + solver );
                 [ -  - ]
    1344                 :            :     }
    1345                 :            : 
    1346                 :            :   }
    1347                 :        460 : }
    1348                 :            : 
    1349                 :            : void
    1350                 :        255 : Transporter::boxvol( tk::real v, tk::real summeshid )
    1351                 :            : // *****************************************************************************
    1352                 :            : // Reduction target computing total volume of IC box(es)
    1353                 :            : //! \param[in] v Total volume within user-specified IC box(es)
    1354                 :            : //! \param[in] summeshid Mesh id as a real (summed accross the distributed mesh)
    1355                 :            : // *****************************************************************************
    1356                 :            : {
    1357         [ +  - ]:        255 :   auto meshid = tk::cref_find( m_meshid, static_cast<std::size_t>(summeshid) );
    1358 [ +  + ][ +  - ]:        255 :   if (v > 0.0) tk::Print() << "IC-box-volume sum: " + std::to_string(v) << '\n';
         [ +  - ][ +  - ]
                 [ +  - ]
    1359                 :            : 
    1360                 :        255 :   const auto& solver = g_cfg.get< tag::solver >();
    1361         [ +  + ]:        255 :   if (solver == "riecg") {
    1362                 :         73 :     m_riecg[ meshid ].setup( v );
    1363                 :            :   }
    1364         [ +  + ]:        182 :   else if (solver == "laxcg") {
    1365                 :         23 :     m_laxcg[ meshid ].setup( v );
    1366                 :            :   }
    1367         [ +  + ]:        159 :   else if (solver == "zalcg") {
    1368                 :         36 :     m_zalcg[ meshid ].setup( v );
    1369                 :            :   }
    1370         [ +  + ]:        123 :   else if (solver == "kozcg") {
    1371                 :         44 :     m_kozcg[ meshid ].setup( v );
    1372                 :            :   }
    1373         [ +  + ]:         79 :   else if (solver == "chocg") {
    1374                 :         46 :     m_chocg[ meshid ].setup( v );
    1375                 :            :   }
    1376         [ +  - ]:         33 :   else if (solver == "lohcg") {
    1377                 :         33 :     m_lohcg[ meshid ].setup( v );
    1378                 :            :   }
    1379                 :            :   else {
    1380 [ -  - ][ -  - ]:          0 :     Throw( "Unknown solver: " + solver );
                 [ -  - ]
    1381                 :            :   }
    1382                 :            : 
    1383                 :            :   // Turn on automatic load balancing
    1384         [ +  - ]:        255 :   if (++m_ncom == m_nelem.size()) { // all worker arrays have finished
    1385                 :        255 :     m_ncom = 0;
    1386                 :        255 :     tk::Print print;
    1387         [ +  - ]:        255 :     m_progWork.end( print );
    1388         [ +  - ]:        255 :     tk::CProxy_LBSwitch::ckNew();
    1389                 :            :   }
    1390                 :        255 : }
    1391                 :            : 
    1392                 :            : void
    1393                 :        267 : Transporter::inthead( const tk::Print& print )
    1394                 :            : // *****************************************************************************
    1395                 :            : // Print out time integration header to screen
    1396                 :            : //! \param[in] print Pretty printer object to use for printing
    1397                 :            : // *****************************************************************************
    1398                 :            : {
    1399                 :        267 :   const auto dea = g_cfg.get< tag::deactivate >();
    1400         [ +  - ]:        267 :   const auto solver = g_cfg.get< tag::solver >();
    1401         [ +  + ]:        267 :   const auto pre = solver == "chocg" ? 1 : 0;
    1402                 :        267 :   const auto theta = g_cfg.get< tag::theta >();
    1403                 :        267 :   const auto eps = std::numeric_limits< tk::real >::epsilon();
    1404 [ +  + ][ +  + ]:        267 :   const auto mom = solver == "chocg" and theta > eps ? 1 : 0;
    1405                 :        267 :   const bool multi = m_input.size() > 1;
    1406                 :            : 
    1407 [ +  - ][ +  - ]:        267 :   print.section( "Time integration" );
    1408                 :            :   print <<
    1409                 :            :   "Legend: it - iteration count\n"
    1410                 :            :   "         t - physics time\n"
    1411                 :            :   "        dt - physics time step size\n"
    1412                 :            :   "       ETE - estimated wall-clock time elapsed (h:m:s)\n"
    1413                 :            :   "       ETA - estimated wall-clock time for accomplishment (h:m:s)\n"
    1414                 :            :   "       EGT - estimated grind wall-clock time (1e-6sec/timestep)\n"
    1415                 :            :   "       EGP - estimated grind performance: wall-clock time "
    1416                 :            :                 "(1e-6sec/DOF/timestep)\n"
    1417                 :        267 :   "       flg - status flags, " << (multi?"only for background mesh, ":"")
    1418                 :            :                                 << "legend:\n"
    1419                 :            :   "             f - field (volume and surface) output\n"
    1420                 :            :   "             i - integral output\n"
    1421                 :            :   "             d - diagnostics output\n"
    1422                 :            :   "             t - physics time history output\n"
    1423                 :            :   "             h - h-refinement\n"
    1424                 :            :   "             l - load balancing\n"
    1425                 :        267 :   "             c - checkpoint\n" << (dea ?
    1426                 :        267 :   "             e:x/y - x of y work units deactivated\n" : "") << (pre ?
    1427                 :        267 :   "             p:it - pressure linear solve iterations\n" : "") << (mom ?
    1428                 :            :   "             m:it - momentum/transport linear solve iterations\n" : "") <<
    1429                 :            :   "\n      it             t            dt        ETE        ETA        EGT"
    1430                 :            :   "           EGP  flg\n"
    1431                 :            :   "-----------------------------------------------------------------------"
    1432 [ +  - ][ -  + ]:       1335 :   "-----------------\n";
         [ +  - ][ +  - ]
         [ +  + ][ +  - ]
         [ +  + ][ +  - ]
         [ +  + ][ +  - ]
                 [ +  - ]
    1433                 :        267 : }
    1434                 :            : 
    1435                 :            : void
    1436                 :       3201 : Transporter::rhodiagnostics( CkReductionMsg* msg )
    1437                 :            : // *****************************************************************************
    1438                 :            : //  Reduction target collecting diagnostics from density-based solvers
    1439                 :            : //! \param[in] msg Serialized diagnostics vector aggregated across all PEs
    1440                 :            : // *****************************************************************************
    1441                 :            : {
    1442                 :            :   using namespace diagnostics;
    1443                 :            : 
    1444                 :            :   std::size_t meshid;
    1445                 :            :   std::size_t ncomp;
    1446                 :       3201 :   std::vector< std::vector< tk::real > > d;
    1447                 :            : 
    1448                 :            :   // Deserialize diagnostics vector
    1449                 :       3201 :   PUP::fromMem creator( msg->getData() );
    1450                 :            :   // cppcheck-suppress uninitvar
    1451         [ +  - ]:       3201 :   creator | meshid;
    1452         [ +  - ]:       3201 :   creator | ncomp;
    1453         [ +  - ]:       3201 :   creator | d;
    1454 [ +  - ][ +  - ]:       3201 :   delete msg;
    1455                 :            : 
    1456                 :            :   // cppcheck-suppress uninitvar
    1457                 :            :   // cppcheck-suppress unreadVariable
    1458         [ +  - ]:       3201 :   auto id = std::to_string(meshid);
    1459                 :            : 
    1460 [ -  + ][ -  - ]:       3201 :   Assert( ncomp > 0, "Number of scalar components must be positive");
         [ -  - ][ -  - ]
    1461 [ -  + ][ -  - ]:       3201 :   Assert( d.size() == NUMDIAG, "Diagnostics vector size mismatch" );
         [ -  - ][ -  - ]
    1462                 :            : 
    1463                 :            :   // cppcheck-suppress unsignedLessThanZero
    1464         [ +  + ]:      28809 :   for (std::size_t i=0; i<d.size(); ++i) {
    1465 [ -  + ][ -  - ]:      25608 :      Assert( d[i].size() == ncomp, "Size mismatch at final stage of "
         [ -  - ][ -  - ]
    1466                 :            :              "diagnostics aggregation for mesh " + id );
    1467                 :            :   }
    1468                 :            : 
    1469                 :            :   // Allocate storage for those diagnostics that are always computed
    1470         [ +  - ]:       3201 :   std::vector< tk::real > diag( ncomp, 0.0 );
    1471                 :            : 
    1472                 :            :   // Finish computing the L2 norm of conserved variables
    1473         [ +  + ]:      19480 :   for (std::size_t i=0; i<d[L2SOL].size(); ++i) {
    1474                 :            :     // cppcheck-suppress uninitvar
    1475                 :      16279 :     diag[i] = sqrt( d[L2SOL][i] / m_meshvol[meshid] );
    1476                 :            :   }
    1477                 :            :  
    1478                 :            :   // Finish computing the L2 norm of the residuals
    1479         [ +  - ]:       3201 :   std::vector< tk::real > l2res( d[L2RES].size(), 0.0 );
    1480         [ +  + ]:      19480 :   for (std::size_t i=0; i<d[L2RES].size(); ++i) {
    1481                 :            :     // cppcheck-suppress uninitvar
    1482                 :      16279 :     l2res[i] = std::sqrt( d[L2RES][i] / m_meshvol[meshid] );
    1483         [ +  - ]:      16279 :     diag.push_back( l2res[i] );
    1484                 :            :   }
    1485                 :            : 
    1486                 :            :   // Append total energy
    1487         [ +  - ]:       3201 :   diag.push_back( d[TOTALEN][0] );
    1488                 :            : 
    1489                 :            :   // Finish computing norms of the numerical - analytical solution
    1490 [ +  - ][ +  + ]:       3201 :   if (problems::SOL()) {
    1491         [ +  + ]:      10200 :     for (std::size_t i=0; i<d[L2ERR].size(); ++i) {
    1492                 :            :       // cppcheck-suppress uninitvar
    1493         [ +  - ]:       8544 :       diag.push_back( std::sqrt( d[L2ERR][i] / m_meshvol[meshid] ) );
    1494                 :            :     }
    1495         [ +  + ]:      10200 :     for (std::size_t i=0; i<d[L1ERR].size(); ++i) {
    1496                 :            :       // cppcheck-suppress uninitvar
    1497         [ +  - ]:       8544 :       diag.push_back( d[L1ERR][i] / m_meshvol[meshid] );
    1498                 :            :     }
    1499                 :            :   }
    1500                 :            :  
    1501                 :            :   // Append diagnostics file at selected times
    1502         [ +  - ]:       3201 :   auto filename = g_cfg.get< tag::diag >();
    1503 [ -  + ][ -  - ]:       3201 :   if (m_nelem.size() > 1) filename += '.' + id;
                 [ -  - ]
    1504                 :            :   tk::DiagWriter dw( filename,
    1505                 :       3201 :                      g_cfg.get< tag::diag_format >(),
    1506                 :       3201 :                      g_cfg.get< tag::diag_precision >(),
    1507         [ +  - ]:       3201 :                      std::ios_base::app );
    1508         [ +  - ]:       3201 :   dw.write( static_cast<uint64_t>(d[ITER][0]), d[TIME][0], d[DT][0], diag );
    1509                 :            : 
    1510                 :       3201 :   const auto& solver = g_cfg.get< tag::solver >();
    1511         [ +  + ]:       3201 :   if (solver == "riecg") {
    1512                 :            :     // cppcheck-suppress uninitvar
    1513         [ +  - ]:       1613 :     m_riecg[ meshid ].evalres( l2res );
    1514                 :            :   }
    1515         [ +  + ]:       1588 :   else if (solver == "laxcg") {
    1516                 :            :     // cppcheck-suppress uninitvar
    1517         [ +  - ]:        260 :     m_laxcg[ meshid ].evalres( l2res );
    1518                 :            :   }
    1519         [ +  + ]:       1328 :   else if (solver == "zalcg") {
    1520                 :            :     // cppcheck-suppress uninitvar
    1521         [ +  - ]:        480 :     m_zalcg[ meshid ].evalres( l2res );
    1522                 :            :   }
    1523         [ +  - ]:        848 :   else if (solver == "kozcg") {
    1524                 :            :     // cppcheck-suppress uninitvar
    1525         [ +  - ]:        848 :     m_kozcg[ meshid ].evalres( l2res );
    1526                 :            :   }
    1527                 :            :   else {
    1528 [ -  - ][ -  - ]:          0 :     Throw( "Unknown solver: " + solver );
                 [ -  - ]
    1529                 :            :   }
    1530                 :       3201 : }
    1531                 :            : 
    1532                 :            : void
    1533                 :        541 : Transporter::prediagnostics( CkReductionMsg* msg )
    1534                 :            : // *****************************************************************************
    1535                 :            : //  Reduction target collecting diagnostics from pressure-based solvers
    1536                 :            : //! \param[in] msg Serialized diagnostics vector aggregated across all PEs
    1537                 :            : // *****************************************************************************
    1538                 :            : {
    1539                 :            :   using namespace diagnostics;
    1540                 :            : 
    1541                 :            :   std::size_t meshid;
    1542                 :            :   std::size_t ncomp;
    1543                 :        541 :   std::vector< std::vector< tk::real > > d;
    1544                 :            : 
    1545                 :            :   // Deserialize diagnostics vector
    1546                 :        541 :   PUP::fromMem creator( msg->getData() );
    1547                 :            :   // cppcheck-suppress uninitvar
    1548         [ +  - ]:        541 :   creator | meshid;
    1549         [ +  - ]:        541 :   creator | ncomp;
    1550         [ +  - ]:        541 :   creator | d;
    1551 [ +  - ][ +  - ]:        541 :   delete msg;
    1552                 :            : 
    1553                 :            :   // cppcheck-suppress uninitvar
    1554                 :            :   // cppcheck-suppress unreadVariable
    1555         [ +  - ]:        541 :   auto id = std::to_string(meshid);
    1556                 :            : 
    1557 [ -  + ][ -  - ]:        541 :   Assert( ncomp > 0, "Number of scalar components must be positive");
         [ -  - ][ -  - ]
    1558 [ -  + ][ -  - ]:        541 :   Assert( d.size() == NUMDIAG, "Diagnostics vector size mismatch" );
         [ -  - ][ -  - ]
    1559                 :            : 
    1560                 :            :   // cppcheck-suppress unsignedLessThanZero
    1561         [ +  + ]:       4869 :   for (std::size_t i=0; i<d.size(); ++i) {
    1562 [ -  + ][ -  - ]:       4328 :      Assert( d[i].size() == ncomp, "Size mismatch at final stage of "
         [ -  - ][ -  - ]
    1563                 :            :              "diagnostics aggregation for mesh " + id );
    1564                 :            :   }
    1565                 :            : 
    1566                 :            :   // Allocate storage for those diagnostics that are always computed
    1567         [ +  - ]:        541 :   std::vector< tk::real > diag( ncomp, 0.0 );
    1568                 :            : 
    1569                 :            :   // Finish computing the L2 norm of conserved variables
    1570         [ +  + ]:       2788 :   for (std::size_t i=0; i<d[L2SOL].size(); ++i) {
    1571                 :            :     // cppcheck-suppress uninitvar
    1572                 :       2247 :     diag[i] = sqrt( d[L2SOL][i] / m_meshvol[meshid] );
    1573                 :            :   }
    1574                 :            : 
    1575                 :            :   // Finish computing the L2 norm of the residuals
    1576         [ +  - ]:        541 :   std::vector< tk::real > l2res( d[L2RES].size(), 0.0 );
    1577         [ +  + ]:       2788 :   for (std::size_t i=0; i<d[L2RES].size(); ++i) {
    1578                 :            :     // cppcheck-suppress uninitvar
    1579                 :       2247 :     l2res[i] = std::sqrt( d[L2RES][i] / m_meshvol[meshid] );
    1580         [ +  - ]:       2247 :     diag.push_back( l2res[i] );
    1581                 :            :   }
    1582                 :            : 
    1583                 :            :   // Finish computing norms of the numerical - analytical pressure solution
    1584 [ +  - ][ +  + ]:        541 :   if (problems::PRESSURE_SOL()) {
    1585         [ +  - ]:          7 :     diag.push_back( std::sqrt( d[L2ERR][0] / m_meshvol[meshid] ) );
    1586         [ +  - ]:          7 :     diag.push_back( d[L1ERR][0] / m_meshvol[meshid] );
    1587                 :            :   }
    1588                 :            : 
    1589                 :            :   // Finish computing norms of the numerical - analytical adv/diff solution
    1590 [ +  - ][ +  + ]:        541 :   if (problems::SOL()) {
    1591         [ +  + ]:        507 :     for (std::size_t i=1; i<d[L2ERR].size(); ++i) {
    1592                 :            :       // cppcheck-suppress uninitvar
    1593         [ +  - ]:        400 :       diag.push_back( std::sqrt( d[L2ERR][i] / m_meshvol[meshid] ) );
    1594                 :            :     }
    1595         [ +  + ]:        507 :     for (std::size_t i=1; i<d[L1ERR].size(); ++i) {
    1596                 :            :       // cppcheck-suppress uninitvar
    1597         [ +  - ]:        400 :       diag.push_back( d[L1ERR][i] / m_meshvol[meshid] );
    1598                 :            :     }
    1599                 :            :   }
    1600                 :            : 
    1601                 :            :   // Append diagnostics file at selected times
    1602         [ +  - ]:        541 :   auto filename = g_cfg.get< tag::diag >();
    1603 [ -  + ][ -  - ]:        541 :   if (m_nelem.size() > 1) filename += '.' + id;
                 [ -  - ]
    1604                 :            :   tk::DiagWriter dw( filename,
    1605                 :        541 :                      g_cfg.get< tag::diag_format >(),
    1606                 :        541 :                      g_cfg.get< tag::diag_precision >(),
    1607         [ +  - ]:        541 :                      std::ios_base::app );
    1608         [ +  - ]:        541 :   dw.write( static_cast<uint64_t>(d[ITER][0]), d[TIME][0], d[DT][0], diag );
    1609                 :            : 
    1610                 :        541 :   const auto& solver = g_cfg.get< tag::solver >();
    1611         [ +  - ]:        541 :   if (solver == "chocg") {
    1612                 :            :     // cppcheck-suppress uninitvar
    1613         [ +  - ]:        541 :     m_chocg[ meshid ].evalres( l2res );
    1614                 :            :   }
    1615                 :            :   else {
    1616 [ -  - ][ -  - ]:          0 :     Throw( "Unknown solver: " + solver );
                 [ -  - ]
    1617                 :            :   }
    1618                 :        541 : }
    1619                 :            : 
    1620                 :            : void
    1621                 :        424 : Transporter::acdiagnostics( CkReductionMsg* msg )
    1622                 :            : // *****************************************************************************
    1623                 :            : //  Reduction target collecting diagnostics from artificial compressibility
    1624                 :            : //  solvers
    1625                 :            : //! \param[in] msg Serialized diagnostics vector aggregated across all PEs
    1626                 :            : // *****************************************************************************
    1627                 :            : {
    1628                 :            :   using namespace diagnostics;
    1629                 :            : 
    1630                 :            :   std::size_t meshid;
    1631                 :            :   std::size_t ncomp;
    1632                 :        424 :   std::vector< std::vector< tk::real > > d;
    1633                 :            : 
    1634                 :            :   // Deserialize diagnostics vector
    1635                 :        424 :   PUP::fromMem creator( msg->getData() );
    1636                 :            :   // cppcheck-suppress uninitvar
    1637         [ +  - ]:        424 :   creator | meshid;
    1638         [ +  - ]:        424 :   creator | ncomp;
    1639         [ +  - ]:        424 :   creator | d;
    1640 [ +  - ][ +  - ]:        424 :   delete msg;
    1641                 :            : 
    1642                 :            :   // cppcheck-suppress uninitvar
    1643                 :            :   // cppcheck-suppress unreadVariable
    1644         [ +  - ]:        424 :   auto id = std::to_string(meshid);
    1645                 :            : 
    1646 [ -  + ][ -  - ]:        424 :   Assert( ncomp > 0, "Number of scalar components must be positive");
         [ -  - ][ -  - ]
    1647 [ -  + ][ -  - ]:        424 :   Assert( d.size() == NUMDIAG, "Diagnostics vector size mismatch" );
         [ -  - ][ -  - ]
    1648                 :            : 
    1649                 :            :   // cppcheck-suppress unsignedLessThanZero
    1650         [ +  + ]:       3816 :   for (std::size_t i=0; i<d.size(); ++i) {
    1651 [ -  + ][ -  - ]:       3392 :      Assert( d[i].size() == ncomp, "Size mismatch at final stage of "
         [ -  - ][ -  - ]
    1652                 :            :              "diagnostics aggregation for mesh " + id );
    1653                 :            :   }
    1654                 :            : 
    1655                 :            :   // Allocate storage for those diagnostics that are always computed
    1656         [ +  - ]:        424 :   std::vector< tk::real > diag( ncomp, 0.0 );
    1657                 :            : 
    1658                 :            :   // Finish computing the L2 norm of conserved variables
    1659         [ +  + ]:       2200 :   for (std::size_t i=0; i<d[L2SOL].size(); ++i) {
    1660                 :            :     // cppcheck-suppress uninitvar
    1661                 :       1776 :     diag[i] = sqrt( d[L2SOL][i] / m_meshvol[meshid] );
    1662                 :            :   }
    1663                 :            : 
    1664                 :            :   // Finish computing the L2 norm of the residuals
    1665         [ +  - ]:        424 :   std::vector< tk::real > l2res( d[L2RES].size(), 0.0 );
    1666         [ +  + ]:       2200 :   for (std::size_t i=0; i<d[L2RES].size(); ++i) {
    1667                 :            :     // cppcheck-suppress uninitvar
    1668                 :       1776 :     l2res[i] = std::sqrt( d[L2RES][i] / m_meshvol[meshid] );
    1669         [ +  - ]:       1776 :     diag.push_back( l2res[i] );
    1670                 :            :   }
    1671                 :            : 
    1672                 :            :   // Finish computing norms of the numerical - analytical adv/diff solution
    1673 [ +  - ][ +  + ]:        424 :   if (problems::SOL()) {
    1674         [ +  + ]:        400 :     for (std::size_t i=1; i<d[L2ERR].size(); ++i) {
    1675                 :            :       // cppcheck-suppress uninitvar
    1676         [ +  - ]:        320 :       diag.push_back( std::sqrt( d[L2ERR][i] / m_meshvol[meshid] ) );
    1677                 :            :     }
    1678         [ +  + ]:        400 :     for (std::size_t i=1; i<d[L1ERR].size(); ++i) {
    1679                 :            :       // cppcheck-suppress uninitvar
    1680         [ +  - ]:        320 :       diag.push_back( d[L1ERR][i] / m_meshvol[meshid] );
    1681                 :            :     }
    1682                 :            :   }
    1683                 :            : 
    1684                 :            :   // Append diagnostics file at selected times
    1685         [ +  - ]:        424 :   auto filename = g_cfg.get< tag::diag >();
    1686         [ +  - ]:        424 :   auto format = g_cfg.get< tag::diag_format >();
    1687                 :        424 :   auto precision = g_cfg.get< tag::diag_precision >();
    1688 [ -  + ][ -  - ]:        424 :   if (m_nelem.size() > 1) filename += '.' + id;
                 [ -  - ]
    1689         [ +  - ]:        424 :   tk::DiagWriter dw( filename, format, precision, std::ios_base::app );
    1690         [ +  - ]:        424 :   dw.write( static_cast<uint64_t>(d[ITER][0]), d[TIME][0], d[DT][0], diag );
    1691                 :            : 
    1692                 :        424 :   const auto& solver = g_cfg.get< tag::solver >();
    1693         [ +  - ]:        424 :   if (solver == "lohcg") {
    1694                 :            :     // cppcheck-suppress uninitvar
    1695         [ +  - ]:        424 :     m_lohcg[ meshid ].evalres( l2res );
    1696                 :            :   }
    1697                 :            :   else {
    1698 [ -  - ][ -  - ]:          0 :     Throw( "Unknown solver: " + solver );
                 [ -  - ]
    1699                 :            :   }
    1700                 :        424 : }
    1701                 :            : 
    1702                 :            : void
    1703                 :         98 : Transporter::integrals( CkReductionMsg* msg )
    1704                 :            : // *****************************************************************************
    1705                 :            : // Reduction target optionally collecting integrals
    1706                 :            : //! \param[in] msg Serialized integrals aggregated across all PEs
    1707                 :            : // *****************************************************************************
    1708                 :            : {
    1709                 :            :   using namespace integrals;
    1710                 :            : 
    1711                 :            :   // cppcheck-suppress unassignedVariable
    1712                 :            :   std::size_t meshid;
    1713                 :         98 :   std::vector< std::map< int, tk::real > > d;
    1714                 :            : 
    1715                 :            :   // Deserialize integrals vector
    1716                 :         98 :   PUP::fromMem creator( msg->getData() );
    1717                 :            :   // cppcheck-suppress uninitvar
    1718         [ +  - ]:         98 :   creator | meshid;
    1719         [ +  - ]:         98 :   creator | d;
    1720 [ +  - ][ +  - ]:         98 :   delete msg;
    1721                 :            : 
    1722                 :         98 :   const auto& ti = g_cfg.get< tag::integout >();
    1723                 :         98 :   const auto& sidesets_integral = ti.get< tag::sidesets >();
    1724                 :            :   // cppcheck-suppress
    1725         [ +  - ]:         98 :   if (not sidesets_integral.empty()) {
    1726                 :            : 
    1727 [ -  + ][ -  - ]:         98 :     Assert( d.size() == NUMINT, "Integrals vector size mismatch" );
         [ -  - ][ -  - ]
    1728                 :            : 
    1729                 :            :     // Collect integrals for output
    1730                 :         98 :     std::vector< tk::real > ints;
    1731 [ +  - ][ +  + ]:        246 :     for (const auto& [s,m] : d[MASS_FLOW_RATE]) ints.push_back( m );
    1732 [ +  - ][ +  + ]:        122 :     for (const auto& [s,m] : d[FORCE_X]) ints.push_back( m );
    1733 [ +  - ][ +  + ]:        122 :     for (const auto& [s,m] : d[FORCE_Y]) ints.push_back( m );
    1734 [ +  - ][ +  + ]:        122 :     for (const auto& [s,m] : d[FORCE_Z]) ints.push_back( m );
    1735                 :            : 
    1736                 :            :     // Append integrals file at selected times
    1737         [ +  - ]:         98 :     auto filename = g_cfg.get< tag::output >() + ".int";
    1738                 :            :     tk::DiagWriter dw( filename,
    1739                 :         98 :                        ti.get< tag::format >(),
    1740                 :         98 :                        ti.get< tag::precision >(),
    1741         [ +  - ]:         98 :                        std::ios_base::app );
    1742                 :            :     // cppcheck-suppress containerOutOfBounds
    1743 [ +  - ][ +  - ]:         98 :     dw.write( static_cast<uint64_t>(tk::cref_find( d[ITER], 0 )),
    1744                 :            :               // cppcheck-suppress containerOutOfBounds
    1745         [ +  - ]:         98 :               tk::cref_find( d[TIME], 0 ),
    1746                 :            :               // cppcheck-suppress containerOutOfBounds
    1747         [ +  - ]:         98 :               tk::cref_find( d[DT], 0 ),
    1748                 :            :               ints );
    1749                 :         98 :   }
    1750                 :            : 
    1751                 :         98 :   const auto& solver = g_cfg.get< tag::solver >();
    1752         [ +  + ]:         98 :   if (solver == "riecg") {
    1753                 :            :     // cppcheck-suppress uninitvar
    1754         [ +  - ]:         74 :     m_riecg[ meshid ].step();
    1755                 :            :   }
    1756         [ -  + ]:         24 :   else if (solver == "laxcg") {
    1757                 :            :     // cppcheck-suppress uninitvar
    1758         [ -  - ]:          0 :     m_laxcg[ meshid ].step();
    1759                 :            :   }
    1760         [ -  + ]:         24 :   else if (solver == "zalcg") {
    1761                 :            :     // cppcheck-suppress uninitvar
    1762         [ -  - ]:          0 :     m_zalcg[ meshid ].step();
    1763                 :            :   }
    1764         [ -  + ]:         24 :   else if (solver == "kozcg") {
    1765                 :            :     // cppcheck-suppress uninitvar
    1766         [ -  - ]:          0 :     m_kozcg[ meshid ].step();
    1767                 :            :   }
    1768         [ +  + ]:         24 :   else if (solver == "chocg") {
    1769                 :            :     // cppcheck-suppress uninitvar
    1770         [ +  - ]:         20 :     m_chocg[ meshid ].step();
    1771                 :            :   }
    1772         [ +  - ]:          4 :   else if (solver == "lohcg") {
    1773                 :            :     // cppcheck-suppress uninitvar
    1774         [ +  - ]:          4 :     m_lohcg[ meshid ].step();
    1775                 :            :   }
    1776                 :            :   else
    1777 [ -  - ][ -  - ]:          0 :     Throw( "Unknown solver: " + solver );
                 [ -  - ]
    1778                 :         98 : }
    1779                 :            : 
    1780                 :            : void
    1781                 :        279 : Transporter::resume()
    1782                 :            : // *****************************************************************************
    1783                 :            : // Resume execution from checkpoint/restart files
    1784                 :            : //! \details This is invoked by Charm++ after the checkpoint is done, as well as
    1785                 :            : //!   when the restart (returning from a checkpoint) is complete
    1786                 :            : // *****************************************************************************
    1787                 :            : {
    1788         [ +  + ]:        558 :   if (std::any_of(begin(m_finished), end(m_finished), [](auto f){return !f;})) {
    1789                 :            : 
    1790                 :            :     // If just restarted from a checkpoint, Main( CkMigrateMessage* msg ) has
    1791                 :            :     // increased g_nrestart, but only on PE 0, so broadcast.
    1792                 :            : 
    1793                 :         12 :     const auto& solver = g_cfg.get< tag::solver >();
    1794         [ +  + ]:         12 :     if (solver == "riecg") {
    1795         [ +  + ]:          4 :       for (std::size_t i=0; i<m_nelem.size(); ++i) {
    1796                 :          2 :         m_riecg[i].evalLB( g_nrestart );
    1797                 :            :       }
    1798                 :            :     }
    1799         [ +  + ]:         10 :     else if (solver == "laxcg") {
    1800         [ +  + ]:          4 :       for (std::size_t i=0; i<m_nelem.size(); ++i) {
    1801                 :          2 :         m_laxcg[i].evalLB( g_nrestart );
    1802                 :            :       }
    1803                 :            :     }
    1804         [ +  + ]:          8 :     else if (solver == "zalcg") {
    1805         [ +  + ]:          4 :       for (std::size_t i=0; i<m_nelem.size(); ++i) {
    1806                 :          2 :         m_zalcg[i].evalLB( g_nrestart );
    1807                 :            :       }
    1808                 :            :     }
    1809         [ +  + ]:          6 :     else if ( solver == "kozcg") {
    1810         [ +  + ]:          4 :       for (std::size_t i=0; i<m_nelem.size(); ++i) {
    1811                 :          2 :         m_kozcg[i].evalLB( g_nrestart );
    1812                 :            :       }
    1813                 :            :     }
    1814         [ +  + ]:          4 :     else if ( solver == "chocg") {
    1815         [ +  + ]:          4 :       for (std::size_t i=0; i<m_nelem.size(); ++i) {
    1816                 :          2 :         m_chocg[i].evalLB( g_nrestart );
    1817                 :            :       }
    1818                 :            :     }
    1819         [ +  - ]:          2 :     else if ( solver == "lohcg") {
    1820         [ +  + ]:          4 :       for (std::size_t i=0; i<m_nelem.size(); ++i) {
    1821                 :          2 :         m_lohcg[i].evalLB( g_nrestart );
    1822                 :            :       }
    1823                 :            :     }
    1824                 :            :     else {
    1825 [ -  - ][ -  - ]:          0 :       Throw( "Unknown solver: " + solver );
                 [ -  - ]
    1826                 :            :     }
    1827                 :            : 
    1828                 :            : 
    1829                 :            :   } else {
    1830                 :            : 
    1831                 :        267 :     mainProxy.finalize();
    1832                 :            : 
    1833                 :            :   }
    1834                 :        279 : }
    1835                 :            : 
    1836                 :            : void
    1837                 :        267 : Transporter::checkpoint( std::size_t finished, std::size_t meshid )
    1838                 :            : // *****************************************************************************
    1839                 :            : // Save checkpoint/restart files
    1840                 :            : //! \param[in] finished Nonzero if finished with time stepping
    1841                 :            : //! \param[in] meshid Mesh id
    1842                 :            : // *****************************************************************************
    1843                 :            : {
    1844                 :        267 :   m_finished[meshid] = finished;
    1845                 :            : 
    1846         [ +  - ]:        267 :   if (++m_nchk == m_nelem.size()) { // all worker arrays have checkpointed
    1847                 :        267 :     m_nchk = 0;
    1848         [ +  + ]:        267 :     if (not g_cfg.get< tag::benchmark >()) {
    1849                 :        159 :       const auto& ckptdir = g_cfg.get< tag::checkpoint >();
    1850 [ +  - ][ +  - ]:        159 :       CkCallback res( CkIndex_Transporter::resume(), thisProxy );
    1851         [ +  - ]:        159 :       CkStartCheckpoint( ckptdir.c_str(), res );
    1852                 :            :       //CkStartMemCheckpoint( res );
    1853                 :        159 :     } else {
    1854                 :        108 :       resume();
    1855                 :            :     }
    1856                 :            :   }
    1857                 :        267 : }
    1858                 :            : 
    1859                 :            : void
    1860                 :        267 : Transporter::finish( std::size_t meshid )
    1861                 :            : // *****************************************************************************
    1862                 :            : // Normal finish of time stepping
    1863                 :            : //! \param[in] meshid Mesh id
    1864                 :            : // *****************************************************************************
    1865                 :            : {
    1866                 :        267 :   checkpoint( /* finished = */ 1, meshid );
    1867                 :        267 : }
    1868                 :            : 
    1869                 :            : #include "NoWarning/transporter.def.h"

Generated by: LCOV version 1.16