diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..05eb13f --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,32 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: +// https://github.com/microsoft/vscode-dev-containers/tree/v0.187.0/containers/docker-existing-dockerfile +{ + "name": "Phaethon Dockerfile", + + // Sets the run context to one level up instead of the .devcontainer folder. + "context": "..", + + // Update the 'dockerFile' property if you aren't using the standard 'Dockerfile' filename. + "dockerFile": "../Dockerfile", + + // Set *default* container specific settings.json values on container create. + "settings": {}, + + // Add the IDs of extensions you want installed when the container is created. + "extensions": ["ms-vscode.cpptools-extension-pack", "ms-azuretools.vscode-docker"] + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Uncomment the next line to run commands after the container is created - for example installing curl. + // "postCreateCommand": "apt-get update && apt-get install -y curl", + + // Uncomment when using a ptrace-based debugger like C++, Go, and Rust + // "runArgs": [ "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined" ], + + // Uncomment to use the Docker CLI from inside the container. See https://aka.ms/vscode-remote/samples/docker-from-docker. + // "mounts": [ "source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind" ], + + // Uncomment to connect as a non-root user if you've added one. See https://aka.ms/vscode-remote/containers/non-root. + // "remoteUser": "vscode" +} diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..52ca57e --- /dev/null +++ b/.dockerignore @@ -0,0 +1,21 @@ +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/charts +**/docker-compose* +**/compose* +**/Dockerfile* +**/secrets.dev.yaml +**/values.dev.yaml +/moose diff --git a/.gitmodules b/.gitmodules index eb22281..672802c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,10 +1,6 @@ [submodule "ascot5-python"] path = ascot5-python url = git@version.aalto.fi:ascot/python.git -[submodule "moose"] - path = moose - url = git@github.com:idaholab/moose.git - branch = master [submodule "ascot5"] path = ascot5 url = git@version.aalto.fi:ascot/ascot5.git diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..a090484 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,44 @@ +{ + "configurations": [ + { + "name": "MOOSE-Linux", + "includePath": [ + "${workspaceFolder}", + "${workspaceFolder}/build/header_symlinks", + "${workspaceFolder}/unit/build/header_symlinks", + "${MOOSE_DIR}/framework/build/header_symlinks", + "${MOOSE_DIR}/framework/contrib/gtest", + "${MOOSE_DIR}/modules/module_loader/build/header_symlinks", + "${MOOSE_DIR}/framework/contrib/boost/include", + "${MOOSE_DIR}/framework/contrib/hit", + "${MOOSE_DIR}/framework/contrib/json/include", + "${MOOSE_DIR}/libmesh/installed/include", + "/usr/include/hdf5/serial", + "${PETSC_DIR}/include" + ], + "defines": [], + "compilerPath": "/usr/bin/mpicxx", + "cStandard": "c11", + "cppStandard": "c++17", + "intelliSenseMode": "linux-gcc-x64", + "browse": { + "path": [ + "${workspaceFolder}", + "${workspaceFolder}/build/header_symlinks", + "${workspaceFolder}/unit/build/header_symlinks", + "${MOOSE_DIR}/framework/build/header_symlinks", + "${MOOSE_DIR}/framework/contrib/gtest", + "${MOOSE_DIR}/modules/module_loader/build/header_symlinks", + "${MOOSE_DIR}/framework/contrib/boost/include", + "${MOOSE_DIR}/framework/contrib/hit", + "${MOOSE_DIR}/framework/contrib/json/include", + "${MOOSE_DIR}/libmesh/installed/include", + "/usr/include/hdf5/serial", + "${PETSC_DIR}/include" + ] + }, + "compilerArgs": [ ] + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..655283d --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,48 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Python: Current File", + "type": "python", + "request": "launch", + "program": "${file}", + "console": "integratedTerminal" + }, + { + "name": "(lldb) Launch", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/phaethon-dbg", + "args": [ + "-i", + "test/tests/simple_diffusion/simple_diffusion.i" + ], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": true, + "MIMode": "lldb", + "logging": { + "trace": true, + "traceResponse": true, + "engineLogging": true + } + }, + { + "name": "(lldb) Unit Test Launch", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/unit/phaethon-unit-dbg", + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": true, + "MIMode": "gdb", + "logging": { + "trace": true, + "traceResponse": true, + "engineLogging": true + } + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..dc66182 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,20 @@ +{ + "files.associations": { + "*.C": "cpp", + "*.h": "cpp", + "cmath": "cpp", + "ratio": "cpp", + "*.tcc": "cpp", + "fstream": "cpp", + "iosfwd": "cpp", + "istream": "cpp", + "limits": "cpp", + "shared_mutex": "cpp", + "sstream": "cpp", + "streambuf": "cpp", + "vector": "cpp" + }, + "python.linting.flake8Enabled": true, + "python.linting.enabled": true, + "restructuredtext.languageServer.disabled": true +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..71d0d64 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,117 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Build Unit Tests", + "type": "shell", + "command": "make", + "group": { + "kind": "build", + "isDefault": true + }, + "options": {"shell": {"args": ["-ic"]}}, + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "shared" + }, + "args": ["--directory=${workspaceFolder}/unit", "METHOD=devel", "-j4"], + "problemMatcher": { + "owner": "cpp", + "fileLocation": ["absolute"], + "pattern": { + "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + } + } + }, + { + "label": "Makefike debug", + "type": "shell", + "command": "make", + "group": "none", + "options": {"shell": {"args": ["-ic"]}}, + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "shared" + }, + "args": ["METHOD=dbg", "-j4"], + "problemMatcher": { + "owner": "cpp", + "fileLocation": ["absolute"], + "pattern": { + "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + } + } + }, + { + "label": "Makefike clean", + "type": "shell", + "command": "make", + "group": "none", + "options": {"shell": {"args": ["-ic"]}}, + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "shared" + }, + "args": ["clean"], + "problemMatcher": { + "owner": "cpp", + "fileLocation": ["absolute"], + "pattern": { + "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + } + } + }, + { + "label": "Test", + "type": "shell", + "command": "./run_tests", + "group": "test", + "options": {"shell": {"args": ["-ic"]}}, + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "shared" + }, + "args": ["-j4"] + }, + { + "label": "Run Unit Tests", + "type": "shell", + "command": "./unit/run_tests", + "group": { + "kind": "test", + "isDefault": true + }, + "options": {"shell": {"args": ["-ic"]}}, + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "shared" + }, + "args": ["-j4"] + } + ] +} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..56c3b6c --- /dev/null +++ b/Dockerfile @@ -0,0 +1,57 @@ +#################### +# ASCOT5 Build Stage +#################### +# TODO should probably move away from using submodules. It means the version +# information of dependencies is scattered, and it would be better to centralise +# it here. +FROM helenbrooks/moose-ubuntu AS ascot5-moose-ubuntu + +# Basic environment +ARG DEBIAN_FRONTEND=noninteractive +WORKDIR /home/ascot5 +# Set path to shared library for Python interface to use and other environment +ENV LD_LIBRARY_PATH=/home/ascot5 EDITOR=vim LC_ALL=C.UTF-8 LANG=C.UTF-8 + +# ASCOT5 main C program and library +RUN apt-get update && apt-get -y install make libhdf5-dev +COPY ascot5 ./ +# This is a completely serial version with no MPI or OpenMP offloading to GPUs +ENV MAKE_OPT='NOGIT=true CC=h5cc MPI=0 FLAGS=-foffload=disable' +RUN make clean ${MAKE_OPT}} && make ascot5_main ${MAKE_OPT} && \ + make libascot ${MAKE_OPT} && \ + ln -s -t /usr/local/bin/ $(readlink -f ascot5_main) + +# ASCOT5 Python +RUN apt-get -y install python3-pip +COPY ascot5-python ./ascot5-python +RUN pip install ascot5-python/a5py + +################################### +# Phaethon Dependencies Build Stage +################################### +FROM ascot5-moose-ubuntu AS phaethon-deps + +RUN pip install meshio[all] click + +################################## +# Phaethon Development Environment +################################## +FROM phaethon-deps as phaethon-dev + +ENV METHOD=devel +WORKDIR /home/moose +# Update libMesh and PETSc +RUN ./scripts/update_and_rebuild_petsc.sh --prefix=/home/petsc && \ + ./scripts/update_and_rebuild_libmesh.sh --with-mpi +# This is needed or it mpiexec complains because docker runs as root +# Discussion on this issue https://github.com/open-mpi/ompi/issues/4451 +ENV OMPI_ALLOW_RUN_AS_ROOT=1 +ENV OMPI_ALLOW_RUN_AS_ROOT_CONFIRM=1 +# Re-build MOOSE framework in devel mode +RUN cd test && make -j4 && ./run_tests -j4 +RUN cd modules && make -j4 && ./run_tests -j4 + +RUN apt-get -y install clang-format curl +RUN curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash && \ + apt-get -y install git-lfs && \ + git lfs install \ No newline at end of file diff --git a/Makefile b/Makefile index dda9cf9..9d0764a 100644 --- a/Makefile +++ b/Makefile @@ -49,6 +49,10 @@ XFEM := no include $(MOOSE_DIR)/modules/modules.mk ############################################################################### +# Additional libraries for HDF5 support +ADDITIONAL_INCLUDES := -I/usr/include/hdf5/serial +ADDITIONAL_LIBS := -lhdf5_hl_cpp -lhdf5_cpp -lhdf5_serial_hl -lhdf5_serial + # dep apps APPLICATION_DIR := $(CURDIR) APPLICATION_NAME := phaethon diff --git a/README.md b/README.md index ee91079..4d5b9f4 100644 --- a/README.md +++ b/README.md @@ -2,17 +2,23 @@ ## Installation -`Phaethon` relies on both submodules and conda environments for installation. -Issue the following commands from the command line: +The easiest way to get Phaethon running is with Docker as this will handle all +dependencies for you. Issue the following commands from the command line: ``` git clone --recurse-submodules git@github.com:aurora-multiphysics/phaethon.git cd phaethon -conda env create --file conda_env_freeze.yml -conda activate phaethon +docker build --tag phaethon:dev --file Dockerfile . +docker run -it phaethon:dev /bin/bash make -j ``` +### Building from Source + +In short, take a look at the `Dockerfile` to see what dependencies are necessary. + +TODO fill this out + ## Building on Phaethon You can fork `Phaethon` to create a new MOOSE-based application. diff --git a/ascot5-python b/ascot5-python index 9d19a0b..e8bbd60 160000 --- a/ascot5-python +++ b/ascot5-python @@ -1 +1 @@ -Subproject commit 9d19a0bab74cb9f4689e2e05ee93763cfbafe1b5 +Subproject commit e8bbd603b750ac27d3029718da7c34abffe569b3 diff --git a/conda_env_freeze.yml b/conda_env_freeze.yml deleted file mode 100644 index 83dc015..0000000 --- a/conda_env_freeze.yml +++ /dev/null @@ -1,261 +0,0 @@ -name: phaethon -channels: - - idaholab - - conda-forge -dependencies: - - _libgcc_mutex=0.1=conda_forge - - _openmp_mutex=4.5=1_gnu - - attrs=21.2.0=pyhd8ed1ab_0 - - backcall=0.2.0=pyh9f0ad1d_0 - - backports=1.0=py_2 - - backports.functools_lru_cache=1.6.4=pyhd8ed1ab_0 - - bashlex=0.15=py37h89c1867_2 - - beautifulsoup4=4.9.3=pyhb0f4dca_0 - - binutils_impl_linux-64=2.35.1=h193b22a_2 - - binutils_linux-64=2.35=hc3fd857_29 - - bleach=3.3.0=pyh44b312d_0 - - blosc=1.21.0=h9c3ff4c_0 - - bzip2=1.0.8=h7f98852_4 - - c-ares=1.17.1=h7f98852_1 - - ca-certificates=2021.5.30=ha878542_0 - - certifi=2021.5.30=py37h89c1867_0 - - cftime=1.5.0=py37h6f94858_0 - - click=8.0.1=py37h89c1867_0 - - cloudpickle=1.6.0=py_0 - - cmake=3.19.4=h4547794_0 - - compiledb=0.10.1=py_0 - - curl=7.76.1=h979ede3_1 - - cycler=0.10.0=py_2 - - cytoolz=0.11.0=py37h5e8e339_3 - - dask-core=2021.5.1=pyhd8ed1ab_0 - - dbus=1.13.6=hfdff14a_1 - - decorator=5.0.9=pyhd8ed1ab_0 - - defusedxml=0.7.1=pyhd8ed1ab_0 - - entrypoints=0.3=pyhd8ed1ab_1003 - - expat=2.4.1=h9c3ff4c_0 - - flake8=3.9.2=pyhd8ed1ab_0 - - fontconfig=2.13.1=hba837de_1005 - - freetype=2.10.4=h0708190_1 - - fsspec=2021.5.0=pyhd8ed1ab_0 - - future=0.18.2=py37h89c1867_3 - - gcc_impl_linux-64=9.3.0=h28f5a38_17 - - gcc_linux-64=9.3.0=h7247604_29 - - gettext=0.19.8.1=hf34092f_1004 - - gfortran_impl_linux-64=9.3.0=hc4a2995_19 - - gfortran_linux-64=9.3.0=ha1c937c_29 - - glib=2.66.3=h58526e2_0 - - gmp=6.2.1=h58526e2_0 - - gmsh=4.6.0=hd134328_0 - - gst-plugins-base=1.14.5=h0935bb2_2 - - gstreamer=1.14.5=h36ae1b5_2 - - gxx_impl_linux-64=9.3.0=h53cdd4c_17 - - gxx_linux-64=9.3.0=h0d07fa4_29 - - h5py=2.10.0=nompi_py37h513d04c_102 - - hdf4=4.2.15=h10796ff_3 - - hdf5=1.10.5=nompi_h5b725eb_1114 - - icu=67.1=he1b5a44_0 - - imagecodecs-lite=2019.12.3=py37h902c9e0_3 - - imageio=2.9.0=py_0 - - importlib-metadata=4.4.0=py37h89c1867_0 - - importlib_metadata=4.4.0=hd8ed1ab_0 - - ipykernel=5.5.5=py37h085eea5_0 - - ipython=7.24.1=py37h085eea5_0 - - ipython_genutils=0.2.0=py_1 - - ipywidgets=7.6.3=pyhd3deb0d_0 - - jedi=0.18.0=py37h89c1867_2 - - jinja2=3.0.1=pyhd8ed1ab_0 - - jpeg=9d=h36c2ea0_0 - - jsoncpp=1.8.4=hc9558a2_1002 - - jsonschema=3.2.0=pyhd8ed1ab_3 - - jupyter=1.0.0=py37h89c1867_6 - - jupyter_client=6.1.12=pyhd8ed1ab_0 - - jupyter_console=6.4.0=pyhd8ed1ab_0 - - jupyter_core=4.7.1=py37h89c1867_0 - - jupyterlab_widgets=1.0.0=pyhd8ed1ab_1 - - kernel-headers_linux-64=2.6.32=h77966d4_13 - - kiwisolver=1.3.1=py37h2527ec5_1 - - krb5=1.17.2=h926e7f8_0 - - latexcodec=2.0.1=pyh9f0ad1d_0 - - lcms2=2.11=hcbb858e_1 - - ld_impl_linux-64=2.35.1=hea4e1c9_2 - - libblas=3.9.0=9_openblas - - libcblas=3.9.0=9_openblas - - libclang=10.0.1=default_hde54327_1 - - libcurl=7.76.1=hc4aaa36_1 - - libdrm-cos6-x86_64=2.4.65=h9d98e8f_1104 - - libedit=3.1.20191231=he28a2e2_2 - - libev=4.33=h516909a_1 - - libevent=2.1.10=hcdb4288_3 - - libffi=3.2.1=he1b5a44_1007 - - libgcc-devel_linux-64=9.3.0=hfd08b2a_17 - - libgcc-ng=9.3.0=h2828fa1_19 - - libgfortran-ng=9.3.0=hff62375_19 - - libgfortran5=9.3.0=hff62375_19 - - libglib=2.66.3=hbe7bbb4_0 - - libglu=9.0.0=hf484d3e_1000 - - libgomp=9.3.0=h2828fa1_19 - - libice-cos6-x86_64=1.0.6=h9d98e8f_1104 - - libice-devel-cos6-x86_64=1.0.6=h9d98e8f_1104 - - libiconv=1.16=h516909a_0 - - liblapack=3.9.0=9_openblas - - libllvm10=10.0.1=he513fc3_3 - - libnetcdf=4.6.2=h303dfb8_1003 - - libnghttp2=1.43.0=h812cca2_0 - - libopenblas=0.3.15=pthreads_h8fe5266_1 - - libpng=1.6.37=hed695b0_0 - - libpq=12.3=h255efa7_3 - - libsm-cos6-x86_64=1.2.1=h9d98e8f_1104 - - libsm-devel-cos6-x86_64=1.2.1=h9d98e8f_1104 - - libsodium=1.0.18=h36c2ea0_1 - - libssh2=1.9.0=ha56f1ee_6 - - libstdcxx-devel_linux-64=9.3.0=h4084dd6_17 - - libstdcxx-ng=9.3.0=h6de172a_19 - - libtiff=4.1.0=hc3755c2_3 - - libuuid=2.32.1=h7f98852_1000 - - libuv=1.41.0=h7f98852_0 - - libx11-common-cos6-x86_64=1.6.4=h9d98e8f_1104 - - libx11-cos6-x86_64=1.6.4=h9d98e8f_1104 - - libx11-devel-cos6-x86_64=1.6.4=h9d98e8f_1104 - - libxcb=1.13=h7f98852_1003 - - libxext-cos6-x86_64=1.3.3=h9d98e8f_1104 - - libxext-devel-cos6-x86_64=1.3.3=h9d98e8f_1104 - - libxkbcommon=0.10.0=he1b5a44_0 - - libxml2=2.9.10=h68273f3_2 - - libxslt=1.1.33=hf705e74_1 - - libxt-cos6-x86_64=1.1.4=h9d98e8f_1104 - - libxt-devel-cos6-x86_64=1.1.4=h9d98e8f_1104 - - livereload=2.6.3=pyh9f0ad1d_0 - - locket=0.2.0=py_2 - - lxml=4.6.3=py37h77fd288_0 - - lz4-c=1.8.3=he1b5a44_1001 - - lzo=2.10=h516909a_1000 - - mako=1.1.4=pyh44b312d_0 - - markupsafe=2.0.1=py37h5e8e339_0 - - matplotlib=3.4.2=py37h89c1867_0 - - matplotlib-base=3.4.2=py37hdd32ed1_0 - - matplotlib-inline=0.1.2=pyhd8ed1ab_2 - - mccabe=0.6.1=py_1 - - mesa-dri-drivers-cos6-x86_64=11.0.7=h9d98e8f_1104 - - mesa-dri1-drivers-cos6-x86_64=7.11=h9d98e8f_1104 - - mesa-libgl-cos6-x86_64=11.0.7=h9d98e8f_1104 - - mesa-libgl-devel-cos6-x86_64=11.0.7=h9d98e8f_1104 - - mesalib=18.3.1=h590aaf7_0 - - meshio=4.4.5=pyhd8ed1ab_0 - - mistune=0.8.4=py37h5e8e339_1003 - - mock=4.0.3=py37h89c1867_1 - - moose-libmesh=2021.05.25=build_0 - - moose-libmesh-vtk=6.3.0=build_5 - - moose-mpich=3.3.2=build_5 - - moose-petsc=3.14.2=build_4 - - moose-tools=2021.01.06=py_0 - - mpi=1.0=mpich - - mysql-common=8.0.21=0 - - mysql-libs=8.0.21=h43e1182_0 - - nbconvert=5.6.1=py37hc8dfbb8_1 - - nbformat=5.1.3=pyhd8ed1ab_0 - - ncurses=6.2=h58526e2_4 - - netcdf4=1.5.1.2=py37h73a1b54_1 - - networkx=2.5=py_0 - - notebook=5.7.10=py37hc8dfbb8_0 - - nspr=4.30=h9c3ff4c_0 - - nss=3.66=hb5efdd6_0 - - numexpr=2.7.3=py37hdc94413_0 - - numpy=1.20.3=py37h038b26d_1 - - occt=7.4.0=h9121d39_3 - - olefile=0.46=pyh9f0ad1d_1 - - openssl=1.1.1k=h7f98852_0 - - packaging=20.9=pyh44b312d_0 - - pandas=1.2.4=py37h219a48f_0 - - pandoc=2.14.0.2=h7f98852_0 - - pandocfilters=1.4.2=py_1 - - parso=0.8.2=pyhd8ed1ab_0 - - partd=1.2.0=pyhd8ed1ab_0 - - pcre=8.44=he1b5a44_0 - - pexpect=4.8.0=pyh9f0ad1d_2 - - pickleshare=0.7.5=py_1003 - - pillow=8.1.0=py37he6b4880_1 - - pip=21.1.2=pyhd8ed1ab_0 - - pkg-config=0.29.2=h36c2ea0_1008 - - prometheus_client=0.11.0=pyhd8ed1ab_0 - - prompt-toolkit=3.0.18=pyha770c72_0 - - prompt_toolkit=3.0.18=hd8ed1ab_0 - - pthread-stubs=0.4=h36c2ea0_1001 - - ptyprocess=0.7.0=pyhd3deb0d_0 - - pybtex=0.24.0=py37h89c1867_0 - - pycodestyle=2.7.0=pyhd8ed1ab_0 - - pyflakes=2.3.1=pyhd8ed1ab_0 - - pygments=2.9.0=pyhd8ed1ab_0 - - pylatexenc=2.10=pyhd8ed1ab_0 - - pyparsing=2.4.7=pyh9f0ad1d_0 - - pyqt=5.12.3=py37h89c1867_7 - - pyqt-impl=5.12.3=py37he336c9b_7 - - pyqt5-sip=4.19.18=py37hcd2ae1e_7 - - pyqtchart=5.12=py37he336c9b_7 - - pyqtwebengine=5.12.1=py37he336c9b_7 - - pyrsistent=0.17.3=py37h5e8e339_2 - - pytables=3.6.1=py37h9f153d1_1 - - python=3.7.8=h8bdb77d_2_cpython - - python-dateutil=2.8.1=py_0 - - python-gmsh=4.6.0=hd8ed1ab_2 - - python_abi=3.7=1_cp37m - - pytz=2021.1=pyhd8ed1ab_0 - - pywavelets=1.1.1=py37h902c9e0_3 - - pyyaml=5.4.1=py37h5e8e339_0 - - pyzmq=22.1.0=py37h336d617_0 - - qt=5.12.9=h1f2b2cb_0 - - qtconsole=5.1.0=pyhd8ed1ab_0 - - qtpy=1.9.0=py_0 - - readline=8.1=h46c0cb4_0 - - rhash=1.4.1=h7f98852_0 - - scikit-image=0.17.2=py37hdc94413_4 - - scipy=1.6.3=py37h29e03ee_0 - - send2trash=1.5.0=py_0 - - setuptools=49.6.0=py37h89c1867_3 - - shutilwhich=1.1.0=py_1 - - six=1.16.0=pyh6c4a22f_0 - - soupsieve=2.0.1=py_1 - - sqlite=3.35.5=h74cdb3f_0 - - sysroot_linux-64=2.12=h77966d4_13 - - tbb=2020.2=h4bd325d_4 - - terminado=0.10.1=py37h89c1867_0 - - testpath=0.5.0=pyhd8ed1ab_0 - - tifffile=2020.6.3=py_0 - - tk=8.6.10=h21135ba_1 - - toolz=0.11.1=py_0 - - tornado=6.1=py37h5e8e339_1 - - traitlets=5.0.5=py_0 - - typing_extensions=3.7.4.3=py_0 - - vitables=3.0.2=py37h8f50634_1 - - vtk=8.2.0=py37hfdee58b_203 - - wcwidth=0.2.5=pyh9f0ad1d_2 - - webencodings=0.5.1=py_1 - - wheel=0.36.2=pyhd3deb0d_0 - - widgetsnbextension=3.5.1=py37h89c1867_4 - - xorg-fixesproto=5.0=h7f98852_1002 - - xorg-kbproto=1.0.7=h7f98852_1002 - - xorg-libice=1.0.10=h7f98852_0 - - xorg-libsm=1.2.3=hd9c2040_1000 - - xorg-libx11=1.7.1=h7f98852_0 - - xorg-libxau=1.0.9=h7f98852_0 - - xorg-libxdmcp=1.1.3=h7f98852_0 - - xorg-libxext=1.3.4=h7f98852_1 - - xorg-libxfixes=5.0.3=h7f98852_1004 - - xorg-libxmu=1.1.3=h7f98852_0 - - xorg-libxrender=0.9.10=h7f98852_1003 - - xorg-libxt=1.2.1=h7f98852_2 - - xorg-renderproto=0.11.1=h7f98852_1002 - - xorg-x11-proto-devel-cos6-x86_64=7.7=h9d98e8f_1104 - - xorg-xextproto=7.3.0=h7f98852_1002 - - xorg-xproto=7.0.31=h7f98852_1007 - - xz=5.2.5=h516909a_1 - - yaml=0.2.5=h516909a_0 - - zeromq=4.3.4=h9c3ff4c_0 - - zipp=3.4.1=pyhd8ed1ab_0 - - zlib=1.2.11=h516909a_1010 - - zstd=1.4.4=h3b9ef0a_2 - - pip: - - ./ascot5-python/a5py -variables: - EDITOR: vim - LD_LIBRARY_PATH: /home/mbluteau/work/projects/moose_fi_app/code/ascot5 -prefix: /home/mbluteau/miniforge3/envs/phaethon diff --git a/conda_env_fresh.yml b/conda_env_fresh.yml deleted file mode 100644 index aa82205..0000000 --- a/conda_env_fresh.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: phaethon -channels: - - idaholab - - conda-forge -dependencies: - - moose-libmesh - - moose-tools - - compiledb - - python-gmsh - - h5py - - ipython - - matplotlib - - numpy - - pip - - scipy - - vitables - - vtk - - pip: - # The next line installs a5py. This needs to be run from top level - # directory of Phaethon project - - ascot5-python/a5py -variables: - EDITOR: vim - LD_LIBRARY_PATH: /home/mbluteau/work/projects/moose_fi_app/code/ascot5 diff --git a/include/problems/AscotProblem.h b/include/problems/AscotProblem.h index 7cdda7f..aa3b421 100644 --- a/include/problems/AscotProblem.h +++ b/include/problems/AscotProblem.h @@ -11,6 +11,13 @@ #include "ExternalProblem.h" #include "PhaethonApp.h" +#include "H5Cpp.h" + +namespace constants +{ +const double_t c = 299792458.0; +const double_t amu = 1.6605390666e-27; +} class AscotProblem : public ExternalProblem { @@ -45,9 +52,46 @@ class AscotProblem : public ExternalProblem */ virtual void addExternalVariables() override {} + /** + * @brief Get the Active Endstate Group object + * + * @param hdf5_file the ASCOT5 HDF5 file with output data. + * @return Group the HDF5 group object for the active endstate. + */ + H5::Group getActiveEndstate(const H5::H5File & hdf5_file); + + /** + * @brief Get the indices of wall tiles that each particle has collided with + * + * @param endstate_group the HDF5 group object for the active endstate. + * @return std::vector the wall mesh elements that each particle has + * hit in this timestep. Indexed by particles. + */ + std::vector getWallTileHits(H5::Group & endstate_group); + + /** + * @brief Get the Particle Energies + * + * @param endstate_group the HDF5 group object for the active endstate. + * @return std::vector the particles energies in Joules. + */ + std::vector getParticleEnergies(H5::Group & endstate_group); + + /** + * @brief Calculate the relativistic energy for a particle from velocities + * + * @param mass the particle's mass in kg. + * @param velocity the particle's velocity vector in m/s. + * @return double_t the particle's energy in Joules + */ + static double_t calculateRelativisticEnergy(double_t mass, std::vector velocity); + private: - /// The name of the variable to transfer to + /// The name of the AuxVariable to transfer to const VariableName & _sync_to_var_name; - /// The libMesh System object that contains + /// The Auxiliary system in which the heat flux values will be stored System & _problem_system; + /// The HDF5 file that is both the ASCOT5 input and output + const H5std_string _ascot5_file_name; + H5::H5File _ascot5_file; }; diff --git a/moose b/moose deleted file mode 160000 index 0c6666e..0000000 --- a/moose +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0c6666e7ddb1aaae77400708fc6e9eba9f324ed5 diff --git a/src/problems/AscotProblem.C b/src/problems/AscotProblem.C index f10e1c1..b412ec3 100644 --- a/src/problems/AscotProblem.C +++ b/src/problems/AscotProblem.C @@ -10,6 +10,8 @@ // MOOSE includes #include "AscotProblem.h" #include "AuxiliarySystem.h" +#include +using namespace H5; registerMooseObject("PhaethonApp", AscotProblem); @@ -27,7 +29,8 @@ AscotProblem::validParams() AscotProblem::AscotProblem(const InputParameters & parameters) : ExternalProblem(parameters), _sync_to_var_name(getParam("sync_variable")), - _problem_system(getAuxiliarySystem().system()) + _problem_system(getAuxiliarySystem().system()), + _ascot5_file_name("ascot5.h5") { } @@ -51,7 +54,121 @@ AscotProblem::syncSolutions(Direction direction) { if (direction == Direction::FROM_EXTERNAL_APP) { - return; + // Open ASCOT5 file and relevant group + H5File ascot5_file(_ascot5_file_name, H5F_ACC_RDONLY); + Group ascot5_active_endstate = getActiveEndstate(ascot5_file); + + // Get particle information + std::vector walltile = getWallTileHits(ascot5_active_endstate); + std::vector energies = getParticleEnergies(ascot5_active_endstate); + + /* + TODO + - Calculate heat flux values for each mesh element using walltile and energies + - Map these onto the AuxVariable in _problem_system + */ } return; } + +Group +AscotProblem::getActiveEndstate(const H5File & hdf5_file) +{ + // Open the results group + Group results_group = hdf5_file.openGroup("results"); + + // Check if the attribute 'active' is present + if (results_group.attrExists("active")) + { + // Open the attribute + H5::Attribute results_active_attr = results_group.openAttribute("active"); + // Get its string type + StrType stype = results_active_attr.getStrType(); + // Read the active run number into a string buffer + std::string active_result_num; + results_active_attr.read(stype, active_result_num); + // Open the active run group + std::string endstate_name = "run_" + active_result_num + "/endstate"; + Group endstate_group = results_group.openGroup(endstate_name); + return endstate_group; + } + else + { + throw MooseException("ASCOT5 HDF5 File missing 'active' attribute."); + } +} + +std::vector +AscotProblem::getWallTileHits(Group & endstate_group) +{ + // Open the walltile dataset + DataSet walltile_dataset = endstate_group.openDataSet("walltile"); + // Get the walltile dataset's data space + DataSpace walltile_dataspace = walltile_dataset.getSpace(); + // check we only have 1 dim + if (walltile_dataspace.getSimpleExtentNdims() == 1) + { + hssize_t n_markers = walltile_dataspace.getSimpleExtentNpoints(); + std::vector walltile(n_markers); + walltile_dataset.read(walltile.data(), PredType::NATIVE_INT64); + return walltile; + } + else + { + throw MooseException("ASCOT5 HDF5 File walltile dataset of incorrect dim."); + } +} + +std::vector +AscotProblem::getParticleEnergies(Group & endstate_group) +{ + + std::vector particle_energies; + // Open the one of the datasets to check the number of ions/markers + DataSet mass_dataset = endstate_group.openDataSet("mass"); + DataSpace mass_dataspace = mass_dataset.getSpace(); + // Check we only have 1 dim + if (mass_dataspace.getSimpleExtentNdims() != 1) + { + throw MooseException("ASCOT5 HDF5 File walltile dataset of incorrect dim."); + } + const hsize_t n_markers = mass_dataspace.getSimpleExtentNpoints(); + + // Read in mass + std::vector mass(n_markers); + mass_dataset.read(mass.data(), PredType::NATIVE_DOUBLE); + // Read in velocities + std::unordered_map> velocities; + std::vector velocity_names{"vr", "vphi", "vz"}; + for (auto && name : velocity_names) + { + velocities[name].resize(n_markers); + DataSet v_dataset = endstate_group.openDataSet(name); + v_dataset.read(velocities[name].data(), PredType::NATIVE_DOUBLE); + } + + std::vector velocity; + for (hsize_t i = 0; i < n_markers; i++) + { + for (auto && name : velocity_names) + { + velocity.push_back(velocities[name][i]); + } + particle_energies.push_back(calculateRelativisticEnergy(mass[i], velocity)); + velocity.clear(); + } + + return particle_energies; +} + +double_t +AscotProblem::calculateRelativisticEnergy(double_t mass, std::vector velocity) +{ + + std::transform(velocity.begin(), velocity.end(), velocity.begin(), [](double_t & v) { + return v / constants::c; + }); + double_t magnitude = std::inner_product(velocity.begin(), velocity.end(), velocity.begin(), 0.0); + double_t gamma = 1.0 / sqrt(1.0 - magnitude); + return (gamma - 1.0) * mass * constants::amu * constants::c * constants::c; +} \ No newline at end of file diff --git a/.gitattributes b/supplementary/ascot5/.gitattributes similarity index 100% rename from .gitattributes rename to supplementary/ascot5/.gitattributes diff --git a/supplementary/ascot5/calculate_simple_run_particle_energies.ipynb b/supplementary/ascot5/calculate_simple_run_particle_energies.ipynb new file mode 100644 index 0000000..19c781d --- /dev/null +++ b/supplementary/ascot5/calculate_simple_run_particle_energies.ipynb @@ -0,0 +1,252 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "e0be1d35", + "metadata": {}, + "source": [ + "The particle energy values returned by the ASCOT5 Python interface are not accurate for some reason. There is some internal conversion going on that results in results that are off in about the 4th significant digit and causing unit tests to fail. The code below is to generate the energy values independently from the mass and velocity values. Empirically, these have matched the results from the MOOSE App (`AscotProblem`). " + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "41efb82d", + "metadata": {}, + "outputs": [], + "source": [ + "from a5py.ascot5io import ascot5\n", + "import numpy as np\n", + "from scipy import constants\n", + "import pprint" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "495ab464", + "metadata": {}, + "outputs": [], + "source": [ + "a5file = ascot5.Ascot('simple_run.h5')" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "2925e850", + "metadata": {}, + "outputs": [], + "source": [ + "endstate = a5file.active.endstate\n", + "velocities = np.array([endstate[index] for index in ('vr', 'vphi', 'vz')])\n", + "mass = endstate['mass']" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "7b6a2516", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([6.64215627e-27, 6.64215627e-27, 6.64215627e-27, 6.64215627e-27,\n", + " 6.64215627e-27, 6.64215627e-27, 6.64215627e-27, 6.64215627e-27,\n", + " 6.64215627e-27, 6.64215627e-27, 6.64215627e-27, 6.64215627e-27,\n", + " 6.64215627e-27, 6.64215627e-27, 6.64215627e-27, 6.64215627e-27,\n", + " 6.64215627e-27, 6.64215627e-27, 6.64215627e-27, 6.64215627e-27,\n", + " 6.64215627e-27, 6.64215627e-27, 6.64215627e-27, 6.64215627e-27,\n", + " 6.64215627e-27, 6.64215627e-27, 6.64215627e-27, 6.64215627e-27,\n", + " 6.64215627e-27, 6.64215627e-27, 6.64215627e-27, 6.64215627e-27,\n", + " 6.64215627e-27, 6.64215627e-27, 6.64215627e-27, 6.64215627e-27,\n", + " 6.64215627e-27, 6.64215627e-27, 6.64215627e-27, 6.64215627e-27,\n", + " 6.64215627e-27, 6.64215627e-27, 6.64215627e-27, 6.64215627e-27,\n", + " 6.64215627e-27, 6.64215627e-27, 6.64215627e-27, 6.64215627e-27,\n", + " 6.64215627e-27, 6.64215627e-27, 6.64215627e-27, 6.64215627e-27,\n", + " 6.64215627e-27, 6.64215627e-27, 6.64215627e-27, 6.64215627e-27,\n", + " 6.64215627e-27, 6.64215627e-27, 6.64215627e-27, 6.64215627e-27,\n", + " 6.64215627e-27, 6.64215627e-27, 6.64215627e-27, 6.64215627e-27,\n", + " 6.64215627e-27, 6.64215627e-27, 6.64215627e-27, 6.64215627e-27,\n", + " 6.64215627e-27, 6.64215627e-27, 6.64215627e-27, 6.64215627e-27,\n", + " 6.64215627e-27, 6.64215627e-27, 6.64215627e-27, 6.64215627e-27,\n", + " 6.64215627e-27, 6.64215627e-27, 6.64215627e-27, 6.64215627e-27,\n", + " 6.64215627e-27, 6.64215627e-27, 6.64215627e-27, 6.64215627e-27,\n", + " 6.64215627e-27, 6.64215627e-27, 6.64215627e-27, 6.64215627e-27,\n", + " 6.64215627e-27, 6.64215627e-27, 6.64215627e-27, 6.64215627e-27,\n", + " 6.64215627e-27, 6.64215627e-27, 6.64215627e-27, 6.64215627e-27,\n", + " 6.64215627e-27, 6.64215627e-27, 6.64215627e-27, 6.64215627e-27])" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "velocities = velocities.T" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "0726a43e", + "metadata": {}, + "outputs": [], + "source": [ + "def calculate_rel_energy(mass, velocities):\n", + " c_sqrd = constants.c**2\n", + " gamma = 1 / np.sqrt(1 - np.square(velocities).sum() / c_sqrd)\n", + " return (gamma - 1) * mass * c_sqrd" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "c3ef657d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[5.605926430766929e-13,\n", + " 5.601051900561567e-13,\n", + " 5.605507494388142e-13,\n", + " 5.605521060424595e-13,\n", + " 5.605507494389468e-13,\n", + " 5.605419474202633e-13,\n", + " 5.605507494389468e-13,\n", + " 5.605230803343478e-13,\n", + " 4.8187003883044004e-14,\n", + " 5.600793767077879e-13,\n", + " 5.493419161077282e-14,\n", + " 5.60065615647442e-13,\n", + " 5.607982721999194e-13,\n", + " 5.605507494389468e-13,\n", + " 5.597399589610087e-13,\n", + " 5.609889157350513e-13,\n", + " 5.605467255517832e-13,\n", + " 5.601083012514452e-13,\n", + " 5.605917132098798e-13,\n", + " 5.605465781923524e-13,\n", + " 5.605558284969342e-13,\n", + " 5.605618763590173e-13,\n", + " 2.0217818919896866e-15,\n", + " 5.601996318234811e-13,\n", + " 5.605121299265648e-13,\n", + " 5.605573776524855e-13,\n", + " 5.601718010601258e-13,\n", + " 5.605507494388142e-13,\n", + " 5.60437135749313e-13,\n", + " 4.583489379583762e-14,\n", + " 5.605507494389468e-13,\n", + " 5.605507494392119e-13,\n", + " 5.601922633496998e-13,\n", + " 5.597604996911506e-13,\n", + " 5.605483815852361e-13,\n", + " 5.605498044238039e-13,\n", + " 5.605974841660187e-13,\n", + " 5.602017727087353e-13,\n", + " 5.605508751150348e-13,\n", + " 5.605507494389468e-13,\n", + " 5.60736391874695e-13,\n", + " 5.606891917619445e-13,\n", + " 5.605507494389468e-13,\n", + " 5.604382320411032e-13,\n", + " 5.610998403998983e-13,\n", + " 5.605507494388142e-13,\n", + " 2.0498838052658058e-14,\n", + " 5.605554641374569e-13,\n", + " 5.601533005143227e-13,\n", + " 5.605501683576524e-13,\n", + " 5.605507494390794e-13,\n", + " 5.605507494388142e-13,\n", + " 5.604745474953177e-13,\n", + " 5.605507494388142e-13,\n", + " 5.605507494389468e-13,\n", + " 5.605477399784898e-13,\n", + " 3.1963590684255424e-13,\n", + " 5.605469077076623e-13,\n", + " 5.605507494389468e-13,\n", + " 5.601656161475514e-13,\n", + " 5.602356950913613e-13,\n", + " 5.601689312043307e-13,\n", + " 5.605507494390794e-13,\n", + " 5.605507494388142e-13,\n", + " 5.601159061748266e-13,\n", + " 5.605457615743528e-13,\n", + " 5.60546590906605e-13,\n", + " 5.603182193530339e-13,\n", + " 5.605507494389468e-13,\n", + " 5.599371462290527e-13,\n", + " 5.597735375312527e-13,\n", + " 5.060830674399048e-15,\n", + " 3.2042099743819206e-16,\n", + " 5.60927426253862e-13,\n", + " 1.1805070617155672e-14,\n", + " 5.59996737743059e-13,\n", + " 5.605564375481793e-13,\n", + " 3.499971908884817e-14,\n", + " 5.601468719299787e-13,\n", + " 5.602773784667478e-13,\n", + " 5.605507494389468e-13,\n", + " 5.608335956994626e-13,\n", + " 5.605506143298319e-13,\n", + " 5.598687451474493e-13,\n", + " 5.605507494389468e-13,\n", + " 5.605507494390794e-13,\n", + " 5.338941835714529e-14,\n", + " 5.605507494389468e-13,\n", + " 5.605507494390794e-13,\n", + " 5.603962540140598e-13,\n", + " 5.605507494389468e-13,\n", + " 5.606533306652346e-13,\n", + " 5.605507494390794e-13,\n", + " 5.602775486684352e-13,\n", + " 5.605507494388142e-13,\n", + " 5.605507494389468e-13,\n", + " 5.605442437704533e-13,\n", + " 5.605507494393444e-13,\n", + " 5.600653006044399e-13,\n", + " 5.605565120199672e-13]\n" + ] + } + ], + "source": [ + "energies = [calculate_rel_energy(mass[i], velocities[i]) for i in range(mass.size)]\n", + "pprint.pprint(energies)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d826a2c4", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.8" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/supplementary/ascot5/generate_test_data.sh b/supplementary/ascot5/generate_test_data.sh index 6fc0565..a6b67e3 100755 --- a/supplementary/ascot5/generate_test_data.sh +++ b/supplementary/ascot5/generate_test_data.sh @@ -1,26 +1,15 @@ #!/bin/bash # coding: utf-8 -# # Generate test data from ASCOT5 'simplerun' -# -# Build docker image (if not already in existence) +# Generate test data from ASCOT5 'simplerun' -cd ../../ascot5 -make docker - -# Generate the input file using a preprocessing script - -python3 ../ascot5-python/a5py/a5py/preprocessing/simpleruns.py +python ../../ascot5-python/a5py/a5py/preprocessing/simpleruns.py +mv helloworld.h5 simple_run.h5 # Run ascot5 on input data -./run_docker helloworld - -# Move output to this directory - -mv helloworld.h5 ../supplementary/ascot5/simple_run.h5 +ascot5_main --in simple_run -# # Generate dummy mesh for use in MOOSE app +# Generate dummy mesh for use in MOOSE app -cd - ./a5wall_to_gmsh.py simple_run.h5 diff --git a/unit/Makefile b/unit/Makefile index f8e14f3..5cc23f0 100644 --- a/unit/Makefile +++ b/unit/Makefile @@ -44,9 +44,9 @@ LEVEL_SET := no include $(MOOSE_DIR)/modules/modules.mk ############################################################################### -# Extra stuff for GTEST -ADDITIONAL_INCLUDES := -I$(FRAMEWORK_DIR)/contrib/gtest -ADDITIONAL_LIBS := $(FRAMEWORK_DIR)/contrib/gtest/libgtest.la +# Extra stuff for GTEST and HDF5 +ADDITIONAL_INCLUDES := -I$(FRAMEWORK_DIR)/contrib/gtest -I/usr/include/hdf5/serial +ADDITIONAL_LIBS := $(FRAMEWORK_DIR)/contrib/gtest/libgtest.la -lhdf5_hl_cpp -lhdf5_cpp -lhdf5_serial_hl -lhdf5_serial # dep apps CURRENT_DIR := $(shell pwd) diff --git a/unit/include/AscotProblemTest.h b/unit/include/AscotProblemTest.h index 3d89194..7ae8bb5 100644 --- a/unit/include/AscotProblemTest.h +++ b/unit/include/AscotProblemTest.h @@ -26,7 +26,7 @@ class AscotProblemTest : public PhaethonAppInputTest ASSERT_NE(executionerPtr, nullptr); // Get the FE problem - problemPtr = &(executionerPtr->feProblem()); + problemPtr = dynamic_cast(&(executionerPtr->feProblem())); ASSERT_NE(problemPtr, nullptr); // Check type (i.e. make sure this is an AscotProblem) @@ -34,5 +34,24 @@ class AscotProblemTest : public PhaethonAppInputTest } Executioner * executionerPtr = nullptr; - FEProblemBase * problemPtr = nullptr; + AscotProblem * problemPtr = nullptr; +}; + +class AscotProblemHDF5Test : public AscotProblemTest +{ +protected: + AscotProblemHDF5Test() + : AscotProblemTest("ascot_hdf5.i"), + hdf5_file(H5::H5File("inputs/simple_run.h5", H5F_ACC_RDONLY)){}; + + virtual void SetUp() override + { + // Call the base class method + EXPECT_NO_THROW(AscotProblemTest::SetUp()); + + // Get the file and briefly check it + EXPECT_GE(hdf5_file.getId(), 0); + } + + H5::H5File hdf5_file; }; diff --git a/unit/inputs/simple_run.h5 b/unit/inputs/simple_run.h5 new file mode 120000 index 0000000..e76c1d4 --- /dev/null +++ b/unit/inputs/simple_run.h5 @@ -0,0 +1 @@ +../../supplementary/ascot5/simple_run.h5 \ No newline at end of file diff --git a/unit/src/AscotProblemTest.C b/unit/src/AscotProblemTest.C index 5f723b4..cead63b 100644 --- a/unit/src/AscotProblemTest.C +++ b/unit/src/AscotProblemTest.C @@ -8,11 +8,95 @@ //* https://www.gnu.org/licenses/lgpl-2.1.html #include "AscotProblemTest.h" +#include -class AscotProblemHDF5Test : public AscotProblemTest +using namespace H5; + +TEST_F(AscotProblemHDF5Test, check_hdf5) +{ + + ASSERT_FALSE(appIsNull); + // Check that the results group is present, then open it + ASSERT_TRUE(hdf5_file.nameExists("results")); + Group results_group = hdf5_file.openGroup("results"); + + // Check that the attribute 'active' is present, and then open + ASSERT_TRUE(results_group.attrExists("active")); + H5::Attribute results_active_attr = results_group.openAttribute("active"); + + // Get the string type from the attribute; this seems to be the only way to + // read a string in without declaring its size in advance + StrType stype = results_active_attr.getStrType(); + // String buffer where attribute value will be stored + std::string active_result_num; + // Read the attribute value + results_active_attr.read(stype, active_result_num); + // Check that the active run number is as expected + ASSERT_EQ(active_result_num, "0069271660"); +} + +TEST_F(AscotProblemHDF5Test, read_walltile) +{ + + ASSERT_FALSE(appIsNull); + Group endstate_group = problemPtr->getActiveEndstate(hdf5_file); + std::vector simple_run_walltile{ + 16, 376, 33, 0, 74, 0, 271, 16, 13, 256, 173, 53, 133, 311, 133, 133, 0, + 0, 56, 0, 0, 0, 0, 213, 93, 0, 213, 154, 0, 334, 76, 193, 0, 0, + 0, 0, 0, 213, 0, 151, 93, 0, 391, 296, 373, 274, 374, 0, 93, 0, 31, + 274, 0, 73, 396, 0, 213, 0, 71, 94, 214, 53, 233, 194, 336, 0, 0, 53, + 196, 0, 373, 0, 0, 133, 293, 293, 0, 53, 0, 294, 391, 253, 0, 216, 356, + 236, 333, 116, 193, 253, 116, 293, 111, 334, 74, 356, 0, 236, 0, 0}; + + ASSERT_EQ(problemPtr->getWallTileHits(endstate_group), simple_run_walltile); +} + +TEST_F(AscotProblemHDF5Test, read_energy) { -protected: - AscotProblemHDF5Test() : AscotProblemTest("ascot_hdf5.i"){}; -}; -TEST_F(AscotProblemHDF5Test, setup) { ASSERT_FALSE(appIsNull); } + ASSERT_FALSE(appIsNull); + std::vector simple_run_energy{ + 5.605926430766929e-13, 5.601051900561567e-13, 5.605507494388142e-13, 5.605521060424595e-13, + 5.605507494389468e-13, 5.605419474202633e-13, 5.605507494389468e-13, 5.605230803343478e-13, + 4.8187003883044004e-14, 5.600793767077879e-13, 5.493419161077282e-14, 5.60065615647442e-13, + 5.607982721999194e-13, 5.605507494389468e-13, 5.597399589610087e-13, 5.609889157350513e-13, + 5.605467255517832e-13, 5.601083012514452e-13, 5.605917132098798e-13, 5.605465781923524e-13, + 5.605558284969342e-13, 5.605618763590173e-13, 2.0217818919896866e-15, 5.601996318234811e-13, + 5.605121299265648e-13, 5.605573776524855e-13, 5.601718010601258e-13, 5.605507494388142e-13, + 5.60437135749313e-13, 4.583489379583762e-14, 5.605507494389468e-13, 5.605507494392119e-13, + 5.601922633496998e-13, 5.597604996911506e-13, 5.605483815852361e-13, 5.605498044238039e-13, + 5.605974841660187e-13, 5.602017727087353e-13, 5.605508751150348e-13, 5.605507494389468e-13, + 5.60736391874695e-13, 5.606891917619445e-13, 5.605507494389468e-13, 5.604382320411032e-13, + 5.610998403998983e-13, 5.605507494388142e-13, 2.0498838052658058e-14, 5.605554641374569e-13, + 5.601533005143227e-13, 5.605501683576524e-13, 5.605507494390794e-13, 5.605507494388142e-13, + 5.604745474953177e-13, 5.605507494388142e-13, 5.605507494389468e-13, 5.605477399784898e-13, + 3.1963590684255424e-13, 5.605469077076623e-13, 5.605507494389468e-13, 5.601656161475514e-13, + 5.602356950913613e-13, 5.601689312043307e-13, 5.605507494390794e-13, 5.605507494388142e-13, + 5.601159061748266e-13, 5.605457615743528e-13, 5.60546590906605e-13, 5.603182193530339e-13, + 5.605507494389468e-13, 5.599371462290527e-13, 5.597735375312527e-13, 5.060830674399048e-15, + 3.2042099743819206e-16, 5.60927426253862e-13, 1.1805070617155672e-14, 5.59996737743059e-13, + 5.605564375481793e-13, 3.499971908884817e-14, 5.601468719299787e-13, 5.602773784667478e-13, + 5.605507494389468e-13, 5.608335956994626e-13, 5.605506143298319e-13, 5.598687451474493e-13, + 5.605507494389468e-13, 5.605507494390794e-13, 5.338941835714529e-14, 5.605507494389468e-13, + 5.605507494390794e-13, 5.603962540140598e-13, 5.605507494389468e-13, 5.606533306652346e-13, + 5.605507494390794e-13, 5.602775486684352e-13, 5.605507494388142e-13, 5.605507494389468e-13, + 5.605442437704533e-13, 5.605507494393444e-13, 5.600653006044399e-13, 5.605565120199672e-13}; + + Group endstate_group = problemPtr->getActiveEndstate(hdf5_file); + std::vector particle_energies = problemPtr->getParticleEnergies(endstate_group); + + for (size_t i = 0; i < simple_run_energy.size(); i++) + { + ASSERT_DOUBLE_EQ(particle_energies[i], simple_run_energy[i]); + } +} + +TEST_F(AscotProblemHDF5Test, calculate_relativistic_energy) +{ + // velocity components (r, phi, z) in m/s + std::vector velocity{6726950.87616652, -9727805.12233284, 5355264.46022884}; + // mass in amu + double_t mass = 4.0; + // relativistic energies compared in SI units (i.e. Joules) + ASSERT_DOUBLE_EQ(problemPtr->calculateRelativisticEnergy(mass, velocity), 5.605926430766929e-13); +} \ No newline at end of file