# Copyright (c) 2024-2026 Karana Dynamics Pty Ltd. All rights reserved.
#
# NOTICE TO USER:
#
# This source code and/or documentation (the "Licensed Materials") is
# the confidential and proprietary information of Karana Dynamics Inc.
# Use of these Licensed Materials is governed by the terms and conditions
# of a separate software license agreement between Karana Dynamics and the
# Licensee ("License Agreement"). Unless expressly permitted under that
# agreement, any reproduction, modification, distribution, or disclosure
# of the Licensed Materials, in whole or in part, to any third party
# without the prior written consent of Karana Dynamics is strictly prohibited.
#
# THE LICENSED MATERIALS ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND.
# KARANA DYNAMICS DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
# BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT, AND
# FITNESS FOR A PARTICULAR PURPOSE.
#
# IN NO EVENT SHALL KARANA DYNAMICS BE LIABLE FOR ANY DAMAGES WHATSOEVER,
# INCLUDING BUT NOT LIMITED TO LOSS OF PROFITS, DATA, OR USE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, WHETHER IN CONTRACT, TORT,
# OR OTHERWISE ARISING OUT OF OR IN CONNECTION WITH THE LICENSED MATERIALS.
#
# U.S. Government End Users: The Licensed Materials are a "commercial item"
# as defined at 48 C.F.R. 2.101, and are provided to the U.S. Government
# only as a commercial end item under the terms of this license.
#
# Any use of the Licensed Materials in individual or commercial software must
# include, in the user documentation and internal source code comments,
# this Notice, Disclaimer, and U.S. Government Use Provision.
from typing import TYPE_CHECKING, Self
import numpy as np
import Karana.Math as km
from Karana.Math.Ktyping import (
Mat3n,
RotationalNodalMatrix,
TranslationalNodalMatrix,
Vec,
ModalStiffness,
ModalDamping,
)
if TYPE_CHECKING:
from Karana.Dynamics import (
PhysicalBodyParams,
PhysicalHingeParams,
PinSubhingeParams,
HingeType,
ParentPhysicalModalBodyAttachmentParams,
ParentBodyAttachmentParams,
)
import Karana.Scene as ks
else:
from ._params import PhysicalBodyParams, PhysicalHingeParams, PinSubhingeParams
from ._SOADyn_Py import HingeType
from ._SOAFlexDyn_Py import ParentPhysicalModalBodyAttachmentParams
def _stiffnessDefault():
return np.linspace(1, 4, 4) * 0.1
def _dampingDefault():
return np.linspace(1, 4, 4) * 0.01
def _rotDefault(val: float):
dark = np.empty((3, 4))
for i in range(3):
for j in range(4):
dark[i, j] = i + j + 1
return val * dark
def _transDefault(val: float):
dark = np.empty((3, 4))
for i in range(3):
for j in range(4):
dark[i, j] = i + j + 4
return val * dark
class PhysicalModalBodyParams(PhysicalBodyParams):
"""Parameters used to configure a PhysicalModalBody.
Parameters
----------
spatial_inertia : Karana.Math.SpatialInertia
Spatial inertia assigned to the body.
body_to_joint_transform : Karana.Math.HomTran
Transform from the body frame to its hinge joint frame.
hinge_params : PhysicalHingeParams
Parameters for the body's physical hinge.
parent_body_attachment_params : ParentBodyAttachmentParams
Parameters for attaching this body to its parent.
scene_part_specs : list[ScenePartSpec]
Scene-part specifications attached to the body.
scene_file_object_specs : list[SceneFileObjectSpec]
Scene-file-object specifications attached to the body.
nmodes : int
The number of deformation modes
stiffness: ModalStiffness[Vec]
The stiffness vector (based on modal frequencies)
damping: ModalDamping[Vec]
The damping coefficients
pnode_rotational_nodal_matrix: Mat3n
The rotational nodal matrix for the pnode
pnode_translational_nodal_matrix: Mat3n
The translational nodal matrix for the pnode
"""
nmodes: int
stiffness: ModalStiffness[Vec]
damping: ModalDamping[Vec]
pnode_rotational_nodal_matrix: RotationalNodalMatrix[Mat3n]
pnode_translational_nodal_matrix: TranslationalNodalMatrix[Mat3n]
if TYPE_CHECKING:
# Add type hint for init that includes coercion
def __init__(
self,
spatial_inertia: km.SpatialInertia,
body_to_joint_transform: km.HomTran,
hinge_params: PhysicalHingeParams,
parent_body_attachment_params: ParentBodyAttachmentParams,
scene_part_specs: list[ks.ScenePartSpec],
scene_file_object_specs: list[ks.SceneFileObjectSpec],
nmodes: int,
stiffness: ModalStiffness[Vec] | Vec,
damping: ModalDamping[Vec] | Vec,
pnode_rotational_nodal_matrix: RotationalNodalMatrix[Mat3n] | Mat3n,
pnode_translational_nodal_matrix: TranslationalNodalMatrix[Mat3n] | Mat3n,
):
"""Parameters used to configure a PhysicalModalBody.
Parameters
----------
spatial_inertia : Karana.Math.SpatialInertia
Spatial inertia assigned to the body.
body_to_joint_transform : Karana.Math.HomTran
Transform from the body frame to its hinge joint frame.
hinge_params : PhysicalHingeParams
Parameters for the body's physical hinge.
parent_body_attachment_params : ParentBodyAttachmentParams
Parameters for attaching this body to its parent.
scene_part_specs : list[ScenePartSpec]
Scene-part specifications attached to the body.
scene_file_object_specs : list[SceneFileObjectSpec]
Scene-file-object specifications attached to the body.
nmodes : int
The number of deformation modes
stiffness: ModalStiffness[Vec]
The stiffness vector (based on modal frequencies)
damping: ModalDamping[Vec]
The damping coefficients
pnode_rotational_nodal_matrix: Mat3n
The rotational nodal matrix for the pnode
pnode_translational_nodal_matrix: Mat3n
The translational nodal matrix for the pnode
"""
...
[docs]
@classmethod
def createDefault(cls) -> Self:
"""Create a version of PhysicalModalBodyParams with all values filled in.
This is useful for testing or when you just need a body for a simple demo.
Returns
-------
Self
An instance of PhysicalModalBodyParams with all values filled in.
"""
return cls(
spatial_inertia=km.SpatialInertia(
2.0, np.array([0.3, 0.2, 0.1]), np.diag([3.0, 2.0, 1.0])
),
body_to_joint_transform=km.HomTran(
km.UnitQuaternion(0.8, 0.6, 0.0, 0.0), np.array([0.2, 0.3, 0.4])
),
hinge_params=PhysicalHingeParams(
hinge_type=HingeType.REVOLUTE,
subhinge_params=[PinSubhingeParams(unit_axis=np.array([0.0, 1.0, 0.0]))],
),
parent_body_attachment_params=ParentPhysicalModalBodyAttachmentParams(
inb_to_joint_transform=km.HomTran(
km.UnitQuaternion(0.5, 0.5, 0.5, 0.5), np.array([0.4, 0.2, 0.3])
),
onode_rotational_nodal_matrix=_rotDefault(0.2),
onode_translational_nodal_matrix=_transDefault(0.2),
),
scene_part_specs=[],
scene_file_object_specs=[],
nmodes=4,
stiffness=_stiffnessDefault(),
damping=_dampingDefault(),
pnode_rotational_nodal_matrix=_rotDefault(0.1),
pnode_translational_nodal_matrix=_transDefault(0.1),
)
__all__ = ["PhysicalModalBodyParams"]