Skip to content

Commit

Permalink
Merge pull request #71 from ManuelLerchner/60-csv-outputter-for-bench…
Browse files Browse the repository at this point in the history
…marks

CSV outputter for benchmarks
  • Loading branch information
TobiasEppacher authored Dec 6, 2023
2 parents d5bb070 + cdb2b68 commit 3697a80
Show file tree
Hide file tree
Showing 10 changed files with 191 additions and 64 deletions.
42 changes: 26 additions & 16 deletions benchmarks/2DParticleRect/2DParticleRect.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include <array>
#include <memory>

#include "io/logger/Logger.h"
Expand All @@ -15,39 +16,46 @@ void execute2DRectBenchmark(int x, int y) {
Logger::logger->set_level(spdlog::level::info);
Logger::logger->info("Starting 2DRect-benchmark. Dimensions {}x{}...", x, y);

// Settings for the Linked Cells Container simulation
std::array<double, 3> domain_size = {300, 300, 3};
double cutoff_radius = 30;
std::array<LinkedCellsContainer::BoundaryCondition, 6> boundary_conditions = {
LinkedCellsContainer::BoundaryCondition::REFLECTIVE, LinkedCellsContainer::BoundaryCondition::REFLECTIVE,
LinkedCellsContainer::BoundaryCondition::REFLECTIVE, LinkedCellsContainer::BoundaryCondition::REFLECTIVE,
LinkedCellsContainer::BoundaryCondition::REFLECTIVE, LinkedCellsContainer::BoundaryCondition::REFLECTIVE};

// Settings for the Cuboid spawner for both simulations
std::array<double, 3> center_offset = {domain_size[0] / 2, domain_size[1] / 2, domain_size[2] / 2};

CuboidSpawner spawner(center_offset - std::array<double, 3>{x * 1.225 / 2, y * 1.225 / 2, 0}, {x, y, 1}, 1.225, 1, {0, 0, 0}, 0);

// Settings for the forces for both simulations
std::vector<std::unique_ptr<ForceSource>> forces;
forces.push_back(std::make_unique<LennardJonesForce>());

// Instantiation of the Direct Sum Container simulation
SimulationParams params_ds{"2DParticleRect", "", 0.01, 5, 0, 30, SimulationParams::DirectSumType{}, "none"};
std::unique_ptr<ParticleContainer> particle_container_ds = std::make_unique<DirectSumContainer>();
spawner.spawnParticles(particle_container_ds);
Simulation simulation_ds(particle_container_ds, forces, params_ds);

SimulationParams params = SimulationParams("test_only", "", 0.01, 5, 0, 30, SimulationParams::DirectSumType{}, "none");

Simulation simulation_ds(particle_container_ds, forces, params);

// Simulating with Direct Sum Container
Logger::logger->info("Starting simulation using Direct Sum container...");
Logger::logger->set_level(spdlog::level::off);
SimulationOverview direct_sum_data = simulation_ds.runSimulation();
Logger::logger->set_level(spdlog::level::info);
SimulationOverview direct_sum_data = simulation_ds.runSimulationPerfTest();
Logger::logger->info("Finished simulation using Direct Sum container\n");

// Instantiation of the Linked Cells Container simulation
SimulationParams params_lc{
"2DParticleRect", "", 0.01, 5, 0, 30, SimulationParams::LinkedCellsType{domain_size, cutoff_radius, boundary_conditions}, "none"};
std::unique_ptr<ParticleContainer> particle_container_lc = std::make_unique<LinkedCellsContainer>(domain_size, cutoff_radius);
spawner.spawnParticles(particle_container_lc);
Simulation simulation_lc(particle_container_lc, forces, params);
Simulation simulation_lc(particle_container_lc, forces, params_lc);

// Simulating with Linked Cells Container
Logger::logger->info("Starting simulation using Linked Cells container...");
Logger::logger->set_level(spdlog::level::off);
SimulationOverview linked_cells_data = simulation_lc.runSimulation();
Logger::logger->set_level(spdlog::level::info);
SimulationOverview linked_cells_data = simulation_lc.runSimulationPerfTest();
Logger::logger->info("Finished simulation using Linked Cells container\n");

// Final Logging
Logger::logger->info("Simulation of {} particles in a {}x{} grid\n", x * y, x, y);

Logger::logger->info("Direct sum container:");
Expand All @@ -69,9 +77,11 @@ void execute2DRectBenchmark(int x, int y) {
* Can be used to compare the performance of the different particle containers.
*/
int main() {
execute2DRectBenchmark(25, 40);
execute2DRectBenchmark(50, 40);
execute2DRectBenchmark(50, 80);
execute2DRectBenchmark(100, 80);
std::vector<std::pair<int, int>> sizes = {{25, 40}, {50, 40}, {50, 80}, {100, 80}};

for (auto [size_x, size_y] : sizes) {
execute2DRectBenchmark(size_x, size_y);
}

return 0;
}
4 changes: 0 additions & 4 deletions benchmarks/2DParticleRect/TestExecution.csv

This file was deleted.

44 changes: 19 additions & 25 deletions src/MolSim.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,19 @@ int main(int argc, char* argsv[]) {
print_simulation_input(simulation_params, num_particles_start, forces);

// Run simulation
SimulationOverview overview = simulation.runSimulation();
if (simulation_params.performance_test) {
SimulationOverview overview = simulation.runSimulationPerfTest();

// Print simulation info again (for convenience)
print_simulation_input(simulation_params, num_particles_start, forces);
// Print simulation overview
print_simulation_overview(overview, initial_particles->size());
} else {
SimulationOverview overview = simulation.runSimulation();

// Print simulation overview
print_simulation_overview(overview, initial_particles->size());
// Print simulation info again (for convenience)
print_simulation_input(simulation_params, num_particles_start, forces);
// Print simulation overview
print_simulation_overview(overview, initial_particles->size());
}

return 0;
}
Expand All @@ -68,8 +74,8 @@ void print_simulation_input(const SimulationParams& simulation_params, size_t nu
Logger::logger->info(ansi_yellow_bold + "Simulation arguments:" + ansi_end);
Logger::logger->info(" Input file path: {}", simulation_params.input_file_path);
Logger::logger->info(" Output directory path: {}", simulation_params.output_dir_path);
Logger::logger->info(" Delta t: {}", simulation_params.delta_t);
Logger::logger->info(" End time: {}", simulation_params.end_time);
Logger::logger->info(" Delta_t: {}", simulation_params.delta_t);
Logger::logger->info(" End_time: {}", simulation_params.end_time);

Logger::logger->info(ansi_yellow_bold + "Rendering arguments:" + ansi_end);
Logger::logger->info(" Frames per second: {}", simulation_params.fps);
Expand All @@ -90,29 +96,17 @@ void print_simulation_input(const SimulationParams& simulation_params, size_t nu
if (std::holds_alternative<SimulationParams::LinkedCellsType>(simulation_params.container_type)) {
auto lc_container = std::get<SimulationParams::LinkedCellsType>(simulation_params.container_type);

// lambda function convert boundary condition to string
auto boundary_condition_to_string = [](const LinkedCellsContainer::BoundaryCondition& bc) {
switch (bc) {
case LinkedCellsContainer::BoundaryCondition::OUTFLOW:
return "Outflow";
case LinkedCellsContainer::BoundaryCondition::REFLECTIVE:
return "Reflective";
default:
return "Unknown";
}
};

auto domain_size = lc_container.domain_size;
Logger::logger->info(" Linked Cells");
Logger::logger->info(" Domain size: {} x {} x {}", domain_size[0], domain_size[1], domain_size[2]);
Logger::logger->info(" Cutoff radius: {}", lc_container.cutoff_radius);
Logger::logger->info(" Boundary conditions: ");
Logger::logger->info(" Left: {}", boundary_condition_to_string(lc_container.boundary_conditions[0]));
Logger::logger->info(" Right: {}", boundary_condition_to_string(lc_container.boundary_conditions[1]));
Logger::logger->info(" Bottom: {}", boundary_condition_to_string(lc_container.boundary_conditions[2]));
Logger::logger->info(" Top: {}", boundary_condition_to_string(lc_container.boundary_conditions[3]));
Logger::logger->info(" Back: {}", boundary_condition_to_string(lc_container.boundary_conditions[4]));
Logger::logger->info(" Front: {}", boundary_condition_to_string(lc_container.boundary_conditions[5]));
Logger::logger->info(" Left: {}", LinkedCellsContainer::boundaryConditionToString(lc_container.boundary_conditions[0]));
Logger::logger->info(" Right: {}", LinkedCellsContainer::boundaryConditionToString(lc_container.boundary_conditions[1]));
Logger::logger->info(" Bottom: {}", LinkedCellsContainer::boundaryConditionToString(lc_container.boundary_conditions[2]));
Logger::logger->info(" Top: {}", LinkedCellsContainer::boundaryConditionToString(lc_container.boundary_conditions[3]));
Logger::logger->info(" Back: {}", LinkedCellsContainer::boundaryConditionToString(lc_container.boundary_conditions[4]));
Logger::logger->info(" Front: {}", LinkedCellsContainer::boundaryConditionToString(lc_container.boundary_conditions[5]));
} else if (std::holds_alternative<SimulationParams::DirectSumType>(simulation_params.container_type)) {
Logger::logger->info(" Direct Sum");
} else {
Expand Down
10 changes: 9 additions & 1 deletion src/io/cli/CLIParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ SimulationParams parse_arguments(int argc, char* argsv[]) {
int fps = 0;
int video_length = 0;

bool performance_test = false;

// choosing 0 as one of the parameters (end_time, delta_t, fps, video_length) is equivalent to choosing the default value
boost::program_options::options_description options_desc("Allowed options");
options_desc.add_options()("help,h", "produce help message");
Expand All @@ -40,6 +42,7 @@ SimulationParams parse_arguments(int argc, char* argsv[]) {
"The log level. Possible values: trace, debug, info, warning, error, critical, off");
options_desc.add_options()("output_format", boost::program_options::value<std::string>(&output_format)->default_value("vtk"),
"The output format. Possible values: vtk, xyz, none");
options_desc.add_options()("performance_test,p", "Run the simulation in performance test mode");
options_desc.add_options()(
"log_output", boost::program_options::value<std::string>(&log_output)->default_value("std"),
"You can only choose between the output options std(only cl output) and file (only file output). Default: no file output");
Expand Down Expand Up @@ -95,9 +98,12 @@ SimulationParams parse_arguments(int argc, char* argsv[]) {
Logger::logger->info(help_message.str());
exit(-1);
}
if (variables_map.count("performance_test")) {
performance_test = true;
}

return SimulationParams{input_file_path, output_dir_path, delta_t, end_time, fps, video_length, SimulationParams::DirectSumType{},
output_format};
output_format, performance_test};
}

SimulationParams merge_parameters(const SimulationParams& params_cli, const SimulationParams& params_xml) {
Expand All @@ -123,5 +129,7 @@ SimulationParams merge_parameters(const SimulationParams& params_cli, const Simu
// Must be given in the CLI
params.output_format = params_cli.output_format;

params.performance_test = params_cli.performance_test;

return params;
}
11 changes: 11 additions & 0 deletions src/particles/containers/linkedcells/LinkedCellsContainer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,17 @@ Cell* LinkedCellsContainer::particlePosToCell(double x, double y, double z) {
return &cells[cell_index];
}

std::string LinkedCellsContainer::boundaryConditionToString(const BoundaryCondition& bc) {
switch (bc) {
case BoundaryCondition::OUTFLOW:
return "Outflow";
case BoundaryCondition::REFLECTIVE:
return "Reflective";
default:
return "Unknown";
}
};

/*
Private methods of the LinkedCellsContainer
*/
Expand Down
5 changes: 5 additions & 0 deletions src/particles/containers/linkedcells/LinkedCellsContainer.h
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,11 @@ class LinkedCellsContainer : public ParticleContainer {
*/
Cell* particlePosToCell(double x, double y, double z);

/**
* @brief Returns a string description of a boundary condition
*/
static std::string boundaryConditionToString(const BoundaryCondition& bc);

private:
/**
* @brief Populates the cell vector and sets the cells types
Expand Down
75 changes: 73 additions & 2 deletions src/simulation/Simulation.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#include "Simulation.h"

#include <spdlog/fmt/chrono.h>

#include <chrono>
#include <filesystem>
#include <iostream>

#include "integration/VerletFunctor.h"
Expand All @@ -15,6 +18,7 @@ Simulation::Simulation(std::unique_ptr<ParticleContainer>& particles, const std:
file_output_handler(FileOutputHandler(simulation_params.output_format, simulation_params.output_dir_path)),
fps(simulation_params.fps),
video_length(simulation_params.video_length),
simulation_params(simulation_params),
forces(forces) {
switch (integration_method) {
case IntegrationMethod::VERLET:
Expand Down Expand Up @@ -78,6 +82,73 @@ SimulationOverview Simulation::runSimulation() const {

auto total_simulation_time =
std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start_time).count();
return SimulationOverview{total_simulation_time / 1000.0, total_simulation_time / static_cast<double>(iteration),
static_cast<size_t>(iteration), expected_iterations / save_every_nth_iteration};

return SimulationOverview{total_simulation_time / 1000.0, total_simulation_time / static_cast<double>(iteration - 1),
static_cast<size_t>(iteration - 1), expected_iterations / save_every_nth_iteration};
}

SimulationOverview Simulation::runSimulationPerfTest() const {
const size_t initial_particle_count = particles->size();

double simulation_time = 0;
size_t iteration = 0;

// Calculate initial forces
particles->applyPairwiseForces(forces);

// keep track of time for progress high precision
auto start_time = std::chrono::high_resolution_clock::now();

while (simulation_time < simulation_end_time) {
integration_functor->step(particles, forces, delta_t);

simulation_time += delta_t;
iteration++;
}

auto total_simulation_time =
std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start_time).count();

SimulationOverview overview{total_simulation_time / 1000.0, total_simulation_time / static_cast<double>(iteration),
static_cast<size_t>(iteration - 1), 0};

savePerformanceTest(overview, simulation_params, initial_particle_count);

return overview;
}

void Simulation::savePerformanceTest(const SimulationOverview& overview, const SimulationParams& params, size_t num_particles) const {
if (!std::filesystem::exists(params.output_dir_path)) {
std::filesystem::create_directories(params.output_dir_path);
}

std::ofstream csv_file;

if (!std::filesystem::exists(params.output_dir_path + "/performance_test.csv")) {
csv_file.open(params.output_dir_path + "/performance_test.csv");
// Write the Headers to the file
csv_file << "datetime,num_particles,particle_container,delta_t,total_time[s],time_per_iteration[ms],total_iterations\n";
} else {
csv_file.open(params.output_dir_path + "/performance_test.csv", std::ios_base::app);
}

std::string container_type_string;
if (std::holds_alternative<SimulationParams::DirectSumType>(params.container_type)) {
container_type_string = std::get<SimulationParams::DirectSumType>(params.container_type);
} else if (std::holds_alternative<SimulationParams::LinkedCellsType>(params.container_type)) {
container_type_string = std::get<SimulationParams::LinkedCellsType>(params.container_type);
} else {
Logger::logger->error("Invalid container type when saving performance test");
exit(-1);
}

// write the results to the file
std::time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
auto formatted_time = fmt::format("{:%d.%m.%Y-%H:%M:%S}", fmt::localtime(now));
csv_file << formatted_time << "," << num_particles << "," << container_type_string << "," << params.delta_t << ","
<< overview.total_time_seconds << "," << overview.average_time_per_iteration_millis << "," << overview.total_iterations
<< "\n";

// close the file
csv_file.close();
}
16 changes: 16 additions & 0 deletions src/simulation/Simulation.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ class Simulation {
*/
const int video_length;

/**
* @brief Reference to the simulation parameters object
*/
const SimulationParams& simulation_params;

const std::vector<std::unique_ptr<ForceSource>>& forces;
std::unique_ptr<IntegrationFunctor> integration_functor;

Expand All @@ -68,4 +73,15 @@ class Simulation {
* @return SimulationOverview object containing some data about the simulation performed
*/
SimulationOverview runSimulation() const;

/**
* @brief Runs the simulation without any output for logging- or vtk/xyz-files, using the parameters given at construction and returns a
* `SimulationOverview` object containing some data
*
* @return SimulationOverview object containing some data about the simulation performed
*/
SimulationOverview runSimulationPerfTest() const;

private:
void savePerformanceTest(const SimulationOverview& overview, const SimulationParams& params, size_t num_particles) const;
};
18 changes: 7 additions & 11 deletions src/simulation/SimulationParams.cpp
Original file line number Diff line number Diff line change
@@ -1,28 +1,24 @@
#include "SimulationParams.h"

#include <filesystem>

#include "io/logger/Logger.h"

std::string construct_output_path(const std::string& input_file_path) {
auto last_slash_pos = input_file_path.find_last_of('/');
auto last_dot_pos = input_file_path.find_last_of('.');
if (last_slash_pos == std::string::npos) {
last_slash_pos = 0;
}
if (last_dot_pos == std::string::npos) {
last_dot_pos = input_file_path.size();
}
return "./output/" + input_file_path.substr(last_slash_pos + 1, last_dot_pos - last_slash_pos - 1) + "/";
std::filesystem::path input_path{input_file_path};
return "./output/" + std::string(input_path.stem()) + "/";
};

SimulationParams::SimulationParams(const std::string& input_file_path, const std::string& output_dir_path, double delta_t, double end_time,
int fps, int video_length, const std::variant<DirectSumType, LinkedCellsType>& container_type,
const std::string& output_format)
const std::string& output_format, bool performance_test)
: input_file_path(input_file_path),
delta_t(delta_t),
end_time(end_time),
fps(fps),
video_length(video_length),
container_type(container_type) {
container_type(container_type),
performance_test(performance_test) {
if (fps < 0) {
Logger::logger->error("FPS must be positive");
exit(-1);
Expand Down
Loading

0 comments on commit 3697a80

Please sign in to comment.