pub struct TransientAnalysis<const NDIM: usize = PLANAR_NDIM, const NDOF: usize = NDF, NId = NodeId, E = Element>where
NId: Key,
E: ElementOps<NDIM, NDOF, NId>,{ /* private fields */ }Expand description
Time-history (transient) analysis via Newmark-beta integration — a
distinct type from Analysis, not a third Integrator/Algorithm
variant squeezed into it: static analysis is about a scalar load factor
and (optionally) Newton-iterating displacement at a fixed time, dynamic
analysis is about propagating a very different state (displacement,
velocity, acceleration) forward through actual time. Trying to unify
them into one Analysis/AnalysisBuilder would blur two genuinely
different physical processes for no real benefit — same reasoning as
modal_analysis being a free function rather than an Analysis mode.
Fixed at the “average acceleration” Newmark parameters
(beta = 1/4, gamma = 1/2) — unconditionally stable, the standard
default (matches OpenSees’ own Newmark integrator default). Exact for
genuinely linear elastic response (Truss/
ZeroLength/ElasticBeamColumn with linear materials) since the
tangent stiffness formed once per step doesn’t change with displacement
— one linear solve per step, no Newton iteration, mirroring Algorithm:: Linear’s same caveat for the static case. A Newton-iterated corrector
(needed once nonlinear materials are driven dynamically) is a natural
extension, not built until something needs it.
Generic over the same kinematic profile as Domain/Analysis (see
Domain’s doc comment) — Newmark stepping, the initial-acceleration
solve, and ground-motion excitation only ever touch domain through its
generic free-DOF interface (mass diagonal, gather/scatter, tangent
assembly, direction_incidence), never anything DOF-count-specific, so
one implementation covers both Domain/Domain3. Defaults to the
planar profile, so bare TransientAnalysis keeps working unchanged;
TransientAnalysis3 (spatial) is a type alias below. A spatial
GroundMotion::direction of 0..3 selects ux/uy/uz, unchanged
from planar beyond the extra valid index.
Implementations§
Source§impl<const NDIM: usize, const NDOF: usize, NId, E> TransientAnalysis<NDIM, NDOF, NId, E>
impl<const NDIM: usize, const NDOF: usize, NId, E> TransientAnalysis<NDIM, NDOF, NId, E>
Sourcepub fn new(
domain: Domain<NDIM, NDOF, NId, E>,
damping: RayleighDamping,
dt: f64,
) -> Result<Self, AnalysisError>
pub fn new( domain: Domain<NDIM, NDOF, NId, E>, damping: RayleighDamping, dt: f64, ) -> Result<Self, AnalysisError>
Builds a transient analysis from a domain whose nodes may already
carry initial conditions (Node::with_initial_displacement/
with_initial_velocity). Computes the one thing Newmark needs that
isn’t a direct initial condition: a consistent initial acceleration
from equilibrium at t=0, M*a0 = F0 - K*u0 - C*v0 - M*ι*ag(0) (the
last term only present once with_ground_motion adds one — see
recompute_initial_acceleration). M is diagonal, so this is a
single elementwise division, no solve needed.
Sourcepub fn with_algorithm(self, algorithm: Algorithm, test: ConvergenceTest) -> Self
pub fn with_algorithm(self, algorithm: Algorithm, test: ConvergenceTest) -> Self
Opts into a real Newton corrector (docs/algorithms.md §6.1)
instead of the default Algorithm::Linear (today’s original
behavior: one effective-system solve per step, no iteration, exact
only for linear-material response). Mirrors with_ground_motion’s
consuming-builder style; unlike it, doesn’t need to re-derive
anything (the initial acceleration doesn’t depend on algorithm).
Sourcepub fn with_ground_motion(self, motion: GroundMotion) -> Self
pub fn with_ground_motion(self, motion: GroundMotion) -> Self
Adds a GroundMotion and re-derives the initial acceleration to
include its contribution at t=0 (usually zero — accelerograms
conventionally start at ag(0) = 0 — but not assumed). Must be
called before any step(); re-scatters/re-commits the domain’s
state exactly as new did, so it’s equivalent to having passed this
motion to new directly.
pub fn domain(&self) -> &Domain<NDIM, NDOF, NId, E>
Sourcepub fn reaction(&self, node: NId, dof: usize) -> f64
pub fn reaction(&self, node: NId, dof: usize) -> f64
Support reaction including the uniform-excitation inertial load at that restrained DOF. Like OpenSees’ plain reaction recorder, excludes damping and relative inertial forces (use relative acceleration separately).
Sourcepub fn into_domain(self) -> Domain<NDIM, NDOF, NId, E>
pub fn into_domain(self) -> Domain<NDIM, NDOF, NId, E>
Ends this (dynamic) phase and hands back the Domain — symmetric
with Analysis::into_domain, so a dynamic phase can itself be
followed by another phase (static or dynamic).
pub fn time(&self) -> f64
Sourcepub fn step(&mut self) -> Result<TransientStepResult, AnalysisError>
pub fn step(&mut self) -> Result<TransientStepResult, AnalysisError>
Advance one Newmark step of size dt. External load each step is
Domain::assemble_reference_load(time) (every LoadPattern’s
current/frozen contribution — see its doc comment) plus each active
GroundMotion’s effective inertial force at time (ground_force).
On failure, the domain and time/step_count are restored to their
state before this call — same reasoning as Analysis::step.
Auto Trait Implementations§
impl<const NDIM: usize = PLANAR_NDIM, const NDOF: usize = NDF, NId = NodeId, E = Element> !Freeze for TransientAnalysis<NDIM, NDOF, NId, E>
impl<const NDIM: usize, const NDOF: usize, NId, E> RefUnwindSafe for TransientAnalysis<NDIM, NDOF, NId, E>where
NId: RefUnwindSafe,
E: RefUnwindSafe,
<E as ElementOps<NDIM, NDOF, NId>>::Id: RefUnwindSafe,
<E as ElementOps<NDIM, NDOF, NId>>::Load: RefUnwindSafe,
impl<const NDIM: usize, const NDOF: usize, NId, E> Send for TransientAnalysis<NDIM, NDOF, NId, E>where
NId: Send,
E: Send,
<E as ElementOps<NDIM, NDOF, NId>>::Id: Send,
<E as ElementOps<NDIM, NDOF, NId>>::Load: Send,
impl<const NDIM: usize, const NDOF: usize, NId, E> Sync for TransientAnalysis<NDIM, NDOF, NId, E>where
NId: Sync,
E: Sync,
<E as ElementOps<NDIM, NDOF, NId>>::Id: Sync,
<E as ElementOps<NDIM, NDOF, NId>>::Load: Sync,
impl<const NDIM: usize, const NDOF: usize, NId, E> Unpin for TransientAnalysis<NDIM, NDOF, NId, E>where
NId: Unpin,
E: Unpin,
<E as ElementOps<NDIM, NDOF, NId>>::Id: Unpin,
<E as ElementOps<NDIM, NDOF, NId>>::Load: Unpin,
impl<const NDIM: usize, const NDOF: usize, NId, E> UnsafeUnpin for TransientAnalysis<NDIM, NDOF, NId, E>
impl<const NDIM: usize, const NDOF: usize, NId, E> UnwindSafe for TransientAnalysis<NDIM, NDOF, NId, E>where
NId: UnwindSafe,
E: UnwindSafe,
<E as ElementOps<NDIM, NDOF, NId>>::Id: UnwindSafe,
<E as ElementOps<NDIM, NDOF, NId>>::Load: UnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<T, U> Imply<T> for U
§impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
§fn to_subset(&self) -> Option<SS>
fn to_subset(&self) -> Option<SS>
self from the equivalent element of its
superset. Read more§fn is_in_subset(&self) -> bool
fn is_in_subset(&self) -> bool
self is actually part of its subset T (and can be converted to it).§fn to_subset_unchecked(&self) -> SS
fn to_subset_unchecked(&self) -> SS
self.to_subset but without any property checks. Always succeeds.§fn from_subset(element: &SS) -> SP
fn from_subset(element: &SS) -> SP
self to the equivalent element of its superset.