@@ -340,17 +340,14 @@ RomOperator::RomOperator(const IoData &iodata, SpaceOperator &space_op,
340340 ksp = std::make_unique<ComplexKspSolver>(iodata, space_op.GetNDSpaces (),
341341 &space_op.GetH1Spaces ());
342342
343- auto excitation_helper = space_op. GetPortExcitations ( );
343+ MFEM_VERIFY (max_size_per_excitation > 0 , " Reduced order basis must have > 0 size! " );
344344
345- // The initial PROM basis is empty. The provided maximum dimension is the number of sample
346- // points (2 basis vectors per point). Basis orthogonalization method is configured using
347- // GMRES/FGMRES settings.
348- MFEM_VERIFY (max_size_per_excitation * excitation_helper.Size () > 0 ,
349- " Reduced order basis storage must have > 0 columns!" );
350- V.resize (2 * max_size_per_excitation * excitation_helper.Size (), Vector ());
345+ // Reserve empty vectors but don't pre-allocate actual memory size due to overhead.
346+ V.reserve (max_prom_size);
347+ v_node_label.reserve (max_prom_size);
351348
352- // Set up MRI .
353- for (const auto &[excitation_idx, data] : excitation_helper )
349+ // Set up MinimalRationalInterpolation .
350+ for (const auto &[excitation_idx, data] : space_op. GetPortExcitations () )
354351 {
355352 mri.emplace (excitation_idx, MinimalRationalInterpolation (max_size_per_excitation));
356353 }
@@ -376,6 +373,7 @@ void RomOperator::SetExcitationIndex(int excitation_idx)
376373 else
377374 {
378375 // Project RHS1 to RHS1r with current PROM.
376+ auto dim_V = V.size ();
379377 if (dim_V > 0 )
380378 {
381379 MPI_Comm comm = space_op.GetComm ();
@@ -421,63 +419,58 @@ void RomOperator::SolveHDM(int excitation_idx, double omega, ComplexVector &u)
421419
422420void RomOperator::UpdatePROM (const ComplexVector &u, std::string_view node_label)
423421{
424-
425- // Update V. The basis is always real (each complex solution adds two basis vectors if it
426- // has a nonzero real and imaginary parts).
422+ // Update PROM basis V. The basis is always real (each complex solution adds two basis
423+ // vectors, if it has a nonzero real and imaginary parts).
427424 BlockTimer bt (Timer::CONSTRUCT_PROM);
428425 MPI_Comm comm = space_op.GetComm ();
429426
430- const double normr = linalg::Norml2 (comm, u.Real ());
431- const double normi = linalg::Norml2 (comm, u.Imag ());
432- const bool has_real = (normr > ORTHOG_TOL * std::sqrt (normr * normr + normi * normi));
433- const bool has_imag = (normi > ORTHOG_TOL * std::sqrt (normr * normr + normi * normi));
427+ const auto norm_re = linalg::Norml2 (comm, u.Real ());
428+ const auto norm_im = linalg::Norml2 (comm, u.Imag ());
429+ const auto norm_tol = ORTHOG_TOL * std::sqrt (norm_re * norm_re + norm_im * norm_im);
430+ const bool has_real = (norm_re > norm_tol);
431+ const bool has_imag = (norm_im > norm_tol);
432+
433+ const std::size_t dim_V_old = V.size ();
434+ const std::size_t dim_V_new =
435+ V.size () + static_cast <std::size_t >(has_real) + static_cast <std::size_t >(has_imag);
434436
435- const std::size_t dim_V_new = dim_V + std::size_t (has_real) + std::size_t (has_imag);
436- MFEM_VERIFY (dim_V_new <= V.size (),
437- " Unable to increase basis storage size, increase maximum number of vectors!" );
438- const std::size_t dim_V_old = dim_V;
439- v_node_label.reserve (dim_V_new);
440437 orth_R.conservativeResizeLike (Eigen::MatrixXd::Zero (dim_V_new, dim_V_new));
441438
439+ auto add_real_vector_to_basis = [this ](const Vector &vector, std::string_view full_label)
440+ {
441+ auto dim_V = V.size ();
442+ V.push_back (vector);
443+ OrthogonalizeColumn (orthog_type, space_op.GetComm (), V, V.back (),
444+ orth_R.col (dim_V).data (), dim_V);
445+ orth_R (dim_V, dim_V) = linalg::Norml2 (space_op.GetComm (), V.back ());
446+ V.back () *= 1.0 / orth_R (dim_V, dim_V);
447+ v_node_label.emplace_back (full_label);
448+ };
449+
442450 if (has_real)
443451 {
444- V[dim_V] = u.Real ();
445- OrthogonalizeColumn (orthog_type, comm, V, V[dim_V], orth_R.col (dim_V).data (), dim_V);
446- orth_R (dim_V, dim_V) = linalg::Norml2 (comm, V[dim_V]);
447- V[dim_V] *= 1.0 / orth_R (dim_V, dim_V);
448- v_node_label.emplace_back (fmt::format (" {}_re" , node_label));
449- dim_V++;
452+ add_real_vector_to_basis (u.Real (), fmt::format (" {}_re" , node_label));
450453 }
451454 if (has_imag)
452455 {
453- V[dim_V] = u.Imag ();
454- OrthogonalizeColumn (orthog_type, comm, V, V[dim_V], orth_R.col (dim_V).data (), dim_V);
455- orth_R (dim_V, dim_V) = linalg::Norml2 (comm, V[dim_V]);
456- V[dim_V] *= 1.0 / orth_R (dim_V, dim_V);
457- v_node_label.emplace_back (fmt::format (" {}_im" , node_label));
458- dim_V++;
456+ add_real_vector_to_basis (u.Imag (), fmt::format (" {}_im" , node_label));
459457 }
460458
461- // Update reduced-order operators. Resize preserves the upper dim0 x dim0 block of each
462- // matrix and first dim0 entries of each vector and the projection uses the values
463- // computed for the unchanged basis vectors.
464- Kr.conservativeResize (dim_V, dim_V);
459+ // Update reduced-order operators.
460+ Kr.conservativeResize (dim_V_new, dim_V_new);
465461 ProjectMatInternal (comm, V, *K, Kr, r, dim_V_old);
466462 if (C)
467463 {
468- Cr.conservativeResize (dim_V, dim_V );
464+ Cr.conservativeResize (dim_V_new, dim_V_new );
469465 ProjectMatInternal (comm, V, *C, Cr, r, dim_V_old);
470466 }
471- Mr.conservativeResize (dim_V, dim_V );
467+ Mr.conservativeResize (dim_V_new, dim_V_new );
472468 ProjectMatInternal (comm, V, *M, Mr, r, dim_V_old);
473469 if (RHS1.Size ())
474470 {
475- RHS1r.conservativeResize (dim_V );
471+ RHS1r.conservativeResize (dim_V_new );
476472 ProjectVecInternal (comm, V, RHS1, RHS1r, dim_V_old);
477473 }
478- // Placeholder matrices.
479- Ar.resize (dim_V, dim_V);
480- RHSr.resize (dim_V);
481474}
482475
483476void RomOperator::UpdateMRI (int excitation_idx, double omega, const ComplexVector &u)
@@ -494,7 +487,18 @@ void RomOperator::SolvePROM(int excitation_idx, double omega, ComplexVector &u)
494487 // the matrix Aᵣ(ω) = Kᵣ + iω Cᵣ - ω² Mᵣ + Vᴴ A2 V(ω) and source vector RHSᵣ(ω) =
495488 // iω RHS1ᵣ + Vᴴ RHS2(ω). A2(ω) and RHS2(ω) are constructed only if required and are
496489 // only nonzero on boundaries, will be empty if not needed.
497- if (has_A2 && Ar.rows () > 0 )
490+
491+ // No basis states ill-defined: return zero vector to match current behaviour.
492+ if (V.size () == 0 )
493+ {
494+ u = 0.0 ;
495+ return ;
496+ }
497+
498+ Ar.resize (V.size (), V.size ());
499+ RHSr.resize (V.size ());
500+
501+ if (has_A2)
498502 {
499503 A2 = space_op.GetExtraSystemMatrix <ComplexOperator>(omega, Operator::DIAG_ZERO);
500504 ProjectMatInternal (space_op.GetComm (), V, *A2, Ar, r, 0 );
@@ -510,7 +514,7 @@ void RomOperator::SolvePROM(int excitation_idx, double omega, ComplexVector &u)
510514 }
511515 Ar += (-omega * omega) * Mr;
512516
513- if (has_RHS2 && RHSr. size () > 0 )
517+ if (has_RHS2)
514518 {
515519 space_op.GetExcitationVector2 (excitation_idx, omega, RHS2);
516520 ProjectVecInternal (space_op.GetComm (), V, RHS2, RHSr, 0 );
@@ -587,7 +591,7 @@ void RomOperator::PrintPROMMatrices(const Units &units, const fs::path &post_dir
587591 auto unit_farad = units.GetScaleFactor <Units::ValueType::CAPACITANCE>();
588592 auto m_C = (unit_farad * v_d) * Mr * v_d;
589593 print_table (m_C.real (), " rom-C-re.csv" );
590- if (C ->Imag ())
594+ if (M ->Imag ())
591595 {
592596 print_table (m_C.imag (), " rom-C-im.csv" );
593597 }
@@ -599,7 +603,7 @@ void RomOperator::PrintPROMMatrices(const Units &units, const fs::path &post_dir
599603 auto unit_ohm = units.GetScaleFactor <Units::ValueType::IMPEDANCE>();
600604 auto m_Rinv = ((1.0 / unit_ohm) * v_d) * Cr * v_d;
601605 print_table (m_Rinv.real (), " rom-Rinv-re.csv" );
602- if (M ->Imag ())
606+ if (C ->Imag ())
603607 {
604608 print_table (m_Rinv.imag (), " rom-Rinv-im.csv" );
605609 }
0 commit comments