LCOV - code coverage report
Current view: top level - drivers - transientsolver.cpp (source / functions) Coverage Total Hit
Test: Palace Coverage Report Lines: 0.0 % 74 0
Test Date: 2025-10-23 22:45:05 Functions: 0.0 % 4 0
Legend: Lines: hit not hit

            Line data    Source code
       1              : // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
       2              : // SPDX-License-Identifier: Apache-2.0
       3              : 
       4              : #include "transientsolver.hpp"
       5              : 
       6              : #include <mfem.hpp>
       7              : #include "fem/errorindicator.hpp"
       8              : #include "fem/mesh.hpp"
       9              : #include "linalg/errorestimator.hpp"
      10              : #include "linalg/vector.hpp"
      11              : #include "models/lumpedportoperator.hpp"
      12              : #include "models/portexcitations.hpp"
      13              : #include "models/postoperator.hpp"
      14              : #include "models/spaceoperator.hpp"
      15              : #include "models/surfacecurrentoperator.hpp"
      16              : #include "models/timeoperator.hpp"
      17              : #include "utils/communication.hpp"
      18              : #include "utils/excitations.hpp"
      19              : #include "utils/iodata.hpp"
      20              : #include "utils/timer.hpp"
      21              : 
      22              : namespace palace
      23              : {
      24              : 
      25              : std::pair<ErrorIndicator, long long int>
      26            0 : TransientSolver::Solve(const std::vector<std::unique_ptr<Mesh>> &mesh) const
      27              : {
      28              :   // Set up the spatial discretization and time integrators for the E and B fields.
      29            0 :   BlockTimer bt0(Timer::CONSTRUCT);
      30            0 :   std::function<double(double)> J_coef = GetTimeExcitation(false);
      31            0 :   std::function<double(double)> dJdt_coef = GetTimeExcitation(true);
      32            0 :   SpaceOperator space_op(iodata, mesh);
      33            0 :   TimeOperator time_op(iodata, space_op, dJdt_coef);
      34              : 
      35            0 :   double delta_t = iodata.solver.transient.delta_t;
      36            0 :   int n_step = config::GetNumSteps(0.0, iodata.solver.transient.max_t, delta_t);
      37            0 :   SaveMetadata(space_op.GetNDSpaces());
      38              : 
      39              :   // Time stepping is uniform in the time domain. Index sets are for computing things like
      40              :   // port voltages and currents in postprocessing.
      41            0 :   PostOperator<ProblemType::TRANSIENT> post_op(iodata, space_op);
      42              : 
      43              :   // Transient solver only supports a single excitation, this is check in SpaceOperator.
      44            0 :   Mpi::Print("\nComputing transient response for:\n{}",
      45            0 :              space_op.GetPortExcitations().FmtLog());
      46              : 
      47              :   // Initialize structures for storing and reducing the results of error estimation.
      48              :   TimeDependentFluxErrorEstimator<Vector> estimator(
      49              :       space_op.GetMaterialOp(), space_op.GetNDSpaces(), space_op.GetRTSpaces(),
      50            0 :       iodata.solver.linear.estimator_tol, iodata.solver.linear.estimator_max_it, 0,
      51            0 :       iodata.solver.linear.estimator_mg);
      52              :   ErrorIndicator indicator;
      53              : 
      54              :   // Main time integration loop.
      55            0 :   double t = -delta_t;
      56              :   auto t0 = Timer::Now();
      57            0 :   for (int step = 0; step < n_step; step++)
      58              :   {
      59            0 :     const double ts = iodata.units.Dimensionalize<Units::ValueType::TIME>(t + delta_t);
      60            0 :     Mpi::Print("\nIt {:d}/{:d}: t = {:e} ns (elapsed time = {:.2e} s)\n", step, n_step - 1,
      61            0 :                ts, Timer::Duration(Timer::Now() - t0).count());
      62              : 
      63              :     // Single time step t -> t + dt.
      64            0 :     BlockTimer bt1(Timer::TS);
      65            0 :     if (step == 0)
      66              :     {
      67            0 :       Mpi::Print("\n");
      68            0 :       t += delta_t;
      69            0 :       time_op.Init();  // Initial conditions
      70              :     }
      71              :     else
      72              :     {
      73            0 :       time_op.Step(t, delta_t);  // Advances t internally
      74              :     }
      75              : 
      76              :     // Postprocess for the time step.
      77            0 :     BlockTimer bt2(Timer::POSTPRO);
      78              :     const Vector &E = time_op.GetE();
      79              :     const Vector &B = time_op.GetB();
      80            0 :     Mpi::Print(" Sol. ||E|| = {:.6e}, ||B|| = {:.6e}\n",
      81            0 :                linalg::Norml2(space_op.GetComm(), E),
      82            0 :                linalg::Norml2(space_op.GetComm(), B));
      83              : 
      84            0 :     auto total_domain_energy = post_op.MeasureAndPrintAll(step, E, B, t, J_coef(t));
      85              : 
      86              :     // Calculate and record the error indicators.
      87            0 :     Mpi::Print(" Updating solution error estimates\n");
      88            0 :     estimator.AddErrorIndicator(E, B, total_domain_energy, indicator);
      89            0 :   }
      90              :   // Final postprocessing & printing.
      91            0 :   BlockTimer bt1(Timer::POSTPRO);
      92            0 :   time_op.PrintStats();
      93            0 :   SaveMetadata(time_op.GetLinearSolver());
      94            0 :   post_op.MeasureFinalize(indicator);
      95            0 :   return {indicator, space_op.GlobalTrueVSize()};
      96            0 : }
      97              : 
      98            0 : std::function<double(double)> TransientSolver::GetTimeExcitation(bool dot) const
      99              : {
     100              :   using namespace excitations;
     101              :   using F = std::function<double(double)>;
     102            0 :   const config::TransientSolverData &data = iodata.solver.transient;
     103              :   const Excitation &type = data.excitation;
     104            0 :   if (type == Excitation::SINUSOIDAL || type == Excitation::MOD_GAUSSIAN)
     105              :   {
     106            0 :     MFEM_VERIFY(data.pulse_f > 0.0,
     107              :                 "Excitation frequency is missing for transient simulation!");
     108              :   }
     109            0 :   if (type == Excitation::GAUSSIAN || type == Excitation::DIFF_GAUSSIAN ||
     110            0 :       type == Excitation::MOD_GAUSSIAN || type == Excitation::SMOOTH_STEP)
     111              :   {
     112            0 :     MFEM_VERIFY(data.pulse_tau > 0.0,
     113              :                 "Excitation width is missing for transient simulation!");
     114              :   }
     115              :   const double delay = (type == Excitation::GAUSSIAN || type == Excitation::DIFF_GAUSSIAN ||
     116              :                         type == Excitation::MOD_GAUSSIAN)
     117            0 :                            ? 4.5 * data.pulse_tau
     118              :                            : 0.0;
     119            0 :   switch (type)
     120              :   {
     121            0 :     case Excitation::SINUSOIDAL:
     122            0 :       if (dot)
     123              :       {
     124            0 :         return F{[=](double t) { return dpulse_sinusoidal(t, data.pulse_f, delay); }};
     125              :       }
     126              :       else
     127              :       {
     128            0 :         return F{[=](double t) { return pulse_sinusoidal(t, data.pulse_f, delay); }};
     129              :       }
     130              :       break;
     131            0 :     case Excitation::GAUSSIAN:
     132            0 :       if (dot)
     133              :       {
     134            0 :         return F{[=](double t) { return dpulse_gaussian(t, data.pulse_tau, delay); }};
     135              :       }
     136              :       else
     137              :       {
     138            0 :         return F{[=](double t) { return pulse_gaussian(t, data.pulse_tau, delay); }};
     139              :       }
     140              :       break;
     141            0 :     case Excitation::DIFF_GAUSSIAN:
     142            0 :       if (dot)
     143              :       {
     144            0 :         return F{[=](double t) { return dpulse_gaussian_diff(t, data.pulse_tau, delay); }};
     145              :       }
     146              :       else
     147              :       {
     148            0 :         return F{[=](double t) { return pulse_gaussian_diff(t, data.pulse_tau, delay); }};
     149              :       }
     150              :       break;
     151            0 :     case Excitation::MOD_GAUSSIAN:
     152            0 :       if (dot)
     153              :       {
     154            0 :         return F{[=](double t)
     155            0 :                  { return dpulse_gaussian_mod(t, data.pulse_f, data.pulse_tau, delay); }};
     156              :       }
     157              :       else
     158              :       {
     159            0 :         return F{[=](double t)
     160            0 :                  { return pulse_gaussian_mod(t, data.pulse_f, data.pulse_tau, delay); }};
     161              :       }
     162              :       break;
     163            0 :     case Excitation::RAMP_STEP:
     164            0 :       if (dot)
     165              :       {
     166            0 :         return F{[=](double t) { return dpulse_ramp(t, data.pulse_tau, delay); }};
     167              :       }
     168              :       else
     169              :       {
     170            0 :         return F{[=](double t) { return pulse_ramp(t, data.pulse_tau, delay); }};
     171              :       }
     172              :       break;
     173            0 :     case Excitation::SMOOTH_STEP:
     174            0 :       if (dot)
     175              :       {
     176            0 :         return F{[=](double t) { return dpulse_smootherstep(t, data.pulse_tau, delay); }};
     177              :       }
     178              :       else
     179              :       {
     180            0 :         return F{[=](double t) { return pulse_smootherstep(t, data.pulse_tau, delay); }};
     181              :       }
     182              :       break;
     183              :   }
     184              :   return F{};
     185              : }
     186              : 
     187              : }  // namespace palace
        

Generated by: LCOV version 2.0-1