Dof calculation when redundant is allowed.

pull/1159/head
EvilSpirit 2017-05-11 20:53:12 +07:00 committed by phkahler
parent 708a08f04b
commit 7f86a78472
3 changed files with 23 additions and 22 deletions

View File

@ -550,8 +550,11 @@ void SolveSpaceUI::SolveGroup(hGroup hg, bool andFindFree) {
}
SolveResult SolveSpaceUI::TestRankForGroup(hGroup hg, int *rank) {
WriteEqSystemForGroup(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);
FreeAllTemporary();
return result;

View File

@ -261,7 +261,7 @@ public:
static const double RANK_MAG_TOLERANCE, CONVERGE_TOLERANCE;
int CalculateRank();
bool TestRank(int *rank = NULL);
bool TestRank(int *dof = NULL);
static bool SolveLinearSystem(double X[], double A[][MAX_UNKNOWNS],
double B[], int N);
bool SolveLeastSquares();
@ -279,7 +279,6 @@ public:
bool NewtonSolve(int tag);
void MarkParamsFree(bool findFree);
int CalculateDof();
SolveResult Solve(Group *g, int *rank = NULL, int *dof = NULL,
List<hConstraint> *bad = NULL,

View File

@ -242,10 +242,12 @@ int System::CalculateRank() {
return rank;
}
bool System::TestRank(int *rank) {
bool System::TestRank(int *dof) {
EvalJacobian();
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;
}
@ -498,9 +500,9 @@ SolveResult System::Solve(Group *g, int *rank, int *dof, List<hConstraint> *bad,
param.ClearTags();
eq.ClearTags();
// Solving by substitution eliminates duplicate e.g. H/V constraints, which can cause rank test
// to succeed even on overdefined systems, which will fail later.
if(!forceDofCheck) {
// Since we are allowing redundant, we
// don't want to catch result of dof checking without substitution
if(g->allowRedundant || !forceDofCheck) {
SolveBySubstitution();
}
@ -538,22 +540,20 @@ SolveResult System::Solve(Group *g, int *rank, int *dof, List<hConstraint> *bad,
if(!WriteJacobian(0)) {
return SolveResult::TOO_MANY_UNKNOWNS;
}
rankOk = TestRank(rank);
// Clear dof value in order to have indication when dof is actually not calculated
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
if(!NewtonSolve(0)) {
goto didnt_converge;
}
rankOk = TestRank(rank);
rankOk = TestRank(dof);
if(!rankOk) {
if(andFindBad) FindWhichToRemoveToFixJacobian(g, bad, forceDofCheck);
} 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);
}
// 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;
}
bool rankOk = TestRank(rank);
bool rankOk = TestRank(dof);
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 {
if(dof) *dof = CalculateDof();
MarkParamsFree(andFindFree);
}
return rankOk ? SolveResult::OKAY : SolveResult::REDUNDANT_OKAY;
@ -649,7 +652,3 @@ void System::MarkParamsFree(bool find) {
}
}
int System::CalculateDof() {
return mat.n - mat.m;
}