dragonfly_sim.utils.gradient_condensation ========================================= .. py:module:: dragonfly_sim.utils.gradient_condensation .. autoapi-nested-parse:: Newton problems whose residual reads a gradient field that is eliminated from the unknowns. At p = 0 the RANS model reconstructs a DG0 gradient G of the state by Green-Gauss (core/reconstruction.py), M_G G = b(U), b(U; tau) = sum over facets of int u_f (x) n : tau ds, with M_G the diagonal (cell-volume) DG0 mass matrix. G is linear in the facet states, so it is eliminated exactly instead of being carried as an unknown: R(U) = R_U(U, G(U)), dR/dU = A_UU + A_UG M_G^-1 B_GU, with A_UU = dR_U/dU at fixed G, A_UG = dR_U/dG and B_GU = db/dU. The product widens the Jacobian's stencil to the neighbours' neighbours, which is the stencil of the reconstructed scheme. Everything downstream (SNES, the positivity limiter, the time integrator) still sees a single-field problem in U. jacobian_mode selects what Newton's linear solve uses (configure_snes wires it into an existing SNES): exact operator = preconditioning matrix = A_UU + A_UG M^-1 B_GU compact_pc operator exact, preconditioning matrix A_UU: the compact, nearest-neighbour part (gradients frozen), as finite-volume codes precondition with their first-order Jacobian. The default: on the coarse SA NACA0012 C-grid it takes the same PTC path as MUMPS, 5x faster, and scales to the 181k-cell STW wing where every exact factorization runs out of memory. compact operator = preconditioning matrix = A_UU: approximate Newton (defect correction); converges linearly .. !! processed by numpydoc !! Classes ------- .. autoapisummary:: dragonfly_sim.utils.gradient_condensation.CondensedGradientProblem dragonfly_sim.utils.gradient_condensation.CondensedJacobian dragonfly_sim.utils.gradient_condensation.TransposedCondensedOperator Module Contents --------------- .. py:class:: CondensedGradientProblem(F, J, u, G, b_G, update_G, inv_mass, jit_options={}) Bases: :py:obj:`dragonfly_sim.utils.Nonlinear_utils.NonlinearProblem_mod` NonlinearProblem_mod for R_U(U, G(U)). `G` is the gradient Function the residual reads, `b_G` the UFL form of the Green-Gauss right-hand side, `update_G()` recomputes G from the current u in place and `inv_mass` is M_G^-1 as a Vec in G's layout. .. !! processed by numpydoc !! .. py:method:: F(x, b) Assemble the residual F into the vector b. Args: x: The vector containing the latest solution b: Vector to assemble the residual into .. !! processed by numpydoc !! .. py:method:: J(x, A) Assemble the Jacobian matrix. Args: x: The vector containing the latest solution A: The matrix that will hold the Jacobian matrix .. !! processed by numpydoc !! .. py:method:: configure_snes(snes, mode) Re-wire `snes`'s Jacobian for jacobian_mode `mode` (see the module docstring). Call after the solver is built. .. !! processed by numpydoc !! .. py:attribute:: G .. py:attribute:: MODES :value: ('exact', 'compact_pc', 'compact') .. py:attribute:: _A .. py:attribute:: _A_UU .. py:attribute:: _condensed .. py:attribute:: jacobian_mode :value: 'exact' .. py:attribute:: update_G .. py:class:: CondensedJacobian(F, u, G, b_G, inv_mass, jit_options={}, A_UU=None, a_UU=None) A = A_UU + A_UG M^-1 B_GU for a residual form F(U, G), with `b_G` the UFL Green-Gauss right-hand side (test function on G's space) and `inv_mass` M_G^-1 as a Vec in G's layout. The matrices are plain aij: MatMatMult does not take baij here. The product's sparsity is fixed by the operands', so one symbolic product sizes A for good. .. !! processed by numpydoc !! .. py:method:: _assemble_blocks() .. py:method:: assemble() Assemble A_UU, A_UG, M^-1 B_GU and A at the current state; G must be up to date. .. !! processed by numpydoc !! .. py:attribute:: A .. py:attribute:: A_UG .. py:attribute:: A_UU .. py:attribute:: B_GU .. py:attribute:: _C .. py:attribute:: _a .. py:attribute:: _a_GU .. py:attribute:: _a_UG .. py:attribute:: _inv_mass .. py:class:: TransposedCondensedOperator(P, A_UG, B, release_B) Python-Mat context of the transposed condensed Jacobian without forming it: A^T x = (A_UU + A_UG B)^T x = P x + B^T (A_UG^T x), P = A_UU^T with B = M_G^-1 dG/dU (any Mat with mult / multTranspose, e.g. the structured GreenGaussStateOperator). Neither A nor the product A_UG B is ever assembled. It owns P (also the preconditioning matrix), A_UG and B (released through `release_B`, a callable) and frees them in destroy(). .. !! processed by numpydoc !! .. py:method:: create_mat(comm) .. py:method:: destroy(mat=None) .. py:method:: mult(mat, x, y) .. py:attribute:: _w