Refactoring
This commit is contained in:
parent
6e682e1e71
commit
8793dc5408
44
csvfile.hpp
44
csvfile.hpp
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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";
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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");
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue