Dof calculation when redundant is allowed.
This commit is contained in:
parent
708a08f04b
commit
7f86a78472
@ -550,8 +550,11 @@ void SolveSpaceUI::SolveGroup(hGroup hg, bool andFindFree) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SolveResult SolveSpaceUI::TestRankForGroup(hGroup hg, int *rank) {
|
SolveResult SolveSpaceUI::TestRankForGroup(hGroup hg, int *rank) {
|
||||||
WriteEqSystemForGroup(hg);
|
|
||||||
Group *g = SK.GetGroup(hg);
|
Group *g = SK.GetGroup(hg);
|
||||||
|
// If redundant is allowed, there is
|
||||||
|
// no point to solve rank because this result is not meaningful
|
||||||
|
if(g->allowRedundant) return SolveResult::OKAY;
|
||||||
|
WriteEqSystemForGroup(hg);
|
||||||
SolveResult result = sys.SolveRank(g, rank);
|
SolveResult result = sys.SolveRank(g, rank);
|
||||||
FreeAllTemporary();
|
FreeAllTemporary();
|
||||||
return result;
|
return result;
|
||||||
|
@ -261,7 +261,7 @@ public:
|
|||||||
|
|
||||||
static const double RANK_MAG_TOLERANCE, CONVERGE_TOLERANCE;
|
static const double RANK_MAG_TOLERANCE, CONVERGE_TOLERANCE;
|
||||||
int CalculateRank();
|
int CalculateRank();
|
||||||
bool TestRank(int *rank = NULL);
|
bool TestRank(int *dof = NULL);
|
||||||
static bool SolveLinearSystem(double X[], double A[][MAX_UNKNOWNS],
|
static bool SolveLinearSystem(double X[], double A[][MAX_UNKNOWNS],
|
||||||
double B[], int N);
|
double B[], int N);
|
||||||
bool SolveLeastSquares();
|
bool SolveLeastSquares();
|
||||||
@ -279,7 +279,6 @@ public:
|
|||||||
bool NewtonSolve(int tag);
|
bool NewtonSolve(int tag);
|
||||||
|
|
||||||
void MarkParamsFree(bool findFree);
|
void MarkParamsFree(bool findFree);
|
||||||
int CalculateDof();
|
|
||||||
|
|
||||||
SolveResult Solve(Group *g, int *rank = NULL, int *dof = NULL,
|
SolveResult Solve(Group *g, int *rank = NULL, int *dof = NULL,
|
||||||
List<hConstraint> *bad = NULL,
|
List<hConstraint> *bad = NULL,
|
||||||
|
@ -242,10 +242,12 @@ int System::CalculateRank() {
|
|||||||
return rank;
|
return rank;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool System::TestRank(int *rank) {
|
bool System::TestRank(int *dof) {
|
||||||
EvalJacobian();
|
EvalJacobian();
|
||||||
int jacobianRank = CalculateRank();
|
int jacobianRank = CalculateRank();
|
||||||
if(rank) *rank = jacobianRank;
|
// We are calculating dof based on real rank, not mat.m.
|
||||||
|
// Using this approach we can calculate real dof even when redundant is allowed.
|
||||||
|
if(dof != NULL) *dof = mat.n - jacobianRank;
|
||||||
return jacobianRank == mat.m;
|
return jacobianRank == mat.m;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -498,9 +500,9 @@ SolveResult System::Solve(Group *g, int *rank, int *dof, List<hConstraint> *bad,
|
|||||||
param.ClearTags();
|
param.ClearTags();
|
||||||
eq.ClearTags();
|
eq.ClearTags();
|
||||||
|
|
||||||
// Solving by substitution eliminates duplicate e.g. H/V constraints, which can cause rank test
|
// Since we are allowing redundant, we
|
||||||
// to succeed even on overdefined systems, which will fail later.
|
// don't want to catch result of dof checking without substitution
|
||||||
if(!forceDofCheck) {
|
if(g->allowRedundant || !forceDofCheck) {
|
||||||
SolveBySubstitution();
|
SolveBySubstitution();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -538,22 +540,20 @@ SolveResult System::Solve(Group *g, int *rank, int *dof, List<hConstraint> *bad,
|
|||||||
if(!WriteJacobian(0)) {
|
if(!WriteJacobian(0)) {
|
||||||
return SolveResult::TOO_MANY_UNKNOWNS;
|
return SolveResult::TOO_MANY_UNKNOWNS;
|
||||||
}
|
}
|
||||||
|
// Clear dof value in order to have indication when dof is actually not calculated
|
||||||
rankOk = TestRank(rank);
|
if(dof != NULL) *dof = -1;
|
||||||
|
// We are allowing redundant, so we no need to catch unsolveable + redundant
|
||||||
|
rankOk = (!g->allowRedundant) ? TestRank(dof) : true;
|
||||||
|
|
||||||
// And do the leftovers as one big system
|
// And do the leftovers as one big system
|
||||||
if(!NewtonSolve(0)) {
|
if(!NewtonSolve(0)) {
|
||||||
goto didnt_converge;
|
goto didnt_converge;
|
||||||
}
|
}
|
||||||
|
|
||||||
rankOk = TestRank(rank);
|
rankOk = TestRank(dof);
|
||||||
if(!rankOk) {
|
if(!rankOk) {
|
||||||
if(andFindBad) FindWhichToRemoveToFixJacobian(g, bad, forceDofCheck);
|
if(andFindBad) FindWhichToRemoveToFixJacobian(g, bad, forceDofCheck);
|
||||||
} else {
|
} else {
|
||||||
// This is not the full Jacobian, but any substitutions or single-eq
|
|
||||||
// solves removed one equation and one unknown, therefore no effect
|
|
||||||
// on the number of DOF.
|
|
||||||
if(dof) *dof = CalculateDof();
|
|
||||||
MarkParamsFree(andFindFree);
|
MarkParamsFree(andFindFree);
|
||||||
}
|
}
|
||||||
// System solved correctly, so write the new values back in to the
|
// System solved correctly, so write the new values back in to the
|
||||||
@ -610,11 +610,14 @@ SolveResult System::SolveRank(Group *g, int *rank, int *dof, List<hConstraint> *
|
|||||||
return SolveResult::TOO_MANY_UNKNOWNS;
|
return SolveResult::TOO_MANY_UNKNOWNS;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool rankOk = TestRank(rank);
|
bool rankOk = TestRank(dof);
|
||||||
if(!rankOk) {
|
if(!rankOk) {
|
||||||
if(andFindBad) FindWhichToRemoveToFixJacobian(g, bad, /*forceDofCheck=*/true);
|
// When we are testing with redundant allowed, we don't want to have additional info
|
||||||
|
// about redundants since this test is working only for single redundant constraint
|
||||||
|
if(!g->allowRedundant) {
|
||||||
|
if(andFindBad) FindWhichToRemoveToFixJacobian(g, bad, true);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if(dof) *dof = CalculateDof();
|
|
||||||
MarkParamsFree(andFindFree);
|
MarkParamsFree(andFindFree);
|
||||||
}
|
}
|
||||||
return rankOk ? SolveResult::OKAY : SolveResult::REDUNDANT_OKAY;
|
return rankOk ? SolveResult::OKAY : SolveResult::REDUNDANT_OKAY;
|
||||||
@ -649,7 +652,3 @@ void System::MarkParamsFree(bool find) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int System::CalculateDof() {
|
|
||||||
return mat.n - mat.m;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user