use super::functions::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CouplingMethod {
Direct,
BridgingDomain,
Arlequin,
}
#[derive(Debug, Clone)]
pub struct RkpmShape {
pub psi: Vec<f64>,
pub dpsi_dx: Vec<f64>,
pub dpsi_dy: Vec<f64>,
pub neighbours: Vec<usize>,
}
#[derive(Debug, Clone)]
pub struct ConvergenceRate {
pub l2_rate: f64,
pub linf_rate: f64,
pub h1_rate: f64,
pub energy_rate: f64,
}
#[derive(Debug, Clone, Copy, Default)]
pub struct StressState {
pub sigma_xx: f64,
pub sigma_yy: f64,
pub tau_xy: f64,
}
impl StressState {
pub fn von_mises(&self) -> f64 {
(self.sigma_xx * self.sigma_xx + self.sigma_yy * self.sigma_yy
- self.sigma_xx * self.sigma_yy
+ 3.0 * self.tau_xy * self.tau_xy)
.sqrt()
}
pub fn principal(&self) -> (f64, f64) {
let avg = (self.sigma_xx + self.sigma_yy) / 2.0;
let diff = (self.sigma_xx - self.sigma_yy) / 2.0;
let r = (diff * diff + self.tau_xy * self.tau_xy).sqrt();
(avg + r, avg - r)
}
}
#[derive(Debug, Clone)]
pub struct RbfInterpolant {
pub centres: Vec<Point2>,
pub coeffs: Vec<f64>,
pub c: f64,
pub rtype: RbfType,
}
impl RbfInterpolant {
pub fn eval(&self, pt: Point2) -> f64 {
let mut val = 0.0;
for (i, centre) in self.centres.iter().enumerate() {
let r = dist2(pt, *centre);
val += self.coeffs[i] * rbf_eval(r, self.c, self.rtype);
}
val
}
}
#[derive(Debug, Clone)]
pub struct ConvergenceStudySummary {
pub points: Vec<ConvergencePoint>,
pub rates: Vec<ConvergenceRate>,
pub avg_l2_rate: f64,
pub avg_h1_rate: f64,
}
#[derive(Debug, Clone)]
pub struct CouplingInterface {
pub nodes: Vec<CouplingNode>,
pub method: CouplingMethod,
pub penalty: f64,
}
impl CouplingInterface {
pub fn new(method: CouplingMethod, penalty: f64) -> Self {
Self {
nodes: Vec::new(),
method,
penalty,
}
}
pub fn add_node(&mut self, node: CouplingNode) {
self.nodes.push(node);
}
pub fn compute_penalty_coupling(&self, ndof_meshfree: usize, ndof_fem: usize) -> Vec<f64> {
let ndof_total = ndof_meshfree + ndof_fem;
let mut coupling_k = vec![0.0; ndof_total * ndof_total];
for cn in &self.nodes {
if let (Some(mi), Some(fi)) = (cn.meshfree_idx, cn.fem_idx) {
for dof in 0..2 {
let im = mi * 2 + dof;
let jf = ndof_meshfree + fi * 2 + dof;
if im < ndof_meshfree && jf < ndof_total {
coupling_k[im * ndof_total + im] += self.penalty;
coupling_k[jf * ndof_total + jf] += self.penalty;
coupling_k[im * ndof_total + jf] -= self.penalty;
coupling_k[jf * ndof_total + im] -= self.penalty;
}
}
}
}
coupling_k
}
pub fn compute_bridging_weights(&mut self, overlap_width: f64) {
for cn in &mut self.nodes {
cn.blend_weight = cn.blend_weight.clamp(0.0, 1.0);
let _ = overlap_width;
}
}
pub fn num_coupling_nodes(&self) -> usize {
self.nodes.len()
}
}
#[derive(Debug, Clone)]
pub struct SupportDomain {
pub nodes: Vec<MeshfreeNode>,
pub dilation: f64,
}
impl SupportDomain {
pub fn new(nodes: Vec<MeshfreeNode>, dilation: f64) -> Self {
Self { nodes, dilation }
}
pub fn neighbours(&self, pt: Point2) -> Vec<usize> {
self.nodes
.iter()
.enumerate()
.filter_map(|(i, n)| {
let d = dist2(pt, n.pos);
if d < n.support_radius * self.dilation {
Some(i)
} else {
None
}
})
.collect()
}
pub fn neighbours_sorted(&self, pt: Point2) -> Vec<(usize, f64)> {
let mut pairs: Vec<(usize, f64)> = self
.nodes
.iter()
.enumerate()
.filter_map(|(i, n)| {
let d = dist2(pt, n.pos);
if d < n.support_radius * self.dilation {
Some((i, d))
} else {
None
}
})
.collect();
pairs.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap_or(std::cmp::Ordering::Equal));
pairs
}
pub fn node_count(&self) -> usize {
self.nodes.len()
}
}
#[derive(Debug, Clone)]
pub struct EfgResult {
pub displacements: Vec<f64>,
pub num_nodes: usize,
}
#[derive(Debug, Clone)]
pub struct MeshfreeNode {
pub pos: Point2,
pub support_radius: f64,
pub value: f64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum KernelType {
CubicSpline,
QuarticSpline,
Gaussian,
WendlandC2,
WendlandC4,
}
#[derive(Debug, Clone)]
pub struct EssentialBc {
pub node: usize,
pub dof: usize,
pub value: f64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BcEnforcementMethod {
Penalty,
LagrangeMultiplier,
Nitsche,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RbfType {
Multiquadric,
InverseMultiquadric,
Gaussian,
ThinPlateSpline,
Polyharmonic3,
}
#[derive(Debug, Clone)]
pub struct FemElement {
pub nodes: Vec<Point2>,
pub connectivity: Vec<usize>,
pub stiffness: Vec<f64>,
}
#[derive(Debug, Clone, Copy)]
pub struct ErrorIndicator {
pub node: usize,
pub error: f64,
}
#[derive(Debug, Clone)]
pub struct CouplingNode {
pub pos: Point2,
pub meshfree_idx: Option<usize>,
pub fem_idx: Option<usize>,
pub blend_weight: f64,
}
#[derive(Debug, Clone, Copy)]
pub struct TriCell {
pub vertices: [Point2; 3],
}
impl TriCell {
pub fn area(&self) -> f64 {
let v = self.vertices;
0.5 * ((v[1][0] - v[0][0]) * (v[2][1] - v[0][1])
- (v[2][0] - v[0][0]) * (v[1][1] - v[0][1]))
.abs()
}
pub fn centroid(&self) -> Point2 {
let v = self.vertices;
[
(v[0][0] + v[1][0] + v[2][0]) / 3.0,
(v[0][1] + v[1][1] + v[2][1]) / 3.0,
]
}
}
#[derive(Debug, Clone, Copy)]
pub struct EfgMaterial {
pub young: f64,
pub poisson: f64,
pub thickness: f64,
}
#[derive(Debug, Clone)]
pub struct ConvergencePoint {
pub h: f64,
pub num_nodes: usize,
pub l2_error: f64,
pub linf_error: f64,
pub h1_error: f64,
pub energy_error: f64,
}
#[derive(Debug, Clone)]
pub struct MlsShape {
pub phi: Vec<f64>,
pub dphi_dx: Vec<f64>,
pub dphi_dy: Vec<f64>,
pub neighbours: Vec<usize>,
}