dragonfly_sim.utils.solver_utils ================================ .. py:module:: dragonfly_sim.utils.solver_utils Attributes ---------- .. autoapisummary:: dragonfly_sim.utils.solver_utils.MIN_POSITIVITY_THETA dragonfly_sim.utils.solver_utils.POSITIVITY_FLOOR dragonfly_sim.utils.solver_utils._KSP_NORM_TYPE_NAMES dragonfly_sim.utils.solver_utils._KSP_REASON_NAMES Functions --------- .. autoapisummary:: dragonfly_sim.utils.solver_utils._enum_name_map dragonfly_sim.utils.solver_utils.compute_positivity_preserving_theta dragonfly_sim.utils.solver_utils.ksp_converged_reason_name dragonfly_sim.utils.solver_utils.ksp_norm_type_name dragonfly_sim.utils.solver_utils.ksp_pc_side_name dragonfly_sim.utils.solver_utils.locate_positivity_limiting_nodes Module Contents --------------- .. py:function:: _enum_name_map(enum_cls) Reverse map {code: name} for a petsc4py enum-like class. petsc4py exposes most codes under several aliases -- PC.Side has both "L" and "LEFT" for 0, KSP.ConvergedReason both "DIVERGED_PC_FAILED" and "DIVERGED_PCSETUP_FAILED" for -11 -- so the map has to choose. Longest name first, ties broken alphabetically: longest picks the descriptive alias over the terse one (which is the whole point of printing a name instead of the integer), and the tie-break makes the result identical on every run rather than dependent on `dir()` ordering. .. !! processed by numpydoc !! .. py:function:: compute_positivity_preserving_theta(comm, x_arr, dx_arr, gamma=1.4, initial_theta=1.0, min_theta=None, block_size=4) Computes the maximum theta <= initial_theta such that x_new = x_arr - theta * dx_arr has positive mass density and positive pressure everywhere. Returns the step length only. To find out WHICH nodes bounded it -- the question a collapsed theta raises -- pass twice the returned value to locate_positivity_limiting_nodes. .. !! processed by numpydoc !! .. py:function:: ksp_converged_reason_name(reason) Human-readable name for a PETSc KSP convergence reason code. Worth printing next to the iteration count because the count alone cannot distinguish the two failures that call for opposite responses: DIVERGED_MAX_IT means a hard but well-posed operator that simply exhausted its Krylov budget (tune the solver), while DIVERGED_BREAKDOWN or DIVERGED_PCSETUP_FAILED means the Arnoldi process or the preconditioner itself failed (the operator or the coarse space is broken). Both show up as "ran to max_it" in a log that reports only iterations. Unknown codes come back as "REASON()" rather than raising -- this is a diagnostic and must never be the thing that breaks a solve. .. !! processed by numpydoc !! .. py:function:: ksp_norm_type_name(norm_type) Human-readable name for a PETSc KSP norm type. This is what says whether a reported residual norm is the true ||b - Ax|| or the preconditioned one, which decides whether a norm LARGER than ||b|| is impossible (UNPRECONDITIONED, as fgmres defaults to) or unremarkable (PRECONDITIONED, as gmres defaults to). Without it the number cannot be read at all. .. !! processed by numpydoc !! .. py:function:: ksp_pc_side_name(pc_side) Human-readable name for a PETSc preconditioner side (LEFT/RIGHT/SYMMETRIC). .. !! processed by numpydoc !! .. py:function:: locate_positivity_limiting_nodes(x_arr, dx_arr, theta_probe, gamma=1.4, block_size=4, floor=POSITIVITY_FLOOR) Find which local nodes make x_arr - theta_probe*dx_arr unphysical. Diagnostic companion to compute_positivity_preserving_theta, which returns the surviving step length and says nothing about what bounded it. Pass theta_probe = twice the accepted theta -- the smallest step that bisection actually rejected -- and the nodes reported here are exactly the ones that forced the final halving. Rank-local and pure numpy: the caller owns the MPI reduction and the dof-coordinate lookup. `block` is an index into the BLOCKS of x_arr, which for a blocked function space is also a row index into that space's local dof coordinates. Returns a dict: n_density, n_pressure, n_nonfinite local counts of nodes violating each way, for the caller to sum across ranks. One violating node out of millions and a whole region going unphysical at once are different problems, and the count is what tells them apart. block block index of this rank's WORST violator, or None if this rank has none -- in which case the keys below are absent. severity trial value over current value at that node, so that a density and a pressure violation are comparable and one argmin ranks the whole set; more negative is a worse overshoot, -inf for a non-finite trial state. constraint "density", "pressure" or "non-finite". rho, p, rho_trial, p_trial, d_rho, d_rhou_norm, d_rhoE the state, the trial state and the update at that node. .. !! processed by numpydoc !! .. py:data:: MIN_POSITIVITY_THETA :value: 1e-06 .. py:data:: POSITIVITY_FLOOR :value: 0.0001 .. py:data:: _KSP_NORM_TYPE_NAMES :value: None .. py:data:: _KSP_REASON_NAMES :value: None