SOFA, sprint 2025
Informations
Details
| Role | Info |
|---|---|
| Product owner | Paul Baksic |
| Scrum master | Paul Baksic |
| first meeting with team | 2025/04/09 |
| second meeting with team | 2025/05/07 |
| sprint dates | 2025/05/12 - 2025/05/15 |
The sprint will be held in a hybrid mode with part of the team in Strasbourg and the rest in Nancy.
Tasks
1) Deployement of the template method pattern in SOFA
A concept has been introduced in SOFA for some times now : the component state. It defines the current state of the object during the simulation. It is taken from the following enum :
enum class ComponentState {
Undefined, ///< default value
Loading, ///< the component never passed successfully its init()
Valid, ///< the component has passed successfully its init()
Dirty, ///< the component is ready but requires a call to reinit()
Busy, ///< the component is doing "something", don't trust its values
Invalid ///< the component reached an error and cannot behave normally.
};This is important for application where crash is forbidden (e.g. robotics). But to enable this safety, the template method pattern needs to be applied to the whole API (currently only some component have implemented this).
Let’s say we’ve got this base class
class BaseForceField : public BaseObject
{
public:
BaseForceField() = default;
virtual void init() = 0;
virtual void applyForces() = 0;
}Here the method applyForces() will be called by the API and is expected to be overridden, same for the init method. What is currently expected from the dev to do is the following:
class MySuperForceField : public BaseForceField
{
public:
MySuperForceField() = default;
virtual void init() override
{
d_componentState.setValue(ComponentState::Loading);
/** Do stuff **/
if(wentRight)
d_componentState.setValue(ComponentState::Valid);
else
d_componentState.setValue(ComponentState::Invalid);
return;
}
virtual void applyForces()
{
if(!componentStateIsValid())
return;
/** Do stuff **/
}
}But this is rarely done correctly so we need to change the API to force this pattern to be enforced.
Issues to be addressed
The application of the template method pattern on the entire codebase will help homogenizing the use of the d_componentState, thus easing API updates:
class BaseForceField : public BaseObject
{
public:
BaseForceField() = default;
virtual void init() final
{
d_componentState.setValue(ComponentState::Loading);
d_componentState.setValue(this->doInit());
}
virtual void applyForces() final
{
if(!this->componentStateIsValid())
return;
this->doApplyForces();
}
virtual ComponentState doInit() = 0;
virtual void doApplyForces() = 0;
}This will simply require to modify the name of existing overriding of the base method by a doXX() method, and adding the good return type for init methods. This doesn’t require lots of C++ skills. the debugging of the PR will then require some more skills.
Deliverables
- Multiple PRs (one per virtual class) integrating the changes required to implement the pattern for all API methods. This task can be performed in parallel on the various Base classes (on their
init()+ API-specific functions) - Correction of unit tests
- (optional) Correction of scene-related tests (scene-tests and regression-tests)
Initial state:
class BaseClassSomething : public BaseObject
{
public:
BaseClassSomething() = default;
virtual T functionName(Args... args) = 0;
}
class ChildClassSomething : public BaseClassSomething
{
public:
ChildClassSomething() = default;
virtual T functionName(Args... args) override
{
//Do stuff
}
}What is expected in PR:
class BaseClassSomething : public BaseObject
{
public:
BaseClassSomething() = default;
/**
* !!! WARNING since v25.12 !!!
*
* The template method pattern has been applied to this part of the API.
* This method calls the newly introduced method "doFunctionName" internally,
* which is the method to override from now on.
*
**/
virtual T functionName(Args... args) final
{
//TODO (SPRINT SED 2025): Component state mechanism
return this->doFunctionName(args...);
}
protected:
virtual T doFunctionName(Args... args) = 0;
}
class ChildClassSomething : public BaseClassSomething
{
public:
ChildClassSomething() = default;
protected:
virtual T doFunctionName(Args... args) override
{
//Do stuff
}
}Team
| Person | Availability |
|---|---|
| Hugo Talbot | 80% |
| Théo Biasutto-Levrat | 80% |
| Olivier Rochel | 100% |
| Paul Breugnot | 100% |
| Benjamin Loillier | 100% |
Work done
Here are the PRs done by the team member during the sprint
- BaseAnimationLoop [name=Theo] #5434
- BaseConstraintCorrection [name=Paul Baksic] #5444
- BaseConstraintSet [name=Paul Baksic] #5478
- BaseLoader [name=Paul Br.] #5454
- BaseMapping [name=Paul Baksic] #5466
- BaseMaterial [name=Theo] #5439
- BaseMatrixLinearSystem [name=Theo] #5473
- BaseOrderingMethod [name=Theo] #5452 + Sofa.Metis #10
- BaseRotationFinder [name=Olivier] #5435
- BaseSimulationExporter [name=Benjamin] #5436
- BaseState [name=Olivier] #5453
- BaseVisualStyle [name=Benjamin] #5441
- BehaviorModel [name=Benjamin] #5443 + PluginExample #16
- CollisionModel [name=Benjamin] #5481
- ConstraintSolver [name=Olivier] #5457
- Contact [name=Theo] #5456 + Registration #24
- ContextObject [name=Theo] #5463
- Intersection [name=Paul Br] #5455
- OdeSolver [name=Olivier] #5462
- Pipeline [name=Paul Baksic] #5433
- Shader [name=Benjamin] #5459
- BaseForceField [name=Hugo] #5485
- BaseMass [name=Hugo] #5446
- BaseMatrixProjectionMethod [name=Olivier] #5465
- BaseProjectiveConstraintSet [name=Paul Br] #5477
- TopologicalMapping [name=Benjamin] #5468
- Topology [name=Benjamin] #5464
- CollisionAlgorithm [name=Olivier] #5476
- VisualModel [name=Paul Baksic] #5470
- BaseCamera [name=Benjamin] #5471
2) Dasboard for plugins
SOFA has been a huge block of code for a long time. This was mainly due to extensions (that we call plugins) added inside the main project to enable easy in-tree compilation. But with new CMake features such as the ability to clone repository and add them as subproject during the CMake call, this is neither mandatory, nor wanted anymore. We have therefore “pluginized” a lot of them, putting them in their own repository.
The problem is now that modification of those plugins are done inside their own PRs, and might break the main project (where we still build all plugins in-tree). Plus, the out-of-tree compilation of those plugin might be broken from main project modifications. Even if they all have their own CI enforcing the project health, we need a way to have a “one glance” check to know if and which plugin is broken, and what is broken (compilation, tests, packaging).
Work
The work is divided in two phases:
- Implementation of a rest API to publish data from plugins
- Implementation of a frontend allowing for a quick glance update of the CI status of more than 20 plugins.
The dashboard requirements are very light. In term of front end, we expect a X by Y matrix of squares containing formatted informations :
- Plugin name with hyperlink to the github action url passed as “url” in the request
- Date when the request has been recieved
- three line containing the boolean information recieved, displayed in the form of
ok/failed - A color depending on the results and the age of the information:
- “Green” :
(build & tests & binary) & (age < 2 weeks) - “Orange” :
(build & (~tests | ~binary)) & (age < 2 weeks) - “Red” :
~build & (age < 2 weeks) - “Gray” :
age > 2 weeks
Plugin CI will send a request at the end of a nightly-build with update information in the following shape :
{"id":"string:PluginName",
"url":"string:GithubActionRunURL",
"build":"boolean",
"tests":"boolean",
"binary":"boolean"}The dashboard will only keep the most recent update recieved for each plugin (with a forgetting time of 2 months)
Deliverables
- The dashboard in production on a server (might be an existing server such as sofa-framework.org)
- Documentation to take ownership on it
Team
| Person | Availability |
|---|---|
| Bertrand Wallrich | 100% (took only two days) |
| Frederick Beck | 100% (took only two days) |
Work done
- REST API to publish [name=Frederick]
- Front end for visualization [name=Bertrand]
- Deployement of dockerized dashboard on sofa-framework.org server : https://sofa-framework.org:5000/dashboard [name=Frederick]