Commit c90eabb9 authored by Lukas Weber's avatar Lukas Weber

BREAKING: set observable vector_length automatically

register_observable becomes optional,
the 'binsize' parameter is now required and becomes the default
binsize for new observables
parent 2ff2366b
#include "mc.h"
namespace loadl {
mc::mc(const parser &p) : param{p} {
mc::mc(const parser &p) : param{p}, measure{p.get<size_t>("binsize")} {
therm_ = p.get<int>("thermalization");
pt_sweeps_per_global_update_ = p.get<int>("pt_sweeps_per_global_update", 1);
}
......
......@@ -3,6 +3,10 @@
#include <mpi.h>
namespace loadl {
measurements::measurements(size_t default_bin_size)
: default_bin_size_{default_bin_size} {
}
bool measurements::observable_name_is_legal(const std::string &obs_name) {
if(obs_name.find('/') != obs_name.npos) {
return false;
......@@ -13,14 +17,18 @@ bool measurements::observable_name_is_legal(const std::string &obs_name) {
return true;
}
void measurements::register_observable(const std::string &name, size_t bin_size,
size_t vector_length) {
void measurements::register_observable(const std::string &name, size_t bin_size) {
if(!observable_name_is_legal(name)) {
throw std::runtime_error(
fmt::format("Illegal observable name '{}': names must not contain / or .", name));
}
observables_.emplace(name, observable{name, bin_size, vector_length});
if(observables_.count(name) > 0) {
throw std::runtime_error(
fmt::format("Observable '{}' already exists.", name));
}
observables_.emplace(name, observable{name, bin_size, 0});
}
void measurements::checkpoint_write(const iodump::group &dump_file) {
......@@ -31,8 +39,7 @@ void measurements::checkpoint_write(const iodump::group &dump_file) {
void measurements::checkpoint_read(const iodump::group &dump_file) {
for(const auto &obs_name : dump_file) {
register_observable(obs_name);
observables_.at(obs_name).checkpoint_read(obs_name, dump_file.open_group(obs_name));
observables_.emplace(obs_name, observable::checkpoint_read(obs_name, dump_file.open_group(obs_name)));
}
}
......
......@@ -12,10 +12,13 @@ namespace loadl {
class measurements {
public:
measurements(size_t default_bin_size);
static bool observable_name_is_legal(const std::string &name);
void register_observable(const std::string &name, size_t bin_size = 1,
size_t vector_length = 1);
// only needed if you want to set the bin_size explicitly
// otherwise observables are automatically created on first add
void register_observable(const std::string &name, size_t bin_size);
// use this to add a measurement sample to an observable.
template<class T>
......@@ -35,13 +38,23 @@ public:
private:
std::set<int> mpi_checked_targets_;
std::map<std::string, observable> observables_;
const size_t default_bin_size_{1};
template<class T>
size_t value_length(const T& val) {
if constexpr (std::is_arithmetic_v<T>) {
return 1;
} else {
return val.size();
}
}
};
template<class T>
void measurements::add(const std::string name, T value) {
if(observables_.count(name) == 0) {
throw std::runtime_error{
fmt::format("tried to add to observable '{}' which was not registered!", name)};
observables_.emplace(name, observable{name, default_bin_size_, value_length(value)});
}
observables_.at(name).add(value);
}
......
......@@ -46,13 +46,15 @@ void observable::measurement_write(const iodump::group &meas_file) {
current_bin_ = 0;
}
void observable::checkpoint_read(const std::string &name, const iodump::group &d) {
name_ = name;
d.read("vector_length", vector_length_);
d.read("bin_length", bin_length_);
d.read("current_bin_filling", current_bin_filling_);
d.read("samples", samples_);
current_bin_ = 0;
observable observable::checkpoint_read(const std::string &name, const iodump::group &d) {
size_t vector_length, bin_length;
d.read("vector_length", vector_length);
d.read("bin_length", bin_length);
observable obs{name, bin_length, vector_length};
d.read("current_bin_filling", obs.current_bin_filling_);
d.read("samples", obs.samples_);
return obs;
}
void observable::mpi_sendrecv(int target_rank) {
......
......@@ -25,7 +25,7 @@ public:
// This will empty the cache of already completed bins
void measurement_write(const iodump::group &meas_file);
void checkpoint_read(const std::string &name, const iodump::group &dump_file);
static observable checkpoint_read(const std::string &name, const iodump::group &dump_file);
// switch copy with target rank.
// useful for parallel tempering mode
......@@ -50,11 +50,22 @@ void observable::add(T val) {
template<class T>
auto observable::add(const T &val) -> decltype(val[0], void()) {
if(val.size() == 0) {
throw std::runtime_error("observable::add: tried to add zero-length value.");
}
if(vector_length_ != val.size()) {
throw std::runtime_error{
fmt::format("observable::add: added vector has unexpected size ({}). Observable was "
"initialized with vector length ({})",
val.size(), vector_length_)};
if(vector_length_ != 0) {
throw std::runtime_error{
fmt::format("observable::add: added vector has inconsistent size ({}). Observable was "
"initialized with vector length ({})",
val.size(), vector_length_)};
} else {
// when the variable is manually registered, it can happen that the vector length was not yet set.
vector_length_ = val.size();
assert(samples_.size() == 0);
samples_.resize(vector_length_);
}
}
for(size_t j = 0; j < vector_length_; ++j)
......
......@@ -71,8 +71,6 @@ private:
std::map<int, int> rank_to_chain_run_;
int current_chain_id_{-1};
measurements pt_meas_;
void construct_pt_chains();
void checkpoint_write();
void checkpoint_read();
......
......@@ -19,10 +19,8 @@ void silly_mc::do_measurement() {
void silly_mc::init() {
idx_=0;
int binsize = param.get("binsize", 1);
measure.register_observable("MagicNumber", binsize,2);
measure.register_observable("MagicNumber2", binsize);
measure.register_observable("MagicNumberValarray", binsize,2);
measure.register_observable("MagicNumberValarray", 10);
}
void silly_mc::checkpoint_write(const loadl::iodump::group &d) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment