# 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 let n0 = Node::new( [0.0, 1.0].into(), Constraint::Pin, ); // Note that From<[f64; N]> is implemented for Vector 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::::new(nodes); ``` ## Creating Elements Create elements according to the following pattern. ``` truss.add(n0, n1); ``` This function has two arguments. - `n0: usize`. The index in `nodes` of the first node to which this element connects. - `n1: usize`. The index in `nodes` of the second node to which this element connects. Note that the area and material of this element will be passed at evaluation time. This allows improved run-time on specific optimization problems. Call `Truss::add` for every element in your truss. This function returns `Option`. 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 ``` let (forces, displacements) = truss.solve(areas, materials).unwrap(); ``` This function has two arguments. - `areas: [f64; K]`. The areas of each element in the truss. - `materials: [Material; K]`. The materials of each element in the truss. ## Determining Member Forces ``` let force: Option = truss.internal_force(areas, materials, k); ``` This function has three arguments. - `areas: [f64; K]`. The areas of each element in the truss. - `materials: [Material; K]`. The materials of each element in the truss. - `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> = truss.displacement(areas, materials, n); ``` This function has three arguments. - `areas: [f64; K]`. The areas of each element in the truss. - `materials: [Material; K]`. The materials of each element in the truss. - `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 = truss.compliance(areas, materials); ``` This function has two arguments. - `areas: [f64; K]`. The areas of each element in the truss. - `materials: [Material; K]`. The materials of each element in the truss. 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. ## Determining Truss Volume ``` let volume: f64 = truss.volume(areas); ``` This function has one argument. - `areas: [f64; K]`. The areas of each element in the truss. ## Determining Truss Fabrication Complexity ``` let complexity: f64 = truss.volume(areas, maxarea, beta); ``` This function has three arguments. - `areas: [f64; K]`. The areas of each element in the truss. - `maxarea: f64`. An area standardization term of each element. This should be close to the maximum allowable area. - `beta: f64`. A term to adjust the regularized Heaviside distribution.