dragonfly_sim.core.pod ====================== .. py:module:: dragonfly_sim.core.pod .. autoapi-nested-parse:: Proper orthogonal decomposition (POD) of solution snapshots, distributed over MPI with PETSc. SnapshotMatrix keeps the snapshot matrix S = [x_1, ..., x_n] only as its incrementally updated, optionally truncated SVD, in a weighted inner product (x, y)_W = x^T W y. PODBasis turns that SVD into a reduced basis for the current design point:: global the leading rb_size left-singular vectors of S; local_weighted the leading left-singular vectors of S diag(w), with partition-of-unity weights w that decay with the distance between each snapshot's parameter vector and the current one (compact-support cubic by default). Both bases are W-orthonormal (V^T W V = I). core/reduced_order_model.py builds W and drives the reduced solves. .. !! processed by numpydoc !! Classes ------- .. autoapisummary:: dragonfly_sim.core.pod.PODBasis dragonfly_sim.core.pod.SnapshotMatrix Module Contents --------------- .. py:class:: PODBasis(comm, n_dofs, basis_mode='global', subtract_mean=False, mean_weighting='snapshot_weights', IP_matrix=None, max_rank=None, qr_rank_tol=1e-10) A reduced basis from the snapshots in a SnapshotMatrix (see the module docstring for the basis modes). `basis` is the current basis, a distributed MATDENSE in the state layout, rebuilt (destroyed and reallocated) by every construct_basis call. .. !! processed by numpydoc !! .. py:method:: _local_weighted_snapshot_weights(local_parametervector, weightfunction, parameter_weights, n_nonzero_weights, rb_size, cubic_cutoff=None) Partition-of-unity weights over the accepted snapshots (one per column of VT), from the distances between their parameter vectors and `local_parametervector`. Duplicate-parameter (rejected) snapshots take part in the distance weighting like accepted ones, and their weight is then redistributed onto the accepted snapshots that reconstruct them. Returns (weights, distances of the accepted snapshots). .. !! processed by numpydoc !! .. py:method:: _set_basis_from_local_block(basis_local_block) Rebuild self.basis from this rank's row block. (MatCreateSubMatrix is not used to slice columns of U: for MATDENSE it fails on a width change, and under MPI returns replicated columns or corrupts the heap, depending on how the column IS is split.) .. !! processed by numpydoc !! .. py:method:: construct_basis(rb_size=10, local_parametervector=None, parameter_weights=None, weightfunction='Cubic', n_nonzero_weights=None, cubic_cutoff=None, return_distance_norms=False, layout_vec=None) (Re)build self.basis from the current snapshot SVD; with no snapshots self.basis becomes None. local_weighted only:: local_parametervector the current design point parameter_weights per-parameter factors on the distance (None: 1) weightfunction 'Cubic' (compact support), 'Linear', 'Quadratic' or 'InverseDistance' n_nonzero_weights Cubic: number of nearest snapshots with a nonzero weight (default rb_size) cubic_cutoff Cubic: instead of n_nonzero_weights, a c in [0, 1) with support radius max(c min_dist + (1 - c) max_dist, r_rb), r_rb the smallest radius that leaves the rb_size nearest accepted snapshots a nonzero weight (utils/pod_utils.basis_size_floor) `layout_vec` (the state vector) guards the one invariant the reduced solve depends on: the basis rows are distributed exactly like it. Returns the accepted snapshots' distances with return_distance_norms (local_weighted), else None. .. !! processed by numpydoc !! .. py:method:: destroy() .. py:attribute:: IP_matrix :value: None .. py:attribute:: SUPPORTED_BASIS_MODES :value: ('global', 'local_weighted') .. py:attribute:: WEIGHT_FUNCTIONS :value: ('Cubic', 'Linear', 'Quadratic', 'InverseDistance') .. py:attribute:: basis :value: None .. py:attribute:: basis_mode :value: 'global' .. py:attribute:: comm .. py:attribute:: mean :value: None .. py:attribute:: mean_weighting :value: 'snapshot_weights' .. py:attribute:: n_dofs .. py:attribute:: snapshot_matrix .. py:attribute:: subtract_mean :value: False .. py:class:: SnapshotMatrix(comm, n_dofs=None, W=None, qr_rank_tol=1e-10, reorthogonalize=True, max_rank=None) Incremental weighted QR and SVD of the snapshot matrix. Each snapshot x_k (a PETSc Vec in the state layout) updates a weighted QR decomposition S = Q R with Q^T W Q = I, then the SVD of the small R; Q is rotated into R's left-singular basis every update (Q <- Q U_R), so Q IS the SVD's U and only one dense n_dofs x rank matrix is stored. The rotation is also what makes truncation to max_rank the standard truncated incremental SVD. Storage: Q distributed (MATDENSE, rows in the state layout); R, Sigma, VT small and replicated on PETSc.COMM_SELF. W is any object with W.mult(x, y) (a PETSc Mat or utils/pod_utils.DiagonalWeight), or None for the Euclidean inner product. A snapshot is rejected (no new column) when its parameter vector duplicates an earlier one; its location and the weights reconstructing it from the existing snapshots are kept, and the local_weighted basis redistributes its weight onto those. A rank-deficient snapshot -- one in the span of Q up to a weighted residual ||x - Q Q^T W x||_W below qr_rank_tol ||x||_W, a test independent of the snapshot's scale -- adds a column to R/VT but not to Q, so row i of the parameter array matches column i of R/VT, never of Q. .. !! processed by numpydoc !! .. py:method:: _apply_W(x) (W x, owned): W x as a fresh Vec, or x itself when unweighted -- `owned` says whether the caller must destroy it. .. !! processed by numpydoc !! .. py:method:: _is_duplicate_parameter(par_vec) .. py:method:: _project_onto_Q(x_k, Wx) W-orthogonal projection of x_k onto Q: (r, e_local, rho) with r = Q^T W x_k (replicated), e_local this rank's slice of x_k - Q r, and rho = sqrt(e^T W e). `Wx` is W x_k (or x_k when unweighted). With reorthogonalize, a second projection pass (CGS2) removes the round-off a single pass leaves when x_k is nearly in span(Q), as snapshots from nearby design points are; without it orthogonality degrades catastrophically over many updates. .. !! processed by numpydoc !! .. py:method:: _update_weighted_QR_and_SVD(x_k) .. py:method:: _weighted_norm(x, Wx) ||x||_W = sqrt(x^T W x), given W x. Collective. .. !! processed by numpydoc !! .. py:method:: construct_snapshot_parameter_array() .. py:method:: destroy() .. py:method:: gather_dense_to_rank0_numpy(mat, root=0) A distributed dense Mat as one numpy array on `root` (diagnostics). .. !! processed by numpydoc !! .. py:method:: print_info() .. py:method:: process_and_append_to_snapshot_lists(x_k, par_vec) Incorporate snapshot `x_k` (not modified) with parameter vector `par_vec`. Returns True if it added a new basis direction, False if it was a duplicate parameter or rank-deficient within qr_rank_tol. .. !! processed by numpydoc !! .. py:attribute:: Q :value: None .. py:attribute:: R :value: None .. py:attribute:: Sigma :value: None .. py:property:: U The left-singular vectors: the same object as self.Q. .. !! processed by numpydoc !! .. py:attribute:: VT :value: None .. py:attribute:: W :value: None .. py:attribute:: comm .. py:property:: full_SVD_triplet .. py:attribute:: max_rank :value: None .. py:attribute:: n_dofs :value: None .. py:attribute:: n_snapshots :value: 0 .. py:attribute:: qr_rank_tol :value: 1e-10 .. py:attribute:: rank :value: 0 .. py:attribute:: rejected_snapshot_parameters :value: [] .. py:attribute:: rejected_snapshot_reconstruction_weights :value: [] .. py:attribute:: reorthogonalize :value: True .. py:attribute:: snapshot_list_parameters :value: [] .. py:attribute:: snapshot_parameter_array