Source code for buffalo_panel.views.internal.line_family_2d

"""Generic diagnostic view for solved line-element families."""

from __future__ import annotations

from dataclasses import dataclass
from typing import Protocol

import numpy as np
from buffalo_core import as_float_array

from buffalo_panel.families.element_family import ElementFamily
from buffalo_panel.geometry.line2d import LineKernelGeometry2D
from buffalo_panel.kernels.interfaces import (
    ElementKernel,
    KernelEvaluationOptions,
)
from buffalo_panel.post import FieldPoints2D
from buffalo_panel.type_aliases import FloatArray, FloatInput


[docs] class LineFieldView2D[GeometryT_co: LineKernelGeometry2D](Protocol): """Read-only protocol for objects that evaluate one line-family field.""" @property def geometry(self) -> GeometryT_co: """Return the geometry used to evaluate the field.""" ...
[docs] def velocity_at( self, x: FloatInput, y: FloatInput, ) -> tuple[FloatArray, FloatArray]: """Evaluate induced velocity at field points.""" ...
[docs] def potential_at(self, x: FloatInput, y: FloatInput) -> FloatArray: """Evaluate induced potential at field points.""" ...
[docs] def stream_function_at( self, x: FloatInput, y: FloatInput, ) -> FloatArray: """Evaluate induced stream function at field points.""" ...
[docs] @dataclass(frozen=True, slots=True) class LineFamily2DView[GeometryT: LineKernelGeometry2D]: """ Diagnostic field view for one line-element family. The view evaluates velocity, potential, and stream-function contributions by combining family-local unit-influence blocks with an explicit vector of family-local coefficients. This makes the view layer compatible with constant, shared, and future higher-order families without assuming one scalar strength per panel. """ geometry: GeometryT """Geometry containing the family source panels.""" family: ElementFamily """Element family defining panel ownership and local coefficient layout.""" local_coefficients: FloatInput """Solved or user-specified family-local coefficients.""" kernel: ElementKernel[GeometryT] """Kernel used to evaluate family-local unit influence blocks.""" top: bool = True """Branch-side convention for points on panel cuts.""" def __post_init__(self) -> None: """Normalize and validate stored family-local coefficients.""" coefficients = as_float_array(self.local_coefficients).reshape(-1) if coefficients.size != self.family.n_local_dofs: raise ValueError( "local_coefficients size must match family.n_local_dofs." ) object.__setattr__(self, "local_coefficients", coefficients)
[docs] def velocity_at( self, x: FloatInput, y: FloatInput, ) -> tuple[FloatArray, FloatArray]: """ Evaluate induced velocity at field points. Parameters ---------- x : FloatInput Field-point x-coordinates. y : FloatInput Field-point y-coordinates. Returns ------- FloatArray Global x-velocity contribution with the broadcast input shape. FloatArray Global y-velocity contribution with the broadcast input shape. """ points = FieldPoints2D.from_inputs(x, y) options = KernelEvaluationOptions(top=self.top) u_block, v_block = self.kernel.build_field_velocity_blocks( self.family, self.geometry, points.x_flat, points.y_flat, options, ) coefficients = np.asarray(self.local_coefficients, dtype=np.float64) return ( points.reshape_values(u_block @ coefficients), points.reshape_values(v_block @ coefficients), )
[docs] def potential_at(self, x: FloatInput, y: FloatInput) -> FloatArray: """ Evaluate induced velocity potential at field points. Parameters ---------- x : FloatInput Field-point x-coordinates. y : FloatInput Field-point y-coordinates. Returns ------- FloatArray Velocity potential contribution with the broadcast input shape. """ points = FieldPoints2D.from_inputs(x, y) options = KernelEvaluationOptions(top=self.top) block = self.kernel.build_field_potential_block( self.family, self.geometry, points.x_flat, points.y_flat, options, ) coefficients = np.asarray(self.local_coefficients, dtype=np.float64) return points.reshape_values(block @ coefficients)
[docs] def stream_function_at(self, x: FloatInput, y: FloatInput) -> FloatArray: """ Evaluate induced stream function at field points. Parameters ---------- x : FloatInput Field-point x-coordinates. y : FloatInput Field-point y-coordinates. Returns ------- FloatArray Stream-function contribution with the broadcast input shape. """ points = FieldPoints2D.from_inputs(x, y) options = KernelEvaluationOptions(top=self.top) block = self.kernel.build_field_stream_function_block( self.family, self.geometry, points.x_flat, points.y_flat, options, ) coefficients = np.asarray(self.local_coefficients, dtype=np.float64) return points.reshape_values(block @ coefficients)
[docs] def field_at( self, x: FloatInput, y: FloatInput, ) -> tuple[FloatArray, FloatArray, FloatArray, FloatArray]: """ Evaluate velocity, potential, and stream function together. Parameters ---------- x : FloatInput Field-point x-coordinates. y : FloatInput Field-point y-coordinates. Returns ------- FloatArray Global x-velocity contribution. FloatArray Global y-velocity contribution. FloatArray Velocity potential contribution. FloatArray Stream-function contribution. """ u, v = self.velocity_at(x, y) potential = self.potential_at(x, y) stream_function = self.stream_function_at(x, y) return u, v, potential, stream_function