Skip to content

Commit

Permalink
Simulator with JSON interface
Browse files Browse the repository at this point in the history
  • Loading branch information
dweindl committed Nov 8, 2024
1 parent 96a797e commit eb35624
Show file tree
Hide file tree
Showing 5 changed files with 276 additions and 1 deletion.
25 changes: 25 additions & 0 deletions examples/parpeamici/steadystate/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,31 @@ if(${BUILD_TESTING})
endif()
# /example_steadystate_multi executable_simulator

# example_steadystate_multi_simulator_json executable
project(example_steadystate_multi_simulator_json)

set(SRC_LIST_EXE_PARALLEL main_simulator_json.cpp
steadyStateMultiConditionDataprovider.cpp)

add_executable(${PROJECT_NAME} ${SRC_LIST_EXE_PARALLEL})
add_dependencies(${PROJECT_NAME} ${MODEL_NAME})

include(FetchContent)

FetchContent_Declare(json URL https://github.com/nlohmann/json/releases/download/v3.11.3/json.tar.xz)
FetchContent_MakeAvailable(json)

target_link_libraries(
${PROJECT_NAME}
PRIVATE
${MODEL_LIBRARIES}
parpeamici
nlohmann_json::nlohmann_json
${GCOV_LIBRARY}
)

# /example_steadystate_multi executable_simulator_json

if(${BUILD_TESTING})
project(test_steadystate)

Expand Down
108 changes: 108 additions & 0 deletions examples/parpeamici/steadystate/main_simulator_json.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*
* Executable for evaluating the objective function for parameters specified
* in a json file. The results will be written to a json file.
*
* The input is a list of objects with the following fields:
* - conditionFileName: the name of the file containing the conditions
* - parameters: object with parameterId => parameterValue
* - gradient: boolean indicating whether the gradient should be computed
*
* The output is a list of objects with the following fields:
* - conditionFileName: the name of the file containing the conditions
* - parameters: object with parameterId => parameterValue
* - fval: the objective function value
* - gradient: boolean indicating whether the gradient should be computed
*/

#include <parpecommon/parpeConfig.h>

#include "steadyStateMultiConditionDataprovider.h"
#include <parpeamici/multiConditionProblem.h>
#include <parpeamici/standaloneSimulator.h>
#include <parpecommon/misc.h>
#include <parpecommon/parpeConfig.h>

#include <cstdio> // remove
#include <iostream>
#include <fstream>
#include <nlohmann/json.hpp>
#ifdef PARPE_ENABLE_MPI
#include <mpi.h>
#endif

using json = nlohmann::json;

namespace amici::generic_model {
std::unique_ptr<amici::Model> getModel();
}


void printUsage() {
std::cerr<<"Error: wrong number of arguments.\n";
std::cerr<<"Usage: ... infile outfile\n";
}

int main(int argc, char **argv) {
int status = EXIT_SUCCESS;

if(argc != 3) {
printUsage();
return EXIT_FAILURE;
}

std::string inFileArgument = argv[1];
std::string outFileArgument = argv[2];

std::ifstream istream(inFileArgument);
json jobs = json::parse(istream);

json results = json::array();
std::unique_ptr<parpe::MultiConditionDataProvider> dataProvider;
std::string h5file_name;

for (auto& job : jobs) {
std::cout<<job<<std::endl;
auto cur_result = job;
try {
if (job["conditionFileName"] != h5file_name) {
h5file_name = job["conditionFileName"];
dataProvider = std::make_unique<parpe::MultiConditionDataProviderHDF5>(
amici::generic_model::getModel(), h5file_name);
}
parpe::MultiConditionProblem problem(
dataProvider.get(), nullptr,
std::make_unique<parpe::Logger>(),
nullptr);

// parameter values
auto objective = dynamic_cast<parpe::SummedGradientFunctionGradientFunctionAdapter<int>*>(problem.cost_fun_.get());

auto parameter_ids = objective->getParameterIds();
std::vector<double> parameters;
parameters.reserve(parameter_ids.size());

for (auto& parameter_id: parameter_ids) {
parameters.push_back(job["parameters"][parameter_id]);
}

double fval;
std::vector<double> gradient(parameter_ids.size());
auto fv = objective->evaluate(parameters, fval, job["gradient"]?gsl::make_span(gradient):gsl::span<double>(nullptr, 0));
cur_result["fval"] = fval;
if (job["gradient"]) {
cur_result["gradient"] = gradient;
}
cur_result["status"] = fv;
} catch(std::exception& e) {
std::cerr<<e.what()<<std::endl;
cur_result["error"] = e.what();

}
results.push_back(cur_result);
// not efficient, but let's save it after every simulation for now
std::ofstream ostream(outFileArgument);
ostream << std::setw(4) << results << std::endl;
}

return status;
}
24 changes: 24 additions & 0 deletions templates/CMakeLists.template.txt
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,30 @@ target_link_libraries(${PROJECT_NAME}
)
target_include_directories(${PROJECT_NAME} PUBLIC "model")

#################################
# simulateJSON executable
#################################

project(simulateJSON_${MODEL_NAME})

set(SRC_LIST main_json.cpp)

add_executable(${PROJECT_NAME} ${SRC_LIST})
add_dependencies(${PROJECT_NAME} ${MODEL_NAME})

include(FetchContent)

FetchContent_Declare(json URL https://github.com/nlohmann/json/releases/download/v3.11.3/json.tar.xz)
FetchContent_MakeAvailable(json)

target_link_libraries(
${PROJECT_NAME}
PRIVATE
model
Upstream::parpe
nlohmann_json::nlohmann_json
)

#################################

project(${MODEL_NAME}) # for IDE, will use last project as label
2 changes: 1 addition & 1 deletion templates/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# To show in IDE
add_custom_target(
templates SOURCES CMakeLists.template.txt main.cpp main_debug.cpp
main_nominal.cpp main_simulate.cpp)
main_nominal.cpp main_simulate.cpp main_json.cpp)

set_target_properties(
templates
Expand Down
118 changes: 118 additions & 0 deletions templates/main_json.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/*
* Executable for evaluating the objective function for parameters specified
* in a json file. The results will be written to a json file.
*
* The input is a list of objects with the following fields:
* - conditionFileName: the name of the file containing the conditions
* - parameters: object with parameterId => parameterValue
* - gradient: boolean indicating whether the gradient should be computed
*
* The output is a list of objects with the following fields:
* - conditionFileName: the name of the file containing the conditions
* - parameters: object with parameterId => parameterValue
* - fval: the objective function value
* - gradient: boolean indicating whether the gradient should be computed
*/

#include <parpecommon/parpeConfig.h>

#include <parpeamici/multiConditionDataProvider.h>
#include <parpeamici/multiConditionProblem.h>
#include <parpeamici/standaloneSimulator.h>
#include <parpecommon/misc.h>
#include <parpecommon/parpeConfig.h>

#include <cstdio> // remove
#include <iostream>
#include <fstream>
#include <string_view>
#include <nlohmann/json.hpp>
#ifdef PARPE_ENABLE_MPI
#include <mpi.h>
#endif

using json = nlohmann::json;

// fields in the input/output json
constexpr std::string_view DATA_FILE = "conditionFileName";
constexpr std::string_view PARAMETERS = "parameters";
constexpr std::string_view FVAL = "fval";
constexpr std::string_view GRADIENT = "gradient";
constexpr std::string_view STATUS = "status";
constexpr std::string_view ERROR = "error";


namespace amici::generic_model {
std::unique_ptr<amici::Model> getModel();
}


void printUsage() {
std::cerr<<"Error: wrong number of arguments.\n";
std::cerr<<"Usage: ... infile outfile\n";
}

int main(int argc, char **argv) {
int status = EXIT_SUCCESS;

if(argc != 3) {
printUsage();
return EXIT_FAILURE;
}

std::string inFileArgument = argv[1];
std::string outFileArgument = argv[2];

std::ifstream istream(inFileArgument);
json jobs = json::parse(istream);

json results = json::array();
std::unique_ptr<parpe::MultiConditionDataProvider> dataProvider;
std::string h5file_name;

for (auto& job : jobs) {
std::cout<<job<<std::endl;
auto cur_result = job;
try {
if (job[DATA_FILE] != h5file_name) {
h5file_name = job[DATA_FILE];
dataProvider = std::make_unique<parpe::MultiConditionDataProviderHDF5>(
amici::generic_model::getModel(), h5file_name);
}
parpe::MultiConditionProblem problem(
dataProvider.get(), nullptr,
std::make_unique<parpe::Logger>(),
nullptr);

// parameter values
auto objective = dynamic_cast<parpe::SummedGradientFunctionGradientFunctionAdapter<int>*>(problem.cost_fun_.get());

auto parameter_ids = objective->getParameterIds();
std::vector<double> parameters;
parameters.reserve(parameter_ids.size());

for (auto& parameter_id: parameter_ids) {
parameters.push_back(job[PARAMETERS][parameter_id]);
}

double fval;
std::vector<double> gradient(parameter_ids.size());
auto fv = objective->evaluate(parameters, fval, job[GRADIENT]?gsl::make_span(gradient):gsl::span<double>(nullptr, 0));
cur_result[FVAL] = fval;
if (job[GRADIENT]) {
cur_result[GRADIENT] = gradient;
}
cur_result[STATUS] = fv;
} catch(std::exception& e) {
std::cerr<<e.what()<<std::endl;
cur_result[ERROR] = e.what();

}
results.push_back(cur_result);
// not efficient, but let's save it after every simulation for now
std::ofstream ostream(outFileArgument);
ostream << std::setw(4) << results << std::endl;
}

return status;
}

0 comments on commit eb35624

Please sign in to comment.