diff --git a/.github/scripts/install_name_tool_macos.sh b/.github/scripts/install_name_tool_macos.sh index 9cd9d1d03..4f54f49ec 100755 --- a/.github/scripts/install_name_tool_macos.sh +++ b/.github/scripts/install_name_tool_macos.sh @@ -8,11 +8,12 @@ shopt -s -o nounset for exe in `ls *_x64` do echo "fixing paths in ${exe}" - for libpath in `otool -L ${exe} | grep "/" | grep -v "System" | awk '{print $1}'` + for libpath in `otool -L ${exe} | grep "/" | grep -v "/usr/lib" | grep -v "System" | awk '{print $1}'` do libfilename=${libpath##*/} echo install_name_tool -change $libpath @executable_path/$libfilename $exe install_name_tool -change $libpath @executable_path/$libfilename $exe + cp libpath "$(pwd)" done done @@ -29,7 +30,7 @@ do echo install_name_tool -id "@loader_path/$libfilename" $libfilename install_name_tool -id "@loader_path/$libfilename" $libfilename - for dependentlibpath in `otool -L ${libfilename} | grep "/" | grep -v "System" | awk '{print $1}'` + for dependentlibpath in `otool -L ${libfilename} | grep "/" | grep -v "/usr/lib" | grep -v "System" | awk '{print $1}'` do dependentlibfilename=${dependentlibpath##*/} # diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 3428fe41e..4c7be8978 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -1,194 +1,196 @@ name: CD -on: [push, workflow_dispatch] +on: + workflow_dispatch: + pull_request: + push: + branches: + - master + release: + types: + - published + jobs: - native-build: + MacOS: name: - native-build-${{ matrix.platform }} + Build on ${{ matrix.platform }} (for python3.10) strategy: fail-fast: false matrix: - platform: [windows-latest, ubuntu-latest, ubuntu-24.04-arm, macos-13, macos-latest] - #platform: [windows-latest, windows-11-arm, ubuntu-latest, ubuntu-24.04-arm, macos-13, macos-latest] - + platform: [ macos-15-intel, macos-15 ] runs-on: ${{ matrix.platform }} steps: - name: checkout vcell-ode repo - uses: actions/checkout@v4 - - - name: Install Windows Dependencies (Part 0 - Setup LLVM-style) - if: matrix.platform == 'windows-latest' || matrix.platform == 'windows-11-arm' - uses: llvm/actions/setup-windows@main + uses: actions/checkout@v6 with: - arch: amd64 - - - name: Install Windows Dependencies (Part 1 - Configure Conan ...and zip) - if: matrix.platform == 'windows-latest' || matrix.platform == 'windows-11-arm' - shell: powershell - run: | - choco install zip -y - choco install conan -y - $conanDir = "C:\Program Files\Conan\conan" - $env:PATH = "$conanDir;$env:PATH" - $conanDir | Set-Content -Path $env:GITHUB_PATH - $env:CONAN_HOME = "C:\.conan" - "CONAN_HOME=C:\.conan" | Out-File -FilePath $env:GITHUB_ENV -Append - conan --version - conan profile detect --force - - - name: Install Windows Dependencies (Part 2 - Reconfigure Conan) - if: matrix.platform == 'windows-latest' - shell: bash - run: | - cp conan-profiles/CI-CD/Windows-AMD64_profile.txt $CONAN_HOME/profiles/default - - - name: Install Windows Dependencies (Part 2 - Reconfigure Conan) - if: matrix.platform == 'windows-11-arm' - shell: bash - run: | - cp conan-profiles/CI-CD/Windows-ARM64_profile.txt $CONAN_HOME/profiles/default - + submodules: recursive + - name: Install MacOS dependencies - if: matrix.platform == 'macos-13' + if: matrix.platform == 'macos-15-intel' shell: bash run: | - brew install conan + brew install conan spdlog conan --version mkdir -p ~/.conan2/profiles/ touch ~/.conan2/profiles/default # if we don't make a file first, cp thinks its a folder that doesn't exist cp conan-profiles/CI-CD/MacOS-AMD64_profile.txt ~/.conan2/profiles/default - name: Install MacOS dependencies - if: matrix.platform == 'macos-latest' + if: matrix.platform == 'macos-15' shell: bash run: | - brew install conan + brew install conan spdlog conan --version mkdir -p ~/.conan2/profiles/ touch ~/.conan2/profiles/default # if we don't make a file first, cp thinks its a folder that doesn't exist cp conan-profiles/CI-CD/MacOS-ARM64_profile.txt ~/.conan2/profiles/default - - name: Install Linux Dependencies - if: matrix.platform == 'ubuntu-latest' + - name: Install Dependencies through Conan on MacOS + shell: bash run: | - sudo apt update - sudo apt upgrade -y - sudo apt install -y wget - wget --version - wget https://github.com/conan-io/conan/releases/download/2.17.0/conan-2.17.0-amd64.deb - sudo apt install -y ./conan-*.deb - conan --version - mkdir -p ~/.conan2/profiles/ - touch ~/.conan2/profiles/default # if we don't make a file first, cp thinks its a folder that doesn't exist - cp conan-profiles/CI-CD/Linux-AMD64_profile.txt ~/.conan2/profiles/default + conan install . --build=missing - - name: Install Linux Dependencies - if: matrix.platform == 'ubuntu-24.04-arm' + - name: Build Mac run: | - sudo apt update - python3 -m pip install conan - conan --version - mkdir -p ~/.conan2/profiles/ - touch ~/.conan2/profiles/default # if we don't make a file first, cp thinks its a folder that doesn't exist - cp conan-profiles/CI-CD/Linux-ARM64_profile.txt ~/.conan2/profiles/default + echo "working dir is $PWD" + cd build + source generators/conanbuild.sh + MACOSX_DEPLOYMENT_TARGET=15.0 cmake -B . -S .. -G "Ninja" -DCMAKE_TOOLCHAIN_FILE="generators/conan_toolchain.cmake" -DCMAKE_BUILD_TYPE=Release -DOPTION_TARGET_PYTHON_BINDING=ON + MACOSX_DEPLOYMENT_TARGET=15.0 cmake --build . --config Release - - name: Install Dependencies through Conan on Windows - if: matrix.platform == 'windows-latest' || matrix.platform == 'windows-11-arm' - shell: powershell + - name: Fix MacOS shared object paths + shell: bash run: | - conan install . --output-folder build --build=missing -o include_messaging=False + mkdir build/upload + cp -r build/lib/* build/bin + cd build/bin + ls *_x64 | awk '{print $1}' | xargs -I '{}' otool -L '{}' | grep ")" | grep -v "build" | grep -v "System" | grep -v "/usr/lib/" | awk '{print $1}' | xargs -I '{}' cp -vn '{}' . || true + ls *.dylib | awk '{print $1}' | xargs -I '{}' otool -L '{}' | grep ")" | grep -v "build" | grep -v "System" | grep -v "/usr/lib/" | awk '{print $1}' | xargs -I '{}' cp -vn '{}' . || true + ls *.dylib | awk '{print $1}' | xargs -I '{}' otool -L '{}' | grep ")" | grep -v "build" | grep -v "System" | grep -v "/usr/lib/" | awk '{print $1}' | xargs -I '{}' cp -vn '{}' . || true + chmod u+w,+x * + tar czvf ../upload/mac64_bad_paths.tgz . + ../../.github/scripts/install_name_tool_macos.sh + tar czvf ../upload/mac64.tgz --dereference . - - name: Install Dependencies through Conan on MacOS - if: matrix.platform == 'macos-13' || matrix.platform == 'macos-latest' - shell: bash + - name: Test Mac run: | - conan install . --output-folder build --build=missing + cd build + ctest -VV + echo "------ running SundialsSolverStandalone_x64 ------" + ./bin/SundialsSolverStandalone_x64 || true + + - name: Upload Intel Macos binaries + if: matrix.platform == 'macos-15-intel' && (github.event_name == 'pull_request' || (github.event_name == 'release' && github.event.action == 'published')) + uses: actions/upload-artifact@v7 + with: + name: macos_x86_64 + path: build/upload/mac64.tgz + + - name: Upload ARM Macos binaries + if: matrix.platform == 'macos-15' && (github.event_name == 'pull_request' || (github.event_name == 'release' && github.event.action == 'published')) + uses: actions/upload-artifact@v7 + with: + name: macos_arm64 + path: build/upload/mac64.tgz + + - name: Setup tmate session + if: ${{ failure() }} + uses: mxschmitt/action-tmate@v3 + with: + limit-access-to-actor: false + - - name: Install Dependencies through Conan on Linux - if: matrix.platform == 'ubuntu-latest' + WindowsOS: + name: + Build on ${{ matrix.platform }} (for python3.10) + strategy: + fail-fast: false + matrix: + platform: [ windows-latest, windows-11-arm ] + #platform: [ windows-latest ] + runs-on: ${{ matrix.platform }} + steps: + - name: Pre-install Configuration + if: matrix.platform == 'windows-latest' shell: bash run: | - sudo apt --purge remove gcc - sudo ln -s /usr/bin/clang /usr/bin/cc - sudo apt install mold libc++-dev libc++abi-dev - sudo rm /usr/bin/ld - sudo ln -s $(which mold) /usr/bin/ld - conan install . --output-folder build --build=missing + echo "CONAN_PROFILE_NAME=Windows-AMD64_profile.txt" >> $GITHUB_ENV + echo "CONAN_ENV_PATH=${{ github.workspace }}/build/conan_toolchain.cmake" | sed 's/\\/\//g' >> $GITHUB_ENV - - name: Install Dependencies through Conan on Linux - if: matrix.platform == 'ubuntu-24.04-arm' + - name: Pre-install Configuration + if: matrix.platform == 'windows-11-arm' shell: bash run: | - sudo apt --purge remove gcc - sudo ln -s /usr/bin/clang /usr/bin/cc - sudo ln -s /usr/bin/clang /usr/bin/gcc - sudo ln -s /usr/bin/clang++ /usr/bin/g++ - sudo apt install mold libc++-dev libc++abi-dev - sudo rm /usr/bin/ld - sudo ln -s $(which mold) /usr/bin/ld - conan install . --output-folder build --build=missing + echo "CONAN_PROFILE_NAME=Windows-ARM64_profile.txt" >> $GITHUB_ENV + echo "CONAN_ENV_PATH=${{ github.workspace }}/build/conan_toolchain.cmake" | sed 's/\\/\//g' >> $GITHUB_ENV + - name: checkout vcell-ode repo + uses: actions/checkout@v6 + with: + submodules: recursive - - name: Build Windows - if: matrix.platform == 'windows-latest' || matrix.platform == 'windows-11-arm' - shell: powershell - run: | - cd build - ./conanbuild.ps1 - cmake -B . -S .. -G "Ninja" -DCMAKE_TOOLCHAIN_FILE="conan_toolchain.cmake" -DCMAKE_BUILD_TYPE=Release - cmake --build . --config Release + - name: Install Windows Dependencies (Part 0 - Setup LLVM-style) + if: matrix.platform == 'windows-latest' + uses: llvm/actions/setup-windows@main + with: + arch: amd64 + + - name: Install Windows ARM64 Dependencies (Part 0 - Setup LLVM-style) + if: matrix.platform == 'windows-11-arm' + uses: llvm/actions/setup-windows@main + with: + arch: arm64 - - name: Build Unix - if: matrix.platform == 'ubuntu-latest' || matrix.platform == 'ubuntu-24.04-arm' || matrix.platform == 'macos-13' || matrix.platform == 'macos-latest' + - name: Install Windows Dependencies (Part 1 - Configure Conan ...et all) + shell: powershell run: | - echo "working dir is $PWD" + choco install zip -y + py -m pip install --upgrade conan + $pythonScripts = py -c "import sysconfig; print(sysconfig.get_path('scripts'))" + $env:PATH = "$pythonScripts;$env:PATH" + $pythonScripts | Set-Content -Path $env:GITHUB_PATH + $env:CONAN_HOME = "C:\.conan" + "CONAN_HOME=C:\.conan" | Out-File -FilePath $env:GITHUB_ENV -Append + conan --version + conan profile detect --force - cd build - source conanbuild.sh - cmake -B . -S .. -G "Ninja" -DCMAKE_TOOLCHAIN_FILE="conan_toolchain.cmake" -DCMAKE_BUILD_TYPE=Release - cmake --build . --config Release - - name: Test Windows - if: matrix.platform == 'windows-latest' || matrix.platform == 'windows-11-arm' + - name: Install Windows Dependencies (Part 2 - Reconfigure Conan) + shell: bash run: | - cd build - ctest -VV - ./bin/SundialsSolverStandalone_x64 || true + cp conan-profiles/CI-CD/${{ env.CONAN_PROFILE_NAME }} $CONAN_HOME/profiles/default - - name: Test Unix - if: matrix.platform == 'ubuntu-latest' || matrix.platform == 'ubuntu-24.04-arm' || matrix.platform == 'macos-13' || matrix.platform == 'macos-latest' + - name: Install Dependencies through Conan on Windows + shell: powershell run: | - cd build + conan install . --build=missing - ctest -VV - - echo "------ running SundialsSolverStandalone_x64 ------" - ./bin/SundialsSolverStandalone_x64 || true + - name: Set up Python 3.10 + if: matrix.platform == 'windows-latest' + uses: actions/setup-python@v6 + with: + python-version: "3.10" + - name: Set up Python 3.11 + if: matrix.platform == 'windows-11-arm' + uses: actions/setup-python@v6 + with: + python-version: "3.11" - - name: fix Macos shared object paths - if: matrix.platform == 'macos-13' || matrix.platform == 'macos-latest' - shell: bash + - name: Build Windows + shell: powershell run: | - mkdir build/upload - cd build/bin - rm hello_test TestVCellStoch testzip ziptool || true - ls *_x64 | awk '{print $1}' | xargs -I '{}' otool -L '{}' | grep ")" | grep -v "build" | grep -v "System" | awk '{print $1}' | xargs -I '{}' cp -vn '{}' . || true - ls *.dylib | awk '{print $1}' | xargs -I '{}' otool -L '{}' | grep ")" | grep -v "build" | grep -v "System" | awk '{print $1}' | xargs -I '{}' cp -vn '{}' . || true - ls *.dylib | awk '{print $1}' | xargs -I '{}' otool -L '{}' | grep ")" | grep -v "build" | grep -v "System" | awk '{print $1}' | xargs -I '{}' cp -vn '{}' . || true - chmod u+w,+x * - tar czvf ../upload/mac64_bad_paths.tgz . - ../../.github/scripts/install_name_tool_macos.sh - tar czvf ../upload/mac64.tgz --dereference . + cd build + ./generators/conanbuild.ps1 + cmake -B . -S .. -G "Ninja" -DCMAKE_TOOLCHAIN_FILE="generators/conan_toolchain.cmake" -DCMAKE_BUILD_TYPE=Release -DOPTION_TARGET_PYTHON_BINDING=ON + cmake --build . --config Release - - name: handle shared object paths for Windows native build - if: matrix.platform == 'windows-latest' || matrix.platform == 'windows-11-arm' + - name: Make Windows Shared Object Paths Relative shell: bash run: | mkdir build/upload cd build/bin - rm hello_test* *.pdb || true ls *.exe | awk '{print $1}' | xargs -I '{}' ldd '{}' | grep '=> /' | grep -v build | grep -iv windows | awk '{print $3}' | xargs -I '{}' cp -vn '{}' . || true # Currently, Sundials only requires system32 dlls! # ls *.dll | awk '{print $1}' | xargs -I '{}' ldd '{}' | grep '=> /' | grep -v build | grep -iv windows | awk '{print $3}' | xargs -I '{}' cp -vn '{}' . || true @@ -198,13 +200,158 @@ jobs: cd ../.. # fi - - name: handle shared object paths for Linux native build - if: matrix.platform == 'ubuntu-latest' || matrix.platform == 'ubuntu-24.04-arm' + - name: Test Windows + run: | + cd build + ctest -VV + ./bin/SundialsSolverStandalone_x64 || true + + - name: Upload Windows binaries + if: matrix.platform == 'windows-latest' && (github.event_name == 'pull_request' || (github.event_name == 'release' && github.event.action == 'published')) + uses: actions/upload-artifact@v7 + with: + name: win64_x86_64 + path: build/upload/win64.zip + + - name: Upload Windows binaries + if: matrix.platform == 'windows-11-arm' && (github.event_name == 'pull_request' || (github.event_name == 'release' && github.event.action == 'published')) + uses: actions/upload-artifact@v7 + with: + name: win64_arm64 + path: build/upload/win64.zip + + - name: Modify Archive Name + if: matrix.platform == 'windows-11-arm' && github.event_name == 'release' && github.event.action == 'published' + run: | + mv build/upload/win64.zip build/upload/win64arm.zip + + - name: Attach Windows Binaries to Release + uses: softprops/action-gh-release@v3 + if: matrix.platform == 'windows-latest' && github.event_name == 'release' && github.event.action == 'published' + with: + files: | + build/upload/win64.zip + + - name: Attach Windows Binaries to Release + uses: softprops/action-gh-release@v3 + if: matrix.platform == 'windows-11-arm' && github.event_name == 'release' && github.event.action == 'published' + with: + files: | + build/upload/win64arm.zip + + - name: Copy dll dependencies for python wheels + run: | + cp build/bin/*.dll pyvcell_odesolver/lib/ + + - name: Build Wheels (Windows) + if: github.event_name == 'pull_request' || (github.event_name == 'release' && github.event.action == 'published') + run: | + powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" + $env:Path = "C:\Users\runneradmin\.local\bin;$env:Path" + uv --version + uv sync --extra build --extra test + uv run pytest; if ($LASTEXITCODE -ne 0) { exit 1 } + uv build --wheel -o wheelhouse + + - name: Re-tag Wheels + if: matrix.platform == 'windows-latest' && (github.event_name == 'pull_request' || (github.event_name == 'release' && github.event.action == 'published')) + shell: bash + run: | + uv run python -m wheel tags --remove --platform-tag win_amd64 ./wheelhouse/$(ls ./wheelhouse) + + - name: Re-tag Wheels + if: matrix.platform == 'windows-11-arm' && (github.event_name == 'pull_request' || (github.event_name == 'release' && github.event.action == 'published')) + shell: bash + run: | + uv run python -m wheel tags --remove --platform-tag win_arm64 ./wheelhouse/$(ls ./wheelhouse) + + - name: Upload Python Wheel + if: github.event_name == 'pull_request' || (github.event_name == 'release' && github.event.action == 'published') + uses: actions/upload-artifact@v7 + with: + name: pyvcell-ode-${{ matrix.platform }} + path: ./wheelhouse/*.whl + + - name: Setup tmate session + if: ${{ failure() }} + uses: mxschmitt/action-tmate@v3 + with: + limit-access-to-actor: false + + Linux: + name: + Build for ${{ matrix.platform.name }} + strategy: + fail-fast: false + matrix: + platform: + - name: "GNU AMD64 Linux (glibc 2.28)" + type: "gnu_amd64" + image: "ghcr.io/virtualcell/fvsolver_manylinux_2_28_x86_64:0.1.3" + base: "ubuntu-latest" + - name: "GNU ARM64 Linux (glibc 2.28)" + type: "gnu_arm64" + image: "ghcr.io/virtualcell/fvsolver_manylinux_2_28_aarch64:0.1.3" + base: "ubuntu-24.04-arm" + + runs-on: ${{ matrix.platform.base }} + container: + image: ${{ matrix.platform.image }} + + steps: + - name: Install Node.js (required for actions runtime) + run: | + dnf module list nodejs + dnf module enable -y nodejs:24 + dnf install -y nodejs + + - name: Pre-install Configuration + if: matrix.platform.type == 'gnu_amd64' + shell: bash + run: | + echo "CONAN_PROFILE_NAME=Linux-AMD64_profile.txt" >> $GITHUB_ENV + + - name: Pre-install Configuration + if: matrix.platform.type == 'gnu_arm64' + shell: bash + run: | + echo "CONAN_PROFILE_NAME=Linux-ARM64_profile.txt" >> $GITHUB_ENV + + - name: checkout vcell-ode repo + uses: actions/checkout@v6 + with: + submodules: recursive + + - name: Install Conan and Set Default Profile + run: | + python3 -m pip install conan + mkdir -p ~/.conan2/profiles/ + cp conan-profiles/CI-CD/${{ env.CONAN_PROFILE_NAME }} ~/.conan2/profiles/default + + - name: Install Dependencies through Conan + run: | + CC="clang" CXX="clang++" conan install . --build=missing --build="m4/*" + + - name: Build Linux + run: | + echo "working dir is $PWD" + # Conan writes generators relative to the checkout (see layout() in + # conanfile.py), not to the image's /project dir, so keep these paths + # anchored to $PWD. Absolute is also the unambiguous form for + # CMAKE_TOOLCHAIN_FILE, which CMake otherwise resolves against the + # build tree first and the working dir only as a fallback. + echo "source $PWD/build/generators/conanbuild.sh" >> ~/.profile + echo "source $PWD/build/generators/conanbuild.sh" >> ~/.bashrc + source "$PWD/build/generators/conanbuild.sh" + CC="clang" CXX="clang++" cmake -B build -S . -G "Ninja" -DCMAKE_TOOLCHAIN_FILE="$PWD/build/generators/conan_toolchain.cmake" -DCMAKE_BUILD_TYPE=Release -DOPTION_TARGET_PYTHON_BINDING=ON + CC="clang" CXX="clang++" cmake --build build --config Release + + - name: Make Linux Shared Object Paths Relative shell: bash run: | mkdir build/upload + cp -r build/lib/* build/bin cd build/bin - rm hello_test TestVCellStoch testzip ziptool || true ls *_x64 | awk '{print $1}' | xargs -I '{}' ldd '{}' | grep "=> /" | grep -v "build" | awk '{print $3}' | xargs -I '{}' cp -vn '{}' . || true ls *.so | awk '{print $1}' | xargs -I '{}' ldd '{}' | grep "=> /" | grep -v "build" | awk '{print $3}' | xargs -I '{}' cp -vn '{}' . || true ls *.so | awk '{print $1}' | xargs -I '{}' ldd '{}' | grep "=> /" | grep -v "build" | awk '{print $3}' | xargs -I '{}' cp -vn '{}' . || true @@ -212,47 +359,202 @@ jobs: tar czvf ../upload/linux64.tgz --dereference . cd ../.. - - name: Upload Intel Macos binaries - if: matrix.platform == 'macos-13' - uses: actions/upload-artifact@v4 + - name: Test Linux + run: | + cd build + + ctest -VV + + echo "------ running SundialsSolverStandalone_x64 ------" + ./bin/SundialsSolverStandalone_x64 || true + + - name: Upload Linux (x86_64) binaries + if: matrix.platform.type == 'gnu_amd64' && (github.event_name == 'pull_request' || (github.event_name == 'release' && github.event.action == 'published')) + uses: actions/upload-artifact@v7 with: - name: macos_x86_64.tgz - path: build/upload/mac_x86_64.tgz + name: linux64_x86_64 + path: build/upload/linux64.tgz - - name: Upload ARM Macos binaries - if: matrix.platform == 'macos-latest' - uses: actions/upload-artifact@v4 + - name: Upload Linux (ARM64) binaries + if: matrix.platform.type == 'gnu_arm64' && (github.event_name == 'pull_request' || (github.event_name == 'release' && github.event.action == 'published')) + uses: actions/upload-artifact@v7 with: - name: macos_arm64.tgz - path: build/upload/mac_arm_64.tgz + name: linux64_arm64 + path: build/upload/linux64.tgz - - name: Upload Windows (x86_64) binaries - if: matrix.platform == 'windows-latest' - uses: actions/upload-artifact@v4 + - name: Modify Archive Name + if: matrix.platform.type == 'gnu_arm64' && github.event_name == 'release' && github.event.action == 'published' + run: | + mv build/upload/linux64.tgz build/upload/linux64arm.tgz + + - name: Attach Linux Binaries to Release + uses: softprops/action-gh-release@v3 + if: matrix.platform.type == 'gnu_amd64' && github.event_name == 'release' && github.event.action == 'published' with: - name: win64.zip - path: build/upload/win_x86_64.zip + files: | + build/upload/linux64.tgz - - name: Upload Windows (ARMv8) binaries - if: matrix.platform == 'windows-11-arm' - uses: actions/upload-artifact@v4 + - name: Attach Linux Binaries to Release + uses: softprops/action-gh-release@v3 + if: matrix.platform.type == 'gnu_arm64' && github.event_name == 'release' && github.event.action == 'published' with: - name: win64.zip - path: build/upload/win_ARMv8_64.zip + files: | + build/upload/linux64arm.tgz - - name: Upload Linux (x86_64) binaries - if: matrix.platform == 'ubuntu-latest' - uses: actions/upload-artifact@v4 + - name: Build Python Wheel + if: github.event_name == 'pull_request' || (github.event_name == 'release' && github.event.action == 'published') + run: | + curl -LsSf https://astral.sh/uv/install.sh | sh + uv --version + cp -r build/lib/* pyvcell_odesolver/lib/ + uv sync --extra build --extra test + uv run pytest + uv build --wheel -o wheelhouse + + - name: Re-tag Python Wheel + if: matrix.platform.type == 'gnu_amd64' && (github.event_name == 'pull_request' || (github.event_name == 'release' && github.event.action == 'published')) + run: uv run python -m wheel tags --remove --platform-tag manylinux_2_28_x86_64 ./wheelhouse/$(ls ./wheelhouse) + + - name: Re-tag Python Wheel + if: matrix.platform.type == 'gnu_arm64' && (github.event_name == 'pull_request' || (github.event_name == 'release' && github.event.action == 'published')) + run: uv run python -m wheel tags --remove --platform-tag manylinux_2_28_aarch64 ./wheelhouse/$(ls ./wheelhouse) + + - name: Upload Python Wheel + if: github.event_name == 'pull_request' || (github.event_name == 'release' && github.event.action == 'published') + uses: actions/upload-artifact@v7 with: - name: linux64.tgz - path: build/upload/linux_x86_64.tgz + name: pyvcell-ode-${{ matrix.platform.type }} + path: ./wheelhouse/*.whl - - name: Upload Linux (ARMv8) binaries - if: matrix.platform == 'ubuntu-24.04-arm' - uses: actions/upload-artifact@v4 + - name: Setup tmate session + if: ${{ failure() }} + uses: mxschmitt/action-tmate@v3 with: - name: linux64.tgz - path: build/upload/linux_ARMv8_64.tgz + limit-access-to-actor: false + + + MacOS-Universal: + name: Create Universal macOS Binary + runs-on: macos-15 + if: github.event_name == 'pull_request' || (github.event_name == 'release' && github.event.action == 'published') + needs: + - MacOS + + steps: + - name: checkout vcell-ode repo + uses: actions/checkout@v6 + + # The binaries are "named" (ID'd) different as artifacts, but not as filenames (`mac64.tgz`). + # As soon as we download one of them we need to rename it to avoid overwriting the other one. + - name: Download macOS-Arm64 binary + uses: actions/download-artifact@v8 + with: + name: macos_arm64 + path: binaries + + - name: Unpack & Rename macOS-Arm64 binary + run: | + mkdir binaries/arm + tar xzvf binaries/mac64.tgz -C binaries/arm + rm binaries/mac64.tgz + + - name: Download macOS-x86_64 binary + uses: actions/download-artifact@v4 + with: + name: macos_x86_64 + path: binaries + + - name: Unpack & Rename macOS-x86_64 binary + run: | + mkdir binaries/intel + tar xzvf binaries/mac64.tgz -C binaries/intel + rm binaries/mac64.tgz + + # this will go in the log of the run, useful for debugging + - name: Inspect binaries directory + run: | + echo "Contents of binaries/:" + ls -Rlh binaries/ + + # - name: Setup tmate session for inspection + # uses: mxschmitt/action-tmate@v3 + + - name: Combine with lipo + run: | + mkdir binaries/universal + for exe in `ls binaries/arm/ | grep ".*x64"` + do + echo "fixing ${exe}..." + lipo -create binaries/arm/$exe binaries/intel/${exe} \ + -output binaries/universal/${exe} + done + + for dylib in `ls binaries/arm/ | grep ".*\.dylib"` + do + echo "fixing ${dylib}..." + lipo -create binaries/arm/$dylib binaries/intel/${dylib} \ + -output binaries/universal/${dylib} + done + for entry in `ls binaries/universal/` + do + echo "confirming ${entry}..." + lipo -archs binaries/universal/${entry} + done + mv binaries/universal binaries/mac64 + cd binaries/mac64 + tar czvf macos-universal.tgz . + + - name: Inspect binaries directory + run: | + echo "Contents of binaries/:" + ls -Rlh binaries/ + + - name: Upload MacOS (Universal) binaries + uses: actions/upload-artifact@v7 + if: github.event_name == 'release' && github.event.action == 'published' + with: + name: macos64_universal + path: binaries/mac64/macos-universal.tgz + + - name: Rename MacOS Native Binaries for Release + if: github.event_name == 'release' && github.event.action == 'published' + run: | + cp binaries/mac64/macos-universal.tgz binaries/mac64.tgz + + - name: Attach MacOS Native Binaries to Release + uses: softprops/action-gh-release@v3 + if: github.event_name == 'release' && github.event.action == 'published' + with: + files: | + binaries/mac64.tgz + + - name: Copy dylib dependencies for python wheels + if: github.event_name == 'pull_request' || (github.event_name == 'release' && github.event.action == 'published') + run: | + cp binaries/mac64/*.dylib pyvcell_odesolver/lib/ + + - name: Install Python 3.10 + if: github.event_name == 'pull_request' || (github.event_name == 'release' && github.event.action == 'published') + uses: actions/setup-python@v6 + with: + python-version: '3.10' + + - name: Build Wheels + if: github.event_name == 'pull_request' || (github.event_name == 'release' && github.event.action == 'published') + run: | + curl -LsSf https://astral.sh/uv/install.sh | sh + uv --version + uv sync --extra build --extra test + uv run pytest + uv build --wheel -o wheelhouse + uv run python -m wheel tags --remove --platform-tag macosx_15_0_universal2 ./wheelhouse/$(ls ./wheelhouse) + + - name: Upload Python Wheel + uses: actions/upload-artifact@v7 + if: github.event_name == 'pull_request' || (github.event_name == 'release' && github.event.action == 'published') + with: + name: pyvcell-ode-macosx_universal2 + path: ./wheelhouse/*.whl - name: Setup tmate session if: ${{ failure() }} @@ -260,3 +562,44 @@ jobs: with: limit-access-to-actor: false + + publish-to-pypi: + name: Publish to PyPI + needs: [ WindowsOS, MacOS-Universal, Linux ] + runs-on: ubuntu-latest + if: github.event_name == 'release' && github.event.action == 'published' + environment: pypi + permissions: + id-token: write + + steps: + - name: Download all artifacts (wheels and executables) + uses: actions/download-artifact@v8 + with: + path: dist_temp/ + + - name: Install Python + uses: actions/setup-python@v6 + with: + python-version: '3.10' + + - name: Publish wheels to PyPI + env: + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }} + run: | + pip install twine + mkdir dist + echo "current directory is $(pwd)" + ls -al dist* + echo "absolute paths of wheels:" + find dist_temp -type f -name '*.whl' -exec sh -c 'echo "$(realpath {})"/' \; + echo "moving wheels to dist directory" + find dist_temp -type f -name '*.whl' -exec sh -c 'mv "$(realpath {})" dist/' \; + twine upload --verbose --repository pypi dist/*.whl + + - name: Setup tmate session for PyPI upload failure + uses: mxschmitt/action-tmate@v3 + if: ${{ failure() }} + with: + limit-access-to-actor: true diff --git a/.github/workflows/docker-deploy.yml b/.github/workflows/docker-deploy.yml index dda5774d5..875850b65 100644 --- a/.github/workflows/docker-deploy.yml +++ b/.github/workflows/docker-deploy.yml @@ -1,6 +1,14 @@ name: docker-deploy -on: [push, release] +on: + workflow_dispatch: + pull_request: + push: + branches: + - master + release: + types: + - published env: REGISTRY: ghcr.io @@ -9,6 +17,12 @@ env: jobs: build-and-push-image: runs-on: ubuntu-latest + services: + activemq: + image: rmohr/activemq:latest # Or a specific version like rmohr/activemq:5.15.9 + ports: + - 30163:30163 # JMS port + - 8161:8161 # Web console port permissions: contents: read packages: write diff --git a/.gitignore b/.gitignore index 0f8a2f4ad..1585f9b4c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,30 +1,40 @@ -/build-linux64-server/ -/build-dockcross-win64/ + /.project /.cproject -/build-win64/ /.DS_Store -/build-linux64/ -/build-macos/ /packages/ -/build_archive/ -/build-linux64-ubuntu/ + +/dist /conan/ /singularity/ -/cmake-build* -/build* -/debug-build* /.idea/ -/nfsim/ -/all_solvers/* .DS_Store -NFsim_v1.11/tests/smoke/SimID_273069657_0_.gdat -NFsim_v1.11/tests/smoke/SimID_273069657_0_.species - -IDAWin/tests/smoke/SimID_1489333437_0_.ida +*.ida CMakeUserPresets.json + +/build-linux64-server/ +/build-dockcross-win64/ +/build-win64/ +/build-linux64/ +/build-macos/ +/build_archive/ +/build-linux64-ubuntu/ +/build* +/cmake-build* +/debug-build* conan-build conan-build/* +conan_provider.cmake + +wheelhouse/ + +# Covers every package dir, including pyvcell_odesolver/_internal/, which the +# previous per-directory entries missed. +__pycache__/ + +pyvcell_odesolver/lib/*.dylib +pyvcell_odesolver/lib/*.dll +pyvcell_odesolver/lib/*.so diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..129f69bf0 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "vcell-messaging"] + path = vcell-messaging + url = https://github.com/virtualcell/vcell-messaging.git +[submodule "vcell-expressionparser"] + path = vcell-expressionparser + url = https://github.com/virtualcell/vcell-expressionparser.git diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..35f75693e --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,153 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## What this repo is + +`vcell-ode` is the ODE/DAE numerical solver used by the Virtual Cell framework (https://github.com/virtualcell/vcell). It produces two artifacts from one source tree: + +- **A standalone CLI** (`SundialsSolverStandalone_x64`) that VCell launches as a subprocess against a `.cvodeInput` file. +- **A Python wheel** (`pyvcell_odesolver`) exposing the same `solve()` entry by `ctypes`-loading the shared `IDAWin` library out of `pyvcell_odesolver/lib/`. + +The Python side is **pure Python + ctypes** — there is no compiled extension module. `IDAWin/SundialsSolverInterface.h` exports `extern "C"` shims (`version_ctypes`, `solve_ctypes`) alongside the C++ `version()`/`solve()`, and `pyvcell_odesolver/_internal/native_utils.py` binds them at import time. The vendored `extern/pybind11/` tree was removed once nothing referenced it. + +The numerical core is CVODE/IDA from a vendored copy of `sundials/`, wrapped by `IDAWin/`, with user rate laws evaluated via the `vcell-expressionparser` submodule. Optional progress messaging (libcurl → ActiveMQ over the JMS REST bridge) is provided by the `vcell-messaging` submodule. + +## Build + +CMake-driven. Conan 2.x supplies `spdlog` (and `libcurl` when messaging is on), plus `cmake`/`ninja` as `tool_requires`. Note two dependencies come from CMake `FetchContent`, **not** Conan, so configure needs network access to GitHub: + +- `argparse` — root `CMakeLists.txt`, pinned to `v3.2` (matching the `>=3.2 <4.0` range in `conanfile.py`). Conan also resolves argparse, but the FetchContent target is what actually gets linked. +- `googletest` — `tests/CMakeLists.txt`, pinned to `v1.17.0`. + +### Prerequisites + +Conan resolves the libraries, but you supply the toolchain. `conan-profiles/CI-CD/Linux-*_profile.txt` pins `compiler=clang`, `compiler.version=19`, `compiler.libcxx=libc++`, `compiler.cppstd=20`, and sets `-fuse-ld=mold` for exe and shared link flags — so a matching clang/libc++/mold must be on the box or Conan's ABI hash won't match the binaries it built. On Debian/Ubuntu: + +```bash +sudo apt install clang-19 libc++-19-dev libc++abi-19-dev mold +sudo ln -sf /usr/bin/clang-19 /usr/local/bin/clang +sudo ln -sf /usr/bin/clang++-19 /usr/local/bin/clang++ +``` + +The symlinks matter because CI drives the build as `CC=clang CXX=clang++`, and `compiler.version=19` in the profile must match what bare `clang` resolves to. + +Conan itself needs a Python with the `_sqlite3` extension; if the system interpreter lacks it, `uv tool install --python-preference only-managed conan` sidesteps it with a uv-managed CPython. + +`vcell-expressionparser` and `vcell-messaging` are git submodules — a plain `git clone` leaves both directories empty and CMake fails at `add_subdirectory`. Clone with `--recursive`, or in an existing checkout: + +```bash +git submodule update --init --recursive +``` + +Canonical native build (matches `.github/workflows/cd.yml`): + +```bash +CC=clang CXX=clang++ conan install . --build=missing +source build/generators/conanbuild.sh +CC=clang CXX=clang++ cmake -B build -S . -G Ninja \ + -DCMAKE_TOOLCHAIN_FILE="$PWD/build/generators/conan_toolchain.cmake" \ + -DCMAKE_BUILD_TYPE=Release +cmake --build build --config Release +cd build && ctest -VV +``` + +**Where the generator files land is decided by `layout()` in `conanfile.py`, not by `--output-folder`.** `layout()` calls `cmake_layout()` and then flattens the tree to `build/` + `build/generators/` *only when* `tools.cmake.cmaketoolchain:generator=Ninja` is set in the active profile. Without that conf, `cmake_layout()` inserts the build type and you get `build/Release/generators/` instead — which is exactly how the Linux and macOS CI jobs broke once they stopped passing `--output-folder`. Every CI profile therefore sets that conf; if you build with a hand-rolled `conan profile detect` profile, either add it or adjust your paths to `build/Release/generators/`. + +`source build/generators/conanbuild.sh` matters: it puts Conan's `cmake`/`ninja` on `PATH`. The `tool_requires` floor is `ninja>=1.12.1`, above what Ubuntu 24.04 ships, so the system `ninja` will not satisfy it. + +Wheel build. The backend is **`uv_build`** (`pyproject.toml`), *not* scikit-build-core — it does not invoke CMake at all. The native library is built first by the CMake run above (with `-DOPTION_TARGET_PYTHON_BINDING=ON`, which sends shared libs to `build/lib/`), then hand-copied into the package before `uv` packages it. This is the sequence from `cd.yml`: + +```bash +cmake -B build -S . -G Ninja \ + -DCMAKE_TOOLCHAIN_FILE="$PWD/build/generators/conan_toolchain.cmake" \ + -DCMAKE_BUILD_TYPE=Release -DOPTION_TARGET_PYTHON_BINDING=ON +cmake --build build --config Release +cp -r build/lib/* pyvcell_odesolver/lib/ # <-- ctypes finds the .so here at runtime +uv sync --extra build --extra test +uv run pytest +uv build --wheel -o wheelhouse +``` + +The wheel is then re-tagged for the manylinux platform with `uv run python -m wheel tags --remove --platform-tag manylinux_2_28_x86_64 ...`. `pyvcell_odesolver/lib/` is committed with only a `README.md` placeholder; forgetting the `cp` yields a wheel that imports but raises `OSError: Could not find the shared library` from `native_utils.py`. + +The complete option set in the root `CMakeLists.txt`: + +- `OPTION_TARGET_PYTHON_BINDING` (default OFF) — targets the wheel. Combining it with `OPTION_TARGET_MESSAGING=ON` is a **hard `FATAL_ERROR`** at configure time (it does *not* silently force messaging off). It leaves `CMAKE_LIBRARY_OUTPUT_DIRECTORY` at `build/lib/` instead of redirecting it to `build/bin/`, skips the install-prefix/`OPTION_EXE_DIRECTORY` setup, and adds `install(TARGETS IDAWin DESTINATION pyvcell_odesolver)`. The standalone exe **is still built** in this mode — `IDAWin/CMakeLists.txt` adds that target unconditionally and it lands in `build/bin/` either way. +- `OPTION_TARGET_MESSAGING` (default OFF) — adds `-DUSE_MESSAGING`, links libcurl, and changes the install layout (`OPTION_EXE_DIRECTORY` → `../bin`). Without it, `vcell-messaging` still builds, but the curl path is replaced by `NullCurlProxy` (the `AbstractCurlProxy` polymorphism — not `#ifdef` forests). +- `OPTION_TEST_WITH_LOCALHOST` — adds `-DTEST_WITH_LOCALHOST`; flips `tests/unit/smoke_test.cpp` to the localhost-keyed expected-output baseline. +- `OPTION_STATICALLY_LINK`, `OPTION_TARGET_DOCS`, `OPTION_EXTRA_CONFIG_INFO` — niche flags; rarely flipped. + +Conan profiles for CI live under `conan-profiles/CI-CD/`, one per `(platform, arch)`; CI copies the matching one to `~/.conan2/profiles/default`. They pin `compiler.cppstd=20`, `compiler.libcxx=libc++`, add `mold` for Linux linking, and set `tools.cmake.cmaketoolchain:generator=Ninja` (load-bearing — see the `layout()` note above). For local dev, `conan profile detect --force` also works if you bump `cppstd` to `20` — but it will pick up gcc/libstdc++ and the system linker, which is a *different ABI configuration* than CI ships. Don't compare binaries across the two. + +Platform notes (full recipes in `cd.yml`): +- **Linux**: CI builds inside `ghcr.io/virtualcell/fvsolver_manylinux_2_28_{x86_64,aarch64}` containers, which already carry clang/libc++/mold/cmake/ninja; the job only `pip install conan`s on top. On a bare host, install the toolchain yourself (see Prerequisites). +- **macOS** (arm64 + x86_64): Homebrew `conan` + `spdlog`. arm64 and x86_64 wheels build separately; a `MacOS-Universal` job `lipo`s the resulting `_x64`/`.dylib` files. +- **Windows**: LLVM toolchain via `llvm/actions/setup-windows`, conan + chocolatey. `OPTION_TARGET_MESSAGING` is OFF on Windows, and `requirements()` in `conanfile.py` drops the `libcurl` requirement there outright, so the workflow needs no `-o include_messaging=False`. Builds with `compiler=clang` + `clang-cl`, for which Conan derives the Visual Studio version from **`compiler.runtime_version`** (`v143`/`v144` → VS 17, `v145` → VS 18) — `tools.microsoft.msbuild:vs_version` is consulted only when `compiler=msvc`. The x86_64 and ARM64 runner images carry different VS versions, so the two profiles pin different values; see the comments in `conan-profiles/CI-CD/Windows-*_profile.txt`. +- **Docker** (`Dockerfile`): Debian trixie-slim + clang-19 + libc++-19 + mold + ninja + cmake + spdlog from apt; builds with `OPTION_TARGET_MESSAGING=ON` and `OPTION_TEST_WITH_LOCALHOST=ON`. This is the image published to ghcr.io. + +## Tests + +`ctest -VV` from `build/` runs four C++ tests built into `build/bin/unit_tests`, plus optionally a Python test: + +- `SmokeTest.UserProvidesFilesWithoutJMS` / `SmokeTest.UserProvidesFilesWithJMS` (`tests/unit/smoke_test.cpp`) — runs CVODE against `tests/unit/resources/SimID_*_.cvodeInput` and diffs the output against `*.ida.expected` with relative tolerance `1e-7`. The "WithJMS" variant uses `taskID=2025` and selects the `886118677` (localhost) or `256118677` (vcell.cam.uchc.edu) baseline based on `TEST_WITH_LOCALHOST`. Both variants pass with messaging off — the solver no-ops the curl path under `NullCurlProxy`. +- `HelloTest.BasicAssertions` (`tests/unit/hello_test.cpp`) — gtest sanity. +- `MessageProcessingTest.MessagesAreProcessed` (`tests/unit/message_processing_test.cpp`) — exercises `MessageEventManager` directly (worker thread + lock-ordered queue), independent of `OPTION_TARGET_MESSAGING`. +- `python_smoke_test` (`tests/unit/smoke_test.py`) — pytest, exercises `pyvcell_odesolver.solve()` against the same `1489333437` resource the C++ smoke uses. Registration is **skipped at configure time** unless `${PYTHON_TEST_INTERPRETER}` can `import pyvcell_odesolver`. To enable it locally: build the wheel, install it into a venv, then re-run `cmake -DPYTHON_TEST_INTERPRETER=/bin/python .`. CI's native ctest job uses the system Python so the entry skips silently; the wheel is exercised separately by the `uv run pytest` step in `cd.yml`, after `build/lib/*` has been copied into `pyvcell_odesolver/lib/`. `pyproject.toml` sets `testpaths = ["tests"]` and `filterwarnings = ["error"]`, so any warning under pytest is a failure. + +Run a single test: `ctest -VV -R `. Smoke-test inputs live next to the script and are baselined — if you intentionally change numerical output, regenerate the `.expected` files. + +`ExpressionParserTest/ExpressionParserTest.cpp` exists but is not currently wired into ctest. + +## Produced binaries + +In native builds, `build/bin/` contains: +- `SundialsSolverStandalone_x64` — the CLI VCell invokes; `argparse`-driven, takes ` [-tid ]`. +- `unit_tests` — gtest binary with the C++ tests above. + +In Python-binding builds, `build/lib/` holds `libIDAWin.so` — the only shared object, since `vcell*`/`sundials*` build as static archives and get linked into it — alongside those `.a` files and googletest's. `cd.yml` copies the whole directory into `pyvcell_odesolver/lib/`; the archives are inert baggage, because `check_arch.py`/`native_utils.py` only consider files matching the platform's shared-library extension. There is no per-interpreter extension module, so the wheel is ABI-independent of the Python version — only the platform tag matters. + +The Python API (`pyvcell_odesolver/sundials.py`, re-exported from `__init__.py`): +- `version() -> str` — the solver version string, unwrapped from the `ReturnValue` model's `.message`. +- `solve(input_file_path, output_file_path, task_id=-1) -> int` — `task_id=-1` skips messaging; positive values are JMS job IDs. Returns **0 on success** (it inverts `ReturnValue.success` to mimic a process exit code). + +`pyvcell_odesolver/_internal/` holds the ctypes layer: `native_utils.py` (`VCellNativeLibraryLoader` — scans `pyvcell_odesolver/lib/`, loads each candidate and keeps the first whose `version_ctypes()` contains `"VCell ODE solver (CVODE/IDA) v"`), `native_calls.py` (`ODENativeCalls`, returning pydantic `ReturnValue` models — hence the `pydantic>=2.13.4` runtime dep), and `check_arch.py` (filters candidate libs by architecture). + +## Architecture + +Top-level subdirectories and how they fit: + +- **`vcell-expressionparser/`** (submodule, target `vcellexpressionparser`) — math expression parser (AST `Node`s, `Expression`, `SymbolTable`, `StackMachine`). Used by `IDAWin` to evaluate user-supplied rate laws, initial conditions, and event/discontinuity expressions. Headers live under `include/`, sources under `src/`. Requires C++20 — the AST nodes build error messages with `std::format`. +- **`sundials/`** (vendored, modified) — CVODE + IDA + nvec_ser. A thin top-level `add_subdirectory` aggregates `sundials_cvode`/`sundials_ida`/`sundials_nvecserial`/`sundials_lib` into the `sundials` interface target. +- **`IDAWin/`** — the solver layer. Decomposed (since the stabilization branch) into: + - `VCellSolver.h` — abstract base (`configureFromInput`, `solve`). + - `VCellSolverInput.{h,cpp}` — `VCellSolverInputBreakdown` struct-of-structs holding `ModelSettings`, `TimeCourseSettings`, `SteadyStateSettings`, `DiscontinuitiesSettings`, `EventSettings`. + - `VCellSolverFactory.{h,cpp}` — parses the `.cvodeInput` file into the breakdown and produces the right `VCellSolver` subclass. + - `VCellSundialsSolver.{h,cpp}` — common sundials machinery (events, discontinuities, output, stop-checking). + - `VCellCVodeSolver` / `VCellIDASolver` — concrete subclasses for ODE and DAE. + - `SundialsSolverInterface.{h,cpp}` — the `solve(input, output, tid)` entry shared by the CLI and Python. Also declares the `IDAWIN_API` visibility macro and the `extern "C"` ctypes shims `version_ctypes()` / `solve_ctypes()` that the wheel binds to. + - `SundialsSolverStandalone.cpp` — `argparse`-based `main` that calls `solve()`. + + `IDAWin` builds SHARED by default; `OPTION_STATICALLY_LINK` switches it to STATIC (or to a SHARED lib with statically-linked deps when combined with `OPTION_TARGET_PYTHON_BINDING`). +- **`vcell-messaging/`** (submodule, target `vcellmessaging`) — progress messaging. Decomposed into: + - `SimulationMessaging` — the singleton facade. + - `MessageEventManager` — owns the worker `std::thread` and the event queue; lock ordering documented in the header (**queue mutex *before* the `stopRequested` mutex** — this is the reverse of the pre-submodule in-tree copy, which deadlocked). Shutdown joins the worker rather than waiting for the queue to drain: an empty queue is not the same as "all work finished", since the worker pops under the lock but sends after releasing it. + - `CurlProxyClasses` — `AbstractCurlProxy` / `NullCurlProxy` (always built) / `CurlProxy` (only under `USE_MESSAGING`); polymorphism replaces the old `#ifdef` forests. + - `JobEventStatus` — `JobEvent::Status` namespaced enum + `toString`. + - `WorkerEvent` — the queue payload. +- **`pyvcell_odesolver/`** — the Python package (pure Python; see "Produced binaries" above). `lib/` is the drop point for the native shared libraries and ships with only a `README.md` placeholder in git. +- **`tests/`** — gtest C++ tests, pytest Python tests, and resource files. `RESOURCE_DIR` is passed to the C++ tests via `target_compile_definitions`; the Python test resolves resources via `Path(__file__).parent / "resources"`. +- **`conan-profiles/CI-CD/`** — per-platform Conan profiles; CI copies the matching one to `~/.conan2/profiles/default`. +- **`cmake/modules/`** — `GetGitRevisionDescription.cmake` (used to stamp `g_GIT_DESCRIBE` into `vcell-messaging/src/GitDescribe.cpp`, which the version string surfaces). + +Public headers for shared libraries live in their own dir and are pulled in via `target_include_directories(... PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})` (or `include/` for the two submodules and `sundials`) — there are no installed include dirs at configure time. + +## Repo conventions worth knowing + +- Executables always go to `build/bin/`. Shared libraries go to `build/bin/` too in native builds, but stay in `build/lib/` when `OPTION_TARGET_PYTHON_BINDING=ON` — which is why both the native release step and the wheel step in `cd.yml` start with a `cp -r build/lib/* `. +- `cmake-build-debug/` is the CLion out-of-source build dir; `build/` is the canonical CI/Docker dir. Both are gitignored. +- `sundials/` is vendored; prefer surgical edits over upstream re-syncs. +- Shared-library path fixup for releases is done post-build by `.github/scripts/install_name_tool_macos.sh` (macOS) and the `ldd | cp` loops in `cd.yml` (Linux/Windows). Don't introduce absolute `rpath`s into CMake. +- `OPTION_TARGET_PYTHON_BINDING=ON` and `OPTION_TARGET_MESSAGING=ON` are mutually exclusive — configure aborts with `FATAL_ERROR`. The Python wheel never carries a curl dependency. +- `pyproject.toml` is the source of truth for the Python package: build backend `uv_build`, `requires-python = ">=3.10"`, runtime dep `pydantic`, extras `test` (pytest) and `build` (build, wheel). Ruff lint config lives here too. +- Setting `-DOPTION_EXTRA_CONFIG_INFO=ON` dumps every CMake variable at the end of configure — handy for debugging Conan-generated targets. diff --git a/CMakeLists.txt b/CMakeLists.txt index f0400e856..c87e9ff49 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,15 +3,11 @@ # Top Level CMake File # ############################################## -cmake_minimum_required(VERSION 3.13) -project(vcell-ode-numerics) +cmake_minimum_required(VERSION 3.16) set(CMAKE_CXX_STANDARD 20) if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") endif () -enable_language(CXX) -enable_language(C) -#enable_language(Fortran) ############################################# # If this isn't explicitly set in cmake 3.x.x, we get warnings @@ -20,20 +16,66 @@ if(POLICY CMP0057) cmake_policy(SET CMP0057 NEW) endif() -if (WINDOWS) +if (WIN32) cmake_policy(SET CMP0091 NEW) endif () ############################################# -# Display extra CMAKE info while configuring +# Declare Options ############################################## +option(OPTION_TARGET_PYTHON_BINDING "build Python bindings" OFF) +option(OPTION_TARGET_MESSAGING "Messaging (requires libcurl)" OFF) +option(OPTION_TARGET_DOCS "Generate Doxygen documentation" OFF) +option(OPTION_TEST_WITH_LOCALHOST "Use localhost as server rather than vcell.cam.uchc.edu" OFF) option(OPTION_EXTRA_CONFIG_INFO "Print useful cmake debug info while configuring" OFF) +option(OPTION_STATICALLY_LINK "Decided whether to statically link, or use (and generate) dynamic shared libs" OFF) + +if(OPTION_TARGET_PYTHON_BINDING AND OPTION_TARGET_MESSAGING) + message(FATAL_ERROR "Can not build python bindings and enable messaging in the same build") +endif() + +############################################# +# MinGW check +############################################## +if (MINGW) + message("ERROR: Due to the requirements of the project, mingw builds are currently disabled. Native windows builds should still work.") + return() +endif () + +############################################# +# Static link check +############################################## + +if (OPTION_STATICALLY_LINK) + #set(BUILD_SHARED_LIBS OFF) + set(CMAKE_EXE_LINKER_FLAGS "-static") +else () + set(CMAKE_POSITION_INDEPENDENT_CODE ON) +endif () + +############################################# +# Python Binding check +############################################## +#if (OPTION_TARGET_PYTHON_BINDING) +# project( +# ${SKBUILD_PROJECT_NAME} +# VERSION ${SKBUILD_PROJECT_VERSION} +# LANGUAGES CXX C +# ) +# set(OPTION_TARGET_MESSAGING OFF) +#else() +# +#endif () + +project( + vcell-ode-numerics + LANGUAGES CXX C +) ############################################# # # Build 64bit binaries on Mac and target Macos 10.7 or later # -# set(CMAKE_Fortran_OSX_DEPLOYMENT_TARGET_FLAG "-mmacosx-version-min=10.7" CACHE PATH "") # set(CMAKE_OSX_DEPLOYMENT_TARGET "10.7" CACHE PATH "") # # Choose 32bit or 64bit target arch on Linux @@ -51,68 +93,57 @@ if (LINUX) set (ARCH_64bit FALSE) set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32") set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32") -# set (CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -m32") endif() if (LINUX_64bit_BINARIES) set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m64") set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m64") -# set (CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -m64") endif() endif() -#include (LocalJNI.cmake) +# Settings set(RULE_MESSAGES OFF) set(CMAKE_COLOR_MAKEFILE OFF) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules/") +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) # .exe, .dll +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) # .dylib, .so (non-plugin) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) # .lib, .a (static libs / import libs) include(GetGitRevisionDescription) git_describe(GIT_DESCRIBE) -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) +if (NOT OPTION_TARGET_PYTHON_BINDING) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) -#include (VCellCMakeShowVariables.txt) + #include (VCellCMakeShowVariables.txt) -if(DEFINED CMAKE_BUILD_TYPE) - SET(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.") -else() - SET(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.") -endif() + if(DEFINED CMAKE_BUILD_TYPE) + SET(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.") + else() + SET(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.") + endif() -#include (CMakeTestCCompiler) -#include (CheckCSourceCompiles) -#include (CheckCXXSourceCompiles) -#include (CheckStructHasMember) -#include (CheckLibraryExists) -#include (CheckFunctionExists) -#include (CheckCCompilerFlag) -#include (CheckCSourceRuns) -#include (CheckSymbolExists) -#include (CheckTypeSize) - -option(OPTION_TARGET_MESSAGING "Messaging (requires libcurl)" off) -option(OPTION_TARGET_DOCS "Generate Doxygen documentation" off) - - -if (${OPTION_TARGET_DOCS}) -# if (DOXYGEN_FOUND AND ${CMAKE_VERSION} GREATER_EQUAL 3.9) -# find_package(Doxygen -# REQUIRED dot -# OPTIONAL_COMPONENTS mscgen dia) -# set(DOXYGEN_GENERATE_HTML YES) -# set(DOXYGEN_GENERATE_MAN NO) -# doxygen_add_docs( -# doxygen -# ${PROJECT_SOURCE_DIR} -# COMMENT "Generate man pages" -# ) -# else() - add_custom_target(graphviz ALL - "${CMAKE_COMMAND}" "--graphviz=dependencies.dot" . - WORKING_DIRECTORY "${CMAKE_BINARY_DIR}") -# endif() -endif() + + if (${OPTION_TARGET_DOCS}) + # if (DOXYGEN_FOUND AND ${CMAKE_VERSION} GREATER_EQUAL 3.9) + # find_package(Doxygen + # REQUIRED dot + # OPTIONAL_COMPONENTS mscgen dia) + # set(DOXYGEN_GENERATE_HTML YES) + # set(DOXYGEN_GENERATE_MAN NO) + # doxygen_add_docs( + # doxygen + # ${PROJECT_SOURCE_DIR} + # COMMENT "Generate man pages" + # ) + # else() + add_custom_target(graphviz ALL + "${CMAKE_COMMAND}" "--graphviz=dependencies.dot" . + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}") + # endif() + endif() +endif(NOT OPTION_TARGET_PYTHON_BINDING) if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") @@ -121,49 +152,53 @@ endif() set(HDF5_BUILD_CPP_LIB OFF CACHE BOOL "" ) -set(LINUX FALSE) -if (${CMAKE_SYSTEM_NAME} MATCHES Linux) - set(LINUX TRUE) -endif() -set(WINDOWS FALSE) -if (${CMAKE_SYSTEM_NAME} MATCHES Windows) - set(WINDOWS TRUE) - set(WIN32 TRUE) - set(MINGW TRUE) -endif() +#if (WIN32) # Only linux is designed at this point to support messaging, but unix should work too (and our devs generally work on macs) +# set(OPTION_TARGET_MESSAGING OFF) +#endif() set (ARCH_64bit FALSE) if (CMAKE_SIZEOF_VOID_P EQUAL 8) set (ARCH_64bit TRUE) endif() -if (NOT APPLE AND NOT LINUX AND NOT WINDOWS) +if (NOT APPLE AND NOT LINUX AND NOT WIN32) message(FATAL_ERROR "Unsupported Operating System") endif() #--------------------------- # IDE SUPPORT #--------------------------- -if (WINDOWS) +if (WIN32) set(NETBEANS_WINDOWS TRUE) set(CMAKE_RC_FLAGS "-DGCC_WINDRES") -endif(WINDOWS) +endif(WIN32) #add_definitions(-DFORTRAN_UNDERSCORE) ############################################# # installation directories ############################################# -if (NOT OPTION_TARGET_MESSAGING) - set(OPTION_EXE_DIRECTORY "bin" CACHE PATH "installation directory") -else (NOT OPTION_TARGET_MESSAGING) - set(OPTION_EXE_DIRECTORY "../bin" CACHE PATH "installation directory") -endif (NOT OPTION_TARGET_MESSAGING) - -set(OPTION_LIB_DIRECTORY "lib" CACHE PATH "library directory") -set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}") +# You can install spdlog with the following: +# > Debian: sudo apt install libspdlog-dev +# > Homebrew: brew install spdlog +# > Conan: conan install --requires=spdlog/[*] ( it may be easier just to add to the conan file!) +# > vcpkg: vcpkg install spdlog + +if(NOT TARGET spdlog) + # Stand-alone build + find_package(spdlog REQUIRED) +endif() +if (NOT OPTION_TARGET_PYTHON_BINDING) + if (NOT OPTION_TARGET_MESSAGING) + set(OPTION_EXE_DIRECTORY "bin" CACHE PATH "installation directory") + else (NOT OPTION_TARGET_MESSAGING) + set(OPTION_EXE_DIRECTORY "../bin" CACHE PATH "installation directory") + endif (NOT OPTION_TARGET_MESSAGING) + set(OPTION_LIB_DIRECTORY "lib" CACHE PATH "library directory") + set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}") +endif (NOT OPTION_TARGET_PYTHON_BINDING) add_definitions(-DUNIX) @@ -178,39 +213,41 @@ if (OPTION_TARGET_MESSAGING) add_definitions(-DUSE_MESSAGING) endif() +if (OPTION_TEST_WITH_LOCALHOST) + add_definitions(-DTEST_WITH_LOCALHOST) +endif() + ###################################### # # Add subdirectories # ####################################### -add_subdirectory(VCellMessaging) -message(STATUS "adding ExpressionParser") -add_subdirectory(ExpressionParser) -message(STATUS "adding sundials") +add_subdirectory(vcell-messaging) +add_subdirectory(vcell-expressionparser) add_subdirectory(sundials) add_subdirectory(IDAWin) +enable_testing() +add_subdirectory(tests) set(DOWNLOAD_EXTRACT_TIMESTAMP true) cmake_policy(SET CMP0135 NEW) ############################################# # -# Declare and install dependency: Google-test +# Declare and dynamically net-install dependencies # ############################################## include(FetchContent) +############################################# +# Argparse +############################################## FetchContent_Declare( - googletest - GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG v1.17.0 + argparse + GIT_REPOSITORY https://github.com/p-ranav/argparse.git + GIT_TAG v3.2 ) -if (WINDOWS) - # For Windows: Prevent overriding the parent project's compiler/linker settings - set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) -endif() +FetchContent_MakeAvailable(argparse) -FetchContent_MakeAvailable(googletest) -enable_testing() ############################################# # @@ -226,10 +263,16 @@ if (OPTION_EXTRA_CONFIG_INFO) include(CMakePrintHelpers) cmake_print_variables(OPTION_TARGET_MESSAGING OPTION_TARGET_DOCS) -# cmake_print_variables(CMAKE_CXX_FLAGS CMAKE_C_FLAGS CMAKE_Fortran_FLAGS) cmake_print_variables(CMAKE_CXX_FLAGS CMAKE_C_FLAGS) - cmake_print_variables(CMAKE_SYSTEM_NAME WINDOWS WIN32 MINGW APPLE ARCH_64bit ARCH_32bit) -# cmake_print_variables(CMAKE_CPP_COMPILER CMAKE_C_COMPILER CMAKE_CXX_COMPILER CMAKE_Fortran_COMPILER) + cmake_print_variables(CMAKE_SYSTEM_NAME WIN32 APPLE LINUX ARCH_64bit ARCH_32bit) cmake_print_variables(CMAKE_CPP_COMPILER CMAKE_C_COMPILER CMAKE_CXX_COMPILER) endif () +if (OPTION_TARGET_PYTHON_BINDING) + # Find the module development requirements (requires FindPython from 3.17 or + # scikit-build-core's built-in backport) + find_package(Python REQUIRED COMPONENTS Interpreter) + # The install directory is the output (wheel) directory + install(TARGETS IDAWin DESTINATION pyvcell_odesolver) + +endif (OPTION_TARGET_PYTHON_BINDING) diff --git a/Dockerfile b/Dockerfile index f92d88759..5565be3ba 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,22 +1,33 @@ -FROM debian:bookworm-slim AS build +FROM debian:trixie-slim AS build SHELL ["/bin/bash", "-c"] RUN apt-get -y update && apt-get install -y apt-utils && apt-get remove --purge gcc -RUN apt-get install -y -qq -o=Dpkg::Use-Pty=0 clang mold ninja-build cmake libc++-dev libc++abi-dev libcurl4-openssl-dev \ - git curl wget ca-certificates python3 python3-pip +# line 1 => build dependencies +# line 2 => build tools +# line 3 => dependencies +RUN apt-get install -y -qq -o=Dpkg::Use-Pty=0 \ + git curl wget ca-certificates python3 python3-pip \ + mold ninja-build cmake clang-19 clang++-19 clang-tools-19 libc++-19-dev libc++abi-19-dev \ + libspdlog-dev libcurl4-openssl-dev + RUN rm $(which gcc) || true RUN rm $(which g++) || true RUN rm -rf /var/lib/apt/lists/* && rm /usr/bin/ld RUN ln -s $(which mold) /usr/bin/ld - +RUN clang-19 --version +RUN ln -s $(which clang-19) /usr/bin/clang +RUN clang++-19 --version +RUN ln -s $(which clang++-19) /usr/bin/clang++ COPY . /vcellroot RUN mkdir -p /vcellroot/build/bin WORKDIR /vcellroot/build -RUN /usr/bin/cmake .. -G Ninja -DOPTION_TARGET_MESSAGING=ON -DOPTION_TARGET_DOCS=OFF +RUN /usr/bin/cmake .. -G Ninja -DOPTION_TARGET_MESSAGING=ON -DOPTION_TARGET_DOCS=OFF -DOPTION_TEST_WITH_LOCALHOST=ON +#RUN /usr/bin/cmake .. -G Ninja -DOPTION_TARGET_MESSAGING=ON -DOPTION_TARGET_DOCS=OFF -DCMAKE_CXX_FLAGS="-fexperimental-library" # `experimental-library` needed for new j-thread feature! RUN ninja --verbose -RUN ctest -VV +RUN ctest -VV --output-on-failure +RUN rm /vcellroot/build/bin/unit_tests WORKDIR /vcellroot/build/bin ENV PATH="/vcellroot/build/bin:${PATH}" \ No newline at end of file diff --git a/ExpressionParser/ASTAddNode.cpp b/ExpressionParser/ASTAddNode.cpp deleted file mode 100644 index da0d3994e..000000000 --- a/ExpressionParser/ASTAddNode.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "ASTAddNode.h" -#include "ASTMinusTermNode.h" -#include "ExpressionException.h" -#include "ExpressionParserTreeConstants.h" -#include "StackMachine.h" - -ASTAddNode::ASTAddNode() : Node(JJTADDNODE) { -} - -ASTAddNode::ASTAddNode(int i) : Node(i) { -} - -ASTAddNode::~ASTAddNode() { -} - -string ASTAddNode::infixString(int lang, NameScope* nameScope) -{ - string buffer("("); - for (int i = 0;i < jjtGetNumChildren(); i ++){ - ASTMinusTermNode* pointer = dynamic_cast(jjtGetChild(i)); - if (pointer){ - buffer += jjtGetChild(i)->infixString(lang, nameScope); - }else{ - if (i>0) - buffer += " + "; - buffer += jjtGetChild(i)->infixString(lang, nameScope); - } - } - buffer += ")"; - - return buffer; -} - -void ASTAddNode::getStackElements(vector& elements) { - for (int i = 0;i < jjtGetNumChildren(); i ++){ - jjtGetChild(i)->getStackElements(elements); - if (i>0) - elements.push_back(StackElement(TYPE_ADD)); - } -} - -double ASTAddNode::evaluate(int evalType, double* values) { - - double sum = 0; - for (int i=0;ievaluate(evalType, values); - } - return sum; -} - -Node* ASTAddNode::copyTree() { - ASTAddNode* node = new ASTAddNode(); - for (int i=0;ijjtAddChild(jjtGetChild(i)->copyTree()); - } - return node; -} diff --git a/ExpressionParser/ASTAddNode.h b/ExpressionParser/ASTAddNode.h deleted file mode 100644 index b6728eaba..000000000 --- a/ExpressionParser/ASTAddNode.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef ASTADDNODE_H -#define ASTADDNODE_H - -#include "Node.h" - -class ASTAddNode : public Node -{ -public: - ASTAddNode(int i); - ~ASTAddNode(); - string infixString(int lang, NameScope* nameScope); - void getStackElements(vector& elements); - double evaluate(int evalType, double* values=0); - - Node* copyTree(); - -private: - ASTAddNode(); -}; - -#endif diff --git a/ExpressionParser/ASTAndNode.cpp b/ExpressionParser/ASTAndNode.cpp deleted file mode 100644 index f9a9adc84..000000000 --- a/ExpressionParser/ASTAndNode.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include "ASTAndNode.h" -#include "ExpressionException.h" -#include "ExpressionParserTreeConstants.h" -#include "StackMachine.h" - -ASTAndNode::ASTAndNode() : Node(JJTANDNODE) { -} - -ASTAndNode::ASTAndNode(int i) : Node(i) { -} - -ASTAndNode::~ASTAndNode() { -} - -bool ASTAndNode::isBoolean() { - return true; -} - -string ASTAndNode::infixString(int lang, NameScope* nameScope) -{ - - string buffer; - if(lang == LANGUAGE_VISIT){ - for (int i=0;iinfixString(lang,nameScope); - for (int i=1;iinfixString(lang,nameScope); - buffer += ")"; - } - }else{ - buffer+= "("; - for (int i=0;i0) - buffer += " && "; - buffer += jjtGetChild(i)->infixString(lang, nameScope); - } - buffer += ")"; - } - - return buffer; -} - -void ASTAndNode::getStackElements(vector& elements) { - for (int i=0;igetStackElements(elements);; - if (i>0) - elements.push_back(StackElement(TYPE_AND)); - } -} - -double ASTAndNode::evaluate(int evalType, double* values) { - double sum = 1; - ExpressionException* savedException = NULL; - for (int i = 0; i < jjtGetNumChildren(); i++) { - try { - if (jjtGetChild(i)->evaluate(evalType, values) == 0) { - return 0; - } - } catch(ExpressionException& ex){ - if (evalType == EVALUATE_VECTOR) { - throw ex; - } - savedException = new ExpressionException(ex.getMessage()); - } - } - - if (savedException != NULL){ - throw (*savedException); - }else{ - return sum; - } -} - -Node* ASTAndNode::copyTree() { - ASTAndNode* node = new ASTAndNode(); - for (int i=0;ijjtAddChild(jjtGetChild(i)->copyTree()); - } - return node; -} diff --git a/ExpressionParser/ASTAndNode.h b/ExpressionParser/ASTAndNode.h deleted file mode 100644 index 9eb15acbe..000000000 --- a/ExpressionParser/ASTAndNode.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef ASTANDNODE_H -#define ASTANDNODE_H - -#include "Node.h" - -class ASTAndNode : public Node -{ -public: - ASTAndNode(int i); - ~ASTAndNode(); - string infixString(int lang, NameScope* nameScope); - void getStackElements(vector& elements); - double evaluate(int evalType, double* values=0); - bool isBoolean(); - - Node* copyTree(); - -private: - ASTAndNode(); -}; - -#endif diff --git a/ExpressionParser/ASTExpression.cpp b/ExpressionParser/ASTExpression.cpp deleted file mode 100644 index 87c425dcd..000000000 --- a/ExpressionParser/ASTExpression.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "ASTExpression.h" -#include "ExpressionException.h" -#include "ExpressionParserTreeConstants.h" - -ASTExpression::ASTExpression() : Node(JJTEXPRESSION) { -} - -ASTExpression::ASTExpression(int i) : Node(i) { -} - -ASTExpression::~ASTExpression() { -} - -string ASTExpression::infixString(int lang, NameScope* nameScope) -{ - string buffer; - - for (int i = 0; i < jjtGetNumChildren(); i++) { - buffer += jjtGetChild(i)->infixString(lang, nameScope); - } - return buffer; -} - -void ASTExpression::getStackElements(vector& elements) { - for (int i = 0; i < jjtGetNumChildren(); i++) { - jjtGetChild(i)->getStackElements(elements); - } -} - -double ASTExpression::evaluate(int evalType, double* values) { - return jjtGetChild(0)->evaluate(evalType, values); -} - -Node* ASTExpression::copyTree() { - ASTExpression* node = new ASTExpression(); - for (int i=0;ijjtAddChild(jjtGetChild(i)->copyTree()); - } - return node; -} diff --git a/ExpressionParser/ASTExpression.h b/ExpressionParser/ASTExpression.h deleted file mode 100644 index 547d6a178..000000000 --- a/ExpressionParser/ASTExpression.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef ASTEXPRESSION_H -#define ASTEXPRESSION_H - -#include "Node.h" - -class ASTExpression : public Node -{ -public: - ASTExpression(int i); - ~ASTExpression(); - string infixString(int lang, NameScope* nameScope); - void getStackElements(vector& elements); - double evaluate(int evalType, double* values=0); - - Node* copyTree(); - -private: - ASTExpression(); -}; - -#endif diff --git a/ExpressionParser/ASTFloatNode.cpp b/ExpressionParser/ASTFloatNode.cpp deleted file mode 100644 index b52cbcfa5..000000000 --- a/ExpressionParser/ASTFloatNode.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include - -#include "ASTFloatNode.h" -#include "RuntimeException.h" -#include "ExpressionParserTreeConstants.h" -#include "StackMachine.h" - -ASTFloatNode::ASTFloatNode(double doubleValue) : Node(JJTFLOATNODE) { - // is not a number - if (doubleValue != doubleValue){ - throw RuntimeException("cannot set float node to NaN"); - } - value = doubleValue; -} - -ASTFloatNode::ASTFloatNode(int i) : Node(i) , value(0) -{ -} - -ASTFloatNode::~ASTFloatNode() { -} - -string ASTFloatNode::infixString(int lang, NameScope* nameScope) -{ - //if (value == NULL) { - // return string("NULL"); - //} else - if (value == 0.0) { - return string("0.0"); - } else { - char s[256]; - sprintf(s, "%.20lg\0", value); - return string(s); - } -} - -void ASTFloatNode::getStackElements(vector& elements) { - elements.push_back(StackElement(value)); -} - -double ASTFloatNode::evaluate(int evalType, double* values) { - return value; -} - -Node* ASTFloatNode::copyTree(){ - ASTFloatNode* node = new ASTFloatNode(value); - return node; -} - -bool ASTFloatNode::equals(Node* node) { - // - // check to see if the types and children are the same - // - if (!Node::equals(node)){ - return false; - } - - // - // check this node for same state (value) - // - ASTFloatNode* floatNode = (ASTFloatNode*)node; - if (floatNode->value != value){ - return false; - } - - return true; -} diff --git a/ExpressionParser/ASTFloatNode.h b/ExpressionParser/ASTFloatNode.h deleted file mode 100644 index 03082f6eb..000000000 --- a/ExpressionParser/ASTFloatNode.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef ASTFLOATNODE_H -#define ASTFLOATNODE_H - -#include "Node.h" - -class ASTFloatNode : public Node -{ -public: - ASTFloatNode(double i); - ASTFloatNode(int i); - ~ASTFloatNode(); - double value; - string infixString(int lang, NameScope* nameScope); - void getStackElements(vector& elements); - double evaluate(int evalType, double* values=0); - - Node* copyTree(); - bool equals(Node* node); -}; - -#endif diff --git a/ExpressionParser/ASTFuncNode.cpp b/ExpressionParser/ASTFuncNode.cpp deleted file mode 100644 index d531ba1dd..000000000 --- a/ExpressionParser/ASTFuncNode.cpp +++ /dev/null @@ -1,677 +0,0 @@ -#include - -#include -#include -using std::min; -using std::max; - -#include "ASTFuncNode.h" -#include "RuntimeException.h" -#include "ExpressionException.h" -#include "MathUtil.h" -#include "FunctionDomainException.h" -#include "FunctionRangeException.h" -#include "ExpressionParserTreeConstants.h" -#include "StackMachine.h" - -const int EXP = 0; -const int SQRT = 1; -const int ABS = 2; -const int POW = 3; -const int LOG = 4; -const int SIN = 5; -const int COS = 6; -const int TAN = 7; -const int ASIN = 8; -const int ACOS = 9; -const int ATAN = 10; -const int ATAN2 = 11; -const int MAX = 12; -const int MIN = 13; -const int CEIL = 14; -const int FLOOR = 15; -const int CSC = 16; -const int COT = 17; -const int SEC = 18; -const int ACSC = 19; -const int ACOT = 20; -const int ASEC = 21; -const int SINH = 22; -const int COSH = 23; -const int TANH = 24; -const int CSCH = 25; -const int COTH = 26; -const int SECH = 27; -const int ASINH = 28; -const int ACOSH = 29; -const int ATANH = 30; -const int ACSCH = 31; -const int ACOTH = 32; -const int ASECH = 33; -const int FACTORIAL = 34; -const int J1 = 35; - -int StackMachine_LookupTable[] = {TYPE_EXP, TYPE_SQRT, TYPE_ABS, TYPE_POW, - TYPE_LOG, TYPE_SIN, TYPE_COS, TYPE_TAN, TYPE_ASIN, TYPE_ACOS, TYPE_ATAN, - TYPE_ATAN2, TYPE_MAX, TYPE_MIN, TYPE_CEIL, TYPE_FLOOR, TYPE_CSC, TYPE_COT, - TYPE_SEC, TYPE_ACSC, TYPE_ACOT, TYPE_ASEC, TYPE_SINH, TYPE_COSH, TYPE_TANH, - TYPE_CSCH, TYPE_COTH, TYPE_SECH, TYPE_ASINH, TYPE_ACOSH, TYPE_ATANH, TYPE_ACSCH, - TYPE_ACOTH, TYPE_ASECH, TYPE_FACTORIAL, TYPE_J1 -}; - -const string functionNamesVCML[] = { - "exp", // 0 - "sqrt", // 1 - "abs", // 2 - "pow", // 3 - "log", // 4 - "sin", // 5 - "cos", // 6 - "tan", // 7 - "asin", // 8 - "acos", // 9 - "atan", // 10 - "atan2", // 11 - "max", // 12 - "min", // 13 - "ceil", // 14 - "floor", // 15 - "csc", // 16 - "cot", // 17 - "sec", // 18 - "acsc", // 19 - "acot", // 20 - "asec", // 21 - "sinh", // 22 - "cosh", // 23 - "tanh", // 24 - "csch", // 25 - "coth", // 26 - "sech", // 27 - "asinh", // 28 - "acosh", // 29 - "atanh", // 30 - "acsch", // 31 - "acoth", // 32 - "asech", // 33 - "factorial", // 34 - "j1" -}; - -//const int parserNumFunctions = 35; -const int parserNumFunctions = sizeof(StackMachine_LookupTable)/sizeof(StackMachine_LookupTable[0]); - -ASTFuncNode::ASTFuncNode() : Node(JJTFUNCNODE) { - funcType = -1; -} - -ASTFuncNode::ASTFuncNode(int i) : Node(i) { - funcType = -1; -} - -ASTFuncNode::~ASTFuncNode() { -} - -void ASTFuncNode::setFunctionFromParserToken(string parserToken) -{ - for (int i = 0; i < parserNumFunctions; i++){ - string definedToken = functionNamesVCML[i]; - if (definedToken == parserToken){ - funcType = i; - funcName = parserToken; - return; - } - } - throw RuntimeException("unsupported function '" + parserToken + "'"); -} - -string ASTFuncNode::infixString(int lang, NameScope* nameScope) -{ - string buffer; - - switch (funcType) { - case POW : - { - if (jjtGetNumChildren() != 2) { - throw ExpressionException("Function pow() expects 2 arguments"); - } - if (lang == LANGUAGE_MATLAB) { - buffer += "("; - buffer += jjtGetChild(0)->infixString(lang, nameScope); - buffer += " ^ "; - buffer += jjtGetChild(1)->infixString(lang, nameScope); - buffer += ")"; - } else if (lang == LANGUAGE_DEFAULT || lang == LANGUAGE_C) { - buffer += "pow("; - buffer += jjtGetChild(0)->infixString(lang, nameScope); - buffer += ","; - buffer += jjtGetChild(1)->infixString(lang, nameScope); - buffer += ")"; - } - break; - } - default : - { - buffer += funcName; - buffer += "("; - for (int i = 0; i < jjtGetNumChildren(); i++) { - if (i > 0) - buffer += ", "; - buffer += jjtGetChild(i)->infixString(lang, nameScope); - } - buffer += ")"; - break; - } - } - - return buffer; -} - -void ASTFuncNode::getStackElements(vector& elements) { - for (int i = 0; i < jjtGetNumChildren(); i++) { - jjtGetChild(i)->getStackElements(elements); - } - elements.push_back(StackElement(StackMachine_LookupTable[funcType])); -} - -double ASTFuncNode::evaluate(int evalType, double* values) -{ - double result = 0.0; - Node* child0 = jjtGetChild(0); - - switch (funcType) { - case EXP : - { - if (jjtGetNumChildren() != 1) - throw RuntimeException("exp() expects 1 argument"); - double argument = child0->evaluate(evalType, values); - result = exp(argument); - break; - } - case POW : - { - if (jjtGetNumChildren() != 2) - throw RuntimeException("pow() expects 2 arguments"); - Node* exponentChild = jjtGetChild(1); - Node* mantissaChild = child0; - double exponent = 0.0; - double mantissa = 0.0; - ExpressionException* exponentException = 0; - ExpressionException* mantissaException = 0; - try { - exponent = exponentChild->evaluate(evalType, values); - } catch (ExpressionException& e) { - if (evalType == EVALUATE_VECTOR) - throw e; - exponentException = new ExpressionException(e.getMessage()); - } - try { - mantissa = mantissaChild->evaluate(evalType, values); - } catch (ExpressionException& e) { - if (evalType == EVALUATE_VECTOR) - throw e; - mantissaException = new ExpressionException(e.getMessage()); - } - - if (exponentException == NULL && mantissaException == NULL) { - if (mantissa < 0.0 && (MathUtil::round(exponent) != exponent)) { - char problem[100]; - sprintf(problem, "pow(u,v) and u=%lf<0 and v=%lf not an integer", mantissa, exponent); - string errorMsg = getFunctionDomainError(problem, values, "u", mantissaChild, "v", exponentChild); - throw FunctionDomainException(errorMsg); - } - if (mantissa == 0.0 && exponent < 0) { - char problem[100]; - sprintf(problem, "pow(u,v) and u=0 and v=%lf<0 divide by zero", exponent); - string errorMsg = getFunctionDomainError(problem, values, "u", mantissaChild, "v", exponentChild); - throw FunctionDomainException(errorMsg); - } - result = pow(mantissa, exponent); - if (MathUtil::double_infinity == -result || MathUtil::double_infinity == result || result != result) { - char problem[1000]; - sprintf(problem, "u^v evaluated to %lf, u=%lf, v=%lf", result, mantissa, exponent); - string errorMsg = getFunctionDomainError(problem, values, "u", mantissaChild, "v", exponentChild); - throw FunctionDomainException(errorMsg); - } - } else if (exponentException == 0 && exponent == 0.0) { - result = 1.0; - } else if (mantissaException == 0 && mantissa == 1.0) { - result = 1.0; - } else { - if (mantissaException != NULL) { - throw (*mantissaException); - } else if (exponentException != NULL) { - throw (*exponentException); - } - } - break; - } - case LOG : - { - if (jjtGetNumChildren() != 1) - throw RuntimeException("log() expects 1 argument"); - double argument = child0->evaluate(evalType, values); - if (argument <= 0.0) { - char problem[1000]; - sprintf(problem, "log(u) and u=%lf <= 0.0 is undefined", argument); - string errorMsg = getFunctionDomainError(problem, values, "u", child0); - throw FunctionDomainException(errorMsg); - } - result = log(argument); - break; - } - case ABS : - { - if (jjtGetNumChildren() != 1) - throw RuntimeException("abs() expects 1 argument"); - double argument = child0->evaluate(evalType, values); - result = fabs(argument); - break; - } - case SQRT : - { - if (jjtGetNumChildren() != 1) - throw RuntimeException("sqrt() expects 1 argument"); - double argument = child0->evaluate(evalType, values); - if (argument < 0) { - char problem[1000]; - sprintf(problem, "sqrt(u) where u=%lf<0 is undefined", argument); - string errorMsg = getFunctionDomainError(problem, values, "u", child0); - throw FunctionDomainException(errorMsg); - } - result = sqrt(argument); - break; - } - case SIN : - { - if (jjtGetNumChildren() != 1) - throw RuntimeException("sin() expects 1 argument"); - double argument = child0->evaluate(evalType, values); - result = sin(argument); - break; - } - case COS : - { - if (jjtGetNumChildren() != 1) - throw RuntimeException("cos() expects 1 argument"); - double argument = child0->evaluate(evalType, values); - result = cos(argument); - break; - } - case TAN : - { - if (jjtGetNumChildren() != 1) - throw RuntimeException("tan() expects 1 argument"); - double argument = child0->evaluate(evalType, values); - result = tan(argument); - break; - } - case ASIN : - { - if (jjtGetNumChildren() != 1) - throw RuntimeException("asin() expects 1 argument"); - double argument = child0->evaluate(evalType, values); - if (fabs(argument) > 1.0) { - char problem[1000]; - sprintf(problem, "asin(u) and u=%lf and |u|>1.0 undefined", argument); - string errorMsg = getFunctionDomainError(problem, values, "u", child0); - throw FunctionDomainException(errorMsg); - } - result = asin(argument); - break; - } - case ACOS : - { - if (jjtGetNumChildren() != 1) - throw RuntimeException("acos() expects 1 argument"); - double argument = child0->evaluate(evalType, values); - if (fabs(argument) > 1.0) { - char problem[1000]; - sprintf(problem, "acos(u) and u=%lf and |u|>1.0 undefined", argument); - string errorMsg = getFunctionDomainError(problem, values, "u", child0); - throw FunctionDomainException(errorMsg); - } - result = acos(argument); - break; - } - case ATAN : - { - if (jjtGetNumChildren() != 1) - throw RuntimeException("atan() expects 1 argument"); - double argument = child0->evaluate(evalType, values); - result = atan(argument); - break; - } - case ATAN2 : - { - if (jjtGetNumChildren() != 2) - throw RuntimeException("atan2() expects 2 arguments"); - double argument0 = child0->evaluate(evalType, values); - double argument1 = jjtGetChild(1)->evaluate(evalType, values); - result = atan2(argument0, argument1); - break; - } - case MAX : - { - if (jjtGetNumChildren() != 2) - throw RuntimeException("max() expects 2 arguments"); - double argument0 = child0->evaluate(evalType, values); - double argument1 = jjtGetChild(1)->evaluate(evalType, values); - result = max(argument0, argument1); - break; - } - case MIN : - { - if (jjtGetNumChildren() != 2) - throw RuntimeException("min() expects 2 arguments"); - double argument0 = child0->evaluate(evalType, values); - double argument1 = jjtGetChild(1)->evaluate(evalType, values); - result = min(argument0, argument1); - break; - } - case CEIL : - { - if (jjtGetNumChildren() != 1) - throw RuntimeException("ceil() expects 1 argument"); - double argument = child0->evaluate(evalType, values); - result = ceil(argument); - break; - } - case FLOOR : - { - if (jjtGetNumChildren() != 1) - throw RuntimeException("floor() expects 1 argument"); - double argument = child0->evaluate(evalType, values); - result = floor(argument); - break; - } - case CSC: - { - if (jjtGetNumChildren() != 1) - throw RuntimeException("csc() expects 1 argument"); - double argument = child0->evaluate(evalType, values); - result = sin(argument); - if (result == 0) { - char problem[1000]; - sprintf(problem, "csc(u)=1/sin(u) and sin(u)=0 and u=%lf", argument); - string errorMsg = getFunctionDomainError(problem, values, "u", child0); - throw FunctionDomainException(errorMsg); - } - result = 1/result; - break; - } - case COT: - { - if (jjtGetNumChildren() != 1) - throw RuntimeException("cot() expects 1 argument"); - double argument = child0->evaluate(evalType, values); - result = tan(argument); - if (result == 0) { - char problem[1000]; - sprintf(problem, "cot(u)=1/tan(u) and tan(u)=0 and u=%lf", argument); - string errorMsg = getFunctionDomainError(problem, values, "u", child0); - throw FunctionDomainException(errorMsg); - } - result = 1/result; - break; - } - case SEC: - { - if (jjtGetNumChildren() != 1) - throw RuntimeException("sec() expects 1 argument"); - double argument = child0->evaluate(evalType, values); - result = cos(argument); - if (result == 0) { - char problem[1000]; - sprintf(problem, "sec(u)=1/cos(u) and cos(u)=0 and u=%lf", argument); - string errorMsg = getFunctionDomainError(problem, values, "u", child0); - throw FunctionDomainException(errorMsg); - } - result = 1/result; - break; - } - case ACSC: - { - if (jjtGetNumChildren() != 1) - throw RuntimeException("acsc() expects 1 argument"); - double argument = child0->evaluate(evalType, values); - if (fabs(argument) < 1.0){ - char problem[1000]; - sprintf(problem, "acsc(u) and -1evaluate(evalType, values); - if (argument == 0) { - string errorMsg = getFunctionDomainError("acot(u)=atan(1/u) and u=0", values, "u", child0); - throw FunctionDomainException(errorMsg); - } - result = MathUtil::acot(argument); - break; - } - case ASEC: - { - if (jjtGetNumChildren() != 1) - throw RuntimeException("asec() expects 1 argument"); - double argument = child0->evaluate(evalType, values); - if (fabs(argument) < 1.0){ - char problem[1000]; - sprintf(problem, "asec(u) and -1evaluate(evalType, values); - result = sinh(argument); - break; - } - case COSH: - { - if (jjtGetNumChildren() != 1) - throw RuntimeException("cosh() expects 1 argument"); - double argument = child0->evaluate(evalType, values); - result = cosh(argument); - break; - } - case TANH: - { - if (jjtGetNumChildren() != 1) - throw RuntimeException("tanh() expects 1 argument"); - double argument = child0->evaluate(evalType, values); - result = tanh(argument); - break; - } - case CSCH: - { - if (jjtGetNumChildren() != 1) - throw RuntimeException("csch() expects 1 argument"); - double argument = child0->evaluate(evalType, values); - if (argument == 0.0){ - char problem[1000]; - sprintf(problem, "csch(u) and |u| = 0, u=%lf", argument); - string errorMsg = getFunctionDomainError(problem, values, "u", child0); - throw FunctionDomainException(errorMsg); - } - result = MathUtil::csch(argument); - break; - } - case COTH: - { - if (jjtGetNumChildren() != 1) - throw RuntimeException("coth() expects 1 argument"); - double argument = child0->evaluate(evalType, values); - if (argument == 0.0){ - char problem[1000]; - sprintf(problem, "coth(u) and |u| = 0, u=%lf", argument); - string errorMsg = getFunctionDomainError(problem, values, "u", child0); - throw FunctionDomainException(errorMsg); - } - result = MathUtil::coth(argument); - break; - } - case SECH: - { - if (jjtGetNumChildren()!= 1) - throw RuntimeException("sech() expects 1 argument"); - double argument = child0->evaluate(evalType, values); - result = MathUtil::sech(argument); - break; - } - case ASINH: - { - if (jjtGetNumChildren() != 1 ){ - throw RuntimeException("asinh() expects 1 argument"); - } - double argument = child0->evaluate(evalType, values); - result = MathUtil::asinh(argument); - break; - } - case ACOSH: - { - if (jjtGetNumChildren()!=1) - throw RuntimeException("acosh() expects 1 argument"); - double argument = child0->evaluate(evalType, values); - if (argument < 1.0){ - char problem[1000]; - sprintf(problem, "acosh(u) and u=%lf<1.0", argument); - string errorMsg = getFunctionDomainError(problem, values, "u", child0); - throw FunctionDomainException(errorMsg); - } - result = MathUtil::acosh(argument); - break; - } - case ATANH: - { - if (jjtGetNumChildren()!=1) - throw RuntimeException("atanh() expects 1 argument"); - double argument = child0->evaluate(evalType, values); - if (fabs(argument) >= 1.0){ - char problem[1000]; - sprintf(problem, "atanh(u) and |u| >= 1.0, u=%lf", argument); - string errorMsg = getFunctionDomainError(problem, values, "u", child0); - throw FunctionDomainException(errorMsg); - } - result = MathUtil::atanh(argument); - break; - } - case ACSCH: - { - if (jjtGetNumChildren()!=1) - throw RuntimeException("acsch() expects 1 argument"); - double argument = child0->evaluate(evalType, values); - if (argument == 0.0){ - string errorMsg = getFunctionDomainError("acsch(u) and u=0", values, "u", child0); - throw FunctionDomainException(errorMsg); - } - result = MathUtil::acsch(argument); - break; - } - case ACOTH: - { - if (jjtGetNumChildren()!= 1) - throw RuntimeException("acoth() expects 1 argument"); - double argument = child0->evaluate(evalType, values); - if (fabs(argument) <= 1.0){ - char problem[1000]; - sprintf(problem, "acoth(u) and |u| <= 1.0, u=%lf", argument); - string errorMsg = getFunctionDomainError(problem, values, "u", child0); - throw FunctionDomainException(errorMsg); - } - result = MathUtil::acoth(argument); - break; - } - case ASECH: - { - if (jjtGetNumChildren()!=1) - throw RuntimeException("asech() expects 1 argument"); - double argument = child0->evaluate(evalType, values); - if (argument <= 0.0 || argument > 1.0){ - char problem[1000]; - sprintf(problem, "asech(u) and u <= 0.0 or u > 1.0, u=%lf", argument); - string errorMsg = getFunctionDomainError(problem, values, "u", child0); - throw FunctionDomainException(errorMsg); - } - result = MathUtil::asech(argument); - break; - } - case FACTORIAL: - { - if (jjtGetNumChildren()!= 1) - throw RuntimeException("factorial() expects 1 argument"); - double argument = child0->evaluate(evalType, values); - if (argument < 0.0 || (argument-(int)argument) != 0){ - char problem[1000]; - sprintf(problem, "factorial(u) and u=%lf < 0.0, or u is not an integer", argument); - string errorMsg = getFunctionDomainError(problem, values, "u", child0); - throw FunctionDomainException(errorMsg); - } - result = MathUtil::factorial(argument); - break; - } - case J1: - { - if (jjtGetNumChildren() != 1 ){ - throw RuntimeException("j1() expects 1 argument"); - } - double argument = child0->evaluate(evalType, values); - result = j1(argument); - break; - } - default : - { - throw RuntimeException("undefined function"); - } - } - //result is NAN - if (MathUtil::double_infinity == -result || MathUtil::double_infinity == result || result != result) { - char problem[1000]; - sprintf(problem, "%s evaluated to infinity or NaN", infixString(LANGUAGE_DEFAULT,0).c_str(), functionNamesVCML[funcType].c_str()); - throw FunctionRangeException(problem); - } - return result; -} - -Node* ASTFuncNode::copyTree() { - ASTFuncNode* node = new ASTFuncNode(); - node->funcType = funcType; - node->funcName = funcName; - for (int i=0;ijjtAddChild(jjtGetChild(i)->copyTree()); - } - return node; -} - -bool ASTFuncNode::equals(Node* node) { - // - // check to see if the types and children are the same - // - if (!Node::equals(node)){ - return false; - } - - // - // check this node for same state (function name) - // - ASTFuncNode* funcNode = (ASTFuncNode*)node; - if (funcNode->funcType != funcType){ - return false; - } - if (funcNode->funcName != funcName){ - return false; - } - - return true; -} diff --git a/ExpressionParser/ASTFuncNode.h b/ExpressionParser/ASTFuncNode.h deleted file mode 100644 index 64914c8ed..000000000 --- a/ExpressionParser/ASTFuncNode.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef ASTFUNCNODE_H -#define ASTFUNCNODE_H - -#include "Node.h" - -class ASTFuncNode : public Node -{ -public: - ASTFuncNode(int i); - ~ASTFuncNode(); - void setFunctionFromParserToken(string parserToken); - string infixString(int lang, NameScope* nameScope); - void getStackElements(vector& elements); - double evaluate(int evalType, double* values=0); - - Node* copyTree(); - bool equals(Node* node); - -private: - int funcType; - string funcName; - - ASTFuncNode(); -}; - -#endif diff --git a/ExpressionParser/ASTIdNode.cpp b/ExpressionParser/ASTIdNode.cpp deleted file mode 100644 index 57d05cf6e..000000000 --- a/ExpressionParser/ASTIdNode.cpp +++ /dev/null @@ -1,154 +0,0 @@ -#include - -#include "ASTIdNode.h" -#include "ExpressionException.h" -#include "ExpressionBindingException.h" -#include "RuntimeException.h" -#include "Expression.h" -#include "SymbolTable.h" -#include "SymbolTableEntry.h" -#include "StackMachine.h" -#include "ValueProxy.h" - -using namespace VCell; - -ASTIdNode::ASTIdNode(ASTIdNode* node) : Node(0) , name(node->name), symbolTableEntry(node->symbolTableEntry) { -} - -ASTIdNode::ASTIdNode(int i) : Node(i), symbolTableEntry(NULL) -{ -} - - -ASTIdNode::~ASTIdNode() { -} - -string ASTIdNode::infixString(int lang, NameScope* nameScope) -{ - string idName(name); - return idName; - - if (nameScope == NULL) { - idName = name; - } else { - /* - if (symbolTableEntry != NULL) { - idName = nameScope->getSymbolName(symbolTableEntry); - } else { - idName = nameScope->getUnboundSymbolName(name); - } - } - if (lang == LANGUAGE_DEFAULT || lang == LANGUAGE_C) { - return idName; - } else if (lang == LANGUAGE_MATLAB) { - return cbit.util.TokenMangler.getEscapedTokenMatlab(idName); - } else if (lang == LANGUAGE_JSCL) { - return cbit.util.TokenMangler.getEscapedTokenJSCL(idName); - } else { - */ - char chrs[20]; - sprintf(chrs, "%d\0", lang); - throw RuntimeException(string("Lanaguage '") + chrs + " not supported"); - - } -} - -void ASTIdNode::getStackElements(vector& elements) { - if (symbolTableEntry == NULL){ - throw ExpressionException("tryin to evaluate unbound identifier '" + infixString(LANGUAGE_DEFAULT, 0)+"'"); - } - elements.push_back(StackElement(symbolTableEntry->getValueProxy(), symbolTableEntry->getIndex())); -} - -double ASTIdNode::evaluate(int evalType, double* values) { - if (symbolTableEntry == NULL){ - throw ExpressionException("tryin to evaluate unbound identifier '" + infixString(LANGUAGE_DEFAULT, 0)+"'"); - } - - if (evalType == EVALUATE_CONSTANT) { - if (symbolTableEntry->isConstant()){ - return symbolTableEntry->getConstantValue(); - } - throw ExpressionException("Identifier '" + name + "' cannot be evaluated as a constant."); - } else { - Expression* exp = symbolTableEntry->getExpression(); - if (exp != NULL) { - return exp->evaluateVector(values); - } else { - if (values == 0) { - if (symbolTableEntry->getValueProxy() == NULL) { - throw ExpressionException("Value proxy not found for indentifier '" + name + "'"); - } - return symbolTableEntry->getValueProxy()->evaluate(); - } else { - if (symbolTableEntry->getIndex() < 0) { - throw ExpressionBindingException("referenced symbol table entry " + name + " not bound to an index"); - } - return values[symbolTableEntry->getIndex()]; - } - } - } -} - -SymbolTableEntry* ASTIdNode::getBinding(string symbol) -{ - if (name == symbol){ - return symbolTableEntry; - }else{ - return NULL; - } -} - -void ASTIdNode::bind(SymbolTable* symbolTable) -{ - if (symbolTable == NULL){ - symbolTableEntry = NULL; - return; - } - - symbolTableEntry = symbolTable->getEntry(name); - - if (symbolTableEntry == NULL){ - string id = name; - throw ExpressionBindingException("error binding identifier '" + id + "'"); - } -} - -void ASTIdNode::getSymbols(vector& symbols, int language, NameScope* nameScope) { - string infix = infixString(language, nameScope); - for (int i = 0; i < (int)symbols.size(); i ++) { - if (symbols[i] == infix) { - return; - } - } - symbols.push_back(infix); -} - -Node* ASTIdNode::copyTree() { - ASTIdNode* node = new ASTIdNode(this); - return node; -} - -bool ASTIdNode::equals(Node* node) { - // - // check to see if the types and children are the same - // - if (!Node::equals(node)){ - return false; - } - - // - // check this node for same state (identifier) - // - ASTIdNode* idNode = (ASTIdNode*)node; - if (idNode->name != name){ - return false; - } - - return true; -} - -//virtual -bool ASTIdNode::isConstant( ) const { - return false; -} diff --git a/ExpressionParser/ASTIdNode.h b/ExpressionParser/ASTIdNode.h deleted file mode 100644 index 549fbc75f..000000000 --- a/ExpressionParser/ASTIdNode.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef ASTIDNODE_H -#define ASTIDNODE_H - -#include "Node.h" - -class SymbolTableEntry; - -class ASTIdNode : public Node -{ -public: - ASTIdNode(int i); - ~ASTIdNode(); - string name; - string infixString(int lang, NameScope* nameScope); - SymbolTableEntry* symbolTableEntry; - SymbolTableEntry* getBinding(string symbol); - void bind(SymbolTable* symbolTable); - void getStackElements(vector& elements); - double evaluate(int evalType, double* values=0); - void getSymbols(vector& symbols, int language, NameScope* nameScope); - - Node* copyTree(); - bool equals(Node* node); - /** - * @return false - */ - virtual bool isConstant( ) const; - -private: - ASTIdNode(ASTIdNode*); -}; - -#endif diff --git a/ExpressionParser/ASTInvertTermNode.cpp b/ExpressionParser/ASTInvertTermNode.cpp deleted file mode 100644 index 278966254..000000000 --- a/ExpressionParser/ASTInvertTermNode.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "ASTInvertTermNode.h" -#include "DivideByZeroException.h" -#include "SymbolTable.h" -#include "Expression.h" -#include "ExpressionParserTreeConstants.h" -#include "StackMachine.h" - -ASTInvertTermNode::ASTInvertTermNode() : Node(JJTINVERTTERMNODE) { -} - -ASTInvertTermNode::ASTInvertTermNode(int i) : Node(i) { -} - -ASTInvertTermNode::~ASTInvertTermNode() { -} - -string ASTInvertTermNode::infixString(int lang, NameScope* nameScope) -{ - return jjtGetChild(0)->infixString(lang,nameScope); -} - -void ASTInvertTermNode::getStackElements(vector& elements) { - jjtGetChild(0)->getStackElements(elements); - elements.push_back(StackElement(TYPE_DIV)); -} - - -double ASTInvertTermNode::evaluate(int evalType, double* values) { - double childValue = jjtGetChild(0)->evaluate(evalType, values); - if (childValue == 0.0) { - //string childString = infixString(LANGUAGE_DEFAULT, 0); - //throw DivideByZeroException("divide by zero '" + childString + "'"); - // - // DIVIDE BY ZERO !!!!! - // - // form error message for user's consumption. - // - string errorMsg = getFunctionDomainError("divide by zero", 0, "divisor", jjtGetChild(0)); - throw DivideByZeroException(errorMsg); - } else { - return (1.0 / childValue); - } -} - -Node* ASTInvertTermNode::copyTree() { - ASTInvertTermNode* node = new ASTInvertTermNode(); - for (int i=0;ijjtAddChild(jjtGetChild(i)->copyTree()); - } - return node; -} diff --git a/ExpressionParser/ASTInvertTermNode.h b/ExpressionParser/ASTInvertTermNode.h deleted file mode 100644 index f94ee718d..000000000 --- a/ExpressionParser/ASTInvertTermNode.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef ASTINVERTTERMNODE_H -#define ASTINVERTTERMNODE_H - -#include "Node.h" - -class ASTInvertTermNode : public Node -{ -public: - ASTInvertTermNode(int i); - ~ASTInvertTermNode(); - string infixString(int lang, NameScope* nameScope); - void getStackElements(vector& elements); - double evaluate(int evalType, double* values=0); - - Node* copyTree(); - -private: - ASTInvertTermNode(); -}; - -#endif diff --git a/ExpressionParser/ASTMinusTermNode.cpp b/ExpressionParser/ASTMinusTermNode.cpp deleted file mode 100644 index 3fa6acce5..000000000 --- a/ExpressionParser/ASTMinusTermNode.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "ASTMinusTermNode.h" -#include "ExpressionException.h" -#include "ExpressionParserTreeConstants.h" -#include "StackMachine.h" - -ASTMinusTermNode::ASTMinusTermNode() : Node(JJTMINUSTERMNODE) { -} - -ASTMinusTermNode::ASTMinusTermNode(int i) : Node(i) { -} - -ASTMinusTermNode::~ASTMinusTermNode() { -} - -string ASTMinusTermNode::infixString(int lang, NameScope* nameScope) -{ - string buffer(" - "); - buffer += jjtGetChild(0)->infixString(lang,nameScope); - return buffer; -} - - -void ASTMinusTermNode::getStackElements(vector& elements) { - jjtGetChild(0)->getStackElements(elements); - elements.push_back(StackElement(TYPE_SUB)); -} - -double ASTMinusTermNode::evaluate(int evalType, double* values) { - return (- jjtGetChild(0)->evaluate(evalType, values)); -} - -Node* ASTMinusTermNode::copyTree() { - ASTMinusTermNode* node = new ASTMinusTermNode(); - for (int i=0;ijjtAddChild(jjtGetChild(i)->copyTree()); - } - return node; -} diff --git a/ExpressionParser/ASTMinusTermNode.h b/ExpressionParser/ASTMinusTermNode.h deleted file mode 100644 index b88593419..000000000 --- a/ExpressionParser/ASTMinusTermNode.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef ASTMINUSTERMNODE_H -#define ASTMINUSTERMNODE_H - -#include "Node.h" - -class ASTMinusTermNode : public Node -{ -public: - ASTMinusTermNode(int i); - ~ASTMinusTermNode(); - string infixString(int lang, NameScope* nameScope); - void getStackElements(vector& elements); - double evaluate(int evalType, double* values=0); - - Node* copyTree(); - -private: - ASTMinusTermNode(); -}; - -#endif diff --git a/ExpressionParser/ASTMultNode.cpp b/ExpressionParser/ASTMultNode.cpp deleted file mode 100644 index daf267bc5..000000000 --- a/ExpressionParser/ASTMultNode.cpp +++ /dev/null @@ -1,213 +0,0 @@ -#include "ASTMultNode.h" -#include "ASTInvertTermNode.h" -#include "ExpressionException.h" -#include "ExpressionParserTreeConstants.h" -#include "StackMachine.h" -#include "Expression.h" -//#include "ParseException.h" - -#include -using std::stringstream; - -ASTMultNode::ASTMultNode() : Node(JJTMULTNODE) { -} - -ASTMultNode::ASTMultNode(int i) : Node(i) { -} - -ASTMultNode::~ASTMultNode() { -} - -bool ASTMultNode::isBoolean() { - for (int i=0;iisBoolean()) { - return false; - } - } - return true; -} - -string ASTMultNode::infixString(int lang, NameScope* nameScope) -{ - bool* boolChildFlags = new bool[jjtGetNumChildren()]; - bool bAllBoolean = true; - bool bNoBoolean = true; - for (int i=0;iisBoolean(); - if (boolChildFlags[i]) { - boolChildFlags[i] = true; - bNoBoolean = false; - } else { - bAllBoolean = false; - } - - } - - stringstream buffer; - buffer << "("; - - if (bAllBoolean || bNoBoolean || (lang != LANGUAGE_C && lang != LANGUAGE_VISIT)) { // old way - for (int i=0;i(jjtGetChild(i)); - if (pointer){ - buffer << " / "; - buffer << jjtGetChild(i)->infixString(lang,nameScope); - }else{ - if (i>0) - buffer << " * "; - buffer << jjtGetChild(i)->infixString(lang,nameScope); - } - } - } else { - stringstream conditionBuffer; - stringstream valueBuffer; - for (int i=0;i 0) { - conditionBuffer << " && "; - } - conditionBuffer << jjtGetChild(i)->infixString((lang == LANGUAGE_VISIT?LANGUAGE_DEFAULT:lang),nameScope); - } else { - if (valueBuffer.str().length() == 0) { - ASTInvertTermNode* pointer = dynamic_cast(jjtGetChild(i)); - if (pointer){ - valueBuffer << " 1.0 / "; - } - } else { - ASTInvertTermNode* pointer = dynamic_cast(jjtGetChild(i)); - if (pointer){ - valueBuffer << " / "; - } else { - valueBuffer << " * "; - } - } - valueBuffer << jjtGetChild(i)->infixString(lang,nameScope); - } - } - if(lang == LANGUAGE_VISIT){ - //try{ - VCell::Expression * exp = new VCell::Expression(conditionBuffer.str()); - buffer << "if(" << exp->infix_Visit() << " , " << valueBuffer.str() << " , 0.0)"; - delete exp; - //}catch(...){ - // throw ParseException("Error pasing Expr"); - //} - }else{ - buffer << "((" << conditionBuffer.str() << ") ? (" << valueBuffer.str() << ") : 0.0)"; - } - } - buffer << ")"; - string s = buffer.str(); - delete [] boolChildFlags; - return s; -} - -void ASTMultNode::getStackElements(vector& elements) { - - int startSize = (int)elements.size(); - - // - // Add the stack machine instructions for each boolean child (followed by a branch "BZ" with unknown offset). - // If it is the last term in the product, there is no need to insert the branch instruction. - // - // The "BZ" instruction is inserted before the offset is known (will be updated at the end). - // this enforces any "false" evaluation to skip the rest of the terms in this product (children). - // - int indexBooleanChildren = 0; - for (int i=0;iisBoolean()){ - jjtGetChild(i)->getStackElements(elements); - if (indexBooleanChildren < jjtGetNumChildren()-1){ - elements.push_back(StackElement(TYPE_BZ)); - } - indexBooleanChildren++; - } - } - - // - // add stack machine instructions for all non-boolean children - // - int indexNonBooleanChildren = 0; - for (int i=0;iisBoolean()){ - jjtGetChild(i)->getStackElements(elements); - if (indexNonBooleanChildren > 0){ - elements.push_back(StackElement(TYPE_MULT)); - } - indexNonBooleanChildren++; - } - } - - // - // go back an fill in the offsets for each "BZ" added earlier. This is done by starting at the end with a - // reverse iterator and counting the instructions to each "BZ" that has a zero offset and is part of this product. - // The check for zero offset eliminates setting "BZ" instructions of children of this product. - // This will ensure that any "false" evaluation of a boolean child will skip all non-boolean children - // so will protect against function domain exceptions. - // - if (indexBooleanChildren>0){ - int finalSize = (int)elements.size(); - int size = finalSize-startSize; - vector::reverse_iterator iter = elements.rbegin(); - for (int offset = 0; offset < size; ++offset) { - if ((*iter).type==TYPE_BZ && (*iter).branchOffset==0){ - (*iter).branchOffset = offset+1; - } - iter++; - } - } -} - -double ASTMultNode::evaluate(int evalType, double* values) { - Exception* childException = 0; - - // evaluate boolean children first for conditional expressions. - // if any one of them is false, just return 0; - // this protects against evaluating the terms outside of - // domain defined by the boolean conditions. - for (int i=0;iisBoolean()) { - try { - if (jjtGetChild(i)->evaluate(evalType, values) == 0) { - return 0.0; - } - } catch (ExpressionException& e){ - if (evalType == EVALUATE_VECTOR) { - throw e; - } - childException = new ExpressionException(e.getMessage()); - } - } - } - if (childException != NULL){ - throw (*childException); - } - - double product = 1.0; - for (int i=0;ievaluate(evalType, values); - product *= value; - }catch (ExpressionException& e){ - if (evalType == EVALUATE_VECTOR) { - throw e; - } - childException = new ExpressionException(e.getMessage()); - } - } - if (product == -0.0){ - return 0.0; - } - if (childException != NULL){ - throw (*childException); - } - return product; -} - -Node* ASTMultNode::copyTree() { - ASTMultNode* node = new ASTMultNode(); - for (int i=0;ijjtAddChild(jjtGetChild(i)->copyTree()); - } - return node; -} diff --git a/ExpressionParser/ASTMultNode.h b/ExpressionParser/ASTMultNode.h deleted file mode 100644 index 02daa2833..000000000 --- a/ExpressionParser/ASTMultNode.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef ASTMULTNODE_H -#define ASTMULTNODE_H - -#include "Node.h" - -class ASTMultNode : public Node -{ -public: - ASTMultNode(int i); - ~ASTMultNode(); - string infixString(int lang, NameScope* nameScope); - void getStackElements(vector& elements); - double evaluate(int evalType, double* values=0); - bool isBoolean(); - - Node* copyTree(); - -private: - ASTMultNode(); -}; - -#endif diff --git a/ExpressionParser/ASTNotNode.cpp b/ExpressionParser/ASTNotNode.cpp deleted file mode 100644 index ba0235b01..000000000 --- a/ExpressionParser/ASTNotNode.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include "ASTNotNode.h" -#include "DivideByZeroException.h" -#include "ExpressionException.h" -#include "ExpressionParserTreeConstants.h" -#include "StackMachine.h" - -ASTNotNode::ASTNotNode() : Node(JJTNOTNODE) { -} - -ASTNotNode::ASTNotNode(int i) : Node(i) { -} - -ASTNotNode::~ASTNotNode() { -} - -bool ASTNotNode::isBoolean() { - return true; -} - -string ASTNotNode::infixString(int lang, NameScope* nameScope) -{ - string buffer; - if (lang == LANGUAGE_VISIT){ - buffer.append("not("); - }else{ - buffer.append("!("); - } - buffer += jjtGetChild(0)->infixString(lang,nameScope); - buffer += ")"; - - return buffer; -} - -void ASTNotNode::getStackElements(vector& elements) { - jjtGetChild(0)->getStackElements(elements); - elements.push_back(StackElement(TYPE_NOT)); -} - - -double ASTNotNode::evaluate(int evalType, double* values) { - double childValue = jjtGetChild(0)->evaluate(evalType, values); - if (childValue==0.0){ - return 1.0; - }else{ - return 0.0; - } -} - -Node* ASTNotNode::copyTree() { - ASTNotNode* node = new ASTNotNode(); - for (int i=0;ijjtAddChild(jjtGetChild(i)->copyTree()); - } - return node; -} diff --git a/ExpressionParser/ASTNotNode.h b/ExpressionParser/ASTNotNode.h deleted file mode 100644 index f3e7206d6..000000000 --- a/ExpressionParser/ASTNotNode.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef ASTNOTNODE_H -#define ASTNOTNODE_H - -#include "Node.h" - -class ASTNotNode : public Node -{ -public: - ASTNotNode(int i); - ~ASTNotNode(); - string infixString(int lang, NameScope* nameScope); - void getStackElements(vector& elements); - double evaluate(int evalType, double* values=0); - bool isBoolean(); - - Node* copyTree(); - -private: - ASTNotNode(); -}; - -#endif diff --git a/ExpressionParser/ASTOrNode.cpp b/ExpressionParser/ASTOrNode.cpp deleted file mode 100644 index 3d1b274a5..000000000 --- a/ExpressionParser/ASTOrNode.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include "ASTOrNode.h" -#include "ExpressionException.h" -#include "ExpressionParserTreeConstants.h" -#include "StackMachine.h" - -ASTOrNode::ASTOrNode() : Node(JJTORNODE) { -} - -ASTOrNode::ASTOrNode(int i) : Node(i) { -} - -ASTOrNode::~ASTOrNode() { -} - -bool ASTOrNode::isBoolean() { - return true; -} - -string ASTOrNode::infixString(int lang, NameScope* nameScope) -{ - string buffer; - - if(lang == LANGUAGE_VISIT){ - for (int i=0;iinfixString(lang,nameScope)); - for (int i=1;iinfixString(lang,nameScope)); - buffer.append(")"); - } - }else{ - buffer += "("; - for (int i = 0; i < jjtGetNumChildren(); i++) { - if (i > 0) - buffer += " || "; - buffer += jjtGetChild(i)->infixString(lang, nameScope); - } - buffer += ")"; - } - - return buffer; -} - - -void ASTOrNode::getStackElements(vector& elements) { - for (int i=0;igetStackElements(elements);; - if (i>0) - elements.push_back(StackElement(TYPE_OR)); - } -} - -double ASTOrNode::evaluate(int evalType, double* values) { - Exception* savedException = NULL; - for (int i = 0; i < jjtGetNumChildren(); i++) { - try { - if (jjtGetChild(i)->evaluate(evalType, values) != 0) { - return 1; - } - } catch (ExpressionException& e) { - if (evalType == EVALUATE_VECTOR) { - throw e; - } - savedException = new ExpressionException(e.getMessage()); - } - } - if (savedException != NULL) { - throw (*savedException); - } - return 0.0; -} - -Node* ASTOrNode::copyTree() { - ASTOrNode* node = new ASTOrNode(); - for (int i=0;ijjtAddChild(jjtGetChild(i)->copyTree()); - } - return node; -} diff --git a/ExpressionParser/ASTOrNode.h b/ExpressionParser/ASTOrNode.h deleted file mode 100644 index 8cc4646d0..000000000 --- a/ExpressionParser/ASTOrNode.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef ASTORNODE_H -#define ASTORNODE_H - -#include "Node.h" - -class ASTOrNode : public Node -{ -public: - ASTOrNode(int i); - ~ASTOrNode(); - string infixString(int lang, NameScope* nameScope); - void getStackElements(vector& elements); - double evaluate(int evalType, double* values=0); - bool isBoolean(); - - Node* copyTree(); - -private: - ASTOrNode(); -}; - -#endif diff --git a/ExpressionParser/ASTPowerNode.cpp b/ExpressionParser/ASTPowerNode.cpp deleted file mode 100644 index f65939045..000000000 --- a/ExpressionParser/ASTPowerNode.cpp +++ /dev/null @@ -1,125 +0,0 @@ -#include -#include - -#include "ASTPowerNode.h" -#include "RuntimeException.h" -#include "DivideByZeroException.h" -#include "FunctionDomainException.h" -#include "ExpressionParserTreeConstants.h" -#include "StackMachine.h" -#include "MathUtil.h" - -ASTPowerNode::ASTPowerNode() : Node(JJTPOWERNODE) { -} - -ASTPowerNode::ASTPowerNode(int i) : Node(i) { -} - -ASTPowerNode::~ASTPowerNode() { -} - -string ASTPowerNode::infixString(int lang, NameScope* nameScope) -{ - if (jjtGetNumChildren() != 2) { - char ch[20]; - sprintf(ch, "%d\0", jjtGetNumChildren()); - throw RuntimeException("There are" + string(ch) + " arguments for the power operator, expecting 2"); - } - - string buffer; - if (lang == LANGUAGE_DEFAULT || lang == LANGUAGE_MATLAB) { - buffer += "("; - buffer += jjtGetChild(0)->infixString(lang, nameScope); - buffer += " ^ "; - buffer += jjtGetChild(1)->infixString(lang, nameScope); - buffer += ")"; - } else if (lang == LANGUAGE_C) { - buffer += "pow("; - buffer += jjtGetChild(0)->infixString(lang, nameScope); - buffer += ","; - buffer += jjtGetChild(1)->infixString(lang, nameScope); - buffer += ")"; - } - - return buffer; -} - -void ASTPowerNode::getStackElements(vector& elements) { - jjtGetChild(0)->getStackElements(elements);; - jjtGetChild(1)->getStackElements(elements);; - elements.push_back(StackElement(TYPE_POW)); -} - -double ASTPowerNode::evaluate(int evalType, double* values) { - if (jjtGetNumChildren() != 2) { - char chrs[1000]; - sprintf(chrs, "ASTPowerNode: wrong number of arguments for '^' (%d), expected 2\0", jjtGetNumChildren()); - throw ExpressionException(chrs); - } - // - // see if there are any constant 0.0's, if there are simplify to 0.0 - // - ExpressionException* exponentException = NULL; - ExpressionException* baseException = NULL; - Node* exponentChild = jjtGetChild(1); - Node* baseChild = jjtGetChild(0); - - double exponentValue = 0.0; - double baseValue = 0.0; - try { - exponentValue = exponentChild->evaluate(evalType, values); - } catch (ExpressionException& e) { - if (evalType == EVALUATE_VECTOR) - throw e; - exponentException = new ExpressionException(e.getMessage()); - } - try { - baseValue = baseChild->evaluate(evalType, values); - } catch (ExpressionException& e) { - if (evalType == EVALUATE_VECTOR) - throw e; - baseException = new ExpressionException(e.getMessage()); - } - - if (exponentException == NULL && baseException == NULL) { - if (baseValue == 0.0 && exponentValue < 0.0) { - string childString = infixString(LANGUAGE_DEFAULT,0); - char problem[1000]; - sprintf(problem, "u^v and u=0 and v=%lf<0", exponentValue); - string errorMsg = getFunctionDomainError(problem, values, "u", baseChild, "v", exponentChild); - throw DivideByZeroException(errorMsg); - } else if (baseValue < 0.0 && exponentValue != MathUtil::round(exponentValue)) { - char problem[1000]; - sprintf(problem, "u^v and u=%lf<0 and v=%lf not an integer: undefined", baseValue, exponentValue); - string errorMsg = getFunctionDomainError(problem, values, "u", baseChild, "v", exponentChild); - throw FunctionDomainException(errorMsg); - } else { - double result = pow(baseValue, exponentValue); - if (MathUtil::double_infinity == -result || MathUtil::double_infinity == result || result != result) { - char problem[1000]; - sprintf(problem, "u^v evaluated to %lf, u=%lf, v=%lf", result, baseValue); - string errorMsg = getFunctionDomainError(problem, values, "u", baseChild, "v", exponentChild); - throw FunctionDomainException(errorMsg); - } - return result; - } - } else if (exponentException == 0 && exponentValue == 0.0) { - return 1.0; - } else if (baseException == 0 && baseValue == 1.0) { - return 1.0; - } else { - if (baseException != NULL) { - throw (*baseException); - } else if (exponentException != NULL) { - throw (*exponentException); - } - } -} - -Node* ASTPowerNode::copyTree() { - ASTPowerNode* node = new ASTPowerNode(); - for (int i=0;ijjtAddChild(jjtGetChild(i)->copyTree()); - } - return node; -} diff --git a/ExpressionParser/ASTPowerNode.h b/ExpressionParser/ASTPowerNode.h deleted file mode 100644 index 3ee096c40..000000000 --- a/ExpressionParser/ASTPowerNode.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef ASTPOWERNODE_H -#define ASTPOWERNODE_H - -#include "Node.h" - -class ASTPowerNode : public Node -{ -public: - ASTPowerNode(int i); - ~ASTPowerNode(); - string infixString(int lang, NameScope* nameScope); - void getStackElements(vector& elements); - double evaluate(int evalType, double* values=0); - - Node* copyTree(); - -private: - ASTPowerNode(); -}; - -#endif diff --git a/ExpressionParser/ASTRelationalNode.cpp b/ExpressionParser/ASTRelationalNode.cpp deleted file mode 100644 index 28a7af491..000000000 --- a/ExpressionParser/ASTRelationalNode.cpp +++ /dev/null @@ -1,196 +0,0 @@ -#include "ASTRelationalNode.h" -#include "RuntimeException.h" -#include "ExpressionException.h" -#include "ExpressionParserTreeConstants.h" -#include "StackMachine.h" -#include "ParseException.h" - -const int LT = 1; -const int GT = 2; -const int LE = 3; -const int GE = 4; -const int EQ = 5; -const int NE = 6; -const int UNKNOWN = -1; - -int StackMachine_RelationalLookupTable[] = {0, TYPE_LT, TYPE_GT, TYPE_LE, TYPE_GE, TYPE_EQ, TYPE_NE}; - -ASTRelationalNode::ASTRelationalNode() : Node(JJTRELATIONALNODE) { - operation = 0; - opString = "????"; -} - -ASTRelationalNode::ASTRelationalNode(int i) : Node(i) { - operation = 0; - opString = "????"; -} - -ASTRelationalNode::~ASTRelationalNode() { -} - -bool ASTRelationalNode::isBoolean() { - return true; -} - -void ASTRelationalNode::setOperationFromToken(string op) -{ - if (op == ">"){ - operation = GT; - }else if (op == "<"){ - operation = LT; - }else if (op == ">="){ - operation = GE; - }else if (op == "<="){ - operation = LE; - }else if (op == "=="){ - operation = EQ; - }else if (op == "!="){ - operation = NE; - }else{ - throw RuntimeException("unknown relational operator token = '" + op + "'"); - } - opString = op; -} - - -string ASTRelationalNode::infixString(int lang, NameScope* nameScope) -{ - string buffer; - if(lang == LANGUAGE_VISIT){ - if(jjtGetNumChildren() != 2){ - throw ParseException("ASTRelationalNode for VISIT expecting 2 children"); - } - switch (operation){ - case GT:{ - buffer.append("gt("); - break; - } - case LT:{ - buffer.append("lt("); - break; - } - case GE:{ - buffer.append("gte("); - break; - } - case LE:{ - buffer.append("lte("); - break; - } - case EQ:{ - buffer.append("equal("); - break; - } - case NE:{ - buffer.append("notequal("); - break; - } - default:{ - throw ParseException("ASTRelationalNode VISIT unknown relational operator"); - } - } - buffer.append(jjtGetChild(0)->infixString(lang,nameScope)+","+jjtGetChild(1)->infixString(lang,nameScope)+")"); - - }else{ - buffer += "("; - for (int i = 0; i < jjtGetNumChildren(); i++) { - if (i > 0) - buffer += " " + opString + " "; - buffer += jjtGetChild(i)->infixString(lang, nameScope); - } - buffer += ")"; - } - return buffer; -} - -void ASTRelationalNode::getStackElements(vector& elements) { - for (int i=0;igetStackElements(elements);; - if (i>0) - elements.push_back(StackElement(StackMachine_RelationalLookupTable[operation])); - } -} - -double ASTRelationalNode::evaluate(int evalType, double* values) -{ - if (jjtGetNumChildren() != 2) { - throw ExpressionException("Expected two children"); - } - double first = jjtGetChild(0)->evaluate(evalType, values); - double second = jjtGetChild(1)->evaluate(evalType, values); - - switch (operation) { - case GT : - { - if (first > second) - return 1.0; - else - return 0.0; - } - case LT : - { - if (first < second) - return 1.0; - else - return 0.0; - } - case GE : - { - if (first >= second) - return 1.0; - else - return 0.0; - } - case LE : - { - if (first <= second) - return 1.0; - else - return 0.0; - } - case EQ : - { - if (first == second) - return 1.0; - else - return 0.0; - } - case NE : - { - if (first != second) - return 1.0; - else - return 0.0; - } - } - throw ExpressionException("unsupported relational operation"); -} - -Node* ASTRelationalNode::copyTree() { - ASTRelationalNode* node = new ASTRelationalNode(); - node->operation = this->operation; - node->opString = this->opString; - for (int i=0;ijjtAddChild(jjtGetChild(i)->copyTree()); - } - return node; -} - -bool ASTRelationalNode::equals(Node* node) { - // - // check to see if the types and children are the same - // - if (!Node::equals(node)){ - return false; - } - - // - // check this node for same state (operation string and integer) - // - ASTRelationalNode* relNode = (ASTRelationalNode*)node; - if (relNode->opString != opString || relNode->operation != operation){ - return false; - } - - return true; -} diff --git a/ExpressionParser/ASTRelationalNode.h b/ExpressionParser/ASTRelationalNode.h deleted file mode 100644 index 06bdfe397..000000000 --- a/ExpressionParser/ASTRelationalNode.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef ASTRELATIONALNODE_H -#define ASTRELATIONALNODE_H - -#include "Node.h" - -class ASTRelationalNode : public Node -{ -public: - ASTRelationalNode(int i); - ~ASTRelationalNode(); - void setOperationFromToken(string op); - string infixString(int lang, NameScope* nameScope); - void getStackElements(vector& elements); - double evaluate(int evalType, double* values=0); - bool isBoolean(); - - Node* copyTree(); - bool equals(Node* node); - -private: - int operation; - string opString; - ASTRelationalNode(); -}; - -#endif diff --git a/ExpressionParser/CMakeLists.txt b/ExpressionParser/CMakeLists.txt deleted file mode 100644 index 7585b3e3c..000000000 --- a/ExpressionParser/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -project(ExpressionParser) - -file (GLOB HEADER_FILES *.h) -file (GLOB SRC_FILES *.cpp) - -list (REMOVE_ITEM HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/ExpressionTest.h) -list (REMOVE_ITEM SRC_FILES ${CMAKE_CURRENT_SOURCE_DIR}/ExpressionTest.cpp) - -add_library(ExpressionParser STATIC ${SRC_FILES} ${HEADER_FILES}) -target_include_directories(ExpressionParser INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) - -install(TARGETS ExpressionParser - ARCHIVE DESTINATION bin) \ No newline at end of file diff --git a/ExpressionParser/DivideByZeroException.cpp b/ExpressionParser/DivideByZeroException.cpp deleted file mode 100644 index d5c2633c4..000000000 --- a/ExpressionParser/DivideByZeroException.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "DivideByZeroException.h" - -DivideByZeroException::DivideByZeroException(string msg) : ExpressionException("DivideByZeroException", msg) -{ -} - -DivideByZeroException::~DivideByZeroException(void) throw( ) -{ -} diff --git a/ExpressionParser/DivideByZeroException.h b/ExpressionParser/DivideByZeroException.h deleted file mode 100644 index 33bc0f630..000000000 --- a/ExpressionParser/DivideByZeroException.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef DIVIDEBYZEROEXCEPTION_H -#define DIVIDEBYZEROEXCEPTION_H - -#include "ExpressionException.h" - -class DivideByZeroException : public ExpressionException -{ -public: - DivideByZeroException(string msg); - ~DivideByZeroException(void) throw( ); -}; -#endif diff --git a/ExpressionParser/Exception.cpp b/ExpressionParser/Exception.cpp deleted file mode 100644 index c380ecf56..000000000 --- a/ExpressionParser/Exception.cpp +++ /dev/null @@ -1,175 +0,0 @@ -#include -#include -#include - -#include "Exception.h" -#include "ParserException.h" -#include "RuntimeException.h" -#include "FunctionDomainException.h" -#include "FunctionRangeException.h" -#include "ExpressionException.h" -#include "DivideByZeroException.h" -#include "ParseException.h" -#include "IOException.h" -#include "ExpressionBindingException.h" - -VCell::Exception::Exception(string titleVal, string msg) -{ - title = titleVal; - message = msg; -} - -VCell::Exception::Exception(string msg) -{ - title = "Exception"; - message = msg; -} - -VCell::Exception::~Exception(void) throw( ) -{ -} - -string VCell::Exception::getExactMessage() { - return message; -} - -const char * VCell::Exception::what() const throw( ){ - return message.c_str( ); -} - -string VCell::Exception::getMessage(void) -{ - return title + " : " + getExactMessage(); -} - -void VCell::Exception::replaceMessage(string& replacementMessage) -{ - message = replacementMessage; -} - -void VCell::Exception::rethrowException(Exception& ex, string replacementMessage) -{ - string message = ex.getExactMessage(); - if (replacementMessage.size()>0){ - ex.replaceMessage(replacementMessage); - } - - if (typeid(ex) == typeid(ParseException)) { - ParseException* castex = dynamic_cast((Exception*)(&ex)); - throw (*castex); - } - - if (typeid(ex) == typeid(ParserException)) { - ParserException* castex = dynamic_cast((Exception*)(&ex)); - throw (*castex); - } - - if (typeid(ex) == typeid(DivideByZeroException)) { - DivideByZeroException* castex = dynamic_cast((Exception*)(&ex)); - throw (*castex); - } - - if (typeid(ex) == typeid(FunctionDomainException)) { - FunctionDomainException* castex = dynamic_cast((Exception*)(&ex)); - throw (*castex); - } - - if (typeid(ex) == typeid(FunctionRangeException)) { - FunctionRangeException* castex = dynamic_cast((Exception*)(&ex)); - throw (*castex); - } - - if (typeid(ex) == typeid(ExpressionBindingException)) { - ExpressionBindingException* castex = dynamic_cast((Exception*)(&ex)); - throw (*castex); - } - - if (typeid(ex) == typeid(ExpressionException)) { - ExpressionException* castex = dynamic_cast((Exception*)(&ex)); - throw (*castex); - } - - if (typeid(ex) == typeid(RuntimeException)) { - RuntimeException* castex = dynamic_cast((Exception*)(&ex)); - throw (*castex); - } - - throw ex; -} - -static void reverse(char* s) -{ - int i, j; - char c; - - for (i = 0, j = strlen(s)-1; i 0); /* delete it */ - if (sign < 0) - s[i++] = '-'; - s[i] = '\0'; - reverse(s); -} - -string VCell::Exception::add_escapes(string str) -{ - string retval; - char ch; - for (unsigned int i = 0; i < str.length(); i++) { - switch (str[i]) { - case 0 : - retval += ""; - continue; - case '\b' : - retval += "\\b"; - continue; - case '\t' : - retval += "\\t"; - continue; - case '\n' : - retval += "\\n"; - continue; - case '\f' : - retval += "\\f"; - continue; - case '\r' : - retval += "\\r"; - continue; - case '\"' : - retval += "\\\""; - continue; - case '\'' : - retval += "\\\'"; - continue; - case '\\' : - retval += "\\\\"; - continue; - default : - if ((ch = str[i]) < 0x20 || ch > 0x7e) { - char chrs[20]; - memset(chrs, 0, 20 * sizeof(char)); - itoa1(ch, chrs, 16); - string s = string("0000") + chrs; - retval += "\\u" + s.substr(s.length() - 4, 4); - } else { - retval += ch; - } - continue; - } - } - return retval; -} diff --git a/ExpressionParser/Exception.h b/ExpressionParser/Exception.h deleted file mode 100644 index ae1bec9a8..000000000 --- a/ExpressionParser/Exception.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef EXCEPTION_H -#define EXCEPTION_H -#include -#include - -namespace VCell { - class Exception : public std::exception - { - public: - typedef std::string string; - Exception(); - Exception(string message); - Exception(string title, string message); - /** - * calls #getMessage - */ - virtual const char * what() const throw( ); - - virtual string getExactMessage(); - string getMessage(void); - ~Exception(void) throw( ); - static void rethrowException(Exception& ex, string replacementMessage=""); - void replaceMessage(string& replacementMessage); - static string add_escapes(string str); - // static string add_escape(char ch); - - protected: - string message; - string title; - }; -} - -#endif diff --git a/ExpressionParser/Expression.cpp b/ExpressionParser/Expression.cpp deleted file mode 100644 index 13ca1ad03..000000000 --- a/ExpressionParser/Expression.cpp +++ /dev/null @@ -1,237 +0,0 @@ -#include -#include -#include -#include -#include -using std::cout; -using std::endl; -using std::istringstream; - -#include "Expression.h" -#include "ExpressionParser.h" -#include "ASTFloatNode.h" -#include "ParseException.h" -#include "ParserException.h" -#include "StackMachine.h" - -//long Expression::flattenCount = 0; -//long Expression::diffCount = 0; -//long Expression::parseCount = 0; -//long Expression::derivativeCount = 0; -//long Expression::substituteCount = 0; -//long Expression::bindCount = 0; -using VCell::Expression; - -Expression::Expression(void) - :rootNode(NULL), - stackMachine(NULL) {} - -Expression::Expression(Expression* expression) - :rootNode(expression->rootNode->copyTree()), - stackMachine(NULL) {} - -Expression::Expression(const Expression &rhs) - :rootNode(rhs.rootNode->copyTree()), - stackMachine(NULL) {} - -/** -* create and bind in single ctor -* equivalent to default constructor if #expString is empty -*/ -Expression::Expression(string expString, SymbolTable & symbolTable) - :rootNode(NULL), - stackMachine(NULL) -{ - if (!expString.empty( )) { - init(expString); - bindExpression(&symbolTable); - } -} - -Expression::Expression(string expString) - :rootNode(NULL), - stackMachine(NULL) -{ - init(expString); -} - -void Expression::init(const string & expString) { - - if (expString.length() == 0) { - throw ParserException("Empty expression"); - } - - bool bNumber = true; - for (unsigned int i = 0; i < expString.length(); i ++) { - if (!isdigit(expString[i]) && expString[i] != '.' && expString[i] != ';') { - bNumber = false; - break; - } - } - if (bNumber) { - double value = 0.0; - int n = sscanf(expString.c_str(), "%lf", &value); - if (n == 1) { - rootNode = new ASTFloatNode(value); - return; - } - } - - string trimstr = trim(expString); - if (trimstr[trimstr.length() - 1] != ';'){ - trimstr += ";"; - } - parseExpression(trimstr); -} - -Expression::~Expression(void) -{ - delete rootNode; - delete stackMachine; -} - -Expression & Expression::operator=(const Expression &rhs) { - rootNode = rhs.rootNode->copyTree(); - delete stackMachine; - stackMachine = NULL; - return *this; -} - -void Expression::showStackInstructions(void) -{ - getStackMachine()->showInstructions(); - cout.flush(); -} - -double Expression::evaluateConstant(void) -{ - return getStackMachine()->evaluate(NULL); -} - -double Expression::evaluateConstantTree() -{ - return rootNode->evaluate(EVALUATE_CONSTANT); -} - -double Expression::evaluateVectorTree(double* values) -{ - try { - return rootNode->evaluate(EVALUATE_VECTOR, values); - } catch (Exception& ex) { - Exception::rethrowException(ex, ex.getMessage() + " in " + getEvaluationSummary(values)); - } -} - -string Expression::getEvaluationSummary(double* values) -{ - return rootNode->getNodeSummary(values, rootNode); -} - -double Expression::evaluateVector(double* values) -{ - try { - return getStackMachine()->evaluate(values); - } catch (Exception& ex) { - Exception::rethrowException(ex, ex.getMessage()+ " in " + getEvaluationSummary(values)); - } -} - -void Expression::parseExpression(string exp) -{ - //parseCount++; - try { - istringstream iss(exp); - ExpressionParser parser(&iss); - - delete rootNode; - rootNode = parser.Expression(); - - if (typeid(*rootNode) == typeid(ASTExpression)){ - if (rootNode->jjtGetNumChildren() == 1){ // we abandon the real root node here, so there is tiny memory leak; - Node * old = rootNode; - rootNode = old->abandonChild(0); - delete old; - } - } - } catch (Exception& e) { - throw ParserException("Parse Error while parsing expression " + e.getMessage()); - } -} - -string Expression::infix(void) -{ - return rootNode->infixString(LANGUAGE_DEFAULT, 0); -} - -string Expression::infix_Visit(void) -{ - return rootNode->infixString(LANGUAGE_VISIT, 0); -} - -void Expression::bindExpression(SymbolTable* symbolTable) -{ - //bindCount++; - rootNode->bind(symbolTable); -} - -string Expression::trim(string str) -{ - int len = (int)str.length(); - int st = 0; - const char* val = str.c_str(); - - while ((st < len) && (val[st] <= ' ')) { - st++; - } - while ((st < len) && (val[len - 1] <= ' ')) { - len--; - } - return ((st > 0) || (len < (int)str.length())) ? str.substr(st, len-st) : str; -} - -inline StackMachine* Expression::getStackMachine() { - if (stackMachine == NULL) { - vector elements_vector; - rootNode->getStackElements(elements_vector); - StackElement* elements = new StackElement[elements_vector.size()]; - int i = 0; - for (vector::iterator iter = elements_vector.begin(); iter != elements_vector.end(); iter ++) { - elements[i ++] = *iter; - } - stackMachine = new StackMachine(elements, (int)elements_vector.size()); - elements_vector.clear(); - } - return stackMachine; -} - -void Expression::getSymbols(vector& symbols) { - rootNode->getSymbols(symbols, LANGUAGE_DEFAULT, 0); -} - -SymbolTableEntry* Expression::getSymbolBinding(string symbol){ - return rootNode->getBinding(symbol); -} - -double Expression::evaluateProxy() { - return evaluateVector(0); -} - -void Expression::substituteInPlace(Expression* origExp, Expression* newExp) { - Node* origNode = origExp->rootNode; - Node* newNode = newExp->rootNode->copyTree(); - // - // first check if must replace entire tree, if not then leaves can deal with it - // - if (origNode->equals(rootNode)){ - rootNode = newNode; - } else { - rootNode->substitute(origNode, newNode); - } -} - -bool Expression::isConstant( ) const { - if (rootNode != NULL) { - return rootNode->isConstant( ); - } - return false; -} diff --git a/ExpressionParser/Expression.h b/ExpressionParser/Expression.h deleted file mode 100644 index 383758141..000000000 --- a/ExpressionParser/Expression.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef VCELL_EXPRESSION_H -#define VCELL_EXPRESSION_H - -#include "Node.h" - -class SymbolTable; -class SymbolTableEntry; -class Node; -class StackMachine; - -namespace VCell { - -class Expression -{ -public: - Expression(void); - Expression(string expString); - /** - * symbolTable must remain valid memory - */ - Expression(string expString, SymbolTable & symbolTable); - Expression(Expression* expression); - Expression(const Expression &); - ~Expression(void); - Expression & operator=(const Expression &rhs); - double evaluateConstant(void); - // exercise the old way of evaluating constant and vector by traversing abstract syntax tree - double evaluateConstantTree(); - double evaluateVectorTree(double* values); - // exercise the new way of evaluating vector by using stack machine - double evaluateVector(double* values); - - string infix(void); - /** - * symbolTable must remain valid memory - */ - void bindExpression(SymbolTable* symbolTable); - static string trim(string str); - void getSymbols(vector& symbols); - - string getEvaluationSummary(double* values); - - SymbolTableEntry* getSymbolBinding(string symbol); - double evaluateProxy(); - - void showStackInstructions(); - void substituteInPlace(Expression* origExp, Expression* newExp); - string infix_Visit(void); - bool isConstant( ) const; - -private: - Node *rootNode; - - //static long flattenCount; - //static long diffCount; - //static long parseCount; - //static long derivativeCount; - //static long substituteCount; - //static long bindCount; - void parseExpression(string exp); - StackMachine* stackMachine; - inline StackMachine* getStackMachine(); - /** - * common ctor code - */ - void init(const string & expString); -}; -} -#endif diff --git a/ExpressionParser/ExpressionBindingException.cpp b/ExpressionParser/ExpressionBindingException.cpp deleted file mode 100644 index 8e6f79fc6..000000000 --- a/ExpressionParser/ExpressionBindingException.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "ExpressionBindingException.h" - -ExpressionBindingException::ExpressionBindingException(string msg) : ExpressionException("ExpressionBindingException", msg) -{ -} - -ExpressionBindingException::~ExpressionBindingException(void) throw( ) -{ -} - -std::string ExpressionBindingException::identify(){ - return "ExpressionBindingException"; -} diff --git a/ExpressionParser/ExpressionBindingException.h b/ExpressionParser/ExpressionBindingException.h deleted file mode 100644 index 8f94376c7..000000000 --- a/ExpressionParser/ExpressionBindingException.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef EXPRESSIONBINDINGEXCEPTION_H -#define EXPRESSIONBINDINGEXCEPTION_H - -#include "ExpressionException.h" - -class ExpressionBindingException : public ExpressionException -{ -public: - ExpressionBindingException(string msg); - ~ExpressionBindingException(void) throw( ); - string identify(); -}; - -#endif diff --git a/ExpressionParser/ExpressionException.cpp b/ExpressionParser/ExpressionException.cpp deleted file mode 100644 index cea6fd7ec..000000000 --- a/ExpressionParser/ExpressionException.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "ExpressionException.h" - -ExpressionException::~ExpressionException(void) throw( ) -{ -} - -ExpressionException::ExpressionException(string msg) : Exception("ExpressionException", msg) -{ -} - -ExpressionException::ExpressionException(string title, string msg) : Exception(title, msg) -{ -} diff --git a/ExpressionParser/ExpressionException.h b/ExpressionParser/ExpressionException.h deleted file mode 100644 index 1f3b513a5..000000000 --- a/ExpressionParser/ExpressionException.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef EXPRESSIONEXCEPTION_H -#define EXPRESSIONEXCEPTION_H - -#include "Exception.h" -using namespace VCell; - -class ExpressionException : public VCell::Exception -{ -public: - ~ExpressionException(void) throw( ); - ExpressionException(string msg); - ExpressionException(string title, string msg); -}; - -#endif diff --git a/ExpressionParser/ExpressionParser.cpp b/ExpressionParser/ExpressionParser.cpp deleted file mode 100644 index 126840811..000000000 --- a/ExpressionParser/ExpressionParser.cpp +++ /dev/null @@ -1,1036 +0,0 @@ -#include -#include - -#include "ASTOrNode.h" -#include "ASTAndNode.h" -#include "ASTRelationalNode.h" -#include "ASTAddNode.h" -#include "ASTMinusTermNode.h" -#include "ASTMultNode.h" -#include "ASTInvertTermNode.h" -#include "ASTPowerNode.h" -#include "ASTNotNode.h" -#include "ASTFuncNode.h" -#include "ASTFloatNode.h" -#include "ASTIdNode.h" -#include "ExpressionParser.h" -#include "ParseException.h" -#include "RuntimeException.h" -#include "ExpressionParserConstants.h" -#include "ExpressionParserTreeConstants.h" - -#if defined(VISUAL_LEAK_DETECTION) -#include -#endif -int64 jj_la1_0[] = {0x2000,0x1000,0x30000,0x30000,0xc0000,0xc0000,0x10934000,0x10100000,0x10934000,0x40000000,}; - -ExpressionParser::ExpressionParser(istream* stream) -{ - init(); - jj_input_stream = new SimpleCharStream(stream, 1, 1); - token_source = new ExpressionParserTokenManager(jj_input_stream); -} - -ExpressionParser::ExpressionParser(ExpressionParserTokenManager* tm) -{ - init(); - jj_input_stream = 0; - token_source = tm; -} - -ExpressionParser::~ExpressionParser() -{ - while (headToken != 0) { - Token* token = headToken; - headToken = headToken->next; - delete token; - } - delete token_source; - delete jjtree; - delete jj_input_stream; - delete[] jj_lasttokens; - delete[] jj_la1; - - for (int i = 0; i < jj_2_rtns_length; i++) { - while (jj_2_rtns[i] != 0) { - JJCalls* p = jj_2_rtns[i]; - jj_2_rtns[i] = jj_2_rtns[i]->next; - delete p; - } - delete jj_2_rtns[i]; - } - delete[] jj_2_rtns; - - for (unsigned int i = 0; i < jj_expentries.size(); i ++) { - jj_expentries[i]->clear(); - delete jj_expentries[i]; - } - jj_expentries.clear(); -} - -void ExpressionParser::init(void) -{ - jjtree = new JJTExpressionParserState(); - - jj_la = 0; - jj_nt = 0; - jj_lasttokens = new int[100]; - memset(jj_lasttokens, 0, 100*sizeof(int)); - - jj_la1 = new int[10]; - for (int i = 0; i < 10; i++) - jj_la1[i] = -1; - - jj_2_rtns_length = 4; - jj_2_rtns = new JJCalls*[jj_2_rtns_length]; - for (int i = 0; i < jj_2_rtns_length; i++) - jj_2_rtns[i] = new JJCalls(); - - jj_scanpos = 0; - jj_lastpos = 0; - token = new Token(); - headToken = token; - jj_ntk = -1; - jj_gen = 0; - jj_rescan = false; - jj_gc = 0; - - lookingAhead = false; - jj_kind = -1; - jj_endpos = 0; - - jj_expentry = 0; -} - -ASTExpression* ExpressionParser::Expression(void) -{ - ASTExpression* jjtn000 = new ASTExpression(JJTEXPRESSION); - bool jjtc000 = true; - jjtree->openNodeScope(jjtn000); - try { - LogicalORExpression(); - jj_consume_token(27); - jjtree->closeNodeScope(jjtn000, true); - jjtc000 = false; - { - if (jjtc000) { - jjtree->closeNodeScope(jjtn000, true); - } - if (true) - return jjtn000; - } - } catch (Exception& ex) { - if (jjtc000) { - jjtree->clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree->popNode(); - } - if (jjtc000) { - jjtree->closeNodeScope(jjtn000, true); - } - Exception::rethrowException(ex); - } catch (...) { - if (jjtc000) { - jjtree->clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree->popNode(); - } - if (jjtc000) { - jjtree->closeNodeScope(jjtn000, true); - } - - throw RuntimeException("Exception in ExpressionParser::Expression"); - } - throw RuntimeException("Missing return statement in function"); -} - -void ExpressionParser::LogicalORExpression(void) -{ - ASTOrNode* jjtn001 = new ASTOrNode(JJTORNODE); - bool jjtc001 = true; - jjtree->openNodeScope(jjtn001); - try { - LogicalANDExpression(); - while (true) { - switch ((jj_ntk == -1) ? jj_ntk_func() : jj_ntk) { - case OR: - ; - break; - default: - jj_la1[0] = jj_gen; - goto label_1; - } - jj_consume_token(OR); - LogicalANDExpression(); - } -label_1: - if (jjtc001) { - jjtree->closeNodeScope(jjtn001, jjtree->nodeArity() > 1); - } - } catch (Exception& ex) { - if (jjtc001) { - jjtree->clearNodeScope(jjtn001); - jjtc001 = false; - } else { - jjtree->popNode(); - } - if (jjtc001) { - jjtree->closeNodeScope(jjtn001, jjtree->nodeArity() > 1); - } - Exception::rethrowException(ex); - } catch (...) { - if (jjtc001) { - jjtree->clearNodeScope(jjtn001); - jjtc001 = false; - } else { - jjtree->popNode(); - } - if (jjtc001) { - jjtree->closeNodeScope(jjtn001, jjtree->nodeArity() > 1); - } - throw RuntimeException("Exception in ExpressionParser::LogicalORExpression"); - } -} - -void ExpressionParser::LogicalANDExpression(void) -{ - ASTAndNode* jjtn001 = new ASTAndNode(JJTANDNODE); - bool jjtc001 = true; - jjtree->openNodeScope(jjtn001); - try { - RelationalExpression(); - while (true) { - switch ((jj_ntk==-1)?jj_ntk_func():jj_ntk) { - case AND: - ; - break; - default: - jj_la1[1] = jj_gen; - goto label_2; - } - jj_consume_token(AND); - RelationalExpression(); - } -label_2: - if (jjtc001) { - jjtree->closeNodeScope(jjtn001, jjtree->nodeArity() > 1); - } - } catch (Exception& ex) { - if (jjtc001) { - jjtree->clearNodeScope(jjtn001); - jjtc001 = false; - } else { - jjtree->popNode(); - } - if (jjtc001) { - jjtree->closeNodeScope(jjtn001, jjtree->nodeArity() > 1); - } - Exception::rethrowException(ex); - } catch (...) { - if (jjtc001) { - jjtree->clearNodeScope(jjtn001); - jjtc001 = false; - } else { - jjtree->popNode(); - } - if (jjtc001) { - jjtree->closeNodeScope(jjtn001, jjtree->nodeArity() > 1); - } - throw RuntimeException("Exception in ExpressionParser::LogicalANDExpression."); - } -} - -Token* ExpressionParser::jj_consume_token(int kind) -{ - Token* oldToken = 0; - if ((oldToken = token)->next != 0) - token = token->next; - else - token = token->next = token_source->getNextToken(); - jj_ntk = -1; - - if (token->kind == kind) { - jj_gen++; - if (++jj_gc > 100) { - jj_gc = 0; - for (int i = 0; i < jj_2_rtns_length; i++) { - JJCalls* c = jj_2_rtns[i]; - while (c != 0) { - if (c->gen < jj_gen) - c->first = 0; - c = c->next; - } - } - } - return token; - } - token = oldToken; - jj_kind = kind; - throw generateParseException(); -} - -void ExpressionParser::RelationalExpression(void) -{ - Token* t_name = NULL; - AdditiveExpression(); - if (jj_2_1(2147483647)) { - t_name = jj_consume_token(RELATIONAL_OPERATOR); - AdditiveExpression(); - ASTRelationalNode* jjtn001 = new ASTRelationalNode(JJTRELATIONALNODE); - bool jjtc001 = true; - jjtree->openNodeScope(jjtn001); - try { - jjtree->closeNodeScope(jjtn001, 2); - jjtc001 = false; - if (jjtn001!=NULL){ - ((ASTRelationalNode*)jjtn001)->setOperationFromToken(t_name->image); - } - if (jjtc001) { - jjtree->closeNodeScope(jjtn001, 2); - } - } catch (...) { - if (jjtc001) { - jjtree->closeNodeScope(jjtn001, 2); - } - } - } else { - ; - } -} - -int ExpressionParser::jj_ntk_func(void) -{ - if ((jj_nt=token->next) == NULL) - return (jj_ntk = (token->next=token_source->getNextToken())->kind); - else - return (jj_ntk = jj_nt->kind); -} - -void ExpressionParser::AdditiveExpression(void) -{ - ASTAddNode* jjtn001 = new ASTAddNode(JJTADDNODE); - bool jjtc001 = true; - jjtree->openNodeScope(jjtn001); - try { - MultiplicativeExpression(); - - while (true) { - switch ((jj_ntk==-1)?jj_ntk_func():jj_ntk) { - case ADD: - case SUB: - ; - break; - default: - jj_la1[2] = jj_gen; - goto label_3; - } - switch ((jj_ntk==-1)?jj_ntk_func():jj_ntk) { - case ADD: - jj_consume_token(ADD); - MultiplicativeExpression(); - break; - case SUB: - MinusTerm(); - break; - default: - jj_la1[3] = jj_gen; - jj_consume_token(-1); - throw ParseException(); - } - } -label_3: - if (jjtc001) { - jjtree->closeNodeScope(jjtn001, jjtree->nodeArity() > 1); - } - } catch (Exception& ex) { - if (jjtc001) { - jjtree->clearNodeScope(jjtn001); - jjtc001 = false; - } else { - jjtree->popNode(); - } - if (jjtc001) { - jjtree->closeNodeScope(jjtn001, jjtree->nodeArity() > 1); - } - Exception::rethrowException(ex); - } catch (...) { - if (jjtc001) { - jjtree->clearNodeScope(jjtn001); - jjtc001 = false; - } else { - jjtree->popNode(); - } - if (jjtc001) { - jjtree->closeNodeScope(jjtn001, jjtree->nodeArity() > 1); - } - throw RuntimeException("Exception in ExpressionParser::AdditiveExpression"); - } -} - -void ExpressionParser::MinusTerm(void) -{ - ASTMinusTermNode* jjtn000 = new ASTMinusTermNode(JJTMINUSTERMNODE); - bool jjtc000 = true; - jjtree->openNodeScope(jjtn000); - try { - jj_consume_token(SUB); - MultiplicativeExpression(); - if (jjtc000) { - jjtree->closeNodeScope(jjtn000, true); - } - } catch (Exception& ex) { - if (jjtc000) { - jjtree->clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree->popNode(); - } - if (jjtc000) { - jjtree->closeNodeScope(jjtn000, true); - } - Exception::rethrowException(ex); - } catch (...) { - if (jjtc000) { - jjtree->clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree->popNode(); - } - if (jjtc000) { - jjtree->closeNodeScope(jjtn000, true); - } - - throw RuntimeException("Exception in ExpressionParser::MinusTerm."); - } -} - -void ExpressionParser::MultiplicativeExpression(void) -{ - ASTMultNode* jjtn001 = new ASTMultNode(JJTMULTNODE); - bool jjtc001 = true; - jjtree->openNodeScope(jjtn001); - try { - PowerTerm(); - - while (true) { - switch ((jj_ntk==-1)?jj_ntk_func():jj_ntk) { - case MULT: - case DIV: - ; - break; - default: - jj_la1[4] = jj_gen; - goto label_4; - } - switch ((jj_ntk==-1)?jj_ntk_func():jj_ntk) { - case (MULT): - jj_consume_token(MULT); - PowerTerm(); - break; - case DIV: - DivTerm(); - break; - default: - jj_la1[5] = jj_gen; - jj_consume_token(-1); - throw ParseException(); - } - } -label_4: - if (jjtc001) { - jjtree->closeNodeScope(jjtn001, jjtree->nodeArity() > 1); - } - } catch (Exception& ex) { - if (jjtc001) { - jjtree->clearNodeScope(jjtn001); - jjtc001 = false; - } else { - jjtree->popNode(); - } - if (jjtc001) { - jjtree->closeNodeScope(jjtn001, jjtree->nodeArity() > 1); - } - Exception::rethrowException(ex); - } catch (...) { - if (jjtc001) { - jjtree->clearNodeScope(jjtn001); - jjtc001 = false; - } else { - jjtree->popNode(); - } - if (jjtc001) { - jjtree->closeNodeScope(jjtn001, jjtree->nodeArity() > 1); - } - throw RuntimeException("Exception in ExpressionParser::MultiplicativeExpression"); - } -} - -bool ExpressionParser::jj_2_1(int xla) -{ - jj_la = xla; - jj_lastpos = jj_scanpos = token; - try { - bool retval = !jj_3_1(); - jj_save(0, xla); - return retval; - } catch (LookaheadSuccess ls) { - jj_save(0, xla); - return true; - } -} - -void ExpressionParser::jj_save(int index, int xla) -{ - JJCalls* p = jj_2_rtns[index]; - while (p->gen > jj_gen) { - if (p->next == NULL) { - p = p->next = new JJCalls(); - break; - } - p = p->next; - } - p->gen = jj_gen + xla - jj_la; - p->first = token; - p->arg = xla; -} - -bool ExpressionParser::jj_3_1(void) -{ - if (jj_scan_token(RELATIONAL_OPERATOR)) - return true; - return false; -} - -bool ExpressionParser::jj_scan_token(int kind) -{ - if (jj_scanpos == jj_lastpos) { - jj_la--; - if (jj_scanpos->next == NULL) { - jj_lastpos = jj_scanpos = jj_scanpos->next = token_source->getNextToken(); - } else { - jj_lastpos = jj_scanpos = jj_scanpos->next; - } - } else { - jj_scanpos = jj_scanpos->next; - } - if (jj_rescan) { - int i = 0; - Token* tok = token; - while (tok != NULL && tok != jj_scanpos) { - i++; - tok = tok->next; - } - if (tok != NULL) - jj_add_error_token(kind, i); - } - if (jj_scanpos->kind != kind) - return true; - if (jj_la == 0 && jj_scanpos == jj_lastpos) - throw jj_ls; - return false; -} - -void ExpressionParser::jj_add_error_token(int kind, int pos) -{ - if (pos >= 100) - return; - if (pos == jj_endpos + 1) { - jj_lasttokens[jj_endpos++] = kind; - } else if (jj_endpos != 0) { - jj_expentry = new vector; - for (int i = 0; i < jj_endpos; i++) { - jj_expentry->push_back(jj_lasttokens[i]); - } - bool exists = false; - for (vector< vector* >::iterator iter = jj_expentries.begin(); iter != jj_expentries.end(); iter ++) { - vector* oldentry = (vector*)(*iter); - if (oldentry->size() == jj_expentry->size()) { - exists = true; - for (unsigned int i = 0; i < jj_expentry->size(); i++) { - if ((*oldentry)[i] != (*jj_expentry)[i]) { - exists = false; - break; - } - } - if (exists) break; - } - } - if (!exists) - jj_expentries.push_back(jj_expentry); - if (pos != 0) - jj_lasttokens[(jj_endpos = pos) - 1] = kind; - } -} - -void ExpressionParser::DivTerm(void) -{ - ASTInvertTermNode* jjtn000 = new ASTInvertTermNode(JJTINVERTTERMNODE); - bool jjtc000 = true; - jjtree->openNodeScope(jjtn000); - try { - jj_consume_token(DIV); - PowerTerm(); - if (jjtc000) { - jjtree->closeNodeScope(jjtn000, true); - } - } catch (Exception& ex) { - if (jjtc000) { - jjtree->clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree->popNode(); - } - if (jjtc000) { - jjtree->closeNodeScope(jjtn000, true); - } - Exception::rethrowException(ex); - } catch (...) { - if (jjtc000) { - jjtree->clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree->popNode(); - } - if (jjtc000) { - jjtree->closeNodeScope(jjtn000, true); - } - throw RuntimeException("Exception in ExpressionParser::DivTerm"); - } -} - -void ExpressionParser::PowerTerm(void) -{ - UnaryExpression(); - - while (true) { - if (jj_2_2(2147483647)) { - ; - } else { - goto label_5; - } - jj_consume_token(POWER); - ASTPowerNode* jjtn001 = new ASTPowerNode(JJTPOWERNODE); - bool jjtc001 = true; - jjtree->openNodeScope(jjtn001); - try { - UnaryExpression(); - if (jjtc001) { - jjtree->closeNodeScope(jjtn001, 2); - } - } catch (Exception& ex) { - if (jjtc001) { - jjtree->clearNodeScope(jjtn001); - jjtc001 = false; - } else { - jjtree->popNode(); - } - if (jjtc001) { - jjtree->closeNodeScope(jjtn001, 2); - } - Exception::rethrowException(ex); - } catch (...) { - if (jjtc001) { - jjtree->clearNodeScope(jjtn001); - jjtc001 = false; - } else { - jjtree->popNode(); - } - if (jjtc001) { - jjtree->closeNodeScope(jjtn001, 2); - } - throw RuntimeException("Exception in ExpressionParser::PowerTerm"); - } - } -label_5 : - ; -} - -bool ExpressionParser::jj_2_2(int xla) -{ - jj_la = xla; - jj_lastpos = jj_scanpos = token; - try { - bool retval = !jj_3_2(); - jj_save(1, xla); - return retval; - } catch (LookaheadSuccess ls) { - jj_save(1, xla); - return true; - } -} - -bool ExpressionParser::jj_3_2(void) -{ - if (jj_scan_token(POWER)) - return true; - return false; -} - -void ExpressionParser::UnaryExpression(void) -{ - switch ((jj_ntk == -1) ? jj_ntk_func() : jj_ntk) { - case ADD : - jj_consume_token(ADD); - UnaryExpression(); - break; - case SUB : - { - ASTMinusTermNode* jjtn001 = new ASTMinusTermNode(JJTMINUSTERMNODE); - bool jjtc001 = true; - jjtree->openNodeScope(jjtn001); - try { - jj_consume_token(SUB); - UnaryExpression(); - if (jjtc001) { - jjtree->closeNodeScope(jjtn001, true); - } - } catch (Exception& ex) { - if (jjtc001) { - jjtree->clearNodeScope(jjtn001); - jjtc001 = false; - } else { - jjtree->popNode(); - } - if (jjtc001) { - jjtree->closeNodeScope(jjtn001, true); - } - Exception::rethrowException(ex); - } catch (...) { - if (jjtc001) { - jjtree->clearNodeScope(jjtn001); - jjtc001 = false; - } else { - jjtree->popNode(); - } - if (jjtc001) { - jjtree->closeNodeScope(jjtn001, true); - } - throw RuntimeException("Exception in ExpressionParser::UnaryExpression"); - } - break; - } - case NOT : { - ASTNotNode* jjtn002 = new ASTNotNode(JJTNOTNODE); - bool jjtc002 = true; - jjtree->openNodeScope(jjtn002); - try { - jj_consume_token(NOT); - UnaryExpression(); - if (jjtc002) { - jjtree->closeNodeScope(jjtn002, true); - } - } catch (Exception& ex) { - if (jjtc002) { - jjtree->clearNodeScope(jjtn002); - jjtc002 = false; - } else { - jjtree->popNode(); - } - if (jjtc002) { - jjtree->closeNodeScope(jjtn002, true); - } - Exception::rethrowException(ex); - } catch (...) { - if (jjtc002) { - jjtree->clearNodeScope(jjtn002); - jjtc002 = false; - } else { - jjtree->popNode(); - } - if (jjtc002) { - jjtree->closeNodeScope(jjtn002, true); - } - throw RuntimeException("Exception in ExpressionParser::UnaryExpression"); - } - break; - } - case FLOATING_POINT_LITERAL : - case IDENTIFIER : - case 28 : - PrimaryExpression(); - break; - default : - jj_la1[6] = jj_gen; - jj_consume_token(-1); - throw ParseException(); - } -} - -void ExpressionParser::PrimaryExpression(void) -{ - if (jj_2_3(2147483647)) { - Function(); - } else if (jj_2_4(2147483647)) { - Name(); - } else { - switch ((jj_ntk == -1) ? jj_ntk_func() : jj_ntk) { - case FLOATING_POINT_LITERAL : - Float(); - break; - case 28 : - jj_consume_token(28); - LogicalORExpression(); - jj_consume_token(29); - break; - default : - jj_la1[7] = jj_gen; - jj_consume_token(-1); - throw ParseException(); - } - } -} - -bool ExpressionParser::jj_2_3(int xla) -{ - jj_la = xla; - jj_lastpos = jj_scanpos = token; - try { - bool retval = !jj_3_3(); - jj_save(2, xla); - return retval; - } catch (LookaheadSuccess ls) { - jj_save(2, xla); - return true; - } -} - -bool ExpressionParser::jj_3_3(void) -{ - if (jj_scan_token(IDENTIFIER)) - return true; - if (jj_scan_token(28)) - return true; - return false; -} - -bool ExpressionParser::jj_2_4(int xla) -{ - jj_la = xla; - jj_lastpos = jj_scanpos = token; - try { - bool retval = !jj_3_4(); - jj_save(3, xla); - return retval; - } catch (LookaheadSuccess ls) { - jj_save(3, xla); - return true; - } -} - -bool ExpressionParser::jj_3_4(void) -{ - if (jj_3R_7()) - return true; - return false; -} - -bool ExpressionParser::jj_3R_7(void) -{ - if (jj_scan_token(IDENTIFIER)) - return true; - return false; -} - -void ExpressionParser::Function(void) -{ - ASTFuncNode* jjtn000 = new ASTFuncNode(JJTFUNCNODE); - bool jjtc000 = true; - jjtree->openNodeScope(jjtn000); - Token* t; - try { - t = jj_consume_token(IDENTIFIER); - Arguments(); - jjtree->closeNodeScope(jjtn000, true); - jjtc000 = false; - jjtn000->setFunctionFromParserToken(t->image); - if (jjtc000) { - jjtree->closeNodeScope(jjtn000, true); - } - } catch (Exception& ex) { - if (jjtc000) { - jjtree->clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree->popNode(); - } - if (jjtc000) { - jjtree->closeNodeScope(jjtn000, true); - } - Exception::rethrowException(ex); - } catch (...) { - if (jjtc000) { - jjtree->clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree->popNode(); - } - if (jjtc000) { - jjtree->closeNodeScope(jjtn000, true); - } - throw RuntimeException("Exception in ExpressionParser::Function()"); - } -} - -void ExpressionParser::Arguments(void) -{ - jj_consume_token(28); - switch ((jj_ntk == -1) ? jj_ntk_func() : jj_ntk) { - case NOT : - case ADD : - case SUB : - case FLOATING_POINT_LITERAL : - case IDENTIFIER : - case 28 : - ArgumentList(); - break; - default : - jj_la1[8] = jj_gen; - ; - } - jj_consume_token(29); -} - -void ExpressionParser::ArgumentList(void) -{ - LogicalORExpression(); - while (true) { - switch ((jj_ntk == -1) ? jj_ntk_func() : jj_ntk) { - case 30 : - ; - break; - default : - jj_la1[9] = jj_gen; - goto label_6; - } - jj_consume_token(30); - LogicalORExpression(); - } -label_6 : - ; -} - -void ExpressionParser::Float(void) -{ - ASTFloatNode* jjtn000 = new ASTFloatNode(JJTFLOATNODE); - bool jjtc000 = true; - jjtree->openNodeScope(jjtn000); - Token* t; - try { - t = jj_consume_token(FLOATING_POINT_LITERAL); - jjtree->closeNodeScope(jjtn000, true); - jjtc000 = false; - jjtn000->value = atof(t->image.c_str()); - if (jjtc000) { - jjtree->closeNodeScope(jjtn000, true); - } - } catch (...) { - if (jjtc000) { - jjtree->closeNodeScope(jjtn000, true); - } - } -} - -void ExpressionParser::Name(void) -{ - ASTIdNode* jjtn000 = new ASTIdNode(JJTIDNODE); - bool jjtc000 = true; - jjtree->openNodeScope(jjtn000); - Token* t_name = NULL; - try { - t_name = jj_consume_token(IDENTIFIER); - jjtree->closeNodeScope(jjtn000, true); - jjtc000 = false; - jjtn000->name = t_name->image; - if (jjtc000) { - jjtree->closeNodeScope(jjtn000, true); - } - } catch(...) { - if (jjtc000) { - jjtree->closeNodeScope(jjtn000, true); - } - } -} - -ParseException& ExpressionParser::generateParseException(void) -{ - jj_expentries.clear(); - bool* la1tokens = new bool[31]; - for (int i = 0; i < 31; i++) { - la1tokens[i] = false; - } - if (jj_kind >= 0) { - la1tokens[jj_kind] = true; - jj_kind = -1; - } - - for (int i = 0; i < 10; i++) { - if (jj_la1[i] == jj_gen) { - for (int j = 0; j < 32; j++) { - if ((jj_la1_0[i] & (1 << j)) != 0) { - la1tokens[j] = true; - } - } - } - } - for (int i = 0; i < 31; i++) { - if (la1tokens[i]) { - jj_expentry = new vector; - jj_expentry->push_back(i); - jj_expentries.push_back(jj_expentry); - } - } - - delete [] la1tokens; - - jj_endpos = 0; - jj_rescan_token(); - jj_add_error_token(0, 0); - int numETS = (int)jj_expentries.size(); - int* etsLengthArray = new int[numETS]; - int** exptokseq = new int*[numETS]; - for (int i = 0; i < numETS; i++) { - vector* entry = (vector*)(jj_expentries.at(i)); - etsLengthArray[i] = (int)entry->size(); - exptokseq[i] = new int[etsLengthArray[i]]; - for (int j = 0; j < etsLengthArray[i]; j ++) { - exptokseq[i][j] = entry->at(j); - } - } - - ParseException* ex = new ParseException(token, exptokseq, numETS, etsLengthArray, tokenImage); - throw (*ex); -} - -void ExpressionParser::jj_rescan_token(void) -{ - jj_rescan = true; - for (int i = 0; i < 4; i++) { - try { - JJCalls* p = jj_2_rtns[i]; - do { - if (p->gen > jj_gen) { - jj_la = p->arg; - jj_lastpos = jj_scanpos = p->first; - switch (i) { - case 0 : - jj_3_1(); - break; - case 1 : - jj_3_2(); - break; - case 2 : - jj_3_3(); - break; - case 3 : - jj_3_4(); - break; - } - } - p = p->next; - } while (p != NULL); - } catch(LookaheadSuccess& ls) { } - } - jj_rescan = false; -} diff --git a/ExpressionParser/ExpressionParser.h b/ExpressionParser/ExpressionParser.h deleted file mode 100644 index 41aaffc02..000000000 --- a/ExpressionParser/ExpressionParser.h +++ /dev/null @@ -1,97 +0,0 @@ -#ifndef EXPRESSIONPARSER_H -#define EXPRESSIONPARSER_H - -#include -using std::vector; - -#include "Token.h" -#include "ASTExpression.h" -#include "ExpressionParserTokenManager.h" -#include "JJTExpressionParserState.h" -#include "SimpleCharStream.h" -#include "ParseException.h" - -struct JJCalls { - int gen; - Token* first; - int arg; - JJCalls* next; -}; - -class LookaheadSuccess : public Exception { -public: - LookaheadSuccess() : Exception("LookaheadSuccess", "") {}; - LookaheadSuccess(string msg) : Exception("LookaheadSuccess", msg) {}; -}; - -class ExpressionParser { -protected: - JJTExpressionParserState* jjtree; - SimpleCharStream* jj_input_stream; - -public: - ExpressionParser(ExpressionParserTokenManager* tm); - ExpressionParser(istream* stream); - ~ExpressionParser(); - ASTExpression* Expression(void); - -private: - bool lookingAhead; - ExpressionParserTokenManager* token_source; - Token* token, *jj_nt, *headToken; - void LogicalORExpression(void); - void LogicalANDExpression(void); - void AdditiveExpression(void); - void MinusTerm(void); - void MultiplicativeExpression(void); - void RelationalExpression(void); - void DivTerm(void); - void PowerTerm(void); - void UnaryExpression(void); - void PrimaryExpression(void); - void Function(void); - void Arguments(void); - void ArgumentList(void); - void Float(void); - void Name(void); - ParseException& generateParseException(void); - - int jj_ntk; - Token* jj_scanpos, *jj_lastpos; - int jj_la; - bool jj_semLA; - int jj_gen; - int* jj_la1; - - JJCalls** jj_2_rtns; - int jj_2_rtns_length; - bool jj_rescan; - int jj_gc; - - LookaheadSuccess jj_ls; - - vector< vector* > jj_expentries; - vector *jj_expentry; - int jj_kind; - int* jj_lasttokens; - int jj_endpos; - Token* jj_consume_token(int kind); - int jj_ntk_func(void); - bool jj_2_1(int xla); - void jj_save(int index, int xla); - bool jj_3_1(void); - bool jj_scan_token(int kind); - void jj_add_error_token(int kind, int pos); - bool jj_2_2(int xla); - bool jj_3_2(void); - bool jj_2_3(int xla); - bool jj_3_3(void); - bool jj_2_4(int xla); - bool jj_3_4(void); - bool jj_3R_7(void); - - void init(void); - void jj_rescan_token(void); -}; - -#endif diff --git a/ExpressionParser/ExpressionParserConstants.h b/ExpressionParser/ExpressionParserConstants.h deleted file mode 100644 index e629a6d55..000000000 --- a/ExpressionParser/ExpressionParserConstants.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef EXPRESSIONPARSERCONSTANTS_H -#define EXPRESSIONPARSERCONSTANTS_H - -const int EEOF = 0; -const int RELATIONAL_OPERATOR = 5; -const int LT = 6; -const int GT = 7; -const int LE = 8; -const int GE = 9; -const int EQ = 10; -const int NE = 11; -const int AND = 12; -const int OR = 13; -const int NOT = 14; -const int POWER = 15; -const int ADD = 16; -const int SUB = 17; -const int MULT = 18; -const int DIV = 19; -const int FLOATING_POINT_LITERAL = 20; -const int EXPONENT = 21; -const int INTEGER_LITERAL = 22; -const int IDENTIFIER = 23; -const int ID = 24; -const int LETTER = 25; -const int DIGIT = 26; - -const int DEFAULT = 0; - -const string tokenImage[] = { - "", - "\" \"", - "\"\\t\"", - "\"\\n\"", - "\"\\r\"", - "", - "\"<\"", - "\">\"", - "\"<=\"", - "\">=\"", - "\"==\"", - "\"!=\"", - "", - "", - "", - "\"^\"", - "\"+\"", - "\"-\"", - "\"*\"", - "\"/\"", - "", - "", - "", - "", - "", - "", - "", - "\";\"", - "\"(\"", - "\")\"", - "\",\"", -}; - -#endif diff --git a/ExpressionParser/ExpressionParserTokenManager.cpp b/ExpressionParser/ExpressionParserTokenManager.cpp deleted file mode 100644 index 299b2169f..000000000 --- a/ExpressionParser/ExpressionParserTokenManager.cpp +++ /dev/null @@ -1,625 +0,0 @@ -#include -#include -#include - -#include "ExpressionParserTokenManager.h" -#include "RuntimeException.h" -#include "IOException.h" - -int ExpressionParserTokenManager::jjnextStates[] = {35, 36, 41, 42, 31, 32, 31, 32, 33, 22, 23, 39, 40, 43, 44, }; - -string* ExpressionParserTokenManager::jjstrLiteralImages[] = { - new string(""), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, new string("\136"), new string("\53"), new string("\55"), new string("\52"), new string("\57"), - NULL, NULL, NULL, NULL, NULL, NULL, NULL, new string("\73"), new string("\50"), new string("\51"), new string("\54"), -}; - -string ExpressionParserTokenManager::lexStateNames[] = { - "DEFAULT", -}; - -int64 ExpressionParserTokenManager::jjtoToken[] = { 0x789ff021L, }; - -int64 ExpressionParserTokenManager::jjtoSkip[] = { 0x1eL, }; - -void ExpressionParserTokenManager::setDebugStream(ostream* os) -{ - debugStream = os; -} - -ExpressionParserTokenManager::ExpressionParserTokenManager(SimpleCharStream* stream) -{ - init(stream); -} - - -ExpressionParserTokenManager::ExpressionParserTokenManager(SimpleCharStream* stream, int lexState) -{ - init(stream); - SwitchTo(lexState); -} - -void ExpressionParserTokenManager::init(SimpleCharStream* stream) -{ - if (SimpleCharStream::staticFlag) - throw RuntimeException("ERROR: Cannot use a static CharStream class with a non-static lexical analyzer."); - jjnewStateCnt = 0; - jjround = 0; - jjmatchedKind = 0; - jjmatchedPos = 0; - curLexState = 0; - defaultLexState = 0; - jjrounds = new int[45]; - memset(jjrounds, 0, 45 * sizeof(int)); - jjstateSet = new int[90]; - memset(jjstateSet, 0, 90 * sizeof(int)); - input_stream = stream; - debugStream = 0; -} - -ExpressionParserTokenManager::~ExpressionParserTokenManager(void) -{ - delete[] jjrounds; - delete[] jjstateSet; -} - -int ExpressionParserTokenManager::jjStopStringLiteralDfa_0(int pos, long active0) -{ - switch (pos) - { - default : - return -1; - } -} - -int ExpressionParserTokenManager::jjStartNfa_0(int pos, long active0) -{ - return jjMoveNfa_0(jjStopStringLiteralDfa_0(pos, active0), pos + 1); -} - -int ExpressionParserTokenManager::jjStopAtPos(int pos, int kind) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - return pos + 1; -} - -int ExpressionParserTokenManager::jjStartNfaWithStates_0(int pos, int kind, int state) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - try { - curChar = input_stream->readChar(); - } catch(...) { - return pos + 1; - } - return jjMoveNfa_0(state, pos + 1); -} - -int ExpressionParserTokenManager::jjMoveStringLiteralDfa0_0(void) -{ - switch(curChar) - { - case 40: - return jjStopAtPos(0, 28); - case 41: - return jjStopAtPos(0, 29); - case 42: - return jjStopAtPos(0, 18); - case 43: - return jjStopAtPos(0, 16); - case 44: - return jjStopAtPos(0, 30); - case 45: - return jjStopAtPos(0, 17); - case 47: - return jjStopAtPos(0, 19); - case 59: - return jjStopAtPos(0, 27); - case 94: - return jjStopAtPos(0, 15); - default : - return jjMoveNfa_0(0, 0); - } -} - -void ExpressionParserTokenManager::jjCheckNAdd(int state) -{ - if (jjrounds[state] != jjround) - { - jjstateSet[jjnewStateCnt++] = state; - jjrounds[state] = jjround; - } -} - -void ExpressionParserTokenManager::jjAddStates(int start, int end) -{ - do { - jjstateSet[jjnewStateCnt++] = jjnextStates[start]; - } while (start++ != end); -} - -void ExpressionParserTokenManager::jjCheckNAddTwoStates(int state1, int state2) -{ - jjCheckNAdd(state1); - jjCheckNAdd(state2); -} - -void ExpressionParserTokenManager::jjCheckNAddStates(int start) -{ - jjCheckNAdd(jjnextStates[start]); - jjCheckNAdd(jjnextStates[start + 1]); -} - -void ExpressionParserTokenManager::jjCheckNAddStates(int start, int end) -{ - do { - jjCheckNAdd(jjnextStates[start]); - } while (start++ != end); -} - -int ExpressionParserTokenManager::jjMoveNfa_0(int startState, int curPos) -{ - int* nextStates; - int startsAt = 0; - jjnewStateCnt = 45; - int i = 1; - jjstateSet[0] = startState; - int j, kind = 0x7fffffff; - for (;;) - { - if (++jjround == 0x7fffffff) - ReInitRounds(); - if (curChar < 64) - { - int64 l = ((int64)1LL) << curChar; - MatchLoop1: do - { - switch(jjstateSet[--i]) - { - case 0: - if ((0x3ff000000000000LL & l) != 0LL) - jjCheckNAddStates(0, 3); - else if ((0x5000000000000000LL & l) != 0LL) - { - if (kind > 5) - kind = 5; - } - else if (curChar == 35) - jjstateSet[jjnewStateCnt++] = 28; - else if (curChar == 46) - jjCheckNAdd(20); - else if (curChar == 33) - { - if (kind > 14) - kind = 14; - } - else if (curChar == 38) - jjstateSet[jjnewStateCnt++] = 6; - else if (curChar == 61) - jjCheckNAdd(1); - if ((0x3fe000000000000LL & l) != 0LL) - { - if (kind > 20) - kind = 20; - jjCheckNAdd(25); - } - else if (curChar == 48) - { - if (kind > 20) - kind = 20; - } - else if (curChar == 33) - jjCheckNAdd(1); - else if (curChar == 62) - jjCheckNAdd(1); - else if (curChar == 60) - jjCheckNAdd(1); - break; - case 1: - if (curChar == 61 && kind > 5) - kind = 5; - break; - case 2: - if (curChar == 60) - jjCheckNAdd(1); - break; - case 3: - if (curChar == 62) - jjCheckNAdd(1); - break; - case 4: - if (curChar == 61) - jjCheckNAdd(1); - break; - case 5: - if (curChar == 33) - jjCheckNAdd(1); - break; - case 6: - if (curChar == 38 && kind > 12) - kind = 12; - break; - case 7: - if (curChar == 38) - jjstateSet[jjnewStateCnt++] = 6; - break; - case 15: - if (curChar == 33 && kind > 14) - kind = 14; - break; - case 19: - if (curChar == 46) - jjCheckNAdd(20); - break; - case 20: - if ((0x3ff000000000000LL & l) == 0LL) - break; - if (kind > 20) - kind = 20; - jjCheckNAddTwoStates(20, 21); - break; - case 22: - if ((0x280000000000LL & l) != 0LL) - jjCheckNAdd(23); - break; - case 23: - if ((0x3ff000000000000LL & l) == 0LL) - break; - if (kind > 20) - kind = 20; - jjCheckNAdd(23); - break; - case 24: - if ((0x3fe000000000000LL & l) == 0LL) - break; - if (kind > 20) - kind = 20; - jjCheckNAdd(25); - break; - case 25: - if ((0x3ff000000000000LL & l) == 0LL) - break; - if (kind > 20) - kind = 20; - jjCheckNAdd(25); - break; - case 26: - if (curChar == 48 && kind > 20) - kind = 20; - break; - case 27: - if (curChar == 35) - jjstateSet[jjnewStateCnt++] = 28; - break; - case 29: - if ((0x3ff000000000000LL & l) == 0LL) - break; - if (kind > 23) - kind = 23; - jjstateSet[jjnewStateCnt++] = 29; - break; - case 31: - if ((0x3ff000000000000LL & l) != 0LL) - jjAddStates(4, 5); - break; - case 32: - if (curChar == 46) - jjstateSet[jjnewStateCnt++] = 30; - break; - case 33: - if ((0x3ff000000000000LL & l) == 0LL) - break; - if (kind > 23) - kind = 23; - jjstateSet[jjnewStateCnt++] = 33; - break; - case 34: - if ((0x3ff000000000000LL & l) != 0LL) - jjCheckNAddStates(0, 3); - break; - case 35: - if ((0x3ff000000000000LL & l) != 0LL) - jjCheckNAddTwoStates(35, 36); - break; - case 36: - if (curChar != 46) - break; - if (kind > 20) - kind = 20; - jjCheckNAddTwoStates(37, 38); - break; - case 37: - if ((0x3ff000000000000LL & l) == 0LL) - break; - if (kind > 20) - kind = 20; - jjCheckNAddTwoStates(37, 38); - break; - case 39: - if ((0x280000000000LL & l) != 0LL) - jjCheckNAdd(40); - break; - case 40: - if ((0x3ff000000000000LL & l) == 0LL) - break; - if (kind > 20) - kind = 20; - jjCheckNAdd(40); - break; - case 41: - if ((0x3ff000000000000LL & l) != 0LL) - jjCheckNAddTwoStates(41, 42); - break; - case 43: - if ((0x280000000000LL & l) != 0LL) - jjCheckNAdd(44); - break; - case 44: - if ((0x3ff000000000000LL & l) == 0LL) - break; - if (kind > 20) - kind = 20; - jjCheckNAdd(44); - break; - default : break; - } - } while(i != startsAt); - } - else if (curChar < 128) - { - int64 l = ((int64)1LL) << (curChar & 077); - MatchLoop2: do - { - switch(jjstateSet[--i]) - { - case 0: - if ((0x7fffffe87fffffeLL & l) != 0LL) - { - if (kind > 23) - kind = 23; - jjCheckNAddStates(6, 8); - } - else if (curChar == 124) - jjstateSet[jjnewStateCnt++] = 11; - if ((0x400000004000LL & l) != 0L) - jjstateSet[jjnewStateCnt++] = 17; - else if ((0x800000008000LL & l) != 0LL) - jjstateSet[jjnewStateCnt++] = 14; - else if ((0x200000002LL & l) != 0L) - jjstateSet[jjnewStateCnt++] = 9; - break; - case 8: - if ((0x200000002LL & l) != 0L) - jjstateSet[jjnewStateCnt++] = 9; - break; - case 9: - if ((0x400000004000LL & l) != 0L) - jjstateSet[jjnewStateCnt++] = 10; - break; - case 10: - if ((0x1000000010LL & l) != 0L && kind > 12) - kind = 12; - break; - case 11: - if (curChar == 124 && kind > 13) - kind = 13; - break; - case 12: - if (curChar == 124) - jjstateSet[jjnewStateCnt++] = 11; - break; - case 13: - if ((0x800000008000LL & l) != 0LL) - jjstateSet[jjnewStateCnt++] = 14; - break; - case 14: - if ((0x4000000040000LL & l) != 0LL && kind > 13) - kind = 13; - break; - case 16: - if ((0x400000004000LL & l) != 0LL) - jjstateSet[jjnewStateCnt++] = 17; - break; - case 17: - if ((0x800000008000LL & l) != 0LL) - jjstateSet[jjnewStateCnt++] = 18; - break; - case 18: - if ((0x10000000100000LL & l) != 0LL && kind > 14) - kind = 14; - break; - case 21: - if ((0x2000000020LL & l) != 0LL) - jjAddStates(9, 10); - break; - case 28: - case 29: - if ((0x7fffffe87fffffeLL & l) == 0LL) - break; - if (kind > 23) - kind = 23; - jjCheckNAdd(29); - break; - case 30: - if ((0x7fffffe87fffffeLL & l) == 0LL) - break; - if (kind > 23) - kind = 23; - jjCheckNAddStates(6, 8); - break; - case 31: - if ((0x7fffffe87fffffeLL & l) != 0LL) - jjCheckNAddTwoStates(31, 32); - break; - case 33: - if ((0x7fffffe87fffffeLL & l) == 0LL) - break; - if (kind > 23) - kind = 23; - jjCheckNAdd(33); - break; - case 38: - if ((0x2000000020LL & l) != 0LL) - jjAddStates(11, 12); - break; - case 42: - if ((0x2000000020LL & l) != 0LL) - jjAddStates(13, 14); - break; - default : break; - } - } while(i != startsAt); - } - else - { - int i2 = (curChar & 0xff) >> 6; - int64 l2 = ((int64)1LL) << (curChar & 077); - MatchLoop3: do - { - switch(jjstateSet[--i]) - { - default : break; - } - } while(i != startsAt); - } - if (kind != 0x7fffffff) - { - jjmatchedKind = kind; - jjmatchedPos = curPos; - kind = 0x7fffffff; - } - ++curPos; - if ((i = jjnewStateCnt) == (startsAt = 45 - (jjnewStateCnt = startsAt))) - return curPos; - try { - curChar = input_stream->readChar(); - } catch (...) { - return curPos; - } - } - } - -void ExpressionParserTokenManager::ReInit(SimpleCharStream* stream) -{ - jjmatchedPos = jjnewStateCnt = 0; - curLexState = defaultLexState; - input_stream = stream; - ReInitRounds(); -} - -void ExpressionParserTokenManager::ReInitRounds(void) -{ - int i; - jjround = 0x80000001; - for (i = 45; i-- > 0;) - jjrounds[i] = 0x80000000; -} - -void ExpressionParserTokenManager::ReInit(SimpleCharStream* stream, int lexState) -{ - ReInit(stream); - SwitchTo(lexState); -} - -void ExpressionParserTokenManager::SwitchTo(int lexState) -{ - if (lexState >= 1 || lexState < 0) { - char ex[20]; - sprintf(ex, "%d\0", lexState); - throw RuntimeException("Error: Ignoring invalid lexical state: " + string(ex) + ".State unchanged."); - } - else - curLexState = lexState; -} - -Token* ExpressionParserTokenManager::jjFillToken(void) -{ - Token* t = Token::newToken(jjmatchedKind); - t->kind = jjmatchedKind; - string* im = jjstrLiteralImages[jjmatchedKind]; - t->image = (im == NULL) ? input_stream->GetImage() : *im; - t->beginLine = input_stream->getBeginLine(); - t->beginColumn = input_stream->getBeginColumn(); - t->endLine = input_stream->getEndLine(); - t->endColumn = input_stream->getEndColumn(); - return t; -} - -Token* ExpressionParserTokenManager::getNextToken(void) -{ - int kind; - Token* specialToken = 0; - Token* matchedToken = 0; - int curPos = 0; - - for (;;) - { - try - { - curChar = input_stream->BeginToken(); - } catch(IOException& ex) { - jjmatchedKind = 0; - matchedToken = jjFillToken(); - return matchedToken; - } - - try { - input_stream->backup(0); - while (curChar <= 32 && (0x100002600LL & (((int64)1LL) << curChar)) != 0LL) - curChar = input_stream->BeginToken(); - } catch (...) { - goto EOFLoop; - } - jjmatchedKind = 0x7fffffff; - jjmatchedPos = 0; - curPos = jjMoveStringLiteralDfa0_0(); - if (jjmatchedKind != 0x7fffffff) - { - if (jjmatchedPos + 1 < curPos) - input_stream->backup(curPos - jjmatchedPos - 1); - if ((jjtoToken[jjmatchedKind >> 6] & (((int64)1LL) << (jjmatchedKind & 077))) != 0LL) - { - matchedToken = jjFillToken(); - return matchedToken; - } - else - { - goto EOFLoop; - } - } - int error_line = input_stream->getEndLine(); - int error_column = input_stream->getEndColumn(); - string error_after = ""; - bool EOFSeen = false; - try { - input_stream->readChar(); - input_stream->backup(1); - } catch (...) { - EOFSeen = true; - error_after = curPos <= 1 ? "" : input_stream->GetImage(); - if (curChar == '\n' || curChar == '\r') { - error_line++; - error_column = 0; - } - else - error_column++; - } - if (!EOFSeen) { - input_stream->backup(1); - error_after = curPos <= 1 ? "" : input_stream->GetImage(); - } - char chrs[1000]; - if (EOFSeen) - sprintf(chrs, "Lexical error at line %d, column %d. Encountered: \0", error_line, error_column); - else { - string a = Exception::add_escapes(string(&curChar, 1)); - string b = Exception::add_escapes(error_after); - sprintf(chrs, "Lexical error at line %d, column %d. Encountered: \"%s\" (%d) after : \"%s\"\0", error_line, error_column, a.c_str(), curChar, b.c_str()); - } - - throw RuntimeException(chrs); - } -EOFLoop : - return 0; -} diff --git a/ExpressionParser/ExpressionParserTokenManager.h b/ExpressionParser/ExpressionParserTokenManager.h deleted file mode 100644 index aeb7d4872..000000000 --- a/ExpressionParser/ExpressionParserTokenManager.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef EXPRESSIONPARSERTOKENMANAGER_H -#define EXPRESSIONPARSERTOKENMANAGER_H - -#include -#include -using std::string; -using std::ostream; - -#include "Token.h" -#include "SimpleCharStream.h" - -#ifndef int64 -typedef long long int64; -#endif - -class ExpressionParserTokenManager -{ -public: - ExpressionParserTokenManager(SimpleCharStream* stream); - ExpressionParserTokenManager(SimpleCharStream* stream, int lexState); - ~ExpressionParserTokenManager(void); - Token* getNextToken(void); - -private: - int curLexState; - int defaultLexState; - int jjnewStateCnt; - int jjround; - int jjmatchedPos; - int jjmatchedKind; - static int jjnextStates[]; - static int64 jjtoToken[]; - static int64 jjtoSkip[]; - char curChar; - - static string* jjstrLiteralImages[]; - static string lexStateNames[]; - ostream* debugStream; - void setDebugStream(ostream* os); - void ReInit(SimpleCharStream* stream); - void ReInit(SimpleCharStream* stream, int lexState); - void SwitchTo(int lexState); - - int jjStopStringLiteralDfa_0(int pos, long active0); - int jjStartNfa_0(int pos, long active0); - int jjStopAtPos(int pos, int kind); - int jjStartNfaWithStates_0(int pos, int kind, int state); - SimpleCharStream* input_stream; - int* jjrounds; - int* jjstateSet; - - int jjMoveStringLiteralDfa0_0(void); - void jjCheckNAdd(int state); - void jjAddStates(int start, int end); - void jjCheckNAddTwoStates(int state1, int state2); - void jjCheckNAddStates(int start); - void jjCheckNAddStates(int start, int end); - int jjMoveNfa_0(int startState, int curPos); - void ReInitRounds(void); - void init(SimpleCharStream* stream); - Token* jjFillToken(void); -}; - -#endif diff --git a/ExpressionParser/ExpressionParserTreeConstants.h b/ExpressionParser/ExpressionParserTreeConstants.h deleted file mode 100644 index 591d78555..000000000 --- a/ExpressionParser/ExpressionParserTreeConstants.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef EXPRESSIONPARSERTREECONSTANTS_H -#define EXPRESSIONPARSERTREECONSTANTS_H - -const int JJTEXPRESSION = 0; -const int JJTVOID = 1; -const int JJTORNODE = 2; -const int JJTANDNODE = 3; -const int JJTRELATIONALNODE = 4; -const int JJTADDNODE = 5; -const int JJTMINUSTERMNODE = 6; -const int JJTMULTNODE = 7; -const int JJTINVERTTERMNODE = 8; -const int JJTPOWERNODE = 9; -const int JJTNOTNODE = 10; -const int JJTFUNCNODE = 11; -const int JJTFLOATNODE = 12; -const int JJTIDNODE = 13; - -const string jjtNodeName[] = { - "Expression", - "void", - "OrNode", - "AndNode", - "RelationalNode", - "AddNode", - "MinusTermNode", - "MultNode", - "InvertTermNode", - "PowerNode", - "NotNode", - "FuncNode", - "FloatNode", - "IdNode", -}; - -#endif diff --git a/ExpressionParser/ExpressionTest.cpp b/ExpressionParser/ExpressionTest.cpp deleted file mode 100644 index b7f8905ca..000000000 --- a/ExpressionParser/ExpressionTest.cpp +++ /dev/null @@ -1,260 +0,0 @@ -#include -#include -#include - -#include "MathUtil.h" -#include "Exception.h" -#include "ExpressionTest.h" -#include "Expression.h" -#include "SimpleSymbolTable.h" -#include "RuntimeException.h" -#include "IOException.h" -#include -#include -#include -using std::cout; -using std::endl; -using std::max; -using std::ifstream; - -ExpressionTest::ExpressionTest(void) -{ -} - -ExpressionTest::~ExpressionTest(void) -{ -} - -void ExpressionTest::testEvaluateVector(void) -{ - try { - double d = 0.0; - cout << "Parser: evaluating vector" << endl; - Expression* exp = new Expression("a+b/c"); - string ss[] = { "a", "b", "c" }; - SimpleSymbolTable* simpleSymbolTable = new SimpleSymbolTable(ss, 3); - - const int n = 3; - double v[][n] = {{ 0,1,2 },{ 3,4,5 }, {6,7,8}}; - - exp->bindExpression(simpleSymbolTable); - - for (int i = 0; i < n; i ++) { - d = exp->evaluateVector(v[i]); - cout << i << "." << exp->infix() << " = " << d << endl; - } - delete exp; - delete simpleSymbolTable; - } catch (Exception& ex) { - Exception::rethrowException(ex); - } catch (...) { - throw RuntimeException("Unknown excpetion."); - } -} - -void ExpressionTest::testEvaluateConstant(void) -{ - try { - double d = 0.0; - cout << "Parser: evaluating constant" << endl; - Expression* exp = new Expression("(3/5"); - d = exp->evaluateConstant(); - cout << exp->infix() << " = " << d << endl; - delete exp; - } catch (Exception& ex) { - Exception::rethrowException(ex); - } catch (...) { - throw RuntimeException("Unknown excpetion."); - } -} - -void ExpressionTest::testParser(int count, char* javaresult, double cvalue, char* expStr, SymbolTable* symbolTable, double* values) { - Expression* exp = 0; - string badmsg; - try { - double javavalue = -0.0; - double d = 0.0; - double dtree = 0.0; - int n = -1; - if (strcmp(javaresult, "NaN") == 0) { - javavalue = log(-1.0); - } else if (strcmp(javaresult, "Infinity") == 0) { - javavalue = MathUtil::double_infinity; - } else if (strcmp(javaresult, "-Infinity") == 0) { - javavalue = -MathUtil::double_infinity; - } else { - n = sscanf(javaresult, "%lg", &javavalue); - if (n != 1) { - cout << " Not a Number:: " << javaresult ; - return; - } - } - bool bException = false; - string before = Expression::trim(string(expStr)); - exp = new Expression(expStr); - string exceptionMsg = ""; - try { - exp->bindExpression(symbolTable); - d = exp->evaluateVector(values); - dtree = exp->evaluateVectorTree(values); - } catch (Exception& ex) { - bException = true; - exceptionMsg = ex.getMessage(); - } - if (d != d && javavalue != javavalue && cvalue != cvalue) { - //cout << count << " EVAL_YES :: all NaN" << endl; - } else if (javavalue == d && d == cvalue && d == dtree - || fabs(javavalue - d) < 1E-14 && fabs(cvalue - d) < 1E-14 - || fabs(javavalue - d)/max(fabs(d),fabs(javavalue)) < 1E-14 && fabs(cvalue - d)/max(fabs(d),fabs(cvalue)) < 1E-14 ) { - //cout << count << " EVAL_YES " << endl; - } else { - if (bException) { - //cout << endl << "-------------------------------------------" << endl; - //char chrs[2560]; - //sprintf(chrs, "%d. C++ throws exception: %s", count, exceptionMsg.data()); - //cout << chrs << " EVAL_NO " ; - //printf("Java/Infix_C/C++: %.20g/%.20g/Exception\n", count, cvalue, javavalue); - //cout << expStr << endl; - } else { - cout << endl << "-------------------------------------------" << endl; - printf("%d. EVAL_NO Java/Infix_C/C++ Tree/C++: %.20lg/%.20lg/%.20lg/%.20lg\n", count, javavalue, cvalue, dtree, d); - printf("Java~Infix_C/Java~C++/Infix_C~C++: %.20lg/%.20lg/%.20lg/%.20lg\n", fabs((javavalue-cvalue)/javavalue), fabs((javavalue-d)/javavalue), fabs((dtree-cvalue)/cvalue), fabs((d-cvalue)/cvalue)); - cout << expStr << endl; - } - } - - delete exp; - } catch (Exception& ex) { - cout << ex.getMessage() << endl; - } -} - -void ExpressionTest::testParser(char* filename) -{ - Expression* exp = 0; - /* - exp = new Expression("sqrt(( - (1 * 0.9097624582911913 * 5) * ((0.1156280095277954 * 0.9004846229454024 * 0.5705921628352123) || (0.2422790712041183 + 0.94879464626319 + 0.749322637829414)) * (0.8524685675688051 / 1 * (0.21046361766770427 * 0.1362470304410489 * 0.044029610742542746))))"); - double d = exp->evaluateConstant(); - printf("%s=%.20lg\n", exp->infix().c_str(), d); - */ - - string ids[] = {"id_0", "id_1", "id_2", "id_3", - "id_4", "id_5", "id_6", "id_7", "id_8", "id_9"}; - SimpleSymbolTable* symbolTable = new SimpleSymbolTable(ids, 10); - - const int m = 2; - const int n = 10; - double v[m][n] = {{0,1,2,3,4,5,6,7,8,9 },{ 1,2,3,4,5,6,7,8,9,10}}; - - ifstream ifs(filename); - if (!ifs.is_open()) { - throw IOException(string("") + "Can't open file '" + filename); - } - int count = 0; - vector badmsg; - bool bInfinity = false; - bool bNAN = false; - bool bException = false; - - char line[1000]; - while(!ifs.eof()) { - try { - double value = -0.0; - double d = 0.0; - count ++; - bInfinity = false; - bNAN = false; - cout << count << "...."; - memset(line, 0, 1000*sizeof(char)); - ifs >> line; - int n = -1; - if (strcmp(line, "NaN") == 0) { - bNAN = true; - } else if (strcmp(line, "Infinity") == 0 || strcmp(line, "-Infinity") == 0) { - bInfinity = true; - } else { - n = sscanf(line, "%lg", &value); - if (n != 1) { - cout << " Not a Number:: " << line ; - } - } - memset(line, 0, 1000*sizeof(char)); - ifs.getline(line, 1000); - if (n != 1 && !bInfinity && !bNAN) { - cout << line; - goto label_1; - } - bException = false; - string before = Expression::trim(string(line)); - exp = new Expression(line); - string exceptionMsg = ""; - try { - exp->bindExpression(symbolTable); - d = exp->evaluateVector(v[0]); - } catch (Exception& ex) { - bException = true; - exceptionMsg = ex.getMessage(); - } - if ((MathUtil::double_infinity == d || MathUtil::double_infinity == -d) && bInfinity) { - cout << " INFINITY:::::::::::::Before/After: Infinity/" << d; - } else if (d != d && bNAN) { - cout << " NaN:::::::::::::Before/After: NaN/" << d; - } else if (value == d || fabs(value - d) < 1E-14 || fabs(value - d)/max(fabs(d),fabs(value)) < 1E-14) { - cout << " EVAL_YES "; - } else { - string afterparsing = exp->infix(); - if (before == afterparsing) { - cout << "INFIX_YES " << endl; - } else { - cout << "INFIX_NO " << endl; - } - cout << "Before: " << before << endl; - cout << "After : " << exp->infix() << endl; - - if (bException) { - char chrs[2560]; - sprintf(chrs, "%d. C++ throws exception: %s", count, exceptionMsg.c_str()); - badmsg.push_back(chrs); - cout << chrs << " EVAL_NO "; - printf("Before/After: %.20g/Exception ", value); - } else if (bInfinity) { - char chrs[256]; - sprintf(chrs, "%d. Java evaluation is Infinity", count); - badmsg.push_back(chrs); - cout << chrs << " EVAL_NO "; - printf("Before/After: Infinity/%.20lg ", d); - } else if (bNAN) { - char chrs[256]; - sprintf(chrs, "%d. Java evaluation is NAN", count); - badmsg.push_back(chrs); - cout << chrs << " EVAL_NO "; - printf("Before/After: NAN/%.20lg ", d); - } else { - double m = max(fabs(d),fabs(value)); - if (m < 1e-100) { - char chrs[256]; - sprintf(chrs, "%d. abs(error)=%lg", count, fabs(d-value)); - badmsg.push_back(chrs); - cout << chrs << " EVAL_NO "; - } else { - char chrs[256]; - sprintf(chrs, "%d. relative(error)=%lg", count, fabs((d-value)/m)); - badmsg.push_back(chrs); - cout << chrs << " EVAL_NO "; - } - printf("Before/After: %.20lg/%.20lg ", value, d); - } - } - - delete exp; - } catch (Exception& ex) { - cout << ex.getMessage() << endl; - } -label_1: - cout << endl << "-------------------------------------------" << endl; - } - cout << "BAD " << badmsg.size() << endl; - for (int i = 0; i < badmsg.size(); i ++) { - cout << badmsg[i] << endl; - } -} diff --git a/ExpressionParser/ExpressionTest.h b/ExpressionParser/ExpressionTest.h deleted file mode 100644 index 016b8fad7..000000000 --- a/ExpressionParser/ExpressionTest.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef EXPRESSIONTEST_H -#define EXPRESSIONTEST_H - -class SymbolTable; - -class ExpressionTest -{ -public: - ExpressionTest(void); - ~ExpressionTest(void); - static void testEvaluateVector(void); - static void testEvaluateConstant(void); - static void testParser(char* filename); - static void testParser(int count, char* javaresult, double cvalue, char* expStr, SymbolTable* symbolTable, double* values); -}; - -#endif diff --git a/ExpressionParser/FunctionDomainException.cpp b/ExpressionParser/FunctionDomainException.cpp deleted file mode 100644 index 53169a2fd..000000000 --- a/ExpressionParser/FunctionDomainException.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "FunctionDomainException.h" - -FunctionDomainException::FunctionDomainException(string msg) : ExpressionException("FunctionDomainException", msg) -{ - -} - -FunctionDomainException::~FunctionDomainException(void) throw( ) -{ -} diff --git a/ExpressionParser/FunctionDomainException.h b/ExpressionParser/FunctionDomainException.h deleted file mode 100644 index 3e259f0f1..000000000 --- a/ExpressionParser/FunctionDomainException.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef FUNCTIONDOMAINEXCEPTION_H -#define FUNCTIONDOMAINEXCEPTION_H - -#include "ExpressionException.h" - -class FunctionDomainException : public ExpressionException -{ -public: - FunctionDomainException(string msg); - ~FunctionDomainException(void) throw( ); -}; -#endif diff --git a/ExpressionParser/FunctionRangeException.cpp b/ExpressionParser/FunctionRangeException.cpp deleted file mode 100644 index d3014ff6a..000000000 --- a/ExpressionParser/FunctionRangeException.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "FunctionRangeException.h" - -FunctionRangeException::FunctionRangeException(string msg) : ExpressionException("FunctionRangeException", msg) -{ - -} - -FunctionRangeException::~FunctionRangeException(void) throw() -{ -} diff --git a/ExpressionParser/FunctionRangeException.h b/ExpressionParser/FunctionRangeException.h deleted file mode 100644 index 76fb07bc2..000000000 --- a/ExpressionParser/FunctionRangeException.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef FUNCTIONRANGEEXCEPTION_H -#define FUNCTIONRANGEEXCEPTION_H - -#include "ExpressionException.h" - -class FunctionRangeException : public ExpressionException -{ -public: - FunctionRangeException(string msg); - ~FunctionRangeException(void) throw( ); -}; -#endif diff --git a/ExpressionParser/IOException.cpp b/ExpressionParser/IOException.cpp deleted file mode 100644 index 84f50c370..000000000 --- a/ExpressionParser/IOException.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "IOException.h" - -IOException::IOException(string msg) : Exception("IOException: " + msg) -{ -} - -IOException::~IOException(void) throw( ) -{ -} diff --git a/ExpressionParser/IOException.h b/ExpressionParser/IOException.h deleted file mode 100644 index 354870eec..000000000 --- a/ExpressionParser/IOException.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef IOEXCEPTION_H -#define IOEXCEPTION_H - -#include "Exception.h" -using namespace VCell; - -class IOException : public Exception -{ -public: - IOException(string msg); - ~IOException(void) throw( ); -}; -#endif diff --git a/ExpressionParser/JJTExpressionParserState.cpp b/ExpressionParser/JJTExpressionParserState.cpp deleted file mode 100644 index dc815cb87..000000000 --- a/ExpressionParser/JJTExpressionParserState.cpp +++ /dev/null @@ -1,115 +0,0 @@ -#include "JJTExpressionParserState.h" - -JJTExpressionParserState::JJTExpressionParserState(void) -: sp(0) -, mk(0) -, node_created(false) -{ -} - -JJTExpressionParserState::~JJTExpressionParserState(void) -{ - nodes.clear(); - marks.clear(); -} - -bool JJTExpressionParserState::nodeCreated(void) -{ - return node_created; -} - -void JJTExpressionParserState::reset(void) -{ - nodes.clear(); - marks.clear(); - sp = 0; - mk = 0; -} - -Node* JJTExpressionParserState::rootNode(void) -{ - return nodes.front(); -} - -void JJTExpressionParserState::pushNode(Node* n) -{ - nodes.push_back(n); - ++sp; -} - -Node* JJTExpressionParserState::popNode(void) -{ - if (--sp < mk) { - popMark(); - } - - Node* n = nodes.back(); - nodes.pop_back(); - return n; -} - -Node* JJTExpressionParserState::peekNode(void) { - return nodes.front(); -} - -int JJTExpressionParserState::nodeArity(void) -{ - return sp - mk; -} - -void JJTExpressionParserState::clearNodeScope(Node* n) -{ - while (sp > mk) { - popNode(); - } - popMark(); -} - -void JJTExpressionParserState::openNodeScope(Node* n) -{ - marks.push_back(mk); - mk = sp; - n->jjtOpen(); -} - -void JJTExpressionParserState::closeNodeScope(Node* n, int num) -{ - popMark(); - while (num-- > 0) { - Node* c = popNode(); - c->jjtSetParent(n); - n->jjtAddChild(c, num); - } - n->jjtClose(); - pushNode(n); - node_created = true; -} - -void JJTExpressionParserState::closeNodeScope(Node* n, bool condition) -{ - if (condition) { - int a = nodeArity(); - popMark(); - while (a-- > 0) { - Node* c = popNode(); - c->jjtSetParent(n); - n->jjtAddChild(c, a); - } - n->jjtClose(); - pushNode(n); - node_created = true; - } else { - popMark(); - node_created = false; - delete n; - } -} - -void JJTExpressionParserState::popMark(void) -{ - mk = 0; - if (marks.size() > 0) { - mk = marks.back(); - marks.pop_back(); - } -} diff --git a/ExpressionParser/JJTExpressionParserState.h b/ExpressionParser/JJTExpressionParserState.h deleted file mode 100644 index 4b4b76d86..000000000 --- a/ExpressionParser/JJTExpressionParserState.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef JJEXPRESSIONPARSERSTATE_H -#define JJEXPRESSIONPARSERSTATE_H - -#include -using std::vector; - -#include "Node.h" - -class JJTExpressionParserState -{ -public: - JJTExpressionParserState(void); - ~JJTExpressionParserState(void); - bool nodeCreated(void); - void reset(void); - Node* rootNode(void); - void pushNode(Node* n); - Node* popNode(void); - Node* peekNode(void); - int nodeArity(void); - void clearNodeScope(Node* n); - void openNodeScope(Node* n); - void closeNodeScope(Node* n, int num); - void closeNodeScope(Node* n, bool condition); - -private: - void popMark(void); - vector nodes; - vector marks; - int sp; - int mk; - bool node_created; - -}; - -#endif diff --git a/ExpressionParser/MathUtil.cpp b/ExpressionParser/MathUtil.cpp deleted file mode 100644 index 70a697799..000000000 --- a/ExpressionParser/MathUtil.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include -#include "MathUtil.h" - -#include -double MathUtil::double_infinity = std::numeric_limits::infinity(); - -double MathUtil::acosh(double arg){ - return log(arg+sqrt(arg*arg-1)); -} - -double MathUtil::acot(double arg){ - return atan(1.0/arg); -} - -double MathUtil::acoth(double arg){ - return 0.5*log((arg + 1.0)/(arg - 1.0)); -} - -double MathUtil::acsc(double arg){ - return asin(1.0/arg); -} - -double MathUtil::acsch(double arg){ - if (arg > 0) { - return log( (1.0 + sqrt(1 + arg * arg)) / arg ); - } else if (arg < 0) { - return log( (1.0 - sqrt(1 + arg * arg)) / arg ); - } -} - -double MathUtil::asec(double arg){ - return acos(1.0/arg); -} - -double MathUtil::asech(double arg){ - return log( (1.0 + sqrt(1.0 - arg * arg)) / arg ); -} - -double MathUtil::asinh(double arg){ - return log(arg + sqrt(arg * arg + 1)); -} - -double MathUtil::atanh(double arg){ - return 0.5*(log( (1.0 + arg)/(1.0 - arg) )); -} - -double MathUtil::cot(double arg){ - return 1.0/tan(arg); -} - -double MathUtil::coth(double arg){ - return 1.0/tanh(arg); -} - -double MathUtil::csc(double arg){ - return 1.0/sin(arg); -} - -double MathUtil::csch(double arg){ - return 1.0/sinh(arg); -} - -double MathUtil::factorial(double arg){ - double f = 1.0; - int n = (int)arg; - for(int i = 1; i <= n; i ++) { - f *= i; - } - return f; -} - -double MathUtil::round(double arg) { - return floor(arg + 0.5); -} - -double MathUtil::sec(double arg){ - return 1.0/cos(arg); -} - -double MathUtil::sech(double arg){ - return 1.0/cosh(arg); -} diff --git a/ExpressionParser/MathUtil.h b/ExpressionParser/MathUtil.h deleted file mode 100644 index 5cf9377fe..000000000 --- a/ExpressionParser/MathUtil.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef MATHUTIL_H -#define MATHUTIL_H - -class MathUtil { -public: - static double acosh(double a); - static double acot(double a); - static double acoth(double a); - static double acsc(double a); - static double acsch(double a); - static double asec(double a); - static double asech(double a); - static double asinh(double a); - static double atanh(double a); - - static double cot(double a); - static double coth(double a); - static double csc(double a); - static double csch(double a); - - static double factorial(double n); - static double round(double x); - - static double sec(double a); - static double sech(double a); - - static double double_infinity; -}; -#endif diff --git a/ExpressionParser/NameScope.h b/ExpressionParser/NameScope.h deleted file mode 100644 index ad0cffe7a..000000000 --- a/ExpressionParser/NameScope.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef NAMESCOPE_H -#define NAMESCOPE_H - -#include "stdinc.h" - -class NameScope { -public: - NameScope** getChildren()=0; - SymbolTableEntry getExternalEntry(string identifier)=0;; - String getName(); - NameScope* getNameScopeFromPrefix(string prefix)=0;; - NameScope* getParent()=0;; - string getRelativeScopePrefix(NameScope referenceNameScope)=0;; - ScopedSymbolTable getScopedSymbolTable()=0;; - string getSymbolName(SymbolTableEntry* symbolTableEntry)=0;; - string getUnboundSymbolName(String unboundName)=0;; - bool isAncestor(NameScope nameScope)=0;; - bool isPeer(NameScope nameScope)=0;; -} - -#endif diff --git a/ExpressionParser/Node.cpp b/ExpressionParser/Node.cpp deleted file mode 100644 index 2bfc7c730..000000000 --- a/ExpressionParser/Node.cpp +++ /dev/null @@ -1,240 +0,0 @@ -#include -#include -#include -#include -#include -using std::cout; -using std::endl; - -#include "Node.h" -#include "Expression.h" -#include "Exception.h" -#include "ExpressionException.h" -#include "SymbolTableEntry.h" -#include "ValueProxy.h" - -Node::Node(int i) { - numChildren = 0; - children = 0; - parent = 0; -} - -Node::~Node() { - for (int i = 0; i < numChildren; i ++) { - delete children[i]; - } - delete[] children; -} - -void Node::jjtOpen() { -} - -void Node::jjtClose() { -} - -void Node::jjtSetParent(Node* n) { - parent = n; -} - -Node* Node::jjtGetParent() { - return parent; -} - -void Node::jjtAddChild(Node* n, int i) { - if (numChildren == 0) { - children = new Node*[i + 1]; - memset(children, 0, (i + 1) * sizeof(Node*)); - numChildren = i + 1; - } else if (i >= numChildren) { - Node** c = new Node*[i + 1]; - memset(c, 0, (i + 1) * sizeof(Node*)); - memcpy(c, children, numChildren * sizeof(Node*)); - delete[] children; - children = c; - numChildren = i + 1; - } - children[i] = n; - (children[i])->parent = this; -} - -Node* Node::jjtGetChild(int i) { - return children[i]; -} - -/** - * remove self as child's parent - * remove reference to specified child - * @return removed child - */ -Node* Node::abandonChild(int i) { - Node * rval = children[i]; - rval->jjtSetParent(0); - children[i] = 0; - return rval; -} - -int Node::jjtGetNumChildren() { - return numChildren; -} - -void Node::dump(string prefix) { - cout << toString(prefix) << endl; - if (children != 0) { - for (int i = 0; i < numChildren; ++i) { - Node* n = children[i]; - if (n != 0) { - n->dump(prefix + " "); - } - } - } -} - -string Node::toString(string prefix) -{ - return prefix + infixString(LANGUAGE_DEFAULT, 0); -} - -void Node::getSymbols(vector& symbols, int language, NameScope* nameScope) -{ - for (int i=0;igetSymbols(symbols, language, nameScope); - } -} - -SymbolTableEntry* Node::getBinding(string symbol) -{ - for (int i=0;igetBinding(symbol); - if (ste != NULL){ - return ste; - } - } - return NULL; -} - -void Node::bind(SymbolTable* symbolTable) -{ - for (int i=0;ibind(symbolTable); - } -} - -bool Node::isBoolean() { - return false; -} - -string Node::getFunctionDomainError(string problem, double* values, string argumentName1, Node* node1, string argumentName2, Node* node2){ - string errorMsg = problem + ": " + argumentName1 + "=" + getNodeSummary(values, node1); - if (node2 == 0) { - return errorMsg; - } - errorMsg += "\n" + argumentName2 + "=" + getNodeSummary(values, node2); - return errorMsg; -} - -string Node::getNodeSummary(double* values, Node* node){ - string errorMsg; - vector symbols; - node->getSymbols(symbols, LANGUAGE_DEFAULT, 0); - if (symbols.size() > 0) { - errorMsg += "\"" + node->infixString(LANGUAGE_DEFAULT, 0) + "\"\n where:\n"; - SymbolTableEntry* symbolTableEntry = 0; - for (unsigned int i = 0; i < symbols.size(); i++) { - symbolTableEntry = node->getBinding(symbols.at(i)); - double value = 0.0; - try { - if (symbolTableEntry != 0) { - if (symbolTableEntry->getExpression() != NULL) { - if (values == 0) { - value = symbolTableEntry->getExpression()->evaluateConstant(); - } else { - value = symbolTableEntry->getExpression()->evaluateVector(values); - } - char chrs[1000]; - sprintf(chrs, "\t%s = %lf\n\0", symbolTableEntry->getName().c_str(), value); - errorMsg += chrs; - } else if (symbolTableEntry->getIndex() > -1) { - if (values == NULL) { - if (symbolTableEntry->getValueProxy()!=NULL){ - value = symbolTableEntry->getValueProxy()->evaluate(); - }else{ - value = symbolTableEntry->getConstantValue(); - } - } else { - value = values[symbolTableEntry->getIndex()]; - } - char chrs[1000]; - sprintf(chrs, "\t%s = %lf\n\0", symbolTableEntry->getName().c_str(), value); - errorMsg += chrs; - } else { - errorMsg += "\t" + symbols[i] + " = <<>>\n"; - } - } else { - errorMsg += "\t" + symbols[i] + " = <<>>\n"; - } - } catch (Exception& e) { - throw ExpressionException(errorMsg + "\t" + symbols[i] + " = <<>> " + e.getMessage() + "\n"); - } - } - } else { - errorMsg += node->infixString(LANGUAGE_DEFAULT, 0); - } - return errorMsg; -} - -void Node::jjtAddChild(Node* n) { - jjtAddChild(n, jjtGetNumChildren()); -} - -void Node::substitute(Node* origNode, Node* newNode) { - - for (int i=0;iequals(origNode)) { - children[i] = newNode->copyTree(); - newNode->jjtSetParent(this); - }else{ - jjtGetChild(i)->substitute(origNode,newNode); - } - } -} - -bool Node::equals(Node* node) { - // - // check to see if this node is the same - // - if (typeid(*node) != typeid(*this)){ - return false; - } - // - // check for different number of children - // - if (jjtGetNumChildren() != node->jjtGetNumChildren()){ - return false; - } - // - // now, check to see if all children are the same - // - // (note: I'm assuming the children are in the same order) - // - for (int i=0;ijjtGetChild(i); - if (!myChild->equals(nodeChild)){ - return false; - } - } - - return true; -} - -//default implementation returns false if any children return false, -//true otherwise -bool Node::isConstant( ) const { - for (int i = 0 ; i < numChildren ; i++) { - const Node & child = *children[i]; - if (!child.isConstant( )) { - return false; - } - } - return true; -} diff --git a/ExpressionParser/Node.h b/ExpressionParser/Node.h deleted file mode 100644 index 869c8c4bf..000000000 --- a/ExpressionParser/Node.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef SIMPLENODE_H -#define SIMPLENODE_H -#include -#include -using std::string; -using std::vector; - -#define LANGUAGE_DEFAULT 0 -#define LANGUAGE_C 1 -#define LANGUAGE_MATLAB 2 -#define LANGUAGE_JSCL 3 -#define LANGUAGE_VISIT 5 - -#define EVALUATE_CONSTANT 111 -#define EVALUATE_VECTOR 112 -#define EVALUATE_PROXY 113 - -class NameScope; -class SymbolTableEntry; -struct StackElement; -class SymbolTable; - - -class ExpressionParser; -class NameScope; - -class Node -{ -public: - Node(int unused); - virtual ~Node(void); - virtual Node* copyTree()=0; - virtual void getStackElements(vector& elements)=0; - virtual double evaluate(int type, double* values=0)=0; - - void jjtOpen(); - void jjtClose(); - void jjtSetParent(Node* n); - Node* jjtGetParent(); - void jjtAddChild(Node* n, int i); - /** - * remove self as child's parent - * remove reference to specified child - * @return removed child - */ - Node* abandonChild(int i); - Node* jjtGetChild(int i); - int jjtGetNumChildren(); - void dump(string prefix); - virtual string infixString(int lang, NameScope* nameScope)=0; - string toString(string prefix); - virtual void getSymbols(vector& symbols, int language, NameScope* nameScope); - virtual SymbolTableEntry* getBinding(string symbol); - virtual void bind(SymbolTable* symbolTable); - static string getFunctionDomainError(string problem, double* values, string argumentName1, Node* node1, string argumentName2="", Node* node2=0); - static string getNodeSummary(double* values, Node* node); - virtual bool isBoolean(); - - void jjtAddChild(Node* n); - void substitute(Node* origNode, Node* newNode); - virtual bool equals(Node* node); - virtual bool isConstant( ) const; - -protected: - Node* parent; - Node** children; - int numChildren; -}; -#endif diff --git a/ExpressionParser/ParseException.cpp b/ExpressionParser/ParseException.cpp deleted file mode 100644 index 913518e33..000000000 --- a/ExpressionParser/ParseException.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include - -#include "ParseException.h" - -string ParseException::eol = string("\n"); - -ParseException::ParseException() : Exception("ParseException", "") -{ - specialConstructor = false; - currentToken = NULL; - expectedTokenSequences = NULL; - numETS = 0; - etsLengthArray = NULL; - tokenImage = 0; -} - -ParseException::ParseException(string msg) : Exception("ParseException", msg) -{ - specialConstructor = false; - currentToken = NULL; - expectedTokenSequences = NULL; - numETS = 0; - etsLengthArray = NULL; - tokenImage = 0; -} - -ParseException::~ParseException(void) throw( ) -{ -} - -ParseException::ParseException(Token* currentTokenVal, int** expectedTokenSequencesVal, int numETSVal, int* etsLengthArrayVal, const string* tokenImageVal) : Exception("ParseException: ", "") -{ - specialConstructor = true; - currentToken = currentTokenVal; - expectedTokenSequences = expectedTokenSequencesVal; - numETS = numETSVal; - etsLengthArray = etsLengthArrayVal; - tokenImage = tokenImageVal; -} - -string ParseException::getExactMessage(void) -{ - if (!specialConstructor) { - return Exception::getExactMessage(); - } - - string expected = ""; - int maxSize = 0; - for (int i = 0; i < numETS; i++) { - if (maxSize < etsLengthArray[i]) { - maxSize = etsLengthArray[i]; - } - for (int j = 0; j < etsLengthArray[i]; j++) { - expected += tokenImage[expectedTokenSequences[i][j]] + " "; - } - if (expectedTokenSequences[i][etsLengthArray[i] - 1] != 0) { - expected += "..."; - } - expected += eol + " "; - } - string retval("Encountered \""); - Token* tok = currentToken->next; - for (int i = 0; i < maxSize; i++) { - if (i != 0) - retval += " "; - if (tok->kind == 0) { - retval += tokenImage[0]; - break; - } - retval += add_escapes(tok->image); - tok = tok->next; - } - char chrs[128]; - sprintf(chrs, "\" at line %d, column %d\0", currentToken->next->beginLine, currentToken->next->beginColumn); - retval += chrs; - retval += "." + eol; - if (numETS == 1) { - retval += "Was expecting:" + eol + " "; - } else { - retval += "Was expecting one of:" + eol + " "; - } - retval += expected; - return retval; -} diff --git a/ExpressionParser/ParseException.h b/ExpressionParser/ParseException.h deleted file mode 100644 index 8e80a85f9..000000000 --- a/ExpressionParser/ParseException.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef PARSEEXCEPTION_H -#define PARSEEXCEPTION_H - -#include "Exception.h" -#include "Token.h" -using namespace VCell; - -class ParseException : public Exception -{ -public: - ParseException(); - ParseException(string msg); - ~ParseException(void) throw( ); - Token* currentToken; - int** expectedTokenSequences; - int numETS; - int* etsLengthArray; - const string* tokenImage; - ParseException(Token* currentTokenVal, int** expectedTokenSequencesVal, int numETSVal, int* etsLengthArrayVal, const string* tokenImageVal); - string getExactMessage(void); - -protected: - bool specialConstructor; - static string eol; -}; -#endif diff --git a/ExpressionParser/Parser.jjt b/ExpressionParser/Parser.jjt deleted file mode 100644 index 389af9744..000000000 --- a/ExpressionParser/Parser.jjt +++ /dev/null @@ -1,286 +0,0 @@ -/** - * - * VCell Expression Parser Grammer for JavaCC - * - */ - -options { - LOOKAHEAD = 1; - UNICODE_INPUT = false; - MULTI = true; - STATIC = false; - DEBUG_TOKEN_MANAGER = false; -} - -PARSER_BEGIN(ExpressionParser) - -package cbit.vcell.parser; - -public class ExpressionParser { - - public static void main(String args[]) { - ExpressionParser parser; - if (args.length == 0) { - System.out.println("Java Parser Version 0.2: Reading from standard input . . ."); - parser = new ExpressionParser(new java.io.DataInputStream(System.in)); - } else if (args.length == 1) { - System.out.println("Java Parser Version 0.2: Reading from file " + args[0] + " . . ."); - try { - parser = new ExpressionParser(new java.io.DataInputStream(new java.io.FileInputStream(args[0]))); - } catch (java.io.FileNotFoundException e) { - System.out.println("Java Parser Version 0.2: File " + args[0] + " not found."); - return; - } - } else { - System.out.println("VCELL Model Parser Version 0.2: Usage is one of:"); - System.out.println(" java cbit.vcell.parser.ExpressionParser < inputfile"); - System.out.println("OR"); - System.out.println(" java cbit.vcell.parser.ExpressionParser inputfile"); - return; - } - try { - ASTExpression n = parser.Expression(); - n.dump(""); - System.out.println("Java Parser Version 0.2: Java program parsed successfully."); - } catch (Exception e) { - System.out.println("Java Parser Version 0.2: exception during parse."); - System.out.println(e.getMessage()); - e.printStackTrace(); - } - } -} - -PARSER_END(ExpressionParser) - - -/* - * Tokens to ignore in the BNF follow. - */ - -SKIP : -{ - " " -| "\t" -| "\n" -| "\r" -} - - -/* - * Tokens to consider in BNF follow. - */ -/* -TOKEN : FUNCTION -{ - > -} -*/ - -TOKEN : /* Relational Operators */ -{ - |||||> | - <#LT: "<" > | - <#GT: ">" > | - <#LE: "<=" > | - <#GE: ">=" > | - <#EQ: "==" > | - <#NE: "!=" > -} - -TOKEN : /* Logical Operators */ -{ - | - | - -} - -TOKEN : /* Arithmetic Operators */ -{ - | - | - | - | - -} - -TOKEN : /* LITERALS */ -{ - < FLOATING_POINT_LITERAL: - (["0"-"9"])+ "." (["0"-"9"])* ()? - | "." (["0"-"9"])+ ()? - | (["0"-"9"])+ - | - | "0" - > -| - < #EXPONENT: ["e","E"] (["+","-"])? (["0"-"9"])+ > -| - < #INTEGER_LITERAL: ["1"-"9"] (["0"-"9"])* > -} - -TOKEN : /* IDENTIFIERS */ -{ - < IDENTIFIER: - "#" - | ( ".")* - > -| - < #ID: - (|)* - > -| - < #LETTER: - ["a"-"z", "_", "A"-"Z"] - > -| - < #DIGIT: - ["0"-"9"] - > -} - -/***************************************** - * THE JAVA LANGUAGE GRAMMAR STARTS HERE * - *****************************************/ - -/* - * Expression syntax follows. - */ -ASTExpression Expression() : -{} -{ - LogicalORExpression() ";" - { return jjtThis; } -} - -void LogicalORExpression() #void : -{} -{ - ( - LogicalANDExpression() ( LogicalANDExpression() )* - ) #OrNode(>1) -} - -void LogicalANDExpression() #void : -{} -{ - ( - RelationalExpression() ( RelationalExpression() )* - ) #AndNode(>1) -} - -void RelationalExpression() #void : -{Token t_name=null;} -{ - AdditiveExpression() - [ LOOKAHEAD() t_name = AdditiveExpression() - { - if (jjtThis!=null){ - ((ASTRelationalNode)jjtThis).setOperationFromToken(t_name.image); - } - } - #RelationalNode(2) ] -} - -void AdditiveExpression() #void : -{} -{ - ( - MultiplicativeExpression() (( MultiplicativeExpression()) | MinusTerm())* - ) #AddNode(>1) -} - - -void MinusTerm() #MinusTermNode : -{} -{ - MultiplicativeExpression() -} - - -void MultiplicativeExpression() #void : -{} -{ - ( - PowerTerm() ( ( PowerTerm() ) | DivTerm() )* - ) #MultNode(>1) -} - -void DivTerm() #InvertTermNode : -{} -{ -
PowerTerm() -} - -void PowerTerm() #void : -{} -{ - ( - UnaryExpression() (LOOKAHEAD() UnaryExpression() #PowerNode(2))* - ) -} - -void UnaryExpression() #void : -{} -{ - UnaryExpression() -| - ( - UnaryExpression() - ) #MinusTermNode -| - ( - UnaryExpression() - ) #NotNode -| - PrimaryExpression() -} - - -void PrimaryExpression() #void : -{} -{ - LOOKAHEAD( "(") - Function() -| - LOOKAHEAD(Name()) - Name() -| - Float() -| - "(" LogicalORExpression() ")" -} - -void Function() #FuncNode : -{ Token t; } -{ - (t = Arguments()) - { jjtThis.setFunctionFromParserToken(t.image); } -} - - -void Arguments() #void : -{} -{ - "(" [ ArgumentList() ] ")" -} - -void ArgumentList() #void: -{} -{ - LogicalORExpression() ( "," LogicalORExpression() )* -} - -void Float() #FloatNode: -{ Token t; } -{ - t = - { jjtThis.value = new Double(t.image); } -} - -void Name() #IdNode : -{ Token t_name=null; } -{ - t_name = - { jjtThis.name = t_name.image; } -} - diff --git a/ExpressionParser/ParserException.cpp b/ExpressionParser/ParserException.cpp deleted file mode 100644 index da120b354..000000000 --- a/ExpressionParser/ParserException.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "ParserException.h" - -ParserException::ParserException(string msg) : ExpressionException("ParserException", msg) -{ -} - -ParserException::~ParserException(void) throw( ) -{ -} diff --git a/ExpressionParser/ParserException.h b/ExpressionParser/ParserException.h deleted file mode 100644 index 56cc3e10e..000000000 --- a/ExpressionParser/ParserException.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef PARSEREXCEPTION_H -#define PARSEREXCEPTION_H - -#include "ExpressionException.h" - -class ParserException : public ExpressionException -{ -public: - ParserException(string msg); - ~ParserException(void) throw( ); -}; - -#endif diff --git a/ExpressionParser/RuntimeException.cpp b/ExpressionParser/RuntimeException.cpp deleted file mode 100644 index 2159b8351..000000000 --- a/ExpressionParser/RuntimeException.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "RuntimeException.h" - -RuntimeException::RuntimeException(string msg) : Exception("RuntimeException", msg) -{ - -} - -RuntimeException::~RuntimeException(void) throw( ) -{ -} diff --git a/ExpressionParser/RuntimeException.h b/ExpressionParser/RuntimeException.h deleted file mode 100644 index 781b427ae..000000000 --- a/ExpressionParser/RuntimeException.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef RUNTIMEEXCEPTION_H -#define RUNTIMEEXCEPTION_H - -#include "Exception.h" -using namespace VCell; - -class RuntimeException : public Exception -{ -public: - RuntimeException(string msg); - ~RuntimeException(void) throw( ); -}; -#endif diff --git a/ExpressionParser/ScalarValueProxy.h b/ExpressionParser/ScalarValueProxy.h deleted file mode 100644 index 266c0b18b..000000000 --- a/ExpressionParser/ScalarValueProxy.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * (C) Copyright University of Connecticut Health Center 2001. - * All rights reserved. - */ -#ifndef SCALARVALUEPROXY_H -#define SCALARVALUEPROXY_H - -#include "ValueProxy.h" - -class ScalarValueProxy : public ValueProxy -{ -public: - ScalarValueProxy() : ValueProxy(0, -1, 0) { - value = 0; - }; - - double evaluate() { - return value; - }; - - void setValue(double d) { - value = d; - } - -private: - double value; -}; - -#endif diff --git a/ExpressionParser/SimpleCharStream.cpp b/ExpressionParser/SimpleCharStream.cpp deleted file mode 100644 index bc1e03f3c..000000000 --- a/ExpressionParser/SimpleCharStream.cpp +++ /dev/null @@ -1,332 +0,0 @@ -#include -#include - -#include "SimpleCharStream.h" -#include "IOException.h" -#include "RuntimeException.h" - -bool SimpleCharStream::staticFlag = false; - -SimpleCharStream::SimpleCharStream(istream* dstream, int startline, int startcolumn, int buffersize) -{ - init(dstream, startline, startcolumn, buffersize); -} -void SimpleCharStream::init(istream* dstream, int startline, int startcolumn, int buffersize) { - tokenBegin = 0; - bufpos = -1; - prevCharIsCR = false; - prevCharIsLF = false; - maxNextCharInd = 0; - inBuf = 0; - tabSize = 8; - - inputStream = dstream; - line = startline; - column = startcolumn - 1; - - available = bufsize = buffersize; - buffer = new char[buffersize]; - memset(buffer, 0, buffersize * sizeof(char)); - - bufline = new int[buffersize]; - memset(bufline, 0, buffersize * sizeof(int)); - bufcolumn = new int[buffersize]; - memset(bufcolumn, 0, buffersize * sizeof(int)); -} - -SimpleCharStream::SimpleCharStream(istream* dstream, int startline, int startcolumn) -{ - init(dstream, startline, startcolumn, 4096); -} - -SimpleCharStream::SimpleCharStream(istream* dstream) -{ - init(dstream, 1, 1, 4096); -} - -SimpleCharStream::~SimpleCharStream(void) -{ - delete[] buffer; - delete[] bufline; - delete[] bufcolumn; -} - -void SimpleCharStream::ExpandBuff(bool wrapAround) -{ - char* newbuffer = new char[bufsize + 2048]; - memset(newbuffer, 0, (bufsize + 2048) * sizeof(char)); - int* newbufline = new int[bufsize + 2048]; - memset(newbufline, 0, (bufsize + 2048) * sizeof(int)); - int* newbufcolumn = new int[bufsize + 2048]; - memset(newbufcolumn, 0, (bufsize + 2048) * sizeof(int)); - - try - { - if (wrapAround) - { - memcpy(newbuffer, buffer + tokenBegin, (bufsize - tokenBegin) * sizeof(char)); - memcpy(newbuffer + bufsize - tokenBegin, buffer, bufpos * sizeof(char)); - delete[] buffer; - buffer = newbuffer; - - memcpy(newbufline, bufline + tokenBegin,(bufsize - tokenBegin) * sizeof(int)); - memcpy(newbufline + bufsize - tokenBegin, bufline, bufpos * sizeof(int)); - delete[] bufline; - bufline = newbufline; - - memcpy(newbufcolumn, bufcolumn + tokenBegin, (bufsize - tokenBegin) * sizeof(int)); - memcpy(newbufcolumn + bufsize - tokenBegin, bufcolumn, bufpos * sizeof(int)); - delete[] bufcolumn; - bufcolumn = newbufcolumn; - - maxNextCharInd = (bufpos += (bufsize - tokenBegin)); - } else { - memcpy(newbuffer, buffer + tokenBegin, (bufsize - tokenBegin) * sizeof(char)); - delete[] buffer; - buffer = newbuffer; - - memcpy(newbufline, bufline + tokenBegin,(bufsize - tokenBegin) * sizeof(int)); - delete[] bufline; - bufline = newbufline; - - memcpy(newbufcolumn, bufcolumn + tokenBegin, (bufsize - tokenBegin) * sizeof(int)); - delete[] bufcolumn; - bufcolumn = newbufcolumn; - - maxNextCharInd = (bufpos -= tokenBegin); - } - } catch (char* ex) { - throw RuntimeException(ex); - } catch (...) { - throw RuntimeException("Unknown exception in SimpleCharStream::ExpandBuff"); - } - - bufsize += 2048; - available = bufsize; - tokenBegin = 0; -} - -void SimpleCharStream::FillBuff(void) -{ - if (maxNextCharInd == available) - { - if (available == bufsize) - { - if (tokenBegin > 2048) - { - bufpos = maxNextCharInd = 0; - available = tokenBegin; - } else if (tokenBegin < 0) - bufpos = maxNextCharInd = 0; - else - ExpandBuff(false); - } else if (available > tokenBegin) - available = bufsize; - else if ((tokenBegin - available) < 2048) - ExpandBuff(true); - else - available = tokenBegin; - } - - int i; - try { - inputStream->read(buffer + maxNextCharInd, available - maxNextCharInd); - if (!inputStream->eof() && (inputStream->fail() || inputStream->bad())) { - throw IOException(""); - } else { - i = inputStream->gcount(); - maxNextCharInd += i; - } - return; - } catch(Exception& ex) { - --bufpos; - backup(0); - if (tokenBegin == -1) - tokenBegin = bufpos; - Exception::rethrowException(ex); - } -} - -char SimpleCharStream::BeginToken(void) -{ - tokenBegin = -1; - char c = readChar(); - tokenBegin = bufpos; - - return c; -} - -void SimpleCharStream::UpdateLineColumn(char c) -{ - column++; - - if (prevCharIsLF) - { - prevCharIsLF = false; - line += (column = 1); - } - else if (prevCharIsCR) - { - prevCharIsCR = false; - if (c == '\n') - { - prevCharIsLF = true; - } - else - line += (column = 1); - } - - switch (c) - { - case '\r' : - prevCharIsCR = true; - break; - case '\n' : - prevCharIsLF = true; - break; - case '\t' : - column--; - column += (tabSize - (column % tabSize)); - break; - default : - break; - } - - bufline[bufpos] = line; - bufcolumn[bufpos] = column; -} - -char SimpleCharStream::readChar(void) -{ - if (inBuf > 0) - { - --inBuf; - - if (++bufpos == bufsize) - bufpos = 0; - - return buffer[bufpos]; - } - - if (++bufpos >= maxNextCharInd) - FillBuff(); - - char c = buffer[bufpos]; - - UpdateLineColumn(c); - return (c); -} - -int SimpleCharStream::getColumn(void) -{ - return bufcolumn[bufpos]; -} - -int SimpleCharStream::getLine(void) -{ - return bufline[bufpos]; -} - -int SimpleCharStream::getEndColumn(void) -{ - return bufcolumn[bufpos]; -} - -int SimpleCharStream::getEndLine(void) -{ - return bufline[bufpos]; -} - -int SimpleCharStream::getBeginColumn(void) -{ - return bufcolumn[tokenBegin]; -} - -int SimpleCharStream::getBeginLine(void) -{ - return bufline[tokenBegin]; -} - -void SimpleCharStream::backup(int amount) -{ - inBuf += amount; - if ((bufpos -= amount) < 0) - bufpos += bufsize; -} - -string SimpleCharStream::GetImage(void) -{ - if (bufpos >= tokenBegin) - return string(buffer, tokenBegin, bufpos - tokenBegin + 1); - else - return string(buffer, tokenBegin, bufsize - tokenBegin) + string(buffer, 0, bufpos + 1); -} - -char* SimpleCharStream::GetSuffix(int len) -{ - char* ret = new char[len + 1]; - memset(ret, 0, (len + 1) * sizeof(char)); - - if ((bufpos + 1) >= len) - memcpy(ret, buffer + bufpos - len + 1, len * sizeof(char)); - else - { - memcpy(ret, buffer + bufsize - (len - bufpos - 1), (len - bufpos - 1) * sizeof(char)); - memcpy(ret + len - bufpos - 1, buffer, (bufpos + 1) * sizeof(char)); - - } - - return ret; -} - -void SimpleCharStream::Done(void) -{ - buffer = 0; - bufline = 0; - bufcolumn = 0; -} - -void SimpleCharStream::adjustBeginLineColumn(int newLine, int newCol) -{ - int start = tokenBegin; - int len; - - if (bufpos >= tokenBegin) - { - len = bufpos - tokenBegin + inBuf + 1; - } - else - { - len = bufsize - tokenBegin + bufpos + 1 + inBuf; - } - - int i = 0, j = 0, k = 0; - int nextColDiff = 0, columnDiff = 0; - - while (i < len && - bufline[j = start % bufsize] == bufline[k = ++start % bufsize]) - { - bufline[j] = newLine; - nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j]; - bufcolumn[j] = newCol + columnDiff; - columnDiff = nextColDiff; - i++; - } - - if (i < len) - { - bufline[j] = newLine++; - bufcolumn[j] = newCol + columnDiff; - - while (i++ < len) - { - if (bufline[j = start % bufsize] != bufline[++start % bufsize]) - bufline[j] = newLine++; - else - bufline[j] = newLine; - } - } - - line = bufline[j]; - column = bufcolumn[j]; -} diff --git a/ExpressionParser/SimpleCharStream.h b/ExpressionParser/SimpleCharStream.h deleted file mode 100644 index dc17afc73..000000000 --- a/ExpressionParser/SimpleCharStream.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef SIMPLECHARSTREAM_H -#define SIMPLECHARSTREAM_H - -#include -#include -using std::istream; -using std::string; - -class SimpleCharStream -{ -protected: - int bufsize; - int available; - int tokenBegin; - -private: - int* bufline; - int* bufcolumn; - int column; - int line; - bool prevCharIsCR; - bool prevCharIsLF; - istream* inputStream; - char* buffer; - int maxNextCharInd; - int inBuf; - int tabSize; - void ExpandBuff(bool wrapAround); - void FillBuff(void); - void UpdateLineColumn(char c); - void init(istream* dstream, int startline, int startcolumn, int buffersize); - -public: - SimpleCharStream(istream* dstream, int startline, int startcolumn, int buffersize); - SimpleCharStream(istream* dstream, int startline, int startcolumn); - SimpleCharStream(istream* dstream); - ~SimpleCharStream(void); - - static bool staticFlag; - int bufpos; - - char BeginToken(void); - char readChar(void); - int getColumn(void); - int getLine(void); - int getEndColumn(void); - int getEndLine(void); - int getBeginColumn(void); - int getBeginLine(void); - void backup(int amount); - string GetImage(void); - char* GetSuffix(int len); - void Done(void); - void adjustBeginLineColumn(int newLine, int newCol); -}; - -#endif diff --git a/ExpressionParser/SimpleSymbolTable.cpp b/ExpressionParser/SimpleSymbolTable.cpp deleted file mode 100644 index 4b9360aff..000000000 --- a/ExpressionParser/SimpleSymbolTable.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "SimpleSymbolTable.h" - -SimpleSymbolTable::SimpleSymbolTable(string* symbols, int symbolCount, ValueProxy** valueProxies) -{ - for (int i = 0; i < symbolCount; i ++){ - steArray.push_back(new SimpleSymbolTableEntry(symbols[i],i,0, valueProxies == 0 ? 0 : valueProxies[i])); - } -} - -SimpleSymbolTable::~SimpleSymbolTable(void) -{ - for (unsigned int i = 0; i < steArray.size(); i ++) { - delete steArray[i]; - } - steArray.clear(); -} - - -SymbolTableEntry* SimpleSymbolTable::getLocalEntry(const string & identifier) const -{ - for (unsigned int i = 0; i < steArray.size(); i++){ - if (steArray[i]->getName() == identifier){ - return steArray[i]; - } - } - return NULL; -} diff --git a/ExpressionParser/SimpleSymbolTable.h b/ExpressionParser/SimpleSymbolTable.h deleted file mode 100644 index 61399e895..000000000 --- a/ExpressionParser/SimpleSymbolTable.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef SIMPLESYMBOLTABLE_H -#define SIMPLESYMBOLTABLE_H - -#include -using std::vector; - -#include "SymbolTable.h" -#include "SimpleSymbolTableEntry.h" - -class SimpleSymbolTable : public SymbolTable -{ -public: - SimpleSymbolTable(string* symbols, int symbolCount, ValueProxy** valueProxies=0); - /** - * non-standard copy constructor -- transfers ownership of - * implementation to new object; rhs will be unusable - * @param rhs object to move data from - */ - SimpleSymbolTable(const SimpleSymbolTable &rhs) - :steArray(rhs.steArray) { - SimpleSymbolTable &scr = const_cast(rhs); - scr.steArray.clear( ); - } - - //SimpleSymbolTable(string* symbols, NameScope* namescopeVal); - ~SimpleSymbolTable(void); - /** - * same as #getLocalEntry - */ - SymbolTableEntry* getEntry(const std::string & identifier) const { - return getLocalEntry(identifier); - } - SymbolTableEntry* getLocalEntry(const std::string & identifier) const; - /** - * return number of symbols in table - */ - size_t size( ) const { - return steArray.size( ); - } - -private: - SimpleSymbolTable & operator=(const SimpleSymbolTable &); - vector steArray; -}; - -#endif diff --git a/ExpressionParser/SimpleSymbolTableEntry.cpp b/ExpressionParser/SimpleSymbolTableEntry.cpp deleted file mode 100644 index 30e50cac3..000000000 --- a/ExpressionParser/SimpleSymbolTableEntry.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "SimpleSymbolTableEntry.h" -#include "ExpressionException.h" - -SimpleSymbolTableEntry::SimpleSymbolTableEntry(const string& nameValue, int indexVal, NameScope* namescopeVal, ValueProxy* proxyVal) - : name(nameValue), index(indexVal), namescope(namescopeVal), valueProxy(proxyVal) -{ - bConstant = false; - value = 0.0; -} - -SimpleSymbolTableEntry::~SimpleSymbolTableEntry(void) -{ -} - -double SimpleSymbolTableEntry::getConstantValue() { - if (bConstant){ - return value; - } - - throw ExpressionException("can't evaluate to constant"); -} - -Expression* SimpleSymbolTableEntry::getExpression() { - return NULL; -} - -int SimpleSymbolTableEntry::getIndex() { - return index; -} - -string& SimpleSymbolTableEntry::getName() { - return name; -} - -NameScope* SimpleSymbolTableEntry::getNameScope() { - return namescope; -} - -bool SimpleSymbolTableEntry::isConstant() { - return bConstant; -} - -void SimpleSymbolTableEntry::setIndex(int indexVal) -{ - index = indexVal; -} - -void SimpleSymbolTableEntry::setConstantValue(double v) -{ - value = v; - bConstant = true; -} diff --git a/ExpressionParser/SimpleSymbolTableEntry.h b/ExpressionParser/SimpleSymbolTableEntry.h deleted file mode 100644 index ffebcd439..000000000 --- a/ExpressionParser/SimpleSymbolTableEntry.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef SIMPLESYMBOLTABLEENTRY_H -#define SIMPLESYMBOLTABLEENTRY_H - -#include "SymbolTableEntry.h" - -class SimpleSymbolTableEntry : public SymbolTableEntry -{ -public: - SimpleSymbolTableEntry(const string& nameValue, int indexVal, NameScope* namescopeVal, ValueProxy* proxyVal); - ~SimpleSymbolTableEntry(void); - double getConstantValue(); - VCell::Expression* getExpression(); - int getIndex(); - string& getName(); - NameScope* getNameScope(); - //VCUnitDefinition getUnitDefinition()=0; - bool isConstant(); - void setIndex(int symbolTableIndex); - void setConstantValue(double v); - ValueProxy* getValueProxy() { return valueProxy; }; - -private: - string name; - int index; - NameScope* namescope; - bool bConstant; - double value; - ValueProxy* valueProxy; -}; -#endif diff --git a/ExpressionParser/StackMachine.cpp b/ExpressionParser/StackMachine.cpp deleted file mode 100644 index a5f92d863..000000000 --- a/ExpressionParser/StackMachine.cpp +++ /dev/null @@ -1,395 +0,0 @@ -/* - * (C) Copyright University of Connecticut Health Center 2001. - * All rights reserved. - */ - -#include "Node.h" -#include "StackMachine.h" -#include -#include -#include "MathUtil.h" -#include "DivideByZeroException.h" -#include "FunctionDomainException.h" -#include "FunctionRangeException.h" -#include "Exception.h" -#include "ValueProxy.h" -#include -#include -using std::cout; -using std::endl; -using std::max; -using std::min; - -StackMachine::StackMachine(StackElement* arg_elements, int size) { - elements = arg_elements; - elementSize = size; -} - -StackMachine::~StackMachine() { - delete[] elements; -} -//----------------------------------------------------------------- -// -// class StackMachine -// -//----------------------------------------------------------------- - -void StackMachine::showInstructions(){ - char* opCodes[52] = { "unknown", "BZ", "LT", "GT", "LE", "GE", "EQ", "NE", - "AND", "OR", "NOT", "ADD", "SUB", "MULT", - "DIV", "FLOAT", "IDENTIFIER", "EXP", "SQRT", "ABS", "POW", - "LOG", "SIN", "COS", "TAN", "ASIN", "ACOS", "ATAN", - "TAN2", "MAX", "MIN", "CEIL", "FLOOR", "CSC", "COT", - "SEC", "ACSC", "ACOT", "ASEC", "SINH", "COSH", "TANH", - "CSCH", "COTH", "SECH", "ASINH", "ACOSH", "ATANH", "ACSCH", - "ACOTH", "ASECH", "FACTORIAL"}; - StackElement *token = elements; - for (int i=0; itype==TYPE_BZ){ - cout << "BZ " << token->branchOffset << endl; - }else if (token->type==TYPE_IDENTIFIER){ - cout << "PUSH " << "var[" << token->vectorIndex << "]" << endl; - }else if (token->type==TYPE_FLOAT){ - cout << "PUSH " << token->value << endl; - }else{ - cout << opCodes[token->type] << "()" << endl; - } - } -} - -double StackMachine::evaluate(double* values){ - double workingStack[20]; - StackElement *token = elements; - double *tos = workingStack-1; - // - // iterate through tokens and push floats and identifiers (after evaluation) - // when get to an operator, evaluate and place results back on stack - // - int i=0; - double arg2; - for (i=0; itype){ - case TYPE_BZ: // 1: read tos - branch if zero to offset - arg2 = *(tos); - if (arg2==0.0){ - // - // branch offset - // - int offset = token->branchOffset; - if (offset == 0) { - showInstructions(); - throw "StackMachine::evaluate(), BZ with zero offset, should never happend"; - } - token+=(offset-1); // because token++, i++ will add one - i+=(offset-1); - } else { - tos --; - } - break; - case TYPE_LT: // 2: pop 2 push 1 - arg2 = *(tos--); - *tos = *tos < arg2; - break; - case TYPE_GT: // 3: pop 2 push 1 - arg2 = *(tos--); - *tos = *tos > arg2; - break; - case TYPE_LE: // 4: pop 2 push 1 - arg2 = *(tos--); - *tos = *tos <= arg2; - break; - case TYPE_GE: // 5: pop 2 push 1 - arg2 = *(tos--); - *tos = *tos >= arg2; - break; - case TYPE_EQ: // 6, pop 2 push 1 - arg2 = *(tos--); - *tos = *tos == arg2; - break; - case TYPE_NE: // 7, pop 2 push 1 - arg2 = *(tos--); - *tos = *tos != arg2; - break; - case TYPE_AND: // 8, pop 2 push 1 - arg2 = *(tos--); - *tos = *tos && arg2; - break; - case TYPE_OR: // 9, pop 2 push 1 - arg2 = *(tos--); - *tos = *tos || arg2; - break; - case TYPE_NOT: // 10, pop 1 push 1 - *tos = !*tos; - break; - case TYPE_ADD: // 11, pop 2 push 1 - arg2 = *(tos--); - *tos += arg2; - break; - case TYPE_SUB: // 12, pop 1 push 1 - *tos = -*tos; - break; - case TYPE_MULT: // 13, pop 2 push 1 - arg2 = *(tos--); - *tos *= arg2; - break; - case TYPE_DIV: // 14, pop 1 push 1 - if (*tos == 0.0) { - throw DivideByZeroException("divide by zero"); - } - *tos = 1/(*tos); - break; - case TYPE_FLOAT: // 15, push 1 - *(++tos) = token->value; // push 1 float onto the stack. - break; - case TYPE_IDENTIFIER: // 16, push 1 - if (values == 0){ - *(++tos) = token->valueProxy->evaluate(); // push identifier's value onto stack - } else { - *(++tos) = values[token->vectorIndex]; // push identifier's value onto stack - } - break; - case TYPE_EXP: // 17, pop 1 push 1 - *tos = exp(*tos); - break; - case TYPE_SQRT: // 18, pop 1 push 1 - if (*tos < 0) { - char problem[1000]; - sprintf(problem, "sqrt(u) where u=%lf<0 is undefined", *tos); - throw FunctionDomainException(string(problem)); - } - *tos = sqrt(*tos); - break; - case TYPE_ABS: // 19, pop 1 push 1 - *tos = fabs(*tos); - break; - case TYPE_POW: // 20, pop 2 push 1 - arg2 = *(tos--); - if (*tos < 0.0 && (MathUtil::round(arg2) != arg2)) { - char problem[1000]; - sprintf(problem, "pow(u,v) and u=%lf<0 and v=%lf not an integer", *tos, arg2); - throw FunctionDomainException(string(problem)); - } else if (*tos == 0.0 && arg2 < 0) { - char problem[100]; - sprintf(problem, "pow(u,v) and u=0 and v=%lf<0 divide by zero", arg2); - throw FunctionDomainException(string(problem)); - } - if (arg2 == 0.0) { - *tos = 1.0; - } else if (*tos == 1.0) { - *tos = 1.0; - } else { - double result = pow(*tos, arg2); - if (MathUtil::double_infinity == -result || MathUtil::double_infinity == result || result != result) { - char problem[1000]; - sprintf(problem, "u^v evaluated to %lf, u=%lf, v=%lf", result, *tos, arg2); - throw FunctionDomainException(string(problem)); - } - *tos = result; - } - break; - case TYPE_LOG: // 21, pop 1 push 1 - if (*tos == 0.0) { - throw FunctionDomainException("log(u) and u==0.0 is undefined"); - } else if (*tos < 0.0) { - char problem[1000]; - sprintf(problem, "log(u) and u=%lf < 0.0 is undefined", *tos); - throw FunctionDomainException(string(problem)); - } - *tos = log(*tos); - break; - case TYPE_SIN: // 22, pop 1 push 1 - *tos = sin(*tos); - break; - case TYPE_COS: // 23, pop 1 push 1 - *tos = cos(*tos); - break; - case TYPE_TAN: // 24, op 1 push 1 - *tos = tan(*tos); - break; - case TYPE_ASIN: // 25, pop 1 push 1 - if (fabs(*tos) > 1.0) { - char problem[1000]; - sprintf(problem, "asin(u) and u=%lf and |u|>1.0 undefined", *tos); - throw FunctionDomainException(string(problem)); - } - *tos = asin(*tos); - break; - case TYPE_ACOS: // 26, pop 1 push 1 - if (fabs(*tos) > 1.0) { - char problem[1000]; - sprintf(problem, "acos(u) and u=%lf and |u|>1.0 undefined", *tos); - throw FunctionDomainException(string(problem)); - } - *tos = acos(*tos); - break; - case TYPE_ATAN: // 27, pop 1 push 1 - *tos = atan(*tos); - break; - case TYPE_ATAN2: // 28, pop 2 push 1 - arg2 = *(tos--); - *tos = atan2(*tos, arg2); - break; - case TYPE_MAX: // 29, pop 2 push 1 - arg2 = *(tos--); - *tos = max(*tos, arg2); - break; - case TYPE_MIN: // 30, pop 2 push 1 - arg2 = *(tos--); - *tos = min(*tos, arg2); - break; - case TYPE_CEIL: // 31, pop 1 push 1 - *tos = ceil(*tos); - break; - case TYPE_FLOOR: // 32, pop 1 push 1 - *tos = floor(*tos); - break; - case TYPE_CSC: // 33, pop 1 push 1 - { - double result = sin(*tos); - if (result == 0) { - char problem[1000]; - sprintf(problem, "csc(u)=1/sin(u) and sin(u)=0 and u=%lf", *tos); - throw FunctionDomainException(string(problem)); - } - *tos = 1/result; - } - break; - case TYPE_COT: // 34, pop 1 push 1 - { - double result = tan(*tos); - if (result == 0) { - char problem[1000]; - sprintf(problem, "cot(u)=1/tan(u) and tan(u)=0 and u=%lf", *tos); - throw FunctionDomainException(string(problem)); - } - *tos = 1/result; - } - break; - case TYPE_SEC: // 35, pop 1 push 1 - { - double result = cos(*tos); - if (result == 0) { - char problem[1000]; - sprintf(problem, "sec(u)=1/cos(u) and cos(u)=0 and u=%lf", *tos); - throw FunctionDomainException(string(problem)); - } - *tos = 1/result; - } - break; - case TYPE_ACSC: // 36, pop 1 push 1 - if (fabs(*tos) < 1.0){ - char problem[1000]; - sprintf(problem, "acsc(u) and -1= 1.0){ - char problem[1000]; - sprintf(problem, "atanh(u) and |u| >= 1.0, u=%lf", *tos); - throw FunctionDomainException(string(problem)); - } - *tos = MathUtil::atanh(*tos); - break; - case TYPE_ACSCH: // 48, pop 1 push 1 - if (*tos == 0.0){ - throw FunctionDomainException("acsch(u) and u=0"); - } - *tos = MathUtil::acsch(*tos); - break; - case TYPE_ACOTH: // 49, pop 1 push 1 - if (fabs(*tos) <= 1.0){ - char problem[1000]; - sprintf(problem, "acoth(u) and |u| <= 1.0, u=%lf", *tos); - throw FunctionDomainException(string(problem)); - } - *tos = MathUtil::acoth(*tos); - break; - case TYPE_ASECH: // 50, pop 1 push 1 - if (*tos <= 0.0 || *tos > 1.0){ - char problem[1000]; - sprintf(problem, "asech(u) and u <= 0.0 or u > 1.0, u=%lf", *tos); - throw FunctionDomainException(string(problem)); - } - *tos = MathUtil::asech(*tos); - break; - case TYPE_FACTORIAL: // 51, pop 1 push 1 - if (*tos < 0.0 || (*tos-(int)*tos) != 0){ - char problem[1000]; - sprintf(problem, "factorial(u) and u=%lf < 0.0 or is not an integer", *tos); - throw FunctionDomainException(string(problem)); - } - *tos = MathUtil::factorial(*tos); - break; - case TYPE_J1: - *tos = j1(*tos); - break; - default: - throw Exception("StackMachine: unknown stack element type " + token->type); - } - if (tos >= workingStack) { - if (MathUtil::double_infinity == -*tos || MathUtil::double_infinity == *tos) { - throw FunctionRangeException("Evaluated to infinity"); - } else if (*tos != *tos) { - throw FunctionRangeException("Evaluated to NaN"); - } - } - //cout << "------" << i << "--------" << endl; - //for (int c = 0; c < tos-workingStack+1; c++) { - // cout << c << " " << workingStack[c] << endl; - //} - } - return *tos; -} diff --git a/ExpressionParser/StackMachine.h b/ExpressionParser/StackMachine.h deleted file mode 100644 index ebfd650f5..000000000 --- a/ExpressionParser/StackMachine.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef STACKMACHINE_H -#define STACKMACHINE_H - -/** - * for expression: "(((1 < 2) * 3) + (5 * log(0.0) * (0.0 > 0.0)) + 2)" - * - * The following are the Stack Machine Instructions (e.g. FLOAT 1 means push 1.0 on the stack, - * and LT() means Stack[top] = (Stack[top] < Stack[top+1])) - * - * FLOAT 1 - * FLOAT 2 - * LT() - * BZ 2 - * FLOAT 3 - * FLOAT 0 - * FLOAT 0 - * GT() - * BZ 5 - * FLOAT 5 - * FLOAT 0 - * LOG() - * MULT() - * ADD() - * FLOAT 2 - * ADD() - * - * which results in the answer 5.0 - * - * Note that "BZ offset" means branch to IP+offset if Stack[top] is zero and doesn't modify the stack. -**/ - -enum STACK_ELEMENT_TYPE {TYPE_BZ = 1, TYPE_LT, TYPE_GT, TYPE_LE, TYPE_GE, TYPE_EQ, TYPE_NE, - TYPE_AND, TYPE_OR, TYPE_NOT, TYPE_ADD, TYPE_SUB, TYPE_MULT, - TYPE_DIV, TYPE_FLOAT, TYPE_IDENTIFIER, TYPE_EXP, TYPE_SQRT, TYPE_ABS, TYPE_POW, - TYPE_LOG, TYPE_SIN, TYPE_COS, TYPE_TAN, TYPE_ASIN, TYPE_ACOS, TYPE_ATAN, - TYPE_ATAN2, TYPE_MAX, TYPE_MIN, TYPE_CEIL, TYPE_FLOOR, TYPE_CSC, TYPE_COT, - TYPE_SEC, TYPE_ACSC, TYPE_ACOT, TYPE_ASEC, TYPE_SINH, TYPE_COSH, TYPE_TANH, - TYPE_CSCH, TYPE_COTH, TYPE_SECH, TYPE_ASINH, TYPE_ACOSH, TYPE_ATANH, TYPE_ACSCH, - TYPE_ACOTH, TYPE_ASECH, TYPE_FACTORIAL,TYPE_J1}; // totally 52 - -class ValueProxy; - -struct StackElement { - int type; - int branchOffset; - double value; - int vectorIndex; - ValueProxy* valueProxy; - - StackElement() { - type = 0; - value = 0; - valueProxy = 0; - vectorIndex = 0; - branchOffset = 0; - } - - StackElement(int arg_type) { - type = arg_type; - value = 0.0; - valueProxy = 0; - vectorIndex = 0; - branchOffset = 0; - } - - StackElement(ValueProxy* arg_vp, int index) { - type = TYPE_IDENTIFIER; - value = 0.0; - valueProxy = arg_vp; - vectorIndex = index; - branchOffset = 0; - } - StackElement(double arg_value) { - type = TYPE_FLOAT; - value = arg_value; - valueProxy = 0; - vectorIndex = 0; - branchOffset = 0; - } -}; - -class StackMachine { -private: - //double *workingStack; - StackElement* elements; - int elementSize; - -public: - StackMachine(StackElement* arg_elements, int size); - ~StackMachine(); - double evaluate(double* values=0); - void showInstructions(); -}; - -#endif diff --git a/ExpressionParser/SymbolTable.h b/ExpressionParser/SymbolTable.h deleted file mode 100644 index d85fe4aed..000000000 --- a/ExpressionParser/SymbolTable.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef SYMBOLTABLE_H -#define SYMBOLTABLE_H - -#include -using std::string; - -class SymbolTableEntry; - -class SymbolTable { -public: - virtual SymbolTableEntry* getEntry(const std::string & identifier) const = 0; - virtual ~SymbolTable() {} -}; - -#endif diff --git a/ExpressionParser/SymbolTableEntry.h b/ExpressionParser/SymbolTableEntry.h deleted file mode 100644 index c39abc04c..000000000 --- a/ExpressionParser/SymbolTableEntry.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef SYMBOLTABLEENTRY_H -#define SYMBOLTABLEENTRY_H - -#include -using std::string; - -class ValueProxy; -namespace VCell { -class Expression; -} -class NameScope; - -class SymbolTableEntry { -public: - virtual double getConstantValue()=0; - virtual VCell::Expression* getExpression()=0; - virtual int getIndex()=0; - virtual string& getName()=0; - virtual NameScope* getNameScope()=0; - //VCUnitDefinition getUnitDefinition()=0; - virtual bool isConstant()=0; - virtual ValueProxy* getValueProxy()=0; -}; - -#endif diff --git a/ExpressionParser/Token.cpp b/ExpressionParser/Token.cpp deleted file mode 100644 index f7343a66a..000000000 --- a/ExpressionParser/Token.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "Token.h" - -Token::Token(void) -{ - next = 0; - specialToken = 0; - kind = 0; - beginLine = 0; - beginColumn = 0; - endLine = 0; - endColumn = 0; -} - -Token::~Token(void) -{ -} - -Token* Token::newToken(int ofKind) -{ - switch (ofKind) { - default: - return new Token(); - } -} diff --git a/ExpressionParser/Token.h b/ExpressionParser/Token.h deleted file mode 100644 index 03a53fc37..000000000 --- a/ExpressionParser/Token.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef TOKEN_H -#define TOKEN_H - -#include -using std::string; - -class Token -{ -public: - Token(void); - ~Token(void); - - int kind; - int beginLine, beginColumn, endLine, endColumn; - string image; - - Token* next; - Token* specialToken; - static Token* newToken(int ofKind); -}; - -#endif diff --git a/ExpressionParser/ValueProxy.cpp b/ExpressionParser/ValueProxy.cpp deleted file mode 100644 index 4f667a660..000000000 --- a/ExpressionParser/ValueProxy.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* - * (C) Copyright University of Connecticut Health Center 2001. - * All rights reserved. - */ - -#include "ValueProxy.h" - -//----------------------------------------------------------------- -// -// class ValueProxy -// -//----------------------------------------------------------------- -ValueProxy::ValueProxy(double* arg_values, int arg_indexindex, int* arg_indices) -{ - values = arg_values; - indexindex = arg_indexindex; - indices = arg_indices; -} - -double ValueProxy::evaluate(){ - return values[indices[indexindex]]; -} diff --git a/ExpressionParser/ValueProxy.h b/ExpressionParser/ValueProxy.h deleted file mode 100644 index b7c7f097e..000000000 --- a/ExpressionParser/ValueProxy.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * (C) Copyright University of Connecticut Health Center 2001. - * All rights reserved. - */ -#ifndef VALUEPROXY_H -#define VALUEPROXY_H - -/*----------------------------------------------------------- - vartype is the index to the indices of array - ------------------------------------------------------------*/ -class ValueProxy -{ -public: - ValueProxy(double* arg_values, int arg_vartype, int* arg_indices); - virtual double evaluate(); - -protected: - double* values; - int indexindex; - int* indices; -}; - -#endif diff --git a/ExpressionParserTest/ExpressionParserTest.cpp b/ExpressionParserTest/ExpressionParserTest.cpp index 4cc934c97..4ac91cd4a 100644 --- a/ExpressionParserTest/ExpressionParserTest.cpp +++ b/ExpressionParserTest/ExpressionParserTest.cpp @@ -1,41 +1,38 @@ #include "Expression.h" #include "Exception.h" -using namespace VCell; -#include + #include -using std::cout; -using std::endl; -using std::cerr; -int main(int argc, char *argv[]) { - - vector expStrs; - expStrs.push_back(string("log(0)")); - expStrs.push_back(string("(1<(2*(1<2)))*5+(1<(2*(2<1)))*5")); - expStrs.push_back(string("(1<2)*3+5*log(0)*(0>0)+2")); - expStrs.push_back(string("(1<2)*1*2+3*5+4+(1<1)")); - expStrs.push_back(string("(1<3)*(1 + +int main() { + std::vector expStrs; + expStrs.push_back(std::string("log(0)")); + expStrs.push_back(std::string("(1<(2*(1<2)))*5+(1<(2*(2<1)))*5")); + expStrs.push_back(std::string("(1<2)*3+5*log(0)*(0>0)+2")); + expStrs.push_back(std::string("(1<2)*1*2+3*5+4+(1<1)")); + expStrs.push_back(std::string("(1<3)*(1 " << expression.evaluateConstant() << endl; - cout << "tree eval (constant) ==> " << expression.evaluateConstantTree() << endl; - cout << "stack machine (vector) ==> " << expression.evaluateVector(values) << endl; - cout << "tree eval (vector) ==> " << expression.evaluateVectorTree(values) << endl; + std::cout << "stack machine (constant) ==> " << expression.evaluateConstant() << std::endl; + std::cout << "tree eval (constant) ==> " << expression.evaluateConstantTree() << std::endl; + std::cout << "stack machine (vector) ==> " << expression.evaluateVector(values) << std::endl; + std::cout << "tree eval (vector) ==> " << expression.evaluateVectorTree(values) << std::endl; } catch (const char* ex) { - cerr << "ExpressionParserTest failed : " << ex << endl; - } catch (string& ex) { - cerr << "ExpressionParserTest failed : " << ex << endl; - } catch (Exception& ex) { - cerr << "ExpressionParserTest failed : " << ex.getMessage() << endl; + std::cerr << "ExpressionParserTest failed : " << ex << std::endl; + } catch (std::string& ex) { + std::cerr << "ExpressionParserTest failed : " << ex << std::endl; + } catch (VCell::Exception& ex) { + std::cerr << "ExpressionParserTest failed : " << ex.getMessage() << std::endl; } catch (...) { - cerr << "ExpressionParserTest failed : unknown error." << endl; + std::cerr << "ExpressionParserTest failed : unknown error." << std::endl; } } } diff --git a/IDAWin/CMakeLists.txt b/IDAWin/CMakeLists.txt index 0dcf9f0a3..eb4f4b79a 100644 --- a/IDAWin/CMakeLists.txt +++ b/IDAWin/CMakeLists.txt @@ -1,61 +1,81 @@ project(IDAWin) -set (SRC_FILES - OdeResultSet.cpp - StoppedByUserException.cpp - VCellCVodeSolver.cpp - VCellIDASolver.cpp - VCellSundialsSolver.cpp +set (SRC_FILES + SundialsSolverInterface.cpp + OdeResultSet.cpp + StoppedByUserException.cpp + VCellCVodeSolver.cpp + VCellIDASolver.cpp + VCellSundialsSolver.cpp + SteadyStateDriver.cpp + VCellSolverFactory.cpp + VCellSolverInput.cpp ) set (HEADER_FILES - OdeResultSet.h - StoppedByUserException.h - VCellCVodeSolver.h - VCellIDASolver.h - VCellSundialsSolver.h + OdeResultSet.h + StoppedByUserException.h + VCellSolverFactory.h + VCellSolver.h + VCellSolverInput.h + VCellSundialsSolver.h + VCellCVodeSolver.h + VCellIDASolver.h + SteadyStateDriver.h + SundialsSolverInterface.h ) set (EXE_SRC_FILES SundialsSolverStandalone.cpp ) -add_library(IDAWin STATIC ${SRC_FILES} ${HEADER_FILES}) -target_link_libraries(IDAWin sundials ExpressionParser vcellmessaging) + +if (OPTION_STATICALLY_LINK AND OPTION_TARGET_PYTHON_BINDING) + message("Creating Dynamic IDAWin with statically linked dependencies (for python)") + add_library(IDAWin SHARED ${SRC_FILES} ${HEADER_FILES}) + target_link_libraries( + IDAWin + sundials -static + vcellexpressionparser -static + vcellmessaging -static + argparse -static + spdlog::spdlog -static + # if MinGW is enabled, add `$<$:ws2_32>` + ) +elseif(OPTION_STATICALLY_LINK AND NOT OPTION_TARGET_PYTHON_BINDING) + message("Creating IDAWin for static linkage") + add_library(IDAWin STATIC ${SRC_FILES} ${HEADER_FILES}) + target_link_libraries( + IDAWin + sundials -static + vcellexpressionparser -static + vcellmessaging -static + argparse -static + spdlog::spdlog -static + # if MinGW is enabled, add `$<$:ws2_32>` + ) +else () + message("Creating IDAWin for dynamic linkage.") + add_library(IDAWin SHARED ${SRC_FILES} ${HEADER_FILES}) + target_link_libraries( + IDAWin + sundials + vcellexpressionparser + vcellmessaging + argparse + spdlog::spdlog + # if MinGW is enabled, add `$<$:ws2_32>` + ) +endif () + set(EXE_FILE SundialsSolverStandalone) if (ARCH_64bit) set(EXE_FILE ${EXE_FILE}_x64) endif() +target_include_directories(IDAWin PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_compile_definitions(IDAWin PRIVATE IDAWIN_BUILDING_DLL) add_executable(${EXE_FILE} ${EXE_SRC_FILES}) target_link_libraries(${EXE_FILE} IDAWin) install(TARGETS ${EXE_FILE} RUNTIME DESTINATION ${OPTION_EXE_DIRECTORY}) -install(TARGETS IDAWin ARCHIVE DESTINATION bin) - - -enable_testing() - -if (MINGW) - set(test_sundials_exe ${CMAKE_BINARY_DIR}/bin/${EXE_FILE}.exe) - set(python_cmd py) -else (MINGW) - set(test_sundials_exe ${CMAKE_BINARY_DIR}/bin/${EXE_FILE}) - set(python_cmd python3) -endif (MINGW) -set(test_dir ${CMAKE_CURRENT_SOURCE_DIR}/tests/smoke) - -# smoke test as a python script, for bash test example, see NFsim/tests/smoke -add_test(NAME ${EXE_FILE}_smoke COMMAND ${python_cmd} ${test_dir}/smoke.py ${test_sundials_exe} WORKING_DIRECTORY ${test_dir}) - - -add_executable( - hello_test - hello_test.cpp -) -target_link_libraries( - hello_test - GTest::gtest_main -) - -include(GoogleTest) -gtest_discover_tests(hello_test) \ No newline at end of file +install(TARGETS IDAWin ARCHIVE DESTINATION bin) \ No newline at end of file diff --git a/IDAWin/OdeResultSet.cpp b/IDAWin/OdeResultSet.cpp index 9ca5758d0..dc0ffc616 100644 --- a/IDAWin/OdeResultSet.cpp +++ b/IDAWin/OdeResultSet.cpp @@ -1,190 +1,171 @@ +#include +#include #include "OdeResultSet.h" -#include "Expression.h" -#include "SymbolTable.h" #include "Exception.h" +#include "Expression.h" -#include +OdeResultSet::OdeResultSet(): columnWeights(nullptr), rowData(nullptr), numRowsAllocated(0), numRowsUsed(0), numFunctionColumns(0), numDataColumns(0) +{} -OdeResultSet::OdeResultSet() -{ - columnWeights = NULL; - numFunctionColumns = 0; - numRowsAllocated = 0; - numRowsUsed = 0; - numDataColumns = 0; - rowData = 0; -} - -OdeResultSet::~OdeResultSet() -{ - for (int i = 0; i < (int)columns.size(); i ++) { - delete columns[i].expression; - } - columns.clear(); +OdeResultSet::~OdeResultSet(){ + for (const Column& column : this->columns) delete column.expression; + this->columns.clear(); delete[] rowData; delete[] columnWeights; } -void OdeResultSet::addColumn(const string& aColumn) { - if (numRowsAllocated != 0) { - throw VCell::Exception("Can't add column when rowData is not empty"); - } - columns.push_back(Column(aColumn, 0)); - numDataColumns ++; +void OdeResultSet::addColumn(const std::string& aColumn) { + if (0 != this->numRowsAllocated) throw VCell::Exception("Can't add column when rowData is not empty"); + this->columns.emplace_back(aColumn, nullptr); + this->numDataColumns++; } -void OdeResultSet::bindFunctionExpression(SymbolTable* symbolTable) { - for (int i = 0; i < (int)columns.size(); i ++) { - if (columns[i].expression != 0) { - columns[i].expression->bindExpression(symbolTable); - } +void OdeResultSet::bindFunctionExpression(SymbolTable* symbolTable) const { + for (const Column& column : this->columns) { + if (column.expression == nullptr) continue; + column.expression->bindExpression(symbolTable); } } -void OdeResultSet::addFunctionColumn(const string& aColumn, const string& exp) { - columns.push_back(Column(aColumn, new VCell::Expression(exp))); - numFunctionColumns ++; +void OdeResultSet::addFunctionColumn(const std::string& aColumn, const std::string& columnExpression) { + this->columns.push_back(Column(aColumn, new VCell::Expression(columnExpression))); + this->numFunctionColumns ++; } -void OdeResultSet::addRow(double* aRow) { - if (numRowsAllocated == 0) { - numRowsAllocated = 500; - rowData = new double[numRowsAllocated * numDataColumns]; - memset(rowData, 0, numRowsAllocated * numDataColumns * sizeof(double)); - } else if (numRowsAllocated == numRowsUsed) { - int oldNumRowsAllocated = numRowsAllocated; - double* oldRowData = rowData; - numRowsAllocated += 500; - rowData = new double[numRowsAllocated * numDataColumns]; - memset(rowData, 0, numRowsAllocated * numDataColumns * sizeof(double)); - memcpy(rowData, oldRowData, oldNumRowsAllocated * numDataColumns * sizeof(double)); +void OdeResultSet::addRow(const double* aRow) { + if (this->numRowsAllocated == 0) { + this->numRowsAllocated = 500; + this->rowData = new double[this->numRowsAllocated * this->numDataColumns]; + memset(this->rowData, 0, this->numRowsAllocated * this->numDataColumns * sizeof(double)); + } else if (this->numRowsAllocated == this->numRowsUsed) { + const int oldNumRowsAllocated = this->numRowsAllocated; + const double* oldRowData = this->rowData; + this->numRowsAllocated += 500; + this->rowData = new double[this->numRowsAllocated * this->numDataColumns]; + memset(this->rowData, 0, this->numRowsAllocated * this->numDataColumns * sizeof(double)); + memcpy(this->rowData, oldRowData, oldNumRowsAllocated * this->numDataColumns * sizeof(double)); delete[] oldRowData; } - int index = numRowsUsed * numDataColumns; - for (int i = 0; i < numDataColumns; i ++, index ++) { - rowData[index] = aRow[i]; + int index = this->numRowsUsed * this->numDataColumns; + for (int i = 0; i < this->numDataColumns; i ++, index ++) { + this->rowData[index] = aRow[i]; } - numRowsUsed ++; + this->numRowsUsed++; } -void OdeResultSet::setColumnWeights(double* weights){ - delete[] columnWeights; - columnWeights = new double[columns.size()]; - memcpy(columnWeights, weights, columns.size() * sizeof(double)); +void OdeResultSet::setColumnWeights(const double* weights){ + delete[] this->columnWeights; + this->columnWeights = new double[this->columns.size()]; + memcpy(this->columnWeights, weights, this->columns.size() * sizeof(double)); } -double* OdeResultSet::getRowData(int index) { - if (index >= numRowsUsed) { +double* OdeResultSet::getRowData(const int index) { + if (index >= this->numRowsUsed) { throw VCell::Exception("OdeResultSet::getRowData(int index), row index is out of bounds"); } - return rowData + index * numDataColumns; + return this->rowData + index * this->numDataColumns; } void OdeResultSet::clearData() { - numRowsUsed = 0; - memset(rowData, 0, numRowsAllocated * numDataColumns * sizeof(double)); + this->numRowsUsed = 0; + memset(this->rowData, 0, this->numRowsAllocated * this->numDataColumns * sizeof(double)); } -int OdeResultSet::findColumn(const string& aColumn) { +int OdeResultSet::findColumn(const std::string& aColumn) const { int columnIndex = 0; - for (vector::iterator iter = columns.begin(); iter < columns.end(); iter++) { - if ((*iter).name == aColumn) { - break; - } - columnIndex ++; - } - if (columnIndex == columns.size()) { - columnIndex = -1; + for (const Column& column : this->columns) { + if (column.name == aColumn) break; + columnIndex++; } + if (columnIndex == this->columns.size()) columnIndex = -1; return columnIndex; } double OdeResultSet::getColumnWeight(int index) { - if (index >= (int)columns.size()) { - throw "OdeResultSet::getColumnWeight(int index), column index is out of bounds"; + if (index >= (int)this->columns.size()) { + throw std::out_of_range("OdeResultSet::getColumnWeight(int index), column index is out of bounds"); } return columnWeights[index]; } -int OdeResultSet::getNumColumns() { - return (int)columns.size(); +int OdeResultSet::getNumColumns() const { + return static_cast(this->columns.size()); } -string& OdeResultSet::getColumnName(int index) { - if (index >= (int)columns.size()) { - throw "OdeResultSet::getColumnName(int index), column index is out of bounds"; +std::string& OdeResultSet::getColumnName(const int index) { + if (index >= static_cast(this->columns.size())) { + throw std::out_of_range("OdeResultSet::getColumnName(int index), column index is out of bounds"); } - return columns[index].name; + return this->columns[index].name; } -int OdeResultSet::getNumRows() { - return numRowsUsed; +int OdeResultSet::getNumRows() const { + return this->numRowsUsed; } -VCell::Expression* OdeResultSet::getColumnFunctionExpression(int columnIndex) { - if (columnIndex >= (int)columns.size()) { - throw "OdeResultSet::getColumnFunctionExpression(), column index is out of bounds"; +VCell::Expression* OdeResultSet::getColumnFunctionExpression(const int columnIndex) const { + if (columnIndex >= static_cast(this->columns.size())) { + throw std::out_of_range("OdeResultSet::getColumnFunctionExpression(), column index is out of bounds"); } - return columns[columnIndex].expression; + return this->columns[columnIndex].expression; } -void OdeResultSet::getColumnData(int columnIndex, int numParams, double* paramValues, double* colData) { - int numCols = getNumColumns(); - if (columnIndex < 0 || columnIndex >= numCols){ - throw "OdeResultSet::getColumnData(int columnIndex), columnIndex out of bounds"; +void OdeResultSet::getColumnData(const int index, const int numParams, const double* paramValues, double* colData) const { + if (index < 0 || index >= this->getNumColumns()){ + throw std::out_of_range("OdeResultSet::getColumnData(int columnIndex), columnIndex out of bounds"); } - if (columns[columnIndex].expression == 0) { - for (int i = 0; i < numRowsUsed; i++){ - colData[i] = rowData[i * numDataColumns + columnIndex]; + if (this->columns[index].expression == nullptr) { + for (int i = 0; i < this->numRowsUsed; i++){ + colData[i] = this->rowData[i * this->numDataColumns + index]; } } else { // Function - double* values = new double[numDataColumns + numParams]; - memcpy(values + numDataColumns, paramValues, numParams * sizeof(double)); - for (int i = 0; i < numRowsUsed; i++){ - memcpy(values, rowData + i * numDataColumns, numDataColumns * sizeof(double)); - colData[i] = columns[columnIndex].expression->evaluateVector(values); + auto* values = new double[this->numDataColumns + numParams]; + memcpy(values + this->numDataColumns, paramValues, numParams * sizeof(double)); + for (int i = 0; i < this->numRowsUsed; i++){ + memcpy(values, this->rowData + i * this->numDataColumns, this->numDataColumns * sizeof(double)); + colData[i] = this->columns[index].expression->evaluateVector(values); } delete[] values; } } -void OdeResultSet::copyInto(OdeResultSet* otherOdeResultSet) { +void OdeResultSet::copyInto(OdeResultSet* otherOdeResultSet) const { // columns - if (otherOdeResultSet->columns.size() != columns.size()) { - for (int i = 0; i < (int)otherOdeResultSet->columns.size(); i ++) { - delete otherOdeResultSet->columns[i].expression; + if (otherOdeResultSet->columns.size() != this->columns.size()) { + for (const Column& column : otherOdeResultSet->columns) { + delete column.expression; } otherOdeResultSet->columns.clear(); - for (int i = 0; i < (int)columns.size(); i ++) { - if (columns[i].expression == 0) { - otherOdeResultSet->addColumn(columns[i].name); + for (const Column& column : this->columns) { + if (nullptr == column.expression) { + otherOdeResultSet->addColumn(column.name); } else { - otherOdeResultSet->addFunctionColumn(columns[i].name, columns[i].expression->infix()); + otherOdeResultSet->addFunctionColumn(column.name, column.expression->infix()); } } - if (columnWeights != 0) { - otherOdeResultSet->setColumnWeights(columnWeights); + if (nullptr != this->columnWeights) { + otherOdeResultSet->setColumnWeights(this->columnWeights); } } // rows - if (otherOdeResultSet->numRowsAllocated != numRowsAllocated) { + if (otherOdeResultSet->numRowsAllocated != this->numRowsAllocated) { delete[] otherOdeResultSet->rowData; - otherOdeResultSet->rowData = new double[numRowsAllocated * numDataColumns]; - otherOdeResultSet->numRowsAllocated = numRowsAllocated; + otherOdeResultSet->rowData = new double[this->numRowsAllocated * this->numDataColumns]; + otherOdeResultSet->numRowsAllocated = this->numRowsAllocated; } - otherOdeResultSet->numRowsUsed = numRowsUsed; - memcpy(otherOdeResultSet->rowData, rowData, numRowsAllocated * numDataColumns * sizeof(double)); + otherOdeResultSet->numRowsUsed = this->numRowsUsed; + memcpy(otherOdeResultSet->rowData, this->rowData, this->numRowsAllocated * this->numDataColumns * sizeof(double)); } void OdeResultSet::addEmptyRows(int numRowsToAdd) { - if (numRowsAllocated < numRowsUsed + numRowsToAdd) { - int oldNumRowsAllocated = numRowsAllocated; - double* oldRowData = rowData; - numRowsAllocated = numRowsUsed + numRowsToAdd; - rowData = new double[numRowsAllocated * numDataColumns]; - memset(rowData, 0, numRowsAllocated * numDataColumns * sizeof(double)); - memcpy(rowData, oldRowData, oldNumRowsAllocated * numDataColumns * sizeof(double)); + if (this->numRowsAllocated < this->numRowsUsed + numRowsToAdd) { + int oldNumRowsAllocated = this->numRowsAllocated; + double* oldRowData = this->rowData; + this->numRowsAllocated = this->numRowsUsed + numRowsToAdd; + this->rowData = new double[this->numRowsAllocated * this->numDataColumns]; + memset(this->rowData, 0, this->numRowsAllocated * this->numDataColumns * sizeof(double)); + memcpy(this->rowData, oldRowData, oldNumRowsAllocated * this->numDataColumns * sizeof(double)); delete[] oldRowData; } - numRowsUsed += numRowsToAdd; + this->numRowsUsed += numRowsToAdd; } diff --git a/IDAWin/OdeResultSet.h b/IDAWin/OdeResultSet.h index 08eb0fcfe..42a8505e7 100644 --- a/IDAWin/OdeResultSet.h +++ b/IDAWin/OdeResultSet.h @@ -2,67 +2,84 @@ #define ODERESULTSET_H #include +#include #include namespace VCell { class Expression; } + class SymbolTable; struct Column { std::string name; - VCell::Expression* expression; - - Column(std::string arg_name, VCell::Expression* exp) { - name = arg_name; - expression = exp; + VCell::Expression *expression; + + Column(std::string arg_name, VCell::Expression *exp) { + this->name = std::move(arg_name); + this->expression = exp; } }; -class OdeResultSet -{ -public: - OdeResultSet(); - ~OdeResultSet(); - void addColumn(const std::string& aColumn); - void addFunctionColumn(const std::string& aColumn, const std::string& columnExpression); - void addRow(double* aRow); - void setColumnWeights(double* weights); - - void bindFunctionExpression(SymbolTable* symbolTable); - - double* getRowData(int index); - const double* getRowData() { - return rowData; - } +class OdeResultSet { + public: + OdeResultSet(); + + ~OdeResultSet(); + + // Column Methods + [[nodiscard]] int getNumColumns() const; + + std::vector getColumns() { return this->columns; } + + void addColumn(const std::string &aColumn); + + [[nodiscard]] int findColumn(const std::string &aColumn) const; + + std::string &getColumnName(int index); + + double getColumnWeight(int index); + + void setColumnWeights(const double *weights); + + void getColumnData(int index, int numParams, const double *paramValues, double *colData) const; + + // Function Methods + void addFunctionColumn(const std::string &aColumn, const std::string &columnExpression); + + [[nodiscard]] int getNumFunctionColumns() const { return this->numFunctionColumns; } + [[nodiscard]] int getNumDataColumns() const { return this->numDataColumns; } + + [[nodiscard]] VCell::Expression *getColumnFunctionExpression(int columnIndex) const; + + void bindFunctionExpression(SymbolTable *symbolTable) const; + + // Row Methods + [[nodiscard]] int getNumRows() const; + + void addRow(const double *aRow); + + double *getRowData(int index); + + [[nodiscard]] double *getAllRowData() const { return this->rowData; } + + void addEmptyRows(int numRowsToAdd); + + // Misc. + void copyInto(OdeResultSet *otherOdeResultSet) const; + + void clearData(); - int findColumn(const std::string& aColumn); - double getColumnWeight(int index); - std::string& getColumnName(int index); - void getColumnData(int index, int numParams, double* paramValues, double* colData); - - int getNumColumns(); - int getNumRows(); - int getNumFunctionColumns() { return numFunctionColumns; } - int getNumDataColumns() { return numDataColumns; } - std::vector getColumns(){ return columns;} - - VCell::Expression* getColumnFunctionExpression(int columnIndex); - void clearData(); - - void copyInto(OdeResultSet* otherOdeResultSet); - void addEmptyRows(int numRowsToAdd); - -private: - // 0 : t - // 1 ~ N : variable names; - std::vector columns; - double* columnWeights; - double* rowData; - int numRowsAllocated; - int numRowsUsed; - int numFunctionColumns; - int numDataColumns; + private: + // 0 : t + // 1 ~ N : variable names; + std::vector columns; + double *columnWeights; + double *rowData; + int numRowsAllocated; + int numRowsUsed; + int numFunctionColumns; + int numDataColumns; }; #endif diff --git a/IDAWin/SteadyStateDriver.cpp b/IDAWin/SteadyStateDriver.cpp new file mode 100644 index 000000000..297021cce --- /dev/null +++ b/IDAWin/SteadyStateDriver.cpp @@ -0,0 +1,4 @@ +// +// Created by Logan Drescher on 6/25/25. +// +#include "SteadyStateDriver.h" diff --git a/IDAWin/SteadyStateDriver.h b/IDAWin/SteadyStateDriver.h new file mode 100644 index 000000000..d70cdd6f8 --- /dev/null +++ b/IDAWin/SteadyStateDriver.h @@ -0,0 +1,8 @@ +// +// Created by Logan Drescher on 6/25/25. +// + +#ifndef STEADYSTATEDRIVER_H +#define STEADYSTATEDRIVER_H + +#endif //STEADYSTATEDRIVER_H diff --git a/IDAWin/StoppedByUserException.cpp b/IDAWin/StoppedByUserException.cpp index 6bc89b05a..e1ef6787c 100644 --- a/IDAWin/StoppedByUserException.cpp +++ b/IDAWin/StoppedByUserException.cpp @@ -1,9 +1,6 @@ #include "StoppedByUserException.h" -StoppedByUserException::StoppedByUserException(string msg) : Exception("StoppedByUserException: " + msg) -{ -} +StoppedByUserException::StoppedByUserException(const string& msg) + : Exception("StoppedByUserException: " + msg){} -StoppedByUserException::~StoppedByUserException(void) throw( ) -{ -} +StoppedByUserException::~StoppedByUserException() noexcept = default; diff --git a/IDAWin/StoppedByUserException.h b/IDAWin/StoppedByUserException.h index 813db45b3..de2f56c6e 100644 --- a/IDAWin/StoppedByUserException.h +++ b/IDAWin/StoppedByUserException.h @@ -3,11 +3,10 @@ #include -class StoppedByUserException : public VCell::Exception -{ +class StoppedByUserException final : public VCell::Exception { public: - StoppedByUserException(string msg); - ~StoppedByUserException(void) throw( ); + explicit StoppedByUserException(const string& msg); + ~StoppedByUserException() noexcept override; }; #endif diff --git a/IDAWin/SundialsSolverInterface.cpp b/IDAWin/SundialsSolverInterface.cpp new file mode 100644 index 000000000..48f18b7fc --- /dev/null +++ b/IDAWin/SundialsSolverInterface.cpp @@ -0,0 +1,138 @@ +// +// Created by Logan Drescher on 11/12/25. +// +// Messaging +#include "SundialsSolverInterface.h" +#include "VCellSundialsSolver.h" +#include "VCellSolverFactory.h" + +// included referenced in commented out code: +#include +#include +#include +#include +#include "StoppedByUserException.h" + +#define CVODE_SOLVER "CVODE" +#define IDA_SOLVER "IDA" + +void errExit(int returnCode, const std::string &errorMsg); + +std::string version() { + return "VCell ODE solver (CVODE/IDA) v" + std::string(g_GIT_DESCRIBE); +} + +int solve(const std::string& inputFilePath, const std::string& outputFilePath, const int taskID) { + int returnCode = 0; + FILE *outputFile = NULL; + std::ifstream inputFileStream{inputFilePath}; + try { + if (!inputFileStream.is_open()) { throw std::runtime_error("input file [" + inputFilePath + "] doesn't exit!"); } + + // Open the output file... + if ((outputFile = fopen(outputFilePath.c_str(), "w")) == NULL) { + throw std::runtime_error("Could not open output file[" + outputFilePath + "] for writing."); + } + activateSolver(inputFileStream, outputFile, taskID); + } catch (const std::runtime_error& err) { + std::cerr << err.what() << std::endl; + returnCode = 5; + } catch (...) { + std::cerr << "Unknown exception thrown." << std::endl; + returnCode = 255; + } + + if (outputFile != NULL) { fclose(outputFile); } + if (inputFileStream.is_open()) { inputFileStream.close(); } + return returnCode; +} + + +void activateSolver(std::ifstream& inputFileStream, FILE* outputFile, int taskID) { + int returnCode = 0; + std::string errorMsg; + VCellSolver* targetSolver; + // First try block - create the solver; failure => no need to delete targetSolver! + try { + targetSolver = VCellSolverFactory::produceVCellSolver(inputFileStream, taskID); + } catch (const char *ex) { + returnCode = -1; + errorMsg = ex; + targetSolver = nullptr; + } catch (std::string &ex) { + returnCode = -2; + errorMsg = ex; + targetSolver = nullptr; + } catch (StoppedByUserException&) { + returnCode = 0; + errorMsg = "Execution Stopped By User"; + targetSolver = nullptr; + } catch (VCell::Exception &ex) { + returnCode = -3; + errorMsg = ex.getMessage(); + targetSolver = nullptr; + } catch (const std::exception& err) { + returnCode = -4; + errorMsg = err.what(); + targetSolver = nullptr; + } catch (...) { + returnCode = -5; + errorMsg = "Unknown Error Detected"; + targetSolver = nullptr; + } + // second try block - solver is created; must delete it! + if (nullptr != targetSolver) { + try { + targetSolver->solve(nullptr, true, outputFile, VCellSundialsSolver::checkStopRequested); + } catch (const char *ex) { + returnCode = -1; + errorMsg = ex; + // errExit(-1, ex); + } catch (std::string &ex) { + returnCode = -2; + errorMsg = ex; + } catch (StoppedByUserException&) { + returnCode = 0; + errorMsg = "Execution Stopped By User"; + } catch (VCell::Exception &ex) { + returnCode = -3; + errorMsg = ex.getMessage(); + } catch (const std::exception& err) { + returnCode = -4; + errorMsg = err.what(); + } catch (...) { + returnCode = -5; + errorMsg = "Unknown Error Detected"; + } + // !!! DELETE THE SOLVER !!! + delete targetSolver; + } + + // cleanup + SimulationMessaging::cleanupInstanceVar(); + + if (!errorMsg.empty()) errExit(returnCode, errorMsg); +} + +void errExit(int returnCode, const std::string &errorMsg) { + #ifdef USE_MESSAGING + if (returnCode && SimulationMessaging::getInstVar() && !SimulationMessaging::getInstVar()->isStopRequested()) { + SimulationMessaging::getInstVar()->setWorkerEvent(JobEvent::JOB_FAILURE, errorMsg.c_str()); + } + #endif + std::cerr << errorMsg << std::endl; +} + +// C-bound functions +extern "C" const char* version_ctypes() { + static std::string originalVersion = version(); + return originalVersion.c_str(); +} + +extern "C" int solve_ctypes(const char* inputFilePath, const char* outputFilePath, const int taskID) { + const std::string ifp{inputFilePath}; + const std::string ofp{outputFilePath}; + const int returnCode = solve(ifp, ofp, taskID); + return returnCode; +} + diff --git a/IDAWin/SundialsSolverInterface.h b/IDAWin/SundialsSolverInterface.h new file mode 100644 index 000000000..51f78e97e --- /dev/null +++ b/IDAWin/SundialsSolverInterface.h @@ -0,0 +1,31 @@ +// +// Created by Logan Drescher on 11/12/25. +// +#ifndef VCELL_ODE_NUMERICS_SUNDIALSSOLVERINTERFACE_H +#define VCELL_ODE_NUMERICS_SUNDIALSSOLVERINTERFACE_H + +#include + +// We need to explicitly declare functions as exposed for Windows...fun +#if defined(_WIN32) + #if defined(IDAWIN_BUILDING_DLL) + #define IDAWIN_API __declspec(dllexport) + #else + #define IDAWIN_API __declspec(dllimport) + #endif +#else + #define IDAWIN_API __attribute__((visibility("default"))) +#endif + +IDAWIN_API std::string version(); + +IDAWIN_API int solve(const std::string& inputFilePath, const std::string& outputFilePath, const int taskID); + +IDAWIN_API void activateSolver(std::ifstream& inputFileStream, FILE* outputFile, int taskID); + +// C-bound functions +extern "C" IDAWIN_API const char* version_ctypes(); + +extern "C" IDAWIN_API int solve_ctypes(const char* inputFilePath, const char* outputFilePath, const int taskID); + +#endif //VCELL_ODE_NUMERICS_SUNDIALSSOLVERINTERFACE_H \ No newline at end of file diff --git a/IDAWin/SundialsSolverStandalone.cpp b/IDAWin/SundialsSolverStandalone.cpp index e3e2ec661..ba0dfef2c 100644 --- a/IDAWin/SundialsSolverStandalone.cpp +++ b/IDAWin/SundialsSolverStandalone.cpp @@ -1,273 +1,50 @@ -// Debug -#ifdef _DEBUG - //#define _CRTDBG_MAP_ALLOC - #ifdef _CRTDBG_MAP_ALLOC - #include - #include - #else - //#include - #endif -#endif // Messaging -#ifdef USE_MESSAGING + #include -#endif +#include // Standard Includes #include #include #include -#include -#include // Local Includes -#include "VCellCVodeSolver.h" -#include "VCellIDASolver.h" -#include "OdeResultSet.h" +#include "SundialsSolverInterface.h" + #include "StoppedByUserException.h" #include - - +#include #define CVODE_SOLVER "CVODE" #define IDA_SOLVER "IDA" -void printUsage() { - std::string usageMessage{"Usage: SundialsSolverStandalone input output"}; - #ifdef USE_MESSAGING - usageMessage += " [-tid 0]"; - #endif - std::cout << usageMessage << std::endl; -} - -void loadJMSInfo(std::istream& ifsInput, int taskID) { - char *broker = new char[256]; - char *smqusername = new char[256]; - char *password = new char[256]; - char *qname = new char[256]; - char *tname = new char[256]; - char *vcusername = new char[256]; - string nextToken; - int simKey, jobIndex; - - while (!ifsInput.eof()) { - nextToken = ""; - ifsInput >> nextToken; - if (nextToken.size() == 0) { - continue; - } else if (nextToken[0] == '#') { - getline(ifsInput, nextToken); - continue; - } else if (nextToken == "JMS_PARAM_END") { - break; - } else if (nextToken == "JMS_BROKER") { - std::string brokerStr; - ifsInput >> brokerStr; - memset(broker, 0, 256 * sizeof(char)); - strncpy(broker, brokerStr.c_str(), 256); - } else if (nextToken == "JMS_USER") { - std::string usernameStr, passwordStr; - ifsInput >> usernameStr >> passwordStr; - memset(smqusername, 0, 256 * sizeof(char)); - memset(password, 0, 256 * sizeof(char)); - strncpy(smqusername, usernameStr.c_str(), 256); - strncpy(password, passwordStr.c_str(), 256); - } else if (nextToken == "JMS_QUEUE") { - std::string qnameStr; - ifsInput >> qnameStr; - memset(qname, 0, 256 * sizeof(char)); - strncpy(qname, qnameStr.c_str(), 256); - } else if (nextToken == "JMS_TOPIC") { - std::string topicStr; - ifsInput >> topicStr; - memset(tname, 0, 256 * sizeof(char)); - strncpy(tname, topicStr.c_str(), 256); - } else if (nextToken == "VCELL_USER") { - std::string vcusernameStr; - ifsInput >> vcusernameStr; - memset(vcusername, 0, 256 * sizeof(char)); - strncpy(vcusername, vcusernameStr.c_str(), 256); - } else if (nextToken == "SIMULATION_KEY") { - ifsInput >> simKey; - continue; - } else if (nextToken == "JOB_INDEX") { - ifsInput >> jobIndex; - continue; - } - } - -#ifdef USE_MESSAGING - if (taskID >= 0) { - SimulationMessaging::create(broker, smqusername, password, qname, tname, vcusername, simKey, jobIndex, taskID); - } else { - SimulationMessaging::create(); - } -#endif -} - -void errExit(int returnCode, std::string& errorMsg) { -#ifdef USE_MESSAGING - if (returnCode != 0) { - if (SimulationMessaging::getInstVar() != 0 && !SimulationMessaging::getInstVar()->isStopRequested()) { - SimulationMessaging::getInstVar()->setWorkerEvent(new WorkerEvent(JOB_FAILURE, errorMsg.c_str())); - } - } - if (SimulationMessaging::getInstVar() != 0) { - SimulationMessaging::getInstVar()->waitUntilFinished(); - delete SimulationMessaging::getInstVar(); - } else { - if (returnCode != 0) { - std::cerr << errorMsg << std::endl; - } - } -#else - if (returnCode != 0) { - std::cerr << errorMsg << std::endl; - } -#endif -} +int parseAndRunWithArgParse(int argc, char *argv[]); int main(int argc, char *argv[]) { - std::cout - << "Sundials Standalone version " << g_GIT_DESCRIBE - << std::endl; std::cout << std::setprecision(20); + return parseAndRunWithArgParse(argc, argv); +} +int parseAndRunWithArgParse(int argc, char *argv[]) { int taskID = -1; - string inputfname; - string outputfname; - string solver; - string errMsg; - int returnCode = 0; - - if (argc < 3) { - std::cout << "Missing arguments!" << std::endl; - printUsage(); - exit(1); - } - for (int i = 1; i < argc; i ++) { - if (!strcmp(argv[i], "-tid")) { -#ifdef USE_MESSAGING - i ++; - if (i >= argc) { - std::cout << "Missing taskID!" << std::endl; - printUsage(); - exit(1); - } - for (int j = 0; j < (int)strlen(argv[i]); j ++) { - if (argv[i][j] < '0' || argv[i][j] > '9') { - std::cout << "Wrong argument : " << argv[i] << ", taskID must be an integer!" << std::endl; - printUsage(); - exit(1); - } - } - taskID = atoi(argv[i]); -#else - std::cout << "Wrong argument : " << argv[i] << std::endl; - printUsage(); - exit(1); -#endif - } else { - inputfname = argv[i]; - i ++; - outputfname = argv[i]; - } - } - - FILE* outputFile = NULL; - std::ifstream inputstream(inputfname.c_str()); - try { - if (!inputstream.is_open()) { - throw std::string("input file [") + inputfname + "] doesn't exit!"; - } - - // Open the output file... - if ((outputFile = fopen(argv[2], "w")) == NULL) { - throw std::string("Could not open output file[") + outputfname + "] for writing."; - } - - string nextToken; + std::string inputFilePath; + std::string outputFilePath; - while (!inputstream.eof()) { - nextToken = ""; - inputstream >> nextToken; - if (nextToken.empty()) { - continue; - } else if (nextToken[0] == '#') { - getline(inputstream, nextToken); - continue; - } else if (nextToken == "JMS_PARAM_BEGIN") { - loadJMSInfo(inputstream, taskID); -#ifdef USE_MESSAGING - SimulationMessaging::getInstVar()->start(); // start the thread -#endif - } else if (nextToken == "SOLVER") { - inputstream >> solver; - break; - } - } -#ifdef USE_MESSAGING - // should only happen during testing for solver compiled with messaging but run locally. - if (SimulationMessaging::getInstVar() == nullptr) { - SimulationMessaging::create(); - } -#endif + const std::string programVersion{version()}; - if (solver.empty()) { - throw "Solver not defined "; - } - -#ifdef _CRTDBG_MAP_ALLOC - _CrtMemState s1, s2, s3; -#endif - errMsg += solver + " solver failed : "; -#ifdef _CRTDBG_MAP_ALLOC - _CrtMemCheckpoint( &s1 ); -#endif - VCellSundialsSolver* vss = 0; - if (solver == IDA_SOLVER) { - vss = new VCellIDASolver(); - } else if (solver == CVODE_SOLVER) { - vss = new VCellCVodeSolver(); - } else { - std::stringstream ss; - ss << "Solver " << solver << " not defined!"; - throw ss.str(); - } - vss->readInput(inputstream); - vss->solve(0, true, outputFile, VCellSundialsSolver::checkStopRequested); + argparse::ArgumentParser argumentParser("program_name", programVersion); + argumentParser.add_argument("input").help("path to directory with input files.").store_into(inputFilePath); + argumentParser.add_argument("output").help("path to directory for output files.").store_into(outputFilePath); + #ifdef USE_MESSAGING + argumentParser.add_argument("-tid").help("id of the job").store_into(taskID); + #endif - delete vss; -#ifdef _CRTDBG_MAP_ALLOC - _CrtMemCheckpoint( &s2 ); - if ( _CrtMemDifference( &s3, &s1, &s2) ) - _CrtMemDumpStatistics( &s3 ); - _CrtDumpMemoryLeaks(); -#endif - } catch (const char* ex) { - errMsg += ex; - returnCode = -1; - } catch (string& ex) { - errMsg += ex; - returnCode = -1; - } catch (StoppedByUserException) { - returnCode = 0; // stopped by user; - } catch (VCell::Exception& ex) { - errMsg += ex.getMessage(); - returnCode = -1; - } catch (...) { - errMsg += "unknown error"; - returnCode = -1; - } - - if (outputFile != NULL) { - fclose(outputFile); + try { + argumentParser.parse_args(argc, argv); } - if (inputstream.is_open()) { - inputstream.close(); + catch (const std::exception& err) { + std::cerr << err.what() << std::endl; + std::cerr << argumentParser; + return -1; } - errExit(returnCode, errMsg); -#ifdef _CRTDBG_MAP_ALLOC - _CrtDumpMemoryLeaks(); -#endif - return returnCode; + return solve(inputFilePath, outputFilePath, taskID); } diff --git a/IDAWin/VCellCVodeSolver.cpp b/IDAWin/VCellCVodeSolver.cpp index b36e7e5ad..eb2e82b1a 100644 --- a/IDAWin/VCellCVodeSolver.cpp +++ b/IDAWin/VCellCVodeSolver.cpp @@ -1,31 +1,24 @@ #include "VCellCVodeSolver.h" #include "OdeResultSet.h" #include -#include #include -#include +#include #include #include #include -#include "StoppedByUserException.h" -#include #include #include -using std::stringstream; - -#ifdef USE_MESSAGING -#include -#endif - +#include #include - #include /* prototypes for CVODE fcts. and consts. */ #include /* serial N_Vector types, fcts., and macros */ #include /* prototype for CVDense */ //#include /* prototype for CVSPGMR */ #include /* definitions DenseMat DENSE_ELEM */ #include /* definition of type realtype */ - +#ifdef USE_MESSAGING +#include +#endif #define ToleranceType CV_SS /** @@ -122,17 +115,17 @@ void VCellCVodeSolver::throwCVodeErrorMessage(int returnCode) { throw "CV_LSOLVE_FAIL: the linear solver's solve routine failed in an unrecoverable manner"; } case CV_REPTD_RHSFUNC_ERR: { - stringstream ss; + std::stringstream ss; ss << "CV_REPTD_RHSFUNC_ERR: repeated recoverable right-hand side function errors : " << recoverableErrMsg; throw ss.str(); } case CV_UNREC_RHSFUNC_ERR:{ - stringstream ss; + std::stringstream ss; ss << "CV_UNREC_RHSFUNC_ERR: the right-hand side failed in a recoverable manner, but no recovery is possible : " << recoverableErrMsg; throw ss.str(); } case CV_FIRST_RHSFUNC_ERR: { - stringstream ss; + std::stringstream ss; ss << "CV_FIRST_RHSFUNC_ERR: The right-hand side routine failed at the first call : " << recoverableErrMsg; throw ss.str(); } @@ -154,13 +147,13 @@ VCellCVodeSolver::VCellCVodeSolver() : VCellSundialsSolver() { VCellCVodeSolver::~VCellCVodeSolver() { CVodeFree(&solver); - for (int i = 0; i < NEQ; i ++) { + for (int i = 0; i < NUM_EQUATIONS; i ++) { delete rateExpressions[i]; } delete[] rateExpressions; } -/* +/**---------------------------------------------------- Input format: STARTING_TIME 0.0 ENDING_TIME 0.1 @@ -175,38 +168,27 @@ Input format: RATE ((20.0 * x_o * D_B0) - (50.0 * x_i)); ODE x_o INIT 0.0; RATE ( - ((20.0 * x_o * D_B0) - (50.0 * x_i)) + (1505000.0 * (3.322259136212625E-4 - (3.322259136212625E-4 * x_o) - (3.322259136212625E-4 * x_i))) - (100.0 * x_o)); -*/ -void VCellCVodeSolver::readEquations(std::istream& inputstream) { - try { - string name; - string exp; - - rateExpressions = new Expression*[NEQ]; - - for (int i = 0; i < NEQ; i ++) { - // ODE - inputstream >> name >> variableNames[i]; - - // INIT - inputstream >> name; - try { - initialConditionExpressions[i] = readExpression(inputstream); - } catch (VCell::Exception& ex) { - throw VCell::Exception(string("Initial condition expression for [") + variableNames[i] + "] " + ex.getMessage()); - } +--------------------------------------------------------------*/ - // RATE - inputstream >> name; +void VCellCVodeSolver::readEquations(VCellSolverInputBreakdown& inputBreakdown) { + try { + for (int i = 0; i < NUM_EQUATIONS; i ++) { + variableNames[i] = inputBreakdown.modelSettings.VARIABLE_NAMES[i]; try { - rateExpressions[i] = readExpression(inputstream); + initialConditionExpressions[i] = new Expression(inputBreakdown.modelSettings.INITIAL_CONDITION_EXPRESSIONS[i]); } catch (VCell::Exception& ex) { - throw VCell::Exception(string("Rate expression for [") + variableNames[i] + "] " + ex.getMessage()); + throw VCell::Exception(std::string("Initial condition expression for [") + variableNames[i] + "] " + ex.getMessage()); } - } + } + + rateExpressions = new Expression*[inputBreakdown.modelSettings.RATE_EXPRESSIONS.size()]; + for (int i = 0; i < inputBreakdown.modelSettings.RATE_EXPRESSIONS.size(); i++) { + rateExpressions[i] = new Expression(inputBreakdown.modelSettings.RATE_EXPRESSIONS[i]); + } } catch (char* ex) { - throw VCell::Exception(string("VCellCVodeSolver::readInput() : ") + ex); + throw VCell::Exception(std::string("VCellCVodeSolver::readInput() : ") + ex); } catch (VCell::Exception& ex) { - throw VCell::Exception(string("VCellCVodeSolver::readInput() : ") + ex.getMessage()); + throw VCell::Exception(std::string("VCellCVodeSolver::readInput() : ") + ex.getMessage()); } catch (...) { throw "VCellCVodeSolver::readInput() : caught unknown exception"; } @@ -216,7 +198,7 @@ void VCellCVodeSolver::initialize() { VCellSundialsSolver::initialize(); // rate can be function of variables, parameters and discontinuities. - for (int i = 0; i < NEQ; i ++) { + for (int i = 0; i < NUM_EQUATIONS; i ++) { rateExpressions[i]->bindExpression(defaultSymbolTable); } } @@ -225,20 +207,20 @@ int VCellCVodeSolver::RHS (realtype t, N_Vector y, N_Vector r) { try { updateTandVariableValues(t, y); double* r_data = NV_DATA_S(r); - for (int i = 0; i < NEQ; i ++) { + for (int i = 0; i < NUM_EQUATIONS; i ++) { r_data[i] = rateExpressions[i]->evaluateVector(values); } recoverableErrMsg = ""; return 0; - }catch (DivideByZeroException e){ + }catch (DivideByZeroException& e){ std::cout << "failed to evaluate residual: " << e.getMessage() << std::endl; recoverableErrMsg = e.getMessage(); return 1; - }catch (FunctionDomainException e){ + }catch (FunctionDomainException& e){ std::cout << "failed to evaluate residual: " << e.getMessage() << std::endl; recoverableErrMsg = e.getMessage(); return 1; - }catch (FunctionRangeException e){ + }catch (FunctionRangeException& e){ std::cout << "failed to evaluate residual: " << e.getMessage() << std::endl; recoverableErrMsg = e.getMessage(); return 1; @@ -260,19 +242,16 @@ int VCellCVodeSolver::RootFn_callback(realtype t, N_Vector y, realtype *gout, vo } void VCellCVodeSolver::solve(double* paramValues, bool bPrintProgress, FILE* outputFile, void (*checkStopRequested)(double, long)) { - if (checkStopRequested != 0) { - checkStopRequested(STARTING_TIME, 0); - } - + if (checkStopRequested != nullptr) checkStopRequested(STARTING_TIME, 0); writeFileHeader(outputFile); // clear data in result set before solving - odeResultSet->clearData(); + this->odeResultSet->clearData(); // copy parameter values to the end of values, these will stay the same during solving - memset(values, 0, (NEQ + 1) * sizeof(double)); - memcpy(values + 1 + NEQ, paramValues, NPARAM * sizeof(double)); - memset(values + 1 + NEQ + NPARAM, 0, numDiscontinuities * sizeof(double)); + memset(values, 0, (NUM_EQUATIONS + 1) * sizeof(double)); + memcpy(values + 1 + NUM_EQUATIONS, paramValues, NUM_PARAMETERS * sizeof(double)); + memset(values + 1 + NUM_EQUATIONS + NUM_PARAMETERS, 0, numDiscontinuities * sizeof(double)); initCVode(paramValues); cvodeSolve(bPrintProgress, outputFile, checkStopRequested); @@ -280,7 +259,7 @@ void VCellCVodeSolver::solve(double* paramValues, bool bPrintProgress, FILE* out void VCellCVodeSolver::initCVode(double* paramValues) { //Initialize y, variable portion of values - for (int i = 0; i < NEQ; i ++) { + for (int i = 0; i < NUM_EQUATIONS; i ++) { NV_Ith_S(y, i) = initialConditionExpressions[i]->evaluateVector(paramValues); } @@ -301,9 +280,9 @@ void VCellCVodeSolver::initCVode(double* paramValues) { void VCellCVodeSolver::reInit(double t) { int flag = 0; - if (solver == 0) { + if (solver == nullptr) { solver = CVodeCreate(CV_BDF, CV_NEWTON); - if (solver == 0) { + if (solver == nullptr) { throw "VCellCVodeSolver:: Out of memory"; } flag = CVodeMalloc(solver, RHS_callback, t, y, ToleranceType, RelativeTolerance, &AbsoluteTolerance); @@ -311,7 +290,7 @@ void VCellCVodeSolver::reInit(double t) { flag = CVodeSetFdata(solver, this); checkCVodeFlag(flag); - flag = CVDense(solver, NEQ); + flag = CVDense(solver, NUM_EQUATIONS); //flag = CVSpgmr(solver, PREC_NONE, 0); checkCVodeFlag(flag); @@ -323,8 +302,8 @@ void VCellCVodeSolver::reInit(double t) { } bool VCellCVodeSolver::fixInitialDiscontinuities(double t) { - double* oldy = new double[NEQ]; - memcpy(oldy, NV_DATA_S(y), NEQ * sizeof(realtype)); + double* oldy = new double[NUM_EQUATIONS]; + memcpy(oldy, NV_DATA_S(y), NUM_EQUATIONS * sizeof(realtype)); double epsilon = std::max(1e-15, ENDING_TIME * 1e-10); double currentTime = t; @@ -347,11 +326,11 @@ bool VCellCVodeSolver::fixInitialDiscontinuities(double t) { } } if (bInitChanged) { - memcpy(values + 1 + NEQ + NPARAM, discontinuityValues, numDiscontinuities * sizeof(double)); + memcpy(values + 1 + NUM_EQUATIONS + NUM_PARAMETERS, discontinuityValues, numDiscontinuities * sizeof(double)); } //revert y - memcpy(NV_DATA_S(y), oldy, NEQ * sizeof(realtype)); + memcpy(NV_DATA_S(y), oldy, NUM_EQUATIONS * sizeof(realtype)); reInit(t); delete[] oldy; @@ -433,11 +412,10 @@ void VCellCVodeSolver::cvodeSolve(bool bPrintProgress, FILE* outputFile, void (* if (returnCode == CV_ROOT_RETURN || iterationCount % keepEvery == 0 || Time >= ENDING_TIME){ outputCount++; - if (outputCount * (NEQ + 1) * bytesPerSample > MaxFileSizeBytes){ - /* if more than one gigabyte, then fail */ - char msg[100]; - sprintf(msg, "output exceeded maximum %d bytes", MaxFileSizeBytes); - throw VCell::Exception(msg); + if (outputCount * (NUM_EQUATIONS + 1) * bytesPerSample > MaxFileSizeBytes){ + /* if more than one gigabyte, then fail */ + const std::string msg{"output exceeded maximum " + std::to_string(MaxFileSizeBytes) + " bytes"}; + throw VCell::Exception(msg.c_str()); } writeData(Time, outputFile); if (bPrintProgress) { @@ -488,11 +466,11 @@ void VCellCVodeSolver::cvodeSolve(bool bPrintProgress, FILE* outputFile, void (* } } #ifdef USE_MESSAGING - SimulationMessaging::getInstVar()->setWorkerEvent(new WorkerEvent(JOB_COMPLETED, 1, Time)); + SimulationMessaging::getInstVar()->setWorkerEvent(JobEvent::JOB_COMPLETED, 1, Time); #endif } void VCellCVodeSolver::updateTandVariableValues(realtype t, N_Vector y) { values[0] = t; - memcpy(values + 1, NV_DATA_S(y), NEQ * sizeof(realtype)); + memcpy(values + 1, NV_DATA_S(y), NUM_EQUATIONS * sizeof(realtype)); } diff --git a/IDAWin/VCellCVodeSolver.h b/IDAWin/VCellCVodeSolver.h index ebb4d3f76..cce8d4d66 100644 --- a/IDAWin/VCellCVodeSolver.h +++ b/IDAWin/VCellCVodeSolver.h @@ -2,19 +2,21 @@ #define VCELLCVODESOLVER_H #include "VCellSundialsSolver.h" +#include class VCellCVodeSolver : public VCellSundialsSolver { public: VCellCVodeSolver(); - ~VCellCVodeSolver(); + ~VCellCVodeSolver() override; - void solve(double* paramValues=0, bool bPrintProgress=false, FILE* outputFile=0, void (*checkStopRequested)(double, long)=0); + void solve(double* paramValues=nullptr, bool bPrintProgress=false, FILE* outputFile=nullptr, void (*checkStopRequested)(double, long)=nullptr) override; double RHS(double* allValues, int equationIndex); protected: - void readEquations(std::istream& inputstream); - void initialize(); - string getSolverName() { return "CVODE"; } + void readEquations(VCellSolverInputBreakdown& inputBreakdown) override; + void initialize() override; + std::string getSolverName() override { return "CVODE"; } + VCellSolverTypes getSolverType() override { return VCellSolverTypes::CVODE; } private: VCell::Expression** rateExpressions; @@ -52,8 +54,8 @@ class VCellCVodeSolver : public VCellSundialsSolver { void checkCVodeFlag(int flag); void reInit(realtype t); - bool fixInitialDiscontinuities(double t); - void updateTandVariableValues(realtype t, N_Vector y); + bool fixInitialDiscontinuities(double t) override; + void updateTandVariableValues(realtype t, N_Vector y) override; void onCVodeReturn(realtype Time, int returnCode); diff --git a/IDAWin/VCellIDASolver.cpp b/IDAWin/VCellIDASolver.cpp index bd0e5de63..29fcaf7eb 100644 --- a/IDAWin/VCellIDASolver.cpp +++ b/IDAWin/VCellIDASolver.cpp @@ -9,19 +9,17 @@ #include #include #include -using std::stringstream; - -#ifdef USE_MESSAGING -#include -#endif - #include +#include #include #include //#include #include - #include +#include +#ifdef USE_MESSAGING +#include +#endif /** * calling sequence @@ -158,7 +156,7 @@ void VCellIDASolver::throwIDAErrorMessage(int returnCode) { throw "IDA_CONSTR_FAIL: The inequality constraints were violated, and the solver was unable to recover."; } case IDA_REP_RES_ERR:{ - stringstream ss; + std::stringstream ss; ss << "IDA_REP_RES_ERR: The user's residual function repeatedly returned a recoverable error flag, but the solver was unable to recover. " << recoverableErrMsg; throw ss.str(); } @@ -172,7 +170,7 @@ void VCellIDASolver::throwIDAErrorMessage(int returnCode) { throw "IDA_BAD_EWT: Some component of the error weight vector is zero (illegal)."; } case IDA_FIRST_RES_FAIL:{ - stringstream ss; + std::stringstream ss; ss << "IDA_FIRST_RES_FAIL: The user's residual function returned a recoverable error flag on the first call, but IDA was unable to recover. " << recoverableErrMsg; throw ss.str(); } @@ -213,7 +211,7 @@ VCellIDASolver::~VCellIDASolver() { N_VDestroy_Serial(yp); N_VDestroy_Serial(id); - for (int i = 0; i < NEQ; i ++) { + for (int i = 0; i < NUM_EQUATIONS; i ++) { delete rhsExpressions[i]; delete[] transformMatrix[i]; delete[] inverseTransformMatrix[i]; @@ -292,96 +290,47 @@ Input format: ((1505000.0 * (3.3222591362126253E-4 - (3.322259136212625E-4 * x_i) - (3.322259136212625E-4 * x_o))) - (100.0 * x_o)); --------------------------------------------------------------*/ -void VCellIDASolver::readEquations(std::istream& inputstream) { +void VCellIDASolver::readEquations(VCellSolverInputBreakdown& inputBreakdown) { try { - string token; - string exp; - - // - // test whether it is a "VAR" block (i.e. whether VAR) - // - inputstream >> token; - if (token != "VAR"){ - throw "expecting VAR"; - } - for (int i = 0; i < NEQ; i ++) { - // consume "VAR" token, but first line has it's "VAR" already consumed - if (i > 0){ - inputstream >> token; - } - - inputstream >> variableNames[i]; - - // INIT - inputstream >> token; + for (int i = 0; i < NUM_EQUATIONS; i ++) { + variableNames[i] = inputBreakdown.modelSettings.VARIABLE_NAMES[i]; try { - initialConditionExpressions[i] = readExpression(inputstream); + initialConditionExpressions[i] = new Expression(inputBreakdown.modelSettings.INITIAL_CONDITION_EXPRESSIONS[i]); } catch (VCell::Exception& ex) { - throw VCell::Exception(string("Initial condition expression for [") + variableNames[i] + "] " + ex.getMessage()); - } - } - - //TRANSFORM - transformMatrix = new double*[NEQ]; - inputstream >> token; - if (token != "TRANSFORM") { - throw "expecting TRANSFORM"; - } - getline(inputstream, exp); // go to next line - for (int i = 0; i < NEQ; i ++) { - transformMatrix[i] = new double[NEQ]; - for (int j = 0; j < NEQ; j ++) { - inputstream >> transformMatrix[i][j]; + throw VCell::Exception(std::string("Initial condition expression for [") + variableNames[i] + "] " + ex.getMessage()); } } - //INVERSETRANSFORM - inverseTransformMatrix = new double*[NEQ]; - inputstream >> token; - if (token != "INVERSETRANSFORM") { - throw "expecting INVERSETRANSFORM"; - } - getline(inputstream, exp); // go to next line - for (int i = 0; i < NEQ; i ++) { - inverseTransformMatrix[i] = new double[NEQ]; - for (int j = 0; j < NEQ; j ++) { - inputstream >> inverseTransformMatrix[i][j]; + transformMatrix = new double*[NUM_EQUATIONS]; + for (int i = 0; i < NUM_EQUATIONS; i ++) { + transformMatrix[i] = new double[NUM_EQUATIONS]; + for (int j = 0; j < NUM_EQUATIONS; j ++) { + transformMatrix[i][j] = std::stod(inputBreakdown.modelSettings.FLAT_TRANSFORM_MATRIX[i * NUM_EQUATIONS + j]); } } - //RHS DIFFERENTIAL 2 ALGEBRAIC 1 - inputstream >> token; - if (token != "RHS") { - throw "expecting RHS"; - } - inputstream >> token; - if (token != "DIFFERENTIAL") { - throw "expecting DIFFERENTIAL"; - } - inputstream >> numDifferential; - inputstream >> token; - if (token != "ALGEBRAIC") { - throw "expecting ALGEBRAIC"; - } - inputstream >> numAlgebraic; - if (numDifferential + numAlgebraic != NEQ) { - throw "numDifferential + numAlgebraic != NEQ"; + inverseTransformMatrix = new double*[NUM_EQUATIONS]; + for (int i = 0; i < NUM_EQUATIONS; i ++) { + inverseTransformMatrix[i] = new double[NUM_EQUATIONS]; + for (int j = 0; j < NUM_EQUATIONS; j ++) { + inverseTransformMatrix[i][j] = std::stod(inputBreakdown.modelSettings.FLAT_INVERSE_TRANSFORM_MATRIX[i * NUM_EQUATIONS + j]); + } } - getline(inputstream, exp); // go to next line - - rhsExpressions = new Expression*[NEQ]; - for (int i = 0; i < NEQ; i ++) { + numDifferential = inputBreakdown.modelSettings.NUM_DIFFERENTIAL; + numAlgebraic = inputBreakdown.modelSettings.NUM_ALGEBRAIC; + rhsExpressions = new Expression*[NUM_EQUATIONS]; + for (int i = 0; i < NUM_EQUATIONS; i ++) { try { - rhsExpressions[i] = readExpression(inputstream); + rhsExpressions[i] = new Expression(inputBreakdown.modelSettings.RATE_EXPRESSIONS[i]); } catch (VCell::Exception& ex) { - stringstream ss; + std::stringstream ss; ss << "RHS[" << i << "] " << ex.getMessage(); throw VCell::Exception(ss.str()); } } } catch (const char* ex) { - throw VCell::Exception(string("VCellIDASolver::readInput() : ") + ex); - } catch (VCell::Exception& ex) { - throw VCell::Exception(string("VCellIDASolver::readInput() : ") + ex.getMessage()); + throw VCell::Exception(std::string("VCellIDASolver::readInput() : ") + ex); + } catch (VCell::Exception& ex) { + throw VCell::Exception(std::string("VCellIDASolver::readInput() : ") + ex.getMessage()); } catch (...) { throw VCell::Exception("VCellIDASolver::readInput() caught unknown exception"); } @@ -390,12 +339,12 @@ void VCellIDASolver::readEquations(std::istream& inputstream) { void VCellIDASolver::initialize() { VCellSundialsSolver::initialize(); - for (int i = 0; i < NEQ; i ++) { + for (int i = 0; i < NUM_EQUATIONS; i ++) { rhsExpressions[i]->bindExpression(defaultSymbolTable); } - yp = N_VNew_Serial(NEQ); - id = N_VNew_Serial(NEQ); + yp = N_VNew_Serial(NUM_EQUATIONS); + id = N_VNew_Serial(NUM_EQUATIONS); if (yp == 0 || id == 0) { throw "Out of Memory"; @@ -415,9 +364,9 @@ void VCellIDASolver::solve(double* paramValues, bool bPrintProgress, FILE* outpu // copy parameter values to the end of values, these will stay the same during solving // values[0] is time, y values will be copied to 1~NEQ of values in residual function - memset(values, 0, (NEQ + 1 + NPARAM) * sizeof(double)); - memcpy(values + NEQ + 1, paramValues, NPARAM * sizeof(double)); - memset(values + 1 + NEQ + NPARAM, 0, numDiscontinuities * sizeof(double)); + memset(values, 0, (NUM_EQUATIONS + 1 + NUM_PARAMETERS) * sizeof(double)); + memcpy(values + NUM_EQUATIONS + 1, paramValues, NUM_PARAMETERS * sizeof(double)); + memset(values + 1 + NUM_EQUATIONS + NUM_PARAMETERS, 0, numDiscontinuities * sizeof(double)); initIDA(paramValues); idaSolve(bPrintProgress, outputFile, checkStopRequested); @@ -430,18 +379,18 @@ void VCellIDASolver::solve(double* paramValues, bool bPrintProgress, FILE* outpu void VCellIDASolver::initIDA(double* paramValues) { // compute initial condition - double* initCond = new double[NEQ]; - for (int i = 0; i < NEQ; i ++) { + double* initCond = new double[NUM_EQUATIONS]; + for (int i = 0; i < NUM_EQUATIONS; i ++) { initCond[i] = initialConditionExpressions[i]->evaluateVector(paramValues); } // must initialize y and yp before call IDAMalloc // Initialize y, yp and id. transform initial condition to y - for (int i = 0; i < NEQ; i ++) { + for (int i = 0; i < NUM_EQUATIONS; i ++) { NV_Ith_S(id, i) = i < numDifferential ? RCONST(1) : RCONST(0); NV_Ith_S(yp, i) = 0; // Initialize yp to be 0, they will be reinitialized later. NV_Ith_S(y, i) = 0; - for (int j = 0; j < NEQ; j ++) { + for (int j = 0; j < NUM_EQUATIONS; j ++) { NV_Ith_S(y, i) += transformMatrix[i][j] * initCond[j]; } } @@ -480,7 +429,7 @@ void VCellIDASolver::reInit(double t) { checkIDAFlag(flag); // choose the linear solver (Dense "direct" matrix LU decomposition solver). - flag = IDADense(solver, NEQ); + flag = IDADense(solver, NUM_EQUATIONS); //flag = IDASpgmr(solver, 0); checkIDAFlag(flag); @@ -506,8 +455,8 @@ bool VCellIDASolver::fixInitialDiscontinuities(double t) { int flag = IDARootInit(solver, 0, RootFn_callback, this); checkIDAFlag(flag); - double* oldy = new double[NEQ]; - memcpy(oldy, NV_DATA_S(y), NEQ * sizeof(realtype)); + double* oldy = new double[NUM_EQUATIONS]; + memcpy(oldy, NV_DATA_S(y), NUM_EQUATIONS * sizeof(realtype)); double epsilon = std::max(1e-15, ENDING_TIME * 1e-8); double currentTime = t; @@ -529,12 +478,12 @@ bool VCellIDASolver::fixInitialDiscontinuities(double t) { } } if (bInitChanged) { - memcpy(values + 1 + NEQ + NPARAM, discontinuityValues, numDiscontinuities * sizeof(double)); + memcpy(values + 1 + NUM_EQUATIONS + NUM_PARAMETERS, discontinuityValues, numDiscontinuities * sizeof(double)); } //revert y and yp - memcpy(NV_DATA_S(y), oldy, NEQ * sizeof(realtype)); - memset(NV_DATA_S(yp), 0, NEQ * sizeof(realtype)); + memcpy(NV_DATA_S(y), oldy, NUM_EQUATIONS * sizeof(realtype)); + memset(NV_DATA_S(yp), 0, NUM_EQUATIONS * sizeof(realtype)); reInit(t); flag = IDARootInit(solver, 2*numDiscontinuities, RootFn_callback, this); @@ -621,11 +570,10 @@ void VCellIDASolver::idaSolve(bool bPrintProgress, FILE* outputFile, void (*chec if (returnCode == IDA_ROOT_RETURN || iterationCount % keepEvery == 0 || Time >= ENDING_TIME){ outputCount ++; - if (outputCount *(NEQ + 1) * bytesPerSample > MaxFileSizeBytes){ - /* if more than one gigabyte, then fail */ - char msg[100]; - sprintf(msg, "output exceeded %ld bytes\n", MaxFileSizeBytes); - throw VCell::Exception(msg); + if (outputCount *(NUM_EQUATIONS + 1) * bytesPerSample > MaxFileSizeBytes){ + /* if more than one gigabyte, then fail */ + std::string problem = std::format("output exceeded {} bytes\n", MaxFileSizeBytes); + throw VCell::Exception(problem); } writeData(Time, outputFile); if (bPrintProgress) { @@ -676,7 +624,7 @@ void VCellIDASolver::idaSolve(bool bPrintProgress, FILE* outputFile, void (*chec } } #ifdef USE_MESSAGING - SimulationMessaging::getInstVar()->setWorkerEvent(new WorkerEvent(JOB_COMPLETED, 1, Time)); + SimulationMessaging::getInstVar()->setWorkerEvent(JobEvent::JOB_COMPLETED, 1, Time); #endif } @@ -684,9 +632,9 @@ void VCellIDASolver::idaSolve(bool bPrintProgress, FILE* outputFile, void (*chec // override updateTempRowData, since y values need to be transformed to the original variables. void VCellIDASolver::updateTempRowData(double currTime) { tempRowData[0] = currTime; - for (int i = 0; i < NEQ; i ++) { + for (int i = 0; i < NUM_EQUATIONS; i ++) { tempRowData[i + 1] = 0; - for (int j = 0; j < NEQ; j ++) { + for (int j = 0; j < NUM_EQUATIONS; j ++) { tempRowData[i + 1] += inverseTransformMatrix[i][j] * NV_Ith_S(y, j); } } @@ -694,9 +642,9 @@ void VCellIDASolver::updateTempRowData(double currTime) { void VCellIDASolver::updateTandVariableValues(realtype t, N_Vector y) { values[0] = t; - for (int i = 0; i < NEQ; i ++) { + for (int i = 0; i < NUM_EQUATIONS; i ++) { values[i + 1] = 0; - for (int j = 0; j < NEQ; j ++) { + for (int j = 0; j < NUM_EQUATIONS; j ++) { values[i + 1] += inverseTransformMatrix[i][j] * NV_Ith_S(y, j); } } diff --git a/IDAWin/VCellIDASolver.h b/IDAWin/VCellIDASolver.h index 2d4bae607..004ce4be6 100644 --- a/IDAWin/VCellIDASolver.h +++ b/IDAWin/VCellIDASolver.h @@ -2,19 +2,21 @@ #define VCELLIDASOLVER_H #include "VCellSundialsSolver.h" +#include class VCellIDASolver : public VCellSundialsSolver { public: VCellIDASolver(); - ~VCellIDASolver(); + ~VCellIDASolver() override; - void solve(double* paramValues=0, bool bPrintProgress=false, FILE* outputFile=0, void (*checkStopRequested)(double, long)=0); + void solve(double* paramValues=0, bool bPrintProgress=false, FILE* outputFile=0, void (*checkStopRequested)(double, long)=0) override; protected: - void updateTempRowData(double currTime); - void readEquations(std::istream& inputstream); - void initialize(); - string getSolverName() { return "IDA"; } + void updateTempRowData(double currTime) override; + void readEquations(VCellSolverInputBreakdown& inputBreakdown) override; + void initialize() override; + std::string getSolverName() override { return "IDA"; } + VCellSolverTypes getSolverType() override { return VCellSolverTypes::IDA; } private: VCell::Expression** rhsExpressions; // can be rate expression in ODE case or RHS expression in DAE case @@ -59,8 +61,8 @@ class VCellIDASolver : public VCellSundialsSolver { void checkIDAFlag(int flag); void reInit(realtype t); - bool fixInitialDiscontinuities(double t); - void updateTandVariableValues(realtype t, N_Vector y); + bool fixInitialDiscontinuities(double t) override; + void updateTandVariableValues(realtype t, N_Vector y) override; void onIDAReturn(realtype Time, int returnCode); }; diff --git a/IDAWin/VCellSolver.h b/IDAWin/VCellSolver.h new file mode 100644 index 000000000..1d95dc705 --- /dev/null +++ b/IDAWin/VCellSolver.h @@ -0,0 +1,25 @@ +// +// Created by Logan Drescher on 6/26/25. +// + +#ifndef VCELLSOLVER_H +#define VCELLSOLVER_H +#include "VCellSolverInput.h" + +/** + * Interfacing class for all solvers; we generally only care about configuring and running... + */ +class VCellSolver { + public: + virtual ~VCellSolver() = default; + + virtual void configureFromInput(VCellSolverInputBreakdown& inputBreakdown) = 0; + + virtual void solve(double *paramValues = nullptr, bool bPrintProgress = false, FILE *outputFile = nullptr, + void (*checkStopRequested)(double, long) = nullptr) = 0; + + protected: + VCellSolver() = default; +}; + +#endif //VCELLSOLVER_H diff --git a/IDAWin/VCellSolverFactory.cpp b/IDAWin/VCellSolverFactory.cpp new file mode 100644 index 000000000..648cd9300 --- /dev/null +++ b/IDAWin/VCellSolverFactory.cpp @@ -0,0 +1,472 @@ +// +// Created by Logan Drescher on 6/26/25. +// +#include "VCellSolverFactory.h" +#include "VCellSundialsSolver.h" +#include +#include +#include +#include +#include +#include + +#include "Exception.h" +#include "VCellCVodeSolver.h" +#include "VCellIDASolver.h" +#ifdef USE_MESSAGING +#include +#endif +// Forward Declarations +static void readDiscontinuities (std::istream &inputStream, VCellSolverInputBreakdown& inputBreakdown); +static void readEvents(std::istream &inputStream, VCellSolverInputBreakdown& inputBreakdown); +static std::string getExpressionString(std::istream& inputStream); +static std::string getExpressionString(std::string& unparsedString); +static void trimString(std::string &str); +// static VCell::Expression* readExpression(std::istream &inputstream); +static void collectCVodeEquations(std::ifstream& inputFileStream, VCellSolverInputBreakdown& inputBreakdown); +static void collectIDAEquations(std::ifstream& inputFileStream, VCellSolverInputBreakdown& inputBreakdown); +static void collectSteadyStateTerms(std::ifstream& inputFileStream, VCellSolverInputBreakdown& inputBreakdown); +static void loadJMSInfo(std::istream &ifsInput, int taskID); + +VCellSolver* VCellSolverFactory::produceVCellSolver(std::ifstream& inputFileStream, int taskID){ + VCellSolverInputBreakdown inputBreakdown = parseInputFile(inputFileStream, taskID); + VCellSolver* desiredSolver; + switch (inputBreakdown.solverType) { + case VCellSolverTypes::CVODE: + desiredSolver = new VCellCVodeSolver(); + break; + case VCellSolverTypes::IDA: + desiredSolver = new VCellIDASolver(); + break; + // case VCellSolverTypes::STEADY_STATE: + // break; + default: + throw new VCell::Exception("Unknown VCellSolver type"); + } + try { + desiredSolver->configureFromInput(inputBreakdown); + } catch (...) { + delete desiredSolver; + throw; + } + + return desiredSolver; +} + +VCellSolverInputBreakdown VCellSolverFactory::parseInputFile(std::ifstream& inputFileStream, int taskID) { + VCellSolverInputBreakdown inputBreakdown; + while (!inputFileStream.eof()) { + std::string nextToken; + inputFileStream >> nextToken; + if (nextToken.empty()) continue; + if (nextToken[0] == '#') std::getline(inputFileStream, nextToken); + else if (nextToken == "SOLVER") { + std::string solverName; + inputFileStream >> solverName; + inputBreakdown.solverType = determineSolverType(solverName); + } else if (nextToken == "JMS_PARAM_BEGIN") { + loadJMSInfo(inputFileStream, taskID); + // #ifdef USE_MESSAGING + // SimulationMessaging::getInstVar()->start(); // start the thread + // #endif + } + else if (nextToken == "STARTING_TIME") { inputFileStream >> inputBreakdown.timeCourseSettings.STARTING_TIME; } + else if (nextToken == "ENDING_TIME") { inputFileStream >> inputBreakdown.timeCourseSettings.ENDING_TIME; } + else if (nextToken == "RELATIVE_TOLERANCE") { inputFileStream >> inputBreakdown.timeCourseSettings.RELATIVE_TOLERANCE; } + else if (nextToken == "ABSOLUTE_TOLERANCE") { inputFileStream >> inputBreakdown.timeCourseSettings.ABSOLUTE_TOLERANCE; } + else if (nextToken == "MAX_TIME_STEP") { inputFileStream >> inputBreakdown.timeCourseSettings.MAX_TIME_STEP; } + else if (nextToken == "KEEP_EVERY") { inputFileStream >> inputBreakdown.timeCourseSettings.KEEP_EVERY; } + else if (nextToken == "OUTPUT_TIME_STEP"){ inputFileStream >> inputBreakdown.timeCourseSettings.OUTPUT_TIME_STEP; } + else if (nextToken == "OUTPUT_TIMES") { + std::size_t numOfTimePoints; + inputFileStream >> numOfTimePoints; + double timePoint; + for (std::size_t i = 0; i < numOfTimePoints; i++) { + inputFileStream >> timePoint; + const bool isValidTimePoint = timePoint > inputBreakdown.timeCourseSettings.STARTING_TIME + && timePoint <= inputBreakdown.timeCourseSettings.ENDING_TIME; + if (isValidTimePoint) inputBreakdown.timeCourseSettings.TIME_POINTS.push_back(timePoint); + } + if (inputBreakdown.timeCourseSettings.TIME_POINTS.back() < inputBreakdown.timeCourseSettings.ENDING_TIME) + inputBreakdown.timeCourseSettings.TIME_POINTS.push_back(inputBreakdown.timeCourseSettings.ENDING_TIME); + } else if (nextToken == "DISCONTINUITIES") { + readDiscontinuities(inputFileStream, inputBreakdown); + } else if (nextToken == "NUM_PARAMETERS") { + std::size_t numParameters; + inputFileStream >> numParameters; + for (std::size_t i = 0; i < numParameters; i++) { + std::string name; + inputFileStream >> name; + inputBreakdown.modelSettings.PARAMETER_NAMES.push_back(name); + } + } else if (nextToken == "NUM_EQUATIONS") { VCellSolverFactory::processEquations(inputFileStream, inputBreakdown); } + else if (nextToken == "EVENTS") { readEvents(inputFileStream, inputBreakdown); } + else if (nextToken == "STEADY_STATE") { + std::string confirmation; + inputFileStream >> confirmation; + if (confirmation == "TRUE") { collectSteadyStateTerms(inputFileStream, inputBreakdown); } + } + else throw VCell::Exception("Unexpected token \"" + nextToken + "\" in the input file!"); + + } + return inputBreakdown; +} + +VCellSolverTypes VCellSolverFactory::determineSolverType(const std::string& solverName){ + if (solverName == "CVODE") + return VCellSolverTypes::CVODE; + if (solverName == "IDA") + return VCellSolverTypes::IDA; + if (solverName == "CSSS") + return VCellSolverTypes::STEADY_STATE; // copasi-style steady-state + throw std::runtime_error("Unknown solver type: `" + solverName + "`"); +} + +void VCellSolverFactory::processEquations(std::ifstream& inputFileStream, VCellSolverInputBreakdown& inputBreakdown) { + if (inputBreakdown.solverType == VCellSolverTypes::IDA) collectIDAEquations(inputFileStream, inputBreakdown); + else collectCVodeEquations(inputFileStream, inputBreakdown); +} + +/** * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Local Helper Functions + * * * * * * * * * * * * * * * * * * * * * * * * * * * **/ + +static void readDiscontinuities(std::istream &inputStream, VCellSolverInputBreakdown& inputBreakdown) { + VCellSolverInputBreakdown::DiscontinuityComponents discontinuityComponents; + std::size_t numOfDiscontinuities; + inputStream >> numOfDiscontinuities; + + for (std::size_t i = 0; i < numOfDiscontinuities; i++) { + inputStream >> discontinuityComponents.symbol; + + std::string line = ""; + std::getline(inputStream, line); + std::string::size_type pos = line.find(";"); + if (pos == std::string::npos) { + std::string msg = std::string("discontinuity expression ") + BAD_EXPRESSION_MSG; + throw VCell::Exception(msg); + } + std::string exp = line.substr(0, pos + 1); + trimString(exp); + discontinuityComponents.discontinuityExpression = new VCell::Expression(exp); + + exp = line.substr(pos + 1); + discontinuityComponents.rootFindingExpression = new VCell::Expression(getExpressionString(exp)); + + inputBreakdown.discontinuitiesSettings.DISCONTINUITIES.push_back(std::move(discontinuityComponents)); + } +} + +static void readEvents(std::istream &inputStream, VCellSolverInputBreakdown& inputBreakdown) { + std::size_t numOfEvents; + std::string token; + + inputStream >> numOfEvents; + //events = new Event *[numEvents]; + for (std::size_t i = 0; i < numOfEvents; i++) { + VCellSolverInputBreakdown::EventComponents eventComponents; + while (true) { // Break on "EVENTASSIGNMENTS" + inputStream >> token; + if (token == "EVENT") { inputStream >> eventComponents.eventName; } + else if (token == "TRIGGER") { + try { + eventComponents.triggerExpression = getExpressionString(inputStream); + } catch (VCell::Exception &ex) { + throw VCell::Exception(std::string("trigger expression") + " " + ex.getMessage()); + } + } else if (token == "DELAY") { + inputStream >> token; + eventComponents.shouldUseValuesAtTriggerTime = (token == "true"); + try { + eventComponents.delayDurationExpression = getExpressionString(inputStream); + } catch (VCell::Exception &ex) { + throw VCell::Exception(std::string("delay duration expression") + " " + ex.getMessage()); + } + } else if (token == "EVENTASSIGNMENTS") { + int numEventAssignments; + inputStream >> numEventAssignments; + for (int j = 0; j < numEventAssignments; j++) { + std::pair eventAssignment; + inputStream >> eventAssignment.first; //varIndex + try { + eventAssignment.second = getExpressionString(inputStream); // assignment expression + } catch (VCell::Exception &ex) { + throw VCell::Exception(std::string("event assignment expression") + " " + ex.getMessage()); + } + eventComponents.eventAssignments.push_back(std::move(eventAssignment)); + //eventComponents.eventAssignments.emplace_back(varIndex, assignmentExpression); // should try this in the future, more descriptive + } + break; + } else { throw VCell::Exception("Unexpected event token \"" + token + "\" in the input file!"); } + } + inputBreakdown.eventSettings.EVENTS.push_back(std::move(eventComponents)); + } +} + +static void trimString(std::string &str) { + if (std::string::size_type pos = str.find_last_not_of(" \r\n"); pos != std::string::npos) { + str.erase(pos + 1); + pos = str.find_first_not_of(" \r\n"); + if (pos != std::string::npos) { str.erase(0, pos); } + } else { str.erase(str.begin(), str.end()); } +} + +static std::string getExpressionString(std::istream& inputStream) { + std::string exp; + std::getline(inputStream, exp); + return getExpressionString(exp); +} + +static std::string getExpressionString(std::string& unparsedString) { + trimString(unparsedString); + if (*(unparsedString.end() - 1) != ';') { throw VCell::Exception(std::format("Expression `{}` is not terminated with a ';' character!", unparsedString)); } + return unparsedString; +} + +/**---------------------------------------------------- +Input format: + STARTING_TIME 0.0 + ENDING_TIME 0.1 + RELATIVE_TOLERANCE 1.0E-9 + ABSOLUTE_TOLERANCE 1.0E-9 + MAX_TIME_STEP 1.0 + KEEP_EVERY 1 + DISCONTINUITIES 1 + D_B0 (t > 0.0432); (-0.0432 + t); + NUM_EQUATIONS 2 + ODE x_i INIT 0.0; + RATE ((20.0 * x_o * D_B0) - (50.0 * x_i)); + ODE x_o INIT 0.0; + RATE ( - ((20.0 * x_o * D_B0) - (50.0 * x_i)) + (1505000.0 * (3.322259136212625E-4 - (3.322259136212625E-4 * x_o) - (3.322259136212625E-4 * x_i))) - (100.0 * x_o)); +--------------------------------------------------------------*/ + +static void collectCVodeEquations(std::ifstream& inputFileStream, VCellSolverInputBreakdown& inputBreakdown) { + std::size_t numOfEquations; + inputFileStream >> numOfEquations; + std::string exp; + try { + std::string keyword; + for (std::size_t i = 0; i < numOfEquations; i++) { + // ODE + std::string varName; + inputFileStream >> keyword >> varName; + inputBreakdown.modelSettings.VARIABLE_NAMES.push_back(varName); + + // INIT + inputFileStream >> keyword; + try { + std::string expression{getExpressionString(inputFileStream)}; + inputBreakdown.modelSettings.INITIAL_CONDITION_EXPRESSIONS.push_back(expression); + } catch (VCell::Exception& ex) { + const std::string errMsg{"Initial condition expression for [" + inputBreakdown.modelSettings.VARIABLE_NAMES.back() + "] " + ex.getMessage()}; + throw VCell::Exception(errMsg); + } + + // RATE + inputFileStream >> keyword; + try { + std::string expression{getExpressionString(inputFileStream)}; + inputBreakdown.modelSettings.RATE_EXPRESSIONS.push_back(expression); + } catch (VCell::Exception& ex) { + const std::string errMsg{"Rate expression for [" + inputBreakdown.modelSettings.VARIABLE_NAMES.back() + "] " + ex.getMessage()}; + throw VCell::Exception(errMsg); + } + } + inputBreakdown.modelSettings.NUM_DIFFERENTIAL = inputBreakdown.modelSettings.RATE_EXPRESSIONS.size(); + inputBreakdown.modelSettings.NUM_ALGEBRAIC = 0; + + } catch (char* ex) { + throw VCell::Exception(std::string("VCellSolverFactory::collectCVodeEquations() : ") + ex); + } catch (VCell::Exception& ex) { + throw VCell::Exception(std::string("VCellSolverFactory::collectCVodeEquations() : ") + ex.getMessage()); + } +} + +/**---------------------------------------------------- +Input format: + STARTING_TIME 0.0 + ENDING_TIME 0.1 + RELATIVE_TOLERANCE 1.0E-9 + ABSOLUTE_TOLERANCE 1.0E-9 + MAX_TIME_STEP 1.0 + KEEP_EVERY 1 + DISCONTINUITIES 1 + D_B0 (t > 0.0432); (-0.0432 + t); + NUM_EQUATIONS 2 + VAR x_i INIT (0.0); + VAR x_o INIT (0.8); + TRANSFORM + 3.322259136212625E-4 0.0 + 0.0 1.0 + INVERSETRANSFORM + 3010.0 0.0 + 0.0 1.0 + RHS DIFFERENTIAL 1 ALGEBRAIC 1 + (3.322259136212625E-4 * ((20.0 * x_o * D_B0) - (50.0 * x_i))); + ((1505000.0 * (3.3222591362126253E-4 - (3.322259136212625E-4 * x_i) - (3.322259136212625E-4 * x_o))) - (100.0 * x_o)); +--------------------------------------------------------------*/ +static void collectIDAEquations(std::ifstream& inputFileStream, VCellSolverInputBreakdown& inputBreakdown) { + std::size_t numOfEquations; + inputFileStream >> numOfEquations; + try { + std::string keyword; + std::string _ignored; + + // There should be number of: + // * VAR statements + // * TRANSFORM entries + // * INVERSETRANSFORM entries + // * RHS entries + // We will remove sections when we've gotten the necessary amount of each + std::unordered_map sections = {{"VAR", 0}, {"TRANSFORM", 0} , {"INVERSETRANSFORM", 0}, {"RHS", 0} }; + + while (!sections.empty()) { + inputFileStream >> keyword; + if (!sections.contains(keyword)) throw VCell::Exception(std::string("Encountered unexpected keyword `") + keyword + "`"); + + if (keyword == "VAR") { + std::string varName, initialConditionExpression; + inputFileStream >> varName; + inputBreakdown.modelSettings.VARIABLE_NAMES.push_back(std::move(varName)); + inputFileStream >> keyword; // INIT keyword + try { + inputBreakdown.modelSettings.INITIAL_CONDITION_EXPRESSIONS.push_back(getExpressionString(inputFileStream)); + } catch (VCell::Exception& ex) { + throw VCell::Exception(std::string("Initial condition expression for [") + inputBreakdown.modelSettings.VARIABLE_NAMES.back() + "] " + ex.getMessage()); + } + // check for completion + if (sections[keyword] == numOfEquations - 1) sections.erase(keyword); + else sections[keyword]++; + } else if (keyword == "TRANSFORM") { + std::getline(inputFileStream, _ignored); // go to next line + for (std::size_t i = 0; i < numOfEquations * numOfEquations; i++) { + std::string nextTerm; + inputFileStream >> nextTerm; + inputBreakdown.modelSettings.FLAT_TRANSFORM_MATRIX.push_back(nextTerm); + } + // Affirm completion + sections.erase(keyword); + } else if (keyword == "INVERSETRANSFORM") { + std::getline(inputFileStream, _ignored); // go to next line + for (std::size_t i = 0; i < numOfEquations * numOfEquations; i++) { + std::string nextTerm; + inputFileStream >> nextTerm; + inputBreakdown.modelSettings.FLAT_INVERSE_TRANSFORM_MATRIX.push_back(nextTerm); + } + // Affirm completion + sections.erase(keyword); + } else if (keyword == "RHS") { + std::size_t numDifferentials, numAlgebraics; + inputFileStream >> keyword >> numDifferentials; + if (keyword != "DIFFERENTIAL") throw VCell::Exception("Error: Expected keyword `DIFFERENTIAL`, found `" + keyword +"`"); + inputBreakdown.modelSettings.NUM_DIFFERENTIAL = numDifferentials; + inputFileStream >> keyword >> numAlgebraics; + if (keyword != "ALGEBRAIC") throw VCell::Exception("Error: Expected keyword `ALGEBRAIC`, found `" + keyword +"`"); + inputBreakdown.modelSettings.NUM_ALGEBRAIC = numAlgebraics; + if (numDifferentials + numAlgebraics != numOfEquations) { + throw VCell::Exception(std::format("The sum of differential ({}) and algebraic ({}) equations does not equal the total number of equations ({})", numDifferentials, numAlgebraics, numOfEquations)); + } + std::getline(inputFileStream, _ignored); // go to next line + for (std::size_t i = 0; i < numOfEquations; i ++) { + try { + inputBreakdown.modelSettings.RATE_EXPRESSIONS.push_back(getExpressionString(inputFileStream)); + } catch (VCell::Exception& ex) { + throw VCell::Exception(std::format("RHS[{}] {}", i, ex.getMessage())); + } + } + // Affirm completion + sections.erase(keyword); + } else { + std::string errMsg{"Fatal error: inconsistent state - `" + keyword + "` is a valid section, but no logic exists to deal with it!"}; + throw VCell::Exception(errMsg); + } + } + } catch (const char* ex) { + throw VCell::Exception(std::string("VCellSolverFactory::collectIDAEquations() : ") + ex); + } catch (VCell::Exception& ex) { + throw VCell::Exception(std::string("VCellSolverFactory::collectIDAEquations() : ") + ex.getMessage()); + } catch (...) { + throw VCell::Exception("VCellSolverFactory::collectIDAEquations() caught unknown exception"); + } +} + +/**---------------------------------------------------- +Input format: + ... (STEADY_STATE TRUE) + RESOLUTION 0.0000000001 + MAX_NEWTON_ITERATIONS + MAXIMUM_FORWARD_DURATION + DERIVATION_FACTOR 0.001 + STOP_CRITERIA DISTANCE_AND_RATE + ... +--------------------------------------------------------------*/ +static void collectSteadyStateTerms(std::ifstream& inputFileStream, VCellSolverInputBreakdown& inputBreakdown) { + std::unordered_set sections = {"RESOLUTION", "MAX_NEWTON_ITERATIONS", + "MAXIMUM_FORWARD_DURATION", "DERIVATION_FACTOR", "STOP_CRITERIA"}; + + do { + std::string keyword; + inputFileStream >> keyword; + if (keyword == "RESOLUTION") { inputFileStream >> inputBreakdown.steadyStateSettings.RESOLUTION; } + else if (keyword == "MAXIMUM_NEWTON_ITERATIONS") { inputFileStream >> inputBreakdown.steadyStateSettings.MAX_ITERATIONS; } + else if (keyword == "MAXIMUM_FORWARD_DURATION") { inputFileStream >> inputBreakdown.steadyStateSettings.MAX_FORWARD_DURATION; } + else if (keyword == "DERIVATION_FACTOR") { inputFileStream >> inputBreakdown.steadyStateSettings.DERIVATION_FACTOR; } + else if (keyword == "STOP_CRITERIA") { + std::string stopCriteria; + inputFileStream >> stopCriteria; + if (stopCriteria == "DISTANCE_ONLY") { inputBreakdown.steadyStateSettings.STOP_CRITERIA = VCellSteadyStateStopCriteria::DISTANCE_ONLY; } + else if (stopCriteria == "RATE_ONLY") { inputBreakdown.steadyStateSettings.STOP_CRITERIA = VCellSteadyStateStopCriteria::RATE_ONLY; } + else if (stopCriteria == "DISTANCE_AND_RATE") { inputBreakdown.steadyStateSettings.STOP_CRITERIA = VCellSteadyStateStopCriteria::DISTANCE_AND_RATE; } + else if (stopCriteria == "DISTANCE_OR_RATE") { inputBreakdown.steadyStateSettings.STOP_CRITERIA = VCellSteadyStateStopCriteria::DISTANCE_OR_RATE; } + else throw VCell::Exception("Unknown stop criteria `" + keyword + "`"); + } else throw VCell::Exception("Unknown steady state keyword `" + keyword + "`"); + if (!sections.contains(keyword)) throw VCell::Exception("Duplicate section `" + keyword + "` detected."); + sections.erase(keyword); + } while (!sections.empty()); +} + +static void loadJMSInfo(std::istream &ifsInput, int taskID) { + #ifndef USE_MESSAGING + // We'll still parse the section, as we can still execute the simulation; we'll just toss the values! + std::cerr << "WARNING: Input file expects messaging capabilities; this build does not support JMS messaging!" << std::endl; + #endif + + std::string broker; + std::string smqUserName; + std::string password; + std::string qName; + std::string topicName; + std::string vCellUsername; + int simKey, jobIndex; + + while (true) { + if (ifsInput.eof()) + throw std::runtime_error("VCellSolverFactory::loadJMSInfo() reached end of file, but no `JMS_PARAM_END` reached!"); + + std::string nextToken; + ifsInput >> nextToken; + if (nextToken.empty()) continue; + if (nextToken[0] == '#') { + // getline(ifsInput, nextToken); // Is this ignoring because of a comment? + ifsInput.ignore('\n'); + continue; + } + if (nextToken == "JMS_PARAM_END") break; // Non-error stop condition + + if (nextToken == "JMS_BROKER") ifsInput >> broker; + else if (nextToken == "JMS_USER") ifsInput >> smqUserName >> password; + else if (nextToken == "JMS_QUEUE") ifsInput >> qName; + else if (nextToken == "JMS_TOPIC") ifsInput >> topicName; + else if (nextToken == "VCELL_USER") ifsInput >> vCellUsername; + else if (nextToken == "SIMULATION_KEY") ifsInput >> simKey; + else if (nextToken == "JOB_INDEX") ifsInput >> jobIndex; + } + + #ifdef USE_MESSAGING + // SimulationMessaging::getInstVar()->initialize_curl_messaging(broker.c_str(), smqUserName.c_str(), + // password.c_str(), qName.c_str(), topicName.c_str(), + // vCellUsername.c_str(), simKey, jobIndex, taskID); + SimulationMessaging::getInstVar()->initialize_curl_messaging(false, broker.c_str(), + vCellUsername.c_str(), simKey, jobIndex, taskID); + #endif +} diff --git a/IDAWin/VCellSolverFactory.h b/IDAWin/VCellSolverFactory.h new file mode 100644 index 000000000..9e81b35df --- /dev/null +++ b/IDAWin/VCellSolverFactory.h @@ -0,0 +1,26 @@ +// +// Created by Logan Drescher on 6/26/25. +// + +#ifndef VCELLSOLVERFACTORY_H +#define VCELLSOLVERFACTORY_H +#include +#include +#include "VCellSolver.h" +#include "VCellSolverInput.h" + + + + +class VCellSolverFactory { + public: + static VCellSolver* produceVCellSolver(std::ifstream& inputFileStream, int taskID); + static VCellSolverInputBreakdown parseInputFile(std::ifstream& inputFileStream, int taskID); + private: + static VCellSolverTypes determineSolverType(const std::string& solverName); + static void processEquations(std::ifstream& inputFileStream, VCellSolverInputBreakdown& inputBreakdown); +}; + + + +#endif //VCELLSOLVERFACTORY_H diff --git a/IDAWin/VCellSolverInput.cpp b/IDAWin/VCellSolverInput.cpp new file mode 100644 index 000000000..8f0f7bf26 --- /dev/null +++ b/IDAWin/VCellSolverInput.cpp @@ -0,0 +1,7 @@ +// +// Created by Logan Drescher on 6/26/25. +// + +#include "VCellSolverInput.h" + +// See "TODO" in header file diff --git a/IDAWin/VCellSolverInput.h b/IDAWin/VCellSolverInput.h new file mode 100644 index 000000000..08b9ca4d1 --- /dev/null +++ b/IDAWin/VCellSolverInput.h @@ -0,0 +1,81 @@ +// +// Created by Logan Drescher on 6/26/25. +// + +#ifndef VCELLSOLVERINPUT_H +#define VCELLSOLVERINPUT_H +#include +#include +#include +#include "Expression.h" + +enum VCellSolverTypes{ CVODE, IDA, STEADY_STATE}; +enum VCellSteadyStateStopCriteria{DISTANCE_ONLY, RATE_ONLY, DISTANCE_OR_RATE, DISTANCE_AND_RATE}; + +/// TODO: For better memory management, vectors should have their size initialized by the +/// values in the input file, and allocated on the heap! +struct VCellSolverInputBreakdown { + // Typedefs + + struct ModelSettings { + std::vector PARAMETER_NAMES; + std::vector VARIABLE_NAMES; + std::vector INITIAL_CONDITION_EXPRESSIONS; + std::vector RATE_EXPRESSIONS; + std::vector FLAT_TRANSFORM_MATRIX; + std::vector FLAT_INVERSE_TRANSFORM_MATRIX; + int NUM_DIFFERENTIAL; + int NUM_ALGEBRAIC; + }; + + struct TimeCourseSettings { + realtype STARTING_TIME; + realtype ENDING_TIME; + realtype RELATIVE_TOLERANCE; + realtype ABSOLUTE_TOLERANCE; + double OUTPUT_TIME_STEP = 0.0; + double MAX_TIME_STEP = 0.0; + std::vector TIME_POINTS; + long KEEP_EVERY = 0.0l; + }; + + struct SteadyStateSettings { + realtype RESOLUTION; + realtype DERIVATION_FACTOR; // how far to newton step to satisfy df/dt + realtype MAX_ITERATIONS; // how many times to newton-step before giving up + realtype MAX_FORWARD_DURATION; + VCellSteadyStateStopCriteria STOP_CRITERIA; + }; + + struct DiscontinuityComponents { + std::string symbol; + VCell::Expression* discontinuityExpression; + VCell::Expression* rootFindingExpression; + }; + + + struct DiscontinuitiesSettings { + std::vector DISCONTINUITIES; + }; + + struct EventComponents { + std::string eventName; + std::string triggerExpression; + std::string delayDurationExpression; + std::vector> eventAssignments; + bool shouldUseValuesAtTriggerTime = true; + }; + + struct EventSettings { + std::vector EVENTS; + }; + + VCellSolverTypes solverType; + ModelSettings modelSettings; + TimeCourseSettings timeCourseSettings; + SteadyStateSettings steadyStateSettings; + DiscontinuitiesSettings discontinuitiesSettings; + EventSettings eventSettings; +}; + +#endif //VCELLSOLVERINPUT_H diff --git a/IDAWin/VCellSundialsSolver.cpp b/IDAWin/VCellSundialsSolver.cpp index bc40c3692..a44c40cc0 100644 --- a/IDAWin/VCellSundialsSolver.cpp +++ b/IDAWin/VCellSundialsSolver.cpp @@ -1,98 +1,79 @@ -#include +#include "SimpleSymbolTable.h" #include "StoppedByUserException.h" #include "VCellSundialsSolver.h" #include "OdeResultSet.h" -#include -#include +#include +#include +#include +#include #include -using std::stringstream; - -#include +#include +#include +#include #ifdef USE_MESSAGING #include #endif -static void trimString(string& str) -{ - string::size_type pos = str.find_last_not_of(" \r\n"); - if(pos != string::npos) { - str.erase(pos + 1); - pos = str.find_first_not_of(" \r\n"); - if(pos != string::npos) { - str.erase(0, pos); - } - } - else { - str.erase(str.begin(), str.end()); - } -} - -VCell::Expression* VCellSundialsSolver::readExpression(std::istream& inputstream) { - string exp; - getline(inputstream, exp); - trimString(exp); - if (*(exp.end() - 1) != ';') { - throw VCell::Exception(BAD_EXPRESSION_MSG); - } - return new VCell::Expression(exp); -} +/** * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Local Helper Function Prototypes + * * * * * * * * * * * * * * * * * * * * * * * * * * * **/ +static void trimString(std::string &str); +/** * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Instance Methods + * * * * * * * * * * * * * * * * * * * * * * * * * * * **/ VCellSundialsSolver::VCellSundialsSolver() { - NEQ = 0; - NPARAM = 0; + NUM_EQUATIONS = 0; + NUM_PARAMETERS = 0; STARTING_TIME = 0.0; - ENDING_TIME = 0.0; + ENDING_TIME = 0.0; RelativeTolerance = 0.0; AbsoluteTolerance = 0.0; keepEvery = 0; - maxTimeStep = 0.0; + maxTimeStep = 0.0; - solver = 0; - initialConditionSymbolTable = 0; - initialConditionExpressions = 0; - values = 0; - tempRowData = 0; + solver = nullptr; + initialConditionSymbolTable = nullptr; + initialConditionExpressions = nullptr; + values = nullptr; + tempRowData = nullptr; - variableNames = 0; - paramNames = 0; - allSymbols = 0; + variableNames = nullptr; + paramNames = nullptr; + allSymbols = nullptr; numAllSymbols = 0; - defaultSymbolTable = 0; + defaultSymbolTable = nullptr; numDiscontinuities = 0; - odeDiscontinuities = 0; - discontinuityValues = 0; - discontinuitySymbolTable = 0; - rootsFound = 0; + odeDiscontinuities = nullptr; + discontinuityValues = nullptr; + discontinuitySymbolTable = nullptr; + rootsFound = nullptr; - odeResultSet = new OdeResultSet(); - y = 0; + odeResultSet = new OdeResultSet(); + y = nullptr; - events = 0; + events = nullptr; numEvents = 0; } VCellSundialsSolver::~VCellSundialsSolver() { N_VDestroy_Serial(y); - for (int i = 0; i < NEQ; i ++) { - delete initialConditionExpressions[i]; - } + for (int i = 0; i < NUM_EQUATIONS; i++) { delete initialConditionExpressions[i]; } delete[] initialConditionExpressions; delete[] variableNames; delete[] paramNames; delete[] allSymbols; delete defaultSymbolTable; - for (int i = 0; i < numDiscontinuities; i ++) { - delete odeDiscontinuities[i]; - } + for (int i = 0; i < numDiscontinuities; i++) { delete odeDiscontinuities[i]; } delete[] odeDiscontinuities; delete[] rootsFound; delete[] discontinuityValues; delete discontinuitySymbolTable; - + delete[] values; delete[] tempRowData; delete initialConditionSymbolTable; @@ -100,37 +81,36 @@ VCellSundialsSolver::~VCellSundialsSolver() { outputTimes.clear(); - for (int i = 0; i < numEvents; i ++) { - delete events[i]; - } + for (int i = 0; i < numEvents; i++) { delete events[i]; } delete[] events; + + for (EventExecution* elem : eventExeList) { + delete elem; + } + eventExeList.clear(); } void VCellSundialsSolver::updateTempRowData(double currTime) { - tempRowData[0] = currTime; - for (int i = 0; i < NEQ; i++) { - tempRowData[i+1] = NV_Ith_S(y,i); - } + tempRowData[0] = currTime; + for (int i = 0; i < NUM_EQUATIONS; i++) { tempRowData[i + 1] = NV_Ith_S(y, i); } } -void VCellSundialsSolver::writeData(double currTime, FILE* outputFile) { +void VCellSundialsSolver::writeData(double currTime, FILE *outputFile) { updateTempRowData(currTime); odeResultSet->addRow(tempRowData); writeFileData(outputFile); } -void VCellSundialsSolver::writeFileData(FILE* outputFile) { - if (outputFile != 0) { - fprintf(outputFile, "%0.17E", tempRowData[0]); - for (int i = 1; i < NEQ+1; i++) { - fprintf(outputFile, "\t%0.17E", tempRowData[i]); - } +void VCellSundialsSolver::writeFileData(FILE *outputFile) { + if (outputFile != nullptr) { + fprintf(outputFile, "%0.17E", tempRowData[0]); + for (int i = 1; i < NUM_EQUATIONS + 1; i++) { fprintf(outputFile, "\t%0.17E", tempRowData[i]); } fprintf(outputFile, "\n"); } } -void VCellSundialsSolver::writeFileHeader(FILE* outputFile) { - if (outputFile != 0) { +void VCellSundialsSolver::writeFileHeader(FILE *outputFile) { + if (outputFile != nullptr) { // Print header... for (int i = 0; i < odeResultSet->getNumColumns(); i++) { fprintf(outputFile, "%s:", odeResultSet->getColumnName(i).data()); @@ -139,38 +119,41 @@ void VCellSundialsSolver::writeFileHeader(FILE* outputFile) { } } -void VCellSundialsSolver::printProgress(double currTime, double& lastPercentile, clock_t& lastTime, double increment, FILE* outputFile) { +void VCellSundialsSolver::printProgress(double currTime, double &lastPercentile, clock_t &lastTime, double increment, + FILE *outputFile) const { fflush(outputFile); if (currTime == STARTING_TIME) { // print 0% -#ifdef USE_MESSAGING - SimulationMessaging::getInstVar()->setWorkerEvent(new WorkerEvent(JOB_PROGRESS, lastPercentile, currTime)); -#else + #ifdef USE_MESSAGING + SimulationMessaging::getInstVar()->setWorkerEvent(JobEvent::JOB_PROGRESS, lastPercentile, currTime); + #else printf("[[[progress:%lg%%]]]", lastPercentile*100.0); fflush(stdout); -#endif + #endif } else { clock_t currentTime = clock(); - double duration = (double)(currentTime - lastTime) / CLOCKS_PER_SEC; - if (duration >= 2){ //send out message every 2 seconds - double newPercentile = (long)((currTime - STARTING_TIME)/(ENDING_TIME - STARTING_TIME)/increment) * increment; + double duration = (double) (currentTime - lastTime) / CLOCKS_PER_SEC; + if (duration >= 2) { //send out message every 2 seconds + double newPercentile = (long) ((currTime - STARTING_TIME) / (ENDING_TIME - STARTING_TIME) / increment) * + increment; /*while (true) { double midTime = (percentile + increment) * (ENDING_TIME - STARTING_TIME); - if (STARTING_TIME + midTime > currTime) { + if (STARTING_TIME + midTime > currTime) { break; } percentile += increment; }*/ - if ( lastPercentile != newPercentile) { -#ifdef USE_MESSAGING - SimulationMessaging::getInstVar()->setWorkerEvent(new WorkerEvent(JOB_PROGRESS, newPercentile, currTime)); - SimulationMessaging::getInstVar()->setWorkerEvent(new WorkerEvent(JOB_DATA, newPercentile, currTime)); -#else + if (lastPercentile != newPercentile) { + #ifdef USE_MESSAGING + SimulationMessaging::getInstVar()-> + setWorkerEvent(JobEvent::JOB_PROGRESS, newPercentile, currTime); + SimulationMessaging::getInstVar()->setWorkerEvent(JobEvent::JOB_DATA, newPercentile, currTime); + #else printf("[[[progress:%lg%%]]]", newPercentile*100.0); - printf("[[[data:%lg]]]", currTime); + printf("[[[data:%lg]]]", currTime); fflush(stdout); -#endif + #endif lastPercentile = newPercentile; lastTime = currentTime; } @@ -178,236 +161,128 @@ void VCellSundialsSolver::printProgress(double currTime, double& lastPercentile, } } -void VCellSundialsSolver::readInput(std::istream& inputstream) { +void VCellSundialsSolver::configureFromInput(VCellSolverInputBreakdown& inputBreakdown) { try { - if (solver != 0) { - throw "readInput should only be called once"; + if (solver != nullptr) { throw "configureFromInput should only be called once"; } + if (inputBreakdown.solverType != getSolverType()) throw VCell::Exception("Fatal Error: Solver mismatch detected!"); + STARTING_TIME = inputBreakdown.timeCourseSettings.STARTING_TIME; + ENDING_TIME = inputBreakdown.timeCourseSettings.ENDING_TIME; + RelativeTolerance = inputBreakdown.timeCourseSettings.RELATIVE_TOLERANCE; + AbsoluteTolerance = inputBreakdown.timeCourseSettings.ABSOLUTE_TOLERANCE; + maxTimeStep = inputBreakdown.timeCourseSettings.MAX_TIME_STEP; + keepEvery = inputBreakdown.timeCourseSettings.KEEP_EVERY; + ///TODO: replace "1e-12" with "SMALL_REAL" constant? Probably need to change outputTimes to `std::vector` + if (inputBreakdown.timeCourseSettings.OUTPUT_TIME_STEP != 0.0){ + for (int count = 1; STARTING_TIME + count * inputBreakdown.timeCourseSettings.OUTPUT_TIME_STEP < ENDING_TIME + 1E-12 * ENDING_TIME; count++) + outputTimes.push_back(STARTING_TIME + count * inputBreakdown.timeCourseSettings.OUTPUT_TIME_STEP); + ENDING_TIME = outputTimes.back(); + } else if (!inputBreakdown.timeCourseSettings.TIME_POINTS.empty()) { + for (auto elem : inputBreakdown.timeCourseSettings.TIME_POINTS) outputTimes.push_back(elem); } - string name; - while (!inputstream.eof()) { - name = ""; - inputstream >> name; - if (name.empty()) { - continue; - } - if (name == "SOLVER") { - inputstream >> name; - if (name != getSolverName()) { - throw "Wrong solver"; - } - } else if (name == "STARTING_TIME") { - inputstream >> STARTING_TIME; - } else if (name == "ENDING_TIME") { - inputstream >> ENDING_TIME; - } else if (name == "RELATIVE_TOLERANCE") { - inputstream >> RelativeTolerance; - } else if (name == "ABSOLUTE_TOLERANCE") { - inputstream >> AbsoluteTolerance; - } else if (name == "MAX_TIME_STEP") { - inputstream >> maxTimeStep; - } else if (name == "KEEP_EVERY") { - inputstream >> keepEvery; - } else if (name == "OUTPUT_TIME_STEP") { - double outputTimeStep = 0.0; - inputstream >> outputTimeStep; - double timePoint = 0.0; - int count = 1; - while (STARTING_TIME + count * outputTimeStep < ENDING_TIME + 1E-12 * ENDING_TIME) { - timePoint = STARTING_TIME + count * outputTimeStep; - outputTimes.push_back(timePoint); - count ++; - } - ENDING_TIME = outputTimes[outputTimes.size() - 1]; - } else if (name == "OUTPUT_TIMES") { - int totalNumTimePoints; - double timePoint; - inputstream >> totalNumTimePoints; - for (int i = 0; i < totalNumTimePoints; i ++) { - inputstream >> timePoint; - if (timePoint > STARTING_TIME && timePoint <= ENDING_TIME) { - outputTimes.push_back(timePoint); - } - } - if (outputTimes[outputTimes.size() - 1] < ENDING_TIME) { - outputTimes.push_back(ENDING_TIME); - } - } else if (name == "DISCONTINUITIES") { - readDiscontinuities(inputstream); - } else if (name == "NUM_PARAMETERS") { - inputstream >> NPARAM; - paramNames = new string[NPARAM]; - for (int i = 0; i < NPARAM; i ++) { - inputstream >> paramNames[i]; - } - } else if (name == "NUM_EQUATIONS") { - inputstream >> NEQ; - variableNames = new string[NEQ]; - initialConditionExpressions = new VCell::Expression*[NEQ]; - readEquations(inputstream); - } else if (name == "EVENTS") { - readEvents(inputstream); - } else { - string msg = "Unexpected token \"" + name + "\" in the input file!"; - throw VCell::Exception(msg); - } + numDiscontinuities = inputBreakdown.discontinuitiesSettings.DISCONTINUITIES.size(); + odeDiscontinuities = new OdeDiscontinuity*[numDiscontinuities]; + for (int i = 0; i < numDiscontinuities; i++) { + odeDiscontinuities[i] = new OdeDiscontinuity(); + odeDiscontinuities[i]->discontinuitySymbol = inputBreakdown.discontinuitiesSettings.DISCONTINUITIES[i].symbol; + odeDiscontinuities[i]->discontinuityExpression = inputBreakdown.discontinuitiesSettings.DISCONTINUITIES[i].discontinuityExpression; + odeDiscontinuities[i]->rootFindingExpression = inputBreakdown.discontinuitiesSettings.DISCONTINUITIES[i].rootFindingExpression; } - initialize(); - } catch (char* ex) { - throw VCell::Exception(string("VCellSundialsSolver::readInput() : ") + ex); - } catch (VCell::Exception& ex) { - throw VCell::Exception(string("VCellSundialsSolver::readInput() : ") + ex.getMessage()); - } catch (...) { - throw "VCellSundialsSolver::readInput() : caught unknown exception"; - } -} + NUM_PARAMETERS = inputBreakdown.modelSettings.PARAMETER_NAMES.size(); + paramNames = new std::string[NUM_PARAMETERS]; + for (int i = 0; i < NUM_PARAMETERS; i++) {paramNames[i] = inputBreakdown.modelSettings.PARAMETER_NAMES[i];} + NUM_EQUATIONS = inputBreakdown.modelSettings.VARIABLE_NAMES.size(); + variableNames = new std::string[NUM_EQUATIONS]; + initialConditionExpressions = new VCell::Expression*[NUM_EQUATIONS]; + readEquations(inputBreakdown); + numEvents = inputBreakdown.eventSettings.EVENTS.size(); + events = new Event*[numEvents]; + for (int i = 0; i < inputBreakdown.eventSettings.EVENTS.size(); i++) { + events[i] = new Event(); + events[i]->name = inputBreakdown.eventSettings.EVENTS[i].eventName; + events[i]->bUseValuesAtTriggerTime = inputBreakdown.eventSettings.EVENTS[i].shouldUseValuesAtTriggerTime; + try { + events[i]->triggerExpression = new VCell::Expression(inputBreakdown.eventSettings.EVENTS[i].triggerExpression); + } catch (VCell::Exception &ex) { + throw VCell::Exception(std::string("trigger expression") + " " + ex.getMessage()); + } -void VCellSundialsSolver::readEvents(std::istream& inputstream) { - string token; - - inputstream >> numEvents; - events = new Event*[numEvents]; - for (int i = 0; i < numEvents; i ++) { - events[i] = new Event(); - while (true) { - inputstream >> token; - if (token == "EVENT") { - inputstream >> events[i]->name; - } else if (token == "TRIGGER") { - try { - events[i]->triggerExpression = readExpression(inputstream); - } catch (VCell::Exception& ex) { - throw VCell::Exception(string("trigger expression") + " " + ex.getMessage()); - } - } else if (token == "DELAY") { - inputstream >> token; - events[i]->bUseValuesAtTriggerTime = token == "true"; - try { - events[i]->delayDurationExpression = readExpression(inputstream); - } catch (VCell::Exception& ex) { - throw VCell::Exception(string("delay duration expression") + " " + ex.getMessage()); - } - } else if (token == "EVENTASSIGNMENTS") { - inputstream >> events[i]->numEventAssignments; - events[i]->eventAssignments = new EventAssignment*[events[i]->numEventAssignments]; - for (int j = 0; j < events[i]->numEventAssignments; j ++) { - EventAssignment* ea = new EventAssignment(); - inputstream >> ea->varIndex; - try { - ea->assignmentExpression = readExpression(inputstream); - } catch (VCell::Exception& ex) { - throw VCell::Exception(string("event assignment expression") + " " + ex.getMessage()); - } - events[i]->eventAssignments[j] = ea; - } - break; - } else { - string msg = "Unexpected token \"" + token + "\" in the input file!"; - throw VCell::Exception(msg); + try { + if (!inputBreakdown.eventSettings.EVENTS[i].delayDurationExpression.empty()) + events[i]->delayDurationExpression = new VCell::Expression(inputBreakdown.eventSettings.EVENTS[i].delayDurationExpression); + } catch (VCell::Exception &ex) { + throw VCell::Exception(std::string("delay duration expression") + " " + ex.getMessage()); + } + + for (auto [varIndex, assignmentExpression]: inputBreakdown.eventSettings.EVENTS[i].eventAssignments) { + EventAssignment* eventAssignment = new EventAssignment(); + eventAssignment->varIndex = varIndex; + eventAssignment->assignmentExpression = new VCell::Expression(assignmentExpression); + events[i]->eventAssignmentsVec->emplace_back(eventAssignment); } } + initialize(); + } catch (char *ex) { throw VCell::Exception(std::string("VCellSundialsSolver::readInput() : ") + ex); } catch ( + VCell::Exception &ex) { + throw VCell::Exception(std::string("VCellSundialsSolver::readInput() : ") + ex.getMessage()); } } -void VCellSundialsSolver::readDiscontinuities(std::istream& inputstream) { - inputstream >> numDiscontinuities; - odeDiscontinuities = new OdeDiscontinuity*[numDiscontinuities]; - string line; - string exp; - for (int i = 0; i < numDiscontinuities; i ++) { - OdeDiscontinuity* od = new OdeDiscontinuity; - inputstream >> od->discontinuitySymbol; - - line = ""; - getline(inputstream, line); - string::size_type pos = line.find(";"); - if (pos == string::npos) { - string msg = string("discontinuity expression ") + BAD_EXPRESSION_MSG; - throw VCell::Exception(msg); - } - exp = line.substr(0, pos + 1); - trimString(exp); - od->discontinuityExpression = new VCell::Expression(exp); - - exp = line.substr(pos + 1); - trimString(exp); - if (*(exp.end() - 1) != ';') { - string msg = string("discontinuity root expression ") + BAD_EXPRESSION_MSG; - throw VCell::Exception(msg); - } - od->rootFindingExpression = new VCell::Expression(exp); - odeDiscontinuities[i] = od; - } -} void VCellSundialsSolver::initialize() { // add parameters to symbol table - numAllSymbols = 1 + NEQ + NPARAM + numDiscontinuities; - allSymbols = new string[numAllSymbols]; // t, variables, parameters, discontinuities + numAllSymbols = 1 + NUM_EQUATIONS + NUM_PARAMETERS + numDiscontinuities; + allSymbols = new std::string[numAllSymbols]; // t, variables, parameters, discontinuities //t allSymbols[0] = "t"; odeResultSet->addColumn("t"); // variables - for (int i = 0 ; i < NEQ; i ++) { + for (int i = 0; i < NUM_EQUATIONS; i++) { allSymbols[1 + i] = variableNames[i]; odeResultSet->addColumn(variableNames[i]); } // parameters - for (int i = 0 ; i < NPARAM; i ++) { - allSymbols[1 + NEQ + i] = paramNames[i]; - } + for (int i = 0; i < NUM_PARAMETERS; i++) { allSymbols[1 + NUM_EQUATIONS + i] = paramNames[i]; } //discontinuities - for (int i = 0 ; i < numDiscontinuities; i ++) { - allSymbols[1 + NEQ + NPARAM + i] = odeDiscontinuities[i]->discontinuitySymbol; + for (int i = 0; i < numDiscontinuities; i++) { + allSymbols[1 + NUM_EQUATIONS + NUM_PARAMETERS + i] = odeDiscontinuities[i]->discontinuitySymbol; } // default symbol table has variables, parameters and discontinuities. - defaultSymbolTable = new SimpleSymbolTable(allSymbols, numAllSymbols); + defaultSymbolTable = new SimpleSymbolTable(allSymbols, numAllSymbols); // initial condition can only be function of parameters. - initialConditionSymbolTable = new SimpleSymbolTable(allSymbols + 1 + NEQ, NPARAM); - for (int i = 0; i < NEQ; i ++) { - initialConditionExpressions[i]->bindExpression(initialConditionSymbolTable); - } + initialConditionSymbolTable = new SimpleSymbolTable(allSymbols + 1 + NUM_EQUATIONS, NUM_PARAMETERS); + for (int i = 0; i < NUM_EQUATIONS; i++) { initialConditionExpressions[i]->bindExpression(initialConditionSymbolTable); } if (numDiscontinuities > 0) { - rootsFound = new int[2*numDiscontinuities]; + rootsFound = new int[2 * numDiscontinuities]; discontinuityValues = new double[numDiscontinuities]; // discontinuities can't be function of discontinuity symbols - discontinuitySymbolTable = new SimpleSymbolTable(allSymbols, 1 + NEQ + NPARAM); - for (int i = 0; i < numDiscontinuities; i ++) { + discontinuitySymbolTable = new SimpleSymbolTable(allSymbols, 1 + NUM_EQUATIONS + NUM_PARAMETERS); + for (int i = 0; i < numDiscontinuities; i++) { odeDiscontinuities[i]->discontinuityExpression->bindExpression(discontinuitySymbolTable); odeDiscontinuities[i]->rootFindingExpression->bindExpression(discontinuitySymbolTable); } } - if (numEvents > 0) { - for (int i = 0; i < numEvents; i ++) { - events[i]->bind(defaultSymbolTable); - } - } - try { - values = new realtype[1 + NEQ + NPARAM + numDiscontinuities]; - tempRowData = new realtype[1 + NEQ]; - } catch (...) { - throw "Out of Memory"; - } + if (numEvents > 0) { for (int i = 0; i < numEvents; i++) { events[i]->bind(defaultSymbolTable); } } + values = new realtype[1 + NUM_EQUATIONS + NUM_PARAMETERS + numDiscontinuities]; + tempRowData = new realtype[1 + NUM_EQUATIONS]; - y = N_VNew_Serial(NEQ); - if (y == 0) { - throw "Out of Memory"; - } + y = N_VNew_Serial(NUM_EQUATIONS); + if (y == nullptr) { throw "Out of Memory"; } } bool VCellSundialsSolver::updateDiscontinuities(realtype t, bool bOnRootReturn) { - if (numDiscontinuities == 0) { - return false; - } + if (numDiscontinuities == 0) { return false; } bool bUpdated = false; updateTandVariableValues(t, y); - for (int i = 0; i < numDiscontinuities; i ++) { - std::cout << odeDiscontinuities[i]->discontinuitySymbol << " " << odeDiscontinuities[i]->discontinuityExpression->infix() << " " << discontinuityValues[i]; + for (int i = 0; i < numDiscontinuities; i++) { + std::cout << odeDiscontinuities[i]->discontinuitySymbol << " " + << odeDiscontinuities[i]->discontinuityExpression->infix() + << " " << discontinuityValues[i]; if (bOnRootReturn) { if (rootsFound[2 * i] && rootsFound[2 * i + 1]) { std::cout << " inverted "; @@ -417,66 +292,58 @@ bool VCellSundialsSolver::updateDiscontinuities(realtype t, bool bOnRootReturn) std::cout << " evaluated "; double oldValue = discontinuityValues[i]; discontinuityValues[i] = odeDiscontinuities[i]->discontinuityExpression->evaluateVector(values); - if (oldValue != discontinuityValues[i]) { - bUpdated = true; - } - } else { - std::cout << " nonroot "; - } + if (oldValue != discontinuityValues[i]) { bUpdated = true; } + } else { std::cout << " nonroot "; } } else { std::cout << " evaluated after event execution "; double oldValue = discontinuityValues[i]; discontinuityValues[i] = odeDiscontinuities[i]->discontinuityExpression->evaluateVector(values); - if (oldValue != discontinuityValues[i]) { - bUpdated = true; - } + if (oldValue != discontinuityValues[i]) { bUpdated = true; } } std::cout << discontinuityValues[i] << std::endl; } std::cout << std::endl; // copy discontinuity values to values to evaluate RHS - if (bUpdated) { - memcpy(values + 1 + NEQ + NPARAM, discontinuityValues, numDiscontinuities * sizeof(double)); - } + if (bUpdated) { memcpy(values + 1 + NUM_EQUATIONS + NUM_PARAMETERS, discontinuityValues, numDiscontinuities * sizeof(double)); } return bUpdated; } void VCellSundialsSolver::initDiscontinuities() { - if (numDiscontinuities == 0) { - return; - } + if (numDiscontinuities == 0) { return; } updateTandVariableValues(STARTING_TIME, y); - // init discontinuities - for (int i = 0; i < numDiscontinuities; i ++) { + // init discontinuities + for (int i = 0; i < numDiscontinuities; i++) { discontinuityValues[i] = odeDiscontinuities[i]->discontinuityExpression->evaluateVector(values); } // copy discontinuity values to values to evaluate RHS - memcpy(values + 1 + NEQ + NPARAM, discontinuityValues, numDiscontinuities * sizeof(double)); + memcpy(values + 1 + NUM_EQUATIONS + NUM_PARAMETERS, discontinuityValues, numDiscontinuities * sizeof(double)); } -void VCellSundialsSolver::checkDiscontinuityConsistency() { - if (numDiscontinuities == 0) { - return; - } +void VCellSundialsSolver::checkDiscontinuityConsistency() const { + if (numDiscontinuities == 0) { return; } - for (int i = 0; i < numDiscontinuities; i ++) { + for (int i = 0; i < numDiscontinuities; i++) { double realValue = odeDiscontinuities[i]->discontinuityExpression->evaluateVector(values); if (discontinuityValues[i] != realValue) { - stringstream ss; - ss << "at time " << values[0] << ", discontinuity " << odeDiscontinuities[i]->discontinuityExpression->infix() << " evaluated to " << (realValue ? "TRUE" : "FALSE") << ", solver assumed " << (discontinuityValues[i] ? "TRUE" : "FALSE") << std::endl; + std::stringstream ss; + ss << "at time " << values[0] << ", discontinuity " + << odeDiscontinuities[i]->discontinuityExpression->infix() << " evaluated to " + << (realValue ? "TRUE" : "FALSE") << ", solver assumed " << (discontinuityValues[i] ? "TRUE" : "FALSE") + << std::endl; throw ss.str(); } } } void VCellSundialsSolver::solveInitialDiscontinuities(double t) { - std::cout << "------------------solveInitialDiscontinuities--at-time-" << t << "--------------------------" << std::endl; + std::cout << "------------------solveInitialDiscontinuities--at-time-" << t << "--------------------------" << + std::endl; bool bFoundRoot = false; - string roots_at_initial_str = ""; + std::string roots_at_initial_str; updateTandVariableValues(t, y); - for (int i = 0; i < numDiscontinuities; i ++) { + for (int i = 0; i < numDiscontinuities; i++) { double v = odeDiscontinuities[i]->rootFindingExpression->evaluateVector(values); if (fabs(v) < AbsoluteTolerance) { roots_at_initial_str += odeDiscontinuities[i]->discontinuityExpression->infix() + "; "; @@ -485,23 +352,23 @@ void VCellSundialsSolver::solveInitialDiscontinuities(double t) { } if (bFoundRoot) { - std::cout << "solveInitialDiscontinuities() : roots found at time " << t << "; " << roots_at_initial_str << std::endl; + std::cout << "solveInitialDiscontinuities() : roots found at time " << t << "; " << roots_at_initial_str << + std::endl; int count = 0; - int maxCount = (int)pow(2.0, numDiscontinuities); + int maxCount = (int) pow(2.0, numDiscontinuities); while (count < maxCount) { - try { - if (!fixInitialDiscontinuities(t)) { - break; - } - } catch (const char* err) { - stringstream str; - str << "found discontinuities at time " << t << " but unable to initialize : " << err << "\nDiscontinuities at time 0 are : " << roots_at_initial_str; + try { if (!fixInitialDiscontinuities(t)) { break; } } catch (const char *err) { + std::stringstream str; + str << "found discontinuities at time " << t << " but unable to initialize : " << err << + "\nDiscontinuities at time 0 are : " << roots_at_initial_str; throw str.str(); } - count ++; + count++; } if (count >= maxCount) { - string str = "found discontinuities at time 0 but unable to initialize due to max iterations.\nDiscontinuities at time 0 are : " + roots_at_initial_str; + std::string str = + "found discontinuities at time 0 but unable to initialize due to max iterations.\nDiscontinuities at time 0 are : " + + roots_at_initial_str; throw str; } } @@ -512,16 +379,16 @@ void VCellSundialsSolver::printVariableValues(realtype t) { updateTandVariableValues(t, y); std::cout << "variable values are" << std::endl; std::cout << "t " << values[0] << std::endl; - for (int i = 0; i < NEQ; i ++) { - std::cout << variableNames[i] << " " << values[i + 1] << std::endl; - } + for (int i = 0; i < NUM_EQUATIONS; i++) { std::cout << variableNames[i] << " " << values[i + 1] << std::endl; } std::cout << std::endl; } void VCellSundialsSolver::printDiscontinuityValues() { std::cout << std::endl << "discontinuities values are" << std::endl; - for (int i = 0; i < numDiscontinuities; i ++) { - std::cout << odeDiscontinuities[i]->discontinuitySymbol << " " << odeDiscontinuities[i]->discontinuityExpression->infix() << " " << discontinuityValues[i] << std::endl; + for (int i = 0; i < numDiscontinuities; i++) { + std::cout << odeDiscontinuities[i]->discontinuitySymbol << " " << odeDiscontinuities[i]->discontinuityExpression + ->infix() << " " << + discontinuityValues[i] << std::endl; } std::cout << std::endl; } @@ -531,7 +398,7 @@ int VCellSundialsSolver::RootFn(realtype t, N_Vector y, realtype *gout) { //cout << "RootFn " << endl; //printVariableValues(); - for (int i = 0; i < numDiscontinuities; i ++) { + for (int i = 0; i < numDiscontinuities; i++) { double r = odeDiscontinuities[i]->rootFindingExpression->evaluateVector(values); if (r == 0) { gout[2 * i] = 1e-200; @@ -539,105 +406,118 @@ int VCellSundialsSolver::RootFn(realtype t, N_Vector y, realtype *gout) { } else { gout[2 * i] = r; gout[2 * i + 1] = r; - } + } //cout << "gout[" << i << "]=" << gout[i] << endl; - } + } return 0; } void VCellSundialsSolver::testEventTriggers(realtype Time) { - if (numEvents == 0) { - return; - } + if (numEvents == 0) { return; } updateTandVariableValues(Time, y); - for (int i = 0; i < numEvents; i ++) { + + std::vector eventExecutions; + for (int i = 0; i < numEvents; i++) { bool oldTriggerValue = events[i]->triggerValue; bool newTriggerValue = events[i]->triggerExpression->evaluateVector(values) != 0.0; events[i]->triggerValue = newTriggerValue; if (!oldTriggerValue && newTriggerValue) { // triggered - EventExecution* ee = new EventExecution(events[i]); - ee->exeTime = Time; + eventExecutions.emplace_back(new EventExecution(events[i])); + eventExecutions.back()->timeToExecuteEventAt = Time; if (events[i]->hasDelay()) { - ee->exeTime = Time + events[i]->delayDurationExpression->evaluateVector(values); + eventExecutions.back()->timeToExecuteEventAt = Time + events[i]->delayDurationExpression->evaluateVector(values); } if (events[i]->bUseValuesAtTriggerTime) { - ee->targetValues = new double[events[i]->numEventAssignments]; - for (int j = 0; j < events[i]->numEventAssignments; j ++) { - ee->targetValues[j] = events[i]->eventAssignments[j]->assignmentExpression->evaluateVector(values); + const unsigned long numEventAssignments = events[i]->eventAssignmentsVec->size(); + eventExecutions.back()->targetValues = new double[numEventAssignments]; + for (unsigned long j = 0; j < numEventAssignments; j++) { + eventExecutions.back()->targetValues[j] = events[i]->eventAssignmentsVec->at(j)->assignmentExpression->evaluateVector(values); } } - bool bInserted = false; - for (std::list::iterator iter = eventExeList.begin(); iter != eventExeList.end(); iter ++) { - if ((*iter)->exeTime > ee->exeTime) { - eventExeList.insert(iter, ee); // sort them by execution time - bInserted = true; - break; - } - } - if (!bInserted) { - eventExeList.push_back(ee); - } } } + auto compLambda = [](const EventExecution *e1, const EventExecution *e2) { + return e1->timeToExecuteEventAt < e2->timeToExecuteEventAt; + }; + std::ranges::sort(eventExecutions, compLambda); + std::list eventExecutionsSorted(std::make_move_iterator(eventExecutions.begin()), std::make_move_iterator(eventExecutions.end())); + eventExeList.splice(eventExeList.end(), eventExecutionsSorted); } -bool VCellSundialsSolver::executeEvents(realtype Time) { - if (numEvents == 0) { - return false; - } - testEventTriggers(Time); +bool VCellSundialsSolver::executeEvents(const realtype realTimeVar) { + if (numEvents == 0) { return false; } + testEventTriggers(realTimeVar); static double epsilon = 1e-15; bool bExecuted = false; - while (eventExeList.size() > 0) { - std::list::iterator iter = eventExeList.begin(); - EventExecution* ee = *iter; - - if (ee->exeTime > Time + epsilon) { // not time yet - return bExecuted; - } - - if (fabs(ee->exeTime - Time) < epsilon) { // execute - updateTandVariableValues(Time, y); - double* y_data = NV_DATA_S(y); // assign the values - for (int i = 0; i < ee->event0->numEventAssignments; i ++) { - EventAssignment* ea = ee->event0->eventAssignments[i]; - if (ee->event0->bUseValuesAtTriggerTime) { - y_data[ea->varIndex] = ee->targetValues[i]; - } else { + while (!eventExeList.empty()) { + auto iter = eventExeList.begin(); + EventExecution *ee = *iter; + + if (ee->timeToExecuteEventAt > realTimeVar + epsilon) return bExecuted; // not time yet + + if (fabs(ee->timeToExecuteEventAt - realTimeVar) < epsilon) { // execute + updateTandVariableValues(realTimeVar, y); + double *y_data = NV_DATA_S(y); // assign the values + for (int i = 0; i < ee->event0->eventAssignmentsVec->size(); i++) { + EventAssignment *ea = ee->event0->eventAssignmentsVec->at(i); + if (ee->event0->bUseValuesAtTriggerTime) { y_data[ea->varIndex] = ee->targetValues[i]; } else { y_data[ea->varIndex] = ea->assignmentExpression->evaluateVector(values); } } - std::cout << std::endl << "Executed event " << ee->event0->name << " at time " << Time << std::endl; + std::cout << std::endl << "Executed event " << ee->event0->name << " at time " << realTimeVar << std::endl; eventExeList.pop_front(); // delete from the list delete ee; bExecuted = true; - testEventTriggers(Time); // retest all triggers again. - } else if (ee->exeTime < Time) { - stringstream ss; - ss << "missed Event '" << ee->event0->name << "' with trigger " << ee->event0->triggerExpression->infix() - << ", scheduled time = " << ee->exeTime << ", current time = " << Time << std::endl; + testEventTriggers(realTimeVar); // retest all triggers again. + } else if (ee->timeToExecuteEventAt < realTimeVar) { + std::stringstream ss; + ss << "missed Event '" << ee->event0->name << "' with trigger " << ee->event0->triggerExpression->infix() + << ", scheduled time = " << ee->timeToExecuteEventAt << ", current time = " << realTimeVar << std::endl; throw ss.str(); } - } return bExecuted; } double VCellSundialsSolver::getNextEventTime() { - if (eventExeList.size() > 0) { - std::list::iterator iter = eventExeList.begin(); - EventExecution* ee = *iter; - return ee->exeTime; + if (!eventExeList.empty()) { + auto iter = eventExeList.begin(); + EventExecution *ee = *iter; + return ee->timeToExecuteEventAt; } return DBL_MAX; } void VCellSundialsSolver::checkStopRequested(double time, long numIterations) { -#ifdef USE_MESSAGING - if (SimulationMessaging::getInstVar()->isStopRequested()) { - throw StoppedByUserException("stopped by user"); - } -#endif + #ifdef USE_MESSAGING + auto instVar = SimulationMessaging::getInstVar(); + if (nullptr == instVar) return; + if (instVar->isStopRequested()) { throw StoppedByUserException("stopped by user"); } + #endif +} + +/** * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Static Methods + * * * * * * * * * * * * * * * * * * * * * * * * * * * **/ + +VCell::Expression *VCellSundialsSolver::readExpression(std::istream &inputstream) { + std::string exp; + getline(inputstream, exp); + trimString(exp); + if (*(exp.end() - 1) != ';') { throw VCell::Exception(BAD_EXPRESSION_MSG); } + return new VCell::Expression(exp); +} + +/** * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Local Helper Functions + * * * * * * * * * * * * * * * * * * * * * * * * * * * **/ +static void trimString(std::string &str) { + std::string::size_type pos = str.find_last_not_of(" \r\n"); + if (pos != std::string::npos) { + str.erase(pos + 1); + pos = str.find_first_not_of(" \r\n"); + if (pos != std::string::npos) { str.erase(0, pos); } + } else { str.erase(str.begin(), str.end()); } } diff --git a/IDAWin/VCellSundialsSolver.h b/IDAWin/VCellSundialsSolver.h index a0dab9b1c..889a94f28 100644 --- a/IDAWin/VCellSundialsSolver.h +++ b/IDAWin/VCellSundialsSolver.h @@ -5,193 +5,178 @@ #include #include #include -#include -#include - #include - - #include #include -#include +#include "VCellSolver.h" -class SymbolTable; -class OdeResultSet; +class SymbolTable; // Defined in SymbolTable.h +class OdeResultSet; // Defined in OdeResultSet.h +struct Event; +struct EventAssignment; +struct EventExecution; +struct OdeDiscontinuity; #define bytesPerSample 25 -#define MaxFileSizeBytes 1000000000 /* 1 gigabyte */ +#define MaxFileSizeBytes 1000000000 /* 1 gigabyte */ #define BAD_EXPRESSION_MSG " is not terminated by ';'" #define MAX_NUM_EVENTS_DISCONTINUITIES_EVAL 50 +class VCellSundialsSolver : public VCellSolver { + public: + VCellSundialsSolver(); + virtual ~VCellSundialsSolver(); + + // void readInput(std::istream &inputFileStream); + + void configureFromInput(VCellSolverInputBreakdown& inputBreakdown) override; + + [[nodiscard]] OdeResultSet *getResultSet() const { return this->odeResultSet; } + [[nodiscard]] int getNumEquations() const { return this->NUM_EQUATIONS; } + [[nodiscard]] VCell::Expression **getInitialConditionExpressions() const { return this->initialConditionExpressions; } + void setStartingTime(const realtype newStartingTime) { this->STARTING_TIME = newStartingTime; } + void setEndingTime(const realtype newEndingTime) { this->ENDING_TIME = newEndingTime; } + //void setOutputTimes(int count, double* newOutputTimes); + [[nodiscard]] SymbolTable *getSymbolTable() const { return this->defaultSymbolTable; } + + static void checkStopRequested(double, long); + + protected: + // 0 : t + // 1 ~ N : variable values + // N+1 ~ N+NPARAM : parameter values + // N+NPARAM+1 ~ N+NPARAM+numDiscontinuites : discontinuity values + realtype *values; + // 0 ~ N-1 : equations + VCell::Expression **initialConditionExpressions; + SymbolTable *initialConditionSymbolTable; + OdeResultSet *odeResultSet; // mainly for parameter optimization use, but it also stores column names + + void *solver; // the memory for solver + std::string recoverableErrMsg; + + int NUM_EQUATIONS; + int NUM_PARAMETERS; + realtype STARTING_TIME; + realtype ENDING_TIME; + realtype RelativeTolerance; + realtype AbsoluteTolerance; + long keepEvery; + double maxTimeStep; + std::vector outputTimes; + double *tempRowData; // data for current time to be written to output file and to be added to odeResultSet + + int numDiscontinuities; + OdeDiscontinuity **odeDiscontinuities; + SymbolTable *discontinuitySymbolTable; + double *discontinuityValues; + int *rootsFound; + + std::string *paramNames; + std::string *variableNames; // variables + std::string *allSymbols; + int numAllSymbols; + SymbolTable *defaultSymbolTable; + N_Vector y; + + static VCell::Expression *readExpression(std::istream &inputstream); + + void writeData(double currTime, FILE *outputFile); + virtual void updateTempRowData(double currTime); + void writeFileData(FILE *outputFile); + void writeFileHeader(FILE *outputFile); + void printProgress(double currTime, double &lastPercentile, clock_t &lastTime, double increment, FILE *outputFile) const; + virtual void readEquations(VCellSolverInputBreakdown& inputBreakdown) = 0; + virtual void initialize(); + void initDiscontinuities(); + bool updateDiscontinuities(realtype t, bool bOnRootReturn); + void checkDiscontinuityConsistency() const; + void solveInitialDiscontinuities(double t); + virtual bool fixInitialDiscontinuities(double t) =0; + void printVariableValues(realtype t); + void printDiscontinuityValues(); + virtual void updateTandVariableValues(realtype t, N_Vector y) =0; + int RootFn(realtype t, N_Vector y, realtype *gout); + virtual std::string getSolverName() =0; + virtual VCellSolverTypes getSolverType() =0; + bool executeEvents(realtype realTimeVar); + double getNextEventTime(); + + private: + Event **events; + int numEvents; + std::list eventExeList; + + // void readEvents(std::istream &inputstream); + void testEventTriggers(realtype Time); +}; + struct EventAssignment { int varIndex; - VCell::Expression* assignmentExpression; + VCell::Expression *assignmentExpression; - ~EventAssignment() { - delete assignmentExpression; - } - void bind(SymbolTable* symbolTable) { - assignmentExpression->bindExpression(symbolTable); + ~EventAssignment() { delete assignmentExpression; } + void bind(SymbolTable *symbolTable) const { assignmentExpression->bindExpression(symbolTable); } +}; + +struct EventExecution { + realtype timeToExecuteEventAt; + Event *event0; + double *targetValues; + + EventExecution(Event *e) { + this->timeToExecuteEventAt = RCONST(0.0); + this->event0 = e; + this->targetValues = nullptr; } + + ~EventExecution() { delete this->targetValues; } }; struct Event { - string name; - VCell::Expression* triggerExpression; + std::string name; + VCell::Expression *triggerExpression; bool bUseValuesAtTriggerTime; - VCell::Expression* delayDurationExpression; - int numEventAssignments; - EventAssignment** eventAssignments; - bool triggerValue; + VCell::Expression *delayDurationExpression; + std::vector *eventAssignmentsVec; + bool triggerValue; Event() { - bUseValuesAtTriggerTime = false; - triggerExpression = 0; - triggerValue = false; - delayDurationExpression = 0; - eventAssignments = 0; - } - ~Event() { - delete triggerExpression; - delete delayDurationExpression; - for (int i = 0; i < numEventAssignments; i ++) { - delete eventAssignments[i]; - } - delete[] eventAssignments; + this->bUseValuesAtTriggerTime = false; + this->triggerExpression = nullptr; + this->triggerValue = false; + this->delayDurationExpression = nullptr; + this->eventAssignmentsVec = new std::vector; } - bool hasDelay() { - return delayDurationExpression != 0; - } - - void bind(SymbolTable* symbolTable) { - triggerExpression->bindExpression(symbolTable); - if (delayDurationExpression != 0) { - delayDurationExpression->bindExpression(symbolTable); - } - for (int i = 0; i < numEventAssignments; i ++) { - eventAssignments[i]->bind(symbolTable); - } + ~Event() { + delete this->triggerExpression; + delete this->delayDurationExpression; + for (const EventAssignment *elem: *this->eventAssignmentsVec) delete elem; + this->eventAssignmentsVec->clear(); + delete this->eventAssignmentsVec; } -}; -struct EventExecution { - realtype exeTime; - Event* event0; - double* targetValues; + [[nodiscard]] bool hasDelay() const { return this->delayDurationExpression != nullptr; } - EventExecution(Event* e) { - event0 = e; - targetValues = 0; - } - ~EventExecution() { - delete targetValues; + void bind(SymbolTable *symbolTable) const { + this->triggerExpression->bindExpression(symbolTable); + if (this->delayDurationExpression != nullptr) { this->delayDurationExpression->bindExpression(symbolTable); } + for (const EventAssignment *elem: *this->eventAssignmentsVec) { elem->bind(symbolTable); } } }; struct OdeDiscontinuity { - string discontinuitySymbol; - VCell::Expression* discontinuityExpression; - VCell::Expression* rootFindingExpression; + std::string discontinuitySymbol; + VCell::Expression *discontinuityExpression; + VCell::Expression *rootFindingExpression; ~OdeDiscontinuity() { - delete discontinuityExpression; - delete rootFindingExpression; + delete this->discontinuityExpression; + delete this->rootFindingExpression; } }; -class VCellSundialsSolver { -public: - VCellSundialsSolver(); - virtual ~VCellSundialsSolver(); - - void readInput(std::istream& inputstream); - virtual void solve(double* paramValues=0, bool bPrintProgress=false, FILE* outputFile=0, void (*checkStopRequested)(double, long)=0) = 0; - OdeResultSet* getResultSet() { return odeResultSet; } - int getNumEquations() { return NEQ; } - VCell::Expression** getInitialConditionExpressions() { return initialConditionExpressions; } - void setStartingTime(realtype newStartingTime) { STARTING_TIME = newStartingTime; } - void setEndingTime(realtype newEndingTime) { ENDING_TIME = newEndingTime; } - void setOutputTimes(int count, double* newOutputTimes); - SymbolTable* getSymbolTable() { return defaultSymbolTable;} - - static void checkStopRequested(double, long); - -protected: - // 0 : t - // 1 ~ N : variable values - // N+1 ~ N+NPARAM : parameter values - // N+NPARAM+1 ~ N+NPARAM+numDiscontinuites : discontinuity values - realtype* values; - // 0 ~ N-1 : equations - VCell::Expression** initialConditionExpressions; - SymbolTable* initialConditionSymbolTable; - OdeResultSet* odeResultSet; // mainly for parameter optimization use but it also stores column names - - void* solver; // the memory for solver - string recoverableErrMsg; - - int NEQ; - int NPARAM; - realtype STARTING_TIME; - realtype ENDING_TIME; - realtype RelativeTolerance; - realtype AbsoluteTolerance; - long keepEvery; - double maxTimeStep; - vector outputTimes; - double* tempRowData; // data for current time to be written to output file and to be added to odeResultSet - - int numDiscontinuities; - OdeDiscontinuity** odeDiscontinuities; - SymbolTable* discontinuitySymbolTable; - double* discontinuityValues; - int* rootsFound; - - string* paramNames; - string* variableNames; // variables - string* allSymbols; - int numAllSymbols; - SymbolTable* defaultSymbolTable; - - N_Vector y; - void writeData(double currTime, FILE* outputFile); - virtual void updateTempRowData(double currTime); - void writeFileData(FILE* outputFile); - void writeFileHeader(FILE* outputFile); - void printProgress(double currTime, double& lastPercentile, clock_t& lastTime, double increment, FILE* outputFile); - - void readDiscontinuities(std::istream& inputstream); - virtual void readEquations(std::istream& inputstream) = 0; - virtual void initialize(); - - void initDiscontinuities(); - bool updateDiscontinuities(realtype t, bool bOnRootReturn); - void checkDiscontinuityConsistency(); - - void solveInitialDiscontinuities(double t); - virtual bool fixInitialDiscontinuities(double t)=0; - - void printVariableValues(realtype t); - void printDiscontinuityValues(); - virtual void updateTandVariableValues(realtype t, N_Vector y)=0; - - int RootFn(realtype t, N_Vector y, realtype *gout); - virtual string getSolverName()=0; - - VCell::Expression* readExpression(std::istream& inputstream); - bool executeEvents(realtype Time); - double getNextEventTime(); - -private: - Event** events; - int numEvents; - - void readEvents(std::istream& inputstream); - void testEventTriggers(realtype Time); - std::list eventExeList; -}; - #endif diff --git a/IDAWin/hello_test.cpp b/IDAWin/hello_test.cpp deleted file mode 100644 index 5a57e138f..000000000 --- a/IDAWin/hello_test.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include - -// Demonstrate some basic assertions. -TEST(HelloTest, BasicAssertions) { - // Expect two strings not to be equal. - EXPECT_STRNE("hello", "world"); - // Expect equality. - EXPECT_EQ(7 * 6, 42); -} diff --git a/IDAWin/tests/smoke/smoke.py b/IDAWin/tests/smoke/smoke.py deleted file mode 100755 index 65f4d7fee..000000000 --- a/IDAWin/tests/smoke/smoke.py +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env python3 - -import os -import posixpath -import subprocess -import sys -from pathlib import Path - - -# function to numerically compare the contents of two text files to determine approximate equality -# each line is a space delimited list of numbers, compare them to within 8 significant figures -def compare_files(file1: Path, file2: Path, tolerance: float): - with open(file1, 'r') as f1, open(file2, 'r') as f2: - for line1, line2 in zip(f1, f2): - if (line1 := line1.strip()) == (line2 := line2.strip()): - continue - array1 = [float(x) for x in line1.split()] - array2 = [float(x) for x in line2.split()] - for x, y in zip(array1, array2): - if x != y and abs(x - y) > tolerance * max(abs(x), abs(y)): - return False - return True - - -# get the directory of this script -test_dir = os.path.dirname(os.path.realpath(__file__)) -# in the path replace \ with /, D:\ with /d/ -test_dir = test_dir.replace("\\", "/") -# tell os.path.join to use / as the path separator -os.path.sep = "/" -exe = sys.argv[1] - -print(f"test_dir: {test_dir}") -print(f"exe: {exe}") - -input_file = posixpath.join(test_dir, "SimID_1489333437_0_.cvodeInput") -output_file = posixpath.join(test_dir, "SimID_1489333437_0_.ida") -expected_output_file = posixpath.join(test_dir, "SimID_1489333437_0_.ida.expected") - -if not posixpath.exists(exe): - print(f"SundialsSolverStandalone_x64 executable {exe} not found. Exiting...") - sys.exit(1) - -if not posixpath.exists(input_file): - print(f"Input file {input_file} not found. Exiting...") - sys.exit(1) - -if not posixpath.exists(expected_output_file): - print(f"Expected output file {expected_output_file} not found. Exiting...") - sys.exit(1) - -command = [exe, input_file, output_file] -print(" ".join(command)) - -try: - subprocess.check_call(command) -except subprocess.CalledProcessError: - print("SundialsSolverStandalone_x64 failed to run. Exiting...") - sys.exit(1) - -# verify that the output files exist -if not os.path.isfile(output_file): - print(f"Output file {output_file} not found. Exiting...") - sys.exit(1) - -# verify that the output files match the expected output files -if not compare_files(file1=Path(output_file), file2=Path(expected_output_file), tolerance=1e-8): - print(f"Output file {output_file} does not match expected output {expected_output_file}. Exiting...") - sys.exit(1) - -print("SundialsSolverStandalone_x64 solver completed and solution matched expected output. Exiting...") -sys.exit(0) diff --git a/README.md b/README.md index f58bedc7f..305b830b6 100644 --- a/README.md +++ b/README.md @@ -14,56 +14,56 @@ The Virtual Cell is a modeling and simulation framework for computational biolog Virtual Cell ODE [virtualcell/vcell-ode](https://github.com/virtualcell/vcell-ode) is a collection of numerical simulation libraries and protocols used to process ODEs in the Virtual Cell framework [virtualcell/vcell](https://github.com/virtualcell/vcell)). -## Building VCell ODE -There are two ways to build VCell ODE, but both start out the same way -### Step 1: Acquire the source-code -The source code can be found online at the GitHub repository. -`git clone https://github.com/virtualcell/vcell.git` +## Building VCell ODE with Conan on Windows -### Step 2: Install Dependencies -You will need to acquire a unix-style C and C++ compiler suite in order to build VCell ODE. Traditionally, this project -uses CLang + Mold, but other compiler suites may work. Additionally, you'll need to install the other dependencies for -VCell ODE, which can be done in one of two ways: +Windows builds require a native compiler. MinGW is not supported. Install Visual Studio +Build Tools with the C++ workload and Windows SDK, plus Python 3.10 or newer. Conan 2, +CMake 3.16 or newer, and Ninja 1.12 or newer are required; Conan installs CMake and +Ninja as build requirements, so they do not need to be installed separately. -#### Method 1: Conan Toolchain (Recommended) -The VCell ODE project uses the C++ dependency management system called ***conan*** to handle dependency management when -building VCell ODE. We provide a number of conan-profiles that will provide conan the information need to automatically -build the desired toolchain for cmake. +From a Visual Studio Developer PowerShell, install Conan and create a detected host +profile: -#### Method 2: Manual Dependency Installation -If you'd rather manually install all the dependencies build-tools to create VCell CLI, you'll need the following: -##### Dependencies -* If you want live messaging while the solver runs: `libcurl` (add `-DOPTION_TARGET_MESSAGING` to cmake call below) -##### Build Tools -* `cmake` to perform the build configuration -* `ninja` (or equivalent) to perform the actual build process +```powershell +py -m pip install --upgrade conan +$pythonScripts = py -c "import sysconfig; print(sysconfig.get_path('scripts'))" +$env:Path = "$pythonScripts;$env:Path" +conan profile detect --force +``` + +If PowerShell still cannot find `conan`, run the following once, then open a new +PowerShell window: + +```powershell +$pythonScripts = py -c "import sysconfig; print(sysconfig.get_path('scripts'))" +$userPath = [Environment]::GetEnvironmentVariable('Path', 'User') +[Environment]::SetEnvironmentVariable('Path', "$userPath;$pythonScripts", 'User') +``` -### Step 3: Invoke the Build -In a shell with conan and/or the other build tools in path, navigate to the project's root directory and -run the following commands (tested in bash on unix and powershell on windows) +Build the solver without messaging: -Note that if using `conan`, you'll need to define a profile. use `conan profile detect --force` to generate one automatically, -or use one of the provided ones in `/conan-profiles` [link](https://docs.conan.io/2/reference/config_files/profiles.html) -to further reading on the official `conan` website. -#### Powershell -```pwsh - mdkir build # Must do if not using conan - conan install . --output-folder build --build=missing # If building using conan's help - cd build - ./conanbuild.ps1 # If building using conan's help - cmake -B . -S .. -G "Ninja" -DCMAKE_TOOLCHAIN_FILE="conan_toolchain.cmake" -DCMAKE_BUILD_TYPE=Release - cmake --build . --config Release +```powershell +conan install . --build=missing -o "&:include_messaging=False" -s compiler.cppstd=20 +conan build . -s compiler.cppstd=20 ``` -```bash - mdkir build # must do if not building conan - conan install . --output-folder build --build=missing # If building using conan's help - cd build - ./conanbuild.sh # If building using conan's help - cmake -B . -S .. -G "Ninja" -DCMAKE_TOOLCHAIN_FILE="conan_toolchain.cmake" -DCMAKE_BUILD_TYPE=Release - cmake --build . --config Release +The recipe invokes CMake and Ninja, and produces the executable and DLL under +`build/bin`. To use the checked-in LLVM/Clang-CL profile instead, replace the install +command with: + +```powershell +conan install . ` + --profile:host conan-profiles/CI-CD/Windows-AMD64_profile.txt ` + --profile:build default ` + --build=missing -o "&:include_messaging=False" -s:h compiler.cppstd=20 +conan build . -s compiler.cppstd=20 ``` -### Step 4: Manual user/system install -Currently, VCell ODE does not have an automated installation script. You will either need to move the resulting executables -in `/build/bin` to an appropriate folder in path, or put said folder into path for your computer. \ No newline at end of file +The checked-in profile requires LLVM/Clang 21 (`clang-cl`) on `PATH` and Visual Studio +2022 Build Tools with the v143 toolset. The auto-detected MSVC profile is recommended +when using the compiler supplied by Visual Studio. The checked-in profile is configured +for Visual Studio 2022; it does not target Visual Studio 18. + +Messaging is disabled automatically for Windows Conan builds. It remains enabled by +default on Linux and macOS, where the libcurl dependency is supported. The +`include_messaging` option can be used to disable it on those platforms when needed. diff --git a/VCellMessaging/CMakeLists.txt b/VCellMessaging/CMakeLists.txt deleted file mode 100644 index 35772800b..000000000 --- a/VCellMessaging/CMakeLists.txt +++ /dev/null @@ -1,34 +0,0 @@ -project(vcellmessaging CXX) - -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/GitDescribe.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/GitDescribe.cpp" @ONLY) -list(APPEND SOURCES GitDescribe.h) - -set(HEADER_FILES - include/VCELL/SimulationMessaging.h - include/VCELL/GitDescribe.h -) - -set(SRC_FILES - src/SimulationMessaging.cpp - "${CMAKE_CURRENT_BINARY_DIR}/GitDescribe.cpp") - -include_directories(include) - -add_library(vcellmessaging ${SRC_FILES} ${HEADER_FILES}) - -target_include_directories(vcellmessaging INTERFACE - $ - $ # /include -) -if (${OPTION_TARGET_MESSAGING}) - message(STATUS "CURL_LIBRARIES = '${CURL_LIBRARIES}'") - message(STATUS "CURL_INCLUDE_DIR = '${CURL_INCLUDE_DIR}'") - - target_link_libraries(vcellmessaging ${CURL_LIBRARIES} Threads::Threads) - target_compile_definitions(vcellmessaging PUBLIC USE_MESSAGING=1) - target_include_directories(vcellmessaging PUBLIC ${CURL_INCLUDE_DIR}) -endif() - -install(TARGETS vcellmessaging - ARCHIVE DESTINATION bin - RUNTIME DESTINATION bin) diff --git a/VCellMessaging/include/VCELL/GitDescribe.h b/VCellMessaging/include/VCELL/GitDescribe.h deleted file mode 100644 index d737628a9..000000000 --- a/VCellMessaging/include/VCELL/GitDescribe.h +++ /dev/null @@ -1,10 +0,0 @@ -// -// Created by Jim Schaff on 8/11/23. -// - -#ifndef NUMERICS_GITDESCRIBE_H -#define NUMERICS_GITDESCRIBE_H - -extern const char g_GIT_DESCRIBE[]; - -#endif //NUMERICS_GITDESCRIBE_H diff --git a/VCellMessaging/include/VCELL/SimulationMessaging.h b/VCellMessaging/include/VCELL/SimulationMessaging.h deleted file mode 100644 index e5562b21a..000000000 --- a/VCellMessaging/include/VCELL/SimulationMessaging.h +++ /dev/null @@ -1,234 +0,0 @@ -#ifndef _SIMULATIONMESSAGING_H_ -#define _SIMULATIONMESSAGING_H_ - -#include -#ifdef USE_MESSAGING -#include -#include -#include - -#endif -#include - -#if (defined(_WIN32) || defined(_WIN64) ) -#include -#else -#include -#include -#include -#include -#endif - -#ifdef USE_MESSAGING -#if (!defined(_WIN32) && !defined(_WIN64) ) -#include -#else -#include -#endif - -static const int ONE_SECOND = 1000; -static const int ONE_MINUTE = 60 * ONE_SECOND; -static const int DEFAULT_TTL_HIGH = 10 * ONE_MINUTE; -static const int DEFAULT_TTL_LOW = ONE_MINUTE; -#endif - -static const int WORKEREVENT_OUTPUT_MODE_STDOUT = 0; -static const int WORKEREVENT_OUTPUT_MODE_MESSAGING = 1; - -static const int JOB_STARTING = 999; -static const int JOB_DATA = 1000; -static const int JOB_PROGRESS = 1001; -static const int JOB_FAILURE = 1002; -static const int JOB_COMPLETED = 1003; -static const int JOB_WORKER_ALIVE = 1004; - -static const int DEFAULT_PRIORITY = 0; //range 0-127, the bigger number the higher priority -static const int Message_DEFAULT_PRIORITY = 0; - -struct WorkerEvent { - int status; - double progress; - double timepoint; - char* eventMessage; - - WorkerEvent(const WorkerEvent* aWorkerEvent) { - status = aWorkerEvent->status; - progress = aWorkerEvent->progress; - timepoint = aWorkerEvent->timepoint; - eventMessage = copy(aWorkerEvent->eventMessage); - } - - WorkerEvent(int arg_status, double arg_progress, double arg_timepoint, const char *arg_eventMessage) - :status(arg_status), - progress(arg_progress), - timepoint(arg_timepoint), - eventMessage(copy(arg_eventMessage)) {} - - WorkerEvent(int arg_status, double arg_progress, double arg_timepoint) - :status(arg_status), - progress(arg_progress), - timepoint(arg_timepoint), - eventMessage(0) {} - - - WorkerEvent(int arg_status, const char* arg_eventMessage) - :status(arg_status), - progress(0), - timepoint(0), - eventMessage(copy(arg_eventMessage)) {} -private: - static char *copy(const char *in) { - if (in != 0) { - size_t len = strlen(in) + 1; - char * c = new char[len + 1]; - memset(c, 0, len); - strcpy(c, in); - return c; - } - return 0; - } -public: - - bool equals(WorkerEvent* aWorkerEvent) { - if (status != aWorkerEvent->status || progress != aWorkerEvent->progress || timepoint != aWorkerEvent->timepoint) { - return false; - } - if (eventMessage != NULL && aWorkerEvent->eventMessage != NULL && strcmp(eventMessage, aWorkerEvent->eventMessage) != 0) { - return false; - } - - if (eventMessage != NULL && aWorkerEvent->eventMessage == NULL - || eventMessage == NULL && aWorkerEvent->eventMessage != NULL) { - return false; - } - - return true; - } -}; - -class SimulationMessaging -{ -public: - virtual ~SimulationMessaging() throw(); - static SimulationMessaging* create(); - static SimulationMessaging* getInstVar(); - void start(); - void setWorkerEvent(WorkerEvent* workerEvent); - - bool isStopRequested() { - return bStopRequested; - } - - int getTaskID() { -#ifdef USE_MESSAGING - return m_taskID; -#else - return -1; -#endif - } - - int getJobIndex() { -#ifdef USE_MESSAGING - return m_jobIndex; -#else - return 0; -#endif - } -#ifdef USE_MESSAGING - static SimulationMessaging* create(const char* broker, const char* smqusername, const char* passwd, const char* qname, const char* tname, - const char* vcusername, int simKey, int jobIndex, int taskID, int ttl_low=DEFAULT_TTL_LOW, int ttl_high=DEFAULT_TTL_HIGH); - void waitUntilFinished(); - friend void* startMessagingThread(void* param); -#endif - -private: - SimulationMessaging(); - static SimulationMessaging *m_inst; - std::vector events; - int workerEventOutputMode; - - void sendStatus(); - bool bStopRequested; - /** - * is this a critical message type? - */ - bool criticalDelivery(const WorkerEvent & event) { - switch (event.status) { - case JOB_DATA: - case JOB_PROGRESS: - return false; - default: - return true; - } - } - -#ifdef USE_MESSAGING - bool bStarted; - - SimulationMessaging(const char* broker, const char* smqusername, const char* passwd, const char* qname, const char*tname, const char* vcusername, int simKey, int jobIndex, int taskID, int ttl_low=DEFAULT_TTL_LOW, int ttl_high=DEFAULT_TTL_HIGH); - - void keepAlive(); - static char* trim(char* str); - void setupConnection (); //synchronized - void cleanup(); - - char *m_broker; - char *m_smqusername; - char *m_password; - char *m_qname; - char* m_tname; - char* m_vcusername; - int m_simKey; - int m_taskID; - int m_jobIndex; - - char* m_tListener; - - char m_hostname[256]; - int m_ttl_lowPriority; - int m_ttl_highPriority; - time_t lastSentEventTime; - - const char* getStatusString(int status); - - bool lockMessaging(); - void unlockMessaging(); - void delay(int duration); - - bool lockWorkerEvent(bool bTry=false); - void unlockWorkerEvent(); - struct WorkerEventLocker { - WorkerEventLocker(SimulationMessaging &sm_, bool bTry = false) - :sm(sm_), - locked( sm.lockWorkerEvent(false)) { - } - ~WorkerEventLocker( ) { - sm.unlockWorkerEvent(); - } - SimulationMessaging &sm; - const bool locked; - }; - -#ifdef WIN32 - CRITICAL_SECTION lockForMessaging; - CRITICAL_SECTION lockForWorkerEvent; - HANDLE hNewWorkerEvent; - HANDLE hMessagingThreadEndEvent; -#else // UNIX - pthread_t newWorkerEventThread; - pthread_mutex_t mutex_messaging; - pthread_mutex_t mutex_workerEvent; - pthread_mutex_t mutex_cond_workerEvent; - pthread_cond_t cond_workerEvent; - bool bNewWorkerEvent; -#endif - -#else - //NO MESSAGING compile compatibility variant - struct WorkerEventLocker { - WorkerEventLocker(SimulationMessaging &, bool bTry = false) {} - }; -#endif -}; - -#endif // _SIMULATIONMESSAGING_H_ diff --git a/VCellMessaging/src/GitDescribe.cpp.in b/VCellMessaging/src/GitDescribe.cpp.in deleted file mode 100644 index 6010b0085..000000000 --- a/VCellMessaging/src/GitDescribe.cpp.in +++ /dev/null @@ -1,5 +0,0 @@ -// -// Created by Jim Schaff on 8/11/23. -// -#define GIT_DESCRIBE "@GIT_DESCRIBE@" -extern const char g_GIT_DESCRIBE[] = GIT_DESCRIBE; diff --git a/VCellMessaging/src/SimulationMessaging.cpp b/VCellMessaging/src/SimulationMessaging.cpp deleted file mode 100644 index cb2ee8c0c..000000000 --- a/VCellMessaging/src/SimulationMessaging.cpp +++ /dev/null @@ -1,755 +0,0 @@ -#include -#include -#include -#include -#include -using std::cerr; -using std::cout; -using std::endl; - -#include -#ifdef USE_MESSAGING -#if ( !defined(_WIN32) && !defined(_WIN64) ) // UNIX -#include -#include -#include -#include -#include -#endif - -static const char* TIMETOLIVE_PROPERTY = "JMSTimeToLive"; -static const char* DELIVERYMODE_PROPERTY = "JMSDeliveryMode"; -static const char* DELIVERYMODE_PERSISTENT_VALUE = "persistent"; -static const char* DELIVERYMODE_NONPERSISTENT_VALUE = "nonpersistent"; -static const char* PRIORITY_PROPERTY = "JMSPriority"; -static const char* PRIORITY_DEFAULT_VALUE = "5"; - -static const char* MESSAGE_TYPE_PROPERTY = "MessageType"; -static const char* MESSAGE_TYPE_WORKEREVENT_VALUE = "WorkerEvent"; - -static const char* USERNAME_PROPERTY = "UserName"; -static const char* HOSTNAME_PROPERTY = "HostName"; -static const char* SIMKEY_PROPERTY = "SimKey"; -static const char* TASKID_PROPERTY = "TaskID"; -static const char* JOBINDEX_PROPERTY = "JobIndex"; -static const char* WORKEREVENT_STATUS = "WorkerEvent_Status"; -static const char* WORKEREVENT_PROGRESS = "WorkerEvent_Progress"; -static const char* WORKEREVENT_TIMEPOINT = "WorkerEvent_TimePoint"; -static const char* WORKEREVENT_STATUSMSG = "WorkerEvent_StatusMsg"; - -static const double WORKEREVENT_MESSAGE_MIN_TIME_SECONDS = 15.0; - -#endif - -SimulationMessaging *SimulationMessaging::m_inst = NULL; - -SimulationMessaging::SimulationMessaging(){ - this->bStopRequested = false; -#ifdef USE_MESSAGING - this->m_taskID = -1; - this->bStarted = false; -#endif - this->workerEventOutputMode = WORKEREVENT_OUTPUT_MODE_STDOUT; -} - -#ifdef USE_MESSAGING -SimulationMessaging::SimulationMessaging(const char* broker, const char* smqusername, const char* passwd, const char*qname, - const char* tname, const char* vcusername, int simKey, int jobIndex, int taskID, int ttl_low, int ttl_high){ - m_broker = const_cast(broker); - m_smqusername = const_cast( smqusername ); - m_password = const_cast(passwd ); - m_qname = const_cast( qname ); - m_tname = const_cast( tname ); - - m_vcusername = const_cast( vcusername ); - m_simKey = simKey; - m_jobIndex = jobIndex; - m_taskID = taskID; - - m_ttl_lowPriority = ttl_low; - m_ttl_highPriority = ttl_high; - - curl_global_init(CURL_GLOBAL_ALL); - - { - memset(m_hostname, 0, 256); - - // get hostname -#if ( defined(_WIN32) || defined(_WIN64) ) - WSADATA wsaData; - WORD wVersionRequested = MAKEWORD( 2, 2 ); - WSAStartup( wVersionRequested, &wsaData ); -#endif - gethostname(m_hostname, 256); - //cout) << "hostname is " << m_hostname << endl; - } - - time(&lastSentEventTime); - - workerEventOutputMode = WORKEREVENT_OUTPUT_MODE_MESSAGING; - -#if ( defined(_WIN32) || defined(_WIN64) ) - InitializeCriticalSection(&lockForMessaging); - InitializeCriticalSection(&lockForWorkerEvent); -#else // UNIX - pthread_mutex_init(&mutex_messaging, NULL); - pthread_mutex_init(&mutex_workerEvent, NULL); - pthread_mutex_init(&mutex_cond_workerEvent, NULL); - pthread_cond_init(&cond_workerEvent, NULL); - bNewWorkerEvent = false; -#endif - - bStarted = false; -} -#endif - -namespace { - void cleanupWorkerEvent(WorkerEvent *we) { - delete we; - } -} - -SimulationMessaging::~SimulationMessaging() throw() -{ - if (workerEventOutputMode == WORKEREVENT_OUTPUT_MODE_STDOUT) { - return; - } - std::for_each(events.begin(), events.end( ),cleanupWorkerEvent); - /* - if (workerEvent != NULL) { - delete workerEvent; - workerEvent = NULL; - } - */ -#ifdef USE_MESSAGING - cleanup(); -#if ( defined(_WIN32) || defined(_WIN64) ) - DeleteCriticalSection(&lockForMessaging); - DeleteCriticalSection(&lockForWorkerEvent); -#else // UNIX - pthread_mutex_destroy(&mutex_messaging); - pthread_mutex_destroy(&mutex_workerEvent); - pthread_mutex_destroy(&mutex_cond_workerEvent); - pthread_cond_destroy(&cond_workerEvent); -#endif - curl_global_cleanup(); -#endif -} - -SimulationMessaging* SimulationMessaging::getInstVar() { - return m_inst; -} - -SimulationMessaging* SimulationMessaging::create() -{ - if (m_inst == 0){ - m_inst = new SimulationMessaging(); - } - return(m_inst); -} - -void SimulationMessaging::sendStatus() { - WorkerEvent * workerEvent = 0; //set to null pointer - for (;;) { - { //scope for locking mutex - WorkerEventLocker locker(*this); - if (events.size( ) > 0 ) { - workerEvent = events.front( ); - if (!events.empty()) - { - events.erase(events.begin()); - } - } - else { - return; - } - } //unlocks mutex - - if (workerEventOutputMode == WORKEREVENT_OUTPUT_MODE_STDOUT) { - switch (workerEvent->status) { - case JOB_DATA: - printf("[[[data:%lg]]]", workerEvent->timepoint); - fflush(stdout); - break; - case JOB_PROGRESS: - printf("[[[progress:%lg%%]]]", workerEvent->progress * 100.0); - fflush(stdout); - break; - case JOB_STARTING: - std::cout<< workerEvent->eventMessage << std::endl; - break; - case JOB_COMPLETED: - std::cerr << "Simulation Complete in Main() ... " << std::endl; - break; - case JOB_FAILURE: - std::cerr << workerEvent->eventMessage << std::endl; - break; - } - return; - - } -#ifdef USE_MESSAGING - /* get a curl handle */ - CURL* curl = curl_easy_init(); - if(curl) { - // Documentation for the ActiveMQ restful API is missing, must see source code - // - // https://github.com/apache/activemq/blob/master/activemq-web/src/main/java/org/apache/activemq/web/MessageServlet.java - // https://github.com/apache/activemq/blob/master/activemq-web/src/main/java/org/apache/activemq/web/MessageServletSupport.java - // - // currently, the "web" api seems to use the same credentials as the "web console" ... defaults to admin:admin. - // TODO: pass in credentials, and protect them better (consider HTTPS). - // - /* - PROPERTIES="JMSDeliveryMode=persistent&JMSTimeToLive=3000" - PROPERTIES="${PROPERTIES}&SimKey=12446271133&JobIndex=0&TaskID=0&UserName=schaff" - PROPERTIES="${PROPERTIES}&MessageType=WorkerEvent&WorkerEvent_Status=1001&WorkerEvent_StatusMsg=Running" - PROPERTIES="${PROPERTIES}&WorkerEvent_TimePoint=2.0&WorkerEvent_Progress=0.4&HostName=localhost" - curl -XPOST "http://admin:admin@`hostname`:8165/api/message/workerEvent?type=queue&${PROPERTIES}" - */ - std::stringstream ss_url; - - // ss_url << "http://" << m_smqusername << ":" << m_password << "@" << m_broker << "/api/message/workerEvent?type=queue&"; - ss_url << "http://" << "admin" << ":" << "admin" << "@" << m_broker << "/api/message/workerEvent?type=queue&"; - - switch (workerEvent->status) { - case JOB_DATA: - ss_url << PRIORITY_PROPERTY << "=" << PRIORITY_DEFAULT_VALUE << "&"; - ss_url << TIMETOLIVE_PROPERTY << "=" << m_ttl_lowPriority << "&"; - ss_url << DELIVERYMODE_PROPERTY << "=" << DELIVERYMODE_NONPERSISTENT_VALUE << "&"; - break; - case JOB_PROGRESS: - ss_url << PRIORITY_PROPERTY << "=" << PRIORITY_DEFAULT_VALUE << "&"; - ss_url << TIMETOLIVE_PROPERTY << "=" << m_ttl_lowPriority << "&"; - ss_url << DELIVERYMODE_PROPERTY << "=" << DELIVERYMODE_NONPERSISTENT_VALUE << "&"; - break; - case JOB_STARTING: - ss_url << PRIORITY_PROPERTY << "=" << PRIORITY_DEFAULT_VALUE << "&"; - ss_url << TIMETOLIVE_PROPERTY << "=" << m_ttl_highPriority << "&"; - ss_url << DELIVERYMODE_PROPERTY << "=" << DELIVERYMODE_PERSISTENT_VALUE << "&"; - break; - case JOB_COMPLETED: - ss_url << PRIORITY_PROPERTY << "=" << PRIORITY_DEFAULT_VALUE << "&"; - ss_url << TIMETOLIVE_PROPERTY << "=" << m_ttl_highPriority << "&"; - ss_url << DELIVERYMODE_PROPERTY << "=" << DELIVERYMODE_PERSISTENT_VALUE << "&"; - break; - case JOB_FAILURE: - ss_url << PRIORITY_PROPERTY << "=" << PRIORITY_DEFAULT_VALUE << "&"; - ss_url << TIMETOLIVE_PROPERTY << "=" << m_ttl_highPriority << "&"; - ss_url << DELIVERYMODE_PROPERTY << "=" << DELIVERYMODE_PERSISTENT_VALUE << "&"; - break; - } - - ss_url << MESSAGE_TYPE_PROPERTY << "=" << MESSAGE_TYPE_WORKEREVENT_VALUE << "&"; - ss_url << USERNAME_PROPERTY << "=" << m_vcusername << "&"; - ss_url << HOSTNAME_PROPERTY << "=" << m_hostname << "&"; - ss_url << SIMKEY_PROPERTY << "=" << m_simKey << "&"; - ss_url << TASKID_PROPERTY << "=" << m_taskID << "&"; - ss_url << JOBINDEX_PROPERTY << "=" << m_jobIndex << "&"; - - ss_url << WORKEREVENT_STATUS << "=" << workerEvent->status << "&"; - - char* revisedMsg = workerEvent->eventMessage; - if (revisedMsg != NULL) { - revisedMsg = trim(revisedMsg); - if (strlen(revisedMsg) > 2048) { - revisedMsg[2047] = 0; //status message is only 2048 chars long in database - } - - for (int i = 0; i < (int) strlen(revisedMsg); i++) { - switch (revisedMsg[i]) { - case '\r': - case '\n': - case '\'': - case '\"': - revisedMsg[i] = ' '; - break; - // these characters are not valid both in database and in messages as a property - } - } - } - if (revisedMsg != NULL) { - char *output = curl_easy_escape(curl, revisedMsg, strlen(revisedMsg)); - if(output) { - ss_url << WORKEREVENT_STATUSMSG << "=" << output << "&"; - curl_free(output); - } - } - - ss_url << WORKEREVENT_PROGRESS << "=" << workerEvent->progress << "&"; - ss_url << WORKEREVENT_TIMEPOINT << "=" << workerEvent->timepoint; - - std::string s_url = ss_url.str(); - const char* messaging_http_url = s_url.c_str(); - curl_easy_setopt(curl, CURLOPT_URL, messaging_http_url); - - cout << "curl -XPOST " << messaging_http_url << endl; - - - // - // print message to stdout - // - cout << "!!!SimulationMessaging::sendStatus [" << (long)m_simKey << ":" << getStatusString(workerEvent->status); - if (revisedMsg != NULL) { - cout << ":" << revisedMsg; - } else { - cout << ":" << workerEvent->progress << ":" << workerEvent->timepoint; - } - cout << "]" << endl; - - - - // std::stringstream ss_body; - // ss_body << "empty message body"; // one way to force a POST verb with libcurl, probably better ways. - // std::string s_body = ss_body.str(); - // const char* postfields = s_body.c_str(); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, ""); - - - // Perform the request, res will get the return code - CURLcode res = curl_easy_perform(curl); - // Check for errors - if(res != CURLE_OK) - fprintf(stderr, "curl_easy_perform() failed: %s\n", - curl_easy_strerror(res)); - - // always cleanup - curl_easy_cleanup(curl); - } - - - - time(&lastSentEventTime); - if (workerEvent->status == JOB_COMPLETED || workerEvent->status == JOB_FAILURE) { -#if ( defined(_WIN32) || defined(_WIN64) ) - SetEvent(hMessagingThreadEndEvent); -#else // UNIX - cout << "!!!thread exiting" << endl; - pthread_exit(NULL); -#endif - } -#else - throw "OUPUT_MODE_STANDOUT must be using if not using messaging!"; -#endif - } - delete workerEvent; -} - -void SimulationMessaging::setWorkerEvent(WorkerEvent* arg_workerEvent) { - if (m_inst == 0) { - throw "SimulationMessaging is not initialized"; - } - if (workerEventOutputMode == WORKEREVENT_OUTPUT_MODE_STDOUT) { - events.push_back(arg_workerEvent); - sendStatus(); - return; - } -#ifdef USE_MESSAGING - else { - bool ifset = true; - bool iftry = false; - bool critical = criticalDelivery(*arg_workerEvent); - if (!critical) { - iftry = true; - // - // for portability, if not POSIX, time_t not guaranteed to be in seconds - // add WORKEREVENT_MESSAGE_MIN_TIME_SECONDS to last event time - // - struct tm nextMessageTime_tm = *localtime( &lastSentEventTime); - nextMessageTime_tm.tm_sec += WORKEREVENT_MESSAGE_MIN_TIME_SECONDS; // add MIN_TIME seconds to the time - time_t nextMessageTime = mktime( &nextMessageTime_tm); // normalize it - time_t currTime; - time(&currTime); - if (currTime <= nextMessageTime){ - ifset = false; - } - } - - if (ifset) { - { //scope for lock - WorkerEventLocker locker(*this,iftry); - if (locker.locked) { - events.push_back(arg_workerEvent); - } - } //unlock worker event -#if ( defined(_WIN32) || defined(_WIN64) ) - SetEvent(hNewWorkerEvent); -#else //UNIX - pthread_mutex_lock(&mutex_cond_workerEvent); - bNewWorkerEvent = true; - pthread_cond_signal(&cond_workerEvent); - pthread_mutex_unlock(&mutex_cond_workerEvent); -#endif - } - } -#else - throw "OUPUT_MODE_STANDOUT must be using if not using messaging!"; -#endif -} - -#ifdef USE_MESSAGING -/** - * Keep trying to start the connection. Once it is established, - * setup the message handlers and publishers. (This is synchronized - * because it can be called from the main thread, and from the - * onException handler.) - */ -void SimulationMessaging::setupConnection () { //synchronized - // lockMessaging(); - // unlockMessaging(); -} - -void SimulationMessaging::cleanup(){ -} - - -/** - * Suspend the current thread for "duration" milliseconds. - */ -void SimulationMessaging::delay(int duration) -{ -#if ( defined(_WIN32) || defined(_WIN64) ) - Sleep(duration); -#else // UNIX - sleep(duration/1000); -#endif -} - -bool SimulationMessaging::lockMessaging() -{ -#if ( defined(_WIN32) || defined(_WIN64) ) - EnterCriticalSection(&lockForMessaging); - return true; -#else // UNIX - if (pthread_mutex_lock(&mutex_messaging)) { - cout << "Cannot acquire mutex, fatal error." << endl; - exit(1); - } -#endif -} - -void SimulationMessaging::unlockMessaging() -{ -#if ( defined(_WIN32) || defined(_WIN64) ) - LeaveCriticalSection(&lockForMessaging); -#else // UNIX - pthread_mutex_unlock(&mutex_workerEvent); -#endif -} - - -bool SimulationMessaging::lockWorkerEvent(bool bTry) -{ -#if ( defined(_WIN32) || defined(_WIN64) ) - if (bTry) { - return TryEnterCriticalSection(&lockForWorkerEvent)!=0; - } - try { - EnterCriticalSection(&lockForWorkerEvent); - } catch (...) { - return false; - } - return true; -#else // UNIX - if (bTry) { - return (pthread_mutex_trylock(&mutex_workerEvent) == 0); - } - if (pthread_mutex_lock(&mutex_workerEvent) != 0) { - return false; - } - return true; -#endif -} - -void SimulationMessaging::unlockWorkerEvent() -{ -#if ( defined(_WIN32) || defined(_WIN64) ) - LeaveCriticalSection(&lockForWorkerEvent); -#else // UNIX - pthread_mutex_unlock(&mutex_workerEvent); -#endif -} - -char* SimulationMessaging::trim(char* str) { - int leftIndex, rightIndex; - int len = (int)strlen(str); - for (leftIndex = 0; leftIndex < len; leftIndex ++) { // remove leading spaces - char c = str[leftIndex]; - if (c != ' ' && c != '\n' && c != '\r') { - break; - } - } - for (rightIndex = len - 1; rightIndex >= 0; rightIndex --) { // remove trailing spaces and new line and carriage return - char c = str[rightIndex]; - if (c != ' ' && c != '\n' && c != '\r') { - break; - } - } - - len = rightIndex - leftIndex + 2; - if (len <= 0) { - return 0; - } - - char* newstr = new char[len]; - memset(newstr, 0, len * sizeof(char)); - strncpy(newstr, str + leftIndex, len - 1); - - return newstr; -} - -void SimulationMessaging::keepAlive() { - if (workerEventOutputMode == WORKEREVENT_OUTPUT_MODE_MESSAGING) { - - - CURL* curl = curl_easy_init(); - if(curl) { - // First set the URL that is about to receive our POST. This URL can - // just as well be a https:// URL if that is what should receive the - // data. - curl_easy_setopt(curl, CURLOPT_URL, "http://localhost:6161/message/workerevent?readTimeout=20000&type=queue"); - - - // Now specify the POST data - std::stringstream ss; - - //status - // msg->setIntProperty(WORKEREVENT_STATUS, JOB_WORKER_ALIVE); - ss << WORKEREVENT_STATUS << "=" << JOB_WORKER_ALIVE; - - std::string x = ss.str(); - const char* postfields = x.c_str(); - - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postfields); // e.g. postfields="name=daniel&project=curl" - - // Perform the request, res will get the return code - CURLcode res = curl_easy_perform(curl); - // Check for errors - if(res != CURLE_OK) - fprintf(stderr, "curl_easy_perform() failed: %s\n", - curl_easy_strerror(res)); - - // always cleanup - curl_easy_cleanup(curl); - } - - time(&lastSentEventTime); - } -} - -const char* SimulationMessaging::getStatusString(int status) { - switch (status) { - case JOB_STARTING: - return "JOB_STARTING"; - - case JOB_PROGRESS: - return "JOB_PROGRESS"; - - case JOB_DATA: - return "JOB_DATA"; - - case JOB_COMPLETED: - return "JOB_COMPLETED"; - - case JOB_WORKER_ALIVE: - return "JOB_WORKER_ALIVE"; - - case JOB_FAILURE: - return "JOB_FAILURE"; - - default: - return "Unknown status"; - } -} - -SimulationMessaging* SimulationMessaging::create(const char* broker, const char* smqusername, const char* passwd, const char* qname, const char* tname, const char* vcusername, int simKey, int jobIndex, int taskID, int ttl_low, int ttl_high) -{ - if (m_inst != NULL && m_inst->workerEventOutputMode == WORKEREVENT_OUTPUT_MODE_STDOUT) { - delete m_inst; - m_inst = NULL; - } - if (m_inst == NULL){ - m_inst = new SimulationMessaging(broker, smqusername, passwd, qname, tname, vcusername, simKey, jobIndex, taskID, ttl_low, ttl_high); - } - - return(m_inst); -} - -void SimulationMessaging::waitUntilFinished() { - if (workerEventOutputMode == WORKEREVENT_OUTPUT_MODE_STDOUT) { - return; - } -#if ( defined(_WIN32) || defined(_WIN64) ) - DWORD dwWaitResult = WaitForSingleObject(hMessagingThreadEndEvent, INFINITE); - switch (dwWaitResult) { - case WAIT_OBJECT_0: - case WAIT_TIMEOUT: - break; - - default: - cout << "Wait error: " << GetLastError() << endl; - break; - } -#else - cout << "!!!waiting for thread to exit" << endl; - pthread_join(newWorkerEventThread, NULL); -#endif -} - -void* startMessagingThread(void* param); - -void SimulationMessaging::start() { - if (workerEventOutputMode == WORKEREVENT_OUTPUT_MODE_STDOUT) { - return; - } - if (bStarted) { - return; - } - bStarted = true; - -#if ( defined(_WIN32) || defined(_WIN64) ) - HANDLE hThread; - DWORD IDThread; - - char messagingThreadEndEventName[256]; - char newWorkerEventName[256]; - sprintf(messagingThreadEndEventName, "MessagingThreadEndEvent_%ld_%d_%d", m_simKey, m_jobIndex, m_taskID); - sprintf(newWorkerEventName, "NewWorkerEvent_%ld_%d_%d", m_simKey, m_jobIndex, m_taskID); - - // Create a manual-reset event object. The master thread sets - // this to nonsignaled when it writes to the shared buffer. - hMessagingThreadEndEvent = CreateEvent( - NULL, // no security attributes - true, // manual-reset event - false, // initial state is nonsignaled - messagingThreadEndEventName // object name - ); - - if (hMessagingThreadEndEvent == NULL) { - throw "CreateEvent failed for new worker event"; - } - - if (GetLastError() == ERROR_ALREADY_EXISTS) { - throw "Event for messagingThreadEndEvent already exists"; - } - - hNewWorkerEvent = CreateEvent( - NULL, // no security attributes - true, // manual-reset event - false, // initial state is nonsignaled - newWorkerEventName // object name - ); - - if (hNewWorkerEvent == NULL) { - throw "CreateEvent failed for new worker event"; - } - - if (GetLastError() == ERROR_ALREADY_EXISTS) { - throw "Event for newWorkerEvent already exists"; - } - - // Create multiple threads and an auto-reset event object - // for each thread. Each thread sets its event object to - // signaled when it is not reading from the shared buffer. - - hThread = CreateThread(NULL, 0, - (LPTHREAD_START_ROUTINE) startMessagingThread, - &hNewWorkerEvent, // pass event handle - 0, &IDThread); - if (hThread == NULL) - { - throw "CreateThread failed for messaging thread"; - } -#else // UNIX - int retv = pthread_create(&newWorkerEventThread, NULL, startMessagingThread, this); -#endif -} - -void* startMessagingThread(void* lpParam){ - SimulationMessaging::getInstVar()->setupConnection(); - -#if ( defined(_WIN32) || defined(_WIN64) ) - DWORD dwWaitResult; - HANDLE hEvent; - - hEvent = *(HANDLE*)lpParam; // thread's read event - - while (true) { - dwWaitResult = WaitForSingleObject(hEvent, 5*60*1000); // 5 min wait - - switch (dwWaitResult) { - case WAIT_OBJECT_0: - { - WorkerEvent* sentWorkerEvent = SimulationMessaging::getInstVar()->sendStatus(); - SimulationMessaging::getInstVar()->lockWorkerEvent(); - if (sentWorkerEvent != NULL - && SimulationMessaging::getInstVar()->getWorkerEvent() != NULL - && sentWorkerEvent->equals(SimulationMessaging::getInstVar()->getWorkerEvent())) { - ResetEvent(hEvent); - } - SimulationMessaging::getInstVar()->unlockWorkerEvent(); - delete sentWorkerEvent; - } - break; - - // An error occurred. - case WAIT_TIMEOUT: - SimulationMessaging::getInstVar()->keepAlive(); - break; - - default: - std::cout<< "Wait error: " << GetLastError() << endl; - break; - } - } -#else // UNIX - int waitReturn = 0; - struct timespec timeout; - struct timeval now; - struct timeval start; - SimulationMessaging* simMessaging = (SimulationMessaging*)lpParam; - - while (true) { - waitReturn = 1; - gettimeofday(&start, NULL); - timeout.tv_sec = start.tv_sec; - // condition might be signalled before this thread gets blocked - // so this thread might miss signal and doesn't get wakened - // if this happens don't want to wait too long to check if there - // is new worker event. This is the reason for the loop and 2 sec timeout - pthread_mutex_lock(&simMessaging->mutex_cond_workerEvent); - while (timeout.tv_sec - start.tv_sec < 5 * 60) { - // at this point, there are two possibilities - // 1. this thread has been awakened, waited < 2 secs, waitReturn is 0 - // 2. this thread has waited full 2 sec timout, waitReturn is non zero - // in either case, check if there is new worker event. - if (simMessaging->bNewWorkerEvent) { - simMessaging->bNewWorkerEvent = false; - waitReturn = 0; - break; - } - gettimeofday(&now, NULL); - timeout.tv_sec = now.tv_sec + 2; - timeout.tv_nsec = now.tv_usec * 1000; - waitReturn = pthread_cond_timedwait(&simMessaging->cond_workerEvent, &simMessaging->mutex_cond_workerEvent, &timeout); - } - pthread_mutex_unlock(&simMessaging->mutex_cond_workerEvent); - - switch (waitReturn) { - case 0: { // new event - simMessaging->sendStatus(); - break; - } - - case ETIMEDOUT: // time out - simMessaging->keepAlive(); - break; - - default: - std::cout<< "Wait error: " << waitReturn << endl; - break; - } - } -#endif -} -#endif diff --git a/conan-profiles/CI-CD/Linux-AMD64_profile.txt b/conan-profiles/CI-CD/Linux-AMD64_profile.txt index 3d146a2dc..69d8337f6 100644 --- a/conan-profiles/CI-CD/Linux-AMD64_profile.txt +++ b/conan-profiles/CI-CD/Linux-AMD64_profile.txt @@ -9,6 +9,10 @@ compiler.runtime=dynamic os=Linux [conf] +# Required: conanfile.py's layout() only flattens the tree to build/generators +# when this is set. Without it, cmake_layout() emits build/Release/generators +# and the workflow's `source build/generators/conanbuild.sh` fails. +tools.cmake.cmaketoolchain:generator=Ninja tools.build:exelinkflags=['-fuse-ld=mold'] tools.build:sharedlinkflags=['-fuse-ld=mold'] diff --git a/conan-profiles/CI-CD/Linux-ARM64_profile.txt b/conan-profiles/CI-CD/Linux-ARM64_profile.txt index d8e9a6876..942fa10c9 100644 --- a/conan-profiles/CI-CD/Linux-ARM64_profile.txt +++ b/conan-profiles/CI-CD/Linux-ARM64_profile.txt @@ -9,6 +9,10 @@ compiler.runtime=dynamic os=Linux [conf] +# Required: conanfile.py's layout() only flattens the tree to build/generators +# when this is set. Without it, cmake_layout() emits build/Release/generators +# and the workflow's `source build/generators/conanbuild.sh` fails. +tools.cmake.cmaketoolchain:generator=Ninja tools.build:exelinkflags=['-fuse-ld=mold'] tools.build:sharedlinkflags=['-fuse-ld=mold'] diff --git a/conan-profiles/CI-CD/MacOS-AMD64_profile.txt b/conan-profiles/CI-CD/MacOS-AMD64_profile.txt index 2d4556f59..1fb77ae87 100644 --- a/conan-profiles/CI-CD/MacOS-AMD64_profile.txt +++ b/conan-profiles/CI-CD/MacOS-AMD64_profile.txt @@ -4,5 +4,11 @@ build_type=Release compiler=apple-clang compiler.cppstd=20 compiler.libcxx=libc++ -compiler.version=13 -os=Macos \ No newline at end of file +compiler.version=17 +os=Macos + +[conf] +# Required: conanfile.py's layout() only flattens the tree to build/generators +# when this is set. Without it, cmake_layout() emits build/Release/generators +# and the workflow's `source generators/conanbuild.sh` fails. +tools.cmake.cmaketoolchain:generator=Ninja diff --git a/conan-profiles/CI-CD/MacOS-ARM64_profile.txt b/conan-profiles/CI-CD/MacOS-ARM64_profile.txt index 705ec7538..0152ac201 100644 --- a/conan-profiles/CI-CD/MacOS-ARM64_profile.txt +++ b/conan-profiles/CI-CD/MacOS-ARM64_profile.txt @@ -5,4 +5,10 @@ compiler=apple-clang compiler.cppstd=20 compiler.libcxx=libc++ compiler.version=13 -os=Macos \ No newline at end of file +os=Macos + +[conf] +# Required: conanfile.py's layout() only flattens the tree to build/generators +# when this is set. Without it, cmake_layout() emits build/Release/generators +# and the workflow's `source generators/conanbuild.sh` fails. +tools.cmake.cmaketoolchain:generator=Ninja diff --git a/conan-profiles/CI-CD/Windows-AMD64_profile.txt b/conan-profiles/CI-CD/Windows-AMD64_profile.txt index 674712d27..f500a366b 100644 --- a/conan-profiles/CI-CD/Windows-AMD64_profile.txt +++ b/conan-profiles/CI-CD/Windows-AMD64_profile.txt @@ -1,17 +1,30 @@ [settings] os=Windows arch=x86_64 +build_type=Release compiler=clang -compiler.version=16 -compiler.libcxx=libc++ +compiler.runtime=static compiler.cppstd=20 -build_type=Release +compiler.version=21 +# This picks the Visual Studio install that VCVars looks for. For compiler=clang +# Conan maps runtime_version -> VS IDE version itself (_vcvars_versions in +# conan/tools/microsoft/visual.py): v143/v144 -> VS 17, v145 -> VS 18. The +# `windows-latest` image is now windows-2025-vs2026, which ships only VS 18 +# (MSVC 14.51), so v143 failed with "VS non-existing installation: Visual +# Studio 17". Windows-ARM64 stays on v144 because windows-11-arm64 still has +# VS 17. Revisit both if the runner images change again. +compiler.runtime_version=v145 [conf] tools.cmake.cmaketoolchain:generator=Ninja -tools.build:compiler_executables={'c': 'clang', 'cpp': 'clang++'} +tools.cmake.cmaketoolchain:extra_variables={"CMAKE_FIND_PACKAGE_PREFER_CONFIG": "ON"} tools.env.virtualenv:powershell=pwsh +# Inert for compiler=clang — vs_ide_version() only consults this when +# compiler=msvc. Kept for the msvc path; it does NOT drive the lookup above. +tools.microsoft.msbuild:vs_version=17 +tools.build:cflags=["-w"] +tools.build:cxxflags=["-w"] [buildenv] -CC=clang -CXX=clang++ \ No newline at end of file +CC=clang-cl +CXX=clang-cl diff --git a/conan-profiles/CI-CD/Windows-ARM64_profile.txt b/conan-profiles/CI-CD/Windows-ARM64_profile.txt index 7fd44a5cf..b96c755ba 100644 --- a/conan-profiles/CI-CD/Windows-ARM64_profile.txt +++ b/conan-profiles/CI-CD/Windows-ARM64_profile.txt @@ -1,17 +1,22 @@ [settings] os=Windows arch=armv8 +build_type=Release compiler=clang -compiler.version=16 -compiler.libcxx=libc++ +compiler.runtime=static +compiler.cstd=23 compiler.cppstd=20 -build_type=Release +compiler.version=21 +compiler.runtime_version=v144 [conf] tools.cmake.cmaketoolchain:generator=Ninja -tools.build:compiler_executables={'c': 'clang', 'cpp': 'clang++'} +tools.cmake.cmaketoolchain:extra_variables={"CMAKE_FIND_PACKAGE_PREFER_CONFIG": "ON"} tools.env.virtualenv:powershell=pwsh +tools.microsoft.msbuild:vs_version=17 +tools.build:cflags=["-w"] +tools.build:cxxflags=["-w"] [buildenv] -CC=clang -CXX=clang++ \ No newline at end of file +CC=clang-cl +CXX=clang-cl diff --git a/conanfile.py b/conanfile.py index 1d76fd804..8dc8f7f82 100644 --- a/conanfile.py +++ b/conanfile.py @@ -1,4 +1,3 @@ -import sys from conan import ConanFile from conan.tools.build import check_min_cppstd from conan.tools.cmake import CMake, cmake_layout @@ -21,16 +20,33 @@ class VCellODERecipe(ConanFile): "include_messaging": True, "generate_docs": False} + def layout(self): + cmake_layout(self) + # Keep the CI build tree flat when Ninja is selected. The workflow and + # packaging steps use build/{bin,lib,generators}; cmake_layout() would + # otherwise insert build_type (for example, build/Release) for Ninja. + if self.conf.get("tools.cmake.cmaketoolchain:generator") == "Ninja": + self.folders.build = "build" + self.folders.generators = "build/generators" + def validate(self): check_min_cppstd(self, "17") def build(self): cmake = CMake(self) - cmake.definitions["OPTION_TARGET_MESSAGING"] = "ON" if self.options.include_messaging else "OFF" - cmake.definitions["OPTION_TARGET_DOCS"] = "ON" if self.options.generate_docs else "OFF" + messaging_enabled = ( + bool(self.options.include_messaging) and self.settings.os != "Windows" + ) + cmake.configure(variables={ + "OPTION_TARGET_MESSAGING": "ON" if messaging_enabled else "OFF", + "OPTION_TARGET_DOCS": "ON" if self.options.generate_docs else "OFF", + }) + cmake.build() def requirements(self): - if self.options.include_messaging: + self.requires("argparse/[>=3.2 <4.0]") + self.requires("spdlog/[>=1.16.0 <2.0]") + if self.options.include_messaging and self.settings.os != "Windows": self.requires("libcurl/[<9.0]") def build_requirements(self): @@ -44,8 +60,6 @@ def config_options(self): # self.settings.compiler.libcxx = "libc++" if self.settings.os == "Windows": del self.options.fPIC - if self.options.include_messaging: - print("Warning: Windows-builds do not currently support messaging. Building anyway", file=sys.stderr) def configure(self): diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..f78ede0b5 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,83 @@ +[build-system] +requires = ["uv_build>=0.11.27,<0.12"] +build-backend = "uv_build" + +[project] +name = "pyvcell_odesolver" +version = "0.9.4" +description="Virtual Cell CVODE / IDA based ODE solver" +readme = "README.md" +authors = [ + { name = "Jim Schaff", email = "schaff@uchc.edu" }, + { name = "Logan Drescher", email = "drescher@uchc.edu"} +] +requires-python = ">=3.10" +classifiers = [ + "Development Status :: 4 - Beta", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", +] +dependencies = [ + "pydantic>=2.13.4" +] + +[tool.uv.build-backend] +module-name = "pyvcell_odesolver" +module-root = "" + +[project.optional-dependencies] +test = ["pytest"] +build = ["build", "wheel"] + + +[tool.pytest.ini_options] +minversion = "6.0" +addopts = ["-ra", "--showlocals", "--strict-markers", "--strict-config"] +xfail_strict = true +log_cli_level = "INFO" +filterwarnings = [ + "error", +] +testpaths = ["tests"] + +[tool.ruff] +# The package lives at the repo root (module-root = "" above), not under src/. +src = ["."] + +[tool.ruff.lint] +extend-select = [ + "B", # flake8-bugbear + "I", # isort + "ARG", # flake8-unused-arguments + "C4", # flake8-comprehensions + "EM", # flake8-errmsg + "ICN", # flake8-import-conventions + "G", # flake8-logging-format + "PGH", # pygrep-hooks + "PIE", # flake8-pie + "PL", # pylint + "PT", # flake8-pytest-style + "PTH", # flake8-use-pathlib + "RET", # flake8-return + "RUF", # Ruff-specific + "SIM", # flake8-simplify + "T20", # flake8-print + "UP", # pyupgrade + "YTT", # flake8-2020 + "EXE", # flake8-executable + "NPY", # NumPy specific rules + "PD", # pandas-vet +] +ignore = [ + "PLR09", # Too many X + "PLR2004", # Magic comparison +] +isort.required-imports = ["from __future__ import annotations"] + +[tool.ruff.lint.per-file-ignores] +"tests/**" = ["T20"] diff --git a/pyvcell_odesolver/__init__.py b/pyvcell_odesolver/__init__.py new file mode 100644 index 000000000..52bc1cbb5 --- /dev/null +++ b/pyvcell_odesolver/__init__.py @@ -0,0 +1,5 @@ +from __future__ import annotations + +from pyvcell_odesolver.sundials import __doc__, version, solve + +__all__ = ["__doc__", "version", "solve"] diff --git a/pyvcell_odesolver/_internal/__init__.py b/pyvcell_odesolver/_internal/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/pyvcell_odesolver/_internal/__pycache__/__init__.cpython-310.pyc b/pyvcell_odesolver/_internal/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 000000000..efbbe7a97 Binary files /dev/null and b/pyvcell_odesolver/_internal/__pycache__/__init__.cpython-310.pyc differ diff --git a/pyvcell_odesolver/_internal/__pycache__/check_arch.cpython-310.pyc b/pyvcell_odesolver/_internal/__pycache__/check_arch.cpython-310.pyc new file mode 100644 index 000000000..1d80ad479 Binary files /dev/null and b/pyvcell_odesolver/_internal/__pycache__/check_arch.cpython-310.pyc differ diff --git a/pyvcell_odesolver/_internal/__pycache__/native_calls.cpython-310.pyc b/pyvcell_odesolver/_internal/__pycache__/native_calls.cpython-310.pyc new file mode 100644 index 000000000..646ff3dd3 Binary files /dev/null and b/pyvcell_odesolver/_internal/__pycache__/native_calls.cpython-310.pyc differ diff --git a/pyvcell_odesolver/_internal/__pycache__/native_utils.cpython-310.pyc b/pyvcell_odesolver/_internal/__pycache__/native_utils.cpython-310.pyc new file mode 100644 index 000000000..5d5331008 Binary files /dev/null and b/pyvcell_odesolver/_internal/__pycache__/native_utils.cpython-310.pyc differ diff --git a/pyvcell_odesolver/_internal/check_arch.py b/pyvcell_odesolver/_internal/check_arch.py new file mode 100644 index 000000000..50e2c2338 --- /dev/null +++ b/pyvcell_odesolver/_internal/check_arch.py @@ -0,0 +1,114 @@ +import platform +import struct +import os +import platform + +def get_library_archs(lib_path: str) -> tuple[str, list[str]]: + """Determine architecture based on file type and header.""" + _, ext = os.path.splitext(lib_path) + + # ELF (Linux .so files) + if ext == ".so" or ".so." in str(lib_path): + with open(lib_path, 'rb') as f: + f.seek(5) + endian = '<' if f.read(1)[0] == 1 else '>' + f.seek(18) + machine = struct.unpack(endian + 'H', f.read(2))[0] + + arch_map = { + 0x03: 'i386', + 0x3E: 'x86_64', + 0xB7: 'aarch64', + 0x28: 'armv7', + } + return "Linux", [normalize_arch(arch_map.get(machine, f'unknown (0x{machine:x})'))] + + # Mach-O (macOS .dylib files) + elif ext == '.dylib': + with open(lib_path, 'rb') as f: + # Check for fat binary magic + magic = f.read(4) + if magic == b'\xca\xfe\xba\xbe' or magic == b'\xbf\xba\xfe\xca': + # Fat binary - list all architectures + f.seek(4) + num_archs = struct.unpack('>I', f.read(4))[0] + archs = set() + for i in range(num_archs): + cpu_type = struct.unpack('>I', f.read(4))[0] + f.read(4) # Skip cpu_subtype + f.read(4) # Skip offset + f.read(4) # Skip size + f.read(4) # Skip align + + arch_map = { + 0x00000007: 'i386', + 0x01000007: 'x86_64', + 0x0100000C: 'aarch64', + } + archs.add(normalize_arch(arch_map.get(cpu_type, f'unknown (0x{cpu_type:x})'))) + return "Darwin", list(archs) + else: + # Single-arch Mach-O - determine endianness + f.seek(4) + cpu_type_bytes = f.read(4) + # Try little-endian first (most common) + cpu_type = struct.unpack(' list[str]: + if not lib_path_list: + raise ValueError("A list must be provided, `None` is not allowed.") + + system_name = platform.system() + system_arch = normalize_arch(platform.machine()) + valid_libraries = [] + for lib_path in lib_path_list: + required_system_name, shared_library_archs = get_library_archs(lib_path) + if system_arch in shared_library_archs and required_system_name in system_name: + valid_libraries.append(lib_path) + return valid_libraries + +def normalize_arch(machine_str=None): + if machine_str is None: + machine_str = platform.machine().lower() + + # Normalize common variants + if machine_str in ('x86_64', 'amd64', 'x64'): + return 'x86_64' + elif machine_str in ('aarch64', 'arm64'): + return 'aarch64' + elif machine_str in ('i386', 'i486', 'i586', 'i686', 'x86'): + return 'i386' + elif machine_str.startswith('arm'): + return 'arm' + elif machine_str.lower() != machine_str: + return normalize_arch(machine_str.lower()) + raise OSError(f"Unknown machine type detected: `{machine_str}`") \ No newline at end of file diff --git a/pyvcell_odesolver/_internal/native_calls.py b/pyvcell_odesolver/_internal/native_calls.py new file mode 100644 index 000000000..d4cb0bdba --- /dev/null +++ b/pyvcell_odesolver/_internal/native_calls.py @@ -0,0 +1,53 @@ +import ctypes +import logging +from pathlib import Path + +from pydantic import BaseModel + +from pyvcell_odesolver._internal.native_utils import VCellNativeLibraryLoader + + +class ReturnValue(BaseModel): + success: bool + message: str + + +class MutableString: + def __init__(self, value: str): + self.value: str = value + + +class ODENativeCalls: + def __init__(self) -> None: + self.loader = VCellNativeLibraryLoader() + self.lib: ctypes.CDLL = self.loader.lib + + def call_version(self) -> ReturnValue: + try: + version_str: str = self.lib.version_ctypes() + if version_str is None: + error_msg = "Failed to collect and covert version information" + logging.error(error_msg) + return ReturnValue(success=False, message=error_msg) + return ReturnValue(success=True, message=version_str.decode("utf-8")) + except Exception as e: + logging.exception("Error in vcml_to_finite_volume_input()", exc_info=e) + raise + + def call_solve( + self, input_file_path: str, output_file_path: str, task_id: int + ) -> ReturnValue: + try: + solver_return_code: int = self.lib.solve_ctypes( + ctypes.c_char_p(input_file_path.encode("utf-8")), + ctypes.c_char_p(output_file_path.encode("utf-8")), + ctypes.c_int(task_id), + ) + if solver_return_code == 0: + return ReturnValue(success=True, message="Solver returned successfully.") + error_msg = "Solver failed with exit code {}".format(solver_return_code) + logging.error(error_msg) + return ReturnValue(success=False, message=error_msg) + except Exception as e: + logging.exception("Error in calling SundialsSolverInterface::solve_ctypes(...)", exc_info=e) + raise e diff --git a/pyvcell_odesolver/_internal/native_utils.py b/pyvcell_odesolver/_internal/native_utils.py new file mode 100644 index 000000000..72c4597f9 --- /dev/null +++ b/pyvcell_odesolver/_internal/native_utils.py @@ -0,0 +1,56 @@ +import ctypes +import platform +from _ctypes import byref +from importlib.resources import files +import os +import sys + +import pyvcell_odesolver +from pyvcell_odesolver._internal import check_arch + + +class VCellNativeLibraryLoader: + lib: ctypes.CDLL + + def __init__(self) -> None: + self.lib = self._load_library() + self._define_entry_points() + + def _load_library(self) -> ctypes.CDLL: + system = platform.system() + lib_ext = {"Linux": ".so", "Darwin": ".dylib", "Windows": ".dll"}.get(system) + version_identifier = "VCell ODE solver (CVODE/IDA) v" + + if lib_ext is None: + raise OSError(f"Unsupported operating system: {system}") + + libs_dir = files(pyvcell_odesolver).joinpath("lib") + if not libs_dir.is_dir(): + raise OSError(f"Could not find the shared library directory {libs_dir}") + + + valid_libraries = check_arch.get_all_valid_libraries_from_dir(str(libs_dir)) + for file in valid_libraries: + file_str = str(file) + try: + lib = ctypes.CDLL(name=file_str) + lib.version_ctypes.restype = ctypes.c_char_p # signals ctypes to return as char-array + version_str: str = lib.version_ctypes().decode("utf-8") + if version_identifier not in version_str: + err_str = f"`{file_str}` isn't desired lib (`{version_identifier}` not in `{version_str}`)" + print(err_str, file=sys.stderr) + except AttributeError as e: + print(f"library `{file_str}` could not be loaded: {e}", file=sys.stderr) + continue # If we didn't get a version, we didn't get the correct lib + return lib + + # Didn't find what we needed + files_checked = "\n - ".join(valid_libraries if len(valid_libraries) > 0 else os.listdir(str(libs_dir))) + raise OSError(f"Could not find the shared library; in `{str(libs_dir)}` checked: \n - {files_checked}") + + def _define_entry_points(self) -> None: + self.lib.version_ctypes.restype = ctypes.c_char_p # technically, we did this above, but just in case + self.lib.version_ctypes.argtypes = [] + + self.lib.solve_ctypes.restype = ctypes.c_int + self.lib.solve_ctypes.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.c_int] \ No newline at end of file diff --git a/pyvcell_odesolver/lib/README.md b/pyvcell_odesolver/lib/README.md new file mode 100644 index 000000000..4c235c6ed --- /dev/null +++ b/pyvcell_odesolver/lib/README.md @@ -0,0 +1 @@ +After building the IDAWin library, a copy of it should be placed here for packaging into a working python wheel. \ No newline at end of file diff --git a/pyvcell_odesolver/sundials.py b/pyvcell_odesolver/sundials.py new file mode 100644 index 000000000..518edb6bb --- /dev/null +++ b/pyvcell_odesolver/sundials.py @@ -0,0 +1,13 @@ +from pyvcell_odesolver._internal.native_calls import ODENativeCalls + +def version() -> str: + obj = ODENativeCalls() + return obj.call_version().message + +def solve(input_file_path: str, output_file_path: str, task_id: int = -1) -> int: + obj = ODENativeCalls() + # In python, True == 1; we want 0 == true (a.k.a.: process returned exit code 0) + return int(not obj.call_solve(input_file_path, output_file_path, task_id).success) + +if __name__ == "__main__": + print(version()) \ No newline at end of file diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 000000000..bdbecf93f --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,79 @@ +############################################# +# GoogleTest +############################################## +include(FetchContent) +FetchContent_Declare( + googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG v1.17.0 +) +if (WIN32) + # For Windows: Prevent overriding the parent project's compiler/linker settings + set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +endif() + +FetchContent_MakeAvailable(googletest) +include(GoogleTest) + +# Add test executables +add_executable(unit_tests + unit/smoke_test.cpp + unit/hello_test.cpp + unit/message_processing_test.cpp +) +target_link_libraries(unit_tests PRIVATE + IDAWin + GTest::gtest_main + spdlog::spdlog + # if MinGW is enabled, add `$<$:ws2_32>` +) +gtest_discover_tests(unit_tests) + +target_compile_definitions(unit_tests PRIVATE RESOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}/unit/resources") +if (OPTION_TEST_WITH_LOCALHOST) + target_compile_definitions(unit_tests PRIVATE TEST_WITH_LOCALHOST=1) +else() + target_compile_definitions(unit_tests PRIVATE TEST_WITH_LOCALHOST=0) +endif () + +############################################# +# Python smoke test +# Runs `tests/unit/smoke_test.py` via PYTHON_TEST_INTERPRETER. Registration +# is skipped if `pyvcell_odesolver` is not importable from that interpreter, +# so CI's native ctest run (system Python without the wheel) stays green. +# cibuildwheel exercises the same file independently via pytest. +############################################## +find_package(Python3 COMPONENTS Interpreter QUIET) +set(PYTHON_TEST_INTERPRETER "${Python3_EXECUTABLE}" CACHE FILEPATH + "Python interpreter for pytest-based tests (must have pyvcell_odesolver installed)") +if (PYTHON_TEST_INTERPRETER) + execute_process( + COMMAND ${PYTHON_TEST_INTERPRETER} -c "import pyvcell_odesolver" + RESULT_VARIABLE _pyvcell_import_result + OUTPUT_QUIET ERROR_QUIET + ) + if (_pyvcell_import_result EQUAL 0) + add_test( + NAME python_smoke_test + COMMAND ${PYTHON_TEST_INTERPRETER} -m pytest -v + ${CMAKE_CURRENT_SOURCE_DIR}/unit/smoke_test.py + ) + else() + message(STATUS + "Skipping python_smoke_test: pyvcell_odesolver not importable from " + "${PYTHON_TEST_INTERPRETER}. Install the wheel into a venv and " + "rerun cmake with -DPYTHON_TEST_INTERPRETER=/bin/python.") + endif() +endif() + + +#add_executable(integration_tests +# integration/test_integration.cpp +#) +#target_link_libraries(integration_tests PRIVATE +# IDAWin +# GTest::gtest_main +#) +#gtest_discover_tests(integration_tests) + + diff --git a/tests/test_basic.py b/tests/test_basic.py new file mode 100644 index 000000000..0e6cb3318 --- /dev/null +++ b/tests/test_basic.py @@ -0,0 +1,5 @@ +import pyvcell_odesolver as pvco + + +def test_version_function(): + assert pvco.version() is not None diff --git a/tests/unit/hello_test.cpp b/tests/unit/hello_test.cpp new file mode 100644 index 000000000..2d418cc0e --- /dev/null +++ b/tests/unit/hello_test.cpp @@ -0,0 +1,9 @@ +#include + +// Demonstrate some basic assertions. +TEST(HelloTest, BasicAssertions) { + // Expect two strings not to be equal. + EXPECT_STRNE("hello", "world"); + // Expect equality. + EXPECT_EQ(7 * 6, 42); +} \ No newline at end of file diff --git a/tests/unit/message_processing_test.cpp b/tests/unit/message_processing_test.cpp new file mode 100644 index 000000000..1932291fc --- /dev/null +++ b/tests/unit/message_processing_test.cpp @@ -0,0 +1,80 @@ +// +// Created by Logan Drescher on 12/1/25. +// +#include +#include +#include +#include +#include + +#include "VCellSundialsSolver.h" + +static std::vector eventTracker; + +void appendNextIndex(const WorkerEvent* event); +std::vector generateFibonacci(int length); +long long sequenceComparison(const std::vector &sequence1, const std::vector &sequence2); + + +TEST(MessageProcessingTest, MessagesAreProcessed) { + try { + MessageEventManager eventManager{[](WorkerEvent* event)->void{appendNextIndex(event);}}; + const int NUM_ITERATIONS = 50; + for (int i = 0; i < NUM_ITERATIONS; ++i) { + JobEvent::Status status; + switch (i + 1) { + case 1: status = JobEvent::JOB_STARTING; break; + case NUM_ITERATIONS: status = JobEvent::JOB_COMPLETED; break; + default: status = JobEvent::JOB_PROGRESS; break; + } + eventManager.enqueue(status, (i + 1) / 100.0, i, std::to_string(i).c_str()); + } + eventManager.requestStopAndWaitForIt(); + std::vector expectedResults = generateFibonacci(NUM_ITERATIONS); + // delete eventTrackerMutex; + ASSERT_TRUE(!sequenceComparison(eventTracker, expectedResults)); + } catch (const std::exception& e) { + std::cerr << "Caught exception in main test body: " << e.what() << std::endl; + } +} + +void appendNextIndex(const WorkerEvent* event) { + try { + if (eventTracker.empty()) { + eventTracker.emplace_back("0"); + } else if (1 == eventTracker.size()) { + eventTracker.emplace_back("1"); + } else { + const long long firstValue = std::stoll(eventTracker[eventTracker.size() - 2]); + const long long secondValue = std::stoll(eventTracker[eventTracker.size() - 1]); + const std::string nextValue{std::to_string(firstValue + secondValue)}; + eventTracker.push_back(nextValue); + } + } catch (const std::exception& e) { + std::cerr << "Caught exception in event loop: " << e.what() << std::endl; + exit(2); + } +} + +std::vector generateFibonacci(const int length) { + std::vector sequence; + for (int i = 0; i < length; ++i) { + if (i == 0) { sequence.emplace_back("0"); continue; } + if (i == 1) { sequence.emplace_back("1"); continue; } + const long long firstValue = std::stoll(sequence[sequence.size() - 2]); + const long long secondValue = std::stoll(sequence[sequence.size() - 1]); + const std::string nextValue{std::to_string(firstValue + secondValue)}; + sequence.push_back(nextValue); + } + return sequence; +} + +long long sequenceComparison(const std::vector &sequence1, const std::vector &sequence2) { + if (const size_t comp = sequence2.size() - sequence1.size(); comp) return static_cast(comp); + for (size_t i = 0; i < sequence1.size(); ++i) { + const long long firstValue = std::stoll(sequence1[i]); + const long long secondValue = std::stoll(sequence2[i]); + if (const long long comp = secondValue - firstValue; comp) return comp; + } + return 0; +} \ No newline at end of file diff --git a/IDAWin/tests/smoke/SimID_1489333437_0_.cvodeInput b/tests/unit/resources/SimID_1489333437_0_.cvodeInput similarity index 100% rename from IDAWin/tests/smoke/SimID_1489333437_0_.cvodeInput rename to tests/unit/resources/SimID_1489333437_0_.cvodeInput diff --git a/IDAWin/tests/smoke/SimID_1489333437_0_.functions b/tests/unit/resources/SimID_1489333437_0_.functions similarity index 100% rename from IDAWin/tests/smoke/SimID_1489333437_0_.functions rename to tests/unit/resources/SimID_1489333437_0_.functions diff --git a/IDAWin/tests/smoke/SimID_1489333437_0_.ida.expected b/tests/unit/resources/SimID_1489333437_0_.ida.expected similarity index 100% rename from IDAWin/tests/smoke/SimID_1489333437_0_.ida.expected rename to tests/unit/resources/SimID_1489333437_0_.ida.expected diff --git a/IDAWin/tests/smoke/SimID_1489333437_0_.log b/tests/unit/resources/SimID_1489333437_0_.log similarity index 100% rename from IDAWin/tests/smoke/SimID_1489333437_0_.log rename to tests/unit/resources/SimID_1489333437_0_.log diff --git a/IDAWin/tests/smoke/SimID_1489333437_0__0.simtask.xml b/tests/unit/resources/SimID_1489333437_0__0.simtask.xml similarity index 100% rename from IDAWin/tests/smoke/SimID_1489333437_0__0.simtask.xml rename to tests/unit/resources/SimID_1489333437_0__0.simtask.xml diff --git a/tests/unit/resources/SimID_1607235431_0_.cvodeInput b/tests/unit/resources/SimID_1607235431_0_.cvodeInput new file mode 100644 index 000000000..fcd890744 --- /dev/null +++ b/tests/unit/resources/SimID_1607235431_0_.cvodeInput @@ -0,0 +1,231 @@ +SOLVER CVODE +STARTING_TIME 0.0 +ENDING_TIME 500.0 +RELATIVE_TOLERANCE 1.0E-9 +ABSOLUTE_TOLERANCE 1.0E-9 +MAX_TIME_STEP 1.0 +KEEP_EVERY 1 +DISCONTINUITIES 200 +__D_B_98 (t >= 250.0); (-250.0 + t); +__D_B_37 (t <= 187.75510204081633); (-187.75510204081633 + t); +__D_B_138 (t >= 41.83673469387755); (-41.83673469387755 + t); +__D_B_118 (t >= 22.448979591836736); (-22.448979591836736 + t); +__D_B_122 (t >= 26.3265306122449); (-26.3265306122449 + t); +__D_B_30 (t >= 180.6122448979592); (-180.6122448979592 + t); +__D_B_165 (t <= 68.01020408163264); (-68.01020408163264 + t); +__D_B_180 (t >= 82.55102040816327); (-82.55102040816327 + t); +__D_B_77 (t <= 228.57142857142856); (-228.57142857142856 + t); +__D_B_13 (t <= 163.26530612244898); (-163.26530612244898 + t); +__D_B_28 (t >= 178.57142857142858); (-178.57142857142858 + t); +__D_B_137 (t <= 40.867346938775505); (-40.867346938775505 + t); +__D_B_89 (t <= 240.81632653061223); (-240.81632653061223 + t); +__D_B_198 (t >= 100.0); (-100.0 + t); +__D_B_142 (t >= 45.714285714285715); (-45.714285714285715 + t); +__D_B_42 (t >= 192.85714285714286); (-192.85714285714286 + t); +__D_B_35 (t <= 185.71428571428572); (-185.71428571428572 + t); +__D_B_50 (t >= 201.0204081632653); (-201.0204081632653 + t); +__D_B_179 (t <= 81.58163265306122); (-81.58163265306122 + t); +__D_B_31 (t <= 181.6326530612245); (-181.6326530612245 + t); +__D_B_67 (t <= 218.3673469387755); (-218.3673469387755 + t); +__D_B_164 (t >= 67.0408163265306); (-67.0408163265306 + t); +__D_B_40 (t >= 190.81632653061223); (-190.81632653061223 + t); +__D_B_29 (t <= 179.59183673469389); (-179.59183673469389 + t); +__D_B_45 (t <= 195.91836734693877); (-195.91836734693877 + t); +__D_B_66 (t >= 217.3469387755102); (-217.3469387755102 + t); +__D_B_15 (t <= 165.30612244897958); (-165.30612244897958 + t); +__D_B_47 (t <= 197.9591836734694); (-197.9591836734694 + t); +__D_B_130 (t >= 34.08163265306122); (-34.08163265306122 + t); +__D_B_147 (t <= 50.56122448979591); (-50.56122448979591 + t); +__D_B_182 (t >= 84.48979591836735); (-84.48979591836735 + t); +__D_B_156 (t >= 59.285714285714285); (-59.285714285714285 + t); +__D_B_9 (t <= 159.18367346938774); (-159.18367346938774 + t); +__D_B_60 (t >= 211.22448979591837); (-211.22448979591837 + t); +__D_B_82 (t >= 233.67346938775512); (-233.67346938775512 + t); +__D_B_22 (t >= 172.44897959183675); (-172.44897959183675 + t); +__D_B_51 (t <= 202.0408163265306); (-202.0408163265306 + t); +__D_B_189 (t <= 91.27551020408163); (-91.27551020408163 + t); +__D_B_91 (t <= 242.85714285714286); (-242.85714285714286 + t); +__D_B_143 (t <= 46.68367346938775); (-46.68367346938775 + t); +__D_B_117 (t <= 21.479591836734684); (-21.479591836734684 + t); +__D_B_73 (t <= 224.48979591836735); (-224.48979591836735 + t); +__D_B_12 (t >= 162.24489795918367); (-162.24489795918367 + t); +__D_B_162 (t >= 65.10204081632654); (-65.10204081632654 + t); +__D_B_184 (t >= 86.42857142857143); (-86.42857142857143 + t); +__D_B_109 (t <= 13.724489795918359); (-13.724489795918359 + t); +__D_B_16 (t >= 166.3265306122449); (-166.3265306122449 + t); +__D_B_36 (t >= 186.73469387755102); (-186.73469387755102 + t); +__D_B_86 (t >= 237.75510204081633); (-237.75510204081633 + t); +__D_B_135 (t <= 38.92857142857142); (-38.92857142857142 + t); +__D_B_174 (t >= 76.73469387755102); (-76.73469387755102 + t); +__D_B_145 (t <= 48.62244897959183); (-48.62244897959183 + t); +__D_B_140 (t >= 43.775510204081634); (-43.775510204081634 + t); +__D_B_111 (t <= 15.663265306122442); (-15.663265306122442 + t); +__D_B_110 (t >= 14.693877551020408); (-14.693877551020408 + t); +__D_B_103 (t <= 7.908163265306115); (-7.908163265306115 + t); +__D_B_161 (t <= 64.13265306122449); (-64.13265306122449 + t); +__D_B_194 (t >= 96.12244897959184); (-96.12244897959184 + t); +__D_B_8 (t >= 158.16326530612244); (-158.16326530612244 + t); +__D_B_139 (t <= 42.806122448979586); (-42.806122448979586 + t); +__D_B_1 (t <= 151.0204081632653); (-151.0204081632653 + t); +__D_B_62 (t >= 213.26530612244898); (-213.26530612244898 + t); +__D_B_76 (t >= 227.55102040816325); (-227.55102040816325 + t); +__D_B_85 (t <= 236.73469387755102); (-236.73469387755102 + t); +__D_B_128 (t >= 32.14285714285714); (-32.14285714285714 + t); +__D_B_61 (t <= 212.24489795918367); (-212.24489795918367 + t); +__D_B_33 (t <= 183.6734693877551); (-183.6734693877551 + t); +__D_B_159 (t <= 62.1938775510204); (-62.1938775510204 + t); +__D_B_23 (t <= 173.46938775510205); (-173.46938775510205 + t); +__D_B_144 (t >= 47.6530612244898); (-47.6530612244898 + t); +__D_B_7 (t <= 157.14285714285714); (-157.14285714285714 + t); +__D_B_21 (t <= 171.42857142857142); (-171.42857142857142 + t); +__D_B_136 (t >= 39.89795918367347); (-39.89795918367347 + t); +__D_B_52 (t >= 203.0612244897959); (-203.0612244897959 + t); +__D_B_10 (t >= 160.20408163265307); (-160.20408163265307 + t); +__D_B_2 (t >= 152.0408163265306); (-152.0408163265306 + t); +__D_B_157 (t <= 60.25510204081632); (-60.25510204081632 + t); +__D_B_48 (t >= 198.9795918367347); (-198.9795918367347 + t); +__D_B_58 (t >= 209.18367346938777); (-209.18367346938777 + t); +__D_B_24 (t >= 174.48979591836735); (-174.48979591836735 + t); +__D_B_87 (t <= 238.77551020408163); (-238.77551020408163 + t); +__D_B_146 (t >= 49.59183673469388); (-49.59183673469388 + t); +__D_B_106 (t >= 10.816326530612244); (-10.816326530612244 + t); +__D_B_53 (t <= 204.0816326530612); (-204.0816326530612 + t); +__D_B_54 (t >= 205.10204081632654); (-205.10204081632654 + t); +__D_B_148 (t >= 51.53061224489796); (-51.53061224489796 + t); +__D_B_59 (t <= 210.20408163265307); (-210.20408163265307 + t); +__D_B_108 (t >= 12.755102040816325); (-12.755102040816325 + t); +__D_B_56 (t >= 207.14285714285714); (-207.14285714285714 + t); +__D_B_169 (t <= 71.88775510204081); (-71.88775510204081 + t); +__D_B_101 (t <= 5.969387755102034); (-5.969387755102034 + t); +__D_B_4 (t >= 154.08163265306123); (-154.08163265306123 + t); +__D_B_32 (t >= 182.6530612244898); (-182.6530612244898 + t); +__D_B_74 (t >= 225.51020408163265); (-225.51020408163265 + t); +__D_B_114 (t >= 18.57142857142857); (-18.57142857142857 + t); +__D_B_72 (t >= 223.46938775510205); (-223.46938775510205 + t); +__D_B_119 (t <= 23.41836734693877); (-23.41836734693877 + t); +__D_B_113 (t <= 17.60204081632652); (-17.60204081632652 + t); +__D_B_181 (t <= 83.5204081632653); (-83.5204081632653 + t); +__D_B_90 (t >= 241.83673469387756); (-241.83673469387756 + t); +__D_B_5 (t <= 155.10204081632654); (-155.10204081632654 + t); +__D_B_191 (t <= 93.21428571428571); (-93.21428571428571 + t); +__D_B_133 (t <= 36.989795918367335); (-36.989795918367335 + t); +__D_B_17 (t <= 167.3469387755102); (-167.3469387755102 + t); +__D_B_27 (t <= 177.55102040816325); (-177.55102040816325 + t); +__D_B_177 (t <= 79.64285714285714); (-79.64285714285714 + t); +__D_B_183 (t <= 85.45918367346938); (-85.45918367346938 + t); +__D_B_188 (t >= 90.3061224489796); (-90.3061224489796 + t); +__D_B_132 (t >= 36.0204081632653); (-36.0204081632653 + t); +__D_B_152 (t >= 55.40816326530612); (-55.40816326530612 + t); +__D_B_149 (t <= 52.49999999999999); (-52.49999999999999 + t); +__D_B_79 (t <= 230.6122448979592); (-230.6122448979592 + t); +__D_B_116 (t >= 20.51020408163265); (-20.51020408163265 + t); +__D_B_18 (t >= 168.3673469387755); (-168.3673469387755 + t); +__D_B_96 (t >= 247.9591836734694); (-247.9591836734694 + t); +__D_B_160 (t >= 63.16326530612245); (-63.16326530612245 + t); +__D_B_187 (t <= 89.33673469387755); (-89.33673469387755 + t); +__D_B_55 (t <= 206.12244897959184); (-206.12244897959184 + t); +__D_B_70 (t >= 221.42857142857144); (-221.42857142857144 + t); +__D_B_95 (t <= 246.9387755102041); (-246.9387755102041 + t); +__D_B_38 (t >= 188.77551020408163); (-188.77551020408163 + t); +__D_B_178 (t >= 80.61224489795919); (-80.61224489795919 + t); +__D_B_26 (t >= 176.53061224489795); (-176.53061224489795 + t); +__D_B_158 (t >= 61.224489795918366); (-61.224489795918366 + t); +__D_B_175 (t <= 77.70408163265306); (-77.70408163265306 + t); +__D_B_99 (t <= 251.0204081632653); (-251.0204081632653 + t); +__D_B_107 (t <= 11.785714285714278); (-11.785714285714278 + t); +__D_B_19 (t <= 169.3877551020408); (-169.3877551020408 + t); +__D_B_168 (t >= 70.91836734693878); (-70.91836734693878 + t); +__D_B_3 (t <= 153.0612244897959); (-153.0612244897959 + t); +__D_B_39 (t <= 189.79591836734693); (-189.79591836734693 + t); +__D_B_171 (t <= 73.8265306122449); (-73.8265306122449 + t); +__D_B_25 (t <= 175.51020408163265); (-175.51020408163265 + t); +__D_B_167 (t <= 69.94897959183673); (-69.94897959183673 + t); +__D_B_6 (t >= 156.12244897959184); (-156.12244897959184 + t); +__D_B_176 (t >= 78.6734693877551); (-78.6734693877551 + t); +__D_B_123 (t <= 27.295918367346932); (-27.295918367346932 + t); +__D_B_155 (t <= 58.31632653061224); (-58.31632653061224 + t); +__D_B_141 (t <= 44.74489795918367); (-44.74489795918367 + t); +__D_B_197 (t <= 99.03061224489795); (-99.03061224489795 + t); +__D_B_64 (t >= 215.30612244897958); (-215.30612244897958 + t); +__D_B_170 (t >= 72.85714285714286); (-72.85714285714286 + t); +__D_B_112 (t >= 16.632653061224488); (-16.632653061224488 + t); +__D_B_151 (t <= 54.438775510204074); (-54.438775510204074 + t); +__D_B_94 (t >= 245.9183673469388); (-245.9183673469388 + t); +__D_B_192 (t >= 94.18367346938776); (-94.18367346938776 + t); +__D_B_125 (t <= 29.234693877551013); (-29.234693877551013 + t); +__D_B_153 (t <= 56.377551020408156); (-56.377551020408156 + t); +__D_B_100 (t >= 5.0); (-5.0 + t); +__D_B_69 (t <= 220.40816326530611); (-220.40816326530611 + t); +__D_B_84 (t >= 235.71428571428572); (-235.71428571428572 + t); +__D_B_150 (t >= 53.46938775510204); (-53.46938775510204 + t); +__D_B_131 (t <= 35.051020408163254); (-35.051020408163254 + t); +__D_B_44 (t >= 194.89795918367346); (-194.89795918367346 + t); +__D_B_41 (t <= 191.83673469387753); (-191.83673469387753 + t); +__D_B_49 (t <= 200.0); (-200.0 + t); +__D_B_0 (t >= 150.0); (-150.0 + t); +__D_B_75 (t <= 226.53061224489795); (-226.53061224489795 + t); +__D_B_88 (t >= 239.79591836734693); (-239.79591836734693 + t); +__D_B_196 (t >= 98.06122448979592); (-98.06122448979592 + t); +__D_B_105 (t <= 9.846938775510196); (-9.846938775510196 + t); +__D_B_63 (t <= 214.28571428571428); (-214.28571428571428 + t); +__D_B_80 (t >= 231.6326530612245); (-231.6326530612245 + t); +__D_B_83 (t <= 234.69387755102042); (-234.69387755102042 + t); +__D_B_93 (t <= 244.89795918367346); (-244.89795918367346 + t); +__D_B_57 (t <= 208.16326530612244); (-208.16326530612244 + t); +__D_B_127 (t <= 31.173469387755095); (-31.173469387755095 + t); +__D_B_185 (t <= 87.39795918367346); (-87.39795918367346 + t); +__D_B_115 (t <= 19.540816326530603); (-19.540816326530603 + t); +__D_B_71 (t <= 222.44897959183675); (-222.44897959183675 + t); +__D_B_172 (t >= 74.79591836734694); (-74.79591836734694 + t); +__D_B_199 (t <= 100.96938775510203); (-100.96938775510203 + t); +__D_B_186 (t >= 88.36734693877551); (-88.36734693877551 + t); +__D_B_129 (t <= 33.11224489795917); (-33.11224489795917 + t); +__D_B_14 (t >= 164.28571428571428); (-164.28571428571428 + t); +__D_B_134 (t >= 37.95918367346939); (-37.95918367346939 + t); +__D_B_68 (t >= 219.3877551020408); (-219.3877551020408 + t); +__D_B_193 (t <= 95.15306122448979); (-95.15306122448979 + t); +__D_B_11 (t <= 161.22448979591837); (-161.22448979591837 + t); +__D_B_163 (t <= 66.07142857142857); (-66.07142857142857 + t); +__D_B_124 (t >= 28.26530612244898); (-28.26530612244898 + t); +__D_B_20 (t >= 170.40816326530611); (-170.40816326530611 + t); +__D_B_43 (t <= 193.87755102040816); (-193.87755102040816 + t); +__D_B_102 (t >= 6.938775510204081); (-6.938775510204081 + t); +__D_B_166 (t >= 68.9795918367347); (-68.9795918367347 + t); +__D_B_65 (t <= 216.32653061224488); (-216.32653061224488 + t); +__D_B_92 (t >= 243.87755102040816); (-243.87755102040816 + t); +__D_B_120 (t >= 24.387755102040817); (-24.387755102040817 + t); +__D_B_154 (t >= 57.3469387755102); (-57.3469387755102 + t); +__D_B_46 (t >= 196.9387755102041); (-196.9387755102041 + t); +__D_B_34 (t >= 184.69387755102042); (-184.69387755102042 + t); +__D_B_190 (t >= 92.24489795918367); (-92.24489795918367 + t); +__D_B_97 (t <= 248.9795918367347); (-248.9795918367347 + t); +__D_B_121 (t <= 25.35714285714285); (-25.35714285714285 + t); +__D_B_78 (t >= 229.59183673469389); (-229.59183673469389 + t); +__D_B_173 (t <= 75.76530612244898); (-75.76530612244898 + t); +__D_B_195 (t <= 97.09183673469387); (-97.09183673469387 + t); +__D_B_126 (t >= 30.20408163265306); (-30.20408163265306 + t); +__D_B_81 (t <= 232.6530612244898); (-232.6530612244898 + t); +__D_B_104 (t >= 8.877551020408163); (-8.877551020408163 + t); +EVENTS 2 +EVENT event1 +TRIGGER (((__D_B_0 == 1.0) && (__D_B_1 == 1.0)) || ((__D_B_2 == 1.0) && (__D_B_3 == 1.0)) || ((__D_B_4 == 1.0) && (__D_B_5 == 1.0)) || ((__D_B_6 == 1.0) && (__D_B_7 == 1.0)) || ((__D_B_8 == 1.0) && (__D_B_9 == 1.0)) || ((__D_B_10 == 1.0) && (__D_B_11 == 1.0)) || ((__D_B_12 == 1.0) && (__D_B_13 == 1.0)) || ((__D_B_14 == 1.0) && (__D_B_15 == 1.0)) || ((__D_B_16 == 1.0) && (__D_B_17 == 1.0)) || ((__D_B_18 == 1.0) && (__D_B_19 == 1.0)) || ((__D_B_20 == 1.0) && (__D_B_21 == 1.0)) || ((__D_B_22 == 1.0) && (__D_B_23 == 1.0)) || ((__D_B_24 == 1.0) && (__D_B_25 == 1.0)) || ((__D_B_26 == 1.0) && (__D_B_27 == 1.0)) || ((__D_B_28 == 1.0) && (__D_B_29 == 1.0)) || ((__D_B_30 == 1.0) && (__D_B_31 == 1.0)) || ((__D_B_32 == 1.0) && (__D_B_33 == 1.0)) || ((__D_B_34 == 1.0) && (__D_B_35 == 1.0)) || ((__D_B_36 == 1.0) && (__D_B_37 == 1.0)) || ((__D_B_38 == 1.0) && (__D_B_39 == 1.0)) || ((__D_B_40 == 1.0) && (__D_B_41 == 1.0)) || ((__D_B_42 == 1.0) && (__D_B_43 == 1.0)) || ((__D_B_44 == 1.0) && (__D_B_45 == 1.0)) || ((__D_B_46 == 1.0) && (__D_B_47 == 1.0)) || ((__D_B_48 == 1.0) && (__D_B_49 == 1.0)) || ((__D_B_50 == 1.0) && (__D_B_51 == 1.0)) || ((__D_B_52 == 1.0) && (__D_B_53 == 1.0)) || ((__D_B_54 == 1.0) && (__D_B_55 == 1.0)) || ((__D_B_56 == 1.0) && (__D_B_57 == 1.0)) || ((__D_B_58 == 1.0) && (__D_B_59 == 1.0)) || ((__D_B_60 == 1.0) && (__D_B_61 == 1.0)) || ((__D_B_62 == 1.0) && (__D_B_63 == 1.0)) || ((__D_B_64 == 1.0) && (__D_B_65 == 1.0)) || ((__D_B_66 == 1.0) && (__D_B_67 == 1.0)) || ((__D_B_68 == 1.0) && (__D_B_69 == 1.0)) || ((__D_B_70 == 1.0) && (__D_B_71 == 1.0)) || ((__D_B_72 == 1.0) && (__D_B_73 == 1.0)) || ((__D_B_74 == 1.0) && (__D_B_75 == 1.0)) || ((__D_B_76 == 1.0) && (__D_B_77 == 1.0)) || ((__D_B_78 == 1.0) && (__D_B_79 == 1.0)) || ((__D_B_80 == 1.0) && (__D_B_81 == 1.0)) || ((__D_B_82 == 1.0) && (__D_B_83 == 1.0)) || ((__D_B_84 == 1.0) && (__D_B_85 == 1.0)) || ((__D_B_86 == 1.0) && (__D_B_87 == 1.0)) || ((__D_B_88 == 1.0) && (__D_B_89 == 1.0)) || ((__D_B_90 == 1.0) && (__D_B_91 == 1.0)) || ((__D_B_92 == 1.0) && (__D_B_93 == 1.0)) || ((__D_B_94 == 1.0) && (__D_B_95 == 1.0)) || ((__D_B_96 == 1.0) && (__D_B_97 == 1.0)) || ((__D_B_98 == 1.0) && (__D_B_99 == 1.0))); +EVENTASSIGNMENTS 1 +0 (-5.0 + A); +EVENT event0 +TRIGGER (((__D_B_100 == 1.0) && (__D_B_101 == 1.0)) || ((__D_B_102 == 1.0) && (__D_B_103 == 1.0)) || ((__D_B_104 == 1.0) && (__D_B_105 == 1.0)) || ((__D_B_106 == 1.0) && (__D_B_107 == 1.0)) || ((__D_B_108 == 1.0) && (__D_B_109 == 1.0)) || ((__D_B_110 == 1.0) && (__D_B_111 == 1.0)) || ((__D_B_112 == 1.0) && (__D_B_113 == 1.0)) || ((__D_B_114 == 1.0) && (__D_B_115 == 1.0)) || ((__D_B_116 == 1.0) && (__D_B_117 == 1.0)) || ((__D_B_118 == 1.0) && (__D_B_119 == 1.0)) || ((__D_B_120 == 1.0) && (__D_B_121 == 1.0)) || ((__D_B_122 == 1.0) && (__D_B_123 == 1.0)) || ((__D_B_124 == 1.0) && (__D_B_125 == 1.0)) || ((__D_B_126 == 1.0) && (__D_B_127 == 1.0)) || ((__D_B_128 == 1.0) && (__D_B_129 == 1.0)) || ((__D_B_130 == 1.0) && (__D_B_131 == 1.0)) || ((__D_B_132 == 1.0) && (__D_B_133 == 1.0)) || ((__D_B_134 == 1.0) && (__D_B_135 == 1.0)) || ((__D_B_136 == 1.0) && (__D_B_137 == 1.0)) || ((__D_B_138 == 1.0) && (__D_B_139 == 1.0)) || ((__D_B_140 == 1.0) && (__D_B_141 == 1.0)) || ((__D_B_142 == 1.0) && (__D_B_143 == 1.0)) || ((__D_B_144 == 1.0) && (__D_B_145 == 1.0)) || ((__D_B_146 == 1.0) && (__D_B_147 == 1.0)) || ((__D_B_148 == 1.0) && (__D_B_149 == 1.0)) || ((__D_B_150 == 1.0) && (__D_B_151 == 1.0)) || ((__D_B_152 == 1.0) && (__D_B_153 == 1.0)) || ((__D_B_154 == 1.0) && (__D_B_155 == 1.0)) || ((__D_B_156 == 1.0) && (__D_B_157 == 1.0)) || ((__D_B_158 == 1.0) && (__D_B_159 == 1.0)) || ((__D_B_160 == 1.0) && (__D_B_161 == 1.0)) || ((__D_B_162 == 1.0) && (__D_B_163 == 1.0)) || ((__D_B_164 == 1.0) && (__D_B_165 == 1.0)) || ((__D_B_166 == 1.0) && (__D_B_167 == 1.0)) || ((__D_B_168 == 1.0) && (__D_B_169 == 1.0)) || ((__D_B_170 == 1.0) && (__D_B_171 == 1.0)) || ((__D_B_172 == 1.0) && (__D_B_173 == 1.0)) || ((__D_B_174 == 1.0) && (__D_B_175 == 1.0)) || ((__D_B_176 == 1.0) && (__D_B_177 == 1.0)) || ((__D_B_178 == 1.0) && (__D_B_179 == 1.0)) || ((__D_B_180 == 1.0) && (__D_B_181 == 1.0)) || ((__D_B_182 == 1.0) && (__D_B_183 == 1.0)) || ((__D_B_184 == 1.0) && (__D_B_185 == 1.0)) || ((__D_B_186 == 1.0) && (__D_B_187 == 1.0)) || ((__D_B_188 == 1.0) && (__D_B_189 == 1.0)) || ((__D_B_190 == 1.0) && (__D_B_191 == 1.0)) || ((__D_B_192 == 1.0) && (__D_B_193 == 1.0)) || ((__D_B_194 == 1.0) && (__D_B_195 == 1.0)) || ((__D_B_196 == 1.0) && (__D_B_197 == 1.0)) || ((__D_B_198 == 1.0) && (__D_B_199 == 1.0))); +EVENTASSIGNMENTS 1 +0 (5.0 + A); +NUM_EQUATIONS 6 +ODE A INIT 10.0; + RATE 0.0; +ODE OCT4 INIT 0.01; + RATE ((1000.0 * (1.0E-4 + A + (0.01 * OCT4_SOX2) + (0.2 * NANOG * OCT4_SOX2)) / (1000.0001 + (1.1 * A) + OCT4_SOX2 + (0.7 * NANOG * OCT4_SOX2))) - OCT4 - ((0.05 * OCT4 * SOX2) - (0.001 * OCT4_SOX2))); +ODE SOX2 INIT 0.01; + RATE ( - ((0.05 * OCT4 * SOX2) - (0.001 * OCT4_SOX2)) + (1000.0 * (1.0E-4 + A + (0.01 * OCT4_SOX2) + (0.2 * NANOG * OCT4_SOX2)) / (1000.0001 + (1.1 * A) + OCT4_SOX2 + (0.7 * NANOG * OCT4_SOX2))) - SOX2); +ODE NANOG INIT 0.01; + RATE (((1.0E-4 + (0.005 * OCT4_SOX2) + (0.1 * OCT4_SOX2 * NANOG)) / (1.0000001 + (9.95E-4 * OCT4_SOX2) + (0.001 * OCT4_SOX2 * NANOG))) - NANOG); +ODE OCT4_SOX2 INIT 0.1; + RATE ((0.05 * OCT4 * SOX2) - (0.001 * OCT4_SOX2) - (5.0 * OCT4_SOX2)); +ODE Protein INIT 0.0; + RATE ((1000.0 * (1.0E-4 + (0.1 * OCT4_SOX2)) / (1000.0001 + OCT4_SOX2 + (1000.0 * NANOG * OCT4_SOX2))) - (0.01 * Protein)); + diff --git a/tests/unit/resources/SimID_1607235431_0_.functions b/tests/unit/resources/SimID_1607235431_0_.functions new file mode 100644 index 000000000..94f84ae79 --- /dev/null +++ b/tests/unit/resources/SimID_1607235431_0_.functions @@ -0,0 +1,23 @@ +##--------------------------------------------- +## /Users/logandrescher/.vcell/simdata/temp/SimID_1607235431_0_.functions +##--------------------------------------------- + +Compartment::degradation; 0.0; ; Nonspatial_VariableType; false +event0.triggerFunction; (((t >= 5.0) && (t <= 5.969387755102034)) || ((t >= 6.938775510204081) && (t <= 7.908163265306115)) || ((t >= 8.877551020408163) && (t <= 9.846938775510196)) || ((t >= 10.816326530612244) && (t <= 11.785714285714278)) || ((t >= 12.755102040816325) && (t <= 13.724489795918359)) || ((t >= 14.693877551020408) && (t <= 15.663265306122442)) || ((t >= 16.632653061224488) && (t <= 17.60204081632652)) || ((t >= 18.57142857142857) && (t <= 19.540816326530603)) || ((t >= 20.51020408163265) && (t <= 21.479591836734684)) || ((t >= 22.448979591836736) && (t <= 23.41836734693877)) || ((t >= 24.387755102040817) && (t <= 25.35714285714285)) || ((t >= 26.3265306122449) && (t <= 27.295918367346932)) || ((t >= 28.26530612244898) && (t <= 29.234693877551013)) || ((t >= 30.20408163265306) && (t <= 31.173469387755095)) || ((t >= 32.14285714285714) && (t <= 33.11224489795917)) || ((t >= 34.08163265306122) && (t <= 35.051020408163254)) || ((t >= 36.0204081632653) && (t <= 36.989795918367335)) || ((t >= 37.95918367346939) && (t <= 38.92857142857142)) || ((t >= 39.89795918367347) && (t <= 40.867346938775505)) || ((t >= 41.83673469387755) && (t <= 42.806122448979586)) || ((t >= 43.775510204081634) && (t <= 44.74489795918367)) || ((t >= 45.714285714285715) && (t <= 46.68367346938775)) || ((t >= 47.6530612244898) && (t <= 48.62244897959183)) || ((t >= 49.59183673469388) && (t <= 50.56122448979591)) || ((t >= 51.53061224489796) && (t <= 52.49999999999999)) || ((t >= 53.46938775510204) && (t <= 54.438775510204074)) || ((t >= 55.40816326530612) && (t <= 56.377551020408156)) || ((t >= 57.3469387755102) && (t <= 58.31632653061224)) || ((t >= 59.285714285714285) && (t <= 60.25510204081632)) || ((t >= 61.224489795918366) && (t <= 62.1938775510204)) || ((t >= 63.16326530612245) && (t <= 64.13265306122449)) || ((t >= 65.10204081632654) && (t <= 66.07142857142857)) || ((t >= 67.0408163265306) && (t <= 68.01020408163264)) || ((t >= 68.9795918367347) && (t <= 69.94897959183673)) || ((t >= 70.91836734693878) && (t <= 71.88775510204081)) || ((t >= 72.85714285714286) && (t <= 73.8265306122449)) || ((t >= 74.79591836734694) && (t <= 75.76530612244898)) || ((t >= 76.73469387755102) && (t <= 77.70408163265306)) || ((t >= 78.6734693877551) && (t <= 79.64285714285714)) || ((t >= 80.61224489795919) && (t <= 81.58163265306122)) || ((t >= 82.55102040816327) && (t <= 83.5204081632653)) || ((t >= 84.48979591836735) && (t <= 85.45918367346938)) || ((t >= 86.42857142857143) && (t <= 87.39795918367346)) || ((t >= 88.36734693877551) && (t <= 89.33673469387755)) || ((t >= 90.3061224489796) && (t <= 91.27551020408163)) || ((t >= 92.24489795918367) && (t <= 93.21428571428571)) || ((t >= 94.18367346938776) && (t <= 95.15306122448979)) || ((t >= 96.12244897959184) && (t <= 97.09183673469387)) || ((t >= 98.06122448979592) && (t <= 99.03061224489795)) || ((t >= 100.0) && (t <= 100.96938775510203))); ; Nonspatial_VariableType; false +event1.triggerFunction; (((t >= 150.0) && (t <= 151.0204081632653)) || ((t >= 152.0408163265306) && (t <= 153.0612244897959)) || ((t >= 154.08163265306123) && (t <= 155.10204081632654)) || ((t >= 156.12244897959184) && (t <= 157.14285714285714)) || ((t >= 158.16326530612244) && (t <= 159.18367346938774)) || ((t >= 160.20408163265307) && (t <= 161.22448979591837)) || ((t >= 162.24489795918367) && (t <= 163.26530612244898)) || ((t >= 164.28571428571428) && (t <= 165.30612244897958)) || ((t >= 166.3265306122449) && (t <= 167.3469387755102)) || ((t >= 168.3673469387755) && (t <= 169.3877551020408)) || ((t >= 170.40816326530611) && (t <= 171.42857142857142)) || ((t >= 172.44897959183675) && (t <= 173.46938775510205)) || ((t >= 174.48979591836735) && (t <= 175.51020408163265)) || ((t >= 176.53061224489795) && (t <= 177.55102040816325)) || ((t >= 178.57142857142858) && (t <= 179.59183673469389)) || ((t >= 180.6122448979592) && (t <= 181.6326530612245)) || ((t >= 182.6530612244898) && (t <= 183.6734693877551)) || ((t >= 184.69387755102042) && (t <= 185.71428571428572)) || ((t >= 186.73469387755102) && (t <= 187.75510204081633)) || ((t >= 188.77551020408163) && (t <= 189.79591836734693)) || ((t >= 190.81632653061223) && (t <= 191.83673469387753)) || ((t >= 192.85714285714286) && (t <= 193.87755102040816)) || ((t >= 194.89795918367346) && (t <= 195.91836734693877)) || ((t >= 196.9387755102041) && (t <= 197.9591836734694)) || ((t >= 198.9795918367347) && (t <= 200.0)) || ((t >= 201.0204081632653) && (t <= 202.0408163265306)) || ((t >= 203.0612244897959) && (t <= 204.0816326530612)) || ((t >= 205.10204081632654) && (t <= 206.12244897959184)) || ((t >= 207.14285714285714) && (t <= 208.16326530612244)) || ((t >= 209.18367346938777) && (t <= 210.20408163265307)) || ((t >= 211.22448979591837) && (t <= 212.24489795918367)) || ((t >= 213.26530612244898) && (t <= 214.28571428571428)) || ((t >= 215.30612244897958) && (t <= 216.32653061224488)) || ((t >= 217.3469387755102) && (t <= 218.3673469387755)) || ((t >= 219.3877551020408) && (t <= 220.40816326530611)) || ((t >= 221.42857142857144) && (t <= 222.44897959183675)) || ((t >= 223.46938775510205) && (t <= 224.48979591836735)) || ((t >= 225.51020408163265) && (t <= 226.53061224489795)) || ((t >= 227.55102040816325) && (t <= 228.57142857142856)) || ((t >= 229.59183673469389) && (t <= 230.6122448979592)) || ((t >= 231.6326530612245) && (t <= 232.6530612244898)) || ((t >= 233.67346938775512) && (t <= 234.69387755102042)) || ((t >= 235.71428571428572) && (t <= 236.73469387755102)) || ((t >= 237.75510204081633) && (t <= 238.77551020408163)) || ((t >= 239.79591836734693) && (t <= 240.81632653061223)) || ((t >= 241.83673469387756) && (t <= 242.85714285714286)) || ((t >= 243.87755102040816) && (t <= 244.89795918367346)) || ((t >= 245.9183673469388) && (t <= 246.9387755102041)) || ((t >= 247.9591836734694) && (t <= 248.9795918367347)) || ((t >= 250.0) && (t <= 251.0204081632653))); ; Nonspatial_VariableType; false +Compartment::LumpedJ_J0; (1000.0 * (1.0E-4 + A + (0.01 * OCT4_SOX2) + (0.2 * NANOG * OCT4_SOX2)) / (1000.0001 + (1.1 * A) + OCT4_SOX2 + (0.7 * NANOG * OCT4_SOX2))); ; Nonspatial_VariableType; false +Compartment::LumpedJ_J1; OCT4; ; Nonspatial_VariableType; false +Compartment::LumpedJ_J2; ((1.0E-4 + (0.005 * OCT4_SOX2) + (0.1 * OCT4_SOX2 * NANOG)) / (1.0000001 + (9.95E-4 * OCT4_SOX2) + (0.001 * OCT4_SOX2 * NANOG))); ; Nonspatial_VariableType; false +Compartment::LumpedJ_J3; NANOG; ; Nonspatial_VariableType; false +Compartment::LumpedJ_J4; ((0.05 * OCT4 * SOX2) - (0.001 * OCT4_SOX2)); ; Nonspatial_VariableType; false +Compartment::LumpedJ_J5; (5.0 * OCT4_SOX2); ; Nonspatial_VariableType; false +Compartment::LumpedJ_J6; (1000.0 * (1.0E-4 + A + (0.01 * OCT4_SOX2) + (0.2 * NANOG * OCT4_SOX2)) / (1000.0001 + (1.1 * A) + OCT4_SOX2 + (0.7 * NANOG * OCT4_SOX2))); ; Nonspatial_VariableType; false +Compartment::LumpedJ_J7; SOX2; ; Nonspatial_VariableType; false +Compartment::LumpedJ_J8; (1000.0 * (1.0E-4 + (0.1 * OCT4_SOX2)) / (1000.0001 + OCT4_SOX2 + (1000.0 * NANOG * OCT4_SOX2))); ; Nonspatial_VariableType; false +Compartment::LumpedJ_J9; (0.01 * Protein); ; Nonspatial_VariableType; false +Compartment::NANOG_Gene; 0.0; ; Nonspatial_VariableType; false +Compartment::OCT4_Gene; 1.0; ; Nonspatial_VariableType; false +Compartment::p53; 0.0; ; Nonspatial_VariableType; false +Compartment::SOX2_Gene; 0.0; ; Nonspatial_VariableType; false +Compartment::targetGene; 0.01; ; Nonspatial_VariableType; false + diff --git a/tests/unit/resources/SimID_1607235431_0_.log b/tests/unit/resources/SimID_1607235431_0_.log new file mode 100644 index 000000000..89146ccf2 --- /dev/null +++ b/tests/unit/resources/SimID_1607235431_0_.log @@ -0,0 +1,4 @@ +IDAData logfile +IDAData text format version 1 +SimID_1607235431_0_.ida +KeepMost 1000 diff --git a/tests/unit/resources/SimID_1607235431_0__0.simtask.xml b/tests/unit/resources/SimID_1607235431_0__0.simtask.xml new file mode 100644 index 000000000..e41a76b03 --- /dev/null +++ b/tests/unit/resources/SimID_1607235431_0__0.simtask.xml @@ -0,0 +1,162 @@ + + + 96485.3321 + 9.64853321E-5 + 1.0E-9 + 6.02214179E11 + 3.141592653589793 + 8314.46261815 + 300.0 + 1.0 + 0.1 + 0.2 + 10.0 + 0.0 + 0.0011 + 0.001 + 7.0E-4 + 1.0 + 0.01 + 0.2 + 0.0011 + 0.001 + 7.0E-4 + 0.0 + 0.005 + 0.1 + 1.0E-4 + 1.0E-4 + 1.0E-4 + 1.0E-4 + 0.0 + 100.0 + 5.0 + 50.0 + 0.0 + 250.0 + 150.0 + 50.0 + 1000.0 + 0.001 + 9.95E-4 + 0.01 + 0.1 + 1.0 + 1.0 + 1.0 + 0.01 + 0.1 + 0.001 + 1.0 + 0.05 + 0.001 + 5.0 + 1000.0 + 0.001660538783162726 + 0.0 + 0.01 + 1.0 + 0.01 + 0.1 + 0.0 + 0.0 + 1.0 + 0.0 + 0.01 + 0.0 + 0.01 + + + + + + + degradation_init_l_1 + (((t >= event0.minTime) && (t <= (event0.minTime + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 1.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 1.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 2.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 2.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 3.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 3.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 4.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 4.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 5.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 5.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 6.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 6.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 7.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 7.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 8.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 8.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 9.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 9.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 10.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 10.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 11.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 11.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 12.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 12.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 13.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 13.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 14.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 14.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 15.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 15.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 16.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 16.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 17.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 17.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 18.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 18.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 19.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 19.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 20.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 20.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 21.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 21.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 22.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 22.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 23.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 23.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 24.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 24.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 25.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 25.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 26.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 26.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 27.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 27.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 28.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 28.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 29.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 29.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 30.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 30.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 31.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 31.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 32.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 32.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 33.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 33.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 34.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 34.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 35.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 35.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 36.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 36.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 37.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 37.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 38.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 38.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 39.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 39.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 40.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 40.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 41.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 41.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 42.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 42.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 43.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 43.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 44.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 44.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 45.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 45.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 46.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 46.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 47.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 47.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 48.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 48.0)) + 0.9693877551020336))) || ((t >= (event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 49.0))) && (t <= ((event0.minTime + (((event0.maxTime - event0.minTime) / (event0.numTimes + -1.0)) * 49.0)) + 0.9693877551020336)))) + (((t >= event1.minTime) && (t <= (event1.minTime + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 1.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 1.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 2.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 2.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 3.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 3.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 4.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 4.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 5.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 5.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 6.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 6.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 7.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 7.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 8.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 8.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 9.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 9.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 10.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 10.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 11.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 11.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 12.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 12.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 13.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 13.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 14.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 14.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 15.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 15.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 16.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 16.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 17.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 17.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 18.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 18.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 19.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 19.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 20.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 20.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 21.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 21.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 22.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 22.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 23.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 23.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 24.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 24.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 25.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 25.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 26.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 26.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 27.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 27.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 28.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 28.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 29.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 29.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 30.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 30.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 31.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 31.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 32.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 32.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 33.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 33.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 34.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 34.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 35.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 35.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 36.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 36.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 37.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 37.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 38.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 38.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 39.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 39.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 40.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 40.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 41.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 41.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 42.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 42.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 43.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 43.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 44.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 44.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 45.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 45.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 46.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 46.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 47.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 47.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 48.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 48.0)) + 1.0204081632653015))) || ((t >= (event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 49.0))) && (t <= ((event1.minTime + (((event1.maxTime - event1.minTime) / (event1.numTimes + -1.0)) * 49.0)) + 1.0204081632653015)))) + ((OCT4_Gene * f * ((A * a1) + (OCT4_SOX2 * a2) + (NANOG * OCT4_SOX2 * a3) + eta1)) / (eta1 + f + (A * b1 * f) + (OCT4_SOX2 * b2 * f) + (NANOG * OCT4_SOX2 * b3 * f))) + (OCT4 * gamma1) + ((eta5 + (e1 * OCT4_SOX2) + (e2 * OCT4_SOX2 * NANOG)) / (1.0 + (eta5 / f) + (f2 * OCT4_SOX2) + (f1 * OCT4_SOX2 * NANOG) + (f3 * p53))) + (NANOG * gamma2) + ((k1c * OCT4 * SOX2) - (k2c * OCT4_SOX2)) + (OCT4_SOX2 * k3c) + ((f * ((A * c1) + (OCT4_SOX2 * c2) + (NANOG * OCT4_SOX2 * c3) + eta3)) / (eta3 + f + (A * d1 * f) + (OCT4_SOX2 * d2 * f) + (NANOG * OCT4_SOX2 * d3 * f))) + (SOX2 * gamma3) + ((f * (eta7 + (OCT4_SOX2 * g1))) / (eta7 + f + (OCT4_SOX2 * f * h1) + (NANOG * OCT4_SOX2 * f * h2))) + (Protein * gamma4) + NANOG_Gene_init_l_1 + OCT4_Gene_init_l_1 + p53_init_l_1 + SOX2_Gene_init_l_1 + targetGene_init_l_1 + + + + + + + + + 0.0 + A_init_l_1 + + + ((LumpedJ_J0 / Size_compartment) - (LumpedJ_J1 / Size_compartment) - (LumpedJ_J4 / Size_compartment)) + OCT4_init_l_1 + + + ( - (LumpedJ_J4 / Size_compartment) + (LumpedJ_J6 / Size_compartment) - (LumpedJ_J7 / Size_compartment)) + SOX2_init_l_1 + + + ((LumpedJ_J2 / Size_compartment) - (LumpedJ_J3 / Size_compartment)) + NANOG_init_l_1 + + + ((LumpedJ_J4 / Size_compartment) - (LumpedJ_J5 / Size_compartment)) + OCT4_SOX2_init_l_1 + + + ((LumpedJ_J8 / Size_compartment) - (LumpedJ_J9 / Size_compartment)) + Protein_init_l_1 + + + + + + + + event1.triggerFunction + (A - 5.0) + + + event0.triggerFunction + (A + 5.0) + + + + + + + + + 1 + + + 0.01 + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/unit/resources/SimID_256118677_0_.cvodeInput b/tests/unit/resources/SimID_256118677_0_.cvodeInput new file mode 100644 index 000000000..f5786cddc --- /dev/null +++ b/tests/unit/resources/SimID_256118677_0_.cvodeInput @@ -0,0 +1,24 @@ +# JMS_Paramters +JMS_PARAM_BEGIN +JMS_BROKER vcell.cam.uchc.edu:30163 +JMS_USER clientUser dummy +JMS_QUEUE workerEvent +JMS_TOPIC serviceControl +VCELL_USER ldresche +SIMULATION_KEY 256118677 +JOB_INDEX 0 +JMS_PARAM_END + +SOLVER CVODE +STARTING_TIME 0.0 +ENDING_TIME 10.0 +RELATIVE_TOLERANCE 1.0E-9 +ABSOLUTE_TOLERANCE 1.0E-9 +MAX_TIME_STEP 1.0 +KEEP_EVERY 1 +NUM_EQUATIONS 2 +ODE s0 INIT 1.0; + RATE - ((0.5 * s0) - (0.2 * s1)); +ODE s1 INIT 0.0; + RATE ((0.5 * s0) - (0.2 * s1)); + diff --git a/tests/unit/resources/SimID_256118677_0_.functions b/tests/unit/resources/SimID_256118677_0_.functions new file mode 100644 index 000000000..380a43ce0 --- /dev/null +++ b/tests/unit/resources/SimID_256118677_0_.functions @@ -0,0 +1,6 @@ +##--------------------------------------------- +## /simdata/ldresche/SimID_256118677_0_.functions +##--------------------------------------------- + +Compartment::J_r0; ((0.5 * s0) - (0.2 * s1)); ; Nonspatial_VariableType; false + diff --git a/tests/unit/resources/SimID_256118677_0_.ida.expected b/tests/unit/resources/SimID_256118677_0_.ida.expected new file mode 100644 index 000000000..c0a71f95f --- /dev/null +++ b/tests/unit/resources/SimID_256118677_0_.ida.expected @@ -0,0 +1,159 @@ +t:s0:s1: +0.00000000000000000E+00 1.00000000000000000E+00 0.00000000000000000E+00 +1.02648488190150711E-10 9.99999999948675722E-01 5.13242440913875063E-11 +1.02658753038969712E-06 9.99999486706603657E-01 5.13293396373231300E-07 +1.12914363494047687E-05 9.99994354310467903E-01 5.64568953210529354E-06 +4.48211895830175010E-05 9.99977589784958321E-01 2.24102150417055293E-05 +1.17277047540880841E-04 9.99941363945291539E-01 5.86360547084540949E-05 +2.53272368309885381E-04 9.99873375142890652E-01 1.26624857109333797E-04 +4.96024984269423201E-04 9.99752030703600969E-01 2.47969296398973030E-04 +9.22698163574049712E-04 9.99538800058830001E-01 4.61199941169868684E-04 +1.68044365853622663E-03 9.99160272360433921E-01 8.39727639565850115E-04 +3.18862269929603417E-03 9.98407466672823207E-01 1.59253332717652126E-03 +5.45114110140219790E-03 9.97279622342691741E-01 2.72037765730797233E-03 +7.71365950350836119E-03 9.96153562661734271E-01 3.84643733826544416E-03 +9.97617790561452535E-03 9.95029284922585688E-01 4.97071507741405488E-03 +1.22386963077206895E-02 9.93906786345072457E-01 6.09321365492729479E-03 +1.45012147098268537E-02 9.92786064126930712E-01 7.21393587306905053E-03 +1.73952544462393256E-02 9.91355107543508862E-01 8.64489245649092790E-03 +2.02892941826517993E-02 9.89927047398444282E-01 1.00729526015555741E-02 +2.31833339190642730E-02 9.88501877601865031E-01 1.14981223981348198E-02 +2.60773736554767467E-02 9.87079592114147530E-01 1.29204078858523308E-02 +3.29068688347819438E-02 9.83734614715639721E-01 1.62653852843602023E-02 +3.97363640140871374E-02 9.80405590318767395E-01 1.95944096812325566E-02 +5.02957748456068915E-02 9.75289650084949389E-01 2.47103499150505036E-02 +6.08551856771266456E-02 9.70211385257129355E-01 2.97886147428706068E-02 +7.14145965086463996E-02 9.65170518189519044E-01 3.48294818104809070E-02 +8.19740073401661606E-02 9.60166773545884755E-01 3.98332264541152309E-02 +9.25334181716859216E-02 9.55199878101650190E-01 4.48001218983497956E-02 +1.09712253292456846E-01 9.47197402212381134E-01 5.28025977876188587E-02 +1.26891088413227771E-01 9.39290581299578320E-01 6.07094187004216662E-02 +1.44069923533998695E-01 9.31478272015571096E-01 6.85217279844288346E-02 +1.61248758654769619E-01 9.23759344630696533E-01 7.62406553693034117E-02 +1.89660049003499281E-01 9.11195316277009670E-01 8.88046837229902880E-02 +2.18071339352228943E-01 8.98878691567765453E-01 1.01121308432234533E-01 +2.46482629700958605E-01 8.86804598883420114E-01 1.13195401116579816E-01 +2.74893920049688267E-01 8.74968262536995778E-01 1.25031737463004083E-01 +3.03305210398417957E-01 8.63365000789078185E-01 1.36634999210921676E-01 +3.31716500747147647E-01 8.51990224040054867E-01 1.48009775959944967E-01 +3.60127791095877337E-01 8.40839433068397923E-01 1.59160566931601855E-01 +3.88539081444607026E-01 8.29908217266169590E-01 1.70091782733830132E-01 +4.41138445070370255E-01 8.10235627189399343E-01 1.89764372810600435E-01 +4.77567574856914034E-01 7.97029226508457089E-01 2.02970773491542689E-01 +5.13996704643457814E-01 7.84155337872014080E-01 2.15844662127985643E-01 +5.50425834430001593E-01 7.71605588560225097E-01 2.28394411439774653E-01 +5.86854964216545372E-01 7.59371816557104728E-01 2.40628183442894966E-01 +6.23284094003089151E-01 7.47446066126369102E-01 2.52553933873630565E-01 +6.59713223789632930E-01 7.35820582268969181E-01 2.64179417731030486E-01 +6.96142353576176709E-01 7.24487805053363076E-01 2.75512194946636535E-01 +7.58815310233661888E-01 7.05654481953680968E-01 2.94345518046318699E-01 +8.21488266891147068E-01 6.87629536154125143E-01 3.12370463845874413E-01 +8.84161223548632247E-01 6.70378268923642939E-01 3.29621731076356561E-01 +9.46834180206117426E-01 6.53867470964243247E-01 3.46132529035756198E-01 +1.00950713686360261E+00 6.38065359483856231E-01 3.61934640516143269E-01 +1.07218009352108767E+00 6.22941516449129762E-01 3.77058483550869794E-01 +1.13485305017857274E+00 6.08466829122856878E-01 3.91533170877142678E-01 +1.19752600683605781E+00 5.94613433892461130E-01 4.05386566107538426E-01 +1.26019896349354288E+00 5.81354663050361431E-01 4.18645336949638014E-01 +1.32287192015102795E+00 5.68664993725449097E-01 4.31335006274550459E-01 +1.38554487680851302E+00 5.56519998669646965E-01 4.43480001330352702E-01 +1.44821783346599808E+00 5.44896299070346424E-01 4.55103700929653243E-01 +1.51089079012348315E+00 5.33771519516928472E-01 4.66228480483071195E-01 +1.57356374678096822E+00 5.23124244999401800E-01 4.76875755000597867E-01 +1.63623670343845329E+00 5.12933979731394318E-01 4.87066020268605349E-01 +1.69890966009593836E+00 5.03181107681094364E-01 4.96818892318905247E-01 +1.76158261675342342E+00 4.93846854780748468E-01 5.06153145219251144E-01 +1.82425557341090849E+00 4.84913252781268178E-01 5.15086747218731489E-01 +1.88692853006839356E+00 4.76363104676305715E-01 5.23636895323693952E-01 +1.94960148672587863E+00 4.68179951606793432E-01 5.31820048393206291E-01 +2.01227444338336392E+00 4.60348041167775057E-01 5.39651958832224610E-01 +2.07494740004084921E+00 4.52852297094320178E-01 5.47147702905679489E-01 +2.13762035669833450E+00 4.45678290239669095E-01 5.54321709760330572E-01 +2.20029331335581979E+00 4.38812210792762725E-01 5.61187789207236998E-01 +2.26296627001330508E+00 4.32240841692172695E-01 5.67759158307827083E-01 +2.32563922667079037E+00 4.25951533186333664E-01 5.74048466813666169E-01 +2.38831218332827566E+00 4.19932178485779350E-01 5.80067821514220539E-01 +2.45098513998576095E+00 4.14171190457713889E-01 5.85828809542286000E-01 +2.51365809664324624E+00 4.08657479319653238E-01 5.91342520680346651E-01 +2.57633105330073153E+00 4.03380431291335495E-01 5.96619568708664394E-01 +2.63900400995821682E+00 3.98329888163913515E-01 6.01670111836086319E-01 +2.70167696661570211E+00 3.93496127746071123E-01 6.06503872253928655E-01 +2.76434992327318740E+00 3.88869845148941795E-01 6.11130154851058038E-01 +2.82702287993067269E+00 3.84442134874129537E-01 6.15557865125870296E-01 +2.88969583658815798E+00 3.80204473670731957E-01 6.19795526329267821E-01 +2.95236879324564327E+00 3.76148704128358324E-01 6.23851295871641454E-01 +3.01504174990312857E+00 3.72267018974363595E-01 6.27732981025636239E-01 +3.07771470656061386E+00 3.68551946044992529E-01 6.31448053955007249E-01 +3.14038766321809915E+00 3.64996333901570436E-01 6.35003666098429287E-01 +3.20306061987558444E+00 3.61593338064120084E-01 6.38406661935879582E-01 +3.26573357653306973E+00 3.58336407835898707E-01 6.41663592164100960E-01 +3.32840653319055502E+00 3.55219273693456239E-01 6.44780726306543484E-01 +3.39107948984804031E+00 3.52235935217927731E-01 6.47764064782072047E-01 +3.45375244650552560E+00 3.49380649544342170E-01 6.50619350455657663E-01 +3.51642540316301089E+00 3.46647920306724255E-01 6.53352079693275467E-01 +3.57909835982049618E+00 3.44032487057707448E-01 6.55967512942292386E-01 +3.64177131647798147E+00 3.41529315142283463E-01 6.58470684857716426E-01 +3.70444427313546676E+00 3.39133586006194754E-01 6.60866413993805191E-01 +3.76711722979295205E+00 3.36840687920315074E-01 6.63159312079684926E-01 +3.82979018645043734E+00 3.34646207103166171E-01 6.65353792896833829E-01 +3.89246314310792263E+00 3.32545919224480291E-01 6.67454080775519709E-01 +3.95513609976540792E+00 3.30535781273451845E-01 6.69464218726548155E-01 +4.01780905642289277E+00 3.28611923776025050E-01 6.71388076223975006E-01 +4.08048201308037761E+00 3.26770643346235901E-01 6.73229356653764155E-01 +4.14315496973786246E+00 3.25008395557270624E-01 6.74991604442729431E-01 +4.20582792639534730E+00 3.23321788118517361E-01 6.76678211881482694E-01 +4.26850088305283215E+00 3.21707574345476921E-01 6.78292425654523079E-01 +4.36259663226557493E+00 3.19413195181034726E-01 6.80586804818965274E-01 +4.45669238147831770E+00 3.17265070740067878E-01 6.82734929259932066E-01 +4.55078813069106047E+00 3.15253877871656929E-01 6.84746122128343071E-01 +4.64488387990380325E+00 3.13370887632055728E-01 6.86629112367944217E-01 +4.73897962911654602E+00 3.11607927741266999E-01 6.88392072258733001E-01 +4.83307537832928880E+00 3.09957347043537612E-01 6.90042652956462388E-01 +4.92717112754203157E+00 3.08411982061210621E-01 6.91588017938789434E-01 +5.02126687675477434E+00 3.06965125834067321E-01 6.93034874165932679E-01 +5.11536262596751712E+00 3.05610498904494543E-01 6.94389501095505457E-01 +5.20945837518025989E+00 3.04342222141284424E-01 6.95657777858715631E-01 +5.30355412439300267E+00 3.03154791209282182E-01 6.96845208790717763E-01 +5.39764987360574544E+00 3.02043052635592169E-01 6.97956947364407831E-01 +5.49174562281848821E+00 3.01002181432545757E-01 6.98997818567454243E-01 +5.58584137203123099E+00 3.00027660175653355E-01 6.99972339824346701E-01 +5.67993712124397376E+00 2.99115259411111445E-01 7.00884740588888611E-01 +5.77403287045671654E+00 2.98261019295870233E-01 7.01738980704129878E-01 +5.86812861966945931E+00 2.97461232403345710E-01 7.02538767596654345E-01 +5.96222436888220209E+00 2.96712427631590503E-01 7.03287572368409553E-01 +6.05632011809494486E+00 2.96011355142305865E-01 7.03988644857694190E-01 +6.15041586730768763E+00 2.95354972258738302E-01 7.04645027741261698E-01 +6.24451161652043041E+00 2.94740430259425534E-01 7.05259569740574466E-01 +6.33860736573317318E+00 2.94165062013088063E-01 7.05834937986911881E-01 +6.43270311494591596E+00 2.93626370403025250E-01 7.06373629596974695E-01 +6.52679886415865873E+00 2.93122017490281217E-01 7.06877982509718672E-01 +6.62089461337140150E+00 2.92649814367307026E-01 7.07350185632692807E-01 +6.71499036258414428E+00 2.92207711657821112E-01 7.07792288342178666E-01 +6.80908611179688705E+00 2.91793790622163152E-01 7.08206209377836515E-01 +6.90318186100962983E+00 2.91406254829892186E-01 7.08593745170107536E-01 +6.99727761022237260E+00 2.91043422363364113E-01 7.08956577636635665E-01 +7.09137335943511538E+00 2.90703718518221410E-01 7.09296281481778479E-01 +7.18546910864785815E+00 2.90385668969080357E-01 7.09614331030919643E-01 +7.27956485786060092E+00 2.90087893370859995E-01 7.09912106629139950E-01 +7.37366060707334370E+00 2.89809099368042500E-01 7.10190900631957334E-01 +7.46775635628608647E+00 2.89548076985837011E-01 7.10451923014162823E-01 +7.56185210549882925E+00 2.89303693378861304E-01 7.10696306621138585E-01 +7.65594785471157202E+00 2.89074887914547385E-01 7.10925112085452504E-01 +7.75004360392431479E+00 2.88860667569953156E-01 7.11139332430046678E-01 +7.84413935313705757E+00 2.88660102622012638E-01 7.11339897377987196E-01 +7.93823510234980034E+00 2.88472322612513654E-01 7.11527677387486235E-01 +8.08080669531667084E+00 2.88210359800015581E-01 7.11789640199984253E-01 +8.22337828828354134E+00 2.87973278978804759E-01 7.12026721021195130E-01 +8.36594988125041183E+00 2.87758716623703892E-01 7.12241283376295997E-01 +8.50852147421728233E+00 2.87564533611528172E-01 7.12435466388471661E-01 +8.65109306718415283E+00 2.87388794232750655E-01 7.12611205767249123E-01 +8.79366466015102333E+00 2.87229746815752529E-01 7.12770253184247249E-01 +8.93623625311789382E+00 2.87085806022613133E-01 7.12914193977386645E-01 +9.07880784608476432E+00 2.86955536978731940E-01 7.13044463021267783E-01 +9.22137943905163482E+00 2.86837641067565152E-01 7.13162358932434515E-01 +9.36395103201850532E+00 2.86730943062506516E-01 7.13269056937493207E-01 +9.50652262498537581E+00 2.86634379394257510E-01 7.13365620605742157E-01 +9.64909421795224631E+00 2.86546987502534933E-01 7.13453012497464734E-01 +9.79166581091911681E+00 2.86467896231261898E-01 7.13532103768737769E-01 +9.93423740388598731E+00 2.86396317164659742E-01 7.13603682835339925E-01 +1.00000000000000000E+01 2.86365632344379117E-01 7.13634367655620494E-01 diff --git a/tests/unit/resources/SimID_256118677_0_.log b/tests/unit/resources/SimID_256118677_0_.log new file mode 100644 index 000000000..afdb5aca5 --- /dev/null +++ b/tests/unit/resources/SimID_256118677_0_.log @@ -0,0 +1,4 @@ +IDAData logfile +IDAData text format version 1 +SimID_256118677_0_.ida +KeepMost 1000 diff --git a/tests/unit/resources/SimID_886118677_0_.cvodeInput b/tests/unit/resources/SimID_886118677_0_.cvodeInput new file mode 100644 index 000000000..9c0ba47e1 --- /dev/null +++ b/tests/unit/resources/SimID_886118677_0_.cvodeInput @@ -0,0 +1,24 @@ +# JMS_Paramters +JMS_PARAM_BEGIN +JMS_BROKER localhost:8161 +JMS_USER clientUser dummy +JMS_QUEUE workerEvent +JMS_TOPIC serviceControl +VCELL_USER ldresche +SIMULATION_KEY 886118677 +JOB_INDEX 0 +JMS_PARAM_END + +SOLVER CVODE +STARTING_TIME 0.0 +ENDING_TIME 10.0 +RELATIVE_TOLERANCE 1.0E-9 +ABSOLUTE_TOLERANCE 1.0E-9 +MAX_TIME_STEP 1.0 +KEEP_EVERY 1 +NUM_EQUATIONS 2 +ODE s0 INIT 1.0; + RATE - ((0.5 * s0) - (0.2 * s1)); +ODE s1 INIT 0.0; + RATE ((0.5 * s0) - (0.2 * s1)); + diff --git a/tests/unit/resources/SimID_886118677_0_.functions b/tests/unit/resources/SimID_886118677_0_.functions new file mode 100644 index 000000000..d82a8d6eb --- /dev/null +++ b/tests/unit/resources/SimID_886118677_0_.functions @@ -0,0 +1,6 @@ +##--------------------------------------------- +## /simdata/ldresche/SimID_886118677_0_.functions +##--------------------------------------------- + +Compartment::J_r0; ((0.5 * s0) - (0.2 * s1)); ; Nonspatial_VariableType; false + diff --git a/tests/unit/resources/SimID_886118677_0_.ida.expected b/tests/unit/resources/SimID_886118677_0_.ida.expected new file mode 100644 index 000000000..c0a71f95f --- /dev/null +++ b/tests/unit/resources/SimID_886118677_0_.ida.expected @@ -0,0 +1,159 @@ +t:s0:s1: +0.00000000000000000E+00 1.00000000000000000E+00 0.00000000000000000E+00 +1.02648488190150711E-10 9.99999999948675722E-01 5.13242440913875063E-11 +1.02658753038969712E-06 9.99999486706603657E-01 5.13293396373231300E-07 +1.12914363494047687E-05 9.99994354310467903E-01 5.64568953210529354E-06 +4.48211895830175010E-05 9.99977589784958321E-01 2.24102150417055293E-05 +1.17277047540880841E-04 9.99941363945291539E-01 5.86360547084540949E-05 +2.53272368309885381E-04 9.99873375142890652E-01 1.26624857109333797E-04 +4.96024984269423201E-04 9.99752030703600969E-01 2.47969296398973030E-04 +9.22698163574049712E-04 9.99538800058830001E-01 4.61199941169868684E-04 +1.68044365853622663E-03 9.99160272360433921E-01 8.39727639565850115E-04 +3.18862269929603417E-03 9.98407466672823207E-01 1.59253332717652126E-03 +5.45114110140219790E-03 9.97279622342691741E-01 2.72037765730797233E-03 +7.71365950350836119E-03 9.96153562661734271E-01 3.84643733826544416E-03 +9.97617790561452535E-03 9.95029284922585688E-01 4.97071507741405488E-03 +1.22386963077206895E-02 9.93906786345072457E-01 6.09321365492729479E-03 +1.45012147098268537E-02 9.92786064126930712E-01 7.21393587306905053E-03 +1.73952544462393256E-02 9.91355107543508862E-01 8.64489245649092790E-03 +2.02892941826517993E-02 9.89927047398444282E-01 1.00729526015555741E-02 +2.31833339190642730E-02 9.88501877601865031E-01 1.14981223981348198E-02 +2.60773736554767467E-02 9.87079592114147530E-01 1.29204078858523308E-02 +3.29068688347819438E-02 9.83734614715639721E-01 1.62653852843602023E-02 +3.97363640140871374E-02 9.80405590318767395E-01 1.95944096812325566E-02 +5.02957748456068915E-02 9.75289650084949389E-01 2.47103499150505036E-02 +6.08551856771266456E-02 9.70211385257129355E-01 2.97886147428706068E-02 +7.14145965086463996E-02 9.65170518189519044E-01 3.48294818104809070E-02 +8.19740073401661606E-02 9.60166773545884755E-01 3.98332264541152309E-02 +9.25334181716859216E-02 9.55199878101650190E-01 4.48001218983497956E-02 +1.09712253292456846E-01 9.47197402212381134E-01 5.28025977876188587E-02 +1.26891088413227771E-01 9.39290581299578320E-01 6.07094187004216662E-02 +1.44069923533998695E-01 9.31478272015571096E-01 6.85217279844288346E-02 +1.61248758654769619E-01 9.23759344630696533E-01 7.62406553693034117E-02 +1.89660049003499281E-01 9.11195316277009670E-01 8.88046837229902880E-02 +2.18071339352228943E-01 8.98878691567765453E-01 1.01121308432234533E-01 +2.46482629700958605E-01 8.86804598883420114E-01 1.13195401116579816E-01 +2.74893920049688267E-01 8.74968262536995778E-01 1.25031737463004083E-01 +3.03305210398417957E-01 8.63365000789078185E-01 1.36634999210921676E-01 +3.31716500747147647E-01 8.51990224040054867E-01 1.48009775959944967E-01 +3.60127791095877337E-01 8.40839433068397923E-01 1.59160566931601855E-01 +3.88539081444607026E-01 8.29908217266169590E-01 1.70091782733830132E-01 +4.41138445070370255E-01 8.10235627189399343E-01 1.89764372810600435E-01 +4.77567574856914034E-01 7.97029226508457089E-01 2.02970773491542689E-01 +5.13996704643457814E-01 7.84155337872014080E-01 2.15844662127985643E-01 +5.50425834430001593E-01 7.71605588560225097E-01 2.28394411439774653E-01 +5.86854964216545372E-01 7.59371816557104728E-01 2.40628183442894966E-01 +6.23284094003089151E-01 7.47446066126369102E-01 2.52553933873630565E-01 +6.59713223789632930E-01 7.35820582268969181E-01 2.64179417731030486E-01 +6.96142353576176709E-01 7.24487805053363076E-01 2.75512194946636535E-01 +7.58815310233661888E-01 7.05654481953680968E-01 2.94345518046318699E-01 +8.21488266891147068E-01 6.87629536154125143E-01 3.12370463845874413E-01 +8.84161223548632247E-01 6.70378268923642939E-01 3.29621731076356561E-01 +9.46834180206117426E-01 6.53867470964243247E-01 3.46132529035756198E-01 +1.00950713686360261E+00 6.38065359483856231E-01 3.61934640516143269E-01 +1.07218009352108767E+00 6.22941516449129762E-01 3.77058483550869794E-01 +1.13485305017857274E+00 6.08466829122856878E-01 3.91533170877142678E-01 +1.19752600683605781E+00 5.94613433892461130E-01 4.05386566107538426E-01 +1.26019896349354288E+00 5.81354663050361431E-01 4.18645336949638014E-01 +1.32287192015102795E+00 5.68664993725449097E-01 4.31335006274550459E-01 +1.38554487680851302E+00 5.56519998669646965E-01 4.43480001330352702E-01 +1.44821783346599808E+00 5.44896299070346424E-01 4.55103700929653243E-01 +1.51089079012348315E+00 5.33771519516928472E-01 4.66228480483071195E-01 +1.57356374678096822E+00 5.23124244999401800E-01 4.76875755000597867E-01 +1.63623670343845329E+00 5.12933979731394318E-01 4.87066020268605349E-01 +1.69890966009593836E+00 5.03181107681094364E-01 4.96818892318905247E-01 +1.76158261675342342E+00 4.93846854780748468E-01 5.06153145219251144E-01 +1.82425557341090849E+00 4.84913252781268178E-01 5.15086747218731489E-01 +1.88692853006839356E+00 4.76363104676305715E-01 5.23636895323693952E-01 +1.94960148672587863E+00 4.68179951606793432E-01 5.31820048393206291E-01 +2.01227444338336392E+00 4.60348041167775057E-01 5.39651958832224610E-01 +2.07494740004084921E+00 4.52852297094320178E-01 5.47147702905679489E-01 +2.13762035669833450E+00 4.45678290239669095E-01 5.54321709760330572E-01 +2.20029331335581979E+00 4.38812210792762725E-01 5.61187789207236998E-01 +2.26296627001330508E+00 4.32240841692172695E-01 5.67759158307827083E-01 +2.32563922667079037E+00 4.25951533186333664E-01 5.74048466813666169E-01 +2.38831218332827566E+00 4.19932178485779350E-01 5.80067821514220539E-01 +2.45098513998576095E+00 4.14171190457713889E-01 5.85828809542286000E-01 +2.51365809664324624E+00 4.08657479319653238E-01 5.91342520680346651E-01 +2.57633105330073153E+00 4.03380431291335495E-01 5.96619568708664394E-01 +2.63900400995821682E+00 3.98329888163913515E-01 6.01670111836086319E-01 +2.70167696661570211E+00 3.93496127746071123E-01 6.06503872253928655E-01 +2.76434992327318740E+00 3.88869845148941795E-01 6.11130154851058038E-01 +2.82702287993067269E+00 3.84442134874129537E-01 6.15557865125870296E-01 +2.88969583658815798E+00 3.80204473670731957E-01 6.19795526329267821E-01 +2.95236879324564327E+00 3.76148704128358324E-01 6.23851295871641454E-01 +3.01504174990312857E+00 3.72267018974363595E-01 6.27732981025636239E-01 +3.07771470656061386E+00 3.68551946044992529E-01 6.31448053955007249E-01 +3.14038766321809915E+00 3.64996333901570436E-01 6.35003666098429287E-01 +3.20306061987558444E+00 3.61593338064120084E-01 6.38406661935879582E-01 +3.26573357653306973E+00 3.58336407835898707E-01 6.41663592164100960E-01 +3.32840653319055502E+00 3.55219273693456239E-01 6.44780726306543484E-01 +3.39107948984804031E+00 3.52235935217927731E-01 6.47764064782072047E-01 +3.45375244650552560E+00 3.49380649544342170E-01 6.50619350455657663E-01 +3.51642540316301089E+00 3.46647920306724255E-01 6.53352079693275467E-01 +3.57909835982049618E+00 3.44032487057707448E-01 6.55967512942292386E-01 +3.64177131647798147E+00 3.41529315142283463E-01 6.58470684857716426E-01 +3.70444427313546676E+00 3.39133586006194754E-01 6.60866413993805191E-01 +3.76711722979295205E+00 3.36840687920315074E-01 6.63159312079684926E-01 +3.82979018645043734E+00 3.34646207103166171E-01 6.65353792896833829E-01 +3.89246314310792263E+00 3.32545919224480291E-01 6.67454080775519709E-01 +3.95513609976540792E+00 3.30535781273451845E-01 6.69464218726548155E-01 +4.01780905642289277E+00 3.28611923776025050E-01 6.71388076223975006E-01 +4.08048201308037761E+00 3.26770643346235901E-01 6.73229356653764155E-01 +4.14315496973786246E+00 3.25008395557270624E-01 6.74991604442729431E-01 +4.20582792639534730E+00 3.23321788118517361E-01 6.76678211881482694E-01 +4.26850088305283215E+00 3.21707574345476921E-01 6.78292425654523079E-01 +4.36259663226557493E+00 3.19413195181034726E-01 6.80586804818965274E-01 +4.45669238147831770E+00 3.17265070740067878E-01 6.82734929259932066E-01 +4.55078813069106047E+00 3.15253877871656929E-01 6.84746122128343071E-01 +4.64488387990380325E+00 3.13370887632055728E-01 6.86629112367944217E-01 +4.73897962911654602E+00 3.11607927741266999E-01 6.88392072258733001E-01 +4.83307537832928880E+00 3.09957347043537612E-01 6.90042652956462388E-01 +4.92717112754203157E+00 3.08411982061210621E-01 6.91588017938789434E-01 +5.02126687675477434E+00 3.06965125834067321E-01 6.93034874165932679E-01 +5.11536262596751712E+00 3.05610498904494543E-01 6.94389501095505457E-01 +5.20945837518025989E+00 3.04342222141284424E-01 6.95657777858715631E-01 +5.30355412439300267E+00 3.03154791209282182E-01 6.96845208790717763E-01 +5.39764987360574544E+00 3.02043052635592169E-01 6.97956947364407831E-01 +5.49174562281848821E+00 3.01002181432545757E-01 6.98997818567454243E-01 +5.58584137203123099E+00 3.00027660175653355E-01 6.99972339824346701E-01 +5.67993712124397376E+00 2.99115259411111445E-01 7.00884740588888611E-01 +5.77403287045671654E+00 2.98261019295870233E-01 7.01738980704129878E-01 +5.86812861966945931E+00 2.97461232403345710E-01 7.02538767596654345E-01 +5.96222436888220209E+00 2.96712427631590503E-01 7.03287572368409553E-01 +6.05632011809494486E+00 2.96011355142305865E-01 7.03988644857694190E-01 +6.15041586730768763E+00 2.95354972258738302E-01 7.04645027741261698E-01 +6.24451161652043041E+00 2.94740430259425534E-01 7.05259569740574466E-01 +6.33860736573317318E+00 2.94165062013088063E-01 7.05834937986911881E-01 +6.43270311494591596E+00 2.93626370403025250E-01 7.06373629596974695E-01 +6.52679886415865873E+00 2.93122017490281217E-01 7.06877982509718672E-01 +6.62089461337140150E+00 2.92649814367307026E-01 7.07350185632692807E-01 +6.71499036258414428E+00 2.92207711657821112E-01 7.07792288342178666E-01 +6.80908611179688705E+00 2.91793790622163152E-01 7.08206209377836515E-01 +6.90318186100962983E+00 2.91406254829892186E-01 7.08593745170107536E-01 +6.99727761022237260E+00 2.91043422363364113E-01 7.08956577636635665E-01 +7.09137335943511538E+00 2.90703718518221410E-01 7.09296281481778479E-01 +7.18546910864785815E+00 2.90385668969080357E-01 7.09614331030919643E-01 +7.27956485786060092E+00 2.90087893370859995E-01 7.09912106629139950E-01 +7.37366060707334370E+00 2.89809099368042500E-01 7.10190900631957334E-01 +7.46775635628608647E+00 2.89548076985837011E-01 7.10451923014162823E-01 +7.56185210549882925E+00 2.89303693378861304E-01 7.10696306621138585E-01 +7.65594785471157202E+00 2.89074887914547385E-01 7.10925112085452504E-01 +7.75004360392431479E+00 2.88860667569953156E-01 7.11139332430046678E-01 +7.84413935313705757E+00 2.88660102622012638E-01 7.11339897377987196E-01 +7.93823510234980034E+00 2.88472322612513654E-01 7.11527677387486235E-01 +8.08080669531667084E+00 2.88210359800015581E-01 7.11789640199984253E-01 +8.22337828828354134E+00 2.87973278978804759E-01 7.12026721021195130E-01 +8.36594988125041183E+00 2.87758716623703892E-01 7.12241283376295997E-01 +8.50852147421728233E+00 2.87564533611528172E-01 7.12435466388471661E-01 +8.65109306718415283E+00 2.87388794232750655E-01 7.12611205767249123E-01 +8.79366466015102333E+00 2.87229746815752529E-01 7.12770253184247249E-01 +8.93623625311789382E+00 2.87085806022613133E-01 7.12914193977386645E-01 +9.07880784608476432E+00 2.86955536978731940E-01 7.13044463021267783E-01 +9.22137943905163482E+00 2.86837641067565152E-01 7.13162358932434515E-01 +9.36395103201850532E+00 2.86730943062506516E-01 7.13269056937493207E-01 +9.50652262498537581E+00 2.86634379394257510E-01 7.13365620605742157E-01 +9.64909421795224631E+00 2.86546987502534933E-01 7.13453012497464734E-01 +9.79166581091911681E+00 2.86467896231261898E-01 7.13532103768737769E-01 +9.93423740388598731E+00 2.86396317164659742E-01 7.13603682835339925E-01 +1.00000000000000000E+01 2.86365632344379117E-01 7.13634367655620494E-01 diff --git a/tests/unit/resources/SimID_886118677_0_.log b/tests/unit/resources/SimID_886118677_0_.log new file mode 100644 index 000000000..11b4c8711 --- /dev/null +++ b/tests/unit/resources/SimID_886118677_0_.log @@ -0,0 +1,4 @@ +IDAData logfile +IDAData text format version 1 +SimID_886118677_0_.ida +KeepMost 1000 diff --git a/IDAWin/tests/smoke/simpleModel_Network_orig.vcml b/tests/unit/resources/simpleModel_Network_orig.vcml similarity index 100% rename from IDAWin/tests/smoke/simpleModel_Network_orig.vcml rename to tests/unit/resources/simpleModel_Network_orig.vcml diff --git a/tests/unit/smoke_test.cpp b/tests/unit/smoke_test.cpp new file mode 100644 index 000000000..919c07a32 --- /dev/null +++ b/tests/unit/smoke_test.cpp @@ -0,0 +1,101 @@ +// +// Created by Logan Drescher on 11/12/25. +// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "SundialsSolverInterface.h" + +void compare(const std::filesystem::path& file1, const std::filesystem::path& file2, float tolerance); + +void performSmokeTest(const int taskID, const int hashID) { + const std::filesystem::path RESOURCE_DIRECTORY{RESOURCE_DIR}; + const std::filesystem::path OUTPUT_TARGET{RESOURCE_DIRECTORY /std::format("SimID_{}_0_.ida", hashID)}; + const std::array NECESSARY_FILES{ + RESOURCE_DIRECTORY /std::format("SimID_{}_0_.cvodeInput", hashID), + RESOURCE_DIRECTORY /std::format("SimID_{}_0_.ida.expected", hashID) + }; + for (const auto& file : NECESSARY_FILES) { + assert(std::filesystem::exists(file)); + } + FILE *outputFile = NULL; + std::ifstream inputFileStream{NECESSARY_FILES[0]}; + if (!inputFileStream.is_open()) { throw std::runtime_error("input file [" + NECESSARY_FILES[0].string() + "] doesn't exit!"); } + + // Open the output file... + if (NULL == (outputFile = fopen(OUTPUT_TARGET.string().c_str(), "w"))) { + throw std::runtime_error("Could not open output file[" + OUTPUT_TARGET.string() + "] for writing."); + } + + activateSolver(inputFileStream, outputFile, taskID); + fclose(outputFile); + + compare(OUTPUT_TARGET, NECESSARY_FILES[1], 1e-7); +} + +TEST(SmokeTest, UserProvidesFilesWithoutJMS) { + constexpr int taskID = -1, hashID = 1489333437; + performSmokeTest(taskID, hashID); +} + +/** + * To perform localhost smoke test, run the following docker command: + * `docker run -p 61616:61616 -p 8161:8161 apache/activemq-classic` + * Then connect to http://localhost:8161, and login as `admin` pass `admin` + */ +TEST(SmokeTest, UserProvidesFilesWithJMS) { + constexpr int taskID = 2025; + #ifdef TEST_WITH_LOCALHOST + constexpr int hashID = 886118677; + #else + constexpr int hashID = 256118677; + #endif + + performSmokeTest(taskID, hashID); +} + +void compare(const std::filesystem::path& file1, const std::filesystem::path& file2, float tolerance) { + std::ifstream fileStream1(file1); + std::ifstream fileStream2(file2); + if (!fileStream1.is_open()) throw std::runtime_error("Could not file: `" + file1.string() + "`"); + if (!fileStream2.is_open()) throw std::runtime_error("Could not file: `" + file2.string() + "`"); + + std::string line1, line2; + bool eof1, eof2; + // we do **NOT** short circuit here, so we use `&` not `&&` + while ( + !((eof1 = !std::getline(fileStream1, line1))) + & + !((eof2 = !std::getline(fileStream2, line2))) + ){ + if (line1 == line2) continue; + double value; + std::istringstream lineStream1{line1}; + std::vector lineValues1; + while (lineStream1 >> value) lineValues1.push_back(value); + std::istringstream lineStream2{line2}; + std::vector lineValues2; + while (lineStream2 >> value) lineValues2.push_back(value); + if (lineValues1.size() != lineValues2.size()) throw std::runtime_error("Length of data does not match"); + + for (int i = 0; i < lineValues2.size(); i++) { + if (lineValues1[i] == lineValues2[i]) continue; + double adjustedTolerance = tolerance * std::max(std::abs(lineValues1[i]), std::abs(lineValues2[i])); + if (std::abs(lineValues1[i] - lineValues2[i]) > adjustedTolerance) + throw std::runtime_error("Values outside tolerance"); + } + } + + // last check; make sure they are both eof! + if (eof1 ^ eof2) { + throw std::runtime_error("Files do not contain same number of lines."); + } +} \ No newline at end of file diff --git a/tests/unit/smoke_test.py b/tests/unit/smoke_test.py new file mode 100644 index 000000000..a75c5cab0 --- /dev/null +++ b/tests/unit/smoke_test.py @@ -0,0 +1,49 @@ +from __future__ import annotations + +from pathlib import Path + +import pyvcell_odesolver as pvco + +RESOURCE_DIR = Path(__file__).parent / "resources" +TOLERANCE = 1e-7 + + +def _compare(actual: Path, expected: Path, tolerance: float) -> None: + actual_lines = actual.read_text().splitlines() + expected_lines = expected.read_text().splitlines() + assert len(actual_lines) == len(expected_lines), ( + f"line counts differ: {actual} ({len(actual_lines)}) " + f"vs {expected} ({len(expected_lines)})" + ) + for i, (line_a, line_e) in enumerate( + zip(actual_lines, expected_lines, strict=True) + ): + if line_a == line_e: + continue + values_a = [float(v) for v in line_a.split()] + values_e = [float(v) for v in line_e.split()] + assert len(values_a) == len(values_e), ( + f"line {i} widths differ: {line_a!r} vs {line_e!r}" + ) + for v_a, v_e in zip(values_a, values_e, strict=True): + adjusted = tolerance * max(abs(v_a), abs(v_e)) + assert abs(v_a - v_e) <= adjusted, ( + f"value mismatch on line {i}: {v_a} vs {v_e} " + f"(adjusted tolerance {adjusted})" + ) + + +def test_solve_smoke_without_messaging(tmp_path: Path) -> None: + hash_id = 1489333437 + input_file = RESOURCE_DIR / f"SimID_{hash_id}_0_.cvodeInput" + expected_file = RESOURCE_DIR / f"SimID_{hash_id}_0_.ida.expected" + output_file = tmp_path / f"SimID_{hash_id}_0_.ida" + + assert input_file.exists(), f"missing input: {input_file}" + assert expected_file.exists(), f"missing expected: {expected_file}" + + return_code = pvco.solve(str(input_file), str(output_file)) + assert return_code == 0 + assert output_file.exists() + + _compare(output_file, expected_file, TOLERANCE) diff --git a/uv.lock b/uv.lock new file mode 100644 index 000000000..20bed7a58 --- /dev/null +++ b/uv.lock @@ -0,0 +1,377 @@ +version = 1 +revision = 3 +requires-python = ">=3.10" + +[[package]] +name = "annotated-types" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, +] + +[[package]] +name = "build" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "os_name == 'nt'" }, + { name = "importlib-metadata", marker = "python_full_version < '3.10.2'" }, + { name = "packaging" }, + { name = "pyproject-hooks" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/78/e0/df5e171f685f82f37b12e1f208064e24244911079d7b767447d1af7e0d70/build-1.5.0.tar.gz", hash = "sha256:302c22c3ba2a0fd5f3911918651341ebb3896176cbdec15bd421f80b1afc7647", size = 89796, upload-time = "2026-04-30T03:18:25.17Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0d/fe/6bea5c9162869c5beba5d9c8abbed835ec85bf1ec1fba05a3822325c45f3/build-1.5.0-py3-none-any.whl", hash = "sha256:13f3eecb844759ab66efec90ca17639bbf14dc06cb2fdf37a9010322d9c50a6f", size = 26018, upload-time = "2026-04-30T03:18:23.644Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "exceptiongroup" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" }, +] + +[[package]] +name = "importlib-metadata" +version = "9.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "zipp" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a9/01/15bb152d77b21318514a96f43af312635eb2500c96b55398d020c93d86ea/importlib_metadata-9.0.0.tar.gz", hash = "sha256:a4f57ab599e6a2e3016d7595cfd72eb4661a5106e787a95bcc90c7105b831efc", size = 56405, upload-time = "2026-03-20T06:42:56.999Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/3d/2d244233ac4f76e38533cfcb2991c9eb4c7bf688ae0a036d30725b8faafe/importlib_metadata-9.0.0-py3-none-any.whl", hash = "sha256:2d21d1cc5a017bd0559e36150c21c830ab1dc304dedd1b7ea85d20f45ef3edd7", size = 27789, upload-time = "2026-03-20T06:42:55.665Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + +[[package]] +name = "packaging" +version = "26.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "pydantic" +version = "2.13.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/18/a5/b60d21ac674192f8ab0ba4e9fd860690f9b4a6e51ca5df118733b487d8d6/pydantic-2.13.4.tar.gz", hash = "sha256:c40756b57adaa8b1efeeced5c196f3f3b7c435f90e84ea7f443901bec8099ef6", size = 844775, upload-time = "2026-05-06T13:43:05.343Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl", hash = "sha256:45a282cde31d808236fd7ea9d919b128653c8b38b393d1c4ab335c62924d9aba", size = 472262, upload-time = "2026-05-06T13:43:02.641Z" }, +] + +[[package]] +name = "pydantic-core" +version = "2.46.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9d/56/921726b776ace8d8f5db44c4ef961006580d91dc52b803c489fafd1aa249/pydantic_core-2.46.4.tar.gz", hash = "sha256:62f875393d7f270851f20523dd2e29f082bcc82292d66db2b64ea71f64b6e1c1", size = 471464, upload-time = "2026-05-06T13:37:06.98Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/08/f1ba952f1c8ae5581c70fa9c6da89f247b83e3dd8c09c035d5d7931fc23d/pydantic_core-2.46.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:a396dcc17e5a0b164dbe026896245a4fa9ff402edca1dff0be3d53a517f74de4", size = 2113146, upload-time = "2026-05-06T13:37:36.537Z" }, + { url = "https://files.pythonhosted.org/packages/56/c6/65f646c7ff09bd257f660434adb45c4dfcbbcebcc030562fecf6f5bf887d/pydantic_core-2.46.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:da4b951fe36dc7c3a1ccb4e3cd1747c3542b8c9ceede8fc86cae054e764485f5", size = 1949769, upload-time = "2026-05-06T13:37:46.365Z" }, + { url = "https://files.pythonhosted.org/packages/64/ba/bfb1d928fd5b49e1258935ff104ae356e9fd89384a55bf9f847e9193ad40/pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb63e0198ca18aad131c089b9204c23079c3afa95487e561f4c522d519e55aba", size = 1974958, upload-time = "2026-05-06T13:37:28.611Z" }, + { url = "https://files.pythonhosted.org/packages/4e/74/76223bfb117b64af743c9b6670d1364516f5c0604f96b48f3272f6af6cc6/pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f47286a97f0bc9b8859519809077b91b2cefe4ae47fcbf5e466a009c1c5d742b", size = 2042118, upload-time = "2026-05-06T13:36:55.216Z" }, + { url = "https://files.pythonhosted.org/packages/cb/7b/848732968bc8f48f3187542f08358b9d842db564147b256669426ebb1652/pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:905a0ed8ea6f2d61c1738835f99b699348d7857379083e5fc497fa0c967a407c", size = 2222876, upload-time = "2026-05-06T13:38:25.455Z" }, + { url = "https://files.pythonhosted.org/packages/b5/2f/e90b63ee2e14bd8d3db8f705a6d75d64e6ee1b7c2c8833747ce706e1e0ce/pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea793e075b70290d89d8142074262885d3f7da19634845135751bd6344f73b50", size = 2286703, upload-time = "2026-05-06T13:37:53.304Z" }, + { url = "https://files.pythonhosted.org/packages/ba/1e/acc4d70f88a0a277e4a1fa77ebb985ceabaf900430f875bf9338e11c9420/pydantic_core-2.46.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:395aebd9183f9d112f569aeb5b2214d1a10a33bec8456447f7fbdfa51d38d4cd", size = 2092042, upload-time = "2026-05-06T13:38:46.981Z" }, + { url = "https://files.pythonhosted.org/packages/a9/da/0a422b57bf8504102bf3c4ccea9c41bab5a5cee6a54650acf8faf67f5a24/pydantic_core-2.46.4-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:b078afbc25f3a1436c7a1d2cd3e322497ee99615ba97c563566fdf46aff1ee01", size = 2117231, upload-time = "2026-05-06T13:39:23.146Z" }, + { url = "https://files.pythonhosted.org/packages/bd/2a/2ac13c3af305843e23c5078c53d135656b3f05a2fd78cb7bbbb12e97b473/pydantic_core-2.46.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f747929cf940cddb5b3668a390056ddd5ba2e5010615ea2dcf4f9c4f3ab8791d", size = 2168388, upload-time = "2026-05-06T13:40:08.06Z" }, + { url = "https://files.pythonhosted.org/packages/72/04/2beacf7e1607e93eefe4aed1b4709f079b905fb77530179d4f7c71745f22/pydantic_core-2.46.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:daa27d92c36f24388fe3ad306b174781c747627f134452e4f128ea00ce1fe8c4", size = 2184769, upload-time = "2026-05-06T13:38:13.901Z" }, + { url = "https://files.pythonhosted.org/packages/9e/29/d2b9fd9f539133548eaf622c06a4ce176cb46ac59f32d0359c4abc0de047/pydantic_core-2.46.4-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:19e51f073cd3df251856a8a4189fbdf1de4012c3ebacfb1884f94f1eb406079f", size = 2319312, upload-time = "2026-05-06T13:39:08.24Z" }, + { url = "https://files.pythonhosted.org/packages/7c/af/0f7a5b85fec6075bea96e3ef9187de38fccced0de92c1e7feda8d5cc7bb9/pydantic_core-2.46.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c1747f85cee84c26985853c6f3d9bd3e75da5212912443fa111c113b9c246f39", size = 2361817, upload-time = "2026-05-06T13:38:43.2Z" }, + { url = "https://files.pythonhosted.org/packages/25/a4/73363fec545fd3ec025490bdda2743c56d0dd5b6266b1a53bbe9e4265375/pydantic_core-2.46.4-cp310-cp310-win32.whl", hash = "sha256:2f84c03c8607173d16b5a854ec68a2f9079ae03237a54fb506d13af47e1d018d", size = 1987085, upload-time = "2026-05-06T13:39:25.497Z" }, + { url = "https://files.pythonhosted.org/packages/01/aa/62f082da2c91fac1c234bc9ee0066257ce83f0604abd72e4c9d5991f2d84/pydantic_core-2.46.4-cp310-cp310-win_amd64.whl", hash = "sha256:8358a950c8909158e3df31538a7e4edc2d7265a7c54b47f0864d9e5bae9dcebf", size = 2074311, upload-time = "2026-05-06T13:39:59.922Z" }, + { url = "https://files.pythonhosted.org/packages/5c/fa/6d7708d2cfc1a832acb6aeb0cd16e801902df8a0f583bb3b4b527fde022e/pydantic_core-2.46.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:0e96592440881c74a213e5ad528e2b24d3d4f940de2766bed9010ab1d9e51594", size = 2111872, upload-time = "2026-05-06T13:40:27.596Z" }, + { url = "https://files.pythonhosted.org/packages/ae/6f/aa064a3e74b5745afbdf250594f38e7ead05e2d651bcb35994b9417a0d4d/pydantic_core-2.46.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0d65b8c354be7fb5f720c3caa8bc940bc2d20ce749c8e06135f07f8ed95dd7c", size = 1948255, upload-time = "2026-05-06T13:39:12.574Z" }, + { url = "https://files.pythonhosted.org/packages/43/3a/41114a9f7569b84b4d84e7a018c57c56347dac30c0d4a872946ec4e36c46/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bfb192b3f4b9e8a89b6277b6ce787564f62cfd272055f6e685726b111dc7826", size = 1972827, upload-time = "2026-05-06T13:38:19.841Z" }, + { url = "https://files.pythonhosted.org/packages/ef/25/1ab42e8048fe551934d9884e8d64daa7e990ad386f310a15981aeb6a5b08/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9037063db01f09b09e237c282b6792bd4da634b5402c4e7f0c61effed7701a04", size = 2041051, upload-time = "2026-05-06T13:38:10.447Z" }, + { url = "https://files.pythonhosted.org/packages/94/c2/1a934597ddf08da410385b3b7aae91956a5a76c635effef456074fad7e88/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc010ab034c8c7452522748bf937df58020d256ccae0874463d1f4d01758af8e", size = 2221314, upload-time = "2026-05-06T13:40:13.089Z" }, + { url = "https://files.pythonhosted.org/packages/02/6d/9e8ad178c9c4df27ad3c8f25d1fe2a7ab0d2ba0559fad4aee5d3d1f16771/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c5dac79fa1614d1e06ca695109c6105923bd9c7d1d6c918d4e637b7e6b32fd3", size = 2285146, upload-time = "2026-05-06T13:38:59.224Z" }, + { url = "https://files.pythonhosted.org/packages/80/50/540cd3aeefc041beb111125c4bff779831a2111fc6b15a9138cda277d32c/pydantic_core-2.46.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9fa868638bf362d3d138ea55829cefb3d5f4b0d7f142234382a15e2485dbec4", size = 2089685, upload-time = "2026-05-06T13:38:17.762Z" }, + { url = "https://files.pythonhosted.org/packages/6b/a4/b440ad35f05f6a38f89fa0f149accb3f0e02be94ca5e15f3c449a61b4bc9/pydantic_core-2.46.4-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:17299feefe090f2caa5b8e37222bb5f663e4935a8bfa6931d4102e5df1a9f398", size = 2115420, upload-time = "2026-05-06T13:37:58.195Z" }, + { url = "https://files.pythonhosted.org/packages/99/61/de4f55db8dfd57bfdfa9a12ec90fe1b57c4f41062f7ca86f08586b3e0ac0/pydantic_core-2.46.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4c63ebc82684aa89d9a3bcbd13d515b3be44250dc68dd3bd81526c1cb31286c3", size = 2165122, upload-time = "2026-05-06T13:37:01.167Z" }, + { url = "https://files.pythonhosted.org/packages/f7/52/7c529d7bdb2d1068bd52f51fe32572c8301f9a4febf1948f10639f1436f5/pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:aaa2a54443eff1950ba5ddc6b6ccda0d9c84a364276a62f969bdf2a390650848", size = 2182573, upload-time = "2026-05-06T13:38:45.04Z" }, + { url = "https://files.pythonhosted.org/packages/37/b3/7c40325848ba78247f2812dcf9c7274e38cd801820ca6dd9fe63bcfb0eb4/pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:18e5ceec2ab67e6d5f1a9085e5a24c9c4e2ac4545730bfe668680bca05e555f3", size = 2317139, upload-time = "2026-05-06T13:37:15.539Z" }, + { url = "https://files.pythonhosted.org/packages/d9/37/f913f81a657c865b75da6c0dbed79876073c2a43b5bd9edbe8da785e4d49/pydantic_core-2.46.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a0f62d0a58f4e7da165457e995725421e0064f2255d8eccebc49f41bbc23b109", size = 2360433, upload-time = "2026-05-06T13:37:30.099Z" }, + { url = "https://files.pythonhosted.org/packages/c4/67/6acaa1be2567f9256b056d8477158cac7240813956ce86e49deae8e173b4/pydantic_core-2.46.4-cp311-cp311-win32.whl", hash = "sha256:041bde0a48fd37cf71cab1c9d56d3e8625a3793fef1f7dd232b3ff37e978ecda", size = 1985513, upload-time = "2026-05-06T13:38:15.669Z" }, + { url = "https://files.pythonhosted.org/packages/aa/e6/c505f83dfeda9a2e5c995cfd872949e4d05e12f7feb3dca72f633daefa94/pydantic_core-2.46.4-cp311-cp311-win_amd64.whl", hash = "sha256:6f2eeda33a839975441c86a4119e1383c50b47faf0cbb5176985565c6bb02c33", size = 2071114, upload-time = "2026-05-06T13:40:35.416Z" }, + { url = "https://files.pythonhosted.org/packages/0f/da/7a263a96d965d9d0df5e8de8a475f33495451117035b09acb110288c381f/pydantic_core-2.46.4-cp311-cp311-win_arm64.whl", hash = "sha256:14f4c5d6db102bd796a627bbb3a17b4cf4574b9ae861d8b7c9a9661c6dd3362d", size = 2044298, upload-time = "2026-05-06T13:38:29.754Z" }, + { url = "https://files.pythonhosted.org/packages/ce/8c/af022f0af448d7747c5154288d46b5f2bc5f17366eaa0e23e9aa04d59f3b/pydantic_core-2.46.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3245406455a5d98187ec35530fd772b1d799b26667980872c8d4614991e2c4a2", size = 2106158, upload-time = "2026-05-06T13:38:57.215Z" }, + { url = "https://files.pythonhosted.org/packages/19/95/6195171e385007300f0f5574592e467c568becce2d937a0b6804f218bc49/pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:962ccbab7b642487b1d8b7df90ef677e03134cf1fd8880bf698649b22a69371f", size = 1951724, upload-time = "2026-05-06T13:37:02.697Z" }, + { url = "https://files.pythonhosted.org/packages/8e/bc/f47d1ff9cbb1620e1b5b697eef06010035735f07820180e74178226b27b3/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8233f2947cf85404441fd7e0085f53b10c93e0ee78611099b5c7237e36aacbf7", size = 1975742, upload-time = "2026-05-06T13:37:09.448Z" }, + { url = "https://files.pythonhosted.org/packages/5b/11/9b9a5b0306345664a2da6410877af6e8082481b5884b3ddd78d47c6013ce/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3a233125ac121aa3ffba9a2b59edfc4a985a76092dc8279586ab4b71390875e7", size = 2052418, upload-time = "2026-05-06T13:37:38.234Z" }, + { url = "https://files.pythonhosted.org/packages/f1/b7/a65fec226f5d78fc39f4a13c4cc0c768c22b113438f60c14adc9d2865038/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b712b53160b79a5850310b912a5ef8e57e56947c8ad690c227f5c9d7e561712", size = 2232274, upload-time = "2026-05-06T13:38:27.753Z" }, + { url = "https://files.pythonhosted.org/packages/68/f0/92039db98b907ef49269a8271f67db9cb78ae2fc68062ef7e4e77adb5f61/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9401557acd873c3a7f3eb9383edef8ac4968f9510e340f4808d427e75667e7b4", size = 2309940, upload-time = "2026-05-06T13:38:05.353Z" }, + { url = "https://files.pythonhosted.org/packages/5f/97/2aab507d3d00ca626e8e57c1eac6a79e4e5fbcc63eb99733ff55d1717f65/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:926c9541b14b12b1681dca8a0b75feb510b06c6341b70a8e500c2fdcff837cce", size = 2094516, upload-time = "2026-05-06T13:39:10.577Z" }, + { url = "https://files.pythonhosted.org/packages/22/37/a8aca44d40d737dde2bc05b3c6c07dff0de07ce6f82e9f3167aeaf4d5dea/pydantic_core-2.46.4-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:56cb4851bcaf3d117eddcef4fe66afd750a50274b0da8e22be256d10e5611987", size = 2136854, upload-time = "2026-05-06T13:40:22.59Z" }, + { url = "https://files.pythonhosted.org/packages/24/99/fcef1b79238c06a8cbec70819ac722ba76e02bc8ada9b0fd66eba40da01b/pydantic_core-2.46.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c68fcd102d71ea85c5b2dfac3f4f8476eff42a9e078fd5faefff6d145063536b", size = 2180306, upload-time = "2026-05-06T13:40:10.666Z" }, + { url = "https://files.pythonhosted.org/packages/ae/6c/fc44000918855b42779d007ae63b0532794739027b2f417321cddbc44f6a/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b2f69dec1725e79a012d920df1707de5caf7ed5e08f3be4435e25803efc47458", size = 2190044, upload-time = "2026-05-06T13:40:43.231Z" }, + { url = "https://files.pythonhosted.org/packages/6b/65/d9cadc9f1920d7a127ad2edba16c1db7916e59719285cd6c94600b0080ba/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:8d0820e8192167f80d88d64038e609c31452eeca865b4e1d9950a27a4609b00b", size = 2329133, upload-time = "2026-05-06T13:39:57.365Z" }, + { url = "https://files.pythonhosted.org/packages/d0/cf/c873d91679f3a30bcf5e7ac280ce5573483e72295307685120d0d5ad3416/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fbdb89b3e1c94a30cc5edfce477c6e6a5dc4d8f84665b455c27582f211a1c72c", size = 2374464, upload-time = "2026-05-06T13:38:06.976Z" }, + { url = "https://files.pythonhosted.org/packages/47/bd/6f2fc8188f31bf10590f1e98e7b306336161fac930a8c514cd7bd828c7dc/pydantic_core-2.46.4-cp312-cp312-win32.whl", hash = "sha256:9aa768456404a8bf48a4406685ac2bec8e72b62c69313734fa3b73cf33b3a894", size = 1974823, upload-time = "2026-05-06T13:40:47.985Z" }, + { url = "https://files.pythonhosted.org/packages/40/8c/985c1d41ea1107c2534abd9870e4ed5c8e7669b5c308297835c001e7a1c4/pydantic_core-2.46.4-cp312-cp312-win_amd64.whl", hash = "sha256:e9c26f834c65f5752f3f06cb08cb86a913ceb7274d0db6e267808a708b46bc89", size = 2072919, upload-time = "2026-05-06T13:39:21.153Z" }, + { url = "https://files.pythonhosted.org/packages/c4/ba/f463d006e0c47373ca7ec5e1a261c59dc01ef4d62b2657af925fb0deee3a/pydantic_core-2.46.4-cp312-cp312-win_arm64.whl", hash = "sha256:4fc73cb559bdb54b1134a706a2802a4cddd27a0633f5abb7e53056268751ac6a", size = 2027604, upload-time = "2026-05-06T13:39:03.753Z" }, + { url = "https://files.pythonhosted.org/packages/51/a2/5d30b469c5267a17b39dec53208222f76a8d351dfac4af661888c5aee77d/pydantic_core-2.46.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:5d5902252db0d3cedf8d4a1bc68f70eeb430f7e4c7104c8c476753519b423008", size = 2106306, upload-time = "2026-05-06T13:37:48.029Z" }, + { url = "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c94f0688e7b8d0a67abf40e57a7eaaecd17cc9586706a31b76c031f63df052b4", size = 1951906, upload-time = "2026-05-06T13:37:17.012Z" }, + { url = "https://files.pythonhosted.org/packages/03/d5/fd02da45b659668b05923b17ba3a0100a0a3d5541e3bd8fcc4ecb711309e/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f027324c56cd5406ca49c124b0db10e56c69064fec039acc571c29020cc87c76", size = 1976802, upload-time = "2026-05-06T13:37:35.113Z" }, + { url = "https://files.pythonhosted.org/packages/21/f2/95727e1368be3d3ed485eaab7adbd7dda408f33f7a36e8b48e0144002b91/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e739fee756ba1010f8bcccb534252e85a35fe45ae92c295a06059ce58b74ccd3", size = 2052446, upload-time = "2026-05-06T13:37:12.313Z" }, + { url = "https://files.pythonhosted.org/packages/9c/86/5d99feea3f77c7234b8718075b23db11532773c1a0dbd9b9490215dc2eeb/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d56801be94b86a9da183e5f3766e6310752b99ff647e38b09a9500d88e46e76", size = 2232757, upload-time = "2026-05-06T13:39:01.149Z" }, + { url = "https://files.pythonhosted.org/packages/d2/3a/508ac615935ef7588cf6d9e9b91309fdc2da751af865e02a9098de88258c/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2412e734dcb48da14d4e4006b82b46b74f2518b8a26ee7e58c6844a6cd6d03c4", size = 2309275, upload-time = "2026-05-06T13:37:41.406Z" }, + { url = "https://files.pythonhosted.org/packages/07/f8/41db9de19d7987d6b04715a02b3b40aea467000275d9d758ffaa31af7d50/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9551187363ffc0de2a00b2e47c25aeaeb1020b69b668762966df15fc5659dd5a", size = 2094467, upload-time = "2026-05-06T13:39:18.847Z" }, + { url = "https://files.pythonhosted.org/packages/2c/e2/f35033184cb11d0052daf4416e8e10a502ea2ac006fc4f459aee872727d1/pydantic_core-2.46.4-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:0186750b482eefa11d7f435892b09c5c606193ef3375bcf94aa00ae6bfb66262", size = 2134417, upload-time = "2026-05-06T13:40:17.944Z" }, + { url = "https://files.pythonhosted.org/packages/7e/7b/6ceeb1cc90e193862f444ebe373d8fdf613f0a82572dde03fb10734c6c71/pydantic_core-2.46.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5855698a4856556d86e8e6cd8434bc3ac0314ee8e12089ae0e143f64c6256e4e", size = 2179782, upload-time = "2026-05-06T13:40:32.618Z" }, + { url = "https://files.pythonhosted.org/packages/5a/f2/c8d7773ede6af08036423a00ae0ceffce266c3c52a096c435d68c896083f/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:cbaf13819775b7f769bf4a1f066cb6df7a28d4480081a589828ef190226881cd", size = 2188782, upload-time = "2026-05-06T13:36:51.018Z" }, + { url = "https://files.pythonhosted.org/packages/59/31/0c864784e31f09f05cdd87606f08923b9c9e7f6e51dd27f20f62f975ce9f/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:633147d34cf4550417f12e2b1a0383973bdf5cdfde212cb09e9a581cf10820be", size = 2328334, upload-time = "2026-05-06T13:40:37.764Z" }, + { url = "https://files.pythonhosted.org/packages/c2/eb/4f6c8a41efa30baa755590f4141abf3a8c370fab610915733e74134a7270/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:82cf5301172168103724d49a1444d3378cb20cdee30b116a1bd6031236298a5d", size = 2372986, upload-time = "2026-05-06T13:39:34.152Z" }, + { url = "https://files.pythonhosted.org/packages/5b/24/b375a480d53113860c299764bfe9f349a3dc9108b3adc0d7f0d786492ebf/pydantic_core-2.46.4-cp313-cp313-win32.whl", hash = "sha256:9fa8ae11da9e2b3126c6426f147e0fba88d96d65921799bb30c6abd1cb2c97fb", size = 1973693, upload-time = "2026-05-06T13:37:55.072Z" }, + { url = "https://files.pythonhosted.org/packages/7e/e8/cff247591966f2d22ec8c003cd7587e27b7ba7b81ab2fb888e3ab75dc285/pydantic_core-2.46.4-cp313-cp313-win_amd64.whl", hash = "sha256:6b3ace8194b0e5204818c92802dcdca7fc6d88aabbb799d7c795540d9cd6d292", size = 2071819, upload-time = "2026-05-06T13:38:49.139Z" }, + { url = "https://files.pythonhosted.org/packages/c6/1a/f4aee670d5670e9e148e0c82c7db98d780be566c6e6a97ee8035528ca0b3/pydantic_core-2.46.4-cp313-cp313-win_arm64.whl", hash = "sha256:184c081504d17f1c1066e430e117142b2c77d9448a97f7b65c6ac9fd9aee238d", size = 2027411, upload-time = "2026-05-06T13:40:45.796Z" }, + { url = "https://files.pythonhosted.org/packages/8d/74/228a26ddad29c6672b805d9fd78e8d251cd04004fa7eed0e622096cd0250/pydantic_core-2.46.4-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:428e04521a40150c85216fc8b85e8d39fece235a9cf5e383761238c7fa9b96fb", size = 2102079, upload-time = "2026-05-06T13:38:41.019Z" }, + { url = "https://files.pythonhosted.org/packages/ad/1f/8970b150a4b4365623ae00fc88603491f763c627311ae8031e3111356d6e/pydantic_core-2.46.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:23ace664830ee0bfe014a0c7bc248b1f7f25ed7ad103852c317624a1083af462", size = 1952179, upload-time = "2026-05-06T13:36:59.812Z" }, + { url = "https://files.pythonhosted.org/packages/95/30/5211a831ae054928054b2f79731661087a2bc5c01e825c672b3a4a8f1b3e/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce5c1d2a8b27468f433ca974829c44060b8097eedc39933e3c206a90ee49c4a9", size = 1978926, upload-time = "2026-05-06T13:37:39.933Z" }, + { url = "https://files.pythonhosted.org/packages/57/e9/689668733b1eb67adeef047db3c2e8788fcf65a7fd9c9e2b46b7744fe245/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7283d57845ecf5a163403eb0702dfc220cc4fbdd18919cb5ccea4f95ee1cdab4", size = 2046785, upload-time = "2026-05-06T13:38:01.995Z" }, + { url = "https://files.pythonhosted.org/packages/60/d9/6715260422ff50a2109878fd24d948a6c3446bb2664f34ee78cd972b3acd/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8daafc69c93ee8a0204506a3b6b30f586ef54028f52aeeeb5c4cfc5184fd5914", size = 2228733, upload-time = "2026-05-06T13:40:50.371Z" }, + { url = "https://files.pythonhosted.org/packages/18/ae/fdb2f64316afca925640f8e70bb1a564b0ec2721c1389e25b8eb4bf9a299/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd2213145bcc2ba85884d0ac63d222fece9209678f77b9b4d76f054c561adb28", size = 2307534, upload-time = "2026-05-06T13:37:21.531Z" }, + { url = "https://files.pythonhosted.org/packages/89/1d/8eff589b45bb8190a9d12c49cfad0f176a5cbd1534908a6b5125e2886239/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a5f930472650a82629163023e630d160863fce524c616f4e5186e5de9d9a49b", size = 2099732, upload-time = "2026-05-06T13:39:31.942Z" }, + { url = "https://files.pythonhosted.org/packages/06/d5/ee5a3366637fee41dee51a1fc91562dcf12ddbc68fda34e6b253da2324bb/pydantic_core-2.46.4-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:c1b3f518abeca3aa13c712fd202306e145abf59a18b094a6bafb2d2bbf59192c", size = 2129627, upload-time = "2026-05-06T13:37:25.033Z" }, + { url = "https://files.pythonhosted.org/packages/94/33/2414be571d2c6a6c4d08be21f9292b6d3fdb08949a97b6dfe985017821db/pydantic_core-2.46.4-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a7dd0b3ee80d90150e3495a3a13ac34dbcbfd4f012996a6a1d8900e91b5c0fb", size = 2179141, upload-time = "2026-05-06T13:37:14.046Z" }, + { url = "https://files.pythonhosted.org/packages/7b/79/7daa95be995be0eecc4cf75064cb33f9bbbfe3fe0158caf2f0d4a996a5c7/pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:3fb702cd90b0446a3a1c5e470bfa0dd23c0233b676a9099ddcc964fa6ca13898", size = 2184325, upload-time = "2026-05-06T13:36:53.615Z" }, + { url = "https://files.pythonhosted.org/packages/9f/cb/d0a382f5c0de8a222dc61c65348e0ce831b1f68e0a018450d31c2cace3a5/pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:b8458003118a712e66286df6a707db01c52c0f52f7db8e4a38f0da1d3b94fc4e", size = 2323990, upload-time = "2026-05-06T13:40:29.971Z" }, + { url = "https://files.pythonhosted.org/packages/05/db/d9ba624cc4a5aced1598e88c04fdbd8310c8a69b9d38b9a3d39ce3a61ed7/pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:372429a130e469c9cd698925ce5fc50940b7a1336b0d82038e63d5bbc4edc519", size = 2369978, upload-time = "2026-05-06T13:37:23.027Z" }, + { url = "https://files.pythonhosted.org/packages/f2/20/d15df15ba918c423461905802bfd2981c3af0bfa0e40d05e13edbfa48bc3/pydantic_core-2.46.4-cp314-cp314-win32.whl", hash = "sha256:85bb3611ff1802f3ee7fdd7dbff26b56f343fb432d57a4728fdd49b6ef35e2f4", size = 1966354, upload-time = "2026-05-06T13:38:03.499Z" }, + { url = "https://files.pythonhosted.org/packages/fc/b6/6b8de4c0a7d7ab3004c439c80c5c1e0a3e8d78bbae19379b01960383d9e5/pydantic_core-2.46.4-cp314-cp314-win_amd64.whl", hash = "sha256:811ff8e9c313ab425368bcbb36e5c4ebd7108c2bbf4e4089cfbb0b01eff63fac", size = 2072238, upload-time = "2026-05-06T13:39:40.807Z" }, + { url = "https://files.pythonhosted.org/packages/32/36/51eb763beec1f4cf59b1db243a7dcc39cbb41230f050a09b9d69faaf0a48/pydantic_core-2.46.4-cp314-cp314-win_arm64.whl", hash = "sha256:bfec22eab3c8cc2ceec0248aec886624116dc079afa027ecc8ad4a7e62010f8a", size = 2018251, upload-time = "2026-05-06T13:37:26.72Z" }, + { url = "https://files.pythonhosted.org/packages/e8/91/855af51d625b23aa987116a19e231d2aaef9c4a415273ddc189b79a45fee/pydantic_core-2.46.4-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:af8244b2bef6aaad6d92cda81372de7f8c8d36c9f0c3ea36e827c60e7d9467a0", size = 2099593, upload-time = "2026-05-06T13:39:47.682Z" }, + { url = "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5a4330cdbc57162e4b3aa303f588ba752257694c9c9be3e7ebb11b4aca659b5d", size = 1935226, upload-time = "2026-05-06T13:40:40.428Z" }, + { url = "https://files.pythonhosted.org/packages/e8/e7/1955d28d1afc56dd4b3ad7cc0cf39df1b9852964cf16e5d13912756d6d6b/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29c61fc04a3d840155ff08e475a04809278972fe6aef51e2720554e96367e34b", size = 1974605, upload-time = "2026-05-06T13:37:32.029Z" }, + { url = "https://files.pythonhosted.org/packages/93/e2/3fedbf0ba7a22850e6e9fd78117f1c0f10f950182344d8a6c535d468fdd8/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c50f2528cf200c5eed56faf3f4e22fcd5f38c157a8b78576e6ba3168ec35f000", size = 2030777, upload-time = "2026-05-06T13:38:55.239Z" }, + { url = "https://files.pythonhosted.org/packages/f8/61/46be275fcaaba0b4f5b9669dd852267ce1ff616592dccf7a7845588df091/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0cbe8b01f948de4286c74cdd6c667aceb38f5c1e26f0693b3983d9d74887c65e", size = 2236641, upload-time = "2026-05-06T13:37:08.096Z" }, + { url = "https://files.pythonhosted.org/packages/60/db/12e93e46a8bac9988be3c016860f83293daea8c716c029c9ace279036f2f/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:617d7e2ca7dcb8c5cf6bcb8c59b8832c94b36196bbf1cbd1bfb56ed341905edd", size = 2286404, upload-time = "2026-05-06T13:40:20.221Z" }, + { url = "https://files.pythonhosted.org/packages/e2/4a/4d8b19008f38d31c53b8219cfedc2e3d5de5fe99d90076b7e767de29274f/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7027560ee92211647d0d34e3f7cd6f50da56399d26a9c8ad0da286d3869a53f3", size = 2109219, upload-time = "2026-05-06T13:38:12.153Z" }, + { url = "https://files.pythonhosted.org/packages/88/70/3cbc40978fefb7bb09c6708d40d4ad1a5d70fd7213c3d17f971de868ec1f/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:f99626688942fb746e545232e7726926f3be91b5975f8b55327665fafda991c7", size = 2110594, upload-time = "2026-05-06T13:40:02.971Z" }, + { url = "https://files.pythonhosted.org/packages/9d/20/b8d36736216e29491125531685b2f9e61aa5b4b2599893f8268551da3338/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fc3e9034a63de20e15e8ade85358bc6efc614008cab72898b4b4952bea0509ff", size = 2159542, upload-time = "2026-05-06T13:39:27.506Z" }, + { url = "https://files.pythonhosted.org/packages/1d/a2/367df868eb584dacf6bf82a389272406d7178e301c4ac82545ab98bc2dd9/pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:97e7cf2be5c77b7d1a9713a05605d49460d02c6078d38d8bef3cbe323c548424", size = 2168146, upload-time = "2026-05-06T13:38:31.93Z" }, + { url = "https://files.pythonhosted.org/packages/c1/b8/4460f77f7e201893f649a29ab355dddd3beee8a97bcb1a320db414f9a06e/pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:3bf92c5d0e00fefaab325a4d27828fe6b6e2a21848686b5b60d2d9eeb09d76c6", size = 2306309, upload-time = "2026-05-06T13:37:44.717Z" }, + { url = "https://files.pythonhosted.org/packages/64/c4/be2639293acd87dc8ddbcec41a73cee9b2ebf996fe6d892a1a74e88ad3f7/pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:3ecbc122d18468d06ca279dc26a8c2e2d5acb10943bb35e36ae92096dc3b5565", size = 2369736, upload-time = "2026-05-06T13:37:05.645Z" }, + { url = "https://files.pythonhosted.org/packages/30/a6/9f9f380dbb301f67023bf8f707aaa75daadf84f7152d95c410fd7e81d994/pydantic_core-2.46.4-cp314-cp314t-win32.whl", hash = "sha256:e846ae7835bf0703ae43f534ab79a867146dadd59dc9ca5c8b53d5c8f7c9ef02", size = 1955575, upload-time = "2026-05-06T13:38:51.116Z" }, + { url = "https://files.pythonhosted.org/packages/40/1f/f1eb9eb350e795d1af8586289746f5c5677d16043040d63710e22abc43c9/pydantic_core-2.46.4-cp314-cp314t-win_amd64.whl", hash = "sha256:2108ba5c1c1eca18030634489dc544844144ee36357f2f9f780b93e7ddbb44b5", size = 2051624, upload-time = "2026-05-06T13:38:21.672Z" }, + { url = "https://files.pythonhosted.org/packages/f6/d2/42dd53d0a85c27606f316d3aa5d2869c4e8470a5ed6dec30e4a1abe19192/pydantic_core-2.46.4-cp314-cp314t-win_arm64.whl", hash = "sha256:4fcbe087dbc2068af7eda3aa87634eba216dbda64d1ae73c8684b621d33f6596", size = 2017325, upload-time = "2026-05-06T13:40:52.723Z" }, + { url = "https://files.pythonhosted.org/packages/ee/a4/73995fd4ebbb46ba0ee51e6fa049b8f02c40daebb762208feda8a6b7894d/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:14d4edf427bdcf950a8a02d7cb44a08614388dd6e1bdcbf4f67504fa7887da9c", size = 2111589, upload-time = "2026-05-06T13:37:10.817Z" }, + { url = "https://files.pythonhosted.org/packages/fb/7f/f37d3a5e8bfcc2e403f5c57a730f2d815693fb42119e8ea48b3789335af1/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:0ce40cd7b21210e99342afafbd4d0f76d784eb5b1d60f3bdc566be4983c6c73b", size = 1944552, upload-time = "2026-05-06T13:36:56.717Z" }, + { url = "https://files.pythonhosted.org/packages/15/3c/d7eb777b3ff43e8433a4efb39a17aa8fd98a4ee8561a24a67ef5db07b2d6/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90884113d8b48f760e9587002789ddd741e76ab9f89518cd1e43b1f1a52ec44b", size = 1982984, upload-time = "2026-05-06T13:39:06.207Z" }, + { url = "https://files.pythonhosted.org/packages/63/87/70b9f40170a81afd55ca26c9b2acb25c20d64bcfbf888fafecb3ba077d4c/pydantic_core-2.46.4-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66ce7632c22d837c95301830e111ad0128a32b8207533b60896a96c4915192ea", size = 2138417, upload-time = "2026-05-06T13:39:45.476Z" }, + { url = "https://files.pythonhosted.org/packages/9d/1d/8987ad40f65ae1432753072f214fb5c74fe47ffbd0698bb9cbbb585664f8/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:1d8ba486450b14f3b1d63bc521d410ec7565e52f887b9fb671791886436a42f7", size = 2095527, upload-time = "2026-05-06T13:39:52.283Z" }, + { url = "https://files.pythonhosted.org/packages/64/d3/84c282a7eee1d3ac4c0377546ef5a1ea436ce26840d9ac3b7ed54a377507/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:3009f12e4e90b7f88b4f9adb1b0c4a3d58fe7820f3238c190047209d148026df", size = 1936024, upload-time = "2026-05-06T13:40:15.671Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ca/eac61596cdeb4d7e174d3dc0bd8a6238f14f75f97a24e7b7db4c7e7340a0/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad785e92e6dc634c21555edc8bd6b64957ab844541bcb96a1366c202951ae526", size = 1990696, upload-time = "2026-05-06T13:38:34.717Z" }, + { url = "https://files.pythonhosted.org/packages/fa/c3/7c8b240552251faf6b3a957db200fcfbbcec36763c050428b601e0c9b83b/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00c603d540afdd6b80eb39f078f33ebd46211f02f33e34a32d9f053bba711de0", size = 2147590, upload-time = "2026-05-06T13:39:29.883Z" }, + { url = "https://files.pythonhosted.org/packages/11/cb/428de0385b6c8d44b716feba566abfacfbd23ee3c4439faa789a1456242f/pydantic_core-2.46.4-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:0c563b08bca408dc7f65f700633d8442fffb2421fc47b8101377e9fd65051ff0", size = 2112782, upload-time = "2026-05-06T13:37:04.016Z" }, + { url = "https://files.pythonhosted.org/packages/0b/b5/6a17bdadd0fc1f170adfd05a20d37c832f52b117b4d9131da1f41bb097ce/pydantic_core-2.46.4-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:db06ffe51636ffe9ca531fe9023dd64bdd794be8754cb5df57c5498ae5b518a7", size = 1952146, upload-time = "2026-05-06T13:39:43.092Z" }, + { url = "https://files.pythonhosted.org/packages/2a/dc/03734d80e362cd43ef65428e9de77c730ce7f2f11c60d2b1e1b39f0fbf99/pydantic_core-2.46.4-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:133878133d271ade3d41d1bfb2a45ec38dbdbda40bc065921c6b04e4630127e2", size = 2134492, upload-time = "2026-05-06T13:36:58.124Z" }, + { url = "https://files.pythonhosted.org/packages/de/df/5e5ffc085ed07cc22d298134d3d911c63e91f6a0eb91fe646750a3209910/pydantic_core-2.46.4-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9bc519fbf2b7578398853d815009ae5e4d4603d12f4e3f91da8c06852d3da3e9", size = 2156604, upload-time = "2026-05-06T13:37:49.88Z" }, + { url = "https://files.pythonhosted.org/packages/81/44/6e112a4253e56f5705467cbab7ab5e91ee7398ba3d56d358635958893d3e/pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:c7a7bd4e39e8e4c12c39cd480356842b6a8a06e41b23a55a5e3e191718838ddf", size = 2183828, upload-time = "2026-05-06T13:37:43.053Z" }, + { url = "https://files.pythonhosted.org/packages/ac/ad/5565071e937d8e752842ac241463944c9eb14c87e2d269f2658a5bd05e98/pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:d396ec2b979760aaf3218e76c24e65bd0aca24983298653b3a9d7a45f9e47b30", size = 2310000, upload-time = "2026-05-06T13:37:56.694Z" }, + { url = "https://files.pythonhosted.org/packages/4f/c3/66883a5cec183e7fba4d024b4cbbe61851a63750ef606b0afecc46d1f2bf/pydantic_core-2.46.4-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:86e1a4418c6cd97d60c95c71164158eaf7324fae7b0923264016baa993eba6fc", size = 2361286, upload-time = "2026-05-06T13:40:05.667Z" }, + { url = "https://files.pythonhosted.org/packages/4b/2d/69abac8f838090bbecd5df894befb2c2619e7996a98ddb949db9f3b93225/pydantic_core-2.46.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:d51026d73fcfd93610abc7b27789c26b313920fcfb20e27462d74a7f8b06e983", size = 2193071, upload-time = "2026-05-06T13:38:08.682Z" }, +] + +[[package]] +name = "pygments" +version = "2.20.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, +] + +[[package]] +name = "pyproject-hooks" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/82/28175b2414effca1cdac8dc99f76d660e7a4fb0ceefa4b4ab8f5f6742925/pyproject_hooks-1.2.0.tar.gz", hash = "sha256:1e859bd5c40fae9448642dd871adf459e5e2084186e8d2c2a79a824c970da1f8", size = 19228, upload-time = "2024-09-29T09:24:13.293Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bd/24/12818598c362d7f300f18e74db45963dbcb85150324092410c8b49405e42/pyproject_hooks-1.2.0-py3-none-any.whl", hash = "sha256:9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913", size = 10216, upload-time = "2024-09-29T09:24:11.978Z" }, +] + +[[package]] +name = "pytest" +version = "9.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e4/47/b9efed96c114afcfa3c9d3fe98a76a1d14c74a9e266d397cf6eb64be5e01/pytest-9.1.1.tar.gz", hash = "sha256:1088fbde8f2b49d95a549a195707afa7a76a3ce9bcadc26b6d71f0ffda5fe313", size = 1636369, upload-time = "2026-06-19T10:58:32.857Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl", hash = "sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c", size = 386536, upload-time = "2026-06-19T10:58:31.347Z" }, +] + +[[package]] +name = "pyvcell-odesolver" +version = "0.9.1" +source = { editable = "." } +dependencies = [ + { name = "pydantic" }, +] + +[package.optional-dependencies] +build = [ + { name = "build" }, + { name = "wheel" }, +] +test = [ + { name = "pytest" }, +] + +[package.metadata] +requires-dist = [ + { name = "build", marker = "extra == 'build'" }, + { name = "pydantic", specifier = ">=2.13.4" }, + { name = "pytest", marker = "extra == 'test'" }, + { name = "wheel", marker = "extra == 'build'" }, +] +provides-extras = ["test", "build"] + +[[package]] +name = "tomli" +version = "2.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/22/de/48c59722572767841493b26183a0d1cc411d54fd759c5607c4590b6563a6/tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f", size = 17543, upload-time = "2026-03-25T20:22:03.828Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/11/db3d5885d8528263d8adc260bb2d28ebf1270b96e98f0e0268d32b8d9900/tomli-2.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f8f0fc26ec2cc2b965b7a3b87cd19c5c6b8c5e5f436b984e85f486d652285c30", size = 154704, upload-time = "2026-03-25T20:21:10.473Z" }, + { url = "https://files.pythonhosted.org/packages/6d/f7/675db52c7e46064a9aa928885a9b20f4124ecb9bc2e1ce74c9106648d202/tomli-2.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ab97e64ccda8756376892c53a72bd1f964e519c77236368527f758fbc36a53a", size = 149454, upload-time = "2026-03-25T20:21:12.036Z" }, + { url = "https://files.pythonhosted.org/packages/61/71/81c50943cf953efa35bce7646caab3cf457a7d8c030b27cfb40d7235f9ee/tomli-2.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96481a5786729fd470164b47cdb3e0e58062a496f455ee41b4403be77cb5a076", size = 237561, upload-time = "2026-03-25T20:21:13.098Z" }, + { url = "https://files.pythonhosted.org/packages/48/c1/f41d9cb618acccca7df82aaf682f9b49013c9397212cb9f53219e3abac37/tomli-2.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a881ab208c0baf688221f8cecc5401bd291d67e38a1ac884d6736cbcd8247e9", size = 243824, upload-time = "2026-03-25T20:21:14.569Z" }, + { url = "https://files.pythonhosted.org/packages/22/e4/5a816ecdd1f8ca51fb756ef684b90f2780afc52fc67f987e3c61d800a46d/tomli-2.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47149d5bd38761ac8be13a84864bf0b7b70bc051806bc3669ab1cbc56216b23c", size = 242227, upload-time = "2026-03-25T20:21:15.712Z" }, + { url = "https://files.pythonhosted.org/packages/6b/49/2b2a0ef529aa6eec245d25f0c703e020a73955ad7edf73e7f54ddc608aa5/tomli-2.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ec9bfaf3ad2df51ace80688143a6a4ebc09a248f6ff781a9945e51937008fcbc", size = 247859, upload-time = "2026-03-25T20:21:17.001Z" }, + { url = "https://files.pythonhosted.org/packages/83/bd/6c1a630eaca337e1e78c5903104f831bda934c426f9231429396ce3c3467/tomli-2.4.1-cp311-cp311-win32.whl", hash = "sha256:ff2983983d34813c1aeb0fa89091e76c3a22889ee83ab27c5eeb45100560c049", size = 97204, upload-time = "2026-03-25T20:21:18.079Z" }, + { url = "https://files.pythonhosted.org/packages/42/59/71461df1a885647e10b6bb7802d0b8e66480c61f3f43079e0dcd315b3954/tomli-2.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:5ee18d9ebdb417e384b58fe414e8d6af9f4e7a0ae761519fb50f721de398dd4e", size = 108084, upload-time = "2026-03-25T20:21:18.978Z" }, + { url = "https://files.pythonhosted.org/packages/b8/83/dceca96142499c069475b790e7913b1044c1a4337e700751f48ed723f883/tomli-2.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:c2541745709bad0264b7d4705ad453b76ccd191e64aa6f0fc66b69a293a45ece", size = 95285, upload-time = "2026-03-25T20:21:20.309Z" }, + { url = "https://files.pythonhosted.org/packages/c1/ba/42f134a3fe2b370f555f44b1d72feebb94debcab01676bf918d0cb70e9aa/tomli-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a", size = 155924, upload-time = "2026-03-25T20:21:21.626Z" }, + { url = "https://files.pythonhosted.org/packages/dc/c7/62d7a17c26487ade21c5422b646110f2162f1fcc95980ef7f63e73c68f14/tomli-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085", size = 150018, upload-time = "2026-03-25T20:21:23.002Z" }, + { url = "https://files.pythonhosted.org/packages/5c/05/79d13d7c15f13bdef410bdd49a6485b1c37d28968314eabee452c22a7fda/tomli-2.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9", size = 244948, upload-time = "2026-03-25T20:21:24.04Z" }, + { url = "https://files.pythonhosted.org/packages/10/90/d62ce007a1c80d0b2c93e02cab211224756240884751b94ca72df8a875ca/tomli-2.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:136443dbd7e1dee43c68ac2694fde36b2849865fa258d39bf822c10e8068eac5", size = 253341, upload-time = "2026-03-25T20:21:25.177Z" }, + { url = "https://files.pythonhosted.org/packages/1a/7e/caf6496d60152ad4ed09282c1885cca4eea150bfd007da84aea07bcc0a3e/tomli-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e262d41726bc187e69af7825504c933b6794dc3fbd5945e41a79bb14c31f585", size = 248159, upload-time = "2026-03-25T20:21:26.364Z" }, + { url = "https://files.pythonhosted.org/packages/99/e7/c6f69c3120de34bbd882c6fba7975f3d7a746e9218e56ab46a1bc4b42552/tomli-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5cb41aa38891e073ee49d55fbc7839cfdb2bc0e600add13874d048c94aadddd1", size = 253290, upload-time = "2026-03-25T20:21:27.46Z" }, + { url = "https://files.pythonhosted.org/packages/d6/2f/4a3c322f22c5c66c4b836ec58211641a4067364f5dcdd7b974b4c5da300c/tomli-2.4.1-cp312-cp312-win32.whl", hash = "sha256:da25dc3563bff5965356133435b757a795a17b17d01dbc0f42fb32447ddfd917", size = 98141, upload-time = "2026-03-25T20:21:28.492Z" }, + { url = "https://files.pythonhosted.org/packages/24/22/4daacd05391b92c55759d55eaee21e1dfaea86ce5c571f10083360adf534/tomli-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:52c8ef851d9a240f11a88c003eacb03c31fc1c9c4ec64a99a0f922b93874fda9", size = 108847, upload-time = "2026-03-25T20:21:29.386Z" }, + { url = "https://files.pythonhosted.org/packages/68/fd/70e768887666ddd9e9f5d85129e84910f2db2796f9096aa02b721a53098d/tomli-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:f758f1b9299d059cc3f6546ae2af89670cb1c4d48ea29c3cacc4fe7de3058257", size = 95088, upload-time = "2026-03-25T20:21:30.677Z" }, + { url = "https://files.pythonhosted.org/packages/07/06/b823a7e818c756d9a7123ba2cda7d07bc2dd32835648d1a7b7b7a05d848d/tomli-2.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:36d2bd2ad5fb9eaddba5226aa02c8ec3fa4f192631e347b3ed28186d43be6b54", size = 155866, upload-time = "2026-03-25T20:21:31.65Z" }, + { url = "https://files.pythonhosted.org/packages/14/6f/12645cf7f08e1a20c7eb8c297c6f11d31c1b50f316a7e7e1e1de6e2e7b7e/tomli-2.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:eb0dc4e38e6a1fd579e5d50369aa2e10acfc9cace504579b2faabb478e76941a", size = 149887, upload-time = "2026-03-25T20:21:33.028Z" }, + { url = "https://files.pythonhosted.org/packages/5c/e0/90637574e5e7212c09099c67ad349b04ec4d6020324539297b634a0192b0/tomli-2.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c7f2c7f2b9ca6bdeef8f0fa897f8e05085923eb091721675170254cbc5b02897", size = 243704, upload-time = "2026-03-25T20:21:34.51Z" }, + { url = "https://files.pythonhosted.org/packages/10/8f/d3ddb16c5a4befdf31a23307f72828686ab2096f068eaf56631e136c1fdd/tomli-2.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3c6818a1a86dd6dca7ddcaaf76947d5ba31aecc28cb1b67009a5877c9a64f3f", size = 251628, upload-time = "2026-03-25T20:21:36.012Z" }, + { url = "https://files.pythonhosted.org/packages/e3/f1/dbeeb9116715abee2485bf0a12d07a8f31af94d71608c171c45f64c0469d/tomli-2.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d312ef37c91508b0ab2cee7da26ec0b3ed2f03ce12bd87a588d771ae15dcf82d", size = 247180, upload-time = "2026-03-25T20:21:37.136Z" }, + { url = "https://files.pythonhosted.org/packages/d3/74/16336ffd19ed4da28a70959f92f506233bd7cfc2332b20bdb01591e8b1d1/tomli-2.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51529d40e3ca50046d7606fa99ce3956a617f9b36380da3b7f0dd3dd28e68cb5", size = 251674, upload-time = "2026-03-25T20:21:38.298Z" }, + { url = "https://files.pythonhosted.org/packages/16/f9/229fa3434c590ddf6c0aa9af64d3af4b752540686cace29e6281e3458469/tomli-2.4.1-cp313-cp313-win32.whl", hash = "sha256:2190f2e9dd7508d2a90ded5ed369255980a1bcdd58e52f7fe24b8162bf9fedbd", size = 97976, upload-time = "2026-03-25T20:21:39.316Z" }, + { url = "https://files.pythonhosted.org/packages/6a/1e/71dfd96bcc1c775420cb8befe7a9d35f2e5b1309798f009dca17b7708c1e/tomli-2.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:8d65a2fbf9d2f8352685bc1364177ee3923d6baf5e7f43ea4959d7d8bc326a36", size = 108755, upload-time = "2026-03-25T20:21:40.248Z" }, + { url = "https://files.pythonhosted.org/packages/83/7a/d34f422a021d62420b78f5c538e5b102f62bea616d1d75a13f0a88acb04a/tomli-2.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:4b605484e43cdc43f0954ddae319fb75f04cc10dd80d830540060ee7cd0243cd", size = 95265, upload-time = "2026-03-25T20:21:41.219Z" }, + { url = "https://files.pythonhosted.org/packages/3c/fb/9a5c8d27dbab540869f7c1f8eb0abb3244189ce780ba9cd73f3770662072/tomli-2.4.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fd0409a3653af6c147209d267a0e4243f0ae46b011aa978b1080359fddc9b6cf", size = 155726, upload-time = "2026-03-25T20:21:42.23Z" }, + { url = "https://files.pythonhosted.org/packages/62/05/d2f816630cc771ad836af54f5001f47a6f611d2d39535364f148b6a92d6b/tomli-2.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a120733b01c45e9a0c34aeef92bf0cf1d56cfe81ed9d47d562f9ed591a9828ac", size = 149859, upload-time = "2026-03-25T20:21:43.386Z" }, + { url = "https://files.pythonhosted.org/packages/ce/48/66341bdb858ad9bd0ceab5a86f90eddab127cf8b046418009f2125630ecb/tomli-2.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:559db847dc486944896521f68d8190be1c9e719fced785720d2216fe7022b662", size = 244713, upload-time = "2026-03-25T20:21:44.474Z" }, + { url = "https://files.pythonhosted.org/packages/df/6d/c5fad00d82b3c7a3ab6189bd4b10e60466f22cfe8a08a9394185c8a8111c/tomli-2.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01f520d4f53ef97964a240a035ec2a869fe1a37dde002b57ebc4417a27ccd853", size = 252084, upload-time = "2026-03-25T20:21:45.62Z" }, + { url = "https://files.pythonhosted.org/packages/00/71/3a69e86f3eafe8c7a59d008d245888051005bd657760e96d5fbfb0b740c2/tomli-2.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7f94b27a62cfad8496c8d2513e1a222dd446f095fca8987fceef261225538a15", size = 247973, upload-time = "2026-03-25T20:21:46.937Z" }, + { url = "https://files.pythonhosted.org/packages/67/50/361e986652847fec4bd5e4a0208752fbe64689c603c7ae5ea7cb16b1c0ca/tomli-2.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ede3e6487c5ef5d28634ba3f31f989030ad6af71edfb0055cbbd14189ff240ba", size = 256223, upload-time = "2026-03-25T20:21:48.467Z" }, + { url = "https://files.pythonhosted.org/packages/8c/9a/b4173689a9203472e5467217e0154b00e260621caa227b6fa01feab16998/tomli-2.4.1-cp314-cp314-win32.whl", hash = "sha256:3d48a93ee1c9b79c04bb38772ee1b64dcf18ff43085896ea460ca8dec96f35f6", size = 98973, upload-time = "2026-03-25T20:21:49.526Z" }, + { url = "https://files.pythonhosted.org/packages/14/58/640ac93bf230cd27d002462c9af0d837779f8773bc03dee06b5835208214/tomli-2.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:88dceee75c2c63af144e456745e10101eb67361050196b0b6af5d717254dddf7", size = 109082, upload-time = "2026-03-25T20:21:50.506Z" }, + { url = "https://files.pythonhosted.org/packages/d5/2f/702d5e05b227401c1068f0d386d79a589bb12bf64c3d2c72ce0631e3bc49/tomli-2.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:b8c198f8c1805dc42708689ed6864951fd2494f924149d3e4bce7710f8eb5232", size = 96490, upload-time = "2026-03-25T20:21:51.474Z" }, + { url = "https://files.pythonhosted.org/packages/45/4b/b877b05c8ba62927d9865dd980e34a755de541eb65fffba52b4cc495d4d2/tomli-2.4.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:d4d8fe59808a54658fcc0160ecfb1b30f9089906c50b23bcb4c69eddc19ec2b4", size = 164263, upload-time = "2026-03-25T20:21:52.543Z" }, + { url = "https://files.pythonhosted.org/packages/24/79/6ab420d37a270b89f7195dec5448f79400d9e9c1826df982f3f8e97b24fd/tomli-2.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7008df2e7655c495dd12d2a4ad038ff878d4ca4b81fccaf82b714e07eae4402c", size = 160736, upload-time = "2026-03-25T20:21:53.674Z" }, + { url = "https://files.pythonhosted.org/packages/02/e0/3630057d8eb170310785723ed5adcdfb7d50cb7e6455f85ba8a3deed642b/tomli-2.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1d8591993e228b0c930c4bb0db464bdad97b3289fb981255d6c9a41aedc84b2d", size = 270717, upload-time = "2026-03-25T20:21:55.129Z" }, + { url = "https://files.pythonhosted.org/packages/7a/b4/1613716072e544d1a7891f548d8f9ec6ce2faf42ca65acae01d76ea06bb0/tomli-2.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:734e20b57ba95624ecf1841e72b53f6e186355e216e5412de414e3c51e5e3c41", size = 278461, upload-time = "2026-03-25T20:21:56.228Z" }, + { url = "https://files.pythonhosted.org/packages/05/38/30f541baf6a3f6df77b3df16b01ba319221389e2da59427e221ef417ac0c/tomli-2.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8a650c2dbafa08d42e51ba0b62740dae4ecb9338eefa093aa5c78ceb546fcd5c", size = 274855, upload-time = "2026-03-25T20:21:57.653Z" }, + { url = "https://files.pythonhosted.org/packages/77/a3/ec9dd4fd2c38e98de34223b995a3b34813e6bdadf86c75314c928350ed14/tomli-2.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:504aa796fe0569bb43171066009ead363de03675276d2d121ac1a4572397870f", size = 283144, upload-time = "2026-03-25T20:21:59.089Z" }, + { url = "https://files.pythonhosted.org/packages/ef/be/605a6261cac79fba2ec0c9827e986e00323a1945700969b8ee0b30d85453/tomli-2.4.1-cp314-cp314t-win32.whl", hash = "sha256:b1d22e6e9387bf4739fbe23bfa80e93f6b0373a7f1b96c6227c32bef95a4d7a8", size = 108683, upload-time = "2026-03-25T20:22:00.214Z" }, + { url = "https://files.pythonhosted.org/packages/12/64/da524626d3b9cc40c168a13da8335fe1c51be12c0a63685cc6db7308daae/tomli-2.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:2c1c351919aca02858f740c6d33adea0c5deea37f9ecca1cc1ef9e884a619d26", size = 121196, upload-time = "2026-03-25T20:22:01.169Z" }, + { url = "https://files.pythonhosted.org/packages/5a/cd/e80b62269fc78fc36c9af5a6b89c835baa8af28ff5ad28c7028d60860320/tomli-2.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:eab21f45c7f66c13f2a9e0e1535309cee140182a9cdae1e041d02e47291e8396", size = 100393, upload-time = "2026-03-25T20:22:02.137Z" }, + { url = "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe", size = 14583, upload-time = "2026-03-25T20:22:03.012Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/cc/6253133b5bb138fc3306cebfbda2c520f545d36b5be2c7255cc528bb45d6/typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5", size = 113555, upload-time = "2026-07-02T08:40:05.92Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8", size = 45571, upload-time = "2026-07-02T08:40:04.659Z" }, +] + +[[package]] +name = "typing-inspection" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, +] + +[[package]] +name = "wheel" +version = "0.47.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/39/62/75f18a0f03b4219c456652c7780e4d749b929eb605c098ce3a5b6b6bc081/wheel-0.47.0.tar.gz", hash = "sha256:cc72bd1009ba0cf63922e28f94d9d83b920aa2bb28f798a31d0691b02fa3c9b3", size = 63854, upload-time = "2026-04-22T15:51:27.727Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/87/1b/9e33c09813d65e248f7f773119148a612516a4bea93e9c6f545f78455b7c/wheel-0.47.0-py3-none-any.whl", hash = "sha256:212281cab4dff978f6cedd499cd893e1f620791ca6ff7107cf270781e587eced", size = 32218, upload-time = "2026-04-22T15:51:26.296Z" }, +] + +[[package]] +name = "zipp" +version = "4.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b9/d8/eab98a517c14134c0b2eb4e2387bc5f457334293ec5d2dd3857ec2966802/zipp-4.1.0.tar.gz", hash = "sha256:4cb57381f544315db7688e976e922a2b18cdb513d21cc194eb42232ba2a3e602", size = 26214, upload-time = "2026-05-18T20:08:57.967Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/13/547360d81e6d88d58492968ffda9f9542854f11310ee556fef14260cc886/zipp-4.1.0-py3-none-any.whl", hash = "sha256:25ad4e16390cd314347dd8f1de67a2ac538ae658ed4ab9db16029c07c188e97f", size = 10238, upload-time = "2026-05-18T20:08:57.045Z" }, +] diff --git a/vcell-expressionparser b/vcell-expressionparser new file mode 160000 index 000000000..2fd45ae0d --- /dev/null +++ b/vcell-expressionparser @@ -0,0 +1 @@ +Subproject commit 2fd45ae0d3e9dc3cf0e20b8d863e4b78d1afbfd1 diff --git a/vcell-messaging b/vcell-messaging new file mode 160000 index 000000000..2de74ef66 --- /dev/null +++ b/vcell-messaging @@ -0,0 +1 @@ +Subproject commit 2de74ef666700b815ba2370f55c13e9831625ceb