Skip to content

Commit

Permalink
Flesh out OpenModelica simulate and compile commands
Browse files Browse the repository at this point in the history
  • Loading branch information
kbenne committed Dec 4, 2023
1 parent a5d604f commit f01edb1
Show file tree
Hide file tree
Showing 19 changed files with 299 additions and 76 deletions.
4 changes: 4 additions & 0 deletions modelica/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@ if(ENABLE_COMPILER)

add_library(spawn_modelica
modelica_engine.hpp
create_exe.hpp
create_exe.cpp
create_fmu.hpp
create_fmu.cpp
simulate.hpp
simulate.cpp
)

target_include_directories(spawn_modelica
Expand Down
14 changes: 14 additions & 0 deletions modelica/create_exe.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#include "create_exe.hpp"
#include "open_modelica/open_modelica_engine.hpp"

namespace spawn::modelica {

void CreateEXE::operator()() const
{
spawn::openmodelica::OpenModelicaEngine open_modelica_engine;

auto output_dir = spawn_fs::current_path();
open_modelica_engine.create_exe(model, output_dir, modelica_path, modelica_files);
}

} // namespace spawn::modelica
21 changes: 21 additions & 0 deletions modelica/create_exe.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#ifndef MODELICA_CREATE_EXE_HH_INCLUDED
#define MODELICA_CREATE_EXE_HH_INCLUDED

#include "util/filesystem.hpp"
#include <iostream>
#include <string>
#include <vector>
namespace spawn::modelica {

struct CreateEXE
{
void operator()() const;

std::string modelica_path;
std::vector<spawn_fs::path> modelica_files;
std::string model;
};

} // namespace spawn::modelica

#endif // MODELICA_CREATE_EXE_HH_INCLUDED
3 changes: 1 addition & 2 deletions modelica/create_fmu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ void CreateFMU::operator()() const
spawn::openmodelica::OpenModelicaEngine open_modelica_engine;

auto output_dir = spawn_fs::current_path();
[[maybe_unused]] auto path =
open_modelica_engine.create_fmu(model, output_dir, modelica_path, modelica_files, fmu::toFMUType(fmu_type));
open_modelica_engine.create_fmu(model, output_dir, modelica_path, modelica_files, fmu::toFMUType(fmu_type));
}

} // namespace spawn::modelica
2 changes: 1 addition & 1 deletion modelica/create_fmu.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ struct CreateFMU
{
void operator()() const;

std::vector<spawn_fs::path> modelica_path;
std::string modelica_path;
std::vector<spawn_fs::path> modelica_files;
bool optimica{false};
std::string model;
Expand Down
33 changes: 21 additions & 12 deletions modelica/modelica_engine.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,27 @@ class ModelicaEngine
virtual ~ModelicaEngine() = default;

// Compile moInput to a Functional Mockup Unit
[[nodiscard]] virtual spawn_fs::path create_fmu(const std::string_view mo_input,
const spawn_fs::path &output_dir,
const std::vector<spawn_fs::path> &modelica_paths,
const std::vector<spawn_fs::path> &modelica_files,
const spawn::fmu::FMUType &fmu_type) = 0;

// Not Implemented - Compile moInput to an executable
[[nodiscard]] virtual spawn_fs::path create_exe(const std::string_view mo_input,
const spawn_fs::path &output_dir,
const std::vector<spawn_fs::path> &modelica_paths,
const std::vector<spawn_fs::path> &modelica_files,
const spawn::fmu::FMUType &fmu_type) = 0;
virtual void create_fmu(const std::string_view mo_input,
const spawn_fs::path &output_dir,
const std::string_view modelica_path,
const std::vector<spawn_fs::path> &modelica_files,
const spawn::fmu::FMUType &fmu_type) = 0;

// Compile moInput to an executable
virtual void create_exe(const std::string_view mo_input,
const spawn_fs::path &output_dir,
const std::string_view modelica_path,
const std::vector<spawn_fs::path> &modelica_files) = 0;

// Compile and simulate a model
virtual void simulate(const std::string_view model,
const std::string_view modelica_path,
const std::vector<spawn_fs::path> &modelica_files,
const double &start_time,
double stop_time,
unsigned number_of_intervals,
const double &tolerance,
const std::string_view method) = 0;
};

} // namespace spawn::modelica
Expand Down
16 changes: 16 additions & 0 deletions modelica/simulate.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#include "simulate.hpp"
#include "open_modelica/open_modelica_engine.hpp"

namespace spawn::modelica {

void Simulate::operator()() const
{
spawn::openmodelica::OpenModelicaEngine open_modelica_engine;

auto output_dir = spawn_fs::current_path();

open_modelica_engine.simulate(
model, modelica_path, modelica_files, start_time, stop_time, number_of_intervals, tolerance, method);
}

} // namespace spawn::modelica
27 changes: 27 additions & 0 deletions modelica/simulate.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#ifndef MODELICA_SIMULATE_HH_INCLUDED
#define MODELICA_SIMULATE_HH_INCLUDED

#include "modelica/modelica_engine.hpp"
#include "util/filesystem.hpp"
#include <iostream>
#include <string>
#include <vector>
namespace spawn::modelica {

struct Simulate
{
void operator()() const;

std::string model;
std::string modelica_path;
std::vector<spawn_fs::path> modelica_files;
double start_time{0.0};
double stop_time{31536000.0};
unsigned number_of_intervals{500};
double tolerance{1e-6};
std::string method{"dassl"};
};

} // namespace spawn::modelica

#endif // MODELICA_SIMULATE_HH_INCLUDED
123 changes: 104 additions & 19 deletions open_modelica/open_modelica_engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <iostream>
#include <nlohmann/json.hpp>
#include <omc/c/meta/meta_modelica.h>
#include <spdlog/spdlog.h>

extern "C" {
int omc_Main_handleCommand(void *threadData, void *imsg, void **omsg);
Expand All @@ -29,12 +30,11 @@ OpenModelicaEngine::OpenModelicaEngine()
omc_Main_init(thread_data, args);
}

[[nodiscard]] spawn_fs::path
OpenModelicaEngine::create_fmu([[maybe_unused]] const std::string_view mo_input,
[[maybe_unused]] const spawn_fs::path &output_dir,
[[maybe_unused]] const std::vector<spawn_fs::path> &modelica_paths, // NOLINT
[[maybe_unused]] const std::vector<spawn_fs::path> &modelica_files,
[[maybe_unused]] const spawn::fmu::FMUType &fmu_type)
void OpenModelicaEngine::create_fmu([[maybe_unused]] const std::string_view mo_input,
[[maybe_unused]] const spawn_fs::path &output_dir,
[[maybe_unused]] const std::string_view modelica_path, // NOLINT
[[maybe_unused]] const std::vector<spawn_fs::path> &modelica_files,
[[maybe_unused]] const spawn::fmu::FMUType &fmu_type)
{
for (const auto &file : modelica_files) {
load_file(file);
Expand All @@ -44,33 +44,104 @@ OpenModelicaEngine::create_fmu([[maybe_unused]] const std::string_view mo_input,
load_mbl();
}

auto command = fmt::format(R"(buildModelFMU({}, "2.0", "cs"))", mo_input);
[[maybe_unused]] auto response = eval(command);
const auto command = fmt::format(R"(buildModelFMU({}, "2.0", "cs"))", mo_input);
const auto response = eval(command);

return {};
spdlog::info("OpenModelica buildModel output: {}", response);
}

[[nodiscard]] spawn_fs::path
OpenModelicaEngine::create_exe([[maybe_unused]] const std::string_view mo_input,
[[maybe_unused]] const spawn_fs::path &output_dir,
[[maybe_unused]] const std::vector<spawn_fs::path> &modelica_paths, // NOLINT
[[maybe_unused]] const std::vector<spawn_fs::path> &modelica_files,
[[maybe_unused]] const spawn::fmu::FMUType &fmu_type)
void OpenModelicaEngine::create_exe(const std::string_view mo_input,
[[maybe_unused]] const spawn_fs::path &output_dir,
[[maybe_unused]] const std::string_view modelica_path, // NOLINT
const std::vector<spawn_fs::path> &modelica_files)
{
return {};
for (const auto &file : modelica_files) {
load_file(file);
}

if (!mbl_is_loaded()) {
load_mbl();
}

const auto command = fmt::format(R"(buildModel({}))", mo_input);
const auto response = eval(command);

spdlog::info("OpenModelica buildModel output: {}", response);
}

std::string OpenModelicaEngine::eval(std::string_view command)
void OpenModelicaEngine::simulate(const std::string_view model, // NOLINT
[[maybe_unused]] const std::string_view modelica_path, // NOLINT
const std::vector<spawn_fs::path> &modelica_files,
[[maybe_unused]] const double &start_time, // NOLINT
[[maybe_unused]] double stop_time,
[[maybe_unused]] unsigned number_of_intervals,
[[maybe_unused]] const double &tolerance,
[[maybe_unused]] const std::string_view method)

{
for (const auto &file : modelica_files) {
load_file(file);
}

if (!mbl_is_loaded()) {
load_mbl();
}

auto command =
fmt::format(R"(simulate({}, startTime={}, stopTime={}, numberOfIntervals={}, tolerance={}, method="{}"))",
model,
start_time,
stop_time,
number_of_intervals,
tolerance,
method);
const auto result = eval(command);

spdlog::info("OpenModelica simulation output: {}", result);
}

void OpenModelicaEngine::clear_messages()
{
void *response_data{nullptr};
auto response_code = omc_Main_handleCommand(thread_data, mmc_mk_scon("clearMessages()"), &response_data);
if (response_code != 1) {
throw std::runtime_error("OpenModelicaEngine failed to clear messages before evaluating command");
}
}

void OpenModelicaEngine::log_last_message()
{
void *response_data{nullptr};
auto response_code = omc_Main_handleCommand(thread_data, mmc_mk_scon("getErrorString()"), &response_data);
if (response_code != 1) {
throw std::runtime_error("OpenModelica failed to get error string after evaluating command");
}
std::string error_string = MMC_STRINGDATA(response_data); // NOLINT
spawn::unquote(error_string);
spawn::trim(error_string);
if (!error_string.empty()) {
const auto level = log_level(error_string);
spdlog::log(level, "OpenModelica message: '{}'", error_string);
}
}

std::string OpenModelicaEngine::eval(std::string_view command)
{
spdlog::trace("OpenModelica is evaluating command: '{}'", command);

clear_messages();

void *response_data{nullptr};
auto response_code = omc_Main_handleCommand(thread_data, mmc_mk_scon(std::string(command).c_str()), &response_data);
if (response_code != 1) {
throw std::runtime_error(fmt::format("OpenModelica failed to evaluate command: '{}'", command));
}

std::string response_string = MMC_STRINGDATA(response_data); // NOLINT
return spawn::trim(response_string);
spawn::trim(response_string);

log_last_message();

return response_string;
}

void OpenModelicaEngine::load_file(const spawn_fs::path &file)
Expand All @@ -91,4 +162,18 @@ bool OpenModelicaEngine::mbl_is_loaded()
return std::find(classes.begin(), classes.end(), "Buildings") != classes.end();
}

spdlog::level::level_enum OpenModelicaEngine::log_level(const std::string_view log_message)
{
const std::map<std::string, spdlog::level::level_enum> log_level_map = {
{"Error", spdlog::level::err}, {"Warning", spdlog::level::warn}, {"Notification", spdlog::level::info}};

for (const auto &level : log_level_map) {
if (log_message.rfind(level.first, 0) == 0) {
return level.second;
}
}

return spdlog::level::info;
}

} // namespace spawn::openmodelica
40 changes: 27 additions & 13 deletions open_modelica/open_modelica_engine.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define OPEN_MODELICA_ENGINE_HPP_INCLUDED

#include "modelica/modelica_engine.hpp"
#include <spdlog/common.h>

struct threadData_s;

Expand All @@ -18,25 +19,38 @@ class OpenModelicaEngine : modelica::ModelicaEngine
~OpenModelicaEngine() override = default;

// Compile moInput to a Functional Mockup Unit
[[nodiscard]] spawn_fs::path create_fmu(const std::string_view mo_input,
const spawn_fs::path &output_dir,
const std::vector<spawn_fs::path> &modelica_paths,
const std::vector<spawn_fs::path> &modelica_files,
const spawn::fmu::FMUType &fmu_type) override;

// Not Implemented - Compile moInput to an executable
[[nodiscard]] spawn_fs::path create_exe(const std::string_view mo_input,
const spawn_fs::path &output_dir,
const std::vector<spawn_fs::path> &modelica_paths,
const std::vector<spawn_fs::path> &modelica_files,
const spawn::fmu::FMUType &fmu_type) override;

void create_fmu(const std::string_view mo_input,
const spawn_fs::path &output_dir,
const std::string_view modelica_path,
const std::vector<spawn_fs::path> &modelica_files,
const spawn::fmu::FMUType &fmu_type) override;

// Compile moInput to an executable
void create_exe(const std::string_view mo_input,
const spawn_fs::path &output_dir,
const std::string_view modelica_path,
const std::vector<spawn_fs::path> &modelica_files) override;

// Compile and simulate a model
void simulate(const std::string_view model,
const std::string_view modelica_path,
const std::vector<spawn_fs::path> &modelica_files,
const double &start_time,
double stop_time,
unsigned number_of_intervals,
const double &tolerance,
const std::string_view method) override;

// Evaluate command using the OpenModelica script engine
std::string eval(std::string_view command);

private:
void load_file(const spawn_fs::path &file);
void load_mbl();
bool mbl_is_loaded();
void clear_messages();
void log_last_message();
static spdlog::level::level_enum log_level(const std::string_view log_message);

threadData_s *thread_data;
};
Expand Down
3 changes: 1 addition & 2 deletions open_modelica/test/test_compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,5 @@ TEST_CASE("OpenModelicaEngine is able to compile the single family home example"
{
spawn::openmodelica::OpenModelicaEngine om;

[[maybe_unused]] auto result =
om.create_fmu(one_zone_one_year, spawn_fs::current_path(), {}, {}, spawn::fmu::FMUType::CS);
om.create_fmu(one_zone_one_year, spawn_fs::current_path(), {}, {}, spawn::fmu::FMUType::CS);
}
Loading

0 comments on commit f01edb1

Please sign in to comment.