Skip to content

XML.Tools.installable

Jose Luis Cercos-Pita edited this page Feb 17, 2025 · 1 revision

Installable tool

This is kind of a special tool on AQUAgpusph, which allows the user to compile its own Aqua::CalcServer::Tool C++ tool as a library.

A good way to illustrate this is the coupling with ProjectChrono done to carry out the Apollo capsule simulation.

First the installable tool source code is required, in this case a single header --chronosim.hpp--:

#ifndef INSTALLABLEDEMO_H_INCLUDED
#define INSTALLABLEDEMO_H_INCLUDED

#include <aquagpusph/CalcServer/Tool.hpp>
#include <chrono/physics/ChSystemNSC.h>
#include <chrono/physics/ChBody.h>
#include <chrono/physics/ChForce.h>

namespace Aqua{ namespace CalcServer{

class ApolloSim : public Aqua::CalcServer::Tool
{
public:
    ApolloSim(const std::string tool_name, bool once);

    ~ApolloSim();

    void setup();
protected:
    cl_event _execute(const std::vector<cl_event> events);

private:
    float _pitch;
    float _vel;
    float _cogz;

    std::shared_ptr<chrono::ChSystemNSC> _sys;
    std::shared_ptr<chrono::ChBody> _apollo;
    std::shared_ptr<chrono::ChForce> _force;
    std::shared_ptr<chrono::ChForce> _moment;
};

}}  // namespace

#endif // INSTALLABLEDEMO_H_INCLUDED

as well as a surce code file --chronosim.cpp--:

#include "chronosim.hpp"
#include <aquagpusph/CalcServer/CalcServer.hpp>
#include <aquagpusph/InputOutput/Logger.hpp>
#include <cmath>

extern "C" Aqua::CalcServer::ApolloSim* create_object(
    const std::string name, bool once)
{
    return new Aqua::CalcServer::ApolloSim(name, once);
}

namespace Aqua{ namespace CalcServer{

ApolloSim::ApolloSim(const std::string name, bool once)
    : Tool(name, once)
{
}

ApolloSim::~ApolloSim()
{
}

#define LB2KG 0.4535924
#define IN2M 0.0254

void
ApolloSim::setup()
{
    Tool::setup();
    // Get the configuration variables
    auto vars = CalcServer::singleton()->variables();
    _pitch = *((float*)vars->get("pitch")->get(true));
    _vel = *((float*)vars->get("u0")->get(true));
    _cogz = *((float*)vars->get("cogz")->get(true));
    _pitch *= M_PI / 180.0;

    _sys = chrono_types::make_shared<chrono::ChSystemNSC>();
    _apollo = chrono_types::make_shared<chrono::ChBody>();
    _sys->AddBody(_apollo);
    _force = chrono_types::make_shared<chrono::ChForce>();
    _moment = chrono_types::make_shared<chrono::ChForce>();
    _apollo->AddForce(_force);
    _apollo->AddForce(_moment);

    _apollo->SetName("Apollo");
    _sys->SetGravitationalAcceleration(chrono::ChVector3d(0, 0, -9.81));
    _apollo->SetMass(3900);
    _apollo->SetInertiaXX(chrono::ChVector3d(5560, 5270, 4180));

    _force->SetMode(chrono::ChForce::FORCE);
    _force->SetFrame(chrono::ChForce::BODY);
    _force->SetAlign(chrono::ChForce::WORLD_DIR);
    _force->SetVrelpoint(chrono::ChVector3d(0, 0, 0));
    _moment->SetMode(chrono::ChForce::TORQUE);
    _moment->SetFrame(chrono::ChForce::BODY);
    _moment->SetAlign(chrono::ChForce::WORLD_DIR);
    _moment->SetVrelpoint(chrono::ChVector3d(0, 0, 0));

    _apollo->SetPos(chrono::ChVector3d(0, 0, _cogz));
    _apollo->SetLinVel(chrono::ChVector3d(0, 0, -_vel));
    chrono::ChQuaternion<double> R;
    R.SetFromCardanAnglesXYZ(chrono::ChVector3d(0, _pitch, 0));
    _apollo->SetRot(R);

    setInputDependencies({"dt", "Force_p", "Moment_p"});
    setOutputDependencies({"motion_r", "motion_drdt", "motion_ddrddt",
                           "motion_a", "motion_dadt", "motion_ddaddt",
                           "forces_r"});
};

void
setForce(std::shared_ptr<chrono::ChForce> var, vec4 value)
{
    chrono::ChVector3d v(value.x, value.y, value.z);
    if (v.IsNull()) {
        var->SetMforce(0.0);
    } else {
        const auto norm = v.Length();
        v.Scale(1.0 / norm);
        var->SetVrelpoint(chrono::ChVector3d(0, 0, 0));
        var->SetDir(v);
        var->SetMforce(norm);
    }
}

void
setVec(Aqua::InputOutput::Variable* var, chrono::ChVector3d value)
{
    vec4 v;
    v.x = value.x();
    v.y = value.y();
    v.z = value.z();
    v.w = 0.f;
    var->set(&v, true);
}

cl_event
ApolloSim::_execute(const std::vector<cl_event> UNUSED_PARAM events)
{
    auto vars = CalcServer::singleton()->variables();
    // Get the forces from AQUAgpusph
    float dt = *((float*)vars->get("dt")->get(true));
    const vec4 F = *((vec4*)vars->get("Force_p_iset")->get(true));
    const vec4 M = *((vec4*)vars->get("Moment_p_iset")->get(true));
    // Simulate the body motion
    setForce(_force, F);
    setForce(_moment, M);
    _sys->DoStepDynamics(dt);
    // Get the new position and angle
    const chrono::ChVector3d r = _apollo->GetPos();
    const chrono::ChVector3d drdt = _apollo->GetLinVel();
    const chrono::ChVector3d ddrddt = _apollo->GetLinAcc();
    const chrono::ChVector3d a = _apollo->GetRot().GetCardanAnglesXYZ();
    const chrono::ChVector3d dadt = _apollo->GetAngVelLocal();
    const chrono::ChVector3d ddaddt = _apollo->GetAngAccLocal();
    setVec(vars->get("motion_r"), r);
    setVec(vars->get("motion_drdt"), drdt);
    setVec(vars->get("motion_ddrddt"), ddrddt);
    setVec(vars->get("motion_a"), a);
    setVec(vars->get("motion_dadt"), dadt);
    setVec(vars->get("motion_ddaddt"), ddaddt);
    setVec(vars->get("forces_r"), r);
    return NULL;
}

}}  // namespaces

The code above is compiled with CMake:

find_package(Chrono)

if(NOT Chrono_FOUND)
    message(FATAL_ERROR "PROJECTCHRONO required")
endif(NOT Chrono_FOUND)
add_library(apollo_capsule_sim SHARED chronosim.cpp)
target_include_directories(apollo_capsule_sim PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CHRONO_INCLUDE_DIRS})
target_compile_options(apollo_capsule_sim PRIVATE ${CHRONO_CXX_FLAGS})
target_link_libraries(apollo_capsule_sim aquagpusph ${DEP_LIBS} ${CHRONO_LIBRARIES})
set_target_properties(apollo_capsule_sim PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})

which will produce the library file libapollo_capsule_sim.so, which can be loaded and executed within AQUAgpusph with the following XML element:

<Tool action="insert" before="some marker" name="chrono sim" type="installable" path="libapollo_capsule_sim.so" />

Note that on Windows the .dll file shall be provided. Look at the example source code itself for a more detailed recipe on how to compile and use the tool.