Author: Lukas Breitwieser
This tutorial demonstrates how to replace BioDynaMo's default interaction force with a user-defined one.
The interaction force is used to calculate forces between agent pairs that are in physical contact with each other.
Let's start by setting up BioDynaMo notebooks.
%jsroot on
gROOT->LoadMacro("${BDMSYS}/etc/rootlogon.C");
INFO: Created simulation object 'simulation' with UniqueName='simulation'.
#include "core/operation/mechanical_forces_op.h"
We modify the simulation_max_displacement
parameter to better visualize the difference of the user-defined force that we will add.
auto set_param = [](Param* p) {
p->simulation_max_displacement = 50;
};
Simulation simulation("my-simulation", set_param);
In our experiment we create two overlapping cells and visualize the starting condition.
void Experiment() {
simulation.GetResourceManager()->ClearAgents();
auto* ctxt = simulation.GetExecutionContext();
auto* scheduler = simulation.GetScheduler();
auto* cell1 = new Cell({0, 0, 0});
auto* cell2 = new Cell({10, 0, 0});
cell1->SetDiameter(20);
cell2->SetDiameter(20);
cell1->SetMass(0.1);
cell2->SetMass(0.1);
ctxt->AddAgent(cell1);
ctxt->AddAgent(cell2);
scheduler->FinalizeInitialization();
VisualizeInNotebook();
}
Let's run our experiment and have a look at the visualization.
Experiment();
We continue by simulating 10 iterations and observe how the mechanical force pushed the two cells away from each other, until they don't overlap anymore.
auto* scheduler = simulation.GetScheduler();
scheduler->Simulate(10);
VisualizeInNotebook();
Now we want to add our user-defined force implementation.
First, we have to subclass InteractionForce
and implement our force.
In this case, it is an extremely simple (and unrealistic) implementation.
class MyInteractionForce : public InteractionForce {
public:
MyInteractionForce() {}
virtual ~MyInteractionForce() {}
Real4 Calculate(const Agent* lhs, const Agent* rhs) const override {
if (lhs < rhs) {
return {100, 0, 0, 0};
} else {
return {-100, 0, 0, 0};
}
}
InteractionForce* NewCopy() const override { return new MyInteractionForce(); }
};
With the following three lines we instruct BioDynaMo to use our new MyInteractionForce
instead of the default implementation.
auto* myforce = new MyInteractionForce();
auto* op = scheduler->GetOps("mechanical forces")[0];
op->GetImplementation<MechanicalForcesOp>()->SetInteractionForce(myforce);
We create the same starting condition as before.
Experiment();
Because myforce
is so strong, it is sufficient to simulate only one iteration to clearly see its impact.
auto* scheduler = simulation.GetScheduler();
scheduler->Simulate(1);
VisualizeInNotebook();