diff --git a/.github/workflows/alt_linux_distros.yml b/.github/workflows/alt_linux_distros.yml new file mode 100644 index 00000000..31606d47 --- /dev/null +++ b/.github/workflows/alt_linux_distros.yml @@ -0,0 +1,178 @@ +name: More Linux + +on: + schedule: + - cron: '0 0 * * 0' + workflow_dispatch: + +jobs: + build: + strategy: + fail-fast: false + matrix: + cfg: +#-------- Operating Systems ---------------- + - { os: ubuntu, tag: 18.04, arch: debian, arch_ver: 10 } + - { os: ubuntu, tag: 20.04, arch: debian, arch_ver: 11 } + - { os: debian, tag: 10, arch: debian, arch_ver: 10 } + - { os: debian, tag: 11, arch: debian, arch_ver: 11 } + - { os: debian, tag: bookworm, arch: debian, arch_ver: 12 } + - { os: almalinux, tag: 8, arch: rhel, arch_ver: 8 } + python: [2, 3] + +#-------- Defaults -------------------------- + include: + - cfg: {} + deps: >- + bison + clang + flex + git + llvm + make + maven + cmake + zip + install_gtest: echo gtest already installed + conf_pkg: echo package manager already configured + install_cmd: install -y +#-------- Debian-based Dependencies ---------------- + - cfg: { arch: debian } + pkg_mgr: apt-get + conf_pkg: apt-get update + arch_deps: >- + swig + curl + g++ + libx11-dev + libxml2-dev + libxt-dev + libmotif-common + libmotif-dev + zlib1g-dev + llvm-dev + libclang-dev + libudunits2-dev + libgtest-dev + default-jdk + python3-dev + python3-pip + python3-venv + install_gtest: | + apt-get install -y libgtest-dev + cd /usr/src/gtest + cmake . + make + cp lib/libgtest* /usr/lib/ +#-------- RHEL Dependencies ---------------- + - cfg: { arch: rhel } + arch_deps: >- + clang-devel + gcc + gcc-c++ + java-11-openjdk-devel + libxml2-devel + llvm-devel + llvm-static + ncurses-devel + openmotif + openmotif-devel + perl + perl-Digest-MD5 + udunits2 + udunits2-devel + which + zlib-devel + python2-devel + python3-devel +#-------- RHEL 8-based Only Dependencies ---------------- + - cfg: { arch: rhel, arch_ver: 8 } + pkg_mgr: dnf + tag_deps: >- + swig + diffutils + conf_pkg: | + dnf -y install epel-release + dnf -y update + dnf install -y 'dnf-command(config-manager)' + install_gtest: | + dnf config-manager --enable powertools + dnf install -y gtest-devel +#-------- Debian 10-based Only Dependencies ---------------- + - cfg: { arch: debian, arch_ver: 10 } + install_gtest: | + apt-get install -y libgtest-dev + cd /usr/src/gtest + cmake . + make + cp libgtest* /usr/lib/ +#-------- Debian 11-based Only Dependencies ---------------- + - cfg: { arch: debian, arch_ver: 11 } + conf_pkg: | + export DEBIAN_FRONTEND=noninteractive + apt-get update + apt-get install -y tzdata +#-------- Python2.7 dependencies --------------------------- + - cfg: { arch: debian } + python: 2 + python_deps: >- + python2.7-dev +#-------- Exclude bookworm on python 2 --------------------- + exclude: + - cfg: { tag: bookworm } + python: 2 + +#-------- OS and Version Specific Dependencies ---------------- +# None +#-------- Job definition ---------------- + runs-on: ubuntu-latest + container: docker://${{matrix.cfg.os}}:${{matrix.cfg.tag}} + steps: + - name: Update Package Manager + run: ${{matrix.conf_pkg}} + - name: Install Dependencies + run: > + ${{matrix.pkg_mgr}} + ${{matrix.install_cmd}} + ${{matrix.deps}} + ${{matrix.arch_deps}} + ${{matrix.os_deps}} + ${{matrix.tag_deps}} + ${{matrix.python_deps}} + - name: Install GTest + run: ${{matrix.install_gtest}} + - name: Checkout repository + uses: actions/checkout@master + - name: Configure Trick + run: | + export MAKEFLAGS=-j`nproc` + export PYTHON_VERSION=${{matrix.python}} + ./configure + - name: Build Trick + run: | + export MAKEFLAGS=-j`nproc` + make + - name: Test + run: | + cd share/trick/trickops/ + python3 -m venv .venv && . .venv/bin/activate && pip3 install -r requirements.txt + cd ../../../; make test + - name: Upload Tests + uses: actions/upload-artifact@v3.0.0 + if: success() || failure() # run this step even if previous step failed + with: + name: Trick_${{matrix.cfg.os}}${{matrix.cfg.tag}}_py${{matrix.python}} + path: trick_test/*.xml + retention-days: 1 +# Uncomment for build artifacts +# - name: Upload Trick Build +# uses: actions/upload-artifact@v3.0.0 +# with: +# name: Trick_${{matrix.cfg.os}}${{matrix.cfg.tag}}_py${{matrix.python}} +# path: | +# bin +# include +# lib +# share +# libexec +# retention-days: 1 diff --git a/.github/workflows/code_coverage.yml b/.github/workflows/code_coverage.yml new file mode 100644 index 00000000..27f90b37 --- /dev/null +++ b/.github/workflows/code_coverage.yml @@ -0,0 +1,73 @@ +name: Code Coverage + +on: + push: + branches: + - master + paths-ignore: + - 'docs/**' + - '.github/workflows/**' + - '!.github/workflows/code_coverage.yml' + pull_request: + workflow_dispatch: + +jobs: + code-coverage: + runs-on: ubuntu-latest + container: docker://oraclelinux:8 + steps: + - name: Update Package Manager + run: | + dnf -y install epel-release + dnf -y update + dnf install -y 'dnf-command(config-manager)' + + - name: Install Dependencies + run: | + dnf install -y bison clang flex git llvm make maven cmake zip clang-devel gcc gcc-c++ java-11-openjdk-devel libxml2-devel llvm-devel llvm-static ncurses-devel openmotif openmotif-devel perl perl-Digest-MD5 udunits2 udunits2-devel which zlib-devel python2-devel python3-devel swig diffutils lcov + + - name: Install GTest + run: | + dnf config-manager --enable ol8_codeready_builder + dnf install -y gtest-devel + + - name: Checkout repository + uses: actions/checkout@master + + - name: Configure Trick + run: | + export MAKEFLAGS=-j`nproc` + export PYTHON_VERSION=3 + ./configure + - name: Build Trick + run: | + export MAKEFLAGS=-j`nproc` + export CFLAGS="-fprofile-arcs -ftest-coverage -O0" + export CXXFLAGS="-fprofile-arcs -ftest-coverage -O0" + export LDFLAGS="-fprofile-arcs -ftest-coverage -O0" + export TRICK_CFLAGS="-fprofile-arcs -ftest-coverage -O0" + export TRICK_CXXFLAGS="-fprofile-arcs -ftest-coverage -O0" + export TRICK_SYSTEM_LDFLAGS="-fprofile-arcs -ftest-coverage -O0" + export TRICK_SYSTEM_CFLAGS="-fprofile-arcs -ftest-coverage -O0" + export TRICK_SYSTEM_CXXFLAGS="-fprofile-arcs -ftest-coverage -O0" + make + - name: Generate Code Coverage + run: | + export MAKEFLAGS=-j`nproc` + export CFLAGS="-fprofile-arcs -ftest-coverage -O0" + export CXXFLAGS="-fprofile-arcs -ftest-coverage -O0" + export LDFLAGS="-fprofile-arcs -ftest-coverage -O0" + export TRICK_CFLAGS="-fprofile-arcs -ftest-coverage -O0" + export TRICK_CXXFLAGS="-fprofile-arcs -ftest-coverage -O0" + export TRICK_SYSTEM_LDFLAGS="-fprofile-arcs -ftest-coverage -O0" + export TRICK_SYSTEM_CFLAGS="-fprofile-arcs -ftest-coverage -O0" + export TRICK_SYSTEM_CXXFLAGS="-fprofile-arcs -ftest-coverage -O0" + cd share/trick/trickops/ + python3 -m venv .venv && . .venv/bin/activate && pip3 install -r requirements.txt + cd ../../../ + make code-coverage + - name: Upload to Coveralls + uses: coverallsapp/github-action@master + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + path-to-lcov: "./coverage.info" diff --git a/.github/workflows/report_alt_linux_distros.yml b/.github/workflows/report_alt_linux_distros.yml new file mode 100644 index 00000000..7ca302cc --- /dev/null +++ b/.github/workflows/report_alt_linux_distros.yml @@ -0,0 +1,34 @@ +name: 'Report More Linux' + +on: + workflow_run: + workflows: ['More Linux'] # runs after CI workflow + types: + - completed +jobs: + report: + strategy: + fail-fast: false + matrix: + cfg: +#-------- Operating Systems ---------------- + - { os: ubuntu, tag: 18.04, arch: debian, arch_ver: 10 } + - { os: ubuntu, tag: 20.04, arch: debian, arch_ver: 11 } + - { os: debian, tag: 10, arch: debian, arch_ver: 10 } + - { os: debian, tag: 11, arch: debian, arch_ver: 11 } + - { os: debian, tag: bookworm, arch: debian, arch_ver: 12 } + - { os: almalinux, tag: 8, arch: rhel, arch_ver: 8 } + python: [2, 3] + #-------- Exclude bookworm on python 2 --------------------- + exclude: + - cfg: { tag: bookworm } + python: 2 + + runs-on: ubuntu-latest + steps: + - uses: dorny/test-reporter@v1 + with: + artifact: Trick_${{matrix.cfg.os}}${{matrix.cfg.tag}}_py${{matrix.python}} # artifact name + name: Results_Trick_${{matrix.cfg.os}}${{matrix.cfg.tag}}_py${{matrix.python}} # Name of the check run which will be created + path: '*.xml' # Path to test results (inside artifact .zip) + reporter: java-junit # Format of test results diff --git a/.github/workflows/report_linux.yml b/.github/workflows/report_linux.yml index b91ea9a9..668be883 100644 --- a/.github/workflows/report_linux.yml +++ b/.github/workflows/report_linux.yml @@ -1,4 +1,4 @@ -name: 'Report' +name: 'Report Linux' on: workflow_run: @@ -12,15 +12,12 @@ jobs: matrix: cfg: #-------- Operating Systems ---------------- - - { os: ubuntu, tag: 18.04, arch: debian, arch_ver: 10 } - - { os: ubuntu, tag: 20.04, arch: debian, arch_ver: 11 } - - { os: debian, tag: 10, arch: debian, arch_ver: 10 } - - { os: debian, tag: 11, arch: debian, arch_ver: 11 } - - { os: centos, tag: 7, arch: rhel, arch_ver: 7 } - - { os: rockylinux, tag: 8, arch: rhel, arch_ver: 8 } - - { os: oraclelinux, tag: 8, arch: rhel, arch_ver: 8 } - - { os: almalinux, tag: 8, arch: rhel, arch_ver: 8 } - python: [2, 3] + - { os: ubuntu, tag: 22.04, arch: debian, arch_ver: 12 } + - { os: centos, tag: 7, arch: rhel, arch_ver: 7 } + - { os: rockylinux, tag: 8, arch: rhel, arch_ver: 8 } + - { os: oraclelinux, tag: 8, arch: rhel, arch_ver: 8 } + python: [3] + runs-on: ubuntu-latest steps: diff --git a/.github/workflows/report_linux_py2.yml b/.github/workflows/report_linux_py2.yml new file mode 100644 index 00000000..d324d7b8 --- /dev/null +++ b/.github/workflows/report_linux_py2.yml @@ -0,0 +1,29 @@ +name: 'Report Linux Python 2' + +on: + workflow_run: + workflows: ['Linux Python 2'] # runs after CI workflow + types: + - completed +jobs: + report: + strategy: + fail-fast: false + matrix: + cfg: +#-------- Operating Systems ---------------- + - { os: ubuntu, tag: 22.04, arch: debian, arch_ver: 12 } + - { os: centos, tag: 7, arch: rhel, arch_ver: 7 } + - { os: rockylinux, tag: 8, arch: rhel, arch_ver: 8 } + - { os: oraclelinux, tag: 8, arch: rhel, arch_ver: 8 } + python: [2] + + + runs-on: ubuntu-latest + steps: + - uses: dorny/test-reporter@v1 + with: + artifact: Trick_${{matrix.cfg.os}}${{matrix.cfg.tag}}_py${{matrix.python}} # artifact name + name: Results_Trick_${{matrix.cfg.os}}${{matrix.cfg.tag}}_py${{matrix.python}} # Name of the check run which will be created + path: '*.xml' # Path to test results (inside artifact .zip) + reporter: java-junit # Format of test results diff --git a/.github/workflows/report_macos.yml b/.github/workflows/report_macos.yml new file mode 100644 index 00000000..03b706c1 --- /dev/null +++ b/.github/workflows/report_macos.yml @@ -0,0 +1,20 @@ +name: 'Report macOS' + +on: + workflow_run: + workflows: ['macOS'] # runs after CI workflow + types: + - completed +jobs: + report: + strategy: + fail-fast: false + + runs-on: ubuntu-latest + steps: + - uses: dorny/test-reporter@v1 + with: + artifact: Trick_macos # artifact name + name: Results_Trick_macos # Name of the check run which will be created + path: '*.xml' # Path to test results (inside artifact .zip) + reporter: java-junit # Format of test results diff --git a/.github/workflows/test_32.yml b/.github/workflows/test_32.yml index 6a77bf2e..964338b0 100644 --- a/.github/workflows/test_32.yml +++ b/.github/workflows/test_32.yml @@ -1,16 +1,13 @@ name: 32-bit on: - push: - paths-ignore: - - 'docs/**' - - '.github/workflows/**' - - '!.github/workflows/test_32.yml' - pull_request: + schedule: + - cron: '0 0 * * 0' + workflow_dispatch: jobs: trick_32bit: - runs-on: ubuntu-18.04 + runs-on: ubuntu-latest container: docker://centos:7 steps: - name: Checkout repository @@ -30,7 +27,7 @@ jobs: glibc.i686 glibc-devel.i686 udunits2 udunits2-devel gtest-devel.i686 java-11-openjdk java-11-openjdk-devel expat-devel.i686 which gcc-gfortran git wget gsl-devel gtest-devel gsl-devel.i686 - maven udunits2 udunits2-devel zip + maven udunits2 udunits2-devel zip libgcc*i686 libstdc++*i686 glibc*i686 - name: Symlink python run: | cd /usr/lib @@ -63,4 +60,10 @@ jobs: ./configure --without-hdf5 --enable-32bit make - name: Run tests - run: make test + run: | + cd share/trick/trickops/ + yum install -y python3-devel + python3 -m venv .venv && . .venv/bin/activate && pip install --upgrade pip && pip3 install -r requirements.txt + cd ../../../ + echo $MAKEFLAGS $CXXFLAGS $CFLAGS + make test diff --git a/.github/workflows/test_32_oracle.yml b/.github/workflows/test_32_oracle.yml new file mode 100644 index 00000000..dc0db9fa --- /dev/null +++ b/.github/workflows/test_32_oracle.yml @@ -0,0 +1,75 @@ +name: 32-bit Oracle + +on: + schedule: + - cron: '0 0 * * 0' + workflow_dispatch: + +jobs: + trick_32bit_oracle: + runs-on: ubuntu-latest + container: docker://oraclelinux:8 + steps: + - name: Add dnf repo + run: dnf -y install epel-release && dnf -y update + - name: Install other dependencies + run: > + dnf install -y tar bison clang clang-devel cmake diffutils + expat-devel.i686 expat.i686 flex gcc gcc-c++ git glibc-devel.i686 + glibc.i686 glibc.x86_64 gsl-devel gsl-devel.i686 java-11-openjdk + java-11-openjdk-devel libstdc++-devel libstdc++-devel.i686 libxml2-devel + libxml2-devel.i686 llvm llvm-devel llvm-static make maven ncurses-devel + ncurses-devel.i686 openmotif openmotif-devel perl perl-Digest-MD5 + python2-devel python3-devel python3-libs.i686 swig tar udunits2 + udunits2-devel wget which zip zlib-devel zlib-devel.i686 + - name: Symlink python + run: | + ln -s /lib/libpython3.6m.so.1.0 /lib/libpython3.6m.so + - name: Install Udunits (32 bit) + run: | + cd / + curl --retry 4 -O https://artifacts.unidata.ucar.edu/repository/downloads-udunits/current/udunits-2.2.28.tar.gz + tar xfvz udunits-2.2.28.tar.gz + rm -rf udunits-2.2.28.tar.gz + cd udunits-2.2.28 + export CFLAGS="-m32" + export CXXFLAGS="-m32" + export MAKEFLAGS=-j`nproc` + ./configure + make + make install + cd / + rm -rf udunit-2.2.28 + - name: Install GTest + run: | + dnf config-manager --enable ol8_codeready_builder + dnf install -y gtest-devel + - name: Install GTest (32 bit) + run: | + wget https://github.com/google/googletest/archive/release-1.8.0.tar.gz + tar xfvz release-1.8.0.tar.gz + cd googletest-release-1.8.0/googletest + export CFLAGS="-m32" + export CXXFLAGS="-m32" + export MAKEFLAGS=-j`nproc` + cmake . + make + make install + - name: Checkout repository + uses: actions/checkout@master + - name: Build Trick + run: | + export CFLAGS="-m32" + export CXXFLAGS="-m32" + export MAKEFLAGS=-j`nproc` + ./configure --without-hdf5 --enable-32bit + make + - name: Run tests + run: | + cd share/trick/trickops/ + python3 -m venv .venv && . .venv/bin/activate && pip3 install -r requirements.txt + cd ../../../ + export CFLAGS="-m32" + export CXXFLAGS="-m32" + export MAKEFLAGS=-j`nproc` + make test diff --git a/.github/workflows/test_linux.yml b/.github/workflows/test_linux.yml index 4eed1072..42637d40 100644 --- a/.github/workflows/test_linux.yml +++ b/.github/workflows/test_linux.yml @@ -2,6 +2,8 @@ name: Linux on: push: + branches: + - master paths-ignore: - 'docs/**' - '.github/workflows/**' @@ -16,17 +18,11 @@ jobs: matrix: cfg: #-------- Operating Systems ---------------- - - { os: ubuntu, tag: 18.04, arch: debian, arch_ver: 10 } - - { os: ubuntu, tag: 20.04, arch: debian, arch_ver: 11 } - { os: ubuntu, tag: 22.04, arch: debian, arch_ver: 12 } - - { os: debian, tag: 10, arch: debian, arch_ver: 10 } - - { os: debian, tag: 11, arch: debian, arch_ver: 11 } - - { os: debian, tag: bookworm, arch: debian, arch_ver: 12 } - { os: centos, tag: 7, arch: rhel, arch_ver: 7 } - { os: rockylinux, tag: 8, arch: rhel, arch_ver: 8 } - { os: oraclelinux, tag: 8, arch: rhel, arch_ver: 8 } - - { os: almalinux, tag: 8, arch: rhel, arch_ver: 8 } - python: [2, 3] + python: [3] #-------- Defaults -------------------------- include: @@ -65,6 +61,8 @@ jobs: default-jdk python2.7-dev python3-dev + python3-pip + python3-venv install_gtest: | apt-get install -y libgtest-dev cd /usr/src/gtest @@ -116,20 +114,6 @@ jobs: install_gtest: | dnf config-manager --enable powertools dnf install -y gtest-devel -#-------- Debian 10-based Only Dependencies ---------------- - - cfg: { arch: debian, arch_ver: 10 } - install_gtest: | - apt-get install -y libgtest-dev - cd /usr/src/gtest - cmake . - make - cp libgtest* /usr/lib/ -#-------- Debian 11-based Only Dependencies ---------------- - - cfg: { arch: debian, arch_ver: 11 } - conf_pkg: | - export DEBIAN_FRONTEND=noninteractive - apt-get update - apt-get install -y tzdata #-------- OS and Version Specific Dependencies ---------------- - cfg: { os: oraclelinux } install_gtest: | @@ -163,7 +147,10 @@ jobs: export MAKEFLAGS=-j`nproc` make - name: Test - run: make test + run: | + cd share/trick/trickops/ + python3 -m venv .venv && . .venv/bin/activate && pip3 install -r requirements.txt + cd ../../../; make test - name: Upload Tests uses: actions/upload-artifact@v3.0.0 if: success() || failure() # run this step even if previous step failed @@ -183,30 +170,3 @@ jobs: # share # libexec # retention-days: 1 - -# report: -# needs: [build] -# strategy: -# fail-fast: false -# matrix: -# cfg: -# #-------- Operating Systems ---------------- -# - { os: ubuntu, tag: 18.04, arch: debian, arch_ver: 10 } -# - { os: ubuntu, tag: 20.04, arch: debian, arch_ver: 11 } -# - { os: debian, tag: 10, arch: debian, arch_ver: 10 } -# - { os: debian, tag: 11, arch: debian, arch_ver: 11 } -# - { os: centos, tag: 7, arch: rhel, arch_ver: 7 } -# - { os: rockylinux, tag: 8, arch: rhel, arch_ver: 8 } -# - { os: oraclelinux, tag: 8, arch: rhel, arch_ver: 8 } -# - { os: almalinux, tag: 8, arch: rhel, arch_ver: 8 } -# python: [2, 3] - -# runs-on: ubuntu-latest -# steps: -# - uses: dorny/test-reporter@v1 -# with: -# artifact: Trick_${{matrix.cfg.os}}${{matrix.cfg.tag}}_py${{matrix.python}} # artifact name -# name: Results_Trick_${{matrix.cfg.os}}${{matrix.cfg.tag}}_py${{matrix.python}} # Name of the check run which will be created -# path: '*.xml' # Path to test results (inside artifact .zip) -# reporter: java-junit # Format of test results - diff --git a/.github/workflows/test_linux_py2.yml b/.github/workflows/test_linux_py2.yml new file mode 100644 index 00000000..f14fc1c4 --- /dev/null +++ b/.github/workflows/test_linux_py2.yml @@ -0,0 +1,166 @@ +name: 'Linux Python 2' + +on: + schedule: + - cron: '0 0 * * 0' + workflow_dispatch: + +jobs: + build: + strategy: + fail-fast: false + matrix: + cfg: +#-------- Operating Systems ---------------- + - { os: ubuntu, tag: 22.04, arch: debian, arch_ver: 12 } + - { os: centos, tag: 7, arch: rhel, arch_ver: 7 } + - { os: rockylinux, tag: 8, arch: rhel, arch_ver: 8 } + - { os: oraclelinux, tag: 8, arch: rhel, arch_ver: 8 } + python: [2] + +#-------- Defaults -------------------------- + include: + - cfg: {} + deps: >- + bison + clang + flex + git + llvm + make + maven + cmake + zip + install_gtest: echo gtest already installed + conf_pkg: echo package manager already configured + install_cmd: install -y +#-------- Debian-based Dependencies ---------------- + - cfg: { arch: debian } + pkg_mgr: apt-get + conf_pkg: apt-get update + arch_deps: >- + swig + curl + g++ + libx11-dev + libxml2-dev + libxt-dev + libmotif-common + libmotif-dev + zlib1g-dev + llvm-dev + libclang-dev + libudunits2-dev + libgtest-dev + default-jdk + python2.7-dev + python3-dev + python3-pip + python3-venv + install_gtest: | + apt-get install -y libgtest-dev + cd /usr/src/gtest + cmake . + make + cp lib/libgtest* /usr/lib/ +#-------- RHEL Dependencies ---------------- + - cfg: { arch: rhel } + arch_deps: >- + clang-devel + gcc + gcc-c++ + java-11-openjdk-devel + libxml2-devel + llvm-devel + llvm-static + ncurses-devel + openmotif + openmotif-devel + perl + perl-Digest-MD5 + udunits2 + udunits2-devel + which + zlib-devel + python2-devel + python3-devel +#-------- RHEL 7-based Only Dependencies ---------------- + - cfg: { arch: rhel, arch_ver: 7 } + pkg_mgr: yum + conf_pkg: | + yum -y install epel-release + yum -y update + os_deps: >- + libX11-devel + libXt-devel + swig3 + gtest-devel +#-------- RHEL 8-based Only Dependencies ---------------- + - cfg: { arch: rhel, arch_ver: 8 } + pkg_mgr: dnf + tag_deps: >- + swig + diffutils + conf_pkg: | + dnf -y install epel-release + dnf -y update + dnf install -y 'dnf-command(config-manager)' + install_gtest: | + dnf config-manager --enable powertools + dnf install -y gtest-devel +#-------- OS and Version Specific Dependencies ---------------- + - cfg: { os: oraclelinux } + install_gtest: | + dnf config-manager --enable ol8_codeready_builder + dnf install -y gtest-devel +#-------- Job definition ---------------- + runs-on: ubuntu-latest + container: docker://${{matrix.cfg.os}}:${{matrix.cfg.tag}} + steps: + - name: Update Package Manager + run: ${{matrix.conf_pkg}} + - name: Install Dependencies + run: > + ${{matrix.pkg_mgr}} + ${{matrix.install_cmd}} + ${{matrix.deps}} + ${{matrix.arch_deps}} + ${{matrix.os_deps}} + ${{matrix.tag_deps}} + - name: Install GTest + run: ${{matrix.install_gtest}} + - name: Checkout repository + uses: actions/checkout@master + - name: Configure Trick + run: | + export MAKEFLAGS=-j`nproc` + export PYTHON_VERSION=${{matrix.python}} + ./configure + - name: Build Trick + run: | + export MAKEFLAGS=-j`nproc` + make + - name: Test + run: | + cd share/trick/trickops/ + python3 -m venv .venv && . .venv/bin/activate && pip3 install -r requirements.txt + cd ../../../; make test + - name: Upload Tests + uses: actions/upload-artifact@v3.0.0 + if: success() || failure() # run this step even if previous step failed + with: + name: Trick_${{matrix.cfg.os}}${{matrix.cfg.tag}}_py${{matrix.python}} + path: trick_test/*.xml + retention-days: 1 +# Uncomment for build artifacts +# - name: Upload Trick Build +# uses: actions/upload-artifact@v3.0.0 +# with: +# name: Trick_${{matrix.cfg.os}}${{matrix.cfg.tag}}_py${{matrix.python}} +# path: | +# bin +# include +# lib +# share +# libexec +# retention-days: 1 diff --git a/.github/workflows/test_macos.yml b/.github/workflows/test_macos.yml index a0e0f79c..d6df3509 100644 --- a/.github/workflows/test_macos.yml +++ b/.github/workflows/test_macos.yml @@ -2,11 +2,14 @@ name: macOS on: push: + branches: + - master paths-ignore: - 'docs/**' - '.github/workflows/**' - '!.github/workflows/test_macos.yml' pull_request: + workflow_dispatch: jobs: macOS: @@ -17,23 +20,29 @@ jobs: - name: Install gtest run: | - wget https://github.com/google/googletest/archive/release-1.8.0.tar.gz - tar xzvf release-1.8.0.tar.gz - cd googletest-release-1.8.0/googletest - cmake . - make - make install + brew install googletest - name: Install dependencies run: | # sudo installer -pkg /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.15.pkg -target / brew install --cask xquartz - brew install llvm@11 swig udunits openmotif maven + brew install swig udunits openmotif maven + wget https://github.com/llvm/llvm-project/releases/download/llvmorg-14.0.6/clang+llvm-14.0.6-x86_64-apple-darwin.tar.xz + tar -xvf clang+llvm-14.0.6-x86_64-apple-darwin.tar.xz - name: Build Trick run: | export MAKEFLAGS=-j4 - ./configure --with-llvm=/usr/local/opt/llvm@11 + ./configure --with-llvm=${GITHUB_WORKSPACE}/clang+llvm-14.0.6-x86_64-apple-darwin make - - name: Run tests + - name: Test run: | + cd share/trick/trickops/ + python3 -m venv .venv && source .venv/bin/activate && pip3 install -r requirements.txt export MAKEFLAGS=-j4 - make test + cd ../../../; make test + - name: Upload Tests + uses: actions/upload-artifact@v3.0.0 + if: success() || failure() # run this step even if previous step failed + with: + name: Trick_macos + path: trick_test/*.xml + retention-days: 1 diff --git a/.github/workflows/trickops.yml b/.github/workflows/trickops.yml index d22f053b..241f2705 100644 --- a/.github/workflows/trickops.yml +++ b/.github/workflows/trickops.yml @@ -1,12 +1,9 @@ name: TrickOps # This workflow is triggered on pushes to the repository. on: - push: - paths-ignore: - - 'docs/**' - - '.github/workflows/**' - - '!.github/workflows/trickops.yml' - pull_request: + schedule: + - cron: '0 0 * * 0' + workflow_dispatch: defaults: run: diff --git a/.gitignore b/.gitignore index b7d0bea1..2d3bd41f 100644 --- a/.gitignore +++ b/.gitignore @@ -34,4 +34,10 @@ civetweb_clone/ include/civet/ .vscode/ civet_server_error.log -server.pem \ No newline at end of file +server.pem +archive/ +.venv +trickops_logs/ +*.gcda +*.gcno +coverage.info \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 83112df3..2110be92 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,8 +3,8 @@ cmake_minimum_required(VERSION 3.1) # trick is a C/C++ project, but we have some macOS # configuration to do before CMake searches for compilers project(trick NONE) -set(TRICK_MAJOR 23) -set(TRICK_MINOR 0) +set(TRICK_MAJOR 19) +set(TRICK_MINOR 6) set(TRICK_TINY 0) # set TRICK_PRERELEASE TO EMPTY STRING "" ON RELEASE set(TRICK_PRERELEASE "-beta") diff --git a/Makefile b/Makefile index 4efba252..a8df1846 100644 --- a/Makefile +++ b/Makefile @@ -42,6 +42,7 @@ SIM_SERV_DIRS = \ ${TRICK_HOME}/trick_source/sim_services/MemoryManager \ ${TRICK_HOME}/trick_source/sim_services/Message \ ${TRICK_HOME}/trick_source/sim_services/MonteCarlo \ + ${TRICK_HOME}/trick_source/sim_services/MonteCarloGeneration \ ${TRICK_HOME}/trick_source/sim_services/RealtimeInjector \ ${TRICK_HOME}/trick_source/sim_services/RealtimeSync \ ${TRICK_HOME}/trick_source/sim_services/ScheduledJobQueue \ @@ -90,19 +91,23 @@ endif ER7_UTILS_OBJS = $(addsuffix /object_$(TRICK_HOST_CPU)/*.o ,$(ER7_UTILS_DIRS)) UTILS_DIRS := \ + ${TRICK_HOME}/trick_source/trick_utils/compareFloatingPoint \ ${TRICK_HOME}/trick_source/trick_utils/interpolator \ ${TRICK_HOME}/trick_source/trick_utils/trick_adt \ ${TRICK_HOME}/trick_source/trick_utils/comm \ ${TRICK_HOME}/trick_source/trick_utils/shm \ ${TRICK_HOME}/trick_source/trick_utils/math \ ${TRICK_HOME}/trick_source/trick_utils/units \ - ${TRICK_HOME}/trick_source/trick_utils/unicode + ${TRICK_HOME}/trick_source/trick_utils/unicode \ + ${TRICK_HOME}/trick_source/trick_utils/var_binary_parser + UTILS_OBJS := $(addsuffix /object_$(TRICK_HOST_CPU)/*.o ,$(UTILS_DIRS)) # filter out the directories that make their own libraries UTILS_OBJS := $(filter-out ${TRICK_HOME}/trick_source/trick_utils/comm/%, $(UTILS_OBJS)) UTILS_OBJS := $(filter-out ${TRICK_HOME}/trick_source/trick_utils/math/%, $(UTILS_OBJS)) UTILS_OBJS := $(filter-out ${TRICK_HOME}/trick_source/trick_utils/units/%, $(UTILS_OBJS)) +UTILS_OBJS := $(filter-out ${TRICK_HOME}/trick_source/trick_utils/var_binary_parser/%, $(UTILS_OBJS)) #------------------------------------------------------------------------------- # Specify the contents of: libtrick_pyip.a @@ -284,6 +289,7 @@ premade: ################################################################################ # TESTING ################################################################################ + # This target runs Trick's Unit-tests and simulation-tests. test: unit_test sim_test @ echo "All tests completed sucessfully" @@ -301,12 +307,27 @@ $(DPX_UNIT_TEST_DIR): sim_test: - @ $(MAKE) -C test - @ $(MAKE) -C trick_sims test + @ $(MAKE) -f test_overrides.mk sim_test pytest: make -C share/trick/pymods/trick +COVERAGE_DIRS = trick_source/sim_services \ + trick_source/trick_utils/var_binary_parser \ + trick_source/trick_utils/unicode \ + trick_source/trick_utils/units \ + trick_source/trick_utils/interpolator \ + trick_source/trick_utils/comm \ + trick_source/trick_utils/SAIntegrator + +extra-coverage-builds: + @ $(MAKE) test -C trick_source/trick_utils/SAIntegrator + +code-coverage: test extra-coverage-builds + lcov --capture $(addprefix --directory , $(COVERAGE_DIRS)) --output-file coverage_large.info + lcov --remove coverage_large.info '/Library/*' '/usr/*' '*/io_src/*' '*/test/*' '*/unittest/*' -o coverage.info + rm coverage_large.info + lcov --list coverage.info #requirements: # @ $(MAKE) -C trick_test/requirements_docs install diff --git a/README.md b/README.md index dcce16a9..2a7abfe4 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,27 @@

- -Trick Logo - + + + + Trick logo +

Linux -

- -

macOS -

- -

macOS + +Coverage Status +

+

The Trick Simulation Environment, developed at the NASA Johnson Space Center, is a powerful simulation development framework that enables users to build applications for all phases of space vehicle development. Trick expedites the creation of simulations for early vehicle design, performance evaluation, flight software development, flight vehicle dynamic load analysis, and virtual/hardware in the loop training. Trick's purpose is to provide a common set of simulation capabilities that allow users to concentrate on their domain specific models, rather than simulation-specific functions like job ordering, input file processing, or data recording.

@@ -66,6 +66,20 @@ The Trick Simulation Environment, developed at the NASA Johnson Space Center, is + + + + + + + + + + + + +
Developer Docs
Read detailed documentation for various Trick internals and processes.
+ --- Trick is released under the NASA Open Source Agreement Version 1.3 [license](https://github.com/nasa/trick/blob/master/LICENSE). diff --git a/TrickLogo_darkmode.png b/TrickLogo_darkmode.png new file mode 100644 index 00000000..b9436fd0 Binary files /dev/null and b/TrickLogo_darkmode.png differ diff --git a/autoconf/config.guess b/autoconf/config.guess old mode 100755 new mode 100644 index b79252d6..a419d864 --- a/autoconf/config.guess +++ b/autoconf/config.guess @@ -1,12 +1,14 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright 1992-2013 Free Software Foundation, Inc. +# Copyright 1992-2022 Free Software Foundation, Inc. -timestamp='2013-06-10' +# shellcheck disable=SC2006,SC2268 # see below for rationale + +timestamp='2022-08-01' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or +# the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but @@ -15,7 +17,7 @@ timestamp='2013-06-10' # General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, see . +# along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a @@ -24,12 +26,20 @@ timestamp='2013-06-10' # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # -# Originally written by Per Bothner. +# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: -# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD +# https://git.savannah.gnu.org/cgit/config.git/plain/config.guess # -# Please send patches with a ChangeLog entry to config-patches@gnu.org. +# Please send patches to . + + +# The "shellcheck disable" line above the timestamp inhibits complaints +# about features and limitations of the classic Bourne shell that were +# superseded or lifted in POSIX. However, this script identifies a wide +# variety of pre-POSIX systems that do not have POSIX shells at all, and +# even some reasonably current systems (Solaris 10 as case-in-point) still +# have a pre-POSIX /bin/sh. me=`echo "$0" | sed -e 's,.*/,,'` @@ -39,7 +49,7 @@ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. -Operation modes: +Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit @@ -50,7 +60,7 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright 1992-2013 Free Software Foundation, Inc. +Copyright 1992-2022 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -84,7 +94,8 @@ if test $# != 0; then exit 1 fi -trap 'exit 1' 1 2 15 +# Just in case it came from the environment. +GUESS= # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires @@ -96,66 +107,90 @@ trap 'exit 1' 1 2 15 # Portable tmp directory creation inspired by the Autoconf team. -set_cc_for_build=' -trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; -trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; -: ${TMPDIR=/tmp} ; - { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || - { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || - { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || - { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; -dummy=$tmp/dummy ; -tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; -case $CC_FOR_BUILD,$HOST_CC,$CC in - ,,) echo "int x;" > $dummy.c ; - for c in cc gcc c89 c99 ; do - if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then - CC_FOR_BUILD="$c"; break ; - fi ; - done ; - if test x"$CC_FOR_BUILD" = x ; then - CC_FOR_BUILD=no_compiler_found ; - fi - ;; - ,,*) CC_FOR_BUILD=$CC ;; - ,*,*) CC_FOR_BUILD=$HOST_CC ;; -esac ; set_cc_for_build= ;' +tmp= +# shellcheck disable=SC2172 +trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15 + +set_cc_for_build() { + # prevent multiple calls if $tmp is already set + test "$tmp" && return 0 + : "${TMPDIR=/tmp}" + # shellcheck disable=SC2039,SC3028 + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } + dummy=$tmp/dummy + case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in + ,,) echo "int x;" > "$dummy.c" + for driver in cc gcc c89 c99 ; do + if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then + CC_FOR_BUILD=$driver + break + fi + done + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; + esac +} # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) -if (test -f /.attbin/uname) >/dev/null 2>&1 ; then +if test -f /.attbin/uname ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown -UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown -case "${UNAME_SYSTEM}" in +case $UNAME_SYSTEM in Linux|GNU|GNU/*) - # If the system lacks a compiler, then just pick glibc. - # We could probably try harder. - LIBC=gnu + LIBC=unknown - eval $set_cc_for_build - cat <<-EOF > $dummy.c + set_cc_for_build + cat <<-EOF > "$dummy.c" #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc - #else + #elif defined(__GLIBC__) LIBC=gnu + #else + #include + /* First heuristic to detect musl libc. */ + #ifdef __DEFINED_va_list + LIBC=musl + #endif #endif EOF - eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` + cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` + eval "$cc_set_libc" + + # Second heuristic to detect musl libc. + if [ "$LIBC" = unknown ] && + command -v ldd >/dev/null && + ldd --version 2>&1 | grep -q ^musl; then + LIBC=musl + fi + + # If the system lacks a compiler, then just pick glibc. + # We could probably try harder. + if [ "$LIBC" = unknown ]; then + LIBC=gnu + fi ;; esac # Note: order is significant - the case branches are not exclusive. -case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in +case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, @@ -167,22 +202,32 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". - sysctl="sysctl -n hw.machine_arch" - UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ - /usr/sbin/$sysctl 2>/dev/null || echo unknown)` - case "${UNAME_MACHINE_ARCH}" in + UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ + /sbin/sysctl -n hw.machine_arch 2>/dev/null || \ + /usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \ + echo unknown)` + case $UNAME_MACHINE_ARCH in + aarch64eb) machine=aarch64_be-unknown ;; armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; - *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + earmv*) + arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` + endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` + machine=${arch}${endian}-unknown + ;; + *) machine=$UNAME_MACHINE_ARCH-unknown ;; esac # The Operating System including object format, if it has switched - # to ELF recently, or will in the future. - case "${UNAME_MACHINE_ARCH}" in + # to ELF recently (or will in the future) and ABI. + case $UNAME_MACHINE_ARCH in + earm*) + os=netbsdelf + ;; arm*|i386|m68k|ns32k|sh3*|sparc|vax) - eval $set_cc_for_build + set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then @@ -197,45 +242,80 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in os=netbsd ;; esac + # Determine ABI tags. + case $UNAME_MACHINE_ARCH in + earm*) + expr='s/^earmv[0-9]/-eabi/;s/eb$//' + abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` + ;; + esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. - case "${UNAME_VERSION}" in + case $UNAME_VERSION in Debian*) release='-gnu' ;; *) - release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. - echo "${machine}-${os}${release}" - exit ;; + GUESS=$machine-${os}${release}${abi-} + ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` - echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} - exit ;; + GUESS=$UNAME_MACHINE_ARCH-unknown-bitrig$UNAME_RELEASE + ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` - echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} - exit ;; + GUESS=$UNAME_MACHINE_ARCH-unknown-openbsd$UNAME_RELEASE + ;; + *:SecBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/SecBSD.//'` + GUESS=$UNAME_MACHINE_ARCH-unknown-secbsd$UNAME_RELEASE + ;; + *:LibertyBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` + GUESS=$UNAME_MACHINE_ARCH-unknown-libertybsd$UNAME_RELEASE + ;; + *:MidnightBSD:*:*) + GUESS=$UNAME_MACHINE-unknown-midnightbsd$UNAME_RELEASE + ;; *:ekkoBSD:*:*) - echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} - exit ;; + GUESS=$UNAME_MACHINE-unknown-ekkobsd$UNAME_RELEASE + ;; *:SolidBSD:*:*) - echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} - exit ;; + GUESS=$UNAME_MACHINE-unknown-solidbsd$UNAME_RELEASE + ;; + *:OS108:*:*) + GUESS=$UNAME_MACHINE-unknown-os108_$UNAME_RELEASE + ;; macppc:MirBSD:*:*) - echo powerpc-unknown-mirbsd${UNAME_RELEASE} - exit ;; + GUESS=powerpc-unknown-mirbsd$UNAME_RELEASE + ;; *:MirBSD:*:*) - echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} - exit ;; + GUESS=$UNAME_MACHINE-unknown-mirbsd$UNAME_RELEASE + ;; + *:Sortix:*:*) + GUESS=$UNAME_MACHINE-unknown-sortix + ;; + *:Twizzler:*:*) + GUESS=$UNAME_MACHINE-unknown-twizzler + ;; + *:Redox:*:*) + GUESS=$UNAME_MACHINE-unknown-redox + ;; + mips:OSF1:*.*) + GUESS=mips-dec-osf1 + ;; alpha:OSF1:*:*) + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + trap '' 0 case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` @@ -249,163 +329,158 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` - case "$ALPHA_CPU_TYPE" in + case $ALPHA_CPU_TYPE in "EV4 (21064)") - UNAME_MACHINE="alpha" ;; + UNAME_MACHINE=alpha ;; "EV4.5 (21064)") - UNAME_MACHINE="alpha" ;; + UNAME_MACHINE=alpha ;; "LCA4 (21066/21068)") - UNAME_MACHINE="alpha" ;; + UNAME_MACHINE=alpha ;; "EV5 (21164)") - UNAME_MACHINE="alphaev5" ;; + UNAME_MACHINE=alphaev5 ;; "EV5.6 (21164A)") - UNAME_MACHINE="alphaev56" ;; + UNAME_MACHINE=alphaev56 ;; "EV5.6 (21164PC)") - UNAME_MACHINE="alphapca56" ;; + UNAME_MACHINE=alphapca56 ;; "EV5.7 (21164PC)") - UNAME_MACHINE="alphapca57" ;; + UNAME_MACHINE=alphapca57 ;; "EV6 (21264)") - UNAME_MACHINE="alphaev6" ;; + UNAME_MACHINE=alphaev6 ;; "EV6.7 (21264A)") - UNAME_MACHINE="alphaev67" ;; + UNAME_MACHINE=alphaev67 ;; "EV6.8CB (21264C)") - UNAME_MACHINE="alphaev68" ;; + UNAME_MACHINE=alphaev68 ;; "EV6.8AL (21264B)") - UNAME_MACHINE="alphaev68" ;; + UNAME_MACHINE=alphaev68 ;; "EV6.8CX (21264D)") - UNAME_MACHINE="alphaev68" ;; + UNAME_MACHINE=alphaev68 ;; "EV6.9A (21264/EV69A)") - UNAME_MACHINE="alphaev69" ;; + UNAME_MACHINE=alphaev69 ;; "EV7 (21364)") - UNAME_MACHINE="alphaev7" ;; + UNAME_MACHINE=alphaev7 ;; "EV7.9 (21364A)") - UNAME_MACHINE="alphaev79" ;; + UNAME_MACHINE=alphaev79 ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. - echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - # Reset EXIT trap before exiting to avoid spurious non-zero exit code. - exitcode=$? - trap '' 0 - exit $exitcode ;; - Alpha\ *:Windows_NT*:*) - # How do we know it's Interix rather than the generic POSIX subsystem? - # Should we change UNAME_MACHINE based on the output of uname instead - # of the specific Alpha model? - echo alpha-pc-interix - exit ;; - 21064:Windows_NT:50:3) - echo alpha-dec-winnt3.5 - exit ;; + OSF_REL=`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + GUESS=$UNAME_MACHINE-dec-osf$OSF_REL + ;; Amiga*:UNIX_System_V:4.0:*) - echo m68k-unknown-sysv4 - exit ;; + GUESS=m68k-unknown-sysv4 + ;; *:[Aa]miga[Oo][Ss]:*:*) - echo ${UNAME_MACHINE}-unknown-amigaos - exit ;; + GUESS=$UNAME_MACHINE-unknown-amigaos + ;; *:[Mm]orph[Oo][Ss]:*:*) - echo ${UNAME_MACHINE}-unknown-morphos - exit ;; + GUESS=$UNAME_MACHINE-unknown-morphos + ;; *:OS/390:*:*) - echo i370-ibm-openedition - exit ;; + GUESS=i370-ibm-openedition + ;; *:z/VM:*:*) - echo s390-ibm-zvmoe - exit ;; + GUESS=s390-ibm-zvmoe + ;; *:OS400:*:*) - echo powerpc-ibm-os400 - exit ;; + GUESS=powerpc-ibm-os400 + ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) - echo arm-acorn-riscix${UNAME_RELEASE} - exit ;; + GUESS=arm-acorn-riscix$UNAME_RELEASE + ;; arm*:riscos:*:*|arm*:RISCOS:*:*) - echo arm-unknown-riscos - exit ;; + GUESS=arm-unknown-riscos + ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) - echo hppa1.1-hitachi-hiuxmpp - exit ;; + GUESS=hppa1.1-hitachi-hiuxmpp + ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. - if test "`(/bin/universe) 2>/dev/null`" = att ; then - echo pyramid-pyramid-sysv3 - else - echo pyramid-pyramid-bsd - fi - exit ;; + case `(/bin/universe) 2>/dev/null` in + att) GUESS=pyramid-pyramid-sysv3 ;; + *) GUESS=pyramid-pyramid-bsd ;; + esac + ;; NILE*:*:*:dcosx) - echo pyramid-pyramid-svr4 - exit ;; + GUESS=pyramid-pyramid-svr4 + ;; DRS?6000:unix:4.0:6*) - echo sparc-icl-nx6 - exit ;; + GUESS=sparc-icl-nx6 + ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in - sparc) echo sparc-icl-nx7; exit ;; - esac ;; + sparc) GUESS=sparc-icl-nx7 ;; + esac + ;; s390x:SunOS:*:*) - echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=$UNAME_MACHINE-ibm-solaris2$SUN_REL + ;; sun4H:SunOS:5.*:*) - echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=sparc-hal-solaris2$SUN_REL + ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) - echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=sparc-sun-solaris2$SUN_REL + ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) - echo i386-pc-auroraux${UNAME_RELEASE} - exit ;; + GUESS=i386-pc-auroraux$UNAME_RELEASE + ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) - eval $set_cc_for_build - SUN_ARCH="i386" + set_cc_for_build + SUN_ARCH=i386 # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. - if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + (CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then - SUN_ARCH="x86_64" + SUN_ARCH=x86_64 fi fi - echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=$SUN_ARCH-pc-solaris2$SUN_REL + ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. - echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=sparc-sun-solaris3$SUN_REL + ;; sun4*:SunOS:*:*) - case "`/usr/bin/arch -k`" in + case `/usr/bin/arch -k` in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. - echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` - exit ;; + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'` + GUESS=sparc-sun-sunos$SUN_REL + ;; sun3*:SunOS:*:*) - echo m68k-sun-sunos${UNAME_RELEASE} - exit ;; + GUESS=m68k-sun-sunos$UNAME_RELEASE + ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` - test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 - case "`/bin/arch`" in + test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 + case `/bin/arch` in sun3) - echo m68k-sun-sunos${UNAME_RELEASE} + GUESS=m68k-sun-sunos$UNAME_RELEASE ;; sun4) - echo sparc-sun-sunos${UNAME_RELEASE} + GUESS=sparc-sun-sunos$UNAME_RELEASE ;; esac - exit ;; + ;; aushp:SunOS:*:*) - echo sparc-auspex-sunos${UNAME_RELEASE} - exit ;; + GUESS=sparc-auspex-sunos$UNAME_RELEASE + ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor @@ -415,44 +490,44 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} - exit ;; + GUESS=m68k-atari-mint$UNAME_RELEASE + ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} - exit ;; + GUESS=m68k-atari-mint$UNAME_RELEASE + ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} - exit ;; + GUESS=m68k-atari-mint$UNAME_RELEASE + ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) - echo m68k-milan-mint${UNAME_RELEASE} - exit ;; + GUESS=m68k-milan-mint$UNAME_RELEASE + ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) - echo m68k-hades-mint${UNAME_RELEASE} - exit ;; + GUESS=m68k-hades-mint$UNAME_RELEASE + ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) - echo m68k-unknown-mint${UNAME_RELEASE} - exit ;; + GUESS=m68k-unknown-mint$UNAME_RELEASE + ;; m68k:machten:*:*) - echo m68k-apple-machten${UNAME_RELEASE} - exit ;; + GUESS=m68k-apple-machten$UNAME_RELEASE + ;; powerpc:machten:*:*) - echo powerpc-apple-machten${UNAME_RELEASE} - exit ;; + GUESS=powerpc-apple-machten$UNAME_RELEASE + ;; RISC*:Mach:*:*) - echo mips-dec-mach_bsd4.3 - exit ;; + GUESS=mips-dec-mach_bsd4.3 + ;; RISC*:ULTRIX:*:*) - echo mips-dec-ultrix${UNAME_RELEASE} - exit ;; + GUESS=mips-dec-ultrix$UNAME_RELEASE + ;; VAX*:ULTRIX*:*:*) - echo vax-dec-ultrix${UNAME_RELEASE} - exit ;; + GUESS=vax-dec-ultrix$UNAME_RELEASE + ;; 2020:CLIX:*:* | 2430:CLIX:*:*) - echo clipper-intergraph-clix${UNAME_RELEASE} - exit ;; + GUESS=clipper-intergraph-clix$UNAME_RELEASE + ;; mips:*:*:UMIPS | mips:*:*:RISCos) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c + set_cc_for_build + sed 's/^ //' << EOF > "$dummy.c" #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { @@ -461,95 +536,96 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) - printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) - printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) - printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF - $CC_FOR_BUILD -o $dummy $dummy.c && - dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && - SYSTEM_NAME=`$dummy $dummyarg` && + $CC_FOR_BUILD -o "$dummy" "$dummy.c" && + dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`"$dummy" "$dummyarg"` && { echo "$SYSTEM_NAME"; exit; } - echo mips-mips-riscos${UNAME_RELEASE} - exit ;; + GUESS=mips-mips-riscos$UNAME_RELEASE + ;; Motorola:PowerMAX_OS:*:*) - echo powerpc-motorola-powermax - exit ;; + GUESS=powerpc-motorola-powermax + ;; Motorola:*:4.3:PL8-*) - echo powerpc-harris-powermax - exit ;; + GUESS=powerpc-harris-powermax + ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) - echo powerpc-harris-powermax - exit ;; + GUESS=powerpc-harris-powermax + ;; Night_Hawk:Power_UNIX:*:*) - echo powerpc-harris-powerunix - exit ;; + GUESS=powerpc-harris-powerunix + ;; m88k:CX/UX:7*:*) - echo m88k-harris-cxux7 - exit ;; + GUESS=m88k-harris-cxux7 + ;; m88k:*:4*:R4*) - echo m88k-motorola-sysv4 - exit ;; + GUESS=m88k-motorola-sysv4 + ;; m88k:*:3*:R3*) - echo m88k-motorola-sysv3 - exit ;; + GUESS=m88k-motorola-sysv3 + ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` - if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110 then - if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ - [ ${TARGET_BINARY_INTERFACE}x = x ] + if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \ + test "$TARGET_BINARY_INTERFACE"x = x then - echo m88k-dg-dgux${UNAME_RELEASE} + GUESS=m88k-dg-dgux$UNAME_RELEASE else - echo m88k-dg-dguxbcs${UNAME_RELEASE} + GUESS=m88k-dg-dguxbcs$UNAME_RELEASE fi else - echo i586-dg-dgux${UNAME_RELEASE} + GUESS=i586-dg-dgux$UNAME_RELEASE fi - exit ;; + ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) - echo m88k-dolphin-sysv3 - exit ;; + GUESS=m88k-dolphin-sysv3 + ;; M88*:*:R3*:*) # Delta 88k system running SVR3 - echo m88k-motorola-sysv3 - exit ;; + GUESS=m88k-motorola-sysv3 + ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) - echo m88k-tektronix-sysv3 - exit ;; + GUESS=m88k-tektronix-sysv3 + ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) - echo m68k-tektronix-bsd - exit ;; + GUESS=m68k-tektronix-bsd + ;; *:IRIX*:*:*) - echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` - exit ;; + IRIX_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/g'` + GUESS=mips-sgi-irix$IRIX_REL + ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. - echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id - exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + GUESS=romp-ibm-aix # uname -m gives an 8 hex-code CPU id + ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) - echo i386-ibm-aix - exit ;; + GUESS=i386-ibm-aix + ;; ia64:AIX:*:*) - if [ -x /usr/bin/oslevel ] ; then + if test -x /usr/bin/oslevel ; then IBM_REV=`/usr/bin/oslevel` else - IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + IBM_REV=$UNAME_VERSION.$UNAME_RELEASE fi - echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} - exit ;; + GUESS=$UNAME_MACHINE-ibm-aix$IBM_REV + ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c + set_cc_for_build + sed 's/^ //' << EOF > "$dummy.c" #include main() @@ -560,76 +636,77 @@ EOF exit(0); } EOF - if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` then - echo "$SYSTEM_NAME" + GUESS=$SYSTEM_NAME else - echo rs6000-ibm-aix3.2.5 + GUESS=rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then - echo rs6000-ibm-aix3.2.4 + GUESS=rs6000-ibm-aix3.2.4 else - echo rs6000-ibm-aix3.2 + GUESS=rs6000-ibm-aix3.2 fi - exit ;; + ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` - if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi - if [ -x /usr/bin/oslevel ] ; then - IBM_REV=`/usr/bin/oslevel` + if test -x /usr/bin/lslpp ; then + IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | \ + awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else - IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + IBM_REV=$UNAME_VERSION.$UNAME_RELEASE fi - echo ${IBM_ARCH}-ibm-aix${IBM_REV} - exit ;; + GUESS=$IBM_ARCH-ibm-aix$IBM_REV + ;; *:AIX:*:*) - echo rs6000-ibm-aix - exit ;; - ibmrt:4.4BSD:*|romp-ibm:BSD:*) - echo romp-ibm-bsd4.4 - exit ;; + GUESS=rs6000-ibm-aix + ;; + ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) + GUESS=romp-ibm-bsd4.4 + ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and - echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to - exit ;; # report: romp-ibm BSD 4.3 + GUESS=romp-ibm-bsd$UNAME_RELEASE # 4.3 with uname added to + ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) - echo rs6000-bull-bosx - exit ;; + GUESS=rs6000-bull-bosx + ;; DPX/2?00:B.O.S.:*:*) - echo m68k-bull-sysv3 - exit ;; + GUESS=m68k-bull-sysv3 + ;; 9000/[34]??:4.3bsd:1.*:*) - echo m68k-hp-bsd - exit ;; + GUESS=m68k-hp-bsd + ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) - echo m68k-hp-bsd4.4 - exit ;; + GUESS=m68k-hp-bsd4.4 + ;; 9000/[34678]??:HP-UX:*:*) - HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` - case "${UNAME_MACHINE}" in - 9000/31? ) HP_ARCH=m68000 ;; - 9000/[34]?? ) HP_ARCH=m68k ;; + HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` + case $UNAME_MACHINE in + 9000/31?) HP_ARCH=m68000 ;; + 9000/[34]??) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) - if [ -x /usr/bin/getconf ]; then + if test -x /usr/bin/getconf; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` - case "${sc_cpu_version}" in - 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 - 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + case $sc_cpu_version in + 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 + 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 - case "${sc_kernel_bits}" in - 32) HP_ARCH="hppa2.0n" ;; - 64) HP_ARCH="hppa2.0w" ;; - '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + case $sc_kernel_bits in + 32) HP_ARCH=hppa2.0n ;; + 64) HP_ARCH=hppa2.0w ;; + '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 esac ;; esac fi - if [ "${HP_ARCH}" = "" ]; then - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c + if test "$HP_ARCH" = ""; then + set_cc_for_build + sed 's/^ //' << EOF > "$dummy.c" #define _HPUX_SOURCE #include @@ -662,13 +739,13 @@ EOF exit (0); } EOF - (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac - if [ ${HP_ARCH} = "hppa2.0w" ] + if test "$HP_ARCH" = hppa2.0w then - eval $set_cc_for_build + set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler @@ -679,23 +756,23 @@ EOF # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 - if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then - HP_ARCH="hppa2.0w" + HP_ARCH=hppa2.0w else - HP_ARCH="hppa64" + HP_ARCH=hppa64 fi fi - echo ${HP_ARCH}-hp-hpux${HPUX_REV} - exit ;; + GUESS=$HP_ARCH-hp-hpux$HPUX_REV + ;; ia64:HP-UX:*:*) - HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` - echo ia64-hp-hpux${HPUX_REV} - exit ;; + HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` + GUESS=ia64-hp-hpux$HPUX_REV + ;; 3050*:HI-UX:*:*) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c + set_cc_for_build + sed 's/^ //' << EOF > "$dummy.c" #include int main () @@ -720,38 +797,38 @@ EOF exit (0); } EOF - $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } - echo unknown-hitachi-hiuxwe2 - exit ;; - 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) - echo hppa1.1-hp-bsd - exit ;; + GUESS=unknown-hitachi-hiuxwe2 + ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) + GUESS=hppa1.1-hp-bsd + ;; 9000/8??:4.3bsd:*:*) - echo hppa1.0-hp-bsd - exit ;; + GUESS=hppa1.0-hp-bsd + ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) - echo hppa1.0-hp-mpeix - exit ;; - hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) - echo hppa1.1-hp-osf - exit ;; + GUESS=hppa1.0-hp-mpeix + ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) + GUESS=hppa1.1-hp-osf + ;; hp8??:OSF1:*:*) - echo hppa1.0-hp-osf - exit ;; + GUESS=hppa1.0-hp-osf + ;; i*86:OSF1:*:*) - if [ -x /usr/sbin/sysversion ] ; then - echo ${UNAME_MACHINE}-unknown-osf1mk + if test -x /usr/sbin/sysversion ; then + GUESS=$UNAME_MACHINE-unknown-osf1mk else - echo ${UNAME_MACHINE}-unknown-osf1 + GUESS=$UNAME_MACHINE-unknown-osf1 fi - exit ;; + ;; parisc*:Lites*:*:*) - echo hppa1.1-hp-lites - exit ;; + GUESS=hppa1.1-hp-lites + ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) - echo c1-convex-bsd - exit ;; + GUESS=c1-convex-bsd + ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd @@ -759,139 +836,148 @@ EOF fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) - echo c34-convex-bsd - exit ;; + GUESS=c34-convex-bsd + ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) - echo c38-convex-bsd - exit ;; + GUESS=c38-convex-bsd + ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) - echo c4-convex-bsd - exit ;; + GUESS=c4-convex-bsd + ;; CRAY*Y-MP:*:*:*) - echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit ;; + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=ymp-cray-unicos$CRAY_REL + ;; CRAY*[A-Z]90:*:*:*) - echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) - echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit ;; + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=t90-cray-unicos$CRAY_REL + ;; CRAY*T3E:*:*:*) - echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit ;; + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=alphaev5-cray-unicosmk$CRAY_REL + ;; CRAY*SV1:*:*:*) - echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit ;; + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=sv1-cray-unicos$CRAY_REL + ;; *:UNICOS/mp:*:*) - echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit ;; + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=craynv-cray-unicosmp$CRAY_REL + ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) - FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` - echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" - exit ;; + FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` + GUESS=${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} + ;; 5000:UNIX_System_V:4.*:*) - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` - echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" - exit ;; + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` + GUESS=sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} + ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) - echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} - exit ;; + GUESS=$UNAME_MACHINE-pc-bsdi$UNAME_RELEASE + ;; sparc*:BSD/OS:*:*) - echo sparc-unknown-bsdi${UNAME_RELEASE} - exit ;; + GUESS=sparc-unknown-bsdi$UNAME_RELEASE + ;; *:BSD/OS:*:*) - echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} - exit ;; + GUESS=$UNAME_MACHINE-unknown-bsdi$UNAME_RELEASE + ;; + arm:FreeBSD:*:*) + UNAME_PROCESSOR=`uname -p` + set_cc_for_build + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabi + else + FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabihf + fi + ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` - case ${UNAME_PROCESSOR} in + case $UNAME_PROCESSOR in amd64) - echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; - *) - echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + UNAME_PROCESSOR=x86_64 ;; + i386) + UNAME_PROCESSOR=i586 ;; esac - exit ;; + FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL + ;; i*:CYGWIN*:*) - echo ${UNAME_MACHINE}-pc-cygwin - exit ;; + GUESS=$UNAME_MACHINE-pc-cygwin + ;; *:MINGW64*:*) - echo ${UNAME_MACHINE}-pc-mingw64 - exit ;; + GUESS=$UNAME_MACHINE-pc-mingw64 + ;; *:MINGW*:*) - echo ${UNAME_MACHINE}-pc-mingw32 - exit ;; - i*:MSYS*:*) - echo ${UNAME_MACHINE}-pc-msys - exit ;; - i*:windows32*:*) - # uname -m includes "-pc" on this system. - echo ${UNAME_MACHINE}-mingw32 - exit ;; + GUESS=$UNAME_MACHINE-pc-mingw32 + ;; + *:MSYS*:*) + GUESS=$UNAME_MACHINE-pc-msys + ;; i*:PW*:*) - echo ${UNAME_MACHINE}-pc-pw32 - exit ;; + GUESS=$UNAME_MACHINE-pc-pw32 + ;; + *:SerenityOS:*:*) + GUESS=$UNAME_MACHINE-pc-serenity + ;; *:Interix*:*) - case ${UNAME_MACHINE} in + case $UNAME_MACHINE in x86) - echo i586-pc-interix${UNAME_RELEASE} - exit ;; + GUESS=i586-pc-interix$UNAME_RELEASE + ;; authenticamd | genuineintel | EM64T) - echo x86_64-unknown-interix${UNAME_RELEASE} - exit ;; + GUESS=x86_64-unknown-interix$UNAME_RELEASE + ;; IA64) - echo ia64-unknown-interix${UNAME_RELEASE} - exit ;; + GUESS=ia64-unknown-interix$UNAME_RELEASE + ;; esac ;; - [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) - echo i${UNAME_MACHINE}-pc-mks - exit ;; - 8664:Windows_NT:*) - echo x86_64-pc-mks - exit ;; - i*:Windows_NT*:* | Pentium*:Windows_NT*:*) - # How do we know it's Interix rather than the generic POSIX subsystem? - # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we - # UNAME_MACHINE based on the output of uname instead of i386? - echo i586-pc-interix - exit ;; i*:UWIN*:*) - echo ${UNAME_MACHINE}-pc-uwin - exit ;; + GUESS=$UNAME_MACHINE-pc-uwin + ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) - echo x86_64-unknown-cygwin - exit ;; - p*:CYGWIN*:*) - echo powerpcle-unknown-cygwin - exit ;; + GUESS=x86_64-pc-cygwin + ;; prep*:SunOS:5.*:*) - echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=powerpcle-unknown-solaris2$SUN_REL + ;; *:GNU:*:*) # the GNU system - echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` - exit ;; + GNU_ARCH=`echo "$UNAME_MACHINE" | sed -e 's,[-/].*$,,'` + GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's,/.*$,,'` + GUESS=$GNU_ARCH-unknown-$LIBC$GNU_REL + ;; *:GNU/*:*:*) # other systems with GNU libc and userland - echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} - exit ;; - i*86:Minix:*:*) - echo ${UNAME_MACHINE}-pc-minix - exit ;; + GNU_SYS=`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"` + GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC + ;; + *:Minix:*:*) + GUESS=$UNAME_MACHINE-unknown-minix + ;; aarch64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; alpha:Linux:*:*) - case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; @@ -901,172 +987,237 @@ EOF EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 - if test "$?" = 0 ; then LIBC="gnulibc1" ; fi - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - arc:Linux:*:* | arceb:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; + if test "$?" = 0 ; then LIBC=gnulibc1 ; fi + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + arc:Linux:*:* | arceb:Linux:*:* | arc32:Linux:*:* | arc64:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; arm*:Linux:*:*) - eval $set_cc_for_build + set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then - echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi + GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabi else - echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf + GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabihf fi fi - exit ;; + ;; avr32*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; cris:Linux:*:*) - echo ${UNAME_MACHINE}-axis-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-axis-linux-$LIBC + ;; crisv32:Linux:*:*) - echo ${UNAME_MACHINE}-axis-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-axis-linux-$LIBC + ;; + e2k:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; frv:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; hexagon:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; i*86:Linux:*:*) - echo ${UNAME_MACHINE}-pc-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-pc-linux-$LIBC + ;; ia64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + k1om:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + loongarch32:Linux:*:* | loongarch64:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; m32r*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; m68*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; mips:Linux:*:* | mips64:Linux:*:*) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c + set_cc_for_build + IS_GLIBC=0 + test x"${LIBC}" = xgnu && IS_GLIBC=1 + sed 's/^ //' << EOF > "$dummy.c" #undef CPU - #undef ${UNAME_MACHINE} - #undef ${UNAME_MACHINE}el + #undef mips + #undef mipsel + #undef mips64 + #undef mips64el + #if ${IS_GLIBC} && defined(_ABI64) + LIBCABI=gnuabi64 + #else + #if ${IS_GLIBC} && defined(_ABIN32) + LIBCABI=gnuabin32 + #else + LIBCABI=${LIBC} + #endif + #endif + + #if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 + CPU=mipsisa64r6 + #else + #if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 + CPU=mipsisa32r6 + #else + #if defined(__mips64) + CPU=mips64 + #else + CPU=mips + #endif + #endif + #endif + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) - CPU=${UNAME_MACHINE}el + MIPS_ENDIAN=el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) - CPU=${UNAME_MACHINE} + MIPS_ENDIAN= #else - CPU= + MIPS_ENDIAN= #endif #endif EOF - eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` - test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } + cc_set_vars=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'` + eval "$cc_set_vars" + test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; } + ;; + mips64el:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + openrisc*:Linux:*:*) + GUESS=or1k-unknown-linux-$LIBC + ;; + or32:Linux:*:* | or1k*:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; - or1k:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - or32:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; padre:Linux:*:*) - echo sparc-unknown-linux-${LIBC} - exit ;; + GUESS=sparc-unknown-linux-$LIBC + ;; parisc64:Linux:*:* | hppa64:Linux:*:*) - echo hppa64-unknown-linux-${LIBC} - exit ;; + GUESS=hppa64-unknown-linux-$LIBC + ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in - PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; - PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; - *) echo hppa-unknown-linux-${LIBC} ;; + PA7*) GUESS=hppa1.1-unknown-linux-$LIBC ;; + PA8*) GUESS=hppa2.0-unknown-linux-$LIBC ;; + *) GUESS=hppa-unknown-linux-$LIBC ;; esac - exit ;; + ;; ppc64:Linux:*:*) - echo powerpc64-unknown-linux-${LIBC} - exit ;; + GUESS=powerpc64-unknown-linux-$LIBC + ;; ppc:Linux:*:*) - echo powerpc-unknown-linux-${LIBC} - exit ;; + GUESS=powerpc-unknown-linux-$LIBC + ;; ppc64le:Linux:*:*) - echo powerpc64le-unknown-linux-${LIBC} - exit ;; + GUESS=powerpc64le-unknown-linux-$LIBC + ;; ppcle:Linux:*:*) - echo powerpcle-unknown-linux-${LIBC} - exit ;; + GUESS=powerpcle-unknown-linux-$LIBC + ;; + riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; s390:Linux:*:* | s390x:Linux:*:*) - echo ${UNAME_MACHINE}-ibm-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-ibm-linux-$LIBC + ;; sh64*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; sh*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; sparc:Linux:*:* | sparc64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; tile*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; vax:Linux:*:*) - echo ${UNAME_MACHINE}-dec-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-dec-linux-$LIBC + ;; x86_64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; + set_cc_for_build + CPU=$UNAME_MACHINE + LIBCABI=$LIBC + if test "$CC_FOR_BUILD" != no_compiler_found; then + ABI=64 + sed 's/^ //' << EOF > "$dummy.c" + #ifdef __i386__ + ABI=x86 + #else + #ifdef __ILP32__ + ABI=x32 + #endif + #endif +EOF + cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'` + eval "$cc_set_abi" + case $ABI in + x86) CPU=i686 ;; + x32) LIBCABI=${LIBC}x32 ;; + esac + fi + GUESS=$CPU-pc-linux-$LIBCABI + ;; xtensa*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. - echo i386-sequent-sysv4 - exit ;; + GUESS=i386-sequent-sysv4 + ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. - echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} - exit ;; + GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION + ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. - echo ${UNAME_MACHINE}-pc-os2-emx - exit ;; + GUESS=$UNAME_MACHINE-pc-os2-emx + ;; i*86:XTS-300:*:STOP) - echo ${UNAME_MACHINE}-unknown-stop - exit ;; + GUESS=$UNAME_MACHINE-unknown-stop + ;; i*86:atheos:*:*) - echo ${UNAME_MACHINE}-unknown-atheos - exit ;; + GUESS=$UNAME_MACHINE-unknown-atheos + ;; i*86:syllable:*:*) - echo ${UNAME_MACHINE}-pc-syllable - exit ;; + GUESS=$UNAME_MACHINE-pc-syllable + ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) - echo i386-unknown-lynxos${UNAME_RELEASE} - exit ;; + GUESS=i386-unknown-lynxos$UNAME_RELEASE + ;; i*86:*DOS:*:*) - echo ${UNAME_MACHINE}-pc-msdosdjgpp - exit ;; - i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) - UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + GUESS=$UNAME_MACHINE-pc-msdosdjgpp + ;; + i*86:*:4.*:*) + UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then - echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + GUESS=$UNAME_MACHINE-univel-sysv$UNAME_REL else - echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + GUESS=$UNAME_MACHINE-pc-sysv$UNAME_REL fi - exit ;; + ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in @@ -1074,12 +1225,12 @@ EOF *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac - echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} - exit ;; + GUESS=$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 @@ -1089,43 +1240,43 @@ EOF && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 - echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + GUESS=$UNAME_MACHINE-pc-sco$UNAME_REL else - echo ${UNAME_MACHINE}-pc-sysv32 + GUESS=$UNAME_MACHINE-pc-sysv32 fi - exit ;; + ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub - # prints for the "djgpp" host, or else GDB configury will decide that + # prints for the "djgpp" host, or else GDB configure will decide that # this is a cross-build. - echo i586-pc-msdosdjgpp - exit ;; + GUESS=i586-pc-msdosdjgpp + ;; Intel:Mach:3*:*) - echo i386-pc-mach3 - exit ;; + GUESS=i386-pc-mach3 + ;; paragon:*:*:*) - echo i860-intel-osf1 - exit ;; + GUESS=i860-intel-osf1 + ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then - echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + GUESS=i860-stardent-sysv$UNAME_RELEASE # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. - echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + GUESS=i860-unknown-sysv$UNAME_RELEASE # Unknown i860-SVR4 fi - exit ;; + ;; mini*:CTIX:SYS*5:*) # "miniframe" - echo m68010-convergent-sysv - exit ;; + GUESS=m68010-convergent-sysv + ;; mc68k:UNIX:SYSTEM5:3.51m) - echo m68k-convergent-sysv - exit ;; + GUESS=m68k-convergent-sysv + ;; M680?0:D-NIX:5.3:*) - echo m68k-diab-dnix - exit ;; + GUESS=m68k-diab-dnix + ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) @@ -1133,9 +1284,9 @@ EOF test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ - && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; @@ -1144,228 +1295,287 @@ EOF test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ - && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ - && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) - echo m68k-unknown-lynxos${UNAME_RELEASE} - exit ;; + GUESS=m68k-unknown-lynxos$UNAME_RELEASE + ;; mc68030:UNIX_System_V:4.*:*) - echo m68k-atari-sysv4 - exit ;; + GUESS=m68k-atari-sysv4 + ;; TSUNAMI:LynxOS:2.*:*) - echo sparc-unknown-lynxos${UNAME_RELEASE} - exit ;; + GUESS=sparc-unknown-lynxos$UNAME_RELEASE + ;; rs6000:LynxOS:2.*:*) - echo rs6000-unknown-lynxos${UNAME_RELEASE} - exit ;; + GUESS=rs6000-unknown-lynxos$UNAME_RELEASE + ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) - echo powerpc-unknown-lynxos${UNAME_RELEASE} - exit ;; + GUESS=powerpc-unknown-lynxos$UNAME_RELEASE + ;; SM[BE]S:UNIX_SV:*:*) - echo mips-dde-sysv${UNAME_RELEASE} - exit ;; + GUESS=mips-dde-sysv$UNAME_RELEASE + ;; RM*:ReliantUNIX-*:*:*) - echo mips-sni-sysv4 - exit ;; + GUESS=mips-sni-sysv4 + ;; RM*:SINIX-*:*:*) - echo mips-sni-sysv4 - exit ;; + GUESS=mips-sni-sysv4 + ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` - echo ${UNAME_MACHINE}-sni-sysv4 + GUESS=$UNAME_MACHINE-sni-sysv4 else - echo ns32k-sni-sysv + GUESS=ns32k-sni-sysv fi - exit ;; + ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says - echo i586-unisys-sysv4 - exit ;; + GUESS=i586-unisys-sysv4 + ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm - echo hppa1.1-stratus-sysv4 - exit ;; + GUESS=hppa1.1-stratus-sysv4 + ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. - echo i860-stratus-sysv4 - exit ;; + GUESS=i860-stratus-sysv4 + ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. - echo ${UNAME_MACHINE}-stratus-vos - exit ;; + GUESS=$UNAME_MACHINE-stratus-vos + ;; *:VOS:*:*) # From Paul.Green@stratus.com. - echo hppa1.1-stratus-vos - exit ;; + GUESS=hppa1.1-stratus-vos + ;; mc68*:A/UX:*:*) - echo m68k-apple-aux${UNAME_RELEASE} - exit ;; + GUESS=m68k-apple-aux$UNAME_RELEASE + ;; news*:NEWS-OS:6*:*) - echo mips-sony-newsos6 - exit ;; + GUESS=mips-sony-newsos6 + ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) - if [ -d /usr/nec ]; then - echo mips-nec-sysv${UNAME_RELEASE} + if test -d /usr/nec; then + GUESS=mips-nec-sysv$UNAME_RELEASE else - echo mips-unknown-sysv${UNAME_RELEASE} + GUESS=mips-unknown-sysv$UNAME_RELEASE fi - exit ;; + ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. - echo powerpc-be-beos - exit ;; + GUESS=powerpc-be-beos + ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. - echo powerpc-apple-beos - exit ;; + GUESS=powerpc-apple-beos + ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. - echo i586-pc-beos - exit ;; + GUESS=i586-pc-beos + ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. - echo i586-pc-haiku - exit ;; - x86_64:Haiku:*:*) - echo x86_64-unknown-haiku - exit ;; + GUESS=i586-pc-haiku + ;; + ppc:Haiku:*:*) # Haiku running on Apple PowerPC + GUESS=powerpc-apple-haiku + ;; + *:Haiku:*:*) # Haiku modern gcc (not bound by BeOS compat) + GUESS=$UNAME_MACHINE-unknown-haiku + ;; SX-4:SUPER-UX:*:*) - echo sx4-nec-superux${UNAME_RELEASE} - exit ;; + GUESS=sx4-nec-superux$UNAME_RELEASE + ;; SX-5:SUPER-UX:*:*) - echo sx5-nec-superux${UNAME_RELEASE} - exit ;; + GUESS=sx5-nec-superux$UNAME_RELEASE + ;; SX-6:SUPER-UX:*:*) - echo sx6-nec-superux${UNAME_RELEASE} - exit ;; + GUESS=sx6-nec-superux$UNAME_RELEASE + ;; SX-7:SUPER-UX:*:*) - echo sx7-nec-superux${UNAME_RELEASE} - exit ;; + GUESS=sx7-nec-superux$UNAME_RELEASE + ;; SX-8:SUPER-UX:*:*) - echo sx8-nec-superux${UNAME_RELEASE} - exit ;; + GUESS=sx8-nec-superux$UNAME_RELEASE + ;; SX-8R:SUPER-UX:*:*) - echo sx8r-nec-superux${UNAME_RELEASE} - exit ;; + GUESS=sx8r-nec-superux$UNAME_RELEASE + ;; + SX-ACE:SUPER-UX:*:*) + GUESS=sxace-nec-superux$UNAME_RELEASE + ;; Power*:Rhapsody:*:*) - echo powerpc-apple-rhapsody${UNAME_RELEASE} - exit ;; + GUESS=powerpc-apple-rhapsody$UNAME_RELEASE + ;; *:Rhapsody:*:*) - echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} - exit ;; + GUESS=$UNAME_MACHINE-apple-rhapsody$UNAME_RELEASE + ;; + arm64:Darwin:*:*) + GUESS=aarch64-apple-darwin$UNAME_RELEASE + ;; *:Darwin:*:*) - UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown - eval $set_cc_for_build - if test "$UNAME_PROCESSOR" = unknown ; then - UNAME_PROCESSOR=powerpc + UNAME_PROCESSOR=`uname -p` + case $UNAME_PROCESSOR in + unknown) UNAME_PROCESSOR=powerpc ;; + esac + if command -v xcode-select > /dev/null 2> /dev/null && \ + ! xcode-select --print-path > /dev/null 2> /dev/null ; then + # Avoid executing cc if there is no toolchain installed as + # cc will be a stub that puts up a graphical alert + # prompting the user to install developer tools. + CC_FOR_BUILD=no_compiler_found + else + set_cc_for_build fi - if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ - grep IS_64BIT_ARCH >/dev/null + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi + # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc + if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_PPC >/dev/null + then + UNAME_PROCESSOR=powerpc + fi + elif test "$UNAME_PROCESSOR" = i386 ; then + # uname -m returns i386 or x86_64 + UNAME_PROCESSOR=$UNAME_MACHINE fi - echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} - exit ;; + GUESS=$UNAME_PROCESSOR-apple-darwin$UNAME_RELEASE + ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` - if test "$UNAME_PROCESSOR" = "x86"; then + if test "$UNAME_PROCESSOR" = x86; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi - echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} - exit ;; + GUESS=$UNAME_PROCESSOR-$UNAME_MACHINE-nto-qnx$UNAME_RELEASE + ;; *:QNX:*:4*) - echo i386-pc-qnx - exit ;; - NEO-?:NONSTOP_KERNEL:*:*) - echo neo-tandem-nsk${UNAME_RELEASE} - exit ;; + GUESS=i386-pc-qnx + ;; + NEO-*:NONSTOP_KERNEL:*:*) + GUESS=neo-tandem-nsk$UNAME_RELEASE + ;; NSE-*:NONSTOP_KERNEL:*:*) - echo nse-tandem-nsk${UNAME_RELEASE} - exit ;; - NSR-?:NONSTOP_KERNEL:*:*) - echo nsr-tandem-nsk${UNAME_RELEASE} - exit ;; + GUESS=nse-tandem-nsk$UNAME_RELEASE + ;; + NSR-*:NONSTOP_KERNEL:*:*) + GUESS=nsr-tandem-nsk$UNAME_RELEASE + ;; + NSV-*:NONSTOP_KERNEL:*:*) + GUESS=nsv-tandem-nsk$UNAME_RELEASE + ;; + NSX-*:NONSTOP_KERNEL:*:*) + GUESS=nsx-tandem-nsk$UNAME_RELEASE + ;; *:NonStop-UX:*:*) - echo mips-compaq-nonstopux - exit ;; + GUESS=mips-compaq-nonstopux + ;; BS2000:POSIX*:*:*) - echo bs2000-siemens-sysv - exit ;; + GUESS=bs2000-siemens-sysv + ;; DS/*:UNIX_System_V:*:*) - echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} - exit ;; + GUESS=$UNAME_MACHINE-$UNAME_SYSTEM-$UNAME_RELEASE + ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. - if test "$cputype" = "386"; then + if test "${cputype-}" = 386; then UNAME_MACHINE=i386 - else - UNAME_MACHINE="$cputype" + elif test "x${cputype-}" != x; then + UNAME_MACHINE=$cputype fi - echo ${UNAME_MACHINE}-unknown-plan9 - exit ;; + GUESS=$UNAME_MACHINE-unknown-plan9 + ;; *:TOPS-10:*:*) - echo pdp10-unknown-tops10 - exit ;; + GUESS=pdp10-unknown-tops10 + ;; *:TENEX:*:*) - echo pdp10-unknown-tenex - exit ;; + GUESS=pdp10-unknown-tenex + ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) - echo pdp10-dec-tops20 - exit ;; + GUESS=pdp10-dec-tops20 + ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) - echo pdp10-xkl-tops20 - exit ;; + GUESS=pdp10-xkl-tops20 + ;; *:TOPS-20:*:*) - echo pdp10-unknown-tops20 - exit ;; + GUESS=pdp10-unknown-tops20 + ;; *:ITS:*:*) - echo pdp10-unknown-its - exit ;; + GUESS=pdp10-unknown-its + ;; SEI:*:*:SEIUX) - echo mips-sei-seiux${UNAME_RELEASE} - exit ;; + GUESS=mips-sei-seiux$UNAME_RELEASE + ;; *:DragonFly:*:*) - echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` - exit ;; + DRAGONFLY_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_MACHINE-unknown-dragonfly$DRAGONFLY_REL + ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` - case "${UNAME_MACHINE}" in - A*) echo alpha-dec-vms ; exit ;; - I*) echo ia64-dec-vms ; exit ;; - V*) echo vax-dec-vms ; exit ;; + case $UNAME_MACHINE in + A*) GUESS=alpha-dec-vms ;; + I*) GUESS=ia64-dec-vms ;; + V*) GUESS=vax-dec-vms ;; esac ;; *:XENIX:*:SysV) - echo i386-pc-xenix - exit ;; + GUESS=i386-pc-xenix + ;; i*86:skyos:*:*) - echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' - exit ;; + SKYOS_REL=`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'` + GUESS=$UNAME_MACHINE-pc-skyos$SKYOS_REL + ;; i*86:rdos:*:*) - echo ${UNAME_MACHINE}-pc-rdos - exit ;; - i*86:AROS:*:*) - echo ${UNAME_MACHINE}-pc-aros - exit ;; + GUESS=$UNAME_MACHINE-pc-rdos + ;; + i*86:Fiwix:*:*) + GUESS=$UNAME_MACHINE-pc-fiwix + ;; + *:AROS:*:*) + GUESS=$UNAME_MACHINE-unknown-aros + ;; x86_64:VMkernel:*:*) - echo ${UNAME_MACHINE}-unknown-esx - exit ;; + GUESS=$UNAME_MACHINE-unknown-esx + ;; + amd64:Isilon\ OneFS:*:*) + GUESS=x86_64-unknown-onefs + ;; + *:Unleashed:*:*) + GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE + ;; esac -eval $set_cc_for_build -cat >$dummy.c < "$dummy.c" < -# include +#include +#include +#endif +#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) +#if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) +#include +#if defined(_SIZE_T_) || defined(SIGLOST) +#include +#endif +#endif #endif main () { @@ -1378,22 +1588,14 @@ main () #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 - "4" + "4" #else - "" + "" #endif - ); exit (0); + ); exit (0); #endif #endif -#if defined (__arm) && defined (__acorn) && defined (__unix) - printf ("arm-acorn-riscix\n"); exit (0); -#endif - -#if defined (hp300) && !defined (hpux) - printf ("m68k-hp-bsd\n"); exit (0); -#endif - #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" @@ -1433,39 +1635,54 @@ main () #endif #if defined (_SEQUENT_) - struct utsname un; - - uname(&un); - - if (strncmp(un.version, "V2", 2) == 0) { - printf ("i386-sequent-ptx2\n"); exit (0); - } - if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ - printf ("i386-sequent-ptx1\n"); exit (0); - } - printf ("i386-sequent-ptx\n"); exit (0); + struct utsname un; + uname(&un); + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) -# if !defined (ultrix) -# include -# if defined (BSD) -# if BSD == 43 - printf ("vax-dec-bsd4.3\n"); exit (0); -# else -# if BSD == 199006 - printf ("vax-dec-bsd4.3reno\n"); exit (0); -# else - printf ("vax-dec-bsd\n"); exit (0); -# endif -# endif -# else - printf ("vax-dec-bsd\n"); exit (0); -# endif -# else - printf ("vax-dec-ultrix\n"); exit (0); -# endif +#if !defined (ultrix) +#include +#if defined (BSD) +#if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +#else +#if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +#else + printf ("vax-dec-bsd\n"); exit (0); +#endif +#endif +#else + printf ("vax-dec-bsd\n"); exit (0); +#endif +#else +#if defined(_SIZE_T_) || defined(SIGLOST) + struct utsname un; + uname (&un); + printf ("vax-dec-ultrix%s\n", un.release); exit (0); +#else + printf ("vax-dec-ultrix\n"); exit (0); +#endif +#endif +#endif +#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) +#if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) +#if defined(_SIZE_T_) || defined(SIGLOST) + struct utsname *un; + uname (&un); + printf ("mips-dec-ultrix%s\n", un.release); exit (0); +#else + printf ("mips-dec-ultrix\n"); exit (0); +#endif +#endif #endif #if defined (alliant) && defined (i860) @@ -1476,54 +1693,46 @@ main () } EOF -$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && +$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. +test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; } -test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } +echo "$0: unable to guess system type" >&2 -# Convex versions that predate uname can use getsysinfo(1) +case $UNAME_MACHINE:$UNAME_SYSTEM in + mips:Linux | mips64:Linux) + # If we got here on MIPS GNU/Linux, output extra information. + cat >&2 <&2 < in order to provide the needed -information to handle your system. +our_year=`echo $timestamp | sed 's,-.*,,'` +thisyear=`date +%Y` +# shellcheck disable=SC2003 +script_age=`expr "$thisyear" - "$our_year"` +if test "$script_age" -lt 3 ; then + cat >&2 </dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` -UNAME_MACHINE = ${UNAME_MACHINE} -UNAME_RELEASE = ${UNAME_RELEASE} -UNAME_SYSTEM = ${UNAME_SYSTEM} -UNAME_VERSION = ${UNAME_VERSION} +UNAME_MACHINE = "$UNAME_MACHINE" +UNAME_RELEASE = "$UNAME_RELEASE" +UNAME_SYSTEM = "$UNAME_SYSTEM" +UNAME_VERSION = "$UNAME_VERSION" EOF +fi exit 1 # Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) +# eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" diff --git a/autoconf/config.sub b/autoconf/config.sub old mode 100755 new mode 100644 index c765b34b..fbaa37f2 --- a/autoconf/config.sub +++ b/autoconf/config.sub @@ -1,12 +1,14 @@ #! /bin/sh # Configuration validation subroutine script. -# Copyright 1992-2013 Free Software Foundation, Inc. +# Copyright 1992-2022 Free Software Foundation, Inc. -timestamp='2013-04-24' +# shellcheck disable=SC2006,SC2268 # see below for rationale + +timestamp='2022-08-01' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or +# the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but @@ -15,7 +17,7 @@ timestamp='2013-04-24' # General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, see . +# along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a @@ -25,7 +27,7 @@ timestamp='2013-04-24' # of the GNU General Public License, version 3 ("GPLv3"). -# Please send patches with a ChangeLog entry to config-patches@gnu.org. +# Please send patches to . # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. @@ -33,7 +35,7 @@ timestamp='2013-04-24' # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: -# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD +# https://git.savannah.gnu.org/cgit/config.git/plain/config.sub # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases @@ -50,15 +52,21 @@ timestamp='2013-04-24' # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. +# The "shellcheck disable" line above the timestamp inhibits complaints +# about features and limitations of the classic Bourne shell that were +# superseded or lifted in POSIX. However, this script identifies a wide +# variety of pre-POSIX systems that do not have POSIX shells at all, and +# even some reasonably current systems (Solaris 10 as case-in-point) still +# have a pre-POSIX /bin/sh. + me=`echo "$0" | sed -e 's,.*/,,'` usage="\ -Usage: $0 [OPTION] CPU-MFR-OPSYS - $0 [OPTION] ALIAS +Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS Canonicalize a configuration name. -Operation modes: +Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit @@ -68,7 +76,7 @@ Report bugs and patches to ." version="\ GNU config.sub ($timestamp) -Copyright 1992-2013 Free Software Foundation, Inc. +Copyright 1992-2022 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -90,12 +98,12 @@ while test $# -gt 0 ; do - ) # Use stdin as input. break ;; -* ) - echo "$me: invalid option $1$help" + echo "$me: invalid option $1$help" >&2 exit 1 ;; *local*) # First pass through any local machine types. - echo $1 + echo "$1" exit ;; * ) @@ -111,1209 +119,1186 @@ case $# in exit 1;; esac -# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). -# Here we must recognize all the valid KERNEL-OS combinations. -maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` -case $maybe_os in - nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ - linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ - knetbsd*-gnu* | netbsd*-gnu* | \ - kopensolaris*-gnu* | \ - storm-chaos* | os2-emx* | rtmk-nova*) - os=-$maybe_os - basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` - ;; - android-linux) - os=-linux-android - basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown - ;; - *) - basic_machine=`echo $1 | sed 's/-[^-]*$//'` - if [ $basic_machine != $1 ] - then os=`echo $1 | sed 's/.*-/-/'` - else os=; fi - ;; -esac +# Split fields of configuration type +# shellcheck disable=SC2162 +saved_IFS=$IFS +IFS="-" read field1 field2 field3 field4 <&2 + exit 1 ;; - -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ - -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ - -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ - -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ - -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ - -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ - -apple | -axis | -knuth | -cray | -microblaze*) - os= - basic_machine=$1 + *-*-*-*) + basic_machine=$field1-$field2 + basic_os=$field3-$field4 ;; - -bluegene*) - os=-cnk + *-*-*) + # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two + # parts + maybe_os=$field2-$field3 + case $maybe_os in + nto-qnx* | linux-* | uclinux-uclibc* \ + | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ + | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ + | storm-chaos* | os2-emx* | rtmk-nova*) + basic_machine=$field1 + basic_os=$maybe_os + ;; + android-linux) + basic_machine=$field1-unknown + basic_os=linux-android + ;; + *) + basic_machine=$field1-$field2 + basic_os=$field3 + ;; + esac ;; - -sim | -cisco | -oki | -wec | -winbond) - os= - basic_machine=$1 + *-*) + # A lone config we happen to match not fitting any pattern + case $field1-$field2 in + decstation-3100) + basic_machine=mips-dec + basic_os= + ;; + *-*) + # Second component is usually, but not always the OS + case $field2 in + # Prevent following clause from handling this valid os + sun*os*) + basic_machine=$field1 + basic_os=$field2 + ;; + zephyr*) + basic_machine=$field1-unknown + basic_os=$field2 + ;; + # Manufacturers + dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \ + | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \ + | unicom* | ibm* | next | hp | isi* | apollo | altos* \ + | convergent* | ncr* | news | 32* | 3600* | 3100* \ + | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \ + | ultra | tti* | harris | dolphin | highlevel | gould \ + | cbm | ns | masscomp | apple | axis | knuth | cray \ + | microblaze* | sim | cisco \ + | oki | wec | wrs | winbond) + basic_machine=$field1-$field2 + basic_os= + ;; + *) + basic_machine=$field1 + basic_os=$field2 + ;; + esac + ;; + esac ;; - -scout) - ;; - -wrs) - os=-vxworks - basic_machine=$1 - ;; - -chorusos*) - os=-chorusos - basic_machine=$1 - ;; - -chorusrdb) - os=-chorusrdb - basic_machine=$1 - ;; - -hiux*) - os=-hiuxwe2 - ;; - -sco6) - os=-sco5v6 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco5) - os=-sco3.2v5 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco4) - os=-sco3.2v4 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco3.2.[4-9]*) - os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco3.2v[4-9]*) - # Don't forget version if it is 3.2v4 or newer. - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco5v6*) - # Don't forget version if it is 3.2v4 or newer. - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco*) - os=-sco3.2v2 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -udk*) - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -isc) - os=-isc2.2 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -clix*) - basic_machine=clipper-intergraph - ;; - -isc*) - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -lynx*178) - os=-lynxos178 - ;; - -lynx*5) - os=-lynxos5 - ;; - -lynx*) - os=-lynxos - ;; - -ptx*) - basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` - ;; - -windowsnt*) - os=`echo $os | sed -e 's/windowsnt/winnt/'` - ;; - -psos*) - os=-psos - ;; - -mint | -mint[0-9]*) - basic_machine=m68k-atari - os=-mint + *) + # Convert single-component short-hands not valid as part of + # multi-component configurations. + case $field1 in + 386bsd) + basic_machine=i386-pc + basic_os=bsd + ;; + a29khif) + basic_machine=a29k-amd + basic_os=udi + ;; + adobe68k) + basic_machine=m68010-adobe + basic_os=scout + ;; + alliant) + basic_machine=fx80-alliant + basic_os= + ;; + altos | altos3068) + basic_machine=m68k-altos + basic_os= + ;; + am29k) + basic_machine=a29k-none + basic_os=bsd + ;; + amdahl) + basic_machine=580-amdahl + basic_os=sysv + ;; + amiga) + basic_machine=m68k-unknown + basic_os= + ;; + amigaos | amigados) + basic_machine=m68k-unknown + basic_os=amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + basic_os=sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + basic_os=sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + basic_os=bsd + ;; + aros) + basic_machine=i386-pc + basic_os=aros + ;; + aux) + basic_machine=m68k-apple + basic_os=aux + ;; + balance) + basic_machine=ns32k-sequent + basic_os=dynix + ;; + blackfin) + basic_machine=bfin-unknown + basic_os=linux + ;; + cegcc) + basic_machine=arm-unknown + basic_os=cegcc + ;; + convex-c1) + basic_machine=c1-convex + basic_os=bsd + ;; + convex-c2) + basic_machine=c2-convex + basic_os=bsd + ;; + convex-c32) + basic_machine=c32-convex + basic_os=bsd + ;; + convex-c34) + basic_machine=c34-convex + basic_os=bsd + ;; + convex-c38) + basic_machine=c38-convex + basic_os=bsd + ;; + cray) + basic_machine=j90-cray + basic_os=unicos + ;; + crds | unos) + basic_machine=m68k-crds + basic_os= + ;; + da30) + basic_machine=m68k-da30 + basic_os= + ;; + decstation | pmax | pmin | dec3100 | decstatn) + basic_machine=mips-dec + basic_os= + ;; + delta88) + basic_machine=m88k-motorola + basic_os=sysv3 + ;; + dicos) + basic_machine=i686-pc + basic_os=dicos + ;; + djgpp) + basic_machine=i586-pc + basic_os=msdosdjgpp + ;; + ebmon29k) + basic_machine=a29k-amd + basic_os=ebmon + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + basic_os=ose + ;; + gmicro) + basic_machine=tron-gmicro + basic_os=sysv + ;; + go32) + basic_machine=i386-pc + basic_os=go32 + ;; + h8300hms) + basic_machine=h8300-hitachi + basic_os=hms + ;; + h8300xray) + basic_machine=h8300-hitachi + basic_os=xray + ;; + h8500hms) + basic_machine=h8500-hitachi + basic_os=hms + ;; + harris) + basic_machine=m88k-harris + basic_os=sysv3 + ;; + hp300 | hp300hpux) + basic_machine=m68k-hp + basic_os=hpux + ;; + hp300bsd) + basic_machine=m68k-hp + basic_os=bsd + ;; + hppaosf) + basic_machine=hppa1.1-hp + basic_os=osf + ;; + hppro) + basic_machine=hppa1.1-hp + basic_os=proelf + ;; + i386mach) + basic_machine=i386-mach + basic_os=mach + ;; + isi68 | isi) + basic_machine=m68k-isi + basic_os=sysv + ;; + m68knommu) + basic_machine=m68k-unknown + basic_os=linux + ;; + magnum | m3230) + basic_machine=mips-mips + basic_os=sysv + ;; + merlin) + basic_machine=ns32k-utek + basic_os=sysv + ;; + mingw64) + basic_machine=x86_64-pc + basic_os=mingw64 + ;; + mingw32) + basic_machine=i686-pc + basic_os=mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + basic_os=mingw32ce + ;; + monitor) + basic_machine=m68k-rom68k + basic_os=coff + ;; + morphos) + basic_machine=powerpc-unknown + basic_os=morphos + ;; + moxiebox) + basic_machine=moxie-unknown + basic_os=moxiebox + ;; + msdos) + basic_machine=i386-pc + basic_os=msdos + ;; + msys) + basic_machine=i686-pc + basic_os=msys + ;; + mvs) + basic_machine=i370-ibm + basic_os=mvs + ;; + nacl) + basic_machine=le32-unknown + basic_os=nacl + ;; + ncr3000) + basic_machine=i486-ncr + basic_os=sysv4 + ;; + netbsd386) + basic_machine=i386-pc + basic_os=netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + basic_os=linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + basic_os=newsos + ;; + news1000) + basic_machine=m68030-sony + basic_os=newsos + ;; + necv70) + basic_machine=v70-nec + basic_os=sysv + ;; + nh3000) + basic_machine=m68k-harris + basic_os=cxux + ;; + nh[45]000) + basic_machine=m88k-harris + basic_os=cxux + ;; + nindy960) + basic_machine=i960-intel + basic_os=nindy + ;; + mon960) + basic_machine=i960-intel + basic_os=mon960 + ;; + nonstopux) + basic_machine=mips-compaq + basic_os=nonstopux + ;; + os400) + basic_machine=powerpc-ibm + basic_os=os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + basic_os=ose + ;; + os68k) + basic_machine=m68k-none + basic_os=os68k + ;; + paragon) + basic_machine=i860-intel + basic_os=osf + ;; + parisc) + basic_machine=hppa-unknown + basic_os=linux + ;; + psp) + basic_machine=mipsallegrexel-sony + basic_os=psp + ;; + pw32) + basic_machine=i586-unknown + basic_os=pw32 + ;; + rdos | rdos64) + basic_machine=x86_64-pc + basic_os=rdos + ;; + rdos32) + basic_machine=i386-pc + basic_os=rdos + ;; + rom68k) + basic_machine=m68k-rom68k + basic_os=coff + ;; + sa29200) + basic_machine=a29k-amd + basic_os=udi + ;; + sei) + basic_machine=mips-sei + basic_os=seiux + ;; + sequent) + basic_machine=i386-sequent + basic_os= + ;; + sps7) + basic_machine=m68k-bull + basic_os=sysv2 + ;; + st2000) + basic_machine=m68k-tandem + basic_os= + ;; + stratus) + basic_machine=i860-stratus + basic_os=sysv4 + ;; + sun2) + basic_machine=m68000-sun + basic_os= + ;; + sun2os3) + basic_machine=m68000-sun + basic_os=sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + basic_os=sunos4 + ;; + sun3) + basic_machine=m68k-sun + basic_os= + ;; + sun3os3) + basic_machine=m68k-sun + basic_os=sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + basic_os=sunos4 + ;; + sun4) + basic_machine=sparc-sun + basic_os= + ;; + sun4os3) + basic_machine=sparc-sun + basic_os=sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + basic_os=sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + basic_os=solaris2 + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + basic_os= + ;; + sv1) + basic_machine=sv1-cray + basic_os=unicos + ;; + symmetry) + basic_machine=i386-sequent + basic_os=dynix + ;; + t3e) + basic_machine=alphaev5-cray + basic_os=unicos + ;; + t90) + basic_machine=t90-cray + basic_os=unicos + ;; + toad1) + basic_machine=pdp10-xkl + basic_os=tops20 + ;; + tpf) + basic_machine=s390x-ibm + basic_os=tpf + ;; + udi29k) + basic_machine=a29k-amd + basic_os=udi + ;; + ultra3) + basic_machine=a29k-nyu + basic_os=sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + basic_os=none + ;; + vaxv) + basic_machine=vax-dec + basic_os=sysv + ;; + vms) + basic_machine=vax-dec + basic_os=vms + ;; + vsta) + basic_machine=i386-pc + basic_os=vsta + ;; + vxworks960) + basic_machine=i960-wrs + basic_os=vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + basic_os=vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + basic_os=vxworks + ;; + xbox) + basic_machine=i686-pc + basic_os=mingw32 + ;; + ymp) + basic_machine=ymp-cray + basic_os=unicos + ;; + *) + basic_machine=$1 + basic_os= + ;; + esac ;; esac -# Decode aliases for certain CPU-COMPANY combinations. +# Decode 1-component or ad-hoc basic machines case $basic_machine in - # Recognize the basic CPU types without company name. - # Some are omitted here because they have special meanings below. - 1750a | 580 \ - | a29k \ - | aarch64 | aarch64_be \ - | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ - | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ - | am33_2.0 \ - | arc | arceb \ - | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ - | avr | avr32 \ - | be32 | be64 \ - | bfin \ - | c4x | clipper \ - | d10v | d30v | dlx | dsp16xx \ - | epiphany \ - | fido | fr30 | frv \ - | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ - | hexagon \ - | i370 | i860 | i960 | ia64 \ - | ip2k | iq2000 \ - | le32 | le64 \ - | lm32 \ - | m32c | m32r | m32rle | m68000 | m68k | m88k \ - | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ - | mips | mipsbe | mipseb | mipsel | mipsle \ - | mips16 \ - | mips64 | mips64el \ - | mips64octeon | mips64octeonel \ - | mips64orion | mips64orionel \ - | mips64r5900 | mips64r5900el \ - | mips64vr | mips64vrel \ - | mips64vr4100 | mips64vr4100el \ - | mips64vr4300 | mips64vr4300el \ - | mips64vr5000 | mips64vr5000el \ - | mips64vr5900 | mips64vr5900el \ - | mipsisa32 | mipsisa32el \ - | mipsisa32r2 | mipsisa32r2el \ - | mipsisa64 | mipsisa64el \ - | mipsisa64r2 | mipsisa64r2el \ - | mipsisa64sb1 | mipsisa64sb1el \ - | mipsisa64sr71k | mipsisa64sr71kel \ - | mipsr5900 | mipsr5900el \ - | mipstx39 | mipstx39el \ - | mn10200 | mn10300 \ - | moxie \ - | mt \ - | msp430 \ - | nds32 | nds32le | nds32be \ - | nios | nios2 | nios2eb | nios2el \ - | ns16k | ns32k \ - | open8 \ - | or1k | or32 \ - | pdp10 | pdp11 | pj | pjl \ - | powerpc | powerpc64 | powerpc64le | powerpcle \ - | pyramid \ - | rl78 | rx \ - | score \ - | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ - | sh64 | sh64le \ - | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ - | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ - | spu \ - | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ - | ubicom32 \ - | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ - | we32k \ - | x86 | xc16x | xstormy16 | xtensa \ - | z8k | z80) - basic_machine=$basic_machine-unknown + # Here we handle the default manufacturer of certain CPU types. It is in + # some cases the only manufacturer, in others, it is the most popular. + w89k) + cpu=hppa1.1 + vendor=winbond ;; - c54x) - basic_machine=tic54x-unknown + op50n) + cpu=hppa1.1 + vendor=oki ;; - c55x) - basic_machine=tic55x-unknown + op60c) + cpu=hppa1.1 + vendor=oki ;; - c6x) - basic_machine=tic6x-unknown + ibm*) + cpu=i370 + vendor=ibm ;; - m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) - basic_machine=$basic_machine-unknown - os=-none + orion105) + cpu=clipper + vendor=highlevel ;; - m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + mac | mpw | mac-mpw) + cpu=m68k + vendor=apple ;; - ms1) - basic_machine=mt-unknown + pmac | pmac-mpw) + cpu=powerpc + vendor=apple ;; - strongarm | thumb | xscale) - basic_machine=arm-unknown + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + cpu=m68000 + vendor=att ;; - xgate) - basic_machine=$basic_machine-unknown - os=-none + 3b*) + cpu=we32k + vendor=att ;; - xscaleeb) - basic_machine=armeb-unknown + bluegene*) + cpu=powerpc + vendor=ibm + basic_os=cnk + ;; + decsystem10* | dec10*) + cpu=pdp10 + vendor=dec + basic_os=tops10 + ;; + decsystem20* | dec20*) + cpu=pdp10 + vendor=dec + basic_os=tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + cpu=m68k + vendor=motorola + ;; + dpx2*) + cpu=m68k + vendor=bull + basic_os=sysv3 + ;; + encore | umax | mmax) + cpu=ns32k + vendor=encore + ;; + elxsi) + cpu=elxsi + vendor=elxsi + basic_os=${basic_os:-bsd} + ;; + fx2800) + cpu=i860 + vendor=alliant + ;; + genix) + cpu=ns32k + vendor=ns + ;; + h3050r* | hiux*) + cpu=hppa1.1 + vendor=hitachi + basic_os=hiuxwe2 + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + cpu=hppa1.0 + vendor=hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + cpu=m68000 + vendor=hp + ;; + hp9k3[2-9][0-9]) + cpu=m68k + vendor=hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + cpu=hppa1.0 + vendor=hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + cpu=hppa1.1 + vendor=hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + cpu=hppa1.1 + vendor=hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + cpu=hppa1.1 + vendor=hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + cpu=hppa1.1 + vendor=hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + cpu=hppa1.0 + vendor=hp + ;; + i*86v32) + cpu=`echo "$1" | sed -e 's/86.*/86/'` + vendor=pc + basic_os=sysv32 + ;; + i*86v4*) + cpu=`echo "$1" | sed -e 's/86.*/86/'` + vendor=pc + basic_os=sysv4 + ;; + i*86v) + cpu=`echo "$1" | sed -e 's/86.*/86/'` + vendor=pc + basic_os=sysv + ;; + i*86sol2) + cpu=`echo "$1" | sed -e 's/86.*/86/'` + vendor=pc + basic_os=solaris2 + ;; + j90 | j90-cray) + cpu=j90 + vendor=cray + basic_os=${basic_os:-unicos} + ;; + iris | iris4d) + cpu=mips + vendor=sgi + case $basic_os in + irix*) + ;; + *) + basic_os=irix4 + ;; + esac + ;; + miniframe) + cpu=m68000 + vendor=convergent + ;; + *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*) + cpu=m68k + vendor=atari + basic_os=mint + ;; + news-3600 | risc-news) + cpu=mips + vendor=sony + basic_os=newsos + ;; + next | m*-next) + cpu=m68k + vendor=next + case $basic_os in + openstep*) + ;; + nextstep*) + ;; + ns2*) + basic_os=nextstep2 + ;; + *) + basic_os=nextstep3 + ;; + esac + ;; + np1) + cpu=np1 + vendor=gould + ;; + op50n-* | op60c-*) + cpu=hppa1.1 + vendor=oki + basic_os=proelf + ;; + pa-hitachi) + cpu=hppa1.1 + vendor=hitachi + basic_os=hiuxwe2 + ;; + pbd) + cpu=sparc + vendor=tti + ;; + pbb) + cpu=m68k + vendor=tti + ;; + pc532) + cpu=ns32k + vendor=pc532 + ;; + pn) + cpu=pn + vendor=gould + ;; + power) + cpu=power + vendor=ibm + ;; + ps2) + cpu=i386 + vendor=ibm + ;; + rm[46]00) + cpu=mips + vendor=siemens + ;; + rtpc | rtpc-*) + cpu=romp + vendor=ibm + ;; + sde) + cpu=mipsisa32 + vendor=sde + basic_os=${basic_os:-elf} + ;; + simso-wrs) + cpu=sparclite + vendor=wrs + basic_os=vxworks + ;; + tower | tower-32) + cpu=m68k + vendor=ncr + ;; + vpp*|vx|vx-*) + cpu=f301 + vendor=fujitsu + ;; + w65) + cpu=w65 + vendor=wdc + ;; + w89k-*) + cpu=hppa1.1 + vendor=winbond + basic_os=proelf + ;; + none) + cpu=none + vendor=none + ;; + leon|leon[3-9]) + cpu=sparc + vendor=$basic_machine + ;; + leon-*|leon[3-9]-*) + cpu=sparc + vendor=`echo "$basic_machine" | sed 's/-.*//'` ;; - xscaleel) - basic_machine=armel-unknown + *-*) + # shellcheck disable=SC2162 + saved_IFS=$IFS + IFS="-" read cpu vendor <&2 - exit 1 - ;; - # Recognize the basic CPU types with company name. - 580-* \ - | a29k-* \ - | aarch64-* | aarch64_be-* \ - | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ - | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ - | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ - | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ - | avr-* | avr32-* \ - | be32-* | be64-* \ - | bfin-* | bs2000-* \ - | c[123]* | c30-* | [cjt]90-* | c4x-* \ - | clipper-* | craynv-* | cydra-* \ - | d10v-* | d30v-* | dlx-* \ - | elxsi-* \ - | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ - | h8300-* | h8500-* \ - | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ - | hexagon-* \ - | i*86-* | i860-* | i960-* | ia64-* \ - | ip2k-* | iq2000-* \ - | le32-* | le64-* \ - | lm32-* \ - | m32c-* | m32r-* | m32rle-* \ - | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ - | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ - | microblaze-* | microblazeel-* \ - | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ - | mips16-* \ - | mips64-* | mips64el-* \ - | mips64octeon-* | mips64octeonel-* \ - | mips64orion-* | mips64orionel-* \ - | mips64r5900-* | mips64r5900el-* \ - | mips64vr-* | mips64vrel-* \ - | mips64vr4100-* | mips64vr4100el-* \ - | mips64vr4300-* | mips64vr4300el-* \ - | mips64vr5000-* | mips64vr5000el-* \ - | mips64vr5900-* | mips64vr5900el-* \ - | mipsisa32-* | mipsisa32el-* \ - | mipsisa32r2-* | mipsisa32r2el-* \ - | mipsisa64-* | mipsisa64el-* \ - | mipsisa64r2-* | mipsisa64r2el-* \ - | mipsisa64sb1-* | mipsisa64sb1el-* \ - | mipsisa64sr71k-* | mipsisa64sr71kel-* \ - | mipsr5900-* | mipsr5900el-* \ - | mipstx39-* | mipstx39el-* \ - | mmix-* \ - | mt-* \ - | msp430-* \ - | nds32-* | nds32le-* | nds32be-* \ - | nios-* | nios2-* | nios2eb-* | nios2el-* \ - | none-* | np1-* | ns16k-* | ns32k-* \ - | open8-* \ - | orion-* \ - | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ - | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ - | pyramid-* \ - | rl78-* | romp-* | rs6000-* | rx-* \ - | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ - | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ - | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ - | sparclite-* \ - | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ - | tahoe-* \ - | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ - | tile*-* \ - | tron-* \ - | ubicom32-* \ - | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ - | vax-* \ - | we32k-* \ - | x86-* | x86_64-* | xc16x-* | xps100-* \ - | xstormy16-* | xtensa*-* \ - | ymp-* \ - | z8k-* | z80-*) - ;; - # Recognize the basic CPU types without company name, with glob match. - xtensa*) - basic_machine=$basic_machine-unknown - ;; - # Recognize the various machine names and aliases which stand - # for a CPU type and a company and sometimes even an OS. - 386bsd) - basic_machine=i386-unknown - os=-bsd - ;; - 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) - basic_machine=m68000-att - ;; - 3b*) - basic_machine=we32k-att - ;; - a29khif) - basic_machine=a29k-amd - os=-udi - ;; - abacus) - basic_machine=abacus-unknown - ;; - adobe68k) - basic_machine=m68010-adobe - os=-scout - ;; - alliant | fx80) - basic_machine=fx80-alliant - ;; - altos | altos3068) - basic_machine=m68k-altos - ;; - am29k) - basic_machine=a29k-none - os=-bsd - ;; - amd64) - basic_machine=x86_64-pc - ;; - amd64-*) - basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - amdahl) - basic_machine=580-amdahl - os=-sysv - ;; - amiga | amiga-*) - basic_machine=m68k-unknown - ;; - amigaos | amigados) - basic_machine=m68k-unknown - os=-amigaos - ;; - amigaunix | amix) - basic_machine=m68k-unknown - os=-sysv4 - ;; - apollo68) - basic_machine=m68k-apollo - os=-sysv - ;; - apollo68bsd) - basic_machine=m68k-apollo - os=-bsd - ;; - aros) - basic_machine=i386-pc - os=-aros - ;; - aux) - basic_machine=m68k-apple - os=-aux - ;; - balance) - basic_machine=ns32k-sequent - os=-dynix - ;; - blackfin) - basic_machine=bfin-unknown - os=-linux - ;; - blackfin-*) - basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` - os=-linux - ;; - bluegene*) - basic_machine=powerpc-ibm - os=-cnk - ;; - c54x-*) - basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - c55x-*) - basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - c6x-*) - basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - c90) - basic_machine=c90-cray - os=-unicos - ;; - cegcc) - basic_machine=arm-unknown - os=-cegcc - ;; - convex-c1) - basic_machine=c1-convex - os=-bsd - ;; - convex-c2) - basic_machine=c2-convex - os=-bsd - ;; - convex-c32) - basic_machine=c32-convex - os=-bsd - ;; - convex-c34) - basic_machine=c34-convex - os=-bsd - ;; - convex-c38) - basic_machine=c38-convex - os=-bsd - ;; - cray | j90) - basic_machine=j90-cray - os=-unicos - ;; - craynv) - basic_machine=craynv-cray - os=-unicosmp - ;; - cr16 | cr16-*) - basic_machine=cr16-unknown - os=-elf - ;; - crds | unos) - basic_machine=m68k-crds - ;; - crisv32 | crisv32-* | etraxfs*) - basic_machine=crisv32-axis - ;; - cris | cris-* | etrax*) - basic_machine=cris-axis - ;; - crx) - basic_machine=crx-unknown - os=-elf - ;; - da30 | da30-*) - basic_machine=m68k-da30 - ;; - decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) - basic_machine=mips-dec - ;; - decsystem10* | dec10*) - basic_machine=pdp10-dec - os=-tops10 - ;; - decsystem20* | dec20*) - basic_machine=pdp10-dec - os=-tops20 - ;; - delta | 3300 | motorola-3300 | motorola-delta \ - | 3300-motorola | delta-motorola) - basic_machine=m68k-motorola - ;; - delta88) - basic_machine=m88k-motorola - os=-sysv3 - ;; - dicos) - basic_machine=i686-pc - os=-dicos - ;; - djgpp) - basic_machine=i586-pc - os=-msdosdjgpp - ;; - dpx20 | dpx20-*) - basic_machine=rs6000-bull - os=-bosx - ;; - dpx2* | dpx2*-bull) - basic_machine=m68k-bull - os=-sysv3 - ;; - ebmon29k) - basic_machine=a29k-amd - os=-ebmon - ;; - elxsi) - basic_machine=elxsi-elxsi - os=-bsd - ;; - encore | umax | mmax) - basic_machine=ns32k-encore - ;; - es1800 | OSE68k | ose68k | ose | OSE) - basic_machine=m68k-ericsson - os=-ose - ;; - fx2800) - basic_machine=i860-alliant - ;; - genix) - basic_machine=ns32k-ns - ;; - gmicro) - basic_machine=tron-gmicro - os=-sysv - ;; - go32) - basic_machine=i386-pc - os=-go32 - ;; - h3050r* | hiux*) - basic_machine=hppa1.1-hitachi - os=-hiuxwe2 - ;; - h8300hms) - basic_machine=h8300-hitachi - os=-hms - ;; - h8300xray) - basic_machine=h8300-hitachi - os=-xray - ;; - h8500hms) - basic_machine=h8500-hitachi - os=-hms - ;; - harris) - basic_machine=m88k-harris - os=-sysv3 - ;; - hp300-*) - basic_machine=m68k-hp - ;; - hp300bsd) - basic_machine=m68k-hp - os=-bsd - ;; - hp300hpux) - basic_machine=m68k-hp - os=-hpux - ;; - hp3k9[0-9][0-9] | hp9[0-9][0-9]) - basic_machine=hppa1.0-hp - ;; - hp9k2[0-9][0-9] | hp9k31[0-9]) - basic_machine=m68000-hp - ;; - hp9k3[2-9][0-9]) - basic_machine=m68k-hp - ;; - hp9k6[0-9][0-9] | hp6[0-9][0-9]) - basic_machine=hppa1.0-hp - ;; - hp9k7[0-79][0-9] | hp7[0-79][0-9]) - basic_machine=hppa1.1-hp - ;; - hp9k78[0-9] | hp78[0-9]) - # FIXME: really hppa2.0-hp - basic_machine=hppa1.1-hp - ;; - hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) - # FIXME: really hppa2.0-hp - basic_machine=hppa1.1-hp - ;; - hp9k8[0-9][13679] | hp8[0-9][13679]) - basic_machine=hppa1.1-hp - ;; - hp9k8[0-9][0-9] | hp8[0-9][0-9]) - basic_machine=hppa1.0-hp - ;; - hppa-next) - os=-nextstep3 - ;; - hppaosf) - basic_machine=hppa1.1-hp - os=-osf - ;; - hppro) - basic_machine=hppa1.1-hp - os=-proelf - ;; - i370-ibm* | ibm*) - basic_machine=i370-ibm - ;; - i*86v32) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv32 - ;; - i*86v4*) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv4 - ;; - i*86v) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv - ;; - i*86sol2) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-solaris2 - ;; - i386mach) - basic_machine=i386-mach - os=-mach - ;; - i386-vsta | vsta) - basic_machine=i386-unknown - os=-vsta - ;; - iris | iris4d) - basic_machine=mips-sgi - case $os in - -irix*) - ;; - *) - os=-irix4 - ;; - esac - ;; - isi68 | isi) - basic_machine=m68k-isi - os=-sysv - ;; - m68knommu) - basic_machine=m68k-unknown - os=-linux - ;; - m68knommu-*) - basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` - os=-linux - ;; - m88k-omron*) - basic_machine=m88k-omron - ;; - magnum | m3230) - basic_machine=mips-mips - os=-sysv - ;; - merlin) - basic_machine=ns32k-utek - os=-sysv - ;; - microblaze*) - basic_machine=microblaze-xilinx - ;; - mingw64) - basic_machine=x86_64-pc - os=-mingw64 - ;; - mingw32) - basic_machine=i386-pc - os=-mingw32 - ;; - mingw32ce) - basic_machine=arm-unknown - os=-mingw32ce - ;; - miniframe) - basic_machine=m68000-convergent - ;; - *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) - basic_machine=m68k-atari - os=-mint - ;; - mips3*-*) - basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` - ;; - mips3*) - basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown - ;; - monitor) - basic_machine=m68k-rom68k - os=-coff - ;; - morphos) - basic_machine=powerpc-unknown - os=-morphos - ;; - msdos) - basic_machine=i386-pc - os=-msdos - ;; - ms1-*) - basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` - ;; - msys) - basic_machine=i386-pc - os=-msys - ;; - mvs) - basic_machine=i370-ibm - os=-mvs - ;; - nacl) - basic_machine=le32-unknown - os=-nacl - ;; - ncr3000) - basic_machine=i486-ncr - os=-sysv4 - ;; - netbsd386) - basic_machine=i386-unknown - os=-netbsd - ;; - netwinder) - basic_machine=armv4l-rebel - os=-linux - ;; - news | news700 | news800 | news900) - basic_machine=m68k-sony - os=-newsos - ;; - news1000) - basic_machine=m68030-sony - os=-newsos - ;; - news-3600 | risc-news) - basic_machine=mips-sony - os=-newsos - ;; - necv70) - basic_machine=v70-nec - os=-sysv - ;; - next | m*-next ) - basic_machine=m68k-next - case $os in - -nextstep* ) - ;; - -ns2*) - os=-nextstep2 - ;; - *) - os=-nextstep3 - ;; - esac - ;; - nh3000) - basic_machine=m68k-harris - os=-cxux - ;; - nh[45]000) - basic_machine=m88k-harris - os=-cxux - ;; - nindy960) - basic_machine=i960-intel - os=-nindy - ;; - mon960) - basic_machine=i960-intel - os=-mon960 - ;; - nonstopux) - basic_machine=mips-compaq - os=-nonstopux - ;; - np1) - basic_machine=np1-gould - ;; - neo-tandem) - basic_machine=neo-tandem - ;; - nse-tandem) - basic_machine=nse-tandem - ;; - nsr-tandem) - basic_machine=nsr-tandem - ;; - op50n-* | op60c-*) - basic_machine=hppa1.1-oki - os=-proelf - ;; - openrisc | openrisc-*) - basic_machine=or32-unknown - ;; - os400) - basic_machine=powerpc-ibm - os=-os400 - ;; - OSE68000 | ose68000) - basic_machine=m68000-ericsson - os=-ose - ;; - os68k) - basic_machine=m68k-none - os=-os68k - ;; - pa-hitachi) - basic_machine=hppa1.1-hitachi - os=-hiuxwe2 - ;; - paragon) - basic_machine=i860-intel - os=-osf - ;; - parisc) - basic_machine=hppa-unknown - os=-linux - ;; - parisc-*) - basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` - os=-linux - ;; - pbd) - basic_machine=sparc-tti - ;; - pbb) - basic_machine=m68k-tti - ;; - pc532 | pc532-*) - basic_machine=ns32k-pc532 + cpu=$basic_machine + vendor=pc ;; + # These rules are duplicated from below for sake of the special case above; + # i.e. things that normalized to x86 arches should also default to "pc" pc98) - basic_machine=i386-pc + cpu=i386 + vendor=pc ;; - pc98-*) - basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + x64 | amd64) + cpu=x86_64 + vendor=pc ;; - pentium | p5 | k5 | k6 | nexgen | viac3) - basic_machine=i586-pc + # Recognize the basic CPU types without company name. + *) + cpu=$basic_machine + vendor=unknown ;; - pentiumpro | p6 | 6x86 | athlon | athlon_*) - basic_machine=i686-pc +esac + +unset -v basic_machine + +# Decode basic machines in the full and proper CPU-Company form. +case $cpu-$vendor in + # Here we handle the default manufacturer of certain CPU types in canonical form. It is in + # some cases the only manufacturer, in others, it is the most popular. + craynv-unknown) + vendor=cray + basic_os=${basic_os:-unicosmp} ;; - pentiumii | pentium2 | pentiumiii | pentium3) - basic_machine=i686-pc + c90-unknown | c90-cray) + vendor=cray + basic_os=${Basic_os:-unicos} ;; - pentium4) - basic_machine=i786-pc + fx80-unknown) + vendor=alliant ;; - pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) - basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + romp-unknown) + vendor=ibm ;; - pentiumpro-* | p6-* | 6x86-* | athlon-*) - basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + mmix-unknown) + vendor=knuth ;; - pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) - basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + microblaze-unknown | microblazeel-unknown) + vendor=xilinx ;; - pentium4-*) - basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + rs6000-unknown) + vendor=ibm ;; - pn) - basic_machine=pn-gould + vax-unknown) + vendor=dec ;; - power) basic_machine=power-ibm + pdp11-unknown) + vendor=dec ;; - ppc | ppcbe) basic_machine=powerpc-unknown + we32k-unknown) + vendor=att ;; - ppc-* | ppcbe-*) - basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + cydra-unknown) + vendor=cydrome ;; - ppcle | powerpclittle | ppc-le | powerpc-little) - basic_machine=powerpcle-unknown + i370-ibm*) + vendor=ibm ;; - ppcle-* | powerpclittle-*) - basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + orion-unknown) + vendor=highlevel ;; - ppc64) basic_machine=powerpc64-unknown - ;; - ppc64-* | ppc64p7-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - ppc64le | powerpc64little | ppc64-le | powerpc64-little) - basic_machine=powerpc64le-unknown - ;; - ppc64le-* | powerpc64little-*) - basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - ps2) - basic_machine=i386-ibm - ;; - pw32) - basic_machine=i586-unknown - os=-pw32 - ;; - rdos | rdos64) - basic_machine=x86_64-pc - os=-rdos - ;; - rdos32) - basic_machine=i386-pc - os=-rdos - ;; - rom68k) - basic_machine=m68k-rom68k - os=-coff - ;; - rm[46]00) - basic_machine=mips-siemens - ;; - rtpc | rtpc-*) - basic_machine=romp-ibm - ;; - s390 | s390-*) - basic_machine=s390-ibm - ;; - s390x | s390x-*) - basic_machine=s390x-ibm - ;; - sa29200) - basic_machine=a29k-amd - os=-udi - ;; - sb1) - basic_machine=mipsisa64sb1-unknown - ;; - sb1el) - basic_machine=mipsisa64sb1el-unknown - ;; - sde) - basic_machine=mipsisa32-sde - os=-elf - ;; - sei) - basic_machine=mips-sei - os=-seiux - ;; - sequent) - basic_machine=i386-sequent - ;; - sh) - basic_machine=sh-hitachi - os=-hms - ;; - sh5el) - basic_machine=sh5le-unknown - ;; - sh64) - basic_machine=sh64-unknown - ;; - sparclite-wrs | simso-wrs) - basic_machine=sparclite-wrs - os=-vxworks - ;; - sps7) - basic_machine=m68k-bull - os=-sysv2 - ;; - spur) - basic_machine=spur-unknown - ;; - st2000) - basic_machine=m68k-tandem - ;; - stratus) - basic_machine=i860-stratus - os=-sysv4 - ;; - strongarm-* | thumb-*) - basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - sun2) - basic_machine=m68000-sun - ;; - sun2os3) - basic_machine=m68000-sun - os=-sunos3 - ;; - sun2os4) - basic_machine=m68000-sun - os=-sunos4 - ;; - sun3os3) - basic_machine=m68k-sun - os=-sunos3 - ;; - sun3os4) - basic_machine=m68k-sun - os=-sunos4 - ;; - sun4os3) - basic_machine=sparc-sun - os=-sunos3 - ;; - sun4os4) - basic_machine=sparc-sun - os=-sunos4 - ;; - sun4sol2) - basic_machine=sparc-sun - os=-solaris2 - ;; - sun3 | sun3-*) - basic_machine=m68k-sun - ;; - sun4) - basic_machine=sparc-sun - ;; - sun386 | sun386i | roadrunner) - basic_machine=i386-sun - ;; - sv1) - basic_machine=sv1-cray - os=-unicos - ;; - symmetry) - basic_machine=i386-sequent - os=-dynix - ;; - t3e) - basic_machine=alphaev5-cray - os=-unicos - ;; - t90) - basic_machine=t90-cray - os=-unicos - ;; - tile*) - basic_machine=$basic_machine-unknown - os=-linux-gnu - ;; - tx39) - basic_machine=mipstx39-unknown - ;; - tx39el) - basic_machine=mipstx39el-unknown - ;; - toad1) - basic_machine=pdp10-xkl - os=-tops20 - ;; - tower | tower-32) - basic_machine=m68k-ncr - ;; - tpf) - basic_machine=s390x-ibm - os=-tpf - ;; - udi29k) - basic_machine=a29k-amd - os=-udi - ;; - ultra3) - basic_machine=a29k-nyu - os=-sym1 - ;; - v810 | necv810) - basic_machine=v810-nec - os=-none - ;; - vaxv) - basic_machine=vax-dec - os=-sysv - ;; - vms) - basic_machine=vax-dec - os=-vms - ;; - vpp*|vx|vx-*) - basic_machine=f301-fujitsu - ;; - vxworks960) - basic_machine=i960-wrs - os=-vxworks - ;; - vxworks68) - basic_machine=m68k-wrs - os=-vxworks - ;; - vxworks29k) - basic_machine=a29k-wrs - os=-vxworks - ;; - w65*) - basic_machine=w65-wdc - os=-none - ;; - w89k-*) - basic_machine=hppa1.1-winbond - os=-proelf - ;; - xbox) - basic_machine=i686-pc - os=-mingw32 - ;; - xps | xps100) - basic_machine=xps100-honeywell - ;; - xscale-* | xscalee[bl]-*) - basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` - ;; - ymp) - basic_machine=ymp-cray - os=-unicos - ;; - z8k-*-coff) - basic_machine=z8k-unknown - os=-sim - ;; - z80-*-coff) - basic_machine=z80-unknown - os=-sim - ;; - none) - basic_machine=none-none - os=-none + xps-unknown | xps100-unknown) + cpu=xps100 + vendor=honeywell ;; -# Here we handle the default manufacturer of certain CPU types. It is in -# some cases the only manufacturer, in others, it is the most popular. - w89k) - basic_machine=hppa1.1-winbond + # Here we normalize CPU types with a missing or matching vendor + armh-unknown | armh-alt) + cpu=armv7l + vendor=alt + basic_os=${basic_os:-linux-gnueabihf} ;; - op50n) - basic_machine=hppa1.1-oki + dpx20-unknown | dpx20-bull) + cpu=rs6000 + vendor=bull + basic_os=${basic_os:-bosx} ;; - op60c) - basic_machine=hppa1.1-oki + + # Here we normalize CPU types irrespective of the vendor + amd64-*) + cpu=x86_64 ;; - romp) - basic_machine=romp-ibm + blackfin-*) + cpu=bfin + basic_os=linux ;; - mmix) - basic_machine=mmix-knuth + c54x-*) + cpu=tic54x ;; - rs6000) - basic_machine=rs6000-ibm + c55x-*) + cpu=tic55x ;; - vax) - basic_machine=vax-dec + c6x-*) + cpu=tic6x ;; - pdp10) - # there are many clones, so DEC is not a safe bet - basic_machine=pdp10-unknown + e500v[12]-*) + cpu=powerpc + basic_os=${basic_os}"spe" ;; - pdp11) - basic_machine=pdp11-dec + mips3*-*) + cpu=mips64 ;; - we32k) - basic_machine=we32k-att + ms1-*) + cpu=mt ;; - sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) - basic_machine=sh-unknown + m68knommu-*) + cpu=m68k + basic_os=linux ;; - sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) - basic_machine=sparc-sun + m9s12z-* | m68hcs12z-* | hcs12z-* | s12z-*) + cpu=s12z ;; - cydra) - basic_machine=cydra-cydrome + openrisc-*) + cpu=or32 ;; - orion) - basic_machine=orion-highlevel + parisc-*) + cpu=hppa + basic_os=linux ;; - orion105) - basic_machine=clipper-highlevel + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + cpu=i586 ;; - mac | mpw | mac-mpw) - basic_machine=m68k-apple + pentiumpro-* | p6-* | 6x86-* | athlon-* | athalon_*-*) + cpu=i686 ;; - pmac | pmac-mpw) - basic_machine=powerpc-apple + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + cpu=i686 ;; - *-unknown) - # Make sure to match an already-canonicalized machine name. + pentium4-*) + cpu=i786 ;; + pc98-*) + cpu=i386 + ;; + ppc-* | ppcbe-*) + cpu=powerpc + ;; + ppcle-* | powerpclittle-*) + cpu=powerpcle + ;; + ppc64-*) + cpu=powerpc64 + ;; + ppc64le-* | powerpc64little-*) + cpu=powerpc64le + ;; + sb1-*) + cpu=mipsisa64sb1 + ;; + sb1el-*) + cpu=mipsisa64sb1el + ;; + sh5e[lb]-*) + cpu=`echo "$cpu" | sed 's/^\(sh.\)e\(.\)$/\1\2e/'` + ;; + spur-*) + cpu=spur + ;; + strongarm-* | thumb-*) + cpu=arm + ;; + tx39-*) + cpu=mipstx39 + ;; + tx39el-*) + cpu=mipstx39el + ;; + x64-*) + cpu=x86_64 + ;; + xscale-* | xscalee[bl]-*) + cpu=`echo "$cpu" | sed 's/^xscale/arm/'` + ;; + arm64-* | aarch64le-*) + cpu=aarch64 + ;; + + # Recognize the canonical CPU Types that limit and/or modify the + # company names they are paired with. + cr16-*) + basic_os=${basic_os:-elf} + ;; + crisv32-* | etraxfs*-*) + cpu=crisv32 + vendor=axis + ;; + cris-* | etrax*-*) + cpu=cris + vendor=axis + ;; + crx-*) + basic_os=${basic_os:-elf} + ;; + neo-tandem) + cpu=neo + vendor=tandem + ;; + nse-tandem) + cpu=nse + vendor=tandem + ;; + nsr-tandem) + cpu=nsr + vendor=tandem + ;; + nsv-tandem) + cpu=nsv + vendor=tandem + ;; + nsx-tandem) + cpu=nsx + vendor=tandem + ;; + mipsallegrexel-sony) + cpu=mipsallegrexel + vendor=sony + ;; + tile*-*) + basic_os=${basic_os:-linux-gnu} + ;; + *) - echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 - exit 1 + # Recognize the canonical CPU types that are allowed with any + # company name. + case $cpu in + 1750a | 580 \ + | a29k \ + | aarch64 | aarch64_be \ + | abacus \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] \ + | alphapca5[67] | alpha64pca5[67] \ + | am33_2.0 \ + | amdgcn \ + | arc | arceb | arc32 | arc64 \ + | arm | arm[lb]e | arme[lb] | armv* \ + | avr | avr32 \ + | asmjs \ + | ba \ + | be32 | be64 \ + | bfin | bpf | bs2000 \ + | c[123]* | c30 | [cjt]90 | c4x \ + | c8051 | clipper | craynv | csky | cydra \ + | d10v | d30v | dlx | dsp16xx \ + | e2k | elxsi | epiphany \ + | f30[01] | f700 | fido | fr30 | frv | ft32 | fx80 \ + | h8300 | h8500 \ + | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | hexagon \ + | i370 | i*86 | i860 | i960 | ia16 | ia64 \ + | ip2k | iq2000 \ + | k1om \ + | le32 | le64 \ + | lm32 \ + | loongarch32 | loongarch64 \ + | m32c | m32r | m32rle \ + | m5200 | m68000 | m680[012346]0 | m68360 | m683?2 | m68k \ + | m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x \ + | m88110 | m88k | maxq | mb | mcore | mep | metag \ + | microblaze | microblazeel \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64eb | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa32r3 | mipsisa32r3el \ + | mipsisa32r5 | mipsisa32r5el \ + | mipsisa32r6 | mipsisa32r6el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64r3 | mipsisa64r3el \ + | mipsisa64r5 | mipsisa64r5el \ + | mipsisa64r6 | mipsisa64r6el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipsr5900 | mipsr5900el \ + | mipstx39 | mipstx39el \ + | mmix \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nds32 | nds32le | nds32be \ + | nfp \ + | nios | nios2 | nios2eb | nios2el \ + | none | np1 | ns16k | ns32k | nvptx \ + | open8 \ + | or1k* \ + | or32 \ + | orion \ + | picochip \ + | pdp10 | pdp11 | pj | pjl | pn | power \ + | powerpc | powerpc64 | powerpc64le | powerpcle | powerpcspe \ + | pru \ + | pyramid \ + | riscv | riscv32 | riscv32be | riscv64 | riscv64be \ + | rl78 | romp | rs6000 | rx \ + | s390 | s390x \ + | score \ + | sh | shl \ + | sh[1234] | sh[24]a | sh[24]ae[lb] | sh[23]e | she[lb] | sh[lb]e \ + | sh[1234]e[lb] | sh[12345][lb]e | sh[23]ele | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet \ + | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v | sv1 | sx* \ + | spu \ + | tahoe \ + | thumbv7* \ + | tic30 | tic4x | tic54x | tic55x | tic6x | tic80 \ + | tron \ + | ubicom32 \ + | v70 | v850 | v850e | v850e1 | v850es | v850e2 | v850e2v3 \ + | vax \ + | visium \ + | w65 \ + | wasm32 | wasm64 \ + | we32k \ + | x86 | x86_64 | xc16x | xgate | xps100 \ + | xstormy16 | xtensa* \ + | ymp \ + | z8k | z80) + ;; + + *) + echo Invalid configuration \`"$1"\': machine \`"$cpu-$vendor"\' not recognized 1>&2 + exit 1 + ;; + esac ;; esac # Here we canonicalize certain aliases for manufacturers. -case $basic_machine in - *-digital*) - basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` +case $vendor in + digital*) + vendor=dec ;; - *-commodore*) - basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + commodore*) + vendor=cbm ;; *) ;; @@ -1321,200 +1306,215 @@ esac # Decode manufacturer-specific aliases for certain operating systems. -if [ x"$os" != x"" ] +if test x$basic_os != x then + +# First recognize some ad-hoc cases, or perhaps split kernel-os, or else just +# set os. +case $basic_os in + gnu/linux*) + kernel=linux + os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'` + ;; + os2-emx) + kernel=os2 + os=`echo "$basic_os" | sed -e 's|os2-emx|emx|'` + ;; + nto-qnx*) + kernel=nto + os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'` + ;; + *-*) + # shellcheck disable=SC2162 + saved_IFS=$IFS + IFS="-" read kernel os <&2 - exit 1 + # No normalization, but not necessarily accepted, that comes below. ;; esac + else # Here we handle the default operating systems that come with various machines. @@ -1527,261 +1527,363 @@ else # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. -case $basic_machine in +kernel= +case $cpu-$vendor in score-*) - os=-elf + os=elf ;; spu-*) - os=-elf + os=elf ;; *-acorn) - os=-riscix1.2 + os=riscix1.2 ;; arm*-rebel) - os=-linux + kernel=linux + os=gnu ;; arm*-semi) - os=-aout + os=aout ;; c4x-* | tic4x-*) - os=-coff + os=coff + ;; + c8051-*) + os=elf + ;; + clipper-intergraph) + os=clix ;; hexagon-*) - os=-elf + os=elf ;; tic54x-*) - os=-coff + os=coff ;; tic55x-*) - os=-coff + os=coff ;; tic6x-*) - os=-coff + os=coff ;; # This must come before the *-dec entry. pdp10-*) - os=-tops20 + os=tops20 ;; pdp11-*) - os=-none + os=none ;; *-dec | vax-*) - os=-ultrix4.2 + os=ultrix4.2 ;; m68*-apollo) - os=-domain + os=domain ;; i386-sun) - os=-sunos4.0.2 + os=sunos4.0.2 ;; m68000-sun) - os=-sunos3 + os=sunos3 ;; m68*-cisco) - os=-aout + os=aout ;; mep-*) - os=-elf + os=elf ;; mips*-cisco) - os=-elf + os=elf ;; mips*-*) - os=-elf - ;; - or1k-*) - os=-elf + os=elf ;; or32-*) - os=-coff + os=coff ;; *-tti) # must be before sparc entry or we get the wrong os. - os=-sysv3 + os=sysv3 ;; sparc-* | *-sun) - os=-sunos4.1.1 + os=sunos4.1.1 + ;; + pru-*) + os=elf ;; *-be) - os=-beos - ;; - *-haiku) - os=-haiku + os=beos ;; *-ibm) - os=-aix + os=aix ;; *-knuth) - os=-mmixware + os=mmixware ;; *-wec) - os=-proelf + os=proelf ;; *-winbond) - os=-proelf + os=proelf ;; *-oki) - os=-proelf + os=proelf ;; *-hp) - os=-hpux + os=hpux ;; *-hitachi) - os=-hiux + os=hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) - os=-sysv + os=sysv ;; *-cbm) - os=-amigaos + os=amigaos ;; *-dg) - os=-dgux + os=dgux ;; *-dolphin) - os=-sysv3 + os=sysv3 ;; m68k-ccur) - os=-rtu + os=rtu ;; m88k-omron*) - os=-luna - ;; - *-next ) - os=-nextstep - ;; - *-sequent) - os=-ptx - ;; - *-crds) - os=-unos - ;; - *-ns) - os=-genix - ;; - i370-*) - os=-mvs + os=luna ;; *-next) - os=-nextstep3 + os=nextstep + ;; + *-sequent) + os=ptx + ;; + *-crds) + os=unos + ;; + *-ns) + os=genix + ;; + i370-*) + os=mvs ;; *-gould) - os=-sysv + os=sysv ;; *-highlevel) - os=-bsd + os=bsd ;; *-encore) - os=-bsd + os=bsd ;; *-sgi) - os=-irix + os=irix ;; *-siemens) - os=-sysv4 + os=sysv4 ;; *-masscomp) - os=-rtu + os=rtu ;; f30[01]-fujitsu | f700-fujitsu) - os=-uxpv + os=uxpv ;; *-rom68k) - os=-coff + os=coff ;; *-*bug) - os=-coff + os=coff ;; *-apple) - os=-macos + os=macos ;; *-atari*) - os=-mint + os=mint + ;; + *-wrs) + os=vxworks ;; *) - os=-none + os=none ;; esac + fi +# Now, validate our (potentially fixed-up) OS. +case $os in + # Sometimes we do "kernel-libc", so those need to count as OSes. + musl* | newlib* | relibc* | uclibc*) + ;; + # Likewise for "kernel-abi" + eabi* | gnueabi*) + ;; + # VxWorks passes extra cpu info in the 4th filed. + simlinux | simwindows | spe) + ;; + # Now accept the basic system types. + # The portable systems comes first. + # Each alternative MUST end in a * to match a version number. + gnu* | android* | bsd* | mach* | minix* | genix* | ultrix* | irix* \ + | *vms* | esix* | aix* | cnk* | sunos | sunos[34]* \ + | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \ + | sym* | plan9* | psp* | sim* | xray* | os68k* | v88r* \ + | hiux* | abug | nacl* | netware* | windows* \ + | os9* | macos* | osx* | ios* \ + | mpw* | magic* | mmixware* | mon960* | lnews* \ + | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \ + | aos* | aros* | cloudabi* | sortix* | twizzler* \ + | nindy* | vxsim* | vxworks* | ebmon* | hms* | mvs* \ + | clix* | riscos* | uniplus* | iris* | isc* | rtu* | xenix* \ + | mirbsd* | netbsd* | dicos* | openedition* | ose* \ + | bitrig* | openbsd* | secbsd* | solidbsd* | libertybsd* | os108* \ + | ekkobsd* | freebsd* | riscix* | lynxos* | os400* \ + | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \ + | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \ + | udi* | lites* | ieee* | go32* | aux* | hcos* \ + | chorusrdb* | cegcc* | glidix* | serenity* \ + | cygwin* | msys* | pe* | moss* | proelf* | rtems* \ + | midipix* | mingw32* | mingw64* | mint* \ + | uxpv* | beos* | mpeix* | udk* | moxiebox* \ + | interix* | uwin* | mks* | rhapsody* | darwin* \ + | openstep* | oskit* | conix* | pw32* | nonstopux* \ + | storm-chaos* | tops10* | tenex* | tops20* | its* \ + | os2* | vos* | palmos* | uclinux* | nucleus* | morphos* \ + | scout* | superux* | sysv* | rtmk* | tpf* | windiss* \ + | powermax* | dnix* | nx6 | nx7 | sei* | dragonfly* \ + | skyos* | haiku* | rdos* | toppers* | drops* | es* \ + | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \ + | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \ + | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx* | zephyr* \ + | fiwix* ) + ;; + # This one is extra strict with allowed versions + sco3.2v2 | sco3.2v[4-9]* | sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + ;; + none) + ;; + *) + echo Invalid configuration \`"$1"\': OS \`"$os"\' not recognized 1>&2 + exit 1 + ;; +esac + +# As a final step for OS-related things, validate the OS-kernel combination +# (given a valid OS), if there is a kernel. +case $kernel-$os in + linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* \ + | linux-musl* | linux-relibc* | linux-uclibc* ) + ;; + uclinux-uclibc* ) + ;; + -dietlibc* | -newlib* | -musl* | -relibc* | -uclibc* ) + # These are just libc implementations, not actual OSes, and thus + # require a kernel. + echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2 + exit 1 + ;; + kfreebsd*-gnu* | kopensolaris*-gnu*) + ;; + vxworks-simlinux | vxworks-simwindows | vxworks-spe) + ;; + nto-qnx*) + ;; + os2-emx) + ;; + *-eabi* | *-gnueabi*) + ;; + -*) + # Blank kernel with real OS is always fine. + ;; + *-*) + echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2 + exit 1 + ;; +esac + # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. -vendor=unknown -case $basic_machine in - *-unknown) - case $os in - -riscix*) +case $vendor in + unknown) + case $cpu-$os in + *-riscix*) vendor=acorn ;; - -sunos*) + *-sunos*) vendor=sun ;; - -cnk*|-aix*) + *-cnk* | *-aix*) vendor=ibm ;; - -beos*) + *-beos*) vendor=be ;; - -hpux*) + *-hpux*) vendor=hp ;; - -mpeix*) + *-mpeix*) vendor=hp ;; - -hiux*) + *-hiux*) vendor=hitachi ;; - -unos*) + *-unos*) vendor=crds ;; - -dgux*) + *-dgux*) vendor=dg ;; - -luna*) + *-luna*) vendor=omron ;; - -genix*) + *-genix*) vendor=ns ;; - -mvs* | -opened*) + *-clix*) + vendor=intergraph + ;; + *-mvs* | *-opened*) vendor=ibm ;; - -os400*) + *-os400*) vendor=ibm ;; - -ptx*) + s390-* | s390x-*) + vendor=ibm + ;; + *-ptx*) vendor=sequent ;; - -tpf*) + *-tpf*) vendor=ibm ;; - -vxsim* | -vxworks* | -windiss*) + *-vxsim* | *-vxworks* | *-windiss*) vendor=wrs ;; - -aux*) + *-aux*) vendor=apple ;; - -hms*) + *-hms*) vendor=hitachi ;; - -mpw* | -macos*) + *-mpw* | *-macos*) vendor=apple ;; - -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + *-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*) vendor=atari ;; - -vos*) + *-vos*) vendor=stratus ;; esac - basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac -echo $basic_machine$os +echo "$cpu-$vendor-${kernel:+$kernel-}$os" exit # Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) +# eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" diff --git a/autoconf/configure.ac b/autoconf/configure.ac index b5cee7f4..bde64a1b 100644 --- a/autoconf/configure.ac +++ b/autoconf/configure.ac @@ -1,307 +1,25 @@ dnl To generate a new top level configure script from this autoconf directory dnl 1. aclocal dnl 2. autoconf -o ../configure -dnl If you run into "configure.ac:15: error: possibly undefined macro: AC_MSG_ERROR", -dnl try: -dnl autoreconf -fi AC_INIT([Trick],[17+]) AC_LANG(C++) AC_CONFIG_AUX_DIR([autoconf]) - -AC_DEFUN([AX_LLVM_HOME],[ - AC_ARG_WITH([llvm], - AS_HELP_STRING([--with-llvm@<:@=DIR@:>@], [LLVM root directory]), - [LLVM_HOME="$withval" - AC_PATH_PROG(LLVM_CONFIG, llvm-config, no-llvm-config, "$LLVM_HOME/bin") - AS_IF([test "$ac_cv_path_LLVM_CONFIG" = "no-llvm-config"],AC_MSG_ERROR([could not find llvm-config]),[]) - ], - [ - AC_PATH_PROG(LLVM_CONFIG, llvm-config, no-llvm-config, "/bin:/usr/bin:/usr/local/bin:/sw/bin:/usr/local/opt/llvm/bin") - AS_IF([test "$ac_cv_path_LLVM_CONFIG" = "no-llvm-config"],AC_MSG_ERROR([could not find llvm-config]),[]) - LLVM_HOME=`$LLVM_CONFIG --prefix` - ] - ) -]) - -AC_DEFUN([AX_HDF5_HOME],[ - AC_ARG_WITH([hdf5], - AS_HELP_STRING([--with-hdf5@<:@=DIR@:>@], [HDF5 root directory]), - [HDF5_HOME="$withval" - AS_IF([test "$HDF5_HOME" = "yes"], - AC_CHECK_HEADER(hdf5.h,[HDF5_HOME="/usr"],AC_MSG_ERROR([could not find hdf5.h])), - AS_IF([test "$HDF5_HOME" = "no"],[HDF5_HOME=""], - AC_CHECK_FILE([$HDF5_HOME/include/hdf5.h], - [], - AC_MSG_ERROR([could not find $HDF5_HOME/include/hdf5.h]) - ) - ) - )], - [ - AC_CHECK_HEADER(hdf5.h, [HDF5_HOME="/usr"], [HDF5_HOME=""]) - ] - ) - AS_IF([test "$HDF5_HOME" != ""], - [ - LDFLAGS="${LDFLAGS} -L${HDF5_HOME}/lib" - AC_CHECK_LIB(hdf5, main, [],AC_MSG_ERROR([could not find libhdf5])) - ] - [] - ) - AC_SUBST([HDF5_HOME]) -]) - -AC_DEFUN([AX_GSL_HOME],[ - AC_ARG_WITH([gsl], - AS_HELP_STRING([--with-gsl@<:@=DIR@:>@], [GSL root directory]), - [GSL_HOME="$withval" - AS_IF([test "$GSL_HOME" = "yes"], - AC_CHECK_HEADER(gsl/gsl_rng.h,[GSL_HOME="/usr"],AC_MSG_ERROR([could not find gsl/gsl_rng.h])), - AS_IF([test "$GSL_HOME" = "no"],[GSL_HOME=""], - AC_CHECK_FILE([$GSL_HOME/include/gsl], - [], - AC_MSG_ERROR([could not find $GSL_HOME/include/gsl]) - ) - ) - )], - [AC_CHECK_HEADER(gsl/gsl_rng.h, [GSL_HOME="/usr"], [GSL_HOME=""])] - ) - AS_IF([test "$GSL_HOME" != ""], - [ - LDFLAGS="${LDFLAGS} -L${GSL_HOME}/lib" - AC_CHECK_LIB(gsl, main, [],AC_MSG_ERROR([could not find libgsl]),[-lgslcblas]) - ], - [] - ) - AC_SUBST([GSL_HOME]) -]) - -AC_DEFUN([AX_GTEST_HOME],[ - AC_ARG_WITH([gtest], - AS_HELP_STRING([--with-gtest@<:@=DIR@:>@], [GTEST root directory]), - [GTEST_HOME="$withval" - AS_IF([test "$GTEST_HOME" = "yes"], - AC_CHECK_HEADER(gtest/gtest.h,[GTEST_HOME="/usr"],AC_MSG_ERROR([could not find gtest/gtest.h])), - AS_IF([test "$GTEST_HOME" = "no"],[GTEST_HOME=""], - AC_CHECK_FILE([$GTEST_HOME/include/gtest], - [], - AC_MSG_ERROR([could not find $GTEST_HOME/include/gtest]) - ) - ) - )], - [AC_CHECK_HEADER(gtest/gtest.h, [GTEST_HOME="/usr"], [GTEST_HOME=""])] - ) - AC_SUBST([GTEST_HOME]) -]) - -AC_DEFUN([AX_CIVETWEB_HOME],[ - AC_ARG_WITH([civetweb], - AS_HELP_STRING([--with-civetweb@<:@=DIR@:>@], - [CIVETWEB root directory]), - # --with option was provided. - [CIVETWEB_HOME="$withval" - USE_CIVETWEB="0" - # check whether directory arg was also provided. - AS_IF([test "$CIVETWEB_HOME" = "yes"], - AC_CHECK_HEADER(civetweb.h, - [CIVETWEB_HOME="/usr"; USE_CIVETWEB="1"], - AC_MSG_ERROR([could not find civetweb.h])), - # else check whether --without-civet or --with-civet=no specified. - AS_IF([test "$CIVETWEB_HOME" = "no"], - [CIVETWEB_HOME=""], - # else --with-civet was provided with a directory path. - AC_CHECK_FILES([$CIVETWEB_HOME/include/civetweb.h $CIVETWEB_HOME/lib/libcivetweb.a], - [USE_CIVETWEB="1"], - AC_MSG_ERROR([Could not find all of the civetweb files.])) - )) - ], - # --with option not provided. - [AC_CHECK_HEADER(civetweb.h, - [CIVETWEB_HOME="/usr"; USE_CIVETWEB="1"], - [CIVETWEB_HOME=""; USE_CIVETWEB="0"]) - ] - ) - AC_SUBST([CIVETWEB_HOME]) - AC_SUBST([USE_CIVETWEB]) -]) - - -AC_DEFUN([AX_SWIG_BIN],[ - AC_ARG_WITH([swig], - [AS_HELP_STRING([--with-swig@<:@=DIR@:>@], [path of directory containing the SWIG executable.])], - [ - TEMP_PATH="${PATH}" - PATH="$withval:${PATH}" - AX_PKG_SWIG($1, [], [AC_MSG_ERROR([Trick requires SWIG version >= 2.0])]) - PATH="${TEMP_PATH}" - ], - [AX_PKG_SWIG($1, [], [AC_MSG_ERROR([Trick requires SWIG version >= 2.0])])] - ) -]) - -AC_DEFUN([AX_UDUNITS_HOME],[ - AC_ARG_WITH([udunits], - AS_HELP_STRING([--with-udunits@<:@=DIR@:>@], [UDUnits root directory]), - [UDUNITS_HOME="$withval"], - [UDUNITS_HOME=""] - ) - AC_SUBST([UDUNITS_HOME]) -]) - -dnl SOURCE: https://stackoverflow.com/a/59191148 - -dnl NA_HELP_STRINGS(list1, help1[, list2, help2[, ... listN, helpN]]) -dnl ************************************************************************** -dnl -dnl Similar to `AS_HELP_STRING()`, but with support for multiple strings, each -dnl one associated with one or more options -dnl -dnl From: https://github.com/madmurphy/not-autotools -dnl -dnl ************************************************************************** -m4_define([NA_HELP_STRINGS], - [m4_if(m4_count($1), [1], - [m4_if([$#], [0], [], [$#], [1], - [m4_text_wrap($1, [ ])], - [AS_HELP_STRING(m4_normalize($1), [$2])m4_if([$#], [2], [], [m4_newline()NA_HELP_STRINGS(m4_shift2($@))])])], - [m4_text_wrap(m4_argn(1, $1)[,], [ ])m4_newline()NA_HELP_STRINGS(m4_dquote(m4_shift($1))m4_if([$#], [1], [], [, m4_shift($@)]))])]) - - - -dnl test if want to prepend /usr/local/bin to PATH -dnl AC_ARG_WITH (package, help-string, [action-if-given], [action-if-not-given]) -AC_DEFUN( - [AX_PREPEND_PATH], - [AC_ARG_WITH( - [prepend-path], - [NA_HELP_STRINGS( -[--without-prepend-path], [do not prepend to path (this is default)], [--with-prepend-path@<:@=DIR@:>@], [specify a directory to prepend to PATH (default is /usr/local/bin)])], - [AS_IF( - [test "x${with_prepend_path}" = xyes], - [PATH="/usr/local/bin:${PATH}"], - [AS_IF( - [test "x${with_prepend_path}" != xno], - [PATH="${withval}:${PATH}"], - [] - )] - )], - [] - )] -) - - -dnl test if we want to use java, default to yes -AC_DEFUN([AX_JAVA],[ - AC_ARG_ENABLE([java], - AS_HELP_STRING([--enable-java], [use java (default is yes)]), - AS_IF([test "x$enable_java" = xyes], [USE_JAVA="1"], [USE_JAVA="0"]), - [USE_JAVA="1"] - ) - AC_SUBST([USE_JAVA]) - AS_IF([test "$USE_JAVA" = "1"],[ - AC_PROG_AWK - AX_PROG_JAVA_CC(javac) - JAVA_VER=`$JAVA_CC -version 2>&1 | $ac_cv_path_PERL -ne 'print $& if /\d+(\.\d+)?/'` - AC_MSG_CHECKING([$JAVA_CC version >= 1.8]) - AX_COMPARE_VERSION([$JAVA_VER],[ge],[1.8], [AC_MSG_RESULT([yes])], - [AC_MSG_RESULT([no]) - AC_MSG_ERROR([Trick requires javac version >= 1.8]) - ]) - AS_IF([test "$TRICK_OFFLINE" = "0"], [ - AC_PATH_PROG(MVN, mvn, nomvn) - AS_IF([test "$ac_cv_path_MVN" = "nomvn"],AC_MSG_ERROR([could not find maven]),[]) - ], []) - ],[]) -]) - -dnl test if we want to use er7_utils, default to yes -AC_DEFUN([AX_ER7_UTILS],[ - AC_ARG_ENABLE([er7utils], - AS_HELP_STRING([--enable-er7utils], [use er7_utils (default is yes)]), - AS_IF([test "x$enable_er7utils" = xyes], [USE_ER7_UTILS="1"], [USE_ER7_UTILS="0"]), - [USE_ER7_UTILS="1"] - ) - AC_SUBST([USE_ER7_UTILS]) -]) - -dnl if fermi-ware directory exists, test for motif. -AC_DEFUN([AX_JSC_DIRS],[ - AC_CHECK_FILE([trick_source/data_products/fermi-ware], - [ - AC_CHECK_HEADER(Xm/Xm.h, [MOTIF_HOME="/usr"], - AC_CHECK_FILE(/usr/local/include/Xm/Xm.h, [MOTIF_HOME="/usr/local"], - AC_CHECK_FILE(/sw/include/Xm/Xm.h, [MOTIF_HOME="/sw"],AC_MSG_ERROR([could not find Xm/Xm.h])))) - ], - [ - MOTIF_HOME="" - ] - ) - AC_SUBST([MOTIF_HOME]) -]) - -AC_DEFUN([AX_GCC_VERSION], [ - GCC_VERSION="" - AS_IF([test "x$GCC" = "xyes"],[ - AS_IF([test "x$ax_gcc_version_option" != "xno"],[ - AC_CACHE_CHECK([gcc version],[ax_cv_gcc_version],[ - ax_cv_gcc_version="`$CC -dumpversion`" - AS_IF([test "x$ax_cv_gcc_version" = "x"],[ - ax_cv_gcc_version="" - ]) - ]) - GCC_VERSION=$ax_cv_gcc_version - ]) - ]) - AC_SUBST([GCC_VERSION]) -]) +AC_CONFIG_MACRO_DIRS([m4]) dnl get the host and build. AC_CANONICAL_HOST AC_CANONICAL_BUILD -dnl AC_CANONICAL_HOST provides platform. MacOSX is diverging... have to do special things -ON_MAC=no -case "${host_os}" in - darwin*) - ON_MAC=yes - ;; - *) - ;; -esac - - -dnl add extra paths to find xml headers and X headers on the mac. -AS_IF([test "$ON_MAC" = "yes"], -[ - AC_PATH_PROG(XCRUN, xcrun, noxcrun) - AS_IF([test "$ac_cv_path_XCRUN" = "norun"],AC_MSG_ERROR([could not find xcrun - install Xcode command line tools]),[]) - XCODE_SDK_PATH=`$XCRUN --show-sdk-path` - XTRAINCPATHS="-I/usr/X11/include -I${XCODE_SDK_PATH}/usr/include -I${XCODE_SDK_PATH}/usr/include/libxml2" -], -[ - XTRAINCPATHS="-I/usr/include/libxml2/" -]) -CFLAGS="$CFLAGS $XTRAINCPATHS" -CPPFLAGS="$CPPFLAGS $XTRAINCPATHS" +dnl check if we are on a mac +TR_MAC_DARWIN() +dnl add x11 libs to environment +TR_X11() dnl look for X windows libraries and headers we need to compile dnl these checks must be done before we force 32bit mode. -AC_PATH_X -AS_IF([test "$no_x" = "yes"], - [ - USE_X_WINDOWS=0 - ], - [ - USE_X_WINDOWS=1 - AS_IF([test "x$x_includes" = "x"],[],[X_INCLUDE_DIR=-I$x_includes]) - AS_IF([test "x$x_libraries" = "x"],[],[X_LIB_DIR=-L$x_libraries]) - AC_CHECK_HEADER([X11/Intrinsic.h],[],AC_MSG_ERROR([could not find libxt development headers])) - AX_JSC_DIRS([]) - ] -) -AC_SUBST([USE_X_WINDOWS]) -AC_SUBST([X_LIB_DIR]) +TR_XWINDOWS() dnl TODO Need to check 64bit only! AC_CHECK_LIB(xml2, main, @@ -377,7 +95,7 @@ AC_PROG_CC AC_PROG_CXX dnl do not test gcc version on mac. clang as gcc will return version and it's not >= 4.8 -AS_IF([test "$ON_MAC" = "no"],[AX_GCC_VERSION],[]) +AS_IF([test "$ON_MAC" = "no"],[TR_GCC_VERSION],[]) dnl if the compiler is gcc, test for gcc >= 4.8 AS_IF([test "x$GCC_VERSION" = "x"],[], [AC_MSG_CHECKING([gcc version >= 4.8]) @@ -394,7 +112,7 @@ AC_PATH_PROG(TEE, tee, notee) AS_IF([test "$ac_cv_path_TEE" = "notee"],AC_MSG_ERROR([could not find tee]),[]) AC_PATH_PROG(LD, ld, nold) AS_IF([test "$ac_cv_path_LD" = "nold"],AC_MSG_ERROR([could not find ld]),[]) -AC_PROG_LEX +AC_PROG_LEX([noyywrap]) AS_IF([test "x$LEX" = "x:"],AC_MSG_ERROR([could not find flex]),[]) AC_PATH_PROG(BISON, bison, nobison) AS_IF([test "$ac_cv_path_BISON" = "nobison"],AC_MSG_ERROR([could not find bison]),[]) @@ -463,21 +181,22 @@ AX_COMPARE_VERSION( PYTHON_CPPFLAGS=`${PYTHON_CONFIG} --includes | sed 's/-I/-isystem/g'` PYTHON_LIBS=`${PYTHON_LIBS_COMMAND} | tr '\r\n' ' '` + AC_SUBST([PYTHON_CPPFLAGS]) AC_SUBST([PYTHON_LIBS]) AC_SUBST([PYTHON_EXTRA_LIBS]) -AX_PREPEND_PATH +TR_PREPEND_PATH() AC_PATH_PROG(GNUPLOT, gnuplot, nognuplot) AS_IF([test "$ac_cv_path_GNUPLOT" = "nognuplot"],AC_MSG_NOTICE([could not find gnuplot]),[]) -AX_SWIG_BIN([2.0]) -AX_JAVA +TR_SWIG_BIN([2.0]) +TR_JAVA AX_PTHREAD() AX_PROG_PERL_MODULES( Text::Balanced ,[],AC_MSG_ERROR([could not find perl modules Text::Balanced])) AX_PROG_PERL_MODULES( Digest::MD5,[],AC_MSG_ERROR([could not find perl module Digest::MD5])) dnl process the optional --with-llvm command line arguments -AX_LLVM_HOME([]) +TR_LLVM_HOME([]) LLVM_LIB_DIR=`$LLVM_CONFIG --libdir` LLVM_BIN_DIR=`$LLVM_CONFIG --bindir` LLVM_INCLUDE_DIR=`$LLVM_CONFIG --includedir` @@ -514,19 +233,11 @@ AC_CHECK_FILE([$LLVM_LIB_DIR/libclangFrontend.a], ) ) +AC_CHECK_FILE([$LLVM_LIB_DIR/libclangSupport.a],[ICG_CLANGLIBS="$ICG_CLANGLIBS -lclangSupport"],[]) + AC_SUBST([ICG_CLANGLIBS]) - -AC_DEFUN([AX_CLANG_VERSION], [ - CLANG_VERSION="" - ax_cv_clang_version="`$CLANG --version | grep "version" | sed "s/.*version \([0-9]*\.[0-9]*\.[0-9]*\).*/\1/"`" - AS_IF([test "x$ax_cv_clang_version" = "x"],[ - ax_cv_clang_version="" - ]) - CLANG_VERSION=$ax_cv_clang_version - AC_SUBST([CLANG_VERSION]) -]) -AX_CLANG_VERSION +TR_CLANG_VERSION dnl if llvm/clang, test for version >= 3.4.2 AS_IF([test "x$CLANG_VERSION" = "x"],[], [AC_MSG_CHECKING([clang version >= 3.4.2]) @@ -539,7 +250,7 @@ AS_IF([test "x$CLANG_VERSION" = "x"],[], AX_CHECK_ZLIB([],AC_MSG_ERROR([could not find zlib])) dnl look for udunits in /usr/include and /usr/include/udunits2 -AX_UDUNITS_HOME([]) +TR_UDUNITS_HOME([]) AS_IF([test "$UDUNITS_HOME" = ""], [ AC_CHECK_HEADER([udunits2.h], @@ -571,11 +282,11 @@ AC_SUBST([UDUNITS_LDFLAGS]) AC_SUBST([UDUNITS_EXCLUDE]) dnl process the other optional command line arguments -AX_HDF5_HOME([]) -AX_GSL_HOME([]) -AX_GTEST_HOME([]) -AX_CIVETWEB_HOME([]) -AX_ER7_UTILS([]) +TR_HDF5_HOME([]) +TR_GSL_HOME([]) +TR_GTEST_HOME([]) +TR_CIVETWEB_HOME([]) +TR_ER7_UTILS([]) AC_CONFIG_FILES([share/trick/makefiles/config_user.mk]) AC_OUTPUT diff --git a/autoconf/install-sh b/autoconf/install-sh index 377bb868..ec298b53 100755 --- a/autoconf/install-sh +++ b/autoconf/install-sh @@ -1,7 +1,7 @@ #!/bin/sh # install - install a program, script, or datafile -scriptversion=2011-11-20.07; # UTC +scriptversion=2020-11-14.01; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the @@ -41,19 +41,15 @@ scriptversion=2011-11-20.07; # UTC # This script is compatible with the BSD install script, but was written # from scratch. +tab=' ' nl=' ' -IFS=" "" $nl" +IFS=" $tab$nl" -# set DOITPROG to echo to test this script +# Set DOITPROG to "echo" to test this script. -# Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} -if test -z "$doit"; then - doit_exec=exec -else - doit_exec=$doit -fi +doit_exec=${doit:-exec} # Put in absolute file names if you don't have them in your path; # or use environment vars. @@ -68,22 +64,16 @@ mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} -posix_glob='?' -initialize_posix_glob=' - test "$posix_glob" != "?" || { - if (set -f) 2>/dev/null; then - posix_glob= - else - posix_glob=: - fi - } -' - posix_mkdir= # Desired mode of installed file. mode=0755 +# Create dirs (including intermediate dirs) using mode 755. +# This is like GNU 'install' as of coreutils 8.32 (2020). +mkdir_umask=22 + +backupsuffix= chgrpcmd= chmodcmd=$chmodprog chowncmd= @@ -97,7 +87,7 @@ dir_arg= dst_arg= copy_on_change=false -no_target_directory= +is_target_a_directory=possibly usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE @@ -114,18 +104,28 @@ Options: --version display version info and exit. -c (ignored) - -C install only if different (preserve the last data modification time) + -C install only if different (preserve data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. + -p pass -p to $cpprog. -s $stripprog installed files. + -S SUFFIX attempt to back up existing files, with suffix SUFFIX. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG + +By default, rm is invoked with -f; when overridden with RMPROG, +it's up to you to specify -f if you want it. + +If -S is not specified, no backups are attempted. + +Email bug reports to bug-automake@gnu.org. +Automake home page: https://www.gnu.org/software/automake/ " while test $# -ne 0; do @@ -137,46 +137,62 @@ while test $# -ne 0; do -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" - shift;; + shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 - case $mode in - *' '* | *' '* | *' -'* | *'*'* | *'?'* | *'['*) - echo "$0: invalid mode: $mode" >&2 - exit 1;; - esac - shift;; + case $mode in + *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; -o) chowncmd="$chownprog $2" - shift;; + shift;; + + -p) cpprog="$cpprog -p";; -s) stripcmd=$stripprog;; - -t) dst_arg=$2 - # Protect names problematic for 'test' and other utilities. - case $dst_arg in - -* | [=\(\)!]) dst_arg=./$dst_arg;; - esac - shift;; + -S) backupsuffix="$2" + shift;; - -T) no_target_directory=true;; + -t) + is_target_a_directory=always + dst_arg=$2 + # Protect names problematic for 'test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + shift;; + + -T) is_target_a_directory=never;; --version) echo "$0 $scriptversion"; exit $?;; - --) shift - break;; + --) shift + break;; - -*) echo "$0: invalid option: $1" >&2 - exit 1;; + -*) echo "$0: invalid option: $1" >&2 + exit 1;; *) break;; esac shift done +# We allow the use of options -d and -T together, by making -d +# take the precedence; this is for compatibility with GNU install. + +if test -n "$dir_arg"; then + if test -n "$dst_arg"; then + echo "$0: target directory not allowed when installing a directory." >&2 + exit 1 + fi +fi + if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. @@ -207,6 +223,15 @@ if test $# -eq 0; then exit 0 fi +if test -z "$dir_arg"; then + if test $# -gt 1 || test "$is_target_a_directory" = always; then + if test ! -d "$dst_arg"; then + echo "$0: $dst_arg: Is not a directory." >&2 + exit 1 + fi + fi +fi + if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 @@ -223,16 +248,16 @@ if test -z "$dir_arg"; then *[0-7]) if test -z "$stripcmd"; then - u_plus_rw= + u_plus_rw= else - u_plus_rw='% 200' + u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then - u_plus_rw= + u_plus_rw= else - u_plus_rw=,u+rw + u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac @@ -250,6 +275,10 @@ do dstdir=$dst test -d "$dstdir" dstdir_status=$? + # Don't chown directories that already exist. + if test $dstdir_status = 0; then + chowncmd="" + fi else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command @@ -266,178 +295,148 @@ do fi dst=$dst_arg - # If destination is a directory, append the input filename; won't work - # if double slashes aren't ignored. + # If destination is a directory, append the input filename. if test -d "$dst"; then - if test -n "$no_target_directory"; then - echo "$0: $dst_arg: Is a directory" >&2 - exit 1 + if test "$is_target_a_directory" = never; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 fi dstdir=$dst - dst=$dstdir/`basename "$src"` + dstbase=`basename "$src"` + case $dst in + */) dst=$dst$dstbase;; + *) dst=$dst/$dstbase;; + esac dstdir_status=0 else - # Prefer dirname, but fall back on a substitute if dirname fails. - dstdir=` - (dirname "$dst") 2>/dev/null || - expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$dst" : 'X\(//\)[^/]' \| \ - X"$dst" : 'X\(//\)$' \| \ - X"$dst" : 'X\(/\)' \| . 2>/dev/null || - echo X"$dst" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q' - ` - + dstdir=`dirname "$dst"` test -d "$dstdir" dstdir_status=$? fi fi + case $dstdir in + */) dstdirslash=$dstdir;; + *) dstdirslash=$dstdir/;; + esac + obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') - # Create intermediate dirs using mode 755 as modified by the umask. - # This is like FreeBSD 'install' as of 1997-10-28. - umask=`umask` - case $stripcmd.$umask in - # Optimize common cases. - *[2367][2367]) mkdir_umask=$umask;; - .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi - *[0-7]) - mkdir_umask=`expr $umask + 22 \ - - $umask % 100 % 40 + $umask % 20 \ - - $umask % 10 % 4 + $umask % 2 - `;; - *) mkdir_umask=$umask,go-w;; - esac + posix_mkdir=false + # The $RANDOM variable is not portable (e.g., dash). Use it + # here however when possible just to lower collision chance. + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ - # With -d, create the new directory with the user-specified mode. - # Otherwise, rely on $mkdir_umask. - if test -n "$dir_arg"; then - mkdir_mode=-m$mode + trap ' + ret=$? + rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null + exit $ret + ' 0 + + # Because "mkdir -p" follows existing symlinks and we likely work + # directly in world-writeable /tmp, make sure that the '$tmpdir' + # directory is successfully created first before we actually test + # 'mkdir -p'. + if (umask $mkdir_umask && + $mkdirprog $mkdir_mode "$tmpdir" && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + test_tmpdir="$tmpdir/a" + ls_ld_tmpdir=`ls -ld "$test_tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" else - mkdir_mode= + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null fi - - posix_mkdir=false - case $umask in - *[123567][0-7][0-7]) - # POSIX mkdir -p sets u+wx bits regardless of umask, which - # is incompatible with FreeBSD 'install' when (umask & 300) != 0. - ;; - *) - tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ - trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 - - if (umask $mkdir_umask && - exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 - then - if test -z "$dir_arg" || { - # Check for POSIX incompatibilities with -m. - # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or - # other-writable bit of parent directory when it shouldn't. - # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. - ls_ld_tmpdir=`ls -ld "$tmpdir"` - case $ls_ld_tmpdir in - d????-?r-*) different_mode=700;; - d????-?--*) different_mode=755;; - *) false;; - esac && - $mkdirprog -m$different_mode -p -- "$tmpdir" && { - ls_ld_tmpdir_1=`ls -ld "$tmpdir"` - test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" - } - } - then posix_mkdir=: - fi - rmdir "$tmpdir/d" "$tmpdir" - else - # Remove any dirs left behind by ancient mkdir implementations. - rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null - fi - trap '' 0;; - esac;; + trap '' 0;; esac if $posix_mkdir && ( - umask $mkdir_umask && - $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else - # The umask is ridiculous, or mkdir does not conform to POSIX, + # mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in - /*) prefix='/';; - [-=\(\)!]*) prefix='./';; - *) prefix='';; + /*) prefix='/';; + [-=\(\)!]*) prefix='./';; + *) prefix='';; esac - eval "$initialize_posix_glob" - oIFS=$IFS IFS=/ - $posix_glob set -f + set -f set fnord $dstdir shift - $posix_glob set +f + set +f IFS=$oIFS prefixes= for d do - test X"$d" = X && continue + test X"$d" = X && continue - prefix=$prefix$d - if test -d "$prefix"; then - prefixes= - else - if $posix_mkdir; then - (umask=$mkdir_umask && - $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break - # Don't fail if two instances are running concurrently. - test -d "$prefix" || exit 1 - else - case $prefix in - *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; - *) qprefix=$prefix;; - esac - prefixes="$prefixes '$qprefix'" - fi - fi - prefix=$prefix/ + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ done if test -n "$prefixes"; then - # Don't fail if two instances are running concurrently. - (umask $mkdir_umask && - eval "\$doit_exec \$mkdirprog $prefixes") || - test -d "$dstdir" || exit 1 - obsolete_mkdir_used=true + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true fi fi fi @@ -450,14 +449,25 @@ do else # Make a couple of temp file names in the proper directory. - dsttmp=$dstdir/_inst.$$_ - rmtmp=$dstdir/_rm.$$_ + dsttmp=${dstdirslash}_inst.$$_ + rmtmp=${dstdirslash}_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. - (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && + (umask $cp_umask && + { test -z "$stripcmd" || { + # Create $dsttmp read-write so that cp doesn't create it read-only, + # which would cause strip to fail. + if test -z "$doit"; then + : >"$dsttmp" # No need to fork-exec 'touch'. + else + $doit touch "$dsttmp" + fi + } + } && + $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # @@ -472,20 +482,24 @@ do # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && - old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && - new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && - - eval "$initialize_posix_glob" && - $posix_glob set -f && + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && + set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && - $posix_glob set +f && - + set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else + # If $backupsuffix is set, and the file being installed + # already exists, attempt a backup. Don't worry if it fails, + # e.g., if mv doesn't support -f. + if test -n "$backupsuffix" && test -f "$dst"; then + $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null + fi + # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || @@ -493,24 +507,24 @@ do # to itself, or perhaps because mv is so ancient that it does not # support -f. { - # Now remove or move aside any old file at destination location. - # We try this two ways since rm can't unlink itself on some - # systems and the destination file might be busy for other - # reasons. In this case, the final cleanup might fail but the new - # file should still install successfully. - { - test ! -f "$dst" || - $doit $rmcmd -f "$dst" 2>/dev/null || - { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && - { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } - } || - { echo "$0: cannot unlink or rename $dst" >&2 - (exit 1); exit 1 - } - } && + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + test ! -f "$dst" || + $doit $rmcmd "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd "$rmtmp" 2>/dev/null; :; } + } || + { echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + } && - # Now rename the file to the real destination. - $doit $mvcmd "$dsttmp" "$dst" + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 @@ -519,9 +533,9 @@ do done # Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) +# eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-time-zone: "UTC" +# time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: diff --git a/autoconf/m4/tr_civetweb_home.m4 b/autoconf/m4/tr_civetweb_home.m4 new file mode 100644 index 00000000..5ed7ff1f --- /dev/null +++ b/autoconf/m4/tr_civetweb_home.m4 @@ -0,0 +1,32 @@ + + +AC_DEFUN([TR_CIVETWEB_HOME],[ + AC_ARG_WITH([civetweb], + AS_HELP_STRING([--with-civetweb@<:@=DIR@:>@], + [CIVETWEB root directory]), + # --with option was provided. + [CIVETWEB_HOME="$withval" + USE_CIVETWEB="0" + # check whether directory arg was also provided. + AS_IF([test "$CIVETWEB_HOME" = "yes"], + AC_CHECK_HEADER(civetweb.h, + [CIVETWEB_HOME="/usr"; USE_CIVETWEB="1"], + AC_MSG_ERROR([could not find civetweb.h])), + # else check whether --without-civet or --with-civet=no specified. + AS_IF([test "$CIVETWEB_HOME" = "no"], + [CIVETWEB_HOME=""], + # else --with-civet was provided with a directory path. + AC_CHECK_FILES([$CIVETWEB_HOME/include/civetweb.h $CIVETWEB_HOME/lib/libcivetweb.a], + [USE_CIVETWEB="1"], + AC_MSG_ERROR([Could not find all of the civetweb files.])) + )) + ], + # --with option not provided. + [AC_CHECK_HEADER(civetweb.h, + [CIVETWEB_HOME="/usr"; USE_CIVETWEB="1"], + [CIVETWEB_HOME=""; USE_CIVETWEB="0"]) + ] + ) + AC_SUBST([CIVETWEB_HOME]) + AC_SUBST([USE_CIVETWEB]) +]) diff --git a/autoconf/m4/tr_clang_version.m4 b/autoconf/m4/tr_clang_version.m4 new file mode 100644 index 00000000..99b0aac8 --- /dev/null +++ b/autoconf/m4/tr_clang_version.m4 @@ -0,0 +1,11 @@ + + +AC_DEFUN([TR_CLANG_VERSION], [ + CLANG_VERSION="" + ax_cv_clang_version="`$CLANG --version | grep "version" | sed "s/.*version \([0-9]*\.[0-9]*\.[0-9]*\).*/\1/"`" + AS_IF([test "x$ax_cv_clang_version" = "x"],[ + ax_cv_clang_version="" + ]) + CLANG_VERSION=$ax_cv_clang_version + AC_SUBST([CLANG_VERSION]) +]) \ No newline at end of file diff --git a/autoconf/m4/tr_er7_utils.m4 b/autoconf/m4/tr_er7_utils.m4 new file mode 100644 index 00000000..574ad8e1 --- /dev/null +++ b/autoconf/m4/tr_er7_utils.m4 @@ -0,0 +1,11 @@ + + +dnl test if we want to use er7_utils, default to yes +AC_DEFUN([TR_ER7_UTILS],[ + AC_ARG_ENABLE([er7utils], + AS_HELP_STRING([--enable-er7utils], [use er7_utils (default is yes)]), + AS_IF([test "x$enable_er7utils" = xyes], [USE_ER7_UTILS="1"], [USE_ER7_UTILS="0"]), + [USE_ER7_UTILS="1"] + ) + AC_SUBST([USE_ER7_UTILS]) +]) \ No newline at end of file diff --git a/autoconf/m4/tr_gcc_version.m4 b/autoconf/m4/tr_gcc_version.m4 new file mode 100644 index 00000000..0b9c96fb --- /dev/null +++ b/autoconf/m4/tr_gcc_version.m4 @@ -0,0 +1,17 @@ + + +AC_DEFUN([TR_GCC_VERSION], [ + GCC_VERSION="" + AS_IF([test "x$GCC" = "xyes"],[ + AS_IF([test "x$ax_gcc_version_option" != "xno"],[ + AC_CACHE_CHECK([gcc version],[ax_cv_gcc_version],[ + ax_cv_gcc_version="`$CC -dumpfullversion -dumpversion`" + AS_IF([test "x$ax_cv_gcc_version" = "x"],[ + ax_cv_gcc_version="" + ]) + ]) + GCC_VERSION=$ax_cv_gcc_version + ]) + ]) + AC_SUBST([GCC_VERSION]) +]) \ No newline at end of file diff --git a/autoconf/m4/tr_gsl_home.m4 b/autoconf/m4/tr_gsl_home.m4 new file mode 100644 index 00000000..d0e51536 --- /dev/null +++ b/autoconf/m4/tr_gsl_home.m4 @@ -0,0 +1,26 @@ + + +AC_DEFUN([TR_GSL_HOME],[ + AC_ARG_WITH([gsl], + AS_HELP_STRING([--with-gsl@<:@=DIR@:>@], [GSL root directory]), + [GSL_HOME="$withval" + AS_IF([test "$GSL_HOME" = "yes"], + AC_CHECK_HEADER(gsl/gsl_rng.h,[GSL_HOME="/usr"],AC_MSG_ERROR([could not find gsl/gsl_rng.h])), + AS_IF([test "$GSL_HOME" = "no"],[GSL_HOME=""], + AC_CHECK_FILE([$GSL_HOME/include/gsl], + [], + AC_MSG_ERROR([could not find $GSL_HOME/include/gsl]) + ) + ) + )], + [AC_CHECK_HEADER(gsl/gsl_rng.h, [GSL_HOME="/usr"], [GSL_HOME=""])] + ) + AS_IF([test "$GSL_HOME" != ""], + [ + LDFLAGS="${LDFLAGS} -L${GSL_HOME}/lib" + AC_CHECK_LIB(gsl, main, [],AC_MSG_ERROR([could not find libgsl]),[-lgslcblas]) + ], + [] + ) + AC_SUBST([GSL_HOME]) +]) diff --git a/autoconf/m4/tr_gtest_home.m4 b/autoconf/m4/tr_gtest_home.m4 new file mode 100644 index 00000000..312c227a --- /dev/null +++ b/autoconf/m4/tr_gtest_home.m4 @@ -0,0 +1,19 @@ + + +AC_DEFUN([TR_GTEST_HOME],[ + AC_ARG_WITH([gtest], + AS_HELP_STRING([--with-gtest@<:@=DIR@:>@], [GTEST root directory]), + [GTEST_HOME="$withval" + AS_IF([test "$GTEST_HOME" = "yes"], + AC_CHECK_HEADER(gtest/gtest.h,[GTEST_HOME="/usr"],AC_MSG_ERROR([could not find gtest/gtest.h])), + AS_IF([test "$GTEST_HOME" = "no"],[GTEST_HOME=""], + AC_CHECK_FILE([$GTEST_HOME/include/gtest], + [], + AC_MSG_ERROR([could not find $GTEST_HOME/include/gtest]) + ) + ) + )], + [AC_CHECK_HEADER(gtest/gtest.h, [GTEST_HOME="/usr"], [GTEST_HOME=""])] + ) + AC_SUBST([GTEST_HOME]) +]) \ No newline at end of file diff --git a/autoconf/m4/tr_hdf5_home.m4 b/autoconf/m4/tr_hdf5_home.m4 new file mode 100644 index 00000000..09ff850b --- /dev/null +++ b/autoconf/m4/tr_hdf5_home.m4 @@ -0,0 +1,28 @@ + + +AC_DEFUN([TR_HDF5_HOME],[ + AC_ARG_WITH([hdf5], + AS_HELP_STRING([--with-hdf5@<:@=DIR@:>@], [HDF5 root directory]), + [HDF5_HOME="$withval" + AS_IF([test "$HDF5_HOME" = "yes"], + AC_CHECK_HEADER(hdf5.h,[HDF5_HOME="/usr"],AC_MSG_ERROR([could not find hdf5.h])), + AS_IF([test "$HDF5_HOME" = "no"],[HDF5_HOME=""], + AC_CHECK_FILE([$HDF5_HOME/include/hdf5.h], + [], + AC_MSG_ERROR([could not find $HDF5_HOME/include/hdf5.h]) + ) + ) + )], + [ + AC_CHECK_HEADER(hdf5.h, [HDF5_HOME="/usr"], [HDF5_HOME=""]) + ] + ) + AS_IF([test "$HDF5_HOME" != ""], + [ + LDFLAGS="${LDFLAGS} -L${HDF5_HOME}/lib" + AC_CHECK_LIB(hdf5, main, [],AC_MSG_ERROR([could not find libhdf5])) + ] + [] + ) + AC_SUBST([HDF5_HOME]) +]) \ No newline at end of file diff --git a/autoconf/m4/tr_java.m4 b/autoconf/m4/tr_java.m4 new file mode 100644 index 00000000..e4f1e5bb --- /dev/null +++ b/autoconf/m4/tr_java.m4 @@ -0,0 +1,25 @@ + + +dnl test if we want to use java, default to yes +AC_DEFUN([TR_JAVA],[ + AC_ARG_ENABLE([java], + AS_HELP_STRING([--enable-java], [use java (default is yes)]), + AS_IF([test "x$enable_java" = xyes], [USE_JAVA="1"], [USE_JAVA="0"]), + [USE_JAVA="1"] + ) + AC_SUBST([USE_JAVA]) + AS_IF([test "$USE_JAVA" = "1"],[ + AC_PROG_AWK + AX_PROG_JAVA_CC(javac) + JAVA_VER=`$JAVA_CC -version 2>&1 | $ac_cv_path_PERL -ne 'print $& if /\d+(\.\d+)?/'` + AC_MSG_CHECKING([$JAVA_CC version >= 1.8]) + AX_COMPARE_VERSION([$JAVA_VER],[ge],[1.8], [AC_MSG_RESULT([yes])], + [AC_MSG_RESULT([no]) + AC_MSG_ERROR([Trick requires javac version >= 1.8]) + ]) + AS_IF([test "$TRICK_OFFLINE" = "0"], [ + AC_PATH_PROG(MVN, mvn, nomvn) + AS_IF([test "$ac_cv_path_MVN" = "nomvn"],AC_MSG_ERROR([could not find maven]),[]) + ], []) + ],[]) +]) diff --git a/autoconf/m4/tr_jsc_dirs.m4 b/autoconf/m4/tr_jsc_dirs.m4 new file mode 100644 index 00000000..696a582f --- /dev/null +++ b/autoconf/m4/tr_jsc_dirs.m4 @@ -0,0 +1,16 @@ + + +dnl if fermi-ware directory exists, test for motif. +AC_DEFUN([TR_JSC_DIRS],[ + AC_CHECK_FILE([trick_source/data_products/fermi-ware], + [ + AC_CHECK_HEADER(Xm/Xm.h, [MOTIF_HOME="/usr"], + AC_CHECK_FILE(/usr/local/include/Xm/Xm.h, [MOTIF_HOME="/usr/local"], + AC_CHECK_FILE(/sw/include/Xm/Xm.h, [MOTIF_HOME="/sw"],AC_MSG_ERROR([could not find Xm/Xm.h])))) + ], + [ + MOTIF_HOME="" + ] + ) + AC_SUBST([MOTIF_HOME]) +]) \ No newline at end of file diff --git a/autoconf/m4/tr_llvm_home.m4 b/autoconf/m4/tr_llvm_home.m4 new file mode 100644 index 00000000..005d4cd1 --- /dev/null +++ b/autoconf/m4/tr_llvm_home.m4 @@ -0,0 +1,16 @@ + + +AC_DEFUN([TR_LLVM_HOME],[ + AC_ARG_WITH([llvm], + AS_HELP_STRING([--with-llvm@<:@=DIR@:>@], [LLVM root directory]), + [LLVM_HOME="$withval" + AC_PATH_PROG(LLVM_CONFIG, llvm-config, no-llvm-config, "$LLVM_HOME/bin") + AS_IF([test "$ac_cv_path_LLVM_CONFIG" = "no-llvm-config"],AC_MSG_ERROR([could not find llvm-config]),[]) + ], + [ + AC_PATH_PROG(LLVM_CONFIG, llvm-config, no-llvm-config, "/bin:/usr/bin:/usr/local/bin:/sw/bin:/usr/local/opt/llvm/bin") + AS_IF([test "$ac_cv_path_LLVM_CONFIG" = "no-llvm-config"],AC_MSG_ERROR([could not find llvm-config]),[]) + LLVM_HOME=`$LLVM_CONFIG --prefix` + ] + ) +]) \ No newline at end of file diff --git a/autoconf/m4/tr_mac_darwin.m4 b/autoconf/m4/tr_mac_darwin.m4 new file mode 100644 index 00000000..fecbbbce --- /dev/null +++ b/autoconf/m4/tr_mac_darwin.m4 @@ -0,0 +1,13 @@ + +dnl Set ON_MAC=yes if we are on a mac (darwin host) +AC_DEFUN([TR_MAC_DARWIN], [ + dnl AC_CANONICAL_HOST provides platform. MacOSX is diverging... have to do special things + ON_MAC=no + case "${host_os}" in + darwin*) + ON_MAC=yes + ;; + *) + ;; + esac +]) \ No newline at end of file diff --git a/autoconf/m4/tr_prepend_path.m4 b/autoconf/m4/tr_prepend_path.m4 new file mode 100644 index 00000000..87b0b533 --- /dev/null +++ b/autoconf/m4/tr_prepend_path.m4 @@ -0,0 +1,19 @@ + +dnl test if want to prepend /usr/local/bin to PATH +dnl AC_ARG_WITH (package, help-string, [action-if-given], [action-if-not-given]) +AC_DEFUN([TR_PREPEND_PATH], + [AC_ARG_WITH( + [prepend-path], + [AS_HELP_STRING([--with-prepend-path@<:@=DIR@:>@], [specify a directory to prepend to PATH (default is /usr/local/bin). Use --without-prepend-path for no directory.])], + [AS_IF( + [test "x${with_prepend_path}" = xyes], + [PATH="/usr/local/bin:${PATH}"], + [AS_IF( + [test "x${with_prepend_path}" != xno], + [PATH="${withval}:${PATH}"], + [] + )] + )], + [] + )] +) diff --git a/autoconf/m4/tr_swig_bin.m4 b/autoconf/m4/tr_swig_bin.m4 new file mode 100644 index 00000000..d9bbfc1c --- /dev/null +++ b/autoconf/m4/tr_swig_bin.m4 @@ -0,0 +1,14 @@ + + +AC_DEFUN([TR_SWIG_BIN],[ + AC_ARG_WITH([swig], + [AS_HELP_STRING([--with-swig@<:@=DIR@:>@], [path of directory containing the SWIG executable.])], + [ + TEMP_PATH="${PATH}" + PATH="$withval:${PATH}" + AX_PKG_SWIG($1, [], [AC_MSG_ERROR([Trick requires SWIG version >= 2.0])]) + PATH="${TEMP_PATH}" + ], + [AX_PKG_SWIG($1, [], [AC_MSG_ERROR([Trick requires SWIG version >= 2.0])])] + ) +]) \ No newline at end of file diff --git a/autoconf/m4/tr_udunits_home.m4 b/autoconf/m4/tr_udunits_home.m4 new file mode 100644 index 00000000..9979eb20 --- /dev/null +++ b/autoconf/m4/tr_udunits_home.m4 @@ -0,0 +1,10 @@ + + +AC_DEFUN([TR_UDUNITS_HOME],[ + AC_ARG_WITH([udunits], + AS_HELP_STRING([--with-udunits@<:@=DIR@:>@], [UDUnits root directory]), + [UDUNITS_HOME="$withval"], + [UDUNITS_HOME=""] + ) + AC_SUBST([UDUNITS_HOME]) +]) \ No newline at end of file diff --git a/autoconf/m4/tr_x11.m4 b/autoconf/m4/tr_x11.m4 new file mode 100644 index 00000000..9f787336 --- /dev/null +++ b/autoconf/m4/tr_x11.m4 @@ -0,0 +1,16 @@ + +dnl find xml headers based on host type +AC_DEFUN([TR_X11], [ + AS_IF([test "$ON_MAC" = "yes"], + [ + AC_PATH_PROG(XCRUN, xcrun, noxcrun) + AS_IF([test "$ac_cv_path_XCRUN" = "norun"],AC_MSG_ERROR([could not find xcrun - install Xcode command line tools]),[]) + XCODE_SDK_PATH=`$XCRUN --show-sdk-path` + XTRAINCPATHS="-I/usr/X11/include -I${XCODE_SDK_PATH}/usr/include -I${XCODE_SDK_PATH}/usr/include/libxml2" + ], + [ + XTRAINCPATHS="-I/usr/include/libxml2/" + ]) + CFLAGS="$CFLAGS $XTRAINCPATHS" + CPPFLAGS="$CPPFLAGS $XTRAINCPATHS" +]) \ No newline at end of file diff --git a/autoconf/m4/tr_xwindows.m4 b/autoconf/m4/tr_xwindows.m4 new file mode 100644 index 00000000..00af2b3c --- /dev/null +++ b/autoconf/m4/tr_xwindows.m4 @@ -0,0 +1,19 @@ + +dnl look for X windows libraries and headers we need to compile +AC_DEFUN([TR_XWINDOWS], [ + AC_PATH_X + AS_IF([test "$no_x" = "yes"], + [ + USE_X_WINDOWS=0 + ], + [ + USE_X_WINDOWS=1 + AS_IF([test "x$x_includes" = "x"],[],[X_INCLUDE_DIR=-I$x_includes]) + AS_IF([test "x$x_libraries" = "x"],[],[X_LIB_DIR=-L$x_libraries]) + AC_CHECK_HEADER([X11/Intrinsic.h],[],AC_MSG_ERROR([could not find libxt development headers])) + TR_JSC_DIRS([]) + ] + ) + AC_SUBST([USE_X_WINDOWS]) + AC_SUBST([X_LIB_DIR]) +]) \ No newline at end of file diff --git a/autoconf/missing b/autoconf/missing old mode 100755 new mode 100644 index cdea5149..74eaae7c --- a/autoconf/missing +++ b/autoconf/missing @@ -1,9 +1,9 @@ #! /bin/sh # Common wrapper for a few potentially missing GNU programs. -scriptversion=2012-06-26.16; # UTC +scriptversion=2018-03-07.03; # UTC -# Copyright (C) 1996-2013 Free Software Foundation, Inc. +# Copyright (C) 1996-2022 Free Software Foundation, Inc. # Originally written by Fran,cois Pinard , 1996. # This program is free software; you can redistribute it and/or modify @@ -17,7 +17,7 @@ scriptversion=2012-06-26.16; # UTC # GNU General Public License for more details. # You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a @@ -101,9 +101,9 @@ else exit $st fi -perl_URL=http://www.perl.org/ -flex_URL=http://flex.sourceforge.net/ -gnu_software_URL=http://www.gnu.org/software +perl_URL=https://www.perl.org/ +flex_URL=https://github.com/westes/flex +gnu_software_URL=https://www.gnu.org/software program_details () { @@ -160,7 +160,7 @@ give_advice () ;; autom4te*) echo "You might have modified some maintainer files that require" - echo "the 'automa4te' program to be rebuilt." + echo "the 'autom4te' program to be rebuilt." program_details 'autom4te' ;; bison*|yacc*) @@ -207,9 +207,9 @@ give_advice "$1" | sed -e '1s/^/WARNING: /' \ exit $st # Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) +# eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-time-zone: "UTC" +# time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: diff --git a/bin/trick-CP b/bin/trick-CP index f537fe5a..67430b0a 100755 --- a/bin/trick-CP +++ b/bin/trick-CP @@ -60,7 +60,7 @@ if ( -f $sdefine ) { system("make -f makefile " . $makefileAddArgs) ; exit $? >> 8; } else { - print "S_define does not exist" ; + print "S_define does not exist\n" ; exit 1 ; } diff --git a/bin/trick-units b/bin/trick-units index 2e86f209..2078dbf6 100755 --- a/bin/trick-units +++ b/bin/trick-units @@ -134,7 +134,7 @@ print "-" x 50 . "\n"; printf "%25s%s", "Kelvin: ", "K, °K, degK"; print "\n"; printf "%25s%s", "Centigrade: ", "°C, degC"; print "\n"; printf "%25s%s", "Fahrenheit: ", "°F, degF"; print "\n"; -printf "%25s%s", "Rankine: ", "°R, degF"; print "\n"; +printf "%25s%s", "Rankine: ", "°R, degR"; print "\n"; print "\n"; diff --git a/configure b/configure index dcea12e7..c920daa5 100755 --- a/configure +++ b/configure @@ -717,7 +717,6 @@ infodir docdir oldincludedir includedir -runstatedir localstatedir sharedstatedir sysconfdir @@ -811,7 +810,6 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' -runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' @@ -1064,15 +1062,6 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; - -runstatedir | --runstatedir | --runstatedi | --runstated \ - | --runstate | --runstat | --runsta | --runst | --runs \ - | --run | --ru | --r) - ac_prev=runstatedir ;; - -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ - | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ - | --run=* | --ru=* | --r=*) - runstatedir=$ac_optarg ;; - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1210,7 +1199,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir runstatedir + libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -1363,7 +1352,6 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -1413,10 +1401,10 @@ Optional Packages: --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-x use the X Window System --with-python[=DIR] python root directory - --without-prepend-path do not prepend to path (this is default) --with-prepend-path[=DIR] specify a directory to prepend to PATH (default is - /usr/local/bin) + /usr/local/bin). Use --without-prepend-path for no + directory. --with-swig[=DIR] path of directory containing the SWIG executable. --with-llvm[=DIR] LLVM root directory --with-zlib=DIR root directory path of zlib installation [defaults to @@ -2406,36 +2394,6 @@ ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 @@ -2509,19 +2467,20 @@ case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac -ON_MAC=no -case "${host_os}" in - darwin*) - ON_MAC=yes - ;; - *) - ;; -esac + + ON_MAC=no + case "${host_os}" in + darwin*) + ON_MAC=yes + ;; + *) + ;; + esac -if test "$ON_MAC" = "yes"; then : + if test "$ON_MAC" = "yes"; then : - # Extract the first word of "xcrun", so it can be a program name with args. + # Extract the first word of "xcrun", so it can be a program name with args. set dummy xcrun; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } @@ -2562,19 +2521,20 @@ $as_echo "no" >&6; } fi - if test "$ac_cv_path_XCRUN" = "norun"; then : + if test "$ac_cv_path_XCRUN" = "norun"; then : as_fn_error $? "could not find xcrun - install Xcode command line tools" "$LINENO" 5 fi - XCODE_SDK_PATH=`$XCRUN --show-sdk-path` - XTRAINCPATHS="-I/usr/X11/include -I${XCODE_SDK_PATH}/usr/include -I${XCODE_SDK_PATH}/usr/include/libxml2" + XCODE_SDK_PATH=`$XCRUN --show-sdk-path` + XTRAINCPATHS="-I/usr/X11/include -I${XCODE_SDK_PATH}/usr/include -I${XCODE_SDK_PATH}/usr/include/libxml2" else - XTRAINCPATHS="-I/usr/include/libxml2/" + XTRAINCPATHS="-I/usr/include/libxml2/" fi -CFLAGS="$CFLAGS $XTRAINCPATHS" -CPPFLAGS="$CPPFLAGS $XTRAINCPATHS" + CFLAGS="$CFLAGS $XTRAINCPATHS" + CPPFLAGS="$CPPFLAGS $XTRAINCPATHS" + ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' @@ -3218,199 +3178,6 @@ ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ex ac_compiler_gnu=$ac_cv_cxx_compiler_gnu -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for X" >&5 -$as_echo_n "checking for X... " >&6; } - - -# Check whether --with-x was given. -if test "${with_x+set}" = set; then : - withval=$with_x; -fi - -# $have_x is `yes', `no', `disabled', or empty when we do not yet know. -if test "x$with_x" = xno; then - # The user explicitly disabled X. - have_x=disabled -else - case $x_includes,$x_libraries in #( - *\'*) as_fn_error $? "cannot use X directory names containing '" "$LINENO" 5;; #( - *,NONE | NONE,*) if ${ac_cv_have_x+:} false; then : - $as_echo_n "(cached) " >&6 -else - # One or both of the vars are not set, and there is no cached value. -ac_x_includes=no ac_x_libraries=no -rm -f -r conftest.dir -if mkdir conftest.dir; then - cd conftest.dir - cat >Imakefile <<'_ACEOF' -incroot: - @echo incroot='${INCROOT}' -usrlibdir: - @echo usrlibdir='${USRLIBDIR}' -libdir: - @echo libdir='${LIBDIR}' -_ACEOF - if (export CC; ${XMKMF-xmkmf}) >/dev/null 2>/dev/null && test -f Makefile; then - # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. - for ac_var in incroot usrlibdir libdir; do - eval "ac_im_$ac_var=\`\${MAKE-make} $ac_var 2>/dev/null | sed -n 's/^$ac_var=//p'\`" - done - # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR. - for ac_extension in a so sl dylib la dll; do - if test ! -f "$ac_im_usrlibdir/libX11.$ac_extension" && - test -f "$ac_im_libdir/libX11.$ac_extension"; then - ac_im_usrlibdir=$ac_im_libdir; break - fi - done - # Screen out bogus values from the imake configuration. They are - # bogus both because they are the default anyway, and because - # using them would break gcc on systems where it needs fixed includes. - case $ac_im_incroot in - /usr/include) ac_x_includes= ;; - *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes=$ac_im_incroot;; - esac - case $ac_im_usrlibdir in - /usr/lib | /usr/lib64 | /lib | /lib64) ;; - *) test -d "$ac_im_usrlibdir" && ac_x_libraries=$ac_im_usrlibdir ;; - esac - fi - cd .. - rm -f -r conftest.dir -fi - -# Standard set of common directories for X headers. -# Check X11 before X11Rn because it is often a symlink to the current release. -ac_x_header_dirs=' -/usr/X11/include -/usr/X11R7/include -/usr/X11R6/include -/usr/X11R5/include -/usr/X11R4/include - -/usr/include/X11 -/usr/include/X11R7 -/usr/include/X11R6 -/usr/include/X11R5 -/usr/include/X11R4 - -/usr/local/X11/include -/usr/local/X11R7/include -/usr/local/X11R6/include -/usr/local/X11R5/include -/usr/local/X11R4/include - -/usr/local/include/X11 -/usr/local/include/X11R7 -/usr/local/include/X11R6 -/usr/local/include/X11R5 -/usr/local/include/X11R4 - -/usr/X386/include -/usr/x386/include -/usr/XFree86/include/X11 - -/usr/include -/usr/local/include -/usr/unsupported/include -/usr/athena/include -/usr/local/x11r5/include -/usr/lpp/Xamples/include - -/usr/openwin/include -/usr/openwin/share/include' - -if test "$ac_x_includes" = no; then - # Guess where to find include files, by looking for Xlib.h. - # First, try using that file with no special directory specified. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if ac_fn_cxx_try_cpp "$LINENO"; then : - # We can compile using X headers with no special include directory. -ac_x_includes= -else - for ac_dir in $ac_x_header_dirs; do - if test -r "$ac_dir/X11/Xlib.h"; then - ac_x_includes=$ac_dir - break - fi -done -fi -rm -f conftest.err conftest.i conftest.$ac_ext -fi # $ac_x_includes = no - -if test "$ac_x_libraries" = no; then - # Check for the libraries. - # See if we find them without any special options. - # Don't add to $LIBS permanently. - ac_save_LIBS=$LIBS - LIBS="-lX11 $LIBS" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ -XrmInitialize () - ; - return 0; -} -_ACEOF -if ac_fn_cxx_try_link "$LINENO"; then : - LIBS=$ac_save_LIBS -# We can link X programs with no special library path. -ac_x_libraries= -else - LIBS=$ac_save_LIBS -for ac_dir in `$as_echo "$ac_x_includes $ac_x_header_dirs" | sed s/include/lib/g` -do - # Don't even attempt the hair of trying to link an X program! - for ac_extension in a so sl dylib la dll; do - if test -r "$ac_dir/libX11.$ac_extension"; then - ac_x_libraries=$ac_dir - break 2 - fi - done -done -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi # $ac_x_libraries = no - -case $ac_x_includes,$ac_x_libraries in #( - no,* | *,no | *\'*) - # Didn't find X, or a directory has "'" in its name. - ac_cv_have_x="have_x=no";; #( - *) - # Record where we found X for the cache. - ac_cv_have_x="have_x=yes\ - ac_x_includes='$ac_x_includes'\ - ac_x_libraries='$ac_x_libraries'" -esac -fi -;; #( - *) have_x=yes;; - esac - eval "$ac_cv_have_x" -fi # $with_x != no - -if test "$have_x" != yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_x" >&5 -$as_echo "$have_x" >&6; } - no_x=yes -else - # If each of the values was on the command line, it overrides each guess. - test "x$x_includes" = xNONE && x_includes=$ac_x_includes - test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries - # Update the cache value to reflect the command line values. - ac_cv_have_x="have_x=yes\ - ac_x_includes='$x_includes'\ - ac_x_libraries='$x_libraries'" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: libraries $x_libraries, headers $x_includes" >&5 -$as_echo "libraries $x_libraries, headers $x_includes" >&6; } -fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : @@ -3670,24 +3437,218 @@ fi done -if test "$no_x" = "yes"; then : - USE_X_WINDOWS=0 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for X" >&5 +$as_echo_n "checking for X... " >&6; } + + +# Check whether --with-x was given. +if test "${with_x+set}" = set; then : + withval=$with_x; +fi + +# $have_x is `yes', `no', `disabled', or empty when we do not yet know. +if test "x$with_x" = xno; then + # The user explicitly disabled X. + have_x=disabled +else + case $x_includes,$x_libraries in #( + *\'*) as_fn_error $? "cannot use X directory names containing '" "$LINENO" 5;; #( + *,NONE | NONE,*) if ${ac_cv_have_x+:} false; then : + $as_echo_n "(cached) " >&6 +else + # One or both of the vars are not set, and there is no cached value. +ac_x_includes=no ac_x_libraries=no +rm -f -r conftest.dir +if mkdir conftest.dir; then + cd conftest.dir + cat >Imakefile <<'_ACEOF' +incroot: + @echo incroot='${INCROOT}' +usrlibdir: + @echo usrlibdir='${USRLIBDIR}' +libdir: + @echo libdir='${LIBDIR}' +_ACEOF + if (export CC; ${XMKMF-xmkmf}) >/dev/null 2>/dev/null && test -f Makefile; then + # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. + for ac_var in incroot usrlibdir libdir; do + eval "ac_im_$ac_var=\`\${MAKE-make} $ac_var 2>/dev/null | sed -n 's/^$ac_var=//p'\`" + done + # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR. + for ac_extension in a so sl dylib la dll; do + if test ! -f "$ac_im_usrlibdir/libX11.$ac_extension" && + test -f "$ac_im_libdir/libX11.$ac_extension"; then + ac_im_usrlibdir=$ac_im_libdir; break + fi + done + # Screen out bogus values from the imake configuration. They are + # bogus both because they are the default anyway, and because + # using them would break gcc on systems where it needs fixed includes. + case $ac_im_incroot in + /usr/include) ac_x_includes= ;; + *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes=$ac_im_incroot;; + esac + case $ac_im_usrlibdir in + /usr/lib | /usr/lib64 | /lib | /lib64) ;; + *) test -d "$ac_im_usrlibdir" && ac_x_libraries=$ac_im_usrlibdir ;; + esac + fi + cd .. + rm -f -r conftest.dir +fi + +# Standard set of common directories for X headers. +# Check X11 before X11Rn because it is often a symlink to the current release. +ac_x_header_dirs=' +/usr/X11/include +/usr/X11R7/include +/usr/X11R6/include +/usr/X11R5/include +/usr/X11R4/include + +/usr/include/X11 +/usr/include/X11R7 +/usr/include/X11R6 +/usr/include/X11R5 +/usr/include/X11R4 + +/usr/local/X11/include +/usr/local/X11R7/include +/usr/local/X11R6/include +/usr/local/X11R5/include +/usr/local/X11R4/include + +/usr/local/include/X11 +/usr/local/include/X11R7 +/usr/local/include/X11R6 +/usr/local/include/X11R5 +/usr/local/include/X11R4 + +/usr/X386/include +/usr/x386/include +/usr/XFree86/include/X11 + +/usr/include +/usr/local/include +/usr/unsupported/include +/usr/athena/include +/usr/local/x11r5/include +/usr/lpp/Xamples/include + +/usr/openwin/include +/usr/openwin/share/include' + +if test "$ac_x_includes" = no; then + # Guess where to find include files, by looking for Xlib.h. + # First, try using that file with no special directory specified. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + # We can compile using X headers with no special include directory. +ac_x_includes= +else + for ac_dir in $ac_x_header_dirs; do + if test -r "$ac_dir/X11/Xlib.h"; then + ac_x_includes=$ac_dir + break + fi +done +fi +rm -f conftest.err conftest.i conftest.$ac_ext +fi # $ac_x_includes = no + +if test "$ac_x_libraries" = no; then + # Check for the libraries. + # See if we find them without any special options. + # Don't add to $LIBS permanently. + ac_save_LIBS=$LIBS + LIBS="-lX11 $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +XrmInitialize () + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + LIBS=$ac_save_LIBS +# We can link X programs with no special library path. +ac_x_libraries= +else + LIBS=$ac_save_LIBS +for ac_dir in `$as_echo "$ac_x_includes $ac_x_header_dirs" | sed s/include/lib/g` +do + # Don't even attempt the hair of trying to link an X program! + for ac_extension in a so sl dylib la dll; do + if test -r "$ac_dir/libX11.$ac_extension"; then + ac_x_libraries=$ac_dir + break 2 + fi + done +done +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi # $ac_x_libraries = no + +case $ac_x_includes,$ac_x_libraries in #( + no,* | *,no | *\'*) + # Didn't find X, or a directory has "'" in its name. + ac_cv_have_x="have_x=no";; #( + *) + # Record where we found X for the cache. + ac_cv_have_x="have_x=yes\ + ac_x_includes='$ac_x_includes'\ + ac_x_libraries='$ac_x_libraries'" +esac +fi +;; #( + *) have_x=yes;; + esac + eval "$ac_cv_have_x" +fi # $with_x != no + +if test "$have_x" != yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_x" >&5 +$as_echo "$have_x" >&6; } + no_x=yes +else + # If each of the values was on the command line, it overrides each guess. + test "x$x_includes" = xNONE && x_includes=$ac_x_includes + test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries + # Update the cache value to reflect the command line values. + ac_cv_have_x="have_x=yes\ + ac_x_includes='$x_includes'\ + ac_x_libraries='$x_libraries'" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: libraries $x_libraries, headers $x_includes" >&5 +$as_echo "libraries $x_libraries, headers $x_includes" >&6; } +fi + + if test "$no_x" = "yes"; then : + + USE_X_WINDOWS=0 else - USE_X_WINDOWS=1 - if test "x$x_includes" = "x"; then : + USE_X_WINDOWS=1 + if test "x$x_includes" = "x"; then : else X_INCLUDE_DIR=-I$x_includes fi - if test "x$x_libraries" = "x"; then : + if test "x$x_libraries" = "x"; then : else X_LIB_DIR=-L$x_libraries fi - ac_fn_cxx_check_header_mongrel "$LINENO" "X11/Intrinsic.h" "ac_cv_header_X11_Intrinsic_h" "$ac_includes_default" + ac_fn_cxx_check_header_mongrel "$LINENO" "X11/Intrinsic.h" "ac_cv_header_X11_Intrinsic_h" "$ac_includes_default" if test "x$ac_cv_header_X11_Intrinsic_h" = xyes; then : else @@ -3777,6 +3738,7 @@ fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lxml2" >&5 $as_echo_n "checking for main in -lxml2... " >&6; } if ${ac_cv_lib_xml2_main+:} false; then : @@ -4771,7 +4733,7 @@ if ${ax_cv_gcc_version+:} false; then : $as_echo_n "(cached) " >&6 else - ax_cv_gcc_version="`$CC -dumpversion`" + ax_cv_gcc_version="`$CC -dumpfullversion -dumpversion`" if test "x$ax_cv_gcc_version" = "x"; then : ax_cv_gcc_version="" @@ -5667,6 +5629,7 @@ PYTHON_LIBS=`${PYTHON_LIBS_COMMAND} | tr '\r\n' ' '` + # Check whether --with-prepend-path was given. if test "${with_prepend_path+set}" = set; then : withval=$with_prepend_path; if test "x${with_prepend_path}" = xyes; then : @@ -7478,6 +7441,26 @@ fi fi +as_ac_File=`$as_echo "ac_cv_file_$LLVM_LIB_DIR/libclangSupport.a" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LLVM_LIB_DIR/libclangSupport.a" >&5 +$as_echo_n "checking for $LLVM_LIB_DIR/libclangSupport.a... " >&6; } +if eval \${$as_ac_File+:} false; then : + $as_echo_n "(cached) " >&6 +else + test "$cross_compiling" = yes && + as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 +if test -r "$LLVM_LIB_DIR/libclangSupport.a"; then + eval "$as_ac_File=yes" +else + eval "$as_ac_File=no" +fi +fi +eval ac_res=\$$as_ac_File + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +if eval test \"x\$"$as_ac_File"\" = x"yes"; then : + ICG_CLANGLIBS="$ICG_CLANGLIBS -lclangSupport" +fi diff --git a/docs/developer_docs/Developer-Docs-Home.md b/docs/developer_docs/Developer-Docs-Home.md new file mode 100644 index 00000000..ed9f2faa --- /dev/null +++ b/docs/developer_docs/Developer-Docs-Home.md @@ -0,0 +1,13 @@ +| [Home](/trick) → Developer Docs | +|------------------------------------------------------------------| + +# Developer Documentation + + +Link documentation for Trick internals, processes, and plans here. + +- [Testing](Testing) +- [How to make a new Trick release on GitHub](How-To-Make-A-Release) +- [Tooling and Sanitizers](Tooling-and-Sanitizers) +- [Python Environment](Python-Environment-Issues) + diff --git a/docs/developer_docs/How-To-Make-A-Release.md b/docs/developer_docs/How-To-Make-A-Release.md new file mode 100644 index 00000000..18bd8e1a --- /dev/null +++ b/docs/developer_docs/How-To-Make-A-Release.md @@ -0,0 +1,44 @@ +| [Home](/trick) → [Developer Docs](Developer-Docs-Home) → How to make a release | +|------------------------------------------------------------------| + +# How To Make A Trick Release +This guide describes how to make a Trick release on GitHub +### Close Open Issues +Go through recently updated issues/pull requests and make sure that any open issues that have been fixed are merged and closed +### Make the release notes +#### Examples +https://github.com/nasa/trick/releases +#### Steps +* Review closed issues, pull requests, and commits since the last release and make a bulleted list of major changes + * UI Changes + * Header Changes + * Dependency Changes + * Major Bugfixes + * New features, tools, and example sims + * New OS/distro support + * New dependency support (such as LLVM/GCC versions) + * Major Documentation changes +### Choose a version number +* Advance major version number if there are interface changes or other major build-breaking changes +* Advance minor version number if there are major improvements or new features that are not build breaking +* Advance patch/tiny version number for hotfixes or other bugfixes +### Change the version numbers in the master branch +#### Example +https://github.com/nasa/trick/commit/a317c222748e706e89b7f344f6910d1f39824feb +#### Steps +* In share/trick/trick_ver.txt change the "current_version" string to match the new version number and remove any suffixes (like: "-beta"). +* In trick_source/java/pom.xml change the \ tag to the new version and remove any suffixes. +* In CMakeLists.txt change TRICK_MAJOR TRICK_MINOR TRICK_TINY to match the current version, and set TRICK_PRERELEASE to an empty string +### Create a commit, tag, and push to github.com + * `git commit -m "update version numbers for Trick Simulation Environment X.Y.Z"` + * `git tag -a -m "Trick Simulation Environment "` e.g. `git tag -a 25.0.0 -m "Trick Simulation Environment 25.0.0"` + * `git push origin ` +### Change version numbers back to prerelease and push + * Reverse the process of changing the version numbers in the files listed above; update to the next minor prerelease version (or major version if planning a major release soon). + * Remember to add the -beta suffix to the version number + * `git commit -m "update version numbers to prerelease X.Y.Z-beta"` + * `git push origin master` +### Create the release through the github UI + * This process is subject to change, so I'm posting the link to GitHub documentation here: + * https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository#creating-a-release + * Currently we do not add any artifacts/binaries or open discussions, so you can ignore those optional steps. diff --git a/docs/developer_docs/Python-Environment-Issues.md b/docs/developer_docs/Python-Environment-Issues.md new file mode 100644 index 00000000..ca3381b1 --- /dev/null +++ b/docs/developer_docs/Python-Environment-Issues.md @@ -0,0 +1,57 @@ +| [Home](/trick) → [Developer Docs](Developer-Docs-Home) → Python Environment Issues | +|------------------------------------------------------------------| + +# Python Environment in Trick + +In the `./configure` step, Trick finds the Python environment that is used as the embedded interpreter to execute input files and events. + +The configure script first tries to find the Python executable and the python-config script. If the `--with-python=[DIR]` option is used, it will only look in that given directory. Otherwise, it will use the system path. The python-config script is used to find the location of Python.h, installed python libraries, etc. + +## Help! The packages that I installed with pip are not being found by my Trick input files! + +This often happens when a machine has multiple Python installations, particularly on Mac with brew python vs system python. To debug this: + +Find where the `python` and `pip` (or `python3` and `pip3`) symlinks are – this is the version that Trick will pick up unless you have specified something else using the `--with-python=` configure option. + +``` +which python3 +which pip +``` + +These should match. cd into that directory. It was `/usr/local/bin` for me, which is the default Brew install directory for python. + +Read the path for the symlinks for `python3`, `pip3`, and `python3-config` (or whichever preferred version). These paths should match as well, but often this is the problem. + +``` +readlink python3 + /Library/Frameworks/Python.framework/Versions/3.10/bin/python3 +readlink pip3 + /usr/local/Cellar/python@3.11/3.11.3/bin/pip3 +``` + +Brew is supposed to be able to detect problems like this with `brew doctor`. Mine detected that `python3.11` was unlinked: + +``` +Warning: You have unlinked kegs in your Cellar. +Leaving kegs unlinked can lead to build-trouble and cause formulae that depend on +those kegs to fail to run properly once built. Run `brew link` on these: + python@3.11 +``` + +Run with the `--overwrite` flag: + +``` +brew link --overwrite python@3.11 +``` + +Running readlink should now show the correct Brew install (the one with Cellar in the path) for all the Python executables. + +Trick will search for the python3 and python3-config executables first on the user provided directory (if given) --with-python= and then along the system path. It then uses python3-config to find installed modules and the CPython headers and libraries. Trick assumes that these symlinks point to the same Python install, and when this assumption is violated it can cause problems with finding pip installed libaries. + +This is a common problem for systems with multiple Python installs, particularly for Macs with Brew python and Xcode python. Another option is just to completely remove the Python install in /Library/Frameworks/Python.framework. + +Helpful links: + +https://faun.pub/the-right-way-to-set-up-python-on-your-mac-e923ffe8cf8e + +https://stackoverflow.com/questions/5157678/how-do-i-use-brew-installed-python-as-the-default-python \ No newline at end of file diff --git a/docs/developer_docs/Testing.md b/docs/developer_docs/Testing.md new file mode 100644 index 00000000..9746e2ce --- /dev/null +++ b/docs/developer_docs/Testing.md @@ -0,0 +1,61 @@ +| [Home](/trick) → [Developer Docs](Developer-Docs-Home) → Testing | +|------------------------------------------------------------------| + + +# Testing + +Currently, Trick has a suite of unit and integration tests that run through a hodgepodge of GTest, Trick's internal unit test framework, Makefiles, and TrickOps. + +Unit tests can be found in their respective `trick_source/[sim_services|utils]/*/test` directories, and primarily use the Gtest framework. These are run primarily through test targets in their Makefiles. See `trick_source/sim_services/MemoryManager/test` for an example of organization. + +Integration tests take the form of Sims with some embedded tests. They live under `trick_sims/` and `test/`. A full list of sims that are used as part of the test suite are in [test_sims.yml](). These are run with TrickOps. + +## Test suite dependencies + +Gtest is required for the unit tests and some integration tests. See the [install guide](../documentation/install_guide/Install-Guide.md) for gtest installation. + +TrickOps requires python3 and the packages `PyYAML` and `psutil` (updated list in [Trickops requirements.txt](https://github.com/nasa/trick/blob/master/share/trick/trickops/requirements.txt)). Install these in your python environment, or create a virtual environment as follows: +``` +cd share/trick/trickops/ +python3 -m venv .venv && . .venv/bin/activate && pip3 install -r requirements.txt +cd ../../../ +``` + + +## Running the test suite +From trick home: +``` +# Run everything +make test + +# Run only integration tests +make sim_test + +# Run only unit tests +make unit_test +``` + +Currently, TrickOps will redirect all console output from tests into logs under {TRICK_HOME}/trickops_logs/, and will also dump the output of failing logs to console after the test suite is finished. + +## Coverage +Trick uses [Coveralls](https://coveralls.io/github/nasa/trick?branch=master) to host code coverage. Coverage is generated by running the test suite with gcov in CI, and then those files are uploaded to Coveralls. + +To enable gcov in Trick, it must be cleaned and compiled with the following: +``` +export CFLAGS="-fprofile-arcs -ftest-coverage -O0" +export CXXFLAGS="-fprofile-arcs -ftest-coverage -O0" +export LDFLAGS="-fprofile-arcs -ftest-coverage -O0" +export TRICK_CFLAGS="-fprofile-arcs -ftest-coverage -O0" +export TRICK_CXXFLAGS="-fprofile-arcs -ftest-coverage -O0" +export TRICK_SYSTEM_LDFLAGS="-fprofile-arcs -ftest-coverage -O0" +export TRICK_SYSTEM_CFLAGS="-fprofile-arcs -ftest-coverage -O0" +export TRICK_SYSTEM_CXXFLAGS="-fprofile-arcs -ftest-coverage -O0" +``` + +After Trick has been rebuild with the instrumentation, run: +``` +make code-coverage +``` +This will generate, collect, and filter all the various coverage data collection files into `coverage.info`. This is the file that is uploaded to Coveralls in the [code_coverage.yml](https://github.com/nasa/trick/blob/master/.github/workflows/code_coverage.yml) Github Actions workflow. + + diff --git a/docs/developer_docs/Tooling-and-Sanitizers.md b/docs/developer_docs/Tooling-and-Sanitizers.md new file mode 100644 index 00000000..19c569e6 --- /dev/null +++ b/docs/developer_docs/Tooling-and-Sanitizers.md @@ -0,0 +1,35 @@ +| [Home](/trick) → [Developer Docs](Developer-Docs-Home) → Tooling and Sanitizers | +|------------------------------------------------------------------| + +Lots of development and debugging tools require a binary to be instrumented with compiler flags. Trick does compiling and linking steps separately and uses several variables to propogate flags to different parts of the build. The following is a convenience function that can be added to your bashrc to easily modify the flags in your environment: + +``` +add-trickenv () { + export CFLAGS="$CFLAGS $1" + export CXXFLAGS="$CXXFLAGS $1" + export LDFLAGS="$LDFLAGS $1" + export TRICK_CFLAGS="$TRICK_CFLAGS $1" + export TRICK_CXXFLAGS="$TRICK_CXXFLAGS $1" + export TRICK_LDFLAGS="$TRICK_LDFLAGS $1" + export TRICK_SYSTEM_CFLAGS="$TRICK_SYSTEM_CFLAGS $1" + export TRICK_SYSTEM_CXXFLAGS="$TRICK_SYSTEM_CXXFLAGS $1" + export TRICK_SYSTEM_LDFLAGS="$TRICK_SYSTEM_LDFLAGS $1" +} +``` + +To debug a sim, you will likely need to run a clean build of all of Trick with these flags set. + +## Tools that are known to work well with Trick + +GDB/LLDB: `-g` + +gcov: `-fprofile-arcs -ftest-coverage -O0` + +tsan: `-g -fsanitize=thread` + +asan: `-g -fsanitize=address -fsanitize-recover=address` + +Suggest running asan instrumented sims with: + +`ASAN_OPTIONS=halt_on_error=0 ./S_main* ` + diff --git a/docs/documentation/Documentation-Home.md b/docs/documentation/Documentation-Home.md index 2b80b6ed..3c9e5183 100644 --- a/docs/documentation/Documentation-Home.md +++ b/docs/documentation/Documentation-Home.md @@ -36,6 +36,7 @@ The user guide contains information pertinent to Trick users. These pages will h 01. [Realtime Sleep Timer](simulation_capabilities/Realtime-Timer) 01. [Realtime Injector](simulation_capabilities/Realtime-Injector) 01. [Monte Carlo](simulation_capabilities/UserGuide-Monte-Carlo) + 02. [Monte Carlo Generation](miscellaneous_trick_tools/MonteCarloGeneration) 01. [Master Slave](simulation_capabilities/Master-Slave) 01. [Data Record](simulation_capabilities/Data-Record) 01. [Checkpoints](simulation_capabilities/Checkpoints) @@ -48,17 +49,17 @@ The user guide contains information pertinent to Trick users. These pages will h 01. [Status Message System](simulation_capabilities/Status-Message-System) 01. [Command Line Arguments](simulation_capabilities/Command-Line-Arguments) 01. [Environment](simulation_capabilities/Environment) - 01. [Standard Template Library Checkpointing](simulation_capabilities/STL-Checkpointing) + 01. [Standard Template Library Checkpointing](simulation_capabilities/STL-capabilities) 01. [Threads](simulation_capabilities/Threads) -01. [Web Server](web) - 01. [Adding a Web Server to Your Sim](web/Adding_a_Web_Server_to_Your_Sim) - 01. Web Server APIs - 01. [HTTP-API_alloc_info](web/HTTP-API_alloc_info) - 01. [WS-API_VariableServer](web/WS-API_VariableServer) - 01. Adding New Web Server APIs - 01. [Extending_the_HTTP-API](web/Extending_the_HTTP-API) - 01. [Extending_the_WS-API](web/Extending_the_WS-API) +01. [Web Server](web/Webserver) + 01. [Configure Trick with Civetweb](web/Configure-Civetweb) + 01. [Add SSL encryption to your webserver](web/SSL) + 01. [Web Server APIs](web/Webserver-apis) + 01. [HTTP alloc API](web/http-alloc-api.md) + 01. [WS Variable Server API](web/ws-variable-server-api.md) + 01. [Extend the HTTP API](web/Extend-http-api.md) + 01. [Extend the WS API](web/Extend-ws-api.md) 01. [Simulation Utilities](simulation_utilities/Simulation-Utilities) 01. [Trickcomm](simulation_utilities/Trickcomm) diff --git a/docs/documentation/building_a_simulation/Building-a-Simulation.md b/docs/documentation/building_a_simulation/Building-a-Simulation.md index d95f0d5f..c7eddd29 100644 --- a/docs/documentation/building_a_simulation/Building-a-Simulation.md +++ b/docs/documentation/building_a_simulation/Building-a-Simulation.md @@ -1,3 +1,6 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → Building a Simulation | +|------------------------------------------------------------------| + The building blocks of a basic Trick simulation are C/C++ structures/classes (models), a Python input file and a Trick simulation definition file (S_define). The S_define contains simulation objects which offer a way to turn the C/C++ function/methods into simulation jobs. Trick generates the necessary Python glue code which makes the C/C++ structures/classes accessible by the Python input file. The input file configures the simulation and is a command-line argument to the simulation executable. ... to be continued ... diff --git a/docs/documentation/building_a_simulation/Environment-Variables.md b/docs/documentation/building_a_simulation/Environment-Variables.md index 91024723..c6d6a694 100644 --- a/docs/documentation/building_a_simulation/Environment-Variables.md +++ b/docs/documentation/building_a_simulation/Environment-Variables.md @@ -1,3 +1,6 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Building a Simulation](Building-a-Simulation) → Environment Variables | +|------------------------------------------------------------------| + Trick uses a list of variables for building sims e.g. TRICK_CFLAGS and TRICK_CXXFLAGS. Each variable has a default value that may be overridden by setting the value in the environment. Trick resolves these variables by a call to a function called "trick-gte". Type in "${TRICK_HOME}/bin/trick-gte" on the command line to see what the "Trick environment" is. ### Adding ${TRICK_HOME}/bin to PATH diff --git a/docs/documentation/building_a_simulation/Making-the-Simulation.md b/docs/documentation/building_a_simulation/Making-the-Simulation.md index 22fa9b23..73ca61b0 100644 --- a/docs/documentation/building_a_simulation/Making-the-Simulation.md +++ b/docs/documentation/building_a_simulation/Making-the-Simulation.md @@ -1,3 +1,7 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Building a Simulation](Building-a-Simulation) → Making the Simulation | +|------------------------------------------------------------------| + + ### Simulation Compilation Environment Variables The -Ipaths in TRICK_CFLAGS and TRICK_CXXFLAGS tell Trick where to find model source files. The flags also can contain compiler settings, for instance the -g flag is used for compiling in debug mode. See section Trick_Environment for more detail and information on variables for linking in external libraries, setting the compiler etc. diff --git a/docs/documentation/building_a_simulation/Model-Source-Code.md b/docs/documentation/building_a_simulation/Model-Source-Code.md index f0b0fb7e..15c56389 100644 --- a/docs/documentation/building_a_simulation/Model-Source-Code.md +++ b/docs/documentation/building_a_simulation/Model-Source-Code.md @@ -1,3 +1,6 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Building a Simulation](Building-a-Simulation) → Model Source Code | +|------------------------------------------------------------------| + This section details the syntax for creating headers and source code that Trick can process. It also details the operation of the Trick Interface Code Generator (ICG) that processes headers, and the Module Interface Specification Processor (MIS) that processes source code. @@ -159,7 +162,7 @@ The `ICG IGNORE TYPES` field lists the structs or classes to be ignored. Any par ###### `PYTHON_MODULE` -Specifying a `python_module` name will place any class/struct and function definitions in this header file in a python module of the same name. All classes and functions are flattened into the python `trick` namespace by default. This capability allows users to avoid possible name collisions between names when they are flattened. +Specifying a `python_module` name will place any class/struct and function definitions in this header file in a python module of the same name. All classes and functions are flattened into the python `trick` namespace by default. This capability allows users to avoid possible name collisions between names when they are flattened. An empty `python_module` statement will be ignored. ##### Compiler Directives diff --git a/docs/documentation/building_a_simulation/Simulation-Definition-File.md b/docs/documentation/building_a_simulation/Simulation-Definition-File.md index 72773652..d5911819 100644 --- a/docs/documentation/building_a_simulation/Simulation-Definition-File.md +++ b/docs/documentation/building_a_simulation/Simulation-Definition-File.md @@ -1,3 +1,6 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Building a Simulation](Building-a-Simulation) → Simulation Definition File | +|------------------------------------------------------------------| + The Simulation Definition File or S_define is the file which lays out the architecture of the simulation. Details about job frequencies, job class, job data, importing/exporting data to other simulations, freeze cycles, integration, etc. are all housed in this one file. @@ -374,15 +377,18 @@ This section of the S_define (encapsulated by "job_class_order{...};) can be use scheduled loop job class order. The user may simply re-order the existing job classes that exist or can specify a new set of scheduled loop job classes. Job classes that are eligible for reassignment are listed in Table SD_1 between automatic and automatic_last inclusive. The order they are shown -in the table is the default ordering. +in the table is the default ordering. Note that if the user provides an ordering, classes that are +not included in the ordering (excluding automatic and automatic_last) will not be handled by any scheduler, + and therefore not executed in the sim. + ```C++ job_class_order { - my_job_class_1 ; - my_job_class_2 ; - scheduled ; - my_job_class_3 ; -} + my_job_class_1 , + my_job_class_2 , + scheduled , + my_job_class_3 +}; ``` ### Simulation Object C++ properties diff --git a/docs/documentation/building_a_simulation/Trickified-Project-Libraries.md b/docs/documentation/building_a_simulation/Trickified-Project-Libraries.md index b4e3a938..cb06ceb3 100644 --- a/docs/documentation/building_a_simulation/Trickified-Project-Libraries.md +++ b/docs/documentation/building_a_simulation/Trickified-Project-Libraries.md @@ -1,3 +1,7 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Building a Simulation](Building-a-Simulation) → Trickified Project Libraries | +|------------------------------------------------------------------| + + During a simulation build, Trick generates several rounds of files to support data recording, checkpointing, and Python access: * Trick generates `S_source.hh` from the `S_define` diff --git a/docs/documentation/data_products/DP-Product-File-Format.md b/docs/documentation/data_products/DP-Product-File-Format.md index 5f806edf..fc282b78 100644 --- a/docs/documentation/data_products/DP-Product-File-Format.md +++ b/docs/documentation/data_products/DP-Product-File-Format.md @@ -1,3 +1,6 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Data Products](Data-Products) → DP Product File Format | +|------------------------------------------------------------------| + Since Trick 10, the DP Product Specification File Format is changed to XML. The DP Product XML file DTD is defined as following: diff --git a/docs/documentation/data_products/DP-Session-File-Format.md b/docs/documentation/data_products/DP-Session-File-Format.md index 9f6c32a0..5b00c49e 100644 --- a/docs/documentation/data_products/DP-Session-File-Format.md +++ b/docs/documentation/data_products/DP-Session-File-Format.md @@ -1,3 +1,5 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Data Products](Data-Products) → DP Session File Format | +|------------------------------------------------------------------| Since Trick 10, the DP Session file is changed to XML format. The Session XML Document Type Definitions(DTD) is defined as following: diff --git a/docs/documentation/data_products/Data-Products-GUIs.md b/docs/documentation/data_products/Data-Products-GUIs.md index e84ca91f..0154aba1 100644 --- a/docs/documentation/data_products/Data-Products-GUIs.md +++ b/docs/documentation/data_products/Data-Products-GUIs.md @@ -1,3 +1,5 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Data Products](Data-Products) → Data Products GUIs | +|------------------------------------------------------------------| There are two main GUIs for viewing Trick logged data: diff --git a/docs/documentation/data_products/Data-Products.md b/docs/documentation/data_products/Data-Products.md index eb653591..fc58b4eb 100644 --- a/docs/documentation/data_products/Data-Products.md +++ b/docs/documentation/data_products/Data-Products.md @@ -1,3 +1,6 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → Data Products | +|------------------------------------------------------------------| + The Data Products (DP) is a simulation data post processor designed to allow visualization of data recorded in the Trick simulation. The data products can plot ASCII, Binary & HDF5 data. HDF5 is the new data format supported since Trick 10. diff --git a/docs/documentation/data_products/Plot-Printing.md b/docs/documentation/data_products/Plot-Printing.md index 5139ade8..1c88ce2f 100644 --- a/docs/documentation/data_products/Plot-Printing.md +++ b/docs/documentation/data_products/Plot-Printing.md @@ -1,3 +1,6 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Data Products](Data-Products) → Plot Printing | +|------------------------------------------------------------------| + To print fermi plots, simply bring up the fermi plot, and press either the "Print" (printer icon) button or the individual "Print" (printer icon) buttons on the plots themselves. In order for this to work you should set two environment variables: ``` diff --git a/docs/documentation/install_guide/Install-Guide.md b/docs/documentation/install_guide/Install-Guide.md index 1afbf4bc..cc025119 100644 --- a/docs/documentation/install_guide/Install-Guide.md +++ b/docs/documentation/install_guide/Install-Guide.md @@ -9,16 +9,16 @@ Trick requires various free third party utilities in order to function. All the | Utility | Version | Description | Usage | Notes | |---------------:|:-------:|:-----------------------:|:---------------------------------------------------------:|:------------------------------------------------------| -| [gcc] and g++ | 4.8+ | C/C++ Compiler | Compiles Trick and Trick simulations. | | -| [clang]/[llvm] | <=13 (14 not currently supported) | C/C++ Compiler | Utilized by the interface code generator. | | -| [python] | 2.7+ | Programming Language | Lets the user interact with a simulation. | Trick has been tested up to python 3.9 as of 02/21 | -| [perl] | 5.6+ | Programming Language | Allows executable scripts in the bin directory to run. | | -| [java] | 11+ | Programming Language | Necessary for Trick GUIs. | | -| [swig] | 2.x-3.x | Language Interfacing | Connects the python input processor with Trick's C code. | 3.0+ required for some unit tests in make test target | -| [make] | 3.78+ | Build Automation | Automates the building and cleaning of Trick. | | -| [openmotif] | 2.2.0+ | GUI Toolkit | Covers Trick GUIs not made with Java. | | -| [udunits] | 2.x+ | C Unit Library/Database | Provides support for units of physical quantities. | | -| [maven] | x.x | Java package manager | Downloads Java dependencies and builds trick GUIs | | +| [gcc] and g++ | 4.8+ | C/C++ Compiler | Compiles Trick and Trick simulations. | | +| [clang]/[llvm] | <=14 | C/C++ Compiler | Utilized by the interface code generator. | Trick Versions <= 19.3 should use LLVM <= 9 | +| [python] | 2.7+ | Programming Language | Lets the user interact with a simulation. | Trick has been tested up to python 3.11 as of 04/23 | +| [perl] | 5.6+ | Programming Language | Allows executable scripts in the bin directory to run. | | +| [java] | 11+ | Programming Language | Necessary for Trick GUIs. | | +| [swig] | 2.x-3.x | Language Interfacing | Connects the python input processor with Trick's C code. | 3.0+ required for some unit tests in make test target. SWIG 4.x is compatible with Trick, but has some issues https://github.com/nasa/trick/issues/1288 | +| [make] | 3.78+ | Build Automation | Automates the building and cleaning of Trick. | | +| [openmotif] | 2.2.0+ | GUI Toolkit | Covers Trick GUIs not made with Java. | | +| [udunits] | 2.x+ | C Unit Library/Database | Provides support for units of physical quantities. | | +| [maven] | x.x | Java package manager | Downloads Java dependencies and builds trick GUIs | | [gcc]: https://gcc.gnu.org/ [clang]: https://clang.llvm.org/ @@ -48,27 +48,44 @@ Trick runs on GNU/Linux and macOS, though any System V/POSIX compatible UNIX wor | Quick Jump Menu | |---| |[RedHat Enterprise Linux (RHEL) 8](#redhat8)| -|[CentOS 8](#redhat8)| +|[Oracle Linux 8](#redhat8)| +|[AlmaLinux 8](#redhat8)| +|[Rocky Linux 8](#redhat8)| |[RedHat Enterprise Linux (RHEL) 7](#redhat7)| |[CentOS 7](#redhat7)| |[Fedora](#fedora)| |[Ubuntu](#ubuntu)| |[macOS](#macos)| |[Windows 10 (Linux Subsystem Only)](#windows10)| +|[Troubleshooting](#trouble)| --- + ### Troubleshooting + +#### Environment Variables +Sometimes environment variables affect the Trick build and can cause it to fail. If you find one that isn't listed here, please create an issue and we'll add it to the list. + + +``` +JAVA_HOME # Trick and Maven will use JAVA_HOME to build the GUIs instead of javac in PATH if it is set. +TRICK_HOME # This variable is optional but may cause a Trick build to fail if it is set to the wrong directory. +CFLAGS, CXXFLAGS, LDFLAGS # If these flags are set they may affect flags passed to your compiler and linker +``` +#### If You Think The Install Instructions Do Not Work Or Are Outdated If the Trick tests are passing, you can see *exactly* how we configure our test machines on Github's test integration platform, Github Actions. If logged into any github account on github.com, you can access the [Actions](https://github.com/nasa/trick/actions) tab on the Trick repo page. Go to [Trick-CI](https://github.com/nasa/trick/actions?query=workflow%3A%22Trick+CI%22), and click the latest passing run. Here you can access a log of our shell commands to configure each OS with dependencies and also the commands we use to install Trick. In fact, that is exactly where I go when I want to update the install guide! @spfennell -The configuration for these tests can be found in the [trick/.github/workflow/test.yml](https://github.com/nasa/trick/blob/master/.github/workflows/test.yml) file. +The configuration for these tests can be found in the [trick/.github/workflow/test_linux.yml](https://github.com/nasa/trick/blob/master/.github/workflows/test_linux.yml) file. +#### Weird Linker Error +It is possible you may have an old version of Trick installed, and Trick's libraries are on your LDPATH and interfering with your new build. The solution is to uninstall the old version before building the new one. Call `sudo make uninstall` from any Trick top level directory and it will remove the old libraries. --- -### RedHat Enterprise Linux (RHEL) 8, CentOS 8 +### RedHat Enterprise Linux (RHEL) 8, Oracle Linux 8, Rocky Linux 8, AlmaLinux 8 Trick requires the clang/llvm compiler to compile and link the Trick Interface Code Generator. clang/llvm is available through the [Extra Packages for Enterprise Linux](https://fedoraproject.org/wiki/EPEL) repository. Download and install the 'epel-release' package. @@ -84,12 +101,21 @@ python3-devel diffutils -Trick makes use of several optional packages if they are present on the system. These include using the HDF5 package for logging, the GSL packages for random number generation, and google test (gtest) for Trick's unit testing. These are available from the EPEL repository. In order to access gtest-devel in the epel repository you need to enable the dnf option PowerTools +Trick makes use of several optional packages if they are present on the system. These include using the HDF5 package for logging, the GSL packages for random number generation, and google test (gtest) for Trick's unit testing. These are available from the EPEL repository. In order to access gtest-devel in the epel repository on RHEL 8 you need to enable the dnf repo CodeReady Linux Builder. In Rocky Linux and Alma Linux you can instead enable the Power Tools Repo. On Oracle Linux 8 you must enable OL8 CodeReady Builder. +See RedHat's documentation to enable the CodeReady Linux Builder repository: +https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/package_manifest/codereadylinuxbuilder-repository + +On AlmaLinux 8, Rocky Linux 8: ```bash -yum install -y 'dnf-command(config-manager)' -yum config-manager --enable PowerTools -yum install hdf5-devel gsl-devel gtest-devel +dnf config-manager --enable powertools + dnf install -y gtest-devel +``` + +On Oracle Linux 8: +``` +dnf config-manager --enable ol8_codeready_builder +dnf install -y gtest-devel ``` proceed to [Install Trick](#install) section of the install guide @@ -168,6 +194,7 @@ export PYTHON_VERSION=3 proceed to [Install Trick](#install) section of the install guide +--- ### macOS Monterey, Big Sur, Catalina #### These instructions are for Intel-based macs. For the latest Apple silicon (M1) instructions see this issue: https://github.com/nasa/trick/issues/1283 @@ -188,10 +215,10 @@ xcode-select --install brew install python java xquartz swig@3 maven udunits openmotif ``` -IMPORTANT: Make sure to follow the instructions for adding java to your path provided by brew. If you missed them, you can see them again by using `brew info java`. +IMPORTANT: Make sure to follow the instructions for adding java and swig to your `PATH` provided by brew. If you missed them, you can see them again by using `brew info java` and `brew info swig@3`. Remember, you may need to restart your terminal for these `PATH` changes to take effect. -5. Download and un-compress the latest pre-built clang+llvm 13 from llvm-project github. Go to https://github.com/llvm/llvm-project/releases -and download the latest version of 13 from the release assets. 13.0.1 is the latest as of the writing of this guide, the link I used is below: +5. Download and un-compress the latest pre-built clang+llvm from llvm-project github. Go to https://github.com/llvm/llvm-project/releases +and download the latest version llvm that matches your Xcode version from the release assets. For example, if your Xcode version is 14 then you will want the latest 14.x.x release of llvm. 13.0.1 is the latest as of the writing of this guide, the link I used is below: https://github.com/llvm/llvm-project/releases/download/llvmorg-13.0.1/clang+llvm-13.0.1-x86_64-apple-darwin.tar.xz Tip: I suggest renaming the untar'd directory to something simple like llvm13 and putting it in your home directory or development environment. @@ -214,6 +241,17 @@ e.g. ./configure --with-llvm=/Users/trickguy/llvm13 --with-udunits=/usr/local/Cellar/udunits/2.2.28 ``` +OPTIONAL: Trick uses google test (gtest) version 1.8 for unit testing. To install gtest: +``` +brew install cmake wget +wget https://github.com/google/googletest/archive/release-1.8.0.tar.gz +tar xzvf release-1.8.0.tar.gz +cd googletest-release-1.8.0/googletest +cmake . +make +make install +``` + proceed to [Install Trick](#install) section of the install guide --- @@ -327,3 +365,12 @@ cp prebuiltTrick/libexec/trick/java/build/*.jar trick/trick-offline ``` 4. Follow regular install instructions above. + +### Python Version + +If you would like to use Python 2 with Trick please first make sure Python 2 and the Python 2 libs are installed. Then you will likely need to set `PYTHON_VERSION=2` in your shell environment before executing the `configure` script so that Trick will use Python 2 instead of Python 3. This can be done in bash or zsh with the following commands: + +``` +export PYTHON_VERSION=2 +./configure +``` diff --git a/docs/documentation/introduction/Introduction.md b/docs/documentation/introduction/Introduction.md index 02ed4bed..6ba3cd18 100644 --- a/docs/documentation/introduction/Introduction.md +++ b/docs/documentation/introduction/Introduction.md @@ -1,3 +1,6 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → Introduction | +|------------------------------------------------------------------| + The responsibility for this document lies with the [Simulation and Graphics Branch (ER7)](https://er.jsc.nasa.gov/ER7/) of the [Automation, Robotics and Simulation Division](https://er.jsc.nasa.gov/) of the NASA JSC Engineering Directorate. The purpose of this document is to provide Trick simulation developers and users with a detailed user’s reference guide on how to install Trick, use Trick processors and utilities, and how to operate a simulation from execution to data post processing. diff --git a/docs/documentation/miscellaneous_trick_tools/MCG_verification_2020.pdf b/docs/documentation/miscellaneous_trick_tools/MCG_verification_2020.pdf new file mode 100644 index 00000000..e53844d2 Binary files /dev/null and b/docs/documentation/miscellaneous_trick_tools/MCG_verification_2020.pdf differ diff --git a/docs/documentation/miscellaneous_trick_tools/Miscellaneous-Trick-Tools.md b/docs/documentation/miscellaneous_trick_tools/Miscellaneous-Trick-Tools.md index df2858fa..a7156bed 100644 --- a/docs/documentation/miscellaneous_trick_tools/Miscellaneous-Trick-Tools.md +++ b/docs/documentation/miscellaneous_trick_tools/Miscellaneous-Trick-Tools.md @@ -1,3 +1,5 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → Miscellaneous Trick Tools | +|------------------------------------------------------------------| ### Interface Code Generator - ICG diff --git a/docs/documentation/miscellaneous_trick_tools/MonteCarloGeneration.md b/docs/documentation/miscellaneous_trick_tools/MonteCarloGeneration.md new file mode 100644 index 00000000..90139ec8 --- /dev/null +++ b/docs/documentation/miscellaneous_trick_tools/MonteCarloGeneration.md @@ -0,0 +1,705 @@ +# MonteCarloGeneration Model + +# Revision History +| Version | Date | Author | Purpose | +| :--- |:---| :--- | :--- | +| 1 | April 2020 | Gary Turner | Initial Version | +| 2 | March 2021 | Gary Turner | Added Verification | +| 3 | October 2022 | Isaac Reaves | Converted to Markdown | + +# 1 Introduction + +The MonteCarlo Model is used to disperse the values assigned to variables at the start of a simulation. Dispersing the initial +conditions and configurations for the simulation allows for robust testing and statistical analysis of the probability of +undesirable outcomes, and measuring the confidence levels associated with achieving desirable outcomes. + +Conventionally, most of the time we think about dispersing variables, we think about apply some sort of statistical +distribution to the value. Most often, that is a normal or uniform distribution, but there may be situations in which other +distributions are desired. In particular, this model provides an extensible framework allowing for any type of distribution to +be applied to any variable. + +For extensive analysis of safety-critical scenarios, where it is necessary to demonstrate high probability of success with high +confidence, traditional MonteCarlo analyses require often many thousands of runs. For long duration simulations, it may +not be feasible to run the number of simulations necessary to reach the high confidence of high success probability that is +necessary to meet requirements. Typically, failure cases occur out near the edges of state-space, but most of the runs will be +“right down the middle”; using conventional MonteCarlo techniques, most of these runs are completely unnecessary. With +a Sequential-MonteCarlo configuration, a small number of runs can be executed, allowing for identification of problem +areas, and a focussing of the distribution on those areas of state-space, thereby reducing the overall number of runs while +adding complexity to the setup. While this model does not (at this time) provide a Sequential-MonteCarlo capability, the +organization of the model has been designed to support external tools seeking to sequentially modify the distributions being +applied to the dispersed variables, and generate new dispersion sets. + +# 2 Requirements + +1. The model shall provide common statistical distribution capabilities, including: + 1. Uniform distribution between specified values + 1. as a floating-point value + 1. as an integer value + 1. Normal distribution, specified by mean and standard deviation + 1. Truncated Normal Distribution, including + 1. symmetric and asymmetric truncations + 1. it shall be possible to specify truncations by: + 1. some number of standard deviations from the mean, + 1. a numerical difference from the mean, and + 1. an upper and lower limit +1. The model shall provide an extensible framework suitable for supporting other statistical distributions +1. The model shall provide the ability to assign a common value to all runs: + 1. This value could be a fixed, user-defined value + 1. This value could be a random assignment, generated once and then applied to all runs +1. The model shall provide the capability to read values from a pre-generated file instead of generating its own values +1. The model shall provide the ability to randomly select from a discrete data set, including: + 1. enumerations, + 1. character-strings, + 1. boolean values, and + 1. numerical values +1. The model shall provide the capability to compute follow-on variables, the values of which are a function of one or more dispersed variables with values generated using any of the methods in requirements 1-5. +1. The model shall provide a record of the generated distributions, allowing for repeated execution of the same scenario using exactly the same conditions. +1. The model shall provide summary data of the dispersions which have been applied, including: + 1. number of dispersions + 1. types of dispersions + 1. correlations between variables + +# 3 Model Specification + +## 3.1 Code Structure + +The model can be broken down into its constituent classes; there are two principle components to the model – the variables, +and the management of the variables. + +### 3.1.1 Variable Management (MonteCarloMaster) + +MonteCarloMaster is the manager of the MonteCarlo variables. This class controls how many sets of dispersed variables +are to be generated; for each set, it has the responsibility for +* instructing each variable to generate its own dispersed value +* collecting those values and writing them to an external file + +### 3.1.2 Dispersed Variables (MonteCarloVariable) + +MonteCarloVariable is an abstract class that forms the basis for all dispersed variables. The following classes inherit from +MonteCarloVariable: +* MonteCarloVariableFile will extract a value for its variable from a specified text file. Typically, a data file will +comprise some number of rows and some number of columns of data. Each column of data represents the possible +values for one variable. Each row of data represents a correlated set of data to be applied to several variables; each +data-set generation will be taken from one line of data. Typically, each subsequent data-set will be generated from the +next line of data; however, this is not required. +* In some situations, it is desirable to have the next line of data to be used for any given data set be somewhat randomly +chosen. This has the disadvantageous effect of having some data sets being used more than others, but it supports +better cross-population when multiple data files are being used. + * For example, if file1 contained 2 data sets and file2 contained 4 data sets, then a sequential sweep through +these file would set up a repeating pattern with line 1 of file2 always being paired with line 1 of file1. For +example, in 8 runs, we would get this pattern of line numbers from each run: + * (1,1), (2,2), (1,3), (2,4), (1,1), (2,2), (1,3), (2,4) + * If the first file was allowed to skip a line, the pattern can produce a more comprehensive combination of +data: + * (1,1), (1,2), (2,3), (1,4), (2,1), (2,2), (2,3), (1,4) +* MonteCarloVariableFixed provides fixed-values to a variable for all generated data-sets. The values can be +represented as a double, int, or STL-string. +* MonteCarloVariableRandom is the base class for all variables being assigned a random value. The values can be +represented as a double, int, or STL-string. There are several subclasses: + * MonteCarloVariableRandomNormal provides a variable with a value dispersed according to a normal +distribution specified by its mean and standard deviation. + * MonteCarloVariableRandomUniformInt provides a variable with a value dispersed according to a uniform +distribution specified by its upper and lower bounds. This class represents a discrete distribution, providing an +integer value. + * MonteCarloVariableRandomUniform provides a variable with a value dispersed according to a uniform +distribution specified by its upper and lower bounds. This class represents a continuous distribution. + * MonteCarloVariableRandomStringSet represents a discrete variable, drawn from a set of STL-strings. The +class inherits from MonteCarloVariableRandomUniform; this distribution generates a continuous value in [0,1) +and scales and casts that to an integer index in {0, …, size-1} where size is the number of available strings +from which to choose. + + Note – an astute reader may question why the discrete MonteCarloVariableRandomStringSet inherits from +the continuous MonteCarloVariableRandomUniform rather than from the discrete +MonteCarloVariableRandomUniformInt. The rationale is based on the population of the vector of +selectable strings in this class. It is desirable to have this vector be available for population outside the +construction of the class, so at construction time the size of this vector is not known. However, the +construction of the MonteCarloVariableRandomUniformInt requires specifying the lower and upper +bounds, which would be 0 and size-1 respectively. Because size is not known at construction, this cannot +be specified. Conversely, constructing a MonteCarloVariableRandomUniform with bounds at [0,1) still +allows for scaling to the eventual size of the strings vector. + +* MonteCarloVariableSemiFixed utilizes a two-step process. First, a seed-variable has its value generated, then that +value is copied to this variable. The seed-variable could be a “throw-away” variable, used only to seed this value, or it +could be an instance of another dispersed variable. Once the value has been copied to this instance, it is retained in this +instance for all data sets. The seed-variable will continue to generate a new value for each data set, but they will not be +seen by this variable after that first set. + + The seed-variable can be any type of MonteCarloVariable, but note that not all types of MonteCarloVariable actually +make sense to use in this context. Most of the usable types are specialized types of MonteCarloVariableRandom. + + However, restricting the seed-variable in such a way would limit the extensibility of the model. All +MonteCarloVariableRandom types use the C++ \ library for data generation. Limiting the +MonteCarloVariableSemiFixed type to be seeded only by something using the \ library violates the concept of +free-extensibility. Consequently, the assigned value may be extracted from any MonteCarloVariable type. The only +constraint is that the command generated by the seed-variable includes an “=” symbol; everything to the right of that +symbol will be assigned to this variable. + +* MonteCarloPythonLineExec provides a line of executable Python code that can be used to compute the value of this +variable. So rather than generating an assignment statement, e.g. + +``` +var_x = 5 +``` + +when the MonteCarloMaster processes an instance of this class, it will use a character string to generate an +instruction statement, e.g. + +``` +var_x = math.sin(2 * math.pi * object.circle_fraction) +``` + +(in this case, the character string would be “math.sin(2 * math.pi * object.circle_fraction)” and +object.circle_fraction could be a previously-dispersed variable). + + A particularly useful application of this capability is in generating systematic data sweeps across a domain, as +opposed to random distributions within a domain. These are commonly implemented as a for-loop, but we can use +the MonteCarloPythonLineExec to generate them internally. The first data assignment made in each file is to a +run-number, which can be used as an index. The example shown below will generate a sweep across the domain +[20,45) in steps of 2.5. + +``` +object.sweep_variable = (monte_carlo.master.monte_run_number % 10) * 2.5 + 20 +``` + + * MonteCarloPythonFileExec is used when simple assignments and one-line instructions are insufficient, such as +when one generated-value that feeds into an analytical algorithm to generate multiple other values. With this class, +the execution of the Python file generated by MonteCarloMaster will hit a call to execute a file as specified by this +class. This is an oddity among the bank of MonteCarloVariable implementations. In all other implementations, +the identifying variable_name is used to identify the variable whose value is to be assigned (or computed). With +the MonteCarloPythonFileExec implementation, the variable_name is hijacked to provide the name of the file to +be executed. + +## 3.2 Mathematical Formulation + +No mathematical formulation. The random number generators use the C++ \ library. + +# 4 User's Guide + +## 4.1 What to expect + +This role played by this model can be easily misunderstood, so let’s start there. +**This model generates Python files containing assignments to variables.** + +That’s it!! It does not manage MonteCarlo runs. It does not execute any simulations. When it runs, it creates the requested +number of Python files and exits. + +This design is deliberate; we want the model to generate the instruction sets that will allow execution of a set of dispersed +configurations. At that point, the simulation should cease, returning control to the user to distribute the execution of those +configurations according to whatever distribution mechanism they desire. This could be: + +* something really simple, like a wild-card, \ `MONTE_RUN_test/RUN*/monte_input.py` +* a batch-script, +* a set of batch-scripts launching subsets onto different machines, +* a load-management service, like SLURM +* any other mechanism tailored to the user’s currently available computing resources + +The intention is that the model runs very early in the simulation sequence. If the model is inactive (as when running a regular, non-MonteCarlo run), it will take no action. But when this model is activated, the user should expect the simulation to terminate before it starts on any propagation. + +**When a simulation executes with this model active, the only result of the simulation will be the generation of files containing the assignments to the dispersed variables. The simulation should be expected to terminate at t=0.** + +## 4.1.1 Trick Users + +The model is currently configured for users of the Trick simulation engine. The functionality of the model is almost exclusively independent of the chosen simulation engine, with the exceptions being the shutdown sequence, and the application of units information in the variables. + +Found at the end of the `MonteCarloMaster::execute()` method, the following code: + +```c++ +exec_terminate_with_return(0, __FILE__, __LINE__,message.c_str()); +``` + +is a Trick instruction set to end the simulation. + +Found at the end of `MonteCarloVariable::insert_units()`, the following code: + +```c++ +// TODO: Pick a unit-conversion mechanism +// Right now, the only one available is Trick: +trick_units( pos_equ+1); +``` + +provides the call to + +```c++ +MonteCarloVariable::trick_units( + size_t insertion_pt) +{ + command.insert(insertion_pt, " trick.attach_units(\"" + units + "\","); + command.append(")"); +``` + +which appends Trick instructions to interpret the generated value as being represented in the specified units. + +The rest of the User’s Guide will use examples of configurations for Trick-simulation input files + +## 4.1.2 Non-Trick Users + +To configure the model for simulation engines other than Trick, the Trick-specific content identified above should be replaced with equivalent content that will result in: +* the shutdown of the simulation, and +* the conversion of units from the type specified in the distribution specification to the type native to the variable to which the generated value is to be assigned. + +While the rest of the User’s Guide will use examples of configurations for Trick-simulation input files, understand that these are mostly just C++ or Python code setting the values in this model to make it work as desired. Similar assignments would be required for any other simulation engine. + +## 4.2 MonteCarlo Manager (MonteCarloMaster) + +### 4.2.1 Instantiation + +The instantiation of MonteCarloMaster would typically be done directly in the S_module. The construction of this instance takes a single argument, a STL-string describing its own location within the simulation data-structure. + +The MonteCarloMaster class has a single public-interface method call, `MonteCarloMaster::execute()`. This method has 2 gate-keeping flags that must be set (the reason for there being 2 will be explained later): +* `active` +* `generate_dispersions` + +If either of these flags is false (for reference, `active` is constructed as false and `generate_dispersions` is constructed as true) then this method returns with no action. If both are true, then the model will generate the dispersions, write those dispersions to the external files, and shut down the simulation. + +An example S-module + +```c++ +class MonteCarloSimObject : public Trick::SimObject +{ + public: + MonteCarloMaster master; // <--- master is instantiated + MonteCarloSimObject(std::string location) + : + master(location) // <--- master is constructed with this STL-string + { + P_MONTECARLO ("initialization") master.execute(); // <--- the only function +call + } +}; +MonteCarloSimObject monte_carlo("monte_carlo.master"); // <--- location of “master” + is passed as an + argument +``` + +### 4.2.2 Configuration + +The configuration of the MonteCarloMaster is something to be handled as a user-input to the simulation without requiring re-compilation; as such, it is typically handled in a Python input file. There are two sections for configuration: +* modifications to the regular input file, and +* new file-input or other external monte-carlo initiation mechanism + +#### 4.2.2.1 Modifications to the regular input file + +A regular input file sets up a particular scenario for a nominal run. To add monte-carlo capabilities to this input file, the +following code should be inserted somewhere in the file: + +```python +if monte_carlo.master.active: + # insert non-mc-variable MC configurations like logging + if monte_carlo.master.generate_dispersions: + exec(open(“Modified_data/monte_variables.py").read()) +``` + +Let’s break this down, because it explains the reason for having 2 flags: + +| `generate_dispersions` | `active` | Result | +| :--- |:---| :--- | +| false | false | Regular (non-monte-carlo) run | +| false | true | Run scenario with monte-carlo configuration and pre-generated dispersions | +| true | false | Regular (non-monte-carlo) runs | +| true | true | Generate dispersions for this scenario, but do not run the scenario | + + 1. If the master is inactive, this content is passed over and the input file runs just as it would without this content + 2. Having the master `active` flag set to true instructs the simulation that the execution is intended to be part of a monte-carlo analysis. Now there are 2 types of executions that fit this intent: + * The generation of the dispersion files + * The execution of this run with the application of previously-generated dispersions + +Any code to be executed for case (a) must go inside the `generate_dispersions` gate. Any code to be executed for +case (b) goes inside the `active` gate, but outside the `generate_dispersions` gate. + +You may wonder why this distinction is made. In many cases, it is desirable to make the execution for monte-carlo +analysis subtly different to that for regular analysis. One commonly used distinction is logging of data; the logging +requirement may differ between a regular run and one as part of a monte-carlo analysis (typically, monte-carlo runs +execute with reduced logging). By providing a configuration area for a monte-carlo run, we can support these +distinctions. +Note – any code to be executed for only non-monte-carlo runs can be put in an else: block. For example, this code +will set up one set of logging for a monte-carlo run, and another for a non-monte-carlo run of the same scenario: +```python +if monte_carlo.master.active: + exec(open(“Log_data/log_for_monte_carlo.py”).read()) + if monte_carlo.master.generate_dispersions: + exec(open(“Modified_data/monte_variables.py").read()) +else: + exec(open(“Log_data/log_for_regular.py”).read()) +``` + 3. If the `generate_dispersions` flag is also set to true, the `MonteCarloMaster::execute()` method will execute, +generating the dispersion files and shutting down the simulation. + +#### 4.2.2.2 Initiating MonteCarlo + +Somewhere outside this file, the `active` and generate_dispersion flags must be set. This can be performed either in a separate input file or via a command-line argument. Unless the command-line argument capability is already supported, by far the easiest mechanism is to create a new input file that subsequently reads the existing input file: + +``` +monte_carlo.master.activate("RUN_1") +exec(open("RUN_1/input.py").read()) +``` + +The activate method takes a single string argument, representing the name of the run. This must be exactly the same name as the directory containing the original input file, “RUN_1” in the example above. This argument is used in 2 places (\ in these descriptions refers to the content of the argument string): + +* In the creation of a `MONTE_` directory. This directory will contain some number of sub-directories identified as, for example, RUN_01, RUN_02, RUN_03, etc. each of which will contain one of the generated dispersion files. +* In the instructions written into the generated dispersion files to execute the content of the input file found in ``. + +#### 4.2.2.3 Additional Configurations + +There are additional configurations instructing the MonteCarloMaster on the generation of the new dispersion files. Depending on the use-case, these could either be embedded within the `if monte_carlo.master.generate_dispersions:` block of the original input file, or in the secondary input file (or command-line arguments if configured to do so). + +* Number of runs is controlled with a single statement, e.g. + + ```monte_carlo.master.set_num_runs(10)``` + +* Generation of meta-data. The meta-data provides a summary of which variables are being dispersed, the type of dispersion applied to each, the random seeds being used, and correlation between different variables. This is written out to a file called MonteCarlo_Meta_data_output in the MONTE_* directory. + + ```monte_carlo.master.generate_meta_data = True``` + +* Changing the name of the automatically-generated monte-directory. By default, this takes the form “MONTE_\” as assigned in the MonteCarloMaster::activate(...) method. The monte_dir variable is public and can be reset after activation and before the `MonteCarloMaster::execute()` method runs. This is particularly useful if it is desired to compare two distribution sets for the same run. + + ```monte_carlo.master.monte_dir = “MONTE_RUN_1_vers2”``` + +* Changing the input file name. It is expected that most applications of this model will run with a typical organization of a Trick simulation. Consequently, the original input file is probably named input.py, and this is the default setting for the input_file_name variable. However, to support other cases, this variable is public and can be changed at any time between construction and the execution of the `MonteCarloMaster::execute()` method. + + ```monte_carlo.master.input_file_name = “modified_input.py”``` + +* Padding the filenames of the generated files. By default, the generated RUN directories in the generated MONTE_* directory will have their numerical component padded according to the number of runs. When: + * between 1 - 10 runs are generated, the directories will be named RUN_0, RUN_1, … + * between 11-100 runs are generated, the directories will be named RUN_00, RUN_01, … + * between 101-1000 runs are generated, the directories will be named RUN_000, RUN_001, … + * etc. + + Specification of a minimum padding width is supported. For example, it might be desired to create 3 runs with names RUN_00000, RUN_00001, and RUN_00002, in which case the minimum-padding should be specified as 5 characters + + ```monte_carlo.master.minimum_padding = 5``` + +* Changing the run-name. For convenience, the run-name is provided as an argument in the MonteCarloMaster::activate(...) method. The run_name variable is public, and can be reset after activation and before the `MonteCarloMaster::execute()` method runs. Because this setting determines which run is to be launched from the dispersion files, resetting run_name has limited application – effectively limited to correcting an error, which could typically be more easily corrected directly. + + ```monte_carlo.master.run_name = “RUN_2”``` + +## 4.3 MonteCarlo Variables (MonteCarloVariable) + +The instantiation of the MonteCarloVariable instances is typically handled as a user-input to the simulation without requiring re-compilation. As such, these are usually implemented in Python input files. This is not a requirement, and these instances can be compiled as part of the simulation build. Both cases are presented. + +### 4.3.1 Instantiation and Registration + +For each variable to be dispersed, an instance of a MonteCarloVariable must be created, and that instance registered with the MonteCarloMaster instance: + +1. Identify the type of dispersion desired +2. Select the appropriate type of MonteCarloVariable to provide that dispersion. +3. Create the new instance using its constructor. +4. Register it with the MonteCarloMaster using the `MonteCarloMaster::add_variable( MonteVarloVariable&)` method + +#### 4.3.1.1 Python input file implementation for Trick: + +When the individual instances are registered with the master, it only records the address of those instances. A user may create completely new variable names for each dispersion, or use a generic name as illustrated in the example below. Because these are typically created within a Python function, it is important to add the thisown=False instruction on each creation to prevent its destruction when the function returns. + +```python +mc_var = trick.MonteCarloVariableRandomUniform( "object.x_uniform", 0, 10, 20) +mc_var.thisown = False +monte_carlo.master.add_variable(mc_var) +mc_var = trick.MonteCarloVariableRandomNormal( "object.x_normal", 0, 0, 5) +mc_var.thisown = False +monte_carlo.master.add_variable(mc_var) +``` + +#### 4.3.1.2 C++ implementation in its own class: + +In this case, the instances do have to be uniquely named. + +Note that the registering of the variables could be done in the class constructor rather than in an additional method (process_variables), thereby eliminating the need to store the reference to MonteCarloMaster. In this case, the `generate_dispersions` flag is completely redundant because the variables are already registered by the time the input file is executed. Realize, however, that doing so does carry the overhead of registering those variables with the MonteCarloMaster every time the simulation starts up. This can a viable solution when there are only a few MonteCarloVariable instances, but is generally not recommended; using an independent method (process_variables) allows restricting the registering of the variables to be executed only when generating new dispersions. + +```c++ +class MonteCarloVarSet { + private: + MonteCarloMaster & master; + public: + MonteCarloVariableRandomUniform x_uniform; + MonteCarloVariableRandomNormal x_normal; + ... + MonteCarloVarSet( MonteCarloMaster & master_) + : + master(master_), + x_uniform("object.x_uniform", 0, 10, 20), + x_normal ("object.x_normal", 0, 0, 5), + ... + { }; + + void process_variables() { + master.add_variable(x_uniform); + master.add_variable(x_normal); + ... + } +}; +``` + +#### 4.3.1.3 C++ implementation within a Trick S-module: + +Instantiating the variables into the same S-module as the master is also a viable design pattern. However, this can lead to a very long S-module so is typically only recommended when there are few variables. As with the C++ implementation in a class, the variables can be registered with the master in the constructor rather than in an additional method, with the same caveats presented earlier. + +```c++ +class MonteCarloSimObject : public Trick::SimObject +{ + public: + MonteCarloMaster master; + MonteCarloVariableRandomUniform x_uniform; + MonteCarloVariableRandomNormal x_normal; + ... + MonteCarloSimObject(std::string location) + : + master(location), + x_uniform("object.x_uniform", 0, 10, 20), + x_normal ("object.x_normal", 0, 0, 5), + ... +{ }; + void process_variables() { + master.add_variable(x_uniform); + master.add_variable(x_normal); + ... +}; + { + P_MONTECARLO ("initialization") master.execute(); +} }; +MonteCarloSimObject monte_carlo("monte_carlo.master"); +``` + +### 4.3.2 input-file Access + +If using a (compiled) C++ implementation with the registration conducted at construction, the `generate_dispersions` flag is not used in the input file. + +```python +if monte_carlo.master.active: + if monte_carlo.master.generate_dispersions: + exec(open(“Modified_data/monte_variables.py").read()) +``` + +(where monte_variables.py is the file containing the mc_var = … content described earlier) + +```python +if monte_carlo.master.active: + if monte_carlo.master.generate_dispersions: + monte_carlo_variables.process_variables() +``` + +If using a (compiled) C++ implementation with a method to process the registration, that method call must be contained inside the `generate_dispersions` gate in the input file: +``` +if monte_carlo.master.active: + # add only those lines such as logging configuration +``` + +### 4.3.3 Configuration + +For all variable-types, the variable_name is provided as the first argument to the constructor. This variable name must include the full address from the top level of the simulation. After this argument, each variable type differs in its construction arguments and subsequent configuration options. + +#### 4.3.3.1 MonteCarloVariable + +MonteCarloVariable is an abstract class; its instantiable implementations are presented below. There is one important configuration for general application to these implementations, the setting of units. In a typical simulation, a variable has an inherent unit-type; these are often SI units, but may be based on another system. Those native units may be different to those in which the distribution is described. In this case, assigning the generated numerical value to the variable without heed to the units mismatch would result in significant error. + +```set_units(std::string units)``` + +This method specifies that the numerical value being generated is to be interpreted in the specified units. + +Notes +* if it is known that the variable’s native units and the dispersion units match (including the case of a dimensionless value), this method is not needed. +* This method is not applicable to all types of MonteCarloVariable; use with MonteCarloVariableRandomBool and MonteCarloPython* is considered undefined behavior. + +#### 4.3.3.2 MonteCarloVariableFile + +The construction arguments are: + +1. variable name +2. filename containing the data +3. column number containing data for this variable +4. (optional) first column number. This defaults to 1, but some users may want to zero-index their column numbers, in which case it can be set to 0. + +There is no additional configuration beyond the constructor + +There is no additional configuration beyond the constructor. + +#### 4.3.3.3 MonteCarloVariableFixed + +The construction arguments are: +1. variable name +2. value to be assigned + +Additional configuration for this model includes the specification of the maximum number of lines to skip between runs. +`max_skip`. This public variable has a default value of 0 – meaning that the next run will be drawn from the next line of data, but this can be adjusted. + +#### 4.3.3.4 MonteCarloVariableRandomBool + +The construction arguments are: +1. variable name +2. seed for random generator +There is no additional configuration beyond the constructor. + +#### 4.3.3.5 MonteCarloVariableRandomNormal + +The construction arguments are: +1. variable name +2. seed for random generator, defaults to 0 +3. mean of distribution, defaults to 0 +4. standard-deviation of distribution, defaults to 1. + +The normal distribution may be truncated, and there are several configuration settings associated with truncation. Note that for all of these truncation options, if the lower truncation bound is set to be larger than the upper truncation bound, the generation of the dispersed value will fail and the simulation will terminate without generation of files. If the upper andlower bound are set to be equal, the result will be a forced assignment to that value. + +`TruncationType` + +This is an enumerated type, supporting the specification of the truncation limits in one of three ways: +* `StandardDeviation`: The distribution will be truncated at the specified number(s) of standard deviations away from the mean. +* `Relative`: The distribution will be truncated at the specified value(s) relative to the mean value. +* `Absolute`: The distribution will be truncated at the specified value(s). + +`max_num_tries` + +The truncation is performed by repeatedly generating a number from the unbounded distribution until one is found that lies within the truncation limits. This max_num_tries value determines how many attempts may be made before the algorithm concedes. It defaults to 10,000. If a value has not been found within the specified number of tries, an error message is sent and the value is calculated according to the following rules: +* For a distribution truncated at only one end, the truncation limit is used +* For a distribution truncated at both ends, the midpoint value between the two truncation limits is used. + +`truncate( double limit, TruncationType)` + +This method provides a symmetric truncation, with the numerical value provided by limit being interpreted as a number of standard-deviations either side of the mean, a relative numerical value from the mean, or an absolute value. + +The value limit should be positive. If a negative value is provided, it will be negated to a positive value. + +The use of TruncationType Absolute and this method requires a brief clarification because this may result in an asymmetric distribution. In this case, the distribution will be truncated to lie between (-limit, limit) which will be asymmteric for all cases in which the mean is non-zero. + +`truncate( double min, double max, TruncationType)` + +This method provides a more general truncation, with the numerical value provided by min and max being interpreted as a number of standard-deviations away from the mean, a relative numerical value from the mean, or an absolute value. + +Unlike the previous method, the numerical arguments (min and max) may be positive or negative, and care must be taken especially when specifying min with TruncationType StandardDeviation or Relative. Realize that a positive value of min will result in a lower bound with value above that of the mean; min does not mean “distance to the left of the mean”, it means the smallest acceptable value relative to the mean. + +`truncate_low( double limit, TruncationType)` + +This method provides a one-sided truncation. All generated values will be above the limit specification. + +`truncate_high( double limit, TruncationType)` + +This method provides a one-sided truncation. All generated values will be below the limit specification. + +`untruncate()` + +This method removes previously configured truncation limits. + +#### 4.3.3.6 MonteCarloVariableRandomStringSet + +The construction arguments are: +1. variable name +2. seed for random generator + +This type of MonteCarloVariable contains a STL-vector of STL-strings containing the possible values that can be assigned by this generator. This vector is NOT populated at construction time and must be configured. + +`add_string(std::string new_string)` + +This method adds the specified string (`new_string`) to the vector of available strings + +#### 4.3.3.7 MonteCarloVariableRandomUniform + +The construction arguments are: +1. variable name +2. seed for random generator, defaults to 0 +3. lower-bound of distribution, default to 0 +4. upper-bound for distribution, defaults to 1 + +There is no additional configuration beyond the constructor + +#### 4.3.3.8 MonteCarloVariableRandomUniformInt + +The construction arguments are: +1. variable name +2. seed for random generator, defaults to 0 +3. lower-bound of distribution, default to 0 +4. upper-bound for distribution, defaults to 1 + +There is no additional configuration beyond the constructor + +#### 4.3.3.9 MonteCarloVariableSemiFixed + +The construction arguments are: +1. variable name +2. reference to the MonteCarloVariable whose generated value is to be used as the fixed value. + +There is no additional configuration beyond the constructor. + +#### 4.3.3.10 MonteCarloPythonLineExec + +The construction arguments are: +1. variable name +2. an STL-string providing the Python instruction for the computing of the value to be assigned to the specified variable. + +There is no additional configuration beyond the constructor. + +#### 4.3.3.11 MonteCarloPythonFileExec +The construction argument is: +1. name of the file to be executed from the generated input file. + +There is no additional configuration beyond the constructor. + +## 4.4 Information on the Generated Files + +This section is for informational purposes only to describe the contents of the automatically-generated dispersion files. Users do not need to take action on any content in here. + +The generated files can be broken down into 3 parts: +* Configuration for the input file. These two lines set the flags such that when this file is executed, the content of the original input file will configure the run for a monte-carlo analysis but without re-generating the dispersion files. + +```python +monte_carlo.master.active = True +monte_carlo.master.generate_dispersions = False +``` + +* Execution of the original input file. This line opens the original input file so that when this file is executed, the original input file is also executed automatically. + +```python +exec(open('RUN_1/input.py').read()) +``` + +* Assignment to simulation variables. This section always starts with the assignment to the run-number, which is also found in the name of the run, so RUN_0 gets a 0, RUN_1 gets a 1, etc. This value can be used, for example, to generate data sweeps as described in section MonteCarloPythonLineExec above. + +```python +monte_carlo.master.monte_run_number = 0 +object.test_variable1 = 5 +object.test_variable1 = 1.23456789 +... +``` + +## 4.5 Extension + +The model is designed to be extensible and while we have tried to cover the most commonly used applications, complete anticipation of all use-case needs is impossible. The most likely candidate for extension is in the area of additional distributions. In this case: +* A new distribution should be defined in its own class +* That class shall inherit from MonteCarloVariable or, if it involves a random generation using a distribution found in the C++ `` library, from MonteCarloVariableRandom. + * Populate the command variable inherited from MonteCarloVariable. This is the STL string representing the content that the MonteCarloMaster will place into the generated dispersion files. + * Call the `insert_units()` method inherited from MonteCarloVariable + * Set the `command_generated` flag to true if the command has been successfully generated. + +## 4.6 Running generated runs within an HPC framework + +Modern HPC (High Performance Computing) labs typically have one or more tools for managing the execution of jobs across multiple computers. There are several linux-based scheduling tools, but this section focuses on running the generated runs using a SLURM (Simple Linux Utility for Resource Management) array job. Consider this script using a simulation built with gcc 4.8 and a user-configured run named `RUN_example` which has already executed once with the Monte-Carlo Generation model enabled to generate 100 runs on disk: + +```bash +#SBATCH --array=0-99 + +# This is an example sbatch script demonstrating running an array job in SLURM. +# SLURM is an HPC (High-Performance-Computing) scheduling tool installed in +# many modern super-compute clusters that manages execution of a massive +# number of user-jobs. When a script like this is associated with an array +# job, this script is executed once per enumerated value in the array. After +# the Monte Carlo Generation Model executes, the resulting RUNs can be queued +# for SLURM execution using a script like this. Alternatively, sbatch --wrap +# can be used. See the SLURM documentation for more in-depth information. +# +# Slurm: https://slurm.schedmd.com/documentation.html + +# $SLURM_ARRAY_TASK_ID is automatically provided by slurm, and will be an +# integer between 0-99 per the "SBATCH --array" flag specified at the top of +# this script +echo "SLURM has provided us with array job integer: $SLURM_ARRAY_TASK_ID" +# Convert this integer to a zero-padded string matching the RUN naming +# convention associated with thi +RUN_NUM=`printf %02d $SLURM_ARRAY_TASK_ID` +# Execute the single trick simulation run associated with RUN_NUM +echo "Running RUN_$RUN_NUM ..." +./S_main_Linux_4.8_x86_64.exe MONTE_RUN_example/RUN_${RUN_NUM}/monte_input.py +``` + +The above script can be executed within a SLURM environment by running `sbatch `. This single command will create 100 independent array jobs in SLURM, allowing the scheduler to execute them as resources permit. Be extra careful with the zero-padding logic in the script above. The monte-carlo generation model will create zero-padded `RUN` names suitable for the number of runs requested to be generated by the user. The `%02d` part of the script above specifies 2-digit zero-padding which is suitable for 100 runs. Be sure to match this logic with the zero-padding as appropriate for your use-case. + +For more information on SLURM, refer to the project documentation: https://slurm.schedmd.com/documentation.html + +# 5 Verification + +The verification of the model is provided by tests defined in `test/SIM_mc_generation`. This sim was originally developed by by JSC/EG NASA in the 2020 timeframe. The verification section of the original documentation is omitted from this markdown file because it heavily leverages formatting that markdown cannot support. It can be viewed [here](MCG_verification_2020.pdf) diff --git a/docs/documentation/miscellaneous_trick_tools/Python-Variable-Server-Client.md b/docs/documentation/miscellaneous_trick_tools/Python-Variable-Server-Client.md index 89e1e32f..720566f9 100644 --- a/docs/documentation/miscellaneous_trick_tools/Python-Variable-Server-Client.md +++ b/docs/documentation/miscellaneous_trick_tools/Python-Variable-Server-Client.md @@ -1,3 +1,7 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Miscellaneous Trick Tools](Miscellaneous-Trick-Tools) → Python Variable Server Client | +|------------------------------------------------------------------| + + `variable_server.py` is a Python module for communicating with a sim's variable server from a Python program. Its primary purpose is to easily get and set variable values and units, but it also includes some additional convenience methods for affecting the sim's state. The code itself is well-commented, so I won't be reproducing the API here. Run `pydoc variable_server` (in the containing directory) for that. # Release Your Resources! @@ -384,4 +388,4 @@ class Variable(__builtin__.object) | should not directly change any part of this class. ``` -[Continue to Software Requirements](software_requirements_specification/SRS) +[Continue to Trick Ops](TrickOps) diff --git a/docs/documentation/miscellaneous_trick_tools/TrickOps.md b/docs/documentation/miscellaneous_trick_tools/TrickOps.md index 228dcd87..024c3c49 100644 --- a/docs/documentation/miscellaneous_trick_tools/TrickOps.md +++ b/docs/documentation/miscellaneous_trick_tools/TrickOps.md @@ -1,3 +1,6 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Miscellaneous Trick Tools](Miscellaneous-Trick-Tools) → Trick Ops | +|------------------------------------------------------------------| + # Table of Contents * [Requirements](#Requirements) * [Features](#Features) @@ -9,10 +12,11 @@ * [Other Useful Examples](#other-useful-examples) * [The TrickOps Design](#regarding-the-design-why-do-i-have-to-write-my-own-script) * [Tips & Best Practices](#tips--best-practices) +* [MonteCarloGenerationHelper](#montecarlogenerationhelper---trickops-helper-class-for-montecarlogeneratesm-users) # TrickOps -TrickOps is shorthand for "Trick Operations", and is a `python3` framework that provides an easy-to-use interface for common testing and workflow actions that Trick simulation developers and users often run repeatedly. Good software developer workflows typically have a script or set of scripts that the developer can run to answer the question "have I broken anything?". The purpose of TrickOps is to provide the logic central to managing these tests while allowing each project to define how and and what they wish to test. Don't reinvent the wheel, use TrickOps! +TrickOps is shorthand for "Trick Operations". TrickOps is a `python3` framework that provides an easy-to-use interface for common testing and workflow actions that Trick simulation developers and users often run repeatedly. Good software developer workflows typically have a script or set of scripts that the developer can run to answer the question "have I broken anything?". The purpose of TrickOps is to provide the logic central to managing these tests while allowing each project to define how and and what they wish to test. Don't reinvent the wheel, use TrickOps! TrickOps is *not* a GUI, it's a set of python modules that you can `import` that let you build a testing framework for your Trick-based project with just a few lines of python code. @@ -51,39 +55,42 @@ Simple and readable, this config file is parsed by `PyYAML` and adheres to all n ```yaml globals: - env: <-- optional literal string executed before all tests, e.g. env setup - parallel_safety: <-- strict won't allow multiple input files per RUN dir - + env: <-- optional literal string executed before all tests, ex: ". env.sh" SIM_abc: <-- required unique name for sim of interest, must start with SIM path: <-- required SIM path relative to project top level description: <-- optional description for this sim labels: <-- optional list of labels for this sim, can be used to get sims - model_x by label within the framework, or for any other project-defined - verification purpose - build_command: <-- optional literal cmd executed for SIM_build, defaults to trick-CP + build_args: <-- optional literal args passed to trick-CP during sim build + binary: <-- optional name of sim binary, defaults to S_main_{cpu}.exe size: <-- optional estimated size of successful build output file in bytes + phase: <-- optional phase to be used for ordering builds if needed + parallel_safety: <-- strict won't allow multiple input files per RUN dir. + Defaults to "loose" if not specified runs: <-- optional dict of runs to be executed for this sim, where the RUN_1/input.py --foo: dict keys are the literal arguments passed to the sim binary RUN_2/input.py: and the dict values are other run-specific optional dictionaries - ... described as follows ... + RUN_[10-20]/input.py: described in indented sections below. Zero-padded integer ranges + can specify a set of runs with continuous numbering using + [-] notation returns: <---- optional exit code of this run upon completion (0-255). Defaults to 0 compare: <---- optional list of vs. comparison strings to be - - a vs. b compared after this run is complete. This is extensible in that - - d vs. e all non-list values are ignored and assumed to be used to define - - ... an alternate comparison method in derived classes + - a vs. b compared after this run is complete. Zero-padded integer ranges + - d vs. e are supported as long as they match the pattern in the parent run. + - ... All non-list values are ignored and assumed to be used to define + - ... an alternate comparison method in a class extending this one analyze: <-- optional arbitrary string to execute as job in bash shell from project top level, for project-specific post-run analysis - valgrind: <-- optional dict describing how to execute runs within valgrind - flags: <-- string of all flags passed to valgrind for all runs - runs: <-- list of literal arguments passed to the sim binary through - - RUN_1... valgrind - + phase: <-- optional phase to be used for ordering runs if needed + valgrind: <-- optional string of flags passed to valgrind for this run. + If missing or empty, this run will not use valgrind non_sim_extension_example: will: be ignored by TrickWorkflow parsing for derived classes to implement as they wish ``` -Almost everything in this file is optional, but there must be at least one top-level key that starts with `SIM` and it must contain a valid `path: ` with respect to the top level directory of your project. Here, `SIM_abc` represents "any sim" and the name is up to the user, but it *must* begin with `SIM` since `TrickWorkflow` purposefully ignores any top-level key not beginning with `SIM` in order to allow for extensibility of the YAML file for non-sim tests specific to a project. +Almost everything in this file is optional, but there must be at least one top-level key that starts with `SIM` and it must contain a valid `path: ` with respect to the top level directory of your project. Here, `SIM_abc` represents "any sim" and the name is up to the user, but it *must* begin with `SIM` since `TrickWorkflow` purposefully ignores any top-level key not beginning with `SIM` and any key found under the `SIM` key not matching any named parameter above. This design allows for extensibility of the YAML file for non-sim tests specific to a project. There is *no limit* to number of `SIM`s, `runs:`, `compare:` lists, `valgrind` `runs:` list, etc. This file is intended to contain every Sim and and every sim's run, and every run's comparison and so on that your project cares about. Remember, this file represents the *pool* of tests, not necessarily what *must* be tested every time your scripts which use it run. @@ -97,19 +104,21 @@ cd trick/share/trick/trickops/ ``` When running, you should see output that looks like this: -![ExampleWorkflow In Action](trickops_example.png) +![ExampleWorkflow In Action](images/trickops_example.png) -When running, you'll notice that tests occur in two phases. First, sims build in parallel up to three at a time. Then when all builds complete, sims run in parallel up to three at a time. Progress bars show how far along each build and sim run is at any given time. The terminal window will accept scroll wheel and arrow input to view current builds/runs that are longer than the terminal height. +When running this example script, you'll notice that tests occur in two phases. First, sims build in parallel up to three at a time. Then when all builds complete, sims run in parallel up to three at a time. Progress bars show how far along each build and sim run is at any given time. The terminal window will accept scroll wheel and arrow input to view current builds/runs that are longer than the terminal height. Before the script finishes, it reports a summary of what was done, providing a list of which sims and runs were successful and which were not. -Looking inside the script, the code at top of the script creates a yaml file containing a large portion of the sims and runs that ship with trick and writes it to `/tmp/config.yml`. This config file will be input to the framework. At the bottom of the script is where the magic happens, this is where the TrickOps modules are used: +Looking inside the script, the code at top of the script creates a yaml file containing a large portion of the sims and runs that ship with trick and writes it to `/tmp/config.yml`. This config file is then used as input to the `TrickWorkflow` framework. At the bottom of the script is where the magic happens, this is where the TrickOps modules are used: ```python from TrickWorkflow import * class ExampleWorkflow(TrickWorkflow): def __init__( self, quiet, trick_top_level='/tmp/trick'): - # Real projects already have trick somewhere, but for this test, just clone it + # Real projects already have trick somewhere, but for this example, just clone & build it if not os.path.exists(trick_top_level): os.system('cd %s && git clone https://github.com/nasa/trick' % (os.path.dirname(trick_top_level))) + if not os.path.exists(os.path.join(trick_top_level, 'lib64/libtrick.a')): + os.system('cd %s && ./configure && make' % (trick_top_level)) # Base Class initialize, this creates internal management structures TrickWorkflow.__init__(self, project_top_level=trick_top_level, log_dir='/tmp/', trick_dir=trick_top_level, config_file="/tmp/config.yml", cpus=3, quiet=quiet) @@ -131,9 +140,11 @@ Let's look at a few key parts of the example script. Here, we create a new class from TrickWorkflow import * class ExampleWorkflow(TrickWorkflow): def __init__( self, quiet, trick_top_level='/tmp/trick'): - # Real projects already have trick somewhere, but for this test, just clone it + # Real projects already have trick somewhere, but for this example, just clone & build it if not os.path.exists(trick_top_level): os.system('cd %s && git clone https://github.com/nasa/trick' % (os.path.dirname(trick_top_level))) + if not os.path.exists(os.path.join(trick_top_level, 'lib64/libtrick.a')): + os.system('cd %s && ./configure && make' % (trick_top_level)) ``` Our new class `ExampleWorkflow.py` can be initialized however we wish as long as it provides the necessary arguments to it's Base class initializer. In this example, `__init__` takes two parameters: `trick_top_level` which defaults to `/tmp/trick`, and `quiet` which will be `False` unless `quiet` is found in the command-line args to this script. The magic happens on the very next line where we call the base-class `TrickWorkflow` initializer which accepts four required parameters: @@ -145,15 +156,15 @@ The required parameters are described as follows: * `project_top_level` is the absolute path to the highest-level directory of your project. The "top level" is up to the user to define, but usually this is the top level of your repository and at minimum must be a directory from which all sims, runs, and other files used in your testing are recursively reachable. * `log_dir` is a path to a user-chosen directory where all logging for all tests will go. This path will be created for you if it doesn't already exist. * `trick_dir` is an absolute path to the top level directory for the instance of trick used for your project. For projects that use trick as a `git` `submodule`, this is usually `/trick` -* `config_file` is the path to a YAML config file describing the sims, runs, etc. for your project. It's recommended this file be tracked in your SCM tool but that is not required. More information on the syntax expected in this file in the **The YAML File** section below. +* `config_file` is the path to a YAML config file describing the sims, runs, etc. for your project. It's recommended this file be tracked in your SCM tool but that is not required. More information on the syntax expected in this file in the **The YAML File** section above. The optional parameters are described as follows: * `cpus` tells the framework how many CPUs to use on sim builds. This translates directly to `MAKEFLAGS` and is separate from the maximum number of simultaneous sim builds. * `quiet` tells the framework to suppress progress bars and other verbose output. It's a good idea to use `quiet=True` if your scripts are going to be run in a continuous integration (CI) testing framework such as GitHub Actions, GitLab CI, or Jenkins, because it suppresses all `curses` logic during job execution which itself expects `stdin` to exist. -When `TrickWorkflow` initializes, it reads the `config_file` and verifies the information given matches the expected convention. If a non-fatal error is encountered, a message detailing the error is printed to `stdout` and the internal timestamped log file under `log_dir`. A fatal error will `raise RuntimeError`. +When `TrickWorkflow` initializes, it reads the `config_file` and verifies the information given matches the expected convention. If a non-fatal error is encountered, a message detailing the error is printed to `stdout` and the internal timestamped log file under `log_dir`. A fatal error will `raise RuntimeError`. Classes which inherit from `TrickWorkflow` may also access `self.parsing_errors` and `self.config_errors` which are lists of errors encountered from parsing the YAML file and errors encountered from processing the YAML file respectively. -Moving on to the next important lines of code in our `ExampleWorkflow.py` script. The `def run(self):` line declares a function whose return code on run is passed back to the calling shell via `sys.exit()`. This is where we use the functions given to us by inherting from `TrickWorkflow`: +Moving on to the next few important lines of code in our `ExampleWorkflow.py` script. The `def run(self):` line declares a function whose return code on run is passed back to the calling shell via `sys.exit()`. This is where we use the functions given to us by inherting from `TrickWorkflow`: ```python @@ -173,7 +184,7 @@ The last three lines simply print a detailed report of what was executed and man return (builds_status or runs_status or self.config_errors) ``` -The `ExampleWorkflow.py` uses sims/runs provided by trick to exercise *some* of the functionality provided by TrickOps. This script does not have any comparisons, post-run analyses, or valgrind runs defined in the YAML file, so there is no execution of those tests in this example. +The `ExampleWorkflow.py` script uses sims/runs provided by trick to exercise *some* of the functionality provided by TrickOps. This script does not have any comparisons, post-run analyses, or valgrind runs defined in the YAML file, so there is no execution of those tests in this example. ## `compare:` - File vs. File Comparisons @@ -188,8 +199,8 @@ SIM_ball: RUN_foo/input.py: RUN_test/input.py: compare: - - path/to/SIM_/ball/RUN_test/log_a.csv vs. regression/SIM_ball/log_a.csv - - path/to/SIM_/ball/RUN_test/log_b.trk vs. regression/SIM_ball/log_b.trk + - path/to/SIM_ball/RUN_test/log_a.csv vs. regression/SIM_ball/log_a.csv + - path/to/SIM_ball/RUN_test/log_b.trk vs. regression/SIM_ball/log_b.trk ``` In this example, `SIM_ball`'s run `RUN_foo/input.py` doesn't have any comparisons, but `RUN_test/input.py` contains two comparisons, each of which compares data generated by the execution of `RUN_test/input.py` to a stored off version of the file under the `regression/` directory relative to the top level of the project. The comparisons themselves can be executed in your python script via the `compare()` function in multiple ways. For example: @@ -233,10 +244,98 @@ if not failure: If an error is encountered, like `koviz` or a given directory cannot be found, `None` is returned in the first index of the tuple, and the error information is returned in the second index of the tuple for `get_koviz_report_job()`. The `get_koviz_report_jobs()` function just wraps the singular call and returns a tuple of `( list_of_jobs, list_of_any_failures )`. Note that `koviz` accepts entire directories as input, not specific paths to files. Keep this in mind when you organize how regression data is stored and how logged data is generated by your runs. + ## `analyze:` - Post-Run Analysis The optional `analyze:` section of a `run:` is intended to be a catch-all for "post-run analysis". The string given will be transformed into a `Job()` instance that can be retrieved and executed via `execute_jobs()` just like any other test. All analyze jobs are assumed to return 0 on success, non-zero on failure. One example use case for this would be creating a `jupytr` notebook that contains an analysis of a particular run. +## Defining sets of runs using [integer-integer] range notation + +The `yaml` file for your project can grow quite large if your sims have a lot of runs. This is especially the case for users of monte-carlo, which may generate hundreds or thousands of runs that you may want to execute as part of your TrickOps script. In order to support these use cases without requiring the user to specify all of these runs individually, TrickOps supports a zero-padded `[integer-integer]` range notation in the `run:` and `compare:` fields. Consider this example `yaml` file: + +```yaml +SIM_many_runs: + path: sims/SIM_many_runs + runs: + RUN_[000-100]/monte_input.py: + returns: 0 + compare: + sims/SIM_many_runs/RUN_[000-100]/log_common.csv vs. baseline/sims/SIM_many_runs/log_common.csv + sims/SIM_many_runs/RUN_[000-100]/log_verif.csv vs. baseline/sims/SIM_many_runs/RUN_[000-100]/log_verif.csv +``` +In this example, `SIM_many_runs` has 101 runs. Instead of specifying each individual run (`RUN_000/`, `RUN_001`, etc), in the `yaml` file, the `[000-100]` notation is used to specify a set of runs. All sub-fields of the run apply to that same set. For example, the default value of `0` is used for `returns:`, which also applies to all 101 runs. The `compare:` subsection supports the same range notation, as long as the same range is used in the `run:` named field. Each of the 101 runs shown above has two comparisons. The first `compare:` line defines a common file to be compared against all 101 runs. The second `compare:` line defines run-specific comparisons using the same `[integer-integer]` sequence. Note that when using these range notations zero-padding must be consistent, the values (inclusive) must be non-negative, and the square bracket notation must be used with the format `[minimum-maximum]`. + + +## `phase:` - An optional mechanism to order builds, runs, and analyses + +The `yaml` file supports an optional parameter `phase: ` at the sim and run level which allows the user to easily order sim builds, runs, and/or analyses, to suit their specific project constraints. If not specified, all sims, runs, and analyses, have a `phase` value of `0` by default. Consider this example `yaml` file with three sims: + +```yaml +SIM_car: + path: sims/SIM_car + +SIM_monte: + path: sims/SIM_monte + runs: + RUN_nominal/input.py --monte-carlo: # Generates the runs below + phase: -1 + MONTE_RUN_nominal/RUN_000/monte_input.py: # Generated run + MONTE_RUN_nominal/RUN_001/monte_input.py: # Generated run + MONTE_RUN_nominal/RUN_002/monte_input.py: # Generated run + MONTE_RUN_nominal/RUN_003/monte_input.py: # Generated run + MONTE_RUN_nominal/RUN_004/monte_input.py: # Generated run + +# A sim with constraints that make the build finnicky, and we can't change the code +SIM_external: + path: sims/SIM_external + phase: -1 + runs: + RUN_test/input.py: + returns: 0 +``` +Here we have three sims: `SIM_car`, `SIM_monte`, and `SIM_external`. `SIM_car` and `SIM_monte` have the default `phase` of `0` and `SIM_external` has been assigned `phase: -1` explicitly. If using non-zero phases, jobs can be optionally filtered by them when calling helper functions like `self.get_jobs(kind, phase)`. Some examples: +```python + build_jobs = self.get_jobs(kind='build') # Get all build jobs regardless of phase + build_jobs = self.get_jobs(kind='build', phase=0) # Get all build jobs with (default) phase 0 + build_jobs = self.get_jobs(kind='build', phase=-1) # Get all build jobs with phase -1 + build_jobs = self.get_jobs(kind='build', phase=[0, 1, 3]) # Get all build jobs with phase 0, 1, or 3 + build_jobs = self.get_jobs(kind='build', phase=range(-10,11)) # Get all build jobs with phases between -10 and 10 +``` +This can be done for runs and analyses in the same manner: +```python + run_jobs = self.get_jobs(kind='run') # Get all run jobs regardless of phase + run_jobs = self.get_jobs(kind='run', phase=0) # Get all run jobs with (default) phase 0 + # Get all run jobs with all phases less than zero + run_jobs = self.get_jobs(kind='run', phase=range(TrickWorkflow.allowed_phase_range['min'],0)) + # Get all analysis jobs with all phases zero or greater + an_jobs = self.get_jobs(kind='analysis', phase=range(0, TrickWorkflow.allowed_phase_range['max'+1])) +``` +Note that since analysis jobs are directly tied to a single named run, they inherit the `phase` value of their run as specfied in the `yaml` file. In other words, do not add a `phase:` section indented under any `analyze:` section in your `yaml` file. + +It's worth emphasizing that the specfiication of a non-zero `phase` in the `yaml` file, by itself, does not affect the order in which actions are taken. **It is on the user of TrickOps to use this information to order jobs appropriately**. Here's an example in code of what that might look for the example use-case described by the `yaml` file in this section: + +```python + first_build_jobs = self.get_jobs(kind='build', phase=-1) # Get all build jobs with phase -1 (SIM_external) + second_build_jobs = self.get_jobs(kind='build', phase=0) # Get all build jobs with phase 0 (SIM_car & SIM_monte) + first_run_jobs = self.get_jobs(kind='run', phase=-1) # Get all run jobs with phase -1 (RUN_nominal/input.py --monte-carlo) + second_run_jobs = self.get_jobs(kind='run', phase=0) # Get all run jobs with phase 0 (All generated runs & RUN_test/input.py) + + # SIM_external must build before SIM_car and SIM_monte, for project-specific reasons + builds_status1 = self.execute_jobs(first_build_jobs, max_concurrent=3, header='Executing 1st phase sim builds.') + # SIM_car and SIM_monte can build at the same time with no issue + builds_status2 = self.execute_jobs(second_build_jobs, max_concurrent=3, header='Executing 2nd phase sim builds.') + # SIM_monte's 'RUN_nominal/input.py --monte-carlo' generates runs + runs_status1 = self.execute_jobs(first_run_jobs, max_concurrent=3, header='Executing 1st phase sim runs.') + # SIM_monte's 'MONTE_RUN_nominal/RUN*/monte_input.py' are the generated runs, they must execute after the generation is complete + runs_status2 = self.execute_jobs(second_run_jobs, max_concurrent=3, header='Executing 2nd phase sim runs.') +``` +Astute observers may have noticed that `SIM_external`'s `RUN_test/input.py` technically has no order dependencies and could execute in either the first or second run job set without issue. + +A couple important points on the motivation for this capability: +* Run phasing was primarly developed to support testing monte-carlo and checkpoint sim scenarios, where output from a set of scenarios (like generated runs or dumped checkpoints) becomes the input to another set of sim scenarios. +* Sim phasing exists primarly to support testing scenarios where sims are poorly architectured or immutable, making them unable to be built independently. + + ## Where does the output of my tests go? All output goes to a single directory `log_dir`, which is a required input to the `TrickWorkflow.__init__()` function. Sim builds, runs, comparisons, koviz reports etc. are all put in a single directory with unique names. This is purposeful for two reasons: @@ -284,11 +383,48 @@ This is purposeful -- handling every project-specific constraint is impossible. * If your project requires an environment, it's usually a good idea to track a source-able environment file that users can execute in their shell. For example, if `myproject/.bashrc` contains your project environment, you should add `source .bashrc ;` to the `env:` section of `globals` in your YAML config file. This tells `TrickWorkflow` to add `source .bashrc ; ` before every `Job()`'s `command`. * Make sure you execute your tests in an order that makes sense logically. The TrickOps framework will not automatically execute a sim build before a sim run for example, it's on the user to define the order in which tests run and which tests are important to them. * Be cognizant of how many CPUs you've passed into `TricKWorkflow.__init__` and how many sims you build at once. Each sim build will use the `cpus` given to `TrickWorkflow.__init__`, so if you are building 3 sims at once each with 3 cpus you're technically requesting 9 cpus worth of build, so to speak. -* If `TrickWorkflow` encounters non-fatal errors while validating the content of the given YAML config file, it will set the internal member `self.config_erros` to be `True`. If you want your script to return non-zero on any non-fatal error, add this return code to your final script `sys.exit()`. +* If `TrickWorkflow` encounters non-fatal errors while verifying the content of the given YAML config file, it will add those errors to the internal `self.config_errors` list of strings. If you want your script to return non-zero on any non-fatal error, include `self.config_errors` in the criteria used for `sys.exit()`. Similar recommendation for `self.parsing_errors` which contains all errors found while parsing the YAML file. * Treat the YAML file like your project owns it. You can store project-specific information and retrieve that information in your scripts by accessing the `self.config` dictionary. Anything not recognized by the internal validation of the YAML file is ignored, but that information is still provided to the user. For example, if you wanted to store a list of POCS in your YAML file so that your script could print a helpful message on error, simply add a new entry `project_pocs: email1, email2...` and then access that information via `self.config['project_pocs']` in your script. +## `MonteCarloGenerationHelper` - TrickOps Helper Class for `MonteCarloGenerate.sm` users + +TrickOps provides the `MonteCarloGenerationHelper` python module as an interface between a sim using the `MonteCarloGenerate.sm` (MCG) sim module and a typical Trick-based workflow. This module allows MCG users to easily generate monte-carlo runs and execute them locally or alternatively through an HPC job scheduler like SLURM. Below is an example usage of the module. This example assumes: +1. The using script inherits from or otherwise leverages `TrickWorkflow`, giving it access to `self.execute_jobs()` +2. `SIM_A` is already built and configured with the `MonteCarloGenerate.sm` sim module +3. `RUN_mc/input.py` is configured with to generate runs when executed, specifically that `monte_carlo.mc_master.generate_dispersions == monte_carlo.mc_master.active == True` in the input file. + +```python +# Instantiate an MCG helper instance, providing the sim and input file for generation +mgh = MonteCarloGenerationHelper(sim_path="path/to/SIM_A", input_path="RUN_mc/input.py") +# Get the generation SingleRun() instance +gj = mgh.get_generation_job() +# Execute the generation Job to generate RUNS +ret = self.execute_jobs([gj]) + +if ret == 0: # Successful generation + # Get a SLURM sbatch array job for all generated runs found in monte_dir + # SLURM is an HPC (High-Performance-Computing) scheduling tool installed on + # many modern super-compute clusters that manages execution of a massive + # number of jobs. See the official documentation for more information + # Slurm: https://slurm.schedmd.com/documentation.html + sbj = mgh.get_sbatch_job(monte_dir="path/to/MONTE_RUN_mc") + # Execute the sbatch job, which queues all runs in SLURM for execution + # Use hpc_passthrough_args ='--wait' to block until all runs complete + ret = self.execute_jobs([sbj]) + + # Instead of using SLURM, generated runs can be executed locally through + # TrickOps calls on the host where this script runs. First get a list of + # run jobs + run_jobs = mgh.get_generated_run_jobs(monte_dir="path/to/MONTE_RUN_mc") + # Then execute all generated SingleRun instances, up to 10 at once + ret = self.execute_jobs(run_jobs, max_concurrent=10) +``` + +Note that the number of runs to-be-generated is configured somewhere in the `input.py` code and this module cannot robustly know that information for any particular use-case. This is why `monte_dir` is a required input to several functions - this directory is processed by the module to understand how many runs were generated. + ## More Information -A lot of time was spent adding `python` docstrings to the `TrickWorkflow.py` and `WorkflowCommon.py` modules. This README does not cover all functionality, so please see the in-code documentation for more detailed information on the framework. +A lot of time was spent adding `python` docstrings to the modules in the `trickops/` directory and tests under the `trickops/tests/`. This README does not cover all functionality, so please see the in-code documentation and unit tests for more detailed information on the framework capabilities. +[Continue to Software Requirements](../software_requirements_specification/SRS) diff --git a/docs/documentation/miscellaneous_trick_tools/trickops_example.png b/docs/documentation/miscellaneous_trick_tools/images/trickops_example.png similarity index 100% rename from docs/documentation/miscellaneous_trick_tools/trickops_example.png rename to docs/documentation/miscellaneous_trick_tools/images/trickops_example.png diff --git a/docs/documentation/running_a_simulation/Input-File.md b/docs/documentation/running_a_simulation/Input-File.md index 577e2bfc..68cfd5b4 100644 --- a/docs/documentation/running_a_simulation/Input-File.md +++ b/docs/documentation/running_a_simulation/Input-File.md @@ -1,3 +1,5 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Running a Simulation](Running-a-Simulation) → Input File | +|------------------------------------------------------------------| The primary interface between the simulation executable and the user is the runstream input file. The Trick simulation input file syntax is Python. All Python syntax rules @@ -253,7 +255,7 @@ There are several ways to include files in Python. ```python # One way is to use the execfile command -execfile("Modified_data/data_record.py") +exec(open("Modified_data/data_record.py").read()) # Another way is to make the included file a module and import it. # Import search paths may be added using the sys.path.append command. @@ -447,6 +449,9 @@ For information on how Trick processes events during runtime, see [Event Process # Add the event to the input processor's list of events (it will be processed at top of frame before scheduled jobs) trick.add_event() + +# Tell trick whether to terminate the sim if an error occurs while parsing Python code. Defaults to False +trick.terminate_on_event_parse_error() ``` #### Advanced Event (Malfunction) Usage diff --git a/docs/documentation/running_a_simulation/Running-a-Simulation.md b/docs/documentation/running_a_simulation/Running-a-Simulation.md index 619c28c2..7baaef8e 100644 --- a/docs/documentation/running_a_simulation/Running-a-Simulation.md +++ b/docs/documentation/running_a_simulation/Running-a-Simulation.md @@ -1,3 +1,6 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → Running a Simulation | +|------------------------------------------------------------------| + S_main_${TRICK_HOST_CPU}.exe is generated by the CP and is the simulation main executable program. The runtime configuration of the executive and its associated support utilities may be manipulated through entries in the simulation input file. The input file is described in detail in Input_File. @@ -9,6 +12,7 @@ S_main_${TRICK_HOST_CPU}.exe [trick_version] [sie] RUN_/ [-d] [-O ] [-OO ] + [--read-only-sim] [-u ] ``` @@ -18,6 +22,7 @@ S_main_${TRICK_HOST_CPU}.exe [trick_version] [sie] - The '-d' argument is optional and, if specified, starts the simulation in an input file verification mode. In this mode the entire input file is read, echoed to standard out, and then the simulation exits without calling any jobs listed in the S_define file. This mode helps debug input file syntax errors. - The '-O ' option allows the user to specify the directory to which simulation data log files will be written. If this option is omitted, the RUN_ directory is used. - The '-OO ' option allows the user to specify the directory to which ALL simulation output files will be written. If this option is omitted, the RUN_ directory is used. +- The '--read-only-sim' flag can be used to redirect all files written at simulation runtime into the output directory. - The '-u' option specifies that all remaining arguments are meant to be used by user supplied jobs. All arguments after the -u can be accessed internal to the simulation jobs by calling the get_cmnd_args() function of the executive as illustrated below. In a master/slave simulation, the master's -u args will be passed to the slave. The following code example shows how a function can access the command line arguments during execution. diff --git a/docs/documentation/running_a_simulation/Runtime-Output.md b/docs/documentation/running_a_simulation/Runtime-Output.md index 229c771e..3910302b 100644 --- a/docs/documentation/running_a_simulation/Runtime-Output.md +++ b/docs/documentation/running_a_simulation/Runtime-Output.md @@ -1,3 +1,6 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Running a Simulation](Running-a-Simulation) → Runtime Output| +|------------------------------------------------------------------| + Executing the simulation main executable S_main_${TRICK_HOST_CPU}.exe generates a handful of log files that document a simulation run. The log files are written to the RUN_ directory by default. The destination can be redirected by specifying the -O or -OO option for the runtime executive. Two of the log files are described below. diff --git a/docs/documentation/running_a_simulation/runtime_guis/MalfunctionsTrickView.md b/docs/documentation/running_a_simulation/runtime_guis/MalfunctionsTrickView.md index a834662d..8d0ed569 100644 --- a/docs/documentation/running_a_simulation/runtime_guis/MalfunctionsTrickView.md +++ b/docs/documentation/running_a_simulation/runtime_guis/MalfunctionsTrickView.md @@ -1,3 +1,6 @@ +| [Home](/trick) → [Documentation Home](../../Documentation-Home) → [Running a Simulation](../Running-a-Simulation) → [Runtime GUIs](Runtime-GUIs) → Malfunctions | +|------------------------------------------------------------------| + ### Events/Malfunctions Trick View Events/Malfunctions Trick View (hereafter referred to as MTV) is a graphical user interface that has two main functions: diff --git a/docs/documentation/running_a_simulation/runtime_guis/MonteMonitor.md b/docs/documentation/running_a_simulation/runtime_guis/MonteMonitor.md index 1293bba7..9b46cdae 100644 --- a/docs/documentation/running_a_simulation/runtime_guis/MonteMonitor.md +++ b/docs/documentation/running_a_simulation/runtime_guis/MonteMonitor.md @@ -1,3 +1,6 @@ +| [Home](/trick) → [Documentation Home](../../Documentation-Home) → [Running a Simulation](../Running-a-Simulation) → [Runtime GUIs](Runtime-GUIs) → Monte Monitor | +|------------------------------------------------------------------| + ### Monte Monitor Monte Monitor (hereafter referred to as MM) is a graphical user interface that allows users to view and modify the states diff --git a/docs/documentation/running_a_simulation/runtime_guis/Runtime-GUIs.md b/docs/documentation/running_a_simulation/runtime_guis/Runtime-GUIs.md index 2e5a38fa..880dfcf4 100644 --- a/docs/documentation/running_a_simulation/runtime_guis/Runtime-GUIs.md +++ b/docs/documentation/running_a_simulation/runtime_guis/Runtime-GUIs.md @@ -1,3 +1,6 @@ +| [Home](/trick) → [Documentation Home](../../Documentation-Home) → [Running a Simulation](../Running-a-Simulation) → Runtime GUIs | +|------------------------------------------------------------------| + Trick provides the following graphical user interfaces: ### Simulation Control Panel diff --git a/docs/documentation/running_a_simulation/runtime_guis/TrickView.md b/docs/documentation/running_a_simulation/runtime_guis/TrickView.md index 0d2aae70..df6e2d7a 100644 --- a/docs/documentation/running_a_simulation/runtime_guis/TrickView.md +++ b/docs/documentation/running_a_simulation/runtime_guis/TrickView.md @@ -1,3 +1,6 @@ +| [Home](/trick) → [Documentation Home](../../Documentation-Home) → [Running a Simulation](../Running-a-Simulation) → [Runtime GUIs](Runtime-GUIs) → Trick View | +|------------------------------------------------------------------| + Trick View (hereafter referred to as TV) is a graphical user interface that allows users to view and modify Trick-managed variables in a simulation while it is running. It also provides for the launching of integrated strip charts and can save and restore lists of variables and their associated strip charts. #### Launching diff --git a/docs/documentation/simulation_capabilities/Checkpoints.md b/docs/documentation/simulation_capabilities/Checkpoints.md index d1eb6f20..0f9aedb3 100644 --- a/docs/documentation/simulation_capabilities/Checkpoints.md +++ b/docs/documentation/simulation_capabilities/Checkpoints.md @@ -1,3 +1,6 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Simulation Capabilities](Simulation-Capabilities) → Checkpoints | +|------------------------------------------------------------------| + The Trick CheckPointWriter is a C++ Class that implements checkpointing. ## Checkpointing @@ -20,6 +23,12 @@ trick.checkpoint_cpu() trick.checkpoint_safestore_set_enabled(True|False) # Set the safestore checkpoint period. default 9x10e18 trick.checkpoint_safestore() + +# Load a checkpoint +trick.load_checkpoint() +# Load a checkpoint without restoring STLs +trick.load_checkpoint(, False) + ``` [Continue to Memory Manager](memory_manager/MemoryManager) diff --git a/docs/documentation/simulation_capabilities/Command-Line-Arguments.md b/docs/documentation/simulation_capabilities/Command-Line-Arguments.md index ddf99bb1..06f33f08 100644 --- a/docs/documentation/simulation_capabilities/Command-Line-Arguments.md +++ b/docs/documentation/simulation_capabilities/Command-Line-Arguments.md @@ -1,3 +1,6 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Simulation Capabilities](Simulation-Capabilities) → Command Line Arguments | +|------------------------------------------------------------------| + The Trick::CommandLineArguments class stores the command line arguments specified by the user when starting the simulation. The class provides routines to diff --git a/docs/documentation/simulation_capabilities/Data-Record.md b/docs/documentation/simulation_capabilities/Data-Record.md index df0a6fc8..f742acbd 100644 --- a/docs/documentation/simulation_capabilities/Data-Record.md +++ b/docs/documentation/simulation_capabilities/Data-Record.md @@ -1,3 +1,5 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Simulation Capabilities](Simulation-Capabilities) → Data Record | +|------------------------------------------------------------------| Data Recording provides the capability to specify any number of data recording groups, each with an unlimited number of parameter references, and with each group recording @@ -43,6 +45,7 @@ For example: drg.add_variable("ball.obj.state.output.position[0]") drg.add_variable("ball.obj.state.output.position[1]") ``` +In this example `position` is an array of floating point numbers. **DO NOT ATTEMPT TO DATA RECORD C OR C++ STRINGS. THIS HAS BEEN OBSERVED TO CREATE MEMORY ISSUES AND TRICK DOES NOT CURRENTLY PROVIDE ERROR CHECKING FOR THIS UNSUPPORTED USE CASE** An optional alias may also be specified in the method as drg.add_variable("" [, ""]). If an alias is present as a second argument, the alias name will be used in the data recording file instead of the actual variable name. @@ -53,6 +56,8 @@ drg.add_variable("ball.obj.state.output.position[0]", "x_pos") drg.add_variable("ball.obj.state.output.position[1]", "y_pos") ``` +Only individual primitive types can be recorded. Arrays, strings/char *, structured objects, or STL types are not supported. + ### Changing the Recording Rate To change the recording rate call the set_cycle() method of the recording group. @@ -380,7 +385,7 @@ The following data-types are used in Trick versions >= 10, that is for, *vv* = " ### DRHDF5 Recording Format HDF5 recording format is an industry conforming HDF5 formatted file. Files written in this format are named -log_.hd5. The contents of this file type are readable by the Trick Data Products packages from +log_.h5. The contents of this file type are readable by the Trick Data Products packages from Trick 07 to the current version. The contents of the file are binary and is not included here. The HDF5 layout of the file follows. @@ -415,4 +420,16 @@ GROUP "/" { } ``` + +### Interaction with Checkpoints + +Data recording groups are able to be checkpointed, reloaded, and restarted without any interaction by the user. When a checkpoint is loaded that includes data recording, +the data recording groups will be initiated and begin recording at the time in the checkpoint. For example, if a checkpoint was dumped when t=5, when the checkpoint is +loaded into another run, it will data record starting at t=5, no matter what time in the run it was loaded or whether the run was already data recording. Loading a checkpoint +will overwrite any data recording files that were being recorded before the load. + +Loading a checkpoint with different data recording groups than the current run will overwrite the current data recording groups. + +Refer to test/SIM_checkpoint_data_recording to see expected behavior in action. Overall, the loading a checkpoint should completely overwrite any other data recording the sim is currently doing, and the new recording will start at the time in the checkpoint. If you come across different behavior, please open an issue. + [Continue to Checkpointing](Checkpoints) diff --git a/docs/documentation/simulation_capabilities/Debug-Pause.md b/docs/documentation/simulation_capabilities/Debug-Pause.md index 10fc3624..e8984587 100644 --- a/docs/documentation/simulation_capabilities/Debug-Pause.md +++ b/docs/documentation/simulation_capabilities/Debug-Pause.md @@ -1,3 +1,5 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Simulation Capabilities](Simulation-Capabilities) → Debug Pause | +|------------------------------------------------------------------| Debug Pause is a debugging feature provided by Trick. When turned on, Debug Pause will print the current simulation time and the name of the current job, and pause the simulation @e before the job is executed. Debug Pause provides a way for the user to step diff --git a/docs/documentation/simulation_capabilities/Echo-Jobs.md b/docs/documentation/simulation_capabilities/Echo-Jobs.md index a2bdce00..0f39b37e 100644 --- a/docs/documentation/simulation_capabilities/Echo-Jobs.md +++ b/docs/documentation/simulation_capabilities/Echo-Jobs.md @@ -1,3 +1,5 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Simulation Capabilities](Simulation-Capabilities) → Echo Jobs | +|------------------------------------------------------------------| Echo Jobs is a handy debugging toggle provided by Trick. When turned on, Echo Jobs will print the current simulation time and the name of the current job being executed. Echo Jobs is a convenient way to see the order of job execution and narrow down when diff --git a/docs/documentation/simulation_capabilities/Environment.md b/docs/documentation/simulation_capabilities/Environment.md index 9eecc030..f29aab0a 100644 --- a/docs/documentation/simulation_capabilities/Environment.md +++ b/docs/documentation/simulation_capabilities/Environment.md @@ -1,3 +1,5 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Simulation Capabilities](Simulation-Capabilities) → Environment | +|------------------------------------------------------------------| This class saves the Trick environment variables at compile-time. The variables are saved inside the S_main executable. These variables are read-only after they @@ -7,4 +9,4 @@ are compiled into the sim. const char * get_trick_env( char * variable_name ) ``` -[Continue to STL Checkpointing](STL-Checkpointing) +[Continue to STL Checkpointing](STL-Capabilities) diff --git a/docs/documentation/simulation_capabilities/Event-Manager.md b/docs/documentation/simulation_capabilities/Event-Manager.md index 263b7448..7d317b89 100644 --- a/docs/documentation/simulation_capabilities/Event-Manager.md +++ b/docs/documentation/simulation_capabilities/Event-Manager.md @@ -1,3 +1,5 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Simulation Capabilities](Simulation-Capabilities) → Event Manager | +|------------------------------------------------------------------| This page describes the methods available in the Trick::EventManager and Trick::EventProcessor class. See [Input_File](/trick/documentation/running_a_simulation/Input-File) for detailed information on the syntax of the input processor file. diff --git a/docs/documentation/simulation_capabilities/Executive-Scheduler.md b/docs/documentation/simulation_capabilities/Executive-Scheduler.md index 5c8a2b8f..48c07af1 100644 --- a/docs/documentation/simulation_capabilities/Executive-Scheduler.md +++ b/docs/documentation/simulation_capabilities/Executive-Scheduler.md @@ -1,3 +1,5 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Simulation Capabilities](Simulation-Capabilities) → Executive Scheduler | +|------------------------------------------------------------------| This scheduler or derivative of this class is required for Trick simulations to run. @@ -203,10 +205,26 @@ If there is a job tag specified for one of more jobs in the S_define file, you c ``` # Python code -trick.exec_set_sim_object_onoff(char * job_name , int on) ; +trick.exec_set_sim_object_onoff(char * sim_object_name , int on) ; ``` -The exec_set_sim_object_onoff routine allows users to turn individual whole sim_objects on and off. +The exec_set_sim_object_onoff routine allows users to turn individual whole sim_objects on and off. If individiual jobs were disabled before the sim object is disabled, they will retain their disabled status when the sim object is turned back on. + +``` +# Python code +trick.exec_get_sim_object_onoff(char * sim_object_name) ; +``` + +The exec_get_sim_object_onoff routine allows users to determine if the sim_object is currently on or off. + + +``` +# Python code +trick.exec_set_sim_object_jobs_onoff(char * sim_object_name , int on) ; +``` + +The exec_set_sim_object_jobs_onoff allows users to turn all of the jobs in a sim_object on or off, but does not change the overall sim object's disabled status. + #### Job Cycle Time diff --git a/docs/documentation/simulation_capabilities/Frame-Logging.md b/docs/documentation/simulation_capabilities/Frame-Logging.md index 537e1e73..4f388baa 100644 --- a/docs/documentation/simulation_capabilities/Frame-Logging.md +++ b/docs/documentation/simulation_capabilities/Frame-Logging.md @@ -1,3 +1,5 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Simulation Capabilities](Simulation-Capabilities) → Frame Logging | +|------------------------------------------------------------------| Trick provides a means to gather simulation performance data and view it using Data Products (see [Data Products](Data-Products)). When the user turns on the Frame Logging feature, Trick will use its Data Recording mechanism to track the following: diff --git a/docs/documentation/simulation_capabilities/Input-Processor.md b/docs/documentation/simulation_capabilities/Input-Processor.md index d0ba447f..f0e011b9 100644 --- a/docs/documentation/simulation_capabilities/Input-Processor.md +++ b/docs/documentation/simulation_capabilities/Input-Processor.md @@ -1,3 +1,5 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Simulation Capabilities](Simulation-Capabilities) → Input Processor | +|------------------------------------------------------------------| This page describes the methods available in the Trick::InputProcessor class. See [Input File](../running_a_simulation/Input-File) for detailed information on the syntax of the input processor file. diff --git a/docs/documentation/simulation_capabilities/Integrator.md b/docs/documentation/simulation_capabilities/Integrator.md index 56382dd2..9b941325 100644 --- a/docs/documentation/simulation_capabilities/Integrator.md +++ b/docs/documentation/simulation_capabilities/Integrator.md @@ -1,3 +1,5 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Simulation Capabilities](Simulation-Capabilities) → Integrator | +|------------------------------------------------------------------| Trick provides a state integration capability described by the inputs below. To use these options a developer must develop application code which interfaces the application states with diff --git a/docs/documentation/simulation_capabilities/JIT-Input-Processor.md b/docs/documentation/simulation_capabilities/JIT-Input-Processor.md index eb4b91e8..b8777385 100644 --- a/docs/documentation/simulation_capabilities/JIT-Input-Processor.md +++ b/docs/documentation/simulation_capabilities/JIT-Input-Processor.md @@ -1,3 +1,6 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Simulation Capabilities](Simulation-Capabilities) → JIT Input Processor | +|------------------------------------------------------------------| + A JIT input file is a C++ input file that can be used along side a python input file, or even replace the python input file. The JIT input file includes "S_source.hh" that gives it access to the entire simulation. The code in a JIT input file is compiled into a shared library during simulation initialization. The simulation dynamically opens the shared library and runs a specific function called "run_me" that must be defined in the JIT input file. There are a couple of advantages to this type of input file. 1. Once compiled, a JIT input file is orders of magnitude faster to execute than a python equivalent. That is because there is no python is involved, everything is C++. diff --git a/docs/documentation/simulation_capabilities/Master-Slave.md b/docs/documentation/simulation_capabilities/Master-Slave.md index 2332fb70..1e798b06 100644 --- a/docs/documentation/simulation_capabilities/Master-Slave.md +++ b/docs/documentation/simulation_capabilities/Master-Slave.md @@ -1,3 +1,5 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Simulation Capabilities](Simulation-Capabilities) → Master/Slave | +|------------------------------------------------------------------| Master/Slave is a way to do distributed processing in Trick using multiple simulations. Master/Slave synchronization synchronizes a master simulation to one or more slave diff --git a/docs/documentation/simulation_capabilities/Realtime-Clock.md b/docs/documentation/simulation_capabilities/Realtime-Clock.md index 95064820..4f0571c0 100644 --- a/docs/documentation/simulation_capabilities/Realtime-Clock.md +++ b/docs/documentation/simulation_capabilities/Realtime-Clock.md @@ -1,3 +1,6 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Simulation Capabilities](Simulation-Capabilities) → Realtime Clock | +|------------------------------------------------------------------| + # Realtime-Clock **Contents** @@ -194,6 +197,6 @@ double exec_get_sim_time(void) ; defined in ```exec_proto.h```. - +Continue to [Realtime Timer](Realtime-Timer) \ No newline at end of file diff --git a/docs/documentation/simulation_capabilities/Realtime-Injector.md b/docs/documentation/simulation_capabilities/Realtime-Injector.md index e18db2a3..eb6f06ec 100644 --- a/docs/documentation/simulation_capabilities/Realtime-Injector.md +++ b/docs/documentation/simulation_capabilities/Realtime-Injector.md @@ -1,3 +1,5 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Simulation Capabilities](Simulation-Capabilities) → Realtime Injector | +|------------------------------------------------------------------| The Real Time Injector (RTI) allows the user to set simulation variables synchronously without impacting real-time performance. The RTI performs the injection diff --git a/docs/documentation/simulation_capabilities/Realtime-Timer.md b/docs/documentation/simulation_capabilities/Realtime-Timer.md index a2e09682..6ecdf360 100644 --- a/docs/documentation/simulation_capabilities/Realtime-Timer.md +++ b/docs/documentation/simulation_capabilities/Realtime-Timer.md @@ -1,3 +1,5 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Simulation Capabilities](Simulation-Capabilities) → Realtime Timer | +|------------------------------------------------------------------| A realtime sleep timer is an optional class for Trick simulations. diff --git a/docs/documentation/simulation_capabilities/Realtime.md b/docs/documentation/simulation_capabilities/Realtime.md index 3bd32c20..59bc4d11 100644 --- a/docs/documentation/simulation_capabilities/Realtime.md +++ b/docs/documentation/simulation_capabilities/Realtime.md @@ -1,3 +1,5 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Simulation Capabilities](Simulation-Capabilities) → Realtime | +|------------------------------------------------------------------| Trick provides a real-time processing capability which is different from many real-time simulation capabilities. The Trick executive is a "time based" executive and can run in diff --git a/docs/documentation/simulation_capabilities/STL-Checkpointing.md b/docs/documentation/simulation_capabilities/STL-Checkpointing.md deleted file mode 100644 index 606c896d..00000000 --- a/docs/documentation/simulation_capabilities/STL-Checkpointing.md +++ /dev/null @@ -1,5 +0,0 @@ - -Trick checkpoints the following STL types: array, vector, list, deque, set, multiset map, multimap, stack, queue, priority_queue, pair. - - -[Continue to Threads](Threads) diff --git a/docs/documentation/simulation_capabilities/STL-capabilities.md b/docs/documentation/simulation_capabilities/STL-capabilities.md new file mode 100644 index 00000000..d8737a93 --- /dev/null +++ b/docs/documentation/simulation_capabilities/STL-capabilities.md @@ -0,0 +1,113 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Simulation Capabilities](Simulation-Capabilities) → Using STLs in Trick Sims | +|------------------------------------------------------------------| + +# Standard Template Libraries (STL) in Trick + +STLs may be used in models. However, STL variables (currently) are not data recordable, visible in the variable server, nor directly accessible in the input file. Some STLs can be checkpointed: array, vector, list, deque, set, multiset, map, multimap, stack, queue, priority_queue, pair. + +STL classes cannot be directly registered with the memory manager, but they can be processed by the checkpoint agent when nested inside normal C++ classes (including sim objects). + +STL checkpoint restore may slow down the default data jobs of some sims. STL restore is on by default. To turn off STL restore: + +If using memory manager through the C interface: +``` +int TMM_set_stl_restore (int on_off); +``` + +If using the memory manager through the C++ interface, set the default or pass a parameter to your read_checkpoint function of choice: +``` +int set_restore_stls_default (bool on); +int read_checkpoint( std::istream* in_s, bool do_restore_stls = restore_stls_default); +int read_checkpoint_from_string( const char* s, bool do_restore_stls = restore_stls_default ); +int init_from_checkpoint( std::istream* in_s, bool do_restore_stls = restore_stls_default); +``` + +If using the checkpoint restart C interface: +``` +int load_checkpoint_stls( const char * file_name, int with_stls ) ; +``` + + + +## What works: + +To checkpoint an STL, it **must** be a member of a class or struct. +``` +class AnyClass { + std::vector vec; +} +``` +Declare an instance of this class with the memory manager in the usual way: +``` +AnyClass * my_class = tmm->declare_var("AnyClass my_alloc"); +``` + +If it is in a class that is nested in a `sim_object`, it will be registered with the memory manager automatically. + +You can nest an arbitrary amount of STLs, they will all be checkpointed as long as +the base is a member of a class that is registered with the memory manager. There +are a some known [**limitations**](#limitations). + +``` +class AnyClass { + std::pair> +} +``` + + + +## Limitations + +The STL checkpointing feature can only handle simple types, pointers, and nested STL types. + +### An STL type within a user defined type within an STL will fail to checkpoint. + +For example: a user defined class with an STL in it: +``` +class VectorWrapper { + int a; + std::vector vec; +} +``` + +An outer class (which is registered with the memory manager, like a member of a sim_object or something that has been explicitly declared) that has an STL container of these objects: +``` +class MyObject { + std::vector vec_user_defined; +} +``` + +If MyObject is populated, it will be able to checkpoint and restore without throwing an error, and all the `VectorWrapper` objects will be present, but `vec` will not be restored (`a` will restore successfully). The contents of `vec` are never written out to the checkpoint file. + + +If `MyObject` instead has a vector of pointers to `VectorWrapper`, and each `VectorWrapper` is registered with the memory manager, `vec` will checkpoint and restore successfully. +``` +class MyObject { + std::vector vec_user_defined_ptr; +} +``` + +### You cannot directly create or register an external stl with the memory manager, you will get a parser error. + +STLs can't register it with the memory manager, so there's no way for the checkpoint to know where the memory is. + +``` +class AnyClass { + std::vector *anything; +} + +class AnyClass { + std::pair[5]; +} + + +memorymanager->declare_var("std::vector my_vector_allocation"); + +std::vector my_vector; +memorymanager->declare_var_extern(&my_vector, "std::vector my_vector_allocation"); + +``` + + + +[Continue to Threads](Threads) diff --git a/docs/documentation/simulation_capabilities/Simulation-Capabilities.md b/docs/documentation/simulation_capabilities/Simulation-Capabilities.md index 8f4956b9..841c9f4f 100644 --- a/docs/documentation/simulation_capabilities/Simulation-Capabilities.md +++ b/docs/documentation/simulation_capabilities/Simulation-Capabilities.md @@ -1,4 +1,5 @@ - +| [Home](/trick) → [Documentation Home](../Documentation-Home) → Simulation Capabilities | +|------------------------------------------------------------------| This section details the runtime capabilities of Trick. diff --git a/docs/documentation/simulation_capabilities/Status-Message-System.md b/docs/documentation/simulation_capabilities/Status-Message-System.md index 8b4b75d6..1f4b4fc9 100644 --- a/docs/documentation/simulation_capabilities/Status-Message-System.md +++ b/docs/documentation/simulation_capabilities/Status-Message-System.md @@ -1,3 +1,5 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Simulation Capabilities](Simulation-Capabilities) → Status Message System | +|------------------------------------------------------------------| The Message Publisher publishes executive and/or model messages. A Message Subscriber gets the messages published by the Publisher. diff --git a/docs/documentation/simulation_capabilities/Threads.md b/docs/documentation/simulation_capabilities/Threads.md index ca2391c4..c032840b 100644 --- a/docs/documentation/simulation_capabilities/Threads.md +++ b/docs/documentation/simulation_capabilities/Threads.md @@ -1,3 +1,6 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Simulation Capabilities](Simulation-Capabilities) → Threads | +|------------------------------------------------------------------| + # The ThreadBase Class A trick sim is a multi-threaded process, and all of the threads that are created by Trick or Trick generated code inherit from the abstract class ThreadBase. ThreadBase classes have the capability to change the priority and cpu affinity of the thread. ThreadBase classes include trick_sys threads as well as user defined threads from the S_define: @@ -70,4 +73,5 @@ Set the priority for the thread. See the man page for sched(7) for more details. ```cpp int set_priority(unsigned int req_priority) ``` -[Continue to Simulation Utilities](/trick/documentation/simulation_utilities/Simulation-Utilities) + +[Continue to Web Server](../web/Webserver) diff --git a/docs/documentation/simulation_capabilities/UserGuide-Monte-Carlo.md b/docs/documentation/simulation_capabilities/UserGuide-Monte-Carlo.md index 409b5a50..39e746e2 100644 --- a/docs/documentation/simulation_capabilities/UserGuide-Monte-Carlo.md +++ b/docs/documentation/simulation_capabilities/UserGuide-Monte-Carlo.md @@ -1,5 +1,5 @@ -| [Home](Home) → [Documentation Home](Documentation-Home) → Monte Carlo | -|--------------------------------------------------------------------------------------| +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Simulation Capabilities](Simulation-Capabilities) → Monte Carlo | +|------------------------------------------------------------------| # Introduction Monte Carlo is an advanced simulation capability provided by Trick that allows users to repeatedly run copies of a simulation with different input values. Users can vary the input space of a simulation via input file, random value generation, or by calculating values from previous Monte Carlo runs in a process called optimization. diff --git a/docs/documentation/simulation_capabilities/Variable-Server.md b/docs/documentation/simulation_capabilities/Variable-Server.md index ff8a1684..6dc5824b 100644 --- a/docs/documentation/simulation_capabilities/Variable-Server.md +++ b/docs/documentation/simulation_capabilities/Variable-Server.md @@ -1,3 +1,5 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Simulation Capabilities](Simulation-Capabilities) → Variable Server | +|------------------------------------------------------------------| When running a Trick simulation, unless specifically turned off, a server called the "variable server" is always up and listening in a separate thread of execution. The @@ -61,6 +63,16 @@ trick.var_server_get_hostname() trick.var_server_get_port() ``` +Additional TCP or UDP sockets can be opened as well. Additional TCP sockets operate the same way as the original variable server socket. A UDP socket will only host 1 variable server session, and the responses will be sent to the latest address that sends commands to it. + +Note that this is not necessary to allow multiple variable server clients - any number of clients can connect to the original variable server port. + +```python +trick.var_server_create_udp_socket( const char * source_address, unsigned short port ) +trick.var_server_create_tcp_socket( const char * source_address, unsigned short port ) +``` + + ### Commands The variable server accepts commands in the form of strings. The variable server parses @@ -135,10 +147,10 @@ The frame refers to the software frame in the Executive. In freeze mode a diffe multiplier and offset are used. ```python -trick.var_set_frame_multiplier(int mult) +trick.var_set_frame_multiple(int mult) trick.var_set_frame_offset(int offset) -trick.var_set_freeze_frame_multiplier(int mult) +trick.var_set_freeze_frame_multiple(int mult) trick.var_set_freeze_frame_offset(int offset) ``` @@ -187,6 +199,22 @@ trick.var_send() The var_send command forces the variable server to return the list of values to the client immediately. +#### Sending variables only once and immediately + +```python +trick.var_send_once( string var_name) +``` + +The var_send_once command forces the variable server to return the value of the given +variable to the client immediately. + +```python +trick.var_send_once( string var_list, int num_vars) +``` + +var_send_once can also accept a comma separated list of variables. The number of variables +in this list must match num_vars, or it will not be processed. + #### Changing the Units ```python @@ -384,12 +412,17 @@ unprintable character) that occurs within the character string value will appear escaped character, i.e. preceded by a backslash. The 1st value returned in the list will always be a message indicator. The possible -values of the message indicator are: -- 0 returned variable value(s) from var_add or var_send -- 1 returned value from var_exists -- 2 returned value from send_sie_resource (special command used by Trick View) -- 3 returned value from send_event_data (special command used by Events/Malfunctions Trick View) or var_send_list_size -- 4 values redirected from stdio if var_set_send_stdio is enabled +values of the message indicator listen in the table below. + +| Name | Value | Meaning | +|-------------------|-------|---------| +| VS\_IP\_ERROR | -1 | Protocol Error| +| VS\_VAR\_LIST | 0 | A list of variable values. | +| VS\_VAR\_EXISTS | 1 | Response to var\_exists( variable_name )| +| VS\_SIE\_RESOURCE | 2 | Response to send_sie_resource| +| VS\_LIST\_SIZE | 3 | Response to var_send_list_size or send_event_data| +| VS\_STDIO | 4 | Values Redirected from stdio if var_set_send_stdio is enabled| +| VS\_SEND\_ONCE | 5 | Response to var\_send\_once| If the variable units are also specified along with the variable name in a var_add or var_units command, then that variable will also have its units specification returned following @@ -487,6 +520,8 @@ on your network sends it's information to this address and port so there may be messages with variable server information available here. Here is some C code that reads all messages on the variable server channel. +Note that the multicast protocol is disabled by default in MacOS. + ```c #include #include diff --git a/docs/documentation/simulation_capabilities/memory_manager/MemoryManager-Declaration-String.md b/docs/documentation/simulation_capabilities/memory_manager/MemoryManager-Declaration-String.md index 049f1e42..b122ad58 100644 --- a/docs/documentation/simulation_capabilities/memory_manager/MemoryManager-Declaration-String.md +++ b/docs/documentation/simulation_capabilities/memory_manager/MemoryManager-Declaration-String.md @@ -1,3 +1,7 @@ +| [Home](/trick) → [Documentation Home](../../Documentation-Home) → [Simulation Capabilities](../Simulation-Capabilities) → [Memory Manager](MemoryManager) → Declaration String| +|------------------------------------------------------------------| + + ### Memory Manager Declaration A declaration provides a data type description of a chunk of memory. diff --git a/docs/documentation/simulation_capabilities/memory_manager/MemoryManager-TRICK_TYPE.md b/docs/documentation/simulation_capabilities/memory_manager/MemoryManager-TRICK_TYPE.md index c052d5e6..43c83ccb 100644 --- a/docs/documentation/simulation_capabilities/memory_manager/MemoryManager-TRICK_TYPE.md +++ b/docs/documentation/simulation_capabilities/memory_manager/MemoryManager-TRICK_TYPE.md @@ -1,3 +1,5 @@ +| [Home](/trick) → [Documentation Home](../../Documentation-Home) → [Simulation Capabilities](../Simulation-Capabilities) → [Memory Manager](MemoryManager) → Trick Type| +|------------------------------------------------------------------| - **TRICK_TYPE** is an enmeration type that specifies data types. Available types are provided in the following table. diff --git a/docs/documentation/simulation_capabilities/memory_manager/MemoryManager.md b/docs/documentation/simulation_capabilities/memory_manager/MemoryManager.md index 3ff0106f..7419ad72 100644 --- a/docs/documentation/simulation_capabilities/memory_manager/MemoryManager.md +++ b/docs/documentation/simulation_capabilities/memory_manager/MemoryManager.md @@ -1,3 +1,6 @@ +| [Home](/trick) → [Documentation Home](../../Documentation-Home) → [Simulation Capabilities](../Simulation-Capabilities) → Memory Manager | +|------------------------------------------------------------------| + ## Trick Memory Manager The Memory Manager diff --git a/docs/documentation/simulation_utilities/Math-Utilities.md b/docs/documentation/simulation_utilities/Math-Utilities.md index b2a5855a..d794a179 100644 --- a/docs/documentation/simulation_utilities/Math-Utilities.md +++ b/docs/documentation/simulation_utilities/Math-Utilities.md @@ -1,3 +1,6 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Simulation Utilities](Simulation-Utilities) → Math Utilities | +|------------------------------------------------------------------| + To be added. [Continue to Miscellaneous Trick Tools](../miscellaneous_trick_tools/Miscellaneous-Trick-Tools) diff --git a/docs/documentation/simulation_utilities/Simulation-Utilities.md b/docs/documentation/simulation_utilities/Simulation-Utilities.md index 020b2ed2..a1b72c08 100644 --- a/docs/documentation/simulation_utilities/Simulation-Utilities.md +++ b/docs/documentation/simulation_utilities/Simulation-Utilities.md @@ -1,3 +1,6 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → Simulation Utilities | +|------------------------------------------------------------------| + This section details the simulation utilities of Trick. Simulation utilities provide a service to user models. These included a socket communication library, Trickcomm, as well as math routines, units conversion routines, and some abstract data types written in C. diff --git a/docs/documentation/simulation_utilities/Trickcomm.md b/docs/documentation/simulation_utilities/Trickcomm.md index 069a26f8..617b4c37 100644 --- a/docs/documentation/simulation_utilities/Trickcomm.md +++ b/docs/documentation/simulation_utilities/Trickcomm.md @@ -1,3 +1,5 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Simulation Utilities](Simulation-Utilities) → TrickComm | +|------------------------------------------------------------------| To be added. diff --git a/docs/documentation/web/Configure-Civetweb.md b/docs/documentation/web/Configure-Civetweb.md new file mode 100644 index 00000000..19ddf882 --- /dev/null +++ b/docs/documentation/web/Configure-Civetweb.md @@ -0,0 +1,26 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Web Server](Webserver) → Configuring Trick with Civetweb | +|------------------------------------------------------------------| + +## Configuring Trick with Civetweb +To configure Trick to support the civetweb web server, you'll need to + +1. Download or clone Civetweb release (currently v1.15) from [Github](https://github.com/civetweb/civetweb). Where you put the Civetweb directory will be designated as $(CIVETWEB_HOME). + +2. Build the Civetweb library. +3. Configure Trick. + +### Building the Civetweb Library +```bash +cd $(CIVETWEB_HOME) +mkdir lib +make install-lib PREFIX=. CAN_INSTALL=1 WITH_WEBSOCKET=1 +``` +### Configuring Trick with Civetweb +```bash +cd $(TRICK_HOME) +./configure --with-civetweb=$(CIVETWEB_HOME) +make clean +make +``` + +Continue to [Adding SSL Encryption](SSL) \ No newline at end of file diff --git a/docs/documentation/web/Configuring_TRICK_with_Civetweb.md b/docs/documentation/web/Configuring_TRICK_with_Civetweb.md deleted file mode 100644 index 36e2ffae..00000000 --- a/docs/documentation/web/Configuring_TRICK_with_Civetweb.md +++ /dev/null @@ -1,21 +0,0 @@ -## Configuring Trick with Civetweb -To configure Trick to support the civetweb web server, you'll need to - -1. Download Civetweb from [Github](https://github.com/civetweb/civetweb). Where you put the Civetweb directory will be designated as $(CIVETWEB_HOME). - -2. Build the Civetweb library. -3. Configure Trick. - -### Building the Civetweb Library -```bash -cd $(CIVETWEB_HOME) -mkdir lib -make install-lib PREFIX=. CAN_INSTALL=1 WITH_WEBSOCKET=1 -``` -### Configuring Trick with Civetweb -```bash -cd $(TRICK_HOME) -./configure --with-civetweb=$(CIVETWEB_HOME) -make clean -make -``` diff --git a/docs/documentation/web/Extending_the_HTTP-API.md b/docs/documentation/web/Extend-http-api.md similarity index 89% rename from docs/documentation/web/Extending_the_HTTP-API.md rename to docs/documentation/web/Extend-http-api.md index 0c114d67..087b39c9 100644 --- a/docs/documentation/web/Extending_the_HTTP-API.md +++ b/docs/documentation/web/Extend-http-api.md @@ -1,3 +1,6 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Web Server](Webserver) → [APIs](WebServerAPIs) → Extending the HTTP API | +|------------------------------------------------------------------| + ## Extending the HTTP-API The HTTP-API is implemented as a collection of ```httpMethodHandlers```. An ```httpMethodHandler``` is a pointer to a function that is expected to respond to an HTTP GET request, using the **CivetWeb** framework. An ```httpMethodHandler``` is defined (in ```trick/CivetWeb.hh```) as follows: @@ -113,3 +116,5 @@ void create_connections() { } ``` + +Continue to [Extending the WS API](Extend-ws-api) \ No newline at end of file diff --git a/docs/documentation/web/Extending_the_WS-API.md b/docs/documentation/web/Extend-ws-api.md similarity index 95% rename from docs/documentation/web/Extending_the_WS-API.md rename to docs/documentation/web/Extend-ws-api.md index a82c47c4..13c35b7e 100644 --- a/docs/documentation/web/Extending_the_WS-API.md +++ b/docs/documentation/web/Extend-ws-api.md @@ -1,3 +1,6 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Web Server](Webserver) → [APIs](WebServerAPIs) → Extend the WS API | +|------------------------------------------------------------------| + ## Extending the WebSocket-API ## When You Create a WebSocket Connection @@ -145,7 +148,7 @@ void TimeSession::sendMessage() { int month = theTime->tm_mon + 1; int year = theTime->tm_year + 1900; - sprintf(message, "Time: %02d:%02d:%02d Date: %02d/%02d/%d\n", hours, minutes, seconds, month, day, year); + snprintf(message, sizeof(message), "Time: %02d:%02d:%02d Date: %02d/%02d/%d\n", hours, minutes, seconds, month, day, year); mg_websocket_write(connection, MG_WEBSOCKET_OPCODE_TEXT, message, strlen(message)); } @@ -267,6 +270,4 @@ To test your new web socket interface, put the following ```time.html``` file in ``` - - - +Continue to [Simulation Utilities](../simulation_utilities/Simulation-Utilities) diff --git a/docs/documentation/web/Adding_SSL_encryption_to_Your_Webserver.md b/docs/documentation/web/SSL.md similarity index 81% rename from docs/documentation/web/Adding_SSL_encryption_to_Your_Webserver.md rename to docs/documentation/web/SSL.md index e4808818..e45b3d20 100644 --- a/docs/documentation/web/Adding_SSL_encryption_to_Your_Webserver.md +++ b/docs/documentation/web/SSL.md @@ -1,3 +1,6 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Web Server](Webserver) → Adding SSL Encryption to your Webserver | +|------------------------------------------------------------------| + # Adding SSL Encryption to Your Webserver ## Getting started @@ -34,3 +37,5 @@ Where server.pem is the path to the server.pem file you created when creating a ## Access your webserver Now that ssl encryption is enabled, to access you webserver use https://localhost.ssl:8888 instead of http and wss://localhost.ssl:8888 for http and ws protocals respectively. + +Continue to [Web Server APIs](Webserver-apis) diff --git a/docs/documentation/web/Webserver-apis.md b/docs/documentation/web/Webserver-apis.md new file mode 100644 index 00000000..da0aaa3b --- /dev/null +++ b/docs/documentation/web/Webserver-apis.md @@ -0,0 +1,12 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Web Server](Webserver) → APIs | +|------------------------------------------------------------------| + +# Web Server APIs + +The web server provides APIs over http and wss protocol. Both can be extended by a client developer if necessary. + +API Documentation Pages +- [HTTP Alloc API](http-alloc-api) +- [WS Variable Server API](ws-variable-server-api) +- [Extending the HTTP API](Extend-http-api) +- [Extending the WS API](Extend-ws-api) \ No newline at end of file diff --git a/docs/documentation/web/Adding_a_Web_Server_to_Your_Sim.md b/docs/documentation/web/Webserver.md similarity index 91% rename from docs/documentation/web/Adding_a_Web_Server_to_Your_Sim.md rename to docs/documentation/web/Webserver.md index 50a1abf4..f854ac1d 100644 --- a/docs/documentation/web/Adding_a_Web_Server_to_Your_Sim.md +++ b/docs/documentation/web/Webserver.md @@ -1,6 +1,9 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → Web Server | +|------------------------------------------------------------------| + # Adding a Web Server to Your Sim -If Trick is [configured with Civetweb](Configuring_TRICK_with_Civetweb.md), +If Trick is [configured with Civetweb](Configure-Civetweb.md), adding a web server to your simulation simply requires including the CivetServer sim module into your **S_define** file: ``` @@ -77,3 +80,4 @@ The **images** directory contains trick_icon.png. **You are encouraged to add to, modify, and/or delete these files and directories to best suite the needs of your project.** +Continue to [Configuring Trick with Civetweb](Configure-Civetweb) diff --git a/docs/documentation/web/HTTP-API_alloc_info.md b/docs/documentation/web/http-alloc-api.md similarity index 92% rename from docs/documentation/web/HTTP-API_alloc_info.md rename to docs/documentation/web/http-alloc-api.md index 3cb9a90c..89be2be9 100644 --- a/docs/documentation/web/HTTP-API_alloc_info.md +++ b/docs/documentation/web/http-alloc-api.md @@ -1,16 +1,19 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Web Server](Webserver) → [APIs](WebServerAPIs) → HTTP Alloc API | +|------------------------------------------------------------------| + # HTTP-API: alloc_info -```http://localhost:8888/api/http/alloc_info``` +```http://localhost:8888/api/http/alloc_info``` ## Purpose -Request a JSON encoded sub-list of allocation descriptors from the Memory Manager’s alloc_info list. +Request a JSON encoded sub-list of allocation descriptors from the Memory Manager’s alloc_info list. ## Query String Parameters | Parameter|Default|Description | -|-------------|----|----------------------------------| -| ```start``` | 0 | starting index of the sub-list. | -| ```count``` | 20 | number of allocation descriptors.| +|-------------|----|----------------------------------| +| ```start``` | 0 | starting index of the sub-list. | +| ```count``` | 20 | number of allocation descriptors.| ### EXAMPLE: @@ -20,11 +23,11 @@ Request a JSON encoded sub-list of allocation descriptors from the Memory Manage Returns a JSON object containing four name-value pairs: -### JSON Response Object +### JSON Response Object | Name | Value Description | -|-------------------|-----------------------------------------| -| ```alloc_total``` | Total number allocations in the Memory Manager’s alloc_info list. | +|-------------------|-----------------------------------------| +| ```alloc_total``` | Total number allocations in the Memory Manager’s alloc_info list. | | ```chunk_size``` | Number of allocation description objects in ```alloc_list```. | | ```chunk_start``` | The Memory Manager alloc_info index of the first ```alloc_list``` element below| | ```alloc_list``` | Array of JSON Allocation Description objects (described below). | @@ -33,8 +36,8 @@ Returns a JSON object containing four name-value pairs: ### JSON Allocation Description Object | Name | Value Description | -|---------------|---------------------------------------------------------------------------------| -| ```name``` | Name of the allocation. May be ```Null``` | +|---------------|---------------------------------------------------------------------------------| +| ```name``` | Name of the allocation. May be ```Null``` | | ```start``` | Starting address of the allocation. | | ```end``` | Ending address of the allocation. | | ```num``` | | @@ -56,32 +59,34 @@ In ```SIM_cannon_numeric``` (one of Trick's example sims) the following query re #### Response ```json -{ "alloc_total":43, - "chunk_size":2, - "chunk_start":20, - "alloc_list":[ - { "name":"dyn", - "start":"0x101aa9900", - "end":"0x101aa9b27", - "num":"1", - "size":"552", - "type":"CannonSimObject", - "stcl":"TRICK_EXTERN", - "language":"Language_CPP", - "index": [] - } - , - { "name":"web", - "start":"0x101aa9610", - "end":"0x101aa98ff", - "num":"1", - "size":"752", - "type":"WebServerSimObject", - "stcl":"TRICK_EXTERN", - "language":"Language_CPP", - "index": [] - } - ] -} +{ "alloc_total":43, + "chunk_size":2, + "chunk_start":20, + "alloc_list":[ + { "name":"dyn", + "start":"0x101aa9900", + "end":"0x101aa9b27", + "num":"1", + "size":"552", + "type":"CannonSimObject", + "stcl":"TRICK_EXTERN", + "language":"Language_CPP", + "index": [] + } + , + { "name":"web", + "start":"0x101aa9610", + "end":"0x101aa98ff", + "num":"1", + "size":"752", + "type":"WebServerSimObject", + "stcl":"TRICK_EXTERN", + "language":"Language_CPP", + "index": [] + } + ] +} -``` \ No newline at end of file +``` + +Continue to [WS Variable Server API](ws-variable-server-api) \ No newline at end of file diff --git a/docs/documentation/web/WS-API_VariableServer.md b/docs/documentation/web/ws-variable-server-api.md similarity index 94% rename from docs/documentation/web/WS-API_VariableServer.md rename to docs/documentation/web/ws-variable-server-api.md index ac98271e..9b294bc5 100644 --- a/docs/documentation/web/WS-API_VariableServer.md +++ b/docs/documentation/web/ws-variable-server-api.md @@ -1,3 +1,6 @@ +| [Home](/trick) → [Documentation Home](../Documentation-Home) → [Web Server](Webserver) → [APIs](WebServerAPIs) → WS Variable Server API | +|------------------------------------------------------------------| + # WS-API: VariableServer ```ws://localhost:8888/api/ws/VariableServer``` @@ -18,62 +21,62 @@ Add a Trick Variable to the current session. Stop sending periodic ```var_list``` messages (*see below*) from the server. ```json -{ "cmd" : "var_pause" } +{ "cmd" : "var_pause" } ``` Resume sending periodic ```var_list``` response messages from the server. ```json -{ "cmd" : "var_unpause" } - +{ "cmd" : "var_unpause" } + ``` Send one ```var_list``` message from the server. ```json -{ "cmd" : "var_send" } +{ "cmd" : "var_send" } ``` Clear all variables from the current session, that is: undo all of the ```var_add``` commands. ```json -{ "cmd" : "var_clear" } +{ "cmd" : "var_clear" } ``` Disconnect from the variable server. ```json -{ "cmd" : "var_exit" } +{ "cmd" : "var_exit" } ``` Set the period (in milliseconds) at which ```var_list``` messages are sent form the server. ```json -{ "cmd" : "var_cycle", - "period" : integer -} +{ "cmd" : "var_cycle", + "period" : integer +} ``` Execute the given Python code in the host sim. ```json -{ "cmd" : "python", - "pycode" : string -} +{ "cmd" : "python", + "pycode" : string +} ``` Send the sie structure from the server. Response will be the ```sie``` response message (*below*). ```json -{ "cmd" : "sie" } +{ "cmd" : "sie" } ``` Send the units for the given variable. Response will be the ```units``` response message (*below*). ```json -{ "cmd" : "units", - "var_name" : string -} +{ "cmd" : "units", + "var_name" : string +} ``` ## Server to Client Response Messages @@ -81,34 +84,34 @@ Send the units for the given variable. Response will be the ```units``` response Error Response ```json -{ "msg_type" : "error", - "error_text" : string +{ "msg_type" : "error", + "error_text" : string } ``` Periodic response containing the values of variables requested by ```var_add```. ```json -{ "msg_type" : "var_list" - "time" : double - "values" : [] +{ "msg_type" : "var_list" + "time" : double + "values" : [] } ``` Response to the ```sie``` command (*above*). ```json -{ "msg_type" : "sie", - "data" : string +{ "msg_type" : "sie", + "data" : string } ``` Response to the ```units``` command (*above*). ```json -{ "msg_type" : "units", - "var_name" : string, - "data" : string +{ "msg_type" : "units", + "var_name" : string, + "data" : string } ``` @@ -208,3 +211,5 @@ Response to the ```units``` command (*above*). ``` + +Continue to [Extending the HTTP API](Extend-http-api) \ No newline at end of file diff --git a/docs/faq/FAQ.md b/docs/faq/FAQ.md index 3def87d8..8ff1d1cc 100644 --- a/docs/faq/FAQ.md +++ b/docs/faq/FAQ.md @@ -71,7 +71,12 @@ MathWorks developed a package to generate Trick friendly code from their models. ### Core Flight Software (CFS) -Trick and CFS can work together, but the software interfacing Trick and CFS is neither actively maintained nor open source. + +cFS support for Trick is provided by the following external projects: + +* [TVS-IO](https://github.com/nasa/tvsio) is an open-source, Core Flight Software (cFS) application that provides for two-way communication between a **cFS** Software Bus Network (SBN) and a Trick simulation. + +* Another soon to be released capability, presumably called TrickCFS should also be available soon as open-source software. Stay-tuned. @@ -175,4 +180,7 @@ var = trick.var_get("my_sim_object.b.a[1].t") ## Is Trick gluten-free, grass-fed, organic, non-GMO, environmentally conservative, free-range, vegan, and dolphin safe? -Yes. + +Trick is composed entirely of information. It contains no matter, organic or otherwise. Therefore Trick contains no gluten, +GMOs, nor is it fed by grass, vegetables, or meat. Trick could be described as environmentally conservative in that it runs on numerous POSIX (Unix-like) operating systems. Trick is of course free-range! It's Opensource!, and freely available to anyone, even dolphins with internet access. + diff --git a/docs/howto_guides/How-To-Containerize-Trick-with-Docker.md b/docs/howto_guides/How-To-Containerize-Trick-with-Docker.md new file mode 100644 index 00000000..b7d5aee6 --- /dev/null +++ b/docs/howto_guides/How-To-Containerize-Trick-with-Docker.md @@ -0,0 +1,381 @@ +# How to "Containerize" Trick With Docker + +This HOWTO assumes that we building our Docker images on a Linux system. If you're using +MacOS or Windows, the translation should hopefully be fairly straight forward. + +**Contents** + +* [Containerize a Basic Trick Environment](#containerize-a-basic-trick-environment) +* [Containerize a Trick Simulation](#containerize-a-trick-simulation) + +*** + +## Prerequisites: + +* Docker is installed on your machine. +* A basic familiarity with Docker. ["A Docker Tutorial for Beginners"](https://docker-curriculum.com) is an excellent way. +* A basic familiarity with bash shell scripting. + +## Create a Place to Build Our Docker Images + +For this HOWTO we'll try to stay organized by first creating a directory in +which we can build our Docker images. Let's also create and environment +variable for this directory. + +* Create the **DockerPlayGround** directory and **DOCKER_PLAYGROUND** environment variable. + +```bash +mkdir DockerPlayGround +export DOCKER_PLAYGROUND="`pwd`/DockerPlayGround" +``` + +## Containerize a Basic Trick Environment + +In this example we'll build a Docker image, based on Ubuntu 18.04, with Trick 19.5.1 +installed. + +### Dockerfile + +```docker +# ------------------------------------------------------------------------------ +# The image we are building with THIS Dockerfile is based on the ubuntu:18.04 +# Docker image from dockerhub (hub.docker.com). +# ------------------------------------------------------------------------------ +FROM ubuntu:18.04 + +# ------------------------------------------------------------------------------ +# Install Trick Dependencies identified at +# https://nasa.github.io/trick/documentation/install_guide/Install-Guide#ubuntu +# ------------------------------------------------------------------------------ +RUN apt-get update && apt-get install -y \ +bison \ +clang \ +flex \ +git \ +llvm \ +make \ +maven \ +swig \ +cmake \ +curl \ +g++ \ +libx11-dev \ +libxml2-dev \ +libxt-dev \ +libmotif-common \ +libmotif-dev \ +python3-dev \ +zlib1g-dev \ +llvm-dev \ +libclang-dev \ +libudunits2-dev \ +libgtest-dev \ +openjdk-11-jdk \ +zip + +ENV PYTHON_VERSION=3 + +# ------------------------------------------------------------------------------ +# Get Trick version 19.5.1 from GitHub, configure and build it. +# ------------------------------------------------------------------------------ +# We want to clone Trick into the /apps directory of our image. +WORKDIR /apps +# Get the 19.5.1 branch (an official release) of Trick from Github. +RUN git clone -b 19.5.1 https://github.com/nasa/trick.git +# cd into the directory we just created and .. +WORKDIR /apps/trick +# configure and make Trick. +RUN ./configure && make + +# ------------------------------------------------------------------------------ +# Add ${TRICK_HOME}/bin to the PATH variable. +# ------------------------------------------------------------------------------ +ENV TRICK_HOME="/apps/trick" +RUN echo "export PATH=${PATH}:${TRICK_HOME}/bin" >> ~/.bashrc + +CMD ["/bin/bash"] +``` + +### Building the docker image: + +* Create a directory for building this docker image: + + ```bash + cd ${DOCKER_PLAYGROUND} + mkdir TRICK_19_5_1 + cd TRICK_19_5_1 + ``` + +* Create a file named ```Dockerfile``` that contains the content listed above. + +* Build the Docker image by executing: ```docker build --tag trick:19.5.1 .``` + + :exclamation: This may take a few minutes. + +* When the build completes, execute : ```docker images```. + + You should see a record of the image that you just created: + + ``` + REPOSITORY TAG IMAGE ID CREATED SIZE + trick 19.5.1 1023a17d7b78 2 minutes ago 2.61GB + ``` + +### Running the docker image: +To Instantiate a container from the image: ```docker run --rm -it trick:19.5.1``` + +You should see the bash shell prompt from your container. Something like: + +``` +root@8615d8bf75c5:/apps/trick# +``` + +Execute: ```ls``` at the prompt to see that it contains Trick. + +``` +CMakeLists.txt Makefile autoconf configure lib test_overrides.mk trickops.py +CMakeModules. README.md bin docs libexec test_sims.yml trigger +CMakeTestFiles TrickLogo.png config.log doxygen share trick_sims +LICENSE TrickLogo_darkmode.png. config.status include test trick_source +root@8615d8bf75c5:/apps/trick# +``` + +This docker container contains a full Trick development environment. You can't run GUI applications on it but you can build a simulation. + + +## Containerize a Trick Simulation + +### Prerequisites: + +* The trick:19.5.1 docker image described above. + +## Introduction + +In this example, we'll create a docker image from which we can run (a version of) ```SIM_cannon_numeric```, +one of the variants of Trick's Cannon Ball simulation. This image will be based on the Trick:19.5.1 image the we previously built. + +Our containerized simulation won't start any variable server clients like the sim-control panel or graphics clients, because we can't easily run graphics clients from __within__ the container. But, we __can__ easily connect graphics clients running on the host machine to our containerized simulation. + +### Creating a Docker friendly version of ```SIM_cannon_numeric``` + +* Create a directory for building this docker image: + + ```bash + cd ${DOCKER_PLAYGROUND} + mkdir SIM_cannon_docker_build + cd SIM_cannon_docker_build + ``` + +* Create a directory for our version of SIM_cannon. + + ```bash + mkdir SIM_cannon_docker + cd SIM_cannon_docker + ``` + +* Copy the ```SIM_cannon_numeric``` **S_define** file into the current directory. + + ```bash + curl -O https://raw.githubusercontent.com/nasa/trick/19.5.1/trick_sims/Cannon/SIM_cannon_numeric/S_define + ``` + +* Copy ```SIM_cannon_numeric``` include files. + + ```bash + curl --create-dirs --output models/cannon/gravity/include/cannon.h \ + https://raw.githubusercontent.com/nasa/trick/19.5.1/trick_sims/Cannon/models/cannon/gravity/include/cannon.h + curl --create-dirs --output models/cannon/gravity/include/cannon_numeric.h \ + https://raw.githubusercontent.com/nasa/trick/19.5.1/trick_sims/Cannon/models/cannon/gravity/include/cannon_numeric.h + ``` + +* Copy ```SIM_cannon_numeric``` source files. + + ```bash + curl --create-dirs --output models/cannon/gravity/src/cannon_init.c \ + https://raw.githubusercontent.com/nasa/trick/19.5.1/trick_sims/Cannon/models/cannon/gravity/src/cannon_init.c + curl --create-dirs --output models/cannon/gravity/src/cannon_numeric.c \ + https://raw.githubusercontent.com/nasa/trick/19.5.1/trick_sims/Cannon/models/cannon/gravity/src/cannon_numeric.c + ``` + +* Create a file named ```S_overrides.mk ``` that contains the following content: + + ```make + TRICK_CFLAGS += -Imodels + TRICK_CXXFLAGS += -Imodels + ``` + +* Create and enter a directory named ```RUN_demo``` and enter it: + + ```bash + mkdir RUN_demo + cd RUN_demo + ``` + +* Create a file named ```input.py ``` that contains the following content: + + ```python + trick.real_time_enable() + trick.exec_set_software_frame(0.1) + trick.itimer_enable() + trick.var_server_set_port(9001) + ``` + + :exclamation: Notice that we are NOT starting a SIM-control-panel, or the graphics client. + + :exclamation: Notice that we are explicitly setting the variable server listen port. + + +### The Graphics Client + + Even though the simulation won't be starting the graphics clients, we will be starting and connecting the graphics clients to the containerized simulation. + + * Download the graphics client's source and Makefile. + + ```bash + cd ${DOCKER_PLAYGROUND}/SIM_cannon_docker_build/SIM_cannon_docker + curl --create-dirs --output models/graphics/src/CannonDisplay.java \ + https://raw.githubusercontent.com/nasa/trick/19.5.1/trick_sims/Cannon/models/graphics/src/CannonDisplay.java + curl --create-dirs --output models/graphics/Makefile \ + https://raw.githubusercontent.com/nasa/trick/19.5.1/trick_sims/Cannon/models/graphics/Makefile + ``` + + * Down-load the graphics client's sound files. + + There are two sound files necessary to build the graphics client, 1) **CannonBoom.wav**, and 2) **Explosion.wav** . + They both need to be placed into ```models/graphics/resources/```. + + * Create the resources directory. + + ``` + mkdir -p models/graphics/resources + ``` + * Down-load the sound files. + + Unfortunately, binary files are more difficult to down-load from Github than text files. + + For each, we have to go to their respective Github pages and click the "Download" button. + + * Download CannonBoom.wav from [here](https://github.com/nasa/trick/blob/master/trick_sims/Cannon/models/graphics/resources/CannonBoom.wav). + + * Download Explosion.wav from [here](https://github.com/nasa/trick/blob/master/trick_sims/Cannon/models/graphics/resources/Explosion.wav). + +:exclamation: When you download the wave files from Github, their names may be set to a flattened version of their full pathnames. So, we have to rename them to their real names. + + * Rename the down-loaded wave files to **CannonBoom.wav**, and **Explosion.wav** respectively, and move them both to ```models/graphics/resources/```. + + + +* Build the cannon graphics client. + + ```bash + cd ${DOCKER_PLAYGROUND}/SIM_cannon_docker_build/SIM_cannon_docker/models/graphics + make + ``` + +### Building the Docker Image + + +#### Dockerfile + +``` +# ------------------------------------------------------------------------------ +# The image we are building with THIS Dockerfile is based on the trick:19.5.1 +# Docker image that we built previously. +# ------------------------------------------------------------------------------ +FROM trick:19.5.1 + +# ------------------------------------------------------------------------------ +# Copy the simulation source code into the image and build it. +# ------------------------------------------------------------------------------ +# Set current working directory to the directory where we want our SIM code. +WORKDIR /apps/SIM_cannon +# Copy the simulation source code from our (host) image-build directory into our +# image. +COPY SIM_cannon_docker . +# Build the SIM. +RUN /apps/trick/bin/trick-CP + +# In out simulation, we decided to use port 9001 for our +# variable server port. We did this by adding +# "trick.var_server_set_port(9001)" to our input file. + +#Expose the variable server port. +EXPOSE 9001/tcp + +# Make a script to run SIM_cannon from the /apps directory. +RUN echo "#! /bin/bash" >> /apps/run_sim.sh +RUN echo "cd /apps/SIM_cannon" >> /apps/run_sim.sh +RUN echo "./S_main_Linux_7.5_x86_64.exe RUN_demo/input.py" >> /apps/run_sim.sh +RUN chmod +x /apps/run_sim.sh + +CMD ["/apps/run_sim.sh"] +``` + +* Make sure you're in the right directory. + +```bash + cd ${DOCKER_PLAYGROUND}/SIM_cannon_docker_build +``` + +* Create a file named ```Dockerfile``` that contains the content listed above. + +* Build the Docker image by executing: ```docker build --tag sim_cannon_docker .``` + +* When the build completes, execute : ```docker images```. + + You should see a record of the image that you just created: + + ``` + REPOSITORY TAG IMAGE ID CREATED SIZE + sim_cannon_docker latest d4547502c2a4 13 seconds ago 2.61GB + trick 19.5.1 1023a17d7b78 2 minutes ago 2.61GB + ``` + +### Running the docker image: +To instanciate a container from the image: ```docker run --name misterbill --rm -P sim_cannon_docker &``` + +* In a host terminal (not in the container) execute: + + ```bash + docker port misterbill + ``` + +to see what host-port container-port 9001 has been mapped to. + +You should see something like: + +``` + 9001/tcp -> 0.0.0.0:32783 + 9001/tcp -> [::]:32783 +``` + +This shows that port 9001 in our container has been mapped to port 32783 +on our host computer. So, in this case we would connect our (host) +java client to port 32783. + +To connect the CannonDisplay variable-server client to the containerized simulation: + +```bash +java -jar SIM_cannon_docker/models/graphics/dist/CannonDisplay.jar & +``` + +:warning: Don't just copy and paste. If you don't put the right port number it won't work. + + +![](images/cannon_display.png) + +* Click **RELOAD**. This re-initializes the cannon. Then click **FIRE**. The cannon will fire. +* Adjust the the controls on the left hand side of the graphics client. **RELOAD** and **FIRE**. +* Do this until you're bored. + +If Trick is installed on your host then you can also connect : + +```bash +trick-simcontrol localhost & +``` + +You can shut down the sim from the trick-simcontrol panel when you're done. +or if you don't have Trick installed, just use: ```docker kill misterbill```. + +# THE END + diff --git a/docs/howto_guides/How-To-Guides.md b/docs/howto_guides/How-To-Guides.md index 1f99ae06..db099956 100644 --- a/docs/howto_guides/How-To-Guides.md +++ b/docs/howto_guides/How-To-Guides.md @@ -7,3 +7,5 @@ 01. [How do I exclude code from being processed by Trick?](How-To-Exclude-Code) 01. [How do I create a model library to save compilation time?](/trick/documentation/building_a_simulation/Trickified-Project-Libraries) 01. [How do I use inherited templates in the input file?](How-To-Use-Inherited-Templates) +01. [How to Dump a Core-file on MacOS](How-to-dump-core-file-on-MacOS) +01. [How to Containerize Trick with Docker](How-To-Containerize-Trick-with-Docker) \ No newline at end of file diff --git a/docs/howto_guides/How-to-dump-core-file-on-MacOS.md b/docs/howto_guides/How-to-dump-core-file-on-MacOS.md new file mode 100644 index 00000000..e9c43654 --- /dev/null +++ b/docs/howto_guides/How-to-dump-core-file-on-MacOS.md @@ -0,0 +1,68 @@ +# How to Dump a Core File on MacOS (Monterey 12.5) + +A core dump (file) records the memory and state of a program at some moment in time, usually when it terminates abnormally. Core dumps can be useful in debugging in certain situations. + +On MacOS, the ability to dump a core file must be enabled. The following steps describe how. + +### 1. Ensure ```/cores``` Directory is Writable +Core-files are stored in the ```/cores``` directory on MacOS. You must have permission to write to it. To ensure this: + +```% sudo chmod 1777 /cores``` + +### 2. Set Kernel State to Allow Core-dumps +The kernel state variable ```kern.coredump``` must be set in order to dump core-files. This needs to be set only once; it is persistent between reboots. To set it: + +```% sudo sysctl kern.coredump=1``` + +To check its current value: + +```% sudo sysctl kern.coredump``` + +### 3. Code-sign the Executable + +For an executable to dump a core-file it must be signed. To do this, create an ```.entitlements``` file with the com.apple.security.get-task-allow entitlement set: + +```/usr/libexec/PlistBuddy -c "Add :com.apple.security.get-task-allow bool true" segv.entitlements``` + +Using this ```.entitlements``` file, sign the executable: + +```codesign -s - -f --entitlements segv.entitlements segv``` + +### 4. Set ```ulimit -c unlimited``` + +Before running the executable from which you want a core-dump run the following : + +```% ulimit -c unlimited``` + +This sets shell resources necessary for a core-dump. This setting is not persistent between shells. + +## Example Code: + + +### segv.c + +```C +int main() { + int *p = (void*)0; + *p = 0; + return 0; +} +``` + +### makefile + +```Makefile +all: segv + +segv: segv.c segv.entitlements + clang -g segv.c -o segv + codesign -s - -f --entitlements segv.entitlements segv + +segv.entitlements: + /usr/libexec/PlistBuddy -c "Add :com.apple.security.get-task-allow bool true" segv.entitlements + +clean: + rm segv + rm segv.entitlements + rm -rf segv.dSYM +``` diff --git a/docs/howto_guides/images/cannon_display.png b/docs/howto_guides/images/cannon_display.png new file mode 100755 index 00000000..5f70b7d4 Binary files /dev/null and b/docs/howto_guides/images/cannon_display.png differ diff --git a/docs/index.md b/docs/index.md index 994345b5..0801eaa6 100644 --- a/docs/index.md +++ b/docs/index.md @@ -42,6 +42,20 @@ The Trick Simulation Environment, developed at the NASA Johnson Space Center, is + + + + + + + + + + + + +
Developer Docs
Read detailed documentation for various Trick internals and processes.
+ --- Trick is released under the NASA Open Source Agreement Version 1.3 [license](https://github.com/nasa/trick/blob/master/LICENSE). diff --git a/docs/related_projects/Related-Projects.md b/docs/related_projects/Related-Projects.md index 40f26da3..ec9ef62a 100644 --- a/docs/related_projects/Related-Projects.md +++ b/docs/related_projects/Related-Projects.md @@ -1,4 +1,4 @@ -| [Home](Home) → Related Projects | +| [Home](/trick) → Related Projects | |---------------------------------| # Open Source Projects diff --git a/docs/tutorial/ATutAnalyticSim.md b/docs/tutorial/ATutAnalyticSim.md index fc8fdd1f..d829f32a 100644 --- a/docs/tutorial/ATutAnalyticSim.md +++ b/docs/tutorial/ATutAnalyticSim.md @@ -479,7 +479,7 @@ our Cannonball simulation is shown in Listing 7, below. ```c++ /************************TRICK HEADER************************* PURPOSE: - (This S_define works with the RUN_analytic input file) + (S_define file for SIM_cannon_analytic) LIBRARY DEPENDENCIES: ( (cannon/src/cannon_init.c) @@ -507,8 +507,6 @@ class CannonSimObject : public Trick::SimObject { CannonSimObject dyn ; ``` - - The `S_define` file syntax is C++ with a couple of Trick specific constructs. Let us dissect this S_define file to see what makes it tick. @@ -647,14 +645,19 @@ In the files that we have created so far, the file paths in `#include` directive and in the `LIBRARY_DEPENDENCY` sections, are **relative** paths. These paths are relative to a **base-path**, that we still need to specify. -For example, the `S_define` file listed above, `#includes` the relative path: -`cannon/include/cannon.h`. We intend for this path to be relative to the -`trick_models` directory that we created in our `$HOME` directory. The complete +For example, the `S_define` file listed above `#includes` the relative path: +`cannon/include/cannon_analytic.h`. We intend for this path to be relative to the +`models` directory that we created in our `SIM_cannon_analytic` directory. The complete path to our cannon.h header file should be: -![Trick Path Construction](images/TrickPaths.png) +``` +${HOME}/trick_sims/SIM_cannon_analytic/models/cannon/include/cannon_analytic.h +``` -So, we need to specify the base-path(s), to the compilers, and to Trick by adding +We need to specify either the absolute path to the `models` directory, or the +relative location of the `models` directory with respect to the top-level +simulation directory (the location of S_define) as the base-path. +We can specify the base-path(s) to the compilers, and to Trick, by adding -I*dir* options, that contain the base-paths, to `$TRICK_CFLAGS` and `$TRICK_CXXFLAGS`. @@ -670,8 +673,8 @@ TRICK_CFLAGS += -Imodels TRICK_CXXFLAGS += -Imodels ``` -When Trick encounters relative paths, these base-paths will be prepended to the -relative paths to create a complete path to the file, thus allowing it to be +When Trick encounters relative paths in an S_define, it prepends these base-path(s) +to the relative paths to create a complete path to the file, thus allowing it to be located. #### Additional Compiler Flag Recommendations @@ -708,15 +711,17 @@ If you typed everything perfectly... Trick is installed properly... there are no bugs in the tutorial... the stars are aligned... and Trick is in a good mood... You should, ultimately see : -![Simulation Make Complete](images/SimMakeComplete.png) +``` +Trick Build Process Complete +``` Now, take a look at the sim directory. Is there an `S_main*.exe` file?? (* is a wildcard, instead of * you will see the name of your platform). If so, cool deal. If not, scream!, then take a look at the next section "Troubleshooting A Bad Build". If all went well, you will notice several other files now resident in the `SIM_cannon_analytic` directory. ```bash % ls -Modified_data S_overrides.mk makefile -RUN_test S_sie.resource trick.zip -S_define S_source.hh +S_overrides.mk makefile +S_sie.resource trick.zip +S_define S_source.hh S_main_.exe build ``` diff --git a/docs/tutorial/ATutDynamicEvents.md b/docs/tutorial/ATutDynamicEvents.md index c55d7382..eb567b32 100644 --- a/docs/tutorial/ATutDynamicEvents.md +++ b/docs/tutorial/ATutDynamicEvents.md @@ -211,7 +211,7 @@ Add the [cannon_impact](#listing_cannon_impact) function, listed above, to the b Add the following job specification, to run our cannon_impact job. ``` -("dynamic_event") cannon_impact( &cannon) ; +("dynamic_event") cannon_impact( &cannon ) ; ``` to the end of the list of jobs in the CannonSimObject. diff --git a/docs/tutorial/ATutIntroduction.md b/docs/tutorial/ATutIntroduction.md index 2185ffdf..90b2894f 100644 --- a/docs/tutorial/ATutIntroduction.md +++ b/docs/tutorial/ATutIntroduction.md @@ -68,24 +68,30 @@ its capabilities. If Trick is not already installed on your machine, then you will need to do that first, by following the directions at: [Install Guide](/trick/documentation/install_guide/Install-Guide). -Once Trick is installed on your machine, you will need add the Trick **bin** -directory to your execution path. For the sake of example, let us assume that +The rest of the tutorial is written as if the Trick **bin** directory is +available on your execution path. This isn't strictly necessary, but allows +you to call `trick-CP` instead of `/full/path/to/trick/bin/trick-CP`. Follow +the steps below if you would like to add the **bin** directory to your PATH. + +For the sake of example, let us assume that you installed Trick in your home directory, and you used the default name for -the repository, which is **trick**. If you named it something different, then +the repository, which is **trick**. If you named it something different, then use that name instead in the scripts below. -If you are using **bash or ksh**, then add the following lines to the file that is automatically sourced by your terminal. Based on your platform this could be **.profile, .bash_profile, .bashrc, .zshrc** or others. Google "How to edit PATH variable" on google to find a wealth of information on this subject. +If you are using **bash or ksh**, then add the following lines to the file +that is automatically sourced by your terminal. Based on your platform this +could be **.profile, .bash_profile, .bashrc, .zshrc** or others. Google "How +to edit PATH variable" on google to find a wealth of information on this +subject. ```bash -export TRICK_HOME="${HOME}/trick" -export PATH=${PATH}:${TRICK_HOME}/bin +export PATH=${PATH}:${HOME}/trick/bin ``` If you are using **csh** or **tcsh**, then add the following lines to your **.cshrc** file. ```csh -setenv TRICK_HOME ${HOME}/trick -setenv PATH ${PATH}:${TRICK_HOME}/bin +setenv PATH ${PATH}:${HOME}/trick/bin ``` Close and then re-open your terminal window. diff --git a/docs/tutorial/ATutMonteCarlo.md b/docs/tutorial/ATutMonteCarlo.md index ee25b200..d35972f3 100644 --- a/docs/tutorial/ATutMonteCarlo.md +++ b/docs/tutorial/ATutMonteCarlo.md @@ -184,7 +184,7 @@ trick-dre & Create a sub-directory called *RUN_test* in your simulation directory. In this new directory create an input file named *test.py*. This input file executes the data recording file you saved above and stops the simulation after 10 seconds of simulation time. ```python -execfile("monte_cannon.dr") +exec(open("monte_cannon.dr").read()) trick.stop(10) ``` @@ -253,7 +253,7 @@ Create a new directory called RUN_file and place the following python script in ```python # -*- coding: UTF-8 -*- -execfile("monte_cannon.dr") +exec(open("monte_cannon.dr").read()) # Enable Monte Carlo. trick.mc_set_enabled(1) @@ -282,7 +282,7 @@ Random Input Generation provides users with the ability to statistically generat ### Script ```python # -*- coding: UTF-8 -*- -execfile("data/monte_cannon.dr") +exec(open("data/monte_cannon.dr").read()) # Enable Monte Carlo. trick.mc_set_enabled(1) @@ -398,7 +398,7 @@ int cannon_master_post(CANNON *C) ```python # -*- coding: UTF-8 -*- -execfile("data/monte_cannon.dr") +exec(open("data/monte_cannon.dr").read()) # Enable Monte Carlo. trick.mc_set_enabled(1) @@ -416,7 +416,7 @@ trick.stop(15) ``` ### Simulation Definition -The last the we need to do is modify our simulation definition file and add the two new Trick jobs. As you can see, we have added a new library dependency, a new ## inclusion, and two new constructor jobs. +The last thing that we need to do is modify our simulation definition file and add the two new Trick jobs. As you can see, we have added a new library dependency, a new ## inclusion, and two new constructor jobs. ```C++ /* PURPOSE: Monte tutorial simulation definition. diff --git a/docs/tutorial/ATutNumericSim.md b/docs/tutorial/ATutNumericSim.md index 89ae0253..4d25d598 100644 --- a/docs/tutorial/ATutNumericSim.md +++ b/docs/tutorial/ATutNumericSim.md @@ -27,7 +27,7 @@ ## How Trick Does Numerical Integration The type of model that we created in the last section relied on the fact that -the cannon ball problem has an closed-form solution from which we can +the cannon ball problem has a closed-form solution from which we can immediately calculate the cannon ball state [position, velocity] at any arbitrary time. In real-world simulation problems, this will almost never be the case. @@ -140,11 +140,8 @@ Producing simulation states by numerical integration requires that the derivativ and integration jobs be called at the appropriate rate and times. This requires a properly configured integration scheduler. -First,an integration scheduler has to be instantiated in the S_define. Then, in -the input files - -1. In the S_define file, define the integration with a declaration of the -following form: +First, instantiate an integration scheduler in the S_define with a declaration +of the following form: ```c++ IntegLoop integLoopName ( integrationTimeStep ) listOfSimObjectNames ; @@ -153,16 +150,18 @@ IntegLoop integLoopName ( integrationTimeStep ) listOfSimObjectNames ; * Jobs within a simObject that are tagged "derivative" or "integration" will be dispatched to the associated integration scheduler. -In the input file, call the IntegLoop **getIntegrator()** method to specify +Then, in the input file, call the IntegLoop **getIntegrator()** method to specify the integration algorithm of choice and the number of state variables to be integrated. -*integLoopName*.getIntegrator( *algorithm*, *N* ); +```py +integLoopName.getIntegrator( algorithm, N ); +``` * *algorithm* is a enumeration value that indicates the numerical integration algorithm to be used, such as: `trick.Euler`, `trick.Runge_Kutta_2`, -`trick.Runge_Kutta_4`. A complete list can be seen Integrator.hh, in -`${TRICK_HOME}/include/trick/Integrator.hh` . +`trick.Runge_Kutta_4`. A complete list is visible in Integrator.hh, in +`${TRICK_HOME}/include/trick/Integrator.hh`. * N is the number of state variables to be integrated. @@ -192,7 +191,7 @@ And then copy the sim directory. ### Create **cannon_numeric.h.** In this new simulation, we're going to create two new functions, 1) -`cannon_deriv()` [our derivative job], 2) `cannon_integ ()` [our integration job]. +`cannon_deriv()` [our derivative job], and 2) `cannon_integ ()` [our integration job]. We'll put prototypes for each these functions into `cannon_numeric.h`. This new header file which will replace `cannon_analytic.h`. @@ -357,8 +356,8 @@ Replace: with: ```c++ - ("derivative") cannon_deriv( &cannon) ; - ("integration") trick_ret= cannon_integ( & cannon); + ("derivative") cannon_deriv( &cannon ) ; + ("integration") trick_ret= cannon_integ( & cannon ) ; ``` ### Add Integration Scheduler and Integrator @@ -385,7 +384,7 @@ The updated S_define is: ```c++ /**************************************************************** -PURPOSE: (S_define File for SIM_cannon_numeric.) +PURPOSE: (S_define file for SIM_cannon_numeric) LIBRARY_DEPENDENCY: ((cannon/src/cannon_init.c) (cannon/src/cannon_numeric.c) (cannon/src/cannon_shutdown.c)) @@ -399,9 +398,9 @@ class CannonSimObject : public Trick::SimObject { CannonSimObject() { ("initialization") cannon_init( &cannon ) ; ("default_data") cannon_default_data( &cannon ) ; - ("derivative") cannon_deriv( &cannon) ; - ("integration") trick_ret= cannon_integ( &cannon); - ("shutdown") cannon_shutdown( &cannon); + ("derivative") cannon_deriv( &cannon ) ; + ("integration") trick_ret= cannon_integ( &cannon ) ; + ("shutdown") cannon_shutdown( &cannon ) ; } }; diff --git a/docs/tutorial/ATutRecordingData.md b/docs/tutorial/ATutRecordingData.md index 7bd44ca6..8c5f6cdd 100644 --- a/docs/tutorial/ATutRecordingData.md +++ b/docs/tutorial/ATutRecordingData.md @@ -26,7 +26,7 @@ recording editor --- aka Dr. Dre) or you may create it manually. * **Step 1.** In the "DR Name" entry box, enter my_cannon. * **Step 2.** In the "DR Cycle" entry box, change 0.1 to 0.01. * **Step 3.** In the "Variables" pane, double-click dyn, then double-click cannon. -* **Step 4.** Double-click pos[2]. The result should result in dyn.cannon.pos[0] +* **Step 4.** Double-click pos[2] and click OK. The result should result in dyn.cannon.pos[0] and dyn.cannon.pos[1] appearing in the "Selected Variables" pane. * **Step 5.** Choose File->Save. In the "Save" dialog, enter the file name cannon.dr. Save cannon.dr in the Modified_data directory. @@ -40,7 +40,7 @@ text file. #### Running The Simulation And Recording Data The simulation must know about the data recording file created in the last -section. This is accomplished by adding execfile to the simulation input file. +section. This is accomplished by adding exec to the simulation input file. ```bash % cd $HOME/trick_sims/SIM_cannon_analytic/RUN_test diff --git a/docs/tutorial/ATutRunningRealtime.md b/docs/tutorial/ATutRunningRealtime.md index 3e58960b..2b2d6b97 100644 --- a/docs/tutorial/ATutRunningRealtime.md +++ b/docs/tutorial/ATutRunningRealtime.md @@ -48,15 +48,15 @@ is beating the system clock, it pauses. If it is falling behind, it registers waiting for the beginning of the next software frame to start the simulation jobs. If interval timers are not used, Trick will spin waiting for the next beat. -`trick.exec_set_freeze_command()` - brings up the simulation in a frozen -(non-running) state. - `trick.exec_set_enable_freeze()` - allows the user to toggle the simulation from a frozen state to a running state at will. +`trick.exec_set_freeze_command()` - brings up the simulation in a frozen +(non-running) state. + `trick.sim_control_panel_set_enabled(True)` or -`simControlPanel = trick.SimControlPanel() & trick.add_external_application(simControlPanel)` - - brings up the simulation control panel GUI. +`simControlPanel = trick.SimControlPanel() & trick.add_external_application(simControlPanel)` - +brings up the simulation control panel GUI. The `realtime.py` file must be included in the RUN_test/input.py file. When finished, the latest version of the input file should look like the following: @@ -100,7 +100,7 @@ Some items to note about the simulation control panel for your future use: (does not complete all jobs during the software frame) and display them in the tiny box next to the simulation name. If the simulation overruns, the sim will run as fast as it can "to catch up" to where it should be. - * Using the File menu at the top, you may set a freeze point in the future. + * Using the Actions menu at the top, you may set a freeze point in the future. --- diff --git a/docs/tutorial/ATutTrickView.md b/docs/tutorial/ATutTrickView.md index 0d9ccc96..8b0ce448 100644 --- a/docs/tutorial/ATutTrickView.md +++ b/docs/tutorial/ATutTrickView.md @@ -60,13 +60,15 @@ to 10 meters. 1. Notice that dyn.cannon.vel[0] is 43.30... meters per second. To view it in feet per second: * Left Click on the variable dyn.cannon.vel[0] on the Variable table. - * Left Click on the "m/s" in the Unit column to bring up a drop-down list. - * Select **ft/s**. Notice that the value of dyn.cannon.vel[0] changes to + * Double Click on the "m/s" in the Unit column to edit the field. + * Type **ft/s**. Notice that the value of dyn.cannon.vel[0] changes to 142.06... ft/s. 1. Resume the simulation run by clicking the **Start** button on the sim control panel. Notice that the trajectory assumes its predetermined path. -This is because we are giving the cannonball a position as a function of time. +This is because we are analytically calculating the cannonball position as a +function of time, rather than calculating it from the previous frame data. + #### TV With An Input File If this simulation were run over and over, it would be laborious to @@ -107,8 +109,8 @@ Again, we need to incorporate the TV input file into our ever expanding simulation input file. ```python -execfile("Modified_data/realtime.py") -execfile("Modified_data/cannon.dr") +exec(open("Modified_data/realtime.py").read()) +exec(open("Modified_data/cannon.dr").read()) trick.trick_view_add_auto_load_file("TV_cannon.tv") trick.stop(5.2) @@ -122,6 +124,4 @@ trick.stop(5.2) You may now run the sim and verify that TV pops up automatically. -Congratulations, you have finished the basic Trick tutorial! - [Next Page](ATutNumericSim) diff --git a/docs/tutorial/TutVariableServer.md b/docs/tutorial/TutVariableServer.md index 98c016bb..d46ac193 100644 --- a/docs/tutorial/TutVariableServer.md +++ b/docs/tutorial/TutVariableServer.md @@ -124,17 +124,17 @@ To run the variable server client : * Execute, but don't "Start" the cannonball simulation. * Find the variable server port number in the bottom left hand corner of the Sim Control Panel, as shown below. -* Execute the script with the port number as an argument. Example: - -```$ ~/CannonDisplay_Rev1.py 50774 &``` ![Cannon](images/SimControlPanel.png) +* Execute the script with the port number as an argument. + Example: ```$ ~/CannonDisplay_Rev1.py 50774 &``` +* "Start" the cannonball simulation. + The output of the script will display three columns of numbers. The left most number is the [variable server message type](#variable-server-message-types). Here, a message type of 0 indicates that the message is the (tab delimited) list -of the values we requested. This is the only message type we'll be concerned -with in this tutorial. The two columns to the right of the message number are +of the values we requested. The two columns to the right of the message number are the values of ```dyn.cannon.pos[0]``` and ```dyn.cannon.pos[1]```, in the order that they were specified in the script. @@ -148,7 +148,6 @@ that they were specified in the script. 0 68.84901960086293 27.34966950000001 0 73.17914661978513 28.24082950000001 - ``` @@ -180,7 +179,7 @@ and "dyn.cannon.pos[1]" to the session variable list. ⚠️ Please notice that the quotes around the variable names must be escaped with the '\' (backslash) character. -``` +```python client_socket.send( "trick.var_add(\"dyn.cannon.pos[0]\") \n" + "trick.var_add(\"dyn.cannon.pos[1]\") \n" ) @@ -208,14 +207,67 @@ Suppose we wanted to get the value of the initial angle of our cannon. We don't need to get it repeatedly, because it doesn't change. We just want to get it once, and then to repeatedly get the position data, which changes over time. -For this situation we can use the [**var_send**](#api-var-send) command, which -tells the variable server to send the values specified in the session variable -list immediately, regardless of whether [**var_pause**](#api-var-pause) was -previously commanded. +For this situation, we can take one of several approaches. The most straightforward +is the [**var_send_once**](#api-var-send-once) command, which tells the variable +server to send the values sent as arguments immediately, regardless of whether +[**var_pause**](#api-var-pause) was previously commanded. To demonstrate how this works, let's add the following code to our script, right after the line where we sent the **var_ascii** command. +```python +client_socket.send( "trick.var_send_once(\"dyn.cannon.init_angle\")\n") +line = insock.readline() +print line +``` + +In this code, we simply ask the variable server to immediately send the value of ```dyn.cannon.init_angle```, +call ```insock.readline()``` to wait for a response, and print the response when it is received. +[**var_send_once**](#api-var-send-once) does not alter the session variable list in any way. + +When we run the client, the first few lines of output should look something like: + +``` +5 0.5235987755982988 + +0 0 0 + +0 0 0 +``` + +The [**var_send_once**](#api-var-send-once) command uses a [message type](#variable-server-message-types) of 5 +to allow a programmer to differentiate between normal session variables and var_send_once variables. var_send_once +does not alter or interfere with the session variable list, which would allow both of these features to be +used simultaneously in a sim. + +The [**var_send_once**](#api-var-send-once) also allows a user to request multiple variables in a single +command. [**var_send_once**](#api-var-send-once) can accept a comma-separated list of variables as the +first argument and the number of variables in the list as the second argument. +In our example, suppose we also wanted to retrieve the initial speed of the cannonball. +We could retrieve both variables with a single command: + +```python +client_socket.send( "trick.var_send_once(\"dyn.cannon.init_angle, dyn.cannon.init_speed\", 2)\n") +``` + +Now, when we run the client, we get both the init_angle and the init_speed with the first message. + +``` +5 0.5235987755982988 50 + +0 0 0 + +0 0 0 +``` + +Another commonly used pattern to retrieve variables only once is to use the [**var_add**](#api-var-add), +[**var_send**](#api-var-send), and [**var_clear**](#api-var-clear) commands. [**var_send**](#api-var-send) tells +the variable server to send all **session** variables immediately regardless of whether [**var_pause**](#api-var-pause) +was previously commanded. + +To demonstrate how this works, replace the code in the previous listing with the snippet below, right +after the line where we sent the **var_ascii** command. + ```python client_socket.send( "trick.var_add(\"dyn.cannon.init_angle\")\n") client_socket.send( "trick.var_send()\n" ) @@ -234,7 +286,9 @@ two ways. We can 1) call [**var_clear**](#api-var-clear) to clear the the list, or 2) we can call [**var_remove**](#api-var-remove). Specifically we could do the following: -```client_socket.send("trick.var_remove(\"dyn.cannon.init_angle\")\n")``` +```python +client_socket.send( "trick.var_remove(\"dyn.cannon.init_angle\")\n" ) +``` So, when we run the modified client, the first three lines of the output should look something like the following. @@ -247,7 +301,7 @@ look something like the following. 0 0 0 ``` -The first line contains the message type ( which is zero), followed by the value +The first line contains the message type (which is zero), followed by the value of ```dyn.cannon.init_angle```. Subsequent lines contain the position data like before. @@ -501,11 +555,11 @@ Add this to the bottom of RUN_test/input.py to give it a try. | VS\_SIE\_RESOURCE | 2 | Response to send_sie_resource| | VS\_LIST\_SIZE | 3 | Response to var_send_list_size or send_event_data| | VS\_STDIO | 4 | Values Redirected from stdio if var_set_send_stdio is enabled| +| VS\_SEND\_ONCE | 5 | Response to var\_send\_once| ### The Variable Server API -`` The following functions are a subset of variable server API functions that are used in this tutorial: @@ -545,6 +599,13 @@ Resume periodic responses. **var\_send()** - Send response immediately. + +**var\_send\_once( variable_name )** - +Immediately send the value of variable_name + +**var\_send\_once( variable_list, num_variables )** - +Immediately send the value of all variables in the comma separated variable_list, or an error if the number of variables in the list does not match num_variables + **var\_clear()** - Clear the session variable list. diff --git a/docs/tutorial/images/SimMakeComplete.png b/docs/tutorial/images/SimMakeComplete.png deleted file mode 100644 index 232f3d5d..00000000 Binary files a/docs/tutorial/images/SimMakeComplete.png and /dev/null differ diff --git a/docs/tutorial/images/TrickPaths.png b/docs/tutorial/images/TrickPaths.png deleted file mode 100644 index d920603b..00000000 Binary files a/docs/tutorial/images/TrickPaths.png and /dev/null differ diff --git a/include/trick/CheckPointRestart.hh b/include/trick/CheckPointRestart.hh index ca071c20..4201d746 100644 --- a/include/trick/CheckPointRestart.hh +++ b/include/trick/CheckPointRestart.hh @@ -247,6 +247,19 @@ namespace Trick { */ virtual void load_checkpoint(std::string file_name) ; + /** + @brief @userdesc Command to load a checkpoint file. (Calls the preload_checkpoint jobs, calls the MemoryManager restore_managed_memory + method, then calls the restart jobs.) + This is invoked when the user clicks the "Load ASCII Chkpnt" button on the sim control panel. + @par Python Usage: + @code trick.load_checkpoint("") @endcode + @param file_name - file to read checkpoint data from + @param stl_restore_on - toggle whether to restore STLs + @return always 0 + */ + virtual void load_checkpoint(std::string file_name, bool stl_restore_on) ; + + /** @brief @userdesc Command to load a checkpoint file. (Calls the preload_checkpoint jobs, calls the MemoryManager restore_managed_memory method, then calls the restart jobs.) diff --git a/include/trick/CheckPointRestart_c_intf.hh b/include/trick/CheckPointRestart_c_intf.hh index 58ccdf9b..6b33c81c 100644 --- a/include/trick/CheckPointRestart_c_intf.hh +++ b/include/trick/CheckPointRestart_c_intf.hh @@ -51,6 +51,8 @@ int checkpoint_objects( const char * file_name, const char * objects ) ; /* load_checkpoint call accessible from C code */ int load_checkpoint( const char * file_name ) ; +int load_checkpoint_stls( const char * file_name, int with_stls ) ; + int load_checkpoint_job() ; void * get_address( const char * var_name ) ; diff --git a/include/trick/CommandLineArguments.hh b/include/trick/CommandLineArguments.hh index 1617ab8a..fad9fd12 100644 --- a/include/trick/CommandLineArguments.hh +++ b/include/trick/CommandLineArguments.hh @@ -139,6 +139,9 @@ namespace Trick { */ void set_output_dir(std::string output_directory) ; + // Helper method to create full path + static int create_path(const std::string& dirname); + } ; } diff --git a/include/trick/DRHDF5.hh b/include/trick/DRHDF5.hh index a08fc28e..a241f20a 100644 --- a/include/trick/DRHDF5.hh +++ b/include/trick/DRHDF5.hh @@ -48,7 +48,7 @@ namespace Trick { /** The DRHDF5 recording format is an industry conforming HDF5 formatted file. Files written in this format are named - log_.hd5. The contents of this file type are readable by the Trick Data Products packages from + log_.h5. The contents of this file type are readable by the Trick Data Products packages from Trick 07 to the current version. The contents of the file are binary and is not included here. The HDF5 layout of the file follows. diff --git a/include/trick/DataRecordDispatcher.hh b/include/trick/DataRecordDispatcher.hh index 7a8bc3b8..f1509da2 100644 --- a/include/trick/DataRecordDispatcher.hh +++ b/include/trick/DataRecordDispatcher.hh @@ -13,7 +13,7 @@ PROGRAMMERS: #include "trick/Scheduler.hh" #include "trick/DataRecordGroup.hh" -#include "trick/ThreadBase.hh" +#include "trick/SysThread.hh" namespace Trick { @@ -28,9 +28,11 @@ namespace Trick { pthread_cond_t init_complete_cv; /**< trick_io(**) */ /** Data writer initialized mutex. */ pthread_mutex_t init_complete_mutex; /**< trick_io(**) */ + /** Flag to exit (instead of pthread_cancel) */ + bool cancelled; } ; - class DRDWriterThread : public Trick::ThreadBase { + class DRDWriterThread : public Trick::SysThread { public: DRDWriterThread(Trick::DRDMutexes & in_mutexes, std::vector & in_groups) ; diff --git a/include/trick/DataRecordGroup.hh b/include/trick/DataRecordGroup.hh index 34869ffe..d6587083 100644 --- a/include/trick/DataRecordGroup.hh +++ b/include/trick/DataRecordGroup.hh @@ -127,6 +127,9 @@ namespace Trick { /** Buffer to hold formatted data ready for disk or other destination.\n */ char * writer_buff ; /**< trick_io(**) trick_units(--) */ + /** Size of the writer_buff. */ + size_t writer_buff_size; + /** Little_endian or big_endian indicator.\n */ std::string byte_order; /**< trick_io(*io) trick_units(--) */ @@ -402,6 +405,10 @@ namespace Trick { */ virtual int add_time_variable() ; + /** Check that a variable is supported by data recording. */ + /** Variable must be a single primitive type - no STL, array, structured, string */ + bool isSupportedType(REF2 * ref2, std::string& message); + /** Max number of digits to expect per recorded value.\n */ static const unsigned int record_size = 25; /**< trick_io(**) trick_units(--) */ diff --git a/include/trick/Executive.hh b/include/trick/Executive.hh index 4b849581..71d014e8 100644 --- a/include/trick/Executive.hh +++ b/include/trick/Executive.hh @@ -207,7 +207,7 @@ namespace Trick { /** Queue to hold unfreeze jobs.\n */ Trick::ScheduledJobQueue unfreeze_queue ; /**< trick_io(**) */ - /** Queue to hold unfreeze jobs.\n */ + /** Queue to hold time_tic_changed jobs.\n */ Trick::ScheduledJobQueue time_tic_changed_queue ; /**< trick_io(**) */ /** Enough threads to accomodate the number of children specified in the S_define file.\n */ @@ -422,6 +422,13 @@ namespace Trick { */ int get_sim_objects(std::vector & in_sim_objects) ; + /** + Search for a sim object with the given name. + @param sim_object_name - name of desired SimObject + @return Pointer to sim object or NULL if not found + */ + SimObject * get_sim_object_by_name(std::string sim_object_name); + /** @userdesc Command to get the real-time software frame in seconds. @par Python Usage: @@ -807,15 +814,34 @@ namespace Trick { int set_job_cycle(std::string job_name, int instance_num, double in_cycle) ; /** - @userdesc Command to turn on/off all jobs in the sim_object. + @userdesc Command to enable or disable all jobs in a sim object (without setting sim object status). @par Python Usage: @code trick.exec_set_sim_object_onoff("", ) @endcode @param sim_object_name - name of sim_object from S_define file - @param on - 1 to turn job on, 0 to turn job off - @return 0 if successful or -1 if the job cannot be found + @param on - 1 to turn jobs on, 0 to turn jobs off + @return 0 if successful or -1 if the object cannot be found + */ + int set_sim_object_jobs_onoff(std::string sim_object_name, int on) ; + + /** + @userdesc Command to turn on/off the sim_object. + @par Python Usage: + @code trick.exec_set_sim_object_onoff("", ) @endcode + @param sim_object_name - name of sim_object from S_define file + @param on - 1 to turn object on, 0 to turn object off + @return 0 if successful or -1 if the object cannot be found */ int set_sim_object_onoff(std::string sim_object_name, int on) ; + /** + @userdesc Command to get whether the sim object is on or off. + @par Python Usage: + @code trick.exec_get_sim_object_onoff("") @endcode + @param sim_object_name - name of sim_object from S_define file + @return 1 if the object is enabled, 0 if the object is disabled, or -1 if the object cannot be found + */ + int get_sim_object_onoff (std::string sim_object_name) ; + /** @userdesc Trick Version & Date at the time executable was built. @par Python Usage: diff --git a/include/trick/FrameLog.hh b/include/trick/FrameLog.hh index 63a42594..edff7600 100644 --- a/include/trick/FrameLog.hh +++ b/include/trick/FrameLog.hh @@ -44,7 +44,7 @@ namespace Trick { /** Data recording group for logging frame/overrun time.\n trick_units(--) */ Trick::FrameDataRecordGroup * drg_frame; /**< trick_io(*io) trick_units(--) */ - int plots_per_page; /**< trick_io(*io) trick_units(--) number of plots per page */ + unsigned int plots_per_page; /**< trick_io(*io) trick_units(--) number of plots per page */ /** Cyclic jobs timeline to log, dimensioned as [num_threads][tl_max_samples].\n */ Trick::timeline_t **timeline; /**< trick_io(**) */ /** Non-Cyclic jobs timeline to log, dimensioned as [num_threads][tl_max_samples].\n */ diff --git a/include/trick/IPPythonEvent.hh b/include/trick/IPPythonEvent.hh index 7a512d4b..f62fe3b9 100644 --- a/include/trick/IPPythonEvent.hh +++ b/include/trick/IPPythonEvent.hh @@ -184,6 +184,15 @@ namespace Trick { */ static void set_event_info_msg_off() ; + /** + @brief @userdesc Command to set whether the sim should check error codes from + Python parsing and terminate if an error is detected. Set to false by default + @par Python Usage: + @code trick.terminate_on_event_parse_error(True|False) @endcode + @return always 0 + */ + static void terminate_on_event_parse_error(bool on_off); + /** @brief called by the event manager when the event is loaded from a checkpoint */ @@ -402,7 +411,7 @@ namespace Trick { any events instantiated yet */ static void set_python_processor(Trick::IPPython * in_ip) ; static void set_mtv(Trick::MTV * in_mtv) ; - + private: /* A static pointer to the python input processor set at the S_define level */ @@ -411,6 +420,8 @@ namespace Trick { /* A static pointer to the MTV set at the S_define level */ static Trick::MTV * mtv ; + /* Defaults to false */ + static bool terminate_sim_on_event_python_error; } ; } diff --git a/include/trick/MemoryManager.hh b/include/trick/MemoryManager.hh index bac485df..6f98c8ad 100644 --- a/include/trick/MemoryManager.hh +++ b/include/trick/MemoryManager.hh @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -301,7 +302,7 @@ namespace Trick { @param address - the address of the variable. @return 0 = SUCCESS, 1 = FAILURE */ - int delete_var(void* address, bool destroy = true); + int delete_var(void* address); /** Forget about the variable with the given name and deallocate the memory associated with it. @@ -370,32 +371,32 @@ namespace Trick { Restore a checkpoint from the given stream. @param in_s - input stream. */ - int read_checkpoint( std::istream* in_s, bool do_restore_stls=false); + int read_checkpoint( std::istream* in_s, bool do_restore_stls = restore_stls_default); /** Read a checkpoint from the file of the given name. @param filename - name of the checkpoint file to be read. */ - int read_checkpoint( const char* filename); + int read_checkpoint( const char* filename, bool do_restore_stls = restore_stls_default); /** Read a checkpoint from the given string. @param s - string containing the checkpoint info. */ - int read_checkpoint_from_string( const char* s ); + int read_checkpoint_from_string( const char* s, bool do_restore_stls = restore_stls_default ); /** Delete all TRICK_LOCAL variables and clear all TRICK_EXTERN variables. Then read and restore the checkpoint from the given stream. @param in_s - input stream. */ - int init_from_checkpoint( std::istream* in_s); + int init_from_checkpoint( std::istream* in_s, bool do_restore_stls = restore_stls_default); /** Delete all TRICK_LOCAL variables and clear all TRICK_EXTERN variables. Then read and restore the checkpoint of the given filename. */ - int init_from_checkpoint( const char* filename); + int init_from_checkpoint( const char* filename, bool do_restore_stls = restore_stls_default); /** Deallocate the memory for all TRICK_LOCAL variables and then forget about them. @@ -661,6 +662,10 @@ namespace Trick { void write_JSON_alloc_info( std::ostream& s, ALLOC_INFO *alloc_info) ; void write_JSON_alloc_list( std::ostream& s, int start_ix, int num) ; + int set_restore_stls_default (bool on); + static bool restore_stls_default; /**< -- true = restore STL variables on checkpoint restore if user does not specify option. false = don't */ + + private: static int instance_count; /**< -- Number of instances of MemoryManager. Not allowed to exceed 1.*/ @@ -683,6 +688,8 @@ namespace Trick { std::vector dependencies; /**< ** list of allocations used in a checkpoint. */ std::vector stl_dependencies; /**< ** list of allocations known to be STL checkpoint allocations */ + bool resetting_memory; + std::list deleted_addr_list; /**< ** list of addresses that have been deleted during reset_memory(). */ void execute_checkpoint( std::ostream& out_s ); @@ -812,19 +819,37 @@ namespace Trick { void io_src_delete_class(ALLOC_INFO * alloc_info); /** - FIXME: I NEED DOCUMENTATION! + Clear the specified primitive or or array of primitives, beginning at the given base_address, + described by attr, and whose specific array element is specified by curr_dim, and offset. */ void clear_rvalue( void* base_address, ATTRIBUTES* attr, int curr_dim, int offset); + /** - FIXME: I NEED DOCUMENTATION! + Clear the variable at the given address. That is, set the value(s) of the variable + at the given address to 0, 0.0, NULL, false or "", as appropriate for the type. + The difference between this function and clear_var(void* address) is that this + doesn't contain calls to lock and unlock mm_mutex (which protects the alloc_info_map, + and variable_map). This is meant to only be called from within other "critical-section" + code that is surrounded by mutex lock and unlock. + */ + void clear_var_critical_section(void* address); + + /** + Clear the members of the class instance at
, and described by . + This too is only meant to be called from within other "critical-section" code that + is surrounded by mutex lock and unlock. */ void clear_class( char *address, ATTRIBUTES * A); + /** - FIXME: I NEED DOCUMENTATION! + Clear the elements of the array at
, described by , and whose . + This too is only meant to be called from within other "critical-section" code that + is surrounded by mutex lock and unlock. */ void clear_arrayed_class( char* address, ATTRIBUTES* A, int curr_dim, int offset); + /** - FIXME: I NEED DOCUMENTATION! + Write the given alloc_info data structure in a human readable to stdout. */ void debug_write_alloc_info( ALLOC_INFO *alloc_info); @@ -842,4 +867,3 @@ extern Trick::MemoryManager* trick_MM; #endif #endif - diff --git a/include/trick/MessageTCDevice.hh b/include/trick/MessageTCDevice.hh index 8d2656e1..c117903b 100644 --- a/include/trick/MessageTCDevice.hh +++ b/include/trick/MessageTCDevice.hh @@ -7,14 +7,14 @@ #include #include "trick/MessageSubscriber.hh" -#include "trick/ThreadBase.hh" +#include "trick/SysThread.hh" #include "trick/tc.h" namespace Trick { class MessageTCDevice ; - class MessageTCDeviceListenThread : public Trick::ThreadBase { + class MessageTCDeviceListenThread : public Trick::SysThread { public: MessageTCDeviceListenThread(MessageTCDevice * in_mtcd) ; diff --git a/include/trick/MessageThreadedCout.hh b/include/trick/MessageThreadedCout.hh index 740fc9d1..dfef3f76 100644 --- a/include/trick/MessageThreadedCout.hh +++ b/include/trick/MessageThreadedCout.hh @@ -7,7 +7,7 @@ #define MESSAGETHREADEDCOUT_HH #include -#include "trick/ThreadBase.hh" +#include "trick/SysThread.hh" #include "trick/MessageSubscriber.hh" namespace Trick { @@ -16,7 +16,7 @@ namespace Trick { * This MessageThreadedCout is a class that inherits from MessageSubscriber. * It defines a type of MessageSubscriber with its received message sending to the standard output stream. */ - class MessageThreadedCout : public MessageSubscriber , public Trick::ThreadBase { + class MessageThreadedCout : public MessageSubscriber , public Trick::SysThread { public: diff --git a/include/trick/MyCivetServer.hh b/include/trick/MyCivetServer.hh index 5e5a2855..e0763269 100644 --- a/include/trick/MyCivetServer.hh +++ b/include/trick/MyCivetServer.hh @@ -63,7 +63,7 @@ class MyCivetServer { void deleteWebSocketSession(struct mg_connection * nc); void installHTTPGEThandler(std::string handlerName, httpMethodHandler handler); void installWebSocketSessionMaker(std::string name, WebSocketSessionMaker maker); - void handleWebSocketClientMessage(struct mg_connection *conn, const char* data); + void handleWebSocketClientMessage(struct mg_connection *conn, const std::string& data); void handleHTTPGETrequest(struct mg_connection *conn, const struct mg_request_info* ri, std::string handlerName); diff --git a/include/trick/Sie.hh b/include/trick/Sie.hh index b5d04c7b..1b23c2d9 100644 --- a/include/trick/Sie.hh +++ b/include/trick/Sie.hh @@ -43,9 +43,11 @@ namespace Trick { void sie_print_json() ; void sie_append_runtime_objs() ; void runtime_objects_print(std::fstream & sie_out) ; + std::string get_runtime_sie_dir(); private: + // These are called at trick-cp time void top_level_objects_print(std::ofstream & sie_out) ; void top_level_objects_json(std::ofstream & sie_out) ; @@ -53,6 +55,8 @@ namespace Trick { Trick::AttributesMap * class_attr_map ; /* ** -- This is be ignored by ICG */ Trick::EnumAttributesMap * enum_attr_map ; /* ** -- This is be ignored by ICG */ + bool move_runtime_generation; + } ; } diff --git a/include/trick/SimObject.hh b/include/trick/SimObject.hh index 7ada230e..30f47344 100644 --- a/include/trick/SimObject.hh +++ b/include/trick/SimObject.hh @@ -11,6 +11,7 @@ PROGRAMMERS: #include #include +#include #include "trick/JobData.hh" @@ -32,11 +33,19 @@ namespace Trick { public: + SimObject () : object_disabled(false) {} + /** Name of SimObject given to object */ std::string name ; /* trick_units(--) */ /** SimObject id assigned by CP */ - int id ; /* trick_units(--) */ + int id ; /* trick_units(--) */ + + /** Indicates if the sim_object is enabled */ + bool object_disabled; /* trick_units(--) */ + + /** Save the job disabled states when the entire sim object is disabled */ + std::map saved_job_states; /* trick_io(**) */ /** Included simobjects -- currently not used */ std::vector pre_component_objects ; /* trick_io(**) */ @@ -97,12 +106,14 @@ namespace Trick { /** * Enables all jobs in the SimObject */ + void enable_all_jobs() ; void enable() ; /** * Disables all jobs in the SimObject */ - void disable() ; + void disable_all_jobs() ; + void disable(); /** * Calls all jobs that are not "dynamic_event" class diff --git a/include/trick/SysThread.hh b/include/trick/SysThread.hh new file mode 100644 index 00000000..a565b8c5 --- /dev/null +++ b/include/trick/SysThread.hh @@ -0,0 +1,56 @@ +/* + PURPOSE: + (Trick Sys Threads implementation) +*/ + +#ifndef SYSTHREAD_HH +#define SYSTHREAD_HH + +#include +#include +#include +#include +#include +#if __linux +#include +#endif +#include +#include +#include "trick/ThreadBase.hh" + + +namespace Trick { + + /** + * The purpose of this class is to ensure safe shutdown for Trick system threads, since user threads are handled separately in + * the Trick::Threads and Executive classes. + * + * This class was implemented as a solution to issue https://github.com/nasa/trick/issues/1445 + * + * @author Jackie Deans + * + * + **/ + class SysThread : public Trick::ThreadBase { + public: + SysThread(std::string in_name, bool self_deleting = false); + ~SysThread(); + + static int ensureAllShutdown(); + + private: + // Had to use Construct On First Use here to avoid the static initialziation fiasco + static pthread_mutex_t& list_mutex(); + static pthread_cond_t& list_empty_cv(); + + static std::vector & all_sys_threads(); + + static bool shutdown_finished; + + bool self_deleting; + } ; + +} + +#endif + diff --git a/include/trick/ThreadBase.hh b/include/trick/ThreadBase.hh index 085b0b76..41ec3273 100644 --- a/include/trick/ThreadBase.hh +++ b/include/trick/ThreadBase.hh @@ -130,6 +130,12 @@ namespace Trick { */ virtual int cancel_thread() ; + /** + * Cancels thread. + * @return always 0 + */ + virtual int join_thread() ; + /** * The thread body. * @return always 0 diff --git a/include/trick/VariableServer.hh b/include/trick/VariableServer.hh index 9aee8409..10cf4ee2 100644 --- a/include/trick/VariableServer.hh +++ b/include/trick/VariableServer.hh @@ -18,7 +18,7 @@ #include "trick/variable_server_sync_types.h" #include "trick/VariableServerThread.hh" #include "trick/VariableServerListenThread.hh" -#include "trick/ThreadBase.hh" +#include "trick/SysThread.hh" namespace Trick { @@ -295,7 +295,7 @@ namespace Trick { } -int vs_format_ascii(Trick::VariableReference * var, char *value); +int vs_format_ascii(Trick::VariableReference * var, char *value, size_t value_size); Trick::VariableServer * var_server_get_var_server() ; @@ -305,6 +305,8 @@ int var_add(std::string in_name, std::string units_name) ; int var_remove(std::string in_name) ; int var_units(std::string var_name , std::string units_name) ; int var_exists(std::string in_name) ; +int var_send_once(std::string in_name) ; +int var_send_once(std::string in_name, int numArgs) ; int var_send() ; int var_clear() ; int var_cycle(double in_rate) ; diff --git a/include/trick/VariableServerListenThread.hh b/include/trick/VariableServerListenThread.hh index e773d3cb..4b7af4e6 100644 --- a/include/trick/VariableServerListenThread.hh +++ b/include/trick/VariableServerListenThread.hh @@ -9,7 +9,7 @@ #include #include #include "trick/tc.h" -#include "trick/ThreadBase.hh" +#include "trick/SysThread.hh" namespace Trick { @@ -17,7 +17,7 @@ namespace Trick { This class runs the variable server listen loop. @author Alex Lin */ - class VariableServerListenThread : public Trick::ThreadBase { + class VariableServerListenThread : public Trick::SysThread { public: VariableServerListenThread() ; diff --git a/include/trick/VariableServerThread.hh b/include/trick/VariableServerThread.hh index 1b3ce499..fed81f59 100644 --- a/include/trick/VariableServerThread.hh +++ b/include/trick/VariableServerThread.hh @@ -11,9 +11,11 @@ #include #include #include "trick/tc.h" -#include "trick/ThreadBase.hh" +#include "trick/SysThread.hh" #include "trick/VariableServerReference.hh" #include "trick/variable_server_sync_types.h" +#include "trick/variable_server_message_types.h" + namespace Trick { @@ -23,7 +25,7 @@ namespace Trick { This class provides variable server command processing on a separate thread for each client. @author Alex Lin */ - class VariableServerThread : public Trick::ThreadBase { + class VariableServerThread : public Trick::SysThread { public: enum ConnectionType { TCP, UDP, MCAST } ; @@ -120,6 +122,16 @@ namespace Trick { */ int var_exists( std::string in_name ) ; + /** + @brief @userdesc Command to immediately send the value of a comma separated list of variables + @par Python Usage: + @code trick.var_send_once("", ) @endcode + @param in_name_list - the variables name to retrieve, comma separated + @param num_vars - number of vars in in_name_list + @return always 0 + */ + int var_send_once(std::string in_name_list, int num_vars); + /** @brief @userdesc Command to instruct the variable server to immediately send back the values of variables that are registered with the var_add command @@ -369,11 +381,22 @@ namespace Trick { */ int copy_sim_data(); + /** + @brief Copy given variable values from Trick memory to each variable's output buffer. + cyclical indicated whether it is a normal cyclical copy or a send_once copy + */ + int copy_sim_data(std::vector given_vars, bool cyclical); + /** @brief Write data in the appropriate format (var_ascii or var_binary) from variable output buffers to socket. */ int write_data(); + /** + @brief Write data from the given var only to the appropriate format (var_ascii or var_binary) from variable output buffers to socket. + */ + int write_data(std::vector var) ; + /** @brief gets the send_stdio flag. */ @@ -426,9 +449,19 @@ namespace Trick { int transmit_file(std::string file_name); /** - @brief Called by write_data to write data to socket in var_binary format. + @brief Called by write_data to write given variables to socket in var_binary format. */ - int write_binary_data( int Start, char *buf1, int PacketNum ); + int write_binary_data( int Start, char *buf1, const std::vector& given_vars, VS_MESSAGE_TYPE message_type); + + /** + @brief Called by write_data to write given variables to socket in var_ascii format. + */ + int write_ascii_data(char * dest_buf, size_t dest_buf_size, const std::vector& given_vars, VS_MESSAGE_TYPE message_type ); + + /** + @brief Construct a variable reference from the string in_name and handle error checking + */ + VariableReference* create_var_reference(std::string in_name); /** @brief Make a time reference. diff --git a/include/trick/WebSocketSession.hh b/include/trick/WebSocketSession.hh index 0c643365..4dc2a416 100644 --- a/include/trick/WebSocketSession.hh +++ b/include/trick/WebSocketSession.hh @@ -21,7 +21,7 @@ class WebSocketSession { */ virtual void marshallData()=0; virtual void sendMessage()=0; - virtual int handleMessage(std::string)=0; + virtual int handleMessage(const std::string&)=0; struct mg_connection* connection; /* ** */ }; diff --git a/include/trick/checkpoint_map.hh b/include/trick/checkpoint_map.hh index d52939cb..65916c38 100644 --- a/include/trick/checkpoint_map.hh +++ b/include/trick/checkpoint_map.hh @@ -317,17 +317,18 @@ int checkpoint_map_stl_sk_sd(STL & in_map , std::string object_name , std::strin /* copy the contents of the map the 2 arrays */ for ( iter = in_map.begin() , ii = 0 ; iter != in_map.end() ; iter++ , ii++ ) { - std::ostringstream sub_elements ; + std::stringstream sub_elements ; sub_elements << object_name << "_" << var_name << "_keys_" << ii ; keys[ii] = sub_elements.str() ; - std::ostringstream index_string ; + std::stringstream index_string ; index_string << ii ; checkpoint_stl( const_cast(iter->first) , object_name + "_" + var_name + "_keys", index_string.str() ) ; - sub_elements << object_name << "_" << var_name << "_data_" << ii ; - items[ii] = sub_elements.str() ; + std::stringstream sub_elements_data; + sub_elements_data << object_name << "_" << var_name << "_data_" << ii ; + items[ii] = sub_elements_data.str() ; checkpoint_stl( iter->second , object_name + "_" + var_name + "_data", index_string.str() ) ; diff --git a/include/trick/checkpoint_pair.hh b/include/trick/checkpoint_pair.hh index badaf33a..c4fc014d 100644 --- a/include/trick/checkpoint_pair.hh +++ b/include/trick/checkpoint_pair.hh @@ -82,7 +82,6 @@ int checkpoint_stl(std::pair & in_pair , std::string object_name int status ; std::string temp_str; - FIRST * first = nullptr ; std::string * second = nullptr ; std::replace_if(object_name.begin(), object_name.end(), static_cast(std::ispunct), '_'); @@ -109,9 +108,10 @@ int checkpoint_stl(std::pair & in_pair , std::string object_name temp_str = var_declare.str(); second = (std::string *)TMM_declare_var_s(temp_str.c_str()) ; if ( second ) { + *second = std::string("inner"); temp_str = std::string(object_name + "_" + var_name + "_second"); TMM_add_checkpoint_alloc_dependency(temp_str.c_str()) ; - checkpoint_stl( in_pair.second , object_name + "_" + var_name , "second" ) ; + checkpoint_stl( in_pair.second , object_name + "_" + var_name , "second_inner" ) ; } } @@ -136,9 +136,10 @@ int checkpoint_stl(std::pair & in_pair , std::string object_name << object_name << "_" << var_name << "_first[1]" ; temp_str = var_declare.str() ; first = (std::string *)TMM_declare_var_s(temp_str.c_str()) ; + *first = std::string("inner"); temp_str = std::string(object_name + "_" + var_name + "_first"); TMM_add_checkpoint_alloc_dependency(temp_str.c_str()) ; - checkpoint_stl( in_pair.first , object_name + "_" + var_name , "first" ) ; + checkpoint_stl( in_pair.first , object_name + "_" + var_name , "first_inner" ) ; var_declare.str("") ; var_declare.clear() ; @@ -178,9 +179,10 @@ int checkpoint_stl(std::pair & in_pair , std::string object_name << object_name << "_" << var_name << "_first[1]" ; temp_str = var_declare.str(); first = (std::string *)TMM_declare_var_s(temp_str.c_str()) ; + *first = std::string("inner"); temp_str = std::string(object_name + "_" + var_name + "_first"); TMM_add_checkpoint_alloc_dependency(temp_str.c_str()) ; - checkpoint_stl( in_pair.first , object_name + "_" + var_name , "first" ) ; + checkpoint_stl( in_pair.first , object_name + "_" + var_name , "first_inner" ) ; var_declare.str("") ; var_declare.clear() ; @@ -188,9 +190,10 @@ int checkpoint_stl(std::pair & in_pair , std::string object_name << object_name << "_" << var_name << "_second[1]" ; temp_str = var_declare.str(); second = (std::string *)TMM_declare_var_s(temp_str.c_str()) ; + *second = std::string("inner"); temp_str = std::string(object_name + "_" + var_name + "_second"); TMM_add_checkpoint_alloc_dependency(temp_str.c_str()) ; - checkpoint_stl( in_pair.second , object_name + "_" + var_name , "second" ) ; + checkpoint_stl( in_pair.second , object_name + "_" + var_name , "second_inner" ) ; return 0 ; } @@ -256,7 +259,7 @@ int restore_stl(std::pair & in_pair , std::string object_name , REF2 * second_ref ; FIRST * first ; - std::string * second ; + std::string * second_inner ; std::string temp_str; @@ -269,10 +272,10 @@ int restore_stl(std::pair & in_pair , std::string object_name , if ( first_ref != NULL && second_ref != NULL ) { first = (FIRST *)first_ref->address ; - second = (std::string *)second_ref->address ; - + second_inner = (std::string *)second_ref->address ; + temp_str = object_name + "_" + var_name + "_second"; in_pair.first = first[0] ; - restore_stl( in_pair.second , object_name + "_" + var_name , "second" ) ; + restore_stl( in_pair.second , temp_str , *second_inner ) ; delete_stl( in_pair , object_name , var_name ) ; } @@ -288,7 +291,7 @@ int restore_stl(std::pair & in_pair , std::string object_name , REF2 * first_ref ; REF2 * second_ref ; - std::string * first ; + std::string * first_inner ; SECOND * second ; std::string temp_str; @@ -300,10 +303,10 @@ int restore_stl(std::pair & in_pair , std::string object_name , second_ref = ref_attributes((char *)temp_str.c_str()) ; if ( first_ref != NULL && second_ref != NULL ) { - first = (std::string *)first_ref->address ; + first_inner = (std::string *)first_ref->address ; second = (SECOND *)second_ref->address ; - restore_stl( in_pair.first , object_name + "_" + var_name , "first" ) ; + restore_stl( in_pair.first , object_name + "_" + var_name + "_first", *first_inner ) ; in_pair.second = second[0] ; delete_stl( in_pair , object_name , var_name ) ; @@ -319,8 +322,8 @@ int restore_stl(std::pair & in_pair , std::string object_name , REF2 * first_ref ; REF2 * second_ref ; - std::string * first ; - std::string * second ; + std::string * first_inner ; + std::string * second_inner ; std::string temp_str; @@ -332,11 +335,11 @@ int restore_stl(std::pair & in_pair , std::string object_name , second_ref = ref_attributes((char *)temp_str.c_str()) ; if ( first_ref != NULL && second_ref != NULL ) { - first = (std::string *)first_ref->address ; - second = (std::string *)second_ref->address ; + first_inner = (std::string *)first_ref->address ; + second_inner = (std::string *)second_ref->address ; - restore_stl( in_pair.first , object_name + "_" + var_name , "first" ) ; - restore_stl( in_pair.second , object_name + "_" + var_name , "second" ) ; + restore_stl( in_pair.first , object_name + "_" + var_name + "_first" , *first_inner ) ; + restore_stl( in_pair.second , object_name + "_" + var_name + "_second", *second_inner ) ; delete_stl( in_pair , object_name , var_name ) ; } diff --git a/include/trick/checkpoint_sequence_stl.hh b/include/trick/checkpoint_sequence_stl.hh index bb6f5918..ce616692 100644 --- a/include/trick/checkpoint_sequence_stl.hh +++ b/include/trick/checkpoint_sequence_stl.hh @@ -111,7 +111,8 @@ int checkpoint_sequence_s(STL & in_stl , std::string object_name , std::string v std::ostringstream index_string ; index_string << ii ; //message_publish(1, "recursive call to checkpoint_stl %s\n", __PRETTY_FUNCTION__) ; - checkpoint_stl( (*it) , object_name + "_" + var_name , index_string.str() ) ; + checkpoint_stl( const_cast(*it) , object_name + "_" + var_name , index_string.str() ) ; + } } } diff --git a/include/trick/compareFloatingPoint.hh b/include/trick/compareFloatingPoint.hh new file mode 100644 index 00000000..ac0b4c5b --- /dev/null +++ b/include/trick/compareFloatingPoint.hh @@ -0,0 +1,13 @@ +#ifndef COMPARE_FLOATING_POINT_HH +#define COMPARE_FLOATING_POINT_HH + +/* author: John M. Penn */ + +namespace Trick { + +bool dbl_is_near( double A, double B, double tolerance); +bool flt_is_near( float A, float B, float tolerance); + +} + +#endif diff --git a/include/trick/files_to_ICG.hh b/include/trick/files_to_ICG.hh index c725117d..524e5241 100644 --- a/include/trick/files_to_ICG.hh +++ b/include/trick/files_to_ICG.hh @@ -18,6 +18,17 @@ #include "trick/JSONVariableServer.hh" #include "trick/JSONVariableServerThread.hh" #include "trick/Master.hh" +#include "trick/mc_master.hh" +#include "trick/mc_python_code.hh" +#include "trick/mc_variable_file.hh" +#include "trick/mc_variable_fixed.hh" +#include "trick/mc_variable.hh" +#include "trick/mc_variable_random_bool.hh" +#include "trick/mc_variable_random.hh" +#include "trick/mc_variable_random_normal.hh" +#include "trick/mc_variable_random_string.hh" +#include "trick/mc_variable_random_uniform.hh" +#include "trick/mc_variable_semi_fixed.hh" #include "trick/Slave.hh" #include "trick/MSSocket.hh" #include "trick/MSSharedMem.hh" @@ -33,14 +44,12 @@ #include "trick/RealtimeSync.hh" #include "trick/ITimer.hh" #include "trick/VariableServer.hh" - #include "trick/regula_falsi.h" #include "trick/Integrator.hh" #include "trick/IntegAlgorithms.hh" #include "trick/IntegLoopScheduler.hh" #include "trick/IntegLoopManager.hh" #include "trick/IntegLoopSimObject.hh" - #include "trick/ABM_Integrator.hh" #include "trick/Euler_Cromer_Integrator.hh" #include "trick/Euler_Integrator.hh" @@ -51,7 +60,6 @@ #include "trick/RKF45_Integrator.hh" #include "trick/RKF78_Integrator.hh" #include "trick/RKG4_Integrator.hh" - #include "trick/SimTime.hh" /* from the er7_utils directory */ diff --git a/include/trick/mc_master.hh b/include/trick/mc_master.hh new file mode 100644 index 00000000..588d1bc3 --- /dev/null +++ b/include/trick/mc_master.hh @@ -0,0 +1,124 @@ +/*******************************TRICK HEADER****************************** +PURPOSE: (Provides the front-end interface to the monte-carlo model) + +LIBRARY DEPENDENCY: + ((../src/mc_master.cc)) + +PROGRAMMERS: + (((Gary Turner) (OSR) (October 2019) (Antares) (Initial))) + (((Isaac Reaves) (NASA) (November 2022) (Integration into Trick Core))) +**********************************************************************/ +#ifndef CML_MONTE_CARLO_MASTER_HH +#define CML_MONTE_CARLO_MASTER_HH + +#include +#include +#include // std::pair + +#include "mc_variable.hh" +#include "mc_variable_file.hh" +#include "mc_python_code.hh" +#include "mc_variable_random.hh" +#include "mc_variable_fixed.hh" +#include "mc_variable_semi_fixed.hh" + +/***************************************************************************** +MonteCarloMaster +Purpose:() +*****************************************************************************/ +class MonteCarloMaster +{ + public: + bool active; /* (--) + The main active flag determining whether an input file should be + processed for a monte-carlo run. This flag is used to manage the + configuration of the scenario, including things like which variables + to log.*/ + bool generate_dispersions; /* (--) + This flag controls whether the variables should be loaded and + dispersed. It has no effect if the active flag is off. + False: Configure the run for MC; this + configuration typically uses a previously-generated + monte_input.py file; it does not read in MC variables and + does not generate new monte_input files. + True: Use this execution of the sim to read in the MC variables and + generating the monte-input files. After doing so, the + execution will terminate. + The sim can then be re-run using one of the new monte_input files. + Default: true. This is set to false in the monte_input.py files to + allow the base input file to be processed from within the + monte-input file without regenerting the monte-input files.*/ + std::string run_name; /* (--) + The name of the scenario, used in generating the "MONTE_" + directory, which contains all of the runs.*/ + std::string monte_dir; /* (--) + The name of the MONTE directory relative to the SIM directory + where runs will be generated*/ + std::string input_file_name; /* (--) + The name of the original file used as the main input file. + Default: input.py.*/ + bool generate_meta_data; /* (--) + Flag indicating whether to generate the meta-data output file.*/ + bool generate_summary; /* (--) + Flag indicating whether to generate the dispersion summary file. */ + int minimum_padding; /* (--) + The minimum width of the run-number field, e.g. RUN_1 vs RUN_00001; + The run-number field will be sized to the minimum of this value or the + width necessary to accommodate the highest number. + Defaults to 0. */ + size_t monte_run_number; /* (--) + A unique identifying number for each run.*/ + + protected: + bool input_files_prepared; /* (--) + Internal flag indicating that the input files have been generated and + waiting for execution. Effectively blocks further modifications to + variables after this flag has been set.*/ + + std::string location; /* (--) + The location in the main sim by which this instance may be addressed + in an input file. */ + + std::list variables; /* (--) + A STL-list of pointers to instances of all the base-class + MonteVarVariable instances. Note that this has to be a list of pointers + rather than instances because the actual instances are polymorphic; + making a copy would restrict them to be actual MonteCarloVariable + instances and we need the polymorphic capabilities for generating the + monte_input command.*/ + + unsigned int num_runs; /* (--) + The number of runs to execute for this scenario.*/ + + private: + std::list< std::pair< std::string, + MonteCarloVariableFile *> > file_list; /* (--) + A list of filenames being read as part of the MonteVarFile variables + being managed by this class. */ + + + public: + MonteCarloMaster(std::string location); + virtual ~MonteCarloMaster(){}; + + void activate( std::string run_name); + bool prepare_input_files(); + void add_variable( MonteCarloVariable & variable); + MonteCarloVariable * find_variable( std::string var_name); + void remove_variable( std::string var_name); + void set_num_runs( unsigned int num_runs); + void execute(); + void collate_meta_data(); + + private: + static bool seed_sort( std::pair< unsigned int, std::string> left, + std::pair< unsigned int, std::string> right) + { + return left.first < right.first; + } + + // and undefined: + MonteCarloMaster (const MonteCarloMaster&); + MonteCarloMaster& operator = (const MonteCarloMaster&); +}; +#endif diff --git a/include/trick/mc_python_code.hh b/include/trick/mc_python_code.hh new file mode 100644 index 00000000..4beaf9be --- /dev/null +++ b/include/trick/mc_python_code.hh @@ -0,0 +1,115 @@ +/*******************************TRICK HEADER****************************** +PURPOSE: ( Implementation of a simple python executable code instruction) + +LIMITATION: (This implementation is intended to provide a fixed operation + that generates one variable as a function of one or more + variables -- such as random variables -- that were previously + generated by the MonteCarlo process. + E.g. y = x + 2 + It does not provide randomization of the operation itself; in + this example the value y will always be generated as x+2, using + the value x which may be variable. However, it will never be + generated as x+3. + To implement randomization of the operation itself, use the + MonteCarloVariableRandomStringSet class instead.) + +PROGRAMMERS: + (((Gary Turner) (OSR) (October 2019) (Antares) (Initial))) + (((Isaac Reaves) (NASA) (November 2022) (Integration into Trick Core))) +**********************************************************************/ +#ifndef CML_MONTE_CARLO_PYTHON_CODE_HH +#define CML_MONTE_CARLO_PYTHON_CODE_HH + +#include "mc_variable.hh" + +class MonteCarloPythonLineExec : public MonteCarloVariable +{ + public: + std::string instruction_set; /* (--) + The right-hand-side of an equation that gets inserted into the + monte-input file and looks like: + = */ + protected: + bool instruction_is_command; /* (--) + Indicates whether to implement a command that looks like: + - variable=instruction vs + variable representing the standalone command, in which case + variable_name and instruction_set are identical. */ + + public: + // 2 constructors: + MonteCarloPythonLineExec(const std::string & var_name, + const std::string & instruction) + : + MonteCarloVariable( var_name), + instruction_set(instruction), + instruction_is_command(false) + { + include_in_summary = false; + type = MonteCarloVariable::Calculated; + } + // other constructor + MonteCarloPythonLineExec( const std::string & instruction) + : + MonteCarloVariable( instruction), + instruction_set(instruction), + instruction_is_command(true) + { + include_in_summary = false; + type = MonteCarloVariable::Execute; + } + virtual ~MonteCarloPythonLineExec(){}; + + void generate_assignment() + { + if (instruction_is_command) { + command = "\n" + instruction_set; + } + else { + command = "\n" + variable_name + " = " + instruction_set; + } + } + private: // and undefined: + MonteCarloPythonLineExec( const MonteCarloPythonLineExec & ); + MonteCarloPythonLineExec& operator = (const MonteCarloPythonLineExec&); +}; + + +/***************************************************************************** +MonteCarloPythonFileExec +Purpose:(Provides a filename for execution to support more extensive + calculations than are possible with the simple one-liner commands + provided by MonteCarloPythonLineExec) +Assumptions: The file identified by filename is expected to be a Python file +Limitations: The file is not tested prior to execution +Other notes: + This class inherits from MonteCarloVariable to simplify the inclusion of + its "command" into the monte_input files. However, it does not populate + a specific variable; its command string is an executive statement, unlike + other MonteCarloVariable instances, which have a command string that + looks like "variable = ..." + This class's "variable_name" is instead re-purposed as a filename +*****************************************************************************/ +class MonteCarloPythonFileExec : public MonteCarloVariable +{ + public: + MonteCarloPythonFileExec(const std::string & filename) + : + MonteCarloVariable( filename) + { + include_in_summary = false; + type = MonteCarloVariable::Execute; + } + virtual ~MonteCarloPythonFileExec(){}; + + void generate_assignment() + { + command = + "\nexec(open('" + variable_name + "').read())"; + } + private: // and undefined: + MonteCarloPythonFileExec( const MonteCarloPythonFileExec & ); + MonteCarloPythonFileExec& operator = (const MonteCarloPythonFileExec&); +}; + +#endif diff --git a/include/trick/mc_variable.hh b/include/trick/mc_variable.hh new file mode 100644 index 00000000..84ba2ed7 --- /dev/null +++ b/include/trick/mc_variable.hh @@ -0,0 +1,83 @@ +/*******************************TRICK HEADER****************************** +PURPOSE: ( Base class for the MonteCarloVariable type) + +LIBRARY DEPENDENCY: + ((../src/mc_variable.cc)) + +PROGRAMMERS: + (((Gary Turner) (OSR) (October 2019) (Antares) (Initial))) + (((Isaac Reaves) (NASA) (November 2022) (Integration into Trick Core))) +**********************************************************************/ +#ifndef CML_MONTE_CARLO_VARIABLE_HH +#define CML_MONTE_CARLO_VARIABLE_HH + +#include + +class MonteCarloVariable +{ + public: + enum MonteCarloVariableType + { + Undefined = 0, + Calculated, + Constant, + Execute, + Prescribed, + Random + }; + + std::string units; /* (--) + optional setting in the case where the specified values are in units + different from the native units of the variable. + These are the units associated with the specified-value.*/ + bool include_in_summary; /* (--) + Flag telling MonteCarloMaster whether to include this variable in the + dispersion summary file. The default depends on the type of variable but + is generally true. */ + + protected: + std::string variable_name; /* (--) + The name of the sim-variable being assigned by this instance. */ + std::string assignment; /* (--) + The value assigned to the variable. Used in MonteCarloMaster to generate + the dispersion summary file. */ + std::string command; /* (--) + the command that gets pushed to the monte_input input file.*/ + MonteCarloVariableType type; /* (--) + Broad categorization of types of MonteCarloVariable. This is set in the + constructor of the specific classes derived from MonteCarloVariable and + provides information to the MonteCarloMaster about what general type of + variable it is dealing with.*/ + + + public: + MonteCarloVariable( const std::string & var_name); + virtual ~MonteCarloVariable() {}; + + + virtual void generate_assignment() = 0; + virtual void shutdown() {}; // deliberately empty + + // These getters are intended to be used by the MonteCarloMaster class in + // preparing the input files and summary data files. They may also be used + // in the user interface, but -- especially get_assignment and get_command -- + // have limited use there. + const std::string & get_command() const {return command;} + const std::string & get_variable_name() const {return variable_name;} + const std::string & get_assignment() const {return assignment;} + MonteCarloVariableType get_type() const {return type;} + virtual unsigned int get_seed() const {return 0;} + + protected: + void insert_units(); + void trick_units(size_t); + void assign_double(double value); + void assign_int(int value); + void generate_command(); + + private: // and undefined: + MonteCarloVariable( const MonteCarloVariable &); + MonteCarloVariable& operator = (const MonteCarloVariable&); +}; + +#endif diff --git a/include/trick/mc_variable_file.hh b/include/trick/mc_variable_file.hh new file mode 100644 index 00000000..7b1df70b --- /dev/null +++ b/include/trick/mc_variable_file.hh @@ -0,0 +1,87 @@ +/*******************************TRICK HEADER****************************** +PURPOSE: ( Implementation of a file-lookup assignment + +LIBRARY DEPENDENCY: + (../src/mc_variable_file.cc) + +PROGRAMMERS: + (((Gary Turner) (OSR) (October 2019) (Antares) (Initial))) + (((Isaac Reaves) (NASA) (November 2022) (Integration into Trick Core))) +**********************************************************************/ +#ifndef CML_MONTE_CARLO_VARIABLE_FILE_HH +#define CML_MONTE_CARLO_VARIABLE_FILE_HH + +#include // ifstream +#include // default_random_engine, uniform_int_distribution +#include + +#include "trick/mc_variable.hh" + +/***************************************************************************** +MonteCarloVariableFile +Purpose:( + Grabs a value from a data file. + The data value is located within the file at some column number and + row number. + The column number is specified for the variable. + The row -- or line -- number changes from run to run. + The file is expected to provide consistent presentation of data from + row to row.) +*****************************************************************************/ +class MonteCarloVariableFile : public MonteCarloVariable +{ + public: + size_t max_skip; /* (--) + The maximum number of lines to skip in a file. This defaults to 0, + indicating that the file will be read sequentially.*/ + bool is_dependent; /* (--) + A flag indicating that this instance is dependent upon another instance + for reading the file "filename". Only one instance will read each + filename. Default: false. */ + protected: + std::mt19937 rand_gen; /* (--) + A random number generator used in the case that the lines are not read + sequentially. This will generate a value from 0 to max_skip indicating + how many lines should be skipped.*/ + std::string filename; /* (--) + The name of the file containing the data for this variable. Assigned + at construction.*/ + size_t column_number;/* (--) + The column number indicating from where in the data file the data for + this variable should be extracted.*/ + size_t first_column_number; /* (--) + Usually used to distinguish between whether the first column should be + identified with a 0 or 1, but extensible to other integers as well. + Default: 1. */ + std::list< MonteCarloVariableFile *> dependents; /* (--) + A list of MonteVarVariableFile instances that use the same file as + this one. This list is only populated if this instance was the first + registered to use this file.*/ + std::ifstream file; /* (--) + Input file stream being the file containing the data.*/ + + public: + MonteCarloVariableFile( const std::string & var_name, + const std::string & filename, + size_t column_number_, + size_t first_column_number = 1); + virtual ~MonteCarloVariableFile(){}; + void initialize_file(); + void generate_assignment(); + void register_dependent( MonteCarloVariableFile *); + virtual void shutdown() {file.close();} + + + bool has_dependents() {return (dependents.size() > 1);} + size_t get_column_number() {return column_number;} + size_t get_first_column_number() {return first_column_number;} + const std::string & get_filename() {return filename;} + const std::list< MonteCarloVariableFile *> & get_dependents() {return dependents;} + protected: + void process_line(); + static bool sort_by_col_num(MonteCarloVariableFile *, MonteCarloVariableFile *); + private: // and undefined: + MonteCarloVariableFile(const MonteCarloVariableFile&); + MonteCarloVariableFile& operator = ( const MonteCarloVariableFile&); +}; +#endif diff --git a/include/trick/mc_variable_fixed.hh b/include/trick/mc_variable_fixed.hh new file mode 100644 index 00000000..31ac366a --- /dev/null +++ b/include/trick/mc_variable_fixed.hh @@ -0,0 +1,70 @@ +/*******************************TRICK HEADER****************************** +PURPOSE: ( Implementation of a class template to support assignment of + a fixed value to a variable based on its type.) + +LIMITATION: (Because these types are typically instantiated + from the Python input processor via SWIG, use of + templates is problematic. Consequently, it would + require a whole different setup to handle integers + differently than floats. Instead, integers and floats + will both be treated using the "double" data type. + Values that cannot be assigned to a double (like bool or strings) + cannot be represented by an instance of this class.) + +PROGRAMMERS: + (((Gary Turner) (OSR) (October 2019) (Antares) (Initial))) + (((Isaac Reaves) (NASA) (November 2022) (Integration into Trick Core))) +**********************************************************************/ +#ifndef CML_MONTE_CARLO_VARIABLE_FIXED_HH +#define CML_MONTE_CARLO_VARIABLE_FIXED_HH + +#include "mc_variable.hh" +#include // ostringstream + +class MonteCarloVariableFixed : public MonteCarloVariable +{ + protected: + int var_type; /* (--) 0: double + 1: integer + 2: string;*/ + public: + + MonteCarloVariableFixed(const std::string & var_name, + double assignment_) + : + MonteCarloVariable( var_name), + var_type(0) + { + type = MonteCarloVariable::Constant; + assign_double(assignment_); + } + + MonteCarloVariableFixed(const std::string & var_name, + int assignment_) + : + MonteCarloVariable( var_name), + var_type(1) + { + type = MonteCarloVariable::Constant; + assign_int(assignment_); + } + MonteCarloVariableFixed(const std::string & var_name, + const std::string & assignment_) + : + MonteCarloVariable( var_name), + var_type(2) + { + include_in_summary = false; + assignment = assignment_; + type = MonteCarloVariable::Constant; + generate_command(); + } + virtual ~MonteCarloVariableFixed(){}; + + void generate_assignment(){}; // to make this class instantiable + + private: // and undefined: + MonteCarloVariableFixed( const MonteCarloVariableFixed & ); + MonteCarloVariableFixed& operator = (const MonteCarloVariableFixed&); +}; +#endif diff --git a/include/trick/mc_variable_random.hh b/include/trick/mc_variable_random.hh new file mode 100644 index 00000000..649b4ea1 --- /dev/null +++ b/include/trick/mc_variable_random.hh @@ -0,0 +1,48 @@ +/*******************************TRICK HEADER****************************** +PURPOSE: ( Implementation of a class to support assignment of + a random value to a variable based on its type.) + +PROGRAMMERS: + (((Gary Turner) (OSR) (October 2019) (Antares) (Initial))) + (((Isaac Reaves) (NASA) (November 2022) (Integration into Trick Core))) +**********************************************************************/ +#ifndef CML_MONTE_CARLO_VARIABLE_RANDOM_HH +#define CML_MONTE_CARLO_VARIABLE_RANDOM_HH + +#include "mc_variable.hh" + +#include +#include + +/***************************************************************************** +MonteCarloVariableRandom +Purpose:(An intermediate interface class that supports generation of random + variables of multiple types. Currently, double, integer, bool, and + string assignments are supported; others may be added later.) +NOTE - deliberately not using templates here because of the difficulty of having + SWIG use templates; Monte-Carlo variables are typically created and + populated via an input-process so the SWIG interface is critical and the + use of templates a non-starter. +*****************************************************************************/ +class MonteCarloVariableRandom : public MonteCarloVariable +{ + protected: + std::mt19937 random_generator; /* (--) + the basic random-generator used by all different types of random number + generators in the library. */ + unsigned int seed_m; /* (--) + the value used to seed the generator.*/ + public: + MonteCarloVariableRandom(const std::string & var_name, unsigned int seed = 0): MonteCarloVariable(var_name),random_generator(seed),seed_m(seed) //changed seed member variable to seed_m + { + type = MonteCarloVariable::Random; + } + virtual ~MonteCarloVariableRandom(){}; + unsigned int get_seed() const {return seed_m;} // override but SWIG cannot process the + // override keyword + + private: // and undefined: + MonteCarloVariableRandom( const MonteCarloVariableRandom & ); + MonteCarloVariableRandom& operator = (const MonteCarloVariableRandom&); +}; +#endif diff --git a/include/trick/mc_variable_random_bool.hh b/include/trick/mc_variable_random_bool.hh new file mode 100644 index 00000000..73d9a6d5 --- /dev/null +++ b/include/trick/mc_variable_random_bool.hh @@ -0,0 +1,42 @@ +/*******************************TRICK HEADER****************************** +PURPOSE: ( Uses the RandomString generator to generate either a "True" or + "False" string for assignment through the SWIG interface. + Note that SWIG uses the Python uppercase True/False rather than + C++ lowercase true/false identifiers. + +PROGRAMMERS: + (((Gary Turner) (OSR) (October 2019) (Antares) (Initial))) + (((Isaac Reaves) (NASA) (November 2022) (Integration into Trick Core))) +**********************************************************************/ +#ifndef CML_MONTE_CARLO_VARIABLE_RANDOM_BOOL_HH +#define CML_MONTE_CARLO_VARIABLE_RANDOM_BOOL_HH + +#include "mc_variable_random_string.hh" + +/***************************************************************************** +MonteCarloVariableRandomBool +Purpose:(Generates either a True or False string for assignment) +*****************************************************************************/ +class MonteCarloVariableRandomBool : public MonteCarloVariableRandomStringSet +{ + public: + MonteCarloVariableRandomBool( const std::string & var_name, + unsigned int seed) + : + MonteCarloVariableRandomStringSet( var_name, seed) + { + add_string("False"); + add_string("True"); + include_in_summary = true; // String variables are excluded by default + // because they may contain commas, which would + // cause trouble in the comma-delimited summary + // file. However, this is a special case in which + // the possible strings are "True" and "False". + } + virtual ~MonteCarloVariableRandomBool(){}; + private: // and undefined: + MonteCarloVariableRandomBool(const MonteCarloVariableRandomBool&); + MonteCarloVariableRandomBool& operator = ( + const MonteCarloVariableRandomBool&); +}; +#endif diff --git a/include/trick/mc_variable_random_normal.hh b/include/trick/mc_variable_random_normal.hh new file mode 100644 index 00000000..2353ecf4 --- /dev/null +++ b/include/trick/mc_variable_random_normal.hh @@ -0,0 +1,57 @@ +/*******************************TRICK HEADER****************************** +PURPOSE: ( Implementation of a class to support generation and assignment + of a random value distributed normally.) + +LIBRARY DEPENDENCY: + (../src/mc_variable_random_normal.cc) + +PROGRAMMERS: + (((Gary Turner) (OSR) (October 2019) (Antares) (Initial))) + (((Isaac Reaves) (NASA) (November 2022) (Integration into Trick Core))) +**********************************************************************/ +#ifndef CML_MONTE_CARLO_VARIABLE_RANDOM_NORMAL_HH +#define CML_MONTE_CARLO_VARIABLE_RANDOM_NORMAL_HH + +#include + +#include "mc_variable_random.hh" + +class MonteCarloVariableRandomNormal : public MonteCarloVariableRandom +{ + public: + enum TruncationType + { + StandardDeviation, + Relative, + Absolute + }; + size_t max_num_tries; + + protected: + #ifndef SWIG + std::normal_distribution distribution; + #endif + double min_value; + double max_value; + bool truncated_low; + bool truncated_high; + + public: + MonteCarloVariableRandomNormal( const std::string & var_name, + unsigned int seed = 0, + double mean = 0, + double stdev = 1); + + virtual ~MonteCarloVariableRandomNormal(){}; + virtual void generate_assignment(); + void truncate(double limit, TruncationType type = StandardDeviation); + void truncate(double min, double max, TruncationType type = StandardDeviation); + void truncate_low(double limit, TruncationType type = StandardDeviation); + void truncate_high(double limit, TruncationType type = StandardDeviation); + void untruncate(); + private: // and undefined: + MonteCarloVariableRandomNormal(const MonteCarloVariableRandomNormal&); + MonteCarloVariableRandomNormal& operator = ( + const MonteCarloVariableRandomNormal&); +}; +#endif diff --git a/include/trick/mc_variable_random_string.hh b/include/trick/mc_variable_random_string.hh new file mode 100644 index 00000000..602e8eea --- /dev/null +++ b/include/trick/mc_variable_random_string.hh @@ -0,0 +1,52 @@ +/*******************************TRICK HEADER****************************** +PURPOSE: ( Implementation of a class to randomly pick one of a set of + character strings. These strings could represent actual string + variables, or enumerated types, or commands, or any other concept + that can be expressed as an assignment.) + +ASSUMPTIONS: (The content of the selected string will be assigned as written. + Consequently, if the value is being assigned to an actual string + or char variable, the contents of the string should be enclosed + in quotes. + E.g. the string might look like: "'actual_string'" so that the + assignment would look like + variable = 'actual_string' + This is to support the use of a string to represent a non-string + variable such as an enumeration or command: + E.g. the string might look like "x * 3 + 2" to achieve: + variable = x * 3 + 2 + ) + + +LIBRARY DEPENDENCY: + (../src/mc_variable_random_string.cc) + +PROGRAMMERS: + (((Gary Turner) (OSR) (October 2019) (Antares) (Initial))) + (((Isaac Reaves) (NASA) (November 2022) (Integration into Trick Core))) +**********************************************************************/ +#ifndef CML_MONTE_CARLO_VARIABLE_RANDOM_STRING_HH +#define CML_MONTE_CARLO_VARIABLE_RANDOM_STRING_HH + +#include "mc_variable_random_uniform.hh" + +#include +#include +#include + +class MonteCarloVariableRandomStringSet : public MonteCarloVariableRandomUniform +{ + public: + std::vector< std::string> values; + MonteCarloVariableRandomStringSet( const std::string & var_name, + unsigned int seed); + + virtual ~MonteCarloVariableRandomStringSet(){}; + virtual void generate_assignment(); + void add_string(std::string); + private: // and undefined: + MonteCarloVariableRandomStringSet(const MonteCarloVariableRandomStringSet&); + MonteCarloVariableRandomStringSet& operator = ( + const MonteCarloVariableRandomStringSet&); +}; +#endif diff --git a/include/trick/mc_variable_random_uniform.hh b/include/trick/mc_variable_random_uniform.hh new file mode 100644 index 00000000..e563ab34 --- /dev/null +++ b/include/trick/mc_variable_random_uniform.hh @@ -0,0 +1,67 @@ +/*******************************TRICK HEADER****************************** +PURPOSE: ( Implementation of a class to support generation and assignment + of a random value distributed uniformally. + Provides float and integer distributions) + +LIBRARY DEPENDENCY: + (../src/mc_variable_random_uniform.cc) + +PROGRAMMERS: + (((Gary Turner) (OSR) (October 2019) (Antares) (Initial))) + (((Isaac Reaves) (NASA) (November 2022) (Integration into Trick Core))) +**********************************************************************/ +#ifndef CML_MONTE_CARLO_VARIABLE_RANDOM_UNIFORM_HH +#define CML_MONTE_CARLO_VARIABLE_RANDOM_UNIFORM_HH + +#include "mc_variable_random.hh" + +#include + +/***************************************************************************** +MonteCarloVariableRandomUniform +Purpose:() +*****************************************************************************/ +class MonteCarloVariableRandomUniform : public MonteCarloVariableRandom +{ + protected: + #ifndef SWIG + std::uniform_real_distribution distribution; + #endif + + public: + MonteCarloVariableRandomUniform( const std::string & var_name, + unsigned int seed = 0, + double lower_bound = 0.0, + double upper_bound = 1.0); + virtual ~MonteCarloVariableRandomUniform(){}; + virtual void generate_assignment(); + private: // and undefined: + MonteCarloVariableRandomUniform( const MonteCarloVariableRandomUniform & ); + MonteCarloVariableRandomUniform& operator = ( + const MonteCarloVariableRandomUniform&); +}; + +/***************************************************************************** +MonteCarloVariableRandomUniformInt +Purpose:() +*****************************************************************************/ +class MonteCarloVariableRandomUniformInt : public MonteCarloVariableRandom +{ + protected: + #ifndef SWIG + std::uniform_int_distribution distribution; + #endif + + public: + MonteCarloVariableRandomUniformInt( const std::string & var_name, + unsigned int seed = 0, + double lower_bound = 0, + double upper_bound = 1); + virtual ~MonteCarloVariableRandomUniformInt(){}; + virtual void generate_assignment(); + private: // and undefined: + MonteCarloVariableRandomUniformInt(const MonteCarloVariableRandomUniformInt&); + MonteCarloVariableRandomUniformInt& operator = ( + const MonteCarloVariableRandomUniformInt&); +}; +#endif diff --git a/include/trick/mc_variable_semi_fixed.hh b/include/trick/mc_variable_semi_fixed.hh new file mode 100644 index 00000000..cde702e5 --- /dev/null +++ b/include/trick/mc_variable_semi_fixed.hh @@ -0,0 +1,81 @@ +/*******************************TRICK HEADER****************************** +PURPOSE: ( + Implementation of a semi-fixed monte-carlo variable. + The value of a MonteCarloVariableFixed instance is assigned at + construction time and held at that value for all runs. + The value of a MonteCarloVariableSemiFixed instance is assigned + from another MonteCarloVariable generated value for the first + input file generated, and held at that value for all runs. So the + assignment to a Semi-fixed can change each time the input files are + generated, but it is the same for all input files in any given + generation.) + +PROGRAMMERS: + (((Gary Turner) (OSR) (October 2019) (Antares) (Initial))) + (((Isaac Reaves) (NASA) (November 2022) (Integration into Trick Core))) +**********************************************************************/ +#ifndef CML_MONTE_CARLO_VARIABLE_SEMI_FIXED_HH +#define CML_MONTE_CARLO_VARIABLE_SEMI_FIXED_HH + +#include "mc_variable_random.hh" +#include "trick/message_proto.h" +#include "trick/message_proto.h" + +// TODO Turner 2019/11 +// The reference to a MonteCarloVariable might be difficult to +// obtain because these are typically created on-the-fly and +// the handle to the created instance is lost. Might be +// nice to provide the seed-variable-name instead of the reference +// to the seed-variable itself, and have the MonteCarloMaster find +// the MonteCarloVariable associated with that name. +// But that's non-trivial and not necessarily desirable, so it is +// left unimplemented. + +class MonteCarloVariableSemiFixed : public MonteCarloVariable +{ + protected: + const MonteCarloVariable & seed_variable; /* (--) + A reference to another MonteCarloVariable; the value of *this* + variable is taken from the value of this seed-variable during + preparation of the first monte-input file. */ + bool command_generated; /* (--) + flag indicating the fixed command has been generated.*/ + public: + MonteCarloVariableSemiFixed(const std::string & var_name, + const MonteCarloVariable & seed_) + : + MonteCarloVariable( var_name), + seed_variable(seed_), + command_generated(false) + { + type = MonteCarloVariable::Constant; + } + virtual ~MonteCarloVariableSemiFixed(){}; + + void generate_assignment() { + if (!command_generated) { + // parse the command from seed_variable to get the assignment. + std::string seed_command = seed_variable.get_command(); + size_t pos_equ = seed_command.find("="); + if (pos_equ == std::string::npos) { + std::string message = + std::string("File: ") + __FILE__ + + ", Line: " + std::to_string(__LINE__) + std::string(", Invalid " + "sequencing\nFor variable ") + variable_name.c_str() + + std::string(" the necessary pre-dispersion to obtain the\n " + "random value for assignment has not been completed.\nCannot " + "generate the assignment for this variable.\n"); + message_publish(MSG_ERROR, message.c_str()); + return; + } + assignment = seed_command.substr(pos_equ+1); + generate_command(); + insert_units(); + command_generated = true; + } + } + private: // and undefined: + MonteCarloVariableSemiFixed( const MonteCarloVariableSemiFixed & ); + MonteCarloVariableSemiFixed& operator = (const MonteCarloVariableSemiFixed&); +}; +#endif diff --git a/include/trick/memorymanager_c_intf.h b/include/trick/memorymanager_c_intf.h index 0603dbaa..9c57fb7f 100644 --- a/include/trick/memorymanager_c_intf.h +++ b/include/trick/memorymanager_c_intf.h @@ -50,12 +50,14 @@ void TMM_delete_extern_var_a( void* address); void TMM_delete_extern_var_n( const char* var_name ); void TMM_write_checkpoint( const char* filename) ; + int TMM_read_checkpoint( const char* filename); int TMM_read_checkpoint_from_string( const char* str); - int TMM_init_from_checkpoint( const char* filename); + int TMM_add_shared_library_symbols( const char* filename); +int TMM_set_stl_restore (int on_off); REF2* ref_attributes(const char* name); int ref_var(REF2* R, char* name); diff --git a/include/trick/mm_macros.hh b/include/trick/mm_macros.hh index c872b6eb..1bdc028e 100644 --- a/include/trick/mm_macros.hh +++ b/include/trick/mm_macros.hh @@ -37,10 +37,10 @@ return addr ; \ } ; \ static void operator delete (void *p) { \ - if ( get_alloc_info_at(p) ) { trick_MM->delete_var(p, false) ; free(p) ; } \ + if ( get_alloc_info_at(p) ) { trick_MM->delete_var(p) ; free(p) ; } \ } ; \ static void operator delete[] (void *p) { \ - if ( get_alloc_info_at(p) ) { trick_MM->delete_var(p, false) ; free(p) ; } \ + if ( get_alloc_info_at(p) ) { trick_MM->delete_var(p) ; free(p) ; } \ } ; #endif diff --git a/include/trick/sie_c_intf.h b/include/trick/sie_c_intf.h index cc458423..4842aec3 100644 --- a/include/trick/sie_c_intf.h +++ b/include/trick/sie_c_intf.h @@ -8,6 +8,7 @@ void sie_class_attr_map_print_xml(void) ; void sie_enum_attr_map_print_xml(void) ; void sie_top_level_objects_print_xml(void) ; void sie_append_runtime_objs(void) ; +std::string sie_get_runtime_sie_dir(void); #ifdef __cplusplus } diff --git a/include/trick/var_binary_parser.hh b/include/trick/var_binary_parser.hh new file mode 100644 index 00000000..723166b5 --- /dev/null +++ b/include/trick/var_binary_parser.hh @@ -0,0 +1,142 @@ +#include +#include +#include +#include +#include + +#include "trick/parameter_types.h" + +class IncorrectUsageException : public std::exception +{ + private: + std::string _message; + public: + IncorrectUsageException(std::string msg) : _message(msg) {} + const char * what() const noexcept override { return _message.c_str(); } +}; + +class ParseTypeException : public IncorrectUsageException +{ + public: + ParseTypeException() : IncorrectUsageException("Mismatched trick type and template call") {} +}; + +class MalformedMessageException : public std::exception +{ + private: + std::string _message; + public: + MalformedMessageException() : _message("Attempted to parse an incorrectly formed message") {} + MalformedMessageException(std::string msg) : _message(msg) {} + const char * what() const noexcept override { return _message.c_str(); } +}; + +typedef union Number { + unsigned char raw_bytes[sizeof(long long)]; // Raw bytes + + uint8_t unsigned_char_val; + int8_t char_val; + bool bool_val; + + wchar_t wchar_val; + uint16_t unsigned_short_val; + int16_t short_val; + + uint32_t unsigned_int_val; + int32_t int_val; + + uint64_t unsigned_long_val; + int64_t long_val; + + unsigned long long unsigned_long_long_val; + long long long_long_val; + + float float_val; + double double_val; +} Number; + +const static std::map type_size_map = {{TRICK_CHARACTER, sizeof(char)}, + {TRICK_UNSIGNED_CHARACTER, sizeof(unsigned char)}, + {TRICK_SHORT, sizeof(short)}, + {TRICK_UNSIGNED_SHORT, sizeof(unsigned short)}, + {TRICK_INTEGER, sizeof(int)}, + {TRICK_UNSIGNED_INTEGER, sizeof(unsigned int)}, + {TRICK_LONG, sizeof(long)}, + {TRICK_UNSIGNED_LONG, sizeof(unsigned long)}, + {TRICK_LONG_LONG, sizeof(long long)}, + {TRICK_UNSIGNED_LONG_LONG, sizeof(unsigned long)}, + {TRICK_FLOAT, sizeof (float)}, + {TRICK_DOUBLE, sizeof (double)}, + {TRICK_BOOLEAN, sizeof (bool)}, + {TRICK_WCHAR, sizeof (wchar_t)} + }; + + +class Var { + public: + Var () : _has_name(false) {}; + void setValue(const std::vector& bytes, size_t size, TRICK_TYPE type, bool byteswap = false); + void setName(size_t name_size, const std::vector& name_data); + + // The closest to runtime return type polymorphism that I can think of + // There won't be a general case + template + T getValue() const; + std::vector getRawBytes() const; + + int getArraySize() const; + std::string getName() const; + TRICK_TYPE getType() const; + + + private: + std::vector value_bytes; + Number getInterpreter () const; + + bool _has_name; + unsigned int _name_length; + std::string _name; + + bool _byteswap; + + TRICK_TYPE _trick_type; + unsigned int _var_size; + unsigned int _arr_length; +}; + +class ParsedBinaryMessage { + public: + ParsedBinaryMessage() : ParsedBinaryMessage(false, false) {} + ParsedBinaryMessage (bool byteswap, bool nonames) : _message_type(0), _message_size(0), _num_vars(0), _byteswap(byteswap), _nonames(nonames) {} + + void combine (const ParsedBinaryMessage& message); + + int parse (const std::vector& bytes); + int parse (char * raw_bytes); + + int getMessageType() const; + unsigned int getMessageSize() const; + unsigned int getNumVars() const; + Var getVariable(const std::string& name); + Var getVariable(unsigned int index); + + std::vector variables; + + private: + static bool validateMessageType(int message_type); + + int _message_type; + unsigned int _message_size; + unsigned int _num_vars; + + bool _byteswap; + bool _nonames; + + const static size_t header_size; + const static size_t message_indicator_size; + const static size_t variable_num_size; + const static size_t message_size_size; + const static size_t variable_name_length_size; + const static size_t variable_type_size; + const static size_t variable_size_size; +}; \ No newline at end of file diff --git a/include/trick/variable_server_message_types.h b/include/trick/variable_server_message_types.h index a7280cbd..51793ba4 100644 --- a/include/trick/variable_server_message_types.h +++ b/include/trick/variable_server_message_types.h @@ -12,7 +12,10 @@ typedef enum { VS_VAR_EXISTS = 1, VS_SIE_RESOURCE = 2, VS_LIST_SIZE = 3 , - VS_STDIO = 4 + VS_STDIO = 4, + VS_SEND_ONCE = 5, + VS_MIN_CODE = VS_IP_ERROR, + VS_MAX_CODE = VS_SEND_ONCE } VS_MESSAGE_TYPE ; #endif diff --git a/libexec/trick/pm/html.pm b/libexec/trick/pm/html.pm index a6da5c62..d9524373 100644 --- a/libexec/trick/pm/html.pm +++ b/libexec/trick/pm/html.pm @@ -31,7 +31,7 @@ sub extract_trick_header($$$$) { $header{icg_ignore} = $2 if $trick_header =~ /ICG[ _]IGNORE[ _]TYPE(S)?:[^(]*(.*?)\)([A-Z _\t\n\r]+:|[ \t\n\r]*$)/si ; $header{swig} = $1 if $trick_header =~ /SWIG:[^(]*\((.*?)\)([A-Z _\t\n\r]+:|[ \t\n\r]*$)/si ; $header{default_data} = $1 if $trick_header =~ /DEFAULT[ _]DATA:[^(]*(.*?)\)([A-Z _\t\n\r]+:|[ \t\n\r]*$)/si ; - $header{python_module} = $1 if $trick_header =~ /PYTHON[ _]MODULE:[^(]*\((.*?)\)([A-Z _\t\n\r]+:|[ \t\n\r]*$)/si ; + $header{python_module} = $1 if $trick_header =~ /PYTHON[ _]MODULE:[^(]*\((.+?)\)([A-Z _\t\n\r]+:|[ \t\n\r]*$)/si ; $header{programmers} = $1 if $trick_header =~ /PROGRAMMERS:[^(]*(.*?)\)([A-Z _\t\n\r]+:|[ \t\n\r]*$)/si ; $header{language} = $1 if $trick_header =~ /LANGUAGE:[^(]*(.*?)\)([A-Z _\t\n\r]+:|[ \t\n\r]*$)/si ; diff --git a/libexec/trick/pm/parse_s_define.pm b/libexec/trick/pm/parse_s_define.pm index c0313c50..5c179ed4 100644 --- a/libexec/trick/pm/parse_s_define.pm +++ b/libexec/trick/pm/parse_s_define.pm @@ -960,7 +960,19 @@ sub preparse_job_class_order($$) { # save the new order @{$$sim_ref{user_class_order}} = @class_list ; - # push on the advance_sim_time class last if not specified + # push on classes important to trick system function if not specified + if ( !exists $temp_hash{automatic} ) { + unshift @{$$sim_ref{user_class_order}} , "automatic" ; + } + + if ( !exists $temp_hash{automatic_last} ) { + push @{$$sim_ref{user_class_order}} , "automatic_last" ; + } + + if ( !exists $temp_hash{logging} ) { + push @{$$sim_ref{user_class_order}} , "logging" ; + } + if ( !exists $temp_hash{data_record} ) { push @{$$sim_ref{user_class_order}} , "data_record" ; } @@ -976,6 +988,10 @@ sub preparse_job_class_order($$) { if ( !exists $temp_hash{system_moding} ) { push @{$$sim_ref{user_class_order}} , "system_moding" ; } + + if ( !exists $temp_hash{integ_loop} ) { + push @{$$sim_ref{user_class_order}} , "integ_loop" ; + } } 1; diff --git a/share/doc/trick/Trick17_Tutorial_Review.pdf b/share/doc/trick/Trick17_Tutorial_Review.pdf deleted file mode 100644 index 50c247bf..00000000 Binary files a/share/doc/trick/Trick17_Tutorial_Review.pdf and /dev/null differ diff --git a/share/doc/trick/Trick17_Tutorial_Review.pptx b/share/doc/trick/Trick17_Tutorial_Review.pptx deleted file mode 100644 index 172959e0..00000000 Binary files a/share/doc/trick/Trick17_Tutorial_Review.pptx and /dev/null differ diff --git a/share/doc/trick/Trick_Tutorial_Review.pdf b/share/doc/trick/Trick_Tutorial_Review.pdf index b780417e..72325533 100644 Binary files a/share/doc/trick/Trick_Tutorial_Review.pdf and b/share/doc/trick/Trick_Tutorial_Review.pdf differ diff --git a/share/doc/trick/Trick_Tutorial_Review.pptx b/share/doc/trick/Trick_Tutorial_Review.pptx index 6e5bbe90..7b0afae3 100644 Binary files a/share/doc/trick/Trick_Tutorial_Review.pptx and b/share/doc/trick/Trick_Tutorial_Review.pptx differ diff --git a/share/trick/makefiles/Makefile.common b/share/trick/makefiles/Makefile.common index 5e3ea318..77978933 100644 --- a/share/trick/makefiles/Makefile.common +++ b/share/trick/makefiles/Makefile.common @@ -72,6 +72,7 @@ export TRICK_SYSTEM_ICG_EXCLUDE := $(TRICK_SYSTEM_ICG_EXCLUDE) export TRICK_SWIG_FLAGS := $(TRICK_SWIG_FLAGS) export TRICK_SWIG_CFLAGS := $(TRICK_SWIG_CFLAGS) export TRICK_CONVERT_SWIG_FLAGS := $(TRICK_CONVERT_SWIG_FLAGS) +export TRICK_TEST_FLAGS := $(TRICK_TEST_FLAGS) IO_SRC_DIR := io_src/ OBJ_DIR := object_${TRICK_HOST_CPU} @@ -193,6 +194,8 @@ export TRICK_SYSTEM_CFLAGS := $(TRICK_SYSTEM_CXXFLAGS) -fexceptions TRICK_SYSTEM_CFLAGS += $(TRICK_ADDITIONAL_CFLAGS) TRICK_SYSTEM_CXXFLAGS += $(TRICK_ADDITIONAL_CXXFLAGS) +TRICK_TEST_FLAGS += -Wall -Wextra $(TRICK_ADDITIONAL_TEST_FLAGS) + TRICK_INCLUDE = $(shell $(PERL) -e '@inc_paths = "${TRICK_CFLAGS}" =~ /-(?:I|isystem)\s*(\S+)/g ; foreach $$i (@inc_paths) { print "-I$$i " if (-e $$i and $$i ne "/usr/include")}') \ $(shell $(PERL) -e '@inc_paths = "${TRICK_SYSTEM_CFLAGS}" =~ /-(?:I|isystem)\s*(\S+)/g ; foreach $$i (@inc_paths) { print "-I$$i " if (-e $$i)}') diff --git a/share/trick/makefiles/config_Darwin.mk b/share/trick/makefiles/config_Darwin.mk index fb533ad1..249c565d 100644 --- a/share/trick/makefiles/config_Darwin.mk +++ b/share/trick/makefiles/config_Darwin.mk @@ -12,3 +12,4 @@ RPATH = -Wl,-rpath,${TRICK_LIB_DIR} LD_WHOLE_ARCHIVE := -Wl,-all_load LD_NO_WHOLE_ARCHIVE := +TRICK_ADDITIONAL_TEST_FLAGS += -std=c++14 diff --git a/share/trick/makefiles/config_Linux.mk b/share/trick/makefiles/config_Linux.mk index 4a6b6745..8a8876a0 100644 --- a/share/trick/makefiles/config_Linux.mk +++ b/share/trick/makefiles/config_Linux.mk @@ -24,7 +24,7 @@ endif SHARED_LIB_OPT := -shared RPATH = -Wl,-rpath=${TRICK_LIB_DIR} -TRICK_SYSTEM_LDFLAGS = -Wl,--export-dynamic +TRICK_SYSTEM_LDFLAGS += -Wl,--export-dynamic PLATFORM_LIBS = -lrt LD_WHOLE_ARCHIVE := -Wl,-whole-archive @@ -61,3 +61,5 @@ ifeq "" "c++11" TRICK_ADDITIONAL_CXXFLAGS += -std=c++11 -D_HAVE_STL_RANDOM endif +TRICK_ADDITIONAL_TEST_FLAGS += -std=c++11 + diff --git a/share/trick/makefiles/config_user.mk.in b/share/trick/makefiles/config_user.mk.in index 1347929b..011dbdba 100644 --- a/share/trick/makefiles/config_user.mk.in +++ b/share/trick/makefiles/config_user.mk.in @@ -47,5 +47,6 @@ USE_ER7_UTILS = @USE_ER7_UTILS@ LIBXML = @LIBXML@ PREFIX ?= @prefix@ +TRICK_GCC_VERSION = @GCC_VERSION@ CONFIG_MK = 1 diff --git a/share/trick/sim_objects/MonteCarloGenerate.sm b/share/trick/sim_objects/MonteCarloGenerate.sm new file mode 100644 index 00000000..9fa92326 --- /dev/null +++ b/share/trick/sim_objects/MonteCarloGenerate.sm @@ -0,0 +1,73 @@ +/*******************************TRICK HEADER****************************** +PURPOSE: Provides a one-stop shop for all MonteCarlo operations that Trick + cannot support, including: + - assignment of values to non-floats + - assignment of variables to other dispersed variables + - computation of variables as a function of one or more dispersed + variables. +PROGRAMMERS: + (((Gary Turner) (OSR) (October 2018) (Antares) (initial creation for CML))) + (((Isaac Reaves) (NASA) (November 2022) (Integration into Trick Core))) +***********************************************************************/ +#ifndef SIM_OBJECT_MONTE_CARLO_Generation +#define SIM_OBJECT_MONTE_CARLO_Generation +##include "trick/mc_master.hh" +##include "trick/mc_python_code.hh" +##include "trick/mc_variable_random_uniform.hh" +##include "trick/mc_variable_random_normal.hh" +##include "trick/mc_variable_random_string.hh" +##include "trick/mc_variable_random_bool.hh" +##include "trick/mc_variable_file.hh" +##include "trick/mc_variable_fixed.hh" +##include "trick/mc_variable_semi_fixed.hh" +##include "trick/message_type.h" +##include "trick/message_proto.h" +##include "trick/exec_proto.h" +#include "sim_objects/default_trick_sys.sm" +##include "trick/MonteCarlo.hh" + +class MonteCarloGeneratorSimObject : public Trick::SimObject +{ + protected: + Trick::MonteCarlo * mc; + public: + MonteCarloMaster mc_master; + MonteCarloGeneratorSimObject(std::string location, Trick::MonteCarlo * mc_) + : + mc(mc_), + mc_master(location) + { + // pre-initialization assignments: + P0 ("initialization") generate_dispersions(); + } + void generate_dispersions() + { + if (!mc_master.active || !mc_master.generate_dispersions) return; + const std::vector variables = mc->get_variables(); + if (!variables.empty()) { + for (auto it :variables) { + std::string message = std::string("File: ") + __FILE__ + ", Line: " + + std::to_string(__LINE__) + ", Monte Carlo Variable added using wrong " + "method\n" + "The variable " + it->name + " was added " + "improperly. Details:\n" + it->describe_variable(); + message_publish(MSG_ERROR, message.c_str()); + } + std::string message = std::string("File: ") + __FILE__ + ", Line: " + + std::to_string(__LINE__) + ", MonteCarloGeneratorSimObject is active but " + "variable(s) have been added using the older MonteCarloSimObject method. " + "Only one method can be used per sim. You must replace all trick_mc " + "based variables with monte_carlo sim object equivalents. See the trick " + "documentation for support.\n"; + message_publish(MSG_ERROR, message.c_str()); + exec_terminate_with_return(1, __FILE__, __LINE__, message.c_str()); + } + mc_master.execute(); + } + private: + // copy constructor, operator= blocked: + MonteCarloGeneratorSimObject (const MonteCarloGeneratorSimObject&); + MonteCarloGeneratorSimObject & operator = + ( const MonteCarloGeneratorSimObject&); +}; +MonteCarloGeneratorSimObject monte_carlo("monte_carlo.mc_master", &trick_mc.mc); +#endif diff --git a/share/trick/sim_objects/default_trick_sys.sm b/share/trick/sim_objects/default_trick_sys.sm index cf4a1f0d..9b7a871e 100644 --- a/share/trick/sim_objects/default_trick_sys.sm +++ b/share/trick/sim_objects/default_trick_sys.sm @@ -175,7 +175,7 @@ class MonteCarloSimObject : public Trick::SimObject { exec_register_scheduler(&mc) ; {TRK} P0 ("default_data") mc.process_sim_args() ; - {TRK} P0 ("initialization") mc.execute_monte() ; + {TRK} P1 ("initialization") mc.execute_monte() ; {TRK} ("shutdown") mc.shutdown() ; } } @@ -229,6 +229,7 @@ class SieSimObject : public Trick::SimObject { Trick::Sie sie ; SieSimObject() { + {TRK} P0 ("default_data") sie.process_sim_args() ; // We now append runtime objects when sie is requested by variable server instead. // {TRK} P65535 ("initialization") sie.sie_append_runtime_objs() ; } diff --git a/share/trick/swig/shortcuts.py b/share/trick/swig/shortcuts.py index eaa6c783..7bd36f0d 100644 --- a/share/trick/swig/shortcuts.py +++ b/share/trick/swig/shortcuts.py @@ -44,6 +44,7 @@ if hasattr(top.cvar, 'trick_ip'): set_event_info_msg_on = trick.IPPythonEvent.set_event_info_msg_on set_event_info_msg_off = trick.IPPythonEvent.set_event_info_msg_off +terminate_on_event_parse_error = trick.IPPythonEvent.terminate_on_event_parse_error # bind pyton input_processor event routines to shortcut names. new_event = trick.ippython_new_event diff --git a/share/trick/trick_ver.txt b/share/trick/trick_ver.txt index 281d9a1a..fe3886e0 100644 --- a/share/trick/trick_ver.txt +++ b/share/trick/trick_ver.txt @@ -1 +1 @@ -current_version = "23.0.0-beta" +current_version = "19.6.0-beta" diff --git a/share/trick/trickops/.yaml_requirements.yml b/share/trick/trickops/.yaml_requirements.yml new file mode 100644 index 00000000..3be57db5 --- /dev/null +++ b/share/trick/trickops/.yaml_requirements.yml @@ -0,0 +1,94 @@ +# This file represents the required types, ranges, and values +# as applicable expected for keys found while parsing TrickWorkflow +# Yaml files. This is used by TrickWorkflowYamlVerifier to verify +# user-supplied content. The information is used in the following +# way: +# content: +# required: 0|1 <-- if 1, content must not be empty (None) +# default: <-- if required:0 and content not given, use this value +# overridable: 0|1 <-- if 0, check all given keys below +# type: <-- isinstance(content, type) +# contains: <-- contains in content +# min: <-- content > min +# max: <-- content < max +# This file should not be modified except in the case of TrickOps +# development. + +# Default values of content if not specified in structures below +# Keys with empty values end up as None. Structures below override +# these values. +content: + required: 0 + default: + overridable: 0 + type: + contains: + min: + max: + +# Expectations for everything under a top-level global key: +globals: + env: + default: '' + type: str + +# Expectations for everything under a top-level SIM key: +sim: + name: # Comes from SIM key itself + required: 1 + type: str + path: + required: 1 + type: str + description: + type: str + labels: + type: list + build_args: + type: str + binary: + default: S_main_{cpu}.exe + type: str + size: + default: 2200000 + type: int + min: 1 + phase: + default: 0 + type: int + min: -1000 + max: 1000 + parallel_safety: + default: loose + type: str + contains: + - strict + - loose + runs: + type: dict # Subsection validation articulated below + +# Expectations for every key under a sim's run: subsection +run: + input: # Comes from run key itself + required: 1 + type: str + returns: + type: int + default: 0 + min: 0 + max: 255 + compare: + overridable: 1 + type: list + analyze: + overridable: 1 + type: str + phase: + default: 0 + type: int + min: -1000 + max: 1000 + valgrind: + type: str + + diff --git a/share/trick/trickops/ExampleWorkflow.py b/share/trick/trickops/ExampleWorkflow.py index 118d7c28..0bcec229 100755 --- a/share/trick/trickops/ExampleWorkflow.py +++ b/share/trick/trickops/ExampleWorkflow.py @@ -124,9 +124,11 @@ f.close() from TrickWorkflow import * class ExampleWorkflow(TrickWorkflow): def __init__( self, quiet, trick_top_level='/tmp/trick'): - # Real projects already have trick somewhere, but for this test, just clone it + # Real projects already have trick somewhere, but for this example, just clone & build it if not os.path.exists(trick_top_level): os.system('cd %s && git clone https://github.com/nasa/trick' % (os.path.dirname(trick_top_level))) + if not os.path.exists(os.path.join(trick_top_level, 'lib64/libtrick.a')): + os.system('cd %s && ./configure && make' % (trick_top_level)) # Base Class initialize, this creates internal management structures TrickWorkflow.__init__(self, project_top_level=trick_top_level, log_dir='/tmp/', trick_dir=trick_top_level, config_file="/tmp/config.yml", cpus=3, quiet=quiet) diff --git a/share/trick/trickops/MonteCarloGenerationHelper.py b/share/trick/trickops/MonteCarloGenerationHelper.py new file mode 100644 index 00000000..10d2c62a --- /dev/null +++ b/share/trick/trickops/MonteCarloGenerationHelper.py @@ -0,0 +1,305 @@ +""" +Module to be used in conjunction with the MonteCarloGenerate (MCG) sim module +provided by Trick and optionally TrickOps. This module allows MCG users to +easily generate monte-carlo runs and execute them locally or through an HPC job +scheduler like SLURM. Below is an example usage of the module assuming: + 1. The using script inherits from TrickWorkflow, giving access to execute_jobs() + 2. SIM_A/RUN_mc/input.py is configured with MonteCarloGenerate.sm sim module + to generate runs when executed + +# Instantiate an MCG helper instance, providing the sim and input file for generation +mgh = MonteCarloGenerationHelper(sim_path="path/to/SIM_A", input_path="RUN_mc/input.py") +# Get the generation SingleRun() instance +gj = mgh.get_generation_job() +# Execute the generation Job to generate RUNS +ret = self.execute_jobs([gj]) + +if ret == 0: # Successful generation + # Get a SLURM sbatch array job for all generated runs + sbj = mgh.get_sbatch_job(monte_dir="path/to/MONTE_RUN_mc") + # Execute the sbatch job, which queues all runs in SLURM for execution + # Use hpc_passthrough_args ='--wait' to block until all runs complete + ret = self.execute_jobs([sbj]) + + # Instead of using SLURM, generated runs can be executed locally through + # TrickOps calls. First get a list of run jobs + run_jobs = mgh.get_generated_run_jobs(monte_dir="path/to/MONTE_RUN_mc") + # Execute all generated SingleRun instances, up to 10 at once + ret = self.execute_jobs(run_jobs, max_concurrent=10) +""" + +import sys, os + +import send_hs +import argparse, glob + +import subprocess, errno +import pprint, logging +import WorkflowCommon, TrickWorkflow + +# This global is the result of hours of frustration and debugging. See comment at the top of +# TrickWorkflow.py for details +this_trick = os.path.normpath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../..')) + +class MonteCarloGenerationHelper(): + """ + Helper class for generating runs via Trick's built-in MonteCarloGenerate sim module. + """ + def __init__(self, sim_path, input_path, S_main_name='S_main*.exe', env=None, sim_args_gen=None): + """ + Initialize this instance. + + >>> mgh = MonteCarloGenerationHelper(sim_path=os.path.join(this_trick, "test/SIM_mc_generation"), input_path="RUN_nominal/input_a.py") + + Parameters + ---------- + sim_path : str + Path to the directory containing the built simulation + input_path : str + Path to input file used for monte-carlo generation, relative to sim_path + S_main_name : str + Literal string of S_main binary. Defaults to (lazy) S_main*.exe + env : str + Optional literal string to execute before everything, typically for sourcing + a project environment file. + sim_args_gen : str + Optional literal string to pass to the simulation after the input_path during + generation. + """ + self.sim_path = os.path.abspath(sim_path) + self.input_path = input_path + self.S_main_name = S_main_name + self.sim_args_gen = '' if not sim_args_gen else sim_args_gen + self.env = '' if not env else env + + self.generated_input_files = [] # Will be list of successfully generated runs + # Sanity check inputs + if not isinstance(self.sim_args_gen, str): + msg = (f"ERROR: Given sim_args_gen ({sim_args_gen}) has invalid type {type(self.sim_args_gen)}." + f" It must be a string.") + raise TypeError(msg) + if not isinstance(self.env, str): + msg = (f"ERROR: Given env ({env}) has invalid type {type(self.env)}." + f" It must be a string.") + raise TypeError(msg) + if not os.path.isfile(os.path.join(self.sim_path, self.input_path)): + msg = (f"ERROR: input_path {os.path.join(self.sim_path, self.input_path)} " + f"doesn't exist.") + raise RuntimeError(msg) + # Construct job used to generate runs + cmd = "%s cd %s && " % (self.env, self.sim_path) + cmd += "./%s " % (self.S_main_name) + cmd += "%s " % self.input_path + if self.sim_args_gen: + cmd += "%s" % self.sim_args_gen + self.generation_job = TrickWorkflow.SingleRun( + name=f'Monte Carlo Generation for: {self.sim_path}/{self.input_path}', + command=cmd, log_file=os.path.join(self.sim_path, os.path.dirname(self.input_path), + 'MCG_generation_output.txt'), + expected_exit_status=0, use_var_server=False) + + def get_generation_job(self): + """ + Return the SingleRun (Job) instance corresponding to an MCG generation execution + as configured inside this instance. This SingleRun can be executed via + WorkflowCommon.execute_jobs() to generate runs. + + >>> mgh = MonteCarloGenerationHelper(sim_path=os.path.join(this_trick, "test/SIM_mc_generation"), input_path="RUN_nominal/input_a.py") + >>> job = mgh.get_generation_job() + """ + return self.generation_job + + def get_generated_input_files(self, monte_dir): + """ + Return a sorted list of absolute paths to the generated input files. + + Parameters + ---------- + monte_dir : str + Path to monte_dir in which input_files were generated. This is a required input + since this class has no way to know where the user configured the sim to locate + the generated runs. + + Returns + ---------- + list of strings (absolute paths) + Sorted list of absolute paths to input files found under monte_dir + + Raises + ------ + RuntimeError + If an error in finding input files occurs. + """ + if os.path.isdir(monte_dir) == False: + msg = (f"Given monte_dir {monte_dir} doesn't exist! Cannot get run list.") + raise RuntimeError(msg) + just_input_file = ("monte_"+os.path.basename(self.input_path)) + monte_dir_path_full = os.path.abspath(monte_dir) + run_list = [x for x in os.listdir(monte_dir_path_full) if \ + (x.startswith("RUN_") and os.path.isdir(os.path.join(monte_dir_path_full,x)))] + if len(run_list) == 0: + msg = (f"Error: {monte_dir} doesn't have any runs!") + raise RuntimeError(msg) + self.generated_input_files = [os.path.join(monte_dir, x, just_input_file) for x in run_list + if os.path.isfile(os.path.join( monte_dir_path_full, x, just_input_file ))] + if len(self.generated_input_files) == 0: + msg = (f"Error: {monte_dir}'s RUN directories don't have any input files of expected " + f"name: {just_input_file}. Make sure input_path is correct and that MCG is configured " + "appropriately.") + raise RuntimeError(msg) + self.generated_input_files.sort() + # error checking regarding missing files or not enough runs + if len(run_list) != len(self.generated_input_files): + msg = ("WARNING in get_generated_input_files(): There's a mismatch between the number " + f"of MONTE*/RUN* directories and the number of input files ({just_input_file}) " + "in those directories. Returning only the found subset") + print(msg) + + return(list(self.generated_input_files)) + + def get_zero_padding(self, monte_dir=None): + """ + Returns an integer representing the highest zero-padding contained in + monte_dir, or in self.generated_input_files list if monte_dir is None + + Parameters + ---------- + monte_dir : str + Path to monte_dir in which input_files were generated + + Returns + ---------- + int + Integer representing zero-padding length. Ready for use in printf-style + "%0d" use-cases. + + Raises + ------ + RuntimeError + If zero-padding information cannot be determined + """ + gif = [] + if monte_dir: + gif = self.get_generated_input_files(monte_dir) + else: + gif = self.generated_input_files + + if not gif or len(gif) < 1: + msg = ("Cannot find zero-padding information because self.generated_input_files " + "is empty! Have you run get_generated_input_files()?") + raise RuntimeError(msg) + # This exception may be unreachable, but for extra safety... + try: + padding = len(os.path.dirname(gif[-1]).split('_')[-1]) + except Exception as e: + msg = ("Encountered unhandled exception attempting to determine zero-padding " + f"information. Error:\n{e}") + raise RuntimeError(msg) + return padding + + def get_sbatch_job(self, monte_dir, sim_args=None, hpc_passthrough_args=None): + """ + Return a Job() whose command is an sbatch array job for running generated runs + found in monte_dir, with the given hpc_passthrough_args if specified. This single + Job() when executed will submit the entire set of monte-carlo runs in monte_dir + to a SLURM job scheduling system as an array job. This function simply creates + the Job(), it does not execute it. + + Parameters + ---------- + monte_dir : str + Path to monte_dir in which input_files were generated. This is a required input + since this class has no way to know where the user configured the sim to locate + the generated runs. + + hpc_passthrough_args : str + Literal string of args to be passed through to the HPC scheduling system SLURM + + sim_args : str + Literal string of args to be passed through to the simulation binary + + Returns + ---------- + Job() + Job instance with sbatch command configured for array submission. + """ + generated_runs = self.get_generated_input_files(monte_dir) + zero_padding = self.get_zero_padding() + just_input_file = os.path.basename(generated_runs[0]) + sbatch_cmd = self.env + " sbatch " + + # Build the default --array option, this is overridden later if the user gave it + # Homogeneous array assumption, last zero-padded num in last run in array + array = ("--array 0-%s " % os.path.dirname(generated_runs[-1]).split('_')[-1]) + # A couple sbatch options are special: if the user has specified --array , use + # theirs, if not then generate the --array field for the mc_num_runs given. If --wait + # is given, we won't be able to post-process, so store that information off. Easiest + # way to get this passthrough information is to use arparse to parse the + # hpc_passthrough_args list, leaving what's left in rest list to be passed through + sbatch_parser = argparse.ArgumentParser() + sbatch_parser.add_argument('-a', '--array') + sbatch_parser.add_argument('-W', '--wait', action="store_true") + if hpc_passthrough_args: + subargs, rest = sbatch_parser.parse_known_args(hpc_passthrough_args.split()) + if subargs.wait: # Since --wait not in rest, re-add it to passthrough args + rest.append('--wait') + if subargs.array: # If custom array given by user + # Custom array definition + array = "--array %s " % subargs.array + sbatch_cmd += ' '.join(rest) + ' ' + sbatch_cmd += array + sbatch_cmd += "--wrap 'RUN_NUM=`printf %0" + str(zero_padding) + 'd $SLURM_ARRAY_TASK_ID`; ' + sbatch_cmd += "%s cd %s && " % (self.env, self.sim_path) + sbatch_cmd += "./%s %s/RUN_${RUN_NUM}/%s" % (self.S_main_name, monte_dir, just_input_file) + if sim_args: + sbatch_cmd += " " + sim_args + " " + + sbatch_cmd += (" 2> %s/RUN_${RUN_NUM}/stderr 1> %s/RUN_${RUN_NUM}/stdout '" % + (monte_dir, monte_dir)) + job = WorkflowCommon.Job(name=(f'Running sbatch array job for ' + f'{os.path.basename(self.sim_path)}' + f' {os.path.basename(monte_dir)}'), + command=sbatch_cmd, log_file=f'{os.path.join(monte_dir)}/sbatch_out.txt') + return (job) + + #TODO Implement a Portable Batch System (PBS) job getter, and support for other HPC + # schedulers go here + + def get_generated_run_jobs(self, monte_dir, sim_args=None): + """ + Return a list of SingleRun() instances, configured for each of the RUNs in + monte_dir. Each run's output goes to the generated RUN location in a file + called stdouterr, containing both stdout and stderr + + Parameters + ---------- + monte_dir : str + Path to monte_dir in which input_files were generated. This must either be a + path relative to the sim dir or an absolute path. + + sim_args : str + Literal string of args to be passed through to the sim binary + """ + jobs = [] + generated_runs = self.get_generated_input_files(monte_dir) + for run in generated_runs: + cmd = "%s cd %s && " % (self.env, self.sim_path) + cmd += "./%s %s" % (self.S_main_name, run) + if sim_args: + cmd += " " + sim_args + " " + jobs.append( TrickWorkflow.SingleRun( + name=f'Executing generated run {os.path.basename(os.path.dirname(run))}', + command=cmd, log_file=os.path.join(os.path.dirname(run), + 'stdouterr'), expected_exit_status=0) + ) + return jobs + + def is_sim_built(self): + """ + Return True if self.S_main_name exists in self.sim_path. False otherwise + """ + if glob.glob(os.path.join(self.sim_path, self.S_main_name)): + return True + else: + return False + diff --git a/share/trick/trickops/TrickWorkflow.py b/share/trick/trickops/TrickWorkflow.py index 8ab5076c..28d2b9f4 100644 --- a/share/trick/trickops/TrickWorkflow.py +++ b/share/trick/trickops/TrickWorkflow.py @@ -8,7 +8,7 @@ Requires: python3 and requirements.txt containing: psutil # For child process acquisition """ import os, sys, threading, socket, abc, time, re, copy, subprocess, hashlib, inspect -import yaml # Provided by PyYAML +from TrickWorkflowYamlVerifier import * # TODO revisit this import - Jordan from WorkflowCommon import * import pprint @@ -59,7 +59,7 @@ class TrickWorkflow(WorkflowCommon): # Job statuses are stored internally and can be queried after they've already # executed, for example, after execute_jobs() finishes: for b in builds: - print("Build job %s completed with status %d " % (b.name, b.get_status() is job.Status.SUCCESS)) + print("Build job %s completed with status %d " % (b.name, b.get_status())) print("and ran command %s " % (b._command)) # All jobs store their status internally regardless of whether they have @@ -76,6 +76,83 @@ class TrickWorkflow(WorkflowCommon): # Note that runs, comparisons, and analysis management classes and/or jobs also # support the report() method """ + # These are static so Run and Sim classes can access them when needed + # TODO: It would be nice to consolidate and read this from .yaml_requirements.txt + # -Jordan 12/2022 + allowed_phase_range = {'min': -1000, 'max': 1000} + all_possible_phases = range(allowed_phase_range['min'], allowed_phase_range['max']+1) + + def listify_phase(phase=None): + """ + Given a phase of different potential types, return a list of integers within + the allowed_phase_range. + + >>> TrickWorkflow.listify_phase(0) + [0] + >>> TrickWorkflow.listify_phase(range(0,5)) + [0, 1, 2, 3, 4] + + Parameters + ---------- + phase : int, list, range, or None + Phase or phases requested by user + + Returns + ------- + list of integers which must be equal to or a subset of all_possible_phases + + Raises + ------ + RuntimeError + If input is not an int, list of ints, range, or None, or if given values + are not within TrickWorkflow.all_possible_phases + """ + # Handle type of phase given + phases = [] # To be populated with all valid phases requested by user + if (phase is None): + phases = list(TrickWorkflow.all_possible_phases) + elif isinstance(phase, int) and phase in TrickWorkflow.all_possible_phases: + phases = [phase] + elif ( (isinstance(phase, list) or isinstance(phase, range)) and + all(isinstance(p, int) for p in phase) and + all(p in TrickWorkflow.all_possible_phases for p in phase)): + phases = list(phase) # Cast to list to cover range case + else: + msg =("ERROR: Given phase %s in listify_given_phase() must be an int," + " list of ints, or range() within the bounds [%s, %s]" % (phase, + TrickWorkflow.allowed_phase_range['min'], + TrickWorkflow.allowed_phase_range['max'])) + raise RuntimeError(msg) + return(phases) + + def _find_range_string(string): + """ + Given a string, return the range in square bracket notation if found + This does not check for validity of the string, it only finds it. + + >>> TrickWorkflow._find_range_string('SET_hi/RUN_[000-999]/input.py') + '[000-999]' + + Returns: str or None + str: string of range notation found + None: if not found + + Raises + ------ + RuntimeError + If more than one range string found + """ + pattern = "\[\d+-\d+\]" + if (len(re.findall(pattern, string))) > 1: + msg = ("ERROR: [min-max] pattern found more than once in %s. Only one instance is" + " supported." % (string)) + raise RuntimeError(msg) + m = re.search(pattern, string) + if m: + return m.group(0) + else: + return None + def __init__(self, project_top_level, log_dir, trick_dir, config_file, cpus=3, quiet=False): """ Initialize this instance. @@ -100,20 +177,114 @@ class TrickWorkflow(WorkflowCommon): available """ super().__init__(project_top_level=project_top_level, log_dir=log_dir, quiet=quiet) - # If not found in the config file, these defaults are used - self.defaults = {'cpus': 3, 'name': None, 'description': None, - 'build_command': 'trick-CP', 'size': 2200000, 'env': None} - self.config_errors = False + self.config_errors = [] # Contains errors in setup of management classes self.compare_errors = False # True if comparison errors were found self.sims = [] # list of Sim() instances, filled out from config file self.config_file = config_file # path to yml config self.cpus = cpus # Number of CPUs this workflow should use when running - # 'loose' or 'strict' controls if multiple input files per RUN dir are allowed in YAML config file - self.parallel_safety = 'loose' - self.config = self._read_config(self.config_file) # Contains resulting Dict parsed by yaml.load + self.yaml_verifier = TrickWorkflowYamlVerifier(self.config_file) + # If not found in the config file, these defaults are used self.trick_dir = trick_dir self.trick_host_cpu = self.get_trick_host_cpu() - self._validate_config() + self.env = '' + self.config = self.yaml_verifier.verify() + self.parsing_errors = self.yaml_verifier.parsing_errors # All errors found during parsing + for e in self.parsing_errors: + tprint(e, 'DARK_RED') + self._populate_sims() + + def _populate_sims(self): + """ + Given a verified self.config, populate the self.sims list of Sim() instances + Note that all the checking of expected dict key/values has already taken place + during yaml verification, so we can safely access all dict keys here. + Furthermore, any sim or run without required key/values have already been purged + from self.config so we can create all management classes at the sim and run + levels without worry. + """ + def cprint(msg, color): + self.config_errors.append(msg) + tprint(msg, color) + self.env = self.config['globals']['env'] + all_sim_paths = [] # Keep a list of all paths for uniqueness check + for s in self.config: + if not str(s).startswith('SIM'): # Ignore everything not starting with SIM + continue + if (not os.path.exists(os.path.join(self.project_top_level, self.config[s]['path'])) ): + cprint("ERROR: %s's 'path' %s not found. Continuing but skipping this entire entry from %s." + % (s, self.config[s]['path'], self.config_file), 'DARK_RED') + continue + if self.config[s]['path'] in all_sim_paths: + cprint("ERROR: %s's 'path' is not unique in %s. Continuing but ignoring this sim." + % (s, self.config_file), 'DARK_RED') + continue + # Add the CPU format string (won't fail if there is no CPU placeholder) + self.config[s]['binary'] = self.config[s]['binary'].format(cpu=self.trick_host_cpu) + # Add the full path to the build command + trick_CP=os.path.join(self.trick_dir, "bin/trick-CP") + if self.config[s]['build_args']: + trick_CP+=(' ' + self.config[s]['build_args']) + thisSim = TrickWorkflow.Sim(name=s, sim_dir=self.config[s]['path'], + description=self.config[s]['description'], labels=self.config[s]['labels'], + prebuild_cmd=self.env, build_cmd=trick_CP, + cpus=self.cpus, size=self.config[s]['size'], phase=self.config[s]['phase'], + log_dir=self.log_dir) + all_sim_paths.append(self.config[s]['path']) + + all_run_paths = [] # Keep a list of all paths for uniqueness check + for r in self.config[s]['runs']: + just_RUN = r.split()[0] # Drop arguments after RUN../...py + just_RUN_dir = os.path.dirname(just_RUN) # Drop path before RUN../..py + # TODO: This check will break generated runs, do we even need to check this at all? - Jordan 2022 + #if not os.path.exists(os.path.join(self.project_top_level, self.config[s]['path'], just_RUN)): + # cprint("ERROR: %s's 'run' path %s not found. Continuing but skipping this run " + # "from %s." % (s, just_RUN, self.config_file), 'DARK_RED') + # continue + if just_RUN_dir in all_run_paths and self.config[s]['parallel_safety'] == 'strict': + cprint("ERROR: %s's run directory %s is not unique in %s. With setting " + "parallel_safety: strict, you cannot have the same RUN directory listed " + "more than once per sim. Continuing but skipping this run." % + (s, r, self.config_file), 'DARK_RED') + continue + + thisRun = TrickWorkflow.Run(sim_dir=self.config[s]['path'], input_file=r, + binary= self.config[s]['binary'], prerun_cmd=self.env, + returns=self.config[s]['runs'][r]['returns'], + valgrind_flags=self.config[s]['runs'][r]['valgrind'], + phase=self.config[s]['runs'][r]['phase'], log_dir=self.log_dir) + + # The check for list allows all other non-list types in the yaml file, + # allowing groups to define their own comparison methodology + if isinstance(self.config[s]['runs'][r]['compare'], list): + for cmp in self.config[s]['runs'][r]['compare']: + lhs, rhs = [ s.strip() for s in cmp.split(' vs.') ] + thisRun.add_comparison(test_data=lhs, baseline_data=rhs) + + if self.config[s]['runs'][r]['analyze'] is not None: + thisRun.add_analysis(cmd=self.config[s]['runs'][r]['analyze']) + + theseRuns = [] + try: + theseRuns = thisRun.multiply() # If [from-to] notation used, expand runs + except RuntimeError as e: + msg = ("ERROR: Unable to multiply run %s in sim %s. Ignoring this run. " + "Check for bad [min-max] syntax in run keys in %s and try again.\n %s" + % (r, s, self.config_file, e) ) + cprint(msg, 'DARK_RED') + + for r in theseRuns: + thisSim.add_run(r) # Add Run/Runs to this Sim() + + all_run_paths.append(just_RUN_dir) # Keep track of all runs to check parallel safety + + self.sims.append(thisSim) # Add Sim() to internal list + if len(self.sims) < 1: # At minimum, one valid SIM structure must exist + msg = ("ERROR: After validating config file, there is insufficient information to continue." + " Check the syntax in config file %s and try again." + % (self.config_file) ) + cprint(msg, 'DARK_RED') + self._cleanup() + raise RuntimeError(msg) def create_test_suite(self): """ @@ -214,6 +385,7 @@ class TrickWorkflow(WorkflowCommon): return self.sims sims_found = [] ls = [] + if type(labels) == str: ls = [labels] elif type(labels) == list: @@ -225,309 +397,6 @@ class TrickWorkflow(WorkflowCommon): sims_found.append(sim) return sims_found - def _read_config(self, config_file): - """ - Read the yaml file into a dict and return it - - - Parameters - ---------- - config_file : str - path to YAML config file to be read - - Returns - ------- - dict or None - dictionary representation of YAML content as parsed by yaml.safe_load() - or None if parsing failed - """ - try: - with open(config_file) as file: - y = yaml.safe_load(file) - return y - except Exception as e: - tprint("Unable to parse config file: %s\nERROR: %s" % (config_file,e), 'DARK_RED') - return None - - def _validate_config(self): - """ - Sanity check what we've read from the yml config file and create internal Sim() - objects which populate the self.sims [] list. Makes sure some values - exist and paths are valid locations where applicable. The self.config dict - may be modified to add missing entries as part of this process. If errors - in the config file are detected, self.config_errors is set to True - - The yaml format expected by this framework is described as follows: - - globals: - env: <-- optional literal string executed before all tests, e.g. env setup - parallel_safety: <-- strict won't allow multiple input files per RUN dir - SIM_abc: <-- required unique name for sim of interest, must start with SIM - path: <-- required SIM path relative to project top level - description: <-- optional description for this sim - labels: <-- optional list of labels for this sim, can be used to get sims - - model_x by label within the framework, or for any other project-defined - - verification purpose - build_command: <-- optional literal cmd executed for SIM_build, defaults to trick-CP - size: <-- optional estimated size of successful build output file in bytes - runs: <-- optional dict of runs to be executed for this sim, where the - RUN_1/input.py --foo: dict keys are the literal arguments passed to the sim binary - RUN_2/input.py: and the dict values are other run-specific optional dictionaries - ... described as follows ... - returns: <---- optional exit code of this run upon completion (0-255). Defaults - to 0 - compare: <---- optional list of vs. comparison strings to be - - a vs. b compared after this run is complete. This is extensible in that - - d vs. e all non-list values are ignored and assumed to be used to define - - ... an alternate comparison method in a class extending this one - analyze: <-- optional arbitrary string to execute as job in bash shell from - project top level, for project-specific post-run analysis - valgrind: <-- optional dict describing how to execute runs within valgrind - flags: <-- string of all flags passed to valgrind for all runs - runs: <-- list of literal arguments passed to the sim binary through - valgrind - non_sim_extension_example: - will: be ignored by TrickWorkflow parsing for derived classes to implement as they wish - - Any top-level key not matching the SIM naming pattern is ignored purposefully to provide - users of this framework to extend the same YAML file for other non-trick tests - - Raises - ------ - RuntimeError - If self.config has insufficient content - """ - # All error messages in config validation will trigger self.config_errors to be True - def cprint(msg, color): - self.config_errors = True - tprint(msg, color) - - # Utility method for ensuring a variable is the expected type. Returns True if type - # matches expected type, False otherwise. If fatal=True, raise RuntimeError. - def type_expected(var, expected_type, fatal=False, extra_msg=''): - if type(var) != expected_type: - prepend = "FATAL: " if fatal else "ERROR: " - msg =(prepend + "Entry resembling %s expected to be %s, but got %s instead. Please" - " look for errors in %s. " % - ( str(var), expected_type, type(var), self.config_file) + extra_msg) - cprint(msg, 'DARK_RED') - if fatal: - raise RuntimeError(msg) - else: - return False - return True - - c = copy.deepcopy(self.config) # Make a copy for extra saftey - if not c: # If entire config is empty - msg =("ERROR: Config file %s could not be loaded. Make sure file exists and is valid YAML syntax." - " Cannot continue." % (self.config_file)) - cprint(msg, 'DARK_RED') - self._cleanup() - raise RuntimeError(msg) - # Check global parameters - if 'globals' not in c or not c['globals']: # If globals section is missing or None - self.env = '' - self.parallel_safety = 'loose' - else: - if 'env' not in c['globals'] or not c['globals']['env']: # If section is missing or None - self.env = '' - else: - self.env = c['globals']['env'] - # If env section is missing or None - if 'parallel_safety' not in c['globals'] or not c['globals']['parallel_safety']: - self.parallel_safety = 'loose' - elif c['globals']['parallel_safety'] != 'loose' and c['globals']['parallel_safety'] != 'strict': - cprint( "ERROR: parallel_safety value of %s in config file %s is unsupported. Defaulting to" - " 'loose' and continuing..." % (c['globals']['parallel_safety'], self.config_file), - 'DARK_RED') - self.parallel_safety = 'loose' - else: - self.parallel_safety = c['globals']['parallel_safety'] - if not type_expected(c, expected_type=dict, fatal=True, extra_msg='Cannot continue.'): - pass # Unreachable, type_expected will raise - c.pop('globals', None) # Remove to iterate on the rest of the non-global content - all_sim_paths = [] # Keep a list of all paths for uniqueness check - # Check sub-parameters of SIM entries - for s in c: - if not c[s]: # If the structure is completely empty, skip it - cprint("ERROR: %s is empty!. Continuing but skipping this entire entry from %s." - % (s, self.config_file), 'DARK_RED') - self.config.pop(s) - continue - # If the structure doesn't start with SIM, ignore it and move on - if not s.lower().startswith('sim'): - continue - # If what's stored under SIM_..: is not itself a dict - if not type_expected(c[s], expected_type=dict, extra_msg="SIM definitions must start with SIM, end" - " with :, and contain the path: key-value pair. Skipping over %s." % c[s]): - self.config.pop(s) - continue - # If optional entries missing, or None, set defaults - if 'description' not in c[s] or not c[s]['description']: - self.config[s]['description'] = self.defaults['description'] - if 'build_command' not in c[s] or not c[s]['build_command']: - self.config[s]['build_command'] = self.defaults['build_command'] - if 'size' not in c[s] or not c[s]['size']: - self.config[s]['size'] = self.defaults['size'] - # SIM dir path check - if ('path' not in c[s] or not c[s]['path'] or not - os.path.exists(os.path.join(self.project_top_level, c[s]['path'])) ): - cprint("ERROR: %s's 'path' not found. Continuing but skipping this entire entry from %s." - % (s, self.config_file), 'DARK_RED') - self.config.pop(s) - continue - # SIM dir uniquness check - if c[s]['path'] in all_sim_paths: - cprint("ERROR: %s's 'path' is not unique in %s. Continuing but skipping this sim." - % (s, self.config_file), 'DARK_RED') - self.config.pop(s) - continue - # Ensure labels is a list of strings - if ('labels' not in c[s] or not c[s]['labels'] or not type_expected( - c[s]['labels'], expected_type=list, extra_msg='Ignoring labels.')): - self.config[s]['labels'] = [] - else: - sanitized_labels =( [l for l in c[s]['labels'] if type_expected( - l, expected_type=str, extra_msg='Ignoring label "%s".' % l) ] ) - self.config[s]['labels'] = sanitized_labels - # Create internal object to be populated with runs, valgrind runs, etc - thisSim = TrickWorkflow.Sim(name=s, sim_dir=self.config[s]['path'], - description=self.config[s]['description'], labels=self.config[s]['labels'], - prebuild_cmd=self.env, build_cmd=self.config[s]['build_command'], - cpus=self.cpus, size=self.config[s]['size'], log_dir=self.log_dir) - all_sim_paths.append(c[s]['path']) - # RUN sanity checks - if 'runs' in c[s]: # If it's there... - if not type_expected(c[s]['runs'], expected_type=dict, - extra_msg='Skipping entire run: section in %s' % c[s]): - self.config[s].pop('runs') - else: # If it's there and a valid list, check paths - all_run_paths = [] # Keep a list of all paths for uniqueness check - for r in c[s]['runs']: - if not type_expected(r, expected_type=str, extra_msg='Skipping this run.'): - continue - just_RUN = r.split()[0] - just_RUN_dir = os.path.dirname(just_RUN) - if not os.path.exists(os.path.join(self.project_top_level, c[s]['path'], just_RUN)): - cprint("ERROR: %s's 'run' path %s not found. Continuing but skipping this run " - "from %s." % (s, just_RUN, self.config_file), 'DARK_RED') - self.config[s]['runs'].pop(r) - continue - if just_RUN_dir in all_run_paths and self.parallel_safety == 'strict': - cprint("ERROR: %s's run directory %s is not unique in %s. With global setting " - "parallel_safety: strict, you cannot have the same RUN directory listed " - "more than once per sim. Continuing but skipping this run." % - (s, r, self.config_file), 'DARK_RED') - self.config[s]['runs'].pop(r) - continue - # if the value of : has nothing specified under it, fill out defaults - if not c[s]['runs'][r]: - self.config[s]['runs'][r] = {} - self.config[s]['runs'][r]['returns'] = 0 - self.config[s]['runs'][r]['compare'] = None - self.config[s]['runs'][r]['analyze'] = None - # Have to update the dict we're iterating b/c we check more content a dozen lines down - c[s]['runs'][r] = dict(self.config[s]['runs'][r]) - elif 'returns' not in c[s]['runs'][r]: - self.config[s]['runs'][r]['returns'] = 0 - - elif (not type_expected(c[s]['runs'][r]['returns'], expected_type=int, - extra_msg='Continuing but ignoring %s %s "returns:" value "%s"' % - (s, r, c[s]['runs'][r]['returns']))): - self.config[s]['runs'][r]['returns'] = 0 # Default to zero - elif (c[s]['runs'][r]['returns'] < 0 or c[s]['runs'][r]['returns'] > 255): - cprint("ERROR: %s's run '%s' has invalid 'returns' value (must be 0-255). " - "Continuing but assuming this run is expected to return 0 in %s." % (s, r, self.config_file), - 'DARK_RED') - self.config[s]['runs'][r]['returns'] = 0 # Default to zero - # Create internal object to be added to thisSim - thisRun = TrickWorkflow.Run(sim_dir=self.config[s]['path'], input=r, - binary= 'S_main_' + self.trick_host_cpu + '.exe', prerun_cmd=self.env, - returns=self.config[s]['runs'][r]['returns'], - valgrind_flags=None, log_dir=self.log_dir) - # Handle 'compare' option, if given, if not, assume 0 - if 'compare' not in c[s]['runs'][r]: - self.config[s]['runs'][r]['compare'] = None - elif type(c[s]['runs'][r]['compare']) != list: - pass # Deliberately leave open for workflows to extend how comparisons are defined - else: # If it's a list, make sure it fits the 'path vs. path' format - for cmp in c[s]['runs'][r]['compare']: - if not type_expected(cmp, expected_type=str, - extra_msg='Continuing but ignoring comparison %s' % cmp): - continue - if ' vs. ' not in cmp: - cprint("ERROR: %s's run %s comparison '%s' does not match expected pattern. Must be of " - "form: 'path/to/log1 vs. path/to/log2'. Continuing but ignoring this comparison in %s." - % (s, r, cmp, self.config_file), 'DARK_RED') - self.config[s]['runs'][r]['compare'].remove(cmp) - continue - lhs, rhs = [ s.strip() for s in cmp.split(' vs.') ] - thisRun.add_comparison(test_data=lhs, baseline_data=rhs) - # Handle 'analysze' option, if given, if not, assume 0 - if 'analyze' not in c[s]['runs'][r]: - self.config[s]['runs'][r]['analyze'] = None - elif type(c[s]['runs'][r]['analyze']) != str: - pass # Deliberately leave open for workflows to extend how analyze is defined - else: - thisRun.add_analysis(cmd=self.config[s]['runs'][r]['analyze']) - all_run_paths.append(just_RUN_dir) - thisSim.add_run(thisRun) - # SIM's valgrind RUN path checks - if 'valgrind' in c[s]: # If it's there... - if not type_expected(c[s]['valgrind'], expected_type=dict, - extra_msg='Skipping entire valgrind: section in %s' % c[s]): - self.config[s].pop('valgrind') - else: # If it's there and a valid dict - if self.this_os == 'darwin': - cprint("ERROR: Valgrind entry for %s is not valid for platform: %s in " - "config file %s. Continuing but skipping this valgrind: section..." - % (s, self.this_os, self.config_file), 'DARK_RED') - self.config[s].pop('valgrind') - else: - if 'flags' not in c[s]['valgrind']: - self.config[s]['valgrind']['flags'] = '' - if 'runs' in c[s]['valgrind']: # If it's there... - if not type_expected(c[s]['valgrind']['runs'], expected_type=list, - extra_msg='Skipping this valgrind runs: section for %s' % c[s]): - self.config[s].pop('valgrind') - else: - for r in c[s]['valgrind']['runs']: # If it's there and a valid list, check paths - if not type_expected(r, expected_type=str, extra_msg='Skipping this valgrind run.'): - continue - just_RUN = r.split()[0] - if not os.path.exists(os.path.join(self.project_top_level, c[s]['path'], just_RUN)): - cprint("ERROR: %s's valgrind 'run' path %s not found. Continuing but skipping " - "this run from %s." % (s, just_RUN, self.config_file), 'DARK_RED') - self.config[s]['valgrind']['runs'].remove(r) - else: - # Create internal object to be added to thisSim - vRun = TrickWorkflow.Run(sim_dir=self.config[s]['path'], input=r, - binary= 'S_main_' + self.trick_host_cpu + '.exe', - prerun_cmd=self.env, valgrind_flags=self.config[s]['valgrind']['flags'], - log_dir=self.log_dir) - thisSim.add_run(vRun) - # Done building up thisSim, store it off for later - self.sims.append(thisSim) - if len(self.sims) < 1: # At minimum, one valid SIM structure must exist - msg = ("ERROR: After validating config file, there is insufficient information to continue." - " Check the syntax in config file %s and try again." - % (self.config_file) ) - cprint(msg, 'DARK_RED') - self._cleanup() - raise RuntimeError(msg) - self._validate_config_custom(copy.deepcopy(self.config)) - - def _validate_config_custom(self, config): - """ - Customization of config file validation. Intended to be extended in derived class. - If changes are needed to the config file, derived classes should edit self.config, not config. - - Parameters - ---------- - config : dict - deep copy of self.config for reading - """ - pass def report(self, indent=''): """ @@ -592,7 +461,7 @@ class TrickWorkflow(WorkflowCommon): """ return any([sim.compare() for sim in self.sims]) - def get_jobs(self, kind): + def get_jobs(self, kind, phase=None): """ Return a list of Jobs() from the self.sims structure of the kind given @@ -608,26 +477,37 @@ class TrickWorkflow(WorkflowCommon): ---------- kind : str Kind of jobs to return from internal self.sims structure: 'build', 'run', 'valgrind', or 'analysis' + phase : int, list of ints, or None + Optional filter to return only jobs of phase or phases given. Analysis jobs + inherit the phase of the Run() it is associated with Returns ------- list - List of jobs of given kind + List of jobs of given kind (and phase if specified) """ + # Transform given phase into a list + phases = TrickWorkflow.listify_phase(phase) + jobs = [] if kind == 'build' or kind == 'builds': - jobs = [ sim.get_build_job() for sim in self.sims ] + jobs = [ sim.get_build_job() for sim in self.sims if sim.phase in phases ] elif kind == 'run' or kind == 'runs': for sim in self.sims: - jobs += sim.get_run_jobs(kind='normal') + jobs += sim.get_run_jobs(kind='normal', phase=phases) elif kind == 'valgrind' or kind == 'valgrinds': for sim in self.sims: - jobs += sim.get_run_jobs(kind='valgrind') + jobs += sim.get_run_jobs(kind='valgrind', phase=phases) elif kind == 'analysis' or kind == 'analyses' or kind == 'analyze': for sim in self.sims: - jobs += sim.get_analysis_jobs() + jobs += sim.get_analysis_jobs(phase=phases) else: raise TypeError('get_jobs() only accepts kinds: build, run, valgrind, analysis') + # If these jobs are of type SingleRun and self.quiet is True, tell the jobs to + # skip the variable server connection logic + for job in jobs: + if self.quiet and isinstance(job, SingleRun): + job.set_use_var_server(False) return (jobs) def get_comparisons(self): @@ -759,7 +639,7 @@ class TrickWorkflow(WorkflowCommon): stored in the TrickWorkflow.sims list. """ def __init__(self, name, sim_dir, description=None, labels=[], prebuild_cmd='', - build_cmd='trick-CP', cpus=3, size=2200000, log_dir='/tmp'): + build_cmd='trick-CP', cpus=3, size=2200000, phase=0, log_dir='/tmp'): """ Initialize this instance. @@ -781,6 +661,9 @@ class TrickWorkflow(WorkflowCommon): Optional Number of CPUs to give via MAKEFLAGS for sim build size : int Optional estimated size of successful build output file, for progress bars + phase : int + Optional ordering phase, typically used to order sim builds when parallel + execution is not robust log_dir: str Directory in which log files will be written """ @@ -792,6 +675,7 @@ class TrickWorkflow(WorkflowCommon): self.build_cmd = build_cmd # Build command for sim self.cpus = cpus # Number of CPUs to use in build self.size = size # Estimated size of successful build output in bytes + self.phase = phase # Phase associated with this sim build self.log_dir = log_dir # Directory for which log file should be written self.build_job = None # Contains Build Job instance self.runs = [] # List of normal Run instances @@ -811,6 +695,7 @@ class TrickWorkflow(WorkflowCommon): FileSizeJob() Instance of FileSizeJob() job for compiling this sim """ + if not self.build_job: name = 'Build ' + self.sim_dir self.build_job = FileSizeJob(name=name, @@ -820,9 +705,10 @@ class TrickWorkflow(WorkflowCommon): size=self.size ) return (self.build_job) - def get_run_jobs( self, kind='normal'): + def get_run_jobs( self, kind='normal', phase=None): """ - Collect all SingleRun() instances and return them for all sims + Collect all SingleRun() instances and return them for all sims subject to the filtering + paramters kind and phase >>> s = TrickWorkflow.Sim(name='alloc', sim_dir=os.path.join(this_trick, 'test/SIM_alloc_test')) >>> s.get_run_jobs() # A sim has no runs by default @@ -832,33 +718,48 @@ class TrickWorkflow(WorkflowCommon): ------- kind : str 'normal' for normal runs, 'valgrind' for valgrind runs + phase : int, list of ints, or None + Get only jobs of the given phase integer or list of integers + If None (default), return all jobs Returns ------- list - List of SingleRun() job instances + List of SingleRun() job instances associated with kind and phase """ + # Transform given phase into a list + phases = TrickWorkflow.listify_phase(phase) + all_jobs = [] if (kind == 'valgrind'): - return ([r.get_run_job() for r in self.valgrind_runs]) + all_jobs = [r.get_run_job() for r in self.valgrind_runs if r.phase in phases] else: - return ([r.get_run_job() for r in self.runs]) + all_jobs = [r.get_run_job() for r in self.runs if r.phase in phases] + return (all_jobs) - def get_analysis_jobs( self): + def get_analysis_jobs( self, phase=None): """ - Collect all Job() instances for all analysis across all sim runs + Collect all Job() instances for all analysis across all sim runs and valgrind runs >>> s = TrickWorkflow.Sim(name='alloc', sim_dir=os.path.join(this_trick, 'test/SIM_alloc_test')) >>> s.get_analysis_jobs() # A sim has no analysis jobs by default [] + Parameters + ------- + phase : int, list of ints, or None + Get only jobs of the given phase integer or list of integers + If None (default), return all jobs + Returns ------- list() List of Job() instances for all analyses """ - return ([r.analysis for r in self.runs if r.analysis]) + # Transform given phase into a list + phases = TrickWorkflow.listify_phase(phase) + return ([r.analysis for r in (self.runs + self.valgrind_runs) if (r.analysis and r.phase in phases) ]) - def get_run(self, input): + def get_run(self, input_file): """ Get a Run() instance by unique full input name. This is the full string intended to be passed to the binary. @@ -882,11 +783,11 @@ class TrickWorkflow(WorkflowCommon): TypeError If input is not a str """ - if type(input) != str: + if type(input_file) != str: raise TypeError('get_run() only accepts the unique key representing the entire input to' ' the sim binary. Ex: "RUN_test/input.py --flags-too"') for run in self.runs: - if run.input == input: + if run.input_file == input_file: return run return None @@ -912,13 +813,50 @@ class TrickWorkflow(WorkflowCommon): """ return self.valgrind_runs + def get_phase(self): + """ + Get integer phase member + + >>> s = TrickWorkflow.Sim(name='alloc', sim_dir=os.path.join(this_trick, 'test/SIM_alloc_test')) + >>> s.get_phase() # Default is zero + 0 + + """ + return self.phase + + def set_phase( self, phase): + """ + Set the phase member variable. Phase is an integer in the range(TrickWorkflow.allowed_phase_range['min'], + TrickWorkflow.allowed_phase_range['max']) which can be used to order sim builds when a workflow cannot + support sims building in parallel. + + >>> s = TrickWorkflow.Sim(name='alloc', sim_dir=os.path.join(this_trick, 'test/SIM_alloc_test')) + >>> s.set_phase(1) + >>> s.set_phase(-1001) #doctest: +ELLIPSIS + Traceback (most recent call last): + ... + RuntimeError: ERROR: set_phase() for SIM alloc must be an integer between ... + + Parameters + ------- + phase : int + phase to change to + """ + if (not isinstance(phase, int) or phase < TrickWorkflow.allowed_phase_range['min'] or + phase > TrickWorkflow.allowed_phase_range['max']): + msg =("ERROR: set_phase() for SIM %s must be an integer between [%s, %s]" + % (self.name, TrickWorkflow.allowed_phase_range['min'], TrickWorkflow.allowed_phase_range['max'])) + raise RuntimeError(msg) + else: + self.phase = phase + def add_run( self, run): """ Append a new Run() instance to the internal run lists. Appends to valgrind list if run.valgrind_flags is not None, appends to normal run list otherwise >>> s = TrickWorkflow.Sim(name='alloc', sim_dir=os.path.join(this_trick, 'test/SIM_alloc_test')) - >>> r = TrickWorkflow.Run(sim_dir=os.path.join(this_trick, 'test/SIM_alloc_test'), input='RUN_test/input.py', binary='S_main_Linux_x86_64.exe') + >>> r = TrickWorkflow.Run(sim_dir=os.path.join(this_trick, 'test/SIM_alloc_test'), input_file='RUN_test/input.py', binary='S_main_Linux_x86_64.exe') >>> s.add_run(r) Parameters @@ -931,25 +869,27 @@ class TrickWorkflow(WorkflowCommon): else: self.runs.append(run) - def pop_run( self, input): + def pop_run( self, input_file): """ - Remove a run by its unique self.input value + Remove a run by its unique self.input_file value >>> tw = TrickWorkflow(project_top_level=this_trick, log_dir='/tmp/', trick_dir=this_trick, config_file=os.path.join(this_trick,"share/trick/trickops/tests/trick_sims.yml")) - >>> s = tw.get_sim('SIM_alloc_test') + >>> s = tw.get_sim('SIM_demo_inputfile') + >>> len(s.runs) + 2 >>> r = s.pop_run('RUN_test/input.py') - >>> r.input + >>> r.input_file 'RUN_test/input.py' >>> len(s.runs) - 0 + 1 Returns ------- Run() - Instance in this sim's runs list matching self.input + Instance in this sim's runs list matching self.input_file """ for i, run in enumerate(self.runs): - if run.input == input: + if run.input_file == input_file: return self.runs.pop(i) def compare( self): @@ -1001,39 +941,43 @@ class TrickWorkflow(WorkflowCommon): Management class for run content read from yml config file. Each key in the runs: sub-dict will become a single instance of this management class """ - def __init__(self, sim_dir, input, binary, prerun_cmd = '', returns=0, valgrind_flags=None, - log_dir='/tmp/'): + def __init__(self, sim_dir, input_file, binary, prerun_cmd = '', returns=0, valgrind_flags=None, + phase=0, log_dir='/tmp/'): """ Initialize this instance. - >>> r = TrickWorkflow.Run(sim_dir=os.path.join(this_trick, 'test/SIM_alloc_test'), input='RUN_test/input.py', binary='S_main_Linux_x86_64.exe') - >>> r.input + >>> r = TrickWorkflow.Run(sim_dir=os.path.join(this_trick, 'test/SIM_alloc_test'), input_file='RUN_test/input.py', binary='S_main_Linux_x86_64.exe') + >>> r.input_file 'RUN_test/input.py' Parameters ---------- sim_dir : str path to sim directory from top level of repository for this run - input : str + input_file : str literal argument to sim binary representing how this run is initiated including command-line arguments ex: RUN_test/input.py, or RUN_test/input.py --my-arg binary : str - Name of executable, usually S_min.. bu platform specific + Name of executable, usually S_main.. but platform specific prerun_cmd : str Optional string to execute immediately before sim run, e.g. env sourcing valgrind_flags : str If not None, use these flag and valgrind for this run + phase : int + Optional ordering phase, typically used to order sim runs when parallel + execution is not robust log_dir : str Directory in which log files will be written """ self.sim_dir = sim_dir # Path to sim directory wrt to top level of project for this run self.prerun_cmd = prerun_cmd # Optional string to execute in shell immediately before running (env) - self.input = input # Full RUN.../input.py --any-flags --as-well, relative to sim_dir + self.input_file = input_file # Full RUN.../input.py --any-flags --as-well, relative to sim_dir self.returns = returns # Expected exit code on success for this run self.valgrind_flags = valgrind_flags # If not None, this run is to be run in valgrind w/ these flags + self.phase = phase # Phase associated with this run self.log_dir = log_dir # Dir where all logged output will go - self.just_input = self.input.split(' ')[0] # Strip flags if any + self.just_input = self.input_file.split(' ')[0] # Strip flags if any # Derive Just the "RUN_something" part of run_dir_path self.just_run_dir = os.path.dirname(self.just_input) # Derive Path to run directory wrt to top level of project @@ -1048,7 +992,7 @@ class TrickWorkflow(WorkflowCommon): """ Given two data directories, add a new Comparison() instance to self.comparisons list - >>> r = TrickWorkflow.Run(sim_dir='test/SIM_alloc_test', input='RUN_test/input.py', binary='S_main_Linux_x86_64.exe') + >>> r = TrickWorkflow.Run(sim_dir='test/SIM_alloc_test', input_file='RUN_test/input.py', binary='S_main_Linux_x86_64.exe') >>> r.add_comparison('share/trick/trickops/tests/baselinedata/log_a.csv','share/trick/trickops/tests/testdata/log_a.csv') Parameters @@ -1065,7 +1009,7 @@ class TrickWorkflow(WorkflowCommon): """ Given an analysis command, add it as a post-run analysis for this run - >>> r = TrickWorkflow.Run(sim_dir='test/SIM_alloc_test', input='RUN_test/input.py', binary='S_main_Linux_x86_64.exe') + >>> r = TrickWorkflow.Run(sim_dir='test/SIM_alloc_test', input_file='RUN_test/input.py', binary='S_main_Linux_x86_64.exe') >>> r.add_analysis('echo analysis goes here') Parameters @@ -1075,17 +1019,58 @@ class TrickWorkflow(WorkflowCommon): """ if self.analysis: tprint("WARNING: Overwriting analysis definition for %s's %s" % (self.sim_dir, - self.input), 'DARK_YELLOW') + self.input_file), 'DARK_YELLOW') logfile = (os.path.join(self.log_dir, unixify_string(self.sim_dir)) - +'_'+ unixify_string(self.input) + '_analysis.txt') + +'_'+ unixify_string(self.input_file) + '_analysis.txt') self.analysis = Job(name=textwrap.shorten(cmd, width=90), command=self.prerun_cmd + " " +cmd, log_file=logfile, expected_exit_status=0) + def get_phase(self): + """ + Get integer phase member + + >>> r = TrickWorkflow.Run(sim_dir='test/SIM_alloc_test', input_file='RUN_test/input.py', binary='S_main_Linux_x86_64.exe') + >>> r.get_phase() # Default is zero + 0 + + """ + return self.phase + + def set_phase( self, phase): + """ + Set the phase member variable. Phase is an integer in the range(TrickWorkflow.allowed_phase_range['min'], + TrickWorkflow.allowed_phase_range['max']) which can be used to order sim runs when a workflow cannot + support running sims in parallel. + + >>> r = TrickWorkflow.Run(sim_dir='test/SIM_alloc_test', input_file='RUN_test/input.py', binary='S_main_Linux_x86_64.exe') + >>> r.set_phase(1) + >>> r.set_phase(-1001) #doctest: +ELLIPSIS + Traceback (most recent call last): + ... + RuntimeError: ERROR: set_phase() for test/SIM_alloc_test/RUN_test/input.py must be an integer between ... + + Parameters + ------- + phase : int + phase to change to + """ + # TODO: This is very similar to Sim.set_phase() in functionality but I didn't want to create + # a base class just to support this single instance of reducing code duplication + # -Jordan 12/2022 + if (not isinstance(phase, int) or phase < TrickWorkflow.allowed_phase_range['min'] or + phase > TrickWorkflow.allowed_phase_range['max']): + msg =("ERROR: set_phase() for %s/%s must be an integer between [%s, %s]" + % (self.sim_dir, self.input_file, TrickWorkflow.allowed_phase_range['min'], + TrickWorkflow.allowed_phase_range['max'])) + raise RuntimeError(msg) + else: + self.phase = phase + def compare( self): """ Execute all internal comparisons for this run - >>> r = TrickWorkflow.Run(sim_dir='test/SIM_alloc_test', input='RUN_test/input.py', binary='S_main_Linux_x86_64.exe') + >>> r = TrickWorkflow.Run(sim_dir='test/SIM_alloc_test', input_file='RUN_test/input.py', binary='S_main_Linux_x86_64.exe') >>> r.compare() # No comparisons means success a.k.a 0 False @@ -1108,7 +1093,7 @@ class TrickWorkflow(WorkflowCommon): """ tprint(indent + " %-20s %s" % (self.run_job._translate_status() if self.run_job else printer.colorstr('NOT RUN', 'DARK_YELLOW'), - self.input)) + self.input_file)) if self.comparisons: tprint(indent + " Run Comparisons:") for comparison in self.comparisons: @@ -1121,7 +1106,7 @@ class TrickWorkflow(WorkflowCommon): """ Create if necessary and Return the SingleRun() job instance - >>> r = TrickWorkflow.Run(sim_dir='test/SIM_alloc_test', input='RUN_test/input.py', binary='S_main_Linux_x86_64.exe') + >>> r = TrickWorkflow.Run(sim_dir='test/SIM_alloc_test', input_file='RUN_test/input.py', binary='S_main_Linux_x86_64.exe') >>> j = r.get_run_job() Returns @@ -1139,17 +1124,121 @@ class TrickWorkflow(WorkflowCommon): if self.valgrind_flags: cmd += ( "valgrind %s --log-file=%s " % (self.valgrind_flags, (os.path.join(self.log_dir, sim_name) +'_valgrind_' - + unixify_string(self.input) + '.valgrind') )) + + unixify_string(self.input_file) + '.valgrind') )) logfile += '_valgrind' name += 'Valgrind ' - logfile += "_" + unixify_string(self.input) + '.txt' - cmd += (" ./%s %s" % (self.binary, self.input)) - name += self.sim_dir + ' ' + self.input + logfile += "_" + unixify_string(self.input_file) + '.txt' + cmd += (" ./%s %s" % (self.binary, self.input_file)) + name += self.sim_dir + ' ' + self.input_file self.run_job = SingleRun(name=name, command=(cmd), expected_exit_status=self.returns, log_file=logfile) return (self.run_job) + def _get_range_list(self, pattern): + """ + Given a string matching the following pattern: + [-] - One set of enclosed in square braces + < - First integer must be less than second integer + & > 0 - Both integers must be positive + [001-999] - Leading zeros must be included and consistent + Return a list(range(int1, int2+1)) with leading zeros maintained in + string format + + >>> r = TrickWorkflow.Run(sim_dir='test/SIM_alloc_test', input_file='RUN_[01-04]/input.py', binary='S_main_Linux_x86_64.exe') + >>> rl =r._get_range_list('[0-4]') + >>> len(rl) + 5 + + Returns + ------- + list() + List of zero-padded integer range as strings + Raises + ------ + RuntimeError + If pattern is unrecognized or contains errors + """ + must_exist = ['[', ']', '-'] + if any([char not in pattern for char in must_exist]): + msg = ("ERROR: Pattern %s doesn't match expected syntax of \"[min-max]\"" % (pattern)) + raise RuntimeError(msg) + min, max = pattern.strip('[').strip(']').split('-') + if len(min) != len(max): + msg = ("ERROR: Pattern %s has inconsistent leading zeros." % (pattern)) + raise RuntimeError(msg) + leading_zeros = int(len(min)) + try: + min = int(min) + except ValueError as e: + msg = ("ERROR: Pattern %s minimum cannot be converted to integer. \n%s" % (pattern, e)) + raise RuntimeError(msg) + try: + max = int(max) + except ValueError as e: + msg = ("ERROR: Pattern %s maximum cannot be converted to integer. \n%s" % (pattern, e)) + raise RuntimeError(msg) + if min >= (max): + msg = ("ERROR: Pattern %s minimum must be less than maximum." % pattern) + raise RuntimeError(msg) + range_list = [] + for num in range(min, max+1): + range_list.append(str(num).zfill(leading_zeros)) + return (list(range_list)) + + + def multiply(self): + """ + If [from-to] notation used in input_file, return individual instances + of Run() for the expanded set. Otherwise, return self. The pattern + must meet the following criteria for input_file and optionally comparisons: + [-] - One set of enclosed in square braces + < - First integer must be less than second integer + & > 0 - Both integers must be positive + [001-999] - Leading zeros must be included and consistent + + >>> r = TrickWorkflow.Run(sim_dir='test/SIM_alloc_test', input_file='RUN_[01-04]/input.py', binary='S_main_Linux_x86_64.exe') + >>> runs = r.multiply() + >>> len(runs) + 4 + + Returns + ------- + list of Run() + Resultant list of Run() instances after expansion + Raises + ------ + RuntimeError + If expansion of pattern is not possible + + TODO: Note that this approach requires a 1:1 mapping between the [min-max] notation + specified in the self.input_file and notation in that same run's comparisons. This + approach does not support range expansion for an input_file with no range pattern + but which contains a compare range pattern. If this is attempted by the user in + yaml file, the literal [min-max] is used instead, resulting in (missing) errors. + This use case could be supported by changing this method and potentially + Comparison.pattern_replace() so that [min-max] is expanded in comparisons differently + if self.input file does not contain the range notation. This is left unimplemented + for now since not only does this add significant complexity but it also would mean + two separate behaviors for the user with the same notation in yaml, which feels + like bad mojo. -Jordan 1/2023 + """ + rs = TrickWorkflow._find_range_string(self.input_file) + if rs is None: + return [self] + else: + range_list = self._get_range_list(rs) + multiplied_runs = [] + for i in range_list: + # replace the range string notation with the single run equivalent + acopy = copy.deepcopy(self) + acopy.input_file = self.input_file.replace(rs, i) + # Add comparisons back as multiplied set + for c in acopy.comparisons: + c.pattern_replace(expecting_pattern=rs, replace_with=i) + multiplied_runs.append(acopy) + return multiplied_runs + class Comparison(object): """ Management class for a logged data comparison @@ -1270,60 +1359,78 @@ class TrickWorkflow(WorkflowCommon): string += printer.colorstr(" (missing)", 'DARK_RED') tprint(string) -class SimulationJob(Job): + def pattern_replace(self, expecting_pattern, replace_with): + """ + Replaces expecting_pattern value in self.test_data and self.baseline_data + with replace_with value if found. Mostly intended to be used via + Run.multiply() + + >>> c = TrickWorkflow.Comparison('testdata/RUN_[00-03]/log_a.csv','baseline/RUN_[00-03]/log_a.csv') + >>> c.pattern_replace(expecting_pattern='[00-03]', replace_with='01') + >>> c.test_data + 'testdata/RUN_01/log_a.csv' + >>> c.baseline_data + 'baseline/RUN_01/log_a.csv' + + Raises + ------ + RuntimeError + If expected_pattern doesn't match found pattern in test_data or baseline_data + """ + rsb = TrickWorkflow._find_range_string(self.baseline_data) + rst = TrickWorkflow._find_range_string(self.test_data) + if rsb is None and rst is None: # If no patterns, do nothing + return + if (rsb and rsb != expecting_pattern) or (rst and rst != expecting_pattern): + msg = ("ERROR: [min-max] pattern from run (%s) must match pattern in run's" + " comparisons test (%s) and baseline (%s) sections, if specified." + % (expecting_pattern, rst, rsb)) + raise RuntimeError(msg) + if rsb: + self.baseline_data = self.baseline_data.replace(expecting_pattern, replace_with) + if rst: + self.test_data = self.test_data.replace(expecting_pattern, replace_with) + + +class SingleRun(Job): """ - A Job which is a Trick simulation. + A single trick simulation run Job. SingleRun's can optionally connect to the + trick variable server to get progress bar information. """ - - __metaclass__ = abc.ABCMeta - - @abc.abstractmethod - def _create_variables(self): + def __init__(self, name, command, log_file, expected_exit_status=0, use_var_server=True): """ - Create and return a list of Variables to periodically sample - via the sim's variable server. + Initialize this instance. - Returns - ------- - [variable_server.Variable] - A list of variables to periodically sample. + Parameters + ---------- + name : str + The name of this job. + command : str + The command to execute when start() is called. + log_file : str + The file to which to write log information. """ - pass + self._use_var_server = use_var_server + self._connected = False + super().__init__(name=name, command=command, log_file=log_file, + expected_exit_status=expected_exit_status) - @abc.abstractmethod - def _connected_string(self): - """ - Get a string displaying status information. This method will - be only called after this instance has successfull connected - to the sim. + def set_use_var_server(self, value): + if (not isinstance(value, bool)): + msg =("ERROR: SingleRun.set_use_var_server() Requires a True/False value") + raise RuntimeError(msg) + else: + self._use_var_server = value - Returns - ------- - str - A string containing status information. - """ - pass - - @abc.abstractmethod - def _connected_bar(self): - """ - Get a progress bar representing the current progress. This - method will be only called after this instance has successfull - connected to the sim. - - Returns - ------- - str - A progress bar representing the current progress. - """ - pass + def get_use_var_server(self): + return (self._use_var_server) def start(self): """ Start this Simulation job. Attempts a connection to the sim variable server in another thread after calling the base class Job() start() method """ - super(SimulationJob, self).start() + super(SingleRun, self).start() self._connected = False # Finding a sim via PID can take several seconds. @@ -1367,20 +1474,25 @@ class SimulationJob(Job): return except socket.timeout: pass + # If a SingleRun job terminates before the thread can connect to the + # variable server, Trick's variable_server module throws an IOError + # with the message: The remote endpoint has closed the connection + except IOError as e: + pass - thread = threading.Thread(target=connect, - name='Looking for ' + self.name) - thread.daemon = True - thread.start() + if self._use_var_server: + thread = threading.Thread(target=connect, name='Looking for ' + self.name) + thread.daemon = True + thread.start() def get_status_string_line_count(self): - return super(SimulationJob, self).get_status_string_line_count() + 1 + return super(SingleRun, self).get_status_string_line_count() + 1 def _not_started_string(self): - return super(SimulationJob, self)._not_started_string() + '\n' + return super(SingleRun, self)._not_started_string() + '\n' def _running_string(self): - elapsed_time = super(SimulationJob, self)._running_string() + elapsed_time = super(SingleRun, self)._running_string() if self._connected: return (elapsed_time + self._connected_string() + '\n' + @@ -1390,13 +1502,13 @@ class SimulationJob(Job): create_progress_bar(0, 'Connecting')) def _success_string(self): - text = super(SimulationJob, self)._success_string() + text = super(SingleRun, self)._success_string() if self._connected: text += self._connected_string() return text + '\n' + self._success_progress_bar def _failed_string(self): - text = super(SimulationJob, self)._failed_string() + text = super(SingleRun, self)._failed_string() if self._connected: text += self._connected_string() return text + '\n' + self._failed_progress_bar @@ -1406,7 +1518,7 @@ class SimulationJob(Job): self._variable_server.close() except: pass - super(SimulationJob, self).die() + super(SingleRun, self).die() def __del__(self): try: @@ -1414,11 +1526,6 @@ class SimulationJob(Job): except: pass -class SingleRun(SimulationJob): - """ - A regular (not Monte Carlo) sim. - """ - def _create_variables(self): self._tics = variable_server.Variable( 'trick_sys.sched.time_tics', type_=float) @@ -1456,7 +1563,7 @@ class SingleRun(SimulationJob): Returns ------- str - A string for displaying the ratio of sime time to real time. + A string for displaying the ratio of sim time to real time. """ elapsed_time = ( (self._stop_time if self._stop_time else time.time()) @@ -1464,43 +1571,3 @@ class SingleRun(SimulationJob): return 'Average Speed: {0:4.1f} X'.format( self._tics.value / self._tics_per_sec.value / elapsed_time) -class MonteCarlo(SimulationJob): - """ - A Monte Carlo simulation. - - TODO: This is not currently tested or supported by the TrickWorkflow - management layer. However, this class has been used in a project in - the 2017-2020 timeframe and should still be functional. Reason for - not currently supporting it is mostly because the biggest users of - Trick monte-carlo have already moved away from it's internal master/ - slave architecture so there isn't much of a need. - """ - - def _create_variables(self): - self._total_runs = variable_server.Variable( - 'trick_mc.mc.actual_num_runs', type_=int) - self._finished_runs = variable_server.Variable( - 'trick_mc.mc.num_results', type_=int) - self._num_slaves = variable_server.Variable( - 'trick_mc.mc.num_slaves', type_=int) - return self._total_runs, self._finished_runs, self._num_slaves - - def _connected_string(self): - return ' {0} {1}'.format( - self._slave_count(), self._run_status()) - - def _connected_bar(self): - if self._total_runs.value > 0: - progress = (float(self._finished_runs.value) - / self._total_runs.value) - else: - progress = 0.0 - return create_progress_bar( - progress, '{0:.0f}%'.format(100 * progress)) - - def _slave_count(self): - return 'Slaves: {0:5d}'.format(self._num_slaves.value) - - def _run_status(self): - return 'Completed Runs: {0:>14}'.format('{0}/{1}'.format( - self._finished_runs.value, self._total_runs.value)) diff --git a/share/trick/trickops/TrickWorkflowYamlVerifier.py b/share/trick/trickops/TrickWorkflowYamlVerifier.py new file mode 100644 index 00000000..8e1b5626 --- /dev/null +++ b/share/trick/trickops/TrickWorkflowYamlVerifier.py @@ -0,0 +1,376 @@ +import os, sys, copy +import yaml # Provided by PyYAML +#from WorkflowCommon import tprint +from pydoc import locate +from exceptions import RequiredParamException, IncorrectYAMLException + +this_dir = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)))) + +# This global is the result of hours of frustration and debugging. See comment at the top of +# TrickWorkflow.py for details +this_trick = os.path.normpath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../..')) + +class TrickWorkflowYamlVerifier(): + """ + This class accepts a project YAML config file which contains a list of all + possible sims, runs, analyses, comparisons, etc and verifies that the content + meets the constraints that the TrickWorkflow expects. Specifically, self.config + is santitized to ensure that it is a dictionary matching the format below + + globals: + env: <-- optional literal string executed before all tests, e.g. env setup + SIM_abc: <-- required unique name for sim of interest, must start with SIM + path: <-- required SIM path relative to project top level + description: <-- optional description for this sim + labels: <-- optional list of labels for this sim, can be used to get sims + - model_x by label within the framework, or for any other project-defined + - verification purpose + build_args: <-- optional literal args passed to trick-CP during sim build + binary: <-- optional name of sim binary, defaults to S_main_{cpu}.exe + size: <-- optional estimated size of successful build output file in bytes + phase: <-- optional phase to be used for ordering builds if needed + parallel_safety: <-- strict won't allow multiple input files per RUN dir + runs: <-- optional dict of runs to be executed for this sim, where the + RUN_1/input.py --foo: dict keys are the literal arguments passed to the sim binary + RUN_2/input.py: and the dict values are other run-specific optional dictionaries + RUN_[10-20]/input.py: described in indented sections below. Zero-padded integer ranges + can specify a set of runs with continuous numbering using + [-] notation + returns: <---- optional exit code of this run upon completion (0-255). Defaults + to 0 + compare: <---- optional list of vs. comparison strings to be + - a vs. b compared after this run is complete. This is extensible in that + - d vs. e all non-list values are ignored and assumed to be used to define + - ... an alternate comparison method in a class extending this one + analyze: <-- optional arbitrary string to execute as job in bash shell from + project top level, for project-specific post-run analysis + phase: <-- optional phase to be used for ordering runs if needed + valgrind: <-- optional string of flags passed to valgrind for this run. + If missing or empty, this run will not use valgrind + non_sim_extension_example: + will: be ignored by TrickWorkflow parsing for derived classes to implement as they wish + + Any key matching the above naming schema is checked for type and value validity + Any key not matching the above naming schema is ignored purposefully to provide + users of this framework the ability use the YAML file for project-specific use-cases + """ + def __init__(self, config_file, quiet=False): + """ + Initialize this instance. + + >>> twyv = TrickWorkflowYamlVerifier(config_file=os.path.join(this_trick,"share/trick/trickops/tests/trick_sims.yml")) + >>> twyv.parsing_errors + [] + >>> len(twyv.config.keys()) + 57 + + """ + self.config_file=config_file + self.parsing_errors = [] # List of errors encountered during parsing + self.config = self._read_config(self.config_file) # Contains resulting Dict parsed by yaml.load + self.original_config= copy.deepcopy(self.config) # Keep a copy of original dict as parsed + # Contains requirements the format of key/value pairs inside self.config_file + self.yaml_requirements = self._read_config(os.path.join(this_dir,".yaml_requirements.yml")) + defaults = self.yaml_requirements.pop('content') # Only used to populate default values, can remove + self._populate_yaml_requirements(self.yaml_requirements, defaults) + + def _populate_yaml_requirements(self, thedict, defaults): + """ + Recursively traverse thedict, and overlay thedict values on top + of defaults dict values. This ensures all non-dict values exist + as defined in the content: section of .yaml_requirements.yml without + having to specify them individually in that file + """ + for k,v in thedict.items(): + if isinstance(v, dict): + subdicts = False + for j,u in v.items(): + if isinstance(u, dict): + subdicts = True + if subdicts: # If there are subdicts, recurse + self._populate_yaml_requirements(v, defaults) + else: # No subdicts, overlay values over defaults + thedict[k] = TrickWorkflowYamlVerifier.DictVerifier().merge( + defaults,thedict[k]) + + def _read_config(self, config_file): + """ + Read the yaml file into a dict and return it + + Parameters + ---------- + config_file : str + path to YAML config file to be read + + Returns + ------- + dict + dictionary representation of YAML content as parsed by yaml.safe_load() + + Raises + ------ + RuntimeError + If config_file cannot be read + """ + try: + with open(config_file) as file: + y = yaml.safe_load(file) + return y + except Exception as e: + msg = ("Unable to parse config file: %s\nERROR: %s\nSee" + " the TrickOps documentation for YAML file format expectations" + % (config_file,e)) + raise RuntimeError(msg) + + def get_parsing_errors(self): + """ + Return the list of errors encountered while parsing self.original_config + + Returns + ------- + list + List of error messages encountered during parsing + """ + return self.parsing_errors + + def verify(self): + """ + Verify the content of self.config. This is done by recursively checking content + in self.config against self.yaml_requirements using subclasses defined below. + Parsing errors are added as strings to the self.parsing_errors list + """ + if not self.config: # If entire config is empty + msg =("ERROR: Config file %s appears to be empty. Make sure file exists and is" + " valid YAML syntax." % (self.config_file)) + self.parsing_errors.append(msg) + raise RuntimeError(msg) + if not isinstance(self.config, dict): # If parser did not produce a dict + msg =("ERROR: Config file %s doesn't match expected dictionary format. " + " See the TrickOps documentation for YAML file format expectations." % + (self.config_file)) + self.parsing_errors.append(msg) + raise RuntimeError(msg) + + if 'globals' not in self.config: + self.config['globals'] = {'env': ''} + gv = self.GlobalVerifier( + self.config['globals'], self.yaml_requirements['globals']) + gv.verify() + self.config['globals'] = gv.get_verified_globals_dict() + self.parsing_errors += gv.get_parsing_errors() + for sim in list(self.config.keys()): + if not str(sim).startswith('SIM'): # Ignore everything not starting with SIM + continue + else: + sv = self.SimVerifier(sim_name=sim, sim_dict=self.config[sim], + req_dict=self.yaml_requirements) + try: + # Replace the entire dict for this sim with it's verified equivalent + sv.verify() + self.config[sim] = sv.get_verified_sim_dict() + # If not all required params given, remove this sim entry + except RequiredParamException as e: + del self.config[sim] + finally: + self.parsing_errors += sv.get_parsing_errors() + # Return a copy of sanitized config + return(dict(self.config)) + + # These inner classes provide helper methods for merging default expected content + # in dictionaries produced by YAML files with the actual content produced by + # YAML files. The merged content is then verified for correctness according to + # expected types, ranges, and other constraints. + class DictVerifier(): + def __init__(self): + self.errors = [] # collects all errors found in the YAML file parsing + def get_parsing_errors(self): + return(self.errors) + def merge(self, default_dict, authoritative_dict): + """ + Merges the content of authoritative_dict into default_dict, using values + from authoritative_dict over values in default_dict + """ + try: + merged ={**default_dict, **authoritative_dict} + except Exception as e: + msg=( "Unable to merge given dictionary with default dictionary." + "\n Given: %s" + "\n Default: %s" + "\nThis is usually caused by incorrect format in the YAML file. " + "See the TrickOps documentation for YAML file format expectations." + % (authoritative_dict, default_dict)) + raise IncorrectYAMLException(msg) + return (merged) + def defaults_only(self, thedict): + """ + Given a dict of yaml_requirements format, produce a dict containing + only {key: } + """ + newdict = {} + for k,v in thedict.items(): + newdict[k] = thedict[k]['default'] + return newdict + # Utility methods for ensuring given content matches expected constraints. + # These return True if check passes, False otherwise. Errors ar logged to + # self.errors + def expect_type(self, param, expected_type, where): + if param is None and expected_type is None: + return True + if not isinstance(param, expected_type): + self.errors.append(where + + "value \"%s\" expected to be type:%s, but got type:%s instead. Ignoring." % + ( param, expected_type, type(param))) + return False + return True + def expect_less_than_or_eq(self, param, maximum, where): + if (not param <= maximum): + self.errors.append(where + + "value \"%s\" expected to be <= %s. Ignoring." % + ( param, maximum)) + return False + return True + def expect_more_than_or_eq(self, param, minimum, where): + if (not param >= minimum): + self.errors.append(where + + "value \"%s\" expected to be >= %s. Ignoring." % + ( param, minimum)) + return False + return True + def expect_contains(self, param, contained_in, where): + if (param not in contained_in): + self.errors.append(where + + "value \"%s\" expected to be in subset %s. Ignoring." % + ( param, contained_in)) + return False + return True + def verify(self, user_dict, req_dict, identifier): + """ + Verifies the content of of user_dict matches the requirements of req_dict. + The content of req_dict comes from the .yaml_requirements file + The merge with defaults during __init__ guarantees all keys exist. + """ + for k,v in req_dict.items(): + before_num_errors = len(self.errors) + if v['required']: # Must be given by user + if not self.expect_type(user_dict[k], locate(v['type']), + where=("In %s, required param \"%s\" " % (identifier, k))): + raise RequiredParamException("%s must exist and be of type %s in %s" + % (k, locate(v['type']), identifier)) + elif v['default'] is None and user_dict[k] is None: # Can be given but have None type + # TODO: we may be able to set user_dict[k] = locate(v['type']) here + # which would make runs: and labels: lists, but need to see if that + # has downstream effects. If this works we can remove manual checking + # for None in the derived verifier classes + pass + # Could be another type used by derived class, so don't check anything + elif v['overridable'] == 1: + pass + else: # Check optional params (majority) + # Checking possible values only makes sense if we got the right type + if self.expect_type(user_dict[k], locate(v['type']), + where=("In %s, param \"%s\" " % (identifier, k))): + if v['min'] is not None: + self.expect_more_than_or_eq(int(user_dict[k]), int(v['min']), + where=("In %s, param \"%s\" " % (identifier, k))) + if v['max'] is not None: + self.expect_less_than_or_eq(int(user_dict[k]), int(v['max']), + where=("In %s, param \"%s\" " % (identifier, k))) + if v['contains'] is not None: + self.expect_contains(user_dict[k], v['contains'], + where=("In %s, param \"%s\" " % (identifier, k))) + # If we encountered any errors, set param to default value + if len(self.errors) > before_num_errors: + user_dict[k] = v['default'] + + class GlobalVerifier(DictVerifier): + def __init__(self, globals_dict, globals_req_dict): + super().__init__() + self.globals_req_dict = globals_req_dict + self.defaults = self.defaults_only(globals_req_dict) + self.globals_dict = self.merge(self.defaults, globals_dict) + def verify(self): + """ + Verifies the content of of self.globals_dict. The merge with defaults + during __init__ guarantees all keys exist. + """ + TrickWorkflowYamlVerifier.DictVerifier.verify(self, user_dict=self.globals_dict, + req_dict=self.globals_req_dict, identifier='globals') + def get_verified_globals_dict(self): + return (dict(self.globals_dict)) # Return a copy + + class SimVerifier(DictVerifier): + def __init__(self, sim_name, sim_dict, req_dict): + super().__init__() + sim_dict = {} if not isinstance(sim_dict, dict) else sim_dict + self.req_dict = req_dict # TODO every derived class needs this, move it to the base class + self.defaults = self.defaults_only(self.req_dict['sim']) + self.defaults['name'] = sim_name + # TODO what if SIM: dict is empty? + self.sim_dict = self.merge(self.defaults, sim_dict) + def verify(self): + TrickWorkflowYamlVerifier.DictVerifier.verify(self, user_dict=self.sim_dict, + req_dict=self.req_dict['sim'], identifier=self.sim_dict['name']) + if self.sim_dict['labels'] is None: + self.sim_dict['labels'] = [] # If not given, make it an empty list + # Handle the edge case where labels is a list, but a list of not just strings + if any([ not isinstance(label, str) for label in self.sim_dict['labels']]): + self.errors.append("In %s, labels \"%s\" expected to be list of strings. Ignoring." % + ( self.sim_dict['name'], self.sim_dict['labels'])) + self.sim_dict['labels'] = [] + if self.sim_dict['runs'] is None: + self.sim_dict['runs'] = {} # If not given, make it an empty dict + for run in list(self.sim_dict['runs']): + rv = (TrickWorkflowYamlVerifier.RunVerifier( run, + self.sim_dict['runs'][run], self.req_dict)) + try: + rv.verify() + self.sim_dict['runs'][run] = rv.get_verified_run_dict() + # If not all required params given, remove this run entry. I believe this + # to be unreachable code, but added anyhow for safety -Jordan 12/2022 + except RequiredParamException as e: + del self.sim_dict['runs'][run] + finally: + # Pass errors up to sim level + self.errors += rv.get_parsing_errors() + + def get_verified_sim_dict(self): + return (dict(self.sim_dict)) # Return a copy + + class RunVerifier(DictVerifier): + def __init__(self, run_name, run_dict, req_dict): + super().__init__() + self.req_dict = req_dict + self.defaults = self.defaults_only(self.req_dict['run']) + self.defaults['input'] = run_name + # If run_dict is None, use defaults, otherwise merge content into defaults + self.run_dict = (self.merge(self.defaults, run_dict) if run_dict else dict(self.defaults)) + def verify(self): + """ + Verifies the content of of self.run_dict. The merge with defaults + during __init__ guarantees all keys exist. + """ + # Verify the run + TrickWorkflowYamlVerifier.DictVerifier.verify(self, user_dict=self.run_dict, + req_dict=self.req_dict['run'], identifier=self.run_dict['input']) + # Verify the analyze: section of the run, setting to None if invalid + if (self.run_dict['analyze'] is not None and + not self.expect_type(self.run_dict['analyze'], str, + where=("In %s, analyze section " % (self.run_dict['input'])))): + self.run_dict['analyze'] = None + if self.run_dict['compare'] is None: + self.run_dict['compare'] = [] # If not given, make it an empty list + # Verify the compare list of the run, removing any that aren't correct + # The check for list allows all other non-list types in the yaml file, + # allowing groups to define their own comparison methodology + if isinstance(self.run_dict['compare'], list): + for compare in list(self.run_dict['compare']): + if (not self.expect_type(compare, str, + where=("In %s, compare section " % (self.run_dict['input']))) or + not self.expect_contains(" vs. ", compare, + where=("In %s, compare section " % (self.run_dict['input']))) + ): + self.run_dict['compare'].remove(compare) + + def get_verified_run_dict(self): + return (dict(self.run_dict)) # Return a copy + diff --git a/share/trick/trickops/WorkflowCommon.py b/share/trick/trickops/WorkflowCommon.py index c49bbfd7..0846313b 100644 --- a/share/trick/trickops/WorkflowCommon.py +++ b/share/trick/trickops/WorkflowCommon.py @@ -250,13 +250,15 @@ class Job(object): """ Start this job. """ - logging.debug('Executing command: ' + self._command) - self._start_time = time.time() - self._log_file = open(self.log_file, 'w') - self._process = subprocess.Popen( - self._command, stdout=self._log_file, stderr=self._log_file, - stdin=open(os.devnull, 'r'), shell=True, preexec_fn=os.setsid, - close_fds=True) + # Guard against multiple starts + if self.get_status != self.Status.RUNNING: + logging.debug('Executing command: ' + self._command) + self._start_time = time.time() + self._log_file = open(self.log_file, 'w') + self._process = subprocess.Popen( + self._command, stdout=self._log_file, stderr=self._log_file, + stdin=open(os.devnull, 'r'), shell=True, preexec_fn=os.setsid, + close_fds=True) def get_status(self): """ @@ -592,8 +594,8 @@ class WorkflowCommon: """ if not os.environ.get('TERM') and not self.quiet: tprint( - 'The TERM environment variable must be set when the command\n' - 'line option --quiet is not used. This is usually set by one\n' + 'The TERM environment variable must be set when\n' + 'TrickWorkflow.quiet is False. This is usually set by one\n' "of the shell's configuration files (.profile, .cshrc, etc).\n" 'However, if this was executed via a non-interactive,\n' "non-login shell (for instance: ssh ''), it\n" diff --git a/share/trick/trickops/exceptions.py b/share/trick/trickops/exceptions.py new file mode 100644 index 00000000..355b8f61 --- /dev/null +++ b/share/trick/trickops/exceptions.py @@ -0,0 +1,7 @@ +# define Python user-defined exceptions +class RequiredParamException(Exception): + "Raised when a parameter from a YAML file must exist but doesn't" + pass +class IncorrectYAMLException(Exception): + "Raised when a YAML file does not meet expected format" + pass diff --git a/share/trick/trickops/requirements.txt b/share/trick/trickops/requirements.txt index 6a4f9f2d..c74562aa 100644 --- a/share/trick/trickops/requirements.txt +++ b/share/trick/trickops/requirements.txt @@ -1,2 +1,2 @@ -PyYAML +PyYAML # Needed by TrickWorkflowYamlVerifier.py psutil diff --git a/share/trick/trickops/send_hs.py b/share/trick/trickops/send_hs.py new file mode 100644 index 00000000..8404769f --- /dev/null +++ b/share/trick/trickops/send_hs.py @@ -0,0 +1,67 @@ +import re, os +import pdb + +class send_hs(object): + """ + Reads a file containing the send_hs output and returns a send_hs + object containing the values from that output + """ + def __init__(self, hs_file): + self.hs_file = hs_file + self.actual_init_time = None + self.actual_elapsed_time = None + self.start_time = None + self.stop_time = None + self.elapsed_time = None + self.actual_cpu_time_used = None + self.sim_cpu_time = None + self.init_cpu_time = None + self.parse() + def parse(self): + f = open(self.hs_file, 'r') + lines = f.readlines() + for line in lines: + self.actual_init_time = self.attempt_hs_match('ACTUAL INIT TIME',self.actual_init_time, line) + self.actual_elapsed_time = self.attempt_hs_match('ACTUAL ELAPSED TIME',self.actual_elapsed_time, line) + self.start_time = self.attempt_hs_match('SIMULATION START TIME',self.start_time, line) + self.stop_time = self.attempt_hs_match('SIMULATION STOP TIME',self.stop_time, line) + self.elapsed_time = self.attempt_hs_match('SIMULATION ELAPSED TIME',self.elapsed_time, line) + self.actual_cpu_time_used = self.attempt_hs_match('ACTUAL CPU TIME USED',self.actual_cpu_time_used, line) + self.sim_cpu_time = self.attempt_hs_match('SIMULATION / CPU TIME',self.sim_cpu_time, line) + self.init_cpu_time = self.attempt_hs_match('INITIALIZATION CPU TIME',self.init_cpu_time, line) + # TODO add capture of blade and DIAGNOSTIC: Reached termination time as success criteria + + def attempt_hs_match(self, name, var, text): + """ + name: pattern to match (e.g. SIMULATION START TIME) + var: variable to assign value if match found + text: text to search for pattern + returns: var if not found, found value if found + """ + m = re.match(name+': +([-]?[0-9]*\.?[0-9]+)', text.strip()) + if m: + return(float(m.group(1))) + return(var) + + def get(self,name): + """ + Get a value by the name that appears in the send_hs message + """ + if 'ACTUAL INIT TIME' in name: + return self.actual_init_time + if 'ACTUAL ELAPSED TIME' in name: + return self.actual_elapsed_time + if 'SIMULATION START TIME' in name: + return self.start_time + if 'SIMULATION STOP TIME' in name: + return self.stop_time + if 'SIMULATION ELAPSED TIME' in name: + return self.elapsed_time + if 'ACTUAL CPU TIME USED' in name: + return self.actual_cpu_time_used + if 'SIMULATION / CPU TIME' in name: + return self.sim_cpu_time + if 'INITIALIZATION CPU TIME' in name: + return self.init_cpu_time + else: + return None diff --git a/share/trick/trickops/tests/empty1.yml b/share/trick/trickops/tests/empty1.yml new file mode 100644 index 00000000..6ead163f --- /dev/null +++ b/share/trick/trickops/tests/empty1.yml @@ -0,0 +1,4 @@ +# A YAML file which doesn't specify a single valid SIM +SIM_ball_L1: + path: 30 + diff --git a/share/trick/trickops/tests/errors_nonfatal.yml b/share/trick/trickops/tests/errors_nonfatal.yml index 41775640..be09d3ce 100644 --- a/share/trick/trickops/tests/errors_nonfatal.yml +++ b/share/trick/trickops/tests/errors_nonfatal.yml @@ -7,25 +7,24 @@ globals: extension_example: should: be ignored by this framework -# This sim exists, but has duplicate run entries which is an error +# This sim exists, but has duplicate run entries which means the last +# one is the only one respected SIM_ball_L1: path: trick_sims/Ball/SIM_ball_L1 - size: 6000 + size: 0 + phase: 1001 # Out of bounds runs: RUN_test/input.py: RUN_test/input.py: - valgrind: - runs: - RUN_test/input.py: # Wrong type, dict - - RUN_test/input.py: # Should be list of str not list of dict + valgrind: -# This sim exists, but its valgrind section is empty and its runs have problems +# This sim exists, but runs have problems SIM_alloc_test: path: test/SIM_alloc_test - valgrind: runs: RUN_buddy/input.py: # Doesn't exist RUN_test/input.py: # Does exist + phase: -1001 # Out of bounds extension: foobar # Should be retained in self.config but not used compare: - RUN_test/log.trk: # Should be list of str not list of dict @@ -42,8 +41,6 @@ SIM_events: runs: - RUN_test/input.py: # List of dicts, should be ignored - RUN_test/unit_test.py: # List of dicts, should be ignored - valgrind: # Empty so should be ignored - runs: # Sim exists, but runs have bad return values SIM_threads: diff --git a/share/trick/trickops/tests/run_tests.py b/share/trick/trickops/tests/run_tests.py index 02b94b2d..35f17813 100755 --- a/share/trick/trickops/tests/run_tests.py +++ b/share/trick/trickops/tests/run_tests.py @@ -33,7 +33,8 @@ def run_tests(args): ut_results = runner.run(overall_suite) # Run all doc tests by eating our own dogfood - doctest_files = ['TrickWorkflow.py', 'WorkflowCommon.py'] + doctest_files = ['TrickWorkflow.py', 'WorkflowCommon.py', 'TrickWorkflowYamlVerifier.py', + 'MonteCarloGenerationHelper.py'] wc = WorkflowCommon(this_dir, quiet=True) jobs = [] log_prepend = '_doctest_log.txt' diff --git a/share/trick/trickops/tests/test.py b/share/trick/trickops/tests/test.py index f0fc3baa..8568bcc8 100644 --- a/share/trick/trickops/tests/test.py +++ b/share/trick/trickops/tests/test.py @@ -6,20 +6,26 @@ import os, sys, pdb import unittest import ut_WorkflowCommon +import ut_TrickWorkflowYamlVerifier import ut_TrickWorkflow +import ut_MonteCarloGenerationHelper # Define load_tests function for dynamic loading using Nose2 def load_tests(*args): passed_args = locals() suite = unittest.TestSuite() + suite.addTests(ut_TrickWorkflowYamlVerifier.suite()) suite.addTests(ut_TrickWorkflow.suite()) suite.addTests(ut_WorkflowCommon.suite()) + suite.addTests(ut_MonteCarloGenerationHelper.suite()) return suite # Local module level execution only if __name__ == '__main__': suites = unittest.TestSuite() + suites.addTests(ut_TrickWorkflowYamlVerifier.suite()) suites.addTests(ut_TrickWorkflow.suite()) suites.addTests(ut_WorkflowCommon.suite()) + suites.addTests(ut_MonteCarloGenerationHelper.suite()) unittest.TextTestRunner(verbosity=2).run(suites) diff --git a/share/trick/trickops/tests/trick_sims.yml b/share/trick/trickops/tests/trick_sims.yml index a2ccb36d..f87f5ed2 100644 --- a/share/trick/trickops/tests/trick_sims.yml +++ b/share/trick/trickops/tests/trick_sims.yml @@ -5,19 +5,18 @@ SIM_ball_L1: path: trick_sims/Ball/SIM_ball_L1 size: 6000 + phase: 0 runs: RUN_test/input.py: analyze: echo hi compare: - share/trick/trickops/tests/testdata/log_a.csv vs. share/trick/trickops/tests/baselinedata/log_a.csv - valgrind: - flags: -v - runs: - - RUN_test/input.py SIM_alloc_test: path: test/SIM_alloc_test runs: RUN_test/input.py: + analyze: echo hi there + valgrind: -v SIM_default_member_initializer: path: test/SIM_default_member_initializer SIM_demo_inputfile: @@ -34,7 +33,9 @@ SIM_demo_sdefine: - unit_test runs: RUN_test/input.py: + phase: 0 RUN_test/unit_test.py: + phase: 1 SIM_dynamic_sim_object: path: test/SIM_dynamic_sim_object runs: @@ -77,10 +78,13 @@ SIM_rti: labels: - unit_test SIM_segments: + binary: 'T_main_*.exe' path: test/SIM_segments runs: RUN_test/input.py: SIM_stls: + binary: 'T_main_{cpu}_test.exe' + build_args: "-t" path: test/SIM_stls labels: - unit_test @@ -147,7 +151,6 @@ SIM_test_varserv: labels: - unit_test runs: - RUN_test/realtime.py: RUN_test/unit_test.py: SIM_threads: path: test/SIM_threads @@ -155,21 +158,35 @@ SIM_threads: - unit_test runs: RUN_test/sched.py: + phase: 1 + analyze: echo phase 1 analysis RUN_test/amf.py: + phase: 2 + analyze: echo phase 2 analysis RUN_test/async.py: + phase: 3 + analyze: echo phase 3 analysis RUN_test/unit_test.py: + phase: 4 + analyze: echo phase 4 analysis SIM_threads_simple: path: test/SIM_threads_simple runs: RUN_test/input.py: + phase: 1 + analyze: echo phase 1 analysis RUN_test/sched.py: + phase: 2 + analyze: echo phase 2 analysis RUN_test/async.py: + phase: 3 SIM_trickcomm: path: test/SIM_trickcomm runs: RUN_test/input.py: SIM_ball_L2: path: trick_sims/Ball/SIM_ball_L2 + runs: SIM_ball_L3: path: trick_sims/Ball/SIM_ball_L3 SIM_amoeba: @@ -185,6 +202,7 @@ SIM_cannon_jet: SIM_cannon_numeric: path: trick_sims/Cannon/SIM_cannon_numeric SIM_monte: + phase: -1 path: trick_sims/Cannon/SIM_monte SIM_ode_ball: path: trick_sims/ODE/SIM_ode_ball @@ -211,10 +229,12 @@ SIM_sat2d: SIM_satellite: path: trick_sims/SIM_satellite SIM_sun: + phase: 72 path: trick_sims/SIM_sun SIM_wheelbot: path: trick_sims/SIM_wheelbot SIM_ball_L1_er7_utils: + phase: -88 path: trick_source/er7_utils/sims/SIM_ball_L1 SIM_grav: path: trick_source/er7_utils/sims/SIM_grav diff --git a/share/trick/trickops/tests/type_errors.yml b/share/trick/trickops/tests/type_errors.yml new file mode 100644 index 00000000..b80e1686 --- /dev/null +++ b/share/trick/trickops/tests/type_errors.yml @@ -0,0 +1,60 @@ +# This is a file containing trick sims from this repository to be used +# for unit testing the trickops module. Specifically this file contains +# values for parameters with the wrong type +SIM_type_errors1: + path: path/to/SIM + build_args: 1 # Should be string not int + parallel_safety: 2 # Should be string not int + description: 10 # Should be a string not int + binary: 20 # Should be a string not int + size: 'string' # Should be an int not string + phase: 'string' # Should be an int not string + labels: 'hi there' # Should be a list not string + runs: + RUN_test1/input.py: + returns: 256 # Should be between 0-255 + analyze: 35 # Should be a string not int + compare: + - 40 # Should be a string not int + RUN_test2/input.py: + returns: -1 # Should be between 0-255 + valgrind: 79 # Should be a string not int + + +SIM_type_errors2: + path: path/to/SIM + build_args: + - this shouldnt + - be a list + binary: + - this shouldnt + - be a list + build_args: + - this shouldnt + - be a list + parallel_safety: + - this shouldnt + - be a list + description: + - this shouldnt + - be a list + binary: + - this shouldnt + - be a list + size: + - this shouldnt + - be a list + phase: + - this shouldnt + - be a list + +SIM_range_errors: + path: path/to/SIM + parallel_safety: 'bad_value' + size: -10 + phase: -1000 + +# Bad path must be tested separate, since it halts processing +# of other parameters immediately +SIM_bad_path: + path: 30 # Should be a str not int diff --git a/share/trick/trickops/tests/ut_MonteCarloGenerationHelper.py b/share/trick/trickops/tests/ut_MonteCarloGenerationHelper.py new file mode 100644 index 00000000..ee248002 --- /dev/null +++ b/share/trick/trickops/tests/ut_MonteCarloGenerationHelper.py @@ -0,0 +1,204 @@ +import os, sys, glob +import unittest, shutil +import pdb +from testconfig import this_trick, tests_dir +import TrickWorkflow +from MonteCarloGenerationHelper import * + +def suite(): + """Create test suite from test cases here and return""" + suites = [] + suites.append(unittest.TestLoader().loadTestsFromTestCase(MCGNominalTestCase)) + suites.append(unittest.TestLoader().loadTestsFromTestCase(MCGAllArgsTestCase)) + suites.append(unittest.TestLoader().loadTestsFromTestCase(MCGInvalidGenerationTestCase)) + suites.append(unittest.TestLoader().loadTestsFromTestCase(MCGInvalidInputsTestCase)) + return (suites) + +class MCGNominalTestCase(unittest.TestCase): + + def setUp(self): + # Nominal no-error when parsing the trick-sims config file scenario + self.instance = MonteCarloGenerationHelper(sim_path=os.path.join(this_trick, 'test/SIM_mc_generation'), + input_path='RUN_nominal/input_a.py') + # Create expected generated output directories and files this tests needs. Note this + # matches what SIM_mc_generation produces when run and should work whether output + # from that sim's tests are lingering in the workspace or not + self.monte_dir = os.path.join(this_trick, 'test/SIM_mc_generation', 'MONTE_RUN_nominal') + os.makedirs(os.path.join(self.monte_dir, 'RUN_000'), exist_ok=True) + os.makedirs(os.path.join(self.monte_dir, 'RUN_001'), exist_ok=True) + for dir in ['RUN_000', 'RUN_001']: + if not os.path.isfile(os.path.join(self.monte_dir, dir, 'monte_input_a.py')): + with open(os.path.join(self.monte_dir, dir, 'monte_input_a.py'), 'w') as fp: + pass + + def tearDown(self): + if self.instance: + del self.instance + self.instance = None + + def test_init(self): + self.assertEqual(self.instance.S_main_name, "S_main*.exe") + self.assertEqual(self.instance.sim_path, os.path.join(this_trick,"test/SIM_mc_generation")) + self.assertEqual(self.instance.input_path, "RUN_nominal/input_a.py") + self.assertEqual(self.instance.sim_args_gen, '') + self.assertEqual(self.instance.env, '') + self.assertEqual(self.instance.generated_input_files, []) + self.assertTrue(('trick/test/SIM_mc_generation && ./S_main*.exe RUN_nominal/input_a.py') + in self.instance.generation_job._command) + self.assertTrue(os.path.join(self.instance.sim_path, os.path.dirname(self.instance.input_path), + 'MCG_generation_output.txt') in self.instance.generation_job.log_file) + + def test_get_generation_job(self): + j = self.instance.get_generation_job() + self.assertTrue(isinstance(j, TrickWorkflow.SingleRun)) + + def test_get_generated_input_files(self): + gif = self.instance.get_generated_input_files(os.path.join(self.instance.sim_path, 'MONTE_RUN_nominal')) + self.assertTrue('trick/test/SIM_mc_generation/MONTE_RUN_nominal/RUN_000/monte_input_a.py' in gif[0]) + self.assertTrue('trick/test/SIM_mc_generation/MONTE_RUN_nominal/RUN_001/monte_input_a.py' in gif[1]) + # Given the relative path from sim + os.chdir(self.instance.sim_path) + gif = self.instance.get_generated_input_files('MONTE_RUN_nominal') + + # Given invalid path (relative to cwd()) + with self.assertRaises(RuntimeError): + gif = self.instance.get_generated_input_files('fake/path/MONTE_RUN_nominal') + + def test_get_zero_padding(self): + zp = self.instance.get_zero_padding(monte_dir=self.monte_dir) + self.assertEqual(zp, 3) + # Without any args it should use interal self.generated_input_files + zp = self.instance.get_zero_padding() + self.assertEqual(zp, 3) + + def test_get_sbatch_job(self): + sbj = self.instance.get_sbatch_job(self.monte_dir) + self.assertTrue('--array 0-001 ' in sbj._command) + self.assertTrue(self.instance.S_main_name in sbj._command) + self.assertTrue(self.monte_dir in sbj._command) + self.assertTrue('RUN_${RUN_NUM}' in sbj._command) + + def test_get_sbatch_job_with_passthrough_args(self): + sbj = self.instance.get_sbatch_job(self.monte_dir, hpc_passthrough_args="--array 50-80 --wait") + self.assertTrue('--array 50-80 ' in sbj._command) + self.assertTrue('--wait ' in sbj._command) + sbj = self.instance.get_sbatch_job(self.monte_dir, hpc_passthrough_args="--array 1-100:10") + self.assertTrue('--array 1-100:10 ' in sbj._command) + self.assertTrue('--wait ' not in sbj._command) + sbj = self.instance.get_sbatch_job(self.monte_dir, hpc_passthrough_args="--begin 16:00") + self.assertTrue('--begin 16:00 ' in sbj._command) + self.assertTrue('--array 0-001 ' in sbj._command) + sbj = self.instance.get_sbatch_job(self.monte_dir, sim_args="--logging=verbose") + self.assertTrue('--logging=verbose' in sbj._command) + + def test_get_generated_run_jobs(self): + jobs = self.instance.get_generated_run_jobs(self.monte_dir) + self.assertEqual(len(jobs), 2) + self.assertTrue('MONTE_RUN_nominal/RUN_000/monte_input_a.py' in jobs[0]._command) + self.assertTrue('MONTE_RUN_nominal/RUN_001/monte_input_a.py' in jobs[1]._command) + jobs = self.instance.get_generated_run_jobs(self.monte_dir, sim_args='--logging=off') + self.assertTrue('--logging=off' in jobs[0]._command) + self.assertTrue('--logging=off' in jobs[1]._command) + +class MCGAllArgsTestCase(unittest.TestCase): + + def setUp(self): + # Nominal no-error when parsing the trick-sims config file scenario + self.instance = MonteCarloGenerationHelper(sim_path=os.path.join(this_trick, 'test/SIM_mc_generation'), + input_path='RUN_nominal/input_a.py', env='source bashrc;', sim_args_gen='--monte-carlo --runs=32') + + def tearDown(self): + if self.instance: + del self.instance + self.instance = None + + def test_init(self): + self.assertTrue( self.instance.generation_job._command.startswith('source bashrc; ')) + self.assertTrue( self.instance.generation_job._command.endswith('--monte-carlo --runs=32')) + +class MCGInvalidGenerationTestCase(unittest.TestCase): + + def setUp(self): + # Nominal no-error when parsing the trick-sims config file scenario + self.instance = MonteCarloGenerationHelper(sim_path=os.path.join(this_trick, 'test/SIM_mc_generation'), + input_path='RUN_nominal/input_a.py') + # Create incorrect generated output directories and files this tests needs. + # This simulates a generation error and tests that the MonteCarloGenerationHelper class can + # detect it + monte_dir = os.path.join(this_trick, 'test/SIM_mc_generation', 'MONTE_RUN_missing_input_files') + os.makedirs(os.path.join(monte_dir, 'RUN_000'), exist_ok=True) + os.makedirs(os.path.join(monte_dir, 'RUN_001'), exist_ok=True) + monte_dir = os.path.join(this_trick, 'test/SIM_mc_generation', 'MONTE_RUN_mismatch_input_files') + os.makedirs(os.path.join(monte_dir, 'RUN_000'), exist_ok=True) + os.makedirs(os.path.join(monte_dir, 'RUN_001'), exist_ok=True) + with open(os.path.join(monte_dir, 'RUN_000', 'monte_input_a.py'), 'w') as fp: + pass + monte_dir = os.path.join(this_trick, 'test/SIM_mc_generation', 'MONTE_RUN_incorrect_input_files') + os.makedirs(os.path.join(monte_dir, 'RUN_000'), exist_ok=True) + os.makedirs(os.path.join(monte_dir, 'RUN_001'), exist_ok=True) + for dir in ['RUN_000', 'RUN_001']: + if not os.path.isfile(os.path.join(monte_dir, dir, 'input_a.py')): + with open(os.path.join(monte_dir, dir, 'input_a.py'), 'w') as fp: + pass + monte_dir = os.path.join(this_trick, 'test/SIM_mc_generation', 'MONTE_RUN_completely_bonkers') + os.makedirs(os.path.join(monte_dir, 'RUN_makes_no'), exist_ok=True) + os.makedirs(os.path.join(monte_dir, 'RUN_sense'), exist_ok=True) + for dir in ['RUN_makes_no', 'RUN_sense']: + if not os.path.isfile(os.path.join(monte_dir, dir, 'input_a.py')): + with open(os.path.join(monte_dir, dir, 'input_a.py'), 'w') as fp: + pass + + def tearDown(self): + if self.instance: + del self.instance + self.instance = None + # Remove the fake directory tree created in this test + shutil.rmtree(os.path.join(this_trick, 'test/SIM_mc_generation', 'MONTE_RUN_missing_input_files')) + shutil.rmtree(os.path.join(this_trick, 'test/SIM_mc_generation', 'MONTE_RUN_mismatch_input_files')) + shutil.rmtree(os.path.join(this_trick, 'test/SIM_mc_generation', 'MONTE_RUN_incorrect_input_files')) + shutil.rmtree(os.path.join(this_trick, 'test/SIM_mc_generation', 'MONTE_RUN_completely_bonkers')) + + def test_get_generated_input_files(self): + # Just a warning + gif = self.instance.get_generated_input_files( + os.path.join(self.instance.sim_path, 'MONTE_RUN_mismatch_input_files')) + with self.assertRaises(RuntimeError): + gif = self.instance.get_generated_input_files( + os.path.join(self.instance.sim_path, 'MONTE_RUN_missing_input_files')) + with self.assertRaises(RuntimeError): + gif = self.instance.get_generated_input_files( + os.path.join(self.instance.sim_path, 'MONTE_RUN_incorrect_input_files')) + with self.assertRaises(RuntimeError): + gif = self.instance.get_generated_input_files( + os.path.join(self.instance.sim_path, 'MONTE_RUN_completely_bonkers')) + + def test_get_zero_padding(self): + # Without monte_dir and get_generated_input files never having been run, this will fail + with self.assertRaises(RuntimeError): + zp = self.instance.get_zero_padding() + # Nothing in monte_dir, will fail + with self.assertRaises(RuntimeError): + zp = self.instance.get_zero_padding(monte_dir=os.path.join(this_trick, 'test/SIM_mc_generation', 'MONTE_RUN_missing_input_files')) + +class MCGInvalidInputsTestCase(unittest.TestCase): + + def setUp(self): + # Invalid sim_path + with self.assertRaises(RuntimeError): + self.instance = MonteCarloGenerationHelper(sim_path=os.path.join(this_trick, 'test/SIM_notexist'), + input_path='RUN_nominal/input_a.py') + # Invalid input_path + with self.assertRaises(RuntimeError): + self.instance = MonteCarloGenerationHelper(sim_path=os.path.join(this_trick, 'test/SIM_mc_generation'), + input_path='RUN_nominal/input_x.py',) + # Invalid sim_args_gen + with self.assertRaises(TypeError): + self.instance = MonteCarloGenerationHelper(sim_path=os.path.join(this_trick, 'test/SIM_mc_generation'), + input_path='RUN_nominal/input_a.py', sim_args_gen=3) + # Invalid env + with self.assertRaises(TypeError): + self.instance = MonteCarloGenerationHelper(sim_path=os.path.join(this_trick, 'test/SIM_mc_generation'), + input_path='RUN_nominal/input_a.py', env=3) + + def test_init(self): + pass diff --git a/share/trick/trickops/tests/ut_TrickWorkflow.py b/share/trick/trickops/tests/ut_TrickWorkflow.py index f25065c6..8f08a0fd 100644 --- a/share/trick/trickops/tests/ut_TrickWorkflow.py +++ b/share/trick/trickops/tests/ut_TrickWorkflow.py @@ -5,11 +5,36 @@ from testconfig import this_trick, tests_dir from TrickWorkflow import * def suite(): - """Create test suite from TrickWorkflowTestCase unit test class and return""" - return unittest.TestLoader().loadTestsFromTestCase(TrickWorkflowTestCase) + """Create test suite from test cases here and return""" + suites = [] + suites.append(unittest.TestLoader().loadTestsFromTestCase(TrickWorkflowTestCase)) + suites.append(unittest.TestLoader().loadTestsFromTestCase(TrickWorkflowSingleRunTestCase)) + return (suites) + +class TrickWorkflowSingleRunTestCase(unittest.TestCase): + def setUp(self): + self.instance= SingleRun(name='testname', command='echo hi', + log_file='/tmp/WorkflowCommonTestCase_hi.txt') + + def tearDown(self): + del self.instance + self.instance = None + + def test_SingleRun_Nominal(self): + self.assertEqual(self.instance.name, 'testname') + self.assertEqual(self.instance._command, 'echo hi') + self.assertEqual(self.instance.log_file, '/tmp/WorkflowCommonTestCase_hi.txt') + self.assertEqual(self.instance._log_file, None) + self.assertEqual(self.instance._expected_exit_status, 0) + self.assertEqual(self.instance.get_use_var_server(), True) + # Test the setter for var server interaction + self.instance.set_use_var_server(False) + self.assertEqual(self.instance.get_use_var_server(), False) class TrickWorkflowTestCase(unittest.TestCase): + # TODO: not all jobs even use this setUp, probably should split the ones + # out that need to load a different file or no file at all (static tests) def setUp(self): # Nominal no-error when parsing the trick-sims config file scenario self.instance = TrickWorkflow(project_top_level=this_trick, log_dir='/tmp/', @@ -22,9 +47,9 @@ class TrickWorkflowTestCase(unittest.TestCase): del self.instance self.instance = None - def setUpWithEmptyConfig(self): + def setUpWithEmptyConfig(self, file="empty.yml"): self.instance = TrickWorkflow(project_top_level=this_trick, log_dir='/tmp/', - trick_dir=this_trick, config_file=os.path.join(tests_dir,"empty.yml"), + trick_dir=this_trick, config_file=os.path.join(tests_dir,file), quiet=True) def setUpWithErrorConfig(self, file): @@ -33,21 +58,43 @@ class TrickWorkflowTestCase(unittest.TestCase): trick_dir=this_trick, config_file=os.path.join(tests_dir,file), quiet=True) + def test_static_members(self): + self.assertEqual(TrickWorkflow.all_possible_phases, + range(TrickWorkflow.allowed_phase_range['min'], TrickWorkflow.allowed_phase_range['max']+1) ) + self.assertEqual(TrickWorkflow.listify_phase(3), [3]) # Int becomes list of int + self.assertEqual(TrickWorkflow.listify_phase([-3, 3, 9]), [-3, 3, 9]) # Valid list passes through + self.assertEqual(TrickWorkflow.listify_phase(), list(TrickWorkflow.all_possible_phases)) + self.assertEqual(TrickWorkflow.listify_phase(None), list(TrickWorkflow.all_possible_phases)) + self.assertEqual(TrickWorkflow.listify_phase(range(0,5)), [0, 1, 2, 3, 4]) + with self.assertRaises(RuntimeError): + p = TrickWorkflow.listify_phase('hey') # Bad type + with self.assertRaises(RuntimeError): + p = TrickWorkflow.listify_phase([-3, 3, 'hi']) # Bad type + with self.assertRaises(RuntimeError): + p = TrickWorkflow.listify_phase([-30000, 3, '30000']) # Out of range + with self.assertRaises(RuntimeError): + p = TrickWorkflow.listify_phase([-30000, 3, 'hello']) # Out of range and bad type + def test_init_nominal(self): self.assertEqual(self.instance.cpus, 3) - self.assertEqual(self.instance.parallel_safety, 'loose') - self.assertEqual(self.instance.config_errors, False) + self.assertEqual(self.instance.config_errors, []) self.instance.report() build_jobs = self.instance.get_jobs('build') self.assertEqual(len(build_jobs), 56) self.assertEqual(len(self.instance.sims), 56) run_jobs = self.instance.get_jobs('run') - self.assertEqual(len(run_jobs), 38) + self.assertEqual(len(run_jobs), 36) + val_run_jobs = self.instance.get_jobs('valgrind') + self.assertEqual(len(val_run_jobs), 1) def test_init_empty_so_raises(self): with self.assertRaises(RuntimeError): self.setUpWithEmptyConfig() + def test_init_empty_after_parsing_so_raises(self): + with self.assertRaises(RuntimeError): + self.setUpWithEmptyConfig("empty1.yml") + def test_init_bad_yaml_so_raises(self): with self.assertRaises(RuntimeError): self.setUpWithErrorConfig("errors_fatal1.yml") @@ -56,17 +103,18 @@ class TrickWorkflowTestCase(unittest.TestCase): def test_init_errors_but_no_raise(self): self.setUpWithErrorConfig("errors_nonfatal.yml") - self.assertTrue(self.instance.config_errors) - self.assertEqual(self.instance.parallel_safety , 'loose') + self.assertEqual(len(self.instance.parsing_errors), 11) + self.assertEqual(len(self.instance.config_errors), 2) self.assertEqual(len(self.instance.sims), 4) self.assertEqual(len(self.instance.get_sim('SIM_ball_L1').get_runs()), 1) + #import pprint; pprint.pprint(self.instance.parsing_errors) self.assertEqual(len(self.instance.get_sim('SIM_ball_L1').get_valgrind_runs()), 0) - self.assertEqual(len(self.instance.get_sim('SIM_alloc_test').get_runs()), 1) + self.assertEqual(self.instance.get_sim('SIM_ball_L1').get_phase(), 0) + self.assertEqual(len(self.instance.get_sim('SIM_alloc_test').get_runs()), 2) self.assertEqual(len(self.instance.get_sim('SIM_alloc_test').get_valgrind_runs()), 0) self.assertEqual(self.instance.config['SIM_alloc_test']['runs']['RUN_test/input.py']['extension'], 'foobar') self.assertEqual(len(self.instance.get_sim('SIM_events').get_runs()), 0) - self.assertTrue('fine1' in self.instance.get_sim('SIM_events').labels) - self.assertTrue('fine2' in self.instance.get_sim('SIM_events').labels) + self.assertEqual(self.instance.get_sim('SIM_events').labels, []) self.assertEqual(self.instance.get_sim('SIM_threads').get_run('RUN_test/sched.py').returns, 0) self.assertEqual(self.instance.get_sim('SIM_threads').get_run('RUN_test/amf.py').returns, 0) self.assertEqual(self.instance.get_sim('SIM_threads').get_run('RUN_test/async.py').returns, 0) @@ -75,8 +123,7 @@ class TrickWorkflowTestCase(unittest.TestCase): self.assertTrue(self.instance.get_sim('SIM_L1_ball') is None) self.assertTrue(self.instance.get_sim('SIM_foobar') is None) self.assertTrue(self.instance.get_sim('SIM_parachute') is None) - - self.assertTrue(self.instance.config['extension_example']) + self.assertEqual(self.instance.config['extension_example'], {'should': 'be ignored by this framework'}) self.instance.report() def test_get_sim_nominal(self): @@ -117,21 +164,53 @@ class TrickWorkflowTestCase(unittest.TestCase): sim = self.instance.get_sim(identifier='SIM_ball_L1') run = sim.get_run('RUN_test/input.py') + def test_set_binary_with_cpu_formatter (self): + sim = self.instance.get_sim(identifier="SIM_stls") + cpu = self.instance.get_trick_host_cpu() + run = sim.get_run('RUN_test/unit_test.py') + print("Binary: " , run.binary) + self.assertEqual(run.binary, "T_main_" + cpu + "_test.exe") + + def test_set_binary_without_cpu_formatter (self): + sim = self.instance.get_sim(identifier="SIM_segments") + run = sim.get_run('RUN_test/input.py') + print("Binary: " , run.binary) + self.assertEqual(run.binary, "T_main_*.exe") + + def test_absolute_path_to_custom_build_cmd (self): + sim = self.instance.get_sim(identifier="SIM_stls") + absolute_path = os.path.join(self.instance.trick_dir, "bin", "trick-CP -t") + self.assertEqual(sim.build_cmd, absolute_path) + + def test_absolute_path_to_default_build_cmd (self): + sim = self.instance.get_sim(identifier="SIM_segments") + absolute_path = os.path.join(self.instance.trick_dir, "bin", "trick-CP") + self.assertEqual(sim.build_cmd, absolute_path) + def test_get_unique_comparison_dirs(self): ucd = self.instance.get_unique_comparison_dirs() self.assertTrue(ucd[0] is not None) self.assertTrue(ucd[0][0] is not None) self.assertTrue(ucd[0][1] is not None) - def test_get_koviz_report_jobs_nominal(self): + def test_get_koviz_report_jobs(self): + # Since instrumenting "is koviz on your PATH?" is difficult, this test is + # designed to check both error (not on PATH) and non-error (on PATH) cases krj = self.instance.get_koviz_report_jobs() - self.assertTrue(isinstance(krj[0][0], Job)) - self.assertTrue(not krj[1]) + if krj[1] == []: # No errors implies we have koviz on PATH + self.assertTrue(isinstance(krj[0], list)) + self.assertTrue(isinstance(krj[0][0], Job)) + self.assertTrue(not krj[1]) + else: # Otherwise koviz not on PATH + self.assertTrue('koviz is not found' in krj[1][0]) + self.assertTrue(isinstance(krj[0], list)) + self.assertEqual(len(krj[0]), 0) def test_get_koviz_report_job_missing_dir(self): krj = self.instance.get_koviz_report_job('share/trick/trickops/tests/testdata_noexist', 'share/trick/trickops/tests/baselinedata') self.assertTrue(krj[0] is None) + # Loose check but works even if koviz not on PATH self.assertTrue('ERROR' in krj[1]) def test_status_summary_nominal(self): @@ -142,18 +221,49 @@ class TrickWorkflowTestCase(unittest.TestCase): def test_get_and_pop_run(self): sim = self.instance.get_sim('SIM_ball_L1') run = sim.get_run('RUN_test/input.py') - self.assertEqual(run.input, 'RUN_test/input.py') + self.assertEqual(run.input_file, 'RUN_test/input.py') run = sim.pop_run('RUN_test/input.py') - self.assertEqual(run.input, 'RUN_test/input.py') + self.assertEqual(run.input_file, 'RUN_test/input.py') self.assertEqual(len(sim.get_runs()), 0) - def test_check_run_jobs(self): + def test_get_run_jobs_kind(self): sim = self.instance.get_sim('SIM_ball_L1') normal_run_jobs = sim.get_run_jobs() self.assertTrue('valgrind' not in normal_run_jobs[0]._command) + sim = self.instance.get_sim('SIM_alloc_test') valgrind_run_jobs = sim.get_run_jobs(kind='valgrind') self.assertTrue('valgrind' in valgrind_run_jobs[0]._command) + def test_get_run_jobs_phase(self): + sim = self.instance.get_sim('SIM_demo_sdefine') + run_jobs = sim.get_run_jobs() # Ask for everything + self.assertEqual(len(run_jobs), 2) + run_jobs_phase0_int = sim.get_run_jobs(phase=0) # Ask for only phase 0 as int + self.assertEqual(len(run_jobs_phase0_int), 1) + run_jobs_phase0_list = sim.get_run_jobs(phase=[0]) # Ask for only phase 0 as list + self.assertEqual(run_jobs_phase0_int, run_jobs_phase0_list) # Should be the same + self.assertEqual(len(run_jobs_phase0_list), 1) + run_jobs_phase1_int = sim.get_run_jobs(phase=1) # Ask for only phase 1 as int + self.assertEqual(len(run_jobs_phase1_int), 1) + run_jobs_phase1_list = sim.get_run_jobs(phase=[1]) # Ask for only phase 1 as list + self.assertEqual(run_jobs_phase1_int, run_jobs_phase1_list) # Should be the same + self.assertEqual(len(run_jobs_phase1_list), 1) + run_jobs_both_phases_list = sim.get_run_jobs(phase=[0,1]) # Ask for phase 0-1 as list + self.assertEqual(len(run_jobs_both_phases_list), 2) + self.assertEqual(run_jobs_both_phases_list, run_jobs) # These should be equivalent + run_jobs_one_phase_not_exist = sim.get_run_jobs(phase=[0,1,2]) # Ask for phase 0-2 as list, 2 doesn't exist + self.assertEqual(len(run_jobs_one_phase_not_exist), 2) # We only get what exists + # Ask for everything explicitly, this is far slower than phase=None but should produce equivalent list + run_jobs_all_possible_explicit = sim.get_run_jobs(phase=TrickWorkflow.all_possible_phases) + self.assertEqual(run_jobs_all_possible_explicit , run_jobs) # These should be equivalent + # Error cases + with self.assertRaises(RuntimeError): + run_jobs_invalid_input = sim.get_run_jobs(phase=['abc',1]) # strings aren't permitted + with self.assertRaises(RuntimeError): + run_jobs_invalid_input = sim.get_run_jobs(phase=-10000) # out of range as int + with self.assertRaises(RuntimeError): + run_jobs_invalid_input = sim.get_run_jobs(phase=[-10000]) # out of range as list + def test_compare(self): sim = self.instance.get_sim('SIM_ball_L1') # Sim level comparison (test_data.csv vs. baseline_data.csv) will fail @@ -166,29 +276,93 @@ class TrickWorkflowTestCase(unittest.TestCase): self.assertEqual(run.comparisons[0]._translate_status(), '\x1b[31mFAIL\x1b[0m') def test_get_jobs_nominal(self): - # Test all the permissive permutations + # Test all the kinds permutations builds = self.instance.get_jobs('build') self.assertEqual(len(builds), 56) builds = self.instance.get_jobs('builds') self.assertEqual(len(builds), 56) runs = self.instance.get_jobs('run') - self.assertEqual(len(runs), 38) + self.assertEqual(len(runs), 36) runs = self.instance.get_jobs('runs') - self.assertEqual(len(runs), 38) + self.assertEqual(len(runs), 36) vg = self.instance.get_jobs('valgrind') self.assertEqual(len(vg), 1) vg = self.instance.get_jobs('valgrinds') self.assertEqual(len(vg), 1) a = self.instance.get_jobs('analysis') - self.assertEqual(len(a), 1) + self.assertEqual(len(a), 8) a = self.instance.get_jobs('analyses') - self.assertEqual(len(a), 1) + self.assertEqual(len(a), 8) a = self.instance.get_jobs('analyze') - self.assertEqual(len(a), 1) + self.assertEqual(len(a), 8) + + def test_get_jobs_builds_with_phases(self): + # All builds all phases + builds = self.instance.get_jobs('build', phase=None) + self.assertEqual(len(builds), 56) + builds = self.instance.get_jobs('build', phase=TrickWorkflow.all_possible_phases) + self.assertEqual(len(builds), 56) + # Builds only specific phases + builds = self.instance.get_jobs('build', phase=970) + self.assertEqual(len(builds), 0) + builds = self.instance.get_jobs('build', phase=0) + self.assertEqual(len(builds), 53) + builds = self.instance.get_jobs('build', phase=[0]) + self.assertEqual(len(builds), 53) + builds = self.instance.get_jobs('build', phase=-1) + self.assertEqual(len(builds), 1) + builds = self.instance.get_jobs('build', phase=72) + self.assertEqual(len(builds), 1) + builds = self.instance.get_jobs('build', phase=-88) + self.assertEqual(len(builds), 1) + builds = self.instance.get_jobs('build', phase=[-88, 72]) + self.assertEqual(len(builds), 2) + + def test_get_jobs_runs_with_phases(self): + # All runs all phases + vruns = self.instance.get_jobs('valgrind', phase=None) + self.assertEqual(len(vruns), 1) + vruns = self.instance.get_jobs('valgrind', phase=7) + self.assertEqual(len(vruns), 0) + runs = self.instance.get_jobs('run', phase=None) + self.assertEqual(len(runs), 36) + runs = self.instance.get_jobs('run', phase=TrickWorkflow.all_possible_phases) + self.assertEqual(len(runs), 36) + # Runs specific phases + runs = self.instance.get_jobs('run', phase=[8, 19]) + self.assertEqual(len(runs), 0) + runs = self.instance.get_jobs('run', phase=1) + self.assertEqual(len(runs), 3) + runs = self.instance.get_jobs('run', phase=2) + self.assertEqual(len(runs), 2) + runs = self.instance.get_jobs('run', phase=3) + self.assertEqual(len(runs), 2) + runs = self.instance.get_jobs('run', phase=4) + self.assertEqual(len(runs), 1) + + def test_get_jobs_analysis_with_phases(self): + # All analysis all phases + an = self.instance.get_jobs('analysis', phase=None) + self.assertEqual(len(an), 8) + an = self.instance.get_jobs('analysis', phase=TrickWorkflow.all_possible_phases) + self.assertEqual(len(an), 8) + # Analysis specific phases + an = self.instance.get_jobs('analysis', phase=[8, 19]) + self.assertEqual(len(an), 0) + an = self.instance.get_jobs('analysis', phase=1) + self.assertEqual(len(an), 2) + an = self.instance.get_jobs('analysis', phase=2) + self.assertEqual(len(an), 2) + an = self.instance.get_jobs('analysis', phase=3) + self.assertEqual(len(an), 1) def test_get_jobs_raises(self): with self.assertRaises(TypeError): jobs = self.instance.get_jobs(kind='bucees') + with self.assertRaises(RuntimeError): + jobs = self.instance.get_jobs(kind='build', phase='abx') + with self.assertRaises(RuntimeError): + jobs = self.instance.get_jobs(kind='run', phase=[-10000, 60000]) def test_get_comparisons_nominal(self): c = self.instance.get_comparisons() @@ -196,14 +370,14 @@ class TrickWorkflowTestCase(unittest.TestCase): self.assertEqual(c[0]._translate_status(), '\x1b[33mNOT RUN\x1b[0m') def test_add_comparison(self): - sim = self.instance.get_sim('SIM_alloc_test') + sim = self.instance.get_sim('SIM_demo_inputfile') run = sim.get_run('RUN_test/input.py') - run.add_comparison('share/trick/trickops/tests/baselinedata/log_a.csv', - 'share/trick/trickops/tests/testdata/log_a.csv') + run.add_comparison('share/trick/trickops/tests/testdata/log_a.csv', + 'share/trick/trickops/tests/baselinedata/log_a.csv') self.assertTrue(len(run.comparisons) == 1) def test_add_analysis_nominal(self): - sim = self.instance.get_sim('SIM_alloc_test') + sim = self.instance.get_sim('SIM_demo_inputfile') run = sim.get_run('RUN_test/input.py') run.add_analysis('echo analysis goes here') self.assertTrue( 'echo analysis goes here' in run.analysis._command) @@ -215,12 +389,13 @@ class TrickWorkflowTestCase(unittest.TestCase): self.assertTrue( 'echo overwriting analysis' in run.analysis._command) def test_run_init(self): - r = TrickWorkflow.Run(sim_dir='test/SIM_alloc_test', input='RUN_test/input.py --someflag', + r = TrickWorkflow.Run(sim_dir='test/SIM_alloc_test', input_file='RUN_test/input.py --someflag', binary='S_main_Linux_x86_64.exe') self.assertEqual(r.sim_dir, 'test/SIM_alloc_test') self.assertEqual(r.prerun_cmd, '') - self.assertTrue(r.input == 'RUN_test/input.py --someflag') + self.assertTrue(r.input_file == 'RUN_test/input.py --someflag') self.assertEqual(r.returns, 0) + self.assertEqual(r.phase, 0) self.assertTrue(r.valgrind_flags is None) self.assertEqual(r.log_dir, '/tmp/') self.assertEqual(r.just_input,'RUN_test/input.py') @@ -240,7 +415,7 @@ class TrickWorkflowTestCase(unittest.TestCase): self.assertTrue(c.error is None) def test_run_compare_pass(self): - r = TrickWorkflow.Run(sim_dir='test/SIM_alloc_test', input='RUN_test/input.py --someflag', + r = TrickWorkflow.Run(sim_dir='test/SIM_alloc_test', input_file='RUN_test/input.py --someflag', binary='S_main_Linux_x86_64.exe') # Use same data to get a pass test_data = 'share/trick/trickops/tests/baselinedata/log_a.csv' @@ -249,7 +424,7 @@ class TrickWorkflowTestCase(unittest.TestCase): self.assertEqual(r.compare(), 0) def test_run_compare_fail(self): - r = TrickWorkflow.Run(sim_dir='test/SIM_alloc_test', input='RUN_test/input.py --someflag', + r = TrickWorkflow.Run(sim_dir='test/SIM_alloc_test', input_file='RUN_test/input.py --someflag', binary='S_main_Linux_x86_64.exe') # Use same data to get a pass test_data = 'share/trick/trickops/tests/testdata/log_a.csv' @@ -272,9 +447,8 @@ class TrickWorkflowTestCase(unittest.TestCase): os.makedirs(just_RUN_root, exist_ok=True) Path(os.path.join(SIM_root,run)).touch() yml_content=textwrap.dedent(""" - globals: - parallel_safety: """ + parallel_safety + """ SIM_fake: + parallel_safety: """ + parallel_safety + """ path: """ + SIM_root_rel + """ runs: """) @@ -333,3 +507,165 @@ class TrickWorkflowTestCase(unittest.TestCase): self.assertEqual(len(self.instance.get_sims()), 1) self.assertEqual(len(self.instance.get_sim('SIM_fake').get_runs()), 1) self.teardown_deep_directory_structure() + + def test_sim_init_default_args(self): + s = TrickWorkflow.Sim(name='mySim', sim_dir='sims/SIM_fake') + self.assertEqual(s.name, 'mySim') + self.assertEqual(s.sim_dir, 'sims/SIM_fake') + self.assertEqual(s.description, None) + self.assertEqual(s.build_cmd, 'trick-CP') + self.assertEqual(s.cpus, 3) + self.assertEqual(s.size, 2200000) + self.assertEqual(s.labels, []) + self.assertEqual(s.phase, 0) + self.assertEqual(s.log_dir, '/tmp') + self.assertEqual(s.build_job, None) + self.assertEqual(s.runs, []) + self.assertEqual(s.valgrind_runs, []) + self.assertTrue(isinstance(s.printer, ColorStr)) + job = s.get_build_job() + self.assertEqual(s.build_job, job ) # First get stores it locally + self.assertTrue('cd sims/SIM_fake && export MAKEFLAGS=-j3 && trick-CP' in job._command ) + runs = s.get_run_jobs() + self.assertEqual(runs, []) # No runs have been added + + def test_sim_init_all_args(self): + s = TrickWorkflow.Sim(name='yourSim', sim_dir='sims/SIM_foo', description='desc', + labels=['label1', 'label2'], prebuild_cmd='source env/env.sh; ', + build_cmd='trick-CP --flag', cpus=2, size=10000, phase=2, log_dir='~/logs') + self.assertEqual(s.name, 'yourSim') + self.assertEqual(s.sim_dir, 'sims/SIM_foo') + self.assertEqual(s.description, 'desc') + self.assertEqual(s.build_cmd, 'trick-CP --flag') + self.assertEqual(s.cpus, 2) + self.assertEqual(s.size, 10000) + self.assertEqual(s.labels, ['label1', 'label2']) + self.assertEqual(s.phase, 2) + self.assertEqual(s.log_dir, '~/logs') + job = s.get_build_job() + self.assertTrue('cd sims/SIM_foo && export MAKEFLAGS=-j2 && trick-CP --flag' in job._command ) + self.assertTrue('source env/env.sh;' in job._command ) + #import pdb; pdb.set_trace() + + def test_phase_getters_setters(self): + s = TrickWorkflow.Sim(name='mySim', sim_dir='sims/SIM_fake') + s.set_phase(99) # OK + self.assertEqual(s.get_phase(), 99) + s.set_phase(999) # OK + self.assertEqual(s.get_phase(), 999) + s.set_phase(TrickWorkflow.allowed_phase_range['max']) + self.assertEqual(s.get_phase(), TrickWorkflow.allowed_phase_range['max']) # OK boundary + with self.assertRaises(RuntimeError): + s.set_phase(TrickWorkflow.allowed_phase_range['max']+1) # Over boundary + with self.assertRaises(RuntimeError): + s.set_phase(TrickWorkflow.allowed_phase_range['min']-1) # Under boundary + r = TrickWorkflow.Run(sim_dir='test/SIM_alloc_test', input_file='RUN_test/input.py', + binary='S_main_Linux_x86_64.exe') + r.set_phase(99) # OK + self.assertEqual(r.get_phase(), 99) + r.set_phase(999) # OK + self.assertEqual(r.get_phase(), 999) + with self.assertRaises(RuntimeError): + r.set_phase(TrickWorkflow.allowed_phase_range['max']+1) # Over boundary + with self.assertRaises(RuntimeError): + r.set_phase(TrickWorkflow.allowed_phase_range['min']-1) # Under boundary + + def test_run__find_range_string(self): + r = TrickWorkflow.Run(sim_dir='test/SIM_alloc_test', input_file='RUN_test/input.py', + binary='S_main_Linux_x86_64.exe') + self.assertEqual(TrickWorkflow._find_range_string("[01-09]"), "[01-09]") + self.assertEqual(TrickWorkflow._find_range_string("SET_foo/RUN_[0-9]/input.py"), "[0-9]") + self.assertEqual(TrickWorkflow._find_range_string("SET_foo/RUN_[01-09]/input.py"), "[01-09]") + self.assertEqual(TrickWorkflow._find_range_string("SET_foo/RUN_[001-999]/input.py"), "[001-999]") + self.assertEqual(TrickWorkflow._find_range_string("SET_foo/RUN_[0000-9999]/input.py"), "[0000-9999]") + self.assertEqual(TrickWorkflow._find_range_string("SET_[01-09]/RUN_hi/input.py"), "[01-09]" ) + self.assertEqual(TrickWorkflow._find_range_string("[01-09]/RUN_hello/input.py"), "[01-09]") + self.assertEqual(TrickWorkflow._find_range_string("SET_foo/RUN_bar/input.py"), None) + self.assertEqual(TrickWorkflow._find_range_string("SET_foo/RUN_[001-009/input.py"), None) + self.assertEqual(TrickWorkflow._find_range_string("SET_foo/RUN_(01-09)/input.py"), None) + with self.assertRaises(RuntimeError): + TrickWorkflow._find_range_string("SET_[00-03]/RUN_[01-09]/input.py") + + def test_run__get_range_list(self): + r = TrickWorkflow.Run(sim_dir='test/SIM_alloc_test', input_file='RUN_test/input.py', + binary='S_main_Linux_x86_64.exe') + myRange = r._get_range_list("[01-09]") + self.assertEqual(myRange, ["01", "02", "03", "04", "05", "06", "07", "08", "09"]) + myRange = r._get_range_list("[001-009]") + self.assertEqual(myRange, ["001", "002", "003", "004", "005", "006", "007", "008", "009"]) + with self.assertRaises(RuntimeError): + myRange = r._get_range_list("[009-001]") # Min not less than max + with self.assertRaises(RuntimeError): + myRange = r._get_range_list("[09-001]") # Inconsistent leading zeros + with self.assertRaises(RuntimeError): + myRange = r._get_range_list("[abc-009]") # Min Can't be converted to int + with self.assertRaises(RuntimeError): + myRange = r._get_range_list("[01-zy]") # Max Can't be converted to int + with self.assertRaises(RuntimeError): + myRange = r._get_range_list("01-04") # Wrong syntax + with self.assertRaises(RuntimeError): + myRange = r._get_range_list("[01-04") # Wrong syntax + with self.assertRaises(RuntimeError): + myRange = r._get_range_list("[01/04") # Wrong syntax + myRange = r._get_range_list("[[01-04]]") # Extra brackets are ignored + self.assertEqual(myRange, ["01", "02", "03", "04"]) + + def test_run__multiply(self): + r = TrickWorkflow.Run(sim_dir='test/SIM_alloc_test', input_file='RUN_[00-05]/input.py', + binary='S_main_Linux_x86_64.exe') + runs = r.multiply() + self.assertEqual(len(runs), 6) # Expect 6 copies + + r = TrickWorkflow.Run(sim_dir='test/SIM_alloc_test', input_file='RUN_[0000-9999]/input.py', + binary='S_main_Linux_x86_64.exe') + runs = r.multiply() + self.assertEqual(len(runs), 10000) # Expect 10000 copies + + r = TrickWorkflow.Run(sim_dir='test/SIM_alloc_test', input_file='RUN_[05-01]/input.py', + binary='S_main_Linux_x86_64.exe') + with self.assertRaises(RuntimeError): + runs = r.multiply() # Reverse order in syntax in input_file + + r = TrickWorkflow.Run(sim_dir='test/SIM_alloc_test', input_file='SET_[01-02]/RUN_[05-01]/input.py', + binary='S_main_Linux_x86_64.exe') + with self.assertRaises(RuntimeError): + runs = r.multiply() # Invalid syntax, more than one pattern found + + def test_run__multiply_with_double_pattern_comparisons(self): + r = TrickWorkflow.Run(sim_dir='test/SIM_alloc_test', input_file='RUN_[00-05]/input.py', + binary='S_main_Linux_x86_64.exe') + # Add a fake comparison with correct [min-max] notation + r.add_comparison('testdata/RUN_[00-05]/log_a.csv', 'baselinedata/RUN_[00-05]/log_a.csv') + runs = r.multiply() + # Ensure the run's comparisons patterns are replaced with the expected value + self.assertEqual(len(runs), 6) # Expect 6 copies + self.assertEqual(runs[0].comparisons[0].test_data, 'testdata/RUN_00/log_a.csv') + self.assertEqual(runs[0].comparisons[0].baseline_data, 'baselinedata/RUN_00/log_a.csv') + self.assertEqual(runs[5].comparisons[0].test_data, 'testdata/RUN_05/log_a.csv') + self.assertEqual(runs[5].comparisons[0].baseline_data, 'baselinedata/RUN_05/log_a.csv') + + def test_run__multiply_with_single_pattern_comparisons(self): + r = TrickWorkflow.Run(sim_dir='test/SIM_alloc_test', input_file='RUN_[00-05]/input.py', + binary='S_main_Linux_x86_64.exe') + # Compare many to one + r.add_comparison('testdata/RUN_[00-05]/log_common.csv', 'baselinedata/RUN_common/log_common.csv') + r.add_comparison('testdata/RUN_[00-05]/log_a.csv', 'baselinedata/RUN_[00-05]/log_a.csv') + runs = r.multiply() + # Ensure the run's comparisons patterns are replaced with the expected value + self.assertEqual(len(runs), 6) # Expect 6 copies + self.assertEqual(runs[0].comparisons[0].test_data, 'testdata/RUN_00/log_common.csv') + self.assertEqual(runs[0].comparisons[0].baseline_data, 'baselinedata/RUN_common/log_common.csv') + self.assertEqual(runs[0].comparisons[1].test_data, 'testdata/RUN_00/log_a.csv') + self.assertEqual(runs[0].comparisons[1].baseline_data, 'baselinedata/RUN_00/log_a.csv') + self.assertEqual(runs[5].comparisons[0].test_data, 'testdata/RUN_05/log_common.csv') + self.assertEqual(runs[5].comparisons[0].baseline_data, 'baselinedata/RUN_common/log_common.csv') + self.assertEqual(runs[5].comparisons[1].test_data, 'testdata/RUN_05/log_a.csv') + self.assertEqual(runs[5].comparisons[1].baseline_data, 'baselinedata/RUN_05/log_a.csv') + + def test_run__multiply_with_mismatched_patterns(self): + r = TrickWorkflow.Run(sim_dir='test/SIM_alloc_test', input_file='RUN_[00-05]/input.py', + binary='S_main_Linux_x86_64.exe') + # Compare many to one + r.add_comparison('testdata/RUN_[00-06]/log_common.csv', 'baselinedata/RUN_common/log_common.csv') + with self.assertRaises(RuntimeError): + runs = r.multiply() diff --git a/share/trick/trickops/tests/ut_TrickWorkflowYamlVerifier.py b/share/trick/trickops/tests/ut_TrickWorkflowYamlVerifier.py new file mode 100644 index 00000000..29145da2 --- /dev/null +++ b/share/trick/trickops/tests/ut_TrickWorkflowYamlVerifier.py @@ -0,0 +1,73 @@ +import os, sys +import unittest +import pdb +from testconfig import this_trick, tests_dir +from TrickWorkflowYamlVerifier import * + +def suite(): + """Create test suite from TrickWorkflowTestCase unit test class and return""" + return unittest.TestLoader().loadTestsFromTestCase(TrickWorkflowYamlVerifierTestCase) + +class TrickWorkflowYamlVerifierTestCase(unittest.TestCase): + + def setUp(self): + pass + + def tearDown(self): + pass + + def _verify(self, config_file): + """ + Given a config_file, create a TrickWorkflowYamlVerifier, assert expectations, + and return the instance for further examination + """ + twyv = TrickWorkflowYamlVerifier(config_file=config_file) + twyv.verify() + sim_keys = [sim for sim in twyv.config.keys() if sim.startswith('SIM')] + self.assertTrue('globals' in twyv.config) + self.assertTrue('env' in twyv.config['globals']) + for sk in sim_keys: + self.assertTrue( isinstance( twyv.config[sk]['name' ], str)) + self.assertTrue( isinstance( twyv.config[sk]['binary' ], str)) + self.assertTrue( isinstance( twyv.config[sk]['build_args'], str) or + twyv.config[sk]['build_args'] == None ) + self.assertTrue( isinstance( twyv.config[sk]['name' ], str)) + self.assertTrue( isinstance( twyv.config[sk]['parallel_safety'], str)) + self.assertTrue( twyv.config[sk]['description' ] is None) + self.assertTrue( isinstance( twyv.config[sk]['runs'], dict)) + for run in twyv.config[sk]['runs']: + self.assertTrue( isinstance( twyv.config[sk]['runs'][run]['input'], str)) + self.assertTrue( isinstance( twyv.config[sk]['runs'][run]['returns'], int)) + self.assertTrue( isinstance( twyv.config[sk]['runs'][run]['valgrind'], str) or + (twyv.config[sk]['runs'][run]['valgrind'] == None) ) + self.assertTrue( isinstance( twyv.config[sk]['runs'][run]['analyze'], str) or + (twyv.config[sk]['runs'][run]['analyze'] == None) ) + self.assertTrue( isinstance( twyv.config[sk]['runs'][run]['phase'], int)) + self.assertTrue( isinstance( twyv.config[sk]['runs'][run]['compare'], list)) + self.assertTrue( isinstance( twyv.config[sk]['phase' ], int)) + self.assertTrue( isinstance( twyv.config[sk]['path' ], str)) + return twyv + + def test_type_errors_in_config(self): + twyv = self._verify(config_file=os.path.join(tests_dir,"type_errors.yml")) + self.assertEqual(len(twyv.get_parsing_errors()), 21) + + def test_no_SIM_dict_keys_in_config(self): + twyv = TrickWorkflowYamlVerifier(config_file=os.path.join(tests_dir,"errors_fatal2.yml")) + with self.assertRaises(RuntimeError): + twyv.verify() + self.assertEqual(len(twyv.get_parsing_errors()), 1) + + def test_empty_config(self): + twyv = TrickWorkflowYamlVerifier(config_file=os.path.join(tests_dir,"empty.yml")) + with self.assertRaises(RuntimeError): + twyv.verify() + self.assertEqual(len(twyv.get_parsing_errors()), 1) + + def test_nominal_config(self): + twyv = self._verify(config_file=os.path.join(tests_dir,"trick_sims.yml")) + sim_keys = [sim for sim in twyv.config.keys() if sim.startswith('SIM')] + non_sim_keys = [entry for entry in twyv.config.keys() if not entry.startswith('SIM')] + self.assertEqual(len(non_sim_keys), 2) # Expect 2 non-SIM.*: dict key + self.assertEqual(len(sim_keys), 56) # Expect 56 SIM.*: dict keys + self.assertEqual(len(twyv.get_parsing_errors()), 0) diff --git a/test/.gitignore b/test/.gitignore index 38e6eddd..f3d79c4a 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -6,7 +6,7 @@ send_hs varserver_log log_* chkpnt_* -MONTE_RUN_* +MONTE_* .S_library* .icg_no_found CP_out @@ -25,3 +25,5 @@ trick.zip jitlib build S_sie.json +*.ckpnt +MonteCarlo_Meta_data_output diff --git a/test/Makefile b/test/Makefile new file mode 100644 index 00000000..f60dd273 --- /dev/null +++ b/test/Makefile @@ -0,0 +1,16 @@ +TRICK_HOME := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))..) +export TRICK_HOST_CPU := $(shell $(TRICK_HOME)/bin/trick-gte TRICK_HOST_CPU) +include ${TRICK_HOME}/share/trick/makefiles/Makefile.common + + +SIM_DIRECTORIES = $(wildcard SIM_*) +UNIT_TEST_RESULTS = $(addprefix $(TRICK_HOME)/trick_test/, $(addsuffix .xml, $(SIM_DIRECTORIES))) + + +clean: + rm -f $(UNIT_TEST_RESULTS) + - for i in $(SIM_DIRECTORIES) ; do \ + if [ -f "$$i/"[Mm]"akefile" ] ; then \ + $(MAKE) -C $$i spotless ; \ + fi \ + done diff --git a/test/SIM_checkpoint_data_recording/Modified_data/anotherfoo.dr b/test/SIM_checkpoint_data_recording/Modified_data/anotherfoo.dr new file mode 100644 index 00000000..736798b3 --- /dev/null +++ b/test/SIM_checkpoint_data_recording/Modified_data/anotherfoo.dr @@ -0,0 +1,18 @@ +global DR_GROUP_ID +global drg +try: + if DR_GROUP_ID >= 0: + DR_GROUP_ID += 1 +except NameError: + DR_GROUP_ID = 0 + drg = [] + +drg.append(trick.DRAscii("anotherfoo")) +drg[DR_GROUP_ID].set_freq(trick.DR_Always) +drg[DR_GROUP_ID].set_cycle(0.1) +drg[DR_GROUP_ID].set_single_prec_only(False) +drg[DR_GROUP_ID].add_variable("testSimObject.name") +drg[DR_GROUP_ID].add_variable("testSimObject.my_foo.b") +drg[DR_GROUP_ID].set_max_file_size(1 * 1073741824) # multiply converts GiB to B --Dr. Dre +trick.add_data_record_group(drg[DR_GROUP_ID], trick.DR_Buffer) +drg[DR_GROUP_ID].enable() diff --git a/test/SIM_checkpoint_data_recording/Modified_data/foo.dr b/test/SIM_checkpoint_data_recording/Modified_data/foo.dr new file mode 100644 index 00000000..82066e73 --- /dev/null +++ b/test/SIM_checkpoint_data_recording/Modified_data/foo.dr @@ -0,0 +1,18 @@ +global DR_GROUP_ID +global drg +try: + if DR_GROUP_ID >= 0: + DR_GROUP_ID += 1 +except NameError: + DR_GROUP_ID = 0 + drg = [] + +drg.append(trick.DRAscii("foo")) +drg[DR_GROUP_ID].set_freq(trick.DR_Always) +drg[DR_GROUP_ID].set_cycle(0.1) +drg[DR_GROUP_ID].set_single_prec_only(False) +drg[DR_GROUP_ID].add_variable("testSimObject.my_foo.a") +drg[DR_GROUP_ID].add_variable("testSimObject.my_foo.b") +drg[DR_GROUP_ID].set_max_file_size(1 * 1073741824) # multiply converts GiB to B --Dr. Dre +trick.add_data_record_group(drg[DR_GROUP_ID], trick.DR_Buffer) +drg[DR_GROUP_ID].enable() diff --git a/test/SIM_checkpoint_data_recording/Modified_data/foo2.dr b/test/SIM_checkpoint_data_recording/Modified_data/foo2.dr new file mode 100644 index 00000000..d4b7ef1b --- /dev/null +++ b/test/SIM_checkpoint_data_recording/Modified_data/foo2.dr @@ -0,0 +1,17 @@ +global DR_GROUP_ID +global drg +try: + if DR_GROUP_ID >= 0: + DR_GROUP_ID += 1 +except NameError: + DR_GROUP_ID = 0 + drg = [] + +drg.append(trick.DRAscii("foo2")) +drg[DR_GROUP_ID].set_freq(trick.DR_Always) +drg[DR_GROUP_ID].set_cycle(1) +drg[DR_GROUP_ID].set_single_prec_only(False) +drg[DR_GROUP_ID].add_variable("testSimObject.my_foo.b") +drg[DR_GROUP_ID].set_max_file_size(1 * 1073741824) # multiply converts GiB to B --Dr. Dre +trick.add_data_record_group(drg[DR_GROUP_ID], trick.DR_Buffer) +drg[DR_GROUP_ID].enable() diff --git a/test/SIM_checkpoint_data_recording/Modified_data/realtime.py b/test/SIM_checkpoint_data_recording/Modified_data/realtime.py new file mode 100644 index 00000000..6d5cdd63 --- /dev/null +++ b/test/SIM_checkpoint_data_recording/Modified_data/realtime.py @@ -0,0 +1,10 @@ +trick.frame_log_on() +trick.real_time_enable() +trick.exec_set_software_frame(0.1) +trick.itimer_enable() + +trick.exec_set_enable_freeze(True) +# trick.exec_set_freeze_command(True) + +# simControlPanel = trick.SimControlPanel() +# trick.add_external_application(simControlPanel) diff --git a/test/SIM_checkpoint_data_recording/README.md b/test/SIM_checkpoint_data_recording/README.md new file mode 100644 index 00000000..c5e7629d --- /dev/null +++ b/test/SIM_checkpoint_data_recording/README.md @@ -0,0 +1,39 @@ +This test suite runs different data recording and checkpoint combinations in an effort to document and test expected behaviors. + +RUN_test1 +Checkpoint dumped at t=5 with data recording +Run started without data recording +Checkpoint loaded at t=5 +Expected: log_foo.csv contains data recorded from t=5+ + +RUN_test2 +Checkpoint dumped at t=5 without data recording +Run started with data recording +Checkpoint loaded at t=5 +Expected: log_foo.csv does not exist + +RUN_test3 +Checkpoint dumped at t=5 with data recording +Run started with data recording +Checkpoint loaded at t=5 +Expected: log_foo.csv contains data recorded from t=5+ + +RUN_test4 +Checkpoint dumped at t=2 with data recording +Run started with data recording +Checkpoint loaded at t=5 +Expected: log_foo.csv contains data recorded from t=2+ + +RUN_test5 +Checkpoint dumped at t=7 with data recording +Run started with data recording +Checkpoint loaded at t=5 +Expected: log_foo.csv contains data recorded from t=7+ + +RUN_test6 +Checkpoint dumped at t=7 with data recording group foo2 +Run started with data recording group 1 +Checkpoint loaded at t=5 +Expected: ? + +Overall: expectation is that what loads in from the checkpoint should take precedence and overwrite the file of the same name. \ No newline at end of file diff --git a/test/SIM_checkpoint_data_recording/RUN_test/dump.py b/test/SIM_checkpoint_data_recording/RUN_test/dump.py new file mode 100644 index 00000000..749d69d4 --- /dev/null +++ b/test/SIM_checkpoint_data_recording/RUN_test/dump.py @@ -0,0 +1,14 @@ +import trick +from trick.unit_test import * + +# This was just here for convenience to dump the checkpoints. + +def main(): + exec(open("Modified_data/foo.dr").read()) + + trick.checkpoint(5.0) + + trick.stop(10.0) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/test/SIM_checkpoint_data_recording/RUN_test/input.py b/test/SIM_checkpoint_data_recording/RUN_test/input.py new file mode 100644 index 00000000..47aaa019 --- /dev/null +++ b/test/SIM_checkpoint_data_recording/RUN_test/input.py @@ -0,0 +1,10 @@ +def main(): + + exec(open("Modified_data/realtime.py").read()) + + trick.exec_set_software_frame(0.10) + trick.exec_set_freeze_frame(0.10) + trick.stop(5.0) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/test/SIM_checkpoint_data_recording/RUN_test1/dump.py b/test/SIM_checkpoint_data_recording/RUN_test1/dump.py new file mode 100644 index 00000000..749d69d4 --- /dev/null +++ b/test/SIM_checkpoint_data_recording/RUN_test1/dump.py @@ -0,0 +1,14 @@ +import trick +from trick.unit_test import * + +# This was just here for convenience to dump the checkpoints. + +def main(): + exec(open("Modified_data/foo.dr").read()) + + trick.checkpoint(5.0) + + trick.stop(10.0) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/test/SIM_checkpoint_data_recording/RUN_test1/ref_log_foo.csv b/test/SIM_checkpoint_data_recording/RUN_test1/ref_log_foo.csv new file mode 100644 index 00000000..37c97556 --- /dev/null +++ b/test/SIM_checkpoint_data_recording/RUN_test1/ref_log_foo.csv @@ -0,0 +1,51 @@ +sys.exec.out.time {s},testSimObject.my_foo.a {1},testSimObject.my_foo.b {1} + 5.1,6,12 + 5.2,6,12 + 5.3,6,12 + 5.4,6,12 + 5.5,6,12 + 5.6,6,12 + 5.7,6,12 + 5.8,6,12 + 5.9,6,12 + 6,7,14 + 6.1,7,14 + 6.2,7,14 + 6.3,7,14 + 6.4,7,14 + 6.5,7,14 + 6.6,7,14 + 6.7,7,14 + 6.8,7,14 + 6.9,7,14 + 7,8,16 + 7.1,8,16 + 7.2,8,16 + 7.3,8,16 + 7.4,8,16 + 7.5,8,16 + 7.6,8,16 + 7.7,8,16 + 7.8,8,16 + 7.9,8,16 + 8,9,18 + 8.1,9,18 + 8.199999999999999,9,18 + 8.300000000000001,9,18 + 8.4,9,18 + 8.5,9,18 + 8.6,9,18 + 8.699999999999999,9,18 + 8.800000000000001,9,18 + 8.9,9,18 + 9,10,20 + 9.1,10,20 + 9.199999999999999,10,20 + 9.300000000000001,10,20 + 9.4,10,20 + 9.5,10,20 + 9.6,10,20 + 9.699999999999999,10,20 + 9.800000000000001,10,20 + 9.9,10,20 + 10,11,22 diff --git a/test/SIM_checkpoint_data_recording/RUN_test1/unit_test.py b/test/SIM_checkpoint_data_recording/RUN_test1/unit_test.py new file mode 100644 index 00000000..d5b6008c --- /dev/null +++ b/test/SIM_checkpoint_data_recording/RUN_test1/unit_test.py @@ -0,0 +1,9 @@ +import trick + + +def main(): + trick.add_read(5.0, 'trick.load_checkpoint("RUN_test1/chkpnt_5.000000")') # This checkpoint has data recording + trick.stop(10.0) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/test/SIM_checkpoint_data_recording/RUN_test2/check_log.sh b/test/SIM_checkpoint_data_recording/RUN_test2/check_log.sh new file mode 100755 index 00000000..d0e3cf2b --- /dev/null +++ b/test/SIM_checkpoint_data_recording/RUN_test2/check_log.sh @@ -0,0 +1,9 @@ +FILE=log_foo.csv +if test -f "$FILE"; then + echo "$FILE exists." + exit 1 +else + # Expect the file not to exist. + echo "$FILE does not exist." + exit 0 +fi \ No newline at end of file diff --git a/test/SIM_checkpoint_data_recording/RUN_test2/dump.py b/test/SIM_checkpoint_data_recording/RUN_test2/dump.py new file mode 100644 index 00000000..d05fc532 --- /dev/null +++ b/test/SIM_checkpoint_data_recording/RUN_test2/dump.py @@ -0,0 +1,12 @@ +import trick +from trick.unit_test import * + +# This was just here for convenience to dump the checkpoints. + +def main(): + trick.checkpoint(5.0) + + trick.stop(10.0) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/test/SIM_checkpoint_data_recording/RUN_test2/unit_test.py b/test/SIM_checkpoint_data_recording/RUN_test2/unit_test.py new file mode 100644 index 00000000..8ba141c1 --- /dev/null +++ b/test/SIM_checkpoint_data_recording/RUN_test2/unit_test.py @@ -0,0 +1,11 @@ +import trick + +def main(): + exec(open("Modified_data/foo.dr").read()) + + trick.add_read(5.0, 'trick.load_checkpoint("RUN_test2/chkpnt_5.000000")') # this checkpoint does not contain data recording + + trick.stop(10.0) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/test/SIM_checkpoint_data_recording/RUN_test3/dump.py b/test/SIM_checkpoint_data_recording/RUN_test3/dump.py new file mode 100644 index 00000000..749d69d4 --- /dev/null +++ b/test/SIM_checkpoint_data_recording/RUN_test3/dump.py @@ -0,0 +1,14 @@ +import trick +from trick.unit_test import * + +# This was just here for convenience to dump the checkpoints. + +def main(): + exec(open("Modified_data/foo.dr").read()) + + trick.checkpoint(5.0) + + trick.stop(10.0) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/test/SIM_checkpoint_data_recording/RUN_test3/ref_log_foo.csv b/test/SIM_checkpoint_data_recording/RUN_test3/ref_log_foo.csv new file mode 100644 index 00000000..37c97556 --- /dev/null +++ b/test/SIM_checkpoint_data_recording/RUN_test3/ref_log_foo.csv @@ -0,0 +1,51 @@ +sys.exec.out.time {s},testSimObject.my_foo.a {1},testSimObject.my_foo.b {1} + 5.1,6,12 + 5.2,6,12 + 5.3,6,12 + 5.4,6,12 + 5.5,6,12 + 5.6,6,12 + 5.7,6,12 + 5.8,6,12 + 5.9,6,12 + 6,7,14 + 6.1,7,14 + 6.2,7,14 + 6.3,7,14 + 6.4,7,14 + 6.5,7,14 + 6.6,7,14 + 6.7,7,14 + 6.8,7,14 + 6.9,7,14 + 7,8,16 + 7.1,8,16 + 7.2,8,16 + 7.3,8,16 + 7.4,8,16 + 7.5,8,16 + 7.6,8,16 + 7.7,8,16 + 7.8,8,16 + 7.9,8,16 + 8,9,18 + 8.1,9,18 + 8.199999999999999,9,18 + 8.300000000000001,9,18 + 8.4,9,18 + 8.5,9,18 + 8.6,9,18 + 8.699999999999999,9,18 + 8.800000000000001,9,18 + 8.9,9,18 + 9,10,20 + 9.1,10,20 + 9.199999999999999,10,20 + 9.300000000000001,10,20 + 9.4,10,20 + 9.5,10,20 + 9.6,10,20 + 9.699999999999999,10,20 + 9.800000000000001,10,20 + 9.9,10,20 + 10,11,22 diff --git a/test/SIM_checkpoint_data_recording/RUN_test3/unit_test.py b/test/SIM_checkpoint_data_recording/RUN_test3/unit_test.py new file mode 100644 index 00000000..c91faf0e --- /dev/null +++ b/test/SIM_checkpoint_data_recording/RUN_test3/unit_test.py @@ -0,0 +1,12 @@ +import trick + +def main(): + + exec(open("Modified_data/foo.dr").read()) + + trick.add_read(5.0, 'trick.load_checkpoint("RUN_test3/chkpnt_5.000000")') # contains data recording + + trick.stop(10.0) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/test/SIM_checkpoint_data_recording/RUN_test4/dump.py b/test/SIM_checkpoint_data_recording/RUN_test4/dump.py new file mode 100644 index 00000000..00df66fd --- /dev/null +++ b/test/SIM_checkpoint_data_recording/RUN_test4/dump.py @@ -0,0 +1,14 @@ +import trick +from trick.unit_test import * + +# This was just here for convenience to dump the checkpoints. + +def main(): + exec(open("Modified_data/foo.dr").read()) + + trick.checkpoint(2.0) + + trick.stop(10.0) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/test/SIM_checkpoint_data_recording/RUN_test4/ref_log_foo.csv b/test/SIM_checkpoint_data_recording/RUN_test4/ref_log_foo.csv new file mode 100644 index 00000000..13327df8 --- /dev/null +++ b/test/SIM_checkpoint_data_recording/RUN_test4/ref_log_foo.csv @@ -0,0 +1,81 @@ +sys.exec.out.time {s},testSimObject.my_foo.a {1},testSimObject.my_foo.b {1} + 2.1,3,6 + 2.2,3,6 + 2.3,3,6 + 2.4,3,6 + 2.5,3,6 + 2.6,3,6 + 2.7,3,6 + 2.8,3,6 + 2.9,3,6 + 3,4,8 + 3.1,4,8 + 3.2,4,8 + 3.3,4,8 + 3.4,4,8 + 3.5,4,8 + 3.6,4,8 + 3.7,4,8 + 3.8,4,8 + 3.9,4,8 + 4,5,10 + 4.1,5,10 + 4.2,5,10 + 4.3,5,10 + 4.4,5,10 + 4.5,5,10 + 4.6,5,10 + 4.7,5,10 + 4.8,5,10 + 4.9,5,10 + 5,6,12 + 5.1,6,12 + 5.2,6,12 + 5.3,6,12 + 5.4,6,12 + 5.5,6,12 + 5.6,6,12 + 5.7,6,12 + 5.8,6,12 + 5.9,6,12 + 6,7,14 + 6.1,7,14 + 6.2,7,14 + 6.3,7,14 + 6.4,7,14 + 6.5,7,14 + 6.6,7,14 + 6.7,7,14 + 6.8,7,14 + 6.9,7,14 + 7,8,16 + 7.1,8,16 + 7.2,8,16 + 7.3,8,16 + 7.4,8,16 + 7.5,8,16 + 7.6,8,16 + 7.7,8,16 + 7.8,8,16 + 7.9,8,16 + 8,9,18 + 8.1,9,18 + 8.199999999999999,9,18 + 8.300000000000001,9,18 + 8.4,9,18 + 8.5,9,18 + 8.6,9,18 + 8.699999999999999,9,18 + 8.800000000000001,9,18 + 8.9,9,18 + 9,10,20 + 9.1,10,20 + 9.199999999999999,10,20 + 9.300000000000001,10,20 + 9.4,10,20 + 9.5,10,20 + 9.6,10,20 + 9.699999999999999,10,20 + 9.800000000000001,10,20 + 9.9,10,20 + 10,11,22 diff --git a/test/SIM_checkpoint_data_recording/RUN_test4/unit_test.py b/test/SIM_checkpoint_data_recording/RUN_test4/unit_test.py new file mode 100644 index 00000000..f07baf1d --- /dev/null +++ b/test/SIM_checkpoint_data_recording/RUN_test4/unit_test.py @@ -0,0 +1,12 @@ +import trick + +def main(): + + exec(open("Modified_data/foo.dr").read()) + + trick.add_read(5.0, 'trick.load_checkpoint("RUN_test4/chkpnt_2.000000")') # contains data recording, starts at t=2 + + trick.stop(10.0) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/test/SIM_checkpoint_data_recording/RUN_test5/dump.py b/test/SIM_checkpoint_data_recording/RUN_test5/dump.py new file mode 100644 index 00000000..565a891b --- /dev/null +++ b/test/SIM_checkpoint_data_recording/RUN_test5/dump.py @@ -0,0 +1,14 @@ +import trick +from trick.unit_test import * + +# This was just here for convenience to dump the checkpoints. + +def main(): + exec(open("Modified_data/foo.dr").read()) + + trick.checkpoint(7.0) + + trick.stop(10.0) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/test/SIM_checkpoint_data_recording/RUN_test5/ref_log_foo.csv b/test/SIM_checkpoint_data_recording/RUN_test5/ref_log_foo.csv new file mode 100644 index 00000000..306de1b4 --- /dev/null +++ b/test/SIM_checkpoint_data_recording/RUN_test5/ref_log_foo.csv @@ -0,0 +1,31 @@ +sys.exec.out.time {s},testSimObject.my_foo.a {1},testSimObject.my_foo.b {1} + 7.1,8,16 + 7.2,8,16 + 7.3,8,16 + 7.4,8,16 + 7.5,8,16 + 7.6,8,16 + 7.7,8,16 + 7.8,8,16 + 7.9,8,16 + 8,9,18 + 8.1,9,18 + 8.199999999999999,9,18 + 8.300000000000001,9,18 + 8.4,9,18 + 8.5,9,18 + 8.6,9,18 + 8.699999999999999,9,18 + 8.800000000000001,9,18 + 8.9,9,18 + 9,10,20 + 9.1,10,20 + 9.199999999999999,10,20 + 9.300000000000001,10,20 + 9.4,10,20 + 9.5,10,20 + 9.6,10,20 + 9.699999999999999,10,20 + 9.800000000000001,10,20 + 9.9,10,20 + 10,11,22 diff --git a/test/SIM_checkpoint_data_recording/RUN_test5/unit_test.py b/test/SIM_checkpoint_data_recording/RUN_test5/unit_test.py new file mode 100644 index 00000000..649cb370 --- /dev/null +++ b/test/SIM_checkpoint_data_recording/RUN_test5/unit_test.py @@ -0,0 +1,12 @@ +import trick + +def main(): + + exec(open("Modified_data/foo.dr").read()) + + trick.add_read(5.0, 'trick.load_checkpoint("RUN_test5/chkpnt_7.000000")') # contains data recording, starts at t=7 + + trick.stop(10.0) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/test/SIM_checkpoint_data_recording/RUN_test6/dump.py b/test/SIM_checkpoint_data_recording/RUN_test6/dump.py new file mode 100644 index 00000000..7b7db62a --- /dev/null +++ b/test/SIM_checkpoint_data_recording/RUN_test6/dump.py @@ -0,0 +1,14 @@ +import trick +from trick.unit_test import * + +# This was just here for convenience to dump the checkpoints. + +def main(): + exec(open("Modified_data/foo2.dr").read()) + + trick.checkpoint(7.0) + + trick.stop(10.0) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/test/SIM_checkpoint_data_recording/RUN_test6/ref_log_foo2.csv b/test/SIM_checkpoint_data_recording/RUN_test6/ref_log_foo2.csv new file mode 100644 index 00000000..f7b15a2b --- /dev/null +++ b/test/SIM_checkpoint_data_recording/RUN_test6/ref_log_foo2.csv @@ -0,0 +1,4 @@ +sys.exec.out.time {s},testSimObject.my_foo.b {1} + 8,18 + 9,20 + 10,22 diff --git a/test/SIM_checkpoint_data_recording/RUN_test6/unit_test.py b/test/SIM_checkpoint_data_recording/RUN_test6/unit_test.py new file mode 100644 index 00000000..f5b5f315 --- /dev/null +++ b/test/SIM_checkpoint_data_recording/RUN_test6/unit_test.py @@ -0,0 +1,13 @@ +import trick + +def main(): + + exec(open("Modified_data/foo.dr").read()) + + # trick.checkpoint(7.0) + trick.add_read(5.0, 'trick.load_checkpoint("RUN_test6/chkpnt_7.000000")') # contains data recording, starts at t=7 + + trick.stop(10.0) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/test/SIM_checkpoint_data_recording/S_define b/test/SIM_checkpoint_data_recording/S_define new file mode 100644 index 00000000..6ec5bc45 --- /dev/null +++ b/test/SIM_checkpoint_data_recording/S_define @@ -0,0 +1,16 @@ +#include "sim_objects/default_trick_sys.sm" +##include "Foo.hh" + +class TestSimObject : public Trick::SimObject { + + public: + Foo my_foo; + + TestSimObject () { + ("initialization") my_foo.init (); + (1.0, "scheduled") my_foo.increment () ; + } + +}; + +TestSimObject testSimObject; diff --git a/test/SIM_checkpoint_data_recording/S_overrides.mk b/test/SIM_checkpoint_data_recording/S_overrides.mk new file mode 100644 index 00000000..bce1c170 --- /dev/null +++ b/test/SIM_checkpoint_data_recording/S_overrides.mk @@ -0,0 +1,7 @@ +TRICK_CFLAGS += -I./models +TRICK_CXXFLAGS += -I./models + +clean_logs: + rm -f RUN_test*/log_foo* + +clean: clean_logs \ No newline at end of file diff --git a/test/SIM_checkpoint_data_recording/models/Foo.cpp b/test/SIM_checkpoint_data_recording/models/Foo.cpp new file mode 100644 index 00000000..53e0e3f8 --- /dev/null +++ b/test/SIM_checkpoint_data_recording/models/Foo.cpp @@ -0,0 +1 @@ +#include "Foo.hh" diff --git a/test/SIM_checkpoint_data_recording/models/Foo.hh b/test/SIM_checkpoint_data_recording/models/Foo.hh new file mode 100644 index 00000000..4bc7d023 --- /dev/null +++ b/test/SIM_checkpoint_data_recording/models/Foo.hh @@ -0,0 +1,16 @@ + +class Foo { + public: + int a; + int b; + + void init () { + a = 0; + b = 0; + } + + void increment () { + a++; + b+=2; + } +}; \ No newline at end of file diff --git a/test/SIM_earlyterm/RUN_test/input.py b/test/SIM_earlyterm/RUN_test/input.py new file mode 100644 index 00000000..242edf3f --- /dev/null +++ b/test/SIM_earlyterm/RUN_test/input.py @@ -0,0 +1 @@ +#Nothing diff --git a/test/SIM_earlyterm/S_define b/test/SIM_earlyterm/S_define new file mode 100644 index 00000000..79bcc0a7 --- /dev/null +++ b/test/SIM_earlyterm/S_define @@ -0,0 +1,31 @@ +/***************************************************************************** +PURPOSE: Provide test of simulation early termination. Ensures threads + come down appropriately for unit-test-like cases +PROGRAMMERS: + (((Dan Jordan) (NASA) (Jan 2023) (Deal with it))) +*****************************************************************************/ +#include "sim_objects/default_trick_sys.sm" +##include "trick/exec_proto.h" + +class EarlyTerminationSimObject : public Trick::SimObject +{ + public: + double x; + + EarlyTerminationSimObject() + : + x(0) + { + ("initialization") early_term(); + }; + + void early_term() { + std::string message = "Terminating with exit code 0"; + exec_terminate_with_return(0, "S_define", 24, message.c_str()); + } + private: + EarlyTerminationSimObject( const EarlyTerminationSimObject&); + EarlyTerminationSimObject & operator= ( const EarlyTerminationSimObject&); + +}; +EarlyTerminationSimObject test; diff --git a/test/SIM_events/RUN_test/unit_test_error1.py b/test/SIM_events/RUN_test/unit_test_error1.py new file mode 100644 index 00000000..c72fd8e8 --- /dev/null +++ b/test/SIM_events/RUN_test/unit_test_error1.py @@ -0,0 +1,7 @@ +trick.stop(1.0) + +# print(dir(trick)) +trick.terminate_on_event_parse_error(True) + +# Error in add read +trick.add_read(0.1, "a = b") \ No newline at end of file diff --git a/test/SIM_events/RUN_test/unit_test_error2.py b/test/SIM_events/RUN_test/unit_test_error2.py new file mode 100644 index 00000000..c7e7af3f --- /dev/null +++ b/test/SIM_events/RUN_test/unit_test_error2.py @@ -0,0 +1,12 @@ +trick.terminate_on_event_parse_error(True) + +# Error in condition +event1 = trick.new_event("event1") +event1.condition(0, "this is a syntax error") +event1.action(0, "print (\"event1\");") +event1.action(1, "event1.activate()") +event1.set_cycle(1.0) +event1.activate() +trick.add_event(event1) + +trick.stop(10) \ No newline at end of file diff --git a/test/SIM_events/RUN_test/unit_test_error3.py b/test/SIM_events/RUN_test/unit_test_error3.py new file mode 100644 index 00000000..65d3954c --- /dev/null +++ b/test/SIM_events/RUN_test/unit_test_error3.py @@ -0,0 +1,12 @@ +trick.terminate_on_event_parse_error(True) + +# Error in event action +event1 = trick.new_event("event1") +event1.condition(0, "True") +event1.action(0, "this is a syntax error") +event1.action(1, "event1.activate()") +event1.set_cycle(1.0) +event1.activate() +trick.add_event(event1) + +trick.stop(10) \ No newline at end of file diff --git a/test/SIM_exec_set_time_tic_value/RUN_test/unit_test.py b/test/SIM_exec_set_time_tic_value/RUN_test/unit_test.py new file mode 100644 index 00000000..04f1b809 --- /dev/null +++ b/test/SIM_exec_set_time_tic_value/RUN_test/unit_test.py @@ -0,0 +1,4 @@ + + +trick.stop(1.0); +trick.exec_set_time_tic_value(100000000) diff --git a/test/SIM_exec_set_time_tic_value/S_define b/test/SIM_exec_set_time_tic_value/S_define new file mode 100644 index 00000000..b0e10be0 --- /dev/null +++ b/test/SIM_exec_set_time_tic_value/S_define @@ -0,0 +1,26 @@ +/************************TRICK HEADER************************* +PURPOSE: + (Test that the time tic value can be changed and that + warnings about the resolution of the cycle are displayed + properly. Scheduled2 should produce a warning.) +LIBRARY DEPENDENCIES: +*************************************************************/ + +#include "sim_objects/default_trick_sys.sm" + +##include "ttvtest.h" + +class TTVTestSimObject : public Trick::SimObject { + + public: + TTVTest ttvtest; + + TTVTestSimObject() { + (0.0078125, "scheduled") trick_ret = ttvtest.scheduled(); + (0.000078125, "scheduled") ttvtest.scheduled2(); + (50, "scheduled") ttvtest.scheduled3(); + (100, "scheduled") ttvtest.scheduled4(); + } +}; + +TTVTestSimObject ttvtestSimObject; diff --git a/test/SIM_exec_set_time_tic_value/S_overrides.mk b/test/SIM_exec_set_time_tic_value/S_overrides.mk new file mode 100644 index 00000000..6ca9ea96 --- /dev/null +++ b/test/SIM_exec_set_time_tic_value/S_overrides.mk @@ -0,0 +1,3 @@ + +TRICK_CFLAGS += -I./models +TRICK_CXXFLAGS += -I./models diff --git a/test/SIM_exec_set_time_tic_value/models/ttvtest.cpp b/test/SIM_exec_set_time_tic_value/models/ttvtest.cpp new file mode 100644 index 00000000..cf516ba2 --- /dev/null +++ b/test/SIM_exec_set_time_tic_value/models/ttvtest.cpp @@ -0,0 +1,21 @@ +#include +#include "ttvtest.h" +int TTVTest::scheduled() { + //message_publish(MSG_NORMAL, "Hello World!\n"); + return 0; +} + +int TTVTest::scheduled2() { + //message_publish(MSG_NORMAL, "Hello World!\n"); + return 0; +} + +int TTVTest::scheduled3() { + //message_publish(MSG_NORMAL, "Hello World!\n"); + return 0; +} + +int TTVTest::scheduled4() { + //message_publish(MSG_NORMAL, "Hello World!\n"); + return 0; +} \ No newline at end of file diff --git a/test/SIM_exec_set_time_tic_value/models/ttvtest.h b/test/SIM_exec_set_time_tic_value/models/ttvtest.h new file mode 100644 index 00000000..92a10bdf --- /dev/null +++ b/test/SIM_exec_set_time_tic_value/models/ttvtest.h @@ -0,0 +1,15 @@ +/************************************************************************* +PURPOSE: (Starter class) +LIBRARY DEPENDENCY: + ( + (ttvtest.cpp) + ) +**************************************************************************/ + +class TTVTest { +public: + int scheduled(); + int scheduled2(); + int scheduled3(); + int scheduled4(); +}; \ No newline at end of file diff --git a/test/SIM_job_class_order/RUN_test/input.py b/test/SIM_job_class_order/RUN_test/input.py new file mode 100644 index 00000000..064838e8 --- /dev/null +++ b/test/SIM_job_class_order/RUN_test/input.py @@ -0,0 +1,3 @@ + + +trick.stop(10); diff --git a/test/SIM_job_class_order/S_define b/test/SIM_job_class_order/S_define new file mode 100644 index 00000000..cc11ace7 --- /dev/null +++ b/test/SIM_job_class_order/S_define @@ -0,0 +1,49 @@ +/************************TRICK HEADER************************* +PURPOSE: + () +LIBRARY DEPENDENCIES: +*************************************************************/ + +#include "sim_objects/default_trick_sys.sm" + +##include "starter.h" + +class StarterSimObject : public Trick::SimObject { + + public: + Starter starter; + + StarterSimObject() { + ("top_of_frame") starter.top (); + + (0.5, "scheduled") starter.sched (); + (0.5, "my_class") starter.custom (); + + ("derivative") starter.deriv(); + ("integration") trick_ret = starter.integ() ; + + ("automatic") starter.automatic(); + ("automatic_last") starter.automatic_last(); + + + ("end_of_frame") starter.end (); + + ("shutdown") starter.test_calls (); + + } +}; + +StarterSimObject starterSimObject; + +job_class_order { + my_class , + integ_loop, + scheduled +}; + +IntegLoop dyn_integloop(0.1) starterSimObject; + +void create_connections() { + dyn_integloop.getIntegrator(Runge_Kutta_4, 2); +} + diff --git a/test/SIM_job_class_order/S_overrides.mk b/test/SIM_job_class_order/S_overrides.mk new file mode 100644 index 00000000..016cadcd --- /dev/null +++ b/test/SIM_job_class_order/S_overrides.mk @@ -0,0 +1,3 @@ + +TRICK_CFLAGS += -I./models +TRICK_CXXFLAGS += -I./models -std=c++11 diff --git a/test/SIM_job_class_order/models/starter.cpp b/test/SIM_job_class_order/models/starter.cpp new file mode 100644 index 00000000..ff7b51cb --- /dev/null +++ b/test/SIM_job_class_order/models/starter.cpp @@ -0,0 +1,76 @@ +#include "starter.h" +#include +#include "trick/exec_proto.hh" +#include "trick/exec_proto.h" + +void Starter::sched () { + sched_calls++; +} + +void Starter::custom () { + custom_calls++; +} + +void Starter::top () { + top_calls++; +} + +void Starter::automatic () { + + Trick::JobData * thisJob = exec_get_curr_job() ; + thisJob->set_next_call_time(exec_get_time_tics() + exec_get_time_tic_value()); + automatic_calls++; +} + +void Starter::automatic_last () { + + Trick::JobData * thisJob = exec_get_curr_job() ; + thisJob->set_next_call_time(exec_get_time_tics() + exec_get_time_tic_value()); + + automatic_last_calls++; +} + +void Starter::end() { + end_calls++; +} + +void Starter::deriv() { + deriv_calls++; +} + +int Starter::integ() { + integ_calls++; + + return 0; +} + +void Starter::test_calls() { + if (top_calls == 0) { + exec_terminate_with_return(1, __FILE__, __LINE__, "top_of_frame job never called"); + } + + if (custom_calls == 0) { + exec_terminate_with_return(1, __FILE__, __LINE__, "custom job never called"); + } + + if (sched_calls == 0) { + exec_terminate_with_return(1, __FILE__, __LINE__, "scheduled job never called"); + } + + if (automatic_calls == 0) { + exec_terminate_with_return(1, __FILE__, __LINE__, "automatic job never called"); + } + + if (automatic_last_calls == 0) { + exec_terminate_with_return(1, __FILE__, __LINE__, "automatic_last job never called"); + } + + if (deriv_calls == 0) { + exec_terminate_with_return(1, __FILE__, __LINE__, "derivative job never called"); + } + + if (integ_calls == 0) { + exec_terminate_with_return(1, __FILE__, __LINE__, "integration job never called"); + } + +} diff --git a/test/SIM_job_class_order/models/starter.h b/test/SIM_job_class_order/models/starter.h new file mode 100644 index 00000000..82ebcdb5 --- /dev/null +++ b/test/SIM_job_class_order/models/starter.h @@ -0,0 +1,33 @@ +/************************************************************************* +PURPOSE: (Starter class) +LIBRARY DEPENDENCY: + ( + (starter.cpp) + ) +**************************************************************************/ + +#include + +class Starter { +public: + Starter() {} + + void sched(); + void custom(); + void top(); + void end(); + void automatic(); + void automatic_last(); + void deriv(); + int integ(); + void test_calls(); + + int sched_calls = 0; + int custom_calls = 0; + int top_calls = 0; + int automatic_calls = 0; + int automatic_last_calls = 0; + int deriv_calls = 0; + int integ_calls = 0; + int end_calls = 0; +}; diff --git a/test/SIM_mc_generation/FAIL_IO_error/input.py b/test/SIM_mc_generation/FAIL_IO_error/input.py new file mode 100644 index 00000000..62982da8 --- /dev/null +++ b/test/SIM_mc_generation/FAIL_IO_error/input.py @@ -0,0 +1,18 @@ +monte_carlo.mc_master.activate("FAIL_IO_error") + +print('*********************************************************************') +print('this message is expected:') +print(' DIAGNOSTIC: Fatal Error I/O error') +print(' Unable to open file Modified_data/nonexistent_file.txt for reading.') +print(' Required for variable test.x_file_lookup[0].') +print('*********************************************************************') + + +# try to open a non-existant file +# code coverage for 'mc_variable_file.cc', lines 71-76. +mc_var = trick.MonteCarloVariableFile( "test.x_file_lookup[0]", + "Modified_data/nonexistent_file.txt", + 3) +monte_carlo.mc_master.add_variable(mc_var) + +trick.stop(1) diff --git a/test/SIM_mc_generation/FAIL_config_error/input.py b/test/SIM_mc_generation/FAIL_config_error/input.py new file mode 100644 index 00000000..32508da0 --- /dev/null +++ b/test/SIM_mc_generation/FAIL_config_error/input.py @@ -0,0 +1,19 @@ +monte_carlo.mc_master.activate("FAIL_config_error") + +print('************************************************************************************') +print('this message is expected:') +print(' DIAGNOSTIC: Fatal Error Configuration Error') +print(' In configuring the file for variable test.x_file_lookup[0], it was identified that') +print(' it was specified to draw data from column 4, but that the first') +print(' column was identified as having index 7.') +print('************************************************************************************') + + +# generate the error +mc_var = trick.MonteCarloVariableFile( "test.x_file_lookup[0]", + "Modified_data/datafile.txt", + 4, + 7) +monte_carlo.mc_master.add_variable(mc_var) + +trick.stop(1) diff --git a/test/SIM_mc_generation/FAIL_duplicate_variable/input.py b/test/SIM_mc_generation/FAIL_duplicate_variable/input.py new file mode 100644 index 00000000..97aabdaf --- /dev/null +++ b/test/SIM_mc_generation/FAIL_duplicate_variable/input.py @@ -0,0 +1,17 @@ +monte_carlo.mc_master.activate("FAIL_duplicate_variable") + +print('************************************************************') +print('this message is expected:') +print(' DIAGNOSTIC: Fatal Error Duplicated variable.') +print(' Attempted to add two settings for variable test.x_uniform.') +print(' Terminating to allow resolution of which setting to use.') +print('************************************************************') + + +mc_var = trick.MonteCarloVariableRandomUniform( "test.x_uniform", 0, 10, 20) +monte_carlo.mc_master.add_variable(mc_var) +# Add the variable twice to trigger the "Duplicated variable" fail in +# MonteCarloMaster::add_variable +monte_carlo.mc_master.add_variable(mc_var) + +trick.stop(1) diff --git a/test/SIM_mc_generation/FAIL_illegal_config/input.py b/test/SIM_mc_generation/FAIL_illegal_config/input.py new file mode 100644 index 00000000..eb263cd6 --- /dev/null +++ b/test/SIM_mc_generation/FAIL_illegal_config/input.py @@ -0,0 +1,18 @@ +monte_carlo.mc_master.activate("FAIL_illegal_config") +monte_carlo.mc_master.set_num_runs(1) + +print('**********************************************************************************\n' + +'this message is expected:\n' + +' DIAGNOSTIC: Fatal Error Illegal configuration\n' + +'For variable test.x_normal the specified minimum allowable value (6) >= the specified maximum allowable value (3).\n' + +'One or both of the limits must be changed to generate a random value.\n' + +'**********************************************************************************') + + +mc_var = trick.MonteCarloVariableRandomNormal( "test.x_normal", 2, 10, 2) +# flip low and high values to generate the desired error +mc_var.truncate_low(6, trick.MonteCarloVariableRandomNormal.Absolute) +mc_var.truncate_high(3, trick.MonteCarloVariableRandomNormal.Absolute) +monte_carlo.mc_master.add_variable(mc_var) + +trick.stop(1) diff --git a/test/SIM_mc_generation/FAIL_invalid_config/input.py b/test/SIM_mc_generation/FAIL_invalid_config/input.py new file mode 100644 index 00000000..640e89f6 --- /dev/null +++ b/test/SIM_mc_generation/FAIL_invalid_config/input.py @@ -0,0 +1,24 @@ +monte_carlo.mc_master.activate("FAIL_invalid_config") + +print('******************************************************************************************') +print('this message is expected:') +print(' DIAGNOSTIC: Fatal Error Invalid configuration') +print(' Error in attempting to make test.x_file_lookup[1] be dependent on test.x_file_lookup[0].') +print(' test.x_file_lookup[1] cannot be marked as dependent when it has dependencies of its own.') +print(' The dependency hierarchy can only be one level deep.') +print('******************************************************************************************') + + +mc_var = trick.MonteCarloVariableFile( "test.x_file_lookup[0]", + "Modified_data/datafile.txt", + 3) +monte_carlo.mc_master.add_variable(mc_var) + +mc_var2 = trick.MonteCarloVariableFile( "test.x_file_lookup[1]", + "Modified_data/datafile.txt", + 3) +# the next command is the source of the error! +mc_var2.register_dependent(mc_var) +monte_carlo.mc_master.add_variable(mc_var2) + +trick.stop(1) diff --git a/test/SIM_mc_generation/FAIL_invalid_data_file/input.py b/test/SIM_mc_generation/FAIL_invalid_data_file/input.py new file mode 100644 index 00000000..db137118 --- /dev/null +++ b/test/SIM_mc_generation/FAIL_invalid_data_file/input.py @@ -0,0 +1,17 @@ +monte_carlo.mc_master.activate("FAIL_invalid_data_file") + +print('*****************************************************************************') +print('this message is expected:') +print(' DIAGNOSTIC: Fatal Error Invalid data file') +print(' Data file Modified_data/empty_file.txt contains no recognized lines of data') +print(' Required for variable test.x_file_lookup[0].') +print('*****************************************************************************') + + +# try to open an empty file +mc_var = trick.MonteCarloVariableFile( "test.x_file_lookup[0]", + "Modified_data/empty_file.txt", + 3) +monte_carlo.mc_master.add_variable(mc_var) + +trick.stop(1) diff --git a/test/SIM_mc_generation/FAIL_malformed_data_file/input.py b/test/SIM_mc_generation/FAIL_malformed_data_file/input.py new file mode 100644 index 00000000..ade700c9 --- /dev/null +++ b/test/SIM_mc_generation/FAIL_malformed_data_file/input.py @@ -0,0 +1,20 @@ +monte_carlo.mc_master.activate("FAIL_malformed_data_file") +monte_carlo.mc_master.set_num_runs(1) + +print('**************************************************************************************************') +print('this message is expected:') +print(' DIAGNOSTIC: Fatal Error Malformed data file') +print(' Data file for variable test.x_file_lookup[0] includes this line:') +print(' 0 1 2 3 4') +print(' Which has only 5 values.') +print(' Variable test.x_file_lookup[0] uses the value from position 9, which does not exist in this line') +print('**************************************************************************************************') + + +# generate the error +mc_var = trick.MonteCarloVariableFile( "test.x_file_lookup[0]", + "Modified_data/datafile.txt", + 9) +monte_carlo.mc_master.add_variable(mc_var) + +trick.stop(1) diff --git a/test/SIM_mc_generation/IO_FAIL/input.py b/test/SIM_mc_generation/IO_FAIL/input.py new file mode 100644 index 00000000..cae646a6 --- /dev/null +++ b/test/SIM_mc_generation/IO_FAIL/input.py @@ -0,0 +1,27 @@ +import os, shutil + +# remove write permission to the 'MONTE_RUN' directory +os.chmod("MONTE_IO_FAIL", 0o555) + +monte_carlo.mc_master.activate("IO_FAIL") +monte_carlo.mc_master.generate_meta_data = True +monte_carlo.mc_master.set_num_runs(1) + +print('*********************************************************************************') +print('these messages are expected:') +print(' Error I/O error') +print(' Unable to open the variable summary files for writing.') +print(' Dispersion summary will not be generated.') +print('') +print(' DIAGNOSTIC: Fatal Error I/O error') +print(' Unable to open file MONTE_FAIL_IO_error2/RUN_0/monte_input.py for writing.') +print('*********************************************************************************') + +# this simulation attempts to create good data but with the target +# directory write-protected, it can't generate the required input files. +mc_var = trick.MonteCarloVariableFile( "test.x_file_lookup[0]", + "Modified_data/datafile.txt", + 3) +monte_carlo.mc_master.add_variable(mc_var) + +trick.stop(1) diff --git a/test/SIM_mc_generation/IO_RUN_ERROR1/input.py b/test/SIM_mc_generation/IO_RUN_ERROR1/input.py new file mode 100644 index 00000000..fc44a2dd --- /dev/null +++ b/test/SIM_mc_generation/IO_RUN_ERROR1/input.py @@ -0,0 +1,32 @@ +import os + +# remove write permission to the 'MONTE_RUN' directory +os.chmod("MONTE_IO_RUN_ERROR1", 0o555) + +monte_carlo.mc_master.activate("IO_RUN_ERROR1") +monte_carlo.mc_master.generate_meta_data = True + +print('***********************************************************************************') +print('these messages are expected:') +print(' Error I/O error') +print(' Unable to open the variable summary files for writing.') +print(' Dispersion summary will not be generated.') +print('') +print(' Warning I/O error') +print(' Unable to open file MONTE_ERROR_IO_error/MonteCarlo_Meta_data_output for writing.') +print(' Aborting generation of meta-data.') +print('***********************************************************************************') + +# this simulation attempts to create good data but with the target +# directory write-protected, it can't generate the (optional) summary files. +# NOTE - we avoid the terminal failure of not being able to generate the input +# files by having num_runs = 0, so none are attempted. +mc_var = trick.MonteCarloVariableFile( "test.x_file_lookup[0]", + "Modified_data/datafile.txt", + 3) +monte_carlo.mc_master.add_variable(mc_var) + +trick.add_read(0,""" +os.chmod('MONTE_RUN_ERROR_IO_error', 0o755) +""") +trick.stop(1) diff --git a/test/SIM_mc_generation/IO_RUN_ERROR2/input.py b/test/SIM_mc_generation/IO_RUN_ERROR2/input.py new file mode 100644 index 00000000..5ceb02df --- /dev/null +++ b/test/SIM_mc_generation/IO_RUN_ERROR2/input.py @@ -0,0 +1,25 @@ +import os + +# remove write permission to the 'RUN_0' directory +os.chmod("MONTE_IO_RUN_ERROR2/RUN_0", 0o500) + +monte_carlo.mc_master.activate("IO_RUN_ERROR2") +monte_carlo.mc_master.generate_meta_data = True +monte_carlo.mc_master.set_num_runs(1) + +print('***********************************************************************************') +print('this message is expected:\n'+ + ' Error Output failure\n'+ + ' Failed to record summary data for run 0.') +print('***********************************************************************************') + +# this simulation attempts to create good data but with the target +# directory write-protected, it can't generate the (optional) summary files. +# NOTE - we avoid the terminal failure of not being able to generate the input +# files by having num_runs = 0, so none are attempted. +mc_var = trick.MonteCarloVariableFile( "test.x_file_lookup[0]", + "Modified_data/datafile.txt", + 3) +monte_carlo.mc_master.add_variable(mc_var) + +trick.stop(1) diff --git a/test/SIM_mc_generation/Log_data/log_nominal.py b/test/SIM_mc_generation/Log_data/log_nominal.py new file mode 100755 index 00000000..1cdcb2ef --- /dev/null +++ b/test/SIM_mc_generation/Log_data/log_nominal.py @@ -0,0 +1,20 @@ +dr_group = trick.sim_services.DRAscii("test_data") +dr_group.set_cycle(1) +dr_group.freq = trick.sim_services.DR_Always +trick.add_data_record_group(dr_group, trick.DR_Buffer) + +dr_group.add_variable( "test.x_uniform") +dr_group.add_variable( "test.x_normal") +for ii in range(5): + dr_group.add_variable( "test.x_normal_trunc[%d]" %ii) +dr_group.add_variable( "test.x_normal_length") +dr_group.add_variable( "test.x_integer") +dr_group.add_variable( "test.x_line_command") +for ii in range(3): + dr_group.add_variable( "test.x_file_command[%d]" %ii) +dr_group.add_variable( "test.x_boolean") +dr_group.add_variable( "test.x_file_lookup") +dr_group.add_variable( "test.x_fixed_value_double") +dr_group.add_variable( "test.x_fixed_value_int") +dr_group.add_variable( "test.x_semi_fixed_value") +dr_group.add_variable( "test.x_sdefine_routine_called") diff --git a/test/SIM_mc_generation/Log_data/log_variable_file.py b/test/SIM_mc_generation/Log_data/log_variable_file.py new file mode 100644 index 00000000..fc6d940a --- /dev/null +++ b/test/SIM_mc_generation/Log_data/log_variable_file.py @@ -0,0 +1,6 @@ +dr_group = trick.sim_services.DRAscii("test_data") +dr_group.set_cycle(1) +dr_group.freq = trick.sim_services.DR_Always +trick.add_data_record_group(dr_group, trick.DR_Buffer) + +dr_group.add_variable( "test.x_sdefine_routine_called") diff --git a/test/SIM_mc_generation/MCGTrickOps/.gitignore b/test/SIM_mc_generation/MCGTrickOps/.gitignore new file mode 100644 index 00000000..2211df63 --- /dev/null +++ b/test/SIM_mc_generation/MCGTrickOps/.gitignore @@ -0,0 +1 @@ +*.txt diff --git a/test/SIM_mc_generation/MCGTrickOps/MCGWorkFlow.py b/test/SIM_mc_generation/MCGTrickOps/MCGWorkFlow.py new file mode 100755 index 00000000..c5845fe4 --- /dev/null +++ b/test/SIM_mc_generation/MCGTrickOps/MCGWorkFlow.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +import os, sys + +sys.path.append(os.path.abspath("../../../share/trick/trickops/")) + +from TrickWorkflow import * +class ExampleWorkflow(TrickWorkflow): + def __init__( self, quiet, trick_top_level=os.path.abspath("../../../")): + # Base Class initialize, this creates internal management structures + if not(os.path.isdir(os.path.abspath("./MCGTrickOpsLog"))): + logDirectory = "MCGTrickOpsLog" + logDirectoryParent = os.path.abspath(".") + logPath = os.path.join(logDirectoryParent, logDirectory) + os.mkdir(logPath) + TrickWorkflow.__init__(self, project_top_level=trick_top_level, + log_dir=os.path.join(trick_top_level,'test/SIM_mc_generation/MCGTrickOps/MCGTrickOpsLog'), + trick_dir=trick_top_level, + config_file="test/SIM_mc_generation/MCGTrickOps/MCGenerationTest.yml", + cpus=3, quiet=quiet) + def run( self): + build_jobs = self.get_jobs(kind='build') + run_jobs = self.get_jobs(kind='run') + builds_status = self.execute_jobs(build_jobs, max_concurrent=3, header='Executing all sim builds.') + runs_status = self.execute_jobs(run_jobs, max_concurrent=1, header='Executing all sim runs.') + c = self.compare() + self.report() # Print Verbose report + self.status_summary() # Print a Succinct summary + return (builds_status or runs_status or self.config_errors or c) +if __name__ == "__main__": + ExampleWorkflow(quiet=True).run() diff --git a/test/SIM_mc_generation/MCGTrickOps/MCGenerationTest.yml b/test/SIM_mc_generation/MCGTrickOps/MCGenerationTest.yml new file mode 100644 index 00000000..f6b6aabf --- /dev/null +++ b/test/SIM_mc_generation/MCGTrickOps/MCGenerationTest.yml @@ -0,0 +1,256 @@ +SIM_mc_generation: + path: test/SIM_mc_generation + runs: + RUN_nominal/input_a.py: + MONTE_RUN_nominal/RUN_000/monte_input_a.py: + MONTE_RUN_nominal/RUN_001/monte_input_a.py: + RUN_random_normal_truncate_abs/input.py: + MONTE_RUN_random_normal_truncate_abs/RUN_0/monte_input.py: + MONTE_RUN_random_normal_truncate_abs/RUN_1/monte_input.py: + MONTE_RUN_random_normal_truncate_abs/RUN_2/monte_input.py: + MONTE_RUN_random_normal_truncate_abs/RUN_3/monte_input.py: + MONTE_RUN_random_normal_truncate_abs/RUN_4/monte_input.py: + MONTE_RUN_random_normal_truncate_abs/RUN_5/monte_input.py: + MONTE_RUN_random_normal_truncate_abs/RUN_6/monte_input.py: + MONTE_RUN_random_normal_truncate_abs/RUN_7/monte_input.py: + MONTE_RUN_random_normal_truncate_abs/RUN_8/monte_input.py: + MONTE_RUN_random_normal_truncate_abs/RUN_9/monte_input.py: + RUN_random_normal_truncate_rel/input.py: + MONTE_RUN_random_normal_truncate_rel/RUN_0/monte_input.py: + MONTE_RUN_random_normal_truncate_rel/RUN_1/monte_input.py: + MONTE_RUN_random_normal_truncate_rel/RUN_2/monte_input.py: + MONTE_RUN_random_normal_truncate_rel/RUN_3/monte_input.py: + MONTE_RUN_random_normal_truncate_rel/RUN_4/monte_input.py: + MONTE_RUN_random_normal_truncate_rel/RUN_5/monte_input.py: + MONTE_RUN_random_normal_truncate_rel/RUN_6/monte_input.py: + MONTE_RUN_random_normal_truncate_rel/RUN_7/monte_input.py: + MONTE_RUN_random_normal_truncate_rel/RUN_8/monte_input.py: + MONTE_RUN_random_normal_truncate_rel/RUN_9/monte_input.py: + RUN_random_normal_truncate_sd/input.py: + MONTE_RUN_random_normal_truncate_sd/RUN_0/monte_input.py: + MONTE_RUN_random_normal_truncate_sd/RUN_1/monte_input.py: + MONTE_RUN_random_normal_truncate_sd/RUN_2/monte_input.py: + MONTE_RUN_random_normal_truncate_sd/RUN_3/monte_input.py: + MONTE_RUN_random_normal_truncate_sd/RUN_4/monte_input.py: + MONTE_RUN_random_normal_truncate_sd/RUN_5/monte_input.py: + MONTE_RUN_random_normal_truncate_sd/RUN_6/monte_input.py: + MONTE_RUN_random_normal_truncate_sd/RUN_7/monte_input.py: + MONTE_RUN_random_normal_truncate_sd/RUN_8/monte_input.py: + MONTE_RUN_random_normal_truncate_sd/RUN_9/monte_input.py: + RUN_random_normal__untruncate/input.py: + MONTE_RUN_random_normal__untruncate/RUN_0/monte_input.py: + MONTE_RUN_random_normal__untruncate/RUN_1/monte_input.py: + MONTE_RUN_random_normal__untruncate/RUN_2/monte_input.py: + MONTE_RUN_random_normal__untruncate/RUN_3/monte_input.py: + MONTE_RUN_random_normal__untruncate/RUN_4/monte_input.py: + MONTE_RUN_random_normal__untruncate/RUN_5/monte_input.py: + MONTE_RUN_random_normal__untruncate/RUN_6/monte_input.py: + MONTE_RUN_random_normal__untruncate/RUN_7/monte_input.py: + MONTE_RUN_random_normal__untruncate/RUN_8/monte_input.py: + MONTE_RUN_random_normal__untruncate/RUN_9/monte_input.py: + RUN_random_normal_untruncated/input.py: + MONTE_RUN_random_normal_untruncated/RUN_0/monte_input.py: + MONTE_RUN_random_normal_untruncated/RUN_1/monte_input.py: + MONTE_RUN_random_normal_untruncated/RUN_2/monte_input.py: + MONTE_RUN_random_normal_untruncated/RUN_3/monte_input.py: + MONTE_RUN_random_normal_untruncated/RUN_4/monte_input.py: + MONTE_RUN_random_normal_untruncated/RUN_5/monte_input.py: + MONTE_RUN_random_normal_untruncated/RUN_6/monte_input.py: + MONTE_RUN_random_normal_untruncated/RUN_7/monte_input.py: + MONTE_RUN_random_normal_untruncated/RUN_8/monte_input.py: + MONTE_RUN_random_normal_untruncated/RUN_9/monte_input.py: + RUN_random_uniform/input.py: + MONTE_RUN_random_uniform/RUN_0/monte_input.py: + MONTE_RUN_random_uniform/RUN_1/monte_input.py: + MONTE_RUN_random_uniform/RUN_2/monte_input.py: + MONTE_RUN_random_uniform/RUN_3/monte_input.py: + MONTE_RUN_random_uniform/RUN_4/monte_input.py: + MONTE_RUN_random_uniform/RUN_5/monte_input.py: + MONTE_RUN_random_uniform/RUN_6/monte_input.py: + MONTE_RUN_random_uniform/RUN_7/monte_input.py: + MONTE_RUN_random_uniform/RUN_8/monte_input.py: + MONTE_RUN_random_uniform/RUN_9/monte_input.py: + RUN_ERROR_file_inconsistent_skip/input.py: + MONTE_RUN_ERROR_file_inconsistent_skip/RUN_0/monte_input.py: + RUN_ERROR_invalid_call/input.py: + MONTE_RUN_ERROR_invalid_call/RUN_0/monte_input.py: + RUN_ERROR_invalid_name/input.py: + MONTE_RUN_ERROR_invalid_name/RUN_0/monte_input.py: + RUN_ERROR_invalid_sequence/input.py: + MONTE_RUN_ERROR_invalid_sequence/RUN_0/monte_input.py: + RUN_ERROR_invalid_sequencing/input.py: + MONTE_RUN_ERROR_invalid_sequencing/RUN_0/monte_input.py: + RUN_ERROR_out_of_domain_error/input.py: + MONTE_RUN_ERROR_out_of_domain_error/RUN_0/monte_input.py: + RUN_ERROR_random_value_truncation/input.py: + MONTE_RUN_ERROR_random_value_truncation/RUN_0/monte_input.py: + MONTE_RUN_ERROR_random_value_truncation/RUN_1/monte_input.py: + RUN_generate_meta_data_early/input.py: + RUN_file_sequential/input.py: + MONTE_RUN_file_sequential/RUN_0/monte_input.py: + MONTE_RUN_file_sequential/RUN_1/monte_input.py: + MONTE_RUN_file_sequential/RUN_2/monte_input.py: + MONTE_RUN_file_sequential/RUN_3/monte_input.py: + MONTE_RUN_file_sequential/RUN_4/monte_input.py: + MONTE_RUN_file_sequential/RUN_5/monte_input.py: + MONTE_RUN_file_sequential/RUN_6/monte_input.py: + MONTE_RUN_file_sequential/RUN_7/monte_input.py: + MONTE_RUN_file_sequential/RUN_8/monte_input.py: + MONTE_RUN_file_sequential/RUN_9/monte_input.py: + RUN_file_skip/input.py: + MONTE_RUN_file_skip/RUN_0/monte_input.py: + MONTE_RUN_file_skip/RUN_1/monte_input.py: + MONTE_RUN_file_skip/RUN_2/monte_input.py: + MONTE_RUN_file_skip/RUN_3/monte_input.py: + MONTE_RUN_file_skip/RUN_4/monte_input.py: + MONTE_RUN_file_skip/RUN_5/monte_input.py: + MONTE_RUN_file_skip/RUN_6/monte_input.py: + MONTE_RUN_file_skip/RUN_7/monte_input.py: + MONTE_RUN_file_skip/RUN_8/monte_input.py: + MONTE_RUN_file_skip/RUN_9/monte_input.py: + RUN_file_skip2/input.py: + MONTE_RUN_file_skip2/RUN_0/monte_input.py: + MONTE_RUN_file_skip2/RUN_1/monte_input.py: + MONTE_RUN_file_skip2/RUN_2/monte_input.py: + MONTE_RUN_file_skip2/RUN_3/monte_input.py: + MONTE_RUN_file_skip2/RUN_4/monte_input.py: + RUN_remove_variable/input.py: + RUN_WARN_config_error/input.py: + MONTE_RUN_WARN_config_error/RUN_0/monte_input.py: + RUN_WARN_invalid_name/input.py: + MONTE_RUN_WARN_invalid_name/RUN_0/monte_input.py: + RUN_WARN_overconstrained_config/input.py: + MONTE_RUN_WARN_overconstrained_config/RUN_0/monte_input.py: + FAIL_config_error/input.py: + returns: 1 + FAIL_duplicate_variable/input.py: + returns: 1 + FAIL_illegal_config/input.py: + returns: 1 + FAIL_invalid_config/input.py: + returns: 1 + FAIL_invalid_data_file/input.py: + returns: 1 + FAIL_IO_error/input.py: + returns: 1 + FAIL_malformed_data_file/input.py: + returns: 1 + compare: + - test/SIM_mc_generation/verif_data/MonteCarlo_Meta_data_output vs. test/SIM_mc_generation/MonteCarlo_Meta_data_output + - test/SIM_mc_generation/verif_data/MONTE_RUN_nominal/RUN_000/monte_input_a.py vs. test/SIM_mc_generation/MONTE_RUN_nominal/RUN_000/monte_input_a.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_nominal/RUN_000/log_test_data.csv vs. test/SIM_mc_generation/MONTE_RUN_nominal/RUN_000/log_test_data.csv + - test/SIM_mc_generation/verif_data/MONTE_RUN_nominal/RUN_001/monte_input_a.py vs. test/SIM_mc_generation/MONTE_RUN_nominal/RUN_001/monte_input_a.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_nominal/RUN_001/log_test_data.csv vs. test/SIM_mc_generation/MONTE_RUN_nominal/RUN_001/log_test_data.csv + - test/SIM_mc_generation/verif_data/MONTE_RUN_nominal/monte_values_all_runs vs. test/SIM_mc_generation/MONTE_RUN_nominal/monte_values_all_runs + - test/SIM_mc_generation/verif_data/MONTE_RUN_nominal/monte_variables vs. test/SIM_mc_generation/MONTE_RUN_nominal/monte_variables + - test/SIM_mc_generation/verif_data/MONTE_RUN_nominal/MonteCarlo_Meta_data_output vs. test/SIM_mc_generation/MONTE_RUN_nominal/MonteCarlo_Meta_data_output + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_abs/monte_values_all_runs vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_abs/monte_values_all_runs + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_abs/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_abs/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_abs/RUN_1/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_abs/RUN_1/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_abs/RUN_2/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_abs/RUN_2/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_abs/RUN_3/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_abs/RUN_3/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_abs/RUN_4/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_abs/RUN_4/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_abs/RUN_5/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_abs/RUN_5/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_abs/RUN_6/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_abs/RUN_6/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_abs/RUN_7/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_abs/RUN_7/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_abs/RUN_8/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_abs/RUN_8/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_abs/RUN_9/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_abs/RUN_9/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_rel/monte_values_all_runs vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_rel/monte_values_all_runs + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_rel/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_rel/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_rel/RUN_1/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_rel/RUN_1/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_rel/RUN_2/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_rel/RUN_2/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_rel/RUN_3/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_rel/RUN_3/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_rel/RUN_4/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_rel/RUN_4/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_rel/RUN_5/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_rel/RUN_5/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_rel/RUN_6/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_rel/RUN_6/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_rel/RUN_7/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_rel/RUN_7/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_rel/RUN_8/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_rel/RUN_8/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_rel/RUN_9/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_rel/RUN_9/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_sd/monte_values_all_runs vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_sd/monte_values_all_runs + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_sd/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_sd/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_sd/RUN_1/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_sd/RUN_1/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_sd/RUN_2/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_sd/RUN_2/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_sd/RUN_3/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_sd/RUN_3/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_sd/RUN_4/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_sd/RUN_4/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_sd/RUN_5/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_sd/RUN_5/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_sd/RUN_6/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_sd/RUN_6/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_sd/RUN_7/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_sd/RUN_7/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_sd/RUN_8/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_sd/RUN_8/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_sd/RUN_9/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_sd/RUN_9/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal__untruncate/monte_values_all_runs vs. test/SIM_mc_generation/MONTE_RUN_random_normal__untruncate/monte_values_all_runs + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal__untruncate/monte_variables vs. test/SIM_mc_generation/MONTE_RUN_random_normal__untruncate/monte_variables + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal__untruncate/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal__untruncate/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal__untruncate/RUN_1/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal__untruncate/RUN_1/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal__untruncate/RUN_2/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal__untruncate/RUN_2/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal__untruncate/RUN_3/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal__untruncate/RUN_3/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal__untruncate/RUN_4/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal__untruncate/RUN_4/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal__untruncate/RUN_5/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal__untruncate/RUN_5/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal__untruncate/RUN_6/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal__untruncate/RUN_6/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal__untruncate/RUN_7/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal__untruncate/RUN_7/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal__untruncate/RUN_8/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal__untruncate/RUN_8/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal__untruncate/RUN_9/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal__untruncate/RUN_9/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_untruncated/monte_values_all_runs vs. test/SIM_mc_generation/MONTE_RUN_random_normal_untruncated/monte_values_all_runs + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_untruncated/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_untruncated/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_untruncated/RUN_1/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_untruncated/RUN_1/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_untruncated/RUN_2/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_untruncated/RUN_2/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_untruncated/RUN_3/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_untruncated/RUN_3/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_untruncated/RUN_4/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_untruncated/RUN_4/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_untruncated/RUN_5/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_untruncated/RUN_5/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_untruncated/RUN_6/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_untruncated/RUN_6/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_untruncated/RUN_7/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_untruncated/RUN_7/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_untruncated/RUN_8/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_untruncated/RUN_8/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_untruncated/RUN_9/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_untruncated/RUN_9/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_uniform/monte_values_all_runs vs. test/SIM_mc_generation/MONTE_RUN_random_uniform/monte_values_all_runs + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_uniform/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_uniform/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_uniform/RUN_1/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_uniform/RUN_1/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_uniform/RUN_2/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_uniform/RUN_2/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_uniform/RUN_3/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_uniform/RUN_3/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_uniform/RUN_4/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_uniform/RUN_4/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_uniform/RUN_5/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_uniform/RUN_5/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_uniform/RUN_6/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_uniform/RUN_6/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_uniform/RUN_7/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_uniform/RUN_7/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_uniform/RUN_8/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_uniform/RUN_8/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_uniform/RUN_9/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_uniform/RUN_9/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_ERROR_file_inconsistent_skip/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_ERROR_file_inconsistent_skip/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_ERROR_invalid_call/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_ERROR_invalid_call/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_ERROR_invalid_name/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_ERROR_invalid_name/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_ERROR_invalid_sequence/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_ERROR_invalid_sequence/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_ERROR_invalid_sequencing/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_ERROR_invalid_sequencing/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_ERROR_out_of_domain_error/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_ERROR_out_of_domain_error/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_ERROR_random_value_truncation/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_ERROR_random_value_truncation/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_ERROR_random_value_truncation/RUN_1/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_ERROR_random_value_truncation/RUN_1/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_generate_meta_data_early/monte_values_all_runs vs. test/SIM_mc_generation/MONTE_RUN_generate_meta_data_early/monte_values_all_runs + - test/SIM_mc_generation/verif_data/MONTE_RUN_generate_meta_data_early/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_generate_meta_data_early/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/monte_values_all_runs vs. test/SIM_mc_generation/MONTE_RUN_file_sequential/monte_values_all_runs + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_sequential/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_1/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_sequential/RUN_1/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_2/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_sequential/RUN_2/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_3/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_sequential/RUN_3/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_4/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_sequential/RUN_4/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_5/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_sequential/RUN_5/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_6/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_sequential/RUN_6/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_7/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_sequential/RUN_7/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_8/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_sequential/RUN_8/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_9/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_sequential/RUN_9/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_skip/monte_values_all_runs vs. test/SIM_mc_generation/MONTE_RUN_file_skip/monte_values_all_runs + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_skip/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_skip/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_skip/RUN_1/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_skip/RUN_1/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_skip/RUN_2/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_skip/RUN_2/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_skip/RUN_3/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_skip/RUN_3/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_skip/RUN_4/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_skip/RUN_4/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_skip/RUN_5/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_skip/RUN_5/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_skip/RUN_6/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_skip/RUN_6/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_skip/RUN_7/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_skip/RUN_7/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_skip/RUN_8/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_skip/RUN_8/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_skip/RUN_9/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_skip/RUN_9/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_skip2/monte_values_all_runs vs. test/SIM_mc_generation/MONTE_RUN_file_skip2/monte_values_all_runs + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_skip2/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_skip2/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_skip2/RUN_1/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_skip2/RUN_1/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_skip2/RUN_2/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_skip2/RUN_2/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_skip2/RUN_3/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_skip2/RUN_3/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_skip2/RUN_4/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_skip2/RUN_4/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_remove_variable/RUN_both_variables/monte_variables vs. test/SIM_mc_generation/MONTE_RUN_remove_variable/RUN_both_variables/monte_variables + - test/SIM_mc_generation/verif_data/MONTE_RUN_remove_variable/RUN_one_variable/monte_variables vs. test/SIM_mc_generation/MONTE_RUN_remove_variable/RUN_one_variable/monte_variables + - test/SIM_mc_generation/verif_data/MONTE_RUN_WARN_config_error/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_WARN_config_error/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_WARN_invalid_name/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_WARN_invalid_name/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_WARN_overconstrained_config/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_WARN_overconstrained_config/RUN_0/monte_input.py diff --git a/test/SIM_mc_generation/MCGTrickOps/MCGenerationTestNoGenerate.yml b/test/SIM_mc_generation/MCGTrickOps/MCGenerationTestNoGenerate.yml new file mode 100644 index 00000000..4de55deb --- /dev/null +++ b/test/SIM_mc_generation/MCGTrickOps/MCGenerationTestNoGenerate.yml @@ -0,0 +1,156 @@ +SIM_mc_generation: + path: test/SIM_mc_generation + runs: + RUN_nominal/input_a.py: + RUN_random_normal_truncate_abs/input.py: + RUN_random_normal_truncate_rel/input.py: + RUN_random_normal_truncate_sd/input.py: + RUN_random_normal__untruncate/input.py: + RUN_random_normal_untruncated/input.py: + RUN_random_uniform/input.py: + RUN_ERROR_file_inconsistent_skip/input.py: + RUN_ERROR_invalid_call/input.py: + RUN_ERROR_invalid_name/input.py: + RUN_ERROR_invalid_sequence/input.py: + RUN_ERROR_invalid_sequencing/input.py: + RUN_ERROR_out_of_domain_error/input.py: + RUN_ERROR_random_value_truncation/input.py: + RUN_generate_meta_data_early/input.py: + RUN_file_sequential/input.py: + RUN_file_skip/input.py: + RUN_file_skip2/input.py: + RUN_remove_variable/input.py: + RUN_WARN_config_error/input.py: + RUN_WARN_invalid_name/input.py: + RUN_WARN_overconstrained_config/input.py: + FAIL_config_error/input.py: + returns: 1 + FAIL_duplicate_variable/input.py: + returns: 1 + FAIL_illegal_config/input.py: + returns: 1 + FAIL_invalid_config/input.py: + returns: 1 + FAIL_invalid_data_file/input.py: + returns: 1 + FAIL_IO_error/input.py: + returns: 1 + FAIL_malformed_data_file/input.py: + returns: 1 + compare: + - test/SIM_mc_generation/verif_data/MonteCarlo_Meta_data_output vs. test/SIM_mc_generation/MonteCarlo_Meta_data_output + - test/SIM_mc_generation/verif_data/MONTE_RUN_nominal/RUN_000/monte_input_a.py vs. test/SIM_mc_generation/MONTE_RUN_nominal/RUN_000/monte_input_a.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_nominal/RUN_001/monte_input_a.py vs. test/SIM_mc_generation/MONTE_RUN_nominal/RUN_001/monte_input_a.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_nominal/monte_values_all_runs vs. test/SIM_mc_generation/MONTE_RUN_nominal/monte_values_all_runs + - test/SIM_mc_generation/verif_data/MONTE_RUN_nominal/monte_variables vs. test/SIM_mc_generation/MONTE_RUN_nominal/monte_variables + - test/SIM_mc_generation/verif_data/MONTE_RUN_nominal/MonteCarlo_Meta_data_output vs. test/SIM_mc_generation/MONTE_RUN_nominal/MonteCarlo_Meta_data_output + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_abs/monte_values_all_runs vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_abs/monte_values_all_runs + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_abs/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_abs/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_abs/RUN_1/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_abs/RUN_1/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_abs/RUN_2/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_abs/RUN_2/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_abs/RUN_3/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_abs/RUN_3/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_abs/RUN_4/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_abs/RUN_4/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_abs/RUN_5/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_abs/RUN_5/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_abs/RUN_6/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_abs/RUN_6/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_abs/RUN_7/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_abs/RUN_7/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_abs/RUN_8/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_abs/RUN_8/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_abs/RUN_9/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_abs/RUN_9/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_rel/monte_values_all_runs vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_rel/monte_values_all_runs + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_rel/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_rel/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_rel/RUN_1/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_rel/RUN_1/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_rel/RUN_2/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_rel/RUN_2/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_rel/RUN_3/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_rel/RUN_3/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_rel/RUN_4/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_rel/RUN_4/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_rel/RUN_5/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_rel/RUN_5/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_rel/RUN_6/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_rel/RUN_6/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_rel/RUN_7/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_rel/RUN_7/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_rel/RUN_8/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_rel/RUN_8/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_rel/RUN_9/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_rel/RUN_9/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_sd/monte_values_all_runs vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_sd/monte_values_all_runs + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_sd/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_sd/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_sd/RUN_1/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_sd/RUN_1/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_sd/RUN_2/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_sd/RUN_2/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_sd/RUN_3/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_sd/RUN_3/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_sd/RUN_4/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_sd/RUN_4/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_sd/RUN_5/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_sd/RUN_5/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_sd/RUN_6/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_sd/RUN_6/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_sd/RUN_7/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_sd/RUN_7/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_sd/RUN_8/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_sd/RUN_8/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_truncate_sd/RUN_9/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_truncate_sd/RUN_9/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal__untruncate/monte_values_all_runs vs. test/SIM_mc_generation/MONTE_RUN_random_normal__untruncate/monte_values_all_runs + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal__untruncate/monte_variables vs. test/SIM_mc_generation/MONTE_RUN_random_normal__untruncate/monte_variables + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal__untruncate/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal__untruncate/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal__untruncate/RUN_1/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal__untruncate/RUN_1/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal__untruncate/RUN_2/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal__untruncate/RUN_2/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal__untruncate/RUN_3/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal__untruncate/RUN_3/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal__untruncate/RUN_4/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal__untruncate/RUN_4/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal__untruncate/RUN_5/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal__untruncate/RUN_5/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal__untruncate/RUN_6/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal__untruncate/RUN_6/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal__untruncate/RUN_7/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal__untruncate/RUN_7/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal__untruncate/RUN_8/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal__untruncate/RUN_8/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal__untruncate/RUN_9/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal__untruncate/RUN_9/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_untruncated/monte_values_all_runs vs. test/SIM_mc_generation/MONTE_RUN_random_normal_untruncated/monte_values_all_runs + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_untruncated/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_untruncated/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_untruncated/RUN_1/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_untruncated/RUN_1/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_untruncated/RUN_2/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_untruncated/RUN_2/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_untruncated/RUN_3/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_untruncated/RUN_3/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_untruncated/RUN_4/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_untruncated/RUN_4/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_untruncated/RUN_5/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_untruncated/RUN_5/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_untruncated/RUN_6/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_untruncated/RUN_6/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_untruncated/RUN_7/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_untruncated/RUN_7/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_untruncated/RUN_8/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_untruncated/RUN_8/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_normal_untruncated/RUN_9/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_normal_untruncated/RUN_9/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_uniform/monte_values_all_runs vs. test/SIM_mc_generation/MONTE_RUN_random_uniform/monte_values_all_runs + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_uniform/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_uniform/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_uniform/RUN_1/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_uniform/RUN_1/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_uniform/RUN_2/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_uniform/RUN_2/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_uniform/RUN_3/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_uniform/RUN_3/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_uniform/RUN_4/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_uniform/RUN_4/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_uniform/RUN_5/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_uniform/RUN_5/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_uniform/RUN_6/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_uniform/RUN_6/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_uniform/RUN_7/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_uniform/RUN_7/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_uniform/RUN_8/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_uniform/RUN_8/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_random_uniform/RUN_9/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_random_uniform/RUN_9/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_ERROR_file_inconsistent_skip/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_ERROR_file_inconsistent_skip/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_ERROR_invalid_call/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_ERROR_invalid_call/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_ERROR_invalid_name/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_ERROR_invalid_name/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_ERROR_invalid_sequence/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_ERROR_invalid_sequence/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_ERROR_invalid_sequencing/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_ERROR_invalid_sequencing/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_ERROR_out_of_domain_error/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_ERROR_out_of_domain_error/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_ERROR_random_value_truncation/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_ERROR_random_value_truncation/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_ERROR_random_value_truncation/RUN_1/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_ERROR_random_value_truncation/RUN_1/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_generate_meta_data_early/monte_values_all_runs vs. test/SIM_mc_generation/MONTE_RUN_generate_meta_data_early/monte_values_all_runs + - test/SIM_mc_generation/verif_data/MONTE_RUN_generate_meta_data_early/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_generate_meta_data_early/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/monte_values_all_runs vs. test/SIM_mc_generation/MONTE_RUN_file_sequential/monte_values_all_runs + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_sequential/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_1/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_sequential/RUN_1/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_2/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_sequential/RUN_2/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_3/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_sequential/RUN_3/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_4/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_sequential/RUN_4/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_5/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_sequential/RUN_5/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_6/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_sequential/RUN_6/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_7/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_sequential/RUN_7/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_8/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_sequential/RUN_8/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_9/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_sequential/RUN_9/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_skip/monte_values_all_runs vs. test/SIM_mc_generation/MONTE_RUN_file_skip/monte_values_all_runs + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_skip/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_skip/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_skip/RUN_1/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_skip/RUN_1/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_skip/RUN_2/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_skip/RUN_2/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_skip/RUN_3/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_skip/RUN_3/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_skip/RUN_4/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_skip/RUN_4/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_skip/RUN_5/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_skip/RUN_5/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_skip/RUN_6/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_skip/RUN_6/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_skip/RUN_7/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_skip/RUN_7/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_skip/RUN_8/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_skip/RUN_8/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_skip/RUN_9/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_skip/RUN_9/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_skip2/monte_values_all_runs vs. test/SIM_mc_generation/MONTE_RUN_file_skip2/monte_values_all_runs + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_skip2/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_skip2/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_skip2/RUN_1/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_skip2/RUN_1/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_skip2/RUN_2/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_skip2/RUN_2/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_skip2/RUN_3/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_skip2/RUN_3/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_file_skip2/RUN_4/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_file_skip2/RUN_4/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_remove_variable/RUN_both_variables/monte_variables vs. test/SIM_mc_generation/MONTE_RUN_remove_variable/RUN_both_variables/monte_variables + - test/SIM_mc_generation/verif_data/MONTE_RUN_remove_variable/RUN_one_variable/monte_variables vs. test/SIM_mc_generation/MONTE_RUN_remove_variable/RUN_one_variable/monte_variables + - test/SIM_mc_generation/verif_data/MONTE_RUN_WARN_config_error/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_WARN_config_error/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_WARN_invalid_name/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_WARN_invalid_name/RUN_0/monte_input.py + - test/SIM_mc_generation/verif_data/MONTE_RUN_WARN_overconstrained_config/RUN_0/monte_input.py vs. test/SIM_mc_generation/MONTE_RUN_WARN_overconstrained_config/RUN_0/monte_input.py diff --git a/test/SIM_mc_generation/MONTE_IO_FAIL/git_hold b/test/SIM_mc_generation/MONTE_IO_FAIL/git_hold new file mode 100644 index 00000000..eecc0d1b --- /dev/null +++ b/test/SIM_mc_generation/MONTE_IO_FAIL/git_hold @@ -0,0 +1,2 @@ +This file holds MONTE_FAIL_IO_error2 in the git repo so its permissions can be +modified to support the FAIL_IO_error2 test. diff --git a/test/SIM_mc_generation/MONTE_IO_RUN_ERROR1/git_hold b/test/SIM_mc_generation/MONTE_IO_RUN_ERROR1/git_hold new file mode 100644 index 00000000..85c67f6e --- /dev/null +++ b/test/SIM_mc_generation/MONTE_IO_RUN_ERROR1/git_hold @@ -0,0 +1,2 @@ +This file holds MONTE_ERROR_IO_error in the git repo so its permissions can be +modified to support the ERROR_IO_error test. diff --git a/test/SIM_mc_generation/MONTE_IO_RUN_ERROR2/MonteCarlo_Meta_data_output b/test/SIM_mc_generation/MONTE_IO_RUN_ERROR2/MonteCarlo_Meta_data_output new file mode 100644 index 00000000..0a466a73 --- /dev/null +++ b/test/SIM_mc_generation/MONTE_IO_RUN_ERROR2/MonteCarlo_Meta_data_output @@ -0,0 +1,21 @@ + + +*************************** SUMMARY ************************** +1 total assignments + - 0 constant values + - 0 calculated variables + - 1 prescribed (file-based) variables + - 0 random variables + - 0 files for execution + - 0 variables of undefined type + +********************* LIST OF VARIABLES, TYPES**************** +test.x_file_lookup[0], Prescribed +************************************************************** + + +***** LIST OF DATA FILES AND THE VARIABLES THEY POPULATE ***** +****** +Modified_data/datafile.txt +3 test.x_file_lookup[0] +************************************************************** diff --git a/test/SIM_mc_generation/MONTE_IO_RUN_ERROR2/RUN_0/monte_input.py b/test/SIM_mc_generation/MONTE_IO_RUN_ERROR2/RUN_0/monte_input.py new file mode 100644 index 00000000..cff2d504 --- /dev/null +++ b/test/SIM_mc_generation/MONTE_IO_RUN_ERROR2/RUN_0/monte_input.py @@ -0,0 +1,7 @@ +monte_carlo.mc_master.active = True +monte_carlo.mc_master.generate_dispersions = False + +exec(open('IO_RUN_ERROR2/input.py').read()) +monte_carlo.mc_master.monte_run_number = 0 + +test.x_file_lookup[0] = 2 diff --git a/test/SIM_mc_generation/MONTE_IO_RUN_ERROR2/monte_variables b/test/SIM_mc_generation/MONTE_IO_RUN_ERROR2/monte_variables new file mode 100644 index 00000000..cd043da2 --- /dev/null +++ b/test/SIM_mc_generation/MONTE_IO_RUN_ERROR2/monte_variables @@ -0,0 +1,2 @@ +run_number +test.x_file_lookup[0], diff --git a/test/SIM_mc_generation/Modified_data/datafile.txt b/test/SIM_mc_generation/Modified_data/datafile.txt new file mode 100644 index 00000000..405e062d --- /dev/null +++ b/test/SIM_mc_generation/Modified_data/datafile.txt @@ -0,0 +1,7 @@ +0 1 2 3 4 +# comment +10 11 12 13 14 + +20 21 22 23 24 + +30 31 32 33 34 diff --git a/test/SIM_mc_generation/Modified_data/datafile_1.txt b/test/SIM_mc_generation/Modified_data/datafile_1.txt new file mode 100644 index 00000000..405e062d --- /dev/null +++ b/test/SIM_mc_generation/Modified_data/datafile_1.txt @@ -0,0 +1,7 @@ +0 1 2 3 4 +# comment +10 11 12 13 14 + +20 21 22 23 24 + +30 31 32 33 34 diff --git a/test/SIM_mc_generation/Modified_data/empty_file.txt b/test/SIM_mc_generation/Modified_data/empty_file.txt new file mode 100644 index 00000000..e69de29b diff --git a/test/SIM_mc_generation/Modified_data/monte_variables.py b/test/SIM_mc_generation/Modified_data/monte_variables.py new file mode 100644 index 00000000..310950df --- /dev/null +++ b/test/SIM_mc_generation/Modified_data/monte_variables.py @@ -0,0 +1,104 @@ +mc_var = trick.MonteCarloVariableRandomUniform( "test.x_uniform", 0, 10, 20) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +mc_var = trick.MonteCarloVariableRandomNormal( "test.x_normal", 2, 10, 2) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +mc_var = trick.MonteCarloVariableRandomNormal( "test.x_normal_trunc[0]", 2, 10, 2) +mc_var.truncate(0.5, trick.MonteCarloVariableRandomNormal.StandardDeviation) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +mc_var = trick.MonteCarloVariableRandomNormal( "test.x_normal_trunc[1]", 2, 10, 2) +mc_var.truncate(-0.5, 0.7, trick.MonteCarloVariableRandomNormal.Relative) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +mc_var = trick.MonteCarloVariableRandomNormal( "test.x_normal_trunc[2]", 2, 10, 2) +mc_var.truncate(9.9,11, trick.MonteCarloVariableRandomNormal.Absolute) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +mc_var = trick.MonteCarloVariableRandomNormal( "test.x_normal_trunc[3]", 2, 10, 2) +mc_var.truncate_low(9.9, trick.MonteCarloVariableRandomNormal.Absolute) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +mc_var = trick.MonteCarloVariableRandomNormal( "test.x_normal_trunc[4]", 2, 10, 2) +mc_var.truncate_high(4, trick.MonteCarloVariableRandomNormal.Absolute) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +mc_var = trick.MonteCarloVariableRandomNormal( "test.x_normal_length", 2, 10, 2) +mc_var.units = "ft" +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +mc_var = trick.MonteCarloVariableRandomUniformInt( "test.x_integer", 1, 0, 2) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +mc_var = trick.MonteCarloVariableRandomStringSet( "test.x_string", 3) +mc_var.add_string("\"ABC\"") +mc_var.add_string("\"DEF\"") +mc_var.add_string("'GHIJKL'") +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +mc_var = trick.MonteCarloPythonLineExec( "test.x_line_command", + "test.x_integer * test.x_uniform") +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +mc_var = trick.MonteCarloPythonLineExec( + "test.standalone_function( test.x_normal)") +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +mc_var = trick.MonteCarloPythonFileExec( "Modified_data/sample.py") +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +mc_var = trick.MonteCarloVariableRandomBool( "test.x_boolean", 4) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +# call this one mc_var1 because I'm going to use it as the seed for the +# MonteCarloVariableSemiFixed later. +mc_var1 = trick.MonteCarloVariableFile( "test.x_file_lookup[0]", + "Modified_data/datafile.txt", + 3) +mc_var1.thisown = False +monte_carlo.mc_master.add_variable(mc_var1) + +mc_var = trick.MonteCarloVariableFile( "test.x_file_lookup[1]", + "Modified_data/datafile.txt", + 2) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +mc_var = trick.MonteCarloVariableFile( "test.x_file_lookup[2]", + "Modified_data/datafile.txt", + 1) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + + +mc_var = trick.MonteCarloVariableFixed( "test.x_fixed_value_int", 7) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +mc_var = trick.MonteCarloVariableFixed( "test.x_fixed_value_double", 7.0) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +mc_var = trick.MonteCarloVariableFixed( "test.x_fixed_value_string", "\"7\"") +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +mc_var = trick.MonteCarloVariableSemiFixed( "test.x_semi_fixed_value", mc_var1 ) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + diff --git a/test/SIM_mc_generation/Modified_data/sample.py b/test/SIM_mc_generation/Modified_data/sample.py new file mode 100644 index 00000000..fd5e7827 --- /dev/null +++ b/test/SIM_mc_generation/Modified_data/sample.py @@ -0,0 +1,3 @@ +test.x_file_command[0] = 1 +test.x_file_command[1] = monte_carlo.mc_master.monte_run_number +test.x_file_command[2] = test.x_file_command[0] + test.x_file_command[1] diff --git a/test/SIM_mc_generation/Modified_data/single_col_1.txt b/test/SIM_mc_generation/Modified_data/single_col_1.txt new file mode 100644 index 00000000..97b3d1a5 --- /dev/null +++ b/test/SIM_mc_generation/Modified_data/single_col_1.txt @@ -0,0 +1,15 @@ +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 diff --git a/test/SIM_mc_generation/Modified_data/single_col_2.txt b/test/SIM_mc_generation/Modified_data/single_col_2.txt new file mode 100644 index 00000000..5e565722 --- /dev/null +++ b/test/SIM_mc_generation/Modified_data/single_col_2.txt @@ -0,0 +1,15 @@ +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 diff --git a/test/SIM_mc_generation/Modified_data/single_col_3.txt b/test/SIM_mc_generation/Modified_data/single_col_3.txt new file mode 100644 index 00000000..a96c36d5 --- /dev/null +++ b/test/SIM_mc_generation/Modified_data/single_col_3.txt @@ -0,0 +1,15 @@ +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 diff --git a/test/SIM_mc_generation/README b/test/SIM_mc_generation/README new file mode 100644 index 00000000..fa76a9b6 --- /dev/null +++ b/test/SIM_mc_generation/README @@ -0,0 +1,44 @@ +Verification simulation of monte_carlo. + + +The following tests rely on setting the directories to be non-writable. Their +purpose is to detect situations in which the monte-carlo model cannot generate +certain files. These tests by their very nature are difficult to run within an +automated scripted testing system. + + IO_FAIL + IO_RUN_ERROR1 + IO_RUN_ERROR2 + + +The following cases are expecting either a warning or an error but +the simulation does not terminate. Instead, ZERO is returned. +The purpose of these cases is to emit the error or warning, not generate +viable datasets. Do not evaluate any of these cases for good dispersions. +There is no telling what state the data is in after the warning / error +message is emitted. + + RUN_ERROR_file_inconsistent_skip + RUN_ERROR_invalid_call + RUN_ERROR_invalid_name + RUN_ERROR_invalid_sequence + RUN_ERROR_invalid_sequencing + RUN_ERROR_IO_error + RUN_ERROR_IO_error2 + RUN_ERROR_out_of_domain_error + RUN_ERROR_random_value_truncation + RUN_WARN_config_error + RUN_WARN_invalid_name + RUN_WARN_overconstrained_config + + +The following cases emit a fatal error and the simulation halts in its tracks: + + FAIL_config_error + FAIL_duplicate_variable + FAIL_illegal_config + FAIL_invalid_config + FAIL_invalid_data_file + FAIL_IO_error + FAIL_IO_error2 + FAIL_malformed_data_file diff --git a/test/SIM_mc_generation/RUN_ERROR_file_inconsistent_skip/input.py b/test/SIM_mc_generation/RUN_ERROR_file_inconsistent_skip/input.py new file mode 100644 index 00000000..becba617 --- /dev/null +++ b/test/SIM_mc_generation/RUN_ERROR_file_inconsistent_skip/input.py @@ -0,0 +1,46 @@ +monte_carlo.mc_master.activate("RUN_ERROR_file_inconsistent_skip") +monte_carlo.mc_master.set_num_runs(1) + +print('*********************************************************************') +print('these messages are expected:') +print(' Error Invalid configuration') +print(' It is not permissible for two variables looking at the same file to') +print(' operate under different line-selection criteria.') +print(' test.x_file_lookup[1]') +print(' will be switched to the behavior of') +print(' test.x_file_lookup_rl[0],') +print(' which has a setting for the maximum number of lines to skip of 3') +print('') +print(' Error Invalid configuration') +print(' It is not permissible for two variables looking at the same file to') +print(' operate under different line-selection criteria.') +print(' test.x_file_lookup[2]') +print(' will be switched to the behavior of') +print(' test.x_file_lookup_rl[0],') +print(' which has a setting for the maximum number of lines to skip of 3') +print('*********************************************************************') + + +mc_var = trick.MonteCarloVariableFile( "test.x_file_lookup[0]", + "Modified_data/datafile.txt", + 3) +mc_var.thisown = False +mc_var.max_skip = 3 +monte_carlo.mc_master.add_variable(mc_var) + +mc_var = trick.MonteCarloVariableFile( "test.x_file_lookup[1]", + "Modified_data/datafile.txt", + 2) +mc_var.thisown = False +mc_var.max_skip = 2 +monte_carlo.mc_master.add_variable(mc_var) + +mc_var = trick.MonteCarloVariableFile( "test.x_file_lookup[2]", + "Modified_data/datafile.txt", + 1) +mc_var.thisown = False +mc_var.max_skip = 1 +monte_carlo.mc_master.add_variable(mc_var) + + +trick.stop(1) diff --git a/test/SIM_mc_generation/RUN_ERROR_invalid_call/input.py b/test/SIM_mc_generation/RUN_ERROR_invalid_call/input.py new file mode 100644 index 00000000..120ec268 --- /dev/null +++ b/test/SIM_mc_generation/RUN_ERROR_invalid_call/input.py @@ -0,0 +1,21 @@ +monte_carlo.mc_master.activate("RUN_ERROR_invalid_call") +monte_carlo.mc_master.set_num_runs(1) + +print('*********************************************************************') +print('this message is expected:') +print(' Error Invalid call') +print(' Attempted to register a dependent identified with NULL pointer with') +print(' the MonteCarloVariableFile for variable test.x_file_lookup[0].') +print(' This is not a valid action.') +print(' Registration failed, exiting without action.') +print('*********************************************************************') + + +mc_var = trick.MonteCarloVariableFile( "test.x_file_lookup[0]", + "Modified_data/datafile.txt", + 3) +# the next command is the source of the error! +mc_var.register_dependent(None) +monte_carlo.mc_master.add_variable(mc_var) + +trick.stop(1) diff --git a/test/SIM_mc_generation/RUN_ERROR_invalid_name/input.py b/test/SIM_mc_generation/RUN_ERROR_invalid_name/input.py new file mode 100644 index 00000000..e52baf8a --- /dev/null +++ b/test/SIM_mc_generation/RUN_ERROR_invalid_name/input.py @@ -0,0 +1,15 @@ +monte_carlo.mc_master.activate("RUN_ERROR_invalid_name") +monte_carlo.mc_master.set_num_runs(1) + +print('*********************************************************************') +print('this message is expected:\n'+ + ' Error Invalid name\n' + + ' Could not find MonteCarlo variable with name test.x_uniform.\n'+ + ' Returning a NULL pointer.') +print('*********************************************************************') + +# empty monte carlo master without any variables. +# lets ask it find us a variable. +monte_carlo.mc_master.find_variable("test.x_uniform") + +trick.stop(1) diff --git a/test/SIM_mc_generation/RUN_ERROR_invalid_sequence/input.py b/test/SIM_mc_generation/RUN_ERROR_invalid_sequence/input.py new file mode 100644 index 00000000..4271cca8 --- /dev/null +++ b/test/SIM_mc_generation/RUN_ERROR_invalid_sequence/input.py @@ -0,0 +1,37 @@ +monte_carlo.mc_master.activate("RUN_ERROR_invalid_sequence") +monte_carlo.mc_master.set_num_runs(1) + +print('*****************************************************************************************************************************') +print('three (3) types of messages are expected:') +print(' Error Invalid sequence') +print(' Attempted to set the number of runs to 10, but the input files have') +print(' already been generated.') +print('') +print(' Error Invalid sequence') +print(' Attempted to add a new variable test.x_normal to run RUN_invalid_sequence, but the input files have already been generated.') +print(' Cannot modify input files to accommodate this new variable.') +print(' Addition of variable rejected.') +print('') +print(' Error Invalid sequence') +print(' Attempted to generate a set of input files, but this action has') +print(' already been completed. Keeping the original set of input files.') +print(' Ignoring the later instruction.') +print('*****************************************************************************************************************************') + + +mc_var = trick.MonteCarloVariableRandomUniform( "test.x_uniform", 0, 10, 20) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +# Trigger the "Invalid sequence" errors in MonteCarloMaster +monte_carlo.mc_master.prepare_input_files() + +# Change run-number after prepping inputs +monte_carlo.mc_master.set_num_runs(10) + +# Add a new variable after prepping inputs +mc_var = trick.MonteCarloVariableRandomNormal( "test.x_normal", 2, 10, 2) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +trick.stop(1) diff --git a/test/SIM_mc_generation/RUN_ERROR_invalid_sequencing/input.py b/test/SIM_mc_generation/RUN_ERROR_invalid_sequencing/input.py new file mode 100644 index 00000000..99de57ea --- /dev/null +++ b/test/SIM_mc_generation/RUN_ERROR_invalid_sequencing/input.py @@ -0,0 +1,18 @@ +monte_carlo.mc_master.activate("RUN_ERROR_invalid_sequencing") +monte_carlo.mc_master.set_num_runs(1) + +print('***********************************************************************************') +print('this message is expected:') +print(' Error Invalid sequencing') +print(' For variable test.x_semi_fixed_value, the necessary pre-dispersion to obtain the') +print(' random value for assignment has not been completed.') +print(' Cannot generate the assignment for this variable.') +print('***********************************************************************************') + + +mc_var = trick.MonteCarloVariableSemiFixed("test.x_semi_fixed_value", + test.mc_var_file) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +trick.stop(1) diff --git a/test/SIM_mc_generation/RUN_ERROR_out_of_domain_error/input.py b/test/SIM_mc_generation/RUN_ERROR_out_of_domain_error/input.py new file mode 100644 index 00000000..495e08cf --- /dev/null +++ b/test/SIM_mc_generation/RUN_ERROR_out_of_domain_error/input.py @@ -0,0 +1,18 @@ +monte_carlo.mc_master.activate("RUN_ERROR_out_of_domain_error") +monte_carlo.mc_master.set_num_runs(1) + +print('***********************************************************************') +print('these messages are expected:') +print(' Error Out-of-domain error') +print(' Negative double-sided truncation specified for variable test.x_normal') +print(' truncate() must receive either two limits or one positive limit!') +print(' Using absolute value of limit.') +print('***********************************************************************') + + +mc_var = trick.MonteCarloVariableRandomNormal( "test.x_normal" ) +# the next command is the source of the error! +mc_var.truncate(-1.0) +monte_carlo.mc_master.add_variable(mc_var) + +trick.stop(1) diff --git a/test/SIM_mc_generation/RUN_ERROR_random_value_truncation/input.py b/test/SIM_mc_generation/RUN_ERROR_random_value_truncation/input.py new file mode 100644 index 00000000..ff191844 --- /dev/null +++ b/test/SIM_mc_generation/RUN_ERROR_random_value_truncation/input.py @@ -0,0 +1,57 @@ +monte_carlo.mc_master.activate("RUN_ERROR_random_value_truncation") +monte_carlo.mc_master.set_num_runs(2) + +print('******************************************************************************************') +print('multiple error messages are expected:') +print(' Error Random value truncation failure') +print(' Could not generate a value for test.x_normal_trunc[#] within the specified domain within') +print(' the specified maximum number of tries (1).') +print(' Assuming a value equal to:') +print(' - midpoint value for a distribution truncated at both ends') +print(' - truncation value for a distribution truncated at only one end.') +print('') +print('NOTE: three tests are included here to test different code path after error') +print(' message is emitted') +print('******************************************************************************************') + + +# give some crazy initial values to the class +mc_var = trick.MonteCarloVariableRandomNormal( "test.x_normal_trunc[0]", 9956453, 10, 3.5) +mc_var.thisown = False +# give very small truncate_low & truncate_high distrubution values +mc_var.truncate_low(0.1) +mc_var.truncate_high(0.2) +# lower max_num_tries to an unreasonable # to generate the desired error +mc_var.max_num_tries = 1 +monte_carlo.mc_master.add_variable(mc_var) + +# note: this test also covers mc_variable_random_normal.cc lines 84-86 +# in the same code section after the message + + +# give some crazy initial values to the class +mc_var = trick.MonteCarloVariableRandomNormal( "test.x_normal_trunc[1]", 995656444, 10, 3.5) +mc_var.thisown = False +# give very small truncate_low distrubution value +mc_var.truncate_low(0.1) +# lower max_num_tries to an unreasonable # to generate the desired error +mc_var.max_num_tries = 1 +monte_carlo.mc_master.add_variable(mc_var) + +# note: this test also covers mc_variable_random_normal.cc lines 78-80 +# in the same code section after the message + + +# give some crazy initial values to the class +mc_var = trick.MonteCarloVariableRandomNormal( "test.x_normal_trunc[2]", 995656444, 10, 3.5) +mc_var.thisown = False +# give negative truncate_high distrubution value +mc_var.truncate_high(-50.2) +# lower max_num_tries to an unreasonable # to generate the desired error +mc_var.max_num_tries = 1 +monte_carlo.mc_master.add_variable(mc_var) + +# note: this test also covers mc_variable_random_normal.cc lines 81-83 +# in the same code section after the message + +trick.stop(1) diff --git a/test/SIM_mc_generation/RUN_WARN_config_error/input.py b/test/SIM_mc_generation/RUN_WARN_config_error/input.py new file mode 100644 index 00000000..95fe91f8 --- /dev/null +++ b/test/SIM_mc_generation/RUN_WARN_config_error/input.py @@ -0,0 +1,20 @@ +monte_carlo.mc_master.activate("RUN_WARN_config_error") +monte_carlo.mc_master.set_num_runs(1) + +print('***************************************************************************************') +print('this message is expected:') +print(' Warning Configuration error') +print(' Zero truncation specified for variable test.x_normal which will produce a fixed point') +print('***************************************************************************************') + + +mc_var = trick.MonteCarloVariableRandomNormal( "test.x_normal", 24858569, 10, 2) + +# this call generates the warning! +mc_var.truncate(0.0) + +# fix up the values before generating the assignment to avoid spurrious errors +mc_var.truncate(7.0, 13.0, trick.MonteCarloVariableRandomNormal.Absolute) +monte_carlo.mc_master.add_variable(mc_var) + +trick.stop(1) diff --git a/test/SIM_mc_generation/RUN_WARN_invalid_name/input.py b/test/SIM_mc_generation/RUN_WARN_invalid_name/input.py new file mode 100644 index 00000000..bc0eb5e0 --- /dev/null +++ b/test/SIM_mc_generation/RUN_WARN_invalid_name/input.py @@ -0,0 +1,22 @@ +monte_carlo.mc_master.activate("RUN_WARN_invalid_name") +monte_carlo.mc_master.set_num_runs(1) + +print('*********************************************************************************') +print('this message is expected:') +print(' Warning Invalid name') +print(' Attempt to remove MonteCarlo variable with name monte_carlo.not_found_variable FAILED.') +print(' Did not find a variable with that name.') +print('*********************************************************************************') + + +# give the simulation something to do +# add a variable into memory so list is not empty when we go to +# remove a non-existant variable from memory. +mc_var = trick.MonteCarloVariableRandomUniform( "test.x_uniform", 0, 10, 20) +monte_carlo.mc_master.add_variable(mc_var) + +# Trigger the "Invalid Name" warning in MonteCarloMaster +# by calling remove_variable() to remove a non-existant variable name +monte_carlo.mc_master.remove_variable("monte_carlo.not_found_variable") + +trick.stop(1) diff --git a/test/SIM_mc_generation/RUN_WARN_overconstrained_config/input.py b/test/SIM_mc_generation/RUN_WARN_overconstrained_config/input.py new file mode 100644 index 00000000..c7df0b1b --- /dev/null +++ b/test/SIM_mc_generation/RUN_WARN_overconstrained_config/input.py @@ -0,0 +1,19 @@ +monte_carlo.mc_master.activate("RUN_WARN_overconstrained_config") +monte_carlo.mc_master.set_num_runs(1) + +print('*******************************************************') +print('these messages are expected:') +print(' Warning Overconstrained configuration') +print(' For variable The distribution collapses to a point.') +print(' the specified minimum allowable value and') +print(' the specified maximum allowable value are equal (14).') +print('*******************************************************') + + +mc_var = trick.MonteCarloVariableRandomNormal( "test.x_normal", 2, 10, 2) +# the next two commands are neded to produce the warning! +mc_var.truncate_low(2.0) +mc_var.truncate_high(2.0) +monte_carlo.mc_master.add_variable(mc_var) + +trick.stop(1) diff --git a/test/SIM_mc_generation/RUN_file_sequential/input.py b/test/SIM_mc_generation/RUN_file_sequential/input.py new file mode 100644 index 00000000..735c3405 --- /dev/null +++ b/test/SIM_mc_generation/RUN_file_sequential/input.py @@ -0,0 +1,48 @@ +monte_carlo.mc_master.activate("RUN_file_sequential") +monte_carlo.mc_master.set_num_runs(10) + + +mc_var0 = trick.MonteCarloVariableFile( "test.x_file_lookup[0]", + "Modified_data/datafile.txt", + 3) +monte_carlo.mc_master.add_variable(mc_var0) + +mc_var1 = trick.MonteCarloVariableFile( "test.x_file_lookup[1]", + "Modified_data/datafile.txt", + 2) +monte_carlo.mc_master.add_variable(mc_var1) + +mc_var2 = trick.MonteCarloVariableFile( "test.x_file_lookup[2]", + "Modified_data/datafile.txt", + 1) +monte_carlo.mc_master.add_variable(mc_var2) + + +print("\nmc_var0.has_dependents() returns: " + str(mc_var0.has_dependents())) +print("mc_var0.get_column_number() returns: " + str(mc_var0.get_column_number())) +print("mc_var0.get_first_column_number() returns: " + str(mc_var0.get_first_column_number())) +print("mc_var0.get_filename() returns: '" + mc_var0.get_filename() + "'") +print("\nmc_var1.has_dependents() returns: " + str(mc_var1.has_dependents())) +print("mc_var1.get_column_number() returns: " + str(mc_var1.get_column_number())) +print("mc_var1.get_first_column_number() returns: " + str(mc_var1.get_first_column_number())) +print("mc_var1.get_filename() returns: '" + mc_var1.get_filename() + "'") +print("\nmc_var2.has_dependents() returns: " + str(mc_var2.has_dependents())) +print("mc_var2.get_column_number() returns: " + str(mc_var2.get_column_number())) +print("mc_var2.get_first_column_number() returns: " + str(mc_var2.get_first_column_number())) +print("mc_var2.get_filename() returns: '" + mc_var2.get_filename() + "'") + +# call parent class' "virtual int get_seed() const" method. should return ZERO. +# code coverage for: mc_variable.hh, line 70 +print("\ncode coverage for parent's get_seed() virtual method... should return ZERO.") +print("mc_var2.get_seed() returns: " + str(mc_var2.get_seed())) + +# Check the validity of looking up a variable by name. +print("\nmonte_carloing 'find_variable' and 'get_variable_name' for test.x_file_lookup[0]: "+ + "returns: " + + monte_carlo.mc_master.find_variable("test.x_file_lookup[0]").get_variable_name()) +print("monte_carloing 'find_variable' and 'get_variable_name' for test.x_file_lookup[1]: "+ + "returns: " + + monte_carlo.mc_master.find_variable("test.x_file_lookup[1]").get_variable_name() + "\n") + + +trick.stop(1) diff --git a/test/SIM_mc_generation/RUN_file_skip/input.py b/test/SIM_mc_generation/RUN_file_skip/input.py new file mode 100644 index 00000000..1915b627 --- /dev/null +++ b/test/SIM_mc_generation/RUN_file_skip/input.py @@ -0,0 +1,26 @@ +monte_carlo.mc_master.activate("RUN_file_skip") +monte_carlo.mc_master.set_num_runs(10) + +mc_var = trick.MonteCarloVariableFile( "test.x_file_lookup[0]", + "Modified_data/datafile.txt", + 3) +mc_var.thisown = False +mc_var.max_skip = 3 +monte_carlo.mc_master.add_variable(mc_var) + +mc_var = trick.MonteCarloVariableFile( "test.x_file_lookup[1]", + "Modified_data/datafile.txt", + 2) +mc_var.thisown = False +mc_var.max_skip = 3 +monte_carlo.mc_master.add_variable(mc_var) + +mc_var = trick.MonteCarloVariableFile( "test.x_file_lookup[2]", + "Modified_data/datafile.txt", + 1) +mc_var.thisown = False +mc_var.max_skip = 3 +monte_carlo.mc_master.add_variable(mc_var) + + +trick.stop(1) diff --git a/test/SIM_mc_generation/RUN_file_skip2/input.py b/test/SIM_mc_generation/RUN_file_skip2/input.py new file mode 100644 index 00000000..b4cc1e4a --- /dev/null +++ b/test/SIM_mc_generation/RUN_file_skip2/input.py @@ -0,0 +1,32 @@ +monte_carlo.mc_master.activate("RUN_file_skip2") +# For regression monte_carloing, use 5 runs +# For verification, setting this value to 250 results in 2 duplications. +monte_carlo.mc_master.set_num_runs(5) +#monte_carlo.mc_master.set_num_runs(250) + + +mc_var = trick.MonteCarloVariableFile( "test.x_file_lookup[0]", + "Modified_data/single_col_1.txt", + 0, + 0) +mc_var.max_skip = 1 +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +mc_var = trick.MonteCarloVariableFile( "test.x_file_lookup[1]", + "Modified_data/single_col_2.txt", + 0, + 0) +mc_var.max_skip = 2 +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +mc_var = trick.MonteCarloVariableFile( "test.x_file_lookup[2]", + "Modified_data/single_col_3.txt", + 0, + 0) +mc_var.max_skip = 3 +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +trick.stop(1) diff --git a/test/SIM_mc_generation/RUN_generate_meta_data_early/input.py b/test/SIM_mc_generation/RUN_generate_meta_data_early/input.py new file mode 100644 index 00000000..7ad59c17 --- /dev/null +++ b/test/SIM_mc_generation/RUN_generate_meta_data_early/input.py @@ -0,0 +1,11 @@ +monte_carlo.mc_master.activate("RUN_generate_meta_data_early") +monte_carlo.mc_master.set_num_runs(1) +monte_carlo.mc_master.generate_meta_data = True +monte_carlo.mc_master.input_file_name = "input.py" + +exec(open("Modified_data/monte_variables.py").read()) + +# By running this early, the MonteCarlo_Meta_data_output file +# should end up in the sim directory instead of the MONTE_RUN.. +# directory +monte_carlo.mc_master.collate_meta_data() diff --git a/test/SIM_mc_generation/RUN_nominal/input.py b/test/SIM_mc_generation/RUN_nominal/input.py new file mode 100644 index 00000000..f6b14d38 --- /dev/null +++ b/test/SIM_mc_generation/RUN_nominal/input.py @@ -0,0 +1,48 @@ +# The Monte Carlo tool uses a double execution of the S-main: +# - pass #1 uses the scenario input.py file to process the variables identified +# for dispersion. A specified number, N, of values {v_1, ..., v_N} is +# generated for each variable v, with the values constrained by the specified +# distribution of v; N is specified in the input file. +# A set of N files, {RUN_1/monte_input.py, ... , RUN_N/monte_input.py} is +# created, with each file containing one of the set of values for each +# variable. Once these files are generated, the simulation is complete for +# pass #1 and it terminates. +# - pass #2 uses one of the generated files (monte_input.py) as the input file +# for a regular execution of the simulation. There will typically be many +# executions of the sim, one for each of the generated monte_input.py files. + +# This input file provides one example of how to test this two-pass process, +# although it is admittedly a bit convoluted and hard to read. TODO: Once +# TrickOps is capable of operating with this monte-carlo implementation, that +# framework can manage both the generation and local execution of generated +# monte_input.py files, removing the need for this type of "sim that launches a +# sim" test methodology -Jordan 10/2022 + +# For the purpose of expedient testing, we generate and run only 2 files. +# This is sufficient to demonstrate "multiple" without unnecessarily +# burning CPU time. + +import os +exename = "S_main_" + os.getenv("TRICK_HOST_CPU") + ".exe" + +# Pass #1 Generate the set of scenarios with unique dispersions +print("Processing Pass #1 for run RUN_nominal") +input_file = "RUN_nominal/input_a.py" +ret = os.system("./" + exename + " " + input_file) +if ret != 0: + trick.exec_terminate_with_return(1, "double_pass.py", 34, "Error running " + input_file) + +# Pass #2 Run the scenarios. Logged data will go into each scenario's folder +print("") +print("") +print("Processing Pass #2 for run RUN_nominal") +for ii in range(2): + input_file = "MONTE_RUN_nominal"+"/RUN_00%d/monte_input_a.py" %ii + print ("**************** %s" %input_file) + ret = os.system("./" + exename + " " + input_file) + if ret != 0: + trick.exec_terminate_with_return(1, "double_pass.py", 43, "Error running " + input_file) + +# To be compatible with our current unit-sim framework, this file has to be a +# simulation input file. Therefore it needs a stop time so it doesn't run forever. +trick.stop(0.0) diff --git a/test/SIM_mc_generation/RUN_nominal/input_a.py b/test/SIM_mc_generation/RUN_nominal/input_a.py new file mode 100644 index 00000000..d5ecb48d --- /dev/null +++ b/test/SIM_mc_generation/RUN_nominal/input_a.py @@ -0,0 +1,37 @@ +# Instruct sim to generate MC files for RUN_verif. +# This could be done in a top-level MC-launch script +monte_carlo.mc_master.activate("RUN_nominal") +monte_carlo.mc_master.set_num_runs(2) +monte_carlo.mc_master.generate_meta_data = True +monte_carlo.mc_master.input_file_name = "input_a.py" +monte_carlo.mc_master.minimum_padding = 3 + + + +# Standard if-tests for a regular multi-purpose input file, allowing for a +# MC-implementation of a general scenario. + +# NOTE: in this case, the first test is redundant because this input file is +# ALWAYS going to have mc-master be active. But this is likely to get +# copied and used as a template. + +# Quick breakdown: +# - if running with MC: +# (this test allows a general input file to have MC-specific content) +# +# - setup logging and any other MC-specific configurations +# +# - if generating dispersions, generate them. +# (This test separates out the execution of pass#1 (which generates the +# dispersions) from that of pass#2 (which executes with those +# dispersions). Without this test blocking the generation on pass#2, the +# dispersions would get regenerated for every actual run, which is +# completely unnecessary.) +if monte_carlo.mc_master.active: + # Logging + exec(open("Log_data/log_nominal.py").read()) + + if monte_carlo.mc_master.generate_dispersions: + exec(open("Modified_data/monte_variables.py").read()) + +trick.stop(1) diff --git a/test/SIM_mc_generation/RUN_random_normal__untruncate/input.py b/test/SIM_mc_generation/RUN_random_normal__untruncate/input.py new file mode 100644 index 00000000..0ab6ad12 --- /dev/null +++ b/test/SIM_mc_generation/RUN_random_normal__untruncate/input.py @@ -0,0 +1,22 @@ +monte_carlo.mc_master.activate("RUN_random_normal__untruncate") +monte_carlo.mc_master.set_num_runs(10) + +# generate a set of numbers +mc_var = trick.MonteCarloVariableRandomNormal( "test.x_normal_trunc[0]", 2, 10, 2) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +mc_var = trick.MonteCarloVariableRandomNormal( "test.x_normal_trunc[1]", 2, 10, 2) +# signal an absolute truncation +mc_var.truncate(8, 12, trick.MonteCarloVariableRandomNormal.Absolute) +# changed my mind. no longer wish to truncate. +# this method turns off 'truncated_low' and 'truncated_high' indicators, leaving +# the original variable values alone! +# NOTE: the two values in this sim should match! +# +# code coverage for untruncate() method, mc_variable_random_normal.cc, lines 204-205 +mc_var.untruncate() +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +trick.stop(1) diff --git a/test/SIM_mc_generation/RUN_random_normal_truncate_abs/input.py b/test/SIM_mc_generation/RUN_random_normal_truncate_abs/input.py new file mode 100644 index 00000000..7419212b --- /dev/null +++ b/test/SIM_mc_generation/RUN_random_normal_truncate_abs/input.py @@ -0,0 +1,34 @@ +monte_carlo.mc_master.activate("RUN_random_normal_truncate_abs") +# Use 10 runs for regression comparison; use more (10,000) for confirming +# statistical distribution. +monte_carlo.mc_master.set_num_runs(10) + +# should keep values between -10 and 10, exclusive +# this one calls 'truncate_low(-10)' and 'truncate_high(10)' to establish +# truncation bounds so we need to pivot around ZERO. Otherwise, if mean +# is not ZERO, ex. 25, the truncation bounds would be -25 and 25 which +# does not match the desired values of +/- 10 of mean. +mc_var = trick.MonteCarloVariableRandomNormal( "test.x_normal_trunc[0]", 11122, 0, 5) +mc_var.truncate(10, trick.MonteCarloVariableRandomNormal.Absolute) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +# should keep values 72.5 thru 85.0, exclusive +mc_var = trick.MonteCarloVariableRandomNormal( "test.x_normal_trunc[1]", 77546, 75, 5) +mc_var.truncate(72.5, 85, trick.MonteCarloVariableRandomNormal.Absolute) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +# should keep values greater than 90.0 +mc_var = trick.MonteCarloVariableRandomNormal( "test.x_normal_trunc[2]", 60540, 100, 5) +mc_var.truncate_low(90, trick.MonteCarloVariableRandomNormal.Absolute) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +# should keep values less than 135.0 +mc_var = trick.MonteCarloVariableRandomNormal( "test.x_normal_trunc[3]", 77077, 125, 5) +mc_var.truncate_high(135, trick.MonteCarloVariableRandomNormal.Absolute) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +trick.stop(1) diff --git a/test/SIM_mc_generation/RUN_random_normal_truncate_rel/input.py b/test/SIM_mc_generation/RUN_random_normal_truncate_rel/input.py new file mode 100644 index 00000000..f26828ae --- /dev/null +++ b/test/SIM_mc_generation/RUN_random_normal_truncate_rel/input.py @@ -0,0 +1,33 @@ +monte_carlo.mc_master.activate("RUN_random_normal_truncate_rel") +# Use 10 runs for regression comparison; use more (10,000) for confirming +# statistical distribution. +monte_carlo.mc_master.set_num_runs(10) + +# should keep values between -10 and 10, exclusive +# this one computes mean+10, resulting in calls to +# 'truncate_low(-10)' and 'truncate_high(10)' to establish +# truncation bounds. +mc_var = trick.MonteCarloVariableRandomNormal( "test.x_normal_trunc[0]", 11122, 0, 5) +mc_var.truncate(10, trick.MonteCarloVariableRandomNormal.Relative) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +# should keep values 72.5 thru 85.0, exclusive +mc_var = trick.MonteCarloVariableRandomNormal( "test.x_normal_trunc[1]", 77546, 75, 5) +mc_var.truncate(-2.5, 10, trick.MonteCarloVariableRandomNormal.Relative) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +# should keep values greater than 90.0 +mc_var = trick.MonteCarloVariableRandomNormal( "test.x_normal_trunc[2]", 60540, 100, 5) +mc_var.truncate_low(-10, trick.MonteCarloVariableRandomNormal.Relative) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +# should keep values less than 135.0 +mc_var = trick.MonteCarloVariableRandomNormal( "test.x_normal_trunc[3]", 77077, 125, 5) +mc_var.truncate_high(10, trick.MonteCarloVariableRandomNormal.Relative) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +trick.stop(1) diff --git a/test/SIM_mc_generation/RUN_random_normal_truncate_sd/input.py b/test/SIM_mc_generation/RUN_random_normal_truncate_sd/input.py new file mode 100644 index 00000000..861fc92b --- /dev/null +++ b/test/SIM_mc_generation/RUN_random_normal_truncate_sd/input.py @@ -0,0 +1,33 @@ +monte_carlo.mc_master.activate("RUN_random_normal_truncate_sd") +# Use 10 runs for regression comparison; use more (10,000) for confirming +# statistical distribution. +monte_carlo.mc_master.set_num_runs(10) + +# should keep values between -10 and 10, exclusive +# this one computes (2*std_dev)+mean, resulting in calls to +# 'truncate_low(-10)' and 'truncate_high(10)' to establish +# truncation bounds. +mc_var = trick.MonteCarloVariableRandomNormal( "test.x_normal_trunc[0]", 11122, 0, 5) +mc_var.truncate(2, trick.MonteCarloVariableRandomNormal.StandardDeviation) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +# should keep values 72.5 thru 85.0, exclusive +mc_var = trick.MonteCarloVariableRandomNormal( "test.x_normal_trunc[1]", 77546, 75, 5) +mc_var.truncate(-0.5, 2, trick.MonteCarloVariableRandomNormal.StandardDeviation) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +# should keep values greater than 90.0 +mc_var = trick.MonteCarloVariableRandomNormal( "test.x_normal_trunc[2]", 60540, 100, 5) +mc_var.truncate_low(-2, trick.MonteCarloVariableRandomNormal.StandardDeviation) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +# should keep values less than 135.0 +mc_var = trick.MonteCarloVariableRandomNormal( "test.x_normal_trunc[3]", 77077, 125, 5) +mc_var.truncate_high(2, trick.MonteCarloVariableRandomNormal.StandardDeviation) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +trick.stop(1) diff --git a/test/SIM_mc_generation/RUN_random_normal_untruncated/input.py b/test/SIM_mc_generation/RUN_random_normal_untruncated/input.py new file mode 100644 index 00000000..2048263f --- /dev/null +++ b/test/SIM_mc_generation/RUN_random_normal_untruncated/input.py @@ -0,0 +1,26 @@ +monte_carlo.mc_master.activate("RUN_random_normal_untruncated") +# Use 10 runs for regression comparison; use more (10,000) for confirming +# statistical distribution. +monte_carlo.mc_master.set_num_runs(10) + +# normal distribution from approximately -17.5 to 18.1 +mc_var = trick.MonteCarloVariableRandomNormal( "test.x_normal_trunc[0]", 11122, 0, 5) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +# normal distribution from approximately 53.1 to 94.5 +mc_var = trick.MonteCarloVariableRandomNormal( "test.x_normal_trunc[1]", 77546, 75, 5) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +# normal distribution from approximately 81.4 to 119.75 +mc_var = trick.MonteCarloVariableRandomNormal( "test.x_normal_trunc[2]", 60540, 100, 5) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +# normal distribution from approximately 106.3 to 144.7 +mc_var = trick.MonteCarloVariableRandomNormal( "test.x_normal_trunc[3]", 77077, 125, 5) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +trick.stop(1) diff --git a/test/SIM_mc_generation/RUN_random_uniform/input.py b/test/SIM_mc_generation/RUN_random_uniform/input.py new file mode 100644 index 00000000..b75d7df5 --- /dev/null +++ b/test/SIM_mc_generation/RUN_random_uniform/input.py @@ -0,0 +1,16 @@ +monte_carlo.mc_master.activate("RUN_random_uniform") +# Use 10 runs for regression comparison; use more (10,000) for confirming +# statistical distribution. +monte_carlo.mc_master.set_num_runs(10) + +# generate random uniformly distributed floating point values from 100.0 to 100,000.0 +mc_var = trick.MonteCarloVariableRandomUniform( "test.x_uniform", 77545, 100.0, 100000.0) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +# generate random uniformly distributed integer values from 100.0 to 100,000.0 +mc_var = trick.MonteCarloVariableRandomUniformInt( "test.x_integer", 77001, 100, 100000) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +trick.stop(1) diff --git a/test/SIM_mc_generation/RUN_remove_variable/input.py b/test/SIM_mc_generation/RUN_remove_variable/input.py new file mode 100644 index 00000000..7671c1ed --- /dev/null +++ b/test/SIM_mc_generation/RUN_remove_variable/input.py @@ -0,0 +1,33 @@ +# The purpose of this test is to: +# Execute the first input file to add two variables into MonteCarloMaster. +# Execute the second input file to add the same variables into +# MonteCarloMaster, but removes one of them before monte carlo RUN files +# are generated. +# Then it compares the variable lists from the monte carlo runs. If they differ, +# the test terminate with a non-zero return. + +import os +exename = "S_main_" + os.getenv("TRICK_HOST_CPU") + ".exe" + +print("Processing 1st input file for run RUN_remove_variable") +input_file = "RUN_remove_variable/input_a.py" +ret = os.system("./" + exename + " " + input_file) +if ret != 0: + trick.exec_terminate_with_return(1, "input.py", 16, "Error running " + input_file) + +print("Processing 2nd input file for run RUN_remove_variable") +input_file = "RUN_remove_variable/input_b.py" +ret = os.system("./" + exename + " " + input_file) +if ret != 0: + trick.exec_terminate_with_return(1, "input.py", 22, "Error running " + input_file) + +print('Checking if the variable was successfully removed') +ret = os.system("diff -q MONTE_RUN_remove_variable/RUN_0/monte_variables MONTE_RUN_remove_variable/RUN_1/monte_variables > /dev/null") +if ret != 0: + trick.exec_terminate_with_return(0, "input.py", 27, "variable successfully removed!") +else: + trick.exec_terminate_with_return(1, "input.py", 29, "variable 'test.x_fixed_value_int' was not removed!") + +# To be compatible with our current unit-sim framework, this file has to be a +# simulation input file. Therefore it needs a stop time so it doesn't run forever. +trick.stop(0.0) diff --git a/test/SIM_mc_generation/RUN_remove_variable/input_a.py b/test/SIM_mc_generation/RUN_remove_variable/input_a.py new file mode 100644 index 00000000..0f9eace5 --- /dev/null +++ b/test/SIM_mc_generation/RUN_remove_variable/input_a.py @@ -0,0 +1,7 @@ +monte_carlo.mc_master.activate("RUN_remove_variable/RUN_both_variables") +monte_carlo.mc_master.set_num_runs(1) +monte_carlo.mc_master.input_file_name = "input_a.py" + +exec(open("RUN_remove_variable/variable_list.py").read()) + +trick.stop(1) diff --git a/test/SIM_mc_generation/RUN_remove_variable/input_b.py b/test/SIM_mc_generation/RUN_remove_variable/input_b.py new file mode 100644 index 00000000..9d78d6f3 --- /dev/null +++ b/test/SIM_mc_generation/RUN_remove_variable/input_b.py @@ -0,0 +1,11 @@ +monte_carlo.mc_master.activate("RUN_remove_variable/RUN_one_variable") +monte_carlo.mc_master.set_num_runs(1) +monte_carlo.mc_master.input_file_name = "input_b.py" + +exec(open("RUN_remove_variable/variable_list.py").read()) + +# execute remove_variable() (success path) +# code coverage for mc_master.cc, remove_variable(), lines 288-289 +monte_carlo.mc_master.remove_variable("test.x_fixed_value_int") + +trick.stop(1) diff --git a/test/SIM_mc_generation/RUN_remove_variable/variable_list.py b/test/SIM_mc_generation/RUN_remove_variable/variable_list.py new file mode 100644 index 00000000..ae36a273 --- /dev/null +++ b/test/SIM_mc_generation/RUN_remove_variable/variable_list.py @@ -0,0 +1,8 @@ + +mc_var = trick.MonteCarloVariableRandomUniform( "test.x_uniform", 0, 10, 20) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) + +mc_var = trick.MonteCarloVariableFixed( "test.x_fixed_value_int", 7) +mc_var.thisown = False +monte_carlo.mc_master.add_variable(mc_var) diff --git a/test/SIM_mc_generation/S_define b/test/SIM_mc_generation/S_define new file mode 100644 index 00000000..ba39de48 --- /dev/null +++ b/test/SIM_mc_generation/S_define @@ -0,0 +1,58 @@ +/***************************************************************************** +PURPOSE: SIM object used to Exercise the features and failure cases of the +MonteCarloGeneration model. +PROGRAMMERS: + (((Isaac Reaves) (NASA) (November 2022) (Integration into Trick Core))) +*****************************************************************************/ +#include "sim_objects/default_trick_sys.sm" +#include "sim_objects/MonteCarloGenerate.sm" + +/***************************************************************************** +MC_Test sim object +****************************************************************************/ + +class MC_TestSimObject : public Trick::SimObject +{ + public: + double x_uniform; + double x_normal; + double x_normal_trunc[5]; + double x_normal_length; // (m) Dispersed in ft. + double x_line_command; + double x_file_command[3]; + double x_file_lookup[3]; + double x_fixed_value_double; + double x_semi_fixed_value; + int x_fixed_value_int; + int x_integer; + bool x_boolean; + std::string x_string; + std::string x_fixed_value_string; + int x_sdefine_routine_called; + + MonteCarloVariableFile mc_var_file; + + MC_TestSimObject() + : + mc_var_file("test.x_file_lookup[0]", "Modified_data/datafile.txt", 3) + { + ("initialization") monte_carlo.generate_dispersions(); + (1.0,"environment") output_strings(); + }; + + // standalone_function is used to test using an instance of + // MonteCarloPythonLineExec to execute a standalone function. + void standalone_function( double value) + { + std::cout << "\nStandalone_function received a value of " << value << "\n"; + x_sdefine_routine_called = 1; + } + private: + void output_strings() { + std::cout << "\nstrings : " << x_string << " : " << x_fixed_value_string << "\n"; + } + MC_TestSimObject( const MC_TestSimObject&); + MC_TestSimObject & operator= ( const MC_TestSimObject&); + +}; +MC_TestSimObject test; diff --git a/test/SIM_mc_generation/S_overrides.mk b/test/SIM_mc_generation/S_overrides.mk new file mode 100644 index 00000000..7e7c1958 --- /dev/null +++ b/test/SIM_mc_generation/S_overrides.mk @@ -0,0 +1,8 @@ +TRICK_CFLAGS += -g -Wall -Wextra +TRICK_CXXFLAGS += -g -std=c++11 -Wall -Wextra +# We can't yet make warnings to be errors on MacOS, because +# MACOS deprecates and warns about sprintf. But SWIG +# still generates code containing sprintf.. +ifneq ($(TRICK_HOST_TYPE), Darwin) +TRICK_CXXFLAGS += -Werror -Wno-stringop-truncation +endif diff --git a/test/SIM_mc_generation/verif_data/MONTE_RUN_ERROR_invalid_call/RUN_0/monte_input.py b/test/SIM_mc_generation/verif_data/MONTE_RUN_ERROR_invalid_call/RUN_0/monte_input.py new file mode 100644 index 00000000..9e1bad17 --- /dev/null +++ b/test/SIM_mc_generation/verif_data/MONTE_RUN_ERROR_invalid_call/RUN_0/monte_input.py @@ -0,0 +1,7 @@ +monte_carlo.mc_master.active = True +monte_carlo.mc_master.generate_dispersions = False + +exec(open('RUN_ERROR_invalid_call/input.py').read()) +monte_carlo.mc_master.monte_run_number = 0 + +test.x_file_lookup[0] = 2 diff --git a/test/SIM_mc_generation/verif_data/MONTE_RUN_ERROR_invalid_name/RUN_0/monte_input.py b/test/SIM_mc_generation/verif_data/MONTE_RUN_ERROR_invalid_name/RUN_0/monte_input.py new file mode 100644 index 00000000..f877043b --- /dev/null +++ b/test/SIM_mc_generation/verif_data/MONTE_RUN_ERROR_invalid_name/RUN_0/monte_input.py @@ -0,0 +1,6 @@ +monte_carlo.mc_master.active = True +monte_carlo.mc_master.generate_dispersions = False + +exec(open('RUN_ERROR_invalid_name/input.py').read()) +monte_carlo.mc_master.monte_run_number = 0 + diff --git a/test/SIM_mc_generation/verif_data/MONTE_RUN_ERROR_invalid_sequence/RUN_0/monte_input.py b/test/SIM_mc_generation/verif_data/MONTE_RUN_ERROR_invalid_sequence/RUN_0/monte_input.py new file mode 100644 index 00000000..436d46e3 --- /dev/null +++ b/test/SIM_mc_generation/verif_data/MONTE_RUN_ERROR_invalid_sequence/RUN_0/monte_input.py @@ -0,0 +1,7 @@ +monte_carlo.mc_master.active = True +monte_carlo.mc_master.generate_dispersions = False + +exec(open('RUN_ERROR_invalid_sequence/input.py').read()) +monte_carlo.mc_master.monte_run_number = 0 + +test.x_uniform = 15.92844616516683 diff --git a/test/SIM_mc_generation/verif_data/MONTE_RUN_ERROR_invalid_sequencing/RUN_0/monte_input.py b/test/SIM_mc_generation/verif_data/MONTE_RUN_ERROR_invalid_sequencing/RUN_0/monte_input.py new file mode 100644 index 00000000..3339b9a1 --- /dev/null +++ b/test/SIM_mc_generation/verif_data/MONTE_RUN_ERROR_invalid_sequencing/RUN_0/monte_input.py @@ -0,0 +1,6 @@ +monte_carlo.mc_master.active = True +monte_carlo.mc_master.generate_dispersions = False + +exec(open('RUN_ERROR_invalid_sequencing/input.py').read()) +monte_carlo.mc_master.monte_run_number = 0 + diff --git a/test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_0/monte_input.py b/test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_0/monte_input.py new file mode 100644 index 00000000..a7dcf583 --- /dev/null +++ b/test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_0/monte_input.py @@ -0,0 +1,9 @@ +monte_carlo.mc_master.active = True +monte_carlo.mc_master.generate_dispersions = False + +exec(open('RUN_file_sequential/input.py').read()) +monte_carlo.mc_master.monte_run_number = 0 + +test.x_file_lookup[0] = 2 +test.x_file_lookup[1] = 1 +test.x_file_lookup[2] = 0 diff --git a/test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_1/monte_input.py b/test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_1/monte_input.py new file mode 100644 index 00000000..d6789b49 --- /dev/null +++ b/test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_1/monte_input.py @@ -0,0 +1,9 @@ +monte_carlo.mc_master.active = True +monte_carlo.mc_master.generate_dispersions = False + +exec(open('RUN_file_sequential/input.py').read()) +monte_carlo.mc_master.monte_run_number = 1 + +test.x_file_lookup[0] = 12 +test.x_file_lookup[1] = 11 +test.x_file_lookup[2] = 10 diff --git a/test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_2/monte_input.py b/test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_2/monte_input.py new file mode 100644 index 00000000..89683e01 --- /dev/null +++ b/test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_2/monte_input.py @@ -0,0 +1,9 @@ +monte_carlo.mc_master.active = True +monte_carlo.mc_master.generate_dispersions = False + +exec(open('RUN_file_sequential/input.py').read()) +monte_carlo.mc_master.monte_run_number = 2 + +test.x_file_lookup[0] = 22 +test.x_file_lookup[1] = 21 +test.x_file_lookup[2] = 20 diff --git a/test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_3/monte_input.py b/test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_3/monte_input.py new file mode 100644 index 00000000..d7c22687 --- /dev/null +++ b/test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_3/monte_input.py @@ -0,0 +1,9 @@ +monte_carlo.mc_master.active = True +monte_carlo.mc_master.generate_dispersions = False + +exec(open('RUN_file_sequential/input.py').read()) +monte_carlo.mc_master.monte_run_number = 3 + +test.x_file_lookup[0] = 32 +test.x_file_lookup[1] = 31 +test.x_file_lookup[2] = 30 diff --git a/test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_4/monte_input.py b/test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_4/monte_input.py new file mode 100644 index 00000000..ecc75837 --- /dev/null +++ b/test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_4/monte_input.py @@ -0,0 +1,9 @@ +monte_carlo.mc_master.active = True +monte_carlo.mc_master.generate_dispersions = False + +exec(open('RUN_file_sequential/input.py').read()) +monte_carlo.mc_master.monte_run_number = 4 + +test.x_file_lookup[0] = 2 +test.x_file_lookup[1] = 1 +test.x_file_lookup[2] = 0 diff --git a/test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_5/monte_input.py b/test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_5/monte_input.py new file mode 100644 index 00000000..3e3cd4e7 --- /dev/null +++ b/test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_5/monte_input.py @@ -0,0 +1,9 @@ +monte_carlo.mc_master.active = True +monte_carlo.mc_master.generate_dispersions = False + +exec(open('RUN_file_sequential/input.py').read()) +monte_carlo.mc_master.monte_run_number = 5 + +test.x_file_lookup[0] = 12 +test.x_file_lookup[1] = 11 +test.x_file_lookup[2] = 10 diff --git a/test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_6/monte_input.py b/test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_6/monte_input.py new file mode 100644 index 00000000..60074fed --- /dev/null +++ b/test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_6/monte_input.py @@ -0,0 +1,9 @@ +monte_carlo.mc_master.active = True +monte_carlo.mc_master.generate_dispersions = False + +exec(open('RUN_file_sequential/input.py').read()) +monte_carlo.mc_master.monte_run_number = 6 + +test.x_file_lookup[0] = 22 +test.x_file_lookup[1] = 21 +test.x_file_lookup[2] = 20 diff --git a/test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_7/monte_input.py b/test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_7/monte_input.py new file mode 100644 index 00000000..3d01585a --- /dev/null +++ b/test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_7/monte_input.py @@ -0,0 +1,9 @@ +monte_carlo.mc_master.active = True +monte_carlo.mc_master.generate_dispersions = False + +exec(open('RUN_file_sequential/input.py').read()) +monte_carlo.mc_master.monte_run_number = 7 + +test.x_file_lookup[0] = 32 +test.x_file_lookup[1] = 31 +test.x_file_lookup[2] = 30 diff --git a/test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_8/monte_input.py b/test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_8/monte_input.py new file mode 100644 index 00000000..38be7fe3 --- /dev/null +++ b/test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_8/monte_input.py @@ -0,0 +1,9 @@ +monte_carlo.mc_master.active = True +monte_carlo.mc_master.generate_dispersions = False + +exec(open('RUN_file_sequential/input.py').read()) +monte_carlo.mc_master.monte_run_number = 8 + +test.x_file_lookup[0] = 2 +test.x_file_lookup[1] = 1 +test.x_file_lookup[2] = 0 diff --git a/test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_9/monte_input.py b/test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_9/monte_input.py new file mode 100644 index 00000000..dda981fc --- /dev/null +++ b/test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/RUN_9/monte_input.py @@ -0,0 +1,9 @@ +monte_carlo.mc_master.active = True +monte_carlo.mc_master.generate_dispersions = False + +exec(open('RUN_file_sequential/input.py').read()) +monte_carlo.mc_master.monte_run_number = 9 + +test.x_file_lookup[0] = 12 +test.x_file_lookup[1] = 11 +test.x_file_lookup[2] = 10 diff --git a/test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/monte_values_all_runs b/test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/monte_values_all_runs new file mode 100644 index 00000000..4eb16b27 --- /dev/null +++ b/test/SIM_mc_generation/verif_data/MONTE_RUN_file_sequential/monte_values_all_runs @@ -0,0 +1,10 @@ +0, 2, 1, 0 +1, 12, 11, 10 +2, 22, 21, 20 +3, 32, 31, 30 +4, 2, 1, 0 +5, 12, 11, 10 +6, 22, 21, 20 +7, 32, 31, 30 +8, 2, 1, 0 +9, 12, 11, 10 diff --git a/test/SIM_mc_generation/verif_data/MONTE_RUN_nominal/MonteCarlo_Meta_data_output b/test/SIM_mc_generation/verif_data/MONTE_RUN_nominal/MonteCarlo_Meta_data_output new file mode 100644 index 00000000..c4743ab8 --- /dev/null +++ b/test/SIM_mc_generation/verif_data/MONTE_RUN_nominal/MonteCarlo_Meta_data_output @@ -0,0 +1,74 @@ + + +*************************** SUMMARY ************************** +21 total assignments + - 4 constant values + - 1 calculated variables + - 3 prescribed (file-based) variables + - 11 random variables + - 2 files for execution + - 0 variables of undefined type + +********************* LIST OF VARIABLES, TYPES**************** +test.x_boolean, Random +test.x_file_lookup[0], Prescribed +test.x_file_lookup[1], Prescribed +test.x_file_lookup[2], Prescribed +test.x_fixed_value_double, Constant +test.x_fixed_value_int, Constant +test.x_fixed_value_string, Constant +test.x_integer, Random +test.x_line_command, Calculated +test.x_normal, Random +test.x_normal_length, Random +test.x_normal_trunc[0], Random +test.x_normal_trunc[1], Random +test.x_normal_trunc[2], Random +test.x_normal_trunc[3], Random +test.x_normal_trunc[4], Random +test.x_semi_fixed_value, Constant +test.x_string, Random +test.x_uniform, Random +************************************************************** + + +*********** LIST OF EXECUTABLE FILES AND FUNCTIONS *********** +test.standalone_function( test.x_normal) +*** +Modified_data/sample.py +*** +************************************************************** + + +***** LIST OF DATA FILES AND THE VARIABLES THEY POPULATE ***** +****** +Modified_data/datafile.txt +1 test.x_file_lookup[2] +2 test.x_file_lookup[1] +3 test.x_file_lookup[0] +************************************************************** + + +*****Duplicate seeds; check for intentional correlations***** +2 test.x_normal +2 test.x_normal_trunc[0] +2 test.x_normal_trunc[1] +2 test.x_normal_trunc[2] +2 test.x_normal_trunc[3] +2 test.x_normal_trunc[4] +2 test.x_normal_length +************************************************************** + + +************************ ALL SEEDS ************************* +0 test.x_uniform +1 test.x_integer +2 test.x_normal +2 test.x_normal_trunc[0] +2 test.x_normal_trunc[1] +2 test.x_normal_trunc[2] +2 test.x_normal_trunc[3] +2 test.x_normal_trunc[4] +2 test.x_normal_length +3 test.x_string +4 test.x_boolean diff --git a/test/SIM_mc_generation/verif_data/MONTE_RUN_nominal/monte_variables b/test/SIM_mc_generation/verif_data/MONTE_RUN_nominal/monte_variables new file mode 100644 index 00000000..2a836cdf --- /dev/null +++ b/test/SIM_mc_generation/verif_data/MONTE_RUN_nominal/monte_variables @@ -0,0 +1,17 @@ +run_number +test.x_uniform, +test.x_normal, +test.x_normal_trunc[0], +test.x_normal_trunc[1], +test.x_normal_trunc[2], +test.x_normal_trunc[3], +test.x_normal_trunc[4], +test.x_normal_length, ft +test.x_integer, +test.x_boolean, +test.x_file_lookup[0], +test.x_file_lookup[1], +test.x_file_lookup[2], +test.x_fixed_value_int, +test.x_fixed_value_double, +test.x_semi_fixed_value, diff --git a/test/SIM_mc_generation/verif_data/MONTE_RUN_remove_variable/RUN_both_variables/monte_variables b/test/SIM_mc_generation/verif_data/MONTE_RUN_remove_variable/RUN_both_variables/monte_variables new file mode 100644 index 00000000..a3d0916b --- /dev/null +++ b/test/SIM_mc_generation/verif_data/MONTE_RUN_remove_variable/RUN_both_variables/monte_variables @@ -0,0 +1,3 @@ +run_number +test.x_uniform, +test.x_fixed_value_int, diff --git a/test/SIM_mc_generation/verif_data/MONTE_RUN_remove_variable/RUN_one_variable/monte_variables b/test/SIM_mc_generation/verif_data/MONTE_RUN_remove_variable/RUN_one_variable/monte_variables new file mode 100644 index 00000000..0e31b6c5 --- /dev/null +++ b/test/SIM_mc_generation/verif_data/MONTE_RUN_remove_variable/RUN_one_variable/monte_variables @@ -0,0 +1,2 @@ +run_number +test.x_uniform, diff --git a/test/SIM_mc_generation/verif_data/MonteCarlo_Meta_data_output b/test/SIM_mc_generation/verif_data/MonteCarlo_Meta_data_output new file mode 100644 index 00000000..bbe69dd8 --- /dev/null +++ b/test/SIM_mc_generation/verif_data/MonteCarlo_Meta_data_output @@ -0,0 +1,78 @@ +Generating meta-data on the current configuration. +The input files have not yet been generated which means this +configuration has not been finalized and is subject to change. +Sending meta-data to top-level directory. + + +*************************** SUMMARY ************************** +21 total assignments + - 4 constant values + - 1 calculated variables + - 3 prescribed (file-based) variables + - 11 random variables + - 2 files for execution + - 0 variables of undefined type + +********************* LIST OF VARIABLES, TYPES**************** +test.x_boolean, Random +test.x_file_lookup[0], Prescribed +test.x_file_lookup[1], Prescribed +test.x_file_lookup[2], Prescribed +test.x_fixed_value_double, Constant +test.x_fixed_value_int, Constant +test.x_fixed_value_string, Constant +test.x_integer, Random +test.x_line_command, Calculated +test.x_normal, Random +test.x_normal_length, Random +test.x_normal_trunc[0], Random +test.x_normal_trunc[1], Random +test.x_normal_trunc[2], Random +test.x_normal_trunc[3], Random +test.x_normal_trunc[4], Random +test.x_semi_fixed_value, Constant +test.x_string, Random +test.x_uniform, Random +************************************************************** + + +*********** LIST OF EXECUTABLE FILES AND FUNCTIONS *********** +test.standalone_function( test.x_normal) +*** +Modified_data/sample.py +*** +************************************************************** + + +***** LIST OF DATA FILES AND THE VARIABLES THEY POPULATE ***** +****** +Modified_data/datafile.txt +3 test.x_file_lookup[0] +2 test.x_file_lookup[1] +1 test.x_file_lookup[2] +************************************************************** + + +*****Duplicate seeds; check for intentional correlations***** +2 test.x_normal +2 test.x_normal_trunc[0] +2 test.x_normal_trunc[1] +2 test.x_normal_trunc[2] +2 test.x_normal_trunc[3] +2 test.x_normal_trunc[4] +2 test.x_normal_length +************************************************************** + + +************************ ALL SEEDS ************************* +0 test.x_uniform +1 test.x_integer +2 test.x_normal +2 test.x_normal_trunc[0] +2 test.x_normal_trunc[1] +2 test.x_normal_trunc[2] +2 test.x_normal_trunc[3] +2 test.x_normal_trunc[4] +2 test.x_normal_length +3 test.x_string +4 test.x_boolean diff --git a/test/SIM_python_namespace/RUN_test/unit_test.py b/test/SIM_python_namespace/RUN_test/unit_test.py index b50e2da3..00b5c529 100644 --- a/test/SIM_python_namespace/RUN_test/unit_test.py +++ b/test/SIM_python_namespace/RUN_test/unit_test.py @@ -43,6 +43,13 @@ def main(): yummy.yummy = trick.Foo.Doughnuts TRICK_EXPECT_EQ( yummy.yummy , 2, test_suite , "additional file in same namespace" ) + # new class from TrickFood + trickfood = trick.Food() + trickfood.print_me() + TRICK_EXPECT_EQ( trickfood.fast , 2, test_suite , "blank python_module statement" ) + trickfood.fast = trick.Pizza + TRICK_EXPECT_EQ( trickfood.fast , 0, test_suite , "blank python_module statement" ) + if __name__ == "__main__": main() diff --git a/test/SIM_python_namespace/S_define b/test/SIM_python_namespace/S_define index ff42c34c..ec9da89a 100644 --- a/test/SIM_python_namespace/S_define +++ b/test/SIM_python_namespace/S_define @@ -1,6 +1,6 @@ /************************TRICK HEADER************************* PURPOSE: - (blah blah blah) + (Test different combinations of Python modules and C++ namespaces) *************************************************************/ #include "sim_objects/default_trick_sys.sm" @@ -9,6 +9,7 @@ PURPOSE: ##include "FooInnerFood.hh" ##include "BarFood.hh" ##include "FooYummyFood.hh" +##include "TrickFood.hh" class SimObj : public Trick::SimObject { @@ -17,6 +18,7 @@ class SimObj : public Trick::SimObject { Foo::Inner::Food foo_inner_food ; Bar::Food bar_food ; Foo::YummyFood foo_yummyfood ; + Food trick_food; /** Constructor to add the jobs */ SimObj() { diff --git a/test/SIM_python_namespace/models/TrickFood.hh b/test/SIM_python_namespace/models/TrickFood.hh new file mode 100644 index 00000000..0a86c475 --- /dev/null +++ b/test/SIM_python_namespace/models/TrickFood.hh @@ -0,0 +1,32 @@ +/** +@file + +@verbatim +PURPOSE: (Test that an empty PYTHON_MODULE won't cause errors or have any effect.) +PYTHON_MODULE: () +@endverbatim +*******************************************************************************/ + +#ifndef TRICKFOOD_HH +#define TRICKFOOD_HH + +#include + + + +enum Fast { + Pizza, + Burger, + Taco +}; + +class Food { + public: + Food() : fast(Taco) {} + void print_me() { std::cout << "Food::print_me!" << std::endl; } + Fast fast; +}; + + +#endif + diff --git a/test/SIM_segments/models/SegmentedExecutive/src/SegmentedExecutive.cpp b/test/SIM_segments/models/SegmentedExecutive/src/SegmentedExecutive.cpp index 6efda5e5..6c72684f 100644 --- a/test/SIM_segments/models/SegmentedExecutive/src/SegmentedExecutive.cpp +++ b/test/SIM_segments/models/SegmentedExecutive/src/SegmentedExecutive.cpp @@ -154,7 +154,7 @@ int Trick::SegmentedExecutive::write_s_job_execution(FILE *fp) { /* Get full path to S_job_execution */ output_dir = command_line_args_get_output_dir() ; - sprintf(buf, "%s/S_job_execution", output_dir.c_str()); + snprintf(buf, sizeof(buf), "%s/S_job_execution", output_dir.c_str()); /* Reopen the S_job_execution file. If it fails, it's not a fatal error, return 0. */ if ((fp = fopen(buf, "a")) == NULL) { diff --git a/test/SIM_stls/RUN_test/input.py b/test/SIM_stls/RUN_test/input.py index 458f7730..40dffd39 100644 --- a/test/SIM_stls/RUN_test/input.py +++ b/test/SIM_stls/RUN_test/input.py @@ -1,17 +1,7 @@ def main(): - #trick.echo_jobs_on() - #trick.sim_control_panel_set_enabled(True) - #trick.real_time_enable() - #trick.itimer_enable() - - trick.checkpoint_pre_init(True) - #trick.checkpoint_post_init(True) - #trick.checkpoint_end(True) - - #trick.freeze(2.0) trick.exec_set_software_frame(0.10) trick.exec_set_freeze_frame(0.10) diff --git a/test/SIM_stls/RUN_test/setup.py b/test/SIM_stls/RUN_test/setup.py new file mode 100644 index 00000000..208d871f --- /dev/null +++ b/test/SIM_stls/RUN_test/setup.py @@ -0,0 +1,15 @@ +import trick + +def main(): + trick.exec_set_job_onoff("the_object.stlc.addData", 1, True) + trick.exec_set_job_onoff("the_object.stlc.test", 1, False) + trick.exec_set_job_onoff("the_object.stlc.print", 1, False) + + trick.add_read( 0.5, 'trick.checkpoint("chkpnt_in")') + + trick.exec_set_freeze_frame(0.10) + trick.stop(1.0) + +if __name__ == "__main__": + main() + diff --git a/test/SIM_stls/RUN_test/unit_test.py b/test/SIM_stls/RUN_test/unit_test.py index 6f11ebd5..16c31069 100644 --- a/test/SIM_stls/RUN_test/unit_test.py +++ b/test/SIM_stls/RUN_test/unit_test.py @@ -1,12 +1,20 @@ +import trick +from trick.unit_test import * def main(): - trick.checkpoint_post_init(True) - trick.checkpoint_end(True) + trick.load_checkpoint("RUN_test/chkpnt_in") + trick.load_checkpoint_job() - # Data recording HDF5 test - trick.exec_set_freeze_frame(0.10) - trick.stop(5.0) + trick.exec_set_job_onoff("the_object.stlc.addData", 1, False) + trick.exec_set_job_onoff("the_object.stlc.test", 1, True) + trick.exec_set_job_onoff("the_object.stlc.print", 1, False) + + trick_utest.unit_tests.enable() + trick_utest.unit_tests.set_file_name( os.getenv("TRICK_HOME") + "/trick_test/SIM_stl.xml" ) + trick_utest.unit_tests.set_test_name( "STLCheckpointTest" ) + + trick.stop(1.0) if __name__ == "__main__": main() diff --git a/test/SIM_stls/S_define b/test/SIM_stls/S_define index 908cbe15..7e377dc6 100644 --- a/test/SIM_stls/S_define +++ b/test/SIM_stls/S_define @@ -8,10 +8,15 @@ class theSimObject : public Trick::SimObject { STLCheckpoint stlc ; /** Constructor to add the jobs */ - theSimObject() : stlc("Petunia") { - (1.0, "scheduled") stlc.speak() ; + theSimObject() : stlc() { + ("initialization") stlc.addData(); + (1.0, "scheduled") stlc.test () ; + (1.0, "scheduled") stlc.print () ; + } + + } ; theSimObject the_object ; diff --git a/test/SIM_stls/S_overrides.mk b/test/SIM_stls/S_overrides.mk index c4c9b818..5587ab4f 100644 --- a/test/SIM_stls/S_overrides.mk +++ b/test/SIM_stls/S_overrides.mk @@ -2,4 +2,9 @@ TRICK_CFLAGS += -I./models TRICK_CXXFLAGS += -I./models -#TRICK_CXXFLAGS += -std=c++11 +TRICK_CXXFLAGS += -std=c++11 + +clean: checkpoint_clean + +checkpoint_clean: + rm -f RUN_test/chkpnt_in diff --git a/test/SIM_stls/models/STLCheckpoint.cpp b/test/SIM_stls/models/STLCheckpoint.cpp index 1fcca9e9..1e9839dc 100644 --- a/test/SIM_stls/models/STLCheckpoint.cpp +++ b/test/SIM_stls/models/STLCheckpoint.cpp @@ -1,19 +1,34 @@ #include "sim_services/Message/include/message_proto.h" #include "STLCheckpoint.hh" - +#include "trick/memorymanager_c_intf.h" +#include +#include +#include "sim_services/UnitTest/include/trick_tests.h" /* These 2 constructors add different data to an STLCheckpoint. */ STLCheckpoint::STLCheckpoint() { return ; } -STLCheckpoint::STLCheckpoint(std::string in_name) : - vector_vector_double(4, std::vector(3)) , - vector_vector_vector_double(5, std::vector >(4, std::vector(3))) -{ +template +void compare_data_structures_with_top(T a, T b, std::string test_name) { + const char *test_suite = "STLCheckpoint"; - name = in_name ; + TRICK_EXPECT_EQ(a.size(), b.size(), test_suite, test_name.c_str()); + while (!a.empty()) { + TRICK_EXPECT_EQ(a.top(), b.top(), test_suite, test_name.c_str()); + a.pop(); + b.pop(); + } +} + +int STLCheckpoint::addData() { + dataJobRun = true; + vector_vector_double = std::vector< std::vector< double > >(4, std::vector(3)); + vector_vector_vector_double = std::vector< std::vector< std::vector< double > > >(5, std::vector >(4, std::vector(3))); + + std::cout << "Adding hardcoded data to sim" << std::endl; double_map[44.4] = 444.4 ; double_map[55.5] = 555.5 ; @@ -55,15 +70,24 @@ STLCheckpoint::STLCheckpoint(std::string in_name) : v.push_back(60) ; common_multiples.insert(std::pair< std::pair< int, int >, std::vector< int > >(p,v)) ; + p.first = 3 ; + p.second = 7 ; + v.clear() ; + v.push_back(21) ; + v.push_back(42) ; + v.push_back(84) ; + v.push_back(168) ; + common_multiples.insert(std::pair< std::pair< int, int >, std::vector< int > >(p,v)) ; + string_map[std::string("sister")] = std::string("Lisa") ; string_map[std::string("dog")] = std::string("Santa's Little Helper") ; int_multimap.insert(std::pair(44,444)) ; int_multimap.insert(std::pair(55,555)) ; int_multimap.insert(std::pair(66,666)) ; - int_multimap.insert(std::pair(44,444)) ; - int_multimap.insert(std::pair(55,555)) ; - int_multimap.insert(std::pair(66,666)) ; + int_multimap.insert(std::pair(44,4444)) ; + int_multimap.insert(std::pair(55,5555)) ; + int_multimap.insert(std::pair(66,6666)) ; string_key_multimap.insert(std::pair("four", 4)) ; string_key_multimap.insert(std::pair("five", 5)) ; @@ -118,6 +142,37 @@ STLCheckpoint::STLCheckpoint(std::string in_name) : string_set.insert("abc") ; string_set.insert("def") ; + for (int j = 0; j < 5; j++) { + std::vector temp; + for (int i = j; i < 10; i++) { + temp.push_back(i); + } + vector_set.insert(temp); + } + + pair_set.emplace("One", 1); + pair_set.emplace("Two", 2); + pair_set.emplace("Three", 3); + + std::map m; + m[5] = 500.5; + m[1] = 100.1; + std::map m2; + m2[5] = 5000.5; + m2[1] = 1000.1; + + nested_map_set.insert(m); + nested_map_set.insert(m2); + + for (int j = 0; j < 5; j++) { + std::vector temp; + for (int i = j; i < 10; i++) { + temp.push_back(i); + } + vector_queue.push(temp); + } + + long_multiset.insert(8000) ; long_multiset.insert(4000) ; long_multiset.insert(4000) ; @@ -131,6 +186,16 @@ STLCheckpoint::STLCheckpoint(std::string in_name) : string_multiset.insert("abc") ; string_multiset.insert("def") ; + pair_multiset.emplace(5, 5); + pair_multiset.emplace(5, 5); + pair_multiset.emplace(5, 4); + pair_multiset.emplace(4, 4); + + vec_multiset.emplace(std::vector({1,2,3,4})); + vec_multiset.emplace(std::vector({1,2,3,4})); + vec_multiset.emplace(std::vector({1,2,3,4,5})); + + uint_stack.push(1) ; uint_stack.push(2) ; uint_stack.push(3) ; @@ -141,8 +206,10 @@ STLCheckpoint::STLCheckpoint(std::string in_name) : string_stack.push("with the bigger") ; string_stack.push("Gee Bees") ; - stack_vector_int.push(v) ; - stack_vector_int.push(v) ; + std::vector temp_v1 = {1, 2, 3, 4}; + std::vector temp_v2 = {5, 6, 7, 8}; + stack_vector_int.push(temp_v1) ; + stack_vector_int.push(temp_v2) ; int_queue.push(1) ; int_queue.push(2) ; @@ -164,11 +231,11 @@ STLCheckpoint::STLCheckpoint(std::string in_name) : string_priority_queue.push("an") ; string_priority_queue.push("iPhone 4") ; - queue_vector_int.push(v) ; - queue_vector_int.push(v) ; + queue_vector_int.push(temp_v1) ; + queue_vector_int.push(temp_v2) ; - priority_queue_vector_int.push(v) ; - priority_queue_vector_int.push(v) ; + priority_queue_vector_int.push(temp_v1) ; + priority_queue_vector_int.push(temp_v2) ; int_pair.first = 10 ; int_pair.second = 20 ; @@ -197,6 +264,27 @@ STLCheckpoint::STLCheckpoint(std::string in_name) : pair_pair_pair.second.first = 53 ; pair_pair_pair.second.second = 54 ; + int_vec_pair.first = 5; + int_vec_pair.second.push_back(5); + int_vec_pair.second.push_back(10); + int_vec_pair.second.push_back(15); + int_vec_pair.second.push_back(20); + + vec_int_pair.second = 5; + vec_int_pair.first.push_back(5); + vec_int_pair.first.push_back(10); + vec_int_pair.first.push_back(15); + vec_int_pair.first.push_back(20); + + vec_vec_pair.first.push_back(5); + vec_vec_pair.first.push_back(10); + vec_vec_pair.first.push_back(15); + vec_vec_pair.first.push_back(20); + vec_vec_pair.second.push_back(5); + vec_vec_pair.second.push_back(10); + vec_vec_pair.second.push_back(15); + vec_vec_pair.second.push_back(20); + vector_vector_double[0][0] = 100 ; vector_vector_double[0][1] = 101 ; vector_vector_double[0][2] = 102 ; @@ -275,30 +363,401 @@ STLCheckpoint::STLCheckpoint(std::string in_name) : vector_vector_vector_double[4][3][1] = 4010 ; vector_vector_vector_double[4][3][2] = 4011 ; - return ; + for (int i = 0; i < 10; i++) { + UserClass temp; + for (int j = 0; j < 5; j++) { + temp.a[j] = i+j; + } + temp.b = 8888888888; + temp.c = "Here is a test string"; + + // We'll just make a pointer to the same stuff + + UserClass * user_class_ptr = (UserClass *) TMM_declare_var_s("UserClass"); + for (int j = 0; j < 5; j++) { + user_class_ptr->a[j] = i+j; + } + user_class_ptr->b = 8888888888; + user_class_ptr->c = "Here is a test string"; + + temp.d = user_class_ptr; + + vec_user_simple.emplace_back(temp); + } + + for (int i = 0; i < 10; i++) { + SimpleWrapper temp_wrapper; + temp_wrapper.a = 888; + for (int j = i; j < i+10; j++) { + temp_wrapper.vec.push_back(j); + } + vec_user_defined.emplace_back(temp_wrapper); + } + + for (int i = 0; i < 10; i++) { + SimpleWrapper * temp_wrapper = (SimpleWrapper *) TMM_declare_var_s("SimpleWrapper"); + temp_wrapper->a = 888; + for (int j = i; j < i+10; j++) { + temp_wrapper->vec.push_back(j); + } + vec_user_defined_ptr.push_back(temp_wrapper); + } + + return 0; } -int STLCheckpoint::speak() { - //message_publish(1,"Quack!\n") ; - //message_publish(1,"double_vector: %f %f %f\n", double_vector[0], double_vector[1], double_vector[2]) ; - //message_publish(1,"vector_vector_double[1]: %f %f %f\n", - // vector_vector_double[1][0], vector_vector_double[1][1], vector_vector_double[1][2]) ; - //message_publish(1,"vector_vector_vector_double[4][2]: %f %f %f\n", - // vector_vector_vector_double[4][2][0], vector_vector_vector_double[4][2][1], vector_vector_vector_double[4][2][2]) ; - //message_publish(1,"string_vector[0]: %s\n", string_vector[0].c_str()) ; - //message_publish(1,"map_int_vector_int[1][1] = %d\n", map_int_vector_int[1][1]) ; - //message_publish(1,"gcd = %d\n", gcd[std::pair(24,30)]) ; - //message_publish(1,"common_multiples = %d\n", common_multiples[std::pair(3,5)][1]) ; - //message_publish(1,"common_multiples = %d\n", common_multiples[std::pair(3,5)][1]) ; - //message_publish(1,"int_pair_int_int.second.second = %d\n", int_pair_int_int.second.second) ; - //message_publish(1,"pair_int_int_int.first.second = %d\n", pair_int_int_int.first.second) ; - //message_publish(1,"pair_pair_pair.second.first = %d\n", pair_pair_pair.second.first) ; - //message_publish(1,"int_queue.front = %d\n", int_queue.front()) ; - //message_publish(1,"int_priority_queue.top = %d\n", int_priority_queue.top()) ; - //message_publish(1,"uint_stack.top = %d\n", uint_stack.top()) ; - //message_publish(1,"queue_vector_int.front()[3] = %d\n", queue_vector_int.front()[3]) ; - //message_publish(1,"priority_queue_vector_int.top()[2] = %d\n", priority_queue_vector_int.top()[2]) ; +int STLCheckpoint::print() { + message_publish(1,"Quack!\n") ; + message_publish(1, "Double vector size: %d", double_vector.size() ); + message_publish(1,"double_vector: %f %f %f\n", double_vector[0], double_vector[1], double_vector[2]) ; + message_publish(1,"vector_vector_double[1]: %f %f %f\n", + vector_vector_double[1][0], vector_vector_double[1][1], vector_vector_double[1][2]) ; + message_publish(1,"vector_vector_vector_double[4][2]: %f %f %f\n", + vector_vector_vector_double[4][2][0], vector_vector_vector_double[4][2][1], vector_vector_vector_double[4][2][2]) ; + message_publish(1,"string_vector[0]: %s\n", string_vector[0].c_str()) ; + message_publish(1,"map_int_vector_int[1][1] = %d\n", map_int_vector_int[1][1]) ; + message_publish(1,"gcd = %d\n", gcd[std::pair(24,30)]) ; + message_publish(1,"common_multiples = %d\n", common_multiples[std::pair(3,5)][1]) ; + message_publish(1,"common_multiples = %d\n", common_multiples[std::pair(3,5)][1]) ; + message_publish(1,"int_pair_int_int.second.second = %d\n", int_pair_int_int.second.second) ; + message_publish(1,"pair_int_int_int.first.second = %d\n", pair_int_int_int.first.second) ; + message_publish(1,"pair_pair_pair.second.first = %d\n", pair_pair_pair.second.first) ; + message_publish(1,"int_queue.front = %d\n", int_queue.front()) ; + message_publish(1,"int_priority_queue.top = %d\n", int_priority_queue.top()) ; + message_publish(1,"uint_stack.top = %d\n", uint_stack.top()) ; + message_publish(1,"queue_vector_int.front()[3] = %d\n", queue_vector_int.front()[3]) ; + message_publish(1,"priority_queue_vector_int.top()[2] = %d\n", priority_queue_vector_int.top()[2]) ; message_publish(1,"stack_vector_int.top()[1] = %d\n", stack_vector_int.top()[1]) ; return 0 ; } +int STLCheckpoint::test() { + std::cout << "Running test jobs" << std::endl; + const char *test_suite = "STLCheckpoint"; + + TRICK_EXPECT_EQ( double_vector.size(), 3, test_suite, "double_vector size"); + TRICK_EXPECT_EQ( double_vector[0], 4, test_suite, "double_vector[0]"); + TRICK_EXPECT_EQ( double_vector[1], 5, test_suite, "double_vector[1]"); + TRICK_EXPECT_EQ( double_vector[2], 6, test_suite, "double_vector[2]"); + TRICK_EXPECT_EQ( vector_vector_double[1][0], 103, test_suite, "vector_vector_double[1][0]"); + TRICK_EXPECT_EQ( vector_vector_double[1][1], 104, test_suite, "vector_vector_double[1][1]"); + TRICK_EXPECT_EQ( vector_vector_double[1][2], 105, test_suite, "vector_vector_double[1][2]"); + TRICK_EXPECT_EQ( vector_vector_vector_double[4][2][0], 4006, test_suite, "vector_vector_vector_double[4][2][0]"); + TRICK_EXPECT_EQ( vector_vector_vector_double[4][2][1], 4007, test_suite, "vector_vector_vector_double[4][2][1]"); + TRICK_EXPECT_EQ( vector_vector_vector_double[4][2][2], 4008, test_suite, "vector_vector_vector_double[4][2][2]"); + TRICK_EXPECT_EQ( string_vector[0], std::string("It"), test_suite, "string_vector"); + + TRICK_EXPECT_EQ( double_map[44.4], 444.4, test_suite, "double_map[44.4]" ); + + TRICK_EXPECT_EQ( string_data_map[7], std::string("seiben"), test_suite, "string_data_map[7]" ); + TRICK_EXPECT_EQ( string_data_map[9], std::string("neun") , test_suite, "string_data_map[9]"); + + std::vector< int > v ; + v.push_back(2) ; + v.push_back(4) ; + v.push_back(6) ; + v.push_back(8) ; + TRICK_EXPECT_EQ( map_int_vector_int[1], v, test_suite, "map_int_vector_int[1]"); + + std::pair< int , int > p ; + p.first = 24 ; + p.second = 30 ; + TRICK_EXPECT_EQ(gcd[p], 6, test_suite, "gcd[p]" ); + + p.first = 50 ; + p.second = 60 ; + std::pair< int , int > q ; + q.first = 70 ; + q.second = 80 ; + TRICK_EXPECT_EQ( map_pair_pair[p], q, test_suite, "map_pair_pair[p]" ); + + p.first = 3 ; + p.second = 5 ; + v.clear() ; + v.push_back(15) ; + v.push_back(30) ; + v.push_back(45) ; + v.push_back(60) ; + TRICK_EXPECT_EQ( common_multiples[p], v, test_suite, "common_multiples" ); + + p.first = 3 ; + p.second = 7 ; + v.clear() ; + v.push_back(21) ; + v.push_back(42) ; + v.push_back(84) ; + v.push_back(168) ; + TRICK_EXPECT_EQ( common_multiples[p], v, test_suite, "common_multiples" ); + + + TRICK_EXPECT_EQ( string_map["sister"], "Lisa", test_suite, "string_map[sister]" ); + TRICK_EXPECT_EQ( string_map["dog"], "Santa's Little Helper", test_suite, "string_map[dog]" ); + + + // The easiest way to test the multimaps is to just rebuild copies and compare + std::multimap int_multimap_copy; + int_multimap_copy.insert(std::pair(44,444)) ; + int_multimap_copy.insert(std::pair(55,555)) ; + int_multimap_copy.insert(std::pair(66,666)) ; + int_multimap_copy.insert(std::pair(44,4444)) ; + int_multimap_copy.insert(std::pair(55,5555)) ; + int_multimap_copy.insert(std::pair(66,6666)) ; + TRICK_EXPECT_EQ(int_multimap, int_multimap_copy , test_suite, "int_multimap"); + + int_multimap_copy.insert(std::pair(66,66666)) ; + TRICK_EXPECT_NE(int_multimap, int_multimap_copy , test_suite, "int_multimap_fail"); + + std::multimap string_key_multimap_copy; + string_key_multimap_copy.insert(std::pair("four", 4)) ; + string_key_multimap_copy.insert(std::pair("five", 5)) ; + string_key_multimap_copy.insert(std::pair("six", 6)) ; + string_key_multimap_copy.insert(std::pair("four", 44)) ; + string_key_multimap_copy.insert(std::pair("five", 55)) ; + string_key_multimap_copy.insert(std::pair("six", 66)) ; + TRICK_EXPECT_EQ(string_key_multimap, string_key_multimap_copy , test_suite, "string_key_multimap"); + + std::multimap string_data_multimap_copy; + string_data_multimap_copy.insert(std::pair(7, "seiben")) ; + string_data_multimap_copy.insert(std::pair(8, "acht")) ; + string_data_multimap_copy.insert(std::pair(9, "neun")) ; + string_data_multimap_copy.insert(std::pair(7, "seven")) ; + string_data_multimap_copy.insert(std::pair(8, "eight")) ; + string_data_multimap_copy.insert(std::pair(9, "nine")) ; + TRICK_EXPECT_EQ(string_data_multimap, string_data_multimap_copy , test_suite, "string_data_multimap"); + + std::multimap string_multimap_copy; + string_multimap_copy.insert(std::pair("sister","Lisa")) ; + string_multimap_copy.insert(std::pair("dog","Santa's Little Helper")) ; + string_multimap_copy.insert(std::pair("sister","Meg")) ; + string_multimap_copy.insert(std::pair("dog","Brian")) ; + TRICK_EXPECT_EQ(string_multimap, string_multimap_copy , test_suite, "string_multimap"); + + + // TODO: fix this case + // TRICK_EXPECT_EQ(vec_user_defined.size(), 10, test_suite, "vec_user_defined"); + // for (int i = 0; i < vec_user_defined.size(); i++) { + // TRICK_EXPECT_EQ(vec_user_defined[i].vec.size(), 10, test_suite, "vec_user_defined"); + // TRICK_EXPECT_EQ(vec_user_defined[i].a, 888, test_suite, "vec_user_defined"); + // for (int j = i; j < i+vec_user_defined[i].vec.size(); j++) { + // TRICK_EXPECT_EQ(vec_user_defined[i].vec[j-i], j, test_suite, "vec_user_defined"); + // } + // } + + TRICK_EXPECT_EQ(vec_user_defined_ptr.size(), 10, test_suite, "vec_user_defined_ptr"); + for (int i = 0; i < vec_user_defined_ptr.size(); i++) { + TRICK_EXPECT_EQ(vec_user_defined_ptr[i]->vec.size(), 10, test_suite, "vec_user_defined_ptr"); + TRICK_EXPECT_EQ(vec_user_defined_ptr[i]->a, 888, test_suite, "vec_user_defined_ptr"); + std::vector test_vec; + for (int j = i; j < i+vec_user_defined_ptr[i]->vec.size(); j++) { + test_vec.push_back(j); + } + TRICK_EXPECT_EQ(vec_user_defined_ptr[i]->vec, test_vec, test_suite, "vec_user_defined_ptr"); + } + + + std::vector string_vector_copy = {"It", "has", "the", "Wi-Fies"}; + TRICK_EXPECT_EQ(string_vector, string_vector_copy, test_suite, "string_vector"); + + std::list short_list_copy = {400, 401, 402}; + int list_index = 0; + TRICK_EXPECT_EQ(short_list, short_list_copy, test_suite, "short_list"); + + std::list string_list_copy = {"I", "don't", "care"}; + TRICK_EXPECT_EQ(string_list, string_list_copy, test_suite, "string_list"); + + std::deque float_deque_copy = {98.7, 65.4, 32.1}; + TRICK_EXPECT_EQ(float_deque, float_deque_copy, test_suite, "float_deque"); + + std::deque string_deque_copy = {"Welcome", "to", "PhoneMart"}; + TRICK_EXPECT_EQ(string_deque, string_deque_copy, test_suite, "string_deque"); + + std::set int_set_copy = {8000, 4000, 2000, 1000}; + TRICK_EXPECT_EQ(int_set, int_set_copy, test_suite, "int_set"); + + std::set string_set_copy = {"efg", "abc", "def"}; + TRICK_EXPECT_EQ(string_set, string_set_copy, test_suite, "string_set"); + + std::set> vector_set_copy; + for (int j = 0; j < 5; j++) { + std::vector temp; + for (int i = j; i < 10; i++) { + temp.push_back(i); + } + vector_set_copy.insert(temp); + } + TRICK_EXPECT_EQ(vector_set, vector_set_copy, test_suite, "vector_set"); + + std::set> pair_set_copy; + pair_set_copy.emplace("One", 1); + pair_set_copy.emplace("Two", 2); + pair_set_copy.emplace("Three", 3); + TRICK_EXPECT_EQ(pair_set, pair_set_copy, test_suite, "pair_set"); + + std::set> nested_map_set_copy; + std::map m; + m[5] = 500.5; + m[1] = 100.1; + std::map m2; + m2[5] = 5000.5; + m2[1] = 1000.1; + nested_map_set_copy.insert(m); + nested_map_set_copy.insert(m2); + TRICK_EXPECT_EQ(nested_map_set, nested_map_set_copy, test_suite, "nested_map_set"); + + std::queue> vector_queue_copy; + for (int j = 0; j < 5; j++) { + std::vector temp; + for (int i = j; i < 10; i++) { + temp.push_back(i); + } + vector_queue_copy.push(temp); + } + TRICK_EXPECT_EQ(vector_queue, vector_queue_copy, test_suite, "vector_queue"); + + std::multiset long_multiset_copy = {8000, 4000, 4000, 2000, 1000}; + TRICK_EXPECT_EQ(long_multiset, long_multiset_copy, test_suite, "long_multiset"); + + std::multiset string_multiset_copy = {"efg", "abc", "def", "efg", "abc", "def"}; + TRICK_EXPECT_EQ(string_multiset, string_multiset_copy, test_suite, "string_multiset"); + + std::multiset> pair_multiset_copy; + pair_multiset_copy.emplace(5, 5); + pair_multiset_copy.emplace(5, 5); + pair_multiset_copy.emplace(5, 4); + pair_multiset_copy.emplace(4, 4); + TRICK_EXPECT_EQ(pair_multiset, pair_multiset_copy, test_suite, "pair_multiset"); + + std::multiset> vec_multiset_copy; + vec_multiset_copy.emplace(std::vector({1,2,3,4})); + vec_multiset_copy.emplace(std::vector({1,2,3,4})); + vec_multiset_copy.emplace(std::vector({1,2,3,4,5})); + TRICK_EXPECT_EQ(vec_multiset, vec_multiset_copy, test_suite, "vec_multiset"); + + std::stack uint_stack_copy; + uint_stack_copy.push(1) ; + uint_stack_copy.push(2) ; + uint_stack_copy.push(3) ; + uint_stack_copy.push(4) ; + TRICK_EXPECT_EQ(uint_stack, uint_stack_copy, test_suite, "uint_stack"); + + std::stack string_stack_copy; + string_stack_copy.push("I") ; + string_stack_copy.push("want the one") ; + string_stack_copy.push("with the bigger") ; + string_stack_copy.push("Gee Bees") ; + TRICK_EXPECT_EQ(string_stack, string_stack_copy, test_suite, "string_stack"); + + std::stack> stack_vector_int_copy; + std::vector temp_v1 = {1, 2, 3, 4}; + std::vector temp_v2 = {5, 6, 7, 8}; + stack_vector_int_copy.emplace(temp_v1) ; + stack_vector_int_copy.emplace(temp_v2) ; + TRICK_EXPECT_EQ(stack_vector_int, stack_vector_int_copy, test_suite, "stack_vector_int"); + + std::queue int_queue_copy; + int_queue_copy.push(1) ; + int_queue_copy.push(2) ; + int_queue_copy.push(3) ; + int_queue_copy.push(4) ; + TRICK_EXPECT_EQ(int_queue, int_queue_copy, test_suite, "int_queue"); + + std::queue string_queue_copy; + string_queue_copy.push("I") ; + string_queue_copy.push("want") ; + string_queue_copy.push("an") ; + string_queue_copy.push("iPhone 4") ; + TRICK_EXPECT_EQ(string_queue, string_queue_copy, test_suite, "string_queue"); + + // Why doesn't priority_queue have the == operator but literally everything else does >:( + std::priority_queue int_priority_queue_copy; + int_priority_queue_copy.push(3) ; + int_priority_queue_copy.push(2) ; + int_priority_queue_copy.push(4) ; + int_priority_queue_copy.push(1) ; + compare_data_structures_with_top(int_priority_queue_copy, int_priority_queue, "int_priority_queue"); + + std::priority_queue string_priority_queue_copy; + string_priority_queue_copy.push("I") ; + string_priority_queue_copy.push("want") ; + string_priority_queue_copy.push("an") ; + string_priority_queue_copy.push("iPhone 4") ; + compare_data_structures_with_top(string_priority_queue_copy, string_priority_queue, "string_priority_queue"); + + std::queue> queue_vector_int_copy; + queue_vector_int_copy.emplace(temp_v1) ; + queue_vector_int_copy.emplace(temp_v2) ; + TRICK_EXPECT_EQ(queue_vector_int, queue_vector_int_copy, test_suite, "queue_vector_int"); + + std::priority_queue> priority_queue_vector_int_copy; + priority_queue_vector_int_copy.emplace(temp_v1) ; + priority_queue_vector_int_copy.emplace(temp_v2) ; + compare_data_structures_with_top(priority_queue_vector_int_copy, priority_queue_vector_int, "priority_queue_vector_int"); + + std::pair int_pair_copy(10,20); + TRICK_EXPECT_EQ(int_pair, int_pair_copy, test_suite, "int_pair"); + + std::pair< std::string , int > string_first_pair_copy ("string first", 25); + TRICK_EXPECT_EQ(string_first_pair, string_first_pair_copy, test_suite, "string_first_pair"); + + std::pair< int , std::string > string_second_pair_copy (25, "string second"); + TRICK_EXPECT_EQ(string_second_pair_copy, string_second_pair, test_suite, "string_second_pair"); + + std::pair< std::string , std::string > string_pair_copy ("pair first string", "pair second string"); + TRICK_EXPECT_EQ(string_pair_copy, string_pair, test_suite, "string_pair"); + + + std::pair< int , std::pair< int, int > > int_pair_int_int_copy; + int_pair_int_int_copy.first = 200 ; + p.first = 10 ; + p.second = 20 ; + int_pair_int_int_copy.second = p ; + TRICK_EXPECT_EQ(int_pair_int_int_copy, int_pair_int_int, test_suite, "int_pair_int_int"); + + std::pair< std::pair< int, int > , int > pair_int_int_int_copy; + p.first = 15 ; + p.second = 12 ; + pair_int_int_int_copy.first = p ; + pair_int_int_int_copy.second = 180 ; + TRICK_EXPECT_EQ(pair_int_int_int_copy, pair_int_int_int, test_suite, "pair_int_int_int"); + + std::pair< std::pair< int, int > , std::pair< int, int > > pair_pair_pair_copy ; + pair_pair_pair_copy.first.first = 51 ; + pair_pair_pair_copy.first.second = 52 ; + pair_pair_pair_copy.second.first = 53 ; + pair_pair_pair_copy.second.second = 54 ; + TRICK_EXPECT_EQ(pair_pair_pair_copy, pair_pair_pair, test_suite, "pair_pair_pair"); + + // Check all the int/vec combo pairs together, for laziness + TRICK_EXPECT_EQ(int_vec_pair.first, 5, test_suite, "int_vec_pair.first"); + TRICK_EXPECT_EQ(vec_int_pair.second, 5, test_suite, "vec_int_pair.second"); + + TRICK_EXPECT_EQ(int_vec_pair.second.size(), 4, test_suite, "int_vec_pair.second.size"); + TRICK_EXPECT_EQ(vec_int_pair.first.size(), 4, test_suite, "vec_int_pair.first.size"); + TRICK_EXPECT_EQ(vec_vec_pair.first.size(), 4, test_suite, "vec_vec_pair.first.size"); + TRICK_EXPECT_EQ(vec_vec_pair.second.size(), 4, test_suite, "vec_vec_pair.second.size"); + + for (int i = 0; i < int_vec_pair.second.size(); i++) { + TRICK_EXPECT_EQ(int_vec_pair.second[i], (i+1)*5, test_suite, "int_vec_pair.second elems"); + TRICK_EXPECT_EQ(vec_int_pair.first[i], (i+1)*5, test_suite, "vec_int_pair.first elems"); + TRICK_EXPECT_EQ(vec_vec_pair.first[i], (i+1)*5, test_suite, "vec_vec_pair.first elems"); + TRICK_EXPECT_EQ(vec_vec_pair.second[i], (i+1)*5, test_suite, "vec_vec_pair.second elems"); + + } + + + TRICK_EXPECT_EQ(vec_user_simple.size(), 10, test_suite, "vec_user_simple") + for (int i = 0; i < 10; i++) { + for (int j = 0; j < 5; j++) { + TRICK_EXPECT_EQ(vec_user_simple[i].a[j], i+j, test_suite, "vec_user_simple"); + TRICK_EXPECT_EQ(vec_user_simple[i].d->a[j], i+j, test_suite, "vec_user_simple"); + } + + TRICK_EXPECT_EQ(vec_user_simple[i].b, 8888888888, test_suite, "vec_user_simple"); + TRICK_EXPECT_EQ(vec_user_simple[i].d->b, 8888888888, test_suite, "vec_user_simple"); + + TRICK_EXPECT_EQ(vec_user_simple[i].c, "Here is a test string", test_suite, "vec_user_simple"); + TRICK_EXPECT_EQ(vec_user_simple[i].d->c, "Here is a test string", test_suite, "vec_user_simple"); + } + + +} diff --git a/test/SIM_stls/models/STLCheckpoint.hh b/test/SIM_stls/models/STLCheckpoint.hh index aca8de93..be61a8c0 100644 --- a/test/SIM_stls/models/STLCheckpoint.hh +++ b/test/SIM_stls/models/STLCheckpoint.hh @@ -18,13 +18,31 @@ #include #include + +class SimpleWrapper { + public: + int a; + std::vector vec; +}; + +class UserClass { + public: + int a[5]; + long long b; + std::string c; + UserClass * d; +}; + class STLCheckpoint { public: STLCheckpoint() ; - STLCheckpoint(std::string in_name) ; - int speak() ; + int addData() ; + int print() ; + int test() ; + + bool dataJobRun; std::string name ; @@ -54,9 +72,19 @@ class STLCheckpoint { std::set< int > int_set ; std::set< std::string > string_set ; + std::set< std::vector > vector_set; + std::set< std::pair > pair_set; + std::set> nested_map_set; + + + std::queue< std::vector > vector_queue; + std::multiset< long > long_multiset ; std::multiset< std::string > string_multiset ; + std::multiset< std::pair< int,int > > pair_multiset ; + std::multiset< std::vector< int > > vec_multiset ; + std::stack< unsigned int > uint_stack ; std::stack< std::string > string_stack ; @@ -76,6 +104,10 @@ class STLCheckpoint { std::pair< int , std::string > string_second_pair ; std::pair< std::string , std::string > string_pair ; + std::pair< int, std::vector > int_vec_pair; + std::pair< std::vector, int > vec_int_pair; + std::pair< std::vector, std::vector > vec_vec_pair; + std::pair< int , std::pair< int, int > > int_pair_int_int ; std::pair< std::pair< int, int > , int > pair_int_int_int ; @@ -84,6 +116,12 @@ class STLCheckpoint { std::vector< std::vector< double > > vector_vector_double ; std::vector< std::vector< std::vector< double > > > vector_vector_vector_double ; //std::vector< std::list< double > > vector_list_double ; + + std::vector vec_user_simple; + std::vector vec_user_defined; + std::vector vec_user_defined_ptr; + + } ; #endif diff --git a/test/SIM_target_specific_variables/S_overrides.mk b/test/SIM_target_specific_variables/S_overrides.mk index 11dd3924..372dc22d 100644 --- a/test/SIM_target_specific_variables/S_overrides.mk +++ b/test/SIM_target_specific_variables/S_overrides.mk @@ -2,7 +2,14 @@ MODELS :=$(CURDIR)/models # Warn about comment markers /* within comments and make them errors, causing # the build to fail. -TRICK_CXXFLAGS += -I$(MODELS) -Wcomment -Werror +TRICK_CXXFLAGS += -I$(MODELS) -Wcomment + +# We can't yet make warnings to be errors on MacOS, because +# MACOS deprecates and warns about sprintf. But SWIG +# still generates code containing sprintf.. +ifneq ($(TRICK_HOST_TYPE), Darwin) +TRICK_CXXFLAGS += -Werror +endif PATHS := $(MODELS)/many $(MODELS)/nested diff --git a/test/SIM_test_dr/Modified_data/dr_typesASCII.dr b/test/SIM_test_dr/Modified_data/dr_typesASCII.dr index 7d290b62..57635126 100644 --- a/test/SIM_test_dr/Modified_data/dr_typesASCII.dr +++ b/test/SIM_test_dr/Modified_data/dr_typesASCII.dr @@ -25,5 +25,14 @@ drg[DR_GROUP_ID].add_variable("drx.drt.k") drg[DR_GROUP_ID].add_variable("drx.drt.l") drg[DR_GROUP_ID].add_variable("drx.drt.m") drg[DR_GROUP_ID].add_variable("drx.drt.n") +drg[DR_GROUP_ID].add_variable("drx.drt.o") +drg[DR_GROUP_ID].add_variable("drx.drt.p") +drg[DR_GROUP_ID].add_variable("drx.drt.q[0]") +drg[DR_GROUP_ID].add_variable("drx.drt.q[1]") +drg[DR_GROUP_ID].add_variable("drx.drt.q[2]") +drg[DR_GROUP_ID].add_variable("drx.drt.q[3]") +drg[DR_GROUP_ID].add_variable("drx.drt.q[4]") +drg[DR_GROUP_ID].add_variable("drx.drt.r[0][0]") + trick.add_data_record_group(drg[DR_GROUP_ID], trick.DR_Buffer) drg[DR_GROUP_ID].enable() diff --git a/test/SIM_test_dr/Modified_data/dr_typesBINARY.dr b/test/SIM_test_dr/Modified_data/dr_typesBINARY.dr index 2afbec4e..6c2de8a9 100644 --- a/test/SIM_test_dr/Modified_data/dr_typesBINARY.dr +++ b/test/SIM_test_dr/Modified_data/dr_typesBINARY.dr @@ -25,5 +25,7 @@ drg[DR_GROUP_ID].add_variable("drx.drt.k") drg[DR_GROUP_ID].add_variable("drx.drt.l") drg[DR_GROUP_ID].add_variable("drx.drt.m") drg[DR_GROUP_ID].add_variable("drx.drt.n") +drg[DR_GROUP_ID].add_variable("drx.drt.o") +drg[DR_GROUP_ID].add_variable("drx.drt.p") trick.add_data_record_group(drg[DR_GROUP_ID], trick.DR_Buffer) drg[DR_GROUP_ID].enable() diff --git a/test/SIM_test_dr/RUN_test/Ref_Logs/log_DR_typesASCII_Master.csv b/test/SIM_test_dr/RUN_test/Ref_Logs/log_DR_typesASCII_Master.csv index b8b16b8a..4e7a07f8 100644 --- a/test/SIM_test_dr/RUN_test/Ref_Logs/log_DR_typesASCII_Master.csv +++ b/test/SIM_test_dr/RUN_test/Ref_Logs/log_DR_typesASCII_Master.csv @@ -1,12 +1,12 @@ -sys.exec.out.time {s},drx.drt.a {1},drx.drt.b {1},drx.drt.c {1},drx.drt.d {1},drx.drt.e {1},drx.drt.f {1},drx.drt.g {1},drx.drt.h {1},drx.drt.i {1},drx.drt.j {1},drx.drt.k {1},drx.drt.l {1},drx.drt.m {1},drx.drt.n {1} - 0,a,98,-1234,1234,-123456,123456,-1234567,123456789, 1234.5677, -1234.56789,-12345678912345,12345678912345,0,3 - 0.1,a,98,-1234,1234,-123456,123456,-1234567,123456789, 1234.5677, -1234.56789,-12345678912345,12345678912345,0,3 - 0.2,a,98,-1234,1234,-123456,123456,-1234567,123456789, 1234.5677, -1234.56789,-12345678912345,12345678912345,0,3 - 0.3,a,98,-1234,1234,-123456,123456,-1234567,123456789, 1234.5677, -1234.56789,-12345678912345,12345678912345,0,3 - 0.4,a,98,-1234,1234,-123456,123456,-1234567,123456789, 1234.5677, -1234.56789,-12345678912345,12345678912345,0,3 - 0.5,a,98,-1234,1234,-123456,123456,-1234567,123456789, 1234.5677, -1234.56789,-12345678912345,12345678912345,0,3 - 0.6,a,98,-1234,1234,-123456,123456,-1234567,123456789, 1234.5677, -1234.56789,-12345678912345,12345678912345,0,3 - 0.7,a,98,-1234,1234,-123456,123456,-1234567,123456789, 1234.5677, -1234.56789,-12345678912345,12345678912345,0,3 - 0.8,a,98,-1234,1234,-123456,123456,-1234567,123456789, 1234.5677, -1234.56789,-12345678912345,12345678912345,0,3 - 0.9,a,98,-1234,1234,-123456,123456,-1234567,123456789, 1234.5677, -1234.56789,-12345678912345,12345678912345,0,3 - 1,a,98,-1234,1234,-123456,123456,-1234567,123456789, 1234.5677, -1234.56789,-12345678912345,12345678912345,0,3 +sys.exec.out.time {s},drx.drt.a {1},drx.drt.b {1},drx.drt.c {1},drx.drt.d {1},drx.drt.e {1},drx.drt.f {1},drx.drt.g {1},drx.drt.h {1},drx.drt.i {1},drx.drt.j {1},drx.drt.k {1},drx.drt.l {1},drx.drt.m {1},drx.drt.n {1},drx.drt.q[0] {1},drx.drt.q[1] {1},drx.drt.q[2] {1},drx.drt.q[3] {1},drx.drt.q[4] {1},drx.drt.r[0][0] {1} + 0,a,98,-1234,1234,-123456,123456,-1234567,123456789, 1234.5677, -1234.56789,-12345678912345,12345678912345,0,3,0,1,2,3,4, 10 + 0.1,a,98,-1234,1234,-123456,123456,-1234567,123456789, 1234.5677, -1234.56789,-12345678912345,12345678912345,0,3,0,1,2,3,4, 10 + 0.2,a,98,-1234,1234,-123456,123456,-1234567,123456789, 1234.5677, -1234.56789,-12345678912345,12345678912345,0,3,0,1,2,3,4, 10 + 0.3,a,98,-1234,1234,-123456,123456,-1234567,123456789, 1234.5677, -1234.56789,-12345678912345,12345678912345,0,3,0,1,2,3,4, 10 + 0.4,a,98,-1234,1234,-123456,123456,-1234567,123456789, 1234.5677, -1234.56789,-12345678912345,12345678912345,0,3,0,1,2,3,4, 10 + 0.5,a,98,-1234,1234,-123456,123456,-1234567,123456789, 1234.5677, -1234.56789,-12345678912345,12345678912345,0,3,0,1,2,3,4, 10 + 0.6,a,98,-1234,1234,-123456,123456,-1234567,123456789, 1234.5677, -1234.56789,-12345678912345,12345678912345,0,3,0,1,2,3,4, 10 + 0.7,a,98,-1234,1234,-123456,123456,-1234567,123456789, 1234.5677, -1234.56789,-12345678912345,12345678912345,0,3,0,1,2,3,4, 10 + 0.8,a,98,-1234,1234,-123456,123456,-1234567,123456789, 1234.5677, -1234.56789,-12345678912345,12345678912345,0,3,0,1,2,3,4, 10 + 0.9,a,98,-1234,1234,-123456,123456,-1234567,123456789, 1234.5677, -1234.56789,-12345678912345,12345678912345,0,3,0,1,2,3,4, 10 + 1,a,98,-1234,1234,-123456,123456,-1234567,123456789, 1234.5677, -1234.56789,-12345678912345,12345678912345,0,3,0,1,2,3,4, 10 diff --git a/test/SIM_test_dr/models/dr/include/DR.hh b/test/SIM_test_dr/models/dr/include/DR.hh index 0afebe8c..1cd7b261 100644 --- a/test/SIM_test_dr/models/dr/include/DR.hh +++ b/test/SIM_test_dr/models/dr/include/DR.hh @@ -87,6 +87,10 @@ class DRTypes { unsigned long long l; bool m; NUM_DEFS n; + char * o; // Should not actually be added + std::string p; // Should not actually be added + int q[5]; + double r[2][2]; UINT_BITS uintB; INT_BITS intB; diff --git a/test/SIM_test_dr/models/dr/src/DR_default_data.cpp b/test/SIM_test_dr/models/dr/src/DR_default_data.cpp index 77586c42..38ac316b 100644 --- a/test/SIM_test_dr/models/dr/src/DR_default_data.cpp +++ b/test/SIM_test_dr/models/dr/src/DR_default_data.cpp @@ -25,7 +25,15 @@ int DRTypes::init() { l = 12345678912345; //unsigned long m = false; //boolean n = THREE; //enumerated type - + o = "3 May. Bistritz.—Left Munich at 8:35 P. M., on 1st May, arriving at Vienna early next morning; should have arrived at 6:46, but train was an hour late. Buda-Pesth seems a wonderful place, from the glimpse which I got of it from the train and the little I could walk through the streets. I feared to go very far from the station, as we had arrived late and would start as near the correct time as possible. The impression I had was that we were leaving the West and entering the East; the most western of splendid bridges over the Danube, which is here of noble width and depth, took us among the traditions of Turkish rule."; + p = "We left in pretty good time, and came after nightfall to Klausenburgh. Here I stopped for the night at the Hotel Royale. I had for dinner, or rather supper, a chicken done up some way with red pepper, which was very good but thirsty. (Mem., get recipe for Mina.) I asked the waiter, and he said it was called “paprika hendl,” and that, as it was a national dish, I should be able to get it anywhere along the Carpathians. I found my smattering of German very useful here; indeed, I don't know how I should be able to get on without it."; + for (int i = 0; i < 5; i++) { + q[i] = i; + } + r[0][0] = 10; + r[0][1] = 20; + r[1][0] = 30; + r[1][1] = 40; /*============================================================================ Bitfields diff --git a/test/SIM_test_output_dir/.gitignore b/test/SIM_test_output_dir/.gitignore new file mode 100644 index 00000000..abc50164 --- /dev/null +++ b/test/SIM_test_output_dir/.gitignore @@ -0,0 +1,9 @@ +.trick +MONTE_RUN_* +*log.csv +S_main* +*.resource +S_source.hh +build +makefile +trick.zip diff --git a/test/SIM_test_output_dir/RUN_test/input.py b/test/SIM_test_output_dir/RUN_test/input.py new file mode 100644 index 00000000..842129cd --- /dev/null +++ b/test/SIM_test_output_dir/RUN_test/input.py @@ -0,0 +1,7 @@ + + +trick.stop(15.0); +# trick.real_time_enable() +# trick.sim_control_panel_set_enabled(True) + +trick.sie_append_runtime_objs() \ No newline at end of file diff --git a/test/SIM_test_output_dir/S_define b/test/SIM_test_output_dir/S_define new file mode 100644 index 00000000..c6d068d3 --- /dev/null +++ b/test/SIM_test_output_dir/S_define @@ -0,0 +1,34 @@ +/************************TRICK HEADER************************* +PURPOSE: + () +LIBRARY DEPENDENCIES: +*************************************************************/ + +#include "sim_objects/default_trick_sys.sm" + +##include "starter.h" + +class StarterSimObject : public Trick::SimObject { + + public: + Starter starter; + + StarterSimObject() { + ("default_data") trick_ret = starter.default_data(); + ("initialization") trick_ret = starter.init(); + (5.0, "scheduled") trick_ret = starter.scheduled(); + ("shutdown") starter.shutdown(); + // ("derivative") trick_ret = starter.deriv(); + // ("integration") trick_ret = starter.integ(); + } +}; + +StarterSimObject starterSimObject; + +IntegLoop integLoop (0.01) starterSimObject; +/* +void create_connections() { + integLoop.getIntegrator(Runge_Kutta_4, ); +} +*/ + diff --git a/test/SIM_test_output_dir/S_overrides.mk b/test/SIM_test_output_dir/S_overrides.mk new file mode 100644 index 00000000..2ed9f9e5 --- /dev/null +++ b/test/SIM_test_output_dir/S_overrides.mk @@ -0,0 +1,8 @@ + +TRICK_CFLAGS += -I./models +TRICK_CXXFLAGS += -I./models + +clean: output_clean + +output_clean: + rm -rf sim_output diff --git a/test/SIM_test_output_dir/models/dynamic_obj.h b/test/SIM_test_output_dir/models/dynamic_obj.h new file mode 100644 index 00000000..f1e60c18 --- /dev/null +++ b/test/SIM_test_output_dir/models/dynamic_obj.h @@ -0,0 +1,44 @@ +/************************************************************************* +PURPOSE: (A sim object that is allocated at runtime) +LIBRARY DEPENDENCY: + ( + ) +**************************************************************************/ + +#include "sim_services/SimObject/include/SimObject.hh" + +class DynamicObj : public Trick::SimObject { + // This class should be allocated dynamically + public: + DynamicObj() {} + int doSomething () { + // Do something that we can test for here i guess + return 0; + } + + /** + * Calls all jobs that are not "dynamic_event" class + * @param curr_job - the current job instance + * @return always 0 + */ + virtual int call_function( Trick::JobData * curr_job ) { + return 0; + } + + /** + * Calls all jobs that are "dynamic_event" class + * @param curr_job - the current job instance + * @return always 0 + */ + virtual double call_function_double( Trick::JobData * curr_job ) { + return 0; + } + + + int a; + std::string b; + double * c; + + +}; + diff --git a/test/SIM_test_output_dir/models/starter.cpp b/test/SIM_test_output_dir/models/starter.cpp new file mode 100644 index 00000000..30809e26 --- /dev/null +++ b/test/SIM_test_output_dir/models/starter.cpp @@ -0,0 +1,66 @@ +#include +#include "starter.h" +#include "trick/integrator_c_intf.h" +#include "trick/exec_proto.h" +#include "trick/message_proto.h" +#include "trick/mm_macros.hh" + +Starter::Starter() { + +} + +int Starter::default_data() { + // Allocate a dynamic object + DynamicObj * obj = new DynamicObj() ; + obj->a = 5; + obj->b = "Hello world!"; + obj->c = (double *) malloc (sizeof(double) * 3); + obj->c[0] = 0.0; + obj->c[1] = 1.0; + obj->c[2] = 2.0; + + TMM_declare_ext_var(obj, TRICK_STRUCTURED,"DynamicObj", 0, "DynamicObj_alloc", 0, NULL) ; + + return 0; +} + +int Starter::init() { + return 0; +} + + +int Starter::scheduled() { + message_publish(MSG_NORMAL, "Hello World!\n"); + return 0; +} +int Starter::deriv() { + return 0; +} + +int Starter::integ() { + + int ipass; + load_state( + NULL /* list is NULL terminated */ + ); + + /* LOAD THE POSITION AND VELOCITY STATE DERIVATIVES */ + load_deriv( + NULL /* list is NULL terminated */ + ); + + /* Call the Trick integrate service */ + ipass = integrate(); + + /* unload new state */ + unload_state( + NULL /* list is NULL terminated */ + ); + + /* returns 0 if integerate() was successful */ + return ipass; +} + +int Starter::shutdown() { + return 0; +} diff --git a/test/SIM_test_output_dir/models/starter.h b/test/SIM_test_output_dir/models/starter.h new file mode 100644 index 00000000..6574c5da --- /dev/null +++ b/test/SIM_test_output_dir/models/starter.h @@ -0,0 +1,21 @@ +/************************************************************************* +PURPOSE: (Starter class) +LIBRARY DEPENDENCY: + ( + (starter.cpp) + ) +**************************************************************************/ + +#include "dynamic_obj.h" + +class Starter { +public: + Starter(); + int default_data(); + int init(); + int scheduled(); + int deriv(); + int integ(); + int shutdown(); + +}; \ No newline at end of file diff --git a/test/SIM_test_output_dir/ref_files/check_file_endings.py b/test/SIM_test_output_dir/ref_files/check_file_endings.py new file mode 100644 index 00000000..2d575ab5 --- /dev/null +++ b/test/SIM_test_output_dir/ref_files/check_file_endings.py @@ -0,0 +1,20 @@ +import sys + +if len(sys.argv) != 3: + print ("Usage: check_file_endings.py ") + exit(1) + +ref_file = sys.argv[1] +cmp_file = sys.argv[2] + +ref_lines = reversed(list(open(ref_file))) +cmp_lines = reversed(list(open(cmp_file))) + +for ref_line, cmp_line in zip(ref_lines, cmp_lines): + if (ref_line != cmp_line): + print("Difference in files: ", ref_line, "vs", cmp_line) + exit(1) + +print("Success!") +exit(0) + diff --git a/test/SIM_test_output_dir/ref_files/ref_compiletime_S_sie.resource b/test/SIM_test_output_dir/ref_files/ref_compiletime_S_sie.resource new file mode 100644 index 00000000..90c0a5c1 --- /dev/null +++ b/test/SIM_test_output_dir/ref_files/ref_compiletime_S_sie.resource @@ -0,0 +1,5 @@ + + \ No newline at end of file diff --git a/test/SIM_test_output_dir/ref_files/ref_runtime_S_sie.resource b/test/SIM_test_output_dir/ref_files/ref_runtime_S_sie.resource new file mode 100644 index 00000000..40859b25 --- /dev/null +++ b/test/SIM_test_output_dir/ref_files/ref_runtime_S_sie.resource @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + diff --git a/test/SIM_test_sched/models/sched/src/sched_amf.c b/test/SIM_test_sched/models/sched/src/sched_amf.c index ed2dfdc4..a4fb2b61 100644 --- a/test/SIM_test_sched/models/sched/src/sched_amf.c +++ b/test/SIM_test_sched/models/sched/src/sched_amf.c @@ -21,13 +21,13 @@ int sched_amf( if ( S->amf == 2 ) { /* Things are in order */ - sprintf(test, "Test %d", i); + snprintf(test, sizeof(test), "Test %d", i); add_test_result("sched_amf: Things are in order", test, ""); i++; S->amf = 1 ; } else { /* Things are out of order */ - sprintf(test, "Test %d", i); + snprintf(test, sizeof(test), "Test %d", i); add_test_result("sched_amf: Things are NOT in order", test, ". "); i++; S->amf = 3 ; diff --git a/test/SIM_test_varserv/RUN_test/manual_test.py b/test/SIM_test_varserv/RUN_test/manual_test.py new file mode 100644 index 00000000..982de3ce --- /dev/null +++ b/test/SIM_test_varserv/RUN_test/manual_test.py @@ -0,0 +1,31 @@ +import trick +import socket + +from trick.unit_test import * + +def main(): + + trick.var_server_set_port(4000) + trick.var_ascii() + trick.real_time_enable() + trick.exec_set_software_frame(0.01) + # trick.set_var_server_info_msg_on() + + trick.var_server_create_tcp_socket('localhost', 49000) + trick.var_server_create_udp_socket('', 48000) + trick.var_server_create_multicast_socket('224.10.10.10','', 47000) + + # trick.exec_set_terminate_time(100000.0) + + varServerPort = trick.var_server_get_port() + test_output = ( os.getenv("TRICK_HOME") + "/trick_test/SIM_test_varserv.xml" ) + # command = 'os.system("./models/test_client/test_client ' + str(varServerPort) + ' --gtest_output=xml:' + test_output + ' &")' + + # Start the test client after everything has been initialized (hopefully) + # trick.add_read(1.0, command) + # trick.sim_control_panel_set_enabled(True) + + +if __name__ == "__main__": + main() + diff --git a/test/SIM_test_varserv/RUN_test/realtime.py b/test/SIM_test_varserv/RUN_test/realtime.py deleted file mode 100644 index f140a4e9..00000000 --- a/test/SIM_test_varserv/RUN_test/realtime.py +++ /dev/null @@ -1,20 +0,0 @@ -import trick - -def main(): - trick.var_server_set_port(50000) - - trick.set_var_server_info_msg_on() - #trick.sim_control_panel_set_enabled(True) - - trick.real_time_enable() - trick.itimer_enable() - - #trick.add_read(1.1, """vsx.vst.vs_read()""") - #trick.add_read(2.1, """vsx.vst.vs_read()""") - - trick.exec_set_terminate_time(3000.0) - - #print trick.var_add("vsx.vst.b") - -if __name__ == "__main__": - main() diff --git a/test/SIM_test_varserv/RUN_test/unit_test.py b/test/SIM_test_varserv/RUN_test/unit_test.py index 1f79a15d..bfdd413a 100644 --- a/test/SIM_test_varserv/RUN_test/unit_test.py +++ b/test/SIM_test_varserv/RUN_test/unit_test.py @@ -7,16 +7,22 @@ def main(): trick.var_server_set_port(40000) trick.var_ascii() + trick.real_time_enable() + trick.exec_set_software_frame(0.01) + # trick.set_var_server_info_msg_on() - #trick.set_var_server_info_msg_on() + trick.var_server_create_tcp_socket('localhost', 49000) + trick.var_server_create_udp_socket('', 48000) + trick.var_server_create_multicast_socket('224.10.10.10','', 47000) - trick_utest.unit_tests.enable() ; - trick_utest.unit_tests.set_file_name( os.getenv("TRICK_HOME") + "/trick_test/SIM_test_varserv.xml" ) - trick_utest.unit_tests.set_test_name( "VariableServerTest" ) + trick.exec_set_terminate_time(1000.0) - TRICK_EXPECT_EQ(trick.var_server_get_port(), 40000, "VariableServerTest", "SetPortNumber") + varServerPort = trick.var_server_get_port() + test_output = ( os.getenv("TRICK_HOME") + "/trick_test/SIM_test_varserv.xml" ) + command = 'os.system("./models/test_client/test_client ' + str(varServerPort) + ' --gtest_output=xml:' + test_output + ' &")' - trick.exec_set_terminate_time(3000.0) + # Start the test client after everything has been initialized (hopefully) + trick.add_read(1.0, command) if __name__ == "__main__": main() diff --git a/test/SIM_test_varserv/S_define b/test/SIM_test_varserv/S_define index fb85f3fc..79e25327 100644 --- a/test/SIM_test_varserv/S_define +++ b/test/SIM_test_varserv/S_define @@ -3,11 +3,6 @@ PURPOSE: ( S_define ) LIBRARY DEPENDENCIES: ( (varserv/src/VS.cpp) - (varserv/src/VS_init.cpp) - (varserv/src/VS_default_data.cpp) - (varserv/src/VS_commands.cpp) - (varserv/src/VS_tests.cpp) - (varserv/src/VS_shutdown.cpp) ) *************************************************************/ @@ -22,17 +17,9 @@ class testSimObject : public Trick::SimObject { testSimObject() { ("default_data") vst.default_vars(); ("initialization") vst.init(); - ("initialization") vst.testAddRemove(); - ("initialization") vst.testExists(); - ("initialization") vst.testPause(); - ("initialization") vst.testOther(); - //(1.0, "scheduled") trick_ret = vst.testing(); - ("shutdown") vst.shutdown(); } }; // Instantiations testSimObject vsx; - - diff --git a/test/SIM_test_varserv/S_overrides.mk b/test/SIM_test_varserv/S_overrides.mk index 27536a3b..36707008 100644 --- a/test/SIM_test_varserv/S_overrides.mk +++ b/test/SIM_test_varserv/S_overrides.mk @@ -2,3 +2,14 @@ TRICK_CFLAGS += -I./models TRICK_CXXFLAGS += -I./models +all: test_client +clean: clean_test_client + +TEST_CLIENT_LIBS += -L${GTEST_HOME}/lib64 -L${GTEST_HOME}/lib -lgtest -lgtest_main -lpthread -L${TRICK_LIB_DIR} -ltrick_var_binary_parser + +test_client: models/test_client/test_client.cpp + cd models/test_client; $(TRICK_CXX) test_client.cpp -o test_client $(TRICK_CXXFLAGS) $(TRICK_SYSTEM_CXXFLAGS) $(TRICK_TEST_FLAGS) -Wno-write-strings -Wno-sign-compare -I$(TRICK_HOME)/include $(TEST_CLIENT_LIBS) + +clean_test_client: + rm -f models/test_client/test_client + \ No newline at end of file diff --git a/test/SIM_test_varserv/models/test_client/.gitignore b/test/SIM_test_varserv/models/test_client/.gitignore new file mode 100644 index 00000000..837a5b2a --- /dev/null +++ b/test/SIM_test_varserv/models/test_client/.gitignore @@ -0,0 +1 @@ +test_client \ No newline at end of file diff --git a/test/SIM_test_varserv/models/test_client/test_client.cpp b/test/SIM_test_varserv/models/test_client/test_client.cpp new file mode 100644 index 00000000..4c714be3 --- /dev/null +++ b/test/SIM_test_varserv/models/test_client/test_client.cpp @@ -0,0 +1,1669 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "trick/var_binary_parser.hh" + +#define DOUBLE_TOL 1e-5 +#define SOCKET_BUF_SIZE 204800 + +// Pretend that gtest was kind enough to provide an EXPECT_FEQ operator with a tolerance +#define EXPECT_FEQ(a,b) EXPECT_LE(fabs(a - b), DOUBLE_TOL) + +class Socket { + + public: + + int max_retries = 10; + + Socket() : _initialized(false) {} + int init(std::string hostname, int port, int mode = SOCK_STREAM) { + _multicast_socket = false; + + _hostname = hostname; + _port = port; + int tries = 0; + + while ((_socket_fd = socket(AF_INET, mode, 0)) < 0 && tries < max_retries) tries++; + + if (_socket_fd < 0) { + std::cout << "Socket connection failed" << std::endl; + return -1; + } + + int value = 1; + if (setsockopt(_socket_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &value, (socklen_t) sizeof(value)) < 0) { + std::cout << "init_multicast: Socket option failed" << std::endl; + return -1; + } + + if (setsockopt(_socket_fd, SOL_SOCKET, SO_REUSEPORT, (char *) &value, sizeof(value)) < 0) { + perror("setsockopt: reuseport"); + } + + struct sockaddr_in serv_addr; + serv_addr.sin_family = AF_INET; + serv_addr.sin_port = htons(port); // convert to weird network byte format + serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); + + tries = 0; + int connection_status; + + while ((connection_status = connect(_socket_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr))) < 0 && tries < max_retries) tries++; + + if (connection_status < 0) { + std::cout << "Connection failed" << std::endl; + return -1; + } + + _initialized = true; + + return 0; + } + + #ifndef __APPLE__ + int init_multicast (std::string hostname, int port) { + _multicast_socket = true; + _hostname = hostname; + _port = port; + int tries = 0; + + _socket_fd = socket(AF_INET, SOCK_DGRAM, 0); + if (_socket_fd < 0) { + std::cout << "init_multicast: Socket open failed" << std::endl; + return -1; + } + + int value = 1; + if (setsockopt(_socket_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &value, (socklen_t) sizeof(value)) < 0) { + std::cout << "init_multicast: Socket option failed" << std::endl; + return -1; + } + + if (setsockopt(_socket_fd, SOL_SOCKET, SO_REUSEPORT, (char *) &value, sizeof(value)) < 0) { + perror("setsockopt: reuseport"); + } + + struct ip_mreq mreq; + // Use setsockopt() to request that the kernel join a multicast group + mreq.imr_multiaddr.s_addr = inet_addr(_hostname.c_str()); + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + if (setsockopt(_socket_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, (socklen_t) sizeof(mreq)) < 0) { + std::cout << "init_multicast: setsockopt: ip_add_membership failed" << std::endl; + return -1; + } + + + struct sockaddr_in sockin ; + + // Set up local interface + // We must bind to the multicast address + sockin.sin_family = AF_INET; + sockin.sin_addr.s_addr = inet_addr(_hostname.c_str()); + sockin.sin_port = htons(_port); + + if ( bind(_socket_fd, (struct sockaddr *) &sockin, (socklen_t) sizeof(sockin)) < 0 ) { + std::cout << "init_multicast: bind failed" << std::endl; + return -1; + } + + char loopch = 1; + + if(setsockopt(_socket_fd, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&loopch, sizeof(loopch)) < 0) + { + perror("Setting IP_MULTICAST_LOOP error"); + return -1; + } + + _initialized = true; + return 0; + } + + #endif + + int send (std::string message) { + // weird syntax I've never used before - since the send syscall that i'm trying to use is overloaded in this class, + // I have to append :: to the front of it so that the compiler knows to look in the global namespace + int success = ::send(_socket_fd, message.c_str(), message.size(), 0); + if (success < message.size()) { + std::cout << "init_multicast: Failed to send message" << std::endl; + } + return success; + } + + int operator<< (std::string message) { + return send(message); + } + + std::string receive () { + char buffer[SOCKET_BUF_SIZE]; + + int numBytes = recv(_socket_fd, buffer, SOCKET_BUF_SIZE, 0); + if (numBytes < 0) { + } else if (numBytes < SOCKET_BUF_SIZE) { + buffer[numBytes] = '\0'; + } + + return std::string(buffer); + } + + void operator>> (std::string& ret) { + ret = receive(); + } + + std::vector receive_bytes() { + unsigned char buffer[SOCKET_BUF_SIZE]; + int numBytes = recv(_socket_fd, buffer, SOCKET_BUF_SIZE, 0); + if (numBytes < 0) { + std::cout << "init_multicast: Failed to read from socket" << std::endl; + } + + std::vector bytes; + for (int i = 0; i < numBytes; i++) { + bytes.push_back(buffer[i]); + } + + return bytes; + } + + bool check_for_message_availible(long timeout_sec = 2) { + fd_set read_fd_set; + struct timeval timeout = { .tv_sec = timeout_sec, .tv_usec = 0 }; + FD_ZERO(&read_fd_set); + FD_SET(_socket_fd, &read_fd_set); + + // I have one question for the designers of the interface for this syscall: why + select(_socket_fd+1, &read_fd_set, NULL, NULL, &timeout); + + return FD_ISSET(_socket_fd, &read_fd_set); + } + + void clear_buffered_data() { + // Poll the socket + if (check_for_message_availible(0)) { + // Receive into the void if there is a message + receive(); + } + // otherwise no worries + } + + void close() { + ::close(_socket_fd); + } + + private: + int _port; + std::string _hostname; + int _socket_fd; + bool _initialized; + bool _multicast_socket; +}; + +class VariableServerTest : public ::testing::Test { + protected: + VariableServerTest() { + socket_status = socket.init("localhost", 40000); + if (socket_status == 0) { + std::stringstream request; + request << "trick.var_set_client_tag(\"VSTest"; + request << numSession++; + request << "\") \n"; + + socket << request.str(); + } + } + ~VariableServerTest() { + socket << "trick.var_exit()\n"; + socket.close(); + } + + Socket socket; + int socket_status; + + static int numSession; +}; + +class VariableServerUDPTest : public ::testing::Test { + protected: + VariableServerUDPTest() { + socket_status = socket.init("localhost", 48000, SOCK_DGRAM); + + if (socket_status == 0) { + std::stringstream request; + request << "trick.var_set_client_tag(\"UDP_VSTest"; + request << numSession++; + request << "\") \n"; + + socket << request.str(); + } + } + ~VariableServerUDPTest() { + socket.close(); + } + + Socket socket; + int socket_status; + + static int numSession; +}; + +class VariableServerTestAltListener : public ::testing::Test { + protected: + VariableServerTestAltListener() { + socket_status = socket.init("localhost", 49000); + + if (socket_status == 0) { + std::stringstream request; + request << "trick.var_set_client_tag(\"altListener_VSTest"; + request << numSession++; + request << "\") \n"; + + socket << request.str(); + } + } + ~VariableServerTestAltListener() { + socket << "trick.var_exit()\n"; + socket.close(); + } + + Socket socket; + int socket_status; + + static int numSession; +}; + +#ifndef __APPLE__ +class VariableServerTestMulticast : public ::testing::Test { + protected: + VariableServerTestMulticast() { + socket_status = socket.init("", 47000, SOCK_DGRAM); + multicast_listener.init_multicast("224.10.10.10", 47000); + + if (socket_status == 0) { + std::stringstream request; + request << "trick.var_set_client_tag(\"multicast_VSTest"; + request << numSession++; + request << "\") \n"; + + socket << request.str(); + } + } + ~VariableServerTestMulticast() { + socket.close(); + multicast_listener.close(); + } + + Socket socket; + Socket multicast_listener; + + int socket_status; + + static int numSession; +}; +int VariableServerTestMulticast::numSession = 0; +#endif + +int VariableServerTest::numSession = 0; +int VariableServerUDPTest::numSession = 0; +int VariableServerTestAltListener::numSession = 0; + + +/**********************************************************/ +/* Helpful constants and functions */ +/**********************************************************/ + + +const int MODE_RUN = 5; +const int MODE_FREEZE = 1; + +int strcmp_IgnoringWhiteSpace(std::string s1_str, std::string s2_str) { + const char * s1 = s1_str.c_str(); + const char * s2 = s2_str.c_str(); + + int i1 = 0; + int i2 = 0; + + while (1) { + while ( !isgraph( s1[i1] ) && s1[i1] != '\0') { i1++; } + while ( !isgraph( s2[i2] ) && s2[i2] != '\0') { i2++; } + if ( s1[i1] == '\0' && s2[i2] == '\0') { return 0; } + if ( s1[i1] != s2[i2]) { + if (s1[i1] < s2[i2]) { + return -1; + } else { + return 1; + } + } + i1++; i2++; + } +} + +void spin (Socket& socket, int wait_cycles = 5) { + for (int i = 0; i < wait_cycles; i++) + socket.receive(); +} + +void wait_for_mode_change (Socket& socket, int expected_mode, int max_wait_iterations = 10) { + int iteration = 0; + std::string mode_reply; + std::string expected_reply = "5\t" + std::to_string(expected_mode) + "\n"; + while (iteration++ < max_wait_iterations) { + socket << "trick.var_send_once(\"trick_sys.sched.mode\")\n"; + socket >> mode_reply; + if (mode_reply == expected_reply) + break; + } +} + +void dump_checkpoint (Socket& socket, const std::string& checkpoint_name) { + socket << "trick.var_pause()\ntrick.exec_freeze()\n"; + wait_for_mode_change(socket, MODE_FREEZE); + + std::string checkpoint_cmd = "trick.checkpoint(\"" + checkpoint_name + "\")\n"; + socket << checkpoint_cmd; + + socket << "trick.exec_run()\n"; + wait_for_mode_change(socket, MODE_RUN); + socket << "trick.var_unpause()\n"; +} + +void load_checkpoint (Socket& socket, const std::string& checkpoint_name) { + socket << "trick.var_pause()\ntrick.exec_freeze()\n"; + wait_for_mode_change(socket, MODE_FREEZE); + + std::string checkpoint_cmd = "trick.load_checkpoint(\"" + checkpoint_name + "\")\n"; + socket << checkpoint_cmd; + sleep(5); + + socket << "trick.exec_run()\n"; + wait_for_mode_change(socket, MODE_RUN); + socket << "trick.var_unpause()\n"; +} + +/*****************************************/ +/* Multicast Test */ +/*****************************************/ + +#ifndef __APPLE__ + +TEST_F (VariableServerTestMulticast, Strings) { + if (socket_status != 0) { + FAIL(); + } + + std::string reply; + socket << "trick.var_send_once(\"vsx.vst.o\")\n"; + std::string expected("5\tYou will rejoice to hear that no disaster has accompanied the commencement of an enterprise which you have regarded with such evil forebodings. I arrived here yesterday, and my first task is to assure my dear sister of my welfare and increasing confidence in the success of my undertaking."); + + multicast_listener >> reply; + + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0); + + expected = std::string("5\tI am already far north of London, and as I walk in the streets of Petersburgh, I feel a cold northern breeze play upon my cheeks, which braces my nerves and fills me with delight. Do you understand this feeling?"); + socket << "trick.var_send_once(\"vsx.vst.p\")\n"; + + multicast_listener >> reply; + + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0); +} + + +TEST_F (VariableServerTestMulticast, AddRemove) { + if (socket_status != 0) { + FAIL(); + } + + std::string reply; + std::string expected; + + int max_tries = 3; + int tries = 0; + + socket << "trick.var_add(\"vsx.vst.c\")\n"; + multicast_listener >> reply; + expected = std::string("0 -1234"); + + tries = 0; + while (strcmp_IgnoringWhiteSpace(reply, expected) != 0 && tries++ < max_tries) { + multicast_listener >> reply; + } + + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0) << "Expected: " << expected << "\tAcutal: " << reply; + + multicast_listener >> reply; + tries = 0; + while (strcmp_IgnoringWhiteSpace(reply, expected) != 0 && tries++ < max_tries) { + multicast_listener >> reply; + } + + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0) << "Expected: " << expected << "\tAcutal: " << reply; + + socket << "trick.var_add(\"vsx.vst.m\")\n"; + multicast_listener >> reply; + expected = std::string("0 -1234 1"); + tries = 0; + while (strcmp_IgnoringWhiteSpace(reply, expected) != 0 && tries++ < max_tries) { + multicast_listener >> reply; + } + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0) << "Expected: " << expected << "\tAcutal: " << reply; + + socket << "trick.var_remove(\"vsx.vst.m\")\n"; + multicast_listener >> reply; + expected = std::string("0 -1234"); + tries = 0; + while (strcmp_IgnoringWhiteSpace(reply, expected) != 0 && tries++ < max_tries) { + multicast_listener >> reply; + } + + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0) << "Expected: " << expected << "\tAcutal: " << reply; + + socket << "trick.var_add(\"vsx.vst.n\")\n"; + multicast_listener >> reply; + expected = std::string("0 -1234 0,1,2,3,4"); + tries = 0; + while (strcmp_IgnoringWhiteSpace(reply, expected) != 0 && tries++ < max_tries) { + multicast_listener >> reply; + } + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0) << "Expected: " << expected << "\tAcutal: " << reply; + + socket << "trick.var_exit()\n"; +} + +#endif + +/************************************/ +/* UDP Tests */ +/************************************/ + + +TEST_F (VariableServerUDPTest, Strings) { + if (socket_status != 0) { + FAIL(); + } + + std::string reply; + socket << "trick.var_send_once(\"vsx.vst.o\")\n"; + socket >> reply; + std::string expected("5\tYou will rejoice to hear that no disaster has accompanied the commencement of an enterprise which you have regarded with such evil forebodings. I arrived here yesterday, and my first task is to assure my dear sister of my welfare and increasing confidence in the success of my undertaking."); + + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0); + + + expected = std::string("5\tI am already far north of London, and as I walk in the streets of Petersburgh, I feel a cold northern breeze play upon my cheeks, which braces my nerves and fills me with delight. Do you understand this feeling?"); + socket << "trick.var_send_once(\"vsx.vst.p\")\n"; + + socket >> reply; + + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0); +} + + +TEST_F (VariableServerUDPTest, AddRemove) { + if (socket_status != 0) { + FAIL(); + } + + std::string reply; + std::string expected; + + socket << "trick.var_add(\"vsx.vst.c\")\n"; + socket >> reply; + expected = std::string("0 -1234"); + + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0); + + socket >> reply; + + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0); + + socket << "trick.var_add(\"vsx.vst.m\")\n"; + socket >> reply; + expected = std::string("0 -1234 1"); + + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0); + + socket << "trick.var_remove(\"vsx.vst.m\")\n"; + socket >> reply; + expected = std::string("0 -1234"); + + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0); + + socket << "trick.var_add(\"vsx.vst.n\")\n"; + socket >> reply; + expected = std::string("0 -1234 0,1,2,3,4"); + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0); + + socket << "trick.var_exit()\n"; +} + +/*********************************************/ +/* Alt Listener Tests */ +/*********************************************/ + +TEST_F (VariableServerTestAltListener, Strings) { + if (socket_status != 0) { + FAIL(); + } + + std::string reply; + socket << "trick.var_send_once(\"vsx.vst.o\")\n"; + socket >> reply; + std::string expected("5\tYou will rejoice to hear that no disaster has accompanied the commencement of an enterprise which you have regarded with such evil forebodings. I arrived here yesterday, and my first task is to assure my dear sister of my welfare and increasing confidence in the success of my undertaking."); + + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0); + + + expected = std::string("5\tI am already far north of London, and as I walk in the streets of Petersburgh, I feel a cold northern breeze play upon my cheeks, which braces my nerves and fills me with delight. Do you understand this feeling?"); + socket << "trick.var_send_once(\"vsx.vst.p\")\n"; + + socket >> reply; + + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0); +} + +TEST_F (VariableServerTestAltListener, AddRemove) { + if (socket_status != 0) { + FAIL(); + } + + std::string reply; + std::string expected; + + socket << "trick.var_add(\"vsx.vst.c\")\n"; + socket >> reply; + expected = std::string("0 -1234"); + + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0); + + socket >> reply; + + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0); + + socket << "trick.var_add(\"vsx.vst.m\")\n"; + socket >> reply; + expected = std::string("0 -1234 1"); + + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0); + + socket << "trick.var_remove(\"vsx.vst.m\")\n"; + socket >> reply; + expected = std::string("0 -1234"); + + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0); + + socket << "trick.var_add(\"vsx.vst.n\")\n"; + socket >> reply; + expected = std::string("0 -1234 0,1,2,3,4"); + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0); +} + + +TEST_F (VariableServerTestAltListener, RestartAndSet) { + if (socket_status != 0) { + FAIL(); + } + + std::string reply; + std::string expected; + + socket << "trick.var_add(\"vsx.vst.c\")\n"; + socket >> reply; + expected = std::string("0\t-1234\n"); + + EXPECT_EQ(reply, expected); + + dump_checkpoint(socket, "reload_file.ckpnt"); + + socket << "trick.var_add(\"vsx.vst.e\",\"m\")\n"; + socket >> reply; + expected = std::string("0\t-1234\t-123456 {m}\n"); + + socket << "trick.var_set(\"vsx.vst.c\", 5)\n"; + socket >> reply; + expected = std::string("0\t5\t-123456 {m}\n"); + + EXPECT_EQ(reply, expected); + + load_checkpoint(socket, "RUN_test/reload_file.ckpnt"); + + socket >> reply; + expected = std::string("0\t-1234\t-123456\n"); + + EXPECT_EQ(reply, expected); +} + +/*********************************************/ +/* Normal case tests */ +/*********************************************/ + +TEST_F (VariableServerTest, Strings) { + if (socket_status != 0) { + FAIL(); + } + + std::string reply; + socket << "trick.var_send_once(\"vsx.vst.o\")\n"; + socket >> reply; + std::string expected("5\tYou will rejoice to hear that no disaster has accompanied the commencement of an enterprise which you have regarded with such evil forebodings. I arrived here yesterday, and my first task is to assure my dear sister of my welfare and increasing confidence in the success of my undertaking."); + + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0); + + + expected = std::string("5\tI am already far north of London, and as I walk in the streets of Petersburgh, I feel a cold northern breeze play upon my cheeks, which braces my nerves and fills me with delight. Do you understand this feeling?"); + socket << "trick.var_send_once(\"vsx.vst.p\")\n"; + + socket >> reply; + + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0); + + // TODO: Does wchar actually work? + // expected = std::string("5\tThis breeze, which has travelled from the regions towards which I am advancing, gives me a foretaste of those icy climes. Inspirited by this wind of promise, my daydreams become more fervent and vivid."); + // socket << "trick.var_send_once(\"vsx.vst.q\")\n"; + + // socket >> reply; + + // std::cout << "\tExpected: " << expected << "\n\tActual: " << reply << std::endl; + + // EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0); +} + +TEST_F (VariableServerTest, NoExtraTab) { + if (socket_status != 0) { + FAIL(); + } + + std::string reply; + std::string expected; + + socket << "trick.var_add(\"vsx.vst.c\")\n"; + socket >> reply; + expected = std::string("0\t-1234\n"); + + EXPECT_STREQ(reply.c_str(), expected.c_str()); + + socket >> reply; + + EXPECT_STREQ(reply.c_str(), expected.c_str()); + + socket << "trick.var_add(\"vsx.vst.m\")\n"; + socket >> reply; + expected = std::string("0\t-1234\t1\n"); + + EXPECT_STREQ(reply.c_str(), expected.c_str()); + + socket << "trick.var_remove(\"vsx.vst.m\")\n"; + socket >> reply; + expected = std::string("0\t-1234\n"); + + socket << "trick.var_add(\"vsx.vst.n\")\n"; + socket >> reply; + expected = std::string("0\t-1234\t0,1,2,3,4\n"); + + EXPECT_STREQ(reply.c_str(), expected.c_str()); +} + +TEST_F (VariableServerTest, AddRemove) { + if (socket_status != 0) { + FAIL(); + } + + std::string reply; + std::string expected; + + socket << "trick.var_add(\"vsx.vst.c\")\n"; + socket >> reply; + expected = std::string("0 -1234"); + + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0); + + socket >> reply; + + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0); + + socket << "trick.var_add(\"vsx.vst.m\")\n"; + socket >> reply; + expected = std::string("0 -1234 1"); + + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0); + + socket << "trick.var_remove(\"vsx.vst.m\")\n"; + socket >> reply; + expected = std::string("0 -1234"); + + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0); + + socket << "trick.var_add(\"vsx.vst.n\")\n"; + socket >> reply; + expected = std::string("0 -1234 0,1,2,3,4"); + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0); +} + +TEST_F (VariableServerTest, BadRefResponse) { + if (socket_status != 0) { + FAIL(); + } + + std::string reply; + std::string expected; + + std::cerr << "The purpose of this test is to cause an error. Error messages are expected." << std::endl; + + socket << "trick.var_send_once(\"vsx.vst.no_such_variable\")\n"; + socket >> reply; + expected = std::string("5 BAD_REF"); + + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0); +} + + +TEST_F (VariableServerTest, Units) { + if (socket_status != 0) { + FAIL(); + } + + std::string reply; + std::string expected; + + std::cerr << "The purpose of this test is to cause an error. Error messages are expected." << std::endl; + socket << "trick.var_add(\"vsx.vst.c\")\ntrick.var_units(\"vsx.vst.c\",\"g\")\n"; + socket >> reply; + expected = std::string("0 -1234"); + + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0); + + socket << "trick.var_add(\"vsx.vst.e\",\"m\")\n"; + socket >> reply; + expected = std::string("0 -1234 -123456 {m}"); + + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0); + + socket << "trick.var_units(\"vsx.vst.e\",\"ft\")\n"; + socket >> reply; + expected = std::string("0 -1234 -405039 {ft}"); + + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0); +} + +TEST_F (VariableServerTest, SendOnce) { + if (socket_status != 0) { + FAIL(); + } + + std::string reply; + std::string expected; + + socket << "trick.var_send_once(\"vsx.vst.e\")\n"; + socket >> reply; + expected = std::string("5 -123456"); + + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0); + + // Check that nothing is sent cyclically + EXPECT_EQ(socket.check_for_message_availible(), false); + + socket << "trick.var_send_once(\"vsx.vst.n[0], vsx.vst.n[1], vsx.vst.n[2],\", 3)\n"; + socket >> reply; + expected = std::string("5 0 1 2"); + + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0); + + std::cerr << "The purpose of this test is to cause an error. Error messages are expected." << std::endl; + socket << "trick.var_send_once(\"vsx.vst.n[0], vsx.vst.n[1], vsx.vst.n[2],\", 4)\n"; + + // Wrong number of variables, should not send a response but should see an error message from the Trick side + EXPECT_EQ(socket.check_for_message_availible(), false); +} + +TEST_F (VariableServerTest, Exists) { + if (socket_status != 0) { + FAIL(); + } + + std::string reply; + std::string expected; + + socket << "trick.var_exists(\"vsx.vst.e\")\n"; + socket >> reply; + expected = std::string("1 1"); + + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0); + + + socket << "trick.var_exists(\"vsx.vst.z\")\n"; + socket >> reply; + expected = std::string("1 0"); + + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0); + + socket << "trick.var_binary()\n"; + + std::vector actual_bytes; + std::vector expected_bytes; + socket << "trick.var_exists(\"vsx.vst.e\")\n"; + actual_bytes = socket.receive_bytes(); + expected_bytes = {0x01, 0x00, 0x00, 0x00, 0x01}; + + EXPECT_EQ(expected_bytes, actual_bytes); + + + socket << "trick.var_exists(\"vsx.vst.z\")\n"; + actual_bytes = socket.receive_bytes(); + expected_bytes = {0x01, 0x00, 0x00, 0x00, 0x00}; + + EXPECT_EQ(expected_bytes, actual_bytes); + +} + +TEST_F (VariableServerTest, ListSize) { + if (socket_status != 0) { + FAIL(); + } + + std::string reply; + std::string expected; + + socket << "trick.var_add(\"vsx.vst.a\")\ntrick.var_add(\"vsx.vst.b\")\ntrick.var_add(\"vsx.vst.c\")\ntrick.var_add(\"vsx.vst.d\")\ntrick.var_pause()\n"; + socket << "trick.var_send_list_size()\n"; + + socket >> reply; + expected = "3 4"; + + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0) << "Reply: " << reply << "\tExpected: " << expected; + + // Adding a variable to the list more than once is allowed + socket << "trick.var_add(\"vsx.vst.a\")\n"; + socket << "trick.var_send_list_size()\n"; + + socket >> reply; + expected = "3 5"; + + EXPECT_EQ(strcmp_IgnoringWhiteSpace(reply, expected), 0) << "Reply: " << reply << "\tExpected: " << expected; + + socket << "trick.var_add(\"vsx.vst.e\")\ntrick.var_binary()\ntrick.var_send_list_size()\n"; + + std::vector actual_bytes; + std::vector expected_bytes; + actual_bytes = socket.receive_bytes(); + expected_bytes = {0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00}; + + EXPECT_EQ(expected_bytes, actual_bytes); +} + + +TEST_F (VariableServerTest, RestartAndSet) { + if (socket_status != 0) { + FAIL(); + } + + std::string reply; + std::string expected; + + socket << "trick.var_add(\"vsx.vst.c\")\n"; + socket >> reply; + expected = std::string("0\t-1234\n"); + + EXPECT_EQ(reply, expected); + + dump_checkpoint(socket, "reload_file.ckpnt"); + + socket << "trick.var_add(\"vsx.vst.e\",\"m\")\n"; + socket >> reply; + expected = std::string("0\t-1234\t-123456 {m}\n"); + + socket << "trick.var_set(\"vsx.vst.c\", 5)\n"; + socket >> reply; + expected = std::string("0\t5\t-123456 {m}\n"); + + EXPECT_EQ(reply, expected); + + load_checkpoint(socket, "RUN_test/reload_file.ckpnt"); + + socket >> reply; + expected = std::string("0\t-1234\t-123456\n"); + + EXPECT_EQ(reply, expected); +} + +TEST_F (VariableServerTest, Cycle) { + if (socket_status != 0) { + FAIL(); + } + + double cycle = 1.0; + int num_cycles = 5; + + // Challenge: no loops allowed + // I've been reading about lamdbas and when you have a hammer........ + + // Test: compare the differences in the returned sim time, make sure the difference + // between them are equal to var_cycle + // In copy mode VS_COPY_SCHEDULED and write mode VS_WRITE_WHEN_COPY, we should see exactly the correct copy rate + // Use a very small tolerance to compensate for floating point error + + auto parse_message_for_sim_time = [](const std::string& message) { + // For this case the message will be + // 0\t