Program Listing for File SpringDamper.cc#
↰ Return to documentation for file (doxygen_docs/GeneralKModels/SpringDamper.cc)
#include "Karana/GeneralKModels/SpringDamper.h"
#include "Karana/KCore/Allocator.h"
#include "Karana/SOADyn/Multibody.h"
/**
* @file
* @brief SpringDamper implementation.
*/
namespace Karana::Models {
namespace kd = Karana::Dynamics;
SpringDamper::SpringDamper(std::string_view name,
const kc::ks_ptr<kd::ModelManager> &mm,
const kc::ks_ptr<kd::Node> nd1,
const kc::ks_ptr<kd::Node> nd2)
: KModel<SpringDamper, SpringDamperParams, SpringDamperScratch>(name, mm)
, _nd1(nd1)
, _nd2(nd2) {
params = std::allocate_shared<SpringDamperParams>(kc::Allocator<SpringDamperParams>{},
std::format("{}_params", name));
scratch = std::allocate_shared<SpringDamperScratch>(kc::Allocator<SpringDamperScratch>{},
std::format("{}_scratch", name));
if (not _nd1->isExternalForceNode()) {
throw std::invalid_argument("Node1 is not a force node.");
}
if (not _nd2->isExternalForceNode()) {
throw std::invalid_argument("Node2 is not a force node.");
}
_newton = _nd1->parentBody()->multibody()->getNewtonianFrame();
_f2f1 = _newton->frameToFrame(_nd1);
_f2f2 = _newton->frameToFrame(_nd2);
};
kc::ks_ptr<SpringDamper> SpringDamper::create(std::string_view name,
const kc::ks_ptr<kd::ModelManager> &mm,
const kc::ks_ptr<kd::Node> nd1,
const kc::ks_ptr<kd::Node> nd2) {
kc::ks_ptr<SpringDamper> sd =
std::allocate_shared<SpringDamper>(kc::Allocator<SpringDamper>{}, name, mm, nd1, nd2);
mm->registerModel(sd);
return sd;
}
void SpringDamper::preDeriv(const km::Ktime &, const km::Vec &) {
// The vector from node1 to node2 as measured in the newtonian frame
scratch->offset =
_f2f2->relTransform().getTranslation() - _f2f1->relTransform().getTranslation();
// The velocity of node2 relative to node1 as expressed in the inertial frame.
scratch->velocity_error = _f2f2->relSpVel().getv() - _f2f1->relSpVel().getv();
// The current length between the nodes
double l = scratch->offset.norm();
km::Vec3 dir = scratch->offset / l;
// Signed scalar length error
scratch->position_error = l - params->unsprung_length;
// Force on node1 toward node2 due to spring stiffness, as expressed in
// the inertial frame.
scratch->stiffness_force = params->k * scratch->position_error;
/* Force on node1 due to samping as expressed in the inertial
frame. Based on using the axial/radial velocity component of
the relative velocity:
https://nexus.hexagon.com/documentationcenter/tr-TR/bundle/Adams_2022.4_Adams_View_Function_Builder_User_Guide/resource/Adams_2022.4_Adams_View_Function_Builder_User_Guide.pdf
*/
// scratch->damping_force = params->d * scratch->velocity_error;
scratch->damping_force = (params->d * scratch->velocity_error.dot(dir)) * dir;
// Force on node1 due to the spring as expressed in the inertial frame.
scratch->total_force = scratch->stiffness_force * dir + scratch->damping_force;
// km::Vec3 f = (l - params->unsprung_length) * params->k * t / l - params->d * v;
// Apply the equal and opposing forces to the nodes
_nd1->accumExternalSpForce(km::SpatialVector(km::Vec3{0, 0, 0}, scratch->total_force),
_newton);
_nd2->accumExternalSpForce(km::SpatialVector(km::Vec3{0, 0, 0}, -scratch->total_force),
_newton);
}
const kc::ks_ptr<kd::Node> &SpringDamper::sourceNode() const { return _nd1; }
const kc::ks_ptr<kd::Node> &SpringDamper::targetNode() const { return _nd2; }
SpringDamperParams::SpringDamperParams(std::string_view name)
: KModelParams(name) {
unsprung_length = km::notReadyNaN;
k = km::notReadyNaN;
d = km::notReadyNaN;
}
bool SpringDamperParams::isReady() const {
bool flag = true;
if (km::isNotReadyNaN(k)) {
kc::warn("Parameter k is not ready.");
flag = false;
}
if (km::isNotReadyNaN(d)) {
kc::warn("Parameter d is not ready.");
flag = false;
}
if (km::isNotReadyNaN(unsprung_length)) {
kc::warn("Parameter unsprung_length is not ready.");
flag = false;
}
return flag;
}
std::string
SpringDamperParams::dumpString(std::string_view prefix,
const Karana::Core::Base::DumpOptions * /*options*/) const {
// std::string result;
// std::cout << "JJJJJ<" << prefix << ">KKK\n";
auto result =
std::format("{} k={}, d={}, unsprung_length={}\n", prefix, k, d, unsprung_length);
return result;
}
std::string
SpringDamperScratch::dumpString(std::string_view prefix,
const Karana::Core::Base::DumpOptions * /*options*/) const {
// std::string result;
// std::cout << "JJJJJ<" << prefix << ">KKK\n";
auto result = std::format("{} offset:{}\n", prefix, km::dumpString(offset));
result += std::format("{} position_error:{}\n", prefix, position_error);
result += std::format("{} velocity_error:{}\n", prefix, km::dumpString(velocity_error));
result += std::format("{} stiffness_force:{}\n", prefix, stiffness_force);
result += std::format("{} damping_force:{}\n", prefix, km::dumpString(damping_force));
result += std::format("{} total_force:{}\n", prefix, km::dumpString(total_force));
return result;
}
// Destructor included for MacOS builds. Must have a key-function out-of-line to avoid dulpicate
// symbols.
SpringDamper::~SpringDamper(){};
SpringDamperScratch::SpringDamperScratch(std::string_view name)
: KModelScratch(name) {
km::makeNotReady(offset);
km::makeNotReady(velocity_error);
km::makeNotReady(damping_force);
km::makeNotReady(total_force);
}
} // namespace Karana::Models