def solve_modes(system, formulation, no_of_modes=10, x0=None, dx0=None, t0=0.0, hertz=True): """ Computes the modes of a system, and returns them in a AmfeSolution container Parameters ---------- system : MechanicalSystem mechanical system formulation : ConstraintFormulation A ConstraintFormulation object that can recover the nodal unconstrained displacements of the component from the constrained states of the system no_of_modes : int number of modes to compute x0 : array_like state vector at which the system is linearized dx0 : array_like derivative of the state vector at which the system is linearized t0 : array_like time at which the system is linearized hertz: bool specifies if frequency is measured in Hertz, If False, then the unit 1/s (omega) is used Returns ------- modes : AmfeSolution AMfeSolution container containing the modes as timesteps. The times are the frequencies of the modes and the displacements the corresponding mode shapes. """ if x0 is None: x0 = np.zeros(system.dimension) if dx0 is None: dx0 = np.zeros(system.dimension) omega, V = vibration_modes(system.K(x0, dx0, t0), system.M(x0, dx0, t0), no_of_modes) modes = AmfeSolution() for om, phi in zip(omega, V.T): if hertz: om = om / (2 * np.pi) u_unconstr = formulation.u(phi, 0.0) modes.write_timestep(om, u_unconstr) return modes
def test_amfe_solution_reader(self): self._create_fields() amfesolution = AmfeSolution() sol = self.fields_desired['Nodefield1'] for t, q in zip(sol['timesteps'], sol['data'].T): amfesolution.write_timestep(t, q) mesh = create_amfe_obj() meshcomponent = StructuralComponent(mesh) # Set a material to get a mapping material = KirchhoffMaterial() meshcomponent.assign_material(material, 'Tri6', 'S', 'shape') postprocessorreader = AmfeSolutionReader(amfesolution, meshcomponent)
def solve_nonlinear_dynamic(component, t0, t_end): system, formulation = create_mechanical_system( component, constant_mass=True, constant_damping=True, constraint_formulation='boolean') solfac = SolverFactory() solfac.set_system(system) solfac.set_analysis_type('transient') solfac.set_integrator('genalpha') solfac.set_large_deflection(True) solfac.set_nonlinear_solver('newton') solfac.set_linear_solver('scipy-sparse') solfac.set_acceleration_intializer('zero') solfac.set_newton_maxiter(30) solfac.set_newton_atol(1e-6) solfac.set_newton_rtol(1e-8) solfac.set_dt_initial(0.001) solver = solfac.create_solver() solution_writer = AmfeSolution() def write_callback(t, x, dx, ddx): u, du, ddu = formulation.recover(x, dx, ddx, t) solution_writer.write_timestep(t, u, None, None) no_of_dofs = system.dimension q0 = np.zeros(no_of_dofs) dq0 = q0 solver.solve(write_callback, t0, q0, dq0, t_end) return solution_writer
def solve_linear_static(system, formulation, component): """ Solves a linear, static MechanicalSystem. Parameters ---------- system : MechanicalSystem MechanicalSystem object describing the equilibrium forces formulation : ConstraintFormulation A ConstraintFormulation object that can recover the nodal unconstrained displacements of the component from the constrained states of the system component : StructuralComponent Structural Component belonging to the system Returns ------- solution : AmfeSolution Simple Container for solutions of AMfe simulations """ solfac = SolverFactory() solfac.set_system(system) solfac.set_analysis_type('static') solfac.set_linear_solver('scipy-sparse') solver, solver_options = solfac.create_solver() solution_writer = AmfeSolution() no_of_dofs = system.dimension q0 = np.zeros(no_of_dofs) dq0 = q0 ddq0 = dq0 q = solver.solve(system.K(q0, dq0, 0), system.f_ext(q0, dq0, 0)) u, du, ddu = formulation.recover(q, dq0, ddq0, 0) solution_writer.write_timestep(0, u, None, None) logger = logging.getLogger(__name__) logger.info( 'Strains and stresses are currently not supported for linear models. Only nonlinear kinematics are ' 'currently used during their calculation.') print('Solution finished') return solution_writer
def solve_linear_static(component): system, formulation = create_mechanical_system( component, constant_mass=True, constant_damping=True, constraint_formulation='boolean') solver = ScipySparseLinearSolver() no_of_dofs = system.dimension q0 = np.zeros(no_of_dofs) dq0 = q0 x = solver.solve(system.K(q0, dq0, 0.0), system.f_ext(q0, dq0, 0.0)) u, _, _ = formulation.recover(x, q0, q0, 0.0) solution_writer = AmfeSolution() solution_writer.write_timestep(0.0, u, None, None) return solution_writer
def solve_nonlinear_static(system, formulation, component, load_steps): """ Solves a MechanicalSystem using a nonlinear static method using newton for the nonlinear solver. The deformation is divided into an amount of intermediate steps which are defined in the number of load_steps. Parameters ---------- system : MechanicalSystem Created MechanicalSystem object describing the Structural Component formulation : ConstraintFormulation A ConstraintFormulation object that can recover the nodal unconstrained displacements of the component from the constrained states of the system component : StructuralComponent StructuralComponent belonging to the system load_steps : int Number of load steps used for the solution Returns ------- solution : amfe.solution.AmfeSolution Simple Container for solutions of AMfe simulations """ solfac = SolverFactory() solfac.set_system(system) solfac.set_analysis_type('static') solfac.set_nonlinear_solver('newton') solfac.set_linear_solver('scipy-sparse') solfac.set_acceleration_intializer('zero') solfac.set_newton_maxiter(10) solfac.set_newton_atol(1e-8) solfac.set_newton_rtol(2e-9) solfac.set_dt_initial(1.0 / load_steps) solver = solfac.create_solver() solution_writer = AmfeSolution() no_of_dofs = system.dimension q0 = np.zeros(no_of_dofs) dq0 = q0 t0 = 0.0 t_end = 1.0 def write_callback(t, x, dx, ddx): if isclose(t, t_end): u, du, ddu = formulation.recover(x, dx, ddx, t) strains, stresses = component.strains_and_stresses(u, du, t) solution_writer.write_timestep(t, u, None, None, strains, stresses) solver.solve(write_callback, t0, q0, dq0, t_end) print('Solution finished') return solution_writer
def setUp(self): self.timesteps, self.meshreader, self.fields_desired, \ self.fields_no_of_nodes, self.fields_no_of_timesteps = create_fields(2) amfesolution = AmfeSolution() sol = self.fields_desired['Nodefield1'] strains = copy(self.fields_desired['NodefieldStrains']) stresses = copy(self.fields_desired['NodefieldStresses']) for i in range(len(sol['timesteps'])): t = sol['timesteps'][i] q = sol['data'][:, i].T strain = strains['data'][:, :, i].T stress = stresses['data'][:, :, i].T amfesolution.write_timestep(t, q, q, q, strain, stress) self.mesh = create_amfe_obj() self.meshcomponent = StructuralComponent(self.mesh) # Set a material to get a mapping material = KirchhoffMaterial() self.meshcomponent.assign_material(material, 'Tri6', 'S', 'shape') self.postprocessorreader = AmfeSolutionReader(amfesolution, self.meshcomponent)
# Solving our system solution_obj = feti_solver.solve() """ We now have our solution, but it's a solution object so we need to read it out and store the solution in a way that is readable to us. We are going to create ``.hdf5`` and ``.xdmf`` files that contain the results. """ # Initializing an empty dictionary solution_writer = dict() # Save all items from the solution object in the dictionary for i_prob, local_problem in solution_obj.local_problems.items(): solution_writer[i_prob] = AmfeSolution() q = local_problem.q msys = substructured_system.mechanical_systems[i_prob] if i_prob in substructured_system.constraint_formulations: formulation = substructured_system.constraint_formulations[i_prob] u, du, ddu = formulation.recover(q, np.zeros_like(q), np.zeros_like(q), 0) else: u = q du = np.zeros_like(u) strains, stresses = structural_composite.components[ i_prob].strains_and_stresses(u, du, 0) solution_writer[i_prob].write_timestep(0, u, None, None, strains, stresses) # Export the items in files readable in Paraview for i_comp, comp in structural_composite.components.items():
def test_amfe_solution(self): # Only q solution = AmfeSolution() q1 = np.arange(0, 60, dtype=float) q2 = np.arange(10, 70, dtype=float) t1 = 0.1 t2 = 0.5 solution.write_timestep(t1, q1) solution.write_timestep(t2, q2) assert_array_equal(solution.q[0], q1) assert_array_equal(solution.q[1], q2) self.assertEqual(solution.t[0], t1) self.assertEqual(solution.t[1], t2) self.assertTrue(len(solution.t) == len(solution.q)) self.assertEqual(len(solution.t), 2) # q and dq solution = AmfeSolution() dq1 = np.arange(20, 80, dtype=float) dq2 = np.arange(30, 90, dtype=float) solution.write_timestep(t1, q1, dq1) solution.write_timestep(t2, q2, dq2) assert_array_equal(solution.q[0], q1) assert_array_equal(solution.q[1], q2) assert_array_equal(solution.dq[0], dq1) assert_array_equal(solution.dq[1], dq2) self.assertEqual(solution.t[0], t1) self.assertEqual(solution.t[1], t2) self.assertTrue(len(solution.t) == len(solution.q)) self.assertTrue(len(solution.t) == len(solution.dq)) self.assertEqual(len(solution.t), 2) # q, dq and ddq solution = AmfeSolution() ddq1 = np.arange(40, 100, dtype=float) ddq2 = np.arange(50, 110, dtype=float) solution.write_timestep(t1, q1, dq1, ddq1) solution.write_timestep(t2, q2, dq2, ddq2) assert_array_equal(solution.q[0], q1) assert_array_equal(solution.q[1], q2) assert_array_equal(solution.dq[0], dq1) assert_array_equal(solution.dq[1], dq2) assert_array_equal(solution.ddq[0], ddq1) assert_array_equal(solution.ddq[1], ddq2) self.assertEqual(solution.t[0], t1) self.assertEqual(solution.t[1], t2) self.assertTrue(len(solution.t) == len(solution.q)) self.assertTrue(len(solution.t) == len(solution.dq)) self.assertTrue(len(solution.t) == len(solution.ddq)) self.assertEqual(len(solution.t), 2) # q and ddq solution = AmfeSolution() solution.write_timestep(t1, q1, ddq=ddq1) solution.write_timestep(t2, q2, ddq=ddq2) assert_array_equal(solution.q[0], q1) assert_array_equal(solution.q[1], q2) assert_array_equal(solution.ddq[0], ddq1) assert_array_equal(solution.ddq[1], ddq2) self.assertEqual(solution.t[0], t1) self.assertEqual(solution.t[1], t2) self.assertTrue(len(solution.t) == len(solution.q)) self.assertTrue(len(solution.t) == len(solution.ddq)) self.assertEqual(len(solution.t), 2) self.assertIsNone(solution.dq[0]) self.assertIsNone(solution.dq[1]) # q and strains solution = AmfeSolution() strains1 = np.random.rand(60, 6) strains2 = np.random.rand(60, 6) solution.write_timestep(t1, q1, strain=strains1) solution.write_timestep(t2, q2, strain=strains2) self.assertEqual(solution.t[0], t1) self.assertEqual(solution.t[1], t2) assert_array_equal(solution.q[0], q1) assert_array_equal(solution.q[1], q2) assert_array_equal(solution.strain[0], strains1) assert_array_equal(solution.strain[1], strains2) self.assertIsNone(solution.stress[0]) self.assertIsNone(solution.stress[1]) # q, strains and stresses solution = AmfeSolution() strains1 = np.random.rand(60, 6) strains2 = np.random.rand(60, 6) stresses1 = np.random.rand(60, 6) stresses2 = np.random.rand(60, 6) solution.write_timestep(t1, q1, strain=strains1, stress=stresses1) solution.write_timestep(t2, q2, strain=strains2, stress=stresses2) self.assertEqual(solution.t[0], t1) self.assertEqual(solution.t[1], t2) assert_array_equal(solution.q[0], q1) assert_array_equal(solution.q[1], q2) assert_array_equal(solution.strain[0], strains1) assert_array_equal(solution.strain[1], strains2) assert_array_equal(solution.stress[0], stresses1) assert_array_equal(solution.stress[1], stresses2) return
def test_pendulum_time_integration(self): """ Test that computes the time integration of the pendulum """ formulation_lagrange = SparseLagrangeMultiplierConstraintFormulation( self.cm.no_of_dofs_unconstrained, self.M_raw_func, self.h_func, self.B_func, self.p_func, self.dh_dq, self.dh_ddq, g_func=self.g_func) formulation_nullspace = NullspaceConstraintFormulation( self.cm.no_of_dofs_unconstrained, self.M_raw_func, self.h_func, self.B_func, self.p_func, self.dh_dq, self.dh_ddq, g_func=self.g_func, a_func=self.a_func) sol_lagrange = AmfeSolution() sol_nullspace = AmfeSolution() formulations = [(formulation_lagrange, sol_lagrange), (formulation_nullspace, sol_nullspace)] # Define state: 90deg to the right q0 = np.array([0.0, 0.0, self.L, self.L]) dq0 = np.array([0.0, 0.0, 0.0, 0.0]) nonlinear_solver = NewtonRaphson() for (formulation, sol) in formulations: def write_callback(t, x, dx, ddx): u = formulation.u(x, t) du = formulation.du(x, dx, t) ddu = formulation.ddu(x, dx, ddx, t) sol.write_timestep(t, u, du, ddu) integrator = GeneralizedAlpha(formulation.M, formulation.f_int, formulation.f_ext, formulation.K, formulation.D, alpha_m=0.0) integrator.dt = 0.025 integrator.nonlinear_solver_func = nonlinear_solver.solve integrator.nonlinear_solver_options = {'rtol': 1e-7, 'atol': 1e-6} # Initialize first timestep t = 0.0 t_end = 0.5 x = np.zeros(formulation.dimension) dx = np.zeros(formulation.dimension) ddx = np.zeros(formulation.dimension) x[:4] = q0 dx[:4] = dq0 # Call write timestep for initial conditions write_callback(t, x, dx, ddx) # Run Loop while t < t_end: t, x, dx, ddx = integrator.step(t, x, dx, ddx) write_callback(t, x, dx, ddx) def plot_pendulum_path(u_plot): plt.scatter(self.X[2] + [u[2] for u in u_plot], self.X[3] + [u[3] for u in u_plot]) plt.title( 'Pendulum-test: Positional curve of rigid pendulum under gravitation' ) return # UNCOMMENT THESE LINES IF YOU LIKE TO SEE A TRAJECTORY (THIS CAN NOT BE DONE FOR GITLAB-RUNNER # plot_pendulum_path(sol_lagrange.q) # plot_pendulum_path(sol_nullspace.q) # plt.show() # test if nullspace formulation is almost equal to lagrangian # and test if constraint is not violated for q_lagrange, q_nullspace in zip(sol_lagrange.q, sol_nullspace.q): assert_allclose(q_nullspace, q_lagrange, atol=1e-1) x_lagrange = self.X.reshape(-1) + q_lagrange x_nullspace = self.X.reshape(-1) + q_nullspace assert_allclose(np.array( [np.linalg.norm(x_lagrange[2:] - x_lagrange[:2])]), np.array([self.L]), atol=1e-3) assert_allclose(np.array( [np.linalg.norm(x_nullspace[2:] - x_nullspace[:2])]), np.array([self.L]), atol=1e-1)
def test_pendulum_time_integration(self): """ Test that computes the time integration of the pendulum """ formulation_lagrange = SparseLagrangeMultiplierConstraintFormulation(self.cm.no_of_dofs_unconstrained, self.M_raw_func, self.h_func, self.B_func, self.p_func, self.dh_dq, self.dh_ddq, g_func=self.g_func) formulation_nullspace = NullspaceConstraintFormulation(self.cm.no_of_dofs_unconstrained, self.M_raw_func, self.h_func, self.B_func, self.p_func, self.dh_dq, self.dh_ddq, g_func=self.g_func, a_func=self.a_func) sol_lagrange = AmfeSolution() sol_nullspace = AmfeSolution() phi_analytical = [] formulations = [(formulation_lagrange, sol_lagrange), (formulation_nullspace, sol_nullspace)] # Define state: 90deg to the right q0 = np.array([0.0, 0.0, self.L, self.L]) dq0 = np.array([0.0, 0.0, 0.0, 0.0]) nonlinear_solver = NewtonRaphson() for (formulation, sol) in formulations: def write_callback(t, x, dx, ddx): u = formulation.u(x, t) du = formulation.du(x, dx, t) ddu = formulation.ddu(x, dx, ddx, t) sol.write_timestep(t, u, du, ddu) integrator = GeneralizedAlpha(formulation.M, formulation.f_int, formulation.f_ext, formulation.K, formulation.D, alpha_m=0.0) integrator.dt = 0.025 integration_stepper = NonlinearIntegrationStepper(integrator) integration_stepper.nonlinear_solver_func = nonlinear_solver.solve integration_stepper.nonlinear_solver_options = {'rtol': 1e-7, 'atol': 1e-6} # Initialize first timestep t = 0.0 t_end = 0.5 x = np.zeros(formulation.dimension) dx = np.zeros(formulation.dimension) ddx = np.zeros(formulation.dimension) x[:4] = q0 dx[:4] = dq0 # Call write timestep for initial conditions write_callback(t, x, dx, ddx) i = 0 # Run Loop while t < t_end: phi_analytical.append(np.pi / 2 * np.cos(np.sqrt(self.g / self.L) * t)) t, x, dx, ddx = integration_stepper.step(t, x, dx, ddx) write_callback(t, x, dx, ddx) i += 1 phi_analytical.append(np.pi / 2 * np.cos(np.sqrt(self.g / self.L) * t)) def plot_pendulum_path(u_plot, label_name): return plt.scatter(self.X[2]+[u[2] for u in u_plot], self.X[3]+[u[3] for u in u_plot], label=label_name) plt.title('Pendulum-test: Positional curve of rigid pendulum under gravitation') lagrange = plot_pendulum_path(sol_lagrange.q, 'Lagrange') nullspace = plot_pendulum_path(sol_nullspace.q, 'Nullspace') # ANALYTICAL SOLUTION FOR SMALL ANGLES #analytical = plt.scatter([self.L*np.sin(phi) for phi in phi_analytical], [-self.L*np.cos(phi) for phi in phi_analytical], label='Analytical') axes = plt.gca() axes.set_xlim([-2.1, 2.1]) axes.set_ylim([-2.1, 2.1]) plt.legend(handles=[lagrange, nullspace])#, analytical]) # UNCOMMENT NEXT LINE IF YOU LIKE TO SEE A TRAJECTORY (THIS CAN NOT BE DONE FOR GITLAB-RUNNER) # plt.show() # test if nullspace formulation is almost equal to lagrangian # and test if constraint is not violated for q_lagrange, q_nullspace in zip(sol_lagrange.q, sol_nullspace.q): assert_allclose(q_nullspace, q_lagrange, atol=1e-1) x_lagrange = self.X.reshape(-1) + q_lagrange x_nullspace = self.X.reshape(-1) + q_nullspace assert_allclose(np.array([np.linalg.norm(x_lagrange[2:] - x_lagrange[:2])]), np.array([self.L]), atol=1e-3) assert_allclose(np.array([np.linalg.norm(x_nullspace[2:] - x_nullspace[:2])]), np.array([self.L]), atol=1e-1)
constraint_formulation='boolean') solfac = SolverFactory() solfac.set_system(system) solfac.set_analysis_type('static') solfac.set_dt_initial(0.05) solfac.set_analysis_type('zero') solfac.set_linear_solver('pardiso') solfac.set_newton_verbose(True) solfac.set_nonlinear_solver('newton') solfac.set_newton_atol(1e-5) solfac.set_newton_rtol(1e-7) solver = solfac.create_solver() solution = AmfeSolution() def write_callback(t, x, dx, ddx): u, du, ddu = formulation.recover(x, dx, ddx, t) solution.write_timestep(t, u, du, ddu) x0 = np.zeros(system.dimension) dx0 = x0.copy() t0 = 0.0 t_end = 1.0 solver.solve(write_callback, t0, x0, dx0, t_end) write_results_to_paraview(solution, my_component, output_file)
solfac.set_linear_solver('scipy-sparse') solfac.set_acceleration_intializer('zero') solfac.set_newton_maxiter(20) solfac.set_newton_atol(1e-8) solfac.set_newton_rtol(1e-9) solfac.set_dt_initial(0.00001) solfac._alpha_f = 0.25 solfac._alpha_m = 0.25 solfac._gamma = 0.75 solfac._beta = 0.390625 residuals = list() mysolver = solfac.create_solver() writer = AmfeSolution() def write_callback(t, x, dx, ddx): u, du, ddu = formulation.recover(x, dx, ddx, t) writer.write_timestep(t, u, du, ddu) t0 = 0.0 t_end = 0.15 no_of_dofs = system.dimension q0 = np.zeros(no_of_dofs) dq0 = q0.copy() q0[:len(q0_raw)] = q0_raw dq0[:len(dq0_raw)] = dq0_raw
for dof in glo_dofs_y.reshape(-1): structural_composite.assign_constraint('Dirichlet1', dirichlet, np.array([dof], dtype=int), []) # FETI-solver substructured_system = MulticomponentMechanicalSystem(structural_composite, 'boolean') fetisolver = FETISolver() q_dict = fetisolver.solve(substructured_system.mechanical_systems, substructured_system.connections) u_dict, du_dict, ddu_dict = substructured_system.recover(q_dict) # Exporter for i_comp, comp in structural_composite.components.items(): writer = AmfeSolution() writer.write_timestep(0, u_dict[i_comp], None, None) mesh = comp._mesh preader = AmfeSolutionReader(writer, comp) amfeMeshReader = AmfeMeshObjMeshReader(mesh) path = amfe_dir( 'meshes/gmsh/simple_beam_metis_10/results/partition_mesh_' + str(i_comp) + '.vtk') VTKwriter = VtkMeshConverter(path) amfeMeshReader.parse(VTKwriter) VTKwriter.return_mesh() hdf5resultsfilename = amfe_dir( 'meshes/gmsh/simple_beam_metis_10/results/partition_mesh_' +
def solve_nonlinear_dynamic(system, formulation, component, t0, t_end, dt, write_each=1): """ Solves a system Parameters ---------- system : MechanicalSystem Created MechanicalSystem object describing the Structural Component formulation : ConstraintFormulation A ConstraintFormulation object that can recover the nodal unconstrained displacements of the component from the constrained states of the system component : StructuralComponent StructuralComponent belonging to the system t0 : float initial time t_end : float final time dt : float increment between time steps write_each : int Specifies that the solver writes every n'th solution (eg. type 2 to write every second timestep) Returns ------- solution : amfe.solution.AmfeSolution Simple Container for solutions of AMfe simulations """ solfac = SolverFactory() solfac.set_system(system) solfac.set_analysis_type('transient') solfac.set_integrator('genalpha') solfac.set_nonlinear_solver('newton') solfac.set_linear_solver('scipy-sparse') solfac.set_acceleration_intializer('zero') solfac.set_newton_maxiter(10) solfac.set_newton_atol(1e-8) solfac.set_newton_rtol(2e-11) solfac.set_dt_initial(dt) solver = solfac.create_solver() solution_writer = AmfeSolution() def write_callback(t, x, dx, ddx): cur_ts = int((t - t0) // dt) if abs(cur_ts % write_each) <= 1e-7: u, du, ddu = formulation.recover(x, dx, ddx, t) strains, stresses = component.strains_and_stresses(u, du, t) solution_writer.write_timestep(t, u, du, ddu, strains, stresses) no_of_dofs = system.dimension q0 = np.zeros(no_of_dofs) dq0 = q0 solver.solve(write_callback, t0, q0, dq0, t_end) print('Solution finished') return solution_writer
def solve_linear_dynamic(system, formulation, component, t0, t_end, dt, write_each=1): """ Solves a linear, dynamic MechanicalSystem from t0 to t_end with dt as intermediate steps. Parameters ---------- system : MechanicalSystem MechanicalSystem object describing the equations of motion formulation : ConstraintFormulation A ConstraintFormulation object that can recover the nodal unconstrained displacements of the component from the constrained states of the system component : StructuralComponent StructuralComponent belonging to the system t0 : float initial time t_end : float final time dt : float increment between time steps write_each : int Specifies that the solver writes every n'th solution (eg. type 2 to write every second timestep) Returns ------- solution : amfe.solution.AmfeSolution AmfeSolution container that contains the solution """ solfac = SolverFactory() solfac.set_system(system) solfac.set_analysis_type('transient') solfac.set_linear_solver('scipy-sparse') solfac.set_integrator('newmarkbeta') solfac.set_acceleration_intializer('zero') solfac.set_dt_initial(dt) solver = solfac.create_solver() no_of_dofs = system.dimension q0 = np.zeros(no_of_dofs) dq0 = q0 solution_writer = AmfeSolution() def write_callback(t, x, dx, ddx): cur_ts = int((t - t0) // dt) if abs(cur_ts % write_each) <= 1e-7: u, du, ddu = formulation.recover(x, dx, ddx, t) solution_writer.write_timestep(t, u, du, ddu) solver.solve(write_callback, t0, q0, dq0, t_end) logger = logging.getLogger(__name__) logger.info( 'Strains and stresses are currently not supported for linear models. Only nonlinear kinematics are ' 'currently used during their calculation.') print('Solution finished') return solution_writer