# -*- coding: utf-8 -*-
# TorsoCAE Macro Journal — simple pendulum validation case (best settings)
#
# Single stout ("very stiff", near-rigid) steel rod, pinned at one end via
# set_flexible_multibody (one ground frame, one body frame, one RBE2
# attachment, one revolute joint), released from rest at theta0=10 deg from
# vertical and left to swing freely under gravity. See run_validation.py for
# the physical-pendulum period comparison and angle time-history extraction.

import sys

import numpy as np

sys.path.insert(0, "./server/")
from mesh_generators.structured import build_structured_mesh
from pytorsocae import TorsoCAESession

L, W, T = 1.0, 0.05, 0.05
E, NU, RHO = 210e9, 0.3, 7800.0
G = 9.81
THETA0 = np.radians(10.0)


def rotated_map(x, y, z):
    gx = x * np.sin(THETA0) + y * np.cos(THETA0)
    gy = -x * np.cos(THETA0) + y * np.sin(THETA0)
    gz = z
    return (gx, gy, gz)


mesh = build_structured_mesh(
    bounds=((0.0, L), (-W / 2, W / 2), (-T / 2, T / 2)),
    divisions=(8, 2, 2),
    surface_tags={"xmin": 1, "xmax": 2, "ymin": 3, "ymax": 4, "zmin": 5, "zmax": 6},
    volume_tag=1,
    mapping=rotated_map,
)

session = TorsoCAESession()
session.inline_mesh(mesh, mesh_id="pendulum_mesh", name="Simple Pendulum",
                     volume_names={1: "Pendulum Rod"})
session.solid("Pendulum Rod").material(E=E, nu=NU, rho=RHO)
session.set_flexible_multibody(
    frames=[
        {"id": "ground", "origin": [0.0, 0.0, 0.0], "grounded": True},
        {"id": "link_root", "origin": [0.0, 0.0, 0.0]},
    ],
    bodies=[{"id": "body_a", "kind": "flexible", "reference_frame_id": "link_root"}],
    attachments=[{"frame_id": "link_root", "surface_tag": 1, "body_id": "body_a",
                  "dependent_axes": ["x", "y", "z"]}],
    joints=[{"id": "pivot_hinge", "frame_a": "ground", "frame_b": "link_root",
             "kind": "revolute", "axis": "z"}],
    kkt_augmentation=0.0,
    projection={"tolerance": 1.0e-9, "max_iterations": 15},
)
session.set_model_options(gravity=[0.0, -G, 0.0])
session.set_physics("structural", submodel="flexible_multibody_dynamics", backend="dolfinx")
session.set_solver_options(
    algo="auto", tol=1.0e-7, max_iter=800,
    num_steps=800, dt=0.01, time_scheme="generalized-alpha",
    spectral_radius_infinity=0.99, max_inner_iter=500, inner_tol=1.0e-5,
    n_cores=1, device="cpu",
)
session.compute(mesh_ids=["pendulum_mesh"])
