Source code for structdyn.sdf.sdf

import numpy as np
from structdyn.utils.material_models import LinearElastic
from structdyn.ground_motions import GroundMotion
from structdyn.sdf.sdf_helpers.visualization import SDFVisualizer


[docs] class SDF: """Single Degree of Freedom (SDF) System for Structural Dynamics""" def __init__(self, m, k, ji=0, fd=None): """ Initializes an SDF system. Parameters ---------- m : float Mass of the system in kilograms (kg). k : float Stiffness of the system in Newtons per meter (N/m). ji : float, optional Damping ratio (dimensionless), by default 0. Must be between 0 and 1. fd : MaterialModel class, optional Force-deformation model, by default "LinearElastic". """ self.m = m # mass self.k = k # stiffness self.ji = ji # damping ratio if not (0 <= ji < 1): raise ValueError("Damping ratio must be between 0 and 1") self.w_n = np.sqrt(self.k / self.m) # natural frequency self.w_d = self.w_n * np.sqrt(1 - self.ji**2) # damped natural frequency self.t_n = 2 * np.pi / self.w_n # natural time period self.c = 2 * self.m * self.w_n * self.ji # damping constant if fd is None or fd == "linear": self.fd = "linear" else: self.fd = fd self._plot = None # Placeholder for the visualizer, will be set when accessed
[docs] def find_response(self, time, load, method="newmark_beta", **kwargs): """ Computes the dynamic response of the SDF system. Solves the equation of motion: m u'' + c u' + f_s(u) = p(t). Parameters ---------- time : array-like Array of time points. load : array-like Array of generalized force values at each time point. method : str, optional Numerical method for solving the equation of motion, by default "newmark_beta". Available methods: 'newmark_beta', 'central_difference', 'interpolation'. **kwargs : dict, optional Additional parameters for the numerical solver. Returns ------- pandas.DataFrame A DataFrame containing the time history of the system's response (e.g., displacement, velocity, acceleration). """ time = np.asarray(time) dt = time[1] - time[0] if not np.allclose(np.diff(time), dt): raise ValueError("Time vector must be uniformly spaced") solver_class = self._get_solver_class(method) solver = solver_class(self, dt=dt, **kwargs) return solver.compute_solution(time, load)
[docs] def find_response_ground_motion(self, gm, method="newmark_beta", **kwargs): """ Computes the response of the SDF system to ground motion. Solves the equation of motion for a base-excited system subjected to ground motion. Parameters ---------- gm : GroundMotion A GroundMotion object representing the ground motion record. method : str, optional Numerical method to use, by default "newmark_beta". **kwargs : dict, optional Additional parameters for the numerical solver. Returns ------- pandas.DataFrame A DataFrame containing the time history of the system's response. """ if not isinstance(gm, GroundMotion): raise TypeError("gm must be a GroundMotion object") time = gm.time load = -self.m * gm.acc_g * 9.81 return self.find_response(time, load, method=method, **kwargs)
def _get_solver_class(self, method): if method == "newmark_beta": from structdyn.sdf.numerical_methods.newmark_beta import NewmarkBeta return NewmarkBeta if method == "central_difference": from structdyn.sdf.numerical_methods.central_difference import ( CentralDifference, ) return CentralDifference if method == "interpolation": from structdyn.sdf.numerical_methods.interpolation import Interpolation return Interpolation raise ValueError( f"Invalid method '{method}'. " "Choose 'newmark_beta', 'central_difference', or 'interpolation'." ) @property def plot(self): """ Provides access to visualization methods for the SDF system. Returns ------- SDFVisualizer An instance of the SDFVisualizer class, which can be used to generate plots and animations of the system. """ if self._plot is None: self._plot = SDFVisualizer(self) return self._plot