From 7889057c6473a989e1a1b7aac2ad043d64da98c2 Mon Sep 17 00:00:00 2001 From: arun3688 Date: Fri, 21 Aug 2026 13:44:02 +0200 Subject: [PATCH 1/8] Add C++ CLI options to OMSimulator Python interface --- src/OMSimulatorPython/cli.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/OMSimulatorPython/cli.py b/src/OMSimulatorPython/cli.py index f9c3b5134..faffcceb6 100644 --- a/src/OMSimulatorPython/cli.py +++ b/src/OMSimulatorPython/cli.py @@ -146,17 +146,17 @@ def _runFMU(path: Path, args: argparse.Namespace) -> None: } def main(argv=None) -> int: - parser = argparse.ArgumentParser(prog='OMSimulatorPython3', description=__doc__) + parser = argparse.ArgumentParser(prog='OMSimulatorPython3', description=__doc__, formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument('model', type=Path, help='Path to a .ssp or .fmu file to simulate') - parser.add_argument('--result-file', help='Override the result file name') - parser.add_argument('--start-time', type=float, help='Override the simulation start time') - parser.add_argument('--stop-time', type=float, help='Override the simulation stop time') - parser.add_argument('--tolerance', type=float, help='Override the solver tolerance (.fmu only)') - parser.add_argument('--step-size', type=float, help='Override the (maximum) simulation step size (.fmu only)') - parser.add_argument('--mode', choices=['cs', 'me'], help="Force 'cs' (co-simulation) or 'me' (model exchange) for FMUs that export both " "kinds (.fmu only)") - parser.add_argument('--solver', choices=['euler', 'cvode'], help='Set the ODE solver for model-exchange FMUs (.fmu, mode=me only)') - parser.add_argument('--stripRoot', action='store_true', help='Remove the root system prefix from exported signal names') - parser.add_argument('--skipCSVHeader', action='store_true', help='Skip the CSV delimiter row in the header of .csv result files (already the default)') + parser.add_argument('--resultFile', default='default_res.mat', help='Override the result file name') + parser.add_argument('--startTime', type=float, default=0.0, help='Override the simulation start time') + parser.add_argument('--stopTime', type=float, default=1.0, help='Override the simulation stop time') + parser.add_argument('--tolerance', type=float, default=1e-4, help='Override the solver tolerance (.fmu only)') + parser.add_argument('--stepSize', type=float, default=1e-3, help='Override the (maximum) simulation step size (.fmu only)') + parser.add_argument('--mode', choices=['cs', 'me'], default='me', help="Force 'cs' (co-simulation) or 'me' (model exchange) for FMUs that export both " "kinds (.fmu only)") + parser.add_argument('--solver', choices=['euler', 'cvode'], default='cvode', help='Set the ODE solver for model-exchange FMUs (.fmu, mode=me only)') + parser.add_argument('--stripRoot', action='store_true', default=True, help='Remove the root system prefix from exported signal names') + parser.add_argument('--skipCSVHeader', action='store_true', default=True, help='Skip the CSV delimiter row in the header of .csv result files (already the default)') parser.add_argument('--validate', action='store_true', help='Only validate the file against its schema; do not simulate') args = parser.parse_args(argv) From e03901c041fe492ef0c2fbcb0e9a737e3adc44fa Mon Sep 17 00:00:00 2001 From: arun3688 Date: Fri, 21 Aug 2026 14:32:14 +0200 Subject: [PATCH 2/8] add missing flags --- src/OMSimulatorPython/cli.py | 47 ++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/src/OMSimulatorPython/cli.py b/src/OMSimulatorPython/cli.py index faffcceb6..1da37d40b 100644 --- a/src/OMSimulatorPython/cli.py +++ b/src/OMSimulatorPython/cli.py @@ -77,10 +77,10 @@ def _runSSP(path: Path, args: argparse.Namespace) -> None: ssp = SSP(str(path)) model = ssp.instantiate() - if args.stop_time is not None: - model.setStopTime(args.stop_time) - if args.result_file is not None: - model.setResultFile(args.result_file) + if args.stopTime is not None: + model.setStopTime(args.stopTime) + if args.resultFile is not None: + model.setResultFile(args.resultFile) model.initialize() model.simulate() @@ -106,15 +106,15 @@ def _runFMU(path: Path, args: argparse.Namespace) -> None: # start/stop/tolerance/stepSize must be set before instantiate(): they need to reach # the FMU's fmi2SetupExperiment call, not just the solver's own bookkeeping, otherwise # the FMU's first recorded sample won't reflect the override (only later steps would). - fmu.startTime = args.start_time - fmu.stopTime = args.stop_time + fmu.startTime = args.startTime + fmu.stopTime = args.stopTime fmu.tolerance = args.tolerance - fmu.stepSize = args.step_size + fmu.stepSize = args.stepSize fmu.instantiate() # applies the settings above (falling back to the FMU's DefaultExperiment) if args.solver is not None: fmu.setSolver(args.solver) - fmu.setResultFile(args.result_file or f"{path.stem}_res.mat") + fmu.setResultFile(args.resultFile or f"{path.stem}_res.mat") exp = fmu.appliedExperiment kind_str = _FMU_KIND_STR.get(fmu.mode, fmu.mode) @@ -158,6 +158,37 @@ def main(argv=None) -> int: parser.add_argument('--stripRoot', action='store_true', default=True, help='Remove the root system prefix from exported signal names') parser.add_argument('--skipCSVHeader', action='store_true', default=True, help='Skip the CSV delimiter row in the header of .csv result files (already the default)') parser.add_argument('--validate', action='store_true', help='Only validate the file against its schema; do not simulate') + parser.add_argument('--addParametersToCSV', action='store_true', help='Export parameters to a .csv file') + parser.add_argument('--algLoopSolver', choices=['fixedpoint', 'kinsol'], default='kinsol', help='Specifies the loop solver method (fixedpoint, kinsol) used for algebraic loops spanning multiple components') + parser.add_argument('--clearAllOptions', action='store_true', help='Reset all flags to their default values') + parser.add_argument('--CVODEMaxErrTestFails', type=int, default=100, help='Maximum number of error test failures for CVODE') + parser.add_argument('--CVODEMaxNLSFailures', type=int, default=100, help='Maximum number of nonlinear convergence failures for CVODE') + parser.add_argument('--CVODEMaxNLSIterations', type=int, default=5, help='Maximum number of nonlinear solver iterations for CVODE') + parser.add_argument('--CVODEMaxSteps', type=int, default=1000, help='Maximum number of steps for CVODE') + parser.add_argument('--deleteTempFiles', action=argparse.BooleanOptionalAction, default=True, help='Delete temporary files as soon as they are no longer needed') + parser.add_argument('--directionalDerivatives', action=argparse.BooleanOptionalAction, default=True, help='Use directional derivatives to calculate the Jacobian for algebraic loops') + parser.add_argument('--dumpAlgLoops', action='store_true', help='Dump information for algebraic loops') + parser.add_argument('--emitEvents', action=argparse.BooleanOptionalAction, default=True, help='Emit events during simulation') + parser.add_argument('--ignoreInitialUnknowns', action='store_true', help='Ignore initial unknowns from the modelDescription.xml') + parser.add_argument('--initialStepSize', type=float, default=1e-6, help='Specify the initial step size') + parser.add_argument('--inputExtrapolation', action='store_true', help='Enable input extrapolation using derivative information') + parser.add_argument('--intervals', '-i', type=int, default=500, help='Specify the number of communication points (arg > 1)') + parser.add_argument('--logFile', '-l', help='Specify the log file (stdout is used if no log file is specified)') + parser.add_argument('--logLevel', type=int, default=0, help='Set the log level (0: default, 1: debug, 2: debug+trace)') + parser.add_argument('--master', default='ma', help='Specify the master algorithm (ma)') + parser.add_argument('--maxEventIteration', type=int, default=100, help='Specify the maximum number of iterations for handling a single event') + parser.add_argument('--maxLoopIteration', type=int, default=10, help='Specify the maximum number of iterations for solving algebraic loops between system-level components. Internal algebraic loops of components are not affected.') + parser.add_argument('--minimumStepSize', type=float, default=1e-12, help='Specify the minimum step size') + parser.add_argument('--numProcs', '-n', type=int, default=1, help='Specify the maximum number of processors to use (0=auto, 1=default)') + parser.add_argument('--progressBar', action='store_true', help='Show a progress bar for the simulation progress in the terminal') + parser.add_argument('--realTime', action='store_true', help='Enable experimental feature for (soft) real-time co-simulation') + parser.add_argument('--solverStats', action='store_true', help='Add solver stats to the result file, e.g., step size; not supported for all solvers') + parser.add_argument('--suppressPath', action='store_true', help='Suppress path information in info messages; especially useful for testing') + parser.add_argument('--tempDir', default='.', help='Specify the temporary directory') + parser.add_argument('--timeout', type=int, default=0, help='Specify the maximum allowed time in seconds for running a simulation (0 disables)') + parser.add_argument('--wallTime', action='store_true', help='Add wall time information to the result file') + parser.add_argument('--workingDir', default='.', help='Specify the working directory') + parser.add_argument('--zeroNominal', action='store_true', help='Accept FMUs with invalid nominal values and replace the invalid nominal values with 1.0') args = parser.parse_args(argv) handler = _HANDLERS.get(args.model.suffix.lower()) From d71665294258b962f466f32dbade010cbb520813 Mon Sep 17 00:00:00 2001 From: arun3688 Date: Fri, 21 Aug 2026 15:00:21 +0200 Subject: [PATCH 3/8] fix setting cs solver --- src/OMSimulatorPython/cli.py | 4 +++- src/OMSimulatorPython/fmu.py | 4 +--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/OMSimulatorPython/cli.py b/src/OMSimulatorPython/cli.py index 1da37d40b..afba35117 100644 --- a/src/OMSimulatorPython/cli.py +++ b/src/OMSimulatorPython/cli.py @@ -112,8 +112,10 @@ def _runFMU(path: Path, args: argparse.Namespace) -> None: fmu.stepSize = args.stepSize fmu.instantiate() # applies the settings above (falling back to the FMU's DefaultExperiment) - if args.solver is not None: + if args.solver is not None and args.mode == 'me': fmu.setSolver(args.solver) + elif args.mode == 'cs': + fmu.setSolver('ma') fmu.setResultFile(args.resultFile or f"{path.stem}_res.mat") exp = fmu.appliedExperiment diff --git a/src/OMSimulatorPython/fmu.py b/src/OMSimulatorPython/fmu.py index 548e6f838..a652528d2 100644 --- a/src/OMSimulatorPython/fmu.py +++ b/src/OMSimulatorPython/fmu.py @@ -58,6 +58,7 @@ _FMU_SOLVER = { 'euler': 2, 'cvode': 3, + 'ma':6 } class FMU: @@ -631,9 +632,6 @@ def setSolver(self, method: str): raise RuntimeError("FMU must be instantiated before setting the solver") if method not in _FMU_SOLVER: raise ValueError(f"Invalid solver '{method}': expected one of {sorted(_FMU_SOLVER)}") - if self.mode != 'me': - raise ValueError(f"Cannot set solver '{method}': '{self.instanceName}' is not a model-exchange FMU " - f"({_FMU_KIND_STR.get(self.mode, self.mode)})") status = Capi.setSolver(f"{self.instanceName}.root", _FMU_SOLVER[method]) if status != Status.ok: raise RuntimeError(f"Failed to set solver: {status}") From d365d196ac82045b6e70000811c608490442420f Mon Sep 17 00:00:00 2001 From: arun3688 Date: Mon, 24 Aug 2026 12:52:17 +0200 Subject: [PATCH 4/8] fix version and other flags --- src/OMSimulatorPython/cli.py | 65 +++++++++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 4 deletions(-) diff --git a/src/OMSimulatorPython/cli.py b/src/OMSimulatorPython/cli.py index afba35117..df1b88f0c 100644 --- a/src/OMSimulatorPython/cli.py +++ b/src/OMSimulatorPython/cli.py @@ -140,6 +140,13 @@ def _runFMU(path: Path, args: argparse.Namespace) -> None: '.fmu': _runFMU, } + +def _has_option(argv, option): + return any( + arg == option or arg.startswith(option + '=') + for arg in argv + ) + # Boolean CLI flags that map 1:1 to a global native command line option (applies # process-wide, regardless of .fmu/.ssp). args attribute name -> native option string. _GLOBAL_FLAGS = { @@ -147,7 +154,43 @@ def _runFMU(path: Path, args: argparse.Namespace) -> None: 'skipCSVHeader': '--skipCSVHeader=true', } +_GLOBAL_OPTIONS = { + 'addParametersToCSV': '--addParametersToCSV', + 'algLoopSolver': '--algLoopSolver', + 'clearAllOptions': '--clearAllOptions', + 'CVODEMaxErrTestFails': '--CVODEMaxErrTestFails', + 'CVODEMaxNLSFailures': '--CVODEMaxNLSFailures', + 'CVODEMaxNLSIterations': '--CVODEMaxNLSIterations', + 'CVODEMaxSteps': '--CVODEMaxSteps', + 'deleteTempFiles': '--deleteTempFiles', + 'directionalDerivatives': '--directionalDerivatives', + 'dumpAlgLoops': '--dumpAlgLoops', + 'emitEvents': '--emitEvents', + 'ignoreInitialUnknowns': '--ignoreInitialUnknowns', + 'initialStepSize': '--initialStepSize', + 'inputExtrapolation': '--inputExtrapolation', + 'intervals': '--intervals', + 'logFile': '--logFile', + 'logLevel': '--logLevel', + 'master': '--master', + 'maxEventIteration': '--maxEventIteration', + 'maxLoopIteration': '--maxLoopIteration', + 'minimumStepSize': '--minimumStepSize', + 'numProcs': '--numProcs', + 'progressBar': '--progressBar', + 'realTime': '--realTime', + 'solverStats': '--solverStats', + 'suppressPath': '--suppressPath', + 'tempDir': '--tempDir', + 'timeout': '--timeout', + 'wallTime': '--wallTime', + 'workingDir': '--workingDir', + 'zeroNominal': '--zeroNominal', +} def main(argv=None) -> int: + if argv is None: + argv = sys.argv[1:] + parser = argparse.ArgumentParser(prog='OMSimulatorPython3', description=__doc__, formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument('model', type=Path, help='Path to a .ssp or .fmu file to simulate') parser.add_argument('--resultFile', default='default_res.mat', help='Override the result file name') @@ -174,23 +217,24 @@ def main(argv=None) -> int: parser.add_argument('--ignoreInitialUnknowns', action='store_true', help='Ignore initial unknowns from the modelDescription.xml') parser.add_argument('--initialStepSize', type=float, default=1e-6, help='Specify the initial step size') parser.add_argument('--inputExtrapolation', action='store_true', help='Enable input extrapolation using derivative information') - parser.add_argument('--intervals', '-i', type=int, default=500, help='Specify the number of communication points (arg > 1)') - parser.add_argument('--logFile', '-l', help='Specify the log file (stdout is used if no log file is specified)') + parser.add_argument('--intervals', type=int, default=500, help='Specify the number of communication points (arg > 1)') + parser.add_argument('--logFile', help='Specify the log file (stdout is used if no log file is specified)') parser.add_argument('--logLevel', type=int, default=0, help='Set the log level (0: default, 1: debug, 2: debug+trace)') parser.add_argument('--master', default='ma', help='Specify the master algorithm (ma)') parser.add_argument('--maxEventIteration', type=int, default=100, help='Specify the maximum number of iterations for handling a single event') parser.add_argument('--maxLoopIteration', type=int, default=10, help='Specify the maximum number of iterations for solving algebraic loops between system-level components. Internal algebraic loops of components are not affected.') parser.add_argument('--minimumStepSize', type=float, default=1e-12, help='Specify the minimum step size') - parser.add_argument('--numProcs', '-n', type=int, default=1, help='Specify the maximum number of processors to use (0=auto, 1=default)') + parser.add_argument('--numProcs', type=int, default=1, help='Specify the maximum number of processors to use (0=auto, 1=default)') parser.add_argument('--progressBar', action='store_true', help='Show a progress bar for the simulation progress in the terminal') parser.add_argument('--realTime', action='store_true', help='Enable experimental feature for (soft) real-time co-simulation') parser.add_argument('--solverStats', action='store_true', help='Add solver stats to the result file, e.g., step size; not supported for all solvers') parser.add_argument('--suppressPath', action='store_true', help='Suppress path information in info messages; especially useful for testing') parser.add_argument('--tempDir', default='.', help='Specify the temporary directory') parser.add_argument('--timeout', type=int, default=0, help='Specify the maximum allowed time in seconds for running a simulation (0 disables)') - parser.add_argument('--wallTime', action='store_true', help='Add wall time information to the result file') + parser.add_argument('--wallTime', action='store_true',help='Add wall time information to the result file') parser.add_argument('--workingDir', default='.', help='Specify the working directory') parser.add_argument('--zeroNominal', action='store_true', help='Accept FMUs with invalid nominal values and replace the invalid nominal values with 1.0') + parser.add_argument('--version', action='version', version=f'{Capi.getVersion()}') args = parser.parse_args(argv) handler = _HANDLERS.get(args.model.suffix.lower()) @@ -208,6 +252,19 @@ def main(argv=None) -> int: if status != Status.ok: raise RuntimeError(f"Failed to set {option}: {status}") + for attr, option in _GLOBAL_OPTIONS.items(): + if _has_option(argv, option): + value = getattr(args, attr) + if value == "": + value = "''" # empty string needs to be quoted for the native command line parser + + if isinstance(value, bool): + value = str(value).lower() + + status = Capi.setCommandLineOption(f'{option}={value}') + if status != Status.ok: + raise RuntimeError(f"Failed to set {option}: {status}") + handler(args.model, args) return 0 From 4eb88530596ab685a35ef455f1e7017f2594608b Mon Sep 17 00:00:00 2001 From: arun3688 Date: Tue, 25 Aug 2026 10:35:03 +0200 Subject: [PATCH 5/8] Use OMSimulator scripts as platform-specific CLI launchers --- CMakeLists.txt | 5 -- doc/UsersGuide/CMakeLists.txt | 19 +++++-- src/OMSimulator/CMakeLists.txt | 7 --- src/OMSimulator/main.cpp | 53 ------------------- src/OMSimulatorPython/CMakeLists.txt | 8 +-- ...OMSimulatorPython3.bat => OMSimulator.bat} | 0 .../{OMSimulatorPython3.in => OMSimulator.in} | 0 7 files changed, 19 insertions(+), 73 deletions(-) delete mode 100644 src/OMSimulator/CMakeLists.txt delete mode 100644 src/OMSimulator/main.cpp rename src/OMSimulatorPython/{OMSimulatorPython3.bat => OMSimulator.bat} (100%) rename src/OMSimulatorPython/{OMSimulatorPython3.in => OMSimulator.in} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9e44b4aaa..62e51ae99 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,6 @@ cmake_minimum_required(VERSION 3.14) project(OMSimulator) # Options to enable/disable specific components -option(OMS_ENABLE_OMSimulator "Enable OMSimulator component" ON) option(OMS_ENABLE_OMSimulatorGui "Enable OMSimulator GUI component" OFF) option(OMS_ENABLE_PIP "Enable pip component" OFF) option(OMS_ENABLE_LOCAL_PIP "Prepare pip package using local OMSimulator build" OFF) @@ -78,10 +77,6 @@ add_subdirectory(src/OMSimulatorServer) add_subdirectory(doc) add_subdirectory(schema) -if(OMS_ENABLE_OMSimulator) - add_subdirectory(src/OMSimulator) -endif() - if(OMS_ENABLE_OMSimulatorGui) add_subdirectory(src/OMSimulatorGui) endif() diff --git a/doc/UsersGuide/CMakeLists.txt b/doc/UsersGuide/CMakeLists.txt index 25b77335f..855a34e6d 100644 --- a/doc/UsersGuide/CMakeLists.txt +++ b/doc/UsersGuide/CMakeLists.txt @@ -8,13 +8,24 @@ # if it is changed to link to a shared OMSimulatorLib, then it will not run from the build tree # because it will nto find the shared lib. In that case we need to first install the project and then # use the installed OMSimulator here. -add_custom_target(doc-generate-cmd-help-file - COMMAND $ --help > ${CMAKE_CURRENT_SOURCE_DIR}/source/omsimulator-help.inc - BYPRODUCTS ${CMAKE_CURRENT_SOURCE_DIR}/source/omsimulator-help.inc - COMMENT "Generating omsimulator-help.inc.") +if(WIN32) + set(OMSIMULATOR_COMMAND + "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/OMSimulator.bat") +else() + set(OMSIMULATOR_COMMAND + "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/OMSimulator") +endif() + +add_custom_target(doc-generate-cmd-help-file + COMMAND ${OMSIMULATOR_COMMAND} --help + > "${CMAKE_CURRENT_SOURCE_DIR}/source/omsimulator-help.inc" + BYPRODUCTS + "${CMAKE_CURRENT_SOURCE_DIR}/source/omsimulator-help.inc" + COMMENT "Generating omsimulator-help.inc." +) #################### ## PDF diff --git a/src/OMSimulator/CMakeLists.txt b/src/OMSimulator/CMakeLists.txt deleted file mode 100644 index b4d94f891..000000000 --- a/src/OMSimulator/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -project(OMSimulator) - -add_executable(OMSimulator main.cpp) - -target_link_libraries(OMSimulator PUBLIC OMSimulatorLib_static) - -install(TARGETS OMSimulator DESTINATION bin) diff --git a/src/OMSimulator/main.cpp b/src/OMSimulator/main.cpp deleted file mode 100644 index a9ae320fe..000000000 --- a/src/OMSimulator/main.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * This file is part of OpenModelica. - * - * Copyright (c) 1998-2026, Open Source Modelica Consortium (OSMC), - * c/o Linköpings universitet, Department of Computer and Information Science, - * SE-58183 Linköping, Sweden. - * - * All rights reserved. - * - * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF AGPL VERSION 3 LICENSE OR - * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8. - * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES - * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GNU AGPL - * VERSION 3, ACCORDING TO RECIPIENTS CHOICE. - * - * The OpenModelica software and the OSMC (Open Source Modelica Consortium) - * Public License (OSMC-PL) are obtained from OSMC, either from the above - * address, from the URLs: - * http://www.openmodelica.org or - * https://github.com/OpenModelica/ or - * http://www.ida.liu.se/projects/OpenModelica, - * and in the OpenModelica distribution. - * - * GNU AGPL version 3 is obtained from: - * https://www.gnu.org/licenses/licenses.html#GPL - * - * This program is distributed WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH - * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL. - * - * See the full OSMC Public License conditions for more details. - * - */ - -#include "OMSimulator/OMSimulator.h" -#include - -int main(int argc, char *argv[]) -{ - std::string arg; - for (int i = 1; i < argc; ++i) - { - if (!arg.empty()) - arg += " "; - arg += "\"" + std::string(argv[i]) + "\""; - } - - if (oms_status_ok != oms_setCommandLineOption(arg.c_str())) - return 1; - - return 0; -} diff --git a/src/OMSimulatorPython/CMakeLists.txt b/src/OMSimulatorPython/CMakeLists.txt index 18cbeb48d..d5fcb8169 100644 --- a/src/OMSimulatorPython/CMakeLists.txt +++ b/src/OMSimulatorPython/CMakeLists.txt @@ -24,7 +24,7 @@ endif() configure_file("${CMAKE_CURRENT_SOURCE_DIR}/__init__.py" "${CMAKE_CURRENT_BINARY_DIR}/__init__.py" @ONLY) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/capi.py" "${CMAKE_CURRENT_BINARY_DIR}/capi.py" @ONLY) -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/OMSimulatorPython3.in" "${CMAKE_CURRENT_BINARY_DIR}/OMSimulatorPython3" @ONLY) +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/OMSimulator.in" "${CMAKE_CURRENT_BINARY_DIR}/OMSimulator" @ONLY) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/__init__.py" "${CMAKE_CURRENT_SOURCE_DIR}/__main__.py" @@ -53,14 +53,14 @@ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/__init__.py" DESTINATION ${CMAKE_INSTALL_LIBDIR}/OMSimulator) if(MSVC) - install(FILES OMSimulatorPython3.bat TYPE BIN + install(FILES OMSimulator.bat TYPE BIN PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ) elseif(MINGW) - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/OMSimulatorPython3" OMSimulatorPython3.bat + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/OMSimulator" OMSimulator.bat TYPE BIN PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ) else() - install(FILES "${CMAKE_CURRENT_BINARY_DIR}/OMSimulatorPython3" + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/OMSimulator" TYPE BIN PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ) endif() diff --git a/src/OMSimulatorPython/OMSimulatorPython3.bat b/src/OMSimulatorPython/OMSimulator.bat similarity index 100% rename from src/OMSimulatorPython/OMSimulatorPython3.bat rename to src/OMSimulatorPython/OMSimulator.bat diff --git a/src/OMSimulatorPython/OMSimulatorPython3.in b/src/OMSimulatorPython/OMSimulator.in similarity index 100% rename from src/OMSimulatorPython/OMSimulatorPython3.in rename to src/OMSimulatorPython/OMSimulator.in From 6b26616cddfb34d2d7b613151fad5e5e54dca901 Mon Sep 17 00:00:00 2001 From: arun3688 Date: Tue, 25 Aug 2026 12:13:24 +0200 Subject: [PATCH 6/8] update runtest.py --- testsuite/runtest.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/testsuite/runtest.py b/testsuite/runtest.py index bbdfc8f69..430881895 100755 --- a/testsuite/runtest.py +++ b/testsuite/runtest.py @@ -79,7 +79,7 @@ def absolute(path: Path) -> Path: private work directory of a test never does -- that proof depends on the two lookups failing with the same error code, so the prefix survives every now and then. A `\\\\?\\` directory then breaks the test: every .py test is started - through OMSimulatorPython3.bat, i.e. through cmd.exe, which rejects such a + through OMSimulator.bat, i.e. through cmd.exe, which rejects such a working directory ("UNC paths are not supported"), falls back to C:\\Windows and runs the test where none of its files are. """ @@ -117,10 +117,7 @@ def simulator_executable(test_file: Path, bin_dir: Path) -> Path: # (subprocess uses CreateProcess, not a POSIX exec), which cannot run the # shebang-based shell script directly, so both need the .bat/.exe wrapper. windows = PLATFORM in ("win", "ucrt64") - if test_file.suffix == ".py": - name = "OMSimulatorPython3.bat" if windows else "OMSimulatorPython3" - else: - name = "OMSimulator.exe" if windows else "OMSimulator" + name = "OMSimulator.bat" if windows else "OMSimulator" return bin_dir / name @@ -342,7 +339,7 @@ def main() -> int: parser.add_argument("--work-dir", required=True, type=Path, help="private working directory for this test; it is wiped on every run") parser.add_argument("--bin-dir", required=True, type=Path, - help="directory holding OMSimulator / OMSimulatorPython3") + help="directory holding OMSimulator / OMSimulator") parser.add_argument("--omc-diff", required=True, type=Path, help="the omc-diff executable used to compare results") parser.add_argument("--epsilon", default=DEFAULT_EPSILON, From 20a75ee285ea9001e3d51a6ab254a2e5a5d5d602 Mon Sep 17 00:00:00 2001 From: arun3688 Date: Tue, 25 Aug 2026 13:35:02 +0200 Subject: [PATCH 7/8] update Jenkinsfile to use OMSimulator.bat in windows --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 358357d13..21c75d623 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -310,7 +310,7 @@ IF NOT ["%ERRORLEVEL%"]==["0"] GOTO fail cmake --build build/ --config Release --parallel %NUMBER_OF_PROCESSORS% --target install -v IF NOT ["%ERRORLEVEL%"]==["0"] GOTO fail -call install\\bin\\OMSimulator.exe --version +call install\\bin\\OMSimulator.bat --version IF NOT ["%ERRORLEVEL%"]==["0"] GOTO fail C:\\OMDevUCRT\\tools\\msys\\usr\\bin\\sh --login -i '${env.WORKSPACE}/buildZip.sh' From fe0dd5577683e9b3712c96eaf41fdc5b624b46a6 Mon Sep 17 00:00:00 2001 From: arun3688 Date: Tue, 25 Aug 2026 15:45:37 +0200 Subject: [PATCH 8/8] Use python instead of python3 in Windows launcher --- src/OMSimulatorPython/OMSimulator.bat | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/OMSimulatorPython/OMSimulator.bat b/src/OMSimulatorPython/OMSimulator.bat index aac6929d5..13e762213 100644 --- a/src/OMSimulatorPython/OMSimulator.bat +++ b/src/OMSimulatorPython/OMSimulator.bat @@ -6,7 +6,7 @@ set PATH=%~dp0;%~dp0\..\bin;%PATH% rem A ".py" argument is run as a driver script, as before. Anything else rem (e.g. a .ssp or .fmu model file) is handed to the OMSimulator CLI module. if /I "%~x1"==".py" ( - python3 %* + python %* ) else ( - python3 -m OMSimulator %* + python -m OMSimulator %* )