qtruss 0.3.0

A simple finite-element solver for trusses.
Documentation
# QTruss

A simple finite-element solver for 2D trusses.

# Getting Started

## Importing `maria-linalg`

You must import the latest version of the Rust crate [`maria-linalg`](https://crates.io/crates/maria-linalg) in order to use this package. 

## Creating a List of Nodes

First, you must construct a list of nodes.  Each node must have a location and a constraint type.  There are four types of constraints.

- `Constraint::Pin`.  0 degrees of freedom.  An immobile pin joint.
- `Constraint::Free (force)`.  2 degrees of freedom.  A free joint with an applied `force` of type `maria_linalg::Vector<2>`.  Note that this applied force may be zero.
- `Constraint::HorizontalSlide (force)`.  1 degree of freedom.  A horizontal slider joint with an applied `force` of type `maria_linalg::Vector<2>`.  Note that this applied force may be zero.  This joint is free to move in the X direction but cannot move in the Y direction.
- `Constraint::VerticalSlide (force)`.  1 degree of freedom.  A vertical slider joint with an applied `force` of type `maria_linalg::Vector<2>`.  Note that this applied force may be zero.  This joint is free to move in the X direction but cannot move in the Y direction.

Construct nodes according to the following method.

```
use maria_linalg::Vector;
use qtruss::{Constraint, Node};

// Note that From<[f64; N]> is implemented for Vector<N>
let n0 = Node::new(
    [0.0, 1.0].into(),
    Constraint::Pin,
);

// Note that From<[f64; N]> is implemented for Vector<N>
let n1 = Node::new(
    [0.0, 1.0].into(),
    Constraint::HorizontalSlide ([-1.0, 0.0].into()),
);
```

## Constructing a Truss

Once nodes are constructed, place these in an array like so.

```
let nodes = [
    n0,
    n1,
    // All the nodes
];
```

You are now ready to construct your truss.  Note that the truss should be `mut`able, as you will add elements later.  Additionally, the `Truss::solve` function stores its results inside of the `Truss` structure.

Note that there are *three generic constants* that must be defined.
- `N: usize`.  The number of nodes in this truss.
- `K: usize`.  The number of elements in this truss.
- `F: usize`.  The number of *degrees of freedom* in this truss.  As of the latest version of `qopt`, you must compute this manually.  Compute this by summing the number of degrees of freedom for each node (see above about `enum Constraint`).

```
let mut truss = Truss::<N, K, F>::new(nodes);
```

## Creating Elements

Create elements according to the following pattern.

```
truss.add(n0, n1, e, a);
```

This function has four arguments.
- `n0: usize`.  The index of the first node in `nodes` this element connects to.
- `n1: usize`.  The index of the first node in `nodes` this element connects to.
- `e: f64`.  The elasticity modulus of this element.
- `a: f64`.  The cross-sectional area of this element.

Call `Truss::add` for every element in your truss.

This function returns `Option<usize>`.  If the provided node numbers are valid, it returns variant `Some` with the index of this element.  The first call to `Truss::add` will have index `0`, the second call index `1`, and so on.  If the provided node numbers are invalid (beyond the range of `nodes`), this function returns variant `None`.

## Solving the Truss

```
truss.solve();
```

## Determining Member Forces

```
let force: Option<f64> = truss.internal_force(k);
```

This function has one argument.
- `k: usize`.  The index of the desired element.  This is determined by the number of calls to `Truss::add`.  The first call corresponds to `k = 0`, the second call `k = 1`, and so on.

This function is positive when the element is in tension and negative when the element is in compression.

If `force` is of variant `None`, there is something preventing `qtruss` from solving your truss.  Check your `N`, `K`, and `F` values, and ensure that your truss is fully constrained.

## Determining Node Displacements

```
let displacement: Option<f64> = truss.displacement(n);
```

This function has one argument.
- `n: usize`.  The index of the desired node in `nodes`.

If `displacement` is of variant `None`, there is something preventing `qtruss` from solving your truss.  Check your `N`, `K`, and `F` values, and ensure that your truss is fully constrained.

## Determining Total Truss Compliance

```
let compliance: Option<f64> = truss.compliance();
```

If `compliance` is of variant `None`, there is something preventing `qtruss` from solving your truss.  Check your `N`, `K`, and `F` values, and ensure that your truss is fully constrained.