Source code for buffalo_panel.formulations.lumped_vortex
"""Public lumped-vortex formulation entry points."""
from __future__ import annotations
from dataclasses import dataclass
import numpy as np
from buffalo_panel.assembly import Freestream2D
from buffalo_panel.assembly.internal.system import build_lumped_vortex_system
from buffalo_panel.basis.descriptors import LINE_POINT
from buffalo_panel.families.dof_maps import PerElementDofMap
from buffalo_panel.families.element_family import ElementFamily
from buffalo_panel.geometry.line2d import ThinBodyLineGeometry2D
from buffalo_panel.geometry.supports import LINE_2D
from buffalo_panel.kernels.registry import KernelRegistry
from buffalo_panel.post import BodyReference2D, PanelSolution2D
from buffalo_panel.post.internal.lumped_vortex import (
recover_lumped_vortex_solution,
)
from buffalo_panel.prescribed.internal.point_element_particle_2d import (
PointElementParticle2D,
)
from buffalo_panel.singularities.descriptors import VORTEX
from buffalo_panel.solvers.dense import solve_dense
from buffalo_panel.type_aliases import FloatArray
[docs]
@dataclass(slots=True)
class LumpedVortexFormulation:
"""Solve a thin-body lumped-vortex formulation."""
geometry: ThinBodyLineGeometry2D
"""Thin-body geometry used in the lumped-vortex solver."""
registry: KernelRegistry
"""Registry of computational kernels to use in the solver."""
backend: str = "python"
"""Specific computational kernel backend to use."""
body_reference: BodyReference2D | None = None
"""Reference quantities for integrated coefficient recovery."""
[docs]
def build_body_vortex_family(self) -> ElementFamily:
"""
Build the point-vortex family for the body panels.
Returns
-------
ElementFamily
Body point-vortex assembly for this formulation.
"""
n_body_panels = self.geometry.n_body_panels
body_vortex_indices = np.arange(n_body_panels, dtype=np.int32)
return ElementFamily(
name="body_vortices",
support=LINE_2D,
singularity=VORTEX,
basis=LINE_POINT,
n_elements=n_body_panels,
panel_indices=self.geometry.body_panel_indices,
dof_map=PerElementDofMap(global_indices=body_vortex_indices),
metadata={"role": "body", "lumped": True},
)
[docs]
def solve(
self,
freestream: Freestream2D,
point_particles: tuple[PointElementParticle2D, ...] = (),
) -> tuple[FloatArray, PanelSolution2D]:
"""
Assemble, solve, and recover surface results for one freestream.
Parameters
----------
freestream : Freestream2D
Freestream conditions for this solution.
point_particles : tuple[PointElementParticle2D, ...], optional
Prescribed point particles whose induced fields contribute known
forcing to the body boundary condition and to recovered flow
fields.
Returns
-------
FloatArray
Raw solution from the system of equations.
PanelSolution2D
Processed results information from solution.
"""
vortex_family = self.build_body_vortex_family()
matrix, rhs = build_lumped_vortex_system(
vortex_family,
self.geometry,
freestream,
self.registry,
self.backend,
point_particles,
)
x = solve_dense(matrix, rhs)
results = recover_lumped_vortex_solution(
x,
(vortex_family,),
self.geometry,
freestream,
self.registry,
self.backend,
self.body_reference,
point_particles,
)
return x, results