Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SofaSimulationCore] Clearer message when a linear solver is missing #2221

Merged
merged 4 commits into from
Jul 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,65 +33,13 @@ int BruteForceDetectionClass = core::RegisterObject(

void BruteForceDetection::init()
{
std::vector<std::string> broadPhaseComponents;
std::vector<std::string> narrowPhaseComponents;
findAllDetectionComponents(broadPhaseComponents, narrowPhaseComponents);

if (broadPhaseComponents.empty())
{
broadPhaseComponents.push_back(BruteForceBroadPhase::GetClass()->className);
}
if (narrowPhaseComponents.empty())
{
narrowPhaseComponents.push_back(BVHNarrowPhase::GetClass()->className);
}

const auto comma_fold = [](std::string a, std::string b)
{
return std::move(a) + ", " + std::move(b);
};

const std::string broadPhaseComponentsString = std::accumulate(
std::next(broadPhaseComponents.begin()), broadPhaseComponents.end(),
broadPhaseComponents[0],
comma_fold);

const std::string narrowPhaseComponentsString = std::accumulate(
std::next(narrowPhaseComponents.begin()), narrowPhaseComponents.end(),
narrowPhaseComponents[0],
comma_fold);
const std::string broadPhaseComponentsString = sofa::core::ObjectFactory::getInstance()->listClassesDerivedFrom<sofa::core::collision::BroadPhaseDetection>();
const std::string narrowPhaseComponentsString = sofa::core::ObjectFactory::getInstance()->listClassesDerivedFrom<sofa::core::collision::NarrowPhaseDetection>();

msg_deprecated() << "As a replacement, use a BroadPhase component, such as [" << broadPhaseComponentsString
<< "]," << msgendl
<< " AND a NarrowPhase component, such as [" << narrowPhaseComponentsString << "]." << msgendl
<< " " << BruteForceBroadPhase::GetClass()->className << " and " << BVHNarrowPhase::GetClass()->className << " have been automatically added to your scene for backward compatibility.";
}

void BruteForceDetection::findAllDetectionComponents(std::vector<std::string> &broadPhaseComponents,
std::vector<std::string> &narrowPhaseComponents)
{
std::vector<sofa::core::ObjectFactory::ClassEntry::SPtr> entries;
sofa::core::ObjectFactory::getInstance()->getAllEntries(entries);

for (const auto &entry : entries)
{
const auto creatorEntry = entry->creatorMap.begin();
if (creatorEntry != entry->creatorMap.end())
{
const sofa::core::objectmodel::BaseClass *baseClass = creatorEntry->second->getClass();
if (baseClass)
{
if (baseClass->hasParent(sofa::core::collision::BroadPhaseDetection::GetClass()))
{
broadPhaseComponents.push_back(baseClass->className);
}
if (baseClass->hasParent(sofa::core::collision::NarrowPhaseDetection::GetClass()))
{
narrowPhaseComponents.push_back(baseClass->className);
}
}
}
}
}

} // namespace sofa::component::collision
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,6 @@ class SOFA_SOFABASECOLLISION_API BruteForceDetection final : public sofa::core::
BruteForceDetection() = default;
~BruteForceDetection() override = default;

private:

void findAllDetectionComponents(std::vector<std::string>& broadPhaseComponents, std::vector<std::string>& narrowPhaseComponents);

};

} // namespace sofa::component::collision
47 changes: 47 additions & 0 deletions SofaKernel/modules/SofaCore/src/sofa/core/ObjectFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

#include <sofa/core/objectmodel/BaseObject.h>
#include <sofa/helper/NameDecoder.h>
#include <numeric>

namespace sofa
{
Expand Down Expand Up @@ -127,6 +128,14 @@ class SOFA_CORE_API ObjectFactory
/// Return the list of classes from a given target
std::string listClassesFromTarget(std::string target, std::string separator = ", ");

/// Fill the given vector with all the registered classes derived from BaseClass
template<class BaseClass>
void getEntriesDerivedFrom(std::vector<ClassEntry::SPtr>& result) const;

/// Return the list of classes derived from BaseClass as a string
template<class BaseClass>
std::string listClassesDerivedFrom(const std::string& separator = ", ") const;

/// Add an alias name for an already registered class
///
/// \param name name of the new alias
Expand Down Expand Up @@ -190,6 +199,44 @@ class SOFA_CORE_API ObjectFactory
void setCallback(OnCreateCallback cb) { m_callbackOnCreate = cb ; }
};

template<class BaseClass>
void ObjectFactory::getEntriesDerivedFrom(std::vector<ClassEntry::SPtr>& result) const
{
result.clear();
for (const auto& r : registry)
{
ClassEntry::SPtr entry = r.second;
// Push the entry only if it is not an alias
if (entry->className == r.first)
{
const auto creatorEntry = entry->creatorMap.begin();
if (creatorEntry != entry->creatorMap.end())
{
const auto* baseClass = creatorEntry->second->getClass();
if (baseClass && baseClass->hasParent(BaseClass::GetClass()))
{
result.push_back(entry);
}
}
}
}
}

template<class BaseClass>
std::string ObjectFactory::listClassesDerivedFrom(const std::string& separator) const
{
std::vector<ClassEntry::SPtr> entries;
getEntriesDerivedFrom<BaseClass>(entries);
if (entries.empty()) return std::string();

const auto join = [&separator](std::string a, ClassEntry::SPtr b)
{
return std::move(a) + separator + b->className;
};
return std::accumulate(std::next(entries.begin()), entries.end(),
entries.front()->className, join);
}

/**
* \brief Typed Creator class used to create instances of object type RealObject
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,18 +55,19 @@
#include <sofa/defaulttype/BaseMatrix.h>
#include <sofa/core/behavior/ConstraintSolver.h>

using namespace sofa::core;
namespace sofa
{
#include <sofa/core/ObjectFactory.h>

namespace simulation
{
#include <numeric>

namespace common
using namespace sofa::core;

namespace sofa::simulation::common
{

using namespace sofa::simulation::mechanicalvisitor;

std::map<core::objectmodel::BaseContext*, bool> MechanicalOperations::hasShownMissingLinearSolverMap;

MechanicalOperations::MechanicalOperations(const sofa::core::MechanicalParams* mparams, sofa::core::objectmodel::BaseContext* ctx, bool precomputedTraversalOrder)
:mparams(*mparams),ctx(ctx),executeVisitor(*ctx,precomputedTraversalOrder)
{
Expand Down Expand Up @@ -434,7 +435,7 @@ void MechanicalOperations::m_resetSystem()
LinearSolver* s = ctx->get<LinearSolver>(ctx->getTags(), BaseContext::SearchDown);
if (!s)
{
msg_error(ctx) << "Requires a LinearSolver.";
showMissingLinearSolverError();
return;
}
s->resetSystem();
Expand All @@ -445,7 +446,7 @@ void MechanicalOperations::m_setSystemMBKMatrix(SReal mFact, SReal bFact, SReal
LinearSolver* s = ctx->get<LinearSolver>(ctx->getTags(), BaseContext::SearchDown);
if (!s)
{
msg_error(ctx) << "Requires a LinearSolver.";
showMissingLinearSolverError();
return;
}
mparams.setMFactor(mFact);
Expand All @@ -459,7 +460,7 @@ void MechanicalOperations::m_setSystemRHVector(core::MultiVecDerivId v)
LinearSolver* s = ctx->get<LinearSolver>(ctx->getTags(), BaseContext::SearchDown);
if (!s)
{
msg_error(ctx) << "Requires a LinearSolver.";

return;
}
s->setSystemRHVector(v);
Expand All @@ -470,7 +471,7 @@ void MechanicalOperations::m_setSystemLHVector(core::MultiVecDerivId v)
LinearSolver* s = ctx->get<LinearSolver>(ctx->getTags(), BaseContext::SearchDown);
if (!s)
{
msg_error(ctx) << "Requires a LinearSolver.";
showMissingLinearSolverError();
return;
}
s->setSystemLHVector(v);
Expand All @@ -482,7 +483,7 @@ void MechanicalOperations::m_solveSystem()
LinearSolver* s = ctx->get<LinearSolver>(ctx->getTags(), BaseContext::SearchDown);
if (!s)
{
msg_error(ctx) << "Requires a LinearSolver.";
showMissingLinearSolverError();
return;
}
s->solveSystem();
Expand All @@ -493,7 +494,7 @@ void MechanicalOperations::m_print( std::ostream& out )
LinearSolver* s = ctx->get<LinearSolver>(ctx->getTags(), BaseContext::SearchDown);
if (!s)
{
msg_error(ctx) << "Requires a LinearSolver.";
showMissingLinearSolverError();
return;
}
defaulttype::BaseMatrix* m = s->getSystemBaseMatrix();
Expand Down Expand Up @@ -581,8 +582,16 @@ void MechanicalOperations::printWithElapsedTime( core::ConstMultiVecId /*v*/, un
{
}

}

void MechanicalOperations::showMissingLinearSolverError() const
{
if (!hasShownMissingLinearSolverMap[ctx])
{
const auto solvers = sofa::core::ObjectFactory::getInstance()->listClassesDerivedFrom<sofa::core::behavior::BaseLinearSolver>();
msg_error(ctx) << "A linear solver is required, but has not been found. Add a linear solver to your scene to "
"fix this issue. The list of available linear solver components "
"is: [" << solvers << "].";
hasShownMissingLinearSolverMap[ctx] = true;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,12 @@ class SOFA_SIMULATION_CORE_API MechanicalOperations
void setDf(core::MultiVecDerivId& v);
void setDf(core::ConstMultiVecDerivId& v);

/// Warn the user that a linear solver is required but has not been found
void showMissingLinearSolverError() const;

/// Store if the "missing linear solver" error message has already been shown for a given context
static std::map<core::objectmodel::BaseContext*, bool> hasShownMissingLinearSolverMap;

};

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,66 +31,15 @@ namespace sofa::component::collision

void DirectSAP::init()
{
std::vector<std::string> broadPhaseComponents;
std::vector<std::string> narrowPhaseComponents;
findAllDetectionComponents(broadPhaseComponents, narrowPhaseComponents);

if (broadPhaseComponents.empty())
{
broadPhaseComponents.push_back(BruteForceBroadPhase::GetClass()->className);
}
if (narrowPhaseComponents.empty())
{
narrowPhaseComponents.push_back(DirectSAPNarrowPhase::GetClass()->className);
}

const auto comma_fold = [](std::string a, std::string b)
{
return std::move(a) + ", " + std::move(b);
};

const std::string broadPhaseComponentsString = std::accumulate(
std::next(broadPhaseComponents.begin()), broadPhaseComponents.end(),
broadPhaseComponents[0],
comma_fold);

const std::string narrowPhaseComponentsString = std::accumulate(
std::next(narrowPhaseComponents.begin()), narrowPhaseComponents.end(),
narrowPhaseComponents[0],
comma_fold);
const std::string broadPhaseComponentsString = sofa::core::ObjectFactory::getInstance()->listClassesDerivedFrom<sofa::core::collision::BroadPhaseDetection>();
const std::string narrowPhaseComponentsString = sofa::core::ObjectFactory::getInstance()->listClassesDerivedFrom<sofa::core::collision::NarrowPhaseDetection>();

msg_deprecated() << "As a replacement, use a BroadPhase component such as [" << broadPhaseComponentsString << "] " << msgendl
<< " AND a NarrowPhase component such as [" << narrowPhaseComponentsString << "]." << msgendl
<< " " << BruteForceBroadPhase::GetClass()->className << " and " << DirectSAPNarrowPhase::GetClass()->className
<< " have been automatically added to your scene for backward compatibility.";
}

void DirectSAP::findAllDetectionComponents(std::vector<std::string> &broadPhaseComponents,
std::vector<std::string> &narrowPhaseComponents)
{
std::vector<sofa::core::ObjectFactory::ClassEntry::SPtr> entries;
sofa::core::ObjectFactory::getInstance()->getAllEntries(entries);

for (const auto &entry : entries)
{
const auto creatorEntry = entry->creatorMap.begin();
if (creatorEntry != entry->creatorMap.end())
{
const sofa::core::objectmodel::BaseClass *baseClass = creatorEntry->second->getClass();
if (baseClass)
{
if (baseClass->hasParent(sofa::core::collision::BroadPhaseDetection::GetClass()))
{
broadPhaseComponents.push_back(baseClass->className);
}
if (baseClass->hasParent(sofa::core::collision::NarrowPhaseDetection::GetClass()))
{
narrowPhaseComponents.push_back(baseClass->className);
}
}
}
}
}
} // namespace sofa::component::collision


Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,6 @@ class SOFA_SOFAGENERALMESHCOLLISION_API DirectSAP final : public sofa::core::obj
DirectSAP() = default;
~DirectSAP() override = default;

private:

void findAllDetectionComponents(std::vector<std::string>& broadPhaseComponents, std::vector<std::string>& narrowPhaseComponents);

};

} // namespace sofa::component::collision
Loading