LCOV - code coverage report
Current view: top level - utils - configfile.hpp (source / functions) Coverage Total Hit
Test: Palace Coverage Report Lines: 73.9 % 23 17
Test Date: 2025-10-23 22:45:05 Functions: - 0 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              : #ifndef PALACE_UTILS_CONFIG_FILE_HPP
       5              : #define PALACE_UTILS_CONFIG_FILE_HPP
       6              : 
       7              : #include <array>
       8              : #include <map>
       9              : #include <string>
      10              : #include <vector>
      11              : #include <nlohmann/json_fwd.hpp>
      12              : #include "labels.hpp"
      13              : 
      14              : namespace palace::config
      15              : {
      16              : 
      17              : using json = nlohmann::json;
      18              : 
      19              : //
      20              : // Data structures for storing configuration file data.
      21              : //
      22              : namespace internal
      23              : {
      24              : 
      25              : template <typename DataType>
      26              : struct DataVector
      27              : {
      28              : protected:
      29              :   std::vector<DataType> vecdata = {};
      30              : 
      31              : public:
      32              :   template <typename... Args>
      33              :   decltype(auto) emplace_back(Args &&...args)
      34              :   {
      35           39 :     return vecdata.emplace_back(std::forward<Args>(args)...);
      36              :   }
      37           39 :   [[nodiscard]] const auto &operator[](int i) const { return vecdata[i]; }
      38              :   [[nodiscard]] auto &operator[](int i) { return vecdata[i]; }
      39              :   [[nodiscard]] const auto &at(int i) const { return vecdata.at(i); }
      40              :   [[nodiscard]] auto &at(int i) { return vecdata.at(i); }
      41              :   [[nodiscard]] auto size() const { return vecdata.size(); }
      42              :   [[nodiscard]] auto empty() const { return vecdata.empty(); }
      43              :   [[nodiscard]] auto begin() const { return vecdata.begin(); }
      44              :   [[nodiscard]] auto end() const { return vecdata.end(); }
      45              :   [[nodiscard]] auto begin() { return vecdata.begin(); }
      46              :   [[nodiscard]] auto end() { return vecdata.end(); }
      47              :   [[nodiscard]] auto front() const { return vecdata.front(); }
      48              :   [[nodiscard]] auto back() const { return vecdata.back(); }
      49              :   [[nodiscard]] auto front() { return vecdata.front(); }
      50            1 :   [[nodiscard]] auto back() { return vecdata.back(); }
      51              : };
      52              : 
      53              : template <typename DataType>
      54              : struct DataMap
      55              : {
      56              : protected:
      57              :   // Map keys are the object indices for postprocessing.
      58              :   std::map<int, DataType> mapdata = {};
      59              : 
      60              : public:
      61              :   [[nodiscard]] const auto &operator[](int i) const { return mapdata[i]; }
      62              :   [[nodiscard]] auto &operator[](int i) { return mapdata[i]; }
      63              :   [[nodiscard]] const auto &at(int i) const { return mapdata.at(i); }
      64           22 :   [[nodiscard]] auto &at(int i) { return mapdata.at(i); }
      65              :   [[nodiscard]] auto size() const { return mapdata.size(); }
      66              :   [[nodiscard]] auto empty() const { return mapdata.empty(); }
      67              :   [[nodiscard]] auto begin() const { return mapdata.begin(); }
      68              :   [[nodiscard]] auto end() const { return mapdata.end(); }
      69              :   [[nodiscard]] auto begin() { return mapdata.begin(); }
      70              :   [[nodiscard]] auto end() { return mapdata.end(); }
      71              : };
      72              : 
      73              : // An ElementData consists of a list of attributes making up a single element of a
      74              : // potentially multielement boundary, and a direction and/or a normal defining the incident
      75              : // field. These are used for lumped ports, terminals, surface currents, and other boundary
      76              : // postprocessing objects.
      77           77 : struct ElementData
      78              : {
      79              :   // Vector defining the direction for this port. In a Cartesian system, "X", "Y", and "Z"
      80              :   // map to (1,0,0), (0,1,0), and (0,0,1), respectively.
      81              :   std::array<double, 3> direction{{0.0, 0.0, 0.0}};
      82              : 
      83              :   CoordinateSystem coordinate_system = CoordinateSystem::CARTESIAN;
      84              : 
      85              :   // List of boundary attributes for this element.
      86              :   std::vector<int> attributes = {};
      87              : };
      88              : 
      89              : }  // namespace internal
      90              : 
      91              : // Problem & Model Config.
      92              : 
      93              : struct OutputFormatsData
      94              : {
      95              : public:
      96              :   // Enable Paraview output format.
      97              :   bool paraview = true;
      98              : 
      99              :   // Enable MFEM GLVis grid function output format.
     100              :   bool gridfunction = false;
     101              : };
     102              : 
     103           39 : struct ProblemData
     104              : {
     105              : public:
     106              :   // Simulation type.
     107              :   ProblemType type = ProblemType::DRIVEN;
     108              : 
     109              :   // Level of printing.
     110              :   int verbose = 1;
     111              : 
     112              :   // Output path for storing results.
     113              :   std::string output = "";
     114              : 
     115              :   // Output formats configuration.
     116              :   OutputFormatsData output_formats = {};
     117              : 
     118              :   void SetUp(json &config);
     119              : };
     120              : 
     121              : struct BoxRefinementData
     122              : {
     123              :   // Refinement levels.
     124              :   int ref_levels = 0;
     125              : 
     126              :   // Region bounding box limits [m].
     127              :   std::array<double, 3> bbmin{{0.0, 0.0, 0.0}}, bbmax{{0.0, 0.0, 0.0}};
     128              : };
     129              : 
     130            0 : struct SphereRefinementData
     131              : {
     132              :   // Refinement levels.
     133              :   int ref_levels = 0;
     134              : 
     135              :   // Sphere radius [m].
     136              :   double r = 0.0;
     137              : 
     138              :   // Sphere center [m].
     139              :   std::array<double, 3> center{{0.0, 0.0, 0.0}};
     140              : };
     141              : 
     142              : struct RefinementData
     143              : {
     144              : public:
     145              :   // Non-dimensional tolerance used to specify convergence of adaptive mesh refinement.
     146              :   double tol = 1.0e-2;
     147              : 
     148              :   // Maximum number of iterations to perform during adaptive mesh refinement.
     149              :   int max_it = 0;
     150              : 
     151              :   // If a refinement results in a greater number of DOFs than this value, no future
     152              :   // refinement will be allowed.
     153              :   int max_size = 0;
     154              : 
     155              :   // Whether or not to perform nonconformal adaptation.
     156              :   bool nonconformal = true;
     157              : 
     158              :   // Maximum difference in nonconformal refinements between two adjacent elements. Zero
     159              :   // implies there is no constraint on local nonconformity.
     160              :   int max_nc_levels = 1;
     161              : 
     162              :   // Dörfler update fraction. The set of marked elements is the minimum set that contains
     163              :   // update_fraction of the total error.
     164              :   double update_fraction = 0.7;
     165              : 
     166              :   // Maximum allowable ratio of number of elements across processors before rebalancing is
     167              :   // performed.
     168              :   double maximum_imbalance = 1.1;
     169              : 
     170              :   // Whether to save off results of each adaptation iteration as a subfolder within the post
     171              :   // processing directory.
     172              :   bool save_adapt_iterations = true;
     173              : 
     174              :   // Whether to write a (serial) mesh to file after mesh modification during AMR.
     175              :   bool save_adapt_mesh = false;
     176              : 
     177              :   // Parallel uniform mesh refinement levels.
     178              :   int uniform_ref_levels = 0;
     179              : 
     180              :   // Serial uniform mesh refinement levels.
     181              :   int ser_uniform_ref_levels = 0;
     182              : 
     183              : private:
     184              :   // Refinement data for mesh regions.
     185              :   std::vector<BoxRefinementData> box_list = {};
     186              :   std::vector<SphereRefinementData> sphere_list = {};
     187              : 
     188              : public:
     189              :   auto &GetBox(int i) { return box_list[i]; }
     190              :   const auto &GetBoxes() const { return box_list; }
     191              :   auto &GetBoxes() { return box_list; }
     192              : 
     193              :   auto &GetSphere(int i) { return sphere_list[i]; }
     194              :   const auto &GetSpheres() const { return sphere_list; }
     195              :   auto &GetSpheres() { return sphere_list; }
     196              : 
     197              :   void SetUp(json &model);
     198              : };
     199              : 
     200              : struct ModelData
     201              : {
     202              : public:
     203              :   // Mesh file.
     204              :   std::string mesh = "";
     205              : 
     206              :   // Mesh length unit and optional characteristic length scale for nondimensionalization
     207              :   // [m].
     208              :   double L0 = 1.0e-6;
     209              :   double Lc = -1.0;
     210              : 
     211              :   // Remove high-order curvature information from the mesh.
     212              :   bool remove_curvature = false;
     213              : 
     214              :   // Convert mesh to simplex elements.
     215              :   bool make_simplex = false;
     216              : 
     217              :   // Convert mesh to hexahedral elements (using tet-to-hex algorithm).
     218              :   bool make_hex = false;
     219              : 
     220              :   // Reorder elements based on spatial location after loading the serial mesh, which can
     221              :   // potentially increase memory coherency.
     222              :   bool reorder_elements = false;
     223              : 
     224              :   // Remove elements (along with any associated unattached boundary elements) from the mesh
     225              :   // which do not have any material properties specified.
     226              :   bool clean_unused_elements = true;
     227              : 
     228              :   // Split, or "crack", boundary elements lying on internal boundaries to decouple the
     229              :   // elements on either side.
     230              :   bool crack_bdr_elements = true;
     231              : 
     232              :   // When required, refine elements neighboring a split or crack in order to enable the
     233              :   // decoupling.
     234              :   bool refine_crack_elements = true;
     235              : 
     236              :   // Factor for displacing duplicated interior boundary elements, usually added just for
     237              :   // visualization.
     238              :   double crack_displ_factor = 1.0e-12;
     239              : 
     240              :   // Add new boundary elements for faces are on the computational domain boundary or which
     241              :   // have attached elements on either side with different domain attributes.
     242              :   bool add_bdr_elements = true;
     243              : 
     244              :   // Export mesh after pre-processing but before cracking.
     245              :   bool export_prerefined_mesh = false;
     246              : 
     247              :   // Call MFEM's ReorientTetMesh as a check of mesh orientation after partitioning.
     248              :   bool reorient_tet_mesh = false;
     249              : 
     250              :   // Partitioning file (if specified, does not compute a new partitioning).
     251              :   std::string partitioning = "";
     252              : 
     253              :   // Object controlling mesh refinement.
     254              :   RefinementData refinement = {};
     255              : 
     256              :   void SetUp(json &config);
     257              : };
     258              : 
     259              : // Domain Config.
     260              : 
     261              : // Store symmetric matrix data as set of outer products: Σᵢ sᵢ * vᵢ *  vᵢᵀ.
     262              : template <std::size_t N>
     263              : struct SymmetricMatrixData
     264              : {
     265              : public:
     266              :   std::array<double, N> s;
     267              :   std::array<std::array<double, N>, N> v;
     268              : 
     269           12 :   SymmetricMatrixData(double diag)
     270              :   {
     271              :     s.fill(diag);
     272              :     std::size_t i = 0;
     273           48 :     for (auto &x : v)
     274              :     {
     275              :       x.fill(0.0);
     276           36 :       x[i++] = 1.0;
     277              :     }
     278              :   }
     279              : };
     280              : 
     281           40 : struct MaterialData
     282              : {
     283              : public:
     284              :   // Relative permeability.
     285              :   SymmetricMatrixData<3> mu_r = 1.0;
     286              : 
     287              :   // Relative permittivity.
     288              :   SymmetricMatrixData<3> epsilon_r = 1.0;
     289              : 
     290              :   // Loss tangent.
     291              :   SymmetricMatrixData<3> tandelta = 0.0;
     292              : 
     293              :   // Conductivity [S/m].
     294              :   SymmetricMatrixData<3> sigma = 0.0;
     295              : 
     296              :   // London penetration depth [m].
     297              :   double lambda_L = 0.0;
     298              : 
     299              :   // List of domain attributes for this material.
     300              :   std::vector<int> attributes = {};
     301              : };
     302              : 
     303              : struct DomainMaterialData : public internal::DataVector<MaterialData>
     304              : {
     305              : public:
     306              :   void SetUp(json &domains);
     307              : };
     308              : 
     309              : struct DomainEnergyData
     310              : {
     311              : public:
     312              :   // List of domain attributes for this domain postprocessing index.
     313              :   std::vector<int> attributes = {};
     314              : };
     315              : 
     316              : struct DomainEnergyPostData : public internal::DataMap<DomainEnergyData>
     317              : {
     318              : public:
     319              :   void SetUp(json &postpro);
     320              : };
     321              : 
     322           16 : struct ProbeData
     323              : {
     324              : public:
     325              :   // Physical space coordinates for the probe location [m].
     326              :   std::array<double, 3> center{{0.0, 0.0, 0.0}};
     327              : };
     328              : 
     329              : struct ProbePostData : public internal::DataMap<ProbeData>
     330              : {
     331              : public:
     332              :   void SetUp(json &postpro);
     333              : };
     334              : 
     335              : struct DomainPostData
     336              : {
     337              : public:
     338              :   // List of all postprocessing domain attributes.
     339              :   std::vector<int> attributes = {};
     340              : 
     341              :   // Domain postprocessing objects.
     342              :   DomainEnergyPostData energy;
     343              :   ProbePostData probe;
     344              : 
     345              :   void SetUp(json &domains);
     346              : };
     347              : 
     348              : struct DomainData
     349              : {
     350              : public:
     351              :   // List of all domain attributes (excluding postprocessing).
     352              :   std::vector<int> attributes = {};
     353              : 
     354              :   // Domain objects.
     355              :   DomainMaterialData materials = {};
     356              :   DomainPostData postpro = {};
     357              : 
     358              :   void SetUp(json &config);
     359              : };
     360              : 
     361              : // Boundary Configuration.
     362              : 
     363              : struct PecBoundaryData
     364              : {
     365              : public:
     366              :   // List of boundary attributes with PEC boundary conditions.
     367              :   std::vector<int> attributes = {};
     368              : 
     369              :   [[nodiscard]] auto empty() const { return attributes.empty(); }
     370              : 
     371              :   void SetUp(json &boundaries);
     372              : };
     373              : 
     374              : struct PmcBoundaryData
     375              : {
     376              : public:
     377              :   // List of boundary attributes with PMC boundary conditions.
     378              :   std::vector<int> attributes = {};
     379              : 
     380              :   [[nodiscard]] auto empty() const { return attributes.empty(); }
     381              : 
     382              :   void SetUp(json &boundaries);
     383              : };
     384              : 
     385              : struct WavePortPecBoundaryData
     386              : {
     387              : public:
     388              :   // List of boundary attributes with PEC boundary conditions for wave ports.
     389              :   std::vector<int> attributes = {};
     390              : 
     391              :   [[nodiscard]] auto empty() const { return attributes.empty(); }
     392              : 
     393              :   void SetUp(json &boundaries);
     394              : };
     395              : 
     396              : struct FarfieldBoundaryData
     397              : {
     398              : public:
     399              :   // Approximation order for farfield ABC.
     400              :   int order = 1;
     401              : 
     402              :   // List of boundary attributes with farfield absorbing boundary conditions.
     403              :   std::vector<int> attributes = {};
     404              : 
     405              :   [[nodiscard]] auto empty() const { return attributes.empty(); }
     406              : 
     407              :   void SetUp(json &boundaries);
     408              : };
     409              : 
     410            0 : struct ConductivityData
     411              : {
     412              : public:
     413              :   // Electrical conductivity of the conductor [S/m].
     414              :   double sigma = 0.0;
     415              : 
     416              :   // Conductor relative permeability.
     417              :   double mu_r = 1.0;
     418              : 
     419              :   // Optional conductor thickness [m].
     420              :   double h = 0.0;
     421              : 
     422              :   // Optional flag for an external boundary surface, relevant for the thickness correction.
     423              :   bool external = false;
     424              : 
     425              :   // List of boundary attributes for this surface conductivity boundary condition.
     426              :   std::vector<int> attributes = {};
     427              : };
     428              : 
     429              : struct ConductivityBoundaryData : public internal::DataVector<ConductivityData>
     430              : {
     431              : public:
     432              :   void SetUp(json &boundaries);
     433              : };
     434              : 
     435            0 : struct ImpedanceData
     436              : {
     437              : public:
     438              :   // Boundary surface resistance, inductance, and capacitance [Ω/sq, H/sq, F/sq].
     439              :   double Rs = 0.0;
     440              :   double Ls = 0.0;
     441              :   double Cs = 0.0;
     442              : 
     443              :   // List of boundary attributes for this impedance boundary condition.
     444              :   std::vector<int> attributes = {};
     445              : };
     446              : 
     447              : struct ImpedanceBoundaryData : public internal::DataVector<ImpedanceData>
     448              : {
     449              : public:
     450              :   void SetUp(json &boundaries);
     451              : };
     452              : 
     453          131 : struct LumpedPortData
     454              : {
     455              : public:
     456              :   // Port circuit resistance, inductance, and capacitance [Ω/sq, H/sq, F/sq].
     457              :   double R = 0.0;
     458              :   double L = 0.0;
     459              :   double C = 0.0;
     460              : 
     461              :   // Port surface resistance, inductance, and capacitance [Ω/sq, H/sq, F/sq].
     462              :   double Rs = 0.0;
     463              :   double Ls = 0.0;
     464              :   double Cs = 0.0;
     465              : 
     466              :   // Input excitation for driven & transient solver:
     467              :   // - Wave/Lumped ports with same index are excited together.
     468              :   // - 1-based index if excited; 0 if not excited.
     469              :   int excitation = 0;
     470              : 
     471              :   // Flag for boundary damping term in driven and transient simulations.
     472              :   bool active = true;
     473              : 
     474              :   // For each lumped port index, each element contains a list of attributes making up a
     475              :   // single element of a potentially multielement lumped port.
     476              :   std::vector<internal::ElementData> elements = {};
     477              : };
     478              : 
     479            6 : struct LumpedPortBoundaryData : public internal::DataMap<LumpedPortData>
     480              : {
     481              : public:
     482              :   void SetUp(json &boundaries);
     483              : };
     484              : 
     485            0 : struct PeriodicData
     486              : {
     487              : public:
     488              :   // Vector defining the affine transformation matrix for this periodic boundary condition.
     489              :   std::array<double, 16> affine_transform = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
     490              :                                              0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
     491              : 
     492              :   // List of boundary donor attributes for this periodic boundary condition.
     493              :   std::vector<int> donor_attributes = {};
     494              : 
     495              :   // List of boundary receiver attributes for this periodic boundary condition.
     496              :   std::vector<int> receiver_attributes = {};
     497              : };
     498              : 
     499              : struct PeriodicBoundaryData
     500              : {
     501              : public:
     502              :   // Vector of periodic boundary pairs.
     503              :   std::vector<PeriodicData> boundary_pairs = {};
     504              : 
     505              :   // Floquet/Bloch wavevector specifying the phase delay in the X/Y/Z directions.
     506              :   std::array<double, 3> wave_vector = {0.0, 0.0, 0.0};
     507              : 
     508              :   void SetUp(json &boundaries);
     509              : };
     510              : 
     511           20 : struct WavePortData
     512              : {
     513              : public:
     514              :   // Mode index for the numeric wave port.
     515              :   int mode_idx = 1;
     516              : 
     517              :   // Port offset for de-embedding [m].
     518              :   double d_offset = 0.0;
     519              : 
     520              :   // Eigenvalue solver type for boundary mode calculation.
     521              :   EigenSolverBackend eigen_solver = EigenSolverBackend::DEFAULT;
     522              : 
     523              :   // Input excitation for driven & transient solver:
     524              :   // - Wave/Lumped ports with same index are excited together.
     525              :   // - 1-based index if excited; 0 if not excited.
     526              :   int excitation = 0;
     527              : 
     528              :   // Flag for boundary damping term in driven and transient simulations.
     529              :   bool active = true;
     530              : 
     531              :   // List of boundary attributes for this wave port.
     532              :   std::vector<int> attributes = {};
     533              : 
     534              :   // Maximum number of iterations in linear solver.
     535              :   int ksp_max_its = 45;
     536              : 
     537              :   // Tolerance for linear solver.
     538              :   double ksp_tol = 1e-8;
     539              : 
     540              :   // Tolerance for eigenvalue solver.
     541              :   double eig_tol = 1e-6;
     542              : 
     543              :   // Print level for linear and eigenvalue solvers.
     544              :   int verbose = 0;
     545              : };
     546              : 
     547              : struct WavePortBoundaryData : public internal::DataMap<WavePortData>
     548              : {
     549              : public:
     550              :   void SetUp(json &boundaries);
     551              : };
     552              : 
     553            0 : struct SurfaceCurrentData
     554              : {
     555              : public:
     556              :   // For each surface current source index, each element contains a list of attributes
     557              :   // making up a single element of a potentially multielement current source.
     558              :   std::vector<internal::ElementData> elements = {};
     559              : };
     560              : 
     561              : struct SurfaceCurrentBoundaryData : public internal::DataMap<SurfaceCurrentData>
     562              : {
     563              : public:
     564              :   void SetUp(json &boundaries);
     565              : };
     566              : 
     567           16 : struct SurfaceFluxData
     568              : {
     569              : public:
     570              :   // Surface flux type.
     571              :   SurfaceFlux type = SurfaceFlux::ELECTRIC;
     572              : 
     573              :   // Flag for whether or not to consider the boundary as an infinitely thin two-sided
     574              :   // boundary for postprocessing.
     575              :   bool two_sided = false;
     576              : 
     577              :   // Coordinates of a point away from which to compute the outward flux (for orienting the
     578              :   // surface normal) [m].
     579              :   std::array<double, 3> center{{0.0, 0.0, 0.0}};
     580              : 
     581              :   // Flag which indicates whether or not the center point was specified.
     582              :   bool no_center = true;
     583              : 
     584              :   // List of boundary attributes for this surface flux postprocessing index.
     585              :   std::vector<int> attributes = {};
     586              : };
     587              : 
     588              : struct SurfaceFluxPostData : public internal::DataMap<SurfaceFluxData>
     589              : {
     590              : public:
     591              :   void SetUp(json &postpro);
     592              : };
     593              : 
     594           24 : struct InterfaceDielectricData
     595              : {
     596              : public:
     597              :   // Type of interface dielectric for computing electric field energy participation ratios.
     598              :   InterfaceDielectric type = InterfaceDielectric::DEFAULT;
     599              : 
     600              :   // Dielectric interface thickness [m].
     601              :   double t = 0.0;
     602              : 
     603              :   // Relative permittivity.
     604              :   double epsilon_r = 0.0;
     605              : 
     606              :   // Loss tangent.
     607              :   double tandelta = 0.0;
     608              : 
     609              :   // List of boundary attributes for this interface dielectric postprocessing index.
     610              :   std::vector<int> attributes = {};
     611              : };
     612              : 
     613              : struct InterfaceDielectricPostData : public internal::DataMap<InterfaceDielectricData>
     614              : {
     615              : public:
     616              :   void SetUp(json &postpro);
     617              : };
     618              : 
     619              : struct FarFieldPostData
     620              : {
     621              : public:
     622              :   // List of boundary attributes to use for the surface integral.
     623              :   std::vector<int> attributes = {};
     624              : 
     625              :   // List of (theta, phi) where the wave-zone fields should be evaluated.
     626              :   // Units are radians.
     627              :   std::vector<std::pair<double, double>> thetaphis = {};
     628              : 
     629              :   void SetUp(json &postpro);
     630              : 
     631              :   bool empty() const { return thetaphis.empty(); };
     632              : };
     633              : 
     634              : struct BoundaryPostData
     635              : {
     636              : public:
     637              :   // List of all postprocessing boundary attributes.
     638              :   std::vector<int> attributes = {};
     639              : 
     640              :   // Boundary postprocessing objects.
     641              :   SurfaceFluxPostData flux = {};
     642              :   InterfaceDielectricPostData dielectric = {};
     643              :   FarFieldPostData farfield = {};
     644              : 
     645              :   void SetUp(json &boundaries);
     646              : };
     647              : 
     648              : struct BoundaryData
     649              : {
     650              : public:
     651              :   // List of all boundary attributes (excluding postprocessing).
     652              :   std::vector<int> attributes = {};
     653              : 
     654              :   // Boundary objects.
     655              :   PecBoundaryData pec = {};
     656              :   PmcBoundaryData pmc = {};
     657              :   WavePortPecBoundaryData auxpec = {};
     658              :   FarfieldBoundaryData farfield = {};
     659              :   ConductivityBoundaryData conductivity = {};
     660              :   ImpedanceBoundaryData impedance = {};
     661              :   LumpedPortBoundaryData lumpedport = {};
     662              :   WavePortBoundaryData waveport = {};
     663              :   SurfaceCurrentBoundaryData current = {};
     664              :   PeriodicBoundaryData periodic = {};
     665              :   BoundaryPostData postpro = {};
     666              : 
     667              :   void SetUp(json &config);
     668              : };
     669              : 
     670              : // Solver Configuration.
     671              : 
     672           18 : struct DrivenSolverData
     673              : {
     674              : public:
     675              :   // Explicit frequency samples [GHz].
     676              :   std::vector<double> sample_f = {};
     677              : 
     678              :   // Indices of frequency samples to explicitly add to the PROM.
     679              :   std::vector<std::size_t> prom_indices;
     680              : 
     681              :   // Indices of frequency samples on which to save fields to disk.
     682              :   std::vector<std::size_t> save_indices;
     683              : 
     684              :   // Restart iteration for a partial sweep. 1-based indexing. So 1 <= restart <= nr_freq *
     685              :   // nr_excitations.
     686              :   int restart = 1;
     687              : 
     688              :   // Error tolerance for enabling adaptive frequency sweep.
     689              :   double adaptive_tol = 0.0;
     690              : 
     691              :   // Maximum number of frequency samples for adaptive frequency sweep.
     692              :   int adaptive_max_size = 20;
     693              : 
     694              :   // Memory required for adaptive sampling convergence.
     695              :   int adaptive_memory = 2;
     696              : 
     697              :   void SetUp(json &solver);
     698              : };
     699              : 
     700              : struct EigenSolverData
     701              : {
     702              : public:
     703              :   // Target for shift-and-invert spectral transformation [GHz].
     704              :   double target = 0.0;
     705              : 
     706              :   // Eigenvalue solver relative tolerance.
     707              :   double tol = 1.0e-6;
     708              : 
     709              :   // Maximum iterations for eigenvalue solver.
     710              :   int max_it = -1;
     711              : 
     712              :   // Eigenvalue solver subspace dimension or maximum dimension before restart.
     713              :   int max_size = -1;
     714              : 
     715              :   // Desired number of eigenmodes.
     716              :   int n = 1;
     717              : 
     718              :   // Number of modes to write to disk.
     719              :   int n_post = 0;
     720              : 
     721              :   // Use operator scaling in order to increase numerical robustness.
     722              :   bool scale = true;
     723              : 
     724              :   // Compute and set a starting vector for the eigenvalue solver.
     725              :   bool init_v0 = true;
     726              :   bool init_v0_const = false;
     727              : 
     728              :   // Orthogonalize basis vectors using a mass matrix inner product, instead of generating
     729              :   // using a standard ℓ² (Euclidean) norm.
     730              :   bool mass_orthog = false;
     731              : 
     732              :   // Eigenvalue solver type.
     733              :   EigenSolverBackend type = EigenSolverBackend::DEFAULT;
     734              : 
     735              :   // For SLEPc eigenvalue solver, use linearized formulation for quadratic eigenvalue
     736              :   // problems.
     737              :   bool pep_linear = true;
     738              : 
     739              :   // Nonlinear eigenvalue solver type.
     740              :   NonlinearEigenSolver nonlinear_type = NonlinearEigenSolver::HYBRID;
     741              : 
     742              :   // For nonlinear problems, refine the linearized solution with a nonlinear eigensolver.
     743              :   bool refine_nonlinear = true;
     744              : 
     745              :   // For nonlinear problems using the hybrid approach, relative tolerance of the linear
     746              :   // eigenvalue solver used to generate the initial guess.
     747              :   double linear_tol = 1e-3;
     748              : 
     749              :   // Upper end of the target range for nonlinear eigenvalue solver [GHz]. A value <0
     750              :   // will use the default (3 * target).
     751              :   double target_upper = -1;
     752              : 
     753              :   // Update frequency of the preconditioner in the quasi-Newton nonlinear eigenvalue solver.
     754              :   int preconditioner_lag = 10;
     755              : 
     756              :   // Relative tolerance below which the preconditioner is not updated, regardless of the
     757              :   // lag.
     758              :   double preconditioner_lag_tol = 1e-4;
     759              : 
     760              :   // Maximum number of failed attempts with a given initial guess in the quasi-Newton
     761              :   // nonlinear eigenvalue solver.
     762              :   int max_restart = 2;
     763              : 
     764              :   void SetUp(json &solver);
     765              : };
     766              : 
     767              : struct ElectrostaticSolverData
     768              : {
     769              : public:
     770              :   // Number of fields to write to disk.
     771              :   int n_post = 0;
     772              : 
     773              :   void SetUp(json &solver);
     774              : };
     775              : 
     776              : struct MagnetostaticSolverData
     777              : {
     778              : public:
     779              :   // Number of fields to write to disk.
     780              :   int n_post = 0;
     781              : 
     782              :   void SetUp(json &solver);
     783              : };
     784              : 
     785              : struct TransientSolverData
     786              : {
     787              : public:
     788              :   // Time integration scheme type.
     789              :   TimeSteppingScheme type = TimeSteppingScheme::DEFAULT;
     790              : 
     791              :   // Excitation type for port excitation.
     792              :   Excitation excitation = Excitation::SINUSOIDAL;
     793              : 
     794              :   // Excitation parameters: frequency [GHz] and pulse width [ns].
     795              :   double pulse_f = 0.0;
     796              :   double pulse_tau = 0.0;
     797              : 
     798              :   // Upper bound of time interval [ns].
     799              :   double max_t = 1.0;
     800              : 
     801              :   // Step size for time stepping [ns].
     802              :   double delta_t = 1.0e-2;
     803              : 
     804              :   // Step increment for saving fields to disk.
     805              :   int delta_post = 0;
     806              : 
     807              :   // RK scheme order for SUNDIALS ARKODE integrators.
     808              :   // Max order for SUNDIALS CVODE integrator.
     809              :   // Not used for generalized α and Runge-Kutta integrators.
     810              :   int order = 2;
     811              : 
     812              :   // Adaptive time-stepping tolerances for CVODE and ARKODE.
     813              :   double rel_tol = 1e-4;
     814              :   double abs_tol = 1e-9;
     815              : 
     816              :   void SetUp(json &solver);
     817              : };
     818              : 
     819              : struct LinearSolverData
     820              : {
     821              : public:
     822              :   // Solver type.
     823              :   LinearSolver type = LinearSolver::DEFAULT;
     824              : 
     825              :   // Krylov solver type.
     826              :   KrylovSolver krylov_solver = KrylovSolver::DEFAULT;
     827              : 
     828              :   // Iterative solver relative tolerance.
     829              :   double tol = 1.0e-6;
     830              : 
     831              :   // Maximum iterations for iterative solver.
     832              :   int max_it = 100;
     833              : 
     834              :   // Maximum Krylov space dimension for GMRES/FGMRES iterative solvers.
     835              :   int max_size = -1;
     836              : 
     837              :   // Reuse previous solution as initial guess for Krylov solvers.
     838              :   int initial_guess = -1;
     839              : 
     840              :   // Maximum number of levels for geometric multigrid (set to 1 to disable multigrid).
     841              :   int mg_max_levels = 100;
     842              : 
     843              :   // Type of coarsening for p-multigrid.
     844              :   MultigridCoarsening mg_coarsening = MultigridCoarsening::LOGARITHMIC;
     845              : 
     846              :   // Controls whether or not to include in the geometric multigrid hierarchy the mesh levels
     847              :   // from uniform refinement.
     848              :   bool mg_use_mesh = true;
     849              : 
     850              :   // Number of iterations for preconditioners which support it. For multigrid, this is the
     851              :   // number of V-cycles per Krylov solver iteration.
     852              :   int mg_cycle_it = 1;
     853              : 
     854              :   // Use auxiliary space smoothers on geometric multigrid levels.
     855              :   int mg_smooth_aux = -1;
     856              : 
     857              :   // Number of pre-/post-smoothing iterations at each geometric or algebraic multigrid
     858              :   // level.
     859              :   int mg_smooth_it = 1;
     860              : 
     861              :   // Order of polynomial smoothing for geometric multigrid.
     862              :   int mg_smooth_order = -1;
     863              : 
     864              :   // Safety factors for eigenvalue estimates associated with Chebyshev smoothing for
     865              :   // geometric multigrid.
     866              :   double mg_smooth_sf_max = 1.0;
     867              :   double mg_smooth_sf_min = 0.0;
     868              : 
     869              :   // Smooth based on 4th-kind Chebyshev polynomials for geometric multigrid, otherwise
     870              :   // use standard 1st-kind polynomials.
     871              :   bool mg_smooth_cheby_4th = true;
     872              : 
     873              :   // For frequency domain applications, precondition linear systems with a real-valued
     874              :   // approximation to the system matrix.
     875              :   bool pc_mat_real = false;
     876              : 
     877              :   // For frequency domain applications, precondition linear systems with a shifted matrix
     878              :   // (makes the preconditoner matrix SPD).
     879              :   int pc_mat_shifted = -1;
     880              : 
     881              :   // For frequency domain applications, use the complex-valued system matrix in the sparse
     882              :   // direct solver.
     883              :   bool complex_coarse_solve = false;
     884              : 
     885              :   // Choose left or right preconditioning.
     886              :   PreconditionerSide pc_side = PreconditionerSide::DEFAULT;
     887              : 
     888              :   // Specify details for the column ordering method in the symbolic factorization for sparse
     889              :   // direct solvers.
     890              :   SymbolicFactorization sym_factorization = SymbolicFactorization::DEFAULT;
     891              : 
     892              :   // Low-rank and butterfly compression parameters for sparse direct solvers which support
     893              :   // it (mainly STRUMPACK).
     894              :   SparseCompression strumpack_compression_type = SparseCompression::NONE;
     895              : 
     896              :   double strumpack_lr_tol = 1.0e-3;
     897              :   int strumpack_lossy_precision = 16;
     898              :   int strumpack_butterfly_l = 1;
     899              : 
     900              :   // Option to enable 3D process grid for SuperLU_DIST solver.
     901              :   bool superlu_3d = false;
     902              : 
     903              :   // Option to use vector or scalar Pi-space corrections for the AMS preconditioner.
     904              :   bool ams_vector_interp = false;
     905              : 
     906              :   // Option to tell the AMS solver that the operator is singular, like for magnetostatic
     907              :   // problems.
     908              :   int ams_singular_op = -1;
     909              : 
     910              :   // Option to use aggressive coarsening for Hypre AMG solves (with BoomerAMG or AMS).
     911              :   // Typically use this when the operator is positive definite.
     912              :   int amg_agg_coarsen = -1;
     913              : 
     914              :   // Relative tolerance for solving linear systems in divergence-free projector.
     915              :   double divfree_tol = 1.0e-12;
     916              : 
     917              :   // Maximum number of iterations for solving linear systems in divergence-free projector.
     918              :   int divfree_max_it = 1000;
     919              : 
     920              :   // Relative tolerance for solving linear systems in the error estimator.
     921              :   double estimator_tol = 1.0e-6;
     922              : 
     923              :   // Maximum number of iterations for solving linear systems in the error estimator.
     924              :   int estimator_max_it = 10000;
     925              : 
     926              :   // Use geometric multigrid + AMG for error estimator linear solver preconditioner (instead
     927              :   // of just Jacobi).
     928              :   bool estimator_mg = false;
     929              : 
     930              :   // Enable different variants of Gram-Schmidt orthogonalization for GMRES/FGMRES iterative
     931              :   // solvers and SLEPc eigenvalue solver.
     932              :   Orthogonalization gs_orthog = Orthogonalization::MGS;
     933              : 
     934              :   void SetUp(json &solver);
     935              : };
     936              : 
     937            0 : struct SolverData
     938              : {
     939              : public:
     940              :   // Approximation order.
     941              :   int order = 1;
     942              : 
     943              :   // Order above which to use partial assembly instead of full assembly.
     944              :   int pa_order_threshold = 1;
     945              : 
     946              :   // Include the order of det(J) in the order of accuracy for quadrature rule selection.
     947              :   bool q_order_jac = false;
     948              : 
     949              :   // Additional quadrature order of accuracy (in addition to 2p or 2p + order(|J|)) for
     950              :   // quadrature rule selection.
     951              :   int q_order_extra = 0;
     952              : 
     953              :   // Device used to configure MFEM.
     954              :   Device device = Device::CPU;
     955              : 
     956              :   // Backend for libCEED (https://libceed.org/en/latest/gettingstarted/#backends).
     957              :   std::string ceed_backend = "";
     958              : 
     959              :   // Solver objects.
     960              :   DrivenSolverData driven = {};
     961              :   EigenSolverData eigenmode = {};
     962              :   ElectrostaticSolverData electrostatic = {};
     963              :   MagnetostaticSolverData magnetostatic = {};
     964              :   TransientSolverData transient = {};
     965              :   LinearSolverData linear = {};
     966              : 
     967              :   void SetUp(json &config);
     968              : };
     969              : 
     970              : // Calculate the number of steps from [start, end) in increments of delta. Will only include
     971              : // end if it is a multiple of delta beyond start.
     972              : int GetNumSteps(double start, double end, double delta);
     973              : 
     974              : }  // namespace palace::config
     975              : 
     976              : #endif  // PALACE_UTILS_CONFIG_FILE_HPP
        

Generated by: LCOV version 2.0-1