LCOV - code coverage report
Current view: top level - src/MaxwellSolvers - NonStandardFDTDSolver.hpp (source / functions) Coverage Total Hit
Test: final_report.info Lines: 0.0 % 82 0
Test Date: 2025-07-10 08:24:38 Functions: 0.0 % 4 0

            Line data    Source code
       1              : /**
       2              :  * @file NonStandardFDTDSolver.hpp
       3              :  * @brief Impelmentation of the NonStandardFDTDSolver class functions.
       4              :  */
       5              : 
       6              : namespace ippl {
       7              : 
       8              :     /**
       9              :      * @brief Constructor for the NonStandardFDTDSolver class.
      10              :      *
      11              :      * This constructor initializes the NonStandardFDTDSolver with the given source field and
      12              :      * electromagnetic fields. It checks the dispersion-free CFL condition and initializes the
      13              :      * solver.
      14              :      *
      15              :      * @param source The source field.
      16              :      * @param E The electric field.
      17              :      * @param B The magnetic field.
      18              :      */
      19              :     template <typename EMField, typename SourceField, fdtd_bc boundary_conditions>
      20            0 :     NonStandardFDTDSolver<EMField, SourceField, boundary_conditions>::NonStandardFDTDSolver(
      21              :         SourceField& source, EMField& E, EMField& B)
      22            0 :         : FDTDSolverBase<EMField, SourceField, boundary_conditions>(source, E, B) {
      23            0 :         auto hx = source.get_mesh().getMeshSpacing();
      24            0 :         if ((hx[2] / hx[0]) * (hx[2] / hx[0]) + (hx[2] / hx[1]) * (hx[2] / hx[1]) >= 1) {
      25            0 :             throw IpplException("NonStandardFDTDSolver Constructor",
      26              :                                 "Dispersion-free CFL condition not satisfiable\n");
      27              :         }
      28            0 :         initialize();
      29            0 :     }
      30              : 
      31              :     /**
      32              :      * @brief Advances the simulation by one time step.
      33              :      *
      34              :      * This function updates the fields by one time step using non-standard FDTD method.
      35              :      * It calculates the new field values based on the current and previous field values,
      36              :      * as well as the source field. The boundary conditions are applied after the update.
      37              :      */
      38              :     template <typename EMField, typename SourceField, fdtd_bc boundary_conditions>
      39            0 :     void NonStandardFDTDSolver<EMField, SourceField, boundary_conditions>::step() {
      40            0 :         const auto& ldom       = this->layout_mp->getLocalNDIndex();
      41            0 :         const int nghost       = this->A_n.getNghost();
      42            0 :         const auto aview       = this->A_n.getView();
      43            0 :         const auto anp1view    = this->A_np1.getView();
      44            0 :         const auto anm1view    = this->A_nm1.getView();
      45            0 :         const auto source_view = Maxwell<EMField, SourceField>::JN_mp->getView();
      46              : 
      47            0 :         const scalar calA =
      48              :             0.25
      49            0 :             * (1
      50            0 :                + 0.02
      51            0 :                      / (static_cast<scalar>(Kokkos::pow(this->hr_m[2] / this->hr_m[0], 2))
      52            0 :                         + static_cast<scalar>(Kokkos::pow(this->hr_m[2] / this->hr_m[1], 2))));
      53            0 :         nondispersive<scalar> ndisp{
      54              :             .a1 =
      55              :                 2
      56            0 :                 * (1
      57            0 :                    - (1 - 2 * calA) * static_cast<scalar>(Kokkos::pow(this->dt / this->hr_m[0], 2))
      58            0 :                    - (1 - 2 * calA) * static_cast<scalar>(Kokkos::pow(this->dt / this->hr_m[1], 2))
      59            0 :                    - static_cast<scalar>(Kokkos::pow(this->dt / this->hr_m[2], 2))),
      60            0 :             .a2 = static_cast<scalar>(Kokkos::pow(this->dt / this->hr_m[0], 2)),
      61            0 :             .a4 = static_cast<scalar>(Kokkos::pow(this->dt / this->hr_m[1], 2)),
      62            0 :             .a6 = static_cast<scalar>(Kokkos::pow(this->dt / this->hr_m[2], 2))
      63            0 :                   - 2 * calA * static_cast<scalar>(Kokkos::pow(this->dt / this->hr_m[0], 2))
      64            0 :                   - 2 * calA * static_cast<scalar>(Kokkos::pow(this->dt / this->hr_m[1], 2)),
      65            0 :             .a8 = static_cast<scalar>(Kokkos::pow(this->dt, 2))};
      66            0 :         Vector<uint32_t, Dim> true_nr = this->nr_m;
      67            0 :         true_nr += (nghost * 2);
      68            0 :         constexpr uint32_t one_if_absorbing_otherwise_0 =
      69              :             boundary_conditions == absorbing
      70              :                 ? 1
      71              :                 : 0;  // 1 if absorbing, 0 otherwise, indicates the start index of the field
      72            0 :         Kokkos::parallel_for(
      73            0 :             ippl::getRangePolicy(aview, nghost), KOKKOS_LAMBDA(size_t i, size_t j, size_t k) {
      74              :                 // global indices
      75            0 :                 uint32_t ig = i + ldom.first()[0];
      76            0 :                 uint32_t jg = j + ldom.first()[1];
      77            0 :                 uint32_t kg = k + ldom.first()[2];
      78              :                 // check if at a boundary of the field
      79            0 :                 uint32_t val =
      80            0 :                     uint32_t(ig == one_if_absorbing_otherwise_0)
      81            0 :                     + (uint32_t(jg == one_if_absorbing_otherwise_0) << 1)
      82            0 :                     + (uint32_t(kg == one_if_absorbing_otherwise_0) << 2)
      83            0 :                     + (uint32_t(ig == true_nr[0] - one_if_absorbing_otherwise_0 - 1) << 3)
      84            0 :                     + (uint32_t(jg == true_nr[1] - one_if_absorbing_otherwise_0 - 1) << 4)
      85            0 :                     + (uint32_t(kg == true_nr[2] - one_if_absorbing_otherwise_0 - 1) << 5);
      86              :                 // update the interior field values
      87            0 :                 if (!val) {
      88            0 :                     anp1view(i, j, k) =
      89            0 :                         -anm1view(i, j, k) + ndisp.a1 * aview(i, j, k)
      90            0 :                         + ndisp.a2
      91            0 :                               * (calA * aview(i + 1, j, k - 1) + (1 - 2 * calA) * aview(i + 1, j, k)
      92            0 :                                  + calA * aview(i + 1, j, k + 1))
      93            0 :                         + ndisp.a2
      94            0 :                               * (calA * aview(i - 1, j, k - 1) + (1 - 2 * calA) * aview(i - 1, j, k)
      95            0 :                                  + calA * aview(i - 1, j, k + 1))
      96            0 :                         + ndisp.a4
      97            0 :                               * (calA * aview(i, j + 1, k - 1) + (1 - 2 * calA) * aview(i, j + 1, k)
      98            0 :                                  + calA * aview(i, j + 1, k + 1))
      99            0 :                         + ndisp.a4
     100            0 :                               * (calA * aview(i, j - 1, k - 1) + (1 - 2 * calA) * aview(i, j - 1, k)
     101            0 :                                  + calA * aview(i, j - 1, k + 1))
     102            0 :                         + ndisp.a6 * aview(i, j, k + 1) + ndisp.a6 * aview(i, j, k - 1)
     103            0 :                         + ndisp.a8 * source_view(i, j, k);
     104              :                 }
     105              :             });
     106            0 :         Kokkos::fence();
     107            0 :         this->A_np1.fillHalo();
     108            0 :         this->applyBCs();
     109            0 :     }
     110              : 
     111              :     /**
     112              :      * @brief Initializes the solver.
     113              :      *
     114              :      * This function initializes the solver by setting up the layout, mesh, and fields.
     115              :      * It retrieves the mesh spacing, domain, and mesh size, and initializes the fields to zero.
     116              :      */
     117              :     template <typename EMField, typename SourceField, fdtd_bc boundary_conditions>
     118            0 :     void NonStandardFDTDSolver<EMField, SourceField, boundary_conditions>::initialize() {
     119              :         // get layout and mesh
     120            0 :         this->layout_mp = &(this->JN_mp->getLayout());
     121            0 :         this->mesh_mp   = &(this->JN_mp->get_mesh());
     122              : 
     123              :         // get mesh spacing, domain, and mesh size
     124            0 :         this->hr_m     = this->mesh_mp->getMeshSpacing();
     125            0 :         this->dt       = this->hr_m[2];
     126            0 :         this->domain_m = this->layout_mp->getDomain();
     127            0 :         for (unsigned int i = 0; i < Dim; ++i)
     128            0 :             this->nr_m[i] = this->domain_m[i].length();
     129              : 
     130              :         // initialize fields
     131            0 :         this->A_nm1.initialize(*this->mesh_mp, *this->layout_mp);
     132            0 :         this->A_n.initialize(*this->mesh_mp, *this->layout_mp);
     133            0 :         this->A_np1.initialize(*this->mesh_mp, *this->layout_mp);
     134              : 
     135            0 :         this->A_nm1 = 0.0;
     136            0 :         this->A_n   = 0.0;
     137            0 :         this->A_np1 = 0.0;
     138              : 
     139              :         // set the mesh domain
     140              :         if constexpr (boundary_conditions == periodic) {
     141            0 :             this->setPeriodicBoundaryConditions();
     142              :         }
     143            0 :     };
     144              : }  // namespace ippl
        

Generated by: LCOV version 2.0-1