#self #element #finite #solve #define #systems #norm

finiteelement

A library to define and solve finite element systems

2 unstable releases

0.3.0 Aug 29, 2019
0.1.0 Jul 15, 2019

#11 in #norm

MIT/Apache

210KB
4.5K SLoC

This module defines the trait FiniteElement, and provides methods to solve finite element systems.

Example

use finiteelement::*;
//Define a struct that implements the FiniteElement trait


#[derive(Clone)]
pub struct Spring {
   pub a: usize,
   pub b: usize,
   pub l: f64,
   pub k: f64,
}

impl FiniteElement<f64> for Spring {
   fn forces(&self, positions: &[Point<f64>], forces: &mut [f64]) {
       // add to both a and b the force resulting from this spring.
       let ab = positions[self.b].clone() - positions[self.a].clone();
       let norm = ab.norm();
       forces[3 * self.a] += self.k * (norm - self.l) * ab.x / norm;
       forces[3 * self.a + 1] += self.k * (norm - self.l) * ab.y / norm;
       forces[3 * self.a + 2] += self.k * (norm - self.l) * ab.z / norm;
       forces[3 * self.b] -= self.k * (norm - self.l) * ab.x / norm;
       forces[3 * self.b + 1] -= self.k * (norm - self.l) * ab.y / norm;
       forces[3 * self.b + 2] -= self.k * (norm - self.l) * ab.z / norm;
   }

   fn jacobian(&self, positions: &[Point<f64>], jacobian: &mut Sparse<f64>) {
       // add to both a and b the force resulting from this self.
       let ab = positions[self.b].clone() - positions[self.a].clone();
       let norm = ab.norm();
       let norm3 = norm * norm * norm;
       for u in 0..3 {
           for v in 0..3 {
               let j = if u == v {
                   self.k * (1. - self.l / norm + self.l * ab[u] * ab[u] / norm3)
               } else {
                   self.k * self.l * ab[u] * ab[v] / norm3
               };
               // Change in the force on B when moving B.
               jacobian[3 * self.b + u][3 * self.b + v] -= j;
               // Change in the force on A when moving B.
               jacobian[3 * self.a + u][3 * self.b + v] += j;
               // Change in the force on B when moving A.
               jacobian[3 * self.b + u][3 * self.a + v] += j;
               // Change in the force on A when moving A.
               jacobian[3 * self.a + u][3 * self.a + v] -= j;
           }
       }
   }
}

let elts = [
   Spring {
       a: 0,
       b: 1,
       l: 1.,
       k: 1.,
   },
   Spring {
       a: 1,
       b: 2,
       l: 2.,
       k: 0.5,
   },
   Spring {
       a: 0,
       b: 2,
       l: 3.,
       k: 5.
   },
];
let system = (0..elts.len()).map(|i| {Box::new(elts[i].clone()) as Box<dyn FiniteElement<f64>>}).collect::<Vec<_>>();
let mut positions = vec![
 Point { x: 0., y: 0., z: 0. },
 Point {x : 1., y: 0., z: 0.},
 Point{x: 0., y: 1., z: 1.}];

let mut ws = FesWorkspace::new(positions.len());
let epsilon_stop = 1e-4;
let gradient_switch = 1e-3;
let mut solved = false;
for i in (0..20) {
  solved = fes_one_step(&system, &mut positions, epsilon_stop, gradient_switch, &mut ws);
  if solved {
     break;
  }
}
assert!(solved);

Use of the macro provided by finiteelement_macro

To use one of the macro provided by finiteelement_marco, call it without parameter at the begining or your code. The piece of code surrounded by //======== in the example above can be replaced by a call to finiteelement_macros::auto_impl_spring!{}

 use finiteelement::*;
 use std::borrow::Borrow;
auto_impl_spring!{}
pub fn main() {
 let elts = [
     Spring {
         a: 0,
         b: 1,
         l: 1.,
         k: 1.,
     },
     Spring {
         a: 1,
         b: 2,
         l: 2.,
         k: 0.5,
     },
     Spring {
         a: 0,
         b: 2,
         l: 3.,
         k: 5.
     },
 ];
 let system = (0..elts.len()).map(|i| {Box::new(elts[i].clone()) as Box<dyn FiniteElement<f64>>}).collect::<Vec<_>>();
 let mut positions = vec![
   Point { x: 0., y: 0., z: 0. },
   Point {x : 1., y: 0., z: 0.},
   Point{x: 0., y: 1., z: 1.}];

 let mut ws = FesWorkspace::new(positions.len());
 let epsilon_stop = 1e-4;
 let gradient_switch = 1e-3;
 let mut solved = false;
 for i in (0..20) {
    solved = fes_one_step(&system, &mut positions, epsilon_stop, gradient_switch, &mut ws);
    if solved {
       break;
    }
 }
assert!(solved);
}

Dependencies

~1.5–2.5MB
~49K SLoC