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
|