2020-11-27 11:47:21 +01:00
|
|
|
#ifndef SIMULATIONHISTORYPLOTTER_HPP
|
|
|
|
#define SIMULATIONHISTORYPLOTTER_HPP
|
|
|
|
|
2021-04-08 20:03:23 +02:00
|
|
|
#include "simulationmesh.hpp"
|
|
|
|
#include "simulation_structs.hpp"
|
2020-11-27 11:47:21 +01:00
|
|
|
#include "utilities.hpp"
|
|
|
|
#include <algorithm>
|
|
|
|
#include <matplot/matplot.h>
|
|
|
|
|
|
|
|
struct SimulationResultsReporter {
|
|
|
|
using VertexType = VCGEdgeMesh::VertexType;
|
|
|
|
using CoordType = VCGEdgeMesh::CoordType;
|
|
|
|
|
|
|
|
SimulationResultsReporter() {}
|
|
|
|
|
|
|
|
void writeStatistics(const SimulationResults &results,
|
|
|
|
const std::string &reportFolderPath) {
|
|
|
|
|
|
|
|
ofstream file;
|
|
|
|
file.open(
|
|
|
|
std::filesystem::path(reportFolderPath).append("results.txt").string());
|
|
|
|
|
|
|
|
const size_t numberOfSteps = results.history.numberOfSteps;
|
|
|
|
file << "Number of steps " << numberOfSteps << "\n";
|
|
|
|
|
|
|
|
// file << "Force threshold used " << 1000 << "\n";
|
|
|
|
|
|
|
|
// assert(numberOfSteps == results.history.potentialEnergy.size() &&
|
|
|
|
// numberOfSteps == results.history.residualForces.size());
|
|
|
|
// Write kinetic energies
|
|
|
|
const SimulationHistory &history = results.history;
|
|
|
|
if (!history.kineticEnergy.empty()) {
|
|
|
|
file << "Kinetic energies"
|
|
|
|
<< "\n";
|
|
|
|
for (size_t step = 0; step < numberOfSteps; step++) {
|
|
|
|
file << history.kineticEnergy[step] << "\n";
|
|
|
|
}
|
|
|
|
file << "\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!history.residualForces.empty()) {
|
|
|
|
file << "Residual forces"
|
|
|
|
<< "\n";
|
|
|
|
for (size_t step = 0; step < numberOfSteps; step++) {
|
|
|
|
file << history.residualForces[step] << "\n";
|
|
|
|
}
|
|
|
|
file << "\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!history.potentialEnergies.empty()) {
|
|
|
|
file << "Potential energies"
|
|
|
|
<< "\n";
|
|
|
|
for (size_t step = 0; step < numberOfSteps; step++) {
|
|
|
|
file << history.potentialEnergies[step] << "\n";
|
|
|
|
}
|
|
|
|
file << "\n";
|
|
|
|
}
|
|
|
|
file.close();
|
|
|
|
}
|
|
|
|
|
2021-01-04 13:30:22 +01:00
|
|
|
void reportResults(const std::vector<SimulationResults> &results,
|
|
|
|
const std::string &reportFolderPath,
|
|
|
|
const std::string &graphSuffix = std::string()) {
|
2020-11-27 11:47:21 +01:00
|
|
|
if (results.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// std::filesystem::remove_all(debuggerFolder);
|
|
|
|
std::filesystem::create_directory(reportFolderPath);
|
|
|
|
for (const SimulationResults &simulationResult : results) {
|
|
|
|
const auto simulationResultPath =
|
|
|
|
std::filesystem::path(reportFolderPath)
|
2021-01-04 13:30:22 +01:00
|
|
|
.append(simulationResult.getLabel());
|
2020-11-27 11:47:21 +01:00
|
|
|
std::filesystem::create_directory(simulationResultPath.string());
|
|
|
|
|
|
|
|
createPlots(simulationResult.history, simulationResultPath.string(),
|
|
|
|
graphSuffix);
|
2021-02-04 13:58:41 +01:00
|
|
|
writeStatistics(simulationResult, simulationResultPath.string());
|
2020-11-27 11:47:21 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
static void createPlot(const std::string &xLabel, const std::string &yLabel,
|
2021-01-29 18:39:15 +01:00
|
|
|
const std::vector<double> &XvaluesToPlot,
|
2020-11-27 11:47:21 +01:00
|
|
|
const std::vector<double> &YvaluesToPlot,
|
|
|
|
const std::string &saveTo = {}) {
|
2021-01-29 18:39:15 +01:00
|
|
|
// matplot::figure(true);
|
2020-11-27 11:47:21 +01:00
|
|
|
matplot::xlabel(xLabel);
|
|
|
|
matplot::ylabel(yLabel);
|
2021-01-29 18:39:15 +01:00
|
|
|
matplot::grid(matplot::on);
|
|
|
|
matplot::scatter(XvaluesToPlot, YvaluesToPlot);
|
|
|
|
if (!saveTo.empty()) {
|
|
|
|
matplot::save(saveTo);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void createPlot(const std::string &xLabel, const std::string &yLabel,
|
|
|
|
const std::vector<double> &YvaluesToPlot,
|
|
|
|
const std::string &saveTo = {}) {
|
|
|
|
auto x =
|
|
|
|
matplot::linspace(0, YvaluesToPlot.size() - 1, YvaluesToPlot.size());
|
|
|
|
createPlot(xLabel, yLabel, x, YvaluesToPlot, saveTo);
|
2021-01-12 13:40:25 +01:00
|
|
|
// matplot::figure(true);
|
2020-11-27 11:47:21 +01:00
|
|
|
// matplot::hold(matplot::on);
|
2021-01-29 18:39:15 +01:00
|
|
|
|
|
|
|
// ->marker_indices(history.redMarks)
|
|
|
|
// ->marker_indices(truncatedRedMarks)
|
|
|
|
// .marker_color("r")
|
|
|
|
// ->marker_size(1)
|
|
|
|
;
|
2020-11-27 11:47:21 +01:00
|
|
|
// auto greenMarksY = matplot::transform(
|
|
|
|
// history.greenMarks, [&](auto x) { return history.kineticEnergy[x];
|
|
|
|
// });
|
|
|
|
// matplot::scatter(history.greenMarks, greenMarksY)
|
|
|
|
// ->color("green")
|
|
|
|
// .marker_size(10);
|
|
|
|
// matplot::hold(matplot::off);
|
|
|
|
}
|
|
|
|
|
|
|
|
void createPlots(const SimulationHistory &history,
|
|
|
|
const std::string &reportFolderPath,
|
|
|
|
const std::string &graphSuffix) {
|
|
|
|
const auto graphsFolder =
|
|
|
|
std::filesystem::path(reportFolderPath).append("Graphs");
|
|
|
|
std::filesystem::remove_all(graphsFolder);
|
|
|
|
std::filesystem::create_directory(graphsFolder.string());
|
|
|
|
|
|
|
|
if (!history.kineticEnergy.empty()) {
|
|
|
|
createPlot("Number of Iterations", "Log of Kinetic Energy",
|
|
|
|
history.kineticEnergy,
|
|
|
|
std::filesystem::path(graphsFolder)
|
|
|
|
.append("KineticEnergy" + graphSuffix + ".png")
|
|
|
|
.string());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!history.residualForces.empty()) {
|
|
|
|
createPlot("Number of Iterations", "Residual Forces norm",
|
|
|
|
history.residualForces,
|
|
|
|
std::filesystem::path(graphsFolder)
|
|
|
|
.append("ResidualForces" + graphSuffix + ".png")
|
|
|
|
.string());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!history.potentialEnergies.empty()) {
|
|
|
|
createPlot("Number of Iterations", "Potential energy",
|
|
|
|
history.potentialEnergies,
|
|
|
|
std::filesystem::path(graphsFolder)
|
|
|
|
.append("PotentialEnergy" + graphSuffix + ".png")
|
|
|
|
.string());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif // SIMULATIONHISTORYPLOTTER_HPP
|