LCOV - code coverage report
Current view: top level - src/Integrator - HeatConduction.H (source / functions) Hit Total Coverage
Test: coverage_merged.info Lines: 51 54 94.4 %
Date: 2024-11-18 05:28:54 Functions: 10 12 83.3 %

          Line data    Source code
       1             : //
       2             : // This implements a basic heat conduction method in Alamo.
       3             : // The partial differential equation to be solved is
       4             : //
       5             : // .. math::
       6             : //
       7             : //    \frac{\partial T}{\partial t} = \alpha\,\Delta T
       8             : //
       9             : // where :math:`T` is temperature, :math:`t` is time, and :math:`alpha` 
      10             : // is the thermal diffusivity.
      11             : // Integration is performed explicitly in time using forward Euler, and
      12             : // differentiation is performed using the finite difference method.
      13             : //
      14             : 
      15             : #ifndef INTEGRATOR_HEATCONDUCTION_H // Include guards
      16             : #define INTEGRATOR_HEATCONDUCTION_H // 
      17             : 
      18             : // Standard library includes
      19             : #include <iostream>
      20             : #include <fstream>
      21             : #include <iomanip>
      22             : 
      23             : // AMReX Includes
      24             : #include "AMReX.H"
      25             : #include "AMReX_ParallelDescriptor.H"
      26             : #include "AMReX_ParmParse.H"
      27             : 
      28             : // Alamo Includes
      29             : #include "IO/ParmParse.H"
      30             : #include "Integrator/Integrator.H"
      31             : #include "BC/Constant.H"
      32             : #include "BC/Expression.H"
      33             : #include "IC/IC.H"
      34             : #include "IC/Sphere.H"
      35             : #include "IC/Constant.H"
      36             : #include "IC/Expression.H"
      37             : #include "Numeric/Stencil.H"
      38             : 
      39             : namespace Integrator
      40             : {
      41             : class HeatConduction : virtual public Integrator
      42             : {
      43             : public:
      44             :     // Empty constructor
      45           3 :     HeatConduction(int a_nghost = 2) : 
      46             :         Integrator(),
      47           3 :         number_of_ghost_cells(a_nghost)
      48           3 :     {}
      49             : 
      50             :     // Constructor that triggers parse
      51           3 :     HeatConduction(IO::ParmParse& pp) : HeatConduction()
      52             :     {
      53           3 :         Parse(*this, pp);
      54           3 :     }
      55             : 
      56           6 :     virtual ~HeatConduction()
      57           3 :     {
      58           3 :         delete ic;
      59           3 :         delete bc;
      60           6 :     }
      61             : 
      62             :     // The Parse function initializes the HeatConduction object using
      63             :     // a parser, pp. 
      64             :     // Note that this is a static function, which means it does not have
      65             :     // direct access to member variables. Instead, it initializes the variables
      66             :     // inside the argument, "value", and so all references to member items are
      67             :     // prefixed by "value."
      68           3 :     static void Parse(HeatConduction& value, IO::ParmParse& pp)
      69             :     {
      70             :         // Diffusion coefficient :math:`\alpha`.
      71             :         //   *This is an example of a required input variable -
      72             :         //    - program will terminate unless it is provided.*
      73           3 :         pp_query_required("heat.alpha", value.alpha);
      74             : 
      75             :         // Criterion for mesh refinement.
      76             :         //   *This is an example of a default input variable.
      77             :         //    The default value is provided here, not in the 
      78             :         //    definition of the variable.*
      79           3 :         pp_query_default("heat.refinement_threshold", value.refinement_threshold, 0.01);
      80             : 
      81           6 :         std::string type;
      82             : 
      83             :         // Initial condition type.
      84             :         //   *This is an example of type validation:
      85             :         //    the input variable must be one of the three provided values, 
      86             :         //    and will error if not. The default selection is the first
      87             :         //    argument.*
      88           3 :         pp_query_validate("ic.type", type, {"constant", "sphere","expression"});
      89           3 :         if (type == "sphere")          value.ic = new IC::Sphere(value.geom, pp, "ic.sphere");
      90           0 :         else if (type == "constant")   value.ic = new IC::Constant(value.geom, pp, "ic.constant");
      91           0 :         else if (type == "expression") value.ic = new IC::Expression(value.geom, pp, "ic.expression");
      92           0 :         else  Util::Abort(INFO, "Invalid ic.type ", type);
      93             : 
      94           3 :         std::string bc_type;
      95             :         // Select BC object for temperature
      96           3 :         pp_query_validate("bc.temp.type",bc_type,{"constant","expression"});
      97           3 :         if (bc_type == "expression")      value.bc = new BC::Expression(1, pp, "bc.temp.expression");
      98           3 :         else if (bc_type == "constant")   value.bc = new BC::Constant(1, pp, "bc.temp");
      99             : 
     100             :         // Register the temperature and old temperature fields.
     101             :         // temp_mf and temp_old_mf are defined near the bottom of this Header file.
     102           3 :         value.RegisterNewFab(value.temp_mf, value.bc, value.number_of_components, value.number_of_ghost_cells, "Temp", true);
     103           3 :         value.RegisterNewFab(value.temp_old_mf, value.bc, value.number_of_components, value.number_of_ghost_cells, "Temp_old", false);
     104           3 :     }
     105             : 
     106             : protected:
     107             : 
     108             :     // Use the ic object to initialize the temperature field
     109          14 :     void Initialize(int lev)
     110             :     {
     111          14 :         ic->Initialize(lev, temp_old_mf);
     112          14 :     }
     113             : 
     114             :     // Integrate the heat equation
     115        7560 :     void Advance(int lev, Set::Scalar /*time*/, Set::Scalar dt)
     116             :     {
     117             :         // Swap the old temp fab and the new temp fab so we use
     118             :         // the new one.
     119        7560 :         std::swap(*temp_mf[lev], *temp_old_mf[lev]);
     120             : 
     121             :         // Get the cell size corresponding to this level
     122        7560 :         const Set::Scalar* DX = geom[lev].CellSize();
     123             : 
     124             :         // Iterate over all of the patches on this level
     125      123148 :         for (amrex::MFIter mfi(*temp_mf[lev], amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
     126             :         {
     127             :             // Get the box (index dimensions) for this patch
     128      115588 :             const amrex::Box& bx = mfi.tilebox();
     129             : 
     130             :             // Get an array-accessible handle to the data on this patch.
     131             :             // amrex::Array4<const Set::Scalar> const& temp_old = (*temp_old_mf[lev]).array(mfi);
     132             :             // amrex::Array4<Set::Scalar>       const& temp = temp_mf.Patch(lev,mfi);//(*temp_mf[lev]).array(mfi);
     133      115588 :             Set::Patch<const Set::Scalar>  temp_old = temp_old_mf.Patch(lev,mfi);
     134      115588 :             Set::Patch<Set::Scalar>        temp     = temp_mf.Patch(lev,mfi);
     135             : 
     136             :             // Iterate over the grid on this patch
     137      115588 :             amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k)
     138             :             {
     139             :                 // Do the physics!
     140             :                 // Note that Numeric::Laplacian is an inlined function so there is no overhead.
     141             :                 // You can calculate the derivatives yourself if you want.
     142    44053880 :                 temp(i, j, k) = temp_old(i, j, k) + dt * alpha * Numeric::Laplacian(temp_old, i, j, k, 0, DX);
     143    14684628 :             });
     144             :         }
     145        7560 :     }
     146             : 
     147             :     // Tag cells for mesh refinement based on temperature gradient
     148         583 :     void TagCellsForRefinement(int lev, amrex::TagBoxArray& a_tags, Set::Scalar /*time*/, int /*ngrow*/)
     149             :     {
     150             :         // Get cell dimensions as done above.
     151         583 :         const Set::Scalar* DX = geom[lev].CellSize();
     152             :         // Calculate the diagonal.
     153         583 :         Set::Scalar dr = sqrt(AMREX_D_TERM(DX[0] * DX[0], +DX[1] * DX[1], +DX[2] * DX[2]));
     154             : 
     155             :         // Iterate over the patches on this level
     156        5371 :         for (amrex::MFIter mfi(*temp_mf[lev], amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
     157             :         {
     158             :             // Get the box and handles as done above.
     159        4788 :             const amrex::Box& bx = mfi.tilebox();
     160        4788 :             amrex::Array4<char>         const& tags = a_tags.array(mfi);
     161        4788 :             amrex::Array4<Set::Scalar>  const& temp = (*temp_mf[lev]).array(mfi);
     162             : 
     163             :             // Iterate over the grid as done above.
     164        4788 :             amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k)
     165             :             {
     166             :                 // Calculate the temperature gradient.
     167      408872 :                 Set::Vector grad = Numeric::Gradient(temp, i, j, k, 0, DX);
     168             : 
     169             :                 // Is the gradient * cell_size too big? If so, then
     170             :                 // mark this cell as needing refinement.
     171      408872 :                 if (grad.lpNorm<2>() * dr > refinement_threshold)
     172      601732 :                     tags(i, j, k) = amrex::TagBox::SET;
     173      408872 :             });
     174             :         }
     175         583 :     }
     176             : 
     177             : protected:
     178             :     Set::Field<Set::Scalar> temp_mf;         // Temperature field variable (current timestep)
     179             :     Set::Field<Set::Scalar> temp_old_mf;     // Temperature field variable (previous timestep)
     180             : 
     181             : private:
     182             : 
     183             :     //
     184             :     // Definition of parameters set only at instantiation by
     185             :     // constructors. 
     186             :     //
     187             :     const int number_of_components = 1;      // Number of components
     188             :     const int number_of_ghost_cells = 2;     // Number of ghost cells
     189             : 
     190             :     //
     191             :     // Definition of user-determined variables.
     192             :     //
     193             :     // Instantiate all variables to NAN if possible.
     194             :     // Default values may be set in Parse using query_default.
     195             :     //
     196             : 
     197             :     Set::Scalar alpha = NAN;                 // Thermal diffusivity
     198             :     Set::Scalar refinement_threshold = NAN ; // Criterion for cell refinement
     199             : 
     200             :     //
     201             :     // Definition of user-determined pointer variables.
     202             :     //
     203             :     // These should be set to nullptr. Make sure that they are deleted
     204             :     // in the ~HeatConduction destructor.
     205             :     //
     206             : 
     207             :     IC::IC* ic = nullptr;                    // Object used to initialize temperature field
     208             :     BC::BC<Set::Scalar>* bc = nullptr;       // Object used to update temp field boundary ghost cells
     209             : };
     210             : } // namespace Integrator
     211             : #endif

Generated by: LCOV version 1.14