use rlx_ir::{DType, Graph, NodeId, Shape};
use crate::equilibrium::EquilibriumModel;
use crate::network::Network;
use crate::structure::Structure;
#[derive(Clone, Debug)]
pub struct FdmDenseGraph {
pub k: NodeId,
pub p: NodeId,
pub xyz_free: NodeId,
}
pub fn fdm_dense_graph(g: &mut Graph, network: &Network) -> Result<FdmDenseGraph, String> {
network.validate()?;
let structure = Structure::from_network(network);
let nf = structure.num_free();
if nf == 0 {
return Err("no free nodes".into());
}
let k_mat = EquilibriumModel::stiffness_matrix(&network.q, &structure);
let na = structure.num_fixed();
let mut xyz_fixed = vec![0.0_f32; na * 3];
for (j, &node) in structure.indices_fixed.iter().enumerate() {
for c in 0..3 {
xyz_fixed[j * 3 + c] = network.xyz[node * 3 + c] as f32;
}
}
let p_mat = EquilibriumModel::load_matrix(
&network.q,
&xyz_fixed.iter().map(|&x| x as f64).collect::<Vec<_>>(),
&network.loads,
&structure,
);
let k_shape = Shape::new(&[nf, nf], DType::F64);
let p_shape = Shape::new(&[nf, 3], DType::F64);
let out_shape = Shape::new(&[nf, 3], DType::F64);
let k = g.param("fdm_K", k_shape);
let p = g.param("fdm_P", p_shape);
let xyz_free = g.dense_solve(k, p, out_shape);
let _ = (k_mat, p_mat);
Ok(FdmDenseGraph { k, p, xyz_free })
}
pub fn xyz_free_shape(network: &Network) -> Result<Shape, String> {
network.validate()?;
let s = Structure::from_network(network);
Ok(Shape::new(&[s.num_free(), 3], DType::F64))
}
pub fn pack_stiffness(network: &Network) -> Result<Vec<f64>, String> {
network.validate()?;
let s = Structure::from_network(network);
Ok(EquilibriumModel::stiffness_matrix(&network.q, &s))
}
pub fn pack_load_rhs(network: &Network) -> Result<Vec<f64>, String> {
network.validate()?;
let s = Structure::from_network(network);
let na = s.num_fixed();
let mut xyz_fixed = vec![0.0; na * 3];
for (j, &node) in s.indices_fixed.iter().enumerate() {
for c in 0..3 {
xyz_fixed[j * 3 + c] = network.xyz[node * 3 + c];
}
}
Ok(EquilibriumModel::load_matrix(
&network.q,
&xyz_fixed,
&network.loads,
&s,
))
}