Skip to content

Commit

Permalink
Merge branch 'develop' into 4692_Model_load
Browse files Browse the repository at this point in the history
  • Loading branch information
jmarrec authored Aug 24, 2023
2 parents 0e36453 + a04ae99 commit 5ff5fe7
Show file tree
Hide file tree
Showing 36 changed files with 1,363 additions and 389 deletions.
6 changes: 4 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
message(STATUS "Using CMake ${CMAKE_VERSION}")
cmake_minimum_required(VERSION 3.19.0)
cmake_minimum_required(VERSION 3.20.0)
cmake_policy(SET CMP0048 NEW)

set(CMAKE_CXX_STANDARD 20)
Expand Down Expand Up @@ -1216,7 +1216,9 @@ if(NOT UNIX)
if(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS)
install(FILES ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} DESTINATION "bin")
install(FILES ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} DESTINATION "Ruby" COMPONENT "RubyAPI")
install(FILES ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} DESTINATION "CSharp/openstudio/" COMPONENT "CSharpAPI")
if (BUILD_CSHARP_BINDINGS)
install(FILES ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} DESTINATION "CSharp/openstudio/" COMPONENT "CSharpAPI")
endif()
endif()
endif()

Expand Down
18 changes: 3 additions & 15 deletions ProjectMacros.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -326,20 +326,8 @@ macro(MAKE_SWIG_TARGET NAME SIMPLENAME KEY_I_FILE I_FILES PARENT_TARGET PARENT_S
endif()


# Add the -py3 flag if the version used is Python 3
set(SWIG_PYTHON_3_FLAGS "")
if (Python_VERSION_MAJOR)
if (Python_VERSION_MAJOR EQUAL 3)
set(SWIG_PYTHON_3_FLAGS "-py3;-relativeimport")
message(STATUS "${MODULE_NAME} - Building SWIG Bindings for Python 3")
else()
message(STATUS "${MODULE_NAME} - Building SWIG Bindings for Python 2")
endif()
else()
# Python2 has been EOL since January 1, 2020
set(SWIG_PYTHON_3_FLAGS "-py3;-relativeimport")
message(STATUS "${MODULE_NAME} - Couldn't determine version of Python - Building SWIG Bindings for Python 3")
endif()
# The -py3 flag is now deprecated as Python 3 is the default the version used is Python 3
set(SWIG_PYTHON_3_FLAGS "-relativeimport")

add_custom_command(
OUTPUT "${SWIG_WRAPPER_FULL_PATH}" "${PYTHON_GENERATED_SRC}"
Expand Down Expand Up @@ -511,7 +499,7 @@ macro(MAKE_SWIG_TARGET NAME SIMPLENAME KEY_I_FILE I_FILES PARENT_TARGET PARENT_S
# This is not working: "cannot open file 'python37.lib'"
target_link_libraries(${swig_target} PUBLIC ${${PARENT_TARGET}_depends})
if (MSVC)
message("Python_LIBRARIES=${Python_LIBRARIES}")
message(DEBUG "Python_LIBRARIES=${Python_LIBRARIES}")
target_link_libraries(${swig_target} PRIVATE Python::Module)
endif()
#target_link_libraries(${swig_target} PUBLIC ${${PARENT_TARGET}_depends}) ${Python_LIBRARIES})
Expand Down
19 changes: 10 additions & 9 deletions csharp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ install(DIRECTORY "examples"
PATTERN "*.docx"
)

file(TO_NATIVE_PATH "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/csharp" CSHARP_LIBRARY_OUTPUT_DIRECTORY)
file(TO_NATIVE_PATH "${PROJECT_SOURCE_DIR}/csharp" CSHARP_SOURCE_DIR)
file(TO_NATIVE_PATH "${PROJECT_BINARY_DIR}/csharp_wrapper" CSHARP_BINARY_DIR)
set(CSHARP_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/csharp")

# For csproj.in
file(TO_NATIVE_PATH "${CSHARP_LIBRARY_OUTPUT_DIRECTORY}" CSHARP_LIBRARY_OUTPUT_DIRECTORY_NATIVE)
file(TO_NATIVE_PATH "${PROJECT_SOURCE_DIR}/csharp" CSHARP_SOURCE_DIR_NATIVE)

set(CSHARP_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
set(CSHARP_VERSION_MINOR ${PROJECT_VERSION_MINOR})
Expand Down Expand Up @@ -48,7 +50,9 @@ endif()

# The Release/Debug can be stripped probably
# Also probably don't need to use multiple `<TargetFrameworks>` which is the reason there's an extra netstandard2.0/ level
set(OPENSTUDIO_CSHARP_DLL "${CSHARP_LIBRARY_OUTPUT_DIRECTORY}/${CMAKE_BUILD_TYPE}/netstandard2.0/OpenStudio.dll")
# Note: can't use CMAKE_BUILD_TYPE as it's empty for multi generators (MSVC for eg). So we use a genex
# We use the non-native, cmake_path, version of library output directory otherwise install fails with mistmatched `/` and `\` on windows
set(OPENSTUDIO_CSHARP_DLL "${CSHARP_LIBRARY_OUTPUT_DIRECTORY}/$<CONFIG>/netstandard2.0/OpenStudio.dll")

# ignore deprecated warnings since we will export deprecated methods
add_library(csharp_warnings INTERFACE)
Expand All @@ -60,14 +64,11 @@ target_compile_options(csharp_warnings INTERFACE "$<${is_gnu_or_clang_genex}:-Wn
# custom command to make OPENSTUDIO_CSHARP_DLL
add_custom_command(
OUTPUT ${OPENSTUDIO_CSHARP_DLL}
COMMAND "${DOTNET}" "build" "-c" "$<CONFIGURATION>" "/p:Platform=${CSHARP_PLATFORM}" "${PROJECT_BINARY_DIR}/csharp_wrapper/OpenStudio.csproj"
COMMAND "${DOTNET}" "build" "-c" "$<CONFIG>" "/p:Platform=${CSHARP_PLATFORM}" "${PROJECT_BINARY_DIR}/csharp_wrapper/OpenStudio.csproj"
DEPENDS ${ALL_CSHARP_WRAPPER_TARGETS} ${ALL_CSHARP_WRAPPER_FILES}
)


install(FILES "${OPENSTUDIO_CSHARP_DLL}" DESTINATION CSharp/openstudio/ CONFIGURATIONS DEBUG COMPONENT "CSharpAPI")


install(FILES "${OPENSTUDIO_CSHARP_DLL}" DESTINATION CSharp/openstudio/ COMPONENT "CSharpAPI")

# keep the following lists aligned with translator_names in ProjectMacros.cmake
set(translator_wrappers
Expand Down
4 changes: 2 additions & 2 deletions csharp/developer/OpenStudio/OpenStudio.csproj.in
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
<TargetsForTfmSpecificContentInPackage>$(TargetsForTfmSpecificContentInPackage);IncludeReferencedLibInPackage</TargetsForTfmSpecificContentInPackage>
<AppendTargetFrameworkToOutputPath>true</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<OutputPath>${CSHARP_LIBRARY_OUTPUT_DIRECTORY}\$(Configuration)\</OutputPath>
<OutputPath>${CSHARP_LIBRARY_OUTPUT_DIRECTORY_NATIVE}\$(Configuration)\</OutputPath>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>${CSHARP_SOURCE_DIR}\developer\OpenStudio\StrongNameKeyFile.snk</AssemblyOriginatorKeyFile>
<AssemblyOriginatorKeyFile>${CSHARP_SOURCE_DIR_NATIVE}\developer\OpenStudio\StrongNameKeyFile.snk</AssemblyOriginatorKeyFile>


<!-- CS1591: Missing XML comment for publicly visible type or member 'Type_or_Member' -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ You can also refer to the [OpenStudio SDK Python Binding Version Compatibility M
## New Features, Major Fixes and API-breaking changes

* [#4827](https://github.com/NREL/OpenStudio/pull/4827) - #4748 #4817 - Validate BCLXML with schema when loading + make sorting of files in measure.xml consistent when saving
* [#4873](https://github.com/NREL/OpenStudio/pull/4873) - AirLoopHVACUnitarySystem set Method During XXX Operation
* Fix #4695 - AirLoopHVACUnitarySystem: Supply Air Flow Rate Method During <XXX> Operation should be set via related setters/autosize
* Breaks the return of `supplyAirFlowRateMethodDuringCoolingOperation` and `supplyAirFlowRateMethodDuringHeatingOperation`: now returns `std::string` instead of `boost::optional<std::string>`
* Deprecates many set/reset methods
* [#4932](https://github.com/NREL/OpenStudio/pull/4932) - Support undisturbed ground temperature models on GroundHeatExchangerVertical
* Fix #4930 - Support undisturbed ground temperature models on GroundHeatExchangerVertical
* Update `GroundHeatExchanger:Vertical` to actually use the Ground Temeprature Model field
* [#4923](https://github.com/NREL/OpenStudio/pull/4923) - Fix #4692 - Modify `Model::load` to use the VersionTranslator instead of loading it assuming the version of the loaded OSM is the same as the current SDK version being used.

## Minor changes and bug fixes
Expand Down
4 changes: 2 additions & 2 deletions python/SetupPython.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ set(Python_USE_STATIC_LIBS OFF)
# find_package(Python) has the problem that on github actions in particular it'll pick up the most recent python (eg 3.9) from the tool cache
# even if you have used the setup-python action and set it to 3.8
if (PYTHON_VERSION)
find_package(Python ${PYTHON_VERSION} EXACT COMPONENTS Interpreter Development REQUIRED)
find_package(Python ${PYTHON_VERSION} EXACT REQUIRED COMPONENTS Interpreter Development OPTIONAL_COMPONENTS NumPy)
else()
find_package(Python COMPONENTS Interpreter Development REQUIRED)
find_package(Python 3 EXACT REQUIRED COMPONENTS Interpreter Development OPTIONAL_COMPONENTS NumPy)
endif()

execute_process(COMMAND ${Python_EXECUTABLE} -m pytest --version
Expand Down
53 changes: 41 additions & 12 deletions python/engine/PythonEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,12 @@ void addToPythonPath(const openstudio::path& includePath) {
if (!includePath.empty()) {
PyObject* sys = PyImport_ImportModule("sys");
PyObject* sysPath = PyObject_GetAttrString(sys, "path");
Py_DECREF(sys); // PyImport_ImportModule returns a new reference, decrement it

// fmt::print("Prepending '{}' to sys.path\n", includePath);
PyObject* unicodeIncludePath = PyUnicode_FromString(includePath.string().c_str());
PyList_Insert(sysPath, 0, unicodeIncludePath);
Py_DECREF(sysPath); // PyObject_GetAttrString returns a new reference, decrement it
}
}

Expand All @@ -41,30 +44,56 @@ void PythonEngine::pyimport(const std::string& importName, const std::string& in
PyImport_ImportModule(importName.c_str());
}

void PythonEngine::setupPythonPath(const std::vector<openstudio::path>& includeDirs, const openstudio::path& pythonHomeDir) {
for (const auto& includeDir : includeDirs) {
addToPythonPath(includeDir);
}
if (!pythonHomeDir.empty()) {
wchar_t* a = Py_DecodeLocale(pythonHomeDir.generic_string().c_str(), nullptr);
Py_SetPythonHome(a);
void PythonEngine::setupPythonPath(const std::vector<openstudio::path>& includeDirs) {

// Iterate in reverse order since addToPythonPath always inserts at pos 0
// --python_path path1 --python_path path2 => includeDirs = ["path1", "path2"]
// std::ranges::reverse_view needs modern compilers
for (auto it = includeDirs.rbegin(); it != includeDirs.rend(); it++) {
addToPythonPath(*it);
}
}

PythonEngine::PythonEngine(int argc, char* argv[]) : ScriptEngine(argc, argv), program(Py_DecodeLocale(pythonProgramName, nullptr)) {
// TODO: modernize and use PyConfig (new in 3.8): https://docs.python.org/3/c-api/init_config.html

// this frozen flag tells Python that the package and library have been frozen for embedding, so it shouldn't warn about missing prefixes
Py_FrozenFlag = 1;

// Set the PYTHONPATH / PYTHONHOME to the E+ shipped standard library
// I think we need to set the python path before initializing the library
// Path to the E+ shipped standard library
auto pathToPythonPackages = getEnergyPlusDirectory() / "python_standard_lib";
wchar_t* a = Py_DecodeLocale(pathToPythonPackages.make_preferred().string().c_str(), nullptr);
Py_SetPath(a);
Py_SetPythonHome(a);

// The PYTHONPATH / PYTHONHOME should be set before initializing Python
// If this Py_SetPath is called before Py_Initialize, then Py_GetPath won't attempt to compute a default search path
// The default search path is affected by the Py_SetPythonHome
// * if the user passed --python_home, we use that as the Python Home, and do not use Py_SetPath. But later we add the E+ standard_lib anyways
// so it takes precedence (to limit incompatibility issues...)
// * If the user didn't pass it, we use Py_SetPath set to the E+ standard_lib

std::vector<std::string> args(argv, std::next(argv, static_cast<std::ptrdiff_t>(argc)));
bool pythonHomePassed = false;
auto it = std::find(args.cbegin(), args.cend(), "--python_home");
if (it != args.cend()) {
openstudio::path pythonHomeDir(*std::next(it));
wchar_t* h = Py_DecodeLocale(pythonHomeDir.make_preferred().string().c_str(), nullptr);
Py_SetPythonHome(h);
pythonHomePassed = true;
} else {
wchar_t* a = Py_DecodeLocale(pathToPythonPackages.make_preferred().string().c_str(), nullptr);
Py_SetPath(a);
}

Py_SetProgramName(program); // optional but recommended

Py_Initialize();

if (pythonHomePassed) {
addToPythonPath(pathToPythonPackages);
}
#if defined(__APPLE__) || defined(__linux___) || defined(__unix__)
addToPythonPath(pathToPythonPackages / "lib-dynload");
#endif

PyObject* m = PyImport_AddModule("__main__");
if (m == nullptr) {
throw std::runtime_error("Unable to add module __main__ for python script execution");
Expand Down
2 changes: 1 addition & 1 deletion python/engine/PythonEngine.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class PythonEngine final : public ScriptEngine
ScriptObject eval(std::string_view sv) override;
void exec(std::string_view sv) override;

virtual void setupPythonPath(const std::vector<openstudio::path>& includeDirs, const openstudio::path& pythonHomeDir) override;
virtual void setupPythonPath(const std::vector<openstudio::path>& includeDirs) override;

protected:
void* getAs_impl(ScriptObject& obj, const std::type_info&) override;
Expand Down
10 changes: 8 additions & 2 deletions resources/model/OpenStudio.idd
Original file line number Diff line number Diff line change
Expand Up @@ -11902,6 +11902,7 @@ OS:AirLoopHVAC:UnitarySystem,
\key FlowPerFloorArea
\key FractionOfAutosizedCoolingValue
\key FlowPerCoolingCapacity
\default None
\note Enter the method used to determine the cooling supply air volume flow rate.
\note None is used when a cooling coil is not included in the unitary system or this field may be blank.
\note SupplyAirFlowRate is selected when the magnitude of the supply air volume is used.
Expand Down Expand Up @@ -11946,6 +11947,7 @@ OS:AirLoopHVAC:UnitarySystem,
\key FlowPerFloorArea
\key FractionOfAutosizedHeatingValue
\key FlowPerHeatingCapacity
\default None
\note Enter the method used to determine the heating supply air volume flow rate.
\note None is used when a heating coil is not included in the unitary system or this field may be blank.
\note SupplyAirFlowRate is selected when the magnitude of the supply air volume is used.
Expand Down Expand Up @@ -16669,8 +16671,8 @@ OS:DistrictHeating,

OS:GroundHeatExchanger:Vertical,
\extensible:2
\min-fields 21
\max-fields 219
\min-fields 22
\max-fields 220
\memo Variable short time step vertical ground heat exchanger model based on
\memo Yavuztruk, C., J.D.Spitler. 1999. A Short Time Step response Factor Model for
\memo Vertical Ground Loop Heat Exchangers
Expand Down Expand Up @@ -16748,6 +16750,10 @@ OS:GroundHeatExchanger:Vertical,
N13, \field Maximum Length of Simulation
\type real
\minimum> 0.0
A5, \field Undisturbed Ground Temperature Model
\required-field
\type object-list
\object-list UndisturbedGroundTempModels
N14, \field G-Function Reference Ratio
\type real
\units dimensionless
Expand Down
55 changes: 55 additions & 0 deletions src/cli/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,61 @@ if(BUILD_TESTING)

# ============ EndForward a Path properly no matter the slashes employed ============

# ============ Native Ruby Gems / Python Modules - C extensions =============
if (Python_NumPy_FOUND)

if(NOT EXISTS "${Python_ROOT_DIR}")
# Python_STDLIB: we expect it to be
# Unix: ~/.pyenv/versions/3.8.12/lib/python3.8 or
# or on CI: /usr/lib/python3.8/ ... with numpy if install via pip3 and not apt install python3-numpy in `/usr/local/lib/python3.8/dist-packages/`
# Windows C:\Python38\Lib
cmake_path(GET Python_STDLIB PARENT_PATH Python_ROOT_DIR)
if(UNIX)
cmake_path(GET Python_ROOT_DIR PARENT_PATH Python_ROOT_DIR)
endif()
endif()

if(UNIX)
if(EXISTS "${Python_SITELIB}")
set(PYTHON_PATH "${Python_SITELIB}" "${Python_STDLIB}/lib-dynload")
else()
set(PYTHON_PATH "${Python_STDLIB}/lib-dynload")
endif()

if(NOT APPLE)
set(EXTRA_LOCAL_DIST "/usr/local/lib/python3.8/dist-packages")
if (EXISTS "${EXTRA_LOCAL_DIST}")
list(APPEND PYTHON_PATH "${EXTRA_LOCAL_DIST}")
endif()
endif()
else()
set(PYTHON_PATH "$<SHELL_PATH:${Python_SITELIB}>")
endif()

message(DEBUG "PYTHON_PATH=${PYTHON_PATH}")

add_test(NAME OpenStudioCLI.Labs.execute_python_script.numpy.explicit_sys_path_insert
COMMAND $<TARGET_FILE:openstudio> labs execute_python_script execute_python_script_with_numpy.py ${Python_STDLIB}
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/test/"
)

add_test(NAME OpenStudioCLI.Labs.execute_python_script.numpy.python_path
COMMAND $<TARGET_FILE:openstudio> labs
"$<$<BOOL:${PYTHON_PATH}>:--python_path;$<JOIN:${PYTHON_PATH},;--python_path;>>"
execute_python_script execute_python_script_with_numpy.py
COMMAND_EXPAND_LISTS
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/test/"
)

add_test(NAME OpenStudioCLI.Labs.execute_python_script.numpy.python_home
COMMAND $<TARGET_FILE:openstudio> labs
--python_home "$<SHELL_PATH:${Python_ROOT_DIR}>"
execute_python_script execute_python_script_with_numpy.py
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/test/"
)
else()
message(AUTHOR_WARNING "Cannot run the python numpy test, as numpy isn't installed on your system python")
endif()

file(GLOB RUBY_TEST_SRC
# find all CLI test
Expand Down
12 changes: 10 additions & 2 deletions src/cli/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,28 +136,33 @@ int main(int argc, char* argv[]) {
experimentalApp
->add_option("-I,--include", includeDirs, "Add additional directory to add to front of Ruby $LOAD_PATH (may be used more than once)")
->option_text("DIR")
->check(CLI::ExistingDirectory)
->group(rubySpecificOptionsGroupName);

std::vector<openstudio::path> gemPathDirs;
experimentalApp
->add_option("--gem_path", gemPathDirs,
"Add additional directory to add to front of GEM_PATH environment variable (may be used more than once)")
->option_text("DIR")
->check(CLI::ExistingDirectory)
->group(rubySpecificOptionsGroupName);

openstudio::path gemHomeDir;
experimentalApp->add_option("--gem_home", gemHomeDir, "Set GEM_HOME environment variable")
->option_text("DIR")
->check(CLI::ExistingDirectory)
->group(rubySpecificOptionsGroupName);

openstudio::path bundleGemFilePath;
experimentalApp->add_option("--bundle", bundleGemFilePath, "Use bundler for GEMFILE")
->option_text("GEMFILE")
->check(CLI::ExistingFile)
->group(rubySpecificOptionsGroupName);

openstudio::path bundleGemDirPath;
experimentalApp->add_option("--bundle_path", bundleGemDirPath, "Use bundler installed gems in BUNDLE_PATH")
->option_text("BUNDLE_PATH")
->check(CLI::ExistingDirectory)
->group(rubySpecificOptionsGroupName);

// std::vector<std::string>
Expand Down Expand Up @@ -190,16 +195,19 @@ int main(int argc, char* argv[]) {
->add_option("--python_path", pythonPathDirs,
"Add additional directory to add to front of PYTHONPATH environment variable (may be used more than once)")
->option_text("DIR")
->check(CLI::ExistingDirectory)
->group(pythonSpecificOptionsGroupName);

openstudio::path pythonHomeDir;
experimentalApp->add_option("--python_home", pythonHomeDir, "Set PYTHONHOME environment variable")
->option_text("DIR")
->check(CLI::ExistingDirectory)
->group(pythonSpecificOptionsGroupName);

// This is a callback that's stored on the ScriptEngineInstance, triggered only the first time
std::function<void()> runSetupPythonPath = [&pythonEngine, &pythonPathDirs, &pythonHomeDir]() {
pythonEngine->setupPythonPath(pythonPathDirs, pythonHomeDir);
std::function<void()> runSetupPythonPath = [&pythonEngine, &pythonPathDirs]() {
// pythonHomeDir is retrieved from (argc, argv) actually, as Py_SetPythonHome has to be called before Py_Initialize
pythonEngine->setupPythonPath(pythonPathDirs);
pythonEngine->registerType<openstudio::measure::ModelMeasure*>("openstudio::measure::ModelMeasure *");
pythonEngine->registerType<openstudio::measure::EnergyPlusMeasure*>("openstudio::measure::EnergyPlusMeasure *");
pythonEngine->registerType<openstudio::measure::ReportingMeasure*>("openstudio::measure::ReportingMeasure *");
Expand Down
Loading

0 comments on commit 5ff5fe7

Please sign in to comment.