402 lines
10 KiB
C++
402 lines
10 KiB
C++
#include "MomentOfInertiaSolver.h"
|
|
#include "EulerParameters.h"
|
|
#include <iostream>
|
|
#include <algorithm>
|
|
|
|
using namespace MbD;
|
|
|
|
void MbD::MomentOfInertiaSolver::example1()
|
|
{
|
|
auto aJpp = std::make_shared<FullMatrixDouble>(ListListD{
|
|
{ 1, 0, 0 },
|
|
{ 0, 2, 0 },
|
|
{ 0, 0, 3 }
|
|
});
|
|
|
|
auto rpPp = std::make_shared<FullColumn<double>>(ListD{ 0, 0, 1 });
|
|
auto rotAxis = std::make_shared<FullColumn<double>>(ListD{ 0, 0, 1 });
|
|
auto aApP = std::make_shared<EulerParameters<double>>(rotAxis, M_PI*10/180)->aA;
|
|
auto solver = std::make_shared<MomentOfInertiaSolver>();
|
|
solver->setm(4.0);
|
|
solver->setJPP(aJpp);
|
|
solver->setrPoP(rpPp);
|
|
solver->setAPo(aApP);
|
|
auto rPcmP = std::make_shared<FullColumn<double>>(ListD{ 0, 0, 0 });
|
|
solver->setrPcmP(rPcmP);
|
|
solver->calc();
|
|
auto aJPP = solver->getJoo();
|
|
std::cout << *solver->getJoo() << std::endl;
|
|
std::cout << *solver->getJpp() << std::endl;
|
|
std::cout << *solver->getAPp() << std::endl;
|
|
solver->setm(4.0);
|
|
solver->setJPP(aJPP);
|
|
auto rPoP = aApP->transposeTimesFullColumn(rpPp->negated());
|
|
solver->setrPoP(rPoP);
|
|
auto aAPo = aApP->transpose();
|
|
solver->setAPo(aAPo);
|
|
solver->setrPcmP(rPoP);
|
|
solver->calc();
|
|
std::cout << *solver->getJoo() << std::endl;
|
|
std::cout << *solver->getJpp() << std::endl;
|
|
std::cout << *solver->getAPp() << std::endl;
|
|
}
|
|
|
|
void MbD::MomentOfInertiaSolver::doFullPivoting(int p)
|
|
{
|
|
double max = 0.0;
|
|
auto pivotRow = p;
|
|
auto pivotCol = p;
|
|
for (int i = p; i < 3; i++)
|
|
{
|
|
auto rowi = aJcmPcopy->at(i);
|
|
for (int j = p; j < 3; j++)
|
|
{
|
|
auto aij = rowi->at(j);
|
|
if (aij != 0.0) {
|
|
auto mag = std::abs(aij);
|
|
if (mag > max) {
|
|
max = mag;
|
|
pivotRow = i;
|
|
pivotCol = j;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
if (p != pivotRow) aJcmPcopy->swapElems(p, pivotRow);
|
|
if (p != pivotCol) {
|
|
for (auto& row : *aJcmPcopy) {
|
|
row->swapElems(p, pivotCol);
|
|
}
|
|
colOrder->swapElems(p, pivotCol);
|
|
}
|
|
}
|
|
|
|
void MbD::MomentOfInertiaSolver::forwardEliminateWithPivot(int p)
|
|
{
|
|
auto rowp = aJcmPcopy->at(p);
|
|
auto app = rowp->at(p);
|
|
for (int i = p + 1; i < 3; i++)
|
|
{
|
|
auto rowi = aJcmPcopy->at(i);
|
|
auto aip = rowi->at(p);
|
|
if (aip != 0) {
|
|
rowi->atiput(p, 0.0);
|
|
auto factor = aip / app;
|
|
for (int j = p + 1; j < 3; j++)
|
|
{
|
|
rowi->atiminusNumber(j, factor * rowp->at(j));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void MbD::MomentOfInertiaSolver::backSubstituteIntoDU()
|
|
{
|
|
}
|
|
|
|
void MbD::MomentOfInertiaSolver::postSolve()
|
|
{
|
|
}
|
|
|
|
FColDsptr MbD::MomentOfInertiaSolver::basicSolvewithsaveOriginal(FMatDsptr fullMat, FColDsptr fullCol, bool saveOriginal)
|
|
{
|
|
return FColDsptr();
|
|
}
|
|
|
|
FColDsptr MbD::MomentOfInertiaSolver::basicSolvewithsaveOriginal(SpMatDsptr spMat, FColDsptr fullCol, bool saveOriginal)
|
|
{
|
|
return FColDsptr();
|
|
}
|
|
|
|
void MbD::MomentOfInertiaSolver::preSolvewithsaveOriginal(FMatDsptr fullMat, FColDsptr fullCol, bool saveOriginal)
|
|
{
|
|
}
|
|
|
|
void MbD::MomentOfInertiaSolver::preSolvewithsaveOriginal(SpMatDsptr spMat, FColDsptr fullCol, bool saveOriginal)
|
|
{
|
|
}
|
|
|
|
double MbD::MomentOfInertiaSolver::getmatrixArowimaxMagnitude(int i)
|
|
{
|
|
return 0.0;
|
|
}
|
|
|
|
void MbD::MomentOfInertiaSolver::doPivoting(int p)
|
|
{
|
|
}
|
|
|
|
void MbD::MomentOfInertiaSolver::setm(double mass)
|
|
{
|
|
m = mass;
|
|
}
|
|
|
|
void MbD::MomentOfInertiaSolver::setJPP(FMatDsptr mat)
|
|
{
|
|
aJPP = mat;
|
|
}
|
|
|
|
void MbD::MomentOfInertiaSolver::setrPoP(FColDsptr col)
|
|
{
|
|
rPoP = col;
|
|
}
|
|
|
|
void MbD::MomentOfInertiaSolver::setAPo(FMatDsptr mat)
|
|
{
|
|
aAPo = mat;
|
|
}
|
|
|
|
void MbD::MomentOfInertiaSolver::setrPcmP(FColDsptr col)
|
|
{
|
|
rPcmP = col;
|
|
}
|
|
|
|
FMatDsptr MbD::MomentOfInertiaSolver::getJoo()
|
|
{
|
|
return aJoo;
|
|
}
|
|
|
|
DiagMatDsptr MbD::MomentOfInertiaSolver::getJpp()
|
|
{
|
|
return aJpp;
|
|
}
|
|
|
|
FMatDsptr MbD::MomentOfInertiaSolver::getAPp()
|
|
{
|
|
return aAPp;
|
|
}
|
|
|
|
void MbD::MomentOfInertiaSolver::calc()
|
|
{
|
|
calcJoo();
|
|
calcJpp();
|
|
calcAPp();
|
|
}
|
|
|
|
void MbD::MomentOfInertiaSolver::calcJoo()
|
|
{
|
|
//"aJoo = aAPoT*[aJPP + mass*(rPoPTilde*rPoPTilde + rPoPTilde*rocmPTilde + rocmPTilde*rPoPTilde)]*aAPo"
|
|
|
|
if (!rPoP) {
|
|
rPoP = rPcmP;
|
|
aAPo = FullMatrixDouble::identitysptr(3);
|
|
}
|
|
auto rocmPtilde = FullMatrixDouble::tildeMatrix(rPcmP->minusFullColumn(rPoP));
|
|
auto rPoPtilde = FullMatrixDouble::tildeMatrix(rPoP);
|
|
auto term1 = aJPP;
|
|
auto term21 = rPoPtilde->timesFullMatrix(rPoPtilde);
|
|
auto term22 = rPoPtilde->timesFullMatrix(rocmPtilde);
|
|
auto term23 = term22->transpose();
|
|
auto term2 = term21->plusFullMatrix(term22)->plusFullMatrix(term23)->times(m);
|
|
aJoo = aAPo->transposeTimesFullMatrix(term1->plusFullMatrix(term2))->timesFullMatrix(aAPo);
|
|
aJoo->symLowerWithUpper();
|
|
aJoo->conditionSelfWithTol(aJoo->maxMagnitude() * 1.0e-6);
|
|
}
|
|
|
|
void MbD::MomentOfInertiaSolver::calcJpp()
|
|
{
|
|
//"aJcmP = aJPP + mass*(rPcmPTilde*rPcmPTilde)"
|
|
|
|
auto rPcmPtilde = FullMatrixDouble::tildeMatrix(rPcmP);
|
|
aJcmP = aJPP->plusFullMatrix(rPcmPtilde->timesFullMatrix(rPcmPtilde)->times(m));
|
|
aJcmP->symLowerWithUpper();
|
|
aJcmP->conditionSelfWithTol(aJcmP->maxMagnitude() * 1.0e-6);
|
|
if (aJcmP->isDiagonal()) {
|
|
calcJppFromDiagJcmP();
|
|
}
|
|
else {
|
|
calcJppFromFullJcmP();
|
|
}
|
|
}
|
|
|
|
void MbD::MomentOfInertiaSolver::calcAPp()
|
|
{
|
|
FColDsptr eigenvector1, eigenvector2, eigenvector0;
|
|
auto lam0 = aJpp->at(0);
|
|
auto lam1 = aJpp->at(1);
|
|
auto lam2 = aJpp->at(2);
|
|
if (lam0 == lam1) {
|
|
if (lam1 == lam2) {
|
|
aAPp = FullMatrixDouble::identitysptr(3);
|
|
}
|
|
else {
|
|
eigenvector1 = eigenvectorFor(lam1);
|
|
eigenvector2 = eigenvectorFor(lam2);
|
|
eigenvector1->normalizeSelf();
|
|
eigenvector2->normalizeSelf();
|
|
if (eigenvector1->at(1) < 0.0) eigenvector1->negateSelf();
|
|
if (eigenvector2->at(2) < 0.0) eigenvector2->negateSelf();
|
|
eigenvector0 = eigenvector1->cross(eigenvector2);
|
|
}
|
|
}
|
|
else {
|
|
eigenvector0 = eigenvectorFor(lam0);
|
|
eigenvector1 = eigenvectorFor(lam1);
|
|
eigenvector0->normalizeSelf();
|
|
eigenvector1->normalizeSelf();
|
|
if (eigenvector0->at(0) < 0.0) eigenvector0->negateSelf();
|
|
if (eigenvector1->at(1) < 0.0) eigenvector1->negateSelf();
|
|
eigenvector2 = eigenvector0->cross(eigenvector1);
|
|
}
|
|
aAPp = std::make_shared<FullMatrixDouble>(3, 3);
|
|
aAPp->atijputFullColumn(0, 0, eigenvector0);
|
|
aAPp->atijputFullColumn(0, 1, eigenvector1);
|
|
aAPp->atijputFullColumn(0, 2, eigenvector2);
|
|
}
|
|
|
|
FColDsptr MbD::MomentOfInertiaSolver::eigenvectorFor(double lam)
|
|
{
|
|
//"[aJcmP] - lam[I]."
|
|
|
|
double e0, e1, e2;
|
|
aJcmPcopy = aJcmP->copy();
|
|
colOrder = std::make_shared<FullRow<int>>(3);
|
|
auto eigenvector = std::make_shared<FullColumn<double>>(3);
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
colOrder->atiput(i, i);
|
|
aJcmPcopy->atijminusNumber(i, i, lam);
|
|
}
|
|
for (int p = 0; p < 3; p++)
|
|
{
|
|
doFullPivoting(p);
|
|
forwardEliminateWithPivot(p);
|
|
}
|
|
|
|
auto row0 = aJcmPcopy->at(0);
|
|
auto row1 = aJcmPcopy->at(1);
|
|
auto row2 = aJcmPcopy->at(2);
|
|
auto norm0 = row0->length();
|
|
auto aaaa = row2->length();
|
|
if ((row2->length() / norm0) > 1.0e-5) throw std::runtime_error("3rd row should be very small.");
|
|
if ((row1->length() / norm0) > 1.0e-5) {
|
|
e2 = 1.0;
|
|
e1 = e2 * -row1->at(2) / row1->at(1);
|
|
e0 = -(e1 * row0->at(1) + e2 * row0->at(2)) / row0->at(0);
|
|
}
|
|
else {
|
|
//"Repeated roots."
|
|
e2 = 1.0;
|
|
e1 = 0.0;
|
|
e0 = -(e1 * row0->at(1) + e2 * row0->at(2)) / row0->at(0);
|
|
}
|
|
|
|
|
|
auto dum = std::make_shared<FullColumn<double>>(ListD{ e0, e1, e2 });
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
eigenvector->atiput(colOrder->at(i), dum->at(i));
|
|
}
|
|
return eigenvector;
|
|
}
|
|
|
|
void MbD::MomentOfInertiaSolver::calcJppFromDiagJcmP()
|
|
{
|
|
//"Eigenvalues are orders from smallest to largest."
|
|
|
|
double average;
|
|
auto sortedJ = std::make_shared<DiagonalMatrix<double>>();
|
|
sortedJ->push_back(aJcmP->at(0)->at(0));
|
|
sortedJ->push_back(aJcmP->at(1)->at(1));
|
|
sortedJ->push_back(aJcmP->at(2)->at(2));
|
|
std::sort(sortedJ->begin(), sortedJ->end(), [](double a, double b) { return a < b; });
|
|
auto lam0 = sortedJ->at(0);
|
|
auto lam1 = sortedJ->at(1);
|
|
auto lam2 = sortedJ->at(2);
|
|
if (lam1 == 0 || std::abs((lam0 / lam1) - 1.0) < 1.0e-6) {
|
|
if (lam2 == 0 || std::abs((lam1 / lam2) - 1.0) < 1.0e-6) {
|
|
//"All are equal."
|
|
average = (lam0 + lam1 + lam2) / 3.0;
|
|
lam0 = average;
|
|
lam1 = average;
|
|
lam2 = average;
|
|
}
|
|
else {
|
|
//"lam0 = lam1"
|
|
average = (lam0 + lam1) / 2.0;
|
|
lam0 = average;
|
|
lam1 = average;
|
|
}
|
|
}
|
|
else {
|
|
if (std::abs(lam1 / lam2 - 1.0) < 1.0e-6) {
|
|
//"lam1 = lam2"
|
|
average = (lam1 + lam2) / 2.0;
|
|
lam1 = average;
|
|
lam2 = average;
|
|
}
|
|
}
|
|
aJpp = std::make_shared<DiagonalMatrix<double>>(ListD{ lam0, lam1, lam2 });
|
|
}
|
|
|
|
void MbD::MomentOfInertiaSolver::calcJppFromFullJcmP()
|
|
{
|
|
//"Eigenvalues are orders from smallest to largest."
|
|
//"Rounding error can be significant."
|
|
//"e.g. (diag 100.0d 100.0d 1.0d) gives only 8 digit accuracy."
|
|
|
|
double average;
|
|
auto a00 = aJcmP->at(0)->at(0);
|
|
auto a01 = aJcmP->at(0)->at(1);
|
|
auto a02 = aJcmP->at(0)->at(2);
|
|
auto a11 = aJcmP->at(1)->at(1);
|
|
auto a12 = aJcmP->at(1)->at(2);
|
|
auto a22 = aJcmP->at(2)->at(2);
|
|
auto a = -(a00 + a11 + a22);
|
|
auto b = a00 * a11 + (a00 * a22) + (a11 * a22) - (a01 * a01) - (a02 * a02) - (a12 * a12);
|
|
auto c = a00 * a12 * a12 + (a11 * a02 * a02) + (a22 * a01 * a01) - (a00 * a11 * a22) - (2.0 * a01 * a02 * a12);
|
|
auto aDiv3 = a / 3.0;
|
|
auto p = (b / 3.0) - (aDiv3 * aDiv3);
|
|
auto q = (c + (2.0 * aDiv3 * aDiv3 * aDiv3) - (aDiv3 * b)) / 2.0;
|
|
auto phiDiv3 = modifiedArcCos(-q / std::sqrt(-p * p * p)) / 3.0;
|
|
auto twoSqrtMinusp = 2.0 * std::sqrt(-p);
|
|
auto piDiv3 = M_PI / 3.0;
|
|
auto sortedJ = std::make_shared<DiagonalMatrix<double>>();
|
|
sortedJ->push_back(twoSqrtMinusp * std::cos(phiDiv3));
|
|
sortedJ->push_back(twoSqrtMinusp * -std::cos(phiDiv3 + piDiv3));
|
|
sortedJ->push_back(twoSqrtMinusp * -std::cos(phiDiv3 - piDiv3));
|
|
std::sort(sortedJ->begin(), sortedJ->end(), [](double a, double b) { return a < b; });
|
|
auto lam0 = sortedJ->at(0) - aDiv3;
|
|
auto lam1 = sortedJ->at(1) - aDiv3;
|
|
auto lam2 = sortedJ->at(2) - aDiv3;
|
|
if (lam1 == 0 || std::abs((lam0 / lam1) - 1.0) < 1.0e-6) {
|
|
if (lam2 == 0 || std::abs((lam1 / lam2) - 1.0) < 1.0e-6) {
|
|
//"All are equal."
|
|
average = (lam0 + lam1 + lam2) / 3.0;
|
|
lam0 = average;
|
|
lam1 = average;
|
|
lam2 = average;
|
|
}
|
|
else {
|
|
//"lam0 = lam1"
|
|
average = (lam0 + lam1) / 2.0;
|
|
lam0 = average;
|
|
lam1 = average;
|
|
}
|
|
}
|
|
else {
|
|
if (std::abs((lam1 / lam2) - 1.0) < 1.0e-6) {
|
|
//"lam1 = lam2"
|
|
average = (lam1 + lam2) / 2.0;
|
|
lam1 = average;
|
|
lam2 = average;
|
|
}
|
|
}
|
|
aJpp = std::make_shared<DiagonalMatrix<double>>(ListD{ lam0, lam1, lam2 });
|
|
}
|
|
|
|
double MbD::MomentOfInertiaSolver::modifiedArcCos(double val)
|
|
{
|
|
if (val > 1.0) {
|
|
return 0.0;
|
|
}
|
|
else {
|
|
if (val < -1.0) {
|
|
return M_PI;
|
|
}
|
|
else {
|
|
return std::acos(val);
|
|
}
|
|
}
|
|
}
|