Refactoring

This commit is contained in:
Iason 2021-01-12 14:40:25 +02:00
parent 2e787689fe
commit d933f92eeb
9 changed files with 273 additions and 212 deletions

View File

@ -12,7 +12,7 @@ struct RectangularBeamDimensions {
: b(width), h(height) { : b(width), h(height) {
assert(width > 0 && height > 0); assert(width > 0 && height > 0);
} }
RectangularBeamDimensions() : b(1), h(1) {} RectangularBeamDimensions() : b(0.002), h(0.002) {}
}; };
struct CylindricalBeamDimensions { struct CylindricalBeamDimensions {

View File

@ -8,18 +8,19 @@
#include <execution> #include <execution>
#include <omp.h> #include <omp.h>
const bool debug = true;
void FormFinder::runUnitTests() { void FormFinder::runUnitTests() {
const std::filesystem::path groundOfTruthFolder{ const std::filesystem::path groundOfTruthFolder{
"/home/iason/Coding/Libraries/MySources/formFinder_unitTestFiles"}; "/home/iason/Coding/Libraries/MySources/formFinder_unitTestFiles"};
FormFinder formFinder; FormFinder formFinder;
formFinder.setTotalResidualForcesNormThreshold(1);
// First example of the paper // First example of the paper
VCGEdgeMesh beam; VCGEdgeMesh beam;
// const size_t spanGridSize = 11; // const size_t spanGridSize = 11;
// mesh.createSpanGrid(spanGridSize); // mesh.createSpanGrid(spanGridSize);
beam.loadFromPly( beam.loadPly(
std::filesystem::path(groundOfTruthFolder).append("simpleBeam.ply")); std::filesystem::path(groundOfTruthFolder).append("simpleBeam.ply"));
std::unordered_map<VertexIndex, std::unordered_set<DoFType>> fixedVertices; std::unordered_map<VertexIndex, std::unordered_set<DoFType>> fixedVertices;
fixedVertices[0] = std::unordered_set<DoFType>{0, 1, 2, 3}; fixedVertices[0] = std::unordered_set<DoFType>{0, 1, 2, 3};
@ -39,8 +40,13 @@ void FormFinder::runUnitTests() {
assert(CrossSectionType::name == CylindricalBeamDimensions::name); assert(CrossSectionType::name == CylindricalBeamDimensions::name);
beamSimulationJob.pMesh->setBeamCrossSection(CrossSectionType{0.03, 0.026}); beamSimulationJob.pMesh->setBeamCrossSection(CrossSectionType{0.03, 0.026});
Settings settings;
settings.Dtini = 0.1;
settings.xi = 0.9969;
settings.maxDRMIterations = 0;
settings.totalResidualForcesNormThreshold = 1;
SimulationResults simpleBeam_simulationResults = formFinder.executeSimulation( SimulationResults simpleBeam_simulationResults = formFinder.executeSimulation(
std::make_shared<SimulationJob>(beamSimulationJob), false, true); std::make_shared<SimulationJob>(beamSimulationJob), settings);
simpleBeam_simulationResults.save(); simpleBeam_simulationResults.save();
const std::string simpleBeamGroundOfTruthBinaryFilename = const std::string simpleBeamGroundOfTruthBinaryFilename =
std::filesystem::path(groundOfTruthFolder) std::filesystem::path(groundOfTruthFolder)
@ -60,9 +66,9 @@ void FormFinder::runUnitTests() {
VCGEdgeMesh shortSpanGrid; VCGEdgeMesh shortSpanGrid;
// const size_t spanGridSize = 11; // const size_t spanGridSize = 11;
// mesh.createSpanGrid(spanGridSize); // mesh.createSpanGrid(spanGridSize);
shortSpanGrid.loadFromPly(std::filesystem::path(groundOfTruthFolder) shortSpanGrid.loadPly(std::filesystem::path(groundOfTruthFolder)
.append("shortSpanGridshell.ply") .append("shortSpanGridshell.ply")
.string()); .string());
fixedVertices.clear(); fixedVertices.clear();
//// Corner nodes //// Corner nodes
@ -92,7 +98,7 @@ void FormFinder::runUnitTests() {
SimulationResults shortSpanGridshellSimulationResults = SimulationResults shortSpanGridshellSimulationResults =
formFinder.executeSimulation( formFinder.executeSimulation(
std::make_shared<SimulationJob>(shortSpanGridshellSimulationJob), std::make_shared<SimulationJob>(shortSpanGridshellSimulationJob),
false, false); settings);
shortSpanGridshellSimulationResults.save(); shortSpanGridshellSimulationResults.save();
const std::string groundOfTruthBinaryFilename = const std::string groundOfTruthBinaryFilename =
@ -118,9 +124,9 @@ void FormFinder::runUnitTests() {
// Third example of the paper // Third example of the paper
VCGEdgeMesh longSpanGrid; VCGEdgeMesh longSpanGrid;
longSpanGrid.loadFromPly(std::filesystem::path(groundOfTruthFolder) longSpanGrid.loadPly(std::filesystem::path(groundOfTruthFolder)
.append("longSpanGridshell.ply") .append("longSpanGridshell.ply")
.string()); .string());
const size_t spanGridSize = 11; const size_t spanGridSize = 11;
fixedVertices.clear(); fixedVertices.clear();
@ -174,7 +180,7 @@ void FormFinder::runUnitTests() {
SimulationResults longSpanGridshell_simulationResults = SimulationResults longSpanGridshell_simulationResults =
formFinder.executeSimulation( formFinder.executeSimulation(
std::make_shared<SimulationJob>(longSpanGridshell_simulationJob), std::make_shared<SimulationJob>(longSpanGridshell_simulationJob),
false, false); settings);
longSpanGridshell_simulationResults.save(); longSpanGridshell_simulationResults.save();
const std::string longSpan_groundOfTruthBinaryFilename = const std::string longSpan_groundOfTruthBinaryFilename =
@ -200,12 +206,7 @@ void FormFinder::runUnitTests() {
// polyscope::show(); // polyscope::show();
} }
void FormFinder::setTotalResidualForcesNormThreshold(double value) {
settings.totalResidualForcesNormThreshold = value;
}
void FormFinder::reset() { void FormFinder::reset() {
settings.Dt = settings.Dtini;
mCurrentSimulationStep = 0; mCurrentSimulationStep = 0;
history.clear(); history.clear();
constrainedVertices.clear(); constrainedVertices.clear();
@ -214,9 +215,10 @@ void FormFinder::reset() {
plotYValues.clear(); plotYValues.clear();
plotHandle.reset(); plotHandle.reset();
checkedForMaximumMoment = false; checkedForMaximumMoment = false;
shouldUseKineticEnergyThreshold = false; mSettings.shouldUseTranslationalKineticEnergyThreshold = false;
externalMomentsNorm = 0; externalMomentsNorm = 0;
settings.drawingStep = 1; mSettings.drawingStep = 1;
Dt = mSettings.Dtini;
} }
VectorType FormFinder::computeDisplacementDifferenceDerivative( VectorType FormFinder::computeDisplacementDifferenceDerivative(
@ -841,7 +843,7 @@ void FormFinder::updateResidualForcesOnTheFly(
const double e_k = element.length - element.initialLength; const double e_k = element.length - element.initialLength;
const double e_kDeriv = computeDerivativeElementLength(e, dui); const double e_kDeriv = computeDerivativeElementLength(e, dui);
const double axialForce_dofi = const double axialForce_dofi =
e_kDeriv * e_k * element.axialConstFactor; e_kDeriv * e_k * element.rigidity.axial;
// Torsional force computation // Torsional force computation
const double theta1_j_deriv = const double theta1_j_deriv =
@ -852,7 +854,7 @@ void FormFinder::updateResidualForcesOnTheFly(
const double theta1DiffDerivative = const double theta1DiffDerivative =
theta1_jplus1_deriv - theta1_j_deriv; theta1_jplus1_deriv - theta1_j_deriv;
const double torsionalForce_dofi = const double torsionalForce_dofi =
theta1DiffDerivative * theta1Diff * element.torsionConstFactor; theta1DiffDerivative * theta1Diff * element.rigidity.torsional;
// First bending force computation // First bending force computation
////theta2_j derivative ////theta2_j derivative
@ -880,8 +882,7 @@ void FormFinder::updateResidualForcesOnTheFly(
firstBendingForce_inBracketsTerm_2 + firstBendingForce_inBracketsTerm_2 +
firstBendingForce_inBracketsTerm_3; firstBendingForce_inBracketsTerm_3;
const double firstBendingForce_dofi = const double firstBendingForce_dofi =
firstBendingForce_inBracketsTerm * firstBendingForce_inBracketsTerm * element.rigidity.firstBending;
element.firstBendingConstFactor;
// Second bending force computation // Second bending force computation
////theta2_j derivative ////theta2_j derivative
@ -908,7 +909,7 @@ void FormFinder::updateResidualForcesOnTheFly(
secondBendingForce_inBracketsTerm_2 + secondBendingForce_inBracketsTerm_2 +
secondBendingForce_inBracketsTerm_3; secondBendingForce_inBracketsTerm_3;
double secondBendingForce_dofi = secondBendingForce_inBracketsTerm * double secondBendingForce_dofi = secondBendingForce_inBracketsTerm *
element.secondBendingConstFactor; element.rigidity.secondBending;
const bool shouldBreak = const bool shouldBreak =
mCurrentSimulationStep == 118 && edgeNode.vi == 1 && dofi == 3; mCurrentSimulationStep == 118 && edgeNode.vi == 1 && dofi == 3;
internalForcesContributionFromThisEdge[evi].second[dofi] = internalForcesContributionFromThisEdge[evi].second[dofi] =
@ -947,7 +948,7 @@ void FormFinder::updateResidualForcesOnTheFly(
secondBendingForce_inBracketsTerm_3; secondBendingForce_inBracketsTerm_3;
const double secondBendingForce_dofi = const double secondBendingForce_dofi =
secondBendingForce_inBracketsTerm * secondBendingForce_inBracketsTerm *
element.secondBendingConstFactor; element.rigidity.secondBending;
internalForcesContributionFromThisEdge[evi + 2].second[dofi] = internalForcesContributionFromThisEdge[evi + 2].second[dofi] =
secondBendingForce_dofi; secondBendingForce_dofi;
} }
@ -1162,24 +1163,24 @@ void FormFinder::updateNodalMasses() {
assert(rotationalSumSk_J != 0); assert(rotationalSumSk_J != 0);
} }
mesh->nodes[v].translationalMass = mesh->nodes[v].translationalMass =
gamma * pow(settings.Dtini, 2) * 2 * translationalSumSk; gamma * pow(mSettings.Dtini, 2) * 2 * translationalSumSk;
mesh->nodes[v].rotationalMass_I2 = mesh->nodes[v].rotationalMass_I2 =
gamma * pow(settings.Dtini, 2) * 8 * rotationalSumSk_I2; gamma * pow(mSettings.Dtini, 2) * 8 * rotationalSumSk_I2;
mesh->nodes[v].rotationalMass_I3 = mesh->nodes[v].rotationalMass_I3 =
gamma * pow(settings.Dtini, 2) * 8 * rotationalSumSk_I3; gamma * pow(mSettings.Dtini, 2) * 8 * rotationalSumSk_I3;
mesh->nodes[v].rotationalMass_J = mesh->nodes[v].rotationalMass_J =
gamma * pow(settings.Dtini, 2) * 8 * rotationalSumSk_J; gamma * pow(mSettings.Dtini, 2) * 8 * rotationalSumSk_J;
assert(std::pow(settings.Dtini, 2.0) * translationalSumSk / assert(std::pow(mSettings.Dtini, 2.0) * translationalSumSk /
mesh->nodes[v].translationalMass < mesh->nodes[v].translationalMass <
2); 2);
assert(std::pow(settings.Dtini, 2.0) * rotationalSumSk_I2 / assert(std::pow(mSettings.Dtini, 2.0) * rotationalSumSk_I2 /
mesh->nodes[v].rotationalMass_I2 < mesh->nodes[v].rotationalMass_I2 <
2); 2);
assert(std::pow(settings.Dtini, 2.0) * rotationalSumSk_I3 / assert(std::pow(mSettings.Dtini, 2.0) * rotationalSumSk_I3 /
mesh->nodes[v].rotationalMass_I3 < mesh->nodes[v].rotationalMass_I3 <
2); 2);
assert(std::pow(settings.Dtini, 2.0) * rotationalSumSk_J / assert(std::pow(mSettings.Dtini, 2.0) * rotationalSumSk_J /
mesh->nodes[v].rotationalMass_J < mesh->nodes[v].rotationalMass_J <
2); 2);
} }
@ -1211,7 +1212,7 @@ void FormFinder::updateNodalVelocities() {
for (VertexType &v : mesh->vert) { for (VertexType &v : mesh->vert) {
const VertexIndex vi = mesh->getIndex(v); const VertexIndex vi = mesh->getIndex(v);
Node &node = mesh->nodes[v]; Node &node = mesh->nodes[v];
node.velocity = node.velocity + node.acceleration * settings.Dt; node.velocity = node.velocity + node.acceleration * Dt;
} }
updateKineticEnergy(); updateKineticEnergy();
} }
@ -1219,14 +1220,17 @@ void FormFinder::updateNodalVelocities() {
void FormFinder::updateNodalDisplacements() { void FormFinder::updateNodalDisplacements() {
for (VertexType &v : mesh->vert) { for (VertexType &v : mesh->vert) {
Node &node = mesh->nodes[v]; Node &node = mesh->nodes[v];
node.displacements = node.displacements + node.velocity * settings.Dt; node.displacements = node.displacements + node.velocity * Dt;
if (settings.beVerbose) { // if (mSettings.beVerbose) {
std::cout << "Node " << node.vi << ":" << endl; // std::cout << "Node " << node.vi << ":" << endl;
std::cout << node.displacements[0] << " " << node.displacements[0] << " " // std::cout << node.displacements[0] << " " << node.displacements[0]
<< node.displacements[1] << " " << node.displacements[2] << " " // << " "
<< node.displacements[3] << " " << node.displacements[4] << " " // << node.displacements[1] << " " << node.displacements[2]
<< node.displacements[5] << std::endl; // << " "
} // << node.displacements[3] << " " << node.displacements[4]
// << " "
// << node.displacements[5] << std::endl;
// }
} }
} }
@ -1299,7 +1303,7 @@ void FormFinder::updateNodeNormal(
const bool viHasMoments = const bool viHasMoments =
node.force.external[3] != 0 || node.force.external[4] != 0; node.force.external[3] != 0 || node.force.external[4] != 0;
if (!checkedForMaximumMoment && viHasMoments) { if (!checkedForMaximumMoment && viHasMoments) {
shouldUseKineticEnergyThreshold = true; mSettings.shouldUseTranslationalKineticEnergyThreshold = true;
std::cout std::cout
<< "Maximum moment reached.The Kinetic energy of the system will " << "Maximum moment reached.The Kinetic energy of the system will "
"be used as a convergence criterion" "be used as a convergence criterion"
@ -1340,7 +1344,7 @@ void FormFinder::applyDisplacements(
updateNodeNormal(v, fixedVertices); updateNodeNormal(v, fixedVertices);
} }
updateElementalFrames(); updateElementalFrames();
if (settings.shouldDraw || true) { if (mSettings.shouldDraw || true) {
mesh->updateEigenEdgeAndVertices(); mesh->updateEigenEdgeAndVertices();
} }
} }
@ -1392,6 +1396,7 @@ void FormFinder::applyForcedNormals(
void FormFinder::updateKineticEnergy() { void FormFinder::updateKineticEnergy() {
mesh->previousTotalKineticEnergy = mesh->currentTotalKineticEnergy; mesh->previousTotalKineticEnergy = mesh->currentTotalKineticEnergy;
mesh->currentTotalKineticEnergy = 0; mesh->currentTotalKineticEnergy = 0;
mesh->currentTotalTranslationalKineticEnergy = 0;
for (const VertexType &v : mesh->vert) { for (const VertexType &v : mesh->vert) {
Node &node = mesh->nodes[v]; Node &node = mesh->nodes[v];
node.kineticEnergy = 0; node.kineticEnergy = 0;
@ -1399,19 +1404,21 @@ void FormFinder::updateKineticEnergy() {
const double translationalVelocityNorm = std::sqrt( const double translationalVelocityNorm = std::sqrt(
std::pow(node.velocity[0], 2) + std::pow(node.velocity[1], 2) + std::pow(node.velocity[0], 2) + std::pow(node.velocity[1], 2) +
std::pow(node.velocity[2], 2)); std::pow(node.velocity[2], 2));
node.kineticEnergy += const double nodeTranslationalKineticEnergy =
0.5 * node.translationalMass * pow(translationalVelocityNorm, 2); 0.5 * node.translationalMass * pow(translationalVelocityNorm, 2);
const double nodeRotationalKineticEnergy =
0.5 * (node.rotationalMass_J * pow(node.velocity[3], 2) +
+node.rotationalMass_I3 * pow(node.velocity[4], 2) +
+node.rotationalMass_I2 * pow(node.velocity[5], 2));
node.kineticEnergy +=
nodeTranslationalKineticEnergy /*+ nodeRotationalKineticEnergy*/;
assert(node.kineticEnergy < 10000000000000000000); assert(node.kineticEnergy < 10000000000000000000);
// const double rotationalVelocityNorm = std::sqrt(
// std::pow(node.velocity[3], 2) + std::pow(node.velocity[4], 2) +
// std::pow(node.velocity[5], 2));
// node.kineticEnergy +=
// 0.5 * node.rotationalMass_J * pow(node.velocity[3], 2) +
// 0.5 * node.rotationalMass_I3 * pow(node.velocity[4], 2) +
// 0.5 * node.rotationalMass_I2 * pow(node.velocity[5], 2);
mesh->currentTotalKineticEnergy += node.kineticEnergy; mesh->currentTotalKineticEnergy += node.kineticEnergy;
mesh->currentTotalTranslationalKineticEnergy +=
nodeTranslationalKineticEnergy;
} }
// assert(mesh->currentTotalKineticEnergy < 100000000000000); // assert(mesh->currentTotalKineticEnergy < 100000000000000);
} }
@ -1460,24 +1467,24 @@ void FormFinder::updatePositionsOnTheFly(
// assert(rotationalSumSk_J != 0); // assert(rotationalSumSk_J != 0);
} }
mesh->nodes[v].translationalMass = mesh->nodes[v].translationalMass =
gamma * pow(settings.Dtini, 2) * 2 * translationalSumSk; gamma * pow(mSettings.Dtini, 2) * 2 * translationalSumSk;
mesh->nodes[v].rotationalMass_I2 = mesh->nodes[v].rotationalMass_I2 =
gamma * pow(settings.Dtini, 2) * 8 * rotationalSumSk_I2; gamma * pow(mSettings.Dtini, 2) * 8 * rotationalSumSk_I2;
mesh->nodes[v].rotationalMass_I3 = mesh->nodes[v].rotationalMass_I3 =
gamma * pow(settings.Dtini, 2) * 8 * rotationalSumSk_I3; gamma * pow(mSettings.Dtini, 2) * 8 * rotationalSumSk_I3;
mesh->nodes[v].rotationalMass_J = mesh->nodes[v].rotationalMass_J =
gamma * pow(settings.Dtini, 2) * 8 * rotationalSumSk_J; gamma * pow(mSettings.Dtini, 2) * 8 * rotationalSumSk_J;
// assert(std::pow(Dtini, 2.0) * translationalSumSk / // assert(std::pow(mSettings.Dtini, 2.0) * translationalSumSk /
// mesh->nodes[v].translationalMass < // mesh->nodes[v].translationalMass <
// 2); // 2);
// assert(std::pow(Dtini, 2.0) * rotationalSumSk_I2 / // assert(std::pow(mSettings.Dtini, 2.0) * rotationalSumSk_I2 /
// mesh->nodes[v].rotationalMass_I2 < // mesh->nodes[v].rotationalMass_I2 <
// 2); // 2);
// assert(std::pow(Dtini, 2.0) * rotationalSumSk_I3 / // assert(std::pow(mSettings.Dtini, 2.0) * rotationalSumSk_I3 /
// mesh->nodes[v].rotationalMass_I3 < // mesh->nodes[v].rotationalMass_I3 <
// 2); // 2);
// assert(std::pow(Dtini, 2.0) * rotationalSumSk_J / // assert(std::pow(mSettings.Dtini, 2.0) * rotationalSumSk_J /
// mesh->nodes[v].rotationalMass_J < // mesh->nodes[v].rotationalMass_J <
// 2); // 2);
} }
@ -1503,13 +1510,13 @@ void FormFinder::updatePositionsOnTheFly(
for (VertexType &v : mesh->vert) { for (VertexType &v : mesh->vert) {
Node &node = mesh->nodes[v]; Node &node = mesh->nodes[v];
node.velocity = node.velocity + node.acceleration * settings.Dt; node.velocity = node.velocity + node.acceleration * Dt;
} }
updateKineticEnergy(); updateKineticEnergy();
for (VertexType &v : mesh->vert) { for (VertexType &v : mesh->vert) {
Node &node = mesh->nodes[v]; Node &node = mesh->nodes[v];
node.displacements = node.displacements + node.velocity * settings.Dt; node.displacements = node.displacements + node.velocity * Dt;
} }
for (VertexType &v : mesh->vert) { for (VertexType &v : mesh->vert) {
@ -1636,45 +1643,43 @@ void FormFinder::draw(const std::string &screenshotsFolder = {}) {
polyscope::getCurveNetwork(meshPolyscopeLabel) polyscope::getCurveNetwork(meshPolyscopeLabel)
->addNodeScalarQuantity("Internal force norm", internalForcesNorm) ->addNodeScalarQuantity("Internal force norm", internalForcesNorm)
->setEnabled(true); ->setEnabled(true);
polyscope::getCurveNetwork(meshPolyscopeLabel) // polyscope::getCurveNetwork(meshPolyscopeLabel)
->addNodeVectorQuantity("Internal Axial force", internalAxialForces) // ->addNodeVectorQuantity("Internal Axial force", internalAxialForces)
->setEnabled(false); // ->setEnabled(false);
polyscope::getCurveNetwork(meshPolyscopeLabel) // polyscope::getCurveNetwork(meshPolyscopeLabel)
->addNodeVectorQuantity("First bending force-Translation", // ->addNodeVectorQuantity("First bending force-Translation",
internalFirstBendingTranslationForces) // internalFirstBendingTranslationForces)
->setEnabled(false); // ->setEnabled(false);
polyscope::getCurveNetwork(meshPolyscopeLabel) // polyscope::getCurveNetwork(meshPolyscopeLabel)
->addNodeVectorQuantity("First bending force-Rotation", // ->addNodeVectorQuantity("First bending force-Rotation",
internalFirstBendingRotationForces) // internalFirstBendingRotationForces)
->setEnabled(false); // ->setEnabled(false);
polyscope::getCurveNetwork(meshPolyscopeLabel) // polyscope::getCurveNetwork(meshPolyscopeLabel)
->addNodeVectorQuantity("Second bending force-Translation", // ->addNodeVectorQuantity("Second bending force-Translation",
internalSecondBendingTranslationForces) // internalSecondBendingTranslationForces)
->setEnabled(false); // ->setEnabled(false);
polyscope::getCurveNetwork(meshPolyscopeLabel) // polyscope::getCurveNetwork(meshPolyscopeLabel)
->addNodeVectorQuantity("Second bending force-Rotation", // ->addNodeVectorQuantity("Second bending force-Rotation",
internalSecondBendingRotationForces); // internalSecondBendingRotationForces)
polyscope::getCurveNetwork(meshPolyscopeLabel) // ->setEnabled(false);
->getQuantity("Second bending force-Rotation") // polyscope::getCurveNetwork(meshPolyscopeLabel)
->setEnabled(false); // ->addNodeScalarQuantity("nR", nRs)
polyscope::getCurveNetwork(meshPolyscopeLabel) // ->setEnabled(false);
->addNodeScalarQuantity("nR", nRs) // polyscope::getCurveNetwork(meshPolyscopeLabel)
->setEnabled(false); // ->addNodeScalarQuantity("theta3", theta3)
polyscope::getCurveNetwork(meshPolyscopeLabel) // ->setEnabled(false);
->addNodeScalarQuantity("theta3", theta3) // polyscope::getCurveNetwork(meshPolyscopeLabel)
->setEnabled(false); // ->addNodeScalarQuantity("theta2", theta2)
polyscope::getCurveNetwork(meshPolyscopeLabel) // ->setEnabled(false);
->addNodeScalarQuantity("theta2", theta2)
->setEnabled(false);
polyscope::getCurveNetwork(meshPolyscopeLabel) polyscope::getCurveNetwork(meshPolyscopeLabel)
->addNodeVectorQuantity("Residual force", residualForces) ->addNodeVectorQuantity("Residual force", residualForces)
->setEnabled(false); ->setEnabled(false);
polyscope::getCurveNetwork(meshPolyscopeLabel) polyscope::getCurveNetwork(meshPolyscopeLabel)
->addNodeScalarQuantity("Residual force norm", residualForcesNorm) ->addNodeScalarQuantity("Residual force norm", residualForcesNorm)
->setEnabled(false); ->setEnabled(false);
polyscope::getCurveNetwork(meshPolyscopeLabel) // polyscope::getCurveNetwork(meshPolyscopeLabel)
->addNodeScalarQuantity("Node acceleration x", accelerationX); // ->addNodeScalarQuantity("Node acceleration x", accelerationX);
// Edge quantities // Edge quantities
std::vector<double> A(mesh->EN()); std::vector<double> A(mesh->EN());
@ -1706,9 +1711,9 @@ void FormFinder::draw(const std::string &screenshotsFolder = {}) {
// matching PopItemWidth() below. // matching PopItemWidth() below.
ImGui::InputInt("Simulation drawing step", ImGui::InputInt("Simulation drawing step",
&settings.drawingStep); // set a int variable &mSettings.drawingStep); // set a int variable
ImGui::Checkbox("Enable drawing", ImGui::Checkbox("Enable drawing",
&settings.shouldDraw); // set a int variable &mSettings.shouldDraw); // set a int variable
ImGui::Text("Number of simulation steps: %zu", mCurrentSimulationStep); ImGui::Text("Number of simulation steps: %zu", mCurrentSimulationStep);
ImGui::PopItemWidth(); ImGui::PopItemWidth();
@ -1733,25 +1738,35 @@ void FormFinder::draw(const std::string &screenshotsFolder = {}) {
} }
} }
void FormFinder::printCurrentState() {
std::cout << "Simulation steps executed:" << mCurrentSimulationStep
<< std::endl;
std::cout << "Residual forces norm: " << mesh->totalResidualForcesNorm
<< std::endl;
std::cout << "Kinetic energy:" << mesh->currentTotalKineticEnergy
<< std::endl;
}
void FormFinder::printDebugInfo() const {
std::cout << mesh->elements[0].rigidity.toString() << std::endl;
std::cout << "Number of dampings:" << numOfDampings << endl;
}
SimulationResults SimulationResults
FormFinder::executeSimulation(const std::shared_ptr<SimulationJob> &pJob, FormFinder::executeSimulation(const std::shared_ptr<SimulationJob> &pJob,
const bool &shouldDraw, const bool &beVerbose, const Settings &settings) {
const bool &shouldCreatePlots,
const size_t &maxDRMIterations) {
assert(pJob->pMesh.operator bool()); assert(pJob->pMesh.operator bool());
auto t1 = std::chrono::high_resolution_clock::now(); auto t1 = std::chrono::high_resolution_clock::now();
reset(); reset();
settings.shouldDraw = shouldDraw; mSettings = settings;
settings.beVerbose = beVerbose;
// if(!job.nodalExternalForces.empty()){ if (!pJob->nodalExternalForces.empty()) {
// double externalForcesNorm=0; double externalForcesNorm = 0;
// for(const auto& externalForce:job.nodalExternalForces) for (const auto &externalForce : pJob->nodalExternalForces) {
// { externalForcesNorm += externalForce.second.norm();
// externalForcesNorm+=externalForce.norm(); }
// } mSettings.totalResidualForcesNormThreshold = externalForcesNorm * 1e-3;
// setTotalResidualForcesNormThreshold(externalForcesNorm); }
// }
constrainedVertices = pJob->constrainedVertices; constrainedVertices = pJob->constrainedVertices;
if (!pJob->nodalForcedDisplacements.empty()) { if (!pJob->nodalForcedDisplacements.empty()) {
@ -1764,24 +1779,24 @@ FormFinder::executeSimulation(const std::shared_ptr<SimulationJob> &pJob,
// if (!pJob->nodalForcedNormals.empty()) { // if (!pJob->nodalForcedNormals.empty()) {
// for (std::pair<VertexIndex, Eigen::Vector3d> viNormalPair : // for (std::pair<VertexIndex, Eigen::Vector3d> viNormalPair :
// pJob->nodalForcedDisplacements) { // pJob->nodalForcedDisplacements) {
// assert(viNormalPair.second[2] >= 0); // assert(viNormalPair3second[2] >= 0);
// } // }
// } // }
mesh = std::make_unique<SimulationMesh>(*pJob->pMesh); mesh = std::make_unique<SimulationMesh>(*pJob->pMesh);
if (beVerbose) { if (mSettings.beVerbose) {
std::cout << "Executing simulation for mesh with:" << mesh->VN() std::cout << "Executing simulation for mesh with:" << mesh->VN()
<< " nodes and " << mesh->EN() << " elements." << std::endl; << " nodes and " << mesh->EN() << " elements." << std::endl;
} }
computeRigidSupports(); computeRigidSupports();
if (settings.shouldDraw || true) { if (mSettings.shouldDraw || true) {
if (!polyscope::state::initialized) { if (!polyscope::state::initialized) {
initPolyscope(); initPolyscope();
} }
polyscope::registerCurveNetwork( polyscope::registerCurveNetwork(
meshPolyscopeLabel, mesh->getEigenVertices(), mesh->getEigenEdges()); meshPolyscopeLabel, mesh->getEigenVertices(), mesh->getEigenEdges());
// registerWorldAxes(); registerWorldAxes();
} }
for (auto fixedVertex : pJob->constrainedVertices) { for (auto fixedVertex : pJob->constrainedVertices) {
assert(fixedVertex.first < mesh->VN()); assert(fixedVertex.first < mesh->VN());
@ -1821,35 +1836,38 @@ FormFinder::executeSimulation(const std::shared_ptr<SimulationJob> &pJob,
// applyForcedNormals(pJob->nodalForcedNormals); // applyForcedNormals(pJob->nodalForcedNormals);
// } // }
updateElementalLengths(); updateElementalLengths();
mesh->previousTotalPotentialEnergykN = mesh->currentTotalPotentialEnergykN;
mesh->currentTotalPotentialEnergykN = computeTotalPotentialEnergy() / 1000;
if (mCurrentSimulationStep != 0) { if (mCurrentSimulationStep != 0) {
history.stepPulse(*mesh); history.stepPulse(*mesh);
} }
if (mCurrentSimulationStep > 100000) {
shouldUseKineticEnergyThreshold = true;
}
if (mCurrentSimulationStep > 500000) { if (std::isnan(mesh->currentTotalKineticEnergy)) {
std::time_t now = time(0); std::time_t now = time(0);
std::tm *ltm = std::localtime(&now); std::tm *ltm = std::localtime(&now);
std::string dir = std::string dir = "../ProblematicSimulationJobs/" +
"../ProblematicSimulationJobs/" + std::to_string(ltm->tm_hour) + ":" + std::to_string(ltm->tm_mday) + "_" +
std::to_string(ltm->tm_min) + "_" + std::to_string(ltm->tm_mday) + std::to_string(1 + ltm->tm_mon) + "_" +
"_" + std::to_string(1 + ltm->tm_mon) + "_" + std::to_string(1900 + ltm->tm_year);
std::to_string(1900 + ltm->tm_year); const std::string subDir = std::filesystem::path(dir)
std::filesystem::create_directories(dir); .append(std::to_string(ltm->tm_hour) +
pJob->save(dir); ":" + std::to_string(ltm->tm_min))
.string();
std::filesystem::create_directories(subDir);
pJob->save(subDir);
std::cout << "Non terminating simulation found. Saved simulation job to:" std::cout << "Non terminating simulation found. Saved simulation job to:"
<< dir << std::endl; << dir << std::endl;
std::cout << "Exiting.." << std::endl; std::cout << "Exiting.." << std::endl;
FormFinder debug; // FormFinder debug;
debug.executeSimulation(pJob, true, true, true); // debug.executeSimulation(pJob, true, true, true);
std::terminate(); // std::terminate();
break;
} }
if (settings.shouldDraw && if (mSettings.shouldDraw &&
mCurrentSimulationStep % settings.drawingStep == 0) /* && mCurrentSimulationStep % mSettings.drawingStep == 0) /* &&
currentSimulationStep > maxDRMIterations*/ currentSimulationStep > maxDRMIterations*/
{ {
// std::string saveTo = std::filesystem::current_path() // std::string saveTo = std::filesystem::current_path()
@ -1866,63 +1884,75 @@ currentSimulationStep > maxDRMIterations*/
// shouldUseKineticEnergyThreshold = true; // shouldUseKineticEnergyThreshold = true;
} }
// if (mCurrentSimulationStep % 100 == 0 && mCurrentSimulationStep > if (mSettings.shouldCreatePlots && mCurrentSimulationStep % 10 == 0) {
// 100000) { printCurrentState();
// std::cout << "Current simulation step:" << mCurrentSimulationStep SimulationResultsReporter::createPlot(
// << std::endl; "Number of Steps", "Log of Kinetic energy", history.kineticEnergy);
// std::cout << "Residual forces norm: " << }
// mesh->totalResidualForcesNorm
// << std::endl;
// std::cout << "Kinetic energy:" << mesh->currentTotalKineticEnergy
// << std::endl;
// // auto yValues = history.residualForces;
// // auto xPlot = matplot::linspace(0, yValues.size(),
// yValues.size());
// // plotHandle = matplot::scatter(xPlot, yValues);
// // std::string label = "Residual forces";
// // plotHandle->legend_string(label);
// }
// t = t + Dt; // t = t + Dt;
mCurrentSimulationStep++; mCurrentSimulationStep++;
// std::cout << "Kinetic energy:" << mesh.currentTotalKineticEnergy // std::cout << "Kinetic energy:" << mesh.currentTotalKineticEnergy
// << std::endl; // << std::endl;
// std::cout << "Residual forces norm:" << mesh.totalResidualForcesNorm // std::cout << "Residual forces norm:" << mesh.totalResidualForcesNorm
// << std::endl; // << std::endl;
if (mesh->previousTotalKineticEnergy > mesh->currentTotalKineticEnergy) { // Kinetic energy convergence
if (/*mesh.totalPotentialEnergykN < 10 ||*/ if ((mSettings.shouldUseTranslationalKineticEnergyThreshold ||
mesh->totalResidualForcesNorm < mCurrentSimulationStep > 100000) &&
settings.totalResidualForcesNormThreshold || mesh->currentTotalTranslationalKineticEnergy <
(shouldUseKineticEnergyThreshold && mSettings.totalTranslationalKineticEnergyThreshold) {
mesh->currentTotalKineticEnergy < if (mSettings.beVerbose) {
settings.totalKineticEnergyThreshold)) { std::cout << "Simulation converged." << std::endl;
if (beVerbose) { printCurrentState();
std::cout << "Convergence after " << mCurrentSimulationStep std::cout << "Total potential:" << mesh->currentTotalPotentialEnergykN
<< " steps" << std::endl; << " kNm" << std::endl;
std::cout << "Residual force of magnitude:" }
<< mesh->previousTotalResidualForcesNorm << std::endl; std::cout << "Warning: The kinetic energy of the system was "
std::cout << "Kinetic energy:" << mesh->currentTotalKineticEnergy " used as a convergence criterion"
<< std::endl; << std::endl;
mesh->totalPotentialEnergykN = computeTotalPotentialEnergy() / 1000; break;
std::cout << "Total potential:" << mesh->totalPotentialEnergykN }
// Residual forces norm convergence
if (mesh->previousTotalKineticEnergy > mesh->currentTotalKineticEnergy
/*||
mesh->previousTotalPotentialEnergykN >
mesh->currentTotalPotentialEnergykN*/
/*|| mesh->currentTotalPotentialEnergykN < minPotentialEnergy*/) {
if (mesh->totalResidualForcesNorm <
mSettings.totalResidualForcesNormThreshold) {
if (mSettings.beVerbose) {
std::cout << "Simulation converged." << std::endl;
printCurrentState();
std::cout << "Total potential:" << mesh->currentTotalPotentialEnergykN
<< " kNm" << std::endl; << " kNm" << std::endl;
} }
if (shouldUseKineticEnergyThreshold) {
std::cout << "Warning: The kinetic energy of the system was "
" used as a convergence criterion"
<< std::endl;
}
break; break;
// } // }
} }
// for (VertexType &v : mesh->vert) {
// Node &node = mesh->nodes[v];
// node.displacements = node.displacements - node.velocity * Dt;
// }
// applyDisplacements(constrainedVertices);
// if (!pJob->nodalForcedDisplacements.empty()) {
// applyForcedDisplacements(
// pJob->nodalForcedDisplacements);
// }
// updateElementalLengths();
resetVelocities(); resetVelocities();
settings.Dt = settings.Dt * settings.xi; Dt = Dt * mSettings.xi;
++numOfDampings;
}
if (debug) {
printDebugInfo();
} }
} }
if (mCurrentSimulationStep == maxDRMIterations) { if (mCurrentSimulationStep == maxDRMIterations) {
std::cout << "Did not reach equilibrium before reaching the maximum number " std::cout << "Did not reach equilibrium before reaching the maximum number "
"of DRM steps (" "of DRM steps ("
<< maxDRMIterations << "). Breaking simulation" << std::endl; << maxDRMIterations << "). Breaking simulation" << std::endl;
} else if (beVerbose) { } else if (mSettings.beVerbose) {
auto t2 = std::chrono::high_resolution_clock::now(); auto t2 = std::chrono::high_resolution_clock::now();
double simulationDuration = double simulationDuration =
std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count(); std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count();
@ -1933,18 +1963,19 @@ currentSimulationStep > maxDRMIterations*/
<< simulationDuration / << simulationDuration /
(static_cast<double>(mCurrentSimulationStep) * mesh->VN()) (static_cast<double>(mCurrentSimulationStep) * mesh->VN())
<< "s" << std::endl; << "s" << std::endl;
std::cout << "Number of dampings:" << numOfDampings << endl;
} }
// mesh.printVertexCoordinates(mesh.VN() / 2); // mesh.printVertexCoordinates(mesh.VN() / 2);
if (settings.shouldDraw) { SimulationResults results = computeResults(pJob);
if (mSettings.shouldCreatePlots) {
SimulationResultsReporter reporter;
reporter.reportResults({results}, "Results", pJob->pMesh->getLabel());
}
if (mSettings.shouldDraw) {
draw(); draw();
} }
if (polyscope::hasCurveNetwork(meshPolyscopeLabel)) { if (polyscope::hasCurveNetwork(meshPolyscopeLabel)) {
polyscope::removeCurveNetwork(meshPolyscopeLabel); polyscope::removeCurveNetwork(meshPolyscopeLabel);
} }
SimulationResults results = computeResults(pJob);
if (shouldCreatePlots) {
SimulationResultsReporter reporter;
reporter.reportResults({results}, "Results", pJob->pMesh->getLabel());
}
return results; return results;
} }

View File

@ -21,27 +21,32 @@ struct DifferentiateWithRespectTo {
const VertexType &v; const VertexType &v;
const DoFType &dofi; const DoFType &dofi;
}; };
class FormFinder { class FormFinder {
public:
struct Settings { struct Settings {
bool shouldDraw{false}; bool shouldDraw{false};
bool beVerbose{false};
bool shouldCreatePlots{false};
int drawingStep{1}; int drawingStep{1};
const double totalKineticEnergyThreshold{1e-9}; double totalTranslationalKineticEnergyThreshold{1e-7};
double totalResidualForcesNormThreshold{1e-3}; double totalResidualForcesNormThreshold{1e-3};
const double Dtini{0.000001}; double Dtini{0.1};
double Dt{Dtini}; double xi{0.9969};
const double xi{0.9969}; int maxDRMIterations{0};
bool beVerbose; bool shouldUseTranslationalKineticEnergyThreshold{false};
Settings() {}
}; };
Settings settings;
private: private:
bool shouldUseKineticEnergyThreshold{false}; Settings mSettings;
double Dt{mSettings.Dtini};
bool checkedForMaximumMoment{false}; bool checkedForMaximumMoment{false};
double externalMomentsNorm{0}; double externalMomentsNorm{0};
size_t mCurrentSimulationStep{0}; size_t mCurrentSimulationStep{0};
matplot::line_handle plotHandle; matplot::line_handle plotHandle;
std::vector<double> plotYValues; std::vector<double> plotYValues;
size_t numOfDampings{0};
const std::string meshPolyscopeLabel{"Simulation mesh"}; const std::string meshPolyscopeLabel{"Simulation mesh"};
std::unique_ptr<SimulationMesh> mesh; std::unique_ptr<SimulationMesh> mesh;
@ -189,13 +194,15 @@ private:
void applyForcedNormals( void applyForcedNormals(
const std::unordered_map<VertexIndex, VectorType> nodalForcedRotations); const std::unordered_map<VertexIndex, VectorType> nodalForcedRotations);
void printCurrentState();
void printDebugInfo() const;
public: public:
FormFinder(); FormFinder();
SimulationResults executeSimulation( SimulationResults
const std::shared_ptr<SimulationJob> &pJob, executeSimulation(const std::shared_ptr<SimulationJob> &pJob,
const bool &shouldDraw = false, const bool &beVerbose = false, const Settings &settings = Settings());
const bool &createPlots = false,
const size_t &maxDRMIterations = FormFinder::maxDRMIterations);
inline static const size_t maxDRMIterations{0}; inline static const size_t maxDRMIterations{0};
static void runUnitTests(); static void runUnitTests();

View File

@ -174,7 +174,7 @@ bool VCGEdgeMesh::createSpanGrid(const size_t desiredWidth,
return true; return true;
} }
bool VCGEdgeMesh::loadFromPly(const std::string plyFilename) { bool VCGEdgeMesh::loadPly(const std::string plyFilename) {
std::string usedPath = plyFilename; std::string usedPath = plyFilename;
if (std::filesystem::path(plyFilename).is_relative()) { if (std::filesystem::path(plyFilename).is_relative()) {
@ -352,5 +352,4 @@ void VCGEdgeMesh::registerForDrawing() const {
const double drawingRadius = 0.0007; const double drawingRadius = 0.0007;
polyscope::registerCurveNetwork(label, getEigenVertices(), getEigenEdges()) polyscope::registerCurveNetwork(label, getEigenVertices(), getEigenEdges())
->setRadius(drawingRadius, false); ->setRadius(drawingRadius, false);
std::cout << "Registered:" << label << std::endl;
} }

View File

@ -66,7 +66,7 @@ public:
bool loadUsingNanoply(const std::string &plyFilename); bool loadUsingNanoply(const std::string &plyFilename);
bool loadFromPly(const std::string plyFilename); virtual bool loadPly(const std::string plyFilename);
bool savePly(const std::string plyFilename); bool savePly(const std::string plyFilename);

View File

@ -141,7 +141,7 @@ void SimulationMesh::reset() {
const vcg::Segment3<double> s(p0, p1); const vcg::Segment3<double> s(p0, p1);
element.initialLength = s.Length(); element.initialLength = s.Length();
element.length = element.initialLength; element.length = element.initialLength;
element.updateConstFactors(); element.updateRigidity();
} }
for (const VertexType &v : vert) { for (const VertexType &v : vert) {
@ -194,7 +194,7 @@ void SimulationMesh::initializeElements() {
element.initialLength = s.Length(); element.initialLength = s.Length();
element.length = element.initialLength; element.length = element.initialLength;
// Initialize const factors // Initialize const factors
element.updateConstFactors(); element.updateRigidity();
element.derivativeT1.resize( element.derivativeT1.resize(
2, std::vector<VectorType>(6, VectorType(0, 0, 0))); 2, std::vector<VectorType>(6, VectorType(0, 0, 0)));
element.derivativeT2.resize( element.derivativeT2.resize(
@ -233,14 +233,14 @@ void SimulationMesh::setBeamCrossSection(
for (size_t ei = 0; ei < EN(); ei++) { for (size_t ei = 0; ei < EN(); ei++) {
elements[ei].properties.dimensions = beamDimensions; elements[ei].properties.dimensions = beamDimensions;
elements[ei].properties.computeDimensionsProperties(beamDimensions); elements[ei].properties.computeDimensionsProperties(beamDimensions);
elements[ei].updateConstFactors(); elements[ei].updateRigidity();
} }
} }
void SimulationMesh::setBeamMaterial(const double &pr, const double &ym) { void SimulationMesh::setBeamMaterial(const double &pr, const double &ym) {
for (size_t ei = 0; ei < EN(); ei++) { for (size_t ei = 0; ei < EN(); ei++) {
elements[ei].properties.setMaterial(ElementMaterial{pr, ym}); elements[ei].properties.setMaterial(ElementMaterial{pr, ym});
elements[ei].updateConstFactors(); elements[ei].updateRigidity();
} }
} }
@ -316,7 +316,7 @@ bool SimulationMesh::loadPly(const string &plyFilename) {
if (!handleBeamProperties._handle->data.empty()) { if (!handleBeamProperties._handle->data.empty()) {
for (size_t ei = 0; ei < EN(); ei++) { for (size_t ei = 0; ei < EN(); ei++) {
elements[ei].properties = Element::Properties(handleBeamProperties[ei]); elements[ei].properties = Element::Properties(handleBeamProperties[ei]);
elements[ei].updateConstFactors(); elements[ei].updateRigidity();
} }
} }
@ -469,9 +469,9 @@ std::array<double, 6> Element::Properties::toArray() const {
return std::array<double, 6>({E, G, A, I2, I3, J}); return std::array<double, 6>({E, G, A, I2, I3, J});
} }
void Element::updateConstFactors() { void Element::updateRigidity() {
axialConstFactor = properties.E * properties.A / initialLength; rigidity.axial = properties.E * properties.A / initialLength;
torsionConstFactor = properties.G * properties.J / initialLength; rigidity.torsional = properties.G * properties.J / initialLength;
firstBendingConstFactor = 2 * properties.E * properties.I2 / initialLength; rigidity.firstBending = 2 * properties.E * properties.I2 / initialLength;
secondBendingConstFactor = 2 * properties.E * properties.I3 / initialLength; rigidity.secondBending = 2 * properties.E * properties.I3 / initialLength;
} }

View File

@ -33,15 +33,17 @@ public:
std::vector<VCGEdgeMesh::EdgePointer> std::vector<VCGEdgeMesh::EdgePointer>
getIncidentElements(const VCGEdgeMesh::VertexType &v); getIncidentElements(const VCGEdgeMesh::VertexType &v);
bool loadPly(const string &plyFilename); virtual bool loadPly(const string &plyFilename);
std::vector<CrossSectionType> getBeamDimensions(); std::vector<CrossSectionType> getBeamDimensions();
std::vector<ElementMaterial> getBeamMaterial(); std::vector<ElementMaterial> getBeamMaterial();
double previousTotalKineticEnergy{0}; double previousTotalKineticEnergy{0};
double previousTotalResidualForcesNorm{0}; double previousTotalResidualForcesNorm{0};
double currentTotalKineticEnergy{0}; double currentTotalKineticEnergy{0};
double currentTotalTranslationalKineticEnergy{0};
double totalResidualForcesNorm{0}; double totalResidualForcesNorm{0};
double totalPotentialEnergykN{0}; double currentTotalPotentialEnergykN{0};
double previousTotalPotentialEnergykN{0};
bool savePly(const std::string &plyFilename); bool savePly(const std::string &plyFilename);
void setBeamCrossSection(const CrossSectionType &beamDimensions); void setBeamCrossSection(const CrossSectionType &beamDimensions);
void setBeamMaterial(const double &pr, const double &ym); void setBeamMaterial(const double &pr, const double &ym);
@ -50,6 +52,7 @@ public:
}; };
struct Element { struct Element {
struct Properties { struct Properties {
CrossSectionType dimensions; CrossSectionType dimensions;
ElementMaterial material; ElementMaterial material;
@ -81,17 +84,28 @@ struct Element {
VectorType t3; VectorType t3;
}; };
void updateConstFactors();
EdgeIndex ei; EdgeIndex ei;
double length{0}; double length{0};
Properties properties; Properties properties;
double initialLength; double initialLength;
LocalFrame frame; LocalFrame frame;
double axialConstFactor;
double torsionConstFactor; struct Rigidity {
double firstBendingConstFactor; double axial;
double secondBendingConstFactor; double torsional;
double firstBending;
double secondBending;
std::string toString() const {
return std::string("Rigidity:") + std::string("\nAxial=") +
std::to_string(axial) + std::string("\nTorsional=") +
std::to_string(torsional) + std::string("\nFirstBending=") +
std::to_string(firstBending) + std::string("\nSecondBending=") +
std::to_string(secondBending);
}
};
Rigidity rigidity;
void updateRigidity();
VectorType f1_j; VectorType f1_j;
VectorType f1_jplus1; VectorType f1_jplus1;
VectorType f2_j; VectorType f2_j;

View File

@ -5,8 +5,16 @@
FlatPattern::FlatPattern() {} FlatPattern::FlatPattern() {}
FlatPattern::FlatPattern(const std::string &filename, bool addNormalsIfAbsent) { FlatPattern::FlatPattern(const std::string &filename, bool addNormalsIfAbsent) {
assert(std::filesystem::exists(std::filesystem::path(filename))); if (!std::filesystem::exists(std::filesystem::path(filename))) {
loadFromPly(filename); assert(false);
std::cerr << "No flat pattern with name " << filename << std::endl;
return;
}
if (!loadPly(filename)) {
assert(false);
std::cerr << "File could not be loaded " << filename << std::endl;
return;
}
if (addNormalsIfAbsent) { if (addNormalsIfAbsent) {
bool normalsAreAbsent = vert[0].cN().Norm() < 0.000001; bool normalsAreAbsent = vert[0].cN().Norm() < 0.000001;
if (normalsAreAbsent) { if (normalsAreAbsent) {

View File

@ -85,15 +85,17 @@ struct SimulationResultsReporter {
const std::string &saveTo = {}) { const std::string &saveTo = {}) {
matplot::xlabel(xLabel); matplot::xlabel(xLabel);
matplot::ylabel(yLabel); matplot::ylabel(yLabel);
matplot::figure(true); // matplot::figure(true);
// matplot::hold(matplot::on); // matplot::hold(matplot::on);
matplot::grid(matplot::on); matplot::grid(matplot::on);
auto x = matplot::linspace(0, YvaluesToPlot.size(), YvaluesToPlot.size()); auto x = matplot::linspace(0, YvaluesToPlot.size(), YvaluesToPlot.size());
matplot::scatter(x, YvaluesToPlot) matplot::scatter(x, YvaluesToPlot)
// ->marker_indices(history.redMarks) // ->marker_indices(history.redMarks)
// ->marker_indices(truncatedRedMarks) // ->marker_indices(truncatedRedMarks)
// .marker_color("r") // .marker_color("r")
->marker_size(1); // ->marker_size(1)
;
// auto greenMarksY = matplot::transform( // auto greenMarksY = matplot::transform(
// history.greenMarks, [&](auto x) { return history.kineticEnergy[x]; // history.greenMarks, [&](auto x) { return history.kineticEnergy[x];
// }); // });