Skip to content

Commit

Permalink
Implement config file functionality.
Browse files Browse the repository at this point in the history
  • Loading branch information
Adam-Boesky committed Jan 1, 2024
1 parent 2222137 commit 3adba3a
Show file tree
Hide file tree
Showing 9 changed files with 373 additions and 42 deletions.
5 changes: 3 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
CXX = g++
CXXFLAGS = -std=c++17 -Wall --coverage
LDFLAGS = -lyaml-cpp
SRC_DIR = src
INC_DIR = include
OBJ_DIR = obj
Expand All @@ -22,15 +23,15 @@ INC_DIRS = -I $(INC_DIR)

# Linking step for src files
$(BIN_DIR)/$(TARGET): $(OBJS)
$(CXX) $(CXXFLAGS) -o $@ $^
$(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)

# Compiling step for src files
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
$(CXX) $(CXXFLAGS) $(INC_DIRS) -c -o $@ $<

# Linking step for test files
$(BIN_DIR)/$(TEST_TARGET): $(filter-out $(OBJ_DIR)/simulation.o, $(OBJS)) $(TEST_OBJS)
$(CXX) $(CXXFLAGS) -o $@ $^
$(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)

# Compiling step for test files
$(TEST_OBJ_DIR)/%.o: $(TEST_DIR)/%.cpp
Expand Down
29 changes: 29 additions & 0 deletions configs/default.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
global:
nParticles: 1000
mass:
dist: constant
val: 100000000
x:
dist: uniform
min: 0
max: 4
y:
dist: uniform
min: -2
max: 4
z:
dist: uniform
min: 1
max: 10
vx:
dist: uniform
min: 0
max: 4
vy:
dist: normal
mu: -2
sigma: 4
vz:
dist: uniform
min: -10
max: 10
5 changes: 5 additions & 0 deletions include/environment.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once
#include <vector>
#include <array>
#include <map>
#include <memory> // Include for smart pointers
#include "particle.h"

Expand All @@ -10,8 +11,11 @@ class GravitationalEnvironment {
// Constructors
GravitationalEnvironment(const std::vector<std::shared_ptr<Particle>>& particlePtrs, const bool log);
GravitationalEnvironment(const std::vector<std::shared_ptr<Particle>>& particlePtrs, const bool log, std::string logFilePrefix);
GravitationalEnvironment(const std::string configFileName, const bool log);
GravitationalEnvironment(const std::string configFileName, const bool log, std::string logFilePrefix);

// Define member functions
void loadParticlesFromConfig(std::string configFileName);
std::vector<std::array<double, 3>> getForces(const double timestep);
void updateAll(const std::vector<std::array<double, 3>>& forces, const double timestep);
void step(const double timestep);
Expand All @@ -31,3 +35,4 @@ class GravitationalEnvironment {

// Helper functions
int getLargestLabelNumber(const std::vector<std::string>& filenames, const std::string logFilePrefix);
std::map<std::string, std::map<std::string, std::string>> loadConfig(const std::string& fileName);
18 changes: 18 additions & 0 deletions include/statistics.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#pragma once
#include <vector>
#include <random>

// Assuming you have the random device and generator declared somewhere
extern std::random_device rd;
extern std::mt19937 GENERATOR;

// Distribution template used to sample from random distributions
template <typename Distribution>
std::vector<double> sampleFromDistribution(size_t n, Distribution& distribution) {
// Generate samples
std::vector<double> samples(n);
for (size_t i = 0; i < n; ++i) {
samples[i] = distribution(GENERATOR);
}
return samples;
}
172 changes: 167 additions & 5 deletions src/environment.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,68 @@
#include <iostream>
#include <string>
#include <array>
#include <vector>
#include <random>
#include <map>
#include <math.h>
#include <fstream>
#include <filesystem>
#include <yaml-cpp/yaml.h>

#include "../include/environment.h"
#include "../include/statistics.h"
namespace fs = std::filesystem;
double G = 6.6743e-11;
std::string REPOPATH = std::string(std::getenv("HOOTSIM_PATH"));


// Load config file to a hashmap. These files are of the form (key: param, value: the distribution parameters).
std::map<std::string, std::map<std::string, std::string>> loadConfig(const std::string& fileName) {

std::map<std::string, std::map<std::string, std::string>> configMap; // a 2D hashmap of the configuration
std::string fullPath = std::string(REPOPATH) + "/configs/" + fileName; // the full path to the configfile

try {

// Get file and parse like a map
YAML::Node config = YAML::LoadFile(fullPath);
if (config.IsMap()) {

// Fill in 2D hashmap
for (const auto& element : config) {
std::string outerKey = element.first.as<std::string>();
const YAML::Node& innerNode = element.second;

if (innerNode.IsMap()) { // If there is a 2nd dim for the specific element
std::map<std::string, std::string> innerMap;
for (const auto& innerElement : innerNode) {
std::string innerKey = innerElement.first.as<std::string>();
std::string innerValue = innerElement.second.as<std::string>();
innerMap[innerKey] = innerValue;
}
configMap[outerKey] = innerMap;
}
}
}
} catch (const YAML::BadFile& e) { // fail to open
std::cerr << "Failed to open YAML file: " << fullPath << std::endl;
throw;
} catch (const YAML::Exception& e) { // issue parsing
std::cerr << "YAML parsing error: " << e.what() << std::endl;
throw;
}

// Check if the map contains the key "dist" is assigned for each parameter
for (auto const& [property, propertyDist] : configMap) {
if (property != "global") {
if (propertyDist.find("dist") == propertyDist.end()) {
throw std::runtime_error("Key 'dist' not found in configuration for property " + property + ".");
}
}
}

return configMap;
}


// Get the largest number from a vector of filenames
Expand Down Expand Up @@ -51,8 +106,7 @@ GravitationalEnvironment::GravitationalEnvironment(const std::vector<std::shared

// Get a vector of the filenames in the data directory
std::vector<std::string> lastLogFileNames;
const char* repoPath = std::getenv("HOOTSIM_PATH");
std::string dataPath = std::string(repoPath) + "/data";
std::string dataPath = REPOPATH + "/data";
for (const auto& entry : fs::directory_iterator(dataPath)) {
if (fs::is_regular_file(entry.status())) {
lastLogFileNames.push_back(entry.path().filename().string());
Expand All @@ -75,8 +129,7 @@ GravitationalEnvironment::GravitationalEnvironment(const std::vector<std::shared

// Get a vector of the filenames in the data directory
std::vector<std::string> lastLogFileNames;
const char* repoPath = std::getenv("HOOTSIM_PATH");
std::string dataPath = std::string(repoPath) + "/data";
std::string dataPath = REPOPATH + "/data";
for (const auto& entry : fs::directory_iterator(dataPath)) {
if (fs::is_regular_file(entry.status())) {
lastLogFileNames.push_back(entry.path().filename().string());
Expand All @@ -88,6 +141,114 @@ GravitationalEnvironment::GravitationalEnvironment(const std::vector<std::shared
logFileName = dataPath + "/" + logFilePrefix + std::to_string(lastLogNum + 1) + ".csv";
}
}
GravitationalEnvironment::GravitationalEnvironment(const std::string configFileName, const bool log)
: log(log), time(0) {

// Get particles
loadParticlesFromConfig(configFileName);

// Declare the number of particles
nParticles = particlePtrs.size();

// Create a log file if we want one
if (log == true) {

// Get a vector of the filenames in the data directory
std::vector<std::string> lastLogFileNames;
std::string dataPath = REPOPATH + "/data";
for (const auto& entry : fs::directory_iterator(dataPath)) {
if (fs::is_regular_file(entry.status())) {
lastLogFileNames.push_back(entry.path().filename().string());
}
}

// Get the largest log file number and create new log file
int lastLogNum = getLargestLabelNumber(lastLogFileNames, "run");
logFileName = dataPath + "/run" + std::to_string(lastLogNum + 1) + ".csv";
}
}
GravitationalEnvironment::GravitationalEnvironment(const std::string configFileName, const bool log, std::string logFilePrefix = "run")
: log(log), time(0) {

// Get particles
loadParticlesFromConfig(configFileName);

// Declare the number of particles
nParticles = particlePtrs.size();

// Create a log file if we want one
if (log == true) {

// Get a vector of the filenames in the data directory
std::vector<std::string> lastLogFileNames;
std::string dataPath = REPOPATH + "/data";
for (const auto& entry : fs::directory_iterator(dataPath)) {
if (fs::is_regular_file(entry.status())) {
lastLogFileNames.push_back(entry.path().filename().string());
}
}

// Get the largest log file number and create new log file
int lastLogNum = getLargestLabelNumber(lastLogFileNames, logFilePrefix);
logFileName = dataPath + "/" + logFilePrefix + std::to_string(lastLogNum + 1) + ".csv";
}
}


// Load a full environment from the configuration file
void GravitationalEnvironment::loadParticlesFromConfig(const std::string configFileName) {

// Get configuration map
std::map<std::string, std::map<std::string, std::string>> configMap = loadConfig(configFileName);

// Grab the gloabl config params for the environment
std::map<std::string, std::string> globalConfigMap = configMap.at("global");
int nParticles = std::stoi(globalConfigMap.at("nParticles"));

// Generate distributions for each param
std::map<std::string, std::vector<double>> envParams;

// Iterate through the configuration and sample particles according to config prescirption
for (auto const& [property, propertyDist] : configMap) {

if (property != "global") { // not the global configuarion field

// The type of distribution for the property
std::string distType = propertyDist.at("dist");

// Sample from the distribution for the property
if (distType == "constant") { // Constant dist
envParams[property] = std::vector<double> (nParticles, std::stod(propertyDist.at("val")));
} else if (distType == "normal") { // Normal dist
double mu = std::stod(propertyDist.at("mu"));
double sigma = std::stod(propertyDist.at("sigma"));
std::normal_distribution<> normalDist(mu, sigma);
envParams[property] = sampleFromDistribution(nParticles, normalDist);
} else if (distType == "uniform") { // Uniform dist
double min = std::stod(propertyDist.at("min"));
double max = std::stod(propertyDist.at("max"));
std::uniform_real_distribution<> uniformDist(min, max);
envParams[property] = sampleFromDistribution(nParticles, uniformDist);
} else {
throw std::invalid_argument("Property " + property + " has an invalid distribution.");
}
}
}

// Declare particle pointer vector
std::vector<std::array<double, 3>> positions(nParticles);
std::vector<std::array<double, 3>> velocities(nParticles);
for (int i = 0; i < nParticles; i++) {

// Populate positions and velocities
positions[i] = {envParams.at("x")[i], envParams.at("y")[i], envParams.at("z")[i]};
velocities[i] = {envParams.at("vx")[i], envParams.at("vy")[i], envParams.at("vz")[i]};
double mass = envParams.at("mass")[i];

// Create Particle instance with pointers to elements in the positions and velocities vectors
particlePtrs.push_back(std::make_shared<Particle>(&positions[i], &velocities[i], mass));
}
}


// Get the forces in the environment
Expand Down Expand Up @@ -190,7 +351,7 @@ std::string GravitationalEnvironment::getStepLog() const {

// Run a simulation
void GravitationalEnvironment::simulate(const double duration, const double timestep) {
std::string logStr = getLogHeader();
std::string logStr = getLogHeader() + ",\n";
std::cout << getLogHeader() + "\n";

// Get number of timesteps and take steps iteratively
Expand All @@ -209,6 +370,7 @@ void GravitationalEnvironment::simulate(const double duration, const double time
}
// end state
if (log == true) {
logStr += std::to_string(nTimesteps * timestep) + ",";
logStr += getStepLog() + "\n";
}
std::cout << nTimesteps * timestep << ",\t" << getStepLog() << "\n";
Expand Down
38 changes: 3 additions & 35 deletions src/simulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,42 +6,10 @@
#include "../include/environment.h"

int main() {
GravitationalEnvironment defaultEnv("default.yaml", true);

// Parameters for simulation
float timestep = 0.5;

// Initialize particle specs
double mass = 1E9;
std::array<double, 3> initial_position1 = {0, 0, 0};
std::array<double, 3> initial_position2 = {4, 0, 0};
std::array<double, 3> initial_velocity1 = {0, 0, 0};
std::array<double, 3> initial_velocity2 = {0, 0, 0};


// Define the particles
auto particle1Ptr = std::make_shared<Particle>(&initial_position1, &initial_velocity1, mass);
auto particle2Ptr = std::make_shared<Particle>(&initial_position2, &initial_velocity2, mass);
std::vector<std::shared_ptr<Particle>> particles = {particle1Ptr, particle2Ptr};

// Initialize an environment
GravitationalEnvironment env1(particles, true);

// Take a step
env1.simulate(3, timestep);

// std::cout << particle1.position[0] << "\n";
// std::cout << particle2.position[0];
// Simulate
defaultEnv.simulate(3, 0.5);

return 0;

};



// for (int i=0; i<5; i++) {
// // Update the particle
// particle1.update(&force, timestep);
// }

// // Define the force
// std::array<double, 3> force = {3, 0, 0};
4 changes: 4 additions & 0 deletions src/statistics.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#include "../include/statistics.h"

std::random_device rd;
std::mt19937 GENERATOR(rd());
Loading

0 comments on commit 3adba3a

Please sign in to comment.