diff --git a/.github/workflows/build_windows.yml b/.github/workflows/build_windows.yml index 240a80b2..64611894 100644 --- a/.github/workflows/build_windows.yml +++ b/.github/workflows/build_windows.yml @@ -17,7 +17,7 @@ env: BUILD_CONFIGURATION: Release BUILD_PLATFORM: x64 - # Versions. + # Versions QT_VERSION: 5.15.2 QT_VS_VERSION: msvc2019_64 QT_VS_ADDIN_VERSION: 2.7.2 @@ -73,7 +73,7 @@ jobs: # Also, it installs them to %LOCALAPPDATA%\QtMsBuild, so they can not be used by other Windows users. # Download the extension and extract requited files to the project directory. run: | - Invoke-WebRequest -Uri https://ftp.fau.de/qtproject/archive/vsaddin/${{env.QT_VS_ADDIN_VERSION}}/qt-vsaddin-msvc2019-${{env.QT_VS_ADDIN_VERSION}}.vsix -MaximumRetryCount 10 -RetryIntervalSec 30 -OutFile vspackage.vsix + Invoke-WebRequest -Uri https://ftp.fau.de/qtproject/archive/vsaddin/${{env.QT_VS_ADDIN_VERSION}}/qt-vsaddin-msvc2019-${{env.QT_VS_ADDIN_VERSION}}.vsix -MaximumRetryCount 10 -RetryIntervalSec 30 -OutFile vspackage.vsix Expand-Archive vspackage.vsix -DestinationPath ${{github.workspace}}/ExternalLibraries/qtvsaddin - name: Cache ZLib @@ -159,7 +159,7 @@ jobs: - name: Add MSBuild to PATH uses: microsoft/setup-msbuild@v1 - - name: Download Build Artifact + - name: Download Build Artifact uses: actions/download-artifact@v3 with: name: build-artifact @@ -183,27 +183,27 @@ jobs: - name: Install Graphviz run: choco install graphviz - + - name: Install Doxygen run: choco install doxygen.install - + - name: Install Sphinx run: pip install -U sphinx sphinx-rtd-theme breathe - + - name: Cache MiKTeX id: cache-miktex uses: actions/cache@v3 with: path: C:/Program Files/MiKTeX key: ${{runner.os}}-MiKTeXCache-${{env.MIKTEX_VERSION}} - + - name: Install MiKTeX if: steps.cache-miktex.outputs.cache-hit != 'true' run: choco install miktex.install --version ${{env.MIKTEX_VERSION}} -y - + - name: Add MiKTeX to PATH run: Add-Content $env:GITHUB_PATH "C:\Program Files\MiKTeX\miktex\bin\x64" - + - name: Configure MiKTeX run: | initexmf --admin --verbose --set-config-value=[MPM]AutoInstall=1 @@ -219,12 +219,12 @@ jobs: working-directory: ${{github.workspace}} # Add additional options to the MSBuild command line here: see https://docs.microsoft.com/visualstudio/msbuild/msbuild-command-line-reference. run: msbuild -maxCpuCount -verbosity:minimal -property:Configuration=${{env.BUILD_CONFIGURATION}} -property:Platform=${{env.BUILD_PLATFORM}} -property:SolutionDir=${{github.workspace}}/ ${{env.DOCS_PROJECT_PATH}} - + cleanup: runs-on: windows-2019 needs: [build, tests] if: ${{always()}} - + steps: - name: Delete Build Artifact uses: geekyeggo/delete-artifact@v2 diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c767423..cd56742b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,7 +32,7 @@ SET(INSTALL_HEADERS_PATH ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}/) SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") ################################################## -### Binaries +### Binaries IF(BUILD_BINARIES) add_executable(DyssolC @@ -89,7 +89,7 @@ IF(BUILD_BINARIES) TARGET_LINK_LIBRARIES(libdyssol_shared ${HDF5_LIBRARIES} ${HDF5_HL_LIBRARIES} ${SUNDIALS_LIBRARIES}) TARGET_LINK_LIBRARIES(libdyssol_static ${HDF5_LIBRARIES} ${HDF5_HL_LIBRARIES} ${SUNDIALS_LIBRARIES}) TARGET_LINK_LIBRARIES(DyssolC libdyssol_shared) - + # link filesystem or experimantal/filesystem for gcc IF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") IF (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.0) @@ -126,7 +126,7 @@ IF(BUILD_BINARIES) ENDIF(BUILD_BINARIES) ################################################## -### Testing +### Testing IF(BUILD_TESTS) ENABLE_TESTING() @@ -188,7 +188,7 @@ IF(BUILD_TESTS) COMMAND python3 ${CMAKE_SOURCE_DIR}/tests/compare.py "${CMAKE_SOURCE_DIR}/tests/${CURRENT_TEST}/ideal.res" "${CMAKE_BINARY_DIR}/tests/${CURRENT_TEST}/real.res" -t ${TOLERANCE} ) ENDIF(WIN32) - + # _diff tests can only be run when the _run test is done SET_TESTS_PROPERTIES(${CURRENT_TEST}_diff PROPERTIES DEPENDS ${CURRENT_TEST}_run) ENDIF(NOT CMAKE_BUILD_TYPE MATCHES Debug) @@ -198,7 +198,7 @@ IF(BUILD_TESTS) ENDIF(BUILD_TESTS) ################################################## -### Documentation +### Documentation IF(BUILD_DOCS) #================================================= @@ -274,7 +274,7 @@ IF(BUILD_DOCS) # Replace variables inside @@ with the current values CONFIGURE_FILE(${SPHINX_CONFIG_IN} ${SPHINX_CONFIG_OUT} @ONLY) - + ADD_CUSTOM_COMMAND(OUTPUT ${SPHINX_INDEX_FILE} COMMAND ${SPHINX_EXECUTABLE} -b linkcheck ${SPHINX_SOURCE_DIR} ${SPHINX_BUILD} # Check links COMMAND ${SPHINX_EXECUTABLE} -b html -Dbreathe_projects.Dyssol=${DOXYGEN_OUTPUT_XML_DIR} ${SPHINX_SOURCE_DIR} ${SPHINX_BUILD} diff --git a/Documentation/001_ui/cli.rst b/Documentation/001_ui/cli.rst index b97a8e59..b40dbeb3 100644 --- a/Documentation/001_ui/cli.rst +++ b/Documentation/001_ui/cli.rst @@ -31,30 +31,32 @@ You can find exemplary script files in the installation directory under ``Exampl Only 3 script keys from the list are mandatory: ``SOURCE_FILE`` or ``RESULT_FILE``, ``MODELS_PATH``, and ``MATERIALS_DATABASE``. The rest are optional and will override parameters set in initial file, specified as ``SOURCE_FILE``. If ``SOURCE_FILE`` is not defined, the script should describe the entire flowsheet with all parameters, and ``RESULT_FILE`` is required. If ``RESULT_FILE`` parameter is not specified, results of the simulation will be written to a ``SOURCE_FILE``. -script keys ``MODELS_PATH``, ``DISTRIBUTION_GRID``, ``UNIT``, ``STREAM``, ``UNIT_PARAMETER``, ``UNIT_HOLDUP_*``, ``EXPORT_STREAM_*``, ``EXPORT_HOLDUP_*``, and ``EXPORT_UNIT_*`` can be mentioned several times in the script file, the rest should be places only once. - +script keys ``MODELS_PATH``, ``DISTRIBUTION_GRID``, ``UNIT``, ``STREAM``, ``UNIT_PARAMETER``, ``UNIT_HOLDUP_*``, ``EXPORT_STREAM_*``, ``EXPORT_HOLDUP_*``, ``EXPORT_UNIT_*`` can be mentioned several times in the script file, the rest should be places only once. Main ---- -+--------------------+--------+--------------------------------------------------------------+ -| Script key | Value | Description | -+====================+========+==============================================================+ -| JOB | | Delimiter for a sequentially executed job within one script | -+--------------------+--------+--------------------------------------------------------------+ -| SOURCE_FILE | | Full path to a \*.dflw file with initial flowsheet | -+--------------------+--------+--------------------------------------------------------------+ -| RESULT_FILE | | Full path to a file where simulation results will be written | -+--------------------+--------+--------------------------------------------------------------+ -| MODELS_PATH | | Path to the directory with libraries of units and solvers | -+--------------------+--------+--------------------------------------------------------------+ -| MATERIALS_DATABASE | | Full path to the file with materials database | -+--------------------+--------+--------------------------------------------------------------+ ++--------------------+--------------------------------+--------------------------------------------------------------+ +| Script key | Value | Description | ++====================+================================+==============================================================+ +| JOB | | Delimiter for a sequentially executed job within one script | ++--------------------+--------------------------------+--------------------------------------------------------------+ +| SOURCE_FILE | | Full path to a \*.dflw file with initial flowsheet | ++--------------------+--------------------------------+--------------------------------------------------------------+ +| RESULT_FILE | | Full path to a file where simulation results will be written | ++--------------------+--------------------------------+--------------------------------------------------------------+ +| MODELS_PATH | | Path to the directory with libraries of units and solvers | ++--------------------+--------------------------------+--------------------------------------------------------------+ +| MATERIALS_DATABASE | | Full path to the file with materials database | ++--------------------+--------------------------------+--------------------------------------------------------------+ | +Simulation +---------- + Simulation options ------------------- +^^^^^^^^^^^^^^^^^^ +------------------------------+-----------------------------------------+----------------------------------------------------------------------------------------------------------------------------+ | Script key | Value | Description | @@ -105,7 +107,7 @@ Simulation options | Phases ------- +^^^^^^ +------------+---------------------------------------------------------+----------------+ | Script key | Value | Description | @@ -116,7 +118,7 @@ Phases | Compounds ---------- +^^^^^^^^^ +------------+-----------------------------------+-------------------------------------------+ | Script key | Value | Description | @@ -127,7 +129,7 @@ Compounds | Grids ------ +^^^^^ +----------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ | Script key | Value | Description | @@ -144,7 +146,7 @@ Grids | Flowsheet structure -------------------- +^^^^^^^^^^^^^^^^^^^ +---------------------+----------------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------+ | Script key | Value | Description | @@ -159,7 +161,7 @@ Flowsheet structure | Unit parameters ---------------- +^^^^^^^^^^^^^^^ +----------------+---------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------------------------------+ | Script key | Value | Description | @@ -174,7 +176,7 @@ Unit parameters | Holdups -------- +^^^^^^^ +------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | Script key | Value | Description | @@ -201,7 +203,7 @@ Holdups | Export ------- +^^^^^^ +-----------------------------------+------------------------------------------------------------------------------+-------------------------------------------------------------------------------------+ | Script key | Value | Description | @@ -255,4 +257,4 @@ Export | EXPORT_FLOWSHEET_GRAPH | | Export flowsheet graph as a \*.png file | +-----------------------------------+------------------------------------------------------------------------------+-------------------------------------------------------------------------------------+ -| \ No newline at end of file +| diff --git a/Documentation/001_ui/gui.rst b/Documentation/001_ui/gui.rst index d91afacc..2cf4f9b2 100644 --- a/Documentation/001_ui/gui.rst +++ b/Documentation/001_ui/gui.rst @@ -390,7 +390,7 @@ Application-wide settings. 2. Open application-wide configuration file 3. Path to store cache files 4. Change cache path -5. Delete all cache files +5. Delete all cache files .. _sec.gui.menu_help: diff --git a/Dyssol.sln b/Dyssol.sln index 7f0ab882..be0f67ea 100644 --- a/Dyssol.sln +++ b/Dyssol.sln @@ -148,6 +148,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Documentation", "DyssolInst EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Tests", "DyssolInstallers\Tests\Tests.vcxproj", "{9E33ACE6-5DDA-400C-8242-6BE0B8569221}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SimulationThread", "GUIWidgets\SimulationThread\SimulationThread.vcxproj", "{0F7B1A52-7766-4E37-9ACD-AC76AB000000}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -632,6 +634,14 @@ Global {9E33ACE6-5DDA-400C-8242-6BE0B8569221}.Debug|x64.ActiveCfg = Debug|x64 {9E33ACE6-5DDA-400C-8242-6BE0B8569221}.Release|Win32.ActiveCfg = Release|Win32 {9E33ACE6-5DDA-400C-8242-6BE0B8569221}.Release|x64.ActiveCfg = Release|x64 + {0F7B1A52-7766-4E37-9ACD-AC76AB000000}.Debug|Win32.ActiveCfg = Debug|Win32 + {0F7B1A52-7766-4E37-9ACD-AC76AB000000}.Debug|Win32.Build.0 = Debug|Win32 + {0F7B1A52-7766-4E37-9ACD-AC76AB000000}.Debug|x64.ActiveCfg = Debug|x64 + {0F7B1A52-7766-4E37-9ACD-AC76AB000000}.Debug|x64.Build.0 = Debug|x64 + {0F7B1A52-7766-4E37-9ACD-AC76AB000000}.Release|Win32.ActiveCfg = Release|Win32 + {0F7B1A52-7766-4E37-9ACD-AC76AB000000}.Release|Win32.Build.0 = Release|Win32 + {0F7B1A52-7766-4E37-9ACD-AC76AB000000}.Release|x64.ActiveCfg = Release|x64 + {0F7B1A52-7766-4E37-9ACD-AC76AB000000}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -702,9 +712,10 @@ Global {80FB8E0A-CCA8-4AB7-BC79-21E82A141842} = {DA539701-563C-4DCF-883B-941DE792BC4A} {C91712C5-4A46-4703-9857-4E742D247601} = {FF9F78BB-144A-48EF-87D3-7EEE6C6B4682} {9E33ACE6-5DDA-400C-8242-6BE0B8569221} = {FF9F78BB-144A-48EF-87D3-7EEE6C6B4682} + {0F7B1A52-7766-4E37-9ACD-AC76AB000000} = {8B7A2AEC-46DD-47CE-937E-767D7692C15F} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {CAC327DA-BA65-4990-BEC0-618347D67688} Qt5Version = msvc2019_64 + SolutionGuid = {CAC327DA-BA65-4990-BEC0-618347D67688} EndGlobalSection EndGlobal diff --git a/DyssolInstallers/Scripts/ExtLibs.iss b/DyssolInstallers/Scripts/ExtLibs.iss new file mode 100644 index 00000000..b26edcf3 --- /dev/null +++ b/DyssolInstallers/Scripts/ExtLibs.iss @@ -0,0 +1,24 @@ +; Copyright (c) 2023, DyssolTEC GmbH. All rights reserved. This file is part of Dyssol. See LICENSE file for license information. + +#include "CommonConstants.iss" + +#dim ExternalLibs[4] +#define ExternalLibs[0] "hdf5" +#define ExternalLibs[1] "sundials" +#define ExternalLibs[2] "zlib" + +#define I + +[Files] +; External libraries +#sub ExternalLibsFileEntry +Source: "..\..\ExternalLibraries\{#ExternalLibs[I]}\include\*"; DestDir: "{app}\{code:DirModelsCreator}\{code:DirExternalLibs}\{#ExternalLibs[I]}\include"; Flags: ignoreversion createallsubdirs recursesubdirs + #ifdef IsIncludeX32 +Source: "..\..\ExternalLibraries\{#ExternalLibs[I]}\lib32\*"; DestDir: "{app}\{code:DirModelsCreator}\{code:DirExternalLibs}\{#ExternalLibs[I]}\lib32"; Flags: ignoreversion createallsubdirs recursesubdirs; Check: not Is64BitInstallMode + #endif + #ifdef IsIncludeX64 +Source: "..\..\ExternalLibraries\{#ExternalLibs[I]}\lib64\*"; DestDir: "{app}\{code:DirModelsCreator}\{code:DirExternalLibs}\{#ExternalLibs[I]}\lib64"; Flags: ignoreversion createallsubdirs recursesubdirs; Check: Is64BitInstallMode + #endif +#endsub +#for {I = 0; I < DimOf(ExternalLibs); I++} ExternalLibsFileEntry + diff --git a/DyssolInstallers/Scripts/Main.iss b/DyssolInstallers/Scripts/Main.iss index d6228d91..c9475859 100644 --- a/DyssolInstallers/Scripts/Main.iss +++ b/DyssolInstallers/Scripts/Main.iss @@ -22,6 +22,7 @@ ; #define IsWithSrc ; #define IsWithSDK +#include "ExtLibs.iss" #include "QtLibs.iss" #include "FlowsheetsExamples.iss" #include "SolversExamples.iss" diff --git a/DyssolInstallers/Scripts/ModelsCreator.iss b/DyssolInstallers/Scripts/ModelsCreator.iss index b15bb08c..01958c4d 100644 --- a/DyssolInstallers/Scripts/ModelsCreator.iss +++ b/DyssolInstallers/Scripts/ModelsCreator.iss @@ -11,11 +11,6 @@ #define CppProjects[5] "ModelsAPI" #define CppProjects[6] "Utilities" -#dim ExternalLibs[3] -#define ExternalLibs[0] "hdf5" -#define ExternalLibs[1] "sundials" -#define ExternalLibs[2] "zlib" - #dim SolverTemplates[1] #define SolverTemplates[0] "AgglomerationTemplate" @@ -48,18 +43,6 @@ Source: "..\..\x64\Release\{#CppProjects[I]}*.lib"; DestDir: "{app}\{code:DirM #endsub #for {I = 0; I < DimOf(CppProjects); I++} CppProjectsFileEntry -; External libraries -#sub ExternalLibsFileEntry -Source: "..\..\ExternalLibraries\{#ExternalLibs[I]}\include\*"; DestDir: "{app}\{code:DirModelsCreator}\{code:DirExternalLibs}\{#ExternalLibs[I]}\include"; Flags: ignoreversion createallsubdirs recursesubdirs - #ifdef IsIncludeX32 -Source: "..\..\ExternalLibraries\{#ExternalLibs[I]}\lib32\*"; DestDir: "{app}\{code:DirModelsCreator}\{code:DirExternalLibs}\{#ExternalLibs[I]}\lib32"; Flags: ignoreversion createallsubdirs recursesubdirs; Check: not Is64BitInstallMode - #endif - #ifdef IsIncludeX64 -Source: "..\..\ExternalLibraries\{#ExternalLibs[I]}\lib64\*"; DestDir: "{app}\{code:DirModelsCreator}\{code:DirExternalLibs}\{#ExternalLibs[I]}\lib64"; Flags: ignoreversion createallsubdirs recursesubdirs; Check: Is64BitInstallMode - #endif -#endsub -#for {I = 0; I < DimOf(ExternalLibs); I++} ExternalLibsFileEntry - ; Solvers templates #sub SolverTemplatesFileEntry Source: "..\..\Solvers\Templates\{#SolverTemplates[I]}\*.vcxproj"; DestDir: "{app}\{code:DirModelsCreator}\{code:DirSolverTemplates}\{#SolverTemplates[I]}"; Flags: ignoreversion diff --git a/DyssolInstallers/Tests/build_and_run_tests.ps1 b/DyssolInstallers/Tests/build_and_run_tests.ps1 index 86e887cb..ae45e7fc 100644 --- a/DyssolInstallers/Tests/build_and_run_tests.ps1 +++ b/DyssolInstallers/Tests/build_and_run_tests.ps1 @@ -22,13 +22,14 @@ if ($pre_build_binaries -eq "true") { Write-Host Compiling $platform $configuration devenv $solution_path /build "$($configuration)|$($platform)" } - + # create build directory if (!(Test-Path $build_path)) { New-Item -itemType Directory -Path $build_path } -# compile docs +# compile tests Set-Location $build_path + cmake $solution_dir -D BUILD_BINARIES=NO -D BUILD_DOCS=NO -A $platform -D CMAKE_BUILD_TYPE=$configuration --fresh cmake --build . --target RUN_TESTS --parallel $ENV:NUMBER_OF_PROCESSORS diff --git a/DyssolMainWindow/DyssolMainWindow.vcxproj b/DyssolMainWindow/DyssolMainWindow.vcxproj index 1c25e2fb..15d1c860 100644 --- a/DyssolMainWindow/DyssolMainWindow.vcxproj +++ b/DyssolMainWindow/DyssolMainWindow.vcxproj @@ -218,7 +218,10 @@ {4882842d-566d-456a-a267-a5f9c8fdb16d} - + + {0f7b1a52-7766-4e37-9acd-ac76ab000000} + + {0736ddb9-c29b-4dea-8e9a-6feffed8cfb6} diff --git a/DyssolMainWindow/DyssolMainWindow.vcxproj.user b/DyssolMainWindow/DyssolMainWindow.vcxproj.user index 43fa96c0..e9d8d4dc 100644 --- a/DyssolMainWindow/DyssolMainWindow.vcxproj.user +++ b/DyssolMainWindow/DyssolMainWindow.vcxproj.user @@ -20,4 +20,16 @@ QT_PLUGIN_PATH=$(QtInstallDir)\plugins QT_PLUGIN_PATH=$(QtInstallDir)\plugins WindowsLocalDebugger + + 2023-12-17T19:30:48.8040039Z + + + 2023-12-17T19:30:48.9294808Z + + + 2023-12-17T19:30:49.0089881Z + + + 2023-12-17T19:30:49.1354941Z + \ No newline at end of file diff --git a/ExternalLibraries/CompileZLib.ps1 b/ExternalLibraries/CompileZLib.ps1 index ba5a24b2..11a027a3 100644 --- a/ExternalLibraries/CompileZLib.ps1 +++ b/ExternalLibraries/CompileZLib.ps1 @@ -1,5 +1,5 @@ -# Copyright (c) 2020, Dyssol Development Team. All rights reserved. -# Copyright (c) 2023, DyssolTEC GmbH. All rights reserved. +# Copyright (c) 2020, Dyssol Development Team. All rights reserved. +# Copyright (c) 2023, DyssolTEC GmbH. All rights reserved. # This file is part of Dyssol. See LICENSE file for license information. ################################################################################ diff --git a/GUIDialogs/GridEditor/DimensionParameters.cpp b/GUIDialogs/GridEditor/DimensionParameters.cpp index d6ab6e73..5ddccbea 100644 --- a/GUIDialogs/GridEditor/DimensionParameters.cpp +++ b/GUIDialogs/GridEditor/DimensionParameters.cpp @@ -236,7 +236,11 @@ std::vector CDimensionParameters::CalculateGridNumeric() const const size_t number = ui.spinClasses->value() + 1; std::vector res(number); if (fun != EGridFunction::GRID_FUN_MANUAL) - res = CreateGrid(fun, ui.spinClasses->value(), ui.lineMin->text().toDouble(), ui.lineMax->text().toDouble()); + { + const double val1 = ui.lineMin->text().toDouble(); + const double val2 = ui.lineMax->text().toDouble(); + res = CreateGrid(fun, ui.spinClasses->value(), std::min(val1, val2), std::max(val1, val2)); + } else { const auto values = ui.tableGrid->GetItemsCol(0, 0); @@ -299,7 +303,9 @@ CDimensionParameters::EGridUnit CDimensionParameters::DetermineUnits() const bool CDimensionParameters::IsOfFunction(const std::vector& _v, EGridFunction _fun, EGridUnit _units) const { - const auto ref = ToM(CreateGrid(_fun, _v.size() - 1, FromM(_v.front(), _units), FromM(_v.back(), _units)), _units); + const double val1 = FromM(_v.front(), _units); + const double val2 = FromM(_v.back() , _units); + const auto ref = ToM(CreateGrid(_fun, _v.size() - 1, std::min(val1, val2), std::max(val1, val2)), _units); if (ref.empty()) return false; const size_t iSmallestNonZero = VectorFind(_v, [](double v) { return v > 0; }); if (iSmallestNonZero == static_cast(-1)) return false; diff --git a/GUIDialogs/SimulatorTab/SimulatorTab.cpp b/GUIDialogs/SimulatorTab/SimulatorTab.cpp index fc9a4a2f..f6cba96e 100644 --- a/GUIDialogs/SimulatorTab/SimulatorTab.cpp +++ b/GUIDialogs/SimulatorTab/SimulatorTab.cpp @@ -20,8 +20,8 @@ CSimulatorTab::CSimulatorTab(CFlowsheet* _pFlowsheet, CSimulator* _pSimulator, Q CSimulatorTab::~CSimulatorTab() { - m_progressThread.Stop(); - m_progressThread.deleteLater(); + m_simulationThread.Stop(); + m_simulationThread.deleteLater(); } void CSimulatorTab::InitializeConnections() const @@ -32,7 +32,7 @@ void CSimulatorTab::InitializeConnections() const connect(ui.buttonClearRecycles, &QPushButton::clicked, this, &CSimulatorTab::ClearInitialRecycleStreams); connect(ui.buttonClearResultsAndRecycles, &QPushButton::clicked, this, &CSimulatorTab::ClearAll); - connect(&m_progressThread, &CProgressThread::Finished, this, &CSimulatorTab::SimulationFinished); + connect(&m_simulationThread, &CSimulationThread::Finished, this, &CSimulatorTab::SimulationFinished); connect(&m_logTimer, &QTimer::timeout, this, &CSimulatorTab::UpdateLog); } @@ -95,7 +95,7 @@ void CSimulatorTab::StartSimulation() // run simulation BlockUI(true); emit SimulatorStateToggled(true); - m_progressThread.Run(); + m_simulationThread.Run(); m_logTimer.start(100); } } @@ -103,7 +103,7 @@ void CSimulatorTab::StartSimulation() void CSimulatorTab::AbortSimulation() { // stop simulation - m_progressThread.RequestStop(); + m_simulationThread.RequestStop(); // set the message to the log ui.textBrowserLog->setTextColor(QColor(Qt::red)); @@ -116,11 +116,11 @@ void CSimulatorTab::SimulationFinished() // stop simulation threads and timers const QDateTime now = QDateTime::currentDateTime(); m_logTimer.stop(); - m_progressThread.Stop(); + m_simulationThread.Stop(); // update simulation log UpdateLog(); - if (m_progressThread.WasAborted()) + if (m_simulationThread.WasAborted()) { ui.textBrowserLog->setTextColor(QColor(Qt::red)); ui.textBrowserLog->append(StrConst::ST_LogSimUserStop); diff --git a/GUIDialogs/SimulatorTab/SimulatorTab.h b/GUIDialogs/SimulatorTab/SimulatorTab.h index 3c3ca85e..fd0359d8 100644 --- a/GUIDialogs/SimulatorTab/SimulatorTab.h +++ b/GUIDialogs/SimulatorTab/SimulatorTab.h @@ -5,7 +5,8 @@ #pragma once #include "ui_SimulatorTab.h" -#include "ProgressThread.h" +#include "SimulationThread.h" +#include "Simulator.h" #include "QtDialog.h" #include #include @@ -35,7 +36,7 @@ class CSimulatorTab CFlowsheet* m_pFlowsheet; // Pointer to a current flowsheet. CSimulator* m_pSimulator; // Pointer to a current simulator. - CProgressThread m_progressThread{ m_pSimulator }; // Separate thread for simulator. + CSimulationThread m_simulationThread{[&]() {m_pSimulator->Simulate(); }, [&]() {m_pSimulator->Stop(); }}; // Separate thread for simulator. QElapsedTimer m_simulationTimer; // Timer to determine simulation time. QTimer m_logTimer; // Interrupt timer to update simulation log. diff --git a/GUIDialogs/SimulatorTab/SimulatorTab.vcxproj b/GUIDialogs/SimulatorTab/SimulatorTab.vcxproj index c81a92c9..3f50cd03 100644 --- a/GUIDialogs/SimulatorTab/SimulatorTab.vcxproj +++ b/GUIDialogs/SimulatorTab/SimulatorTab.vcxproj @@ -1,4 +1,4 @@ - + @@ -19,7 +19,6 @@ - @@ -30,10 +29,6 @@ - - - - {0f7b1a52-7766-4b37-9acd-ac76abdb1ca5} diff --git a/GUIWidgets/QtPlot/QtPlot.cpp b/GUIWidgets/QtPlot/QtPlot.cpp index af5c581a..8b28748e 100644 --- a/GUIWidgets/QtPlot/QtPlot.cpp +++ b/GUIWidgets/QtPlot/QtPlot.cpp @@ -1224,6 +1224,12 @@ void CQtPlot::SetNumXGridLines(unsigned _nNumXGridLines) if (_nNumXGridLines > 0) m_nNumXGridLines = _nNumXGridLines; } + +void QtPlot::CQtPlot::SetDefaultNumXGridLines() +{ + m_nNumXGridLines = DEFAULT_NUM_X_GRID_LINES; +} + unsigned CQtPlot::GetNumXGridLines() { return m_nNumXGridLines; diff --git a/GUIWidgets/QtPlot/QtPlot.h b/GUIWidgets/QtPlot/QtPlot.h index b8d7f9e1..6daf33f3 100644 --- a/GUIWidgets/QtPlot/QtPlot.h +++ b/GUIWidgets/QtPlot/QtPlot.h @@ -27,6 +27,8 @@ namespace QtPlot #define ACCURACY 1e-15 +#define DEFAULT_NUM_X_GRID_LINES 10 + enum LabelTypes { LABEL_NONE, @@ -225,6 +227,7 @@ class CQtPlot : public QWidget void SetMinY(double _dMinY, bool bRedrawPlot = true); // set limitation of the y axis double GetMinY(); // returns value of the minimal y value void SetNumXGridLines(unsigned _nNumXGridLines); // set number of grid lines on x-axis + void SetDefaultNumXGridLines(); // set default number of grid lines on x-axis unsigned GetNumXGridLines(); // returns number of grid lines on x-axis void SetNumYGridLines(unsigned _nNumYGridLines); // set number of grid lines on y-axis unsigned GetNumYGridLines(); // returns number of grid lines on y-axis diff --git a/GUIWidgets/QtWidgets/QtTable.cpp b/GUIWidgets/QtWidgets/QtTable.cpp index 06c64485..183b3cbe 100644 --- a/GUIWidgets/QtWidgets/QtTable.cpp +++ b/GUIWidgets/QtWidgets/QtTable.cpp @@ -232,6 +232,13 @@ void CQtTable::SetItemsColNotEditable(int _startrow, int _col, const std::string SetItemNotEditable(_startrow + i, _col, _val); } +void CQtTable::SetItemsColNotEditable(int _startrow, int _col, const std::vector& _val) +{ + for (int i = 0; i < static_cast(_val.size()); ++i) + if (_startrow + i < rowCount()) + SetItemNotEditable(_startrow + i, _col, _val[i]); +} + void CQtTable::SetItemsRowNotEditable(int _row, int _startcol, const std::vector& _val) { for (int i = 0; i < static_cast(_val.size()); ++i) diff --git a/GUIWidgets/QtWidgets/QtTable.h b/GUIWidgets/QtWidgets/QtTable.h index 87b9ce72..49e1b71b 100644 --- a/GUIWidgets/QtWidgets/QtTable.h +++ b/GUIWidgets/QtWidgets/QtTable.h @@ -65,6 +65,7 @@ class CQtTable : public QTableWidget void SetItemsColNotEditable(int _startrow, int _col, const std::vector& _val); void SetItemsColNotEditable(int _startrow, int _col, const std::string& _val); + void SetItemsColNotEditable(int _startrow, int _col, const std::vector& _val); void SetItemsRowNotEditable(int _row, int _startcol, const std::vector& _val); QCheckBox* SetCheckBox(int _row, int _col, bool _checked = true); diff --git a/GUIWidgets/SimulationThread/SimulationThread.cpp b/GUIWidgets/SimulationThread/SimulationThread.cpp new file mode 100644 index 00000000..95d5fc28 --- /dev/null +++ b/GUIWidgets/SimulationThread/SimulationThread.cpp @@ -0,0 +1,30 @@ +/* Copyright (c) 2023, DyssolTEC GmbH. + * All rights reserved. This file is part of Dyssol. See LICENSE file for license information. */ + +#include "SimulationThread.h" + +CSimulationThread::CSimulationThread(std::function _run, std::function _stop, QObject* _parent) : + CBasicThread(_parent) +{ + m_run = _run; + m_stop = _stop; +} + +bool CSimulationThread::WasAborted() const +{ + return m_aborted; +} + +void CSimulationThread::StartTask() +{ + m_aborted = false; // reset flag + m_run(); + emit Finished(); +} + +void CSimulationThread::RequestStop() +{ + m_stop(); + m_aborted = true; + emit Finished(); +} diff --git a/GUIWidgets/SimulationThread/SimulationThread.h b/GUIWidgets/SimulationThread/SimulationThread.h new file mode 100644 index 00000000..3de65cf8 --- /dev/null +++ b/GUIWidgets/SimulationThread/SimulationThread.h @@ -0,0 +1,24 @@ +/* Copyright (c) 2023, DyssolTEC GmbH. + * All rights reserved. This file is part of Dyssol. See LICENSE file for license information. */ + +#pragma once + +#include "BasicThread.h" + +class CSimulationThread : public CBasicThread +{ + Q_OBJECT + + bool m_aborted{ false }; // Whether the simulation was aborted. + std::function m_run; // Function to run simulation + std::function m_stop; // Function to abort simulation + +public: + CSimulationThread(std::function _run, std::function _stop, QObject* _parent = nullptr); + + bool WasAborted() const; // Returns whether the simulation was aborted by user. + +public slots: + void StartTask() override; + void RequestStop() override; +}; diff --git a/GUIWidgets/SimulationThread/SimulationThread.vcxproj b/GUIWidgets/SimulationThread/SimulationThread.vcxproj new file mode 100644 index 00000000..8e81a674 --- /dev/null +++ b/GUIWidgets/SimulationThread/SimulationThread.vcxproj @@ -0,0 +1,128 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + + + + + + + {0F7B1A52-7766-4E37-9ACD-AC76AB000000} + QtVS_v303 + $(MSBuildProjectDirectory)\QtMsBuild + SimulationThread + + + + StaticLibrary + v142 + Unicode + + + StaticLibrary + v142 + Unicode + + + StaticLibrary + true + v142 + Unicode + + + StaticLibrary + true + v142 + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + msvc2019_64 + + + + + msvc2019 + + + + + msvc2019_64 + widgets; + + + msvc2019 + + + + + <_ProjectFileVersion>10.0.40219.1 + + + + + + + + + + + + $(Qt_INCLUDEPATH_);.\GeneratedFiles;$(CAExcludePath) + + \ No newline at end of file diff --git a/GUIWidgets/SimulationThread/SimulationThread.vcxproj.filters b/GUIWidgets/SimulationThread/SimulationThread.vcxproj.filters new file mode 100644 index 00000000..97a116de --- /dev/null +++ b/GUIWidgets/SimulationThread/SimulationThread.vcxproj.filters @@ -0,0 +1,23 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;cxx;c;def + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h + + + + + Header Files + + + + + Source Files + + + \ No newline at end of file diff --git a/GUIWidgets/StatusWindow/StatusWindow.vcxproj b/GUIWidgets/StatusWindow/StatusWindow.vcxproj index 5bab38de..12008f2d 100644 --- a/GUIWidgets/StatusWindow/StatusWindow.vcxproj +++ b/GUIWidgets/StatusWindow/StatusWindow.vcxproj @@ -126,4 +126,16 @@ $(Qt_INCLUDEPATH_);.\GeneratedFiles;$(CAExcludePath) + + + + + + + + + + + + \ No newline at end of file diff --git a/HDF5Handler/H5Handler.cpp b/HDF5Handler/H5Handler.cpp index 6b006025..7e1e8dac 100644 --- a/HDF5Handler/H5Handler.cpp +++ b/HDF5Handler/H5Handler.cpp @@ -174,7 +174,7 @@ void CH5Handler::WriteData(const std::string& _sPath, const std::string& _sDatas WriteValue(_sPath, _sDatasetName, _vData.size(), PredType::NATIVE_DOUBLE, &_vData.front()); } -void CH5Handler::WriteData(const std::string& _sPath, const std::string& _sDatasetName, std::vector>& _vvData) const +void CH5Handler::WriteData(const std::string& _sPath, const std::string& _sDatasetName, const std::vector>& _vvData) const { if (!m_bFileValid) return; if (_vvData.empty()) return; @@ -191,7 +191,7 @@ void CH5Handler::WriteData(const std::string& _sPath, const std::string& _sDatas for (size_t i = 0; i < size; ++i) { buffer[i].len = _vvData[i].size(); - buffer[i].p = !_vvData[i].empty() ? &_vvData[i].front() : nullptr; + buffer[i].p = !_vvData[i].empty() ? const_cast(&_vvData[i].front()) : nullptr; } h5Dataset.write(buffer, h5Varlentype); delete[] buffer; diff --git a/HDF5Handler/H5Handler.h b/HDF5Handler/H5Handler.h index 82da557e..bb0d4b05 100644 --- a/HDF5Handler/H5Handler.h +++ b/HDF5Handler/H5Handler.h @@ -48,7 +48,7 @@ class CH5Handler void WriteData(const std::string& _sPath, const std::string& _sDatasetName, const std::vector& _vData) const; void WriteData(const std::string& _sPath, const std::string& _sDatasetName, const std::vector& _vData) const; void WriteData(const std::string& _sPath, const std::string& _sDatasetName, const std::vector& _vData) const; - void WriteData(const std::string& _sPath, const std::string& _sDatasetName, std::vector>& _vvData) const; + void WriteData(const std::string& _sPath, const std::string& _sDatasetName, const std::vector>& _vvData) const; void WriteData(const std::string& _sPath, const std::string& _sDatasetName, const std::vector& _data) const; void WriteData(const std::string& _sPath, const std::string& _sDatasetName, const std::vector& _data) const; diff --git a/MaterialsDatabase/Compound.cpp b/MaterialsDatabase/Compound.cpp index ee7cdc10..86e26be4 100644 --- a/MaterialsDatabase/Compound.cpp +++ b/MaterialsDatabase/Compound.cpp @@ -106,6 +106,17 @@ const CConstProperty* CCompound::GetConstProperty(ECompoundConstProperties _nTyp return nullptr; } +CConstProperty* CCompound::GetConstPropertyByIndex(size_t _index) +{ + return const_cast(static_cast(*this).GetConstPropertyByIndex(_index)); +} + +const CConstProperty* CCompound::GetConstPropertyByIndex(size_t _index) const +{ + if (_index >= m_vConstProperties.size()) return nullptr; + return &m_vConstProperties[_index]; +} + const std::vector& CCompound::GetConstProperties() const { return m_vConstProperties; @@ -140,17 +151,3 @@ const std::vector& CCompound::GetTPProperties() const { return m_vTPProperties; } - -double CCompound::GetConstPropertyValue(ECompoundConstProperties _nType) const -{ - if (const CConstProperty *prop = GetConstProperty(_nType)) - return prop->GetValue(); - return 0; -} - -double CCompound::GetTPPropertyValue(ECompoundTPProperties _nType, double _dT, double _dP) const -{ - if (const CTPDProperty *prop = GetTPProperty(_nType)) - return prop->GetValue(_dT, _dP); - return 0; -} diff --git a/MaterialsDatabase/Compound.h b/MaterialsDatabase/Compound.h index 2ad85ac8..f7fbfc3b 100644 --- a/MaterialsDatabase/Compound.h +++ b/MaterialsDatabase/Compound.h @@ -57,6 +57,10 @@ class CCompound : public CDescriptable CConstProperty* GetConstProperty(ECompoundConstProperties _nType); // Returns constant pointer to a specified const property. Returns nullptr if property is not found. const CConstProperty* GetConstProperty(ECompoundConstProperties _nType) const; + // Returns pointer to a specified const property by its index. Returns nullptr if property is not found. + CConstProperty* GetConstPropertyByIndex(size_t _index); + // Returns constant pointer to a specified const property by its index. Returns nullptr if property is not found. + const CConstProperty* GetConstPropertyByIndex(size_t _index) const; // Returns vector of defined const properties. const std::vector& GetConstProperties() const; // Returns pointer to a specified temperature/pressure-dependent property. Returns nullptr if property is not found. @@ -69,13 +73,4 @@ class CCompound : public CDescriptable const CTPDProperty* GetTPPropertyByIndex(size_t _index) const; // Returns vector of defined temperature/pressure-dependent properties. const std::vector& GetTPProperties() const; - - - ////////////////////////////////////////////////////////////////////////// - /// Values getters - - // Returns value of a constant property. Returns 0 if such property doesn't exist. - double GetConstPropertyValue(ECompoundConstProperties _nType) const; - // Returns value of a temperature/pressure-dependent property by specified temperature [K] and pressure [Pa]. Returns 0 if such property doesn't exist. - double GetTPPropertyValue(ECompoundTPProperties _nType, double _dT, double _dP) const; }; diff --git a/MaterialsDatabase/Correlation.cpp b/MaterialsDatabase/Correlation.cpp index 72dfc6a8..9dedf5d7 100644 --- a/MaterialsDatabase/Correlation.cpp +++ b/MaterialsDatabase/Correlation.cpp @@ -145,6 +145,8 @@ double CCorrelation::GetValue(double _dT, double _dP) const case ECorrelationTypes::SUTHERLAND: res = m_vParameters[0] * (m_vParameters[1] + m_vParameters[2]) / (_dT + m_vParameters[2]) * pow(_dT / m_vParameters[1], 3. / 2.); break; + case ECorrelationTypes::UNDEFINED: + break; } if (std::isinf(res) || std::isnan(res)) diff --git a/MaterialsDatabase/DefinesMDB.h b/MaterialsDatabase/DefinesMDB.h index 41a2f1c8..02e1d7db 100644 --- a/MaterialsDatabase/DefinesMDB.h +++ b/MaterialsDatabase/DefinesMDB.h @@ -63,6 +63,7 @@ enum class ECorrelationTypes : unsigned POLYNOMIAL_H = 8, // y = a·T + b·(T^2)/2 + c·(T^3)/3 + d·(T^4)/4 − e/T + f − g POLYNOMIAL_S = 9, // y = a·ln(T) + b·T + c·(T^2)/2 + d·(T^3)/3 − e/(2·T^2) + f SUTHERLAND = 10, // y = a·(b + c)/(T + c)·(T/b)^(3/2) + UNDEFINED = 63 }; namespace MDBDescriptors diff --git a/MaterialsDatabase/MaterialsDatabase.cpp b/MaterialsDatabase/MaterialsDatabase.cpp index c7562e5b..c3e8fb77 100644 --- a/MaterialsDatabase/MaterialsDatabase.cpp +++ b/MaterialsDatabase/MaterialsDatabase.cpp @@ -691,15 +691,15 @@ std::vector CMaterialsDatabase::GetCompoundsKeys() const double CMaterialsDatabase::GetConstPropertyValue(const std::string& _sCompoundUniqueKey, ECompoundConstProperties _nConstPropType) const { - if(const CCompound *comp = GetCompound(_sCompoundUniqueKey)) - return comp->GetConstPropertyValue(_nConstPropType); + if (const CCompound* comp = GetCompound(_sCompoundUniqueKey)) + return comp->GetConstProperty(_nConstPropType)->GetValue(); return 0; } double CMaterialsDatabase::GetTPPropertyValue(const std::string& _sCompoundUniqueKey, ECompoundTPProperties _nTPPropType, double _dT, double _dP) const { if (const CCompound *comp = GetCompound(_sCompoundUniqueKey)) - return comp->GetTPPropertyValue(_nTPPropType, _dT, _dP); + return comp->GetTPProperty(_nTPPropType)->GetValue(_dT, _dP); return 0; } diff --git a/ModelsAPI/BaseStream.cpp b/ModelsAPI/BaseStream.cpp index 0060448b..5e0461da 100644 --- a/ModelsAPI/BaseStream.cpp +++ b/ModelsAPI/BaseStream.cpp @@ -78,7 +78,7 @@ void CBaseStream::SetupStructure(const CBaseStream* _other) { // TODO: check that thermodynamic and tolerance settings are correctly set here (if they need to be set at all) Clear(); - SetMaterialsDatabasePtr(_other->m_materialsDB); + SetMaterialsDatabase(_other->m_materialsDB); SetCacheSettings(_other->m_cacheSettings); m_grid = _other->m_grid; for (const auto& [type, old] : _other->m_overall) @@ -481,6 +481,31 @@ void CBaseStream::SetCompoundsFractions(double _time, EPhase _phase, const std:: m_phases[_phase]->SetCompoundsDistribution(_time, _value); } +void CBaseStream::SetCompoundMass(double _time, const std::string& _compoundKey, EPhase _phase, double _value) +{ + if (!HasPhase(_phase) || !HasCompound(_compoundKey)) return; + + // get current masses + double totalPhaseMass = GetPhaseMass(_time, _phase); + std::map compoundsMasses; + for (const auto& key : GetAllCompounds()) + compoundsMasses[key] = GetCompoundMass(_time, key, _phase); + + // calculate adjustment for the total mass + totalPhaseMass += _value - compoundsMasses[_compoundKey]; + + // set new phase fractions according to the changed phase masses + compoundsMasses[_compoundKey] = _value; + for (const auto& key : GetAllCompounds()) + if (totalPhaseMass != 0.0) + SetCompoundFraction(_time, key, _phase, compoundsMasses[key] / totalPhaseMass); + else + SetCompoundFraction(_time, key, _phase, 0.0); + + // set new phase mass + SetPhaseMass(_time, _phase, totalPhaseMass); +} + double CBaseStream::GetCompoundMolFraction(double _time, const std::string& _compoundKey, EPhase _phase) const { if (!HasCompound(_compoundKey) || !HasPhase(_phase)) return {}; @@ -1467,7 +1492,7 @@ const CMultidimensionalGrid& CBaseStream::GetGrid() const return m_grid; } -void CBaseStream::SetMaterialsDatabasePtr(const CMaterialsDatabase* _database) +void CBaseStream::SetMaterialsDatabase(const CMaterialsDatabase* _database) { m_materialsDB = _database; ClearEnthalpyCalculator(); diff --git a/ModelsAPI/BaseStream.h b/ModelsAPI/BaseStream.h index 6b12c900..34f97d3d 100644 --- a/ModelsAPI/BaseStream.h +++ b/ModelsAPI/BaseStream.h @@ -565,6 +565,15 @@ class CBaseStream * \param _value List of mass fractions of all defined compounds. */ void SetCompoundsFractions(double _time, EPhase _phase, const std::vector& _value); + /** + * \brief Sets the mass of the specified compound in the specified phase at the given time point. + * \details Total mass of the stream is correspondingly adjusted, masses of other compounds and phases remain the same. + * \param _time Target time point. + * \param _compoundKey Unique key of the compound. + * \param _phase Phase type identifier. + * \param _value Mass of the compound. + */ + void SetCompoundMass(double _time, const std::string& _compoundKey, EPhase _phase, double _value); /** * \brief Returns the molar fraction of the compound in the specified phase at the given time point. @@ -1280,7 +1289,7 @@ class CBaseStream * \brief Sets new pointer to the used materials database. * \param _database Const pointer to the materials database. */ - void SetMaterialsDatabasePtr(const CMaterialsDatabase* _database); + void SetMaterialsDatabase(const CMaterialsDatabase* _database); /** * \private diff --git a/ModelsAPI/BaseUnit.cpp b/ModelsAPI/BaseUnit.cpp index 6796636d..841fdceb 100644 --- a/ModelsAPI/BaseUnit.cpp +++ b/ModelsAPI/BaseUnit.cpp @@ -23,6 +23,14 @@ void CBaseUnit::SetSettings(const CMaterialsDatabase* _materialsDB, const CMulti m_streams.SetPointers(m_materialsDB, &m_grid, m_overall, m_phases, m_cache, m_tolerances, m_thermodynamics); } +void CBaseUnit::SetMaterialsDatabase(const CMaterialsDatabase* _materialsDB) +{ + m_materialsDB = _materialsDB; + m_streams.SetMaterialsDatabase(m_materialsDB); + ClearEnthalpyCalculator(); +} + + void CBaseUnit::CopyUserData(const CBaseUnit& _unit) { m_ports.CopyUserData(_unit.m_ports); @@ -219,7 +227,7 @@ void CBaseUnit::SetupStream(CBaseStream* _stream) const { if (!_stream) return; _stream->Clear(); - _stream->SetMaterialsDatabasePtr(m_materialsDB); + _stream->SetMaterialsDatabase(m_materialsDB); _stream->SetCacheSettings(*m_cache); _stream->SetToleranceSettings(*m_tolerances); _stream->SetThermodynamicsSettings(*m_thermodynamics); diff --git a/ModelsAPI/BaseUnit.h b/ModelsAPI/BaseUnit.h index dbadae81..5372edc6 100644 --- a/ModelsAPI/BaseUnit.h +++ b/ModelsAPI/BaseUnit.h @@ -149,6 +149,14 @@ class CBaseUnit */ void SetSettings(const CMaterialsDatabase* _materialsDB, const CMultidimensionalGrid& _grid, const std::vector* _overall, const std::vector* _phases, const SCacheSettings* _cache, const SToleranceSettings* _tolerance, const SThermodynamicsSettings* _thermodynamics); + + /** + * \private + * \brief Sets new pointer to global materials database. + * \param _materialsDB Pointer to global materials database. + */ + void SetMaterialsDatabase(const CMaterialsDatabase* _materialsDB); + /** * \private * \brief Copies user-defined data from _unit. diff --git a/ModelsAPI/DependentValues.cpp b/ModelsAPI/DependentValues.cpp index 2447adee..84b6164c 100644 --- a/ModelsAPI/DependentValues.cpp +++ b/ModelsAPI/DependentValues.cpp @@ -2,6 +2,7 @@ #include "DependentValues.h" #include "ContainerFunctions.h" +#include "DyssolUtilities.h" #include "StringFunctions.h" #include #include @@ -26,7 +27,7 @@ double CDependentValues::GetValue(double _param) const { if (m_values.empty()) return 0; // return zero, if there are no data at all if (m_values.size() == 1) return m_values.front(); // return const value, if there is only a single value defined - return Interpolate(_param); // return interpolation otherwise + return ::Interpolate(m_params, m_values, _param); // return interpolation otherwise } void CDependentValues::SetValue(double _param, double _value) @@ -141,26 +142,6 @@ bool CDependentValues::operator==(const CDependentValues& _v) const return m_params == _v.m_params && m_values == _v.m_values; } -double CDependentValues::Interpolate(double _param) const -{ - const auto upper = std::upper_bound(m_params.begin(), m_params.end(), _param); - if (upper == m_params.end()) return m_values.back(); // nearest-neighbor extrapolation to the right - if (upper == m_params.begin()) return m_values.front(); // nearest-neighbor extrapolation to the left - - auto lower = upper; - --lower; - - const double upar = *upper; - const double lpar = *lower; - const double uval = m_values[std::distance(m_params.begin(), upper)]; - const double lval = m_values[std::distance(m_params.begin(), lower)]; - - if (std::abs(upar - _param) <= m_eps) return uval; // exact value found - if (std::abs(lpar - _param) <= m_eps) return lval; // exact value found - - return (uval - lval) / (upar - lpar) * (_param - lpar) + lval; // linearly interpolated value -} - std::ostream& operator<<(std::ostream& _s, const CDependentValues& _obj) { for (size_t i = 0; i < _obj.Size(); ++i) diff --git a/ModelsAPI/DependentValues.h b/ModelsAPI/DependentValues.h index 6f876cfe..0aca1f1e 100644 --- a/ModelsAPI/DependentValues.h +++ b/ModelsAPI/DependentValues.h @@ -68,8 +68,4 @@ class CDependentValues // Comparison. bool operator==(const CDependentValues& _v) const; - -private: - // Performs linear interpolation. If the parameter is out of defined limits, performs nearest-neighbor extrapolation of data. - [[nodiscard]] double Interpolate(double _param) const; }; diff --git a/ModelsAPI/DistributionsFunctions.h b/ModelsAPI/DistributionsFunctions.h index fb24b501..8839c390 100644 --- a/ModelsAPI/DistributionsFunctions.h +++ b/ModelsAPI/DistributionsFunctions.h @@ -8,6 +8,7 @@ #include #include #include +#include /** * \file diff --git a/ModelsAPI/StreamManager.cpp b/ModelsAPI/StreamManager.cpp index cbfb7cb8..2c3af28e 100644 --- a/ModelsAPI/StreamManager.cpp +++ b/ModelsAPI/StreamManager.cpp @@ -19,6 +19,11 @@ void CStreamManager::SetPointers(const CMaterialsDatabase* _materialsDB, const C m_thermodynamics = _thermodynamics; } +void CStreamManager::SetMaterialsDatabase(const CMaterialsDatabase* _materialsDB) +{ + m_materialsDB = _materialsDB; +} + void CStreamManager::CopyUserData(const CStreamManager& _streams) const { if (m_feedsInit.size() > _streams.m_feedsInit.size()) return; diff --git a/ModelsAPI/StreamManager.h b/ModelsAPI/StreamManager.h index d5ac5e5a..d9f94a78 100644 --- a/ModelsAPI/StreamManager.h +++ b/ModelsAPI/StreamManager.h @@ -52,6 +52,12 @@ class CStreamManager void SetPointers(const CMaterialsDatabase* _materialsDB, const CMultidimensionalGrid* _grid, const std::vector* _overall, const std::vector* _phases, const SCacheSettings* _cache, const SToleranceSettings* _tolerances, const SThermodynamicsSettings* _thermodynamics); + /** + * \internal + * \brief Sets pointer to a global materials database. + * \param _materialsDB Pointer to materials database. + */ + void SetMaterialsDatabase(const CMaterialsDatabase* _materialsDB); /** * \internal * \brief Copies user-defined data from _streams. diff --git a/ModelsAPI/TDArray.cpp b/ModelsAPI/TDArray.cpp index 58540566..ea6111ae 100644 --- a/ModelsAPI/TDArray.cpp +++ b/ModelsAPI/TDArray.cpp @@ -99,7 +99,7 @@ double CTDArray::GetValue(double _dTime) size_t indexAfter = GetIndexByTime( _dTime, false ); if(( indexAfter != m_data.size() ) && ( indexAfter != 0 )) // point inside - interpolation //return GetInterpolation( indexAfter-1, indexAfter, _dTime ); - return Interpolate( m_data[indexAfter].value, m_data[indexAfter-1].value, m_data[indexAfter].time, m_data[indexAfter-1].time, _dTime ); + return Interpolate( m_data[indexAfter].time, m_data[indexAfter-1].time, m_data[indexAfter].value, m_data[indexAfter-1].value, _dTime ); else if( indexAfter == m_data.size() ) // point after the last - extrapolation //return GetInterpolation( indexAfter-2, indexAfter-1, _dTime ); return m_data.back().value; @@ -304,7 +304,7 @@ void CTDArray::CompressData( double _dStartTime, double _dEndTime, double _dATol while( i>& _data) @@ -142,7 +142,7 @@ void CTimeDependentValue::Extrapolate(double _timeExtra, double _time1, double _ { const double v1 = GetValue(_time1); const double v2 = GetValue(_time2); - const double res = ::Interpolate(v1, v2, _time1, _time2, _timeExtra); + const double res = ::Interpolate(_time1, _time2, v1, v2, _timeExtra); SetValue(_timeExtra, res); } @@ -186,23 +186,6 @@ void CTimeDependentValue::LoadFromFile(const CH5Handler& _h5File, const std::str SetRawData(data); } -double CTimeDependentValue::Interpolate(double _time) const -{ - if (m_data.empty()) return {}; - if (m_data.size() == 1) return m_data.front().value; - - auto u = std::upper_bound(m_data.begin(), m_data.end(), STDValue{ _time, 0.0 }); - if (u == m_data.end()) return (--u)->value; // nearest-neighbor extrapolation to the right - if (u == m_data.begin()) return u->value; // nearest-neighbor extrapolation to the left - - const auto l = u - 1; - - if (std::abs(u->time - _time) <= m_eps) return u->value; // exact value found - if (std::abs(l->time - _time) <= m_eps) return l->value; // exact value found - - return (u->value - l->value) / (u->time - l->time) * (_time - l->time) + l->value; // linearly interpolated value -} - bool CTimeDependentValue::HasTime(double _time) const { if (m_data.empty()) return false; diff --git a/ModelsAPI/TimeDependentValue.h b/ModelsAPI/TimeDependentValue.h index f6b2584f..d440fc1f 100644 --- a/ModelsAPI/TimeDependentValue.h +++ b/ModelsAPI/TimeDependentValue.h @@ -76,8 +76,6 @@ class CTimeDependentValue void LoadFromFile(const CH5Handler& _h5File, const std::string& _path); private: - // Performs linear interpolation. If the parameter is outside of the defined limits, performs nearest-neighbor extrapolation of data. Returns zero if the data vector is empty. - double Interpolate(double _time) const; // Checks whether the given time point exists. bool HasTime(double _time) const; // Returns the nearest time point before _time. diff --git a/PropertySheets/CommonQt.props b/PropertySheets/CommonQt.props index f8d4c24e..f555ea82 100644 --- a/PropertySheets/CommonQt.props +++ b/PropertySheets/CommonQt.props @@ -7,16 +7,31 @@ <_PropertySheetDisplayName>CommonQt + + false + - $(SolutionDir)GUIWidgets\BasicStreamEditor;$(SolutionDir)$(Platform)\$(Configuration)\BasicStreamEditor\uic;$(SolutionDir)GUIWidgets\BasicStreamsViewer;$(SolutionDir)$(Platform)\$(Configuration)\BasicStreamsViewer\uic;$(SolutionDir)GUIWidgets\BasicThread;$(SolutionDir)GUIWidgets\StatusWindow;$(SolutionDir)$(Platform)\$(Configuration)\StatusWindow\uic;$(SolutionDir)GUIWidgets\QtPlot;$(SolutionDir)$(Platform)\$(Configuration)\QtPlot\uic;$(SolutionDir)GUIWidgets\QtWidgets;%(AdditionalIncludeDirectories) + $(SolutionDir)GUIWidgets\BasicStreamEditor;$(SolutionDir)$(Platform)\$(Configuration)\BasicStreamEditor\uic;$(SolutionDir)GUIWidgets\BasicStreamsViewer;$(SolutionDir)$(Platform)\$(Configuration)\BasicStreamsViewer\uic;$(SolutionDir)GUIWidgets\BasicThread;$(SolutionDir)GUIWidgets\StatusWindow;$(SolutionDir)$(Platform)\$(Configuration)\StatusWindow\uic;$(SolutionDir)GUIWidgets\QtPlot;$(SolutionDir)$(Platform)\$(Configuration)\QtPlot\uic;$(SolutionDir)GUIWidgets\QtWidgets;$(SolutionDir)GUIWidgets\SimulationThread;%(AdditionalIncludeDirectories) + moc %(Identity) + $(IntDir)moc\ + moc_%(Filename).cpp + output + true + false + + uic %(Identity) + $(IntDir)uic\ + ui_%(Filename).h + true + \ No newline at end of file diff --git a/ScriptInterface/NameConverters.h b/ScriptInterface/NameConverters.h index 9316640c..3d32e87c 100644 --- a/ScriptInterface/NameConverters.h +++ b/ScriptInterface/NameConverters.h @@ -1,4 +1,6 @@ -/* Copyright (c) 2021, Dyssol Development Team. All rights reserved. This file is part of Dyssol. See LICENSE file for license information. */ +/* Copyright (c) 2021, Dyssol Development Team. + * Copyright (c) 2023, DyssolTEC GmbH. + * All rights reserved. This file is part of Dyssol. See LICENSE file for license information. */ #pragma once #include "DyssolDefines.h" diff --git a/ScriptInterface/ScriptExporter.cpp b/ScriptInterface/ScriptExporter.cpp index f006db51..f87d57a5 100644 --- a/ScriptInterface/ScriptExporter.cpp +++ b/ScriptInterface/ScriptExporter.cpp @@ -1,4 +1,6 @@ -/* Copyright (c) 2021, Dyssol Development Team. All rights reserved. This file is part of Dyssol. See LICENSE file for license information. */ +/* Copyright (c) 2021, Dyssol Development Team. + * Copyright (c) 2023, DyssolTEC GmbH. + * All rights reserved. This file is part of Dyssol. See LICENSE file for license information. */ #include "ScriptExporter.h" #include "ScriptJob.h" diff --git a/ScriptInterface/ScriptRunner.cpp b/ScriptInterface/ScriptRunner.cpp index aaaf3167..9440217d 100644 --- a/ScriptInterface/ScriptRunner.cpp +++ b/ScriptInterface/ScriptRunner.cpp @@ -1,4 +1,6 @@ -/* Copyright (c) 2021, Dyssol Development Team. All rights reserved. This file is part of Dyssol. See LICENSE file for license information. */ +/* Copyright (c) 2021, Dyssol Development Team. + * Copyright (c) 2023, DyssolTEC GmbH. + * All rights reserved. This file is part of Dyssol. See LICENSE file for license information. */ #include "ScriptRunner.h" #include "ScriptJob.h" @@ -231,7 +233,7 @@ bool CScriptRunner::SetupGrids(const CScriptJob& _job) if (function != EGridFunction::GRID_FUN_MANUAL && entry.valuesNum.size() != 2 || function == EGridFunction::GRID_FUN_MANUAL && entry.valuesNum.size() != entry.classes + 1) return PrintMessage(DyssolC_ErrorArgumentsNumberGrid(StrKey(EScriptKeys::DISTRIBUTION_GRID), unit ? unit->GetName() : "GLOBAL", entry.distrType.name, entry.distrType.key)); // create grid - std::vector res = function == EGridFunction::GRID_FUN_MANUAL ? entry.valuesNum : CreateGrid(function, entry.classes, entry.valuesNum[0], entry.valuesNum[1]); + std::vector res = function == EGridFunction::GRID_FUN_MANUAL ? entry.valuesNum : CreateGrid(function, entry.classes, std::min(entry.valuesNum[0], entry.valuesNum[1]), std::max(entry.valuesNum[0], entry.valuesNum[1])); // convert volumes to diameters if required if (type == DISTR_SIZE && static_cast(entry.psdMeans.key) == EPSDGridType::VOLUME) res = VolumeToDiameter(res); @@ -469,6 +471,17 @@ bool CScriptRunner::SetupHoldupsDistributions(const CScriptJob& _job) return true; } +bool CScriptRunner::SaveFlowsheet(const CScriptJob& _job) +{ + const auto dstFile = fs::absolute(_job.HasKey(EScriptKeys::RESULT_FILE) ? _job.GetValue(EScriptKeys::RESULT_FILE) : _job.GetValue(EScriptKeys::SOURCE_FILE)).make_preferred(); + fs::create_directories(dstFile.parent_path()); + PrintMessage(DyssolC_SaveFlowsheet(dstFile.string())); + CSaveLoadManager saver{ &m_flowsheet }; + if (!saver.SaveToFile(dstFile)) + return PrintMessage(DyssolC_ErrorSave()); + return true; +} + bool CScriptRunner::RunSimulation(const CScriptJob& _job) { if (_job.HasKey(EScriptKeys::EXPORT_ONLY) && _job.GetValue(EScriptKeys::EXPORT_ONLY)) return true; @@ -488,14 +501,7 @@ bool CScriptRunner::RunSimulation(const CScriptJob& _job) PrintMessage(DyssolC_SimFinished(ch::duration_cast(tEnd - tStart).count())); // save simulation results - const auto dstFile = fs::absolute(_job.HasKey(EScriptKeys::RESULT_FILE) ? _job.GetValue(EScriptKeys::RESULT_FILE) : _job.GetValue(EScriptKeys::SOURCE_FILE)).make_preferred(); - fs::create_directories(dstFile.parent_path()); - PrintMessage(DyssolC_SaveFlowsheet(dstFile.string())); - CSaveLoadManager saver{ &m_flowsheet }; - if (!saver.SaveToFile(dstFile)) - return PrintMessage(DyssolC_ErrorSave()); - - return true; + return SaveFlowsheet(_job); } // TODO: split diff --git a/ScriptInterface/ScriptRunner.h b/ScriptInterface/ScriptRunner.h index fb51e4e0..4b6a2f13 100644 --- a/ScriptInterface/ScriptRunner.h +++ b/ScriptInterface/ScriptRunner.h @@ -60,6 +60,8 @@ class CScriptRunner // Sets holdups distributed parameters. Returns success flag. bool SetupHoldupsDistributions(const CScriptJob& _job); + // Saves the flowsheet. Returns success flag. + bool SaveFlowsheet(const CScriptJob& _job); // Performs the simulation. Returns success flag. bool RunSimulation(const CScriptJob& _job); // Exports results from file. diff --git a/ScriptInterface/ScriptTypes.h b/ScriptInterface/ScriptTypes.h index dc1304bb..287cb1e4 100644 --- a/ScriptInterface/ScriptTypes.h +++ b/ScriptInterface/ScriptTypes.h @@ -1,4 +1,6 @@ -/* Copyright (c) 2021, Dyssol Development Team. All rights reserved. This file is part of Dyssol. See LICENSE file for license information. */ +/* Copyright (c) 2021, Dyssol Development Team. + * Copyright (c) 2023, DyssolTEC GmbH. + * All rights reserved. This file is part of Dyssol. See LICENSE file for license information. */ /* * All parsing types are described here. diff --git a/SimulatorCore/Flowsheet.cpp b/SimulatorCore/Flowsheet.cpp index 2d6bb4bd..2e6f35fe 100644 --- a/SimulatorCore/Flowsheet.cpp +++ b/SimulatorCore/Flowsheet.cpp @@ -849,6 +849,17 @@ const CMaterialsDatabase& CFlowsheet::GetMaterialDatabase() const return *m_materialsDB; } +void CFlowsheet::SetMaterialsDatabase(const CMaterialsDatabase* _materialsDB) +{ + m_materialsDB = _materialsDB; + for (const auto& unit : m_units) + unit->SetMaterialsDatabase(m_materialsDB); + for (const auto& stream : m_streams) + stream->SetMaterialsDatabase(m_materialsDB); + for (const auto& stream : m_streamsI) + stream->SetMaterialsDatabase(m_materialsDB); +} + const CParametersHolder* CFlowsheet::GetParameters() const { return &m_parameters; diff --git a/SimulatorCore/Flowsheet.h b/SimulatorCore/Flowsheet.h index 6bfb9998..b540717a 100644 --- a/SimulatorCore/Flowsheet.h +++ b/SimulatorCore/Flowsheet.h @@ -255,6 +255,8 @@ class CFlowsheet const CMultidimensionalGrid& GetGrid() const; // Returns reference to a global database of materials. const CMaterialsDatabase& GetMaterialDatabase() const; + // Sets pointer to a global database of materials + void SetMaterialsDatabase(const CMaterialsDatabase* _materialsDB); // Returns a const pointer to parameters settings. const CParametersHolder* GetParameters() const; diff --git a/SimulatorCore/Simulator.cpp b/SimulatorCore/Simulator.cpp index 0b73f693..839c8ba7 100644 --- a/SimulatorCore/Simulator.cpp +++ b/SimulatorCore/Simulator.cpp @@ -24,6 +24,7 @@ void CSimulator::SetFlowsheet(CFlowsheet* _pFlowsheet) m_pFlowsheet = _pFlowsheet; m_pSequence = m_pFlowsheet->GetCalculationSequence(); m_pParams = m_pFlowsheet->GetParameters(); + m_hasError = false; } void CSimulator::SetCurrentStatus(ESimulatorStatus _nStatus) @@ -36,6 +37,11 @@ ESimulatorStatus CSimulator::GetCurrentStatus() const return m_nCurrentStatus; } +bool CSimulator::HasError() const +{ + return m_hasError; +} + CSimulator::SPartitionStatus CSimulator::GetCurrentPartitionStatus() const { if (m_iCurrentPartition >= m_partitionsStatus.size()) return {}; @@ -45,10 +51,12 @@ CSimulator::SPartitionStatus CSimulator::GetCurrentPartitionStatus() const void CSimulator::Simulate() { m_nCurrentStatus = ESimulatorStatus::SIMULATOR_RUNNED; + m_hasError = false; // Prepare SetupConvergenceMethod(); ClearLogState(); + m_hasError = false; InitializePartitionsStatus(); // Clear initialization flags @@ -105,6 +113,12 @@ void CSimulator::Simulate() m_nCurrentStatus = ESimulatorStatus::SIMULATOR_IDLE; } +void CSimulator::Stop() +{ + if (GetCurrentStatus() != ESimulatorStatus::SIMULATOR_IDLE) + SetCurrentStatus(ESimulatorStatus::SIMULATOR_SHOULD_BE_STOPPED); +} + void CSimulator::InitializePartitionsStatus() { m_partitionsStatus.clear(); @@ -394,6 +408,7 @@ void CSimulator::RaiseError(const std::string& _sError) { m_log.WriteError(_sError); m_nCurrentStatus = ESimulatorStatus::SIMULATOR_SHOULD_BE_STOPPED; + m_hasError = true; } void CSimulator::ClearLogState() diff --git a/SimulatorCore/Simulator.h b/SimulatorCore/Simulator.h index 8546f3cc..3d856ef8 100644 --- a/SimulatorCore/Simulator.h +++ b/SimulatorCore/Simulator.h @@ -56,6 +56,7 @@ class CSimulator //// parameters of convergence methods bool m_bSteffensenTrigger; + bool m_hasError{ false }; // Current simulation finished with error. public: CSimulator(); @@ -67,6 +68,11 @@ class CSimulator void SetCurrentStatus(ESimulatorStatus _nStatus); // Returns current status of the simulator. ESimulatorStatus GetCurrentStatus() const; + /** + * Checks if current simulation finished with error. + * \return Whether current simulation finished with error. + */ + [[nodiscard]] bool HasError() const; // Returns information about currently calculated partition. SPartitionStatus GetCurrentPartitionStatus() const; @@ -74,6 +80,9 @@ class CSimulator /// Perform simulation. void Simulate(); + /// Stop Simulation + void Stop(); + private: /// Initialize status for each partition. void InitializePartitionsStatus(); diff --git a/SimulatorCore/SimulatorLog.cpp b/SimulatorCore/SimulatorLog.cpp index f1f58c6b..08857fdd 100644 --- a/SimulatorCore/SimulatorLog.cpp +++ b/SimulatorCore/SimulatorLog.cpp @@ -29,6 +29,7 @@ void CSimulatorLog::Write(const std::string& _text, ELogColor _color, bool _cons const size_t iPos = m_iWritePos % MAX_LOG_SIZE; // up to MAX_LOG_SIZE and then again cyclic from 0 m_log[iPos].text = _text; m_log[iPos].color = _color; + m_iWritePos++; if(_console) std::cout << _text << std::endl; diff --git a/SimulatorCore/UnitContainer.cpp b/SimulatorCore/UnitContainer.cpp index 81725ef7..83520b5a 100644 --- a/SimulatorCore/UnitContainer.cpp +++ b/SimulatorCore/UnitContainer.cpp @@ -87,6 +87,13 @@ CBaseUnit* CUnitContainer::GetModel() return m_model; } +void CUnitContainer::SetMaterialsDatabase(const CMaterialsDatabase* _materialsDB) +{ + m_materialsDB = _materialsDB; + if (!m_model) return; + m_model->SetMaterialsDatabase(m_materialsDB); +} + std::string CUnitContainer::InitializeExternalSolvers() const { ClearExternalSolvers(); diff --git a/SimulatorCore/UnitContainer.h b/SimulatorCore/UnitContainer.h index f15f41cb..24810a98 100644 --- a/SimulatorCore/UnitContainer.h +++ b/SimulatorCore/UnitContainer.h @@ -66,6 +66,9 @@ class CUnitContainer // Returns a pointer to a contained model. CBaseUnit* GetModel(); + // Sets pointer to a global materials database. + void SetMaterialsDatabase(const CMaterialsDatabase* _materialsDB); + // Initializes all solvers chosen in unit parameters by loading them from corresponding dynamic libraries. Returns an empty string on success, otherwise returns an error description. std::string InitializeExternalSolvers() const; // Unloads all solvers from unit parameters. diff --git a/Utilities/ContainerFunctions.h b/Utilities/ContainerFunctions.h index 1df801fa..c8c54a67 100644 --- a/Utilities/ContainerFunctions.h +++ b/Utilities/ContainerFunctions.h @@ -1,4 +1,6 @@ -/* Copyright (c) 2020, Dyssol Development Team. All rights reserved. This file is part of Dyssol. See LICENSE file for license information. */ +/* Copyright (c) 2020, Dyssol Development Team. + * Copyright (c) 2023, DyssolTEC GmbH. + * All rights reserved. This file is part of Dyssol. See LICENSE file for license information. */ #pragma once @@ -187,6 +189,17 @@ std::vector MapKeys(const std::map& _map) return keys; } +// Returns all values defined in the map. +template +std::vector MapValues(const std::map& _map) +{ + std::vector values; + values.reserve(_map.size()); + for (auto const& entry : _map) + values.push_back(entry.second); + return values; +} + // Returns a sorted copy of the vector. template std::vector VectorSort(const std::vector& _v) @@ -196,7 +209,7 @@ std::vector VectorSort(const std::vector& _v) return res; } -// Calculates union of two sorted vectors. +// Calculates a sorted union of two sorted vectors. template void VectorsUnionSorted(const std::vector& _v1, const std::vector& _v2, std::vector& _res) { @@ -204,7 +217,7 @@ void VectorsUnionSorted(const std::vector& _v1, const std::vector& _v2, st _res.resize(std::set_union(_v1.begin(), _v1.end(), _v2.begin(), _v2.end(), _res.begin()) - _res.begin()); } -// Calculates and returns union of two sorted vectors. +// Calculates and returns a sorted union of two sorted vectors. template std::vector VectorsUnionSorted(const std::vector& _v1, const std::vector& _v2) { diff --git a/Utilities/DisableWarningHelper.h b/Utilities/DisableWarningHelper.h new file mode 100644 index 00000000..5be93dbd --- /dev/null +++ b/Utilities/DisableWarningHelper.h @@ -0,0 +1,12 @@ +#pragma once + +#if defined(_MSC_VER) +#include +#define PRAGMA_WARNING_PUSH __pragma(warning(push)) +#define PRAGMA_WARNING_POP __pragma(warning(pop)) +#define PRAGMA_WARNING_DISABLE __pragma(warning(disable : 4244 4267 4700 ALL_CODE_ANALYSIS_WARNINGS)) +#else +#define PRAGMA_WARNING_PUSH +#define PRAGMA_WARNING_POP +#define PRAGMA_WARNING_DISABLE +#endif diff --git a/Utilities/DyssolDefines.h b/Utilities/DyssolDefines.h index 6513f6e2..c8ef5850 100644 --- a/Utilities/DyssolDefines.h +++ b/Utilities/DyssolDefines.h @@ -67,7 +67,7 @@ enum class EExtrapolationMethod : uint32_t }; //======== SOLID DISTRIBUTIONS DATABASE [0; 50] =============== -#define DISTRIBUTIONS_NUMBER 15 ///< Total number of distributions. +#define DISTRIBUTIONS_NUMBER 16 // TODO: make enum class /** diff --git a/Utilities/DyssolStringConstants.h b/Utilities/DyssolStringConstants.h index 087eae2f..b006bd92 100644 --- a/Utilities/DyssolStringConstants.h +++ b/Utilities/DyssolStringConstants.h @@ -726,6 +726,7 @@ namespace StrConst const char* const FUN_VolumeUnits = "[m3]"; const char* const FUN_DiameterUnitsInv = "[1/m]"; const char* const FUN_VolumeUnitsInv = "[1/m3]"; + const char* const FUN_ManualName = "Manual"; const char* const FUN_NormalName = "Normal"; const char* const FUN_RRSBName = "RRSB"; const char* const FUN_GGSName = "GGS"; diff --git a/Utilities/DyssolUtilities.h b/Utilities/DyssolUtilities.h index 428cc11e..26a9e0f1 100644 --- a/Utilities/DyssolUtilities.h +++ b/Utilities/DyssolUtilities.h @@ -9,34 +9,78 @@ #include #include -// Performs linear interpolation between two selected points. -double inline Interpolate(double Y1, double Y2, double X1, double X2, double X) +/** + * Performs linear interpolation between two selected points. + * \param _x1 First parameter. + * \param _x2 Second parameter. + * \param _y1 First value. + * \param _y2 Second value. + * \param _x Target parameter. + * \return Interpolated value. + */ +double inline Interpolate(double _x1, double _x2, double _y1, double _y2, double _x) +{ + return (_y2 - _y1) / (_x2 - _x1) * (_x - _x1) + _y1; +} + +/** + * Interpolates the value from the input vector time-dependent _values for a given _time. + * Assumes input vector _values is sorted in ascending order. + * Performs linear interpolation between existing points + * or nearest-neighbor extrapolation, if the given _time lays outside the interval of _values. + * \param _values Sorted vector of time-dependent values. + * \param _time Time for which interpolation is sought. + * \param _epsilon Desired accuracy of comparisons (optional). + * \return Interpolated value. + */ +double inline Interpolate(const std::vector& _values, double _time, double _epsilon = 16 * std::numeric_limits::epsilon()) { - return (Y2 - Y1) / (X2 - X1) * (X - X1) + Y1; + if (_values.empty()) return {}; // no values + + const auto upper = std::upper_bound(_values.begin(), _values.end(), STDValue{ _time, {} }); + if (upper == _values.end()) return _values.back().value; // nearest-neighbor extrapolation to the right + if (upper == _values.begin()) return _values.front().value; // nearest-neighbor extrapolation to the left + + auto lower = upper; + --lower; + + if (std::abs(upper->time - _time) <= _epsilon) return upper->value; // exact value found + if (std::abs(lower->time - _time) <= _epsilon) return lower->value; // exact value found + + return Interpolate(lower->time, upper->time, lower->value, upper->value, _time); // linearly interpolated value } -// Returns a (linearly interpolated) value for the given time. -double inline Interpolate(const std::vector& _vals, double _time) +/** + * Interpolates the Y value from the input vectors _xs and _ys for a given _x. + * Assumes input vector _xs is sorted in ascending order. _xs and _ys must be the same size. + * Performs linear interpolation between existing points + * or nearest-neighbor extrapolation, if the given _x lays outside the interval of _xs. + * \param _xs Sorted vector of parameters. + * \param _ys Vector of values. + * \param _x Parameter for which interpolation is sought. + * \param _epsilon Desired accuracy of comparisons (optional). + * \return Interpolated value. + */ +inline double Interpolate(const std::vector& _xs, const std::vector& _ys, double _x, double _epsilon = 16 * std::numeric_limits::epsilon()) { - if (_vals.empty()) return 0; // no values + if (_xs.size() != _ys.size() || _xs.empty()) return {}; - const auto upper = std::upper_bound(_vals.begin(), _vals.end(), _time, [](double p, const STDValue& v) { return p < v.time; }); - if (upper == _vals.end()) return _vals.back().value; // nearest-neighbor extrapolation to the right - if (upper == _vals.begin()) return _vals.front().value; // nearest-neighbor extrapolation to the left + const auto upper = std::upper_bound(_xs.begin(), _xs.end(), _x); + if (upper == _xs.end()) return _ys.back(); // nearest-neighbor extrapolation to the right + if (upper == _xs.begin()) return _ys.front(); // nearest-neighbor extrapolation to the left auto lower = upper; --lower; - const STDValue upar = *upper; - const STDValue lpar = *lower; - const STDValue uval = _vals[std::distance(_vals.begin(), upper)]; - const STDValue lval = _vals[std::distance(_vals.begin(), lower)]; + const double upperX = *upper; + const double lowerX = *lower; + const double upperY = _ys[std::distance(_xs.begin(), upper)]; + const double lowerY = _ys[std::distance(_xs.begin(), lower)]; - constexpr double eps{ 16 * std::numeric_limits::epsilon() }; - if (std::abs(upar.time - _time) <= eps) return uval.value; // exact value found - if (std::abs(lpar.time - _time) <= eps) return lval.value; // exact value found + if (std::abs(upperX - _x) <= _epsilon) return upperY; // exact value found + if (std::abs(lowerX - _x) <= _epsilon) return lowerY; // exact value found - return Interpolate(lval.value, uval.value, lpar.time, upar.time, _time); + return Interpolate(lowerX, upperX, lowerY, upperY, _x); // linearly interpolated value } // Performs spline extrapolation using three points. @@ -70,6 +114,39 @@ double inline Extrapolate(double Y0, double Y1, double Y2, double X0, double X1, return splines[2].a + (splines[2].b + (splines[2].c / 2. + splines[2].d * dx / 6.) * dx) * dx; } +/** + * \brief Finds values laying before and next to the given value. + * Assumes input vector is sorted in ascending order. + * If exact value is found in the vector, it is returned. If vector contains only one value, it is returned. + * If the value lays outside the vector, the closest outermost element of the vector is returned. + * In general, if only one value is to be returned, it is returned in both values of the pair. + * Additionally, one can specify the precision for comparing values. + * \param _vector Sorted input vector of values. + * \param _value Search value. + * \param _epsilon Desired accuracy of comparisons (optional). + * \return A pair of vector values lying on either side of the given value. + */ +inline std::pair FindNeighbors(const std::vector& _vector, double _value, double _epsilon = 16 * std::numeric_limits::epsilon()) +{ + std::pair res{ {}, {} }; + + if (_vector.empty()) return res; + if (_vector.size() == 1) { res.first = res.second = _vector.front(); return res; } + + auto upper = std::upper_bound(_vector.begin(), _vector.end(), _value); + if (upper == _vector.end()) { res.first = res.second = *(--upper); return res; } // value is larger than the last - use the last one + if (upper == _vector.begin()) { res.first = res.second = *upper; return res; } // value is smaller than the first - use the first one + + const auto lower = upper - 1; + if (std::abs(*upper - _value) <= _epsilon) { res.first = res.second = *upper; return res; } // exact value found + if (std::abs(*lower - _value) <= _epsilon) { res.first = res.second = *lower; return res; } // exact value found + + // two values + res.first = *lower; + res.second = *upper; + return res; +} + // Return the sum of all elements of the vector template T VectorSum(const std::vector& _vVec) @@ -650,21 +727,37 @@ std::vector inline CreateGridLogarithmicDec(size_t _classes, double _min return res; } -// Creates a distribution grid according to the given function and parameters. +/** + * \brief Creates a distribution grid according to the given function and parameters. + * \param _fun Grid function. + * \param _min Minimum of the grid interval. + * \param _max Maximum of the grid interval. + * \param _classes Number of classes. + * \return Generated grid. + */ std::vector inline CreateGrid(EGridFunction _fun, size_t _classes, double _min, double _max) { + const bool reversed = _min > _max; + if (reversed) + std::swap(_min, _max); + + std::vector res = {}; switch (_fun) { - case EGridFunction::GRID_FUN_EQUIDISTANT: return CreateGridEquidistant(_classes, _min, _max); - case EGridFunction::GRID_FUN_GEOMETRIC_S2L: return CreateGridGeometricInc(_classes, _min, _max); - case EGridFunction::GRID_FUN_GEOMETRIC_L2S: return CreateGridGeometricDec(_classes, _min, _max); - case EGridFunction::GRID_FUN_LOGARITHMIC_S2L: return CreateGridLogarithmicInc(_classes, _min, _max); - case EGridFunction::GRID_FUN_LOGARITHMIC_L2S: return CreateGridLogarithmicDec(_classes, _min, _max); + case EGridFunction::GRID_FUN_EQUIDISTANT: res = CreateGridEquidistant(_classes, _min, _max); break; + case EGridFunction::GRID_FUN_GEOMETRIC_S2L: res = !reversed ? CreateGridGeometricInc(_classes, _min, _max) : CreateGridGeometricDec(_classes, _min, _max); break; + case EGridFunction::GRID_FUN_GEOMETRIC_L2S: res = !reversed ? CreateGridGeometricDec(_classes, _min, _max) : CreateGridGeometricInc(_classes, _min, _max); break; + case EGridFunction::GRID_FUN_LOGARITHMIC_S2L: res = !reversed ? CreateGridLogarithmicInc(_classes, _min, _max) : CreateGridLogarithmicDec(_classes, _min, _max); break; + case EGridFunction::GRID_FUN_LOGARITHMIC_L2S: res = !reversed ? CreateGridLogarithmicDec(_classes, _min, _max) : CreateGridLogarithmicInc(_classes, _min, _max); break; case EGridFunction::GRID_FUN_MANUAL: case EGridFunction::GRID_FUN_UNDEFINED: return std::vector(_classes + 1); } - return {}; + + if (reversed) + std::reverse(res.begin(), res.end()); + + return res; } // Calculates volume of the sphere from its diameter. diff --git a/Utilities/StringFunctions.cpp b/Utilities/StringFunctions.cpp index 3d6f4b80..ee4e42a4 100644 --- a/Utilities/StringFunctions.cpp +++ b/Utilities/StringFunctions.cpp @@ -271,6 +271,14 @@ namespace StringFunctions return res; } + template <> + std::vector GetValueFromStream>(std::istream& _is) + { + std::vector res; + std::copy(std::istream_iterator{ _is }, std::istream_iterator{}, std::back_inserter(res)); + return res; + } + template <> std::vector GetValueFromStream>(std::istream& _is) { @@ -339,4 +347,15 @@ namespace StringFunctions return _init; return GenerateUniqueKey(_existing, _length); } + + // Returns a name consisting of _namingBase + number not yet in _existing + std::string GenerateUniqueName(const std::string& _namingBase, const std::vector& _existing) + { + int i = 1; + while (true) + { + std::string name = _namingBase + " " + std::to_string(i++); + if (std::find(_existing.begin(), _existing.end(), name) == _existing.end()) return name; + } + } } diff --git a/Utilities/StringFunctions.h b/Utilities/StringFunctions.h index 3d701660..5384b31b 100644 --- a/Utilities/StringFunctions.h +++ b/Utilities/StringFunctions.h @@ -63,6 +63,7 @@ namespace StringFunctions template<> double GetValueFromStream(std::istream& _is); // Returns the next value from the stream and advances stream's iterator correspondingly. Overload for double type. template<> std::string GetValueFromStream(std::istream& _is); // Returns the next value from the stream and advances stream's iterator correspondingly. Overload for string type. template<> std::vector GetValueFromStream(std::istream& _is); // Returns the next value from the stream and advances stream's iterator correspondingly. Overload for vector. + template<> std::vector GetValueFromStream(std::istream& _is); // Returns the next value from the stream and advances stream's iterator correspondingly. Overload for vector. template<> std::vector GetValueFromStream(std::istream& _is); // Returns the next value from the stream and advances stream's iterator correspondingly. Overload for vector. template std::enable_if_t, T> GetEnumFromStream(std::istream& _is) // Returns the next value from the stream and advances stream's iterator correspondingly. Version for enum types. @@ -82,4 +83,6 @@ namespace StringFunctions std::string GenerateUniqueKey(const std::vector& _existing, size_t _length = 20); // Returns a string with the specified length, which will be unique among the set of existing strings. std::string GenerateUniqueKey(const std::string& _init, const std::vector& _existing, size_t _length = 20); + // Returns a name consisting of _namingBase + number not yet in _existing + std::string GenerateUniqueName(const std::string& _namingBase, const std::vector& _existing); } diff --git a/Utilities/Utilities.vcxproj b/Utilities/Utilities.vcxproj index 8230fafe..615de52d 100644 --- a/Utilities/Utilities.vcxproj +++ b/Utilities/Utilities.vcxproj @@ -119,8 +119,10 @@ + + diff --git a/Utilities/Utilities.vcxproj.filters b/Utilities/Utilities.vcxproj.filters index 71b74cf0..1a50c0d0 100644 --- a/Utilities/Utilities.vcxproj.filters +++ b/Utilities/Utilities.vcxproj.filters @@ -63,12 +63,18 @@ Header Files + + Header Files + Header Files Header Files + + Header Files +