Refactoring

This commit is contained in:
iasonmanolas 2021-05-24 14:43:32 +03:00
parent 6e682e1e71
commit 8793dc5408
12 changed files with 511 additions and 267 deletions

View File

@ -1,10 +1,13 @@
#ifndef CSVFILE_HPP #ifndef CSVFILE_HPP
#define CSVFILE_HPP #define CSVFILE_HPP
#include <boost/lexical_cast.hpp>
#include <boost/tokenizer.hpp>
#include <filesystem> #include <filesystem>
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <vector>
class csvFile; class csvFile;
@ -60,7 +63,46 @@ public:
csvFile &operator<<(const std::string &val) { return write(escape(val)); } csvFile &operator<<(const std::string &val) { return write(escape(val)); }
template <typename T> csvFile &operator<<(const T &val) { return write(val); } template<typename T>
csvFile &operator<<(const T &val)
{
return write(val);
}
template<typename T>
static std::vector<std::vector<T>> parse(const std::filesystem::path &csvFilepath)
{
std::vector<std::vector<T>> resultCSV;
if (!std::filesystem::exists(csvFilepath)) {
std::cerr << "The file does not exist:" << csvFilepath.string() << std::endl;
return resultCSV;
}
std::ifstream inputfile(csvFilepath.string().c_str());
if (!inputfile.is_open()) {
std::cerr << "Can't open file:" << csvFilepath.string() << std::endl;
return resultCSV;
}
std::vector<T> row;
std::string line;
using Tokenizer = boost::tokenizer<boost::escaped_list_separator<char>>;
while (std::getline(inputfile, line)) {
Tokenizer tokenizer(line);
row.resize(std::distance(tokenizer.begin(), tokenizer.end()));
std::transform(tokenizer.begin(), tokenizer.end(), row.begin(), [](const std::string &el) {
return boost::lexical_cast<T>(el);
});
// std::cout << std::endl;
// row.assign(tokenizer.begin(), tokenizer.end());
// for (const auto &el : row) {
// std::cout << el << " ";
// }
// std::cout << std::endl;
resultCSV.push_back(row);
}
return resultCSV;
}
private: private:
template <typename T> csvFile &write(const T &val) { template <typename T> csvFile &write(const T &val) {

View File

@ -22,7 +22,7 @@ void DRMSimulationModel::runUnitTests()
// mesh.createSpanGrid(spanGridSize); // mesh.createSpanGrid(spanGridSize);
beam.load(std::filesystem::path(groundOfTruthFolder).append("simpleBeam.ply").string()); beam.load(std::filesystem::path(groundOfTruthFolder).append("simpleBeam.ply").string());
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};
fixedVertices[beam.VN() - 1] = std::unordered_set<DoFType>{1, 2}; fixedVertices[beam.VN() - 1] = std::unordered_set<DoFType>{1, 2};
std::unordered_map<VertexIndex, Vector6d> nodalForces{ std::unordered_map<VertexIndex, Vector6d> nodalForces{
{beam.VN() / 2, Vector6d({0, 1000, 1000, 0, 0, 0})}}; {beam.VN() / 2, Vector6d({0, 1000, 1000, 0, 0, 0})}};
@ -45,9 +45,10 @@ void DRMSimulationModel::runUnitTests()
settings.Dtini = 0.1; settings.Dtini = 0.1;
settings.xi = 0.9969; settings.xi = 0.9969;
settings.maxDRMIterations = 0; settings.maxDRMIterations = 0;
totalResidualForcesNormThreshold = 1; formFinder.totalResidualForcesNormThreshold = 1;
// settings.shouldDraw = true; settings.shouldDraw = false;
settings.beVerbose = true; settings.beVerbose = false;
// settings.shouldCreatePlots = true;
SimulationResults simpleBeam_simulationResults SimulationResults simpleBeam_simulationResults
= formFinder.executeSimulation(std::make_shared<SimulationJob>(beamSimulationJob), settings); = formFinder.executeSimulation(std::make_shared<SimulationJob>(beamSimulationJob), settings);
simpleBeam_simulationResults.save(); simpleBeam_simulationResults.save();
@ -58,10 +59,19 @@ void DRMSimulationModel::runUnitTests()
assert(std::filesystem::exists(std::filesystem::path(simpleBeamGroundOfTruthBinaryFilename))); assert(std::filesystem::exists(std::filesystem::path(simpleBeamGroundOfTruthBinaryFilename)));
Eigen::MatrixXd simpleBeam_groundOfTruthDisplacements; Eigen::MatrixXd simpleBeam_groundOfTruthDisplacements;
Eigen::read_binary(simpleBeamGroundOfTruthBinaryFilename, simpleBeam_groundOfTruthDisplacements); Eigen::read_binary(simpleBeamGroundOfTruthBinaryFilename, simpleBeam_groundOfTruthDisplacements);
if (!simpleBeam_simulationResults.isEqual(simpleBeam_groundOfTruthDisplacements)) {
std::cerr << "Error:Beam simulation produces wrong results." << std::endl; double error;
if (!simpleBeam_simulationResults.isEqual(simpleBeam_groundOfTruthDisplacements, error)) {
std::cerr << "Error:Beam simulation produces wrong results. Error:" << error << std::endl;
// return; // return;
} }
#ifdef POLYSCOPE_DEFINED
beam.registerForDrawing();
simpleBeam_simulationResults.registerForDrawing();
polyscope::show();
beam.unregister();
simpleBeam_simulationResults.unregister();
#endif
// Second example of the paper // Second example of the paper
VCGEdgeMesh shortSpanGrid; VCGEdgeMesh shortSpanGrid;
@ -109,13 +119,21 @@ void DRMSimulationModel::runUnitTests()
// shortSpanGridshellSimulationResults.registerForDrawing( // shortSpanGridshellSimulationResults.registerForDrawing(
// shortSpanGridshellSimulationJob); // shortSpanGridshellSimulationJob);
// polyscope::show(); // polyscope::show();
assert( assert(shortSpanGridshellSimulationResults.isEqual(shortSpanGridshell_groundOfTruthDisplacements,
shortSpanGridshellSimulationResults.isEqual(shortSpanGridshell_groundOfTruthDisplacements)); error));
if (!shortSpanGridshellSimulationResults.isEqual( if (!shortSpanGridshellSimulationResults.isEqual(shortSpanGridshell_groundOfTruthDisplacements,
shortSpanGridshell_groundOfTruthDisplacements)) { error)) {
std::cerr << "Error:Short span simulation produces wrong results." << std::endl; std::cerr << "Error:Short span simulation produces wrong results. Error:" << error
return; << std::endl;
// return;
} }
#ifdef POLYSCOPE_DEFINED
shortSpanGrid.registerForDrawing();
shortSpanGridshellSimulationResults.registerForDrawing();
polyscope::show();
shortSpanGrid.unregister();
shortSpanGridshellSimulationResults.unregister();
#endif
// Third example of the paper // Third example of the paper
VCGEdgeMesh longSpanGrid; VCGEdgeMesh longSpanGrid;
@ -163,6 +181,7 @@ void DRMSimulationModel::runUnitTests()
<< std::endl; << std::endl;
} }
longSpanGridshell_simulationJob.pMesh->setBeamCrossSection(CrossSectionType{0.03, 0.026}); longSpanGridshell_simulationJob.pMesh->setBeamCrossSection(CrossSectionType{0.03, 0.026});
SimulationResults longSpanGridshell_simulationResults SimulationResults longSpanGridshell_simulationResults
= formFinder.executeSimulation(std::make_shared<SimulationJob>( = formFinder.executeSimulation(std::make_shared<SimulationJob>(
longSpanGridshell_simulationJob), longSpanGridshell_simulationJob),
@ -177,12 +196,21 @@ void DRMSimulationModel::runUnitTests()
Eigen::MatrixXd longSpanGridshell_groundOfTruthDisplacements; Eigen::MatrixXd longSpanGridshell_groundOfTruthDisplacements;
Eigen::read_binary(longSpan_groundOfTruthBinaryFilename, Eigen::read_binary(longSpan_groundOfTruthBinaryFilename,
longSpanGridshell_groundOfTruthDisplacements); longSpanGridshell_groundOfTruthDisplacements);
assert( assert(longSpanGridshell_simulationResults.isEqual(longSpanGridshell_groundOfTruthDisplacements,
longSpanGridshell_simulationResults.isEqual(longSpanGridshell_groundOfTruthDisplacements)); error));
if (!longSpanGridshell_simulationResults.isEqual(longSpanGridshell_groundOfTruthDisplacements)) { if (!longSpanGridshell_simulationResults.isEqual(longSpanGridshell_groundOfTruthDisplacements,
std::cerr << "Error:Long span simulation produces wrong results." << std::endl; error)) {
return; std::cerr << "Error:Long span simulation produces wrong results. Error:" << error
<< std::endl;
// return;
} }
#ifdef POLYSCOPE_DEFINED
longSpanGrid.registerForDrawing();
longSpanGridshell_simulationResults.registerForDrawing();
polyscope::show();
longSpanGrid.unregister();
longSpanGridshell_simulationResults.unregister();
#endif
std::cout << "Form finder unit tests succesufully passed." << std::endl; std::cout << "Form finder unit tests succesufully passed." << std::endl;
@ -1130,14 +1158,11 @@ void DRMSimulationModel::updateNodalMasses()
const double SkTranslational = elem.material.youngsModulus * elem.A / elem.length; const double SkTranslational = elem.material.youngsModulus * elem.A / elem.length;
translationalSumSk += SkTranslational; translationalSumSk += SkTranslational;
const double lengthToThe3 = std::pow(elem.length, 3); const double lengthToThe3 = std::pow(elem.length, 3);
const long double SkRotational_I2 const long double SkRotational_I2 = elem.material.youngsModulus * elem.I2
= elem.material.youngsModulus * elem.I2 / lengthToThe3;
/ lengthToThe3; // TODO: I2->t2,I3->t3,t1->polar inertia const long double SkRotational_I3 = elem.material.youngsModulus * elem.I3
const long double SkRotational_I3 / lengthToThe3;
= elem.material.youngsModulus * elem.I3 const long double SkRotational_J = elem.material.youngsModulus * elem.J / lengthToThe3;
/ lengthToThe3; // TODO: I2->t2,I3->t3,t1->polar inertia
const long double SkRotational_J = elem.material.youngsModulus * elem.J
/ lengthToThe3; // TODO: I2->t2,I3->t3,t1->polar inertia
rotationalSumSk_I2 += SkRotational_I2; rotationalSumSk_I2 += SkRotational_I2;
rotationalSumSk_I3 += SkRotational_I3; rotationalSumSk_I3 += SkRotational_I3;
rotationalSumSk_J += SkRotational_J; rotationalSumSk_J += SkRotational_J;
@ -1336,9 +1361,8 @@ void DRMSimulationModel::updateElementalFrames()
} }
void DRMSimulationModel::applyForcedDisplacements( void DRMSimulationModel::applyForcedDisplacements(
const std::unordered_map<VertexIndex, Eigen::Vector3d> nodalForcedDisplacements) const std::unordered_map<VertexIndex, Eigen::Vector3d> &nodalForcedDisplacements)
{ {
const int gradualDisplacementSteps = 500;
for (const std::pair<VertexIndex, Eigen::Vector3d> vertexIndexDisplacementPair : for (const std::pair<VertexIndex, Eigen::Vector3d> vertexIndexDisplacementPair :
nodalForcedDisplacements) { nodalForcedDisplacements) {
const VertexIndex vi = vertexIndexDisplacementPair.first; const VertexIndex vi = vertexIndexDisplacementPair.first;
@ -1347,9 +1371,9 @@ void DRMSimulationModel::applyForcedDisplacements(
VectorType displacementVector(vertexDisplacement(0), VectorType displacementVector(vertexDisplacement(0),
vertexDisplacement(1), vertexDisplacement(1),
vertexDisplacement(2)); vertexDisplacement(2));
if (mCurrentSimulationStep < gradualDisplacementSteps) { if (mCurrentSimulationStep < mSettings.gradualForcedDisplacementSteps) {
displacementVector *= mCurrentSimulationStep displacementVector *= mCurrentSimulationStep
/ static_cast<double>(gradualDisplacementSteps); / static_cast<double>(mSettings.gradualForcedDisplacementSteps);
} }
pMesh->vert[vi].P() = node.initialLocation + displacementVector; pMesh->vert[vi].P() = node.initialLocation + displacementVector;
node.displacements = Vector6d({displacementVector[0], node.displacements = Vector6d({displacementVector[0],
@ -1553,6 +1577,13 @@ void DRMSimulationModel::printCurrentState() const
std::cout << "Simulation steps executed:" << mCurrentSimulationStep << std::endl; std::cout << "Simulation steps executed:" << mCurrentSimulationStep << std::endl;
std::cout << "Residual forces norm: " << pMesh->totalResidualForcesNorm << std::endl; std::cout << "Residual forces norm: " << pMesh->totalResidualForcesNorm << std::endl;
std::cout << "Kinetic energy:" << pMesh->currentTotalKineticEnergy << std::endl; std::cout << "Kinetic energy:" << pMesh->currentTotalKineticEnergy << std::endl;
static std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
const auto timePerNodePerIteration = std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::steady_clock::now() - begin)
.count()
* 1e-6 / (mCurrentSimulationStep * pMesh->VN());
std::cout << "Total potential:" << pMesh->currentTotalPotentialEnergykN << " kNm" << std::endl;
std::cout << "time(s)/(iterations*node) = " << timePerNodePerIteration << std::endl;
} }
void DRMSimulationModel::printDebugInfo() const void DRMSimulationModel::printDebugInfo() const
@ -1694,22 +1725,26 @@ void DRMSimulationModel::draw(const std::string &screenshotsFolder)
->addEdgeScalarQuantity("I3", I3); ->addEdgeScalarQuantity("I3", I3);
// Specify the callback // Specify the callback
PolyscopeInterface::addUserCallback([&]() { static bool calledOnce = false;
// Since options::openImGuiWindowForUserCallback == true by default, if (!calledOnce) {
// we can immediately start using ImGui commands to build a UI PolyscopeInterface::addUserCallback([&]() {
// Since options::openImGuiWindowForUserCallback == true by default,
// we can immediately start using ImGui commands to build a UI
ImGui::PushItemWidth(100); // Make ui elements 100 pixels wide, ImGui::PushItemWidth(100); // Make ui elements 100 pixels wide,
// instead of full width. Must have // instead of full width. Must have
// matching PopItemWidth() below. // matching PopItemWidth() below.
ImGui::InputInt("Simulation drawing step", ImGui::InputInt("Simulation drawing step",
&mSettings.drawingStep); // set a int variable &mSettings.drawingStep); // set a int variable
ImGui::Checkbox("Enable drawing", ImGui::Checkbox("Enable drawing",
&mSettings.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();
}); });
calledOnce = true;
}
if (!screenshotsFolder.empty()) { if (!screenshotsFolder.empty()) {
static bool firstDraw = true; static bool firstDraw = true;
@ -1742,16 +1777,27 @@ SimulationResults DRMSimulationModel::executeSimulation(const std::shared_ptr<Si
for (const std::pair<VertexIndex, Vector6d> &externalForce : pJob->nodalExternalForces) { for (const std::pair<VertexIndex, Vector6d> &externalForce : pJob->nodalExternalForces) {
totalExternalForcesNorm += externalForce.second.norm(); totalExternalForcesNorm += externalForce.second.norm();
} }
totalResidualForcesNormThreshold = settings.totalExternalForcesNormPercentageTermination
* totalExternalForcesNorm;
// if (!pJob->nodalExternalForces.empty()) { if (!pJob->nodalExternalForces.empty()) {
// double externalForcesNorm = 0; totalResidualForcesNormThreshold = settings.totalExternalForcesNormPercentageTermination
// for (const auto &externalForce : pJob->nodalExternalForces) { * totalExternalForcesNorm;
// externalForcesNorm += externalForce.second.norm(); } else {
// } totalResidualForcesNormThreshold = 1;
// mSettings.totalResidualForcesNormThreshold = externalForcesNorm * 1e-2; std::cout << "No forces setted default residual forces norm threshold" << std::endl;
// } }
if (mSettings.beVerbose) {
std::cout << "totalResidualForcesNormThreshold:" << totalResidualForcesNormThreshold
<< std::endl;
}
// if (!pJob->nodalExternalForces.empty()) {
// double externalForcesNorm = 0;
// for (const auto &externalForce : pJob->nodalExternalForces) {
// externalForcesNorm += externalForce.second.norm();
// }
// mSettings.totalResidualForcesNormThreshold = externalForcesNorm * 1e-2;
// }
constrainedVertices = pJob->constrainedVertices; constrainedVertices = pJob->constrainedVertices;
if (!pJob->nodalForcedDisplacements.empty()) { if (!pJob->nodalForcedDisplacements.empty()) {
@ -1773,18 +1819,20 @@ SimulationResults DRMSimulationModel::executeSimulation(const std::shared_ptr<Si
std::cout << "Executing simulation for mesh with:" << pMesh->VN() << " nodes and " std::cout << "Executing simulation for mesh with:" << pMesh->VN() << " nodes and "
<< pMesh->EN() << " elements." << std::endl; << pMesh->EN() << " elements." << std::endl;
} }
vcg::tri::UpdateBounding<SimulationMesh>::Box(*pMesh);
computeRigidSupports(); computeRigidSupports();
for (auto fixedVertex : pJob->constrainedVertices) { for (auto fixedVertex : pJob->constrainedVertices) {
assert(fixedVertex.first < pMesh->VN()); assert(fixedVertex.first < pMesh->VN());
} }
#ifdef POLYSCOPE_DEFINED #ifdef POLYSCOPE_DEFINED
if (mSettings.shouldDraw ) { if (mSettings.shouldDraw || mSettings.isDebugMode) {
PolyscopeInterface::init(); PolyscopeInterface::init();
polyscope::registerCurveNetwork( polyscope::registerCurveNetwork(meshPolyscopeLabel,
meshPolyscopeLabel, pMesh->getEigenVertices(), pMesh->getEigenEdges()); pMesh->getEigenVertices(),
// registerWorldAxes(); pMesh->getEigenEdges());
} // registerWorldAxes();
}
#endif #endif
updateElementalFrames(); updateElementalFrames();
@ -1793,130 +1841,203 @@ SimulationResults DRMSimulationModel::executeSimulation(const std::shared_ptr<Si
shouldApplyInitialDistortion = true; shouldApplyInitialDistortion = true;
} }
updateNodalExternalForces(pJob->nodalExternalForces, constrainedVertices); updateNodalExternalForces(pJob->nodalExternalForces, constrainedVertices);
while (settings.maxDRMIterations == 0 || const size_t movingAverageSampleSize = 50;
mCurrentSimulationStep < settings.maxDRMIterations) { std::queue<double> residualForcesMovingAverageHistorySample;
// while (true) {
updateNormalDerivatives();
updateT1Derivatives();
updateRDerivatives();
updateT2Derivatives();
updateT3Derivatives();
updateResidualForcesOnTheFly(constrainedVertices);
// TODO: write parallel function for updating positions double residualForcesMovingAverageDerivativeMax = 0;
// TODO: Make a single function out of updateResidualForcesOnTheFly while (settings.maxDRMIterations == 0 || mCurrentSimulationStep < settings.maxDRMIterations) {
// updatePositionsOnTheFly // while (true) {
// updatePositionsOnTheFly(constrainedVertices); updateNormalDerivatives();
updateNodalMasses(); updateT1Derivatives();
updateNodalAccelerations(); updateRDerivatives();
updateNodalVelocities(); updateT2Derivatives();
updateNodalDisplacements(); updateT3Derivatives();
applyDisplacements(constrainedVertices); updateResidualForcesOnTheFly(constrainedVertices);
if (!pJob->nodalForcedDisplacements.empty()) {
applyForcedDisplacements(
pJob->nodalForcedDisplacements); // TODO: write parallel function for updating positions
} // TODO: Make a single function out of updateResidualForcesOnTheFly
// if (!pJob->nodalForcedNormals.empty()) { // updatePositionsOnTheFly
// applyForcedNormals(pJob->nodalForcedNormals); // updatePositionsOnTheFly(constrainedVertices);
// } updateNodalMasses();
updateElementalLengths(); updateNodalAccelerations();
// pMesh->previousTotalPotentialEnergykN = updateNodalVelocities();
// pMesh->currentTotalPotentialEnergykN; updateNodalDisplacements();
// pMesh->currentTotalPotentialEnergykN = computeTotalPotentialEnergy() / 1000; applyDisplacements(constrainedVertices);
if (!pJob->nodalForcedDisplacements.empty()) {
applyForcedDisplacements(
// if (mCurrentSimulationStep != 0) { pJob->nodalForcedDisplacements);
// history.stepPulse(*pMesh); }
// } // if (!pJob->nodalForcedNormals.empty()) {
// applyForcedNormals(pJob->nodalForcedNormals);
if (std::isnan(pMesh->currentTotalKineticEnergy)) { // }
if (mSettings.beVerbose) { updateElementalLengths();
std::cout << "Infinite kinetic energy detected.Exiting.." << std::endl; mCurrentSimulationStep++;
double sumOfDisplacementsNorm = 0;
for (size_t vi = 0; vi < pMesh->VN(); vi++) {
sumOfDisplacementsNorm += pMesh->nodes[vi].displacements.getTranslation().norm();
}
sumOfDisplacementsNorm /= pMesh->bbox.Diag();
pMesh->sumOfNormalizedDisplacementNorms = sumOfDisplacementsNorm;
// pMesh->residualForcesMovingAverage = (pMesh->totalResidualForcesNorm
// + mCurrentSimulationStep
// * pMesh->residualForcesMovingAverage)
// / (1 + mCurrentSimulationStep);
pMesh->residualForcesMovingAverage += pMesh->totalResidualForcesNorm
/ movingAverageSampleSize;
residualForcesMovingAverageHistorySample.push(pMesh->residualForcesMovingAverage);
if (movingAverageSampleSize < residualForcesMovingAverageHistorySample.size()) {
const double firstElementValue = residualForcesMovingAverageHistorySample.front();
pMesh->residualForcesMovingAverage -= firstElementValue / movingAverageSampleSize;
residualForcesMovingAverageHistorySample.pop();
pMesh->residualForcesMovingAverageDerivativeNorm
= std::abs((residualForcesMovingAverageHistorySample.back()
- residualForcesMovingAverageHistorySample.front()))
/ (movingAverageSampleSize);
residualForcesMovingAverageDerivativeMax
= std::max(pMesh->residualForcesMovingAverageDerivativeNorm,
residualForcesMovingAverageDerivativeMax);
pMesh->residualForcesMovingAverageDerivativeNorm
/= residualForcesMovingAverageDerivativeMax;
// std::cout << "Normalized derivative:"
// << residualForcesMovingAverageDerivativeNorm
// << std::endl;
}
// pMesh->previousTotalPotentialEnergykN =
// pMesh->currentTotalPotentialEnergykN;
// pMesh->currentTotalPotentialEnergykN = computeTotalPotentialEnergy() / 1000;
// timePerNodePerIterationHistor.push_back(timePerNodePerIteration);
if (mSettings.beVerbose && mSettings.isDebugMode
&& mCurrentSimulationStep % mSettings.debugModeStep == 0) {
printCurrentState();
// SimulationResultsReporter::createPlot("Number of Steps",
// "Residual Forces mov aver",
// movingAverages);
// SimulationResultsReporter::createPlot("Number of Steps",
// "Residual Forces mov aver deriv",
// movingAveragesDerivatives);
// draw();
std::cout << "Mov aver deriv:" << pMesh->residualForcesMovingAverageDerivativeNorm
<< std::endl;
// SimulationResulnodalForcedDisplacementstsReporter::createPlot("Number of Steps",
// "Time/(#nodes*#iterations)",
// timePerNodePerIterationHistory);
}
if ((mSettings.shouldCreatePlots || mSettings.isDebugMode) && mCurrentSimulationStep != 0) {
history.stepPulse(*pMesh);
}
if (std::isnan(pMesh->currentTotalKineticEnergy)) {
if (mSettings.beVerbose) {
std::cout << "Infinite kinetic energy detected.Exiting.." << std::endl;
}
break;
} }
break;
}
#ifdef POLYSCOPE_DEFINED #ifdef POLYSCOPE_DEFINED
if (mSettings.shouldDraw && mCurrentSimulationStep % mSettings.drawingStep == 0) /* && if ((mSettings.shouldDraw && mCurrentSimulationStep % mSettings.drawingStep == 0)
|| (mSettings.isDebugMode && mCurrentSimulationStep % mSettings.debugModeStep == 0)) /* &&
currentSimulationStep > maxDRMIterations*/ currentSimulationStep > maxDRMIterations*/
{ {
// std::string saveTo = std::filesystem::current_path() // std::string saveTo = std::filesystem::current_path()
// .append("Debugging_files") // .append("Debugging_files")
// .append("Screenshots") // .append("Screenshots")
// .string(); // .string();
draw(); draw();
// yValues = history.kineticEnergy; // yValues = history.kineticEnergy;
// plotHandle = matplot::scatter(xPlot, yValues); // plotHandle = matplot::scatter(xPlot, yValues);
// label = "Log of Kinetic energy"; // label = "Log of Kinetic energy";
// plotHandle->legend_string(label); // plotHandle->legend_string(label);
// shouldUseKineticEnergyThreshold = true; // shouldUseKineticEnergyThreshold = true;
} }
#endif #endif
if (mSettings.shouldCreatePlots && mCurrentSimulationStep % 10 == 0) { if (mSettings.isDebugMode && mCurrentSimulationStep % mSettings.debugModeStep == 0) {
printCurrentState(); // SimulationResultsReporter::createPlot("Number of Steps",
SimulationResultsReporter::createPlot( // "Residual Forces mov aver deriv",
"Number of Steps", "Log of Kinetic energy", history.kineticEnergy); // movingAveragesDerivatives_norm);
} SimulationResultsReporter::createPlot("Number of Steps",
// t = t + Dt; "Residual Forces mov aver",
mCurrentSimulationStep++; history.residualForcesMovingAverage);
// std::cout << "Kinetic energy:" << mesh.currentTotalKineticEnergy // SimulationResultsReporter::createPlot("Number of Steps",
// << std::endl; // "Residual Forces",
// std::cout << "Residual forces norm:" << mesh.totalResidualForcesNorm // history.residualForces);
// << std::endl; // SimulationResultsReporter::createPlot("Number of Steps",
// Kinetic energy convergence // "Log of Kinetic energy",
if ((mSettings.shouldUseTranslationalKineticEnergyThreshold || mCurrentSimulationStep > 500000) // history.kineticEnergy);
&& pMesh->currentTotalTranslationalKineticEnergy }
< mSettings.totalTranslationalKineticEnergyThreshold) { // t = t + Dt;
if (mSettings.beVerbose) { // std::cout << "Kinetic energy:" << mesh.currentTotalKineticEnergy
std::cout << "Simulation converged." << std::endl; // << std::endl;
printCurrentState(); // std::cout << "Residual forces norm:" << mesh.totalResidualForcesNorm
std::cout << "Total potential:" << pMesh->currentTotalPotentialEnergykN << " kNm" // << std::endl;
<< std::endl; // Residual forces norm convergence
} if (pMesh->previousTotalKineticEnergy > pMesh->currentTotalKineticEnergy
#ifdef POLYSCOPE_DEFINED && mCurrentSimulationStep > movingAverageSampleSize
std::cout << "Warning: The kinetic energy of the system was " && (pJob->nodalForcedDisplacements.empty()
" used as a convergence criterion" || mCurrentSimulationStep > mSettings.gradualForcedDisplacementSteps)
<< std::endl; /*||
#endif
break;
}
// Residual forces norm convergence
if (pMesh->previousTotalKineticEnergy > pMesh->currentTotalKineticEnergy
/*||
mesh->previousTotalPotentialEnergykN > mesh->previousTotalPotentialEnergykN >
mesh->currentTotalPotentialEnergykN*/ mesh->currentTotalPotentialEnergykN*/
/*|| mesh->currentTotalPotentialEnergykN < minPotentialEnergy*/) { /*|| mesh->currentTotalPotentialEnergykN < minPotentialEnergy*/) {
if (pMesh->totalResidualForcesNorm < totalResidualForcesNormThreshold) { // if (pMesh->totalResidualForcesNorm < totalResidualForcesNormThreshold) {
if (mSettings.beVerbose) { const bool fullfillsKineticEnergyTerminationCriterion
std::cout << "Simulation converged." << std::endl; = mSettings.shouldUseTranslationalKineticEnergyThreshold
printCurrentState(); && pMesh->currentTotalTranslationalKineticEnergy
std::cout << "Total potential:" << pMesh->currentTotalPotentialEnergykN << " kNm" < mSettings.totalTranslationalKineticEnergyThreshold
<< std::endl; && mCurrentSimulationStep > 20 && numOfDampings > 2;
} const bool fullfillsResidualForcesNormTerminationCriterion
break; = pMesh->totalResidualForcesNorm < totalResidualForcesNormThreshold;
// } const bool fullfillsMovingAverageNormTerminationCriterion
} = pMesh->residualForcesMovingAverage
// printCurrentState(); < mSettings.residualForcesMovingAverageNormThreshold;
// for (VertexType &v : mesh->vert) { /*pMesh->residualForcesMovingAverage < totalResidualForcesNormThreshold*/
// Node &node = mesh->nodes[v]; const bool shouldTerminate
// node.displacements = node.displacements - node.velocity * Dt; = fullfillsKineticEnergyTerminationCriterion
// } // || fullfillsMovingAverageNormTerminationCriterion
// applyDisplacements(constrainedVertices); || fullfillsResidualForcesNormTerminationCriterion;
// if (!pJob->nodalForcedDisplacements.empty()) { if (shouldTerminate) {
// applyForcedDisplacements( if (mSettings.beVerbose) {
std::cout << "Simulation converged." << std::endl;
printCurrentState();
if (fullfillsResidualForcesNormTerminationCriterion) {
std::cout << "Converged using residual forces norm threshold criterion"
<< std::endl;
} else if (fullfillsKineticEnergyTerminationCriterion) {
std::cout << "Warning: The kinetic energy of the system was "
" used as a convergence criterion"
<< std::endl;
} else if (fullfillsMovingAverageNormTerminationCriterion) {
std::cout << "Converged using residual forces moving average derivative norm "
"threshold criterion"
<< std::endl;
}
}
break;
// }
}
// printCurrentState();
// 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); // pJob->nodalForcedDisplacements);
// } // }
// updateElementalLengths(); // updateElementalLengths();
resetVelocities(); resetVelocities();
Dt = Dt * mSettings.xi; Dt = Dt * mSettings.xi;
++numOfDampings; ++numOfDampings;
} // std::cout << "Number of dampings:" << numOfDampings << endl;
}
if (mSettings.debugMessages) {
printDebugInfo();
}
} }
SimulationResults results = computeResults(pJob); SimulationResults results = computeResults(pJob);
@ -1929,20 +2050,21 @@ mesh->currentTotalPotentialEnergykN*/
<< std::endl; << std::endl;
results.converged = false; results.converged = false;
} else if (std::isnan(pMesh->currentTotalKineticEnergy)) { } else if (std::isnan(pMesh->currentTotalKineticEnergy)) {
results.converged = false; std::cerr << "Simulation did not converge due to infinite kinetic energy." << std::endl;
results.converged = false;
} else if (mSettings.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)
std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count(); .count();
simulationDuration /= 1000; simulationDuration /= 1000;
std::cout << "Simulation converged after " << simulationDuration << "s" std::cout << "Simulation converged after " << simulationDuration << "s" << std::endl;
<< std::endl; std::cout << "Time/(node*iteration) "
std::cout << "Time/(node*iteration) " << simulationDuration / (static_cast<double>(mCurrentSimulationStep) * pMesh->VN())
<< simulationDuration / << "s" << std::endl;
(static_cast<double>(mCurrentSimulationStep) * pMesh->VN()) std::cout << "Number of dampings:" << numOfDampings << endl;
<< "s" << std::endl; std::cout << "Number of steps:" << mCurrentSimulationStep << endl;
std::cout << "Number of dampings:" << numOfDampings << endl; results.converged = true;
} }
// mesh.printVertexCoordinates(mesh.VN() / 2); // mesh.printVertexCoordinates(mesh.VN() / 2);
#ifdef POLYSCOPE_DEFINED #ifdef POLYSCOPE_DEFINED
@ -1994,7 +2116,7 @@ mesh->currentTotalPotentialEnergykN*/
} }
} }
if (mSettings.shouldCreatePlots) { if (mSettings.shouldCreatePlots && results.converged) {
SimulationResultsReporter reporter; SimulationResultsReporter reporter;
reporter.reportResults({results}, "Results", pJob->pMesh->getLabel()); reporter.reportResults({results}, "Results", pJob->pMesh->getLabel());
} }

View File

@ -23,28 +23,33 @@ struct DifferentiateWithRespectTo {
class DRMSimulationModel class DRMSimulationModel
{ {
public: public:
struct Settings { struct Settings
bool debugMessages{false}; {
bool shouldDraw{false}; bool isDebugMode{false};
bool beVerbose{false}; int debugModeStep{10000};
bool shouldCreatePlots{false}; bool shouldDraw{false};
int drawingStep{1}; bool beVerbose{false};
double totalTranslationalKineticEnergyThreshold{1e-10}; bool shouldCreatePlots{false};
double totalExternalForcesNormPercentageTermination{1e-3}; int drawingStep{1};
double Dtini{0.1}; double totalTranslationalKineticEnergyThreshold{1e-10};
double xi{0.9969}; double totalExternalForcesNormPercentageTermination{1e-3};
int maxDRMIterations{0}; double residualForcesMovingAverageDerivativeNormThreshold{1e-8};
bool shouldUseTranslationalKineticEnergyThreshold{false}; double residualForcesMovingAverageNormThreshold{1e-8};
Settings() {} double Dtini{0.1};
}; double xi{0.9969};
int maxDRMIterations{0};
bool shouldUseTranslationalKineticEnergyThreshold{false};
int gradualForcedDisplacementSteps{100};
Settings() {}
};
double totalResidualForcesNormThreshold{1};
private: private:
Settings mSettings; Settings mSettings;
double Dt{mSettings.Dtini}; double Dt{mSettings.Dtini};
bool checkedForMaximumMoment{false}; bool checkedForMaximumMoment{false};
double externalMomentsNorm{0}; double externalMomentsNorm{0};
size_t mCurrentSimulationStep{0}; size_t mCurrentSimulationStep{0};
double totalResidualForcesNormThreshold{1e-3};
matplot::line_handle plotHandle; matplot::line_handle plotHandle;
std::vector<double> plotYValues; std::vector<double> plotYValues;
size_t numOfDampings{0}; size_t numOfDampings{0};
@ -80,8 +85,7 @@ private:
void updateNodalDisplacements(); void updateNodalDisplacements();
void applyForcedDisplacements( void applyForcedDisplacements(
const std::unordered_map<VertexIndex, Eigen::Vector3d> const std::unordered_map<VertexIndex, Eigen::Vector3d> &nodalForcedDisplacements);
nodalForcedDisplacements);
Vector6d computeElementTorsionalForce( Vector6d computeElementTorsionalForce(
const Element &element, const Vector6d &displacementDifference, const Element &element, const Vector6d &displacementDifference,
@ -208,8 +212,7 @@ private:
executeSimulation(const std::shared_ptr<SimulationJob> &pJob, executeSimulation(const std::shared_ptr<SimulationJob> &pJob,
const Settings &settings = Settings()); const Settings &settings = Settings());
void runUnitTests(); static void runUnitTests();
void setTotalResidualForcesNormThreshold(double value);
}; };
template <typename PointType> PointType Cross(PointType p1, PointType p2) { template <typename PointType> PointType Cross(PointType p1, PointType p2) {

View File

@ -200,7 +200,6 @@ bool VCGEdgeMesh::load(const string &plyFilename) {
getEdges(eigenEdges); getEdges(eigenEdges);
getVertices(eigenVertices); getVertices(eigenVertices);
vcg::tri::UpdateTopology<VCGEdgeMesh>::VertexEdge(*this); vcg::tri::UpdateTopology<VCGEdgeMesh>::VertexEdge(*this);
label = std::filesystem::path(plyFilename).stem().string();
const bool printDebugInfo = false; const bool printDebugInfo = false;
if (printDebugInfo) { if (printDebugInfo) {
@ -208,7 +207,7 @@ bool VCGEdgeMesh::load(const string &plyFilename) {
std::cout << "Mesh has " << EN() << " edges." << std::endl; std::cout << "Mesh has " << EN() << " edges." << std::endl;
} }
label=std::filesystem::path(plyFilename).stem(); label = std::filesystem::path(plyFilename).stem().string();
return true; return true;
} }

View File

@ -126,12 +126,14 @@ struct Colors
} }
xRange x; xRange x;
x.fromString(json.at(jsonXRangeKey)); x.fromString(json.at(jsonXRangeKey));
xRanges.push_back(x);
xRangeIndex++; xRangeIndex++;
} }
numberOfFunctionCalls = json.at(JsonKeys::NumberOfFunctionCalls); numberOfFunctionCalls = json.at(JsonKeys::NumberOfFunctionCalls);
solverAccuracy = json.at(JsonKeys::SolverAccuracy); solverAccuracy = json.at(JsonKeys::SolverAccuracy);
objectiveWeights.translational = json.at(JsonKeys::TranslationalObjectiveWeight); objectiveWeights.translational = json.at(JsonKeys::TranslationalObjectiveWeight);
objectiveWeights.rotational = 2 - objectiveWeights.translational;
return true; return true;
} }
@ -197,6 +199,7 @@ struct Colors
inline void updateMeshWithOptimalVariables(const std::vector<double> &x, SimulationMesh &m) inline void updateMeshWithOptimalVariables(const std::vector<double> &x, SimulationMesh &m)
{ {
assert(CrossSectionType::name == RectangularBeamDimensions::name);
const double E = x[0]; const double E = x[0];
const double A = x[1]; const double A = x[1];
const double beamWidth = std::sqrt(A); const double beamWidth = std::sqrt(A);
@ -207,7 +210,7 @@ struct Colors
const double I3 = x[4]; const double I3 = x[4];
for (EdgeIndex ei = 0; ei < m.EN(); ei++) { for (EdgeIndex ei = 0; ei < m.EN(); ei++) {
Element &e = m.elements[ei]; Element &e = m.elements[ei];
e.setDimensions(RectangularBeamDimensions(beamWidth, beamHeight)); e.setDimensions(CrossSectionType(beamWidth, beamHeight));
e.setMaterial(ElementMaterial(e.material.poissonsRatio, E)); e.setMaterial(ElementMaterial(e.material.poissonsRatio, E));
e.J = J; e.J = J;
e.I2 = I2; e.I2 = I2;
@ -494,6 +497,7 @@ struct Colors
const ReducedPatternOptimization::Results &reducedPattern_optimizationResults, const ReducedPatternOptimization::Results &reducedPattern_optimizationResults,
const shared_ptr<SimulationMesh> &pTiledReducedPattern_simulationMesh) const shared_ptr<SimulationMesh> &pTiledReducedPattern_simulationMesh)
{ {
assert(CrossSectionType::name == RectangularBeamDimensions::name);
// Set reduced parameters fron the optimization results // Set reduced parameters fron the optimization results
std::unordered_map<std::string, double> std::unordered_map<std::string, double>
optimalXVariables(reducedPattern_optimizationResults.optimalXNameValuePairs.begin(), optimalXVariables(reducedPattern_optimizationResults.optimalXNameValuePairs.begin(),
@ -504,7 +508,7 @@ struct Colors
const double A = optimalXVariables.at(ALabel); const double A = optimalXVariables.at(ALabel);
const double beamWidth = std::sqrt(A); const double beamWidth = std::sqrt(A);
const double beamHeight = beamWidth; const double beamHeight = beamWidth;
RectangularBeamDimensions elementDimensions(beamWidth, beamHeight); CrossSectionType elementDimensions(beamWidth, beamHeight);
const double poissonsRatio = 0.3; const double poissonsRatio = 0.3;
const std::string ymLabel = "E"; const std::string ymLabel = "E";

View File

@ -9,11 +9,14 @@ struct SimulationHistory {
size_t numberOfSteps{0}; size_t numberOfSteps{0};
std::string label; std::string label;
std::vector<double> residualForces; std::vector<double> residualForcesLog;
std::vector<double> kineticEnergy; std::vector<double> kineticEnergy;
std::vector<double> potentialEnergies; std::vector<double> potentialEnergies;
std::vector<size_t> redMarks; std::vector<size_t> redMarks;
std::vector<double> greenMarks; std::vector<double> greenMarks;
std::vector<double> residualForcesMovingAverage;
std::vector<double> sumOfNormalizedDisplacementNorms;
// std::vector<double> residualForcesMovingAverageDerivativesLog;
void markRed(const size_t &stepNumber) { redMarks.push_back(stepNumber); } void markRed(const size_t &stepNumber) { redMarks.push_back(stepNumber); }
@ -22,13 +25,21 @@ struct SimulationHistory {
void stepPulse(const SimulationMesh &mesh) { void stepPulse(const SimulationMesh &mesh) {
kineticEnergy.push_back(log(mesh.currentTotalKineticEnergy)); kineticEnergy.push_back(log(mesh.currentTotalKineticEnergy));
// potentialEnergy.push_back(mesh.totalPotentialEnergykN); // potentialEnergy.push_back(mesh.totalPotentialEnergykN);
residualForces.push_back(mesh.totalResidualForcesNorm); residualForcesLog.push_back(std::log(mesh.totalResidualForcesNorm));
residualForcesMovingAverage.push_back(mesh.residualForcesMovingAverage);
sumOfNormalizedDisplacementNorms.push_back(mesh.sumOfNormalizedDisplacementNorms);
// residualForcesMovingAverageDerivativesLog.push_back(
// std::log(mesh.residualForcesMovingAverageDerivativeNorm));
} }
void clear() { void clear()
residualForces.clear(); {
kineticEnergy.clear(); residualForcesLog.clear();
potentialEnergies.clear(); kineticEnergy.clear();
potentialEnergies.clear();
residualForcesMovingAverage.clear();
sumOfNormalizedDisplacementNorms.clear();
// residualForcesMovingAverageDerivativesLog.clear();
} }
}; };
@ -399,6 +410,9 @@ public:
} }
void unregister(const std::string &meshLabel) void unregister(const std::string &meshLabel)
{ {
if (polyscope::getCurveNetwork(meshLabel) == nullptr) {
return;
}
polyscope::getCurveNetwork(meshLabel)->removeQuantity("External force_" + label); polyscope::getCurveNetwork(meshLabel)->removeQuantity("External force_" + label);
polyscope::getCurveNetwork(meshLabel)->removeQuantity("Boundary conditions_" + label); polyscope::getCurveNetwork(meshLabel)->removeQuantity("Boundary conditions_" + label);
} }
@ -478,23 +492,29 @@ struct SimulationResults
void save(const std::string &outputFolder = std::string()) void save(const std::string &outputFolder = std::string())
{ {
const std::filesystem::path outputPath(outputFolder); const std::filesystem::path outputFolderPath = outputFolder.empty()
job->save(std::filesystem::path(outputPath).append("SimulationJob").string()); ? std::filesystem::current_path()
: std::filesystem::path(outputFolder);
std::filesystem::path simulationJobOutputFolderPath
= std::filesystem::path(outputFolderPath).append("SimulationJob");
std::filesystem::create_directories(simulationJobOutputFolderPath);
job->save(simulationJobOutputFolderPath);
const std::string filename(getLabel() + "_displacements.eigenBin"); const std::string filename(getLabel() + "_displacements.eigenBin");
Eigen::MatrixXd m = Utilities::toEigenMatrix(displacements); Eigen::MatrixXd m = Utilities::toEigenMatrix(displacements);
Eigen::write_binary(std::filesystem::path(outputPath).append(filename).string(), m); Eigen::write_binary(std::filesystem::path(outputFolderPath).append(filename).string(), m);
saveDeformedModel(outputFolder); saveDeformedModel(outputFolderPath);
} }
// The comparison of the results happens comparing the 6-dof nodal // The comparison of the results happens comparing the 6-dof nodal
// displacements // displacements
bool isEqual(const Eigen::MatrixXd &nodalDisplacements) bool isEqual(const Eigen::MatrixXd &nodalDisplacements, double &error)
{ {
assert(nodalDisplacements.cols() == 6); assert(nodalDisplacements.cols() == 6);
Eigen::MatrixXd eigenDisplacements = Utilities::toEigenMatrix(this->displacements); Eigen::MatrixXd eigenDisplacements = Utilities::toEigenMatrix(this->displacements);
const double errorNorm = (eigenDisplacements - nodalDisplacements).norm(); const double errorNorm = (eigenDisplacements - nodalDisplacements).norm();
error = errorNorm;
return errorNorm < 1e-10; return errorNorm < 1e-10;
// return eigenDisplacements.isApprox(nodalDisplacements); // return eigenDisplacements.isApprox(nodalDisplacements);
} }

View File

@ -38,11 +38,11 @@ struct SimulationResultsReporter {
file << "\n"; file << "\n";
} }
if (!history.residualForces.empty()) { if (!history.residualForcesLog.empty()) {
file << "Residual forces" file << "Residual forces"
<< "\n"; << "\n";
for (size_t step = 0; step < numberOfSteps; step++) { for (size_t step = 0; step < numberOfSteps; step++) {
file << history.residualForces[step] << "\n"; file << history.residualForcesLog[step] << "\n";
} }
file << "\n"; file << "\n";
} }
@ -92,27 +92,31 @@ struct SimulationResultsReporter {
} }
} }
static void createPlot(const std::string &xLabel, const std::string &yLabel, static void createPlot(const std::string &xLabel,
const std::string &yLabel,
const std::vector<double> &YvaluesToPlot, const std::vector<double> &YvaluesToPlot,
const std::string &saveTo = {}) { const std::string &saveTo = {})
auto x = {
matplot::linspace(0, YvaluesToPlot.size() - 1, YvaluesToPlot.size()); if (YvaluesToPlot.size() < 2) {
createPlot(xLabel, yLabel, x, YvaluesToPlot, saveTo); return;
// matplot::figure(true); }
// matplot::hold(matplot::on); auto x = matplot::linspace(0, YvaluesToPlot.size() - 1, YvaluesToPlot.size());
createPlot(xLabel, yLabel, x, YvaluesToPlot, saveTo);
// matplot::figure(true);
// matplot::hold(matplot::on);
// ->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];
// }); // });
// matplot::scatter(history.greenMarks, greenMarksY) // matplot::scatter(history.greenMarks, greenMarksY)
// ->color("green") // ->color("green")
// .marker_size(10); // .marker_size(10);
// matplot::hold(matplot::off); // matplot::hold(matplot::off);
} }
void createPlots(const SimulationHistory &history, void createPlots(const SimulationHistory &history,
@ -124,27 +128,54 @@ struct SimulationResultsReporter {
std::filesystem::create_directory(graphsFolder.string()); std::filesystem::create_directory(graphsFolder.string());
if (!history.kineticEnergy.empty()) { if (!history.kineticEnergy.empty()) {
createPlot("Number of Iterations", "Log of Kinetic Energy", createPlot("Number of Iterations",
history.kineticEnergy, "Log of Kinetic Energy log",
std::filesystem::path(graphsFolder) history.kineticEnergy,
.append("KineticEnergy" + graphSuffix + ".png") std::filesystem::path(graphsFolder)
.string()); .append("KineticEnergyLog_" + graphSuffix + ".png")
.string());
} }
if (!history.residualForces.empty()) { if (!history.residualForcesLog.empty()) {
createPlot("Number of Iterations", "Residual Forces norm", createPlot("Number of Iterations",
history.residualForces, "Residual Forces norm log",
std::filesystem::path(graphsFolder) history.residualForcesLog,
.append("ResidualForces" + graphSuffix + ".png") std::filesystem::path(graphsFolder)
.string()); .append("ResidualForcesLog_" + graphSuffix + ".png")
.string());
} }
if (!history.potentialEnergies.empty()) { if (!history.potentialEnergies.empty()) {
createPlot("Number of Iterations", "Potential energy", createPlot("Number of Iterations",
history.potentialEnergies, "Potential energy",
std::filesystem::path(graphsFolder) history.potentialEnergies,
.append("PotentialEnergy" + graphSuffix + ".png") std::filesystem::path(graphsFolder)
.string()); .append("PotentialEnergy_" + graphSuffix + ".png")
.string());
}
if (!history.residualForcesMovingAverage.empty()) {
createPlot("Number of Iterations",
"Residual forces moving average",
history.residualForcesMovingAverage,
std::filesystem::path(graphsFolder)
.append("ResidualForcesMovingAverage_" + graphSuffix + ".png")
.string());
}
// if (!history.residualForcesMovingAverageDerivativesLog.empty()) {
// createPlot("Number of Iterations",
// "Residual forces moving average derivative log",
// history.residualForcesMovingAverageDerivativesLog,
// std::filesystem::path(graphsFolder)
// .append("ResidualForcesMovingAverageDerivativesLog_" + graphSuffix + ".png")
// .string());
// }
if (!history.sumOfNormalizedDisplacementNorms.empty()) {
createPlot("Number of Iterations",
"Sum of normalized displacement norms",
history.sumOfNormalizedDisplacementNorms,
std::filesystem::path(graphsFolder)
.append("SumOfNormalizedDisplacementNorms_" + graphSuffix + ".png")
.string());
} }
} }
}; };

View File

@ -9,7 +9,7 @@
struct Element; struct Element;
struct Node; struct Node;
using CrossSectionType = RectangularBeamDimensions; using CrossSectionType = RectangularBeamDimensions;
// using CrossSectionType = CylindricalBeamDimensions; //using CrossSectionType = CylindricalBeamDimensions;
class SimulationMesh : public VCGEdgeMesh { class SimulationMesh : public VCGEdgeMesh {
private: private:
@ -44,6 +44,9 @@ public:
double totalResidualForcesNorm{0}; double totalResidualForcesNorm{0};
double currentTotalPotentialEnergykN{0}; double currentTotalPotentialEnergykN{0};
double previousTotalPotentialEnergykN{0}; double previousTotalPotentialEnergykN{0};
double residualForcesMovingAverageDerivativeNorm{0};
double residualForcesMovingAverage{0};
double sumOfNormalizedDisplacementNorms{0};
bool save(const std::string &plyFilename = std::string()); bool save(const std::string &plyFilename = std::string());
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);

View File

@ -464,7 +464,7 @@ void TopologyEnumerator::computeValidPatterns(
const bool tiledPatternHasEdgesWithAngleSmallerThanThreshold const bool tiledPatternHasEdgesWithAngleSmallerThanThreshold
= patternGeometry.hasAngleSmallerThanThreshold(numberOfNodesPerSlot, 5); = patternGeometry.hasAngleSmallerThanThreshold(numberOfNodesPerSlot, 5);
if (tiledPatternHasEdgesWithAngleSmallerThanThreshold) { if (tiledPatternHasEdgesWithAngleSmallerThanThreshold) {
if (debugIsOn || savePlyFiles) { if (debugIsOn /*|| savePlyFiles*/) {
if (savePlyFiles) { if (savePlyFiles) {
auto danglingEdgesPath = std::filesystem::path(resultsPath) auto danglingEdgesPath = std::filesystem::path(resultsPath)
.append("ExceedingAngleThreshold"); .append("ExceedingAngleThreshold");

View File

@ -435,7 +435,7 @@ bool PatternGeometry::hasAngleSmallerThanThreshold(const std::vector<size_t> &nu
thetaAnglesOfIncidentVectors[thetaAngleIndex] thetaAnglesOfIncidentVectors[thetaAngleIndex]
- thetaAnglesOfIncidentVectors[thetaAngleIndex - 1]); - thetaAnglesOfIncidentVectors[thetaAngleIndex - 1]);
if (absAngleDifference < angleThreshold_rad if (absAngleDifference < angleThreshold_rad
&& absAngleDifference > vcg::math::ToRad(0.01)) { /*&& absAngleDifference > vcg::math::ToRad(0.01)*/) {
// std::cout << "Found angDiff:" << absAngleDifference << std::endl; // std::cout << "Found angDiff:" << absAngleDifference << std::endl;
// vert[vi].C() = vcg::Color4b::Magenta; // vert[vi].C() = vcg::Color4b::Magenta;
// hasAngleSmallerThan = true; // hasAngleSmallerThan = true;
@ -817,7 +817,7 @@ std::shared_ptr<PatternGeometry> PatternGeometry::tilePattern(
const std::vector<int> &connectToNeighborsVi, const std::vector<int> &connectToNeighborsVi,
const VCGPolyMesh &tileInto, const VCGPolyMesh &tileInto,
const std::vector<size_t> &perSurfaceFacePatternIndices, const std::vector<size_t> &perSurfaceFacePatternIndices,
std::vector<int> &tileIntoEdgesToTiledVi, std::vector<size_t> &tileIntoEdgesToTiledVi,
std::vector<std::vector<size_t>> &perPatternIndexToTiledPatternEdgeIndex) std::vector<std::vector<size_t>> &perPatternIndexToTiledPatternEdgeIndex)
{ {
perPatternIndexToTiledPatternEdgeIndex.resize(patterns.size()); perPatternIndexToTiledPatternEdgeIndex.resize(patterns.size());

View File

@ -121,7 +121,7 @@ private:
const std::vector<int> &connectToNeighborsVi, const std::vector<int> &connectToNeighborsVi,
const VCGPolyMesh &tileInto, const VCGPolyMesh &tileInto,
const std::vector<size_t> &perSurfaceFacePatternIndices, const std::vector<size_t> &perSurfaceFacePatternIndices,
std::vector<int> &tileIntoEdgesToTiledVi, std::vector<size_t> &tileIntoEdgesToTiledVi,
std::vector<std::vector<size_t>> &perPatternIndexTiledPatternEdgeIndex); std::vector<std::vector<size_t>> &perPatternIndexTiledPatternEdgeIndex);
}; };

View File

@ -130,13 +130,13 @@ inline void parseIntegers(const std::string &str, std::vector<size_t> &result) {
} }
inline Eigen::MatrixXd toEigenMatrix(const std::vector<Vector6d> &v) { inline Eigen::MatrixXd toEigenMatrix(const std::vector<Vector6d> &v) {
Eigen::MatrixXd m(v.size(), 6); Eigen::MatrixXd m(v.size(), 6);
for (size_t vi = 0; vi < v.size(); vi++) { for (size_t vi = 0; vi < v.size(); vi++) {
const Vector6d &vec = v[vi]; const Vector6d &vec = v[vi];
for (size_t i = 0; i < 6; i++) { for (size_t i = 0; i < 6; i++) {
m(vi, i) = vec[i]; m(vi, i) = vec[i];
} }
} }
return m; return m;
@ -220,7 +220,7 @@ inline void deinitPolyscope()
return; return;
} }
polyscope::shutdown(); polyscope::render::engine->shutdownImGui();
} }
inline void init() inline void init()
@ -302,4 +302,24 @@ std::string to_string_with_precision(const T a_value, const int n = 2)
return out.str(); return out.str();
} }
template<typename T>
size_t computeHashUnordered(const std::vector<T> &v)
{
size_t hash = 0;
for (const auto &el : v) {
hash += std::hash<T>{}(el);
}
return hash;
}
inline size_t computeHashOrdered(const std::vector<size_t> &v)
{
std::string elementsString;
for (const auto &el : v) {
elementsString += std::to_string(el);
}
return std::hash<std::string>{}(elementsString);
}
#endif // UTILITIES_H #endif // UTILITIES_H