dragonfly_sim.core.meshwarping
Attributes
Classes
IDW mesh deformation via the |
Module Contents
- class dragonfly_sim.core.meshwarping.IDWarp_jax(mesh_obj, wall_meshtag_val: int = 2, anchor_meshtag_vals=(3, 4), extrusion_width: float = None, LdefFact: float = 1.0, err_tol: float = 1e-06, **idwarp_kwargs)
Bases:
csdl_alpha.CustomExplicitOperationIDW mesh deformation via the
idwarp-jaxpackage’s kd-tree warper.Maps the replicated
(M_global, dim)wall-node motions (evaluate(bdry_motions, cp_motion_inputs), usuallyshape_parameterization.WallFFD.wall_displacement) to rank-local volume node motions, in geometry-node order. Because the map is closed form rather than a PDE solve, this is aCustomExplicitOperation– CSDL callscomputeandcompute_jacvec_product.Everything that is a property of the mesh rather than of the warp lives on the
Mesh(mesh_manager): the wall and anchor node sets and their global numbering (Mesh.boundary_node_set), the tagged facets and their orientation, applying/resetting node motions, mesh quality, and the output files. The wall numbering here is the mesh’s wall node set’s.The warp itself is
idwarp_jax.build_volume_pts_func, a kd-tree IDWarp that batches its forward and reverse passes internally, so its memory stays bounded without any chunking here.err_tolis its pruning tolerance, relative to the IDW denominator;err_tol=0disables pruning and gives the exact dense IDW sum. This class only turns the mesh’s wall and anchor node sets into the package’s surface and moves arrays between CSDL and it.- Parameters:
- mesh_objmesh_manager.Mesh, with its boundary facets
tagged. Its
output_suffix(Mesh.configure_output) names this class’s memory logs.- wall_meshtag_valtag of the moving (design) surface.
- anchor_meshtag_valstags of the boundaries held at zero displacement.
Pass
()to disable anchoring – but read the note above first.- extrusion_width2D only; width of the extruded boundary ribbon.
None derives it from the smallest boundary edge. See
_resolve_extrusion_widthfor why the default is what it is – the choice trades IDW distance fidelity against the conditioning of Newell’s method, and neither limit is safe.- LdefFactIDWarp’s dimensionless deformation length:
Ldef = LdefFact * Ldef0, withLdef0the largest distance from the wall nodes’ centroid to a wall node. The package takesLdef0over every prescribed node, anchors included – the farfield radius – so the factor is rescaled before it is passed on.- err_tolkd-tree pruning tolerance, see above. Measured against
err_tol=0on the 2D NACA0012 mesh: 1e-6 gives 1.2e-3 relative motion error at half the cost; 1e-10 prunes almost nothing (cost of the exact sum). On the 3D wing mesh 1e-6 keeps ~25% of the dense interactions, with a ~47 GiB host route cache summed over all ranks.- **idwarp_kwargsforwarded to
build_volume_pts_func, over these defaults:
normal_eps = warp_eps = 1e-30. The package defaults (1e-6) are dimensional:normal_epsis added to |2A|^2 of every face, which is ~1e-14 for a 2D ribbon quad and ~1e-10 for a small 3D wall face, andwarp_epsfloors every IDW distance at 1e-3. Either would wreck the warp.symmetry_tolerance: 0 in 2D, where no ribbon node may be pinned to y = 0; 1e-6 in 3D, the tolerance the model tags symmetry facets with.target_batch_interactions = 1_000_000(package: 6e6). Each rank holds one batch of volume-point x source interactions in flight, and the reverse pass’s working arrays scale with it: on the 3D wing mesh at err_tol=1e-6 they add ~0.9 GiB/rank at 1e6 vs ~2.4 GiB/rank at 6e6, with identical results and no measurable slowdown.progress = print_timings = False; this class reports its own timings.
Everything else (
zeroCornerRotations,cornerAngle,useRotations,rotation_eps,bucket_size,route_cache, …) is the package’s default.
- _assemble_motions(wall_motions, interior_3d)
(N_local, dim) mesh-node motions in geometry-node order.
Owned wall nodes take their rows of the replicated wall array, interior nodes the warp output; anchor nodes stay zero.
- _assert_planar(motion_3d)
In 2D the out-of-plane (y) motion must vanish identically.
It does so exactly, per surface node: both nodal normals are in-plane, so the rotation is about y, so the y component of M (x_v - Xs0_i) + Xs_i - x_v is (+-w/2) + (-+w/2) = 0. A nonzero value here means the ribbon construction is wrong, not that a tolerance is tight.
- _build_global_surface_topology()
Assemble the replicated prescribed surface as the package’s mesh dict.
self._mesh_dictholdspoints(the surface rows,self._Xs0) andfaces(every face with type 1, so wall and anchor faces are all prescribed). Every rank ends up with byte-identical arrays, because every rank has to evaluate the IDW sum against the whole surface.
- _build_warper()
Build this rank’s idwarp_jax warper over its own interior nodes.
The volume points are the interior nodes only: wall motions are prescribed and anchors are held at zero, so neither needs warping. A rank that owns no interior node gets one dummy point, because the package cannot preprocess an empty volume.
- _check_surface_topology(n_flipped)
Fail loudly if the ranks assembled different surfaces.
Identical on every rank, byte for byte: otherwise ranks evaluate different surfaces and the gradients they reduce are incoherent. A content hash rather than a sum, so a permutation cannot slip through.
- _expand(wall_vals)
(M_global, dim) wall values -> (n_surface_rows, 3), in every layer.
The anchor rows stay zero.
- _fold(rows)
Adjoint of
_expand: (n_surface_rows, 3) -> (M_global, dim).The layers are summed because the forward writes the same wall motion into every layer. The anchor rows are dropped: they are sensitivities with respect to a constant.
- _log_memory(note)
- _project(wall_vals)
Zero the y component of wall nodes on the symmetry plane.
Takes and returns a full (M_global, dim) array. The package pins those nodes to y = 0 before warping, so this is the wall motion the warp actually assumed. A diagonal projection, hence its own adjoint. Identity in 2D, where no node is pinned.
- _resolve_extrusion_width(node_coords, local_faces)
Pick the 2D ribbon width: a fraction of the shortest boundary edge.
Two effects pull in opposite directions, and the factor below is where they balance.
Smaller w is better for the IDW geometry: w enters the distance as sqrt(d_xy^2 + w^2/4), so a width comparable to the near-wall spacing would blunt exactly the weight concentration that makes the warp follow the surface. At w = 0.1 * h_min the nearest volume node sees its distance inflated by 0.125%, which is nothing.
Larger w is better for conditioning. Newell’s method in idwarp_jax’s normal.py sums cross products of absolute coordinates, whose magnitudes are set by the farfield, and those terms have to cancel down to twice the face area – which for a ribbon quad is only edge_length * w. The relative error in the resulting normal therefore goes as 1/w. Measured on the 2D mesh, as the error in reproducing a rigid surface translation:
w = 1e-5 -> 6.5e-08 w = 1e-2 -> 6.7e-11 w = 1e-4 -> 6.7e-09 w = 1e-1 -> 6.7e-12 w = 1e-3 -> 6.7e-10 w = 1e+0 -> 6.6e-13
0.1 * h_min puts that error around 1e-9 for an O(1) displacement, four orders below the smallest cell, at a distance distortion of 0.1%. (3D is unaffected: real surface faces have areas many orders larger than an extruded ribbon’s, so nothing cancels catastrophically.)
The minimum is taken over every prescribed boundary edge, so in practice it is set by the wall, where the edges are finest.
- compute(input_vals, output_vals)
Forward warp. No collectives: every rank already has the whole surface.
- compute_jacvec_product(input_vals, output_vals, d_inputs, d_outputs, mode)
Matrix-free VJP. Only reverse mode is supported.
Each rank seeds only the rows it owns – its own wall nodes for the identity block, its own interior nodes for the IDW block – so the per-rank gradients are disjoint contributions to one (M_global, dim) array and summing them is exact.
- evaluate(bdry_motions: csdl_alpha.Variable, cp_motion_inputs: csdl_alpha.Variable)
Register the operation.
cp_motion_inputscarries no derivative – it is declared only to keep every rank’s reverse chain attached to the design variables, including ranks that own no wall nodes.
- LdefFact
- M_global
- N_local
- _cols = [0, 2]
- _extrusion_width_arg = None
- _idwarp_kwargs
- _interior_local_idx
- _n_interior
- _n_surface_nodes
- anchor_meshtag_vals = (3, 4)
- anchors
- dimensions
- err_tol
- mesh
- ordered_callbacks = True
- wall
- wall_meshtag_val = 2
- dragonfly_sim.core.meshwarping._NO_PITCH