diff --git a/.gitignore b/.gitignore index 0f18e87edacf0c88a6e61d1d31dd60b24e473ab9..d9722cfa618a922472a7dede3df8d593bf4e3ab4 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ build*/ *.swp *.gch *.csv +!/scenariotest/simulink_test/*.csv *.diff *.mat !/src/unittests/container/*.mat @@ -40,3 +41,5 @@ __pycache__/ !/scenariotest/standalone_test/*.csv !/scenariotest/simulink_test/reference/*/*.mat !/scenarios/*/*.csv +secrets/ +testing/* diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f8192aceb096d535ccdf083a90db73c703744023..6f18ae8c6175d372b9c5b3e963cce800f721e417 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,158 +1,273 @@ +# define stages stages: - - build_framework - - build - - test - - docs - - pages + - build-docker + - build-framework + - build + - test + - docs + - deploy-docs + - build-interactive-docker + +# configure workflow +workflow: + rules: + - if: '$CI_COMMIT_BRANCH == "master"' + - if: '$CI_COMMIT_BRANCH == "web"' + - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' + +# set defaults +default: + tags: [ 'docker' ] + +# set varialbes +variables: + DOCKER_BUILDKIT: 1 + DOCKER_DRIVER: overlay2 + IMAGE_TAG_LINUX_COMPILE: "${CI_REGISTRY_IMAGE}:${CI_COMMIT_REF_SLUG}_linux_compile" + IMAGE_TAG_LINUX_TEST: "${CI_REGISTRY_IMAGE}:${CI_COMMIT_REF_SLUG}_linux_test" + IMAGE_TAG_LINUX_INTERACTIVE: "${CI_REGISTRY_IMAGE}:${CI_COMMIT_REF_SLUG}_linux_interactive" + IMAGE_TAG_LINUX_INTERACTIVE_MATLAB: "${CI_REGISTRY_IMAGE}:${CI_COMMIT_REF_SLUG}_linux_interactive_matlab" + IMAGE_TAG_WINDOWSCC_COMPILE: "${CI_REGISTRY_IMAGE}:${CI_COMMIT_REF_SLUG}_windowscc_compile" + +.ccache_init: &ccache_init + before_script: + - export PATH=/usr/lib/ccache:$PATH + - export CCACHE_BASEDIR="${CI_PROJECT_DIR}" + - export CCACHE_DIR="${CI_PROJECT_DIR}/ccache" + - mkdir -p ${CI_PROJECT_DIR}/ccache + cache: + key: "$TARGET_OS" + paths: + - ccache/ + +docker-retag-images: + image: docker:20.10 + stage: build-docker + rules: + - changes: + - docker/* + when: never + - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' + before_script: + - docker login -u $CI_REGISTRY_USER -p $CI_JOB_TOKEN $CI_REGISTRY + script: + - export CI_MERGE_REQUEST_TARGET_BRANCH_SLUG=$(echo -n ${CI_MERGE_REQUEST_TARGET_BRANCH_NAME} | tr [:upper:] [:lower:] | tr -c [:alnum:] '-') + - 'docker tag "${CI_REGISTRY_IMAGE}:${CI_MERGE_REQUEST_TARGET_BRANCH_SLUG}_linux_compile" $IMAGE_TAG_LINUX_COMPILE || :' + - 'docker tag "${CI_REGISTRY_IMAGE}:${CI_MERGE_REQUEST_TARGET_BRANCH_SLUG}_linux_test" $IMAGE_TAG_LINUX_TEST || :' + - 'docker tag "${CI_REGISTRY_IMAGE}:${CI_MERGE_REQUEST_TARGET_BRANCH_SLUG}_windowscc_compile" $IMAGE_TAG_WINDOWSCC_COMPILE || :' + - 'docker push $IMAGE_TAG_LINUX_COMPILE || :' + - 'docker push $IMAGE_TAG_LINUX_TEST || :' + - 'docker push $IMAGE_TAG_WINDOWSCC_COMPILE || :' + +# build docker image and push it into GitLab container registry +docker-build-linux-compile: + # Use the official docker image. + image: docker:20.10 + stage: build-docker + rules: + - changes: + - docker/* + before_script: + - docker login -u $CI_REGISTRY_USER -p $CI_JOB_TOKEN $CI_REGISTRY + script: + - docker build docker --target iseaframelinux --cache-from $IMAGE_TAG_LINUX_COMPILE --tag $IMAGE_TAG_LINUX_COMPILE --build-arg BASE_IMAGE="base" + - docker push $IMAGE_TAG_LINUX_COMPILE + +# build docker image and push it into GitLab container registry +docker-build-linux-test: + # Use the official docker image. + image: docker:20.10 + stage: build-docker + rules: + - changes: + - docker/* + needs: [ "docker-build-linux-compile" ] + before_script: + - docker login -u $CI_REGISTRY_USER -p $CI_JOB_TOKEN $CI_REGISTRY + script: + - docker tag $IMAGE_TAG_LINUX_COMPILE $IMAGE_TAG_LINUX_TEST + - docker push $IMAGE_TAG_LINUX_TEST + +docker-build-windowscc-compile: + # Use the official docker image. + image: docker:20.10 + stage: build-docker + rules: + - changes: + - docker/* + before_script: + - docker login -u $CI_REGISTRY_USER -p $CI_JOB_TOKEN $CI_REGISTRY + script: + - docker build docker --target iseaframecc --cache-from $IMAGE_TAG_WINDOWSCC_COMPILE --tag $IMAGE_TAG_WINDOWSCC_COMPILE --build-arg BASE_IMAGE="base" + - docker push $IMAGE_TAG_WINDOWSCC_COMPILE linux_compile: - stage: build_framework + stage: build-framework + image: $IMAGE_TAG_LINUX_COMPILE + variables: + TARGET_OS: "linux" + needs: + - job: docker-build-linux-compile + optional: true + - job: docker-retag-images + optional: true artifacts: paths: - - buildReleaseLinux - - src/exceptions/xmlData.cpp - - src/version/version.cpp - - src/version/version.h + - buildReleaseLinux + - src/exceptions/xmlData.cpp + - src/version/version.cpp + - src/version/version.h expire_in: 1 week + <<: *ccache_init script: - - ./buildtools/make_release.sh -c -b buildReleaseLinux ./ ; cd buildReleaseLinux ; make -j32 framework unittests - only: - - master - - web - tags: - - linux + - ./buildtools/make_release.sh -m -c -b buildReleaseLinux ./ ; cd buildReleaseLinux ; make -j32 framework unittests windows_compile: - stage: build_framework + stage: build-framework + image: $IMAGE_TAG_WINDOWSCC_COMPILE + variables: + TARGET_OS: "windows" + needs: + - job: docker-build-windowscc-compile + optional: true + - job: docker-retag-images + optional: true artifacts: paths: - - buildReleaseWindows + - buildReleaseWindows + - src/exceptions/xmlData.cpp + - src/version/version.cpp + - src/version/version.h expire_in: 1 week + <<: *ccache_init script: - - ./buildtools/make_release.sh -w -c -b buildReleaseWindows ./ ; cd buildReleaseWindows ; make -j32 framework unittests - only: - - master - - web - tags: - - linux + - ./buildtools/make_release.sh -m -w -c -b buildReleaseWindows ./ ; cd buildReleaseWindows ; make -j32 ISEAFrameNumeric linux_standalones: stage: build + image: $IMAGE_TAG_LINUX_COMPILE + variables: + TARGET_OS: "linux" + needs: [ "linux_compile" ] artifacts: paths: - - buildReleaseLinux/standalones + - buildReleaseLinux/standalones + <<: *ccache_init script: - cd buildReleaseLinux ; make -j32 standalones - only: - - master - - web - tags: - - linux windows_standalones: stage: build + image: $IMAGE_TAG_WINDOWSCC_COMPILE + variables: + TARGET_OS: "windows" + needs: [ "windows_compile" ] artifacts: paths: - - buildReleaseWindows/standalones + - buildReleaseWindows/standalones + <<: *ccache_init script: - cd buildReleaseWindows ; make -j32 standalones - only: - - master - - web - tags: - - linux - -windows_simulink_converter: - stage: build - artifacts: - paths: - - buildReleaseWindows/simulinkConverter - script: - - cd buildReleaseWindows ; make -j32 simulinkConverter - only: - - master - - web - tags: - - linux unittest_numeric: stage: test + image: $IMAGE_TAG_LINUX_TEST + needs: + - linux_compile + - job: docker-build-linux-test + optional: True + - job: docker-retag-images + optional: true script: - cd buildReleaseLinux/unittest; ./unittestNumeric - only: - - master - - web - tags: - - linux unittest_symbolic: stage: test + image: $IMAGE_TAG_LINUX_TEST + needs: + - linux_compile + - job: docker-build-linux-test + optional: True + - job: docker-retag-images + optional: true script: - cd buildReleaseLinux/unittest; ./unittestSymbolic - only: - - master - - web - tags: - - linux unittest_valgrind: stage: test + image: $IMAGE_TAG_LINUX_TEST + needs: + - linux_compile + - job: docker-build-linux-test + optional: True + - job: docker-retag-images + optional: true script: - cd buildReleaseLinux/unittest/; ../../buildtools/valgrind.sh - only: - - master - - web - tags: - - linux standalone_test: stage: test + image: $IMAGE_TAG_LINUX_TEST + needs: + - linux_standalones + - job: docker-build-linux-test + optional: True + - job: docker-retag-images + optional: true artifacts: paths: - - scenariotest/standalone_test/output.txt + - scenariotest/standalone_test/output.txt expire_in: 1 week script: - - cd scenariotest/standalone_test/; ./runTests.sh ../../buildReleaseLinux/standalones | tee output.txt - only: - - master - - web - tags: - - linux + - set -o pipefail ; cd scenariotest/standalone_test/; ./runTests.sh ../../buildReleaseLinux/standalones | tee output.txt documentation: stage: docs + image: $IMAGE_TAG_LINUX_COMPILE + needs: [ "linux_compile" ] artifacts: paths: - - buildReleaseLinux/docRelease/html + - buildReleaseLinux/docRelease/html script: - - cd buildReleaseLinux ; make -j32 docRelease - only: - - master - - web - tags: - - linux + - cd buildReleaseLinux + - set -o pipefail ; make -j32 docRelease | tee output.txt + - (! grep "^error:" output.txt) development_documentation: stage: docs + image: $IMAGE_TAG_LINUX_COMPILE + needs: [ "linux_compile" ] artifacts: paths: - - buildReleaseLinux/doc/html + - buildReleaseLinux/doc/html script: - - cd buildReleaseLinux ; make -j32 doc - only: - - master - - web - tags: - - linux + - cd buildReleaseLinux + - set -o pipefail ; make -j32 doc | tee output.txt + - (! grep "^error:" output.txt) pages: - stage: pages + stage: deploy-docs + image: alpine:latest + needs: [ "development_documentation" ] + rules: + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH artifacts: paths: - public script: - - cp -r buildReleaseLinux/docRelease/html public - only: - - master - tags: - - linux + - cp -r buildReleaseLinux/doc/html public + +# build docker image and push it into GitLab container registry +docker-build-linux-interactive: + # Use the official docker image. + image: docker:20.10 + stage: build-interactive-docker + needs: [ "linux_standalones" ] + before_script: + - docker login -u $CI_REGISTRY_USER -p $CI_JOB_TOKEN $CI_REGISTRY + script: + - mkdir -p docker/executables + - cp -r buildReleaseLinux/standalones/* docker/executables + - mkdir -p docker/sFunctions + - docker build docker --target iseaframeinteractive --cache-from $IMAGE_TAG_LINUX_INTERACTIVE --tag $IMAGE_TAG_LINUX_INTERACTIVE --build-arg BASE_IMAGE="base" + - docker push $IMAGE_TAG_LINUX_INTERACTIVE diff --git a/CHANGELOG b/CHANGELOG index 3bbfd1270263f97ca62af28a69d3ec2ca46a8dcf..373da846532f13e4c2229a82a42337f060192134 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,8 @@ +Version 2.25.0 +=========== +- Add MaxAlphaCapacity, MaxAlphaResistance, MaxBetaCapacity, and MaxBetaResistance XML parameters to specify maximum aging coefficients +- Add XML options MaximalOperationalCellVoltageV and MinimalOperationalCellVoltageV to skip parts of the current profile that would over- or undercharge a cell + Version 2.24.1 =========== - Fix S-functions build for windows diff --git a/CMakeLists.txt b/CMakeLists.txt index 78cb9095297c2a1ee3a3a4cb6975798237669b3e..fdac00d0818f9637720205a8f2defe2409a479de 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,9 +5,9 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/") cmake_policy(SET CMP0009 NEW) set(ISEAFrameVERSION_MAJOR 2) -set(ISEAFrameVERSION_MINOR 24) -set(ISEAFramePATCH_LEVEL 1) -set(ISEAFrameNAME "misc") +set(ISEAFrameVERSION_MINOR 25) +set(ISEAFramePATCH_LEVEL 0) +set(ISEAFrameNAME "max_aging") set(ISEAFrameVERSION "${ISEAFrameVERSION_MAJOR}.${ISEAFrameVERSION_MINOR}.${ISEAFramePATCH_LEVEL}" ) diff --git a/buildtools/make_release.sh b/buildtools/make_release.sh index d9caa603c25de033305c2ab4bbc3af60646efa7d..8c6c03315471b6839028143da6aaf82efecd110a 100755 --- a/buildtools/make_release.sh +++ b/buildtools/make_release.sh @@ -26,6 +26,9 @@ function PrintHelp PrintMessage "-b <builddir>\t\tSpecify the build dir. Default is \"build\"" PrintMessage "-c\t\tOnly configure, do not start the build process." PrintMessage "-j <n>\t\tUse n threads for building. Default is 20." + PrintMessage "-m\t\tDo not include Matlab-dependent builds" + PrintMessage "-s\t\tDo not include s-functions" + PrintMessage "-e <e>\t\tAppend e to cmake command line options. Default is ''." } function RunCMake @@ -43,7 +46,18 @@ function RunCMake CMAKE_OPTIONS="$CMAKE_OPTIONS -DCMAKE_BUILD_TYPE:STRING=Release -DARCH_TYPE:STRING=64 -DBUILD_AGING:BOOL=ON -DBUILD_NUMERIC:BOOL=ON -DBUILD_SYMBOLIC:BOOL=ON -DBUILD_UNITTESTS:BOOL=ON -DBUILD_DOCS:BOOL=ON -DCREATE_RELEASE_DIRS:BOOL=ON" CMAKE_OPTIONS="$CMAKE_OPTIONS -DBUILD_VISUALIZER:BOOL=ON -DBUILD_DOT_EXPORT:BOOL=ON -DBUILD_QUICKVERIFICATION:BOOL=ON -DBUILD_SVG_EXPORT:BOOL=ON -DBUILD_ELECTRICAL_SIMULATION:BOOL=ON -DBUILD_THERMAL_SIMULATION:BOOL=ON -DBUILD_THERMAL_ELECTRICAL_SIMULATION:BOOL=ON -DBUILD_AGING_SIMULATION:BOOL=ON -DBUILD_GETTOTALCAPACITY:BOOL=ON" CMAKE_OPTIONS="$CMAKE_OPTIONS -DBUILD_EIGENWERTE:BOOL=ON -DBUILD_SYMBOLICOPTIMIZATION:BOOL=ON -DBUILD_SYMBOLIC_2_TEX:BOOL=ON -DBUILD_SYSTEM_2_TEX:BOOL=ON -DBUILD_SYSTEM_2_MATLAB:BOOL=ON -DBUILD_SYSTEM_2_SYMBOLIC:BOOL=ON" - CMAKE_OPTIONS="$CMAKE_OPTIONS -DBUILD_S_FUNCTIONS:BOOL=ON -DBUILD_SIMULINK_MATRIX_MODEL:BOOL=ON" + if [ $MATLAB -eq 1 ] + then + if [ $SFUNCTIONS -eq 1 ] + then + CMAKE_OPTIONS="$CMAKE_OPTIONS -DBUILD_S_FUNCTIONS:BOOL=ON -DBUILD_SIMULINK_MATRIX_MODEL:BOOL=ON" + else + CMAKE_OPTIONS="$CMAKE_OPTIONS -DBUILD_S_FUNCTIONS:BOOL=OFF -DBUILD_SIMULINK_MATRIX_MODEL:BOOL=ON" + fi + else + CMAKE_OPTIONS="$CMAKE_OPTIONS -DBUILD_S_FUNCTIONS:BOOL=OFF -DBUILD_SIMULINK_MATRIX_MODEL:BOOL=OFF" + fi + CMAKE_OPTIONS="$CMAKE_OPTIONS $CMAKE_EXTRA_OPTIONS" cmake $CMAKE_OPTIONS .. cmake $CMAKE_OPTIONS .. @@ -66,7 +80,9 @@ function main ONLY_CONFIGURE=0 BUILDDIR=build THREADS=20 - while getopts "hwb:cj:" opt; do + MATLAB=1 + SFUNCTIONS=1 + while getopts "hwb:cj:e:ms" opt; do case "$opt" in h) PrintHelp exit 0 @@ -79,6 +95,12 @@ function main ;; j) THREADS=$OPTARG ;; + m) MATLAB=0 + ;; + s) SFUNCTIONS=0 + ;; + e) CMAKE_EXTRA_OPTIONS=$OPTARG + ;; esac done @@ -124,4 +146,4 @@ function main fi } -main $@ +main "$@" diff --git a/cmake/FindMATIO.cmake b/cmake/FindMATIO.cmake index f32360f9c09311b183ba0429a24e138907a8eccd..bc9db06e05bd681506e074eafacb0153bbd5f6f8 100644 --- a/cmake/FindMATIO.cmake +++ b/cmake/FindMATIO.cmake @@ -12,7 +12,7 @@ find_path( find_library( MATIO_LIBRARY NAMES matio${ARCH_TYPE} libmatio${ARCH_TYPE} matio libmatio - PATHS ${FRAMEWORK_EXTENSION_FOLDER}/lib/ $ENV{HOME}/lib) + PATHS ${FRAMEWORK_EXTENSION_FOLDER}/lib/ ${FRAMEWORK_EXTENSION_FOLDER}/lib/64 $ENV{HOME}/lib) mark_as_advanced(MATIO_INCLUDE_DIR) mark_as_advanced(MATIO_LIBRARY) diff --git a/docker/Docker.md b/docker/Docker.md new file mode 100644 index 0000000000000000000000000000000000000000..6668e4ad0d5f8184b6855ee2a9eab9d579ae4548 --- /dev/null +++ b/docker/Docker.md @@ -0,0 +1,20 @@ +## Commands for local use of the docker environment. + +Build docker image + +'DOCKER_BUILDKIT=1 docker build . -t iseaframe_cicd:latest \ +--secret id=MATLAB_LICENSE_KEY,src=secrets/MATLAB_LICENSE_KEY.txt \ +--secret id=MATLAB_NETWORK_LICENSE,src=secrets/MATLAB_NETWORK_LICENSE.txt \ +--secret id=MATLAB_UNIX_NETRC,src=secrets/MATLAB_UNIX_NETRC.txt \ +--secret id=MATLAB_WIN_NETRC,src=secrets/MATLAB_WIN_NETRC.txt \ +--secret id=FRAMEWORKEXTENSIONS_NETRC,src=secrets/FRAMEWORKEXTENSIONS_NETRC.txt \ +--progress=plain' + +Build local docker image + +'DOCKER_BUILDKIT=1 docker build . -t iseaframe_cicd:local -f Dockerfile.local' + +Run local docker image + +'docker run --rm -it iseaframe_cicd:local' + diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..1c738cac0b1efd39006d90b2fa4732c8236d045e --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,200 @@ +ARG BASE_IMAGE=base + +FROM phusion/baseimage:hirsute AS iseaframe-base + +FROM mathworks/matlab:r2020b AS iseaframe-matlab + +FROM iseaframe-${BASE_IMAGE} AS iseaframebase + +ARG DEBIAN_FRONTEND=noninteractive + + +# Set locale environment +ENV LC_ALL=C.UTF-8 \ + LANG=C.UTF-8 \ + LANGUAGE=C.UTF-8 + +# install base packages +RUN set -ex ; \ + apt-get update ; \ + apt-get -y -qq install --no-install-recommends \ + build-essential \ + cxxtest \ + doxygen \ + g++ \ + gcc \ + git \ + make \ + python3 \ + python3-pip \ + cmake \ + libeigen3-dev \ + libmatio-dev \ + libarmadillo-dev \ + valgrind \ + graphviz ; \ + apt-get -y -qq install --no-install-recommends ccache ; \ + rm -rf /var/lib/apt/lists/* + +# install python packages +RUN pip install --no-cache-dir numpy matplotlib scipy + +FROM iseaframebase AS iseaframelinux + +# noop if base=matlab, needed otherwise +COPY --from=iseaframe-matlab /opt/matlab/R2020b/appdata/version.xml /usr/local/MATLAB/R2020b/appdata/version.xml +COPY --from=iseaframe-matlab /opt/matlab/R2020b/extern /usr/local/MATLAB/R2020b/extern/ +COPY --from=iseaframe-matlab /opt/matlab/R2020b/bin/mexext /usr/local/MATLAB/R2020b/bin/ +COPY --from=iseaframe-matlab /opt/matlab/R2020b/bin/glnxa64/libmat.so /usr/local/MATLAB/R2020b/bin/glnxa64/ +COPY --from=iseaframe-matlab /opt/matlab/R2020b/bin/glnxa64/libmex.so /usr/local/MATLAB/R2020b/bin/glnxa64/ +COPY --from=iseaframe-matlab /opt/matlab/R2020b/bin/glnxa64/libmx.so /usr/local/MATLAB/R2020b/bin/glnxa64/ + +# lbzip2 package in ubuntu hirsute is broken https://bugs.launchpad.net/ubuntu/+source/lbzip2/+bug/1926092 +# temporarily installed from focal repo + +# install boost +RUN set -ex; \ + cp /etc/apt/sources.list /etc/apt/sources.list.bu ; \ + echo "deb http://cz.archive.ubuntu.com/ubuntu focal main universe" > /etc/apt/sources.list ; \ + apt-get update; \ + apt-get install -y --no-install-recommends \ + wget \ + lbzip2 ; \ + mkdir -p /usr/src/boost; \ + cd /usr/src; \ + wget -O boost.tar.bz2 https://boostorg.jfrog.io/artifactory/main/release/1.67.0/source/boost_1_67_0.tar.bz2; \ + tar -I lbzip2 -xf boost.tar.bz2 -C boost --strip-components=1; \ + cd boost; \ + ./bootstrap.sh; \ + ./b2 install -j 32; \ + cd ..; \ + rm -r boost; \ + rm boost.tar.bz2; \ + apt-get autoremove -y wget lbzip2 ; \ + mv /etc/apt/sources.list.bu /etc/apt/sources.list ; \ + rm -rf /var/lib/apt/lists/* + + +FROM iseaframebase AS iseaframecc + +RUN set -ex ; \ + apt-get update ; \ + apt-get -y -qq install --no-install-recommends \ + g++-mingw-w64 ; \ + rm -rf /var/lib/apt/lists/* ; \ + cd /usr/lib/ccache ; \ + ln -s $(which ccache) i686-w64-mingw32-gcc-posix ; \ + ln -s $(which ccache) i686-w64-mingw32-g++-posix ; \ + ln -s $(which ccache) i686-w64-mingw32-windres ; \ + ln -s $(which ccache) x86_64-w64-mingw32-g++-posix ; \ + ln -s $(which ccache) x86_64-w64-mingw32-gcc-posix ; \ + ln -s $(which ccache) x86_64-w64-mingw32-windres + +# lbzip2 package in ubuntu hirsute is broken https://bugs.launchpad.net/ubuntu/+source/lbzip2/+bug/1926092 +# temporarily installed from focal repo + +# install boost +COPY patches/boost/gcc.jam.patch /usr/src/patches/boost/gcc.jam.patch +COPY patches/boost/mc.jam.patch /usr/src/patches/boost/mc.jam.patch +RUN set -ex; \ + cp /etc/apt/sources.list /etc/apt/sources.list.bu ; \ + echo "deb http://cz.archive.ubuntu.com/ubuntu focal main universe" > /etc/apt/sources.list ; \ + apt-get update; \ + apt-get install -y --no-install-recommends \ + wget \ + patch \ + lbzip2 ; \ + mkdir -p /usr/src/boost; \ + cd /usr/src; \ + wget -O boost.tar.bz2 https://boostorg.jfrog.io/artifactory/main/release/1.71.0/source/boost_1_71_0.tar.bz2; \ + tar -I lbzip2 -xf boost.tar.bz2 -C boost --strip-components=1; \ + cd boost; \ + patch /usr/src/boost/tools/build/src/tools/gcc.jam /usr/src/patches/boost/gcc.jam.patch ; \ + patch /usr/src/boost/tools/build/src/tools/mc.jam /usr/src/patches/boost/mc.jam.patch ; \ + echo "using gcc : mingw : x86_64-w64-mingw32-g++-posix ;" > user-config.jam; \ + ./bootstrap.sh mingw; \ + ./b2 --user-config=./user-config.jam toolset=gcc-mingw mc-compiler=windmc target-os=windows variant=release address-model=64 stage -j $(nproc) || :; \ + mkdir -p /usr/x86_64-w64-mingw32/FrameworkExtensions/boost; \ + mkdir -p /usr/x86_64-w64-mingw32/FrameworkExtensions/include; \ + mkdir -p /usr/x86_64-w64-mingw32/FrameworkExtensions/lib; \ + cp -R /usr/src/boost/boost /usr/x86_64-w64-mingw32/FrameworkExtensions/include/boost; \ + cp stage/lib/* /usr/x86_64-w64-mingw32/FrameworkExtensions/lib/; \ + cd ..; \ + rm -r patches; \ + rm -r boost; \ + rm boost.tar.bz2; \ + apt-get autoremove -y wget patch lbzip2 ; \ + mv /etc/apt/sources.list.bu /etc/apt/sources.list ; \ + rm -rf /var/lib/apt/lists/* + +# install zlib +COPY ToolchainWin64.cmake /usr/src/toolchain_files/ToolchainWin64.cmake +RUN cd /usr/src ; \ + git clone https://github.com/madler/zlib.git ; \ + mkdir zlib/build ; \ + cd zlib/build ; \ + cmake .. -DCMAKE_TOOLCHAIN_FILE=/usr/src/toolchain_files/ToolchainWin64.cmake ; \ + make -j8 ; \ + make install ; \ + mkdir -p /usr/x86_64-w64-mingw32/FrameworkExtensions/lib/64/ ; \ + cp libzlib.dll /usr/x86_64-w64-mingw32/FrameworkExtensions/lib/64/ + +# install matio +RUN cd /usr/src ; \ + git clone https://github.com/tbeu/matio.git ; \ + mkdir matio/build ; \ + cd matio/build ; \ + cmake .. -DCMAKE_TOOLCHAIN_FILE=/usr/src/toolchain_files/ToolchainWin64.cmake -DMATIO_MAT73:BOOL=OFF -DMATIO_WITH_HDF5:BOOL=OFF -DMATIO_SHARED:BOOL=OFF ; \ + make -j8 ; \ + make install ; \ + cp libmatio.a /usr/x86_64-w64-mingw32/FrameworkExtensions/lib/libmatio64.lib ; \ + mkdir -p /usr/x86_64-w64-mingw32/FrameworkExtensions/include/ ; \ + cp ../src/*.h /usr/x86_64-w64-mingw32/FrameworkExtensions/include/ ; \ + cp ./src/*.h /usr/x86_64-w64-mingw32/FrameworkExtensions/include/ + +RUN cp /usr/x86_64-w64-mingw32/lib/libwinpthread-1.dll /usr/x86_64-w64-mingw32/FrameworkExtensions/lib/64/libwinpthread-1.dll ; \ + cp -r /usr/include/eigen3 /usr/x86_64-w64-mingw32/FrameworkExtensions/include/eigen3 ; \ + cp -r /usr/include/armadillo_bits /usr/x86_64-w64-mingw32/FrameworkExtensions/include/armadillo_bits ; \ + cp /usr/include/armadillo /usr/x86_64-w64-mingw32/FrameworkExtensions/include/armadillo + +FROM iseaframelinux AS iseaframedev +RUN set -ex ; \ + apt-get update ; \ + apt-get -y install --no-install-recommends \ + liblapack-dev \ + libmpich-dev \ + libopenblas-dev \ + clang \ + clang-format \ + clang-tidy \ + git-lfs ; \ + rm -rf /var/lib/apt/lists/* + +FROM iseaframedev AS iseaframeinteractive + +COPY set-home-permissions.sh /etc/my_init.d/set-home-permissions.sh + +RUN set -ex ; \ + useradd -m -s /bin/bash -G sudo,docker_env isea ; \ + echo "isea:docker" | chpasswd ; \ + echo "isea ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers ; \ + rm /etc/my_init.d/10_syslog-ng.init ; \ + chmod +x /etc/my_init.d/set-home-permissions.sh ; \ + ldconfig + +COPY --chown=root:root executables /usr/local/bin/ +COPY --chown=isea:isea sFunctions /opt/iseaframe/ + +USER isea +ENV ISEA_HOME /home/isea +RUN set -ex ; \ + touch $ISEA_HOME/.sudo_as_admin_successful ; \ + mkdir $ISEA_HOME/shared +VOLUME /home/isea/shared + + + +WORKDIR /home/isea +USER root +ENTRYPOINT ["/sbin/my_init","--quiet","--","/sbin/setuser","isea","/bin/bash","-l","-c"] +CMD ["/bin/bash","-i"] diff --git a/docker/Dockerfile.local b/docker/Dockerfile.local new file mode 100644 index 0000000000000000000000000000000000000000..ae4f2ec3f65c548b1cf1ac7664a53eb0c2c8632b --- /dev/null +++ b/docker/Dockerfile.local @@ -0,0 +1,6 @@ +FROM iseaframe_cicd:latest + +COPY . /usr/src/iseaframe + +WORKDIR /usr/src/iseaframe + diff --git a/docker/ToolchainWin64.cmake b/docker/ToolchainWin64.cmake new file mode 100644 index 0000000000000000000000000000000000000000..81843f432d03c8d2938213704f123485833c63ad --- /dev/null +++ b/docker/ToolchainWin64.cmake @@ -0,0 +1,40 @@ +set(CMAKE_SYSTEM_NAME Windows) +set(CMAKE_SYSTEM_PROCESSOR "64") +set(ARCH_TYPE + "64" + CACHE STRING "") + +# which compilers to use for C and C++ +set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc-posix) +set(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++-posix) +set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres) + +# For static library creation the indexer should be run only once, e.g. by executing ranlib in the end. +# Hence, ar should be instructed to *not* index the static library. +set(CMAKE_STATIC_LINKER_FLAGS -S) + +# some variables are apparently not propagated from the toolchain file, but the +# cache should always work +set(TOOLCHAIN_COMPILE_OPTIONS + "-O2 -Wa,-mbig-obj -static -static-libgcc -static-libstdc++ -lgcc -lstdc++ -Wl,-Bstatic -lpthread" + CACHE STRING "Compile options specified by the toolchain file") +set(TOOLCHAIN_LINK_OPTIONS + "-Bstatic -static-libgcc -static-libstdc++" + CACHE STRING "Compile options specified by the toolchain file") + +# here is the target environment located +set(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32/FrameworkExtensions) + +set(Matlab_INCLUDE_DIRS + /usr/x86_64-w64-mingw32/matlab/include + CACHE STRING "Path to matlab header files") +file(GLOB LIBRARIES /usr/x86_64-w64-mingw32/matlab/lib/*.lib) +set(Matlab_LIBRARIES + ${LIBRARIES} + CACHE STRING "Path to matlab library files") + +# adjust the default behaviour of the FIND_XXX() commands: search headers and +# libraries in the target environment, search programs in the host environment +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/docker/patches/boost/gcc.jam.patch b/docker/patches/boost/gcc.jam.patch new file mode 100644 index 0000000000000000000000000000000000000000..4cb18c2517fa0b1ae093c12dcaf6692d2a8089c1 --- /dev/null +++ b/docker/patches/boost/gcc.jam.patch @@ -0,0 +1,10 @@ +--- gcc.jam.old 2022-04-06 14:06:18.807536645 +0200 ++++ gcc.jam.new 2022-04-06 14:26:20.709209341 +0200 +@@ -93,6 +93,7 @@ + import cygwin ; + import feature ; + import fortran ; ++import mc ; + import generators ; + import os ; + import pch ; diff --git a/docker/patches/boost/mc.jam.patch b/docker/patches/boost/mc.jam.patch new file mode 100644 index 0000000000000000000000000000000000000000..0823dd7ba7f3ced80d41685bced30d6355f2048c --- /dev/null +++ b/docker/patches/boost/mc.jam.patch @@ -0,0 +1,30 @@ +--- mc.jam.old 2021-10-01 09:58:27.815410417 +0200 ++++ mc.jam.new 2021-09-29 17:04:08.025418898 +0200 +@@ -17,6 +17,9 @@ + import type ; + import rc ; + ++feature.feature mc-compiler : mc windmc : propagated ; ++feature.set-default mc-compiler : mc ; ++ + rule init ( ) + { + } +@@ -36,9 +39,15 @@ + flags mc.compile MCFLAGS <mc-set-customer-bit>no : ; + flags mc.compile MCFLAGS <mc-set-customer-bit>yes : -c ; + +-generators.register-standard mc.compile : MC : H RC ; ++generators.register-standard mc.compile.mc : MC : H RC : <mc-compiler>mc ; ++generators.register-standard mc.compile.windmc : MC : H RC : <mc-compiler>windmc ; + +-actions compile ++actions compile.mc + { + mc $(MCFLAGS) -h "$(<[1]:DW)" -r "$(<[2]:DW)" "$(>:W)" + } ++ ++actions compile.windmc ++{ ++ windmc $(MCFLAGS) -h "$(<[1]:DW)" -r "$(<[2]:DW)" "$(>:W)" ++} diff --git a/docker/set-home-permissions.sh b/docker/set-home-permissions.sh new file mode 100644 index 0000000000000000000000000000000000000000..20a84a72eb3733a943321261998f9945764a6490 --- /dev/null +++ b/docker/set-home-permissions.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# Taken from the fenics project + +# User can pass e.g. --env HOST_UID=1003 so that UID in the container matches +# with the UID on the host. This is useful for Linux users, Mac and Windows +# already do transparent mapping of shared volumes. +if [ "$HOST_UID" ]; then + usermod -u $HOST_UID isea +fi +if [ "$HOST_GID" ]; then + groupmod -g $HOST_GID isea +fi +# This makes sure that all files in /home/isea are accessible by the user +# isea. We exclude the folder ~/shared to reduce IO out to the host. Docker +# for Mac, Docker for Windows and the UID/GID trick above should mean that file +# permissions work seamlessly now. +find /home/isea -maxdepth 1 | sed "1d" | grep -v "/home/isea/shared" | xargs chown -R isea:isea 2> /dev/null || true diff --git a/doxygen/Doxyfile.in b/doxygen/Doxyfile.in index e6e753639040745a48c964f2ed2d99f1bcc9b60d..7eee076780b376385ea0148b76bb0cf2f8876f25 100644 --- a/doxygen/Doxyfile.in +++ b/doxygen/Doxyfile.in @@ -1486,7 +1486,7 @@ FORMULA_TRANSPARENT = YES # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -USE_MATHJAX = NO +USE_MATHJAX = YES # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: @@ -1509,7 +1509,7 @@ MATHJAX_FORMAT = HTML-CSS # The default value is: http://cdn.mathjax.org/mathjax/latest. # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_RELPATH = http://www.mathjax.org/mathjax +MATHJAX_RELPATH = # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example diff --git a/doxygen/Doxyfile_release.in b/doxygen/Doxyfile_release.in index 41e1c9ddcbb3950dbbb638aa3c333fd52e64af4b..9f3a64ea12d329f7e63bf3d490c4413e14b4e28e 100644 --- a/doxygen/Doxyfile_release.in +++ b/doxygen/Doxyfile_release.in @@ -1480,7 +1480,7 @@ FORMULA_TRANSPARENT = YES # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -USE_MATHJAX = NO +USE_MATHJAX = YES # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: @@ -1503,7 +1503,7 @@ MATHJAX_FORMAT = HTML-CSS # The default value is: http://cdn.mathjax.org/mathjax/latest. # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_RELPATH = http://www.mathjax.org/mathjax +MATHJAX_RELPATH = # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example diff --git a/doxygen/aging_simulation.md b/doxygen/aging_simulation.md index 290d6e2dc8b80aab6260229e7289e82ad7c185c0..1d3fa6a60850ef2cb636846f26b72306c8335b19 100644 --- a/doxygen/aging_simulation.md +++ b/doxygen/aging_simulation.md @@ -134,6 +134,8 @@ FormulaCapacity | string | | Formula us FormulaResistance | string | | Formula used to calculate the value of alpha. The symbols V, T and SOC can be used for the cell's voltage, temperature and SOC MinAlphaCapacity | double | | Minimum value for the stress factor. If a lower value is calculated, this value is used instead. MinAlphaResistance | double | | Minimum value for the stress factor. If a lower value is calculated, this value is used instead. +MaxAlphaCapacity | double | | Maximum value for the stress factor. If a higher value is calculated, this value is used instead. +MaxAlphaResistance | double | | Maximum value for the stress factor. If a higher value is calculated, this value is used instead. InitialCapacityFactor | double | 0 - 1 | Initial value for the capacity factor. Optional, default = 1. InitialResistanceFactor | double | 0 - 1 | Initial value for the capacity factor. Optional, default = 1. @@ -150,6 +152,8 @@ FormulaCapacity | string | | Formula us FormulaResistance | string | | Formula used to calculate the value of beta. The symbols meanV, deltaDOD, meanSOC and meanI can be used for the cell's average voltage, depth of discharge, average SOC and average current MinBetaCapacity | double | | Minimum value for the stress factor. If a lower value is calculated, this value is used instead. MinBetaResistance | double | | Minimum value for the stress factor. If a lower value is calculated, this value is used instead. +MaxBetaCapacity | double | | Maximum value for the stress factor. If a higher value is calculated, this value is used instead. +MaxBetaResistance | double | | Maximum value for the stress factor. If a higher value is calculated, this value is used instead. InitialCapacityFactor | double | 0 - 1 | Initial value for the capacity factor. Optional, default = 1. InitialResistanceFactor | double | 0 - 1 | Initial value for the capacity factor. Optional, default = 1. diff --git a/doxygen/xmloptionen.md b/doxygen/xmloptionen.md index ecb67a7445dcc295acff607250a44c5a03fc49ee..24398f835bd58768f26917e0a8ebb8be664b6507 100644 --- a/doxygen/xmloptionen.md +++ b/doxygen/xmloptionen.md @@ -12,6 +12,8 @@ SocStopCriterion | % | 5.0 | Maximum va ThermalStopCriterionInDegreeC | °C | 5.0 | Maximum temperature change in any thermal state during a thermal simulation step before the electrcal simulation is reset. Cycles | int > 0 | 1 | Gives the number of times the current/power profile is executed by the [thermal-electrical standalone](xmlexecutable.html) SampleRate | Hz | 1.0e6 | Sample rate for the automatic simplification of fast time constants, see [automatic simplification](xmlvereinfachung.html) +MaximalOperationalCellVoltageV | V | no limit | Maximum voltage of the simulated cells. If any cell voltage goes above this limit, values from the current profile are skipped until a negative value / discharge is found. +MinimalOperationalCellVoltageV | V | no limit | Minimum voltage of the simulated cells. If any cell voltage goes below this limit, values from the current profile are skipped until a positive value / charge is found. Thermal model =============== diff --git a/src/aging/calendarian_aging.cpp b/src/aging/calendarian_aging.cpp index 9b32444fcdd22d74854370ddc143f105f868903a..edaf2c0b469851a6a34f0441034097af8bf320ba 100644 --- a/src/aging/calendarian_aging.cpp +++ b/src/aging/calendarian_aging.cpp @@ -6,12 +6,13 @@ namespace aging { CalendarianAging::CalendarianAging( const double agingStepTime, const double minAlphaCapacity, const double minAlphaResistance, + const double maxAlphaCapacity, const double maxAlphaResistance, const boost::shared_ptr< object::Object< double > >& alphaCapacity, const boost::shared_ptr< object::Object< double > >& alphaResistance, const double initialCapacityFactor, const double initialResistanceFactor, const bool isEnabled, const double timeExponent ) - : EmpiricalAging( agingStepTime, minAlphaCapacity, minAlphaResistance, alphaCapacity, alphaResistance, - initialCapacityFactor, initialResistanceFactor, isEnabled ) + : EmpiricalAging( agingStepTime, minAlphaCapacity, minAlphaResistance, maxAlphaCapacity, maxAlphaResistance, + alphaCapacity, alphaResistance, initialCapacityFactor, initialResistanceFactor, isEnabled ) , mTimeExponent( timeExponent ) , mActualVoltage( 0.0 ) , mActualTemperature( 0.0 ) @@ -39,10 +40,8 @@ void CalendarianAging::CalculateAging( const TwoportState& twoportState, double dt = mTimeValues[i] - previousTime; alphaCap = this->mCapacityStressFactor->GetValue(); alphaRes = this->mResistanceStressFactor->GetValue(); - if ( alphaCap < this->mMinStressFactorCapacity ) - alphaCap = this->mMinStressFactorCapacity; - if ( alphaRes < this->mMinStressFactorResistance ) - alphaRes = this->mMinStressFactorResistance; + alphaCap = clamp( alphaCap, this->mMinStressFactorCapacity, this->mMaxStressFactorCapacity ); + alphaRes = clamp( alphaRes, this->mMinStressFactorResistance, this->mMaxStressFactorResistance ); alphaCapSum += alphaCap * dt; alphaResSum += alphaRes * dt; previousTime = mTimeValues[i]; diff --git a/src/aging/calendarian_aging.h b/src/aging/calendarian_aging.h index 722d0bbf09951e6693f5e7aaf04413c85b3e0ec9..ce22b40918fbedc17b0e4071807ea024a6e6a5b1 100644 --- a/src/aging/calendarian_aging.h +++ b/src/aging/calendarian_aging.h @@ -29,6 +29,7 @@ class CalendarianAging : public EmpiricalAging public: /// Constructor CalendarianAging( const double agingStepTime, const double minAlphaCapacity, const double minAlphaResistance, + const double maxAlphaCapacity, const double maxAlphaResistance, const boost::shared_ptr< object::Object< double > >& alphaCapacity, const boost::shared_ptr< object::Object< double > >& alphaResistance, const double initialCapacityFactor, const double initialResistanceFactor, const bool isEnabled, const double timeExponent ); diff --git a/src/aging/cyclical_aging.cpp b/src/aging/cyclical_aging.cpp index 9907171ab54ccebaf752bd2bbb6e480fe165e0a2..a49976aaf531fc1786ec0a28a0e27e30721946e1 100644 --- a/src/aging/cyclical_aging.cpp +++ b/src/aging/cyclical_aging.cpp @@ -6,12 +6,13 @@ namespace aging { CyclicalAging::CyclicalAging( const double agingStepTime, const double minBetaCapacity, const double minBetaResistance, + const double maxBetaCapacity, const double maxBetaResistance, const boost::shared_ptr< object::Object< double > >& alphaCapacity, const boost::shared_ptr< object::Object< double > >& alphaResistance, const double initialCapacityFactor, const double initialResistanceFactor, const bool isEnabled, const double chargeThroughputExponentCapacity, const double chargeThroughputExponentResistance ) - : EmpiricalAging( agingStepTime, minBetaCapacity, minBetaResistance, alphaCapacity, alphaResistance, - initialCapacityFactor, initialResistanceFactor, isEnabled ) + : EmpiricalAging( agingStepTime, minBetaCapacity, minBetaResistance, maxBetaCapacity, maxBetaResistance, + alphaCapacity, alphaResistance, initialCapacityFactor, initialResistanceFactor, isEnabled ) , mChargeThroughputExponentCapacity( chargeThroughputExponentCapacity ) , mChargeThroughputExponentResistance( chargeThroughputExponentResistance ) , mActualDod( 0.0 ) @@ -50,6 +51,8 @@ void CyclicalAging::CalculateAging( const TwoportState& twoportState, double tim mActualVoltage = GetAverageVoltage( cycleStart, cycleEnd ); double betaCapacity = this->mCapacityStressFactor->GetValue(); double betaResistance = this->mResistanceStressFactor->GetValue(); + betaCapacity = clamp( betaCapacity, this->mMinStressFactorCapacity, this->mMaxStressFactorCapacity ); + betaResistance = clamp( betaResistance, this->mMinStressFactorResistance, this->mMaxStressFactorResistance ); if ( betaCapacity < this->mMinStressFactorCapacity ) betaCapacity = this->mMinStressFactorCapacity; if ( betaResistance < this->mMinStressFactorResistance ) diff --git a/src/aging/cyclical_aging.h b/src/aging/cyclical_aging.h index 769a67a3d49af549457525b7ffb2977538d10677..22d15513e8bbcb97cb2d8fdea6db4228aa964b8f 100644 --- a/src/aging/cyclical_aging.h +++ b/src/aging/cyclical_aging.h @@ -30,8 +30,8 @@ class CyclicalAging : public EmpiricalAging public: /// Constructor - CyclicalAging( const double agingStepTime, const double minBetaCapacity, const double minBetaResistance, - const boost::shared_ptr< object::Object< double > >& alphaCapacity, + CyclicalAging( const double agingStepTime, const double minBetaCapacity, const double minBetaResistance, const double maxBetaCapacity, + const double maxBetaResistance, const boost::shared_ptr< object::Object< double > >& alphaCapacity, const boost::shared_ptr< object::Object< double > >& alphaResistance, const double initialCapacityFactor, const double initialResistanceFactor, const bool isEnabled, const double chargeThroughputExponentCapacity, const double chargeThroughputExponentResistance ); diff --git a/src/aging/empirical_aging.cpp b/src/aging/empirical_aging.cpp index 6731f5d16cd34500914fdaf43db4e77b08e88663..74dec37ab106e8123bdf0b10cecb5da5da410085 100644 --- a/src/aging/empirical_aging.cpp +++ b/src/aging/empirical_aging.cpp @@ -2,6 +2,7 @@ namespace aging { EmpiricalAging::EmpiricalAging( const double agingStepTime, const double minStressFactorCapacity, const double minStressFactorResistance, + const double maxStressFactorCapacity, const double maxStressFactorResistance, const boost::shared_ptr< object::Object< double > >& capacityStressFactor, const boost::shared_ptr< object::Object< double > >& resistanceStressFactor, const double initialCapacityFactor, const double initialResistanceFactor, const bool isEnabled ) @@ -11,6 +12,8 @@ EmpiricalAging::EmpiricalAging( const double agingStepTime, const double minStre , mChargeLoss( 0.0 ) , mMinStressFactorCapacity( minStressFactorCapacity ) , mMinStressFactorResistance( minStressFactorResistance ) + , mMaxStressFactorCapacity( maxStressFactorCapacity ) + , mMaxStressFactorResistance( maxStressFactorResistance ) , mStressFactorCapacity( 0.0 ) , mStressFactorResistance( 0.0 ) , mCapacityStressFactor( capacityStressFactor ) @@ -24,4 +27,15 @@ void EmpiricalAging::CalculateChargeLoss( const TwoportState& twoportState, doub twoportState.mSocState->template GetInitialCapacity< state::SocGetFormat::AS >() * twoportState.mSocState->template GetValue< state::SocGetFormat::PERCENT >() / 100; } + +double EmpiricalAging::clamp( double value, double min, double max ) +{ + if ( value < min ) + return min; + else if ( value > max ) + return max; + return value; +} + + } // namespace aging diff --git a/src/aging/empirical_aging.h b/src/aging/empirical_aging.h index d95126ecb8b7cb6d5d8f43a0967316f0bb253529..0d91f955d6ab7a6e8f621e53ad8ad939e3138f3a 100644 --- a/src/aging/empirical_aging.h +++ b/src/aging/empirical_aging.h @@ -14,6 +14,7 @@ class EmpiricalAging : public AgingBase public: /// Constructor EmpiricalAging( const double agingStepTime, const double minStressFactorCapacity, const double minStressFactorResistance, + const double maxStressFactorCapacity, const double maxStressFactorResistance, const boost::shared_ptr< object::Object< double > >& capacityStressFactor, const boost::shared_ptr< object::Object< double > >& resistanceStressFactor, const double initialCapacityFactor, const double initialResistanceFactor, const bool isEnabled ); @@ -27,6 +28,8 @@ class EmpiricalAging : public AgingBase protected: virtual void CalculateChargeLoss( const TwoportState& twoportState, double previousCapFactor ); + // helper function, can be replaced by std::clamp in C++17 or newer + static double clamp( double value, double min, double max ); double mCapacityFactor; double mResistanceFactor; @@ -34,6 +37,8 @@ class EmpiricalAging : public AgingBase const double mMinStressFactorCapacity; const double mMinStressFactorResistance; + const double mMaxStressFactorCapacity; + const double mMaxStressFactorResistance; const std::string mFormulaStressFactorCapacity; const std::string mFormulaStressFactorResistance; diff --git a/src/electrical/electrical_simulation.h b/src/electrical/electrical_simulation.h index 34737a78e4bd7ac75ee5d8d62b05ee2c7664d870..704c855d573485ffd77743513198478eeb15e152 100644 --- a/src/electrical/electrical_simulation.h +++ b/src/electrical/electrical_simulation.h @@ -54,7 +54,7 @@ class ElectricalSimulation /// Returns true if current simulation step needs to end, if so it resets mDeltaTime for the next simulation step bool CheckLoopConditionAndSetDeltaTime( T currentChangeTime ); /// Returns true if mTime has exceeded mSimulationDuration - bool CheckIfSimulationTimeHasEnded(); + bool CheckIfSimulationTimeHasEnded() const; /// Gets the time passed since mLoopStartTime (mLoopStartTime is the start time of this simulation step) T GetCurrentSimulationStepTime() const; /// Executes actions needed at the end of a simulation step @@ -67,8 +67,12 @@ class ElectricalSimulation void ResetAllThermalStatesPowerDissipation(); /// Initializes stop criterions and sets the step start time void StartNewTimeStep(); - /// Returns true if SoC or power stop criterion is met + /// Checks true if any stop criterion is met bool IsStopCriterionFulfilled() const; + /// Returns true if SoC or power stop criterion is met + bool IsStopThermalCriterionFulfilled() const; + /// Returns true if voltage limits of cell elements are exceeded + bool IsStopElectricalCriterionFulfilled() const; /// Saves states if stop criterion of thermal simulation is triggered void SaveStatesForLaterReset(); /// Resets states and SoCs to states saved at a certain point of time @@ -109,6 +113,13 @@ class ElectricalSimulation T mStepStartTime; // Soc stop criterion double mSocStopCriterion; + // Voltage stop criterion + double mMinVoltageStopCriterion; + double mMaxVoltageStopCriterion; + + size_t mVoltageLimitDelay; + size_t mVoltageLimitCount; + // Stop criterion if following a power profile double mPowerStopCriterion; std::vector< std::vector< T > > mSocValuesSteps; @@ -132,6 +143,9 @@ ElectricalSimulation< Matrix, T, filterTypeChoice >::ElectricalSimulation( , mMaxSimulationStepDuration( maxSimulationStepDuration ) , mStepStartTime( 0.0 ) , mSocStopCriterion( socStopCriterion ) + , mMinVoltageStopCriterion( 0.0 ) + , mMaxVoltageStopCriterion( 10.0 ) + , mVoltageLimitDelay( 5 ) , mPowerStopCriterion( 0.0 ) , mNumberOfSteps( 0 ) { @@ -273,6 +287,19 @@ ElectricalSimulation< Matrix, T, filterTypeChoice >::ElectricalSimulation( if ( mSocStopCriterion <= 0.0 ) ErrorFunction< std::runtime_error >( __FUNCTION__, __LINE__, __FILE__, "SocStopCriterionInPercentNegative" ); } + // VoltageStopCriterion + if ( optionsNode->HasElementDirectChild( "MinimalOperationalCellVoltageV" ) ) + { + mMinVoltageStopCriterion = optionsNode->GetElementDoubleValue( "MinimalOperationalCellVoltageV" ); + if ( mMinVoltageStopCriterion < 0.0 ) + ErrorFunction< std::runtime_error >( __FUNCTION__, __LINE__, __FILE__, "MinimalVoltageCriterionIsNegative" ); + } + if ( optionsNode->HasElementDirectChild( "MaximalOperationalCellVoltageV" ) ) + { + mMaxVoltageStopCriterion = optionsNode->GetElementDoubleValue( "MaximalOperationalCellVoltageV" ); + if ( mMaxVoltageStopCriterion < 0.0 ) + ErrorFunction< std::runtime_error >( __FUNCTION__, __LINE__, __FILE__, "MinimalVoltageCriterionIsNegative" ); + } } template < typename Matrix, typename T, bool filterTypeChoice > @@ -307,7 +334,7 @@ bool ElectricalSimulation< Matrix, T, filterTypeChoice >::CheckLoopConditionAndS } template < typename Matrix, typename T, bool filterTypeChoice > -bool ElectricalSimulation< Matrix, T, filterTypeChoice >::CheckIfSimulationTimeHasEnded() +bool ElectricalSimulation< Matrix, T, filterTypeChoice >::CheckIfSimulationTimeHasEnded() const { return mTime >= mSimulationDuration; } @@ -356,10 +383,36 @@ void ElectricalSimulation< Matrix, T, filterTypeChoice >::StartNewTimeStep() #endif } + template < typename Matrix, typename T, bool filterTypeChoice > -bool ElectricalSimulation< Matrix, T, filterTypeChoice >::IsStopCriterionFulfilled() const +bool ElectricalSimulation< Matrix, T, filterTypeChoice >::IsStopElectricalCriterionFulfilled() const +{ + bool isStop = false; +#ifndef _SYMBOLIC_ + if ( mNumberOfSteps > mVoltageLimitDelay ) + { + // Check voltage + for ( size_t i = 0; i < mCellElements.size(); ++i ) + { + double cellVoltage = mCellElements[i]->GetVoltageValue(); + if ( cellVoltage > mMaxVoltageStopCriterion || cellVoltage < mMinVoltageStopCriterion ) + { + isStop = true; + break; + } + } + } +#endif + return isStop; +} + + +template < typename Matrix, typename T, bool filterTypeChoice > +bool ElectricalSimulation< Matrix, T, filterTypeChoice >::IsStopThermalCriterionFulfilled() const { bool isStop = false; + + // Check SOC Difference for ( size_t i = 0; i < mSocStates.size(); ++i ) { if ( fabs( mSocValuesSteps[0][i] - mSocStates[i]->GetValue() ) > mSocStopCriterion ) @@ -369,6 +422,7 @@ bool ElectricalSimulation< Matrix, T, filterTypeChoice >::IsStopCriterionFulfill } } + #ifndef _SYMBOLIC_ if ( mPowerStopCriterion > 0.0 ) { @@ -382,6 +436,12 @@ bool ElectricalSimulation< Matrix, T, filterTypeChoice >::IsStopCriterionFulfill return isStop; } +template < typename Matrix, typename T, bool filterTypeChoice > +bool ElectricalSimulation< Matrix, T, filterTypeChoice >::IsStopCriterionFulfilled() const +{ + return ( IsStopElectricalCriterionFulfilled() || IsStopThermalCriterionFulfilled() ); +} + template < typename Matrix, typename T, bool filterTypeChoice > void ElectricalSimulation< Matrix, T, filterTypeChoice >::SaveStatesForLaterReset() { diff --git a/src/electrical/twoport.cpp b/src/electrical/twoport.cpp index 6d4d355caaa576064a4824d1e08490dd40bc6216..a64028e9528c1de90c26a7c4f8ce28e2e08808d8 100644 --- a/src/electrical/twoport.cpp +++ b/src/electrical/twoport.cpp @@ -68,6 +68,18 @@ ScalarUnit TwoPort< T >::GetPowerValue() const return mPowerValue; } +template < typename T > +double TwoPort< T >::GetLostChargeAh() const +{ + return mLostChargeValue; +} + +template < typename T > +double TwoPort< T >::GetLostDischargeAh() const +{ + return mLostDischargeValue; +} + template < typename T > inline ScalarUnit ReturnFirstElement( T& mat ) @@ -103,6 +115,8 @@ TwoPort< T >::TwoPort( const bool observable, DataType dataValues ) , mCurrentValue( mDataStruct->mCurrentValue ) , mVoltageValue( mDataStruct->mVoltageValue ) , mPowerValue( mDataStruct->mPowerValue ) + , mLostChargeValue( 0.0 ) + , mLostDischargeValue( 0.0 ) , mStateSystemGroup( 0 ) , mObservable( observable ) { @@ -183,6 +197,23 @@ void TwoPort< T >::SetCurrent( const T current ) mVoltage.setZero(); } + +template < typename T > +void TwoPort< T >::AddRemainingLoadTime( const double lostTime ) +{ +#ifndef _SYMBOLIC_ + if ( mCurrentValue < 0 ) + { + mLostDischargeValue = mLostDischargeValue + abs( mCurrentValue * lostTime / 3600 ); + } + else + { + mLostChargeValue = mLostChargeValue + abs( mCurrentValue * lostTime / 3600 ); + } +#endif +} + + template < typename T > const T TwoPort< T >::GetCurrent() const { diff --git a/src/electrical/twoport.h b/src/electrical/twoport.h index 05fa261181c0a2bb6b95788c6648fd48013b909a..643d6d7fa6ff96a927ee9f4f70ee9cbeda2bdc76 100644 --- a/src/electrical/twoport.h +++ b/src/electrical/twoport.h @@ -83,6 +83,8 @@ class TwoPort ScalarUnit GetCurrentValue() const; ///< Returns the precalculated current ScalarUnit GetVoltageValue() const; ///< Returns the precalculated voltage ScalarUnit GetPowerValue() const; ///< Returns the precalculated power + double GetLostChargeAh() const; /// Returns the lost load in charge direction by changing the profile + double GetLostDischargeAh() const; /// Returns the lost load in dsicharge direction by changing the profile #ifndef _SYMBOLIC_ @@ -95,6 +97,7 @@ class TwoPort virtual const char* GetName() const; virtual void SetResistanceFactor( const double factor ); // Sets a factor which all resistances are multiplied by const DataType& GetElectricalData() const; + virtual void AddRemainingLoadTime( const double lostTime ); // Adds time to lost ah counter, used in root two port protected: /// Calculate the current of the previous simulation step. @@ -112,6 +115,10 @@ class TwoPort ScalarUnit& mVoltageValue; ScalarUnit& mPowerValue; + double mLostChargeValue; + double mLostDischargeValue; + + systm::StateSystemGroup< T >* mStateSystemGroup; bool mObservable; diff --git a/src/export/mex/CMakeLists.txt b/src/export/mex/CMakeLists.txt index 8b2be3a34a1990dfd4f301c603c2abd6ae07d7ca..73976998e3992178038dc04adf00e804ed2864a1 100644 --- a/src/export/mex/CMakeLists.txt +++ b/src/export/mex/CMakeLists.txt @@ -19,7 +19,7 @@ endif() if(BUILD_SIMULINK_MATRIX_MODEL) if(NOT Matlab_LIBRARIES) - find_package(Matlab REQUIRED COMPONENTS MAT_LIBRARY SIMULINK) + find_package(Matlab REQUIRED COMPONENTS MAT_LIBRARY) endif() function(create_mex mex_name sourcefile) diff --git a/src/factory/aging/aging_class_wrapper.h b/src/factory/aging/aging_class_wrapper.h index 19ef745e6a7b48115e8157c1120d22131198b7bd..86ad3fd94e1ba04469071bd2322b7fbed9678379 100644 --- a/src/factory/aging/aging_class_wrapper.h +++ b/src/factory/aging/aging_class_wrapper.h @@ -87,9 +87,9 @@ class AgingClassWrapper< aging::CalendarianAging > : public AgingClassWrapperBas boost::shared_ptr< object::Object< double > > alphaCapacity; boost::shared_ptr< object::Object< double > > alphaResistance; - std::vector< typename object::ExpressionObject< double >::Parameter > objectParameters{{"V", voltageState}, - {"T", temperatureState}, - {"SOC", socState}}; + std::vector< typename object::ExpressionObject< double >::Parameter > objectParameters{ { "V", voltageState }, + { "T", temperatureState }, + { "SOC", socState } }; // Collects the calendarian data from the cell-specific aging node if ( param->HasElementDirectChild( "AlphaCapacity" ) ) { @@ -111,8 +111,10 @@ class AgingClassWrapper< aging::CalendarianAging > : public AgingClassWrapperBas } const bool isEnabled = param->GetElementAttributeBoolValue( "enabled", true ); const double timeExponent = param->GetElementDoubleValue( "TimeExponent" ); - const double minAlphaCap = param->GetElementDoubleValue( "MinAlphaCapacity" ); - const double minAlphaRes = param->GetElementDoubleValue( "MinAlphaResistance" ); + const double minAlphaCap = param->GetElementDoubleValue( "MinAlphaCapacity", 0 ); + const double minAlphaRes = param->GetElementDoubleValue( "MinAlphaResistance", 0 ); + const double maxAlphaCap = param->GetElementDoubleValue( "MaxAlphaCapacity", std::numeric_limits< double >::max() ); + const double maxAlphaRes = param->GetElementDoubleValue( "MaxAlphaResistance", std::numeric_limits< double >::max() ); double initialCapacityFactor = 1; double initialResistanceFactor = 1; @@ -128,8 +130,9 @@ class AgingClassWrapper< aging::CalendarianAging > : public AgingClassWrapperBas // Creates an object of the class "aging::CalendarianAging" boost::shared_ptr< aging::CalendarianAging > calendarianAging = - boost::make_shared< aging::CalendarianAging >( agingStepTime, minAlphaCap, minAlphaRes, alphaCapacity, alphaResistance, - initialCapacityFactor, initialResistanceFactor, isEnabled, timeExponent ); + boost::make_shared< aging::CalendarianAging >( agingStepTime, minAlphaCap, minAlphaRes, maxAlphaCap, maxAlphaRes, + alphaCapacity, alphaResistance, initialCapacityFactor, + initialResistanceFactor, isEnabled, timeExponent ); *voltageState = state::ValueStateWrapper< double >( &calendarianAging->mActualVoltage ); *temperatureState = state::ValueStateWrapper< double >( &calendarianAging->mActualTemperature ); @@ -162,10 +165,10 @@ class AgingClassWrapper< aging::CyclicalAging > : public AgingClassWrapperBase boost::shared_ptr< object::Object< double > > betaCapacity; boost::shared_ptr< object::Object< double > > betaResistance; - std::vector< typename object::ExpressionObject< double >::Parameter > objectParameters{{"deltaDOD", dodState}, - {"meanV", voltageState}, - {"meanSOC", socState}, - {"meanI", currentState}}; + std::vector< typename object::ExpressionObject< double >::Parameter > objectParameters{ { "deltaDOD", dodState }, + { "meanV", voltageState }, + { "meanSOC", socState }, + { "meanI", currentState } }; // Collects the cyclical data from the cell-specific aging node if ( param->HasElementDirectChild( "BetaCapacity" ) ) { @@ -191,6 +194,8 @@ class AgingClassWrapper< aging::CyclicalAging > : public AgingClassWrapperBase const double chargeExponentResistance = param->GetElementDoubleValue( "ChargeExponentResistance" ); const double minBetaCap = param->GetElementDoubleValue( "MinBetaCapacity" ); const double minBetaRes = param->GetElementDoubleValue( "MinBetaResistance" ); + const double maxBetaCap = param->GetElementDoubleValue( "MaxBetaCapacity", std::numeric_limits< double >::max() ); + const double maxBetaRes = param->GetElementDoubleValue( "MaxBetaResistance", std::numeric_limits< double >::max() ); double initialCapacityFactor = 1; double initialResistanceFactor = 1; @@ -206,7 +211,7 @@ class AgingClassWrapper< aging::CyclicalAging > : public AgingClassWrapperBase // Creates an object of the class "aging::CyclicalAging" boost::shared_ptr< aging::CyclicalAging > cyclicalAging = - boost::make_shared< aging::CyclicalAging >( agingStepTime, minBetaCap, minBetaRes, betaCapacity, + boost::make_shared< aging::CyclicalAging >( agingStepTime, minBetaCap, minBetaRes, maxBetaCap, maxBetaRes, betaCapacity, betaResistance, initialCapacityFactor, initialResistanceFactor, isEnabled, chargeExponentCapacity, chargeExponentResistance ); diff --git a/src/factory/electrical/electricalclasswrapper.h b/src/factory/electrical/electricalclasswrapper.h index b7a2bd1d7c53cabaab743f30a7efc767c054b455..25f8aa0abb5aa8329276923303a87ed837247c11 100644 --- a/src/factory/electrical/electricalclasswrapper.h +++ b/src/factory/electrical/electricalclasswrapper.h @@ -237,8 +237,8 @@ class ElectricalClassWrapperBase : public ClassWrapperBase< TwoPort< MatrixT >, auto thermalState = arg->mParentCell->GetThermalState(); boost::shared_ptr< ElectrodeElement< MatrixT > > electrodeElement; - const bool observable = - param->GetElementAttributeBoolValue( "observable" ) || param->GetElementAttributeBoolValue( "SurfaceEffect" ); + const bool observable = param->GetElementAttributeBoolValue( "observable", false ) || + param->GetElementAttributeBoolValue( "SurfaceEffect", false ); if ( isAnodeElement ) { @@ -341,8 +341,8 @@ class ElectricalClassWrapper< MatrixT, Capacity > : public ElectricalClassWrappe boost::shared_ptr< TwoPort< MatrixT > > CreateInstance( const xmlparser::XmlParameter *param, const ArgumentTypeElectrical *arg = 0 ) { - const bool observable = param->GetElementAttributeBoolValue( "observable" ) || - param->GetElementAttributeBoolValue( "SurfaceEffect" ) || + const bool observable = param->GetElementAttributeBoolValue( "observable", false ) || + param->GetElementAttributeBoolValue( "SurfaceEffect", false ) || ( arg && arg->mMakeAllECMElementsObservable ); boost::shared_ptr< xmlparser::XmlParameter > objparam( param->GetElementChild( "Object" ) ); @@ -372,8 +372,8 @@ class ElectricalClassWrapper< MatrixT, OhmicResistance > : public ElectricalClas boost::shared_ptr< TwoPort< MatrixT > > CreateInstance( const xmlparser::XmlParameter *param, const ArgumentTypeElectrical *arg = 0 ) { - const bool observable = param->GetElementAttributeBoolValue( "observable" ) || - param->GetElementAttributeBoolValue( "SurfaceEffect" ) || + const bool observable = param->GetElementAttributeBoolValue( "observable", false ) || + param->GetElementAttributeBoolValue( "SurfaceEffect", false ) || ( arg && arg->mMakeAllECMElementsObservable ); boost::shared_ptr< xmlparser::XmlParameter > objparam( param->GetElementChild( "Object" ) ); @@ -403,8 +403,8 @@ class ElectricalClassWrapper< MatrixT, ConstantPhaseElement > : public Electrica boost::shared_ptr< TwoPort< MatrixT > > CreateInstance( const xmlparser::XmlParameter *param, const ArgumentTypeElectrical *arg = 0 ) { - const bool observable = param->GetElementAttributeBoolValue( "observable" ) || - param->GetElementAttributeBoolValue( "SurfaceEffect" ) || + const bool observable = param->GetElementAttributeBoolValue( "observable", false ) || + param->GetElementAttributeBoolValue( "SurfaceEffect", false ) || ( arg && arg->mMakeAllECMElementsObservable ); boost::shared_ptr< xmlparser::XmlParameter > objparam( param->GetElementChild( "Object" ) ); @@ -434,8 +434,8 @@ class ElectricalClassWrapper< MatrixT, Inductance > : public ElectricalClassWrap boost::shared_ptr< TwoPort< MatrixT > > CreateInstance( const xmlparser::XmlParameter *param, const ArgumentTypeElectrical *arg = 0 ) { - const bool observable = param->GetElementAttributeBoolValue( "observable" ) || - param->GetElementAttributeBoolValue( "SurfaceEffect" ) || + const bool observable = param->GetElementAttributeBoolValue( "observable", false ) || + param->GetElementAttributeBoolValue( "SurfaceEffect", false ) || ( arg && arg->mMakeAllECMElementsObservable ); boost::shared_ptr< xmlparser::XmlParameter > objparam( param->GetElementChild( "Object" ) ); @@ -483,8 +483,8 @@ class ElectricalClassWrapper< MatrixT, VoltageSource > : public ElectricalClassW argObject->mSetReverseLookUp = arg->mSetReverseLookup; } - const bool observable = param->GetElementAttributeBoolValue( "observable" ) || - param->GetElementAttributeBoolValue( "SurfaceEffect" ) || + const bool observable = param->GetElementAttributeBoolValue( "observable", false ) || + param->GetElementAttributeBoolValue( "SurfaceEffect", false ) || ( arg && arg->mMakeAllECMElementsObservable ); boost::shared_ptr< xmlparser::XmlParameter > objparam( param->GetElementChild( "Object" ) ); @@ -509,8 +509,8 @@ class ElectricalClassWrapper< MatrixT, ParallelRC > : public ElectricalClassWrap boost::shared_ptr< TwoPort< MatrixT > > CreateInstance( const xmlparser::XmlParameter *param, const ArgumentTypeElectrical *arg = 0 ) { - const bool observable = param->GetElementAttributeBoolValue( "observable" ) || - param->GetElementAttributeBoolValue( "SurfaceEffect" ) || + const bool observable = param->GetElementAttributeBoolValue( "observable", false ) || + param->GetElementAttributeBoolValue( "SurfaceEffect", false ) || ( arg && arg->mMakeAllECMElementsObservable ); boost::shared_ptr< xmlparser::XmlParameter > robjparam( param->GetElementChild( "LookupOhmicResistance" ) ); @@ -555,8 +555,8 @@ class ElectricalClassWrapper< MatrixT, Rmphn > : public ElectricalClassWrapperBa boost::shared_ptr< TwoPort< MatrixT > > CreateInstance( const xmlparser::XmlParameter *param, const ArgumentTypeElectrical *arg = 0 ) { - const bool observable = param->GetElementAttributeBoolValue( "observable" ) || - param->GetElementAttributeBoolValue( "SurfaceEffect" ) || + const bool observable = param->GetElementAttributeBoolValue( "observable", false ) || + param->GetElementAttributeBoolValue( "SurfaceEffect", false ) || ( arg && arg->mMakeAllECMElementsObservable ); boost::shared_ptr< xmlparser::XmlParameter > rmpobjparam( param->GetElementChild( "OhmicResistance_RMP" ) ); @@ -630,8 +630,8 @@ class ElectricalClassWrapper< MatrixT, SphericalDiffusion > : public ElectricalC { auto elecData = this->CreateElectricalData(); - const bool observable = param->GetElementAttributeBoolValue( "observable" ) || - param->GetElementAttributeBoolValue( "SurfaceEffect" ) || + const bool observable = param->GetElementAttributeBoolValue( "observable", false ) || + param->GetElementAttributeBoolValue( "SurfaceEffect", false ) || ( arg && arg->mMakeAllECMElementsObservable ); int iMaxElements = param->GetElementAttributeIntValue( "RCCounter", 5 ); // default is 5 RC Elements @@ -731,8 +731,8 @@ class ElectricalClassWrapper< MatrixT, WarburgCotanh > : public ElectricalClassW CreateInstance( const xmlparser::XmlParameter *param, const ArgumentTypeElectrical *arg = 0 ) { auto elecData = this->CreateElectricalData(); - const bool observable = param->GetElementAttributeBoolValue( "observable" ) || - param->GetElementAttributeBoolValue( "SurfaceEffect" ) || + const bool observable = param->GetElementAttributeBoolValue( "observable", false ) || + param->GetElementAttributeBoolValue( "SurfaceEffect", false ) || ( arg && arg->mMakeAllECMElementsObservable ); const bool withCapacity = param->GetElementAttributeBoolValue( "withCapacity", true ); int iMaxElements = param->GetElementAttributeIntValue( "RCCounter", 5 ); // default is 5 RC Elements @@ -867,8 +867,8 @@ class ElectricalClassWrapper< MatrixT, WarburgTanh > : public ElectricalClassWra CreateInstance( const xmlparser::XmlParameter *param, const ArgumentTypeElectrical *arg = 0 ) { auto elecData = this->CreateElectricalData(); - const bool observable = param->GetElementAttributeBoolValue( "observable" ) || - param->GetElementAttributeBoolValue( "SurfaceEffect" ) || + const bool observable = param->GetElementAttributeBoolValue( "observable", false ) || + param->GetElementAttributeBoolValue( "SurfaceEffect", false ) || ( arg && arg->mMakeAllECMElementsObservable ); int iMaxElements = param->GetElementAttributeIntValue( "RCCounter", 5 ); // default is 5 RC Elements size_t maxElements( iMaxElements ); @@ -926,8 +926,8 @@ class ElectricalClassWrapper< MatrixT, ParallelRCAlg > : public ElectricalClassW { auto elecData = this->CreateElectricalData(); - const bool observable = param->GetElementAttributeBoolValue( "observable" ) || - param->GetElementAttributeBoolValue( "SurfaceEffect" ) || + const bool observable = param->GetElementAttributeBoolValue( "observable", false ) || + param->GetElementAttributeBoolValue( "SurfaceEffect", false ) || ( arg && arg->mMakeAllECMElementsObservable ); boost::shared_ptr< xmlparser::XmlParameter > robjparam( param->GetElementChild( "RObject" ) ); @@ -1025,8 +1025,8 @@ class ElectricalClassWrapper< MatrixT, Cellelement > : public ElectricalClassWra count = param->GetElementChild( "Children" )->GetElementAttributeUnsignedIntValue( "count", 1 ); } - const bool observable = - param->GetElementAttributeBoolValue( "observable" ) || param->GetElementAttributeBoolValue( "SurfaceEffect" ); + const bool observable = param->GetElementAttributeBoolValue( "observable", false ) || + param->GetElementAttributeBoolValue( "SurfaceEffect", false ); const size_t numberOfCellElements = param->HasElementDirectChild( "ThermalBlock" ) ? @@ -1224,8 +1224,8 @@ class ElectricalClassWrapper< MatrixT, Zarc > : public ElectricalClassWrapperBas auto elecData = this->CreateElectricalData(); - const bool observable = param->GetElementAttributeBoolValue( "observable" ) || - param->GetElementAttributeBoolValue( "SurfaceEffect" ) || + const bool observable = param->GetElementAttributeBoolValue( "observable", false ) || + param->GetElementAttributeBoolValue( "SurfaceEffect", false ) || ( arg && arg->mMakeAllECMElementsObservable ); double dtValue = 0.001; @@ -1274,8 +1274,8 @@ class ElectricalClassWrapper< MatrixT, ZarcAlg > : public ElectricalClassWrapper auto elecData = this->CreateElectricalData(); - const bool observable = param->GetElementAttributeBoolValue( "observable" ) || - param->GetElementAttributeBoolValue( "SurfaceEffect" ) || + const bool observable = param->GetElementAttributeBoolValue( "observable", false ) || + param->GetElementAttributeBoolValue( "SurfaceEffect", false ) || ( arg && arg->mMakeAllECMElementsObservable ); double sampleRate = 0.001; if ( param->GetConfigurationRoot()->HasElementDirectChild( "Options" ) && diff --git a/src/factory/observer/observerclasswrapper.h b/src/factory/observer/observerclasswrapper.h index 87503150af7462b71ffbcf762482d62e9bc17710..865defdc96574b555bc52d2328056bda0bcfeffb 100644 --- a/src/factory/observer/observerclasswrapper.h +++ b/src/factory/observer/observerclasswrapper.h @@ -309,6 +309,15 @@ class ObserverClassWrapperTwoPort< MatrixT, observer::MatlabFilterTwoPort > filter->SetDataLocation( param->GetElementStringValue( "DataLocation" ) ); } + // Options that influnce the filtering can be read here + boost::shared_ptr< xmlparser::XmlParameter > optionsNode = + param->GetConfigurationRoot()->GetElementChild( "Options" ); + if ( optionsNode->HasElementDirectChild( "MaximalOperationalCellVoltageV" ) || + optionsNode->HasElementDirectChild( "MinimalOperationalCellVoltageV" ) ) + { + filter->SetIsVoltageLimited(); + } + return filter; } }; diff --git a/src/observer/filter/matlabFilter.h b/src/observer/filter/matlabFilter.h index 43126d01661ac97ca699d288ae71a1e8f5e14566..50205f7f4bc057abd7d12c7f4afbb5cbe5fdc5fb 100644 --- a/src/observer/filter/matlabFilter.h +++ b/src/observer/filter/matlabFilter.h @@ -42,6 +42,7 @@ class MatlabFilter : public Filter< T, TConcrete, ArgumentType > , mMaxSize( maxSize ) , mDataLocation( "diga.daten." ) , mFilenamePrefix( filenamePrefix ) + , mIsVoltageLimited( false ) , mMatrixSizes( 0 ){}; virtual ~MatlabFilter() { this->WriteToDisk(); } @@ -92,6 +93,7 @@ class MatlabFilter : public Filter< T, TConcrete, ArgumentType > /// Set the matlab struct that all data is written to, e.g. diga.daten virtual void SetDataLocation( const std::string &location ) { this->mDataLocation = location + "."; } virtual void SetFilenamePrefix( const std::string &prefix ) { this->mFilenamePrefix = prefix; } + virtual void SetIsVoltageLimited() { this->mIsVoltageLimited = true; } virtual void MaxSampleReached( size_t nextNumber ); virtual void PrepareFilter( ArgumentType &prepData ) @@ -115,6 +117,7 @@ class MatlabFilter : public Filter< T, TConcrete, ArgumentType > std::string mDataLocation; std::string mFilenamePrefix; size_t mMatrixSizes; + bool mIsVoltageLimited; std::string MakeFilename( size_t cycle ) { @@ -242,6 +245,11 @@ class MatlabFilterBase< T, electrical::TwoPort, PreparationType< T > > this->mMatlabVectors["Spannung"].push_back( port->GetVoltageValue() ); this->mMatlabVectors["Strom"].push_back( port->GetCurrentValue() ); this->mMatlabVectors["ThermischLeistung"].push_back( port->GetPowerValue() ); + if ( this->mIsVoltageLimited ) + { + this->mMatlabVectors["VerloreneLadeladung"].push_back( port->GetLostChargeAh() ); + this->mMatlabVectors["VerloreneEntladeladung"].push_back( port->GetLostDischargeAh() ); + } } MatlabFilter< T, electrical::TwoPort, PreparationType< T > >::ProcessData( data, t ); } diff --git a/src/time_series/time_series.h b/src/time_series/time_series.h index b5b17a7b7c961c8ce99734047cd3a4312dae1b43..8d7deaeccb49e8be2904b0e53e68c1e20c259d4c 100644 --- a/src/time_series/time_series.h +++ b/src/time_series/time_series.h @@ -76,6 +76,9 @@ class TimeSeries void StartNewCycle(); + /// Moves forward in load profile and updates mValue, used if votlage limits are reached. + bool MoveToNextProfileValue( T time, double &duration ); + /// Gets internal time T GetTime() const; /// Gets the last time step in the series @@ -100,6 +103,7 @@ class TimeSeries bool inline LoopConditionForIndexIncrement() const; vector< T > mTimesData; vector< T > mValuesData; + vector< T > mTimesDataInitial; T mTime; T mValue; T mCycleLength; @@ -182,6 +186,8 @@ TimeSeries< T, EVALUATOR >::TimeSeries( std::istream &stream, T timeScalingFacto mEvaluator.CalculateValue( true, mTimesData, mValuesData, mTime, mIndex, mValue ); mCycleLength = GetMaxTime(); + + mTimesDataInitial = mTimesData; } #endif @@ -202,6 +208,7 @@ TimeSeries< T, EVALUATOR >::TimeSeries( const vector< T > ×Data, const vect , mType( TimeSeriesType::CURRENT ) { ResetData( timesData, valuesData, timeScalingFactor, valueScalingFactor ); + mTimesDataInitial = mTimesData; } @@ -242,13 +249,37 @@ void TimeSeries< T, EVALUATOR >::SetTimeAndTriggerEvaluation( T time ) template < typename T, template < typename > class EVALUATOR > void TimeSeries< T, EVALUATOR >::StartNewCycle() { - std::vector< T > increaseVector( mTimesData.size(), mCycleLength ); + std::vector< T > increaseVector( mTimesDataInitial.size(), mCycleLength ); - std::transform( mTimesData.begin(), mTimesData.end(), increaseVector.begin(), mTimesData.begin(), std::plus< T >() ); + // In case the mTimesData was modified use saved TimesDataInitial + std::transform( mTimesDataInitial.begin(), mTimesDataInitial.end(), increaseVector.begin(), mTimesData.begin(), + std::plus< T >() ); ResetData( mTimesData, mValuesData ); + mTimesDataInitial = mTimesData; +} + +template < typename T, template < typename > class EVALUATOR > +bool TimeSeries< T, EVALUATOR >::MoveToNextProfileValue( T time, double &duration ) +{ + + // size_t indexSave = mIndex; + if ( mIndex + 1 < mTimesData.size() ) + { + // Calculate the difference between the current time and the next timestep. + double remainingTimeInStep = mTimesData[mIndex + 1] - time; + // Substract the time difference from all time values higher than the current step + for ( size_t i = mIndex + 1; i < mTimesData.size(); ++i ) + mTimesData[i] = mTimesData[i] - remainingTimeInStep; + // Set time and evaluate trigger + SetTimeAndTriggerEvaluation( time ); + duration = remainingTimeInStep; + return true; + } + return false; } + template < typename T, template < typename > class EVALUATOR > T TimeSeries< T, EVALUATOR >::GetMaxTime() const { diff --git a/src/unittests/aging/TestCalendarianAging.cpp b/src/unittests/aging/TestCalendarianAging.cpp index 46c95aca388a6118eba47b0b64011ea9d95ce0dd..3db9ff62bc894f0b2c2fe668301ed02da2b79ade 100644 --- a/src/unittests/aging/TestCalendarianAging.cpp +++ b/src/unittests/aging/TestCalendarianAging.cpp @@ -13,7 +13,7 @@ void TestCalendarianAging::testNoAging() std::vector< typename object::ExpressionObject< double >::Parameter > objParams; const auto obj = boost::make_shared< object::ExpressionObject< double > >( "0.0001", objParams ); { // calculation time of zero seconds - aging::CalendarianAging aging( 10, 0, 0, obj, obj, 1, 1, true, 1 ); + aging::CalendarianAging aging( 10, 0, 0, 1e3, 1e3, obj, obj, 1, 1, true, 1 ); aging.CalculateAging( tpState, 3.0, 1.0 ); TS_ASSERT_EQUALS( aging.GetCapacityFactor(), 1.0 ); TS_ASSERT_EQUALS( aging.GetSocOffset(), 0.0 ); @@ -27,7 +27,7 @@ void TestCalendarianAging::testNoAging() TS_ASSERT_EQUALS( aging.GetResistanceFactor(), 1.0 ); } { // aging disabled - aging::CalendarianAging aging( 10, 0, 0, obj, obj, 1, 1, false, 1 ); + aging::CalendarianAging aging( 10, 0, 0, 1e3, 1e3, obj, obj, 1, 1, false, 1 ); aging.CollectData( tpState, tpState, 10 ); aging.CalculateAging( tpState, 3.0, 1.0 ); @@ -49,13 +49,13 @@ void TestCalendarianAging::testAgingCalculation() auto voltageValueState = boost::make_shared< state::ValueStateWrapper< double > >( nullptr ); auto temperatureValueState = boost::make_shared< state::ValueStateWrapper< double > >( nullptr ); auto socValueState = boost::make_shared< state::ValueStateWrapper< double > >( nullptr ); - std::vector< typename object::ExpressionObject< double >::Parameter > objParams{{"V", voltageValueState}, - {"T", temperatureValueState}, - {"SOC", socValueState}}; + std::vector< typename object::ExpressionObject< double >::Parameter > objParams{ { "V", voltageValueState }, + { "T", temperatureValueState }, + { "SOC", socValueState } }; const auto objCap = boost::make_shared< object::ExpressionObject< double > >( "0.0001 * (V + T - 300)", objParams ); const auto objRes = boost::make_shared< object::ExpressionObject< double > >( "0.00015 * (V + T - 300)", objParams ); - aging::CalendarianAging aging( steptime, 0, 0, objCap, objRes, initialCap, initialRes, true, exponent ); + aging::CalendarianAging aging( steptime, 0, 0, 1e3, 1e3, objCap, objRes, initialCap, initialRes, true, exponent ); *voltageValueState = state::ValueStateWrapper< double >( &aging.mActualVoltage ); *temperatureValueState = state::ValueStateWrapper< double >( &aging.mActualTemperature ); *socValueState = state::ValueStateWrapper< double >( &aging.mActualSoc ); @@ -92,13 +92,13 @@ void TestCalendarianAging::testReset() auto voltageValueState = boost::make_shared< state::ValueStateWrapper< double > >( nullptr ); auto temperatureValueState = boost::make_shared< state::ValueStateWrapper< double > >( nullptr ); auto socValueState = boost::make_shared< state::ValueStateWrapper< double > >( nullptr ); - std::vector< typename object::ExpressionObject< double >::Parameter > objParams{{"V", voltageValueState}, - {"T", temperatureValueState}, - {"SOC", socValueState}}; + std::vector< typename object::ExpressionObject< double >::Parameter > objParams{ { "V", voltageValueState }, + { "T", temperatureValueState }, + { "SOC", socValueState } }; const auto objCap = boost::make_shared< object::ExpressionObject< double > >( "0.0001 * (V + T - 300)", objParams ); const auto objRes = boost::make_shared< object::ExpressionObject< double > >( "0.00015 * (V + T - 300)", objParams ); - aging::CalendarianAging aging( steptime, 0, 0, objCap, objRes, initialCap, initialRes, true, exponent ); + aging::CalendarianAging aging( steptime, 0, 0, 1e3, 1e3, objCap, objRes, initialCap, initialRes, true, exponent ); *voltageValueState = state::ValueStateWrapper< double >( &aging.mActualVoltage ); *temperatureValueState = state::ValueStateWrapper< double >( &aging.mActualTemperature ); *socValueState = state::ValueStateWrapper< double >( &aging.mActualSoc ); @@ -153,12 +153,12 @@ void TestCalendarianAging::testFormulaVariables() auto voltageValueState = boost::make_shared< state::ValueStateWrapper< double > >( nullptr ); auto temperatureValueState = boost::make_shared< state::ValueStateWrapper< double > >( nullptr ); auto socValueState = boost::make_shared< state::ValueStateWrapper< double > >( nullptr ); - std::vector< typename object::ExpressionObject< double >::Parameter > objParams{{"V", voltageValueState}, - {"T", temperatureValueState}, - {"SOC", socValueState}}; + std::vector< typename object::ExpressionObject< double >::Parameter > objParams{ { "V", voltageValueState }, + { "T", temperatureValueState }, + { "SOC", socValueState } }; { const auto obj = boost::make_shared< object::ExpressionObject< double > >( "V", objParams ); - aging::CalendarianAging aging( 1.0, 0, 0, obj, obj, 1.0, 1.0, true, 1.0 ); + aging::CalendarianAging aging( 1.0, 0, 0, 1e3, 1e3, obj, obj, 1.0, 1.0, true, 1.0 ); *voltageValueState = state::ValueStateWrapper< double >( &aging.mActualVoltage ); *temperatureValueState = state::ValueStateWrapper< double >( &aging.mActualTemperature ); *socValueState = state::ValueStateWrapper< double >( &aging.mActualSoc ); @@ -169,7 +169,7 @@ void TestCalendarianAging::testFormulaVariables() } { const auto obj = boost::make_shared< object::ExpressionObject< double > >( "T", objParams ); - aging::CalendarianAging aging( 1.0, 0, 0, obj, obj, 1.0, 1.0, true, 1.0 ); + aging::CalendarianAging aging( 1.0, 0, 0, 1e3, 1e3, obj, obj, 1.0, 1.0, true, 1.0 ); *voltageValueState = state::ValueStateWrapper< double >( &aging.mActualVoltage ); *temperatureValueState = state::ValueStateWrapper< double >( &aging.mActualTemperature ); *socValueState = state::ValueStateWrapper< double >( &aging.mActualSoc ); @@ -180,7 +180,7 @@ void TestCalendarianAging::testFormulaVariables() } { const auto obj = boost::make_shared< object::ExpressionObject< double > >( "SOC", objParams ); - aging::CalendarianAging aging( 1.0, 0, 0, obj, obj, 1.0, 1.0, true, 1.0 ); + aging::CalendarianAging aging( 1.0, 0, 0, 1e3, 1e3, obj, obj, 1.0, 1.0, true, 1.0 ); *voltageValueState = state::ValueStateWrapper< double >( &aging.mActualVoltage ); *temperatureValueState = state::ValueStateWrapper< double >( &aging.mActualTemperature ); *socValueState = state::ValueStateWrapper< double >( &aging.mActualSoc ); diff --git a/src/unittests/aging/TestCyclicalAging.cpp b/src/unittests/aging/TestCyclicalAging.cpp index 67e36319f7b06be958273630ae512971ab5a2246..c86f40f6c013c3b243e3b6e8fce13b5f8a1b068b 100644 --- a/src/unittests/aging/TestCyclicalAging.cpp +++ b/src/unittests/aging/TestCyclicalAging.cpp @@ -13,7 +13,7 @@ void TestCyclicalAging::testNoAging() std::vector< typename object::ExpressionObject< double >::Parameter > objParams; const auto obj = boost::make_shared< object::ExpressionObject< double > >( "0.0001", objParams ); { // calculation time of zero seconds - aging::CyclicalAging aging( 10, 0, 0, obj, obj, 1.0, 1.0, true, 1, 1 ); + aging::CyclicalAging aging( 10, 0, 0, 1e3, 1e3, obj, obj, 1.0, 1.0, true, 1, 1 ); aging.CalculateAging( tpState, 3.0, 1.0 ); TS_ASSERT_EQUALS( aging.GetCapacityFactor(), 1.0 ); TS_ASSERT_EQUALS( aging.GetSocOffset(), 0.0 ); @@ -27,7 +27,7 @@ void TestCyclicalAging::testNoAging() TS_ASSERT_EQUALS( aging.GetResistanceFactor(), 1.0 ); } { // aging disabled - aging::CyclicalAging aging( 10, 0, 0, obj, obj, 1.0, 1.0, false, 1, 1 ); + aging::CyclicalAging aging( 10, 0, 0, 1e3, 1e3, obj, obj, 1.0, 1.0, false, 1, 1 ); aging.CollectData( tpState, tpState, 10 ); aging.CalculateAging( tpState, 3.0, 1.0 ); @@ -54,14 +54,14 @@ void TestCyclicalAging::testAgingCalculation() auto voltageValueState = boost::make_shared< state::ValueStateWrapper< double > >( nullptr ); auto socValueState = boost::make_shared< state::ValueStateWrapper< double > >( nullptr ); auto currentValueState = boost::make_shared< state::ValueStateWrapper< double > >( nullptr ); - std::vector< typename object::ExpressionObject< double >::Parameter > objParams{{"deltaDOD", dodValueState}, - {"meanV", voltageValueState}, - {"meanSOC", socValueState}, - {"meanI", currentValueState}}; + std::vector< typename object::ExpressionObject< double >::Parameter > objParams{ { "deltaDOD", dodValueState }, + { "meanV", voltageValueState }, + { "meanSOC", socValueState }, + { "meanI", currentValueState } }; const auto objCap = boost::make_shared< object::ExpressionObject< double > >( "0.0001 * (meanV + deltaDOD)", objParams ); const auto objRes = boost::make_shared< object::ExpressionObject< double > >( "0.00015 * (meanV + deltaDOD)", objParams ); - aging::CyclicalAging aging( steptime, 0, 0, objCap, objRes, initialCap, initialRes, true, exponentCap, exponentRes ); + aging::CyclicalAging aging( steptime, 0, 0, 1e3, 1e3, objCap, objRes, initialCap, initialRes, true, exponentCap, exponentRes ); *dodValueState = state::ValueStateWrapper< double >( &aging.mActualDod ); *voltageValueState = state::ValueStateWrapper< double >( &aging.mActualVoltage ); *socValueState = state::ValueStateWrapper< double >( &aging.mActualSoc ); @@ -107,14 +107,14 @@ void TestCyclicalAging::testReset() auto voltageValueState = boost::make_shared< state::ValueStateWrapper< double > >( nullptr ); auto socValueState = boost::make_shared< state::ValueStateWrapper< double > >( nullptr ); auto currentValueState = boost::make_shared< state::ValueStateWrapper< double > >( nullptr ); - std::vector< typename object::ExpressionObject< double >::Parameter > objParams{{"deltaDOD", dodValueState}, - {"meanV", voltageValueState}, - {"meanSOC", socValueState}, - {"meanI", currentValueState}}; + std::vector< typename object::ExpressionObject< double >::Parameter > objParams{ { "deltaDOD", dodValueState }, + { "meanV", voltageValueState }, + { "meanSOC", socValueState }, + { "meanI", currentValueState } }; const auto objCap = boost::make_shared< object::ExpressionObject< double > >( "0.0001 * (meanV + deltaDOD)", objParams ); const auto objRes = boost::make_shared< object::ExpressionObject< double > >( "0.00015 * (meanV + deltaDOD)", objParams ); - aging::CyclicalAging aging( steptime, 0, 0, objCap, objRes, initialCap, initialRes, true, exponentCap, exponentRes ); + aging::CyclicalAging aging( steptime, 0, 0, 1e3, 1e3, objCap, objRes, initialCap, initialRes, true, exponentCap, exponentRes ); *dodValueState = state::ValueStateWrapper< double >( &aging.mActualDod ); *voltageValueState = state::ValueStateWrapper< double >( &aging.mActualVoltage ); *socValueState = state::ValueStateWrapper< double >( &aging.mActualSoc ); @@ -166,13 +166,13 @@ void TestCyclicalAging::testFormulaVariables() auto voltageValueState = boost::make_shared< state::ValueStateWrapper< double > >( nullptr ); auto socValueState = boost::make_shared< state::ValueStateWrapper< double > >( nullptr ); auto currentValueState = boost::make_shared< state::ValueStateWrapper< double > >( nullptr ); - std::vector< typename object::ExpressionObject< double >::Parameter > objParams{{"deltaDOD", dodValueState}, - {"meanV", voltageValueState}, - {"meanSOC", socValueState}, - {"meanI", currentValueState}}; + std::vector< typename object::ExpressionObject< double >::Parameter > objParams{ { "deltaDOD", dodValueState }, + { "meanV", voltageValueState }, + { "meanSOC", socValueState }, + { "meanI", currentValueState } }; { const auto obj = boost::make_shared< object::ExpressionObject< double > >( "meanV", objParams ); - aging::CyclicalAging aging( 1.0, 0, 0, obj, obj, 1.0, 1.0, true, 1.0, 1.0 ); + aging::CyclicalAging aging( 1.0, 0, 0, 1e3, 1e3, obj, obj, 1.0, 1.0, true, 1.0, 1.0 ); *dodValueState = state::ValueStateWrapper< double >( &aging.mActualDod ); *voltageValueState = state::ValueStateWrapper< double >( &aging.mActualVoltage ); *socValueState = state::ValueStateWrapper< double >( &aging.mActualSoc ); @@ -188,7 +188,7 @@ void TestCyclicalAging::testFormulaVariables() } { const auto obj = boost::make_shared< object::ExpressionObject< double > >( "meanSOC", objParams ); - aging::CyclicalAging aging( 1.0, 0, 0, obj, obj, 1.0, 1.0, true, 1.0, 1.0 ); + aging::CyclicalAging aging( 1.0, 0, 0, 1e3, 1e3, obj, obj, 1.0, 1.0, true, 1.0, 1.0 ); *dodValueState = state::ValueStateWrapper< double >( &aging.mActualDod ); *voltageValueState = state::ValueStateWrapper< double >( &aging.mActualVoltage ); *socValueState = state::ValueStateWrapper< double >( &aging.mActualSoc ); @@ -204,7 +204,7 @@ void TestCyclicalAging::testFormulaVariables() } { const auto obj = boost::make_shared< object::ExpressionObject< double > >( "deltaDOD", objParams ); - aging::CyclicalAging aging( 1.0, 0, 0, obj, obj, 1.0, 1.0, true, 1.0, 1.0 ); + aging::CyclicalAging aging( 1.0, 0, 0, 1e3, 1e3, obj, obj, 1.0, 1.0, true, 1.0, 1.0 ); *dodValueState = state::ValueStateWrapper< double >( &aging.mActualDod ); *voltageValueState = state::ValueStateWrapper< double >( &aging.mActualVoltage ); *socValueState = state::ValueStateWrapper< double >( &aging.mActualSoc ); @@ -220,7 +220,7 @@ void TestCyclicalAging::testFormulaVariables() } { const auto obj = boost::make_shared< object::ExpressionObject< double > >( "meanI", objParams ); - aging::CyclicalAging aging( 1.0, 0, 0, obj, obj, 1.0, 1.0, true, 1.0, 1.0 ); + aging::CyclicalAging aging( 1.0, 0, 0, 1e3, 1e3, obj, obj, 1.0, 1.0, true, 1.0, 1.0 ); *dodValueState = state::ValueStateWrapper< double >( &aging.mActualDod ); *voltageValueState = state::ValueStateWrapper< double >( &aging.mActualVoltage ); *socValueState = state::ValueStateWrapper< double >( &aging.mActualSoc ); diff --git a/src/unittests/factory/observer/TestObserverFactories.cpp b/src/unittests/factory/observer/TestObserverFactories.cpp index bcc6bee2cd748d3c964a82da1d010cc91f590308..edf82581917ba5daa1f6913ac0c8ef3f219c1fe5 100644 --- a/src/unittests/factory/observer/TestObserverFactories.cpp +++ b/src/unittests/factory/observer/TestObserverFactories.cpp @@ -95,7 +95,9 @@ void TestObserverFactories::TestObserverFactoryMatlabFilterCreation() <maxSampleSize> 1 </maxSampleSize> \ </Filter1>\ </Observer>\ - </Configuration>"; + <Options>\ + </Options>\ + </Configuration>"; boost::scoped_ptr< xmlparser::XmlParser > parser( new xmlparser::tinyxml2::XmlParserImpl() ); parser->ReadFromMem( xmlConfig ); std::vector< boost::shared_ptr< xmlparser::XmlParameter > > children = diff --git a/src/unittests/misc/TestSymbolic.cpp b/src/unittests/misc/TestSymbolic.cpp index 30e230fc72d5a436cf2016e0960c70504fdf1219..520f572f52d232c0f6bbf36af6017ee18419d9bb 100644 --- a/src/unittests/misc/TestSymbolic.cpp +++ b/src/unittests/misc/TestSymbolic.cpp @@ -338,6 +338,23 @@ void TestSymbolic::TestSolve() matB.coeffRef( 1, 0 ) = symbolic::Symbolic< OutType >( "x2" ); matB.coeffRef( 2, 0 ) = symbolic::Symbolic< OutType >( "x3" ); SymbolicMatrix< OutType > sol = Eigen::solve123( matA, matB ); + + +// std::cout << "Here is the matrix A:\n" << matA << std::endl; +// std::cout << "Here is the matrix B:\n" << matB << std::endl; +// std::cout << "Here is the solution for coeffRef(0,0):\n" << sol.coeffRef( 0, 0 ) << std::endl; +// std::cout << "Here is the solution for coeffRef(1,0):\n" << sol.coeffRef( 1, 0 ) << std::endl; +// std::cout << "Here is the solution for coeffRef(2,0):\n" << sol.coeffRef( 2, 0 ) << std::endl; + + + TS_ASSERT_EQUALS( sol.coeffRef( 0, 0 ), + symbolic::Symbolic< OutType >( "MUL(SUB(SUB(x1,MUL(MUL(SUB(SUB(x3,MUL(x1,MUL(g,DIV(1.000000,a)))),MUL(SUB(x2,MUL(x1,MUL(d,DIV(1.000000,a)))),MUL(ADD(h,MUL(MUL(g,DIV(1.000000,a)),MUL(-1,b))),DIV(1.000000,ADD(e,MUL(MUL(d,DIV(1.000000,a)),MUL(-1,b))))))),DIV(1,ADD(ADD(i,MUL(MUL(g,DIV(1.000000,a)),MUL(-1,c))),MUL(MUL(ADD(h,MUL(MUL(g,DIV(1.000000,a)),MUL(-1,b))),DIV(1.000000,ADD(e,MUL(MUL(d,DIV(1.000000,a)),MUL(-1,b))))),MUL(-1,SUB(f,MUL(c,MUL(d,DIV(1.000000,a))))))))),c)),MUL(MUL(SUB(SUB(x2,MUL(x1,MUL(d,DIV(1.000000,a)))),MUL(MUL(SUB(SUB(x3,MUL(x1,MUL(g,DIV(1.000000,a)))),MUL(SUB(x2,MUL(x1,MUL(d,DIV(1.000000,a)))),MUL(ADD(h,MUL(MUL(g,DIV(1.000000,a)),MUL(-1,b))),DIV(1.000000,ADD(e,MUL(MUL(d,DIV(1.000000,a)),MUL(-1,b))))))),DIV(1,ADD(ADD(i,MUL(MUL(g,DIV(1.000000,a)),MUL(-1,c))),MUL(MUL(ADD(h,MUL(MUL(g,DIV(1.000000,a)),MUL(-1,b))),DIV(1.000000,ADD(e,MUL(MUL(d,DIV(1.000000,a)),MUL(-1,b))))),MUL(-1,SUB(f,MUL(c,MUL(d,DIV(1.000000,a))))))))),SUB(f,MUL(c,MUL(d,DIV(1.000000,a)))))),DIV(1,ADD(e,MUL(MUL(d,DIV(1.000000,a)),MUL(-1,b))))),b)),DIV(1,a))" ) ); + TS_ASSERT_EQUALS( sol.coeff( 1, 0 ), + symbolic::Symbolic< OutType >( "MUL(SUB(SUB(x2,MUL(x1,MUL(d,DIV(1.000000,a)))),MUL(MUL(SUB(SUB(x3,MUL(x1,MUL(g,DIV(1.000000,a)))),MUL(SUB(x2,MUL(x1,MUL(d,DIV(1.000000,a)))),MUL(ADD(h,MUL(MUL(g,DIV(1.000000,a)),MUL(-1,b))),DIV(1.000000,ADD(e,MUL(MUL(d,DIV(1.000000,a)),MUL(-1,b))))))),DIV(1,ADD(ADD(i,MUL(MUL(g,DIV(1.000000,a)),MUL(-1,c))),MUL(MUL(ADD(h,MUL(MUL(g,DIV(1.000000,a)),MUL(-1,b))),DIV(1.000000,ADD(e,MUL(MUL(d,DIV(1.000000,a)),MUL(-1,b))))),MUL(-1,SUB(f,MUL(c,MUL(d,DIV(1.000000,a))))))))),SUB(f,MUL(c,MUL(d,DIV(1.000000,a)))))),DIV(1,ADD(e,MUL(MUL(d,DIV(1.000000,a)),MUL(-1,b)))))" ) ); + TS_ASSERT_EQUALS( sol.coeff( 2, 0 ), + symbolic::Symbolic< OutType >( "MUL(SUB(SUB(x3,MUL(x1,MUL(g,DIV(1.000000,a)))),MUL(SUB(x2,MUL(x1,MUL(d,DIV(1.000000,a)))),MUL(ADD(h,MUL(MUL(g,DIV(1.000000,a)),MUL(-1,b))),DIV(1.000000,ADD(e,MUL(MUL(d,DIV(1.000000,a)),MUL(-1,b))))))),DIV(1,ADD(ADD(i,MUL(MUL(g,DIV(1.000000,a)),MUL(-1,c))),MUL(MUL(ADD(h,MUL(MUL(g,DIV(1.000000,a)),MUL(-1,b))),DIV(1.000000,ADD(e,MUL(MUL(d,DIV(1.000000,a)),MUL(-1,b))))),MUL(-1,SUB(f,MUL(c,MUL(d,DIV(1.000000,a)))))))))" ) ); + +/* TS_ASSERT_EQUALS( sol.coeffRef( 0, 0 ), symbolic::Symbolic< OutType >( "MUL(SUB(SUB(x1,MUL(MUL(SUB(SUB(x3,MUL(x1,MUL(g,DIV(1.000000,a)))),MUL(SUB(x2,MUL(x1,MUL(d,DIV(" @@ -367,6 +384,8 @@ void TestSymbolic::TestSolve() ",-1),e))))),DIV(1,ADD(MUL(ADD(MUL(MUL(ADD(MUL(MUL(MUL(g,DIV(1.000000,a)),b),-1),h),DIV(1." "000000,ADD(MUL(MUL(MUL(d,DIV(1.000000,a)),b),-1),e))),SUB(f,MUL(c,MUL(d,DIV(1.000000,a)))))," "MUL(MUL(g,DIV(1.000000,a)),c)),-1),i)))" ) ); +*/ + // MATLAB / Octave code // a = 1; b=2; c = -1; d=2; e=2; f=2; g = 1; h = -1; i = 2; diff --git a/src/xmlparser/tinyxml2/xmlparameterimpl.cpp b/src/xmlparser/tinyxml2/xmlparameterimpl.cpp index 5d61a7ed0ff0e2bcbd2f593a931b920c05862c60..2646f5f288f2267534a89bd4eefcb7dc09817539 100644 --- a/src/xmlparser/tinyxml2/xmlparameterimpl.cpp +++ b/src/xmlparser/tinyxml2/xmlparameterimpl.cpp @@ -237,7 +237,7 @@ size_t XmlParameterImpl::GetElementUnsignedIntValue( const char* elementName, si return size_t( abs( res ) ); } -double XmlParameterImpl::GetElementDoubleValue( const char* elementName, double defaultValue ) const +double XmlParameterImpl::GetElementDoubleValue( const char* elementName ) const { XMLElement* node = elementName ? GetRawElement( elementName ) : mNodePtr; @@ -246,12 +246,28 @@ double XmlParameterImpl::GetElementDoubleValue( const char* elementName, double if ( err ) { - if ( defaultValue ) - return defaultValue; + ErrorFunction< std::logic_error >( __FUNCTION__, __LINE__, __FILE__, "CouldNotParseXmlContentException", + elementName, this->GetElementName() ); + } - else - ErrorFunction< std::logic_error >( __FUNCTION__, __LINE__, __FILE__, "CouldNotParseXmlContentException", - elementName, this->GetElementName() ); + return res; +} + +double XmlParameterImpl::GetElementDoubleValue( const char* elementName, double defaultValue ) const +{ + XMLElement* node = elementName ? GetRawElement( elementName, false ) : mNodePtr; + + if ( !node ) + { + return defaultValue; + } + + double res; + XMLError err = node->QueryDoubleText( &res ); + + if ( err ) + { + return defaultValue; } return res; @@ -430,46 +446,46 @@ bool XmlParameterImpl::GetElementAttributeBoolValue( const char* attributeName, if ( !ctmp ) { - if ( defaultValue ) - return defaultValue; - else - return false; + return defaultValue; } return !misc::CaseInsensitiveStringCompare( (const char*)ctmp, "TRUE" ); } +bool XmlParameterImpl::GetElementAttributeBoolValue( const char* attributeName ) const +{ + const char* ctmp = GetAttribute( mNodePtr, attributeName, true ); + return !misc::CaseInsensitiveStringCompare( (const char*)ctmp, "TRUE" ); +} + int XmlParameterImpl::GetElementAttributeIntValue( const char* attributeName, int defaultValue ) const { const char* ctmp = GetAttribute( mNodePtr, attributeName, false ); if ( !ctmp ) { - if ( defaultValue ) - return defaultValue; - - else - return 0; + return defaultValue; } return atoi( GetAttribute( mNodePtr, attributeName ) ); } +int XmlParameterImpl::GetElementAttributeIntValue( const char* attributeName ) const +{ + const char* ctmp = GetAttribute( mNodePtr, attributeName, true ); + return atoi( GetAttribute( mNodePtr, attributeName ) ); +} + size_t XmlParameterImpl::GetElementAttributeUnsignedIntValue( const char* attributeName, size_t defaultValue ) const { const size_t attribute = size_t( abs( this->GetElementAttributeIntValue( attributeName, defaultValue ) ) ); - - if ( attribute < 1 ) - { - if ( defaultValue ) - return defaultValue; - - else - return 0; - } - else - return attribute; + return attribute; } +size_t XmlParameterImpl::GetElementAttributeUnsignedIntValue( const char* attributeName ) const +{ + const size_t attribute = size_t( abs( this->GetElementAttributeIntValue( attributeName ) ) ); + return attribute; +} double XmlParameterImpl::GetElementAttributeDoubleValue( const char* attributeName, double defaultValue ) const { @@ -477,15 +493,17 @@ double XmlParameterImpl::GetElementAttributeDoubleValue( const char* attributeNa if ( !ctmp ) { - if ( defaultValue ) - return defaultValue; - - else - return 0; + return defaultValue; } return atof( GetAttribute( mNodePtr, attributeName ) ); } +double XmlParameterImpl::GetElementAttributeDoubleValue( const char* attributeName ) const +{ + const char* ctmp = GetAttribute( mNodePtr, attributeName, true ); + return atof( GetAttribute( mNodePtr, attributeName ) ); +} + // Private diff --git a/src/xmlparser/tinyxml2/xmlparameterimpl.h b/src/xmlparser/tinyxml2/xmlparameterimpl.h index 3f6cf3f231c36fb641f12869e03d6eb1ced47114..61a6a9fc35564701d1fe4d134ed4246725a1a2eb 100644 --- a/src/xmlparser/tinyxml2/xmlparameterimpl.h +++ b/src/xmlparser/tinyxml2/xmlparameterimpl.h @@ -59,7 +59,9 @@ class XmlParameterImpl : public xmlparser::XmlParameter bool GetElementBoolValue( const char* elementName = 0, bool defaultValue = false ) const; - double GetElementDoubleValue( const char* elementName = 0, double defaultValue = 0 ) const; + double GetElementDoubleValue( const char* elementName = 0 ) const; + + double GetElementDoubleValue( const char* elementName, double defaultValue ) const; int GetElementIntValue( const char* elementName = 0, int defaultValue = 0 ) const; @@ -78,13 +80,17 @@ class XmlParameterImpl : public xmlparser::XmlParameter const char* GetElementAttributeCharPtrValue( const char* attributeName ) const; - bool GetElementAttributeBoolValue( const char* attributeName, bool defaultValue = false ) const; + bool GetElementAttributeBoolValue( const char* attributeName, bool defaultValue ) const; + bool GetElementAttributeBoolValue( const char* attributeName ) const; - int GetElementAttributeIntValue( const char* attributeName, int defaultValue = 0 ) const; + int GetElementAttributeIntValue( const char* attributeName, int defaultValue ) const; + int GetElementAttributeIntValue( const char* attributeName ) const; - size_t GetElementAttributeUnsignedIntValue( const char* attributeName, size_t defaultValue = 0 ) const; + size_t GetElementAttributeUnsignedIntValue( const char* attributeName, size_t defaultValue ) const; + size_t GetElementAttributeUnsignedIntValue( const char* attributeName ) const; - double GetElementAttributeDoubleValue( const char* attributeName, double defaultValue = 0 ) const; + double GetElementAttributeDoubleValue( const char* attributeName, double defaultValue ) const; + double GetElementAttributeDoubleValue( const char* attributeName ) const; // Writing to the xml file diff --git a/src/xmlparser/xmlparameter.h b/src/xmlparser/xmlparameter.h index 22bf2f198db0105c0241d5f453fe44be10ec7b63..357a386bad6823a84d7a9a54e7993c230f005586 100644 --- a/src/xmlparser/xmlparameter.h +++ b/src/xmlparser/xmlparameter.h @@ -80,8 +80,10 @@ class XmlParameter /// Finds a node with the given name and returns its value as bool virtual bool GetElementBoolValue( const char* elementName = nullptr, bool defaultValue = false ) const = 0; - /// Finds a node with the given name and returns it's value as double. Throws ParameterNotFoundException - virtual double GetElementDoubleValue( const char* elementName = nullptr, double defaultValue = 0 ) const = 0; + /// Finds a node with the given name and returns its value as double. Returns default value if node is not found. + virtual double GetElementDoubleValue( const char* elementName, double defaultValue ) const = 0; + /// Finds a node with the given name and returns its value as double. Throws ParameterNotFoundException. + virtual double GetElementDoubleValue( const char* elementName = 0 ) const = 0; /// Finds a node with the given name and returns its value as int. Throws ParameterNotFoundException virtual int GetElementIntValue( const char* elementName = nullptr, int defaultValue = 0 ) const = 0; @@ -110,17 +112,25 @@ class XmlParameter /// Finds an attribute with the given name and return its value. Throws AttributeNotFoundException virtual const char* GetElementAttributeCharPtrValue( const char* attributeName ) const = 0; - /// Finds an attribute with the given name and return its value as bool - virtual bool GetElementAttributeBoolValue( const char* attributeName, bool defaultValue = false ) const = 0; - - /// Finds an attribute with the given name and return its value as int - virtual int GetElementAttributeIntValue( const char* attributeName, int defaultValue = 0 ) const = 0; - - /// Finds an attribute with the given name and return its value as size_t - virtual size_t GetElementAttributeUnsignedIntValue( const char* attributeName, size_t defaultValue = 0 ) const = 0; - - /// Finds an attribute with the given name and return its value as double - virtual double GetElementAttributeDoubleValue( const char* attributeName, double defaultValue = 0 ) const = 0; + /// Finds an attribute with the given name and return its value as bool. Returns default value if attribute is not found. + virtual bool GetElementAttributeBoolValue( const char* attributeName, bool defaultValue ) const = 0; + /// Finds an attribute with the given name and return its value as bool. Throws exception if attribute is not found. + virtual bool GetElementAttributeBoolValue( const char* attributeName ) const = 0; + + /// Finds an attribute with the given name and return its value as int. Returns default value if attribute is not found. + virtual int GetElementAttributeIntValue( const char* attributeName, int defaultValue ) const = 0; + /// Finds an attribute with the given name and return its value as int. Throws exception if attribute is not found. + virtual int GetElementAttributeIntValue( const char* attributeName ) const = 0; + + /// Finds an attribute with the given name and return its value as size_t. Returns default value if attribute is not found. + virtual size_t GetElementAttributeUnsignedIntValue( const char* attributeName, size_t defaultValue ) const = 0; + /// Finds an attribute with the given name and return its value as size_t. Throws exception if attribute is not found. + virtual size_t GetElementAttributeUnsignedIntValue( const char* attributeName ) const = 0; + + /// Finds an attribute with the given name and return its value as double. Returns default value if attribute is not found. + virtual double GetElementAttributeDoubleValue( const char* attributeName, double defaultValue ) const = 0; + /// Finds an attribute with the given name and return its value as double. Throws exception if attribute is not found. + virtual double GetElementAttributeDoubleValue( const char* attributeName ) const = 0; /* Writing to the xml file */ diff --git a/standalone/standalone/aging_standalone.h b/standalone/standalone/aging_standalone.h index 5e8c8ffdff273233221b1bcbd8f0a5480f45175b..eb17f1b5ba19a92f5cfd470d8a619dc3f1a32663 100644 --- a/standalone/standalone/aging_standalone.h +++ b/standalone/standalone/aging_standalone.h @@ -28,7 +28,7 @@ class AgingStandalone : public ThermalElectricalStandalone size_t mAgingCycles; size_t mAgingSteps; size_t mSteadyStateCycles; - size_t mAgingStepTime; + size_t mAgingStepTime; /// Duration of one Aging Step in Days bool mResetThElStates; private: diff --git a/standalone/standalone/electrical_standalone.cpp b/standalone/standalone/electrical_standalone.cpp index 51515e37e71fcb19f29e32cea943e868a4162f54..18dc5827b7fdf50771de45759b866734d6f935b3 100644 --- a/standalone/standalone/electrical_standalone.cpp +++ b/standalone/standalone/electrical_standalone.cpp @@ -60,6 +60,7 @@ bool ElectricalStandalone::CreateElectricalSimulation( factory::FactoryBuilder< void ElectricalStandalone::SetCurrent() { + if ( mElectricalSimulation->mTime >= mProfileChangeTime ) { mProfile->SetTimeAndTriggerEvaluation( mElectricalSimulation->mTime ); @@ -70,6 +71,27 @@ void ElectricalStandalone::SetCurrent() return; } } + // If max. or min. voltage reached modify plan + else if ( mElectricalSimulation->IsStopElectricalCriterionFulfilled() ) + { + printf( "Move to the next Step\n" ); + double remainingTime = 0.0; + if ( mProfile->MoveToNextProfileValue( mElectricalSimulation->mTime, remainingTime ) ) + { + mElectricalSimulation->mRootTwoPort->AddRemainingLoadTime( remainingTime ); + // Update time limits when profile length has changed + UpdateProfileLength(); + mElectricalSimulation->UpdateSimulationDuration( mProfile->GetMaxTime() ); + mProfileChangeTime = mProfile->GetTimeUntilMaxValueDeviation( 0.0 ); + if ( mProfile->GetType() == electrical::TimeSeriesType::CURRENT ) + { + mElectricalSimulation->mRootTwoPort->SetCurrent( mProfile->GetValue() ); + mElectricalSimulation->mRootTwoPort->CalculateStateDependentValues(); + return; + } + } + } + if ( mProfile->GetType() == electrical::TimeSeriesType::POWER ) { diff --git a/standalone/standalone/simulation_standalone.cpp b/standalone/standalone/simulation_standalone.cpp index 0b5da664bb1eafc603ba3f2fb2d060a769290732..a8b22add83fa3ee74b03769dc1f4b25065f7fd04 100644 --- a/standalone/standalone/simulation_standalone.cpp +++ b/standalone/standalone/simulation_standalone.cpp @@ -96,6 +96,14 @@ void SimulationStandalone::ReadXmlOptions() mThermalStopCriterion = optionsNode->GetElementDoubleValue( "ThermalStopCriterionInDegreeC" ); if ( optionsNode->HasElementDirectChild( "Cycles" ) ) mCycles = optionsNode->GetElementUnsignedIntValue( "Cycles" ); + if ( optionsNode->HasElementDirectChild( "MaximalOperationalCellVoltageV" ) ) + mMaxCellVoltage = optionsNode->GetElementDoubleValue( "MaximalOperationalCellVoltageV" ); + else + mMaxCellVoltage = 10.0; // Default voltage limit electrical simulation + if ( optionsNode->HasElementDirectChild( "MinimalOperationalCellVoltageV" ) ) + mMinCellVoltage = optionsNode->GetElementDoubleValue( "MinimalOperationalCellVoltageV" ); + else + mMinCellVoltage = 0.0; // Default voltage limit electrical simulation if ( mOutputDecimation < 0.0 ) // set default value if no decimation was given on the command line mOutputDecimation = mStepTime; } @@ -104,4 +112,6 @@ void SimulationStandalone::FreeXml() { mParser.reset(); } double SimulationStandalone::GetProfileLength() { return mProfileLength; } +void SimulationStandalone::UpdateProfileLength() { mProfileLength = mProfile->GetMaxTime(); } + } // namespace standalone diff --git a/standalone/standalone/simulation_standalone.h b/standalone/standalone/simulation_standalone.h index e0ba4856813dd851bfdbdc93c2fc4c32fe3891a4..4a2edcd09f9192e096beb17a0a3619182beead26 100644 --- a/standalone/standalone/simulation_standalone.h +++ b/standalone/standalone/simulation_standalone.h @@ -21,6 +21,7 @@ class SimulationStandalone : public Standalone virtual void ReadXmlOptions(); void FreeXml(); double GetProfileLength(); + void UpdateProfileLength(); static void CheckHash( const std::string& filename ); static void PrintHash( const std::string& filename ); static void AddHash( const std::string& filename ); @@ -49,6 +50,9 @@ class SimulationStandalone : public Standalone double mProfileChangeTime; // electrical simulation + double mMaxCellVoltage; + double mMinCellVoltage; + }; } // namespace standalone diff --git a/toolchain_files/ToolchainWin64.cmake b/toolchain_files/ToolchainWin64.cmake index ace85786582e8f1192d300a1e500361777a854ab..81843f432d03c8d2938213704f123485833c63ad 100644 --- a/toolchain_files/ToolchainWin64.cmake +++ b/toolchain_files/ToolchainWin64.cmake @@ -9,6 +9,10 @@ set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc-posix) set(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++-posix) set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres) +# For static library creation the indexer should be run only once, e.g. by executing ranlib in the end. +# Hence, ar should be instructed to *not* index the static library. +set(CMAKE_STATIC_LINKER_FLAGS -S) + # some variables are apparently not propagated from the toolchain file, but the # cache should always work set(TOOLCHAIN_COMPILE_OPTIONS