BioDynaMo  v1.05.119-a4ff3934
particle_swarm.cc
Go to the documentation of this file.
1 // -----------------------------------------------------------------------------
2 //
3 // Copyright (C) 2021 CERN & University of Surrey for the benefit of the
4 // BioDynaMo collaboration. All Rights Reserved.
5 //
6 // Licensed under the Apache License, Version 2.0 (the "License");
7 // you may not use this file except in compliance with the License.
8 //
9 // See the LICENSE file distributed with this work for details.
10 // See the NOTICE file distributed with this work for additional information
11 // regarding copyright ownership.
12 //
13 // -----------------------------------------------------------------------------
14 
15 #include <json.hpp>
16 #include "optim.hpp"
17 
24 #include "core/util/spinlock.h"
25 
26 using nlohmann::json;
27 
28 namespace bdm {
29 namespace experimental {
30 
33 struct ParticleSwarm : public Algorithm {
35 
37  Param* default_params) override {
38  OptimizationParam* opt_params = default_params->Get<OptimizationParam>();
39 
40  // The number of times to run an experiment
41  int repetition = opt_params->repetition;
42 
43  // Initial values and the bounds of the free parameters that we want to
44  // optimize
45  std::vector<std::string> param_names;
46  std::vector<double> init_vals;
47  std::vector<double> lower_bounds;
48  std::vector<double> upper_bounds;
49 
50  if (opt_params->params.empty()) {
51  Log::Fatal("ParticleSwarm::operator()",
52  "No optimization parameters were selected. Please check your "
53  "parameter configuration.");
54  }
55 
56  for (auto* el : opt_params->params) {
57  auto* opt_param = dynamic_cast<ParticleSwarmParam*>(el);
58  if (!opt_param) {
59  Log::Error(
60  "ParticleSwarm::operator()",
61  "Encountered non-ParticleSwarmParam type optimization parameter: ",
62  el->GetParamName());
63  continue;
64  }
65  param_names.push_back(opt_param->GetParamName());
66  init_vals.push_back(opt_param->initial_value);
67  lower_bounds.push_back(opt_param->lower_bound);
68  upper_bounds.push_back(opt_param->upper_bound);
69  }
70  arma::vec inout(init_vals);
71  optim::algo_settings_t settings;
72  settings.vals_bound = true;
73  settings.lower_bounds = arma::vec(lower_bounds);
74  settings.upper_bounds = arma::vec(upper_bounds);
75  settings.pso_n_gen = opt_params->max_iterations;
76 
77  auto max_it = settings.pso_n_gen;
78  int iteration = 0;
79  real_t min_mse = 1e9;
80  json best_params;
81  real_t prev_mse = 1.0;
82  Spinlock lock;
83 
84  // The fitting function (i.e. calling a simulation with a paramset)
85  // Anything inside this function should be thread-safe
86  auto fit = [=, &dispatch_experiment, &iteration, &prev_mse, &min_mse,
87  &best_params, &lock](const arma::vec& free_params,
88  arma::vec* grad_out, void* opt_data) {
89  Param new_param = *default_params;
90 
91  std::cout << "iteration (" << iteration << "/" << max_it << ")"
92  << std::endl;
93 
94  // Bug: on the rare occasion that we get NaN values back from optim:pso,
95  // we should ignore it and return the previously obtained error
96  for (auto& p : free_params) {
97  if (std::isnan(p)) {
98  return prev_mse + static_cast<real_t>(0.005);
99  }
100  }
101 
102  // Merge the free param values into the Param object that will be sent to
103  // the worker
104  json j_patch;
105  int i = 0;
106  std::cout << "FP: " << free_params << std::endl;
107  for (auto* opt_param : opt_params->params) {
108  j_patch[opt_param->GetGroupName()][opt_param->GetParamName()] =
109  free_params[i];
110  i++;
111  }
112 
113  std::cout << j_patch << std::endl;
114 
115  new_param.MergeJsonPatch(j_patch.dump());
116 
117  real_t mse = Experiment(dispatch_experiment, repetition, &new_param);
118  std::cout << " MSE " << mse << " inout " << free_params << std::endl;
119  {
120  std::lock_guard<Spinlock> lock_guard(lock);
121  iteration++;
122  prev_mse = mse;
123  // Check if the current error is smaller than the previously smallest
124  // error If it is, then we save the corresponding parameters as the next
125  // best set of parameters
126  if (mse < min_mse) {
127  min_mse = mse;
128  best_params = j_patch;
129  }
130  }
131  return mse;
132  };
133 
134  // Call the optimization routine
135  if (!optim::pso(inout, fit, nullptr, settings)) {
136  Log::Fatal("", "Optimization algorithm didn't complete successfully.");
137  }
138 
139  std::cout << "Best params = " << best_params << std::endl;
140  };
141 };
142 
143 BDM_REGISTER_ALGO(ParticleSwarm);
144 
145 } // namespace experimental
146 } // namespace bdm
bdm::experimental::Experiment
real_t Experiment(Functor< void, Param *, TimeSeries * > &simulation, size_t iterations, const Param *param, TimeSeries *real_ts=nullptr, Functor< void, const std::vector< TimeSeries > &, const TimeSeries &, const TimeSeries & > *post_simulation=nullptr)
Definition: experiment.h:36
particle_swarm_param.h
spinlock.h
bdm
Definition: agent.cc:39
algorithm_registry.h
bdm::experimental::Algorithm
An interface for creating new optimization algorithms.
Definition: algorithm.h:30
bdm::OptimizationParam::repetition
size_t repetition
Definition: optimization_param.h:41
bdm::real_t
double real_t
Definition: real_t.h:21
bdm::experimental::ParticleSwarm::operator()
void operator()(Functor< void, Param *, TimeSeries * > &dispatch_experiment, Param *default_params) override
Definition: particle_swarm.cc:36
bdm::Param::Get
const TParamGroup * Get() const
Definition: param.h:59
bdm::OptimizationParam::max_iterations
size_t max_iterations
Definition: optimization_param.h:43
experiment.h
bdm::Functor
Definition: functor.h:24
bdm::Spinlock
Definition: spinlock.h:22
bdm::OptimizationParam
Definition: optimization_param.h:24
bdm::experimental::BDM_REGISTER_ALGO
BDM_REGISTER_ALGO(ParameterSweep)
bdm::Param::MergeJsonPatch
void MergeJsonPatch(const std::string &patch)
Definition: param.cc:126
bdm::Log::Fatal
static void Fatal(const std::string &location, const Args &... parts)
Prints fatal error message.
Definition: log.h:115
bdm::Log::Error
static void Error(const std::string &location, const Args &... parts)
Prints error message.
Definition: log.h:79
bdm::OptimizationParam::params
std::vector< OptimizationParamType * > params
Definition: optimization_param.h:39
algorithm.h
bdm::experimental::ParticleSwarm::BDM_ALGO_HEADER
BDM_ALGO_HEADER()
bdm::experimental::ParticleSwarm
Definition: particle_swarm.cc:33
multi_simulation_manager.h
bdm::ParticleSwarmParam
Definition: particle_swarm_param.h:27
bdm::Param
Definition: param.h:35
dynamic_loop.h