Skip to content

Conversation

@kbenne
Copy link
Contributor

@kbenne kbenne commented Dec 16, 2025

Summary

  • Introduces a full Modelica workflow stack—ModelicaFile ownership/AST management, generated ANTLR parser artifacts, SWIG bindings, and OSWorkflow plumbing—so ModelicaMeasure authors can
    parse, edit, and run Modelica directly within OpenStudio.
  • Adds ModelicaMeasure and ModelicaParameters, extends OSRunner + WorkflowJSON (seed file metadata, snapshotting, last result path), and captures Modelica runs in run/stdout-modelica
    alongside the .mat result file.
  • Ships an end-to-end example under resources/Examples/compact_osw/, thoroughly documented in MODELICA_README.md—start there for an overview of the workflow, the SetModelicaZones measure,
    and the sample Modelica libraries you can run via the CLI.

Key Areas to Review

  • resources/Examples/compact_osw/
    • MODELICA_README.md: walkthrough for running the Modelica OSW, inspecting results, and troubleshooting.
    • compact_modelica.osw, modellica/OpenStudioExample/*, and measures/SetModelicaZones/ (measure code, README, tests) show how the workflow is wired together.
  • src/modelica/
    • ModelicaFile., ModelicaFileImpl., the generated ANTLR sources, Modelica.i, ModelicaAPI.hpp, and src/modelica/CMakeLists.txt implement parsing, ownership, and bindings.
  • src/measure/
    • ModelicaMeasure., ModelicaParameters., and the updated OSRunner.* surface Modelica parameters and last-result-file info to measures.
  • src/utilities/filetypes/WorkflowJSON* & src/workflow/*
    • Workflow JSON now carries modelicaSeedFile; OSWorkflow tracks snapshots and adds runModelicaMeasures/runModelica stages.
    • RunModelicaMeasures.cpp applies Modelica measures, and RunModelica.cpp builds the .mos, launches OpenModelica, parses tagged output, and records the result file.
  • Supporting changes across CMakeLists.txt, Ruby bindings (Measure.i, InitRubyBindings.cpp, ruby/module/CMakeLists.txt), etc., to integrate the new module.

Notes / Follow-ups

  • Only OpenModelica is supported at the moment; Dymola hooks can follow once we can validate them.
  • There is still no automated CLI regression for the Modelica OSW; the environment setup is involved.

- add a full Modelica parsing stack (ModelicaFile ownership/AST management, ANTLR grammar artifacts, SWIG interface, and CLI driver) so measures can inspect and edit Modelica source safely
- expose ModelicaMeasure/ModelicaParameters, extend OSRunner + WorkflowJSON to pass parameters and surface the last simulation result, and wire everything through OSWorkflow with runModelica/runModelicaMeasures steps
- ship a compact Modelica example workflow, measure, Modelica libraries, and README to demonstrate running the CLI end-to-end, while tightening logging, bindings, and CMake integration to make the feature production-ready
@anchapin anchapin added the Pull Request - Ready for CI This pull request if finalized and is ready for continuous integration verification prior to merge. label Dec 16, 2025
@anchapin anchapin merged commit b652977 into develop Dec 16, 2025
3 checks passed
@anchapin anchapin deleted the issue-5356-modelica-measures-squashed branch December 16, 2025 15:07
Comment on lines +185 to +187
# KSB: This is an abomination. the basic idea is that we need a full path to the crypto library
# so that we can use -force_load
# It would really be nice to have a simpler solution, but this appears to work
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👀

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kbenne did you mean to commit this?

auto classDefinitions = moFile.getClassDefinitions();

for (const auto& classDef : classDefinitions) {
std::cout << "Found class name: " << classDef.longClassSpecifier() << std::endl; // NOLINT
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're already importing fmt, so why not use it instead of iostream?

Comment on lines +84 to +89
ModelicaSyntax(std::shared_ptr<ModelicaFileImpl> modelicaFile, T* ctx) // NOLINT
: m_modelicaFile(std::move(modelicaFile)), m_ctx(ctx), m_id(Derived::idFromCTX(ctx)) {
if (auto file = m_modelicaFile.lock()) {
file->addModelicaSyntax(this);
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick but you're using a cpp file to go with it, so why add the implementation inline in the header file?

Comment on lines +90 to +91
ModelicaSyntax(const ModelicaSyntax&) = delete; // NOLINT
ModelicaSyntax(ModelicaSyntax&&) = default; // NOLINT
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(curious why NOLINT)

Comment on lines +12 to +38
namespace detail {
class ModelicaParameter_Impl
{
public:
ModelicaParameter_Impl(std::string_view model, std::string_view key, std::string_view value) : m_model(model), m_key(key), m_value(value) {}

std::string model() const {
return m_model;
};

std::string key() const {
return m_key;
};

std::string value() const {
return m_value;
}

void setValue(std::string_view value) {
m_value = value;
}

private:
std::string m_model;
std::string m_key;
std::string m_value;
};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find that weird to define the Impl fully inside the cpp file because it doesn't follow the usual convention in the repo.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally we have a single cpp file for both Impl and the public forward methods.

std::string ModelicaFileImpl::printTree() const {
std::stringstream ss;

const std::function<void(antlr4::tree::ParseTree*, antlr4::Parser*, int)> to_s = [&ss, &to_s](antlr4::tree::ParseTree* tree, antlr4::Parser* parser,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

recursive std::function, fancy.

Comment on lines +710 to +753
//std::vector<ComponentDeclaration> ComponentClause::componentDeclarations() {
// std::vector<ComponentDeclaration> result;
//
// const auto component_declarations = antlr4::tree::xpath::XPath::findAll(ctx(), "//Component_declaration", parser());
//
// for (auto* c : component_declarations) {
// auto* component_declaration_ctx = dynamic_cast<modelicaParser::Component_declarationContext*>(c);
// assert(component_declaration_ctx != nullptr);
// result.emplace_back(modelicaFile(), component_declaration_ctx); // NOLINT
// }
//
// return result;
//}

//std::string ComponentDeclaration::idFromCTX([[maybe_unused]] modelicaParser::Component_declarationContext* ctx) {
// // TODO
// return "";
//}

//std::vector<Declaration> ClassDefinition::declarations() {
// class_definition::GetDeclarationsVisitor v;
// v.visit(m_ctx);
// return v.getResult();
//}
//
//void ClassDefinition::addDeclaration(const std::string& declarationText) {
// const auto el = m_ctx->class_specifier()->long_class_specifier()->composition()->element_list();
//
// antlr4::ANTLRInputStream input(declarationText + ";"); // Ensure it's a complete statement
// modelicaLexer lexer(&input);
// antlr4::CommonTokenStream tempTokens(&lexer);
// modelicaParser tempParser(&tempTokens);
//
// [[maybe_unused]] const auto* component = tempParser.component_clause();
//
// // Attempt to parse as a component_clause (variable declaration)
// modelicaParser::Component_clauseContext* parsedDecl = nullptr;
//}
//
//Declaration::Declaration(modelicaParser::DeclarationContext* ctx) : m_ctx(ctx) {}
//
//std::string Declaration::name() const {
// return m_ctx->IDENT()->getText();
//}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's up with the commented code?

if (workflowJSON.runOptions()->debug() && oriLogLevel > Debug) {
targetLogLevel = Debug;
}
LogLevel targetLogLevel = workflowJSON.runOptions()->debug() ? Debug : oriLogLevel;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why?

Seems like you're no longer matching the comment above that says

If the user passed something like openstudio --loglevel Trace run --debug -w workflow.osw, we retain the Trace

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Pull Request - Ready for CI This pull request if finalized and is ready for continuous integration verification prior to merge.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants