further distinguish between rotation and translation solving

This commit is contained in:
Stefan Tröger 2013-12-21 16:19:54 +01:00
parent ee5d3be3cc
commit 81ccdeb331
20 changed files with 363 additions and 268 deletions

View File

@ -165,8 +165,16 @@ void Constraint::init(Assembly::ItemAssembly* ass)
};
//all other constraints need poth parts
if(!part1 || !part2)
if(!part1 || !part2) {
Base::Console().Message("Geometry initialisation error: invalid parts\n");
return;
};
//and both geometries
if(!m_first_geom || !m_second_geom) {
Base::Console().Message("Geometry initialisation error: invalid geometries\n");
return;
};
//we may need the orientation
dcm::Direction dir;

View File

@ -49,6 +49,10 @@ ItemAssembly::ItemAssembly() {
ADD_PROPERTY(Items,(0));
ADD_PROPERTY(Annotations,(0));
ADD_PROPERTY(Rigid,(true));
#ifdef ASSEMBLY_DEBUG_FACILITIES
ADD_PROPERTY(ApplyAtFailure,(false));
ADD_PROPERTY(Precision,(1e-6));
#endif
}
short ItemAssembly::mustExecute() const {
@ -66,6 +70,15 @@ App::DocumentObjectExecReturn* ItemAssembly::execute(void) {
m_downstream_placement = Base::Placement(Base::Vector3<double>(0,0,0), Base::Rotation());
Base::Placement dummy;
initSolver(boost::shared_ptr<Solver>(), dummy, false);
#ifdef ASSEMBLY_DEBUG_FACILITIES
if(ApplyAtFailure.getValue())
m_solver->setOption<dcm::solverfailure>(dcm::ApplyResults);
else
m_solver->setOption<dcm::solverfailure>(dcm::IgnoreResults);
m_solver->setOption<dcm::precision>(Precision.getValue());
#endif
initConstraints(boost::shared_ptr<Solver>());
//solve the system
@ -213,9 +226,12 @@ void ItemAssembly::initSolver(boost::shared_ptr<Solver> parent, Base::Placement&
if(parent) {
if(Rigid.getValue() || stopped) {
m_solver = boost::shared_ptr<Solver>(parent->createSubsystem());
m_solver = parent->createSubsystem();
m_solver->setTransformation(this->Placement.getValue());
stopped = true; //all below belongs to this rigid group
//connect the recalculated signal in case we need to update the placement
m_solver->connectSignal<dcm::recalculated>(boost::bind(&ItemAssembly::finish, this, _1));
}
else {
m_solver = parent;
@ -223,14 +239,9 @@ void ItemAssembly::initSolver(boost::shared_ptr<Solver> parent, Base::Placement&
m_downstream_placement = PL_downstream;
}
}
//connect the recalculated signal in case we need to update the placement
m_solver->connectSignal<dcm::recalculated>(boost::bind(&ItemAssembly::finish, this, _1));
typedef std::vector<App::DocumentObject*>::const_iterator iter;
const std::vector<App::DocumentObject*>& vector = Items.getValues();
for(iter it=vector.begin(); it != vector.end(); it++) {
if((*it)->getTypeId() == Assembly::ItemAssembly::getClassTypeId()) {

View File

@ -78,6 +78,12 @@ public:
boost::shared_ptr<Solver> m_solver;
Base::Placement m_downstream_placement;
#ifdef ASSEMBLY_DEBUG_FACILITIES
App::PropertyBool ApplyAtFailure;
App::PropertyFloat Precision;
#endif
private:
std::stringstream message;
};

View File

@ -26,5 +26,3 @@ int ItemAssemblyPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
{
return 0;
}

View File

@ -111,7 +111,7 @@ protected:
int equationCount();
void calculate(Scalar scale, bool rotation_only = false);
void calculate(Scalar scale, AccessType access = general);
void treatLGZ();
void setMaps(MES& mes);
void collectPseudoPoints(Vec& vec1, Vec& vec2);
@ -128,7 +128,8 @@ protected:
typename Kernel::VectorMap m_diff_second, m_diff_second_rot; //second geometry diff
typename Kernel::VectorMap m_residual;
bool pure_rotation, enabled;
bool enabled;
AccessType access;
typedef Equation eq_type;
};
@ -136,7 +137,7 @@ protected:
struct placeholder {
virtual ~placeholder() {}
virtual placeholder* resetConstraint(geom_ptr first, geom_ptr second) const = 0;
virtual void calculate(geom_ptr first, geom_ptr second, Scalar scale, bool rotation_only = false) = 0;
virtual void calculate(geom_ptr first, geom_ptr second, Scalar scale, AccessType access = general) = 0;
virtual void treatLGZ(geom_ptr first, geom_ptr second) = 0;
virtual int equationCount() = 0;
virtual void setMaps(MES& mes, geom_ptr first, geom_ptr second) = 0;
@ -199,9 +200,9 @@ public:
geom_ptr first, second;
Scalar scale;
bool rot_only;
AccessType access;
Calculater(geom_ptr f, geom_ptr s, Scalar sc, bool rotation_only = false);
Calculater(geom_ptr f, geom_ptr s, Scalar sc, AccessType a = general);
template< typename T >
void operator()(T& val) const;
@ -285,7 +286,7 @@ public:
holder(Objects& obj);
virtual void calculate(geom_ptr first, geom_ptr second, Scalar scale, bool rotation_only = false);
virtual void calculate(geom_ptr first, geom_ptr second, Scalar scale, AccessType a = general);
virtual void treatLGZ(geom_ptr first, geom_ptr second);
virtual placeholder* resetConstraint(geom_ptr first, geom_ptr second) const;
virtual void setMaps(MES& mes, geom_ptr first, geom_ptr second);

View File

@ -147,7 +147,7 @@ struct pushed_seq {
typedef constraint_sequence<vec> type;
};*/
template<typename Derived, typename Option, int id, bool rotation_only = false>
template<typename Derived, typename Option, int id, AccessType a = general>
struct Equation : public EQ {
typedef typename mpl::if_<mpl::is_sequence<Option>, Option, mpl::vector<Option> >::type option_sequence;
@ -155,11 +155,11 @@ struct Equation : public EQ {
typedef typename fusion::result_of::as_map<option_set_map>::type options;
options values;
bool pure_rotation;
AccessType access;
typedef mpl::int_<id> ID;
Equation() : pure_rotation(rotation_only) {};
Equation() : access(a) {};
//assign option
template<typename T>
@ -271,7 +271,7 @@ struct Distance : public Equation<Distance, mpl::vector2<double, SolutionSpace>,
};
};
struct Orientation : public Equation<Orientation, Direction, 2, true> {
struct Orientation : public Equation<Orientation, Direction, 2, rotation> {
using Equation::operator=;
using Equation::options;
@ -337,7 +337,7 @@ struct Orientation : public Equation<Orientation, Direction, 2, true> {
};
};
struct Angle : public Equation<Angle, mpl::vector2<double, SolutionSpace>, 3, true> {
struct Angle : public Equation<Angle, mpl::vector2<double, SolutionSpace>, 3, rotation> {
using Equation::operator=;

View File

@ -50,7 +50,7 @@ Constraint<Sys, Dim>::holder<ConstraintVector, tag1, tag2>::OptionSetter::operat
typedef typename mpl::distance<typename mpl::begin<EquationVector>::type, iterator>::type distance;
BOOST_MPL_ASSERT((mpl::not_<boost::is_same<iterator, typename mpl::end<EquationVector>::type > >));
fusion::copy(fusion::at<distance>(objects).values, val.m_eq.values);
val.pure_rotation = fusion::at<distance>(objects).pure_rotation;
val.access = fusion::at<distance>(objects).access;
};
template<typename Sys, int Dim>
@ -58,13 +58,15 @@ template<typename ConstraintVector, typename tag1, typename tag2>
template<typename T>
typename boost::enable_if<mpl::not_<typename Constraint<Sys, Dim>::template holder<ConstraintVector, tag1, tag2>::template has_option<T>::type>, void>::type
Constraint<Sys, Dim>::holder<ConstraintVector, tag1, tag2>::OptionSetter::operator()(EquationSet<T>& val) const {
typedef typename mpl::find<EquationVector, T>::type iterator;
typedef typename mpl::distance<typename mpl::begin<EquationVector>::type, iterator>::type distance;
val.access = fusion::at<distance>(objects).access;
};
template<typename Sys, int Dim>
template<typename ConstraintVector, typename tag1, typename tag2>
Constraint<Sys, Dim>::holder<ConstraintVector, tag1, tag2>::Calculater::Calculater(geom_ptr f, geom_ptr s, Scalar sc, bool rotation_only)
: first(f), second(s), scale(sc), rot_only(rotation_only) {
Constraint<Sys, Dim>::holder<ConstraintVector, tag1, tag2>::Calculater::Calculater(geom_ptr f, geom_ptr s, Scalar sc, AccessType a)
: first(f), second(s), scale(sc), access(a) {
};
@ -77,8 +79,9 @@ void Constraint<Sys, Dim>::holder<ConstraintVector, tag1, tag2>::Calculater::ope
if(!val.enabled)
return;
//if we only need pure rotational functions and we are not such a nice thing, everything becomes 0
if(rot_only && !val.pure_rotation) {
//if we are not one of the accessed types we dont need to be recalculated
if((access==rotation && val.access!=rotation)
|| (access == general && val.access != general)) {
val.m_residual(0) = 0;
if(first->getClusterMode()) {
@ -171,7 +174,8 @@ void Constraint<Sys, Dim>::holder<ConstraintVector, tag1, tag2>::MapSetter::oper
//when in cluster, there are 6 clusterparameter we differentiat for, if not we differentiat
//for every parameter in the geometry;
int equation = mes.setResidualMap(val.m_residual);
int equation = mes.setResidualMap(val.m_residual, val.access);
if(first->getClusterMode()) {
if(!first->isClusterFixed()) {
mes.setJacobiMap(equation, first->m_offset_rot, 3, val.m_diff_first_rot);
@ -350,8 +354,8 @@ Constraint<Sys, Dim>::holder<ConstraintVector, tag1, tag2>::holder(Objects& obj)
template<typename Sys, int Dim>
template<typename ConstraintVector, typename tag1, typename tag2>
void Constraint<Sys, Dim>::holder<ConstraintVector, tag1, tag2>::calculate(geom_ptr first, geom_ptr second,
Scalar scale, bool rotation_only) {
fusion::for_each(m_sets, Calculater(first, second, scale, rotation_only));
Scalar scale, AccessType access) {
fusion::for_each(m_sets, Calculater(first, second, scale, access));
};
template<typename Sys, int Dim>

View File

@ -159,8 +159,8 @@ int Constraint<Sys, Dim>::equationCount() {
};
template<typename Sys, int Dim>
void Constraint<Sys, Dim>::calculate(Scalar scale, bool rotation_only) {
content->calculate(first, second, scale, rotation_only);
void Constraint<Sys, Dim>::calculate(Scalar scale, AccessType access) {
content->calculate(first, second, scale, access);
};
template<typename Sys, int Dim>

View File

@ -130,8 +130,8 @@ struct option_copy {
};
};
template<typename Derived, typename Option, int id, bool rotation_only >
Derived& Equation<Derived, Option, id, rotation_only>::assign(const Derived& eq) {
template<typename Derived, typename Option, int id, AccessType a >
Derived& Equation<Derived, Option, id, a>::assign(const Derived& eq) {
//we only copy the values which were set and are therefore valid
option_copy<options> oc(values);
@ -144,10 +144,10 @@ Derived& Equation<Derived, Option, id, rotation_only>::assign(const Derived& eq)
};
/*
template<typename Derived, typename Option, int id, bool rotation_only >
template<typename Derived, typename Option, int id, AccessType a >
template<typename T>
typename boost::enable_if< boost::is_base_of< dcm::EQ, T>, typename pushed_seq<T, Derived>::type >::type
Equation<Derived, Option, id, rotation_only>::operator &(T& val) {
Equation<Derived, Option, id, a>::operator &(T& val) {
typename pushed_seq<T, Derived>::type vec;
*fusion::find<T>(vec) = val;
@ -155,10 +155,10 @@ Equation<Derived, Option, id, rotation_only>::operator &(T& val) {
return vec;
};
template<typename Derived, typename Option, int id, bool rotation_only >
template<typename Derived, typename Option, int id, AccessType a >
template<typename T>
typename boost::enable_if< mpl::is_sequence<T>, typename pushed_seq<T, Derived>::type >::type
Equation<Derived, Option, id, rotation_only>::operator &(T& val) {
Equation<Derived, Option, id, a>::operator &(T& val) {
typedef typename pushed_seq<T, Derived>::type Sequence;
@ -182,8 +182,8 @@ Equation<Derived, Option, id, rotation_only>::operator &(T& val) {
};
*/
template<typename Derived, typename Option, int id, bool rotation_only >
void Equation<Derived, Option, id, rotation_only>::setDefault() {
template<typename Derived, typename Option, int id, AccessType a >
void Equation<Derived, Option, id, a>::setDefault() {
fusion::at_key<double>(values) = std::make_pair(false, 0.);
fusion::at_key<SolutionSpace>(values) = std::make_pair(false, bidirectional);
};

View File

@ -22,6 +22,7 @@
#include "../kernel.hpp"
#include <boost/math/special_functions.hpp>
#include <Eigen/QR>
namespace dcm {
@ -58,8 +59,10 @@ void Dogleg<Kernel>::calculateStep(const Eigen::MatrixBase<Derived>& g, const Ei
const typename Kernel::Vector h_sd = -g;
// get the gauss-newton step
const typename Kernel::Vector h_gn = (jacobi).fullPivLu().solve(-residual);
const typename Kernel::Vector h_gn = jacobi.fullPivLu().solve(-residual);
const double eigen_error = (jacobi*h_gn + residual).norm();
#ifdef USE_LOGGING
BOOST_LOG(log)<< "Gauss Newton error: "<<eigen_error;
if(!boost::math::isfinite(h_gn.norm())) {
BOOST_LOG(log)<< "Unnormal gauss-newton detected: "<<h_gn.norm();
@ -78,6 +81,9 @@ void Dogleg<Kernel>::calculateStep(const Eigen::MatrixBase<Derived>& g, const Ei
// compute the dogleg step
if(h_gn.norm() <= delta) {
h_dl = h_gn;
#ifdef USE_LOGGING
BOOST_LOG(log)<< "Gauss Newton Step: "<<eigen_error;
#endif
}
else if((alpha*h_sd).norm() >= delta) {
//h_dl = alpha*h_sd;
@ -88,6 +94,8 @@ void Dogleg<Kernel>::calculateStep(const Eigen::MatrixBase<Derived>& g, const Ei
BOOST_LOG(log)<< "Unnormal dogleg descent detected: "<<h_dl.norm();
}
BOOST_LOG(log)<< "Steepest Descend step";
#endif
}
else {
@ -123,12 +131,23 @@ void Dogleg<Kernel>::calculateStep(const Eigen::MatrixBase<Derived>& g, const Ei
BOOST_LOG(log)<< "Unnormal dogleg beta detected: "<<beta;
}
BOOST_LOG(log)<< "Dogleg Step";
#endif
}
};
template<typename Kernel>
void Dogleg<Kernel>::init(typename Kernel::MappedEquationSystem& sys) {
int Dogleg<Kernel>::solve(typename Kernel::MappedEquationSystem& sys) {
nothing n;
return solve(sys, n);
};
template<typename Kernel>
template<typename Functor>
int Dogleg<Kernel>::solve(typename Kernel::MappedEquationSystem& sys, Functor& rescale) {
clock_t start = clock();
if(!sys.isValid())
throw solving_error() << boost::errinfo_errno(5) << error_message("invalid equation system");
@ -141,7 +160,9 @@ void Dogleg<Kernel>::init(typename Kernel::MappedEquationSystem& sys) {
#ifdef USE_LOGGING
BOOST_LOG(log)<< "initial jacobi: "<<std::endl<<sys.Jacobi<<std::endl
<< "residual: "<<sys.Residual.transpose()<<std::endl
<< "maximal differential: "<<sys.Jacobi.template lpNorm<Eigen::Infinity>();
<< "maximal differential: "<<sys.Jacobi.template lpNorm<Eigen::Infinity>()
<< std::endl<<"Real Jacobi: "<<sys.m_jacobi<<std::endl
<< "Real residual: "<<sys.m_residual.transpose()<<std::endl;
#endif
sys.removeLocalGradientZeros();
@ -168,22 +189,6 @@ void Dogleg<Kernel>::init(typename Kernel::MappedEquationSystem& sys) {
reduce=0;
unused=0;
counter=0;
};
template<typename Kernel>
int Dogleg<Kernel>::solve(typename Kernel::MappedEquationSystem& sys, bool continuous) {
nothing n;
return solve(sys, n, continuous);
};
template<typename Kernel>
template<typename Functor>
int Dogleg<Kernel>::solve(typename Kernel::MappedEquationSystem& sys, Functor& rescale, bool continuous) {
clock_t start = clock();
if(!sys.isValid())
throw solving_error() << boost::errinfo_errno(5) << error_message("invalid equation system");
int maxIterNumber = 5000;//MaxIterations * xsize;
number_type diverging_lim = 1e6*err + 1e12;
@ -216,8 +221,16 @@ int Dogleg<Kernel>::solve(typename Kernel::MappedEquationSystem& sys, Functor& r
//get the update step
calculateStep(g, sys.Jacobi, sys.Residual, h_dl, delta);
#ifdef USE_LOGGING
BOOST_LOG(log)<<"Step in iter "<<iter<<std::endl
<< "Step: "<<h_dl.transpose()<<std::endl
<< "Jacobi: "<<sys.Jacobi<<std::endl
<< "Real Jacobi: "<<sys.m_jacobi<<std::endl
<< "Residual: "<<F_old.transpose()<<std::endl;
#endif
// calculate the linear model
dL = 0.5*sys.Residual.norm() - 0.5*(sys.Residual + sys.Jacobi*h_dl).norm();
dL = sys.Residual.norm() - (sys.Residual + sys.Jacobi*h_dl).norm();
// get the new values
sys.Parameter += h_dl;
@ -253,6 +266,11 @@ int Dogleg<Kernel>::solve(typename Kernel::MappedEquationSystem& sys, Functor& r
nu = 2*nu;
}
#ifdef USE_LOGGING
BOOST_LOG(log)<<"Result of step dF: "<<dF<<", dL: "<<dL<<std::endl
<< "New Residual: "<< sys.Residual.transpose()<<std::endl;
#endif
if(dF > 0 && dL > 0) {
//see if we got too high differentials
@ -279,22 +297,21 @@ int Dogleg<Kernel>::solve(typename Kernel::MappedEquationSystem& sys, Functor& r
// get infinity norms
g_inf = g.template lpNorm<E::Infinity>();
fx_inf = sys.Residual.template lpNorm<E::Infinity>();
}
else {
#ifdef USE_LOGGING
BOOST_LOG(log)<< "Reject step in iter "<<iter<<", dF: "<<dF<<", dL: "<<dL;
#endif
sys.Residual = F_old;
sys.Jacobi = J_old;
sys.Parameter -= h_dl;
unused++;
#ifdef USE_LOGGING
BOOST_LOG(log)<< "Reject step in iter "<<iter;
#endif
}
iter++;
counter++;
}
while(!stop && continuous);
while(!stop);
clock_t end = clock();
@ -320,27 +337,29 @@ int Kernel<Scalar, Nonlinear>::MappedEquationSystem::equationCount() {
};
template<typename Scalar, template<class> class Nonlinear>
bool Kernel<Scalar, Nonlinear>::MappedEquationSystem::rotationOnly() {
return rot_only;
AccessType Kernel<Scalar, Nonlinear>::MappedEquationSystem::access() {
return m_access;
};
template<typename Scalar, template<class> class Nonlinear>
Kernel<Scalar, Nonlinear>::MappedEquationSystem::MappedEquationSystem(int params, int equations)
: rot_only(false), m_jacobi(equations, params),
m_parameter(params), Residual(equations),
: m_access(general), m_jacobi(equations, params),
m_parameter(params), m_residual(equations),
m_params(params), m_eqns(equations), Scaling(1.),
Jacobi(&m_jacobi(0,0),equations,params,DynStride(equations,1)),
Parameter(&m_parameter(0),params,DynStride(1,1)) {
Parameter(&m_parameter(0),params,DynStride(1,1)),
Residual(&m_residual(0),equations,DynStride(1,1)) {
m_param_rot_offset = 0;
m_param_trans_offset = params;
m_eqn_offset = 0;
m_eqn_rot_offset = 0;
m_eqn_trans_offset = equations;
m_jacobi.setZero(); //important as some places are never written
};
template<typename Scalar, template<class> class Nonlinear>
int Kernel<Scalar, Nonlinear>::MappedEquationSystem::setParameterMap(int number, VectorMap& map, ParameterType t) {
int Kernel<Scalar, Nonlinear>::MappedEquationSystem::setParameterMap(int number, VectorMap& map, AccessType t) {
if(t == rotation) {
new(&map) VectorMap(&m_parameter(m_param_rot_offset), number, DynStride(1,1));
@ -355,7 +374,7 @@ int Kernel<Scalar, Nonlinear>::MappedEquationSystem::setParameterMap(int number,
};
template<typename Scalar, template<class> class Nonlinear>
int Kernel<Scalar, Nonlinear>::MappedEquationSystem::setParameterMap(Vector3Map& map, ParameterType t) {
int Kernel<Scalar, Nonlinear>::MappedEquationSystem::setParameterMap(Vector3Map& map, AccessType t) {
if(t == rotation) {
new(&map) Vector3Map(&m_parameter(m_param_rot_offset));
@ -370,9 +389,16 @@ int Kernel<Scalar, Nonlinear>::MappedEquationSystem::setParameterMap(Vector3Map&
};
template<typename Scalar, template<class> class Nonlinear>
int Kernel<Scalar, Nonlinear>::MappedEquationSystem::setResidualMap(VectorMap& map) {
new(&map) VectorMap(&Residual(m_eqn_offset), 1, DynStride(1,1));
return m_eqn_offset++;
int Kernel<Scalar, Nonlinear>::MappedEquationSystem::setResidualMap(VectorMap& map, AccessType t) {
if(t == rotation) {
new(&map) VectorMap(&m_residual(m_eqn_rot_offset), 1, DynStride(1,1));
return m_eqn_rot_offset++;
}
else {
new(&map) VectorMap(&m_residual(--m_eqn_trans_offset), 1, DynStride(1,1));
return m_eqn_trans_offset;
}
};
template<typename Scalar, template<class> class Nonlinear>
@ -394,31 +420,31 @@ bool Kernel<Scalar, Nonlinear>::MappedEquationSystem::isValid() {
};
template<typename Scalar, template<class> class Nonlinear>
void Kernel<Scalar, Nonlinear>::MappedEquationSystem::setAccess(ParameterType t) {
void Kernel<Scalar, Nonlinear>::MappedEquationSystem::setAccess(AccessType t) {
if(t==complete) {
new(&Jacobi) MatrixMap(&m_jacobi(0,0),m_eqns,m_params,DynStride(m_eqns,1));
new(&Parameter) VectorMap(&m_parameter(0),m_params,DynStride(1,1));
new(&Residual) VectorMap(&m_residual(0), m_eqns, DynStride(1,1));
}
else if(t==rotation) {
int num = m_param_trans_offset;
new(&Jacobi) MatrixMap(&m_jacobi(0,0),m_eqns,num,DynStride(m_eqns,1));
new(&Jacobi) MatrixMap(&m_jacobi(0,0),m_eqn_trans_offset,num,DynStride(m_eqns,1));
new(&Parameter) VectorMap(&m_parameter(0),num,DynStride(1,1));
new(&Residual) VectorMap(&m_residual(0), m_eqn_trans_offset, DynStride(1,1));
}
else if(t==general) {
int num = m_params - m_param_trans_offset;
new(&Jacobi) MatrixMap(&m_jacobi(0,m_param_trans_offset),m_eqns,num,DynStride(m_eqns,1));
int eq_num = m_eqns - m_eqn_trans_offset;
new(&Jacobi) MatrixMap(&m_jacobi(m_eqn_trans_offset,m_param_trans_offset),eq_num,num,DynStride(m_eqns,1));
new(&Parameter) VectorMap(&m_parameter(m_param_trans_offset),num,DynStride(1,1));
new(&Residual) VectorMap(&m_residual(m_eqn_trans_offset), eq_num, DynStride(1,1));
}
m_access = t;
};
template<typename Scalar, template<class> class Nonlinear>
void Kernel<Scalar, Nonlinear>::MappedEquationSystem::setGeneralEquationAccess(bool general) {
rot_only = !general;
};
template<typename Scalar, template<class> class Nonlinear>
bool Kernel<Scalar, Nonlinear>::MappedEquationSystem::hasParameterType(ParameterType t) {
bool Kernel<Scalar, Nonlinear>::MappedEquationSystem::hasAccessType(AccessType t) {
if(t==rotation)
return (m_param_rot_offset>0);
@ -436,12 +462,12 @@ Kernel<Scalar, Nonlinear>::Kernel() {
template<typename Scalar, template<class> class Nonlinear>
SolverInfo Kernel<Scalar, Nonlinear>::getSolverInfo() {
SolverInfo info;
info.iterations = m_solver.iter;
info.error = m_solver.err;
info.time = m_solver.time;
return info;
}
@ -484,10 +510,6 @@ template<typename Scalar, template<class> class Nonlinear>
int Kernel<Scalar, Nonlinear>::solve(MappedEquationSystem& mes) {
nothing n;
if(getProperty<solvermode>()==continuous)
m_solver.init(mes);
return m_solver.solve(mes, n);
};
@ -495,9 +517,6 @@ template<typename Scalar, template<class> class Nonlinear>
template<typename Functor>
int Kernel<Scalar, Nonlinear>::solve(MappedEquationSystem& mes, Functor& f) {
if(getProperty<solvermode>()==continuous)
m_solver.init(mes);
return m_solver.solve(mes, f);
};

View File

@ -40,23 +40,18 @@ struct nothing {
//information about solving
struct SolverInfo {
int iterations;
double error;
double time;
int iterations;
double error;
double time;
};
//the parameter types
enum ParameterType {
enum AccessType {
general, //every non-rotation parameter, therefore every translation and non transformed parameter
rotation, //all rotation parameters
complete //all parameter
};
enum SolverModes {
continuous,
step
};
//solver settings
struct precision {
@ -69,17 +64,6 @@ struct precision {
};
};
struct solvermode {
typedef SolverModes type;
typedef setting_property kind;
struct default_value {
SolverModes operator()() {
return continuous;
};
};
};
//and the solver itself
template<typename Kernel>
struct Dogleg {
@ -97,7 +81,7 @@ struct Dogleg {
Dogleg(Kernel* k);
Dogleg();
void setKernel(Kernel* k);
template <typename Derived, typename Derived2, typename Derived3, typename Derived4>
@ -105,16 +89,14 @@ struct Dogleg {
const Eigen::MatrixBase<Derived4>& residual, Eigen::MatrixBase<Derived2>& h_dl,
const double delta);
void init(typename Kernel::MappedEquationSystem& sys);
int solve(typename Kernel::MappedEquationSystem& sys, bool continuous = true);
int solve(typename Kernel::MappedEquationSystem& sys);
template<typename Functor>
int solve(typename Kernel::MappedEquationSystem& sys, Functor& rescale, bool continuous = true);
int solve(typename Kernel::MappedEquationSystem& sys, Functor& rescale);
};
template<typename Scalar, template<class> class Nonlinear = Dogleg>
struct Kernel : public PropertyOwner< mpl::vector2<precision, solvermode> > {
struct Kernel : public PropertyOwner< mpl::vector1<precision> > {
//basics
typedef Scalar number_type;
@ -166,47 +148,45 @@ struct Kernel : public PropertyOwner< mpl::vector2<precision, solvermode> > {
struct MappedEquationSystem {
protected:
//protected:
Matrix m_jacobi;
Vector m_parameter;
Vector m_parameter, m_residual;
bool rot_only; //calculate only rotations?
AccessType m_access; //which parameters/equation shall be calculated?
int m_params, m_eqns; //total amount
int m_param_rot_offset, m_param_trans_offset, m_eqn_offset; //current positions while creation
int m_param_rot_offset, m_param_trans_offset, m_eqn_rot_offset, m_eqn_trans_offset; //current positions while creation
public:
MatrixMap Jacobi;
VectorMap Parameter;
Vector Residual;
VectorMap Residual;
number_type Scaling;
int parameterCount();
int equationCount();
bool rotationOnly();
AccessType access();
MappedEquationSystem(int params, int equations);
int setParameterMap(int number, VectorMap& map, ParameterType t = general);
int setParameterMap(Vector3Map& map, ParameterType t = general);
int setResidualMap(VectorMap& map);
int setParameterMap(int number, VectorMap& map, AccessType t = general);
int setParameterMap(Vector3Map& map, AccessType t = general);
int setResidualMap(VectorMap& map, AccessType t = general);
void setJacobiMap(int eqn, int offset, int number, CVectorMap& map);
void setJacobiMap(int eqn, int offset, int number, VectorMap& map);
bool isValid();
void setAccess(ParameterType t);
void setAccess(AccessType t);
bool hasAccessType(AccessType t);
void setGeneralEquationAccess(bool general);
bool hasParameterType(ParameterType t);
virtual void recalculate() = 0;
virtual void recalculate() = 0;
virtual void removeLocalGradientZeros() = 0;
};
Kernel();
//static comparison versions
template <typename DerivedA,typename DerivedB>
static bool isSame(const E::MatrixBase<DerivedA>& p1,const E::MatrixBase<DerivedB>& p2, number_type precission);
@ -225,15 +205,15 @@ struct Kernel : public PropertyOwner< mpl::vector2<precision, solvermode> > {
template<typename Functor>
int solve(MappedEquationSystem& mes, Functor& f);
SolverInfo getSolverInfo();
private:
NonlinearSolver m_solver;
};
}//dcm
#ifndef DCM_EXTERNAL_CORE

View File

@ -29,7 +29,7 @@ namespace dcm {
namespace details {
//we need a custom orientation type to allow coincidents with points. We can't use the ci_orietation
//as some geometries are supporte by align but not by coincident
struct al_orientation : public Equation<al_orientation, Direction, 6, true> {
struct al_orientation : public Equation<al_orientation, Direction, 6, rotation> {
using Equation::operator=;
using Equation::options;

View File

@ -82,8 +82,8 @@ public:
public:
ClusterMath();
void setParameterOffset(int offset, ParameterType t);
int getParameterOffset(ParameterType t);
void setParameterOffset(int offset, AccessType t);
int getParameterOffset(AccessType t);
typename Kernel::Vector3Map& getNormQuaternionMap();
typename Kernel::Vector3Map& getTranslationMap();

View File

@ -28,7 +28,7 @@ namespace dcm {
namespace details {
//we need a custom orientation type to allow coincidents with points
struct ci_orientation : public Equation<ci_orientation, Direction, 4, true> {
struct ci_orientation : public Equation<ci_orientation, Direction, 4, rotation> {
using Equation::operator=;
using Equation::options;

View File

@ -21,6 +21,24 @@
#define GCM_DEFINES_3D_H
namespace dcm {
enum SolverFailureHandling {
IgnoreResults,
ApplyResults
};
//options
struct solverfailure {
typedef SolverFailureHandling type;
typedef setting_property kind;
struct default_value {
SolverFailureHandling operator()() {
return IgnoreResults;
};
};
};
namespace details {
enum { cluster3D = 100};

View File

@ -44,7 +44,7 @@ ClusterMath<Sys>::ClusterMath() : m_normQ(NULL), m_translation(NULL), init(false
};
template<typename Sys>
void ClusterMath<Sys>::setParameterOffset(int offset, dcm::ParameterType t) {
void ClusterMath<Sys>::setParameterOffset(int offset, dcm::AccessType t) {
if(t == general)
m_offset = offset;
else
@ -52,7 +52,7 @@ void ClusterMath<Sys>::setParameterOffset(int offset, dcm::ParameterType t) {
};
template<typename Sys>
int ClusterMath<Sys>::getParameterOffset(ParameterType t) {
int ClusterMath<Sys>::getParameterOffset(AccessType t) {
if(t == general)
return m_offset;
else

View File

@ -21,6 +21,7 @@
#define DCM_SOLVER_3D_IMP_H
#include "../solver.hpp"
#include "../defines.hpp"
#include <boost/graph/undirected_dfs.hpp>
@ -31,8 +32,8 @@
namespace dcm {
namespace details {
template<typename Sys>
MES<Sys>::MES(boost::shared_ptr<Cluster> cl, int par, int eqn) : Base(par, eqn), m_cluster(cl) {
#ifdef USE_LOGGING
@ -46,6 +47,7 @@ void MES<Sys>::recalculate() {
//first calculate all clusters
typedef typename Cluster::cluster_iterator citer;
std::pair<citer, citer> cit = m_cluster->clusters();
for(; cit.first != cit.second; cit.first++) {
if(!(*cit.first).second->template getProperty<fix_prop>())
@ -55,15 +57,19 @@ void MES<Sys>::recalculate() {
//with everything updated just nicely we can compute the constraints
typedef typename Cluster::template object_iterator<Constraint3D> oiter;
typedef typename boost::graph_traits<Cluster>::edge_iterator eiter;
std::pair<eiter, eiter> eit = boost::edges(*m_cluster);
for(; eit.first != eit.second; eit.first++) {
//as always: every local edge can hold multiple global ones, so iterate over all constraints
//hold by the individual edge
std::pair< oiter, oiter > oit = m_cluster->template getObjects<Constraint3D>(*eit.first);
for(; oit.first != oit.second; oit.first++) {
if(*oit.first)
(*oit.first)->calculate(Base::Scaling, Base::rot_only);
(*oit.first)->calculate(Base::Scaling, Base::m_access);
}
}
};
@ -78,10 +84,12 @@ void MES<Sys>::removeLocalGradientZeros() {
typedef typename Cluster::template object_iterator<Constraint3D> oiter;
typedef typename boost::graph_traits<Cluster>::edge_iterator eiter;
std::pair<eiter, eiter> eit = boost::edges(*m_cluster);
for(; eit.first != eit.second; eit.first++) {
//as always: every local edge can hold multiple global ones, so iterate over all constraints
//hold by the individual edge
std::pair< oiter, oiter > oit = m_cluster->template getObjects<Constraint3D>(*eit.first);
for(; oit.first != oit.second; oit.first++) {
if(*oit.first)
(*oit.first)->treatLGZ();
@ -108,6 +116,7 @@ typename SystemSolver<Sys>::Scalar SystemSolver<Sys>::Rescaler::scaleClusters()
std::pair<citer, citer> cit = cluster->clusters();
//get the maximal scale
Scalar sc = 0;
for(cit = cluster->clusters(); cit.first != cit.second; cit.first++) {
//fixed cluster are irrelevant for scaling
if((*cit.first).second->template getProperty<fix_prop>())
@ -122,11 +131,13 @@ typename SystemSolver<Sys>::Scalar SystemSolver<Sys>::Rescaler::scaleClusters()
const Scalar s = math.calculateClusterScale();
sc = (s>sc) ? s : sc;
}
//if no scaling-value returned we can use 1
sc = (Kernel::isSame(sc,0, 1e-10)) ? 1. : sc;
typedef typename boost::graph_traits<Cluster>::vertex_iterator iter;
std::pair<iter, iter> it = boost::vertices(*cluster);
for(; it.first != it.second; it.first++) {
if(cluster->isCluster(*it.first)) {
@ -139,6 +150,7 @@ typename SystemSolver<Sys>::Scalar SystemSolver<Sys>::Rescaler::scaleClusters()
g->scale(sc*SKALEFAKTOR);
}
}
return 1./(sc*SKALEFAKTOR);
};
@ -153,9 +165,11 @@ void SystemSolver<Sys>::Rescaler::collectPseudoPoints(
typedef typename Cluster::global_edge_iterator c_iter;
typedef typename boost::graph_traits<Cluster>::out_edge_iterator e_iter;
std::pair<e_iter, e_iter> it = boost::out_edges(cluster, *parent);
for(; it.first != it.second; it.first++) {
std::pair< c_iter, c_iter > cit = parent->getGlobalEdges(*it.first);
for(; cit.first != cit.second; cit.first++) {
Cons c = parent->template getObject<Constraint3D>(*cit.first);
@ -165,6 +179,7 @@ void SystemSolver<Sys>::Rescaler::collectPseudoPoints(
//get the first global vertex and see if we have it in the wanted cluster or not
GlobalVertex v = cit.first->source;
std::pair<LocalVertex,bool> res = parent->getLocalVertex(v);
if(!res.second)
return; //means the geometry is in non of the clusters which is not allowed
@ -192,113 +207,124 @@ void SystemSolver<Sys>::execute(Sys& sys) {
template<typename Sys>
void SystemSolver<Sys>::solveCluster(boost::shared_ptr<Cluster> cluster, Sys& sys) {
try {
//set out and solve all relevant subclusters
typedef typename Cluster::cluster_iterator citer;
std::pair<citer, citer> cit = cluster->clusters();
for(; cit.first != cit.second; cit.first++) {
//set out and solve all relevant subclusters
typedef typename Cluster::cluster_iterator citer;
std::pair<citer, citer> cit = cluster->clusters();
boost::shared_ptr<Cluster> c = (*cit.first).second;
if(c->template getProperty<changed_prop>() &&
c->template getProperty<type_prop>() == details::cluster3D)
solveCluster(c, sys);
}
for(; cit.first != cit.second; cit.first++) {
int params=0, constraints=0;
typename Kernel::number_type scale = 1;
boost::shared_ptr<Cluster> c = (*cit.first).second;
//get the ammount of parameters and constraint equations we need
typedef typename boost::graph_traits<Cluster>::vertex_iterator iter;
std::pair<iter, iter> it = boost::vertices(*cluster);
for(; it.first != it.second; it.first++) {
if(c->template getProperty<changed_prop>() &&
c->template getProperty<type_prop>() == details::cluster3D)
solveCluster(c, sys);
}
//when cluster and not fixed it has trans and rot parameter
if(cluster->isCluster(*it.first)) {
if(!cluster->template getSubclusterProperty<fix_prop>(*it.first)) {
params += 6;
}
int params=0, constraints=0;
typename Kernel::number_type scale = 1;
//get the ammount of parameters and constraint equations we need
typedef typename boost::graph_traits<Cluster>::vertex_iterator iter;
std::pair<iter, iter> it = boost::vertices(*cluster);
for(; it.first != it.second; it.first++) {
//when cluster and not fixed it has trans and rot parameter
if(cluster->isCluster(*it.first)) {
if(!cluster->template getSubclusterProperty<fix_prop>(*it.first)) {
params += 6;
}
else {
params += cluster->template getObject<Geometry3D>(*it.first)->m_parameterCount;
};
}
//count the equations in the constraints
typedef typename Cluster::template object_iterator<Constraint3D> ocit;
typedef typename boost::graph_traits<Cluster>::edge_iterator e_iter;
std::pair<e_iter, e_iter> e_it = boost::edges(*cluster);
for(; e_it.first != e_it.second; e_it.first++) {
std::pair< ocit, ocit > it = cluster->template getObjects<Constraint3D>(*e_it.first);
for(; it.first != it.second; it.first++)
constraints += (*it.first)->equationCount();
else {
params += cluster->template getObject<Geometry3D>(*it.first)->m_parameterCount;
};
}
if(params <= 0 || constraints <= 0) {
//TODO:throw
//count the equations in the constraints
typedef typename Cluster::template object_iterator<Constraint3D> ocit;
typedef typename boost::graph_traits<Cluster>::edge_iterator e_iter;
std::pair<e_iter, e_iter> e_it = boost::edges(*cluster);
for(; e_it.first != e_it.second; e_it.first++) {
std::pair< ocit, ocit > it = cluster->template getObjects<Constraint3D>(*e_it.first);
for(; it.first != it.second; it.first++)
constraints += (*it.first)->equationCount();
};
if(params <= 0 || constraints <= 0) {
//TODO:throw
#ifdef USE_LOGGING
BOOST_LOG(log)<< "Error in system counting: params = " << params << " and constraints = "<<constraints;
BOOST_LOG(log)<< "Error in system counting: params = " << params << " and constraints = "<<constraints;
#endif
return;
}
return;
}
//initialise the system with now known size
Mes mes(cluster, params, constraints);
//initialise the system with now known size
Mes mes(cluster, params, constraints);
//iterate all geometrys again and set the needed maps
it = boost::vertices(*cluster);
for(; it.first != it.second; it.first++) {
//iterate all geometrys again and set the needed maps
it = boost::vertices(*cluster);
if(cluster->isCluster(*it.first)) {
boost::shared_ptr<Cluster> c = cluster->getVertexCluster(*it.first);
details::ClusterMath<Sys>& cm = c->template getProperty<math_prop>();
//only get maps and propagate downstream if not fixed
if(!c->template getProperty<fix_prop>()) {
//set norm Quaternion as map to the parameter vector
int offset_rot = mes.setParameterMap(cm.getNormQuaternionMap(), rotation);
//set translation as map to the parameter vector
int offset = mes.setParameterMap(cm.getTranslationMap(), general);
//write initail values to the parameter maps
//remember the parameter offset as all downstream geometry must use this offset
cm.setParameterOffset(offset_rot, rotation);
cm.setParameterOffset(offset, general);
//wirte initial values
cm.initMaps();
}
else
cm.initFixMaps();
for(; it.first != it.second; it.first++) {
//map all geometrie within that cluster to it's rotation matrix
//for collecting all geometries which need updates
cm.clearGeometry();
cm.mapClusterDownstreamGeometry(c);
if(cluster->isCluster(*it.first)) {
boost::shared_ptr<Cluster> c = cluster->getVertexCluster(*it.first);
details::ClusterMath<Sys>& cm = c->template getProperty<math_prop>();
//only get maps and propagate downstream if not fixed
if(!c->template getProperty<fix_prop>()) {
//set norm Quaternion as map to the parameter vector
int offset_rot = mes.setParameterMap(cm.getNormQuaternionMap(), rotation);
//set translation as map to the parameter vector
int offset = mes.setParameterMap(cm.getTranslationMap(), general);
//write initail values to the parameter maps
//remember the parameter offset as all downstream geometry must use this offset
cm.setParameterOffset(offset_rot, rotation);
cm.setParameterOffset(offset, general);
//wirte initial values
cm.initMaps();
}
else {
Geom g = cluster->template getObject<Geometry3D>(*it.first);
g->initMap(&mes);
}
else
cm.initFixMaps();
//map all geometrie within that cluster to it's rotation matrix
//for collecting all geometries which need updates
cm.clearGeometry();
cm.mapClusterDownstreamGeometry(c);
}
//and now the constraints to set the residual and gradient maps
typedef typename Cluster::template object_iterator<Constraint3D> oiter;
e_it = boost::edges(*cluster);
for(; e_it.first != e_it.second; e_it.first++) {
//as always: every local edge can hold multiple global ones, so iterate over all constraints
//hold by the individual edge
std::pair< oiter, oiter > oit = cluster->template getObjects<Constraint3D>(*e_it.first);
for(; oit.first != oit.second; oit.first++) {
//set the maps
Cons c = *oit.first;
if(c)
c->setMaps(mes);
//TODO: else throw (as every global edge was counted as one equation)
}
else {
Geom g = cluster->template getObject<Geometry3D>(*it.first);
g->initMap(&mes);
}
}
//and now the constraints to set the residual and gradient maps
typedef typename Cluster::template object_iterator<Constraint3D> oiter;
e_it = boost::edges(*cluster);
for(; e_it.first != e_it.second; e_it.first++) {
//as always: every local edge can hold multiple global ones, so iterate over all constraints
//hold by the individual edge
std::pair< oiter, oiter > oit = cluster->template getObjects<Constraint3D>(*e_it.first);
for(; oit.first != oit.second; oit.first++) {
//set the maps
Cons c = *oit.first;
if(c)
c->setMaps(mes);
//TODO: else throw (as every global edge was counted as one equation)
}
}
try {
//if we don't have rotations we need no expensive scaling code
if(!mes.hasParameterType(rotation)) {
if(!mes.hasAccessType(rotation)) {
#ifdef USE_LOGGING
BOOST_LOG(log)<< "No rotation parameters in system, solve without scaling";
@ -326,13 +352,13 @@ void SystemSolver<Sys>::solveCluster(boost::shared_ptr<Cluster> cluster, Sys& sy
boost::undirected_dfs(*cluster.get(), boost::visitor(cd).vertex_index_map(vi_map).vertex_color_map(v_cpm).edge_color_map(e_cpm));
bool done = false;
if(!has_cycle) {
#ifdef USE_LOGGING
BOOST_LOG(log)<< "non-cyclic system dedected";
BOOST_LOG(log)<< "non-cyclic system dedected: solve rotation only";
#endif
//cool, lets do uncylic. first all rotational constraints with rotational parameters
mes.setAccess(rotation);
mes.setGeneralEquationAccess(false);
//cool, lets do uncylic. first all rotational constraints with rotational parameters
mes.setAccess(rotation);
//solve can be done without catching exceptions, because this only fails if the system in
//unsolvable
DummyScaler re;
@ -340,11 +366,15 @@ void SystemSolver<Sys>::solveCluster(boost::shared_ptr<Cluster> cluster, Sys& sy
//now let's see if we have to go on with the translations
mes.setAccess(general);
mes.setGeneralEquationAccess(true);
mes.recalculate();
if(mes.Residual.norm()<1e-6)
if(sys.kernel().isSame(mes.Residual.template lpNorm<E::Infinity>(),0.))
done = true;
else {
#ifdef USE_LOGGING
BOOST_LOG(log)<< "Solve Translation after Rotations are not enough";
#endif
//let's try translation only
try {
DummyScaler re;
@ -363,7 +393,10 @@ void SystemSolver<Sys>::solveCluster(boost::shared_ptr<Cluster> cluster, Sys& sy
#ifdef USE_LOGGING
BOOST_LOG(log)<< "Full scale solver used";
#endif
Rescaler re(cluster, mes);
mes.setAccess(complete);
mes.recalculate();
Rescaler re(cluster, mes);
re();
sys.kernel().solve(mes, re);
#ifdef USE_LOGGING
@ -371,38 +404,54 @@ void SystemSolver<Sys>::solveCluster(boost::shared_ptr<Cluster> cluster, Sys& sy
#endif
};
}
//solving is done, now go to all relevant geometries and clusters and write the values back
//(no need to emit recalculated signal as this cluster is never recalculated in this run)
it = boost::vertices(*cluster);
for(; it.first != it.second; it.first++) {
if(cluster->isCluster(*it.first)) {
boost::shared_ptr<Cluster> c = cluster->getVertexCluster(*it.first);
if(!cluster->template getSubclusterProperty<fix_prop>(*it.first))
c->template getProperty<math_prop>().finishCalculation();
else
c->template getProperty<math_prop>().finishFixCalculation();
std::vector<Geom>& vec = c->template getProperty<math_prop>().getGeometry();
for(typename std::vector<Geom>::iterator vit = vec.begin(); vit != vec.end(); vit++)
(*vit)->finishCalculation();
}
else {
Geom g = cluster->template getObject<Geometry3D>(*it.first);
g->scale(mes.Scaling);
g->finishCalculation();
}
}
//we have solved this cluster
cluster->template setProperty<changed_prop>(false);
//done solving, write the results back
finish(cluster, sys, mes);
}
catch(boost::exception&) {
throw;
if(sys.template getOption<solverfailure>()==ApplyResults)
finish(cluster, sys, mes);
else
throw;
}
};
template<typename Sys>
void SystemSolver<Sys>::finish(boost::shared_ptr<Cluster> cluster, Sys& sys, Mes& mes) {
//solving is done, now go to all relevant geometries and clusters and write the values back
//(no need to emit recalculated signal as this cluster is never recalculated in this run)
typedef typename boost::graph_traits<Cluster>::vertex_iterator iter;
std::pair<iter, iter> it = boost::vertices(*cluster);
for(; it.first != it.second; it.first++) {
if(cluster->isCluster(*it.first)) {
boost::shared_ptr<Cluster> c = cluster->getVertexCluster(*it.first);
if(!cluster->template getSubclusterProperty<fix_prop>(*it.first))
c->template getProperty<math_prop>().finishCalculation();
else
c->template getProperty<math_prop>().finishFixCalculation();
std::vector<Geom>& vec = c->template getProperty<math_prop>().getGeometry();
for(typename std::vector<Geom>::iterator vit = vec.begin(); vit != vec.end(); vit++)
(*vit)->finishCalculation();
}
else {
Geom g = cluster->template getObject<Geometry3D>(*it.first);
g->scale(mes.Scaling);
g->finishCalculation();
}
}
//we have solved this cluster
cluster->template setProperty<changed_prop>(false);
}
}//details
}//dcm

View File

@ -269,7 +269,7 @@ struct Module3D {
typedef GlobalEdge type;
};
typedef mpl::vector4<vertex_prop, edge_prop, math_prop, fix_prop> properties;
typedef mpl::vector5<vertex_prop, edge_prop, math_prop, fix_prop, solverfailure> properties;
typedef mpl::vector2<Geometry3D, Constraint3D> objects;
typedef mpl::vector5<tag::point3D, tag::direction3D, tag::line3D, tag::plane3D, tag::cylinder3D> geometries;
typedef mpl::map0<> signals;

View File

@ -111,6 +111,7 @@ struct SystemSolver : public Job<Sys> {
SystemSolver();
virtual void execute(Sys& sys);
void solveCluster(boost::shared_ptr<Cluster> cluster, Sys& sys);
void finish(boost::shared_ptr< Cluster > cluster, Sys& sys, Mes& mes);
};
}//details

View File

@ -43,7 +43,7 @@ struct ModuleState {
void saveState(std::ostream& stream);
void loadState(std::istream& stream);
void system_sub(boost:shared_ptr<Sys> subsys) {};
void system_sub(boost::shared_ptr<Sys> subsys) {};
};