diff --git a/CMakeLists.txt b/CMakeLists.txt index fb52f0b84b67d28f2af26fc316e5a1c904faa28a..c95457bc6c19b6467eedabcb97f9d332d5442d1d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -638,7 +638,9 @@ message(" kokkos devices: ${PUGS_BUILD_KOKKOS_DEVICES}") if (MPI_FOUND) message(" MPI: ${MPI_CXX_LIBRARY_VERSION_STRING}") else() - if(NOT PARMETIS_LIBRARIES) + if (PUGS_ENABLE_MPI MATCHES "^OFF$") + message(" MPI: deactivated!") + elseif(NOT PARMETIS_LIBRARIES) message(" MPI: deactivated: ParMETIS cannot be found!") else() if (PUGS_ENABLE_MPI MATCHES "^(AUTO|ON)$") @@ -669,6 +671,8 @@ else() endif() endif() +message("----------- utilities ----------") + if(CLANG_FORMAT) message(" clang-format: ${CLANG_FORMAT}") else() @@ -693,5 +697,41 @@ else() message(" emacs: not found!") endif() +if (GNUPLOT_FOUND) + message(" gnuplot: ${GNUPLOT}") +else() + message(" gnuplot: not found!") +endif() + +if (PYGMENTIZE) + message(" pygmentize: ${PYGMENTIZE}") +else() + message(" pygmentize: not found!") +endif() + +if (LATEX_PDFLATEX_FOUND) + message(" pdflatex: ${PDFLATEX_COMPILER}") +else() + message(" pdflatex: not found!") +endif() + +if (NOT EMACS OR NOT GNUPLOT_FOUND) + message(" ** Cannot build documentation: missing ") +elseif(NOT LATEX_PDFLATEX_FOUND OR NOT PYGMENTIZE) + message(" ** Cannot build pdf documentation: missing") +endif() +if (NOT EMACS) + message(" - emacs") +endif() +if (NOT GNUPLOT_FOUND) + message(" - gnuplot") +endif() +if (NOT LATEX_PDFLATEX_FOUND) + message(" - pdflatex") +endif() +if (NOT PYGMENTIZE) + message(" - pygmentize") +endif() + message("================================") message("") diff --git a/README.md b/README.md index 4d1ed7f40f80eeb7a25b6b39871ae3c5402b6ee5..62d6b43773cb0164a29e8a3716a818c5ec219c7d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,263 @@ -The Pugs framework -================== +The `pugs` framework +==================== -Pugs stands for Parallel Unstructured Grid Solver. +`pugs` stands for Parallel Unstructured Grid Solvers. + +It aims at providing a collection of numerical methods and utilities +that are assembled together by a user friendly language. + +# Building `pugs` + +## Requirements + +For the most basic build, `pugs` only requires +- a C++-17 compiler. + - g++-10 or higher versions + - clang-10 or higher versions +- `CMake` (at least 3.16) + +> **Warning**:<br> +> Building `pugs` in its source directory is **forbidden**. Trying to +> do so will result in a failure. However it generally leaves some +> garbage files in the source directory, namely the `CMakeCache.txt` +> and the `CMakeFiles` directory. `CMake` itself is not able to remove +> them, to avoid the risk of compilation issues, one has to dot it +> manually... + +In the build directory, one for instance launches +```shell +cmake path-to-pugs-source +``` +and then +```shell +make -j nb_jobs +``` +Specifying the compiler is done for instance as +```shell +CXX=g++ CC=gcc cmake path-to-pugs-source +``` + +When compilation is done, `pugs` binary is produce. Additionally, one +can run unit tests by +```shell +make check +``` + +## Optional packages + +`pugs` can benefit from additional packages to gain more +functionalities or development tools. + +### Optional numerical tools + +#### MPI support + +`pugs` integrates MPI support and should compile with any MPI-3 +implementation. However in order to dispatch meshes on MPI processes +`pugs` requires `ParMETIS`. Without, MPI support will be automatically +deactivated. + +The easiest way to enable MPI support on Debian-like systems is to run +```shell +apt install libparmetis-dev +``` + +#### `PETSc` + +`pugs` can use `PETSc` to solve linear systems. In `pugs` the `PETSc` +support requires MPI support. + +To install `PETSc` on Debian-like systems +```shell +apt install petsc-dev +``` + +#### `SLEPc` + +`SLEPc` is an eigenvalue problem solver based on `PETSc`. It requires +`PETSc`. + +To install `SLEPc` on Debian-like systems +```shell +apt install slepc-dev +``` + +## Documentation + +### User documentation + +To build documentation one requires `emacs` and `gnuplot`, +additionally since examples results are generated, the documentation +can only be produced after the compilation of `pugs` itself. + +To install `emacs` on Debian-like systems +```shell +apt install emacs +``` +To install `gnuplot` one can either use +```shell +apt install gnuplot-nox +``` +or +```shell +apt install gnuplot-x11 +``` +> **Warning**:<br> +> When building the documentation for the first time, a local `emacs` +> configuration is generated. *This requires an internet connection.* + +These packages are enough to build the html documentation. To build +the pdf documentation one requires a few more packages: `pdflatex` +(actually a fresh texlive installation is probably necessary) and `pygmentize` + +On Debian-like systems these two packages are installed after +```shell +apt install texlive-full +``` + +Running the command +```shell +make doc +``` +produces both the `html` and `pdf` documentation. Additional targets +are +- `userdoc`, `userdoc-pdf` and `userdoc-html`. + +> **Warning**:<br> +> The documentation building **should not** be run in +> parallel. Generation uses similar temporary files. A generation race +> can produce corrupted documentations. + +### `doxygen` documentation + +## Development tools + +### `clang-format` + +If `clang-format` is found, a new compilation target is defined which +allows to run + +```shell +make clang-format +``` + +This allows to run `clang-format` on the entire code. **This should +never be run** on non main development branches since `clang-format` +versions may experience unpleasant compatibility issues. + +### Static analysis + +#### `scan-build` + +To install `scan-build` +```shell +apt install clang-tools +``` +It is fairly simple to use. First launch +```shell +scan-build cmake path-to-pugs-source -DCMAKE_BUILD_TYPE=Debug +``` +Observe that the code is built in debug mode to reduce false +positives. + +Then compile `pugs` +```shell +scan-build make -j nb-jobs pugs +``` +One can use any other generator such as `Ninja` for instance. Here we +only build `pugs`'s binary, which is generally enough. + +At the end of the compilation, an hint such as +``` +scan-build: Run 'scan-view /tmp/scan-build-XXXX-XX-XX-XXXXXX-XXXXX-X' to examine bug reports. +``` +is produced. Running this command opens the report in the default +browser. + +`scan-build` is a precious tool but may unfortunately produce false +positives. + +#### `clang-tidy` + +We do not give details here about `clang-tidy`. It is a much more +complex tool and should be used by more experienced developers since +it requires fine tuning and produces a lot of false positive. + +#### `clazy` + +`clazy` is another great static-analysis tool. It checks constructions +and gives some performances hints. It can be install by +```shell +apt install clazy +``` +When `clazy` is installed a new target is defined and one just has to +run +```shell +make clazy-standalone +``` + +> **Warning**:<br> +> Since some generated sources files are required, one must first run +> a classic compilation in the same build directory. + +This is a special homemade compilation procedure: specifying jobs has +no effect. Each file is checked serially. + +## `CMake` building options + +In this section we give specific options that can be used to modify +the way `pugs` is built. + +### Optimization options + +| Description | Variable | Values | +|:------------|:------------------------|:---------------------------------------:| +| Build type | `CMAKE_BUILD_TYPE` | `Release`(default), `Debug`, `Coverage` | +| OpenMP | `Kokkos_ENABLE_OPENMP` | `ON`(default), `OFF` | +| Pthread | `Kokkos_ENABLE_PTHREAD` | `ON`, `OFF`(default) | +| Serial | `Kokkos_ENABLE_SERIAL` | `ON`, `OFF`(default) | + +- `Coverage` is a special compilation mode. It forces the run of unit + tests and produces coverage reports. See below for coverage + instructions. +- OpenMP, PThread and Serial builds are mutually exclusive. OpenMP + support is automatically enabled as soon as the C++ compiler + supports it. + +### Additional packages support + +| Description | Variable | Values | +|:----------------|:--------------------|:----------------------------:| +| MPI support | `PUGS_ENABLE_MPI` | `AUTO`(default), `ON`, `OFF` | +| `PETSc` support | `PUGS_ENABLE_PETSC` | `AUTO`(default), `ON`, `OFF` | +| `SLEPc` support | `PUGS_ENABLE_SLEPC` | `AUTO`(default), `ON`, `OFF` | + +### Code coverage build + +To enable coverage more, one requires the following tools: +- `lcov` +- `gcov` +- and `fastcov` when using `g++` as a compiler. + +To install these tools +```shell +apt install lcov gcov python3-pip +``` +then to install `fastcov`, as the user do +```shell +pip3 install fastcov +``` + +Then to get coverage reports one can do +```shell +CXX=g++ CC=gcc cmake path-to-pugs-source -DCMAKE_BUILD_TYPE=Coverage +``` +and +```shell +make -j nb-jobs +``` +This produces a text report summary and a detailed html report is +produced in the `coverage` directory. + +One can also use `clang` but the production of the report is much +slower (does not use `fastcov`). diff --git a/cmake/PugsDoc.cmake b/cmake/PugsDoc.cmake index 7be934abae82d06b1e5dcf7265c7710521e02c8e..1f8701ccc20f6416b529908f3893d971e86c7452 100644 --- a/cmake/PugsDoc.cmake +++ b/cmake/PugsDoc.cmake @@ -6,10 +6,16 @@ find_program(EMACS emacs) # check for LaTeX find_package(LATEX COMPONENTS PDFLATEX) +# check for pygmentize +find_program(PYGMENTIZE pygmentize) + +# check for gnuplot +find_package(Gnuplot) + add_custom_target(userdoc) add_custom_target(doc DEPENDS userdoc) -if (EMACS) +if (EMACS AND GNUPLOT_FOUND) add_custom_command( OUTPUT "${PUGS_BINARY_DIR}/doc" @@ -64,7 +70,7 @@ if (EMACS) add_dependencies(userdoc userdoc-html) - if (LATEX_FOUND) + if (LATEX_PDFLATEX_FOUND AND PYGMENTIZE) add_custom_command( OUTPUT "${PUGS_BINARY_DIR}/doc/userdoc.pdf" @@ -92,7 +98,37 @@ if (EMACS) add_dependencies(userdoc userdoc-pdf) + else() + if (NOT LATEX_PDFLATEX_FOUND) + add_custom_target(userdoc-missing-latex + COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --no-newline "Cannot build pdf documentation: " + COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --red --bold "pdflatex missing") + add_dependencies(userdoc userdoc-missing-latex) + endif() + + if (NOT PIGMENTIZE_FOUND) + add_custom_target(userdoc-missing-pygmentize + COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --no-newline "Cannot build pdf documentation: " + COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --red --bold "pygmentize missing") + add_dependencies(userdoc userdoc-missing-pygmentize) + endif() + endif() - add_dependencies(doc userdoc) +else() + if (NOT EMACS) + add_custom_target(userdoc-missing-emacs + COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --no-newline "Cannot build documentation: " + COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --red --bold "emacs missing") + add_dependencies(userdoc userdoc-missing-emacs) + endif() + + if (NOT GNUPLOT_FOUND) + add_custom_target(userdoc-missing-gnuplot + COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --no-newline "Cannot build documentation: " + COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --red --bold "gnuplot missing") + add_dependencies(userdoc userdoc-missing-gnuplot) + endif() endif() + +add_dependencies(doc userdoc) diff --git a/doc/userdoc.org b/doc/userdoc.org index 6538215304ff3da89bd385e8b7918569490cc85e..ba7cd798a6a7991d6451c405a5b9c81dfa2c0362 100644 --- a/doc/userdoc.org +++ b/doc/userdoc.org @@ -1223,8 +1223,7 @@ are sorted by type of left hand side variable. Observe that for these small matrix types ($\mathbb{R}^{d\times d}$) the construction ~A *= B;~ where ~B~ is a matrix of the same type as ~A~ is not allowed. The main reason for that is that for $d>1$ this operation has -no interest since it requires a temporary. One will see bellow that it -is possible to write ~A = A*B;~ if needed. +no interest since it requires a temporary. One will see below that it #+END_note - ~string~: the ~*=~ operator is not defined for left hand side string variables. @@ -2588,6 +2587,61 @@ $\mathbb{R}^1$, $\mathbb{R}^2$ and $\mathbb{R}^3$. The output is #+RESULTS: dot-examples +A set of ~det~ functions is defined to get the determinant of matrices +of $\mathbb{R}^{1\times1}$, $\mathbb{R}^{2\times2}$ and +$\mathbb{R}^{3\times3}$. +#+NAME: det-examples +#+BEGIN_SRC pugs :exports both :results output + import math; + cout << "det([[1.2]]) = " << det([[1.2]]) << "\n"; + cout << "det([[1,2],[3,4]]) = " << det([[1,2],[3,4]]) << "\n"; + cout << "det([[1,2,3],[4,5,6],[7,8,9]]) = " + << det([[1,2,3],[4,5,6],[7,8,9]]) << "\n"; +#+END_SRC +The output is +#+RESULTS: det-examples + +The ~trace~ functions compute the trace of matrices of +$\mathbb{R}^{1\times1}$, $\mathbb{R}^{2\times2}$ and $\mathbb{R}^{3\times3}$. +#+NAME: trace-examples +#+BEGIN_SRC pugs :exports both :results output + import math; + cout << "trace([[1.2]]) = " << trace([[1.2]]) << "\n"; + cout << "trace([[1,2],[3,4]]) = " << trace([[1,2],[3,4]]) << "\n"; + cout << "trace([[1,2,3],[4,5,6],[7,8,9]]) = " + << trace([[1,2,3],[4,5,6],[7,8,9]]) << "\n"; +#+END_SRC +The output is +#+RESULTS: trace-examples + +Also, one can compute inverses of $\mathbb{R}^{1\times1}$, +$\mathbb{R}^{2\times2}$ and $\mathbb{R}^{3\times3}$ matrices using the +~inverse~ function set. +#+NAME: inverse-examples +#+BEGIN_SRC pugs :exports both :results output + import math; + cout << "inverse([[1.2]]) = " << inverse([[1.2]]) << "\n"; + cout << "inverse([[1,2],[3,4]]) = " << inverse([[1,2],[3,4]]) << "\n"; + cout << "inverse([[3,2,1],[5,6,4],[7,8,9]]) = " + << inverse([[3,2,1],[5,6,4],[7,8,9]]) << "\n"; +#+END_SRC +The output is +#+RESULTS: inverse-examples + +Transpose of matrices of $\mathbb{R}^{1\times1}$, +$\mathbb{R}^{2\times2}$ and $\mathbb{R}^{3\times3}$ are obtained using the +~transpose~ functions. +#+NAME: transpose-examples +#+BEGIN_SRC pugs :exports both :results output + import math; + cout << "transpose([[1.2]]) = " << transpose([[1.2]]) << "\n"; + cout << "transpose([[1,2],[3,4]]) = " << transpose([[1,2],[3,4]]) << "\n"; + cout << "transpose([[3,2,1],[5,6,4],[7,8,9]]) = " + << transpose([[3,2,1],[5,6,4],[7,8,9]]) << "\n"; +#+END_SRC +The output is +#+RESULTS: transpose-examples + #+BEGIN_note Observe that the use of a proper rounding or truncation function is the right way to convert a real value to an integer one. Available @@ -3196,11 +3250,12 @@ description. ****** ~Vh -> Vh~ -These functions are defined for $\mathbb{P}_0(\mathbb{R})$ data and the -return value is also a $\mathbb{P}_0(\mathbb{R})$ function. The value -is simply the application of the function to the cell values. +The majority of these functions are defined for +$\mathbb{P}_0(\mathbb{R})$ data and the return value is also a +$\mathbb{P}_0(\mathbb{R})$ function. The value is simply the +application of the function to the cell values. -Here is the list of the functions +Here is the list of these functions - ~abs: Vh -> Vh~ - ~acos: Vh -> Vh~ - ~acosh: Vh -> Vh~ @@ -3218,6 +3273,21 @@ Here is the list of the functions - ~tan: Vh -> Vh~ - ~tanh: Vh -> Vh~ +A few functions are defined for $\mathbb{P}_0(\mathbb{R^{}}^{1\times1})$, +$\mathbb{P}_0(\mathbb{R^{}}^{2\times2})$ and +$\mathbb{P}_0(\mathbb{R^{}}^{3\times3})$ data and the return value is a +$\mathbb{P}_0(\mathbb{R})$ function. The value is simply the +application of the function to the cell values. +- ~det: Vh -> Vh~ +- ~trace: Vh -> Vh~ + +Also, functions are defined for $\mathbb{P}_0(\mathbb{R}^{d\times d})$ +data and the return value is a $\mathbb{P}_0(\mathbb{R}^{d\times d})$ +function, with $d\in\{1,2,3\}$. The value is simply the application of +the function to the cell values. +- ~inverse: Vh -> Vh~ +- ~transpose: Vh -> Vh~ + ****** ~Vh*Vh -> Vh~ These functions are defined for $\mathbb{P}_0(\mathbb{R})$ data and the @@ -3406,6 +3476,19 @@ and the return value is an $\mathbb{R}^{3\times3}$ matrix. return value is $$\sum_{j\in\mathcal{J}} A_j.$$ +***** Utilities + +****** ~sum_of_Vh: Vh -> Vh~ + +This function it computes the sum of all the components of +$\vec{\mathbb{P}}_0(\mathbb{R})$ function and stores the result into a +$\mathbb{P}_0(\mathbb{R})$. + +****** ~vectorize: (Vh) -> Vh~ + +This function creates a $\vec{\mathbb{P}}_0(\mathbb{R})$ function using +a tuple of $\mathbb{P}_0(\mathbb{R})$. + ***** Interpolation and integration functions These functions are ways to define discrete functions from analytic diff --git a/packages/kokkos/.github/workflows/continuous-integration-workflow.yml b/packages/kokkos/.github/workflows/continuous-integration-workflow.yml index b2b4bfc3109d9aa10966b2866c472fa4d8457c5f..4ae42bc93ff649401818962ee7e4f16c2c468cb2 100644 --- a/packages/kokkos/.github/workflows/continuous-integration-workflow.yml +++ b/packages/kokkos/.github/workflows/continuous-integration-workflow.yml @@ -10,7 +10,7 @@ jobs: continue-on-error: true strategy: matrix: - distro: ['fedora:latest', 'fedora:rawhide', 'ubuntu:latest'] + distro: ['fedora:latest', 'ubuntu:latest'] cxx: ['g++', 'clang++'] cmake_build_type: ['Release', 'Debug'] backend: ['OPENMP'] diff --git a/packages/kokkos/.gitrepo b/packages/kokkos/.gitrepo index 9b53d527695cc0db4672b75762f449344c305baa..4c3eed6dba9d2682fd85d2185169ac1f5c8e17a6 100644 --- a/packages/kokkos/.gitrepo +++ b/packages/kokkos/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = git@github.com:kokkos/kokkos.git branch = master - commit = 61d7db55fceac3318c987a291f77b844fd94c165 - parent = 91d53e3cfb9a55832aae102ca677044a47f2515d + commit = 5ad609661e570ba6aa7716a26a91cb67d559f8a2 + parent = db24c19be339723f3a10fffce3075fd72dccdfeb method = merge - cmdver = 0.4.3 + cmdver = 0.4.5 diff --git a/packages/kokkos/.jenkins b/packages/kokkos/.jenkins index 09052840e6a7ea4115c1be9abb3f2aa2e644eabd..3025cb558eab0c10d6be328b199515807fbba03b 100644 --- a/packages/kokkos/.jenkins +++ b/packages/kokkos/.jenkins @@ -347,7 +347,7 @@ pipeline { dockerfile { filename 'Dockerfile.nvcc' dir 'scripts/docker' - additionalBuildArgs '--build-arg BASE=nvidia/cuda:11.0-devel --build-arg ADDITIONAL_PACKAGES="g++-8 gfortran clang" --build-arg CMAKE_VERSION=3.17.3' + additionalBuildArgs '--build-arg BASE=nvidia/cuda:11.0.3-devel-ubuntu18.04 --build-arg ADDITIONAL_PACKAGES="g++-8 gfortran clang" --build-arg CMAKE_VERSION=3.17.3' label 'nvidia-docker' args '-v /tmp/ccache.kokkos:/tmp/ccache --env NVIDIA_VISIBLE_DEVICES=$NVIDIA_VISIBLE_DEVICES' } diff --git a/packages/kokkos/CHANGELOG.md b/packages/kokkos/CHANGELOG.md index e81f2944519e1b39b31e1c9d7332b3aa6cb8d45e..bdbc75604bab5fbbfd436767531ab30371cc788b 100644 --- a/packages/kokkos/CHANGELOG.md +++ b/packages/kokkos/CHANGELOG.md @@ -1,5 +1,27 @@ # Change Log +## [3.7.01](https://github.com/kokkos/kokkos/tree/3.7.01) (2022-12-01) +[Full Changelog](https://github.com/kokkos/kokkos/compare/3.7.00...3.7.01) + +### Bug Fixes: +- Add fences to all sorting routines not taking an execution space instance argument [\#5547](https://github.com/kokkos/kokkos/pull/5547) +- Fix repeated `team_reduce` without barrier [\#5552](https://github.com/kokkos/kokkos/pull/5552) +- Fix memory spaces in `create_mirror_view` overloads using `view_alloc` [\#5521](https://github.com/kokkos/kokkos/pull/5521) +- Allow `as_view_of_rank_n()` to be overloaded for "special" scalar types [\#5553](https://github.com/kokkos/kokkos/pull/5553) +- Fix warning calling a `__host__` function from a `__host__ __device__` from `View:: as_view_of_rank_n` [\#5591](https://github.com/kokkos/kokkos/pull/5591) +- OpenMPTarget: adding implementation to set device id. [\#5557](https://github.com/kokkos/kokkos/pull/5557) +- Use `Kokkos::atomic_load` to Correct Race Condition Giving Rise to Seg Faulting Error in OpenMP tests [\#5559](https://github.com/kokkos/kokkos/pull/5559) +- cmake: define `KOKKOS_ARCH_A64FX` [\#5561](https://github.com/kokkos/kokkos/pull/5561) +- Only link against libatomic in gnu-make OpenMPTarget build [\#5565](https://github.com/kokkos/kokkos/pull/5565) +- Fix static extents assignment for LayoutLeft/LayoutRight assignment [\#5566](https://github.com/kokkos/kokkos/pull/5566) +- Do not add -cuda to the link line with NVHPC compiler when the CUDA backend is not actually enabled [\#5569](https://github.com/kokkos/kokkos/pull/5569) +- Export the flags in `KOKKOS_AMDGPU_OPTIONS` when using Trilinos [\#5571](https://github.com/kokkos/kokkos/pull/5571) +- Add support for detecting MPI local rank with MPICH and PMI [\#5570](https://github.com/kokkos/kokkos/pull/5570) [\#5582](https://github.com/kokkos/kokkos/pull/5582) +- Remove listing of undefined TPL dependencies [\#5573](https://github.com/kokkos/kokkos/pull/5573) +- ClockTic changed to 64 bit to fix overflow on Power [\#5592](https://github.com/kokkos/kokkos/pull/5592) +- Fix incorrect offset in CUDA and HIP parallel scan for < 4 byte types [\#5607](https://github.com/kokkos/kokkos/pull/5607) +- Fix initialization of Cuda lock arrays [\#5622](https://github.com/kokkos/kokkos/pull/5622) + ## [3.7.00](https://github.com/kokkos/kokkos/tree/3.7.00) (2022-08-22) [Full Changelog](https://github.com/kokkos/kokkos/compare/3.6.01...3.7.00) @@ -102,7 +124,6 @@ - Deprecate command line arguments (other than `--help`) that are not prefixed with `kokkos-*` [\#5120](https://github.com/kokkos/kokkos/pull/5120) - Deprecate `--[kokkos-]numa` cmdline arg and `KOKKOS_NUMA` env var [\#5117](https://github.com/kokkos/kokkos/pull/5117) - Deprecate `--[kokkos-]threads` command line argument in favor of `--[kokkos-]num-threads` [\#5111](https://github.com/kokkos/kokkos/pull/5111) -- Deprecate `Kokkos::common_view_alloc_prop` [\#5059](https://github.com/kokkos/kokkos/pull/5059) - Deprecate `Kokkos::is_reducer_type` [\#4957](https://github.com/kokkos/kokkos/pull/4957) - Deprecate `OffsetView` constructors taking `index_list_type` [\#4810](https://github.com/kokkos/kokkos/pull/4810) - Deprecate overloads of `Kokkos::sort` taking a parameter `bool always_use_kokkos_sort` [\#5382](https://github.com/kokkos/kokkos/issues/5382) diff --git a/packages/kokkos/CMakeLists.txt b/packages/kokkos/CMakeLists.txt index a05bfcdb94d53e0a7d453d62909e9a5686f6cc41..7b78f29d7340499aff394302911e59c5ef120d52 100644 --- a/packages/kokkos/CMakeLists.txt +++ b/packages/kokkos/CMakeLists.txt @@ -129,7 +129,7 @@ ENDIF() set(Kokkos_VERSION_MAJOR 3) set(Kokkos_VERSION_MINOR 7) -set(Kokkos_VERSION_PATCH 00) +set(Kokkos_VERSION_PATCH 01) set(Kokkos_VERSION "${Kokkos_VERSION_MAJOR}.${Kokkos_VERSION_MINOR}.${Kokkos_VERSION_PATCH}") math(EXPR KOKKOS_VERSION "${Kokkos_VERSION_MAJOR} * 10000 + ${Kokkos_VERSION_MINOR} * 100 + ${Kokkos_VERSION_PATCH}") @@ -152,6 +152,7 @@ ENDIF() # but scoping issues can make it difficult GLOBAL_SET(KOKKOS_COMPILE_OPTIONS) GLOBAL_SET(KOKKOS_LINK_OPTIONS) +GLOBAL_SET(KOKKOS_AMDGPU_OPTIONS) GLOBAL_SET(KOKKOS_CUDA_OPTIONS) GLOBAL_SET(KOKKOS_CUDAFE_OPTIONS) GLOBAL_SET(KOKKOS_XCOMPILER_OPTIONS) @@ -228,6 +229,9 @@ IF (KOKKOS_HAS_TRILINOS) # we have to match the annoying behavior, also we have to preserve quotes # which needs another workaround. SET(KOKKOS_COMPILE_OPTIONS_TMP) + IF (KOKKOS_ENABLE_HIP) + LIST(APPEND KOKKOS_COMPILE_OPTIONS ${KOKKOS_AMDGPU_OPTIONS}) + ENDIF() FOREACH(OPTION ${KOKKOS_COMPILE_OPTIONS}) STRING(FIND "${OPTION}" " " OPTION_HAS_WHITESPACE) IF(OPTION_HAS_WHITESPACE EQUAL -1) diff --git a/packages/kokkos/Makefile.kokkos b/packages/kokkos/Makefile.kokkos index d493abbf1421973a973e93775d90ef83e502e2cd..2e32c9d53893bf552381eb618db37acaf8156822 100644 --- a/packages/kokkos/Makefile.kokkos +++ b/packages/kokkos/Makefile.kokkos @@ -2,7 +2,7 @@ KOKKOS_VERSION_MAJOR = 3 KOKKOS_VERSION_MINOR = 7 -KOKKOS_VERSION_PATCH = 00 +KOKKOS_VERSION_PATCH = 01 KOKKOS_VERSION = $(shell echo $(KOKKOS_VERSION_MAJOR)*10000+$(KOKKOS_VERSION_MINOR)*100+$(KOKKOS_VERSION_PATCH) | bc) # Options: Cuda,HIP,SYCL,OpenMPTarget,OpenMP,Threads,Serial @@ -495,10 +495,6 @@ KOKKOS_LINK_FLAGS = KOKKOS_SRC = KOKKOS_HEADERS = -#ifeq ($(KOKKOS_INTERNAL_COMPILER_GCC), 1) - KOKKOS_LIBS += -latomic -#endif - # Generating the KokkosCore_config.h file. KOKKOS_INTERNAL_CONFIG_TMP=KokkosCore_config.tmp @@ -540,6 +536,7 @@ ifeq ($(KOKKOS_INTERNAL_USE_SYCL), 1) endif ifeq ($(KOKKOS_INTERNAL_USE_OPENMPTARGET), 1) + KOKKOS_LIBS += -latomic tmp := $(call kokkos_append_header,'$H''define KOKKOS_ENABLE_OPENMPTARGET') ifeq ($(KOKKOS_INTERNAL_COMPILER_GCC), 1) tmp := $(call kokkos_append_header,"$H""define KOKKOS_WORKAROUND_OPENMPTARGET_GCC") diff --git a/packages/kokkos/algorithms/cmake/Dependencies.cmake b/packages/kokkos/algorithms/cmake/Dependencies.cmake index 1b413106817cc6adf18dc94189203a27e641c6d5..c36b62523fadb628e970b6eccf57a9caaa317f1e 100644 --- a/packages/kokkos/algorithms/cmake/Dependencies.cmake +++ b/packages/kokkos/algorithms/cmake/Dependencies.cmake @@ -1,5 +1,5 @@ TRIBITS_PACKAGE_DEFINE_DEPENDENCIES( LIB_REQUIRED_PACKAGES KokkosCore KokkosContainers - LIB_OPTIONAL_TPLS Pthread CUDA HWLOC HPX + LIB_OPTIONAL_TPLS Pthread CUDA HWLOC TEST_OPTIONAL_TPLS CUSPARSE ) diff --git a/packages/kokkos/algorithms/src/Kokkos_Sort.hpp b/packages/kokkos/algorithms/src/Kokkos_Sort.hpp index ad0c2d47b6d20d2022b5c60e81e7268b53d47f13..c7be70e09a48eff3fb2bf3a7cb89be1cf1fe6664 100644 --- a/packages/kokkos/algorithms/src/Kokkos_Sort.hpp +++ b/packages/kokkos/algorithms/src/Kokkos_Sort.hpp @@ -265,8 +265,8 @@ class BinSort { //---------------------------------------- // Create the permutation vector, the bin_offset array and the bin_count // array. Can be called again if keys changed - template <class ExecutionSpace = exec_space> - void create_permute_vector(const ExecutionSpace& exec = exec_space{}) { + template <class ExecutionSpace> + void create_permute_vector(const ExecutionSpace& exec) { static_assert( Kokkos::SpaceAccessibility<ExecutionSpace, typename Space::memory_space>::accessible, @@ -297,6 +297,15 @@ class BinSort { *this); } + // Create the permutation vector, the bin_offset array and the bin_count + // array. Can be called again if keys changed + void create_permute_vector() { + Kokkos::fence("Kokkos::Binsort::create_permute_vector: before"); + exec_space e{}; + create_permute_vector(e); + e.fence("Kokkos::Binsort::create_permute_vector: after"); + } + // Sort a subset of a view with respect to the first dimension using the // permutation array template <class ExecutionSpace, class ValuesViewType> @@ -372,9 +381,10 @@ class BinSort { template <class ValuesViewType> void sort(ValuesViewType const& values, int values_range_begin, int values_range_end) const { + Kokkos::fence("Kokkos::Binsort::sort: before"); exec_space exec; sort(exec, values, values_range_begin, values_range_end); - exec.fence("Kokkos::Sort: fence after sorting"); + exec.fence("Kokkos::BinSort:sort: after"); } template <class ExecutionSpace, class ValuesViewType> @@ -641,9 +651,10 @@ std::enable_if_t<Kokkos::is_execution_space<ExecutionSpace>::value> sort( template <class ViewType> void sort(ViewType const& view) { + Kokkos::fence("Kokkos::sort: before"); typename ViewType::execution_space exec; sort(exec, view); - exec.fence("Kokkos::Sort: fence after sorting"); + exec.fence("Kokkos::sort: fence after sorting"); } #ifdef KOKKOS_ENABLE_DEPRECATED_CODE_3 @@ -682,6 +693,7 @@ std::enable_if_t<Kokkos::is_execution_space<ExecutionSpace>::value> sort( template <class ViewType> void sort(ViewType view, size_t const begin, size_t const end) { + Kokkos::fence("Kokkos::sort: before"); typename ViewType::execution_space exec; sort(exec, view, begin, end); exec.fence("Kokkos::Sort: fence after sorting"); diff --git a/packages/kokkos/cmake/KokkosCore_config.h.in b/packages/kokkos/cmake/KokkosCore_config.h.in index 34807ac2b26228a4f0c10aa3ee5c4f7951ac235f..88ddc483786112ca0e70f418921d89ae102b9dde 100644 --- a/packages/kokkos/cmake/KokkosCore_config.h.in +++ b/packages/kokkos/cmake/KokkosCore_config.h.in @@ -66,6 +66,7 @@ #cmakedefine KOKKOS_ARCH_ARMV8_THUNDERX #cmakedefine KOKKOS_ARCH_ARMV81 #cmakedefine KOKKOS_ARCH_ARMV8_THUNDERX2 +#cmakedefine KOKKOS_ARCH_A64FX #cmakedefine KOKKOS_ARCH_AMD_AVX2 #cmakedefine KOKKOS_ARCH_AVX #cmakedefine KOKKOS_ARCH_AVX2 diff --git a/packages/kokkos/cmake/kokkos_arch.cmake b/packages/kokkos/cmake/kokkos_arch.cmake index d4c2cda651f3510bd66e9b8faff344ebf0cf666a..ef16aad047a96cfb31f3ae6c5ecaa93ff8175539 100644 --- a/packages/kokkos/cmake/kokkos_arch.cmake +++ b/packages/kokkos/cmake/kokkos_arch.cmake @@ -187,7 +187,9 @@ IF (KOKKOS_CXX_COMPILER_ID STREQUAL Clang) ELSEIF (KOKKOS_CXX_COMPILER_ID STREQUAL NVHPC) SET(CUDA_ARCH_FLAG "-gpu") GLOBAL_APPEND(KOKKOS_CUDA_OPTIONS -cuda) - GLOBAL_APPEND(KOKKOS_LINK_OPTIONS -cuda) + IF (KOKKOS_ENABLE_CUDA) # FIXME ideally unreachable when CUDA not enabled + GLOBAL_APPEND(KOKKOS_LINK_OPTIONS -cuda) + ENDIF() ELSEIF(KOKKOS_CXX_COMPILER_ID STREQUAL NVIDIA) SET(CUDA_ARCH_FLAG "-arch") ENDIF() diff --git a/packages/kokkos/containers/cmake/Dependencies.cmake b/packages/kokkos/containers/cmake/Dependencies.cmake index 5e29157369c9ab8cab935a1bfc4c6dad2fdd0296..1d71d8af341181f689a6a8bf63036b67584cb138 100644 --- a/packages/kokkos/containers/cmake/Dependencies.cmake +++ b/packages/kokkos/containers/cmake/Dependencies.cmake @@ -1,5 +1,5 @@ TRIBITS_PACKAGE_DEFINE_DEPENDENCIES( LIB_REQUIRED_PACKAGES KokkosCore - LIB_OPTIONAL_TPLS Pthread CUDA HWLOC HPX + LIB_OPTIONAL_TPLS Pthread CUDA HWLOC TEST_OPTIONAL_TPLS CUSPARSE ) diff --git a/packages/kokkos/containers/src/Kokkos_DynRankView.hpp b/packages/kokkos/containers/src/Kokkos_DynRankView.hpp index 442f0d8617524dc0c1459bf10110891e97b3a6b2..059ce8a610d26c9072b1cd15a282364855130d9a 100644 --- a/packages/kokkos/containers/src/Kokkos_DynRankView.hpp +++ b/packages/kokkos/containers/src/Kokkos_DynRankView.hpp @@ -1701,7 +1701,11 @@ namespace Impl { underlying memory, to facilitate implementation of deep_copy() and other routines that are defined on View */ template <unsigned N, typename T, typename... Args> -KOKKOS_FUNCTION auto as_view_of_rank_n(DynRankView<T, Args...> v) { +KOKKOS_FUNCTION auto as_view_of_rank_n( + DynRankView<T, Args...> v, + typename std::enable_if<std::is_same< + typename ViewTraits<T, Args...>::specialize, void>::value>::type* = + nullptr) { if (v.rank() != N) { KOKKOS_IF_ON_HOST( const std::string message = @@ -2114,9 +2118,10 @@ inline auto create_mirror( namespace Impl { template <class T, class... P, class... ViewCtorArgs> inline std::enable_if_t< - std::is_same< - typename DynRankView<T, P...>::memory_space, - typename DynRankView<T, P...>::HostMirror::memory_space>::value && + !Impl::ViewCtorProp<ViewCtorArgs...>::has_memory_space && + std::is_same< + typename DynRankView<T, P...>::memory_space, + typename DynRankView<T, P...>::HostMirror::memory_space>::value && std::is_same< typename DynRankView<T, P...>::data_type, typename DynRankView<T, P...>::HostMirror::data_type>::value, @@ -2128,12 +2133,13 @@ create_mirror_view(const DynRankView<T, P...>& src, template <class T, class... P, class... ViewCtorArgs> inline std::enable_if_t< - !(std::is_same< - typename DynRankView<T, P...>::memory_space, - typename DynRankView<T, P...>::HostMirror::memory_space>::value && - std::is_same< - typename DynRankView<T, P...>::data_type, - typename DynRankView<T, P...>::HostMirror::data_type>::value), + !Impl::ViewCtorProp<ViewCtorArgs...>::has_memory_space && + !(std::is_same< + typename DynRankView<T, P...>::memory_space, + typename DynRankView<T, P...>::HostMirror::memory_space>::value && + std::is_same< + typename DynRankView<T, P...>::data_type, + typename DynRankView<T, P...>::HostMirror::data_type>::value), typename DynRankView<T, P...>::HostMirror> create_mirror_view( const DynRankView<T, P...>& src, @@ -2141,29 +2147,39 @@ create_mirror_view( return Kokkos::Impl::create_mirror(src, arg_prop); } -template <class Space, class T, class... P, class... ViewCtorArgs> +template <class T, class... P, class... ViewCtorArgs, + class = std::enable_if_t< + Impl::ViewCtorProp<ViewCtorArgs...>::has_memory_space>> inline std::enable_if_t< - Kokkos::is_space<Space>::value && - Impl::MirrorDRViewType<Space, T, P...>::is_same_memspace, - typename Impl::MirrorDRViewType<Space, T, P...>::view_type> -create_mirror_view(const Space&, const Kokkos::DynRankView<T, P...>& src, + Kokkos::is_space< + typename Impl::ViewCtorProp<ViewCtorArgs...>::memory_space>::value && + Impl::MirrorDRViewType< + typename Impl::ViewCtorProp<ViewCtorArgs...>::memory_space, T, + P...>::is_same_memspace, + typename Impl::MirrorDRViewType< + typename Impl::ViewCtorProp<ViewCtorArgs...>::memory_space, T, + P...>::view_type> +create_mirror_view(const Kokkos::DynRankView<T, P...>& src, const typename Impl::ViewCtorProp<ViewCtorArgs...>&) { return src; } -template <class Space, class T, class... P, class... ViewCtorArgs> +template <class T, class... P, class... ViewCtorArgs, + class = std::enable_if_t< + Impl::ViewCtorProp<ViewCtorArgs...>::has_memory_space>> inline std::enable_if_t< - Kokkos::is_space<Space>::value && - !Impl::MirrorDRViewType<Space, T, P...>::is_same_memspace, - typename Impl::MirrorDRViewType<Space, T, P...>::view_type> + Kokkos::is_space< + typename Impl::ViewCtorProp<ViewCtorArgs...>::memory_space>::value && + !Impl::MirrorDRViewType< + typename Impl::ViewCtorProp<ViewCtorArgs...>::memory_space, T, + P...>::is_same_memspace, + typename Impl::MirrorDRViewType< + typename Impl::ViewCtorProp<ViewCtorArgs...>::memory_space, T, + P...>::view_type> create_mirror_view( - const Space&, const Kokkos::DynRankView<T, P...>& src, + const Kokkos::DynRankView<T, P...>& src, const typename Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop) { - using MemorySpace = typename Space::memory_space; - using alloc_prop = Impl::ViewCtorProp<ViewCtorArgs..., MemorySpace>; - alloc_prop prop_copy(arg_prop); - - return Kokkos::Impl::create_mirror(src, prop_copy); + return Kokkos::Impl::create_mirror(src, arg_prop); } } // namespace Impl @@ -2224,9 +2240,10 @@ create_mirror_view( template <class Space, class T, class... P> inline auto create_mirror_view(Kokkos::Impl::WithoutInitializing_t wi, - const Space& space, + const Space&, const Kokkos::DynRankView<T, P...>& src) { - return Impl::create_mirror_view(space, src, Kokkos::view_alloc(wi)); + return Impl::create_mirror_view( + src, Kokkos::view_alloc(typename Space::memory_space{}, wi)); } template <class T, class... P, class... ViewCtorArgs> diff --git a/packages/kokkos/containers/src/Kokkos_DynamicView.hpp b/packages/kokkos/containers/src/Kokkos_DynamicView.hpp index 015a75cb0b02c602db2a3bded219497c3414595c..a2b68064de13bd2b8988b6a2025bc3c9ef2c2685 100644 --- a/packages/kokkos/containers/src/Kokkos_DynamicView.hpp +++ b/packages/kokkos/containers/src/Kokkos_DynamicView.hpp @@ -710,7 +710,7 @@ template <class Space, class T, class... P> inline auto create_mirror( const Space&, const Kokkos::Experimental::DynamicView<T, P...>& src) { return Impl::create_mirror( - src, Impl::ViewCtorProp<>{typename Space::memory_space{}}); + src, Kokkos::view_alloc(typename Space::memory_space{})); } template <class Space, class T, class... P> @@ -729,48 +729,68 @@ inline auto create_mirror( } namespace Impl { + template <class T, class... P, class... ViewCtorArgs> inline std::enable_if_t< - (std::is_same< - typename Kokkos::Experimental::DynamicView<T, P...>::memory_space, - typename Kokkos::Experimental::DynamicView< - T, P...>::HostMirror::memory_space>::value && - std::is_same< - typename Kokkos::Experimental::DynamicView<T, P...>::data_type, - typename Kokkos::Experimental::DynamicView< - T, P...>::HostMirror::data_type>::value), + !Impl::ViewCtorProp<ViewCtorArgs...>::has_memory_space && + (std::is_same< + typename Kokkos::Experimental::DynamicView<T, P...>::memory_space, + typename Kokkos::Experimental::DynamicView< + T, P...>::HostMirror::memory_space>::value && + std::is_same< + typename Kokkos::Experimental::DynamicView<T, P...>::data_type, + typename Kokkos::Experimental::DynamicView< + T, P...>::HostMirror::data_type>::value), typename Kokkos::Experimental::DynamicView<T, P...>::HostMirror> -create_mirror_view( - const typename Kokkos::Experimental::DynamicView<T, P...>& src, - const Impl::ViewCtorProp<ViewCtorArgs...>&) { +create_mirror_view(const Kokkos::Experimental::DynamicView<T, P...>& src, + const Impl::ViewCtorProp<ViewCtorArgs...>&) { return src; } template <class T, class... P, class... ViewCtorArgs> inline std::enable_if_t< - !(std::is_same< - typename Kokkos::Experimental::DynamicView<T, P...>::memory_space, - typename Kokkos::Experimental::DynamicView< - T, P...>::HostMirror::memory_space>::value && - std::is_same< - typename Kokkos::Experimental::DynamicView<T, P...>::data_type, - typename Kokkos::Experimental::DynamicView< - T, P...>::HostMirror::data_type>::value), + !Impl::ViewCtorProp<ViewCtorArgs...>::has_memory_space && + !(std::is_same< + typename Kokkos::Experimental::DynamicView<T, P...>::memory_space, + typename Kokkos::Experimental::DynamicView< + T, P...>::HostMirror::memory_space>::value && + std::is_same< + typename Kokkos::Experimental::DynamicView<T, P...>::data_type, + typename Kokkos::Experimental::DynamicView< + T, P...>::HostMirror::data_type>::value), typename Kokkos::Experimental::DynamicView<T, P...>::HostMirror> create_mirror_view(const Kokkos::Experimental::DynamicView<T, P...>& src, const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop) { return Kokkos::create_mirror(arg_prop, src); } -template <class Space, class T, class... P, class... ViewCtorArgs> -inline std::enable_if_t< - Impl::MirrorDynamicViewType<Space, T, P...>::is_same_memspace, - typename Kokkos::Impl::MirrorDynamicViewType<Space, T, P...>::view_type> -create_mirror_view(const Space&, - const Kokkos::Experimental::DynamicView<T, P...>& src, +template <class T, class... P, class... ViewCtorArgs, + class = std::enable_if_t< + Impl::ViewCtorProp<ViewCtorArgs...>::has_memory_space>> +std::enable_if_t<Impl::MirrorDynamicViewType< + typename Impl::ViewCtorProp<ViewCtorArgs...>::memory_space, + T, P...>::is_same_memspace, + typename Impl::MirrorDynamicViewType< + typename Impl::ViewCtorProp<ViewCtorArgs...>::memory_space, + T, P...>::view_type> +create_mirror_view(const Kokkos::Experimental::DynamicView<T, P...>& src, const Impl::ViewCtorProp<ViewCtorArgs...>&) { return src; } + +template <class T, class... P, class... ViewCtorArgs, + class = std::enable_if_t< + Impl::ViewCtorProp<ViewCtorArgs...>::has_memory_space>> +std::enable_if_t<!Impl::MirrorDynamicViewType< + typename Impl::ViewCtorProp<ViewCtorArgs...>::memory_space, + T, P...>::is_same_memspace, + typename Impl::MirrorDynamicViewType< + typename Impl::ViewCtorProp<ViewCtorArgs...>::memory_space, + T, P...>::view_type> +create_mirror_view(const Kokkos::Experimental::DynamicView<T, P...>& src, + const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop) { + return Kokkos::Impl::create_mirror(src, arg_prop); +} } // namespace Impl // Create a mirror view in host space @@ -790,8 +810,9 @@ inline auto create_mirror_view( // Create a mirror in a new space template <class Space, class T, class... P> inline auto create_mirror_view( - const Space& space, const Kokkos::Experimental::DynamicView<T, P...>& src) { - return Impl::create_mirror_view(space, src, Impl::ViewCtorProp<>{}); + const Space&, const Kokkos::Experimental::DynamicView<T, P...>& src) { + return Impl::create_mirror_view(src, + view_alloc(typename Space::memory_space{})); } template <class Space, class T, class... P> diff --git a/packages/kokkos/containers/src/Kokkos_OffsetView.hpp b/packages/kokkos/containers/src/Kokkos_OffsetView.hpp index 0b54d1bdd952f33e433f17b05c56ef415ee286b4..5027763a0297a00c2b9dfb28734da628e763d7dc 100644 --- a/packages/kokkos/containers/src/Kokkos_OffsetView.hpp +++ b/packages/kokkos/containers/src/Kokkos_OffsetView.hpp @@ -1901,19 +1901,22 @@ struct MirrorOffsetType { namespace Impl { template <class T, class... P, class... ViewCtorArgs> -inline typename Kokkos::Experimental::OffsetView<T, P...>::HostMirror +inline std::enable_if_t< + !Impl::ViewCtorProp<ViewCtorArgs...>::has_memory_space, + typename Kokkos::Experimental::OffsetView<T, P...>::HostMirror> create_mirror(const Kokkos::Experimental::OffsetView<T, P...>& src, const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop) { return typename Kokkos::Experimental::OffsetView<T, P...>::HostMirror( Kokkos::create_mirror(arg_prop, src.view()), src.begins()); } -template <class Space, class T, class... P, class... ViewCtorArgs> -inline typename Kokkos::Impl::MirrorOffsetType<Space, T, P...>::view_type -create_mirror(const Space&, - const Kokkos::Experimental::OffsetView<T, P...>& src, - const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop) { +template <class T, class... P, class... ViewCtorArgs, + class = std::enable_if_t< + Impl::ViewCtorProp<ViewCtorArgs...>::has_memory_space>> +inline auto create_mirror(const Kokkos::Experimental::OffsetView<T, P...>& src, + const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop) { using alloc_prop_input = Impl::ViewCtorProp<ViewCtorArgs...>; + using Space = typename Impl::ViewCtorProp<ViewCtorArgs...>::memory_space; static_assert( !alloc_prop_input::has_label, @@ -1923,10 +1926,6 @@ create_mirror(const Space&, !alloc_prop_input::has_pointer, "The view constructor arguments passed to Kokkos::create_mirror must " "not include a pointer!"); - static_assert( - !alloc_prop_input::has_memory_space, - "The view constructor arguments passed to Kokkos::create_mirror must " - "not include a memory space instance!"); static_assert( !alloc_prop_input::allow_padding, "The view constructor arguments passed to Kokkos::create_mirror must " @@ -1962,15 +1961,17 @@ inline auto create_mirror( template <class Space, class T, class... P, typename Enable = std::enable_if_t<Kokkos::is_space<Space>::value>> inline auto create_mirror( - const Space& space, const Kokkos::Experimental::OffsetView<T, P...>& src) { - return Impl::create_mirror(space, src, Impl::ViewCtorProp<>{}); + const Space&, const Kokkos::Experimental::OffsetView<T, P...>& src) { + return Impl::create_mirror( + src, Kokkos::view_alloc(typename Space::memory_space{})); } template <class Space, class T, class... P> typename Kokkos::Impl::MirrorOffsetType<Space, T, P...>::view_type -create_mirror(Kokkos::Impl::WithoutInitializing_t wi, const Space& space, +create_mirror(Kokkos::Impl::WithoutInitializing_t wi, const Space&, const Kokkos::Experimental::OffsetView<T, P...>& src) { - return Impl::create_mirror(space, src, Kokkos::view_alloc(wi)); + return Impl::create_mirror( + src, Kokkos::view_alloc(typename Space::memory_space{}, wi)); } template <class T, class... P, class... ViewCtorArgs> @@ -1983,54 +1984,64 @@ inline auto create_mirror( namespace Impl { template <class T, class... P, class... ViewCtorArgs> inline std::enable_if_t< - (std::is_same< - typename Kokkos::Experimental::OffsetView<T, P...>::memory_space, - typename Kokkos::Experimental::OffsetView< - T, P...>::HostMirror::memory_space>::value && - std::is_same<typename Kokkos::Experimental::OffsetView<T, P...>::data_type, - typename Kokkos::Experimental::OffsetView< - T, P...>::HostMirror::data_type>::value), + !Impl::ViewCtorProp<ViewCtorArgs...>::has_memory_space && + (std::is_same< + typename Kokkos::Experimental::OffsetView<T, P...>::memory_space, + typename Kokkos::Experimental::OffsetView< + T, P...>::HostMirror::memory_space>::value && + std::is_same< + typename Kokkos::Experimental::OffsetView<T, P...>::data_type, + typename Kokkos::Experimental::OffsetView< + T, P...>::HostMirror::data_type>::value), typename Kokkos::Experimental::OffsetView<T, P...>::HostMirror> -create_mirror_view( - const typename Kokkos::Experimental::OffsetView<T, P...>& src, - const Impl::ViewCtorProp<ViewCtorArgs...>&) { +create_mirror_view(const Kokkos::Experimental::OffsetView<T, P...>& src, + const Impl::ViewCtorProp<ViewCtorArgs...>&) { return src; } template <class T, class... P, class... ViewCtorArgs> inline std::enable_if_t< - !(std::is_same< - typename Kokkos::Experimental::OffsetView<T, P...>::memory_space, - typename Kokkos::Experimental::OffsetView< - T, P...>::HostMirror::memory_space>::value && - std::is_same< - typename Kokkos::Experimental::OffsetView<T, P...>::data_type, - typename Kokkos::Experimental::OffsetView< - T, P...>::HostMirror::data_type>::value), + !Impl::ViewCtorProp<ViewCtorArgs...>::has_memory_space && + !(std::is_same< + typename Kokkos::Experimental::OffsetView<T, P...>::memory_space, + typename Kokkos::Experimental::OffsetView< + T, P...>::HostMirror::memory_space>::value && + std::is_same< + typename Kokkos::Experimental::OffsetView<T, P...>::data_type, + typename Kokkos::Experimental::OffsetView< + T, P...>::HostMirror::data_type>::value), typename Kokkos::Experimental::OffsetView<T, P...>::HostMirror> create_mirror_view(const Kokkos::Experimental::OffsetView<T, P...>& src, const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop) { return Kokkos::create_mirror(arg_prop, src); } -template <class Space, class T, class... P, class... ViewCtorArgs> -inline std::enable_if_t< - Impl::MirrorOffsetViewType<Space, T, P...>::is_same_memspace, - Kokkos::Experimental::OffsetView<T, P...>> -create_mirror_view(const Space&, - const Kokkos::Experimental::OffsetView<T, P...>& src, +template <class T, class... P, class... ViewCtorArgs, + class = std::enable_if_t< + Impl::ViewCtorProp<ViewCtorArgs...>::has_memory_space>> +std::enable_if_t<Impl::MirrorOffsetViewType< + typename Impl::ViewCtorProp<ViewCtorArgs...>::memory_space, + T, P...>::is_same_memspace, + typename Impl::MirrorOffsetViewType< + typename Impl::ViewCtorProp<ViewCtorArgs...>::memory_space, + T, P...>::view_type> +create_mirror_view(const Kokkos::Experimental::OffsetView<T, P...>& src, const Impl::ViewCtorProp<ViewCtorArgs...>&) { return src; } -template <class Space, class T, class... P, class... ViewCtorArgs> -std::enable_if_t< - !Impl::MirrorOffsetViewType<Space, T, P...>::is_same_memspace, - typename Kokkos::Impl::MirrorOffsetViewType<Space, T, P...>::view_type> -create_mirror_view(const Space& space, - const Kokkos::Experimental::OffsetView<T, P...>& src, +template <class T, class... P, class... ViewCtorArgs, + class = std::enable_if_t< + Impl::ViewCtorProp<ViewCtorArgs...>::has_memory_space>> +std::enable_if_t<!Impl::MirrorOffsetViewType< + typename Impl::ViewCtorProp<ViewCtorArgs...>::memory_space, + T, P...>::is_same_memspace, + typename Impl::MirrorOffsetViewType< + typename Impl::ViewCtorProp<ViewCtorArgs...>::memory_space, + T, P...>::view_type> +create_mirror_view(const Kokkos::Experimental::OffsetView<T, P...>& src, const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop) { - return create_mirror(space, src, arg_prop); + return Kokkos::Impl::create_mirror(src, arg_prop); } } // namespace Impl @@ -2052,15 +2063,17 @@ inline auto create_mirror_view( template <class Space, class T, class... P, typename Enable = std::enable_if_t<Kokkos::is_space<Space>::value>> inline auto create_mirror_view( - const Space& space, const Kokkos::Experimental::OffsetView<T, P...>& src) { - return Impl::create_mirror_view(space, src, Impl::ViewCtorProp<>{}); + const Space&, const Kokkos::Experimental::OffsetView<T, P...>& src) { + return Impl::create_mirror_view( + src, Kokkos::view_alloc(typename Space::memory_space{})); } template <class Space, class T, class... P> inline auto create_mirror_view( - Kokkos::Impl::WithoutInitializing_t wi, const Space& space, + Kokkos::Impl::WithoutInitializing_t wi, const Space&, const Kokkos::Experimental::OffsetView<T, P...>& src) { - return Impl::create_mirror_view(space, src, Kokkos::view_alloc(wi)); + return Impl::create_mirror_view( + src, Kokkos::view_alloc(typename Space::memory_space{}, wi)); } template <class T, class... P, class... ViewCtorArgs> diff --git a/packages/kokkos/containers/unit_tests/CMakeLists.txt b/packages/kokkos/containers/unit_tests/CMakeLists.txt index f16572b60300562eabd01563ee2469cfa899bf65..261d9dcd4215d712ef7b6fca3b0ad08c9ecb0052 100644 --- a/packages/kokkos/containers/unit_tests/CMakeLists.txt +++ b/packages/kokkos/containers/unit_tests/CMakeLists.txt @@ -46,3 +46,13 @@ foreach(Tag Threads;Serial;OpenMP;HPX;Cuda;HIP;SYCL) KOKKOS_ADD_EXECUTABLE_AND_TEST(UnitTest_${Tag} SOURCES ${UnitTestSources}) endif() endforeach() + +SET(COMPILE_ONLY_SOURCES + TestCreateMirror.cpp +) +KOKKOS_ADD_EXECUTABLE( + TestCompileOnly + SOURCES + TestCompileMain.cpp + ${COMPILE_ONLY_SOURCES} +) diff --git a/packages/kokkos/containers/unit_tests/TestCompileMain.cpp b/packages/kokkos/containers/unit_tests/TestCompileMain.cpp new file mode 100644 index 0000000000000000000000000000000000000000..237c8ce181774d991a9dbdd8cacf1a5fb9f199f1 --- /dev/null +++ b/packages/kokkos/containers/unit_tests/TestCompileMain.cpp @@ -0,0 +1 @@ +int main() {} diff --git a/packages/kokkos/containers/unit_tests/TestCreateMirror.cpp b/packages/kokkos/containers/unit_tests/TestCreateMirror.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0e43be4364154393b30cd349a563d7984a5ca2f0 --- /dev/null +++ b/packages/kokkos/containers/unit_tests/TestCreateMirror.cpp @@ -0,0 +1,179 @@ +/* +//@HEADER +// ************************************************************************ +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, +// the U.S. Government retains certain rights in this software. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the Corporation nor the names of the +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Questions? Contact Christian R. Trott (crtrott@sandia.gov) +// +// ************************************************************************ +//@HEADER +*/ + +#include <Kokkos_Core.hpp> +#include <Kokkos_DynamicView.hpp> +#include <Kokkos_DynRankView.hpp> +#include <Kokkos_OffsetView.hpp> + +template <typename TestView, typename MemorySpace> +void check_memory_space(TestView, MemorySpace) { + static_assert( + std::is_same<typename TestView::memory_space, MemorySpace>::value, ""); +} + +template <class View> +auto host_mirror_test_space(View) { + return std::conditional_t< + Kokkos::SpaceAccessibility<Kokkos::HostSpace, + typename View::memory_space>::accessible, + typename View::memory_space, Kokkos::HostSpace>{}; +} + +template <typename View> +void test_create_mirror_properties(const View& view) { + using namespace Kokkos; + using DeviceMemorySpace = typename DefaultExecutionSpace::memory_space; + + // clang-format off + + // create_mirror +#ifndef KOKKOS_ENABLE_CXX14 + // FIXME DynamicView: HostMirror is the same type + if constexpr (!is_dynamic_view<View>::value) { + check_memory_space(create_mirror(WithoutInitializing, view), host_mirror_test_space(view)); + check_memory_space(create_mirror( view), host_mirror_test_space(view)); + } +#endif + check_memory_space(create_mirror(WithoutInitializing, DefaultExecutionSpace{}, view), DeviceMemorySpace{}); + check_memory_space(create_mirror( DefaultExecutionSpace{}, view), DeviceMemorySpace{}); + + // create_mirror_view +#ifndef KOKKOS_ENABLE_CXX14 + // FIXME DynamicView: HostMirror is the same type + if constexpr (!is_dynamic_view<View>::value) { + check_memory_space(create_mirror_view(WithoutInitializing, view), host_mirror_test_space(view)); + check_memory_space(create_mirror_view( view), host_mirror_test_space(view)); + } +#endif + check_memory_space(create_mirror_view(WithoutInitializing, DefaultExecutionSpace{}, view), DeviceMemorySpace{}); + check_memory_space(create_mirror_view( DefaultExecutionSpace{}, view), DeviceMemorySpace{}); + + // create_mirror view_alloc +#ifndef KOKKOS_ENABLE_CXX14 + // FIXME DynamicView: HostMirror is the same type + if constexpr (!is_dynamic_view<View>::value) { + check_memory_space(create_mirror(view_alloc(WithoutInitializing), view), host_mirror_test_space(view)); + check_memory_space(create_mirror(view_alloc(), view), host_mirror_test_space(view)); + } +#endif + check_memory_space(create_mirror(view_alloc(WithoutInitializing, DeviceMemorySpace{}), view), DeviceMemorySpace{}); + check_memory_space(create_mirror(view_alloc( DeviceMemorySpace{}), view), DeviceMemorySpace{}); + + // create_mirror_view view_alloc +#ifndef KOKKOS_ENABLE_CXX14 + // FIXME DynamicView: HostMirror is the same type + if constexpr (!is_dynamic_view<View>::value) { + check_memory_space(create_mirror_view(view_alloc(WithoutInitializing), view), host_mirror_test_space(view)); + check_memory_space(create_mirror_view(view_alloc(), view), host_mirror_test_space(view)); + } +#endif + check_memory_space(create_mirror_view(view_alloc(WithoutInitializing, DeviceMemorySpace{}), view), DeviceMemorySpace{}); + check_memory_space(create_mirror_view(view_alloc( DeviceMemorySpace{}), view), DeviceMemorySpace{}); + + // create_mirror view_alloc + execution space +#ifndef KOKKOS_ENABLE_CXX14 + // FIXME DynamicView: HostMirror is the same type + if constexpr (!is_dynamic_view<View>::value) { + check_memory_space(create_mirror(view_alloc(DefaultExecutionSpace{}, WithoutInitializing), view), host_mirror_test_space(view)); + check_memory_space(create_mirror(view_alloc(DefaultHostExecutionSpace{}), view), host_mirror_test_space(view)); + } +#endif + check_memory_space(create_mirror(view_alloc(DefaultExecutionSpace{}, WithoutInitializing, DeviceMemorySpace{}), view), DeviceMemorySpace{}); + check_memory_space(create_mirror(view_alloc(DefaultExecutionSpace{}, DeviceMemorySpace{}), view), DeviceMemorySpace{}); + + // create_mirror_view view_alloc + execution space +#ifndef KOKKOS_ENABLE_CXX14 + // FIXME DynamicView: HostMirror is the same type + if constexpr (!is_dynamic_view<View>::value) { + check_memory_space(create_mirror_view(view_alloc(DefaultExecutionSpace{}, WithoutInitializing), view), host_mirror_test_space(view)); + check_memory_space(create_mirror_view(view_alloc(DefaultHostExecutionSpace{}), view), host_mirror_test_space(view)); + } +#endif + check_memory_space(create_mirror_view(view_alloc(DefaultExecutionSpace{}, WithoutInitializing, DeviceMemorySpace{}), view), DeviceMemorySpace{}); + check_memory_space(create_mirror_view(view_alloc(DefaultExecutionSpace{}, DeviceMemorySpace{}), view), DeviceMemorySpace{}); + + // create_mirror_view_and_copy + check_memory_space(create_mirror_view_and_copy(HostSpace{}, view), HostSpace{}); + check_memory_space(create_mirror_view_and_copy(DeviceMemorySpace{}, view), DeviceMemorySpace{}); + + // create_mirror_view_and_copy view_alloc + check_memory_space(create_mirror_view_and_copy(view_alloc(HostSpace{}), view), HostSpace{}); + check_memory_space(create_mirror_view_and_copy(view_alloc(DeviceMemorySpace{}), view), DeviceMemorySpace{}); + + // create_mirror_view_and_copy view_alloc + execution space + check_memory_space(create_mirror_view_and_copy(view_alloc(HostSpace{}, DefaultHostExecutionSpace{}), view), HostSpace{}); + check_memory_space(create_mirror_view_and_copy(view_alloc(DeviceMemorySpace{}, DefaultExecutionSpace{}), view), DeviceMemorySpace{}); + + // clang-format on +} + +void test_create_mirror_dynrankview() { + Kokkos::DynRankView<int, Kokkos::DefaultExecutionSpace> device_view( + "device view", 10); + Kokkos::DynRankView<int, Kokkos::HostSpace> host_view("host view", 10); + + test_create_mirror_properties(device_view); + test_create_mirror_properties(host_view); +} + +void test_reate_mirror_offsetview() { + Kokkos::Experimental::OffsetView<int*, Kokkos::DefaultExecutionSpace> + device_view("device view", {0, 10}); + Kokkos::Experimental::OffsetView<int*, Kokkos::HostSpace> host_view( + "host view", {0, 10}); + + test_create_mirror_properties(device_view); + test_create_mirror_properties(host_view); +} + +void test_create_mirror_dynamicview() { + Kokkos::Experimental::DynamicView<int*, Kokkos::DefaultExecutionSpace> + device_view("device view", 2, 10); + Kokkos::Experimental::DynamicView<int*, Kokkos::HostSpace> host_view( + "host view", 2, 10); + + test_create_mirror_properties(device_view); + test_create_mirror_properties(host_view); +} diff --git a/packages/kokkos/core/cmake/Dependencies.cmake b/packages/kokkos/core/cmake/Dependencies.cmake index cc901a4ede0c6b17fbb89bfa9edfaf6544d7b269..611c089b2e3feec2ec79228360f93c242fc055e2 100644 --- a/packages/kokkos/core/cmake/Dependencies.cmake +++ b/packages/kokkos/core/cmake/Dependencies.cmake @@ -1,5 +1,5 @@ TRIBITS_PACKAGE_DEFINE_DEPENDENCIES( - LIB_OPTIONAL_TPLS Pthread CUDA HWLOC DLlib HPX + LIB_OPTIONAL_TPLS Pthread CUDA HWLOC DLlib TEST_OPTIONAL_TPLS CUSPARSE ) diff --git a/packages/kokkos/core/src/Cuda/Kokkos_Cuda_KernelLaunch.hpp b/packages/kokkos/core/src/Cuda/Kokkos_Cuda_KernelLaunch.hpp index 88810b6fc2bbcf5c6fef3bd4a9de0a72fb30c5e8..b7a80ad84ff22b00d9666956cf5896b259d38b6a 100644 --- a/packages/kokkos/core/src/Cuda/Kokkos_Cuda_KernelLaunch.hpp +++ b/packages/kokkos/core/src/Cuda/Kokkos_Cuda_KernelLaunch.hpp @@ -636,7 +636,7 @@ struct CudaParallelLaunchImpl< DriverType, Kokkos::LaunchBounds<MaxThreadsPerBlock, MinBlocksPerSM>>( base_t::get_kernel_func(), prefer_shmem); - ensure_cuda_lock_arrays_on_device(); + KOKKOS_ENSURE_CUDA_LOCK_ARRAYS_ON_DEVICE(); // Invoke the driver function on the device base_t::invoke_kernel(driver, grid, block, shmem, cuda_instance); diff --git a/packages/kokkos/core/src/Cuda/Kokkos_Cuda_Locks.cpp b/packages/kokkos/core/src/Cuda/Kokkos_Cuda_Locks.cpp index 3796534816a8bdb6bbeb1e517c6e54a04f2c82e1..84d4307cfd549f9567cb2bc5982a882543e19168 100644 --- a/packages/kokkos/core/src/Cuda/Kokkos_Cuda_Locks.cpp +++ b/packages/kokkos/core/src/Cuda/Kokkos_Cuda_Locks.cpp @@ -79,7 +79,8 @@ CudaLockArrays g_host_cuda_lock_arrays = {nullptr, 0}; void initialize_host_cuda_lock_arrays() { #ifdef KOKKOS_ENABLE_IMPL_DESUL_ATOMICS desul::Impl::init_lock_arrays(); - desul::ensure_cuda_lock_arrays_on_device(); + + DESUL_ENSURE_CUDA_LOCK_ARRAYS_ON_DEVICE(); #endif if (g_host_cuda_lock_arrays.atomic != nullptr) return; KOKKOS_IMPL_CUDA_SAFE_CALL( @@ -88,7 +89,7 @@ void initialize_host_cuda_lock_arrays() { Impl::cuda_device_synchronize( "Kokkos::Impl::initialize_host_cuda_lock_arrays: Pre Init Lock Arrays"); g_host_cuda_lock_arrays.n = Cuda::concurrency(); - copy_cuda_lock_arrays_to_device(); + KOKKOS_COPY_CUDA_LOCK_ARRAYS_TO_DEVICE(); init_lock_array_kernel_atomic<<<(CUDA_SPACE_ATOMIC_MASK + 1 + 255) / 256, 256>>>(); Impl::cuda_device_synchronize( @@ -105,7 +106,7 @@ void finalize_host_cuda_lock_arrays() { g_host_cuda_lock_arrays.atomic = nullptr; g_host_cuda_lock_arrays.n = 0; #ifdef KOKKOS_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE - copy_cuda_lock_arrays_to_device(); + KOKKOS_COPY_CUDA_LOCK_ARRAYS_TO_DEVICE(); #endif } diff --git a/packages/kokkos/core/src/Cuda/Kokkos_Cuda_Locks.hpp b/packages/kokkos/core/src/Cuda/Kokkos_Cuda_Locks.hpp index 244f142f0d83550bf79d5cfb5288494e2629226f..bdb7723985e5a3c6c0451ada3d0b6b7303204089 100644 --- a/packages/kokkos/core/src/Cuda/Kokkos_Cuda_Locks.hpp +++ b/packages/kokkos/core/src/Cuda/Kokkos_Cuda_Locks.hpp @@ -67,7 +67,7 @@ struct CudaLockArrays { /// \brief This global variable in Host space is the central definition /// of these arrays. -extern CudaLockArrays g_host_cuda_lock_arrays; +extern Kokkos::Impl::CudaLockArrays g_host_cuda_lock_arrays; /// \brief After this call, the g_host_cuda_lock_arrays variable has /// valid, initialized arrays. @@ -105,12 +105,12 @@ namespace Impl { /// instances in other translation units, we must update this CUDA global /// variable based on the Host global variable prior to running any kernels /// that will use it. -/// That is the purpose of the ensure_cuda_lock_arrays_on_device function. +/// That is the purpose of the KOKKOS_ENSURE_CUDA_LOCK_ARRAYS_ON_DEVICE macro. __device__ #ifdef KOKKOS_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE __constant__ extern #endif - CudaLockArrays g_device_cuda_lock_arrays; + Kokkos::Impl::CudaLockArrays g_device_cuda_lock_arrays; #define CUDA_SPACE_ATOMIC_MASK 0x1FFFF @@ -123,7 +123,9 @@ __device__ inline bool lock_address_cuda_space(void* ptr) { size_t offset = size_t(ptr); offset = offset >> 2; offset = offset & CUDA_SPACE_ATOMIC_MASK; - return (0 == atomicCAS(&g_device_cuda_lock_arrays.atomic[offset], 0, 1)); + return ( + 0 == + atomicCAS(&Kokkos::Impl::g_device_cuda_lock_arrays.atomic[offset], 0, 1)); } /// \brief Release lock for the address @@ -136,7 +138,7 @@ __device__ inline void unlock_address_cuda_space(void* ptr) { size_t offset = size_t(ptr); offset = offset >> 2; offset = offset & CUDA_SPACE_ATOMIC_MASK; - atomicExch(&g_device_cuda_lock_arrays.atomic[offset], 0); + atomicExch(&Kokkos::Impl::g_device_cuda_lock_arrays.atomic[offset], 0); } } // namespace Impl @@ -149,49 +151,45 @@ namespace { static int lock_array_copied = 0; inline int eliminate_warning_for_lock_array() { return lock_array_copied; } } // namespace +} // namespace Impl +} // namespace Kokkos -#ifdef KOKKOS_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE -inline -#else -static -#endif - void - copy_cuda_lock_arrays_to_device() { - if (lock_array_copied == 0) { - KOKKOS_IMPL_CUDA_SAFE_CALL(cudaMemcpyToSymbol(g_device_cuda_lock_arrays, - &g_host_cuda_lock_arrays, - sizeof(CudaLockArrays))); +/* Dan Ibanez: it is critical that this code be a macro, so that it will + capture the right address for Kokkos::Impl::g_device_cuda_lock_arrays! + putting this in an inline function will NOT do the right thing! */ +#define KOKKOS_COPY_CUDA_LOCK_ARRAYS_TO_DEVICE() \ + { \ + if (::Kokkos::Impl::lock_array_copied == 0) { \ + KOKKOS_IMPL_CUDA_SAFE_CALL( \ + cudaMemcpyToSymbol(Kokkos::Impl::g_device_cuda_lock_arrays, \ + &Kokkos::Impl::g_host_cuda_lock_arrays, \ + sizeof(Kokkos::Impl::CudaLockArrays))); \ + } \ + lock_array_copied = 1; \ } - lock_array_copied = 1; -} #ifndef KOKKOS_ENABLE_IMPL_DESUL_ATOMICS #ifdef KOKKOS_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE -inline void ensure_cuda_lock_arrays_on_device() {} +#define KOKKOS_ENSURE_CUDA_LOCK_ARRAYS_ON_DEVICE() #else -inline static void ensure_cuda_lock_arrays_on_device() { - copy_cuda_lock_arrays_to_device(); -} +#define KOKKOS_ENSURE_CUDA_LOCK_ARRAYS_ON_DEVICE() \ + KOKKOS_COPY_CUDA_LOCK_ARRAYS_TO_DEVICE() #endif #else #ifdef KOKKOS_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE -inline void ensure_cuda_lock_arrays_on_device() {} +#define KOKKOS_ENSURE_CUDA_LOCK_ARRAYS_ON_DEVICE() #else // Still Need COPY_CUDA_LOCK_ARRAYS for team scratch etc. -inline static void ensure_cuda_lock_arrays_on_device() { - copy_cuda_lock_arrays_to_device(); - desul::ensure_cuda_lock_arrays_on_device(); -} +#define KOKKOS_ENSURE_CUDA_LOCK_ARRAYS_ON_DEVICE() \ + KOKKOS_COPY_CUDA_LOCK_ARRAYS_TO_DEVICE() \ + DESUL_ENSURE_CUDA_LOCK_ARRAYS_ON_DEVICE() #endif #endif /* defined( KOKKOS_ENABLE_IMPL_DESUL_ATOMICS ) */ -} // namespace Impl -} // namespace Kokkos - #endif /* defined( KOKKOS_ENABLE_CUDA ) */ #endif /* #ifndef KOKKOS_CUDA_LOCKS_HPP */ diff --git a/packages/kokkos/core/src/Cuda/Kokkos_Cuda_Parallel_Range.hpp b/packages/kokkos/core/src/Cuda/Kokkos_Cuda_Parallel_Range.hpp index 98733430063d98815ececb0ac9fcf83592a4e681..ac160f8fe268a42e04eebcee2639160e7edbd512 100644 --- a/packages/kokkos/core/src/Cuda/Kokkos_Cuda_Parallel_Range.hpp +++ b/packages/kokkos/core/src/Cuda/Kokkos_Cuda_Parallel_Range.hpp @@ -465,8 +465,24 @@ class ParallelScan<FunctorType, Kokkos::RangePolicy<Traits...>, Kokkos::Cuda> { public: using pointer_type = typename Analysis::pointer_type; using reference_type = typename Analysis::reference_type; + using value_type = typename Analysis::value_type; using functor_type = FunctorType; using size_type = Cuda::size_type; + // Conditionally set word_size_type to int16_t or int8_t if value_type is + // smaller than int32_t (Kokkos::Cuda::size_type) + // word_size_type is used to determine the word count, shared memory buffer + // size, and global memory buffer size before the scan is performed. + // Within the scan, the word count is recomputed based on word_size_type + // and when calculating indexes into the shared/global memory buffers for + // performing the scan, word_size_type is used again. + // For scalars > 4 bytes in size, indexing into shared/global memory relies + // on the block and grid dimensions to ensure that we index at the correct + // offset rather than at every 4 byte word; such that, when the join is + // performed, we have the correct data that was copied over in chunks of 4 + // bytes. + using word_size_type = std::conditional_t< + sizeof(value_type) < sizeof(size_type), + std::conditional_t<sizeof(value_type) == 2, int16_t, int8_t>, size_type>; private: // Algorithmic constraints: @@ -477,7 +493,7 @@ class ParallelScan<FunctorType, Kokkos::RangePolicy<Traits...>, Kokkos::Cuda> { const FunctorType m_functor; const Policy m_policy; - size_type* m_scratch_space; + word_size_type* m_scratch_space; size_type* m_scratch_flags; size_type m_final; #ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION @@ -501,12 +517,12 @@ class ParallelScan<FunctorType, Kokkos::RangePolicy<Traits...>, Kokkos::Cuda> { __device__ inline void initial() const { typename Analysis::Reducer final_reducer(&m_functor); - const integral_nonzero_constant<size_type, Analysis::StaticValueSize / - sizeof(size_type)> - word_count(Analysis::value_size(m_functor) / sizeof(size_type)); + const integral_nonzero_constant<word_size_type, Analysis::StaticValueSize / + sizeof(word_size_type)> + word_count(Analysis::value_size(m_functor) / sizeof(word_size_type)); - size_type* const shared_value = - kokkos_impl_cuda_shared_memory<size_type>() + + word_size_type* const shared_value = + kokkos_impl_cuda_shared_memory<word_size_type>() + word_count.value * threadIdx.y; final_reducer.init(reinterpret_cast<pointer_type>(shared_value)); @@ -532,7 +548,7 @@ class ParallelScan<FunctorType, Kokkos::RangePolicy<Traits...>, Kokkos::Cuda> { // gridDim.x cuda_single_inter_block_reduce_scan<true>( final_reducer, blockIdx.x, gridDim.x, - kokkos_impl_cuda_shared_memory<size_type>(), m_scratch_space, + kokkos_impl_cuda_shared_memory<word_size_type>(), m_scratch_space, m_scratch_flags); } @@ -541,21 +557,22 @@ class ParallelScan<FunctorType, Kokkos::RangePolicy<Traits...>, Kokkos::Cuda> { __device__ inline void final() const { typename Analysis::Reducer final_reducer(&m_functor); - const integral_nonzero_constant<size_type, Analysis::StaticValueSize / - sizeof(size_type)> - word_count(Analysis::value_size(m_functor) / sizeof(size_type)); + const integral_nonzero_constant<word_size_type, Analysis::StaticValueSize / + sizeof(word_size_type)> + word_count(Analysis::value_size(m_functor) / sizeof(word_size_type)); // Use shared memory as an exclusive scan: { 0 , value[0] , value[1] , // value[2] , ... } - size_type* const shared_data = kokkos_impl_cuda_shared_memory<size_type>(); - size_type* const shared_prefix = + word_size_type* const shared_data = + kokkos_impl_cuda_shared_memory<word_size_type>(); + word_size_type* const shared_prefix = shared_data + word_count.value * threadIdx.y; - size_type* const shared_accum = + word_size_type* const shared_accum = shared_data + word_count.value * (blockDim.y + 1); // Starting value for this thread block is the previous block's total. if (blockIdx.x) { - size_type* const block_total = + word_size_type* const block_total = m_scratch_space + word_count.value * (blockIdx.x - 1); for (unsigned i = threadIdx.y; i < word_count.value; ++i) { shared_accum[i] = block_total[i]; @@ -602,7 +619,7 @@ class ParallelScan<FunctorType, Kokkos::RangePolicy<Traits...>, Kokkos::Cuda> { typename Analysis::pointer_type(shared_data + word_count.value)); { - size_type* const block_total = + word_size_type* const block_total = shared_data + word_count.value * blockDim.y; for (unsigned i = threadIdx.y; i < word_count.value; ++i) { shared_accum[i] = block_total[i]; @@ -690,8 +707,9 @@ class ParallelScan<FunctorType, Kokkos::RangePolicy<Traits...>, Kokkos::Cuda> { // How many block are really needed for this much work: const int grid_x = (nwork + work_per_block - 1) / work_per_block; - m_scratch_space = cuda_internal_scratch_space( - m_policy.space(), Analysis::value_size(m_functor) * grid_x); + m_scratch_space = + reinterpret_cast<word_size_type*>(cuda_internal_scratch_space( + m_policy.space(), Analysis::value_size(m_functor) * grid_x)); m_scratch_flags = cuda_internal_scratch_flags(m_policy.space(), sizeof(size_type) * 1); @@ -752,10 +770,26 @@ class ParallelScanWithTotal<FunctorType, Kokkos::RangePolicy<Traits...>, Policy, FunctorType>; public: + using value_type = typename Analysis::value_type; using pointer_type = typename Analysis::pointer_type; using reference_type = typename Analysis::reference_type; using functor_type = FunctorType; using size_type = Cuda::size_type; + // Conditionally set word_size_type to int16_t or int8_t if value_type is + // smaller than int32_t (Kokkos::Cuda::size_type) + // word_size_type is used to determine the word count, shared memory buffer + // size, and global memory buffer size before the scan is performed. + // Within the scan, the word count is recomputed based on word_size_type + // and when calculating indexes into the shared/global memory buffers for + // performing the scan, word_size_type is used again. + // For scalars > 4 bytes in size, indexing into shared/global memory relies + // on the block and grid dimensions to ensure that we index at the correct + // offset rather than at every 4 byte word; such that, when the join is + // performed, we have the correct data that was copied over in chunks of 4 + // bytes. + using word_size_type = std::conditional_t< + sizeof(value_type) < sizeof(size_type), + std::conditional_t<sizeof(value_type) == 2, int16_t, int8_t>, size_type>; private: // Algorithmic constraints: @@ -766,7 +800,7 @@ class ParallelScanWithTotal<FunctorType, Kokkos::RangePolicy<Traits...>, const FunctorType m_functor; const Policy m_policy; - size_type* m_scratch_space; + word_size_type* m_scratch_space; size_type* m_scratch_flags; size_type m_final; ReturnType& m_returnvalue; @@ -791,12 +825,12 @@ class ParallelScanWithTotal<FunctorType, Kokkos::RangePolicy<Traits...>, __device__ inline void initial() const { typename Analysis::Reducer final_reducer(&m_functor); - const integral_nonzero_constant<size_type, Analysis::StaticValueSize / - sizeof(size_type)> - word_count(Analysis::value_size(m_functor) / sizeof(size_type)); + const integral_nonzero_constant<word_size_type, Analysis::StaticValueSize / + sizeof(word_size_type)> + word_count(Analysis::value_size(m_functor) / sizeof(word_size_type)); - size_type* const shared_value = - kokkos_impl_cuda_shared_memory<size_type>() + + word_size_type* const shared_value = + kokkos_impl_cuda_shared_memory<word_size_type>() + word_count.value * threadIdx.y; final_reducer.init(reinterpret_cast<pointer_type>(shared_value)); @@ -822,7 +856,7 @@ class ParallelScanWithTotal<FunctorType, Kokkos::RangePolicy<Traits...>, // gridDim.x cuda_single_inter_block_reduce_scan<true>( final_reducer, blockIdx.x, gridDim.x, - kokkos_impl_cuda_shared_memory<size_type>(), m_scratch_space, + kokkos_impl_cuda_shared_memory<word_size_type>(), m_scratch_space, m_scratch_flags); } @@ -831,21 +865,22 @@ class ParallelScanWithTotal<FunctorType, Kokkos::RangePolicy<Traits...>, __device__ inline void final() const { typename Analysis::Reducer final_reducer(&m_functor); - const integral_nonzero_constant<size_type, Analysis::StaticValueSize / - sizeof(size_type)> - word_count(Analysis::value_size(m_functor) / sizeof(size_type)); + const integral_nonzero_constant<word_size_type, Analysis::StaticValueSize / + sizeof(word_size_type)> + word_count(Analysis::value_size(m_functor) / sizeof(word_size_type)); // Use shared memory as an exclusive scan: { 0 , value[0] , value[1] , // value[2] , ... } - size_type* const shared_data = kokkos_impl_cuda_shared_memory<size_type>(); - size_type* const shared_prefix = + word_size_type* const shared_data = + kokkos_impl_cuda_shared_memory<word_size_type>(); + word_size_type* const shared_prefix = shared_data + word_count.value * threadIdx.y; - size_type* const shared_accum = + word_size_type* const shared_accum = shared_data + word_count.value * (blockDim.y + 1); // Starting value for this thread block is the previous block's total. if (blockIdx.x) { - size_type* const block_total = + word_size_type* const block_total = m_scratch_space + word_count.value * (blockIdx.x - 1); for (unsigned i = threadIdx.y; i < word_count.value; ++i) { shared_accum[i] = block_total[i]; @@ -894,7 +929,7 @@ class ParallelScanWithTotal<FunctorType, Kokkos::RangePolicy<Traits...>, typename Analysis::pointer_type(shared_data + word_count.value)); { - size_type* const block_total = + word_size_type* const block_total = shared_data + word_count.value * blockDim.y; for (unsigned i = threadIdx.y; i < word_count.value; ++i) { shared_accum[i] = block_total[i]; @@ -983,8 +1018,9 @@ class ParallelScanWithTotal<FunctorType, Kokkos::RangePolicy<Traits...>, // How many block are really needed for this much work: const int grid_x = (nwork + work_per_block - 1) / work_per_block; - m_scratch_space = cuda_internal_scratch_space( - m_policy.space(), Analysis::value_size(m_functor) * grid_x); + m_scratch_space = + reinterpret_cast<word_size_type*>(cuda_internal_scratch_space( + m_policy.space(), Analysis::value_size(m_functor) * grid_x)); m_scratch_flags = cuda_internal_scratch_flags(m_policy.space(), sizeof(size_type) * 1); @@ -1022,7 +1058,8 @@ class ParallelScanWithTotal<FunctorType, Kokkos::RangePolicy<Traits...>, #endif DeepCopy<HostSpace, CudaSpace, Cuda>( m_policy.space(), &m_returnvalue, - m_scratch_space + (grid_x - 1) * size / sizeof(int), size); + m_scratch_space + (grid_x - 1) * size / sizeof(word_size_type), + size); } } diff --git a/packages/kokkos/core/src/Cuda/Kokkos_Cuda_ReduceScan.hpp b/packages/kokkos/core/src/Cuda/Kokkos_Cuda_ReduceScan.hpp index 078315b65dd20d37adc6973f5ffff3a94836236b..34d4bef9fdaaf038a2fcdab257d043438a348887 100644 --- a/packages/kokkos/core/src/Cuda/Kokkos_Cuda_ReduceScan.hpp +++ b/packages/kokkos/core/src/Cuda/Kokkos_Cuda_ReduceScan.hpp @@ -116,6 +116,7 @@ __device__ inline void cuda_inter_warp_reduction( value = result[0]; for (int i = 1; (i * step < max_active_thread) && i < STEP_WIDTH; i++) reducer.join(&value, &result[i]); + __syncthreads(); } template <class ValueType, class ReducerType> diff --git a/packages/kokkos/core/src/HIP/Kokkos_HIP_Parallel_Range.hpp b/packages/kokkos/core/src/HIP/Kokkos_HIP_Parallel_Range.hpp index 5c871e0d615fc58bb01b93566bc0ab7a0ad892b2..dca1fb9073e6de4f5889e0ae61c0f5a5787254de 100644 --- a/packages/kokkos/core/src/HIP/Kokkos_HIP_Parallel_Range.hpp +++ b/packages/kokkos/core/src/HIP/Kokkos_HIP_Parallel_Range.hpp @@ -448,11 +448,27 @@ class ParallelScanHIPBase { Policy, FunctorType>; public: + using value_type = typename Analysis::value_type; using pointer_type = typename Analysis::pointer_type; using reference_type = typename Analysis::reference_type; using functor_type = FunctorType; using size_type = Kokkos::Experimental::HIP::size_type; using index_type = typename Policy::index_type; + // Conditionally set word_size_type to int16_t or int8_t if value_type is + // smaller than int32_t (Kokkos::HIP::size_type) + // word_size_type is used to determine the word count, shared memory buffer + // size, and global memory buffer size before the scan is performed. + // Within the scan, the word count is recomputed based on word_size_type + // and when calculating indexes into the shared/global memory buffers for + // performing the scan, word_size_type is used again. + // For scalars > 4 bytes in size, indexing into shared/global memory relies + // on the block and grid dimensions to ensure that we index at the correct + // offset rather than at every 4 byte word; such that, when the join is + // performed, we have the correct data that was copied over in chunks of 4 + // bytes. + using word_size_type = std::conditional_t< + sizeof(value_type) < sizeof(size_type), + std::conditional_t<sizeof(value_type) == 2, int16_t, int8_t>, size_type>; protected: // Algorithmic constraints: @@ -463,10 +479,10 @@ class ParallelScanHIPBase { const FunctorType m_functor; const Policy m_policy; - size_type* m_scratch_space = nullptr; - size_type* m_scratch_flags = nullptr; - size_type m_final = false; - int m_grid_x = 0; + word_size_type* m_scratch_space = nullptr; + size_type* m_scratch_flags = nullptr; + size_type m_final = false; + int m_grid_x = 0; // Only let one ParallelReduce/Scan modify the shared memory. The // constructor acquires the mutex which is released in the destructor. std::lock_guard<std::mutex> m_shared_memory_lock; @@ -489,12 +505,12 @@ class ParallelScanHIPBase { __device__ inline void initial() const { typename Analysis::Reducer final_reducer(&m_functor); - const integral_nonzero_constant<size_type, Analysis::StaticValueSize / - sizeof(size_type)> - word_count(Analysis::value_size(m_functor) / sizeof(size_type)); + const integral_nonzero_constant<word_size_type, Analysis::StaticValueSize / + sizeof(word_size_type)> + word_count(Analysis::value_size(m_functor) / sizeof(word_size_type)); pointer_type const shared_value = reinterpret_cast<pointer_type>( - Kokkos::Experimental::kokkos_impl_hip_shared_memory<size_type>() + + Kokkos::Experimental::kokkos_impl_hip_shared_memory<word_size_type>() + word_count.value * threadIdx.y); final_reducer.init(shared_value); @@ -518,7 +534,7 @@ class ParallelScanHIPBase { // gridDim.x hip_single_inter_block_reduce_scan<true>( final_reducer, blockIdx.x, gridDim.x, - Kokkos::Experimental::kokkos_impl_hip_shared_memory<size_type>(), + Kokkos::Experimental::kokkos_impl_hip_shared_memory<word_size_type>(), m_scratch_space, m_scratch_flags); } @@ -527,22 +543,22 @@ class ParallelScanHIPBase { __device__ inline void final() const { typename Analysis::Reducer final_reducer(&m_functor); - const integral_nonzero_constant<size_type, Analysis::StaticValueSize / - sizeof(size_type)> - word_count(Analysis::value_size(m_functor) / sizeof(size_type)); + const integral_nonzero_constant<word_size_type, Analysis::StaticValueSize / + sizeof(word_size_type)> + word_count(Analysis::value_size(m_functor) / sizeof(word_size_type)); // Use shared memory as an exclusive scan: { 0 , value[0] , value[1] , // value[2] , ... } - size_type* const shared_data = - Kokkos::Experimental::kokkos_impl_hip_shared_memory<size_type>(); - size_type* const shared_prefix = + word_size_type* const shared_data = + Kokkos::Experimental::kokkos_impl_hip_shared_memory<word_size_type>(); + word_size_type* const shared_prefix = shared_data + word_count.value * threadIdx.y; - size_type* const shared_accum = + word_size_type* const shared_accum = shared_data + word_count.value * (blockDim.y + 1); // Starting value for this thread block is the previous block's total. if (blockIdx.x) { - size_type* const block_total = + word_size_type* const block_total = m_scratch_space + word_count.value * (blockIdx.x - 1); for (unsigned i = threadIdx.y; i < word_count.value; ++i) { shared_accum[i] = block_total[i]; @@ -588,7 +604,7 @@ class ParallelScanHIPBase { typename Analysis::pointer_type(shared_data + word_count.value)); { - size_type* const block_total = + word_size_type* const block_total = shared_data + word_count.value * blockDim.y; for (unsigned i = threadIdx.y; i < word_count.value; ++i) { shared_accum[i] = block_total[i]; @@ -647,8 +663,9 @@ class ParallelScanHIPBase { // How many block are really needed for this much work: m_grid_x = (nwork + work_per_block - 1) / work_per_block; - m_scratch_space = Kokkos::Experimental::Impl::hip_internal_scratch_space( - m_policy.space(), Analysis::value_size(m_functor) * m_grid_x); + m_scratch_space = reinterpret_cast<word_size_type*>( + Kokkos::Experimental::Impl::hip_internal_scratch_space( + m_policy.space(), Analysis::value_size(m_functor) * m_grid_x)); m_scratch_flags = Kokkos::Experimental::Impl::hip_internal_scratch_flags( m_policy.space(), sizeof(size_type) * 1); @@ -734,7 +751,8 @@ class ParallelScanWithTotal<FunctorType, Kokkos::RangePolicy<Traits...>, DeepCopy<HostSpace, Kokkos::Experimental::HIPSpace, Kokkos::Experimental::HIP>( Base::m_policy.space(), &m_returnvalue, - Base::m_scratch_space + (Base::m_grid_x - 1) * size / sizeof(int), + Base::m_scratch_space + (Base::m_grid_x - 1) * size / + sizeof(typename Base::word_size_type), size); } } diff --git a/packages/kokkos/core/src/HIP/Kokkos_HIP_ReduceScan.hpp b/packages/kokkos/core/src/HIP/Kokkos_HIP_ReduceScan.hpp index 1091ad5ceadf6a14b2f162c49d797c6c9564d390..9002f695894e987d34fd1437bbcc1f3da7e2a04c 100644 --- a/packages/kokkos/core/src/HIP/Kokkos_HIP_ReduceScan.hpp +++ b/packages/kokkos/core/src/HIP/Kokkos_HIP_ReduceScan.hpp @@ -225,11 +225,11 @@ struct HIPReductionsFunctor<FunctorType, false> { } } + template <typename SizeType> __device__ static inline bool scalar_inter_block_reduction( FunctorType const& functor, ::Kokkos::Experimental::HIP::size_type const block_count, - ::Kokkos::Experimental::HIP::size_type* const shared_data, - ::Kokkos::Experimental::HIP::size_type* const global_data, + SizeType* const shared_data, SizeType* const global_data, ::Kokkos::Experimental::HIP::size_type* const global_flags) { Scalar* const global_team_buffer_element = reinterpret_cast<Scalar*>(global_data); @@ -411,16 +411,14 @@ __device__ void hip_intra_block_reduce_scan( * Global reduce result is in the last threads' 'shared_data' location. */ -template <bool DoScan, class FunctorType> +template <bool DoScan, typename FunctorType, typename SizeType> __device__ bool hip_single_inter_block_reduce_scan_impl( FunctorType const& functor, ::Kokkos::Experimental::HIP::size_type const block_id, ::Kokkos::Experimental::HIP::size_type const block_count, - ::Kokkos::Experimental::HIP::size_type* const shared_data, - ::Kokkos::Experimental::HIP::size_type* const global_data, + SizeType* const shared_data, SizeType* const global_data, ::Kokkos::Experimental::HIP::size_type* const global_flags) { - using size_type = ::Kokkos::Experimental::HIP::size_type; - + using size_type = SizeType; using value_type = typename FunctorType::value_type; using pointer_type = typename FunctorType::pointer_type; @@ -518,13 +516,12 @@ __device__ bool hip_single_inter_block_reduce_scan_impl( return is_last_block; } -template <bool DoScan, typename FunctorType> +template <bool DoScan, typename FunctorType, typename SizeType> __device__ bool hip_single_inter_block_reduce_scan( FunctorType const& functor, ::Kokkos::Experimental::HIP::size_type const block_id, ::Kokkos::Experimental::HIP::size_type const block_count, - ::Kokkos::Experimental::HIP::size_type* const shared_data, - ::Kokkos::Experimental::HIP::size_type* const global_data, + SizeType* const shared_data, SizeType* const global_data, ::Kokkos::Experimental::HIP::size_type* const global_flags) { // If we are doing a reduction and we don't do an array reduction, we use the // reduction-only path. Otherwise, we use the common path between reduction diff --git a/packages/kokkos/core/src/HIP/Kokkos_HIP_Shuffle_Reduce.hpp b/packages/kokkos/core/src/HIP/Kokkos_HIP_Shuffle_Reduce.hpp index eb85ed4709ed453f40856b05b07e76fd50e06430..d0bbc18da8a1c64839444f5abb8c4d507a01a30b 100644 --- a/packages/kokkos/core/src/HIP/Kokkos_HIP_Shuffle_Reduce.hpp +++ b/packages/kokkos/core/src/HIP/Kokkos_HIP_Shuffle_Reduce.hpp @@ -116,6 +116,7 @@ __device__ inline void hip_inter_warp_shuffle_reduction( value = result[0]; for (int i = 1; (i * step < max_active_thread) && (i < step_width); ++i) reducer.join(&value, &result[i]); + __syncthreads(); } template <typename ValueType, typename ReducerType> diff --git a/packages/kokkos/core/src/Kokkos_CopyViews.hpp b/packages/kokkos/core/src/Kokkos_CopyViews.hpp index 0a66ee9da71fdaf3bb2bf649fb1a7081e4651ea4..d859a5d8ae0f1908b35c4dc31aa9229cfd578bf6 100644 --- a/packages/kokkos/core/src/Kokkos_CopyViews.hpp +++ b/packages/kokkos/core/src/Kokkos_CopyViews.hpp @@ -3711,12 +3711,13 @@ namespace Impl { template <class T, class... P, class... ViewCtorArgs> inline std::enable_if_t< - (std::is_same< - typename Kokkos::View<T, P...>::memory_space, - typename Kokkos::View<T, P...>::HostMirror::memory_space>::value && - std::is_same< - typename Kokkos::View<T, P...>::data_type, - typename Kokkos::View<T, P...>::HostMirror::data_type>::value), + !Impl::ViewCtorProp<ViewCtorArgs...>::has_memory_space && + (std::is_same< + typename Kokkos::View<T, P...>::memory_space, + typename Kokkos::View<T, P...>::HostMirror::memory_space>::value && + std::is_same< + typename Kokkos::View<T, P...>::data_type, + typename Kokkos::View<T, P...>::HostMirror::data_type>::value), typename Kokkos::View<T, P...>::HostMirror> create_mirror_view(const Kokkos::View<T, P...>& src, const Impl::ViewCtorProp<ViewCtorArgs...>&) { @@ -3725,12 +3726,13 @@ create_mirror_view(const Kokkos::View<T, P...>& src, template <class T, class... P, class... ViewCtorArgs> inline std::enable_if_t< - !(std::is_same< - typename Kokkos::View<T, P...>::memory_space, - typename Kokkos::View<T, P...>::HostMirror::memory_space>::value && - std::is_same< - typename Kokkos::View<T, P...>::data_type, - typename Kokkos::View<T, P...>::HostMirror::data_type>::value), + !Impl::ViewCtorProp<ViewCtorArgs...>::has_memory_space && + !(std::is_same<typename Kokkos::View<T, P...>::memory_space, + typename Kokkos::View< + T, P...>::HostMirror::memory_space>::value && + std::is_same< + typename Kokkos::View<T, P...>::data_type, + typename Kokkos::View<T, P...>::HostMirror::data_type>::value), typename Kokkos::View<T, P...>::HostMirror> create_mirror_view(const Kokkos::View<T, P...>& src, const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop) { @@ -3738,25 +3740,33 @@ create_mirror_view(const Kokkos::View<T, P...>& src, } // Create a mirror view in a new space (specialization for same space) -template <class Space, class T, class... P, class... ViewCtorArgs> -std::enable_if_t<Impl::MirrorViewType<Space, T, P...>::is_same_memspace, - typename Impl::MirrorViewType<Space, T, P...>::view_type> -create_mirror_view(const Space&, const Kokkos::View<T, P...>& src, +template <class T, class... P, class... ViewCtorArgs, + class = std::enable_if_t< + Impl::ViewCtorProp<ViewCtorArgs...>::has_memory_space>> +std::enable_if_t<Impl::MirrorViewType< + typename Impl::ViewCtorProp<ViewCtorArgs...>::memory_space, + T, P...>::is_same_memspace, + typename Impl::MirrorViewType< + typename Impl::ViewCtorProp<ViewCtorArgs...>::memory_space, + T, P...>::view_type> +create_mirror_view(const Kokkos::View<T, P...>& src, const Impl::ViewCtorProp<ViewCtorArgs...>&) { return src; } // Create a mirror view in a new space (specialization for different space) -template <class Space, class T, class... P, class... ViewCtorArgs> -std::enable_if_t<!Impl::MirrorViewType<Space, T, P...>::is_same_memspace, - typename Impl::MirrorViewType<Space, T, P...>::view_type> -create_mirror_view(const Space&, const Kokkos::View<T, P...>& src, +template <class T, class... P, class... ViewCtorArgs, + class = std::enable_if_t< + Impl::ViewCtorProp<ViewCtorArgs...>::has_memory_space>> +std::enable_if_t<!Impl::MirrorViewType< + typename Impl::ViewCtorProp<ViewCtorArgs...>::memory_space, + T, P...>::is_same_memspace, + typename Impl::MirrorViewType< + typename Impl::ViewCtorProp<ViewCtorArgs...>::memory_space, + T, P...>::view_type> +create_mirror_view(const Kokkos::View<T, P...>& src, const Impl::ViewCtorProp<ViewCtorArgs...>& arg_prop) { - using MemorySpace = typename Space::memory_space; - using alloc_prop = Impl::ViewCtorProp<ViewCtorArgs..., MemorySpace>; - alloc_prop prop_copy(arg_prop); - - return Kokkos::Impl::create_mirror(src, prop_copy); + return Kokkos::Impl::create_mirror(src, arg_prop); } } // namespace Impl @@ -3815,9 +3825,10 @@ typename Impl::MirrorViewType<Space, T, P...>::view_type create_mirror_view( template <class Space, class T, class... P, typename Enable = std::enable_if_t<Kokkos::is_space<Space>::value>> typename Impl::MirrorViewType<Space, T, P...>::view_type create_mirror_view( - Kokkos::Impl::WithoutInitializing_t wi, Space const& space, + Kokkos::Impl::WithoutInitializing_t wi, Space const&, Kokkos::View<T, P...> const& v) { - return Impl::create_mirror_view(space, v, view_alloc(wi)); + return Impl::create_mirror_view( + v, view_alloc(typename Space::memory_space{}, wi)); } template <class T, class... P, class... ViewCtorArgs> diff --git a/packages/kokkos/core/src/Kokkos_View.hpp b/packages/kokkos/core/src/Kokkos_View.hpp index e92ed7d2e91395aef45292b3a3b3a4f5c9cd5cf7..f8dcfc869e195b93f2ed899b89f6f64be62c46e3 100644 --- a/packages/kokkos/core/src/Kokkos_View.hpp +++ b/packages/kokkos/core/src/Kokkos_View.hpp @@ -1754,7 +1754,10 @@ struct RankDataType<ValueType, 0> { }; template <unsigned N, typename... Args> -KOKKOS_FUNCTION std::enable_if_t<N == View<Args...>::Rank, View<Args...>> +KOKKOS_FUNCTION std::enable_if_t< + N == View<Args...>::Rank && + std::is_same<typename ViewTraits<Args...>::specialize, void>::value, + View<Args...>> as_view_of_rank_n(View<Args...> v) { return v; } @@ -1762,13 +1765,13 @@ as_view_of_rank_n(View<Args...> v) { // Placeholder implementation to compile generic code for DynRankView; should // never be called template <unsigned N, typename T, typename... Args> -std::enable_if_t< - N != View<T, Args...>::Rank, +KOKKOS_FUNCTION std::enable_if_t< + N != View<T, Args...>::Rank && + std::is_same<typename ViewTraits<T, Args...>::specialize, void>::value, View<typename RankDataType<typename View<T, Args...>::value_type, N>::type, Args...>> as_view_of_rank_n(View<T, Args...>) { - Kokkos::Impl::throw_runtime_exception( - "Trying to get at a View of the wrong rank"); + Kokkos::abort("Trying to get at a View of the wrong rank"); return {}; } diff --git a/packages/kokkos/core/src/Kokkos_WorkGraphPolicy.hpp b/packages/kokkos/core/src/Kokkos_WorkGraphPolicy.hpp index fafd825df297123e100ccf008069f24e4a2cf1e5..129a489387a46297bdd5ce17d3ad7873cbc1c80b 100644 --- a/packages/kokkos/core/src/Kokkos_WorkGraphPolicy.hpp +++ b/packages/kokkos/core/src/Kokkos_WorkGraphPolicy.hpp @@ -101,8 +101,8 @@ class WorkGraphPolicy : public Kokkos::Impl::PolicyTraits<Properties...> { void push_work(const std::int32_t w) const noexcept { const std::int32_t N = m_graph.numRows(); - std::int32_t volatile* const ready_queue = &m_queue[0]; - std::int32_t volatile* const end_hint = &m_queue[2 * N + 1]; + std::int32_t* const ready_queue = &m_queue[0]; + std::int32_t* const end_hint = &m_queue[2 * N + 1]; // Push work to end of queue const std::int32_t j = atomic_fetch_add(end_hint, 1); @@ -134,14 +134,14 @@ class WorkGraphPolicy : public Kokkos::Impl::PolicyTraits<Properties...> { std::int32_t pop_work() const noexcept { const std::int32_t N = m_graph.numRows(); - std::int32_t volatile* const ready_queue = &m_queue[0]; - std::int32_t volatile* const begin_hint = &m_queue[2 * N]; + std::int32_t* const ready_queue = &m_queue[0]; + std::int32_t* const begin_hint = &m_queue[2 * N]; // begin hint is guaranteed to be less than or equal to // actual begin location in the queue. - for (std::int32_t i = *begin_hint; i < N; ++i) { - const std::int32_t w = ready_queue[i]; + for (std::int32_t i = Kokkos::atomic_load(begin_hint); i < N; ++i) { + const std::int32_t w = Kokkos::atomic_load(&ready_queue[i]); if (w == END_TOKEN) { return END_TOKEN; @@ -169,7 +169,7 @@ class WorkGraphPolicy : public Kokkos::Impl::PolicyTraits<Properties...> { const std::int32_t N = m_graph.numRows(); - std::int32_t volatile* const count_queue = &m_queue[N]; + std::int32_t* const count_queue = &m_queue[N]; const std::int32_t B = m_graph.row_map(w); const std::int32_t E = m_graph.row_map(w + 1); @@ -199,7 +199,7 @@ class WorkGraphPolicy : public Kokkos::Impl::PolicyTraits<Properties...> { KOKKOS_INLINE_FUNCTION void operator()(const TagCount, int i) const noexcept { - std::int32_t volatile* const count_queue = &m_queue[m_graph.numRows()]; + std::int32_t* const count_queue = &m_queue[m_graph.numRows()]; atomic_increment(count_queue + m_graph.entries[i]); } diff --git a/packages/kokkos/core/src/OpenMPTarget/Kokkos_OpenMPTarget_Instance.cpp b/packages/kokkos/core/src/OpenMPTarget/Kokkos_OpenMPTarget_Instance.cpp index 51921765baf249a1f1dacc57221bc4f4a398c79d..a9bc085912356ec90bbef0c63688cd3f91d11a95 100644 --- a/packages/kokkos/core/src/OpenMPTarget/Kokkos_OpenMPTarget_Instance.cpp +++ b/packages/kokkos/core/src/OpenMPTarget/Kokkos_OpenMPTarget_Instance.cpp @@ -47,6 +47,7 @@ #endif #include <Kokkos_Macros.hpp> +#include <impl/Kokkos_DeviceManagement.hpp> #if defined(KOKKOS_ENABLE_OPENMPTARGET) && defined(_OPENMP) @@ -164,7 +165,11 @@ void OpenMPTarget::impl_static_fence(const std::string& name) { name, Kokkos::Experimental::Impl::openmp_fence_is_static::yes); } -void OpenMPTarget::impl_initialize(InitializationSettings const&) { +void OpenMPTarget::impl_initialize(InitializationSettings const& settings) { + using Kokkos::Impl::get_gpu; + const int device_num = get_gpu(settings); + omp_set_default_device(device_num); + Impl::OpenMPTargetInternal::impl_singleton()->impl_initialize(); } void OpenMPTarget::impl_finalize() { diff --git a/packages/kokkos/core/src/impl/Kokkos_ClockTic.hpp b/packages/kokkos/core/src/impl/Kokkos_ClockTic.hpp index c1cb6a7d91b54b951f445131e43347eaaa33a027..ecece72cf958c937702dd18b4a22642e479c857c 100644 --- a/packages/kokkos/core/src/impl/Kokkos_ClockTic.hpp +++ b/packages/kokkos/core/src/impl/Kokkos_ClockTic.hpp @@ -110,10 +110,9 @@ KOKKOS_IMPL_HOST_FUNCTION inline uint64_t clock_tic_host() noexcept { return ((uint64_t)a) | (((uint64_t)d) << 32); -#elif defined(__powerpc) || defined(__powerpc__) || defined(__powerpc64__) || \ - defined(__POWERPC__) || defined(__ppc__) || defined(__ppc64__) +#elif defined(__powerpc64__) || defined(__ppc64__) - unsigned int cycles = 0; + unsigned long cycles = 0; asm volatile("mftb %0" : "=r"(cycles)); diff --git a/packages/kokkos/core/src/impl/Kokkos_Core.cpp b/packages/kokkos/core/src/impl/Kokkos_Core.cpp index f624e7a14cb21b4a395898125536ec9b55bfeaae..a5bd0032374ffc5e0e73627e33aeb3fa7c1b788e 100644 --- a/packages/kokkos/core/src/impl/Kokkos_Core.cpp +++ b/packages/kokkos/core/src/impl/Kokkos_Core.cpp @@ -166,6 +166,8 @@ int get_device_count() { #elif defined(KOKKOS_ENABLE_OPENACC) return acc_get_num_devices( Kokkos::Experimental::Impl::OpenACC_Traits::dev_type); +#elif defined(KOKKOS_ENABLE_OPENMPTARGET) + return omp_get_num_devices(); #else Kokkos::abort("implementation bug"); return -1; @@ -426,11 +428,17 @@ int Kokkos::Impl::get_gpu(const InitializationSettings& settings) { Kokkos::abort("implementation bug"); } - auto const* local_rank_str = - std::getenv("OMPI_COMM_WORLD_LOCAL_RANK"); // OpenMPI - if (!local_rank_str) - local_rank_str = std::getenv("MV2_COMM_WORLD_LOCAL_RANK"); // MVAPICH2 - if (!local_rank_str) local_rank_str = std::getenv("SLURM_LOCALID"); // SLURM + char const* local_rank_str = nullptr; + for (char const* env_var : { + "OMPI_COMM_WORLD_LOCAL_RANK", // OpenMPI + "MV2_COMM_WORLD_LOCAL_RANK", // MVAPICH2 + "MPI_LOCALRANKID", // MPICH + "SLURM_LOCALID", // SLURM + "PMI_LOCAL_RANK" // PMI + }) { + local_rank_str = std::getenv(env_var); + if (local_rank_str) break; + } // use first GPU available for execution if unable to detect local MPI rank if (!local_rank_str) { diff --git a/packages/kokkos/core/src/impl/Kokkos_ViewMapping.hpp b/packages/kokkos/core/src/impl/Kokkos_ViewMapping.hpp index 738231677c600f6d928122269d848b1a2b51ac46..994dd0b2adf65d9a2440abeb5c4930b43a662d54 100644 --- a/packages/kokkos/core/src/impl/Kokkos_ViewMapping.hpp +++ b/packages/kokkos/core/src/impl/Kokkos_ViewMapping.hpp @@ -1128,9 +1128,8 @@ struct ViewOffset< KOKKOS_INLINE_FUNCTION constexpr ViewOffset( const ViewOffset<DimRHS, Kokkos::LayoutRight, void>& rhs) : m_dim(rhs.m_dim.N0, 0, 0, 0, 0, 0, 0, 0) { - static_assert((DimRHS::rank == 0 && dimension_type::rank == 0) || - (DimRHS::rank == 1 && dimension_type::rank == 1 && - dimension_type::rank_dynamic == 1), + static_assert(((DimRHS::rank == 0 && dimension_type::rank == 0) || + (DimRHS::rank == 1 && dimension_type::rank == 1)), "ViewOffset LayoutLeft and LayoutRight are only compatible " "when rank <= 1"); } @@ -1778,8 +1777,7 @@ struct ViewOffset< const ViewOffset<DimRHS, Kokkos::LayoutLeft, void>& rhs) : m_dim(rhs.m_dim.N0, 0, 0, 0, 0, 0, 0, 0) { static_assert((DimRHS::rank == 0 && dimension_type::rank == 0) || - (DimRHS::rank == 1 && dimension_type::rank == 1 && - dimension_type::rank_dynamic == 1), + (DimRHS::rank == 1 && dimension_type::rank == 1), "ViewOffset LayoutRight and LayoutLeft are only compatible " "when rank <= 1"); } @@ -3059,10 +3057,10 @@ struct ViewValueFunctor<DeviceType, ValueType, true /* is_scalar */> { std::is_trivially_copy_assignable<Dummy>::value> construct_shared_allocation() { // Shortcut for zero initialization - ValueType value{}; // On A64FX memset seems to do the wrong thing with regards to first touch // leading to the significant performance issues #ifndef KOKKOS_ARCH_A64FX + ValueType value{}; if (Impl::is_zero_byte(value)) { uint64_t kpID = 0; if (Kokkos::Profiling::profileLibraryLoaded()) { @@ -3539,9 +3537,7 @@ class ViewMapping< typename SrcTraits::array_layout>::value || std::is_same<typename DstTraits::array_layout, Kokkos::LayoutStride>::value || - (DstTraits::dimension::rank == 0) || - (DstTraits::dimension::rank == 1 && - DstTraits::dimension::rank_dynamic == 1) + (DstTraits::dimension::rank == 0) || (DstTraits::dimension::rank == 1) }; public: diff --git a/packages/kokkos/core/unit_test/CMakeLists.txt b/packages/kokkos/core/unit_test/CMakeLists.txt index 24f70c0ccb3208ca3db1acf82e08bfb56d1ef0de..16fdb39d1a36e9dd8b7d65bbe846c28b37fcf496 100644 --- a/packages/kokkos/core/unit_test/CMakeLists.txt +++ b/packages/kokkos/core/unit_test/CMakeLists.txt @@ -73,6 +73,7 @@ KOKKOS_INCLUDE_DIRECTORIES(${KOKKOS_SOURCE_DIR}/core/unit_test/category_files) SET(COMPILE_ONLY_SOURCES TestArray.cpp + TestCreateMirror.cpp TestDetectionIdiom.cpp TestInterOp.cpp TestLegionInteroperability.cpp @@ -86,6 +87,7 @@ ENDIF() KOKKOS_ADD_EXECUTABLE( TestCompileOnly SOURCES + TestCompileMain.cpp ${COMPILE_ONLY_SOURCES} ) diff --git a/packages/kokkos/core/unit_test/TestCompileMain.cpp b/packages/kokkos/core/unit_test/TestCompileMain.cpp new file mode 100644 index 0000000000000000000000000000000000000000..237c8ce181774d991a9dbdd8cacf1a5fb9f199f1 --- /dev/null +++ b/packages/kokkos/core/unit_test/TestCompileMain.cpp @@ -0,0 +1 @@ +int main() {} diff --git a/packages/kokkos/core/unit_test/TestCreateMirror.cpp b/packages/kokkos/core/unit_test/TestCreateMirror.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e8b3b6ea105950267a862a78ebcb632120e74f66 --- /dev/null +++ b/packages/kokkos/core/unit_test/TestCreateMirror.cpp @@ -0,0 +1,126 @@ +/* +//@HEADER +// ************************************************************************ +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, +// the U.S. Government retains certain rights in this software. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the Corporation nor the names of the +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Questions? Contact Christian R. Trott (crtrott@sandia.gov) +// +// ************************************************************************ +//@HEADER +*/ + +#include <Kokkos_Core.hpp> + +template <typename TestView, typename MemorySpace> +void check_memory_space(TestView, MemorySpace) { + static_assert( + std::is_same<typename TestView::memory_space, MemorySpace>::value, ""); +} + +template <class View> +auto host_mirror_test_space(View) { + return std::conditional_t< + Kokkos::SpaceAccessibility<Kokkos::HostSpace, + typename View::memory_space>::accessible, + typename View::memory_space, Kokkos::HostSpace>{}; +} + +template <typename View> +void test_create_mirror_properties(const View& view) { + using namespace Kokkos; + using DeviceMemorySpace = typename DefaultExecutionSpace::memory_space; + + // clang-format off + + // create_mirror + check_memory_space(create_mirror(WithoutInitializing, view), host_mirror_test_space(view)); + check_memory_space(create_mirror( view), host_mirror_test_space(view)); + check_memory_space(create_mirror(WithoutInitializing, DefaultExecutionSpace{}, view), DeviceMemorySpace{}); + check_memory_space(create_mirror( DefaultExecutionSpace{}, view), DeviceMemorySpace{}); + + // create_mirror_view + check_memory_space(create_mirror_view(WithoutInitializing, view), host_mirror_test_space(view)); + check_memory_space(create_mirror_view( view), host_mirror_test_space(view)); + check_memory_space(create_mirror_view(WithoutInitializing, DefaultExecutionSpace{}, view), DeviceMemorySpace{}); + check_memory_space(create_mirror_view( DefaultExecutionSpace{}, view), DeviceMemorySpace{}); + + // create_mirror view_alloc + check_memory_space(create_mirror(view_alloc(WithoutInitializing), view), host_mirror_test_space(view)); + check_memory_space(create_mirror(view_alloc(), view), host_mirror_test_space(view)); + check_memory_space(create_mirror(view_alloc(WithoutInitializing, DeviceMemorySpace{}), view), DeviceMemorySpace{}); + check_memory_space(create_mirror(view_alloc( DeviceMemorySpace{}), view), DeviceMemorySpace{}); + + // create_mirror_view view_alloc + check_memory_space(create_mirror_view(view_alloc(WithoutInitializing), view), host_mirror_test_space(view)); + check_memory_space(create_mirror_view(view_alloc(), view), host_mirror_test_space(view)); + check_memory_space(create_mirror_view(view_alloc(WithoutInitializing, DeviceMemorySpace{}), view), DeviceMemorySpace{}); + check_memory_space(create_mirror_view(view_alloc( DeviceMemorySpace{}), view), DeviceMemorySpace{}); + + // create_mirror view_alloc + execution space + check_memory_space(create_mirror(view_alloc(DefaultExecutionSpace{}, WithoutInitializing), view), host_mirror_test_space(view)); + check_memory_space(create_mirror(view_alloc(DefaultHostExecutionSpace{}), view), host_mirror_test_space(view)); + check_memory_space(create_mirror(view_alloc(DefaultExecutionSpace{}, WithoutInitializing, DeviceMemorySpace{}), view), DeviceMemorySpace{}); + check_memory_space(create_mirror(view_alloc(DefaultExecutionSpace{}, DeviceMemorySpace{}), view), DeviceMemorySpace{}); + + // create_mirror_view view_alloc + execution space + check_memory_space(create_mirror_view(view_alloc(DefaultExecutionSpace{}, WithoutInitializing), view), host_mirror_test_space(view)); + check_memory_space(create_mirror_view(view_alloc(DefaultHostExecutionSpace{}), view), host_mirror_test_space(view)); + check_memory_space(create_mirror_view(view_alloc(DefaultExecutionSpace{}, WithoutInitializing, DeviceMemorySpace{}), view), DeviceMemorySpace{}); + check_memory_space(create_mirror_view(view_alloc(DefaultExecutionSpace{}, DeviceMemorySpace{}), view), DeviceMemorySpace{}); + + // create_mirror_view_and_copy + check_memory_space(create_mirror_view_and_copy(HostSpace{}, view), HostSpace{}); + check_memory_space(create_mirror_view_and_copy(DeviceMemorySpace{}, view), DeviceMemorySpace{}); + + // create_mirror_view_and_copy view_alloc + check_memory_space(create_mirror_view_and_copy(view_alloc(HostSpace{}), view), HostSpace{}); + check_memory_space(create_mirror_view_and_copy(view_alloc(DeviceMemorySpace{}), view), DeviceMemorySpace{}); + + // create_mirror_view_and_copy view_alloc + execution space + check_memory_space(create_mirror_view_and_copy(view_alloc(HostSpace{}, DefaultHostExecutionSpace{}), view), HostSpace{}); + check_memory_space(create_mirror_view_and_copy(view_alloc(DeviceMemorySpace{}, DefaultExecutionSpace{}), view), DeviceMemorySpace{}); + + // clang-format on +} + +void test() { + Kokkos::View<int*, Kokkos::DefaultExecutionSpace> device_view("device view", + 10); + Kokkos::View<int*, Kokkos::HostSpace> host_view("host view", 10); + + test_create_mirror_properties(device_view); + test_create_mirror_properties(host_view); +} diff --git a/packages/kokkos/core/unit_test/TestDetectionIdiom.cpp b/packages/kokkos/core/unit_test/TestDetectionIdiom.cpp index f87fda615643c5a75ef5ee4da7349bab0eea40cd..23da339cae03246084c0e67e8781d08972fb864e 100644 --- a/packages/kokkos/core/unit_test/TestDetectionIdiom.cpp +++ b/packages/kokkos/core/unit_test/TestDetectionIdiom.cpp @@ -92,5 +92,3 @@ static_assert(std::is_same<difference_type<Woof>, int>::value, static_assert(std::is_same<difference_type<Bark>, std::ptrdiff_t>::value, "Bark's difference_type should be ptrdiff_t!"); } // namespace Example - -int main() {} diff --git a/packages/kokkos/core/unit_test/TestScan.hpp b/packages/kokkos/core/unit_test/TestScan.hpp index 1a4056af07d3f9584b105cd536e5abca051b30c2..356ffde9565aaf40035e033748056cbb3028f678 100644 --- a/packages/kokkos/core/unit_test/TestScan.hpp +++ b/packages/kokkos/core/unit_test/TestScan.hpp @@ -45,20 +45,23 @@ #include <Kokkos_Core.hpp> #include <cstdio> -namespace Test { +namespace { -template <class Device> +template <class Device, class T, T ImbalanceSz> struct TestScan { using execution_space = Device; - using value_type = int64_t; + using value_type = T; Kokkos::View<int, Device, Kokkos::MemoryTraits<Kokkos::Atomic> > errors; KOKKOS_INLINE_FUNCTION void operator()(const int iwork, value_type& update, const bool final_pass) const { - const value_type n = iwork + 1; - const value_type imbalance = ((1000 <= n) && (0 == n % 1000)) ? 1000 : 0; + const value_type n = iwork + 1; + const value_type imbalance = + ((ImbalanceSz <= n) && (value_type(0) == n % ImbalanceSz)) + ? ImbalanceSz + : value_type(0); // Insert an artificial load imbalance @@ -133,12 +136,29 @@ struct TestScan { } } }; +} // namespace TEST(TEST_CATEGORY, scan) { - TestScan<TEST_EXECSPACE>::test_range(1, 1000); - TestScan<TEST_EXECSPACE>(0); - TestScan<TEST_EXECSPACE>(100000); - TestScan<TEST_EXECSPACE>(10000000); - TEST_EXECSPACE().fence(); + constexpr auto imbalance_size = 1000; + TestScan<TEST_EXECSPACE, int64_t, imbalance_size>::test_range(1, 1000); + TestScan<TEST_EXECSPACE, int64_t, imbalance_size>(0); + TestScan<TEST_EXECSPACE, int64_t, imbalance_size>(100000); + TestScan<TEST_EXECSPACE, int64_t, imbalance_size>(10000000); +} + +TEST(TEST_CATEGORY, small_size_scan) { + constexpr auto imbalance_size = 10; // Pick to not overflow... + TestScan<TEST_EXECSPACE, std::int8_t, imbalance_size>(0); + TestScan<TEST_EXECSPACE, std::int8_t, imbalance_size>(5); + TestScan<TEST_EXECSPACE, std::int8_t, imbalance_size>(10); + TestScan<TEST_EXECSPACE, std::int8_t, imbalance_size>( + static_cast<std::size_t>( + std::sqrt(std::numeric_limits<std::int8_t>::max()))); + constexpr auto short_imbalance_size = 100; // Pick to not overflow... + TestScan<TEST_EXECSPACE, std::int16_t, short_imbalance_size>(0); + TestScan<TEST_EXECSPACE, std::int16_t, short_imbalance_size>(5); + TestScan<TEST_EXECSPACE, std::int16_t, short_imbalance_size>(100); + TestScan<TEST_EXECSPACE, std::int16_t, short_imbalance_size>( + static_cast<std::size_t>( + std::sqrt(std::numeric_limits<std::int16_t>::max()))); } -} // namespace Test diff --git a/packages/kokkos/core/unit_test/TestTeam.hpp b/packages/kokkos/core/unit_test/TestTeam.hpp index f1d0f9cb3b8a37f35f9b4962e2f183f26701072c..3f05b2ef66a04783a94f854259253cb984411819 100644 --- a/packages/kokkos/core/unit_test/TestTeam.hpp +++ b/packages/kokkos/core/unit_test/TestTeam.hpp @@ -1616,6 +1616,73 @@ struct TestTeamPolicyHandleByValue { } // namespace +namespace { +template <typename ExecutionSpace> +struct TestRepeatedTeamReduce { + static constexpr int ncol = 1500; // nothing special, just some work + + KOKKOS_FUNCTION void operator()( + const typename Kokkos::TeamPolicy<ExecutionSpace>::member_type &team) + const { + // non-divisible by power of two to make triggering problems easier + constexpr int nlev = 129; + constexpr auto pi = Kokkos::Experimental::pi_v<double>; + double b = 0.; + for (int ri = 0; ri < 10; ++ri) { + // The contributions here must be sufficiently complex, simply adding ones + // wasn't enough to trigger the bug. + const auto g1 = [&](const int k, double &acc) { + acc += Kokkos::cos(pi * double(k) / nlev); + }; + const auto g2 = [&](const int k, double &acc) { + acc += Kokkos::sin(pi * double(k) / nlev); + }; + double a1, a2; + Kokkos::parallel_reduce(Kokkos::TeamThreadRange(team, nlev), g1, a1); + Kokkos::parallel_reduce(Kokkos::TeamThreadRange(team, nlev), g2, a2); + b += a1; + b += a2; + } + const auto h = [&]() { + const auto col = team.league_rank(); + v(col) = b + col; + }; + Kokkos::single(Kokkos::PerTeam(team), h); + } + + KOKKOS_FUNCTION void operator()(const int i, int &bad) const { + if (v(i) != v(0) + i) { + ++bad; + KOKKOS_IMPL_DO_NOT_USE_PRINTF("Failing at %d!\n", i); + } + } + + TestRepeatedTeamReduce() : v("v", ncol) { test(); } + + void test() { + int team_size_recommended = + Kokkos::TeamPolicy<ExecutionSpace>(1, 1).team_size_recommended( + *this, Kokkos::ParallelForTag()); + // Choose a non-recommened (non-power of two for GPUs) team size + int team_size = team_size_recommended > 1 ? team_size_recommended - 1 : 1; + + // The failure was non-deterministic so run the test a bunch of times + for (int it = 0; it < 100; ++it) { + Kokkos::parallel_for( + Kokkos::TeamPolicy<ExecutionSpace>(ncol, team_size, 1), *this); + + int bad = 0; + Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecutionSpace>(0, ncol), + *this, bad); + ASSERT_EQ(bad, 0) << " Failing in iteration " << it; + } + } + + Kokkos::View<double *, ExecutionSpace> v; +}; + +} // namespace + } // namespace Test /*--------------------------------------------------------------------------*/ diff --git a/packages/kokkos/core/unit_test/TestTeamReductionScan.hpp b/packages/kokkos/core/unit_test/TestTeamReductionScan.hpp index 469bba23b73ee9bd316f7c2fbcd9389144f03e12..4d4f3b1f4d34eeae219b9436922162f7279ac8ca 100644 --- a/packages/kokkos/core/unit_test/TestTeamReductionScan.hpp +++ b/packages/kokkos/core/unit_test/TestTeamReductionScan.hpp @@ -134,5 +134,15 @@ TEST(TEST_CATEGORY, team_parallel_dummy_with_reducer_and_scratch_space) { } } +TEST(TEST_CATEGORY, repeated_team_reduce) { +#ifdef KOKKOS_ENABLE_OPENMPTARGET + if (std::is_same<TEST_EXECSPACE, Kokkos::Experimental::OpenMPTarget>::value) + GTEST_SKIP() << "skipping since team_reduce for OpenMPTarget is not " + "properly implemented"; +#endif + + TestRepeatedTeamReduce<TEST_EXECSPACE>(); +} + } // namespace Test #endif diff --git a/packages/kokkos/core/unit_test/TestViewIsAssignable.hpp b/packages/kokkos/core/unit_test/TestViewIsAssignable.hpp index 03c3b977edeab7ec5b51c406da65b0e089f5a0de..3ac392d3e98860fe536a07fbff43cc7d5fc1aecd 100644 --- a/packages/kokkos/core/unit_test/TestViewIsAssignable.hpp +++ b/packages/kokkos/core/unit_test/TestViewIsAssignable.hpp @@ -92,8 +92,18 @@ TEST(TEST_CATEGORY, view_is_assignable) { View<double*, left, d_exec>>::test(false, false, 10); // Layout assignment + Impl::TestAssignability<View<int, left, d_exec>, + View<int, right, d_exec>>::test(true, true); Impl::TestAssignability<View<int*, left, d_exec>, View<int*, right, d_exec>>::test(true, true, 10); + Impl::TestAssignability<View<int[5], left, d_exec>, + View<int*, right, d_exec>>::test(false, false, 10); + Impl::TestAssignability<View<int[10], left, d_exec>, + View<int*, right, d_exec>>::test(false, true, 10); + Impl::TestAssignability<View<int*, left, d_exec>, + View<int[5], right, d_exec>>::test(true, true); + Impl::TestAssignability<View<int[5], left, d_exec>, + View<int[10], right, d_exec>>::test(false, false); // This could be made possible (due to the degenerate nature of the views) but // we do not allow this yet diff --git a/packages/kokkos/master_history.txt b/packages/kokkos/master_history.txt index a1a87ce3199d10449b92be4a8e09ecaa790a303f..bd639c847e03cdd0909fc83ccf6d0843148d6bea 100644 --- a/packages/kokkos/master_history.txt +++ b/packages/kokkos/master_history.txt @@ -29,3 +29,4 @@ tag: 3.5.00 date: 11:19:2021 master: c28a8b03 release: 21b879e4 tag: 3.6.00 date: 04:14:2022 master: 2834f94a release: 6ea708ff tag: 3.6.01 date: 06:16:2022 master: b52f8c83 release: afe9b404 tag: 3.7.00 date: 08:25:2022 master: d19aab99 release: 0018e5fb +tag: 3.7.01 date: 12:01:2022 master: 61d7db55 release: d3bb8cfe diff --git a/packages/kokkos/simd/cmake/Dependencies.cmake b/packages/kokkos/simd/cmake/Dependencies.cmake index 5e29157369c9ab8cab935a1bfc4c6dad2fdd0296..1d71d8af341181f689a6a8bf63036b67584cb138 100644 --- a/packages/kokkos/simd/cmake/Dependencies.cmake +++ b/packages/kokkos/simd/cmake/Dependencies.cmake @@ -1,5 +1,5 @@ TRIBITS_PACKAGE_DEFINE_DEPENDENCIES( LIB_REQUIRED_PACKAGES KokkosCore - LIB_OPTIONAL_TPLS Pthread CUDA HWLOC HPX + LIB_OPTIONAL_TPLS Pthread CUDA HWLOC TEST_OPTIONAL_TPLS CUSPARSE ) diff --git a/packages/kokkos/tpls/desul/include/desul/atomics/Lock_Array_Cuda.hpp b/packages/kokkos/tpls/desul/include/desul/atomics/Lock_Array_Cuda.hpp index 2166fa3cb78e70af887ff7f74e2cac9f141bf1de..1815adb4a7621c8b4b3d93ac626c417f1c42644b 100644 --- a/packages/kokkos/tpls/desul/include/desul/atomics/Lock_Array_Cuda.hpp +++ b/packages/kokkos/tpls/desul/include/desul/atomics/Lock_Array_Cuda.hpp @@ -76,7 +76,7 @@ namespace Impl { /// instances in other translation units, we must update this CUDA global /// variable based on the Host global variable prior to running any kernels /// that will use it. -/// That is the purpose of the ensure_cuda_lock_arrays_on_device function. +/// That is the purpose of the KOKKOS_ENSURE_CUDA_LOCK_ARRAYS_ON_DEVICE macro. __device__ #ifdef __CUDACC_RDC__ __constant__ extern @@ -138,42 +138,33 @@ namespace { static int lock_array_copied = 0; inline int eliminate_warning_for_lock_array() { return lock_array_copied; } } // namespace - -#ifdef __CUDACC_RDC__ -inline -#else -static -#endif - void - copy_cuda_lock_arrays_to_device() { - if (lock_array_copied == 0) { - cudaMemcpyToSymbol(CUDA_SPACE_ATOMIC_LOCKS_DEVICE, - &CUDA_SPACE_ATOMIC_LOCKS_DEVICE_h, - sizeof(int32_t*)); - cudaMemcpyToSymbol(CUDA_SPACE_ATOMIC_LOCKS_NODE, - &CUDA_SPACE_ATOMIC_LOCKS_NODE_h, - sizeof(int32_t*)); - } - lock_array_copied = 1; -} - } // namespace Impl } // namespace desul +/* It is critical that this code be a macro, so that it will + capture the right address for desul::Impl::CUDA_SPACE_ATOMIC_LOCKS_DEVICE + putting this in an inline function will NOT do the right thing! */ +#define DESUL_IMPL_COPY_CUDA_LOCK_ARRAYS_TO_DEVICE() \ + { \ + if (::desul::Impl::lock_array_copied == 0) { \ + cudaMemcpyToSymbol(::desul::Impl::CUDA_SPACE_ATOMIC_LOCKS_DEVICE, \ + &::desul::Impl::CUDA_SPACE_ATOMIC_LOCKS_DEVICE_h, \ + sizeof(int32_t*)); \ + cudaMemcpyToSymbol(::desul::Impl::CUDA_SPACE_ATOMIC_LOCKS_NODE, \ + &::desul::Impl::CUDA_SPACE_ATOMIC_LOCKS_NODE_h, \ + sizeof(int32_t*)); \ + } \ + ::desul::Impl::lock_array_copied = 1; \ + } #endif /* defined( __CUDACC__ ) */ #endif /* defined( DESUL_HAVE_CUDA_ATOMICS ) */ -namespace desul { - #if defined(__CUDACC_RDC__) || (!defined(__CUDACC__)) -inline void ensure_cuda_lock_arrays_on_device() {} +#define DESUL_ENSURE_CUDA_LOCK_ARRAYS_ON_DEVICE() #else -static inline void ensure_cuda_lock_arrays_on_device() { - Impl::copy_cuda_lock_arrays_to_device(); -} +#define DESUL_ENSURE_CUDA_LOCK_ARRAYS_ON_DEVICE() \ + DESUL_IMPL_COPY_CUDA_LOCK_ARRAYS_TO_DEVICE() #endif -} // namespace desul - -#endif /* #ifndef DESUL_ATOMICS_LOCK_ARRAY_CUDA_HPP_ */ +#endif /* #ifndef KOKKOS_CUDA_LOCKS_HPP_ */ diff --git a/packages/kokkos/tpls/desul/src/Lock_Array_CUDA.cpp b/packages/kokkos/tpls/desul/src/Lock_Array_CUDA.cpp index 19944b378e2c47090dbe3ce28913017a3f308933..cb8482c5da8b83bb1fc6323dea09fffce86d115b 100644 --- a/packages/kokkos/tpls/desul/src/Lock_Array_CUDA.cpp +++ b/packages/kokkos/tpls/desul/src/Lock_Array_CUDA.cpp @@ -70,7 +70,7 @@ void init_lock_arrays_cuda() { "init_lock_arrays_cuda: cudaMalloc host locks"); auto error_sync1 = cudaDeviceSynchronize(); - copy_cuda_lock_arrays_to_device(); + DESUL_IMPL_COPY_CUDA_LOCK_ARRAYS_TO_DEVICE(); check_error_and_throw_cuda(error_sync1, "init_lock_arrays_cuda: post mallocs"); init_lock_arrays_cuda_kernel<<<(CUDA_SPACE_ATOMIC_MASK + 1 + 255) / 256, 256>>>(); auto error_sync2 = cudaDeviceSynchronize(); @@ -85,7 +85,7 @@ void finalize_lock_arrays_cuda() { CUDA_SPACE_ATOMIC_LOCKS_DEVICE_h = nullptr; CUDA_SPACE_ATOMIC_LOCKS_NODE_h = nullptr; #ifdef __CUDACC_RDC__ - copy_cuda_lock_arrays_to_device(); + DESUL_IMPL_COPY_CUDA_LOCK_ARRAYS_TO_DEVICE(); #endif } diff --git a/src/algebra/TinyMatrix.hpp b/src/algebra/TinyMatrix.hpp index e34f98ed8c25df7a77ba90bbd7cd05305b5eb115..1717b48c78deaedc7cabd9f60feb215e29a80ebe 100644 --- a/src/algebra/TinyMatrix.hpp +++ b/src/algebra/TinyMatrix.hpp @@ -21,16 +21,21 @@ class [[nodiscard]] TinyMatrix using data_type = T; private: + static_assert((M > 0), "TinyMatrix number of rows must be strictly positive"); + static_assert((N > 0), "TinyMatrix number of columns must be strictly positive"); + T m_values[M * N]; PUGS_FORCEINLINE - constexpr size_t _index(size_t i, size_t j) const noexcept // LCOV_EXCL_LINE (due to forced inline) + constexpr size_t + _index(size_t i, size_t j) const noexcept // LCOV_EXCL_LINE (due to forced inline) { return i * N + j; } template <typename... Args> - PUGS_FORCEINLINE constexpr void _unpackVariadicInput(const T& t, Args&&... args) noexcept + PUGS_FORCEINLINE constexpr void + _unpackVariadicInput(const T& t, Args&&... args) noexcept { m_values[M * N - 1 - sizeof...(args)] = t; if constexpr (sizeof...(args) > 0) { @@ -40,13 +45,15 @@ class [[nodiscard]] TinyMatrix public: PUGS_INLINE - constexpr bool isSquare() const noexcept + constexpr bool + isSquare() const noexcept { return M == N; } PUGS_INLINE - constexpr friend TinyMatrix<N, M, T> transpose(const TinyMatrix& A) + constexpr friend TinyMatrix<N, M, T> + transpose(const TinyMatrix& A) { TinyMatrix<N, M, T> tA; for (size_t i = 0; i < M; ++i) { @@ -58,31 +65,36 @@ class [[nodiscard]] TinyMatrix } PUGS_INLINE - constexpr size_t dimension() const + constexpr size_t + dimension() const { return M * N; } PUGS_INLINE - constexpr size_t numberOfValues() const + constexpr size_t + numberOfValues() const { return this->dimension(); } PUGS_INLINE - constexpr size_t numberOfRows() const + constexpr size_t + numberOfRows() const { return M; } PUGS_INLINE - constexpr size_t numberOfColumns() const + constexpr size_t + numberOfColumns() const { return N; } PUGS_INLINE - constexpr TinyMatrix operator-() const + constexpr TinyMatrix + operator-() const { TinyMatrix opposite; for (size_t i = 0; i < M * N; ++i) { @@ -92,20 +104,23 @@ class [[nodiscard]] TinyMatrix } PUGS_INLINE - constexpr friend TinyMatrix operator*(const T& t, const TinyMatrix& A) + constexpr friend TinyMatrix + operator*(const T& t, const TinyMatrix& A) { TinyMatrix B = A; return B *= t; } PUGS_INLINE - constexpr friend TinyMatrix operator*(const T& t, TinyMatrix&& A) + constexpr friend TinyMatrix + operator*(const T& t, TinyMatrix&& A) { return std::move(A *= t); } PUGS_INLINE - constexpr TinyMatrix& operator*=(const T& t) + constexpr TinyMatrix& + operator*=(const T& t) { for (size_t i = 0; i < M * N; ++i) { m_values[i] *= t; @@ -114,7 +129,8 @@ class [[nodiscard]] TinyMatrix } template <size_t P> - PUGS_INLINE constexpr TinyMatrix<M, P, T> operator*(const TinyMatrix<N, P, T>& B) const + PUGS_INLINE constexpr TinyMatrix<M, P, T> + operator*(const TinyMatrix<N, P, T>& B) const { const TinyMatrix& A = *this; TinyMatrix<M, P, T> AB; @@ -131,7 +147,8 @@ class [[nodiscard]] TinyMatrix } PUGS_INLINE - constexpr TinyVector<M, T> operator*(const TinyVector<N, T>& x) const + constexpr TinyVector<M, T> + operator*(const TinyVector<N, T>& x) const { const TinyMatrix& A = *this; TinyVector<M, T> Ax; @@ -146,7 +163,8 @@ class [[nodiscard]] TinyMatrix } PUGS_INLINE - constexpr friend std::ostream& operator<<(std::ostream& os, const TinyMatrix& A) + constexpr friend std::ostream& + operator<<(std::ostream& os, const TinyMatrix& A) { os << '['; for (size_t i = 0; i < M; ++i) { @@ -165,7 +183,8 @@ class [[nodiscard]] TinyMatrix } PUGS_INLINE - constexpr bool operator==(const TinyMatrix& A) const + constexpr bool + operator==(const TinyMatrix& A) const { for (size_t i = 0; i < M * N; ++i) { if (m_values[i] != A.m_values[i]) @@ -175,13 +194,15 @@ class [[nodiscard]] TinyMatrix } PUGS_INLINE - constexpr bool operator!=(const TinyMatrix& A) const + constexpr bool + operator!=(const TinyMatrix& A) const { return not this->operator==(A); } PUGS_INLINE - constexpr TinyMatrix operator+(const TinyMatrix& A) const + constexpr TinyMatrix + operator+(const TinyMatrix& A) const { TinyMatrix sum; for (size_t i = 0; i < M * N; ++i) { @@ -191,14 +212,16 @@ class [[nodiscard]] TinyMatrix } PUGS_INLINE - constexpr TinyMatrix operator+(TinyMatrix&& A) const + constexpr TinyMatrix + operator+(TinyMatrix&& A) const { A += *this; return std::move(A); } PUGS_INLINE - constexpr TinyMatrix operator-(const TinyMatrix& A) const + constexpr TinyMatrix + operator-(const TinyMatrix& A) const { TinyMatrix difference; for (size_t i = 0; i < M * N; ++i) { @@ -208,7 +231,8 @@ class [[nodiscard]] TinyMatrix } PUGS_INLINE - constexpr TinyMatrix operator-(TinyMatrix&& A) const + constexpr TinyMatrix + operator-(TinyMatrix&& A) const { for (size_t i = 0; i < M * N; ++i) { A.m_values[i] = m_values[i] - A.m_values[i]; @@ -217,7 +241,8 @@ class [[nodiscard]] TinyMatrix } PUGS_INLINE - constexpr TinyMatrix& operator+=(const TinyMatrix& A) + constexpr TinyMatrix& + operator+=(const TinyMatrix& A) { for (size_t i = 0; i < M * N; ++i) { m_values[i] += A.m_values[i]; @@ -226,7 +251,8 @@ class [[nodiscard]] TinyMatrix } PUGS_INLINE - constexpr void operator+=(const volatile TinyMatrix& A) volatile + constexpr void + operator+=(const volatile TinyMatrix& A) volatile { for (size_t i = 0; i < M * N; ++i) { m_values[i] += A.m_values[i]; @@ -234,7 +260,8 @@ class [[nodiscard]] TinyMatrix } PUGS_INLINE - constexpr TinyMatrix& operator-=(const TinyMatrix& A) + constexpr TinyMatrix& + operator-=(const TinyMatrix& A) { for (size_t i = 0; i < M * N; ++i) { m_values[i] -= A.m_values[i]; @@ -243,21 +270,24 @@ class [[nodiscard]] TinyMatrix } PUGS_INLINE - constexpr T& operator()(size_t i, size_t j) noexcept(NO_ASSERT) + constexpr T& + operator()(size_t i, size_t j) noexcept(NO_ASSERT) { Assert((i < M) and (j < N)); return m_values[_index(i, j)]; } PUGS_INLINE - constexpr const T& operator()(size_t i, size_t j) const noexcept(NO_ASSERT) + constexpr const T& + operator()(size_t i, size_t j) const noexcept(NO_ASSERT) { Assert((i < M) and (j < N)); return m_values[_index(i, j)]; } PUGS_INLINE - constexpr TinyMatrix& operator=(ZeroType) noexcept + constexpr TinyMatrix& + operator=(ZeroType) noexcept { static_assert(std::is_arithmetic<T>(), "Cannot assign 'zero' value for non-arithmetic types"); for (size_t i = 0; i < M * N; ++i) { @@ -267,7 +297,8 @@ class [[nodiscard]] TinyMatrix } PUGS_INLINE - constexpr TinyMatrix& operator=(IdentityType) noexcept + constexpr TinyMatrix& + operator=(IdentityType) noexcept { static_assert(std::is_arithmetic<T>(), "Cannot assign 'identity' value for non-arithmetic types"); for (size_t i = 0; i < M; ++i) { @@ -329,7 +360,7 @@ class [[nodiscard]] TinyMatrix constexpr TinyMatrix(const TinyMatrix&) noexcept = default; PUGS_INLINE - TinyMatrix(TinyMatrix && A) noexcept = default; + TinyMatrix(TinyMatrix&& A) noexcept = default; PUGS_INLINE ~TinyMatrix() = default; @@ -450,6 +481,19 @@ getMinor(const TinyMatrix<M, N, T>& A, size_t I, size_t J) return m; } +template <size_t N, typename T> +PUGS_INLINE T +trace(const TinyMatrix<N, N, T>& A) +{ + static_assert(std::is_arithmetic<T>::value, "trace is not defined for non-arithmetic types"); + + T t = A(0, 0); + for (size_t i = 1; i < N; ++i) { + t += A(i, i); + } + return t; +} + template <size_t N, typename T> PUGS_INLINE constexpr TinyMatrix<N, N, T> inverse(const TinyMatrix<N, N, T>& A); diff --git a/src/language/ast/ASTNodeDataTypeFlattener.cpp b/src/language/ast/ASTNodeDataTypeFlattener.cpp index 9cc1fa483196815ed97b3b8134797b79aeea770e..00b77e0bf98e13314fce52396c7a6cef5717254e 100644 --- a/src/language/ast/ASTNodeDataTypeFlattener.cpp +++ b/src/language/ast/ASTNodeDataTypeFlattener.cpp @@ -52,7 +52,7 @@ ASTNodeDataTypeFlattener::ASTNodeDataTypeFlattener(ASTNode& node, FlattenedDataT case ASTNodeDataType::builtin_function_t: { const auto& compound_data_type = getBuiltinFunctionEmbedder(node)->getReturnDataType(); - for (auto data_type : compound_data_type.contentTypeList()) { + for (const auto& data_type : compound_data_type.contentTypeList()) { flattened_datatype_list.push_back({*data_type, node}); } diff --git a/src/language/ast/ASTNodeFunctionExpressionBuilder.cpp b/src/language/ast/ASTNodeFunctionExpressionBuilder.cpp index a381123884250e9cd574495d7c3add369863aa59..656000c69cd45b85bcf72907850230c7e0f9615b 100644 --- a/src/language/ast/ASTNodeFunctionExpressionBuilder.cpp +++ b/src/language/ast/ASTNodeFunctionExpressionBuilder.cpp @@ -15,7 +15,7 @@ ASTNodeFunctionExpressionBuilder::_getArgumentConverter(SymbolType& parameter_sy { const size_t parameter_id = std::get<size_t>(parameter_symbol.attributes().value()); - ASTNodeNaturalConversionChecker{node_sub_data_type, parameter_symbol.attributes().dataType()}; + ASTNodeNaturalConversionChecker<AllowRToR1Conversion>{node_sub_data_type, parameter_symbol.attributes().dataType()}; auto get_function_argument_converter_for = [&](const auto& parameter_v) -> std::unique_ptr<IFunctionArgumentConverter> { @@ -78,13 +78,48 @@ ASTNodeFunctionExpressionBuilder::_getArgumentConverter(SymbolType& parameter_sy // LCOV_EXCL_STOP } } + case ASTNodeDataType::bool_t: { + if ((parameter_v.dimension() == 1)) { + return std::make_unique<FunctionTinyVectorArgumentConverter<ParameterT, bool>>(parameter_id); + } else { + // LCOV_EXCL_START + throw ParseError("unexpected error: invalid argument dimension", + std::vector{node_sub_data_type.m_parent_node.begin()}); + // LCOV_EXCL_STOP + } + } case ASTNodeDataType::int_t: { - if (node_sub_data_type.m_parent_node.is_type<language::integer>()) { + if ((parameter_v.dimension() == 1)) { + return std::make_unique<FunctionTinyVectorArgumentConverter<ParameterT, int64_t>>(parameter_id); + } else if (node_sub_data_type.m_parent_node.is_type<language::integer>()) { if (std::stoi(node_sub_data_type.m_parent_node.string()) == 0) { return std::make_unique<FunctionTinyVectorArgumentConverter<ParameterT, ZeroType>>(parameter_id); } } - [[fallthrough]]; + // LCOV_EXCL_START + throw ParseError("unexpected error: invalid argument type", + std::vector{node_sub_data_type.m_parent_node.begin()}); + // LCOV_EXCL_STOP + } + case ASTNodeDataType::unsigned_int_t: { + if ((parameter_v.dimension() == 1)) { + return std::make_unique<FunctionTinyVectorArgumentConverter<ParameterT, uint64_t>>(parameter_id); + } else { + // LCOV_EXCL_START + throw ParseError("unexpected error: invalid argument dimension", + std::vector{node_sub_data_type.m_parent_node.begin()}); + // LCOV_EXCL_STOP + } + } + case ASTNodeDataType::double_t: { + if ((parameter_v.dimension() == 1)) { + return std::make_unique<FunctionTinyVectorArgumentConverter<ParameterT, double>>(parameter_id); + } else { + // LCOV_EXCL_START + throw ParseError("unexpected error: invalid argument dimension", + std::vector{node_sub_data_type.m_parent_node.begin()}); + // LCOV_EXCL_STOP + } } // LCOV_EXCL_START default: { @@ -110,13 +145,48 @@ ASTNodeFunctionExpressionBuilder::_getArgumentConverter(SymbolType& parameter_sy // LCOV_EXCL_STOP } } + case ASTNodeDataType::bool_t: { + if ((parameter_v.numberOfRows() == 1) and (parameter_v.numberOfColumns() == 1)) { + return std::make_unique<FunctionTinyMatrixArgumentConverter<ParameterT, bool>>(parameter_id); + } else { + // LCOV_EXCL_START + throw ParseError("unexpected error: invalid argument type", + std::vector{node_sub_data_type.m_parent_node.begin()}); + // LCOV_EXCL_STOP + } + } case ASTNodeDataType::int_t: { - if (node_sub_data_type.m_parent_node.is_type<language::integer>()) { + if ((parameter_v.numberOfRows() == 1) and (parameter_v.numberOfColumns() == 1)) { + return std::make_unique<FunctionTinyMatrixArgumentConverter<ParameterT, int64_t>>(parameter_id); + } else if (node_sub_data_type.m_parent_node.is_type<language::integer>()) { if (std::stoi(node_sub_data_type.m_parent_node.string()) == 0) { return std::make_unique<FunctionTinyMatrixArgumentConverter<ParameterT, ZeroType>>(parameter_id); } } - [[fallthrough]]; + // LCOV_EXCL_START + throw ParseError("unexpected error: invalid argument type", + std::vector{node_sub_data_type.m_parent_node.begin()}); + // LCOV_EXCL_STOP + } + case ASTNodeDataType::unsigned_int_t: { + if ((parameter_v.numberOfRows() == 1) and (parameter_v.numberOfColumns() == 1)) { + return std::make_unique<FunctionTinyMatrixArgumentConverter<ParameterT, uint64_t>>(parameter_id); + } else { + // LCOV_EXCL_START + throw ParseError("unexpected error: invalid argument type", + std::vector{node_sub_data_type.m_parent_node.begin()}); + // LCOV_EXCL_STOP + } + } + case ASTNodeDataType::double_t: { + if ((parameter_v.numberOfRows() == 1) and (parameter_v.numberOfColumns() == 1)) { + return std::make_unique<FunctionTinyMatrixArgumentConverter<ParameterT, double>>(parameter_id); + } else { + // LCOV_EXCL_START + throw ParseError("unexpected error: invalid argument type", + std::vector{node_sub_data_type.m_parent_node.begin()}); + // LCOV_EXCL_STOP + } } // LCOV_EXCL_START default: { diff --git a/src/language/modules/BinaryOperatorRegisterForVh.cpp b/src/language/modules/BinaryOperatorRegisterForVh.cpp index 675d84772cc9764df42be29b8be9a03de77c6858..3eb83537323d91bbf6266cbefebf4d004d74c2be 100644 --- a/src/language/modules/BinaryOperatorRegisterForVh.cpp +++ b/src/language/modules/BinaryOperatorRegisterForVh.cpp @@ -4,9 +4,8 @@ #include <language/utils/BinaryOperatorProcessorBuilder.hpp> #include <language/utils/DataHandler.hpp> #include <language/utils/DataVariant.hpp> -#include <language/utils/EmbeddedIDiscreteFunctionOperators.hpp> +#include <language/utils/EmbeddedDiscreteFunctionOperators.hpp> #include <language/utils/OperatorRepository.hpp> -#include <scheme/IDiscreteFunction.hpp> void BinaryOperatorRegisterForVh::_register_plus() @@ -14,89 +13,89 @@ BinaryOperatorRegisterForVh::_register_plus() OperatorRepository& repository = OperatorRepository::instance(); repository.addBinaryOperator<language::plus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>>>()); repository.addBinaryOperator<language::plus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const IDiscreteFunction>, bool, - std::shared_ptr<const IDiscreteFunction>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const DiscreteFunctionVariant>, + bool, std::shared_ptr<const DiscreteFunctionVariant>>>()); repository.addBinaryOperator<language::plus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const IDiscreteFunction>, - int64_t, std::shared_ptr<const IDiscreteFunction>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const DiscreteFunctionVariant>, + int64_t, std::shared_ptr<const DiscreteFunctionVariant>>>()); repository.addBinaryOperator<language::plus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const IDiscreteFunction>, - uint64_t, std::shared_ptr<const IDiscreteFunction>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const DiscreteFunctionVariant>, + uint64_t, std::shared_ptr<const DiscreteFunctionVariant>>>()); repository.addBinaryOperator<language::plus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const IDiscreteFunction>, double, - std::shared_ptr<const IDiscreteFunction>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const DiscreteFunctionVariant>, + double, std::shared_ptr<const DiscreteFunctionVariant>>>()); repository.addBinaryOperator<language::plus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, bool>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, bool>>()); repository.addBinaryOperator<language::plus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, int64_t>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, int64_t>>()); repository.addBinaryOperator<language::plus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, uint64_t>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, uint64_t>>()); repository.addBinaryOperator<language::plus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, double>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, double>>()); repository.addBinaryOperator<language::plus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const IDiscreteFunction>, - TinyVector<1>, std::shared_ptr<const IDiscreteFunction>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const DiscreteFunctionVariant>, + TinyVector<1>, std::shared_ptr<const DiscreteFunctionVariant>>>()); repository.addBinaryOperator<language::plus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const IDiscreteFunction>, - TinyVector<2>, std::shared_ptr<const IDiscreteFunction>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const DiscreteFunctionVariant>, + TinyVector<2>, std::shared_ptr<const DiscreteFunctionVariant>>>()); repository.addBinaryOperator<language::plus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const IDiscreteFunction>, - TinyVector<3>, std::shared_ptr<const IDiscreteFunction>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const DiscreteFunctionVariant>, + TinyVector<3>, std::shared_ptr<const DiscreteFunctionVariant>>>()); repository.addBinaryOperator<language::plus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const IDiscreteFunction>, - TinyMatrix<1>, std::shared_ptr<const IDiscreteFunction>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const DiscreteFunctionVariant>, + TinyMatrix<1>, std::shared_ptr<const DiscreteFunctionVariant>>>()); repository.addBinaryOperator<language::plus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const IDiscreteFunction>, - TinyMatrix<2>, std::shared_ptr<const IDiscreteFunction>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const DiscreteFunctionVariant>, + TinyMatrix<2>, std::shared_ptr<const DiscreteFunctionVariant>>>()); repository.addBinaryOperator<language::plus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const IDiscreteFunction>, - TinyMatrix<3>, std::shared_ptr<const IDiscreteFunction>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const DiscreteFunctionVariant>, + TinyMatrix<3>, std::shared_ptr<const DiscreteFunctionVariant>>>()); repository.addBinaryOperator<language::plus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, TinyVector<1>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, TinyVector<1>>>()); repository.addBinaryOperator<language::plus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, TinyVector<2>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, TinyVector<2>>>()); repository.addBinaryOperator<language::plus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, TinyVector<3>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, TinyVector<3>>>()); repository.addBinaryOperator<language::plus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, TinyMatrix<1>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, TinyMatrix<1>>>()); repository.addBinaryOperator<language::plus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, TinyMatrix<2>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, TinyMatrix<2>>>()); repository.addBinaryOperator<language::plus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, TinyMatrix<3>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::plus_op, std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, TinyMatrix<3>>>()); } void @@ -105,89 +104,89 @@ BinaryOperatorRegisterForVh::_register_minus() OperatorRepository& repository = OperatorRepository::instance(); repository.addBinaryOperator<language::minus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>>>()); repository.addBinaryOperator<language::minus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const IDiscreteFunction>, bool, - std::shared_ptr<const IDiscreteFunction>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const DiscreteFunctionVariant>, + bool, std::shared_ptr<const DiscreteFunctionVariant>>>()); repository.addBinaryOperator<language::minus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const IDiscreteFunction>, - int64_t, std::shared_ptr<const IDiscreteFunction>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const DiscreteFunctionVariant>, + int64_t, std::shared_ptr<const DiscreteFunctionVariant>>>()); repository.addBinaryOperator<language::minus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const IDiscreteFunction>, - uint64_t, std::shared_ptr<const IDiscreteFunction>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const DiscreteFunctionVariant>, + uint64_t, std::shared_ptr<const DiscreteFunctionVariant>>>()); repository.addBinaryOperator<language::minus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const IDiscreteFunction>, - double, std::shared_ptr<const IDiscreteFunction>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const DiscreteFunctionVariant>, + double, std::shared_ptr<const DiscreteFunctionVariant>>>()); repository.addBinaryOperator<language::minus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, bool>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, bool>>()); repository.addBinaryOperator<language::minus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, int64_t>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, int64_t>>()); repository.addBinaryOperator<language::minus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, uint64_t>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, uint64_t>>()); repository.addBinaryOperator<language::minus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, double>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, double>>()); repository.addBinaryOperator<language::minus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const IDiscreteFunction>, - TinyVector<1>, std::shared_ptr<const IDiscreteFunction>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const DiscreteFunctionVariant>, + TinyVector<1>, std::shared_ptr<const DiscreteFunctionVariant>>>()); repository.addBinaryOperator<language::minus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const IDiscreteFunction>, - TinyVector<2>, std::shared_ptr<const IDiscreteFunction>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const DiscreteFunctionVariant>, + TinyVector<2>, std::shared_ptr<const DiscreteFunctionVariant>>>()); repository.addBinaryOperator<language::minus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const IDiscreteFunction>, - TinyVector<3>, std::shared_ptr<const IDiscreteFunction>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const DiscreteFunctionVariant>, + TinyVector<3>, std::shared_ptr<const DiscreteFunctionVariant>>>()); repository.addBinaryOperator<language::minus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const IDiscreteFunction>, - TinyMatrix<1>, std::shared_ptr<const IDiscreteFunction>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const DiscreteFunctionVariant>, + TinyMatrix<1>, std::shared_ptr<const DiscreteFunctionVariant>>>()); repository.addBinaryOperator<language::minus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const IDiscreteFunction>, - TinyMatrix<2>, std::shared_ptr<const IDiscreteFunction>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const DiscreteFunctionVariant>, + TinyMatrix<2>, std::shared_ptr<const DiscreteFunctionVariant>>>()); repository.addBinaryOperator<language::minus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const IDiscreteFunction>, - TinyMatrix<3>, std::shared_ptr<const IDiscreteFunction>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const DiscreteFunctionVariant>, + TinyMatrix<3>, std::shared_ptr<const DiscreteFunctionVariant>>>()); repository.addBinaryOperator<language::minus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, TinyVector<1>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, TinyVector<1>>>()); repository.addBinaryOperator<language::minus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, TinyVector<2>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, TinyVector<2>>>()); repository.addBinaryOperator<language::minus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, TinyVector<3>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, TinyVector<3>>>()); repository.addBinaryOperator<language::minus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, TinyMatrix<1>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, TinyMatrix<1>>>()); repository.addBinaryOperator<language::minus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, TinyMatrix<2>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, TinyMatrix<2>>>()); repository.addBinaryOperator<language::minus_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, TinyMatrix<3>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::minus_op, std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, TinyMatrix<3>>>()); } void @@ -196,77 +195,94 @@ BinaryOperatorRegisterForVh::_register_multiply() OperatorRepository& repository = OperatorRepository::instance(); repository.addBinaryOperator<language::multiply_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::multiply_op, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>>>()); + std::make_shared<BinaryOperatorProcessorBuilder< + language::multiply_op, std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, std::shared_ptr<const DiscreteFunctionVariant>>>()); repository.addBinaryOperator<language::multiply_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::multiply_op, std::shared_ptr<const IDiscreteFunction>, - bool, std::shared_ptr<const IDiscreteFunction>>>()); + std::make_shared< + BinaryOperatorProcessorBuilder<language::multiply_op, std::shared_ptr<const DiscreteFunctionVariant>, bool, + std::shared_ptr<const DiscreteFunctionVariant>>>()); repository.addBinaryOperator<language::multiply_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::multiply_op, std::shared_ptr<const IDiscreteFunction>, - int64_t, std::shared_ptr<const IDiscreteFunction>>>()); + std::make_shared< + BinaryOperatorProcessorBuilder<language::multiply_op, std::shared_ptr<const DiscreteFunctionVariant>, int64_t, + std::shared_ptr<const DiscreteFunctionVariant>>>()); repository.addBinaryOperator<language::multiply_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::multiply_op, std::shared_ptr<const IDiscreteFunction>, - uint64_t, std::shared_ptr<const IDiscreteFunction>>>()); + std::make_shared< + BinaryOperatorProcessorBuilder<language::multiply_op, std::shared_ptr<const DiscreteFunctionVariant>, uint64_t, + std::shared_ptr<const DiscreteFunctionVariant>>>()); repository.addBinaryOperator<language::multiply_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::multiply_op, std::shared_ptr<const IDiscreteFunction>, - double, std::shared_ptr<const IDiscreteFunction>>>()); + std::make_shared< + BinaryOperatorProcessorBuilder<language::multiply_op, std::shared_ptr<const DiscreteFunctionVariant>, double, + std::shared_ptr<const DiscreteFunctionVariant>>>()); repository.addBinaryOperator<language::multiply_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::multiply_op, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, bool>>()); + std::make_shared< + BinaryOperatorProcessorBuilder<language::multiply_op, std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, bool>>()); repository.addBinaryOperator<language::multiply_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::multiply_op, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, int64_t>>()); + std::make_shared< + BinaryOperatorProcessorBuilder<language::multiply_op, std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, int64_t>>()); repository.addBinaryOperator<language::multiply_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::multiply_op, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, uint64_t>>()); + std::make_shared< + BinaryOperatorProcessorBuilder<language::multiply_op, std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, uint64_t>>()); repository.addBinaryOperator<language::multiply_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::multiply_op, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, double>>()); + std::make_shared< + BinaryOperatorProcessorBuilder<language::multiply_op, std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, double>>()); repository.addBinaryOperator<language::multiply_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::multiply_op, std::shared_ptr<const IDiscreteFunction>, - TinyMatrix<1>, std::shared_ptr<const IDiscreteFunction>>>()); + std::make_shared< + BinaryOperatorProcessorBuilder<language::multiply_op, std::shared_ptr<const DiscreteFunctionVariant>, + TinyMatrix<1>, std::shared_ptr<const DiscreteFunctionVariant>>>()); repository.addBinaryOperator<language::multiply_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::multiply_op, std::shared_ptr<const IDiscreteFunction>, - TinyMatrix<2>, std::shared_ptr<const IDiscreteFunction>>>()); + std::make_shared< + BinaryOperatorProcessorBuilder<language::multiply_op, std::shared_ptr<const DiscreteFunctionVariant>, + TinyMatrix<2>, std::shared_ptr<const DiscreteFunctionVariant>>>()); repository.addBinaryOperator<language::multiply_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::multiply_op, std::shared_ptr<const IDiscreteFunction>, - TinyMatrix<3>, std::shared_ptr<const IDiscreteFunction>>>()); + std::make_shared< + BinaryOperatorProcessorBuilder<language::multiply_op, std::shared_ptr<const DiscreteFunctionVariant>, + TinyMatrix<3>, std::shared_ptr<const DiscreteFunctionVariant>>>()); repository.addBinaryOperator<language::multiply_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::multiply_op, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, TinyVector<1>>>()); + std::make_shared< + BinaryOperatorProcessorBuilder<language::multiply_op, std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, TinyVector<1>>>()); repository.addBinaryOperator<language::multiply_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::multiply_op, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, TinyVector<2>>>()); + std::make_shared< + BinaryOperatorProcessorBuilder<language::multiply_op, std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, TinyVector<2>>>()); repository.addBinaryOperator<language::multiply_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::multiply_op, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, TinyVector<3>>>()); + std::make_shared< + BinaryOperatorProcessorBuilder<language::multiply_op, std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, TinyVector<3>>>()); repository.addBinaryOperator<language::multiply_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::multiply_op, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, TinyMatrix<1>>>()); + std::make_shared< + BinaryOperatorProcessorBuilder<language::multiply_op, std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, TinyMatrix<1>>>()); repository.addBinaryOperator<language::multiply_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::multiply_op, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, TinyMatrix<2>>>()); + std::make_shared< + BinaryOperatorProcessorBuilder<language::multiply_op, std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, TinyMatrix<2>>>()); repository.addBinaryOperator<language::multiply_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::multiply_op, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, TinyMatrix<3>>>()); + std::make_shared< + BinaryOperatorProcessorBuilder<language::multiply_op, std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, TinyMatrix<3>>>()); } void @@ -275,21 +291,21 @@ BinaryOperatorRegisterForVh::_register_divide() OperatorRepository& repository = OperatorRepository::instance(); repository.addBinaryOperator<language::divide_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::divide_op, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::divide_op, std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>>>()); repository.addBinaryOperator<language::divide_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::divide_op, std::shared_ptr<const IDiscreteFunction>, - int64_t, std::shared_ptr<const IDiscreteFunction>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::divide_op, std::shared_ptr<const DiscreteFunctionVariant>, + int64_t, std::shared_ptr<const DiscreteFunctionVariant>>>()); repository.addBinaryOperator<language::divide_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::divide_op, std::shared_ptr<const IDiscreteFunction>, - uint64_t, std::shared_ptr<const IDiscreteFunction>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::divide_op, std::shared_ptr<const DiscreteFunctionVariant>, + uint64_t, std::shared_ptr<const DiscreteFunctionVariant>>>()); repository.addBinaryOperator<language::divide_op>( - std::make_shared<BinaryOperatorProcessorBuilder<language::divide_op, std::shared_ptr<const IDiscreteFunction>, - double, std::shared_ptr<const IDiscreteFunction>>>()); + std::make_shared<BinaryOperatorProcessorBuilder<language::divide_op, std::shared_ptr<const DiscreteFunctionVariant>, + double, std::shared_ptr<const DiscreteFunctionVariant>>>()); } BinaryOperatorRegisterForVh::BinaryOperatorRegisterForVh() diff --git a/src/language/modules/MathFunctionRegisterForVh.cpp b/src/language/modules/MathFunctionRegisterForVh.cpp index b15e9796f39f71c266741616db2afe1df2d5b0e1..38dc08b6e4bec82be8cab2666080563bd7cb9736 100644 --- a/src/language/modules/MathFunctionRegisterForVh.cpp +++ b/src/language/modules/MathFunctionRegisterForVh.cpp @@ -2,330 +2,387 @@ #include <language/modules/SchemeModule.hpp> #include <language/utils/BuiltinFunctionEmbedder.hpp> -#include <language/utils/EmbeddedIDiscreteFunctionMathFunctions.hpp> -#include <scheme/IDiscreteFunction.hpp> -#include <scheme/IDiscreteFunctionDescriptor.hpp> +#include <language/utils/EmbeddedDiscreteFunctionMathFunctions.hpp> +#include <scheme/DiscreteFunctionVariant.hpp> MathFunctionRegisterForVh::MathFunctionRegisterForVh(SchemeModule& scheme_module) { scheme_module._addBuiltinFunction("sqrt", std::function( - [](std::shared_ptr<const IDiscreteFunction> a) - -> std::shared_ptr<const IDiscreteFunction> { return sqrt(a); } + [](std::shared_ptr<const DiscreteFunctionVariant> a) + -> std::shared_ptr<const DiscreteFunctionVariant> { return sqrt(a); } )); scheme_module._addBuiltinFunction("abs", std::function( - [](std::shared_ptr<const IDiscreteFunction> a) - -> std::shared_ptr<const IDiscreteFunction> { return abs(a); } + [](std::shared_ptr<const DiscreteFunctionVariant> a) + -> std::shared_ptr<const DiscreteFunctionVariant> { return abs(a); } )); scheme_module._addBuiltinFunction("sin", std::function( - [](std::shared_ptr<const IDiscreteFunction> a) - -> std::shared_ptr<const IDiscreteFunction> { return sin(a); } + [](std::shared_ptr<const DiscreteFunctionVariant> a) + -> std::shared_ptr<const DiscreteFunctionVariant> { return sin(a); } )); scheme_module._addBuiltinFunction("cos", std::function( - [](std::shared_ptr<const IDiscreteFunction> a) - -> std::shared_ptr<const IDiscreteFunction> { return cos(a); } + [](std::shared_ptr<const DiscreteFunctionVariant> a) + -> std::shared_ptr<const DiscreteFunctionVariant> { return cos(a); } )); scheme_module._addBuiltinFunction("tan", std::function( - [](std::shared_ptr<const IDiscreteFunction> a) - -> std::shared_ptr<const IDiscreteFunction> { return tan(a); } + [](std::shared_ptr<const DiscreteFunctionVariant> a) + -> std::shared_ptr<const DiscreteFunctionVariant> { return tan(a); } )); scheme_module._addBuiltinFunction("asin", std::function( - [](std::shared_ptr<const IDiscreteFunction> a) - -> std::shared_ptr<const IDiscreteFunction> { return asin(a); } + [](std::shared_ptr<const DiscreteFunctionVariant> a) + -> std::shared_ptr<const DiscreteFunctionVariant> { return asin(a); } )); scheme_module._addBuiltinFunction("acos", std::function( - [](std::shared_ptr<const IDiscreteFunction> a) - -> std::shared_ptr<const IDiscreteFunction> { return acos(a); } + [](std::shared_ptr<const DiscreteFunctionVariant> a) + -> std::shared_ptr<const DiscreteFunctionVariant> { return acos(a); } )); scheme_module._addBuiltinFunction("atan", std::function( - [](std::shared_ptr<const IDiscreteFunction> a) - -> std::shared_ptr<const IDiscreteFunction> { return atan(a); } + [](std::shared_ptr<const DiscreteFunctionVariant> a) + -> std::shared_ptr<const DiscreteFunctionVariant> { return atan(a); } )); - scheme_module._addBuiltinFunction("atan2", std::function( - - [](std::shared_ptr<const IDiscreteFunction> a, - std::shared_ptr<const IDiscreteFunction> b) - -> std::shared_ptr<const IDiscreteFunction> { return atan2(a, b); } - - )); - - scheme_module._addBuiltinFunction("atan2", std::function( + scheme_module._addBuiltinFunction("atan2", + std::function( - [](double a, std::shared_ptr<const IDiscreteFunction> b) - -> std::shared_ptr<const IDiscreteFunction> { return atan2(a, b); } + [](std::shared_ptr<const DiscreteFunctionVariant> a, + std::shared_ptr<const DiscreteFunctionVariant> b) + -> std::shared_ptr<const DiscreteFunctionVariant> { return atan2(a, b); } - )); + )); scheme_module._addBuiltinFunction("atan2", std::function( - [](std::shared_ptr<const IDiscreteFunction> a, - double b) -> std::shared_ptr<const IDiscreteFunction> { return atan2(a, b); } + [](double a, std::shared_ptr<const DiscreteFunctionVariant> b) + -> std::shared_ptr<const DiscreteFunctionVariant> { return atan2(a, b); } )); + scheme_module._addBuiltinFunction("atan2", std::function( + + [](std::shared_ptr<const DiscreteFunctionVariant> a, + double b) -> std::shared_ptr<const DiscreteFunctionVariant> { + return atan2(a, b); + } + + )); + scheme_module._addBuiltinFunction("sinh", std::function( - [](std::shared_ptr<const IDiscreteFunction> a) - -> std::shared_ptr<const IDiscreteFunction> { return sinh(a); } + [](std::shared_ptr<const DiscreteFunctionVariant> a) + -> std::shared_ptr<const DiscreteFunctionVariant> { return sinh(a); } )); - scheme_module._addBuiltinFunction("std::function", std::function( + scheme_module._addBuiltinFunction("tanh", std::function( - [](std::shared_ptr<const IDiscreteFunction> a) - -> std::shared_ptr<const IDiscreteFunction> { return tanh(a); } + [](std::shared_ptr<const DiscreteFunctionVariant> a) + -> std::shared_ptr<const DiscreteFunctionVariant> { return tanh(a); } - )); + )); scheme_module._addBuiltinFunction("asinh", std::function( - [](std::shared_ptr<const IDiscreteFunction> a) - -> std::shared_ptr<const IDiscreteFunction> { return asinh(a); } + [](std::shared_ptr<const DiscreteFunctionVariant> a) + -> std::shared_ptr<const DiscreteFunctionVariant> { return asinh(a); } )); scheme_module._addBuiltinFunction("acosh", std::function( - [](std::shared_ptr<const IDiscreteFunction> a) - -> std::shared_ptr<const IDiscreteFunction> { return acosh(a); } + [](std::shared_ptr<const DiscreteFunctionVariant> a) + -> std::shared_ptr<const DiscreteFunctionVariant> { return acosh(a); } )); scheme_module._addBuiltinFunction("atanh", std::function( - [](std::shared_ptr<const IDiscreteFunction> a) - -> std::shared_ptr<const IDiscreteFunction> { return atanh(a); } + [](std::shared_ptr<const DiscreteFunctionVariant> a) + -> std::shared_ptr<const DiscreteFunctionVariant> { return atanh(a); } )); scheme_module._addBuiltinFunction("exp", std::function( - [](std::shared_ptr<const IDiscreteFunction> a) - -> std::shared_ptr<const IDiscreteFunction> { return exp(a); } + [](std::shared_ptr<const DiscreteFunctionVariant> a) + -> std::shared_ptr<const DiscreteFunctionVariant> { return exp(a); } )); scheme_module._addBuiltinFunction("log", std::function( - [](std::shared_ptr<const IDiscreteFunction> a) - -> std::shared_ptr<const IDiscreteFunction> { return log(a); } + [](std::shared_ptr<const DiscreteFunctionVariant> a) + -> std::shared_ptr<const DiscreteFunctionVariant> { return log(a); } )); scheme_module._addBuiltinFunction("pow", std::function( - [](double a, std::shared_ptr<const IDiscreteFunction> b) - -> std::shared_ptr<const IDiscreteFunction> { return pow(a, b); } + [](double a, std::shared_ptr<const DiscreteFunctionVariant> b) + -> std::shared_ptr<const DiscreteFunctionVariant> { return pow(a, b); } )); - scheme_module._addBuiltinFunction("pow", - std::function( + scheme_module._addBuiltinFunction("pow", std::function( - [](std::shared_ptr<const IDiscreteFunction> a, - double b) -> std::shared_ptr<const IDiscreteFunction> { return pow(a, b); } + [](std::shared_ptr<const DiscreteFunctionVariant> a, double b) + -> std::shared_ptr<const DiscreteFunctionVariant> { return pow(a, b); } - )); + )); scheme_module._addBuiltinFunction("pow", std::function( - [](std::shared_ptr<const IDiscreteFunction> a, - std::shared_ptr<const IDiscreteFunction> b) - -> std::shared_ptr<const IDiscreteFunction> { return pow(a, b); } + [](std::shared_ptr<const DiscreteFunctionVariant> a, + std::shared_ptr<const DiscreteFunctionVariant> b) + -> std::shared_ptr<const DiscreteFunctionVariant> { return pow(a, b); } )); scheme_module._addBuiltinFunction("dot", std::function( - [](std::shared_ptr<const IDiscreteFunction> a, - std::shared_ptr<const IDiscreteFunction> b) - -> std::shared_ptr<const IDiscreteFunction> { return dot(a, b); } + [](std::shared_ptr<const DiscreteFunctionVariant> a, + std::shared_ptr<const DiscreteFunctionVariant> b) + -> std::shared_ptr<const DiscreteFunctionVariant> { return dot(a, b); } )); scheme_module._addBuiltinFunction("dot", std::function( - [](std::shared_ptr<const IDiscreteFunction> a, const TinyVector<1> b) - -> std::shared_ptr<const IDiscreteFunction> { return dot(a, b); } + [](std::shared_ptr<const DiscreteFunctionVariant> a, const TinyVector<1> b) + -> std::shared_ptr<const DiscreteFunctionVariant> { return dot(a, b); } )); scheme_module._addBuiltinFunction("dot", std::function( - [](std::shared_ptr<const IDiscreteFunction> a, const TinyVector<2> b) - -> std::shared_ptr<const IDiscreteFunction> { return dot(a, b); } + [](std::shared_ptr<const DiscreteFunctionVariant> a, const TinyVector<2> b) + -> std::shared_ptr<const DiscreteFunctionVariant> { return dot(a, b); } )); - scheme_module._addBuiltinFunction("dot", std::function( + scheme_module._addBuiltinFunction("dot", + std::function( - [](std::shared_ptr<const IDiscreteFunction> a, const TinyVector<3>& b) - -> std::shared_ptr<const IDiscreteFunction> { return dot(a, b); } + [](std::shared_ptr<const DiscreteFunctionVariant> a, const TinyVector<3>& b) + -> std::shared_ptr<const DiscreteFunctionVariant> { return dot(a, b); } - )); + )); scheme_module._addBuiltinFunction("dot", std::function( - [](const TinyVector<1> a, std::shared_ptr<const IDiscreteFunction> b) - -> std::shared_ptr<const IDiscreteFunction> { return dot(a, b); } + [](const TinyVector<1> a, std::shared_ptr<const DiscreteFunctionVariant> b) + -> std::shared_ptr<const DiscreteFunctionVariant> { return dot(a, b); } )); scheme_module._addBuiltinFunction("dot", std::function( - [](const TinyVector<2> a, std::shared_ptr<const IDiscreteFunction> b) - -> std::shared_ptr<const IDiscreteFunction> { return dot(a, b); } + [](const TinyVector<2> a, std::shared_ptr<const DiscreteFunctionVariant> b) + -> std::shared_ptr<const DiscreteFunctionVariant> { return dot(a, b); } )); - scheme_module._addBuiltinFunction("dot", std::function( + scheme_module._addBuiltinFunction("dot", + std::function( + + [](const TinyVector<3>& a, std::shared_ptr<const DiscreteFunctionVariant> b) + -> std::shared_ptr<const DiscreteFunctionVariant> { return dot(a, b); } + + )); + + scheme_module._addBuiltinFunction("det", std::function( - [](const TinyVector<3>& a, std::shared_ptr<const IDiscreteFunction> b) - -> std::shared_ptr<const IDiscreteFunction> { return dot(a, b); } + [](std::shared_ptr<const DiscreteFunctionVariant> A) + -> std::shared_ptr<const DiscreteFunctionVariant> { return det(A); } )); + scheme_module._addBuiltinFunction("inverse", + std::function( + + [](std::shared_ptr<const DiscreteFunctionVariant> A) + -> std::shared_ptr<const DiscreteFunctionVariant> { return inverse(A); } + + )); + + scheme_module._addBuiltinFunction("trace", std::function( + + [](std::shared_ptr<const DiscreteFunctionVariant> A) + -> std::shared_ptr<const DiscreteFunctionVariant> { return trace(A); } + + )); + scheme_module._addBuiltinFunction("min", + std::function( + + [](std::shared_ptr<const DiscreteFunctionVariant> a) -> double { return min(a); } + + )); + + scheme_module._addBuiltinFunction("transpose", + std::function( + + [](std::shared_ptr<const DiscreteFunctionVariant> A) + -> std::shared_ptr<const DiscreteFunctionVariant> { return transpose(A); } + + )); + scheme_module._addBuiltinFunction("min", std::function( - [](std::shared_ptr<const IDiscreteFunction> a) -> double { return min(a); } + [](std::shared_ptr<const DiscreteFunctionVariant> a, + std::shared_ptr<const DiscreteFunctionVariant> b) + -> std::shared_ptr<const DiscreteFunctionVariant> { return min(a, b); } )); scheme_module._addBuiltinFunction("min", std::function( - [](std::shared_ptr<const IDiscreteFunction> a, - std::shared_ptr<const IDiscreteFunction> b) - -> std::shared_ptr<const IDiscreteFunction> { return min(a, b); } + [](double a, std::shared_ptr<const DiscreteFunctionVariant> b) + -> std::shared_ptr<const DiscreteFunctionVariant> { return min(a, b); } )); scheme_module._addBuiltinFunction("min", std::function( - [](double a, std::shared_ptr<const IDiscreteFunction> b) - -> std::shared_ptr<const IDiscreteFunction> { return min(a, b); } + [](std::shared_ptr<const DiscreteFunctionVariant> a, double b) + -> std::shared_ptr<const DiscreteFunctionVariant> { return min(a, b); } )); - scheme_module._addBuiltinFunction("min", + scheme_module._addBuiltinFunction("max", std::function( - [](std::shared_ptr<const IDiscreteFunction> a, - double b) -> std::shared_ptr<const IDiscreteFunction> { return min(a, b); } + [](std::shared_ptr<const DiscreteFunctionVariant> a) -> double { return max(a); } )); scheme_module._addBuiltinFunction("max", std::function( - [](std::shared_ptr<const IDiscreteFunction> a) -> double { return max(a); } + [](std::shared_ptr<const DiscreteFunctionVariant> a, + std::shared_ptr<const DiscreteFunctionVariant> b) + -> std::shared_ptr<const DiscreteFunctionVariant> { return max(a, b); } )); scheme_module._addBuiltinFunction("max", std::function( - [](std::shared_ptr<const IDiscreteFunction> a, - std::shared_ptr<const IDiscreteFunction> b) - -> std::shared_ptr<const IDiscreteFunction> { return max(a, b); } + [](double a, std::shared_ptr<const DiscreteFunctionVariant> b) + -> std::shared_ptr<const DiscreteFunctionVariant> { return max(a, b); } )); scheme_module._addBuiltinFunction("max", std::function( - [](double a, std::shared_ptr<const IDiscreteFunction> b) - -> std::shared_ptr<const IDiscreteFunction> { return max(a, b); } + [](std::shared_ptr<const DiscreteFunctionVariant> a, double b) + -> std::shared_ptr<const DiscreteFunctionVariant> { return max(a, b); } )); - scheme_module._addBuiltinFunction("max", + scheme_module._addBuiltinFunction("sum_of_R", std::function( + + [](std::shared_ptr<const DiscreteFunctionVariant> a) -> double { + return sum_of<double>(a); + } + + )); + + scheme_module._addBuiltinFunction("sum_of_R1", std::function( - [](std::shared_ptr<const IDiscreteFunction> a, - double b) -> std::shared_ptr<const IDiscreteFunction> { return max(a, b); } + [](std::shared_ptr<const DiscreteFunctionVariant> a) -> TinyVector<1> { + return sum_of<TinyVector<1>>(a); + } )); - scheme_module._addBuiltinFunction("sum_of_R", std::function( + scheme_module._addBuiltinFunction("sum_of_R2", + std::function( - [](std::shared_ptr<const IDiscreteFunction> a) -> double { - return sum_of<double>(a); - } + [](std::shared_ptr<const DiscreteFunctionVariant> a) -> TinyVector<2> { + return sum_of<TinyVector<2>>(a); + } - )); + )); - scheme_module._addBuiltinFunction("sum_of_R1", std::function( + scheme_module._addBuiltinFunction("sum_of_R3", + std::function( - [](std::shared_ptr<const IDiscreteFunction> a) -> TinyVector<1> { - return sum_of<TinyVector<1>>(a); - } + [](std::shared_ptr<const DiscreteFunctionVariant> a) -> TinyVector<3> { + return sum_of<TinyVector<3>>(a); + } - )); + )); - scheme_module._addBuiltinFunction("sum_of_R2", std::function( + scheme_module._addBuiltinFunction("sum_of_R1x1", + std::function( - [](std::shared_ptr<const IDiscreteFunction> a) -> TinyVector<2> { - return sum_of<TinyVector<2>>(a); - } + [](std::shared_ptr<const DiscreteFunctionVariant> a) -> TinyMatrix<1> { + return sum_of<TinyMatrix<1>>(a); + } - )); + )); - scheme_module._addBuiltinFunction("sum_of_R3", std::function( + scheme_module._addBuiltinFunction("sum_of_R2x2", + std::function( - [](std::shared_ptr<const IDiscreteFunction> a) -> TinyVector<3> { - return sum_of<TinyVector<3>>(a); - } + [](std::shared_ptr<const DiscreteFunctionVariant> a) -> TinyMatrix<2> { + return sum_of<TinyMatrix<2>>(a); + } - )); + )); - scheme_module._addBuiltinFunction("sum_of_R1x1", std::function( + scheme_module._addBuiltinFunction("sum_of_R3x3", + std::function( - [](std::shared_ptr<const IDiscreteFunction> a) -> TinyMatrix<1> { - return sum_of<TinyMatrix<1>>(a); - } + [](std::shared_ptr<const DiscreteFunctionVariant> a) -> TinyMatrix<3> { + return sum_of<TinyMatrix<3>>(a); + } - )); + )); - scheme_module._addBuiltinFunction("sum_of_R2x2", std::function( + scheme_module._addBuiltinFunction("sum_of_Vh", std::function( - [](std::shared_ptr<const IDiscreteFunction> a) -> TinyMatrix<2> { - return sum_of<TinyMatrix<2>>(a); - } + [](std::shared_ptr<const DiscreteFunctionVariant> a) + -> std::shared_ptr<const DiscreteFunctionVariant> { + return sum_of_Vh_components(a); + } - )); + )); - scheme_module._addBuiltinFunction("sum_of_R3x3", std::function( + scheme_module._addBuiltinFunction("vectorize", + std::function( - [](std::shared_ptr<const IDiscreteFunction> a) -> TinyMatrix<3> { - return sum_of<TinyMatrix<3>>(a); - } + [](const std::vector<std::shared_ptr<const DiscreteFunctionVariant>>& + discrete_function_list) -> std::shared_ptr<const DiscreteFunctionVariant> { + return vectorize(discrete_function_list); + } - )); + )); scheme_module._addBuiltinFunction("integral_of_R", std::function( - [](std::shared_ptr<const IDiscreteFunction> a) -> double { + [](std::shared_ptr<const DiscreteFunctionVariant> a) -> double { return integral_of<double>(a); } @@ -334,7 +391,7 @@ MathFunctionRegisterForVh::MathFunctionRegisterForVh(SchemeModule& scheme_module scheme_module._addBuiltinFunction("integral_of_R1", std::function( - [](std::shared_ptr<const IDiscreteFunction> a) -> TinyVector<1> { + [](std::shared_ptr<const DiscreteFunctionVariant> a) -> TinyVector<1> { return integral_of<TinyVector<1>>(a); } @@ -343,7 +400,7 @@ MathFunctionRegisterForVh::MathFunctionRegisterForVh(SchemeModule& scheme_module scheme_module._addBuiltinFunction("integral_of_R2", std::function( - [](std::shared_ptr<const IDiscreteFunction> a) -> TinyVector<2> { + [](std::shared_ptr<const DiscreteFunctionVariant> a) -> TinyVector<2> { return integral_of<TinyVector<2>>(a); } @@ -352,7 +409,7 @@ MathFunctionRegisterForVh::MathFunctionRegisterForVh(SchemeModule& scheme_module scheme_module._addBuiltinFunction("integral_of_R3", std::function( - [](std::shared_ptr<const IDiscreteFunction> a) -> TinyVector<3> { + [](std::shared_ptr<const DiscreteFunctionVariant> a) -> TinyVector<3> { return integral_of<TinyVector<3>>(a); } @@ -361,7 +418,7 @@ MathFunctionRegisterForVh::MathFunctionRegisterForVh(SchemeModule& scheme_module scheme_module._addBuiltinFunction("integral_of_R1x1", std::function( - [](std::shared_ptr<const IDiscreteFunction> a) -> TinyMatrix<1> { + [](std::shared_ptr<const DiscreteFunctionVariant> a) -> TinyMatrix<1> { return integral_of<TinyMatrix<1>>(a); } @@ -370,7 +427,7 @@ MathFunctionRegisterForVh::MathFunctionRegisterForVh(SchemeModule& scheme_module scheme_module._addBuiltinFunction("integral_of_R2x2", std::function( - [](std::shared_ptr<const IDiscreteFunction> a) -> TinyMatrix<2> { + [](std::shared_ptr<const DiscreteFunctionVariant> a) -> TinyMatrix<2> { return integral_of<TinyMatrix<2>>(a); } @@ -379,7 +436,7 @@ MathFunctionRegisterForVh::MathFunctionRegisterForVh(SchemeModule& scheme_module scheme_module._addBuiltinFunction("integral_of_R3x3", std::function( - [](std::shared_ptr<const IDiscreteFunction> a) -> TinyMatrix<3> { + [](std::shared_ptr<const DiscreteFunctionVariant> a) -> TinyMatrix<3> { return integral_of<TinyMatrix<3>>(a); } diff --git a/src/language/modules/MathModule.cpp b/src/language/modules/MathModule.cpp index 4e8e10d1534f55f8c02cccb2f3f48974fdc944d2..4a1e7b35b76a4d9b8b05ebb1355f3cdca4f751d9 100644 --- a/src/language/modules/MathModule.cpp +++ b/src/language/modules/MathModule.cpp @@ -70,6 +70,36 @@ MathModule::MathModule() this->_addBuiltinFunction("dot", std::function([](const TinyVector<3>& x, const TinyVector<3>& y) -> double { return dot(x, y); })); + + this->_addBuiltinFunction("det", std::function([](const TinyMatrix<1> A) -> double { return det(A); })); + + this->_addBuiltinFunction("det", std::function([](const TinyMatrix<2>& A) -> double { return det(A); })); + + this->_addBuiltinFunction("det", std::function([](const TinyMatrix<3>& A) -> double { return det(A); })); + + this->_addBuiltinFunction("trace", std::function([](const TinyMatrix<1> A) -> double { return trace(A); })); + + this->_addBuiltinFunction("trace", std::function([](const TinyMatrix<2>& A) -> double { return trace(A); })); + + this->_addBuiltinFunction("trace", std::function([](const TinyMatrix<3>& A) -> double { return trace(A); })); + + this->_addBuiltinFunction("inverse", + std::function([](const TinyMatrix<1> A) -> TinyMatrix<1> { return inverse(A); })); + + this->_addBuiltinFunction("inverse", + std::function([](const TinyMatrix<2>& A) -> TinyMatrix<2> { return inverse(A); })); + + this->_addBuiltinFunction("inverse", + std::function([](const TinyMatrix<3>& A) -> TinyMatrix<3> { return inverse(A); })); + + this->_addBuiltinFunction("transpose", + std::function([](const TinyMatrix<1> A) -> TinyMatrix<1> { return transpose(A); })); + + this->_addBuiltinFunction("transpose", + std::function([](const TinyMatrix<2>& A) -> TinyMatrix<2> { return transpose(A); })); + + this->_addBuiltinFunction("transpose", + std::function([](const TinyMatrix<3>& A) -> TinyMatrix<3> { return transpose(A); })); } void diff --git a/src/language/modules/MeshModule.cpp b/src/language/modules/MeshModule.cpp index 9c5cf3aec1e11d16f652357db53f68db54f6ed79..af1fca45e7dec5898a12731430358691728c7a2a 100644 --- a/src/language/modules/MeshModule.cpp +++ b/src/language/modules/MeshModule.cpp @@ -12,6 +12,7 @@ #include <language/utils/TypeDescriptor.hpp> #include <mesh/CartesianMeshBuilder.hpp> #include <mesh/Connectivity.hpp> +#include <mesh/ConnectivityUtils.hpp> #include <mesh/DualMeshManager.hpp> #include <mesh/GmshReader.hpp> #include <mesh/IBoundaryDescriptor.hpp> @@ -143,6 +144,37 @@ MeshModule::MeshModule() )); + this->_addBuiltinFunction("check_connectivity_ordering", + std::function( + + [](const std::shared_ptr<const IMesh>& i_mesh) -> bool { + switch (i_mesh->dimension()) { + case 1: { + using MeshType = Mesh<Connectivity<1>>; + + std::shared_ptr p_mesh = std::dynamic_pointer_cast<const MeshType>(i_mesh); + return checkConnectivityOrdering(p_mesh->connectivity()); + } + case 2: { + using MeshType = Mesh<Connectivity<2>>; + + std::shared_ptr p_mesh = std::dynamic_pointer_cast<const MeshType>(i_mesh); + return checkConnectivityOrdering(p_mesh->connectivity()); + } + case 3: { + using MeshType = Mesh<Connectivity<3>>; + + std::shared_ptr p_mesh = std::dynamic_pointer_cast<const MeshType>(i_mesh); + return checkConnectivityOrdering(p_mesh->connectivity()); + } + default: { + throw UnexpectedError("invalid dimension"); + } + } + } + + )); + this->_addBuiltinFunction("cartesianMesh", std::function( diff --git a/src/language/modules/ModuleRepository.cpp b/src/language/modules/ModuleRepository.cpp index 250dc0aad77d999319e3e535a0c42959368493a8..5bdad8bceff609288e318cce8b3f37304afc69b5 100644 --- a/src/language/modules/ModuleRepository.cpp +++ b/src/language/modules/ModuleRepository.cpp @@ -96,7 +96,7 @@ ModuleRepository::_populateSymbolTable(const ASTNode& module_node, const IModule::NameValueMap& name_value_descriptor_map, SymbolTable& symbol_table) { - for (auto [symbol_name, value_descriptor] : name_value_descriptor_map) { + for (const auto& [symbol_name, value_descriptor] : name_value_descriptor_map) { auto [i_symbol, success] = symbol_table.add(symbol_name, module_node.begin()); if (not success) { @@ -139,7 +139,7 @@ ModuleRepository::populateSymbolTable(const ASTNode& module_name_node, SymbolTab this->_populateSymbolTable(module_name_node, module_name, populating_module.getNameValueMap(), symbol_table); - for (auto [symbol_name, embedded] : populating_module.getNameTypeMap()) { + for (const auto& [symbol_name, embedded] : populating_module.getNameTypeMap()) { BasicAffectationRegisterFor<EmbeddedData>(ASTNodeDataType::build<ASTNodeDataType::type_id_t>(symbol_name)); } @@ -163,7 +163,7 @@ ModuleRepository::populateMandatorySymbolTable(const ASTNode& root_node, SymbolT this->_populateSymbolTable(root_node, module_name, i_module->getNameValueMap(), symbol_table); - for (auto [symbol_name, embedded] : i_module->getNameTypeMap()) { + for (const auto& [symbol_name, embedded] : i_module->getNameTypeMap()) { BasicAffectationRegisterFor<EmbeddedData>(ASTNodeDataType::build<ASTNodeDataType::type_id_t>(symbol_name)); } diff --git a/src/language/modules/SchemeModule.cpp b/src/language/modules/SchemeModule.cpp index c1c8eebef320a24ea9c5bcbc2c6ea2bc8b11c579..799a208937f471171e4fb10f2e74600bdfce0f54 100644 --- a/src/language/modules/SchemeModule.cpp +++ b/src/language/modules/SchemeModule.cpp @@ -26,14 +26,15 @@ #include <scheme/DiscreteFunctionInterpoler.hpp> #include <scheme/DiscreteFunctionP0.hpp> #include <scheme/DiscreteFunctionUtils.hpp> +#include <scheme/DiscreteFunctionVariant.hpp> #include <scheme/DiscreteFunctionVectorIntegrator.hpp> #include <scheme/DiscreteFunctionVectorInterpoler.hpp> #include <scheme/ExternalBoundaryConditionDescriptor.hpp> #include <scheme/FixedBoundaryConditionDescriptor.hpp> #include <scheme/FourierBoundaryConditionDescriptor.hpp> #include <scheme/FreeBoundaryConditionDescriptor.hpp> +#include <scheme/HyperelasticSolver.hpp> #include <scheme/IBoundaryConditionDescriptor.hpp> -#include <scheme/IDiscreteFunction.hpp> #include <scheme/IDiscreteFunctionDescriptor.hpp> #include <scheme/NeumannBoundaryConditionDescriptor.hpp> #include <scheme/ScalarDiamondScheme.hpp> @@ -45,7 +46,7 @@ SchemeModule::SchemeModule() { - this->_addTypeDescriptor(ast_node_data_type_from<std::shared_ptr<const IDiscreteFunction>>); + this->_addTypeDescriptor(ast_node_data_type_from<std::shared_ptr<const DiscreteFunctionVariant>>); this->_addTypeDescriptor(ast_node_data_type_from<std::shared_ptr<const IDiscreteFunctionDescriptor>>); this->_addTypeDescriptor(ast_node_data_type_from<std::shared_ptr<const IQuadratureDescriptor>>); @@ -99,11 +100,11 @@ SchemeModule::SchemeModule() std::shared_ptr<const IQuadratureDescriptor> quadrature_descriptor, std::shared_ptr<const IDiscreteFunctionDescriptor> discrete_function_descriptor, const std::vector<FunctionSymbolId>& function_id_list) - -> std::shared_ptr<const IDiscreteFunction> { - return DiscreteFunctionVectorIntegrator{mesh, integration_zone_list, - quadrature_descriptor, - discrete_function_descriptor, function_id_list} - .integrate(); + -> std::shared_ptr<const DiscreteFunctionVariant> { + return std::make_shared<DiscreteFunctionVariant>( + DiscreteFunctionVectorIntegrator{mesh, integration_zone_list, quadrature_descriptor, + discrete_function_descriptor, function_id_list} + .integrate()); } )); @@ -115,34 +116,40 @@ SchemeModule::SchemeModule() std::shared_ptr<const IQuadratureDescriptor> quadrature_descriptor, std::shared_ptr<const IDiscreteFunctionDescriptor> discrete_function_descriptor, const std::vector<FunctionSymbolId>& function_id_list) - -> std::shared_ptr<const IDiscreteFunction> { - return DiscreteFunctionVectorIntegrator{mesh, quadrature_descriptor, - discrete_function_descriptor, function_id_list} - .integrate(); + -> std::shared_ptr<const DiscreteFunctionVariant> { + return std::make_shared<DiscreteFunctionVariant>( + DiscreteFunctionVectorIntegrator{mesh, quadrature_descriptor, + discrete_function_descriptor, function_id_list} + .integrate()); } )); - this->_addBuiltinFunction( - "integrate", - std::function( + this->_addBuiltinFunction("integrate", + std::function( - [](std::shared_ptr<const IMesh> mesh, - const std::vector<std::shared_ptr<const IZoneDescriptor>>& integration_zone_list, - std::shared_ptr<const IQuadratureDescriptor> quadrature_descriptor, - const FunctionSymbolId& function_id) -> std::shared_ptr<const IDiscreteFunction> { - return DiscreteFunctionIntegrator{mesh, integration_zone_list, quadrature_descriptor, function_id}.integrate(); - } + [](std::shared_ptr<const IMesh> mesh, + const std::vector<std::shared_ptr<const IZoneDescriptor>>& integration_zone_list, + std::shared_ptr<const IQuadratureDescriptor> quadrature_descriptor, + const FunctionSymbolId& function_id) + -> std::shared_ptr<const DiscreteFunctionVariant> { + return std::make_shared<DiscreteFunctionVariant>( + DiscreteFunctionIntegrator{mesh, integration_zone_list, quadrature_descriptor, + function_id} + .integrate()); + } - )); + )); this->_addBuiltinFunction("integrate", std::function( [](std::shared_ptr<const IMesh> mesh, std::shared_ptr<const IQuadratureDescriptor> quadrature_descriptor, - const FunctionSymbolId& function_id) -> std::shared_ptr<const IDiscreteFunction> { - return DiscreteFunctionIntegrator{mesh, quadrature_descriptor, function_id}.integrate(); + const FunctionSymbolId& function_id) + -> std::shared_ptr<const DiscreteFunctionVariant> { + return std::make_shared<DiscreteFunctionVariant>( + DiscreteFunctionIntegrator{mesh, quadrature_descriptor, function_id}.integrate()); } )); @@ -154,21 +161,22 @@ SchemeModule::SchemeModule() const std::vector<std::shared_ptr<const IZoneDescriptor>>& interpolation_zone_list, std::shared_ptr<const IDiscreteFunctionDescriptor> discrete_function_descriptor, const std::vector<FunctionSymbolId>& function_id_list) - -> std::shared_ptr<const IDiscreteFunction> { + -> std::shared_ptr<const DiscreteFunctionVariant> { switch (discrete_function_descriptor->type()) { case DiscreteFunctionType::P0: { if (function_id_list.size() != 1) { throw NormalError("invalid function descriptor type"); } - return DiscreteFunctionInterpoler{mesh, interpolation_zone_list, - discrete_function_descriptor, function_id_list[0]} - .interpolate(); + return std::make_shared<DiscreteFunctionVariant>( + DiscreteFunctionInterpoler{mesh, interpolation_zone_list, + discrete_function_descriptor, function_id_list[0]} + .interpolate()); } case DiscreteFunctionType::P0Vector: { - return DiscreteFunctionVectorInterpoler{mesh, interpolation_zone_list, - discrete_function_descriptor, - function_id_list} - .interpolate(); + return std::make_shared<DiscreteFunctionVariant>( + DiscreteFunctionVectorInterpoler{mesh, interpolation_zone_list, + discrete_function_descriptor, function_id_list} + .interpolate()); } default: { throw NormalError("invalid function descriptor type"); @@ -178,30 +186,35 @@ SchemeModule::SchemeModule() )); - this->_addBuiltinFunction( - "interpolate", - std::function( - - [](std::shared_ptr<const IMesh> mesh, - std::shared_ptr<const IDiscreteFunctionDescriptor> discrete_function_descriptor, - const std::vector<FunctionSymbolId>& function_id_list) -> std::shared_ptr<const IDiscreteFunction> { - switch (discrete_function_descriptor->type()) { - case DiscreteFunctionType::P0: { - if (function_id_list.size() != 1) { - throw NormalError("invalid function descriptor type"); - } - return DiscreteFunctionInterpoler{mesh, discrete_function_descriptor, function_id_list[0]}.interpolate(); - } - case DiscreteFunctionType::P0Vector: { - return DiscreteFunctionVectorInterpoler{mesh, discrete_function_descriptor, function_id_list}.interpolate(); - } - default: { - throw NormalError("invalid function descriptor type"); - } - } - } - - )); + this->_addBuiltinFunction("interpolate", + std::function( + + [](std::shared_ptr<const IMesh> mesh, + std::shared_ptr<const IDiscreteFunctionDescriptor> discrete_function_descriptor, + const std::vector<FunctionSymbolId>& function_id_list) + -> std::shared_ptr<const DiscreteFunctionVariant> { + switch (discrete_function_descriptor->type()) { + case DiscreteFunctionType::P0: { + if (function_id_list.size() != 1) { + throw NormalError("invalid function descriptor type"); + } + return std::make_shared<DiscreteFunctionVariant>( + DiscreteFunctionInterpoler{mesh, discrete_function_descriptor, function_id_list[0]} + .interpolate()); + } + case DiscreteFunctionType::P0Vector: { + return std::make_shared<DiscreteFunctionVariant>( + DiscreteFunctionVectorInterpoler{mesh, discrete_function_descriptor, + function_id_list} + .interpolate()); + } + default: { + throw NormalError("invalid function descriptor type"); + } + } + } + + )); this->_addBuiltinFunction("randomizeMesh", std::function( @@ -267,6 +280,18 @@ SchemeModule::SchemeModule() )); + this->_addBuiltinFunction("normalstress", + std::function( + + [](std::shared_ptr<const IBoundaryDescriptor> boundary, + const FunctionSymbolId& normal_stress_id) + -> std::shared_ptr<const IBoundaryConditionDescriptor> { + return std::make_shared<DirichletBoundaryConditionDescriptor>("normal-stress", boundary, + normal_stress_id); + } + + )); + this->_addBuiltinFunction("velocity", std::function( [](std::shared_ptr<const IBoundaryDescriptor> boundary, @@ -336,10 +361,10 @@ SchemeModule::SchemeModule() this->_addBuiltinFunction("glace_fluxes", std::function( - [](const std::shared_ptr<const IDiscreteFunction>& rho, - const std::shared_ptr<const IDiscreteFunction>& u, - const std::shared_ptr<const IDiscreteFunction>& c, - const std::shared_ptr<const IDiscreteFunction>& p, + [](const std::shared_ptr<const DiscreteFunctionVariant>& rho, + const std::shared_ptr<const DiscreteFunctionVariant>& u, + const std::shared_ptr<const DiscreteFunctionVariant>& c, + const std::shared_ptr<const DiscreteFunctionVariant>& p, const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) -> std::tuple<std::shared_ptr<const ItemValueVariant>, @@ -355,17 +380,17 @@ SchemeModule::SchemeModule() this->_addBuiltinFunction("glace_solver", std::function( - [](const std::shared_ptr<const IDiscreteFunction>& rho, - const std::shared_ptr<const IDiscreteFunction>& u, - const std::shared_ptr<const IDiscreteFunction>& E, - const std::shared_ptr<const IDiscreteFunction>& c, - const std::shared_ptr<const IDiscreteFunction>& p, + [](const std::shared_ptr<const DiscreteFunctionVariant>& rho, + const std::shared_ptr<const DiscreteFunctionVariant>& u, + const std::shared_ptr<const DiscreteFunctionVariant>& E, + const std::shared_ptr<const DiscreteFunctionVariant>& c, + const std::shared_ptr<const DiscreteFunctionVariant>& p, const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list, - const double& dt) - -> std::tuple<std::shared_ptr<const IMesh>, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>> { + const double& dt) -> std::tuple<std::shared_ptr<const IMesh>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> { return AcousticSolverHandler{getCommonMesh({rho, u, E, c, p})} .solver() .apply(AcousticSolverHandler::SolverType::Glace, dt, rho, u, E, c, p, @@ -377,10 +402,10 @@ SchemeModule::SchemeModule() this->_addBuiltinFunction("eucclhyd_fluxes", std::function( - [](const std::shared_ptr<const IDiscreteFunction>& rho, - const std::shared_ptr<const IDiscreteFunction>& u, - const std::shared_ptr<const IDiscreteFunction>& c, - const std::shared_ptr<const IDiscreteFunction>& p, + [](const std::shared_ptr<const DiscreteFunctionVariant>& rho, + const std::shared_ptr<const DiscreteFunctionVariant>& u, + const std::shared_ptr<const DiscreteFunctionVariant>& c, + const std::shared_ptr<const DiscreteFunctionVariant>& p, const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) -> std::tuple<std::shared_ptr<const ItemValueVariant>, @@ -396,17 +421,17 @@ SchemeModule::SchemeModule() this->_addBuiltinFunction("eucclhyd_solver", std::function( - [](const std::shared_ptr<const IDiscreteFunction>& rho, - const std::shared_ptr<const IDiscreteFunction>& u, - const std::shared_ptr<const IDiscreteFunction>& E, - const std::shared_ptr<const IDiscreteFunction>& c, - const std::shared_ptr<const IDiscreteFunction>& p, + [](const std::shared_ptr<const DiscreteFunctionVariant>& rho, + const std::shared_ptr<const DiscreteFunctionVariant>& u, + const std::shared_ptr<const DiscreteFunctionVariant>& E, + const std::shared_ptr<const DiscreteFunctionVariant>& c, + const std::shared_ptr<const DiscreteFunctionVariant>& p, const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list, - const double& dt) - -> std::tuple<std::shared_ptr<const IMesh>, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>> { + const double& dt) -> std::tuple<std::shared_ptr<const IMesh>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> { return AcousticSolverHandler{getCommonMesh({rho, u, E, c, p})} .solver() .apply(AcousticSolverHandler::SolverType::Eucclhyd, dt, rho, u, E, c, p, @@ -418,15 +443,15 @@ SchemeModule::SchemeModule() this->_addBuiltinFunction("apply_acoustic_fluxes", std::function( - [](const std::shared_ptr<const IDiscreteFunction>& rho, // - const std::shared_ptr<const IDiscreteFunction>& u, // - const std::shared_ptr<const IDiscreteFunction>& E, // + [](const std::shared_ptr<const DiscreteFunctionVariant>& rho, // + const std::shared_ptr<const DiscreteFunctionVariant>& u, // + const std::shared_ptr<const DiscreteFunctionVariant>& E, // const std::shared_ptr<const ItemValueVariant>& ur, // const std::shared_ptr<const SubItemValuePerItemVariant>& Fjr, // - const double& dt) - -> std::tuple<std::shared_ptr<const IMesh>, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>> { + const double& dt) -> std::tuple<std::shared_ptr<const IMesh>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> { return AcousticSolverHandler{getCommonMesh({rho, u, E})} // .solver() .apply_fluxes(dt, rho, u, E, ur, Fjr); @@ -435,30 +460,30 @@ SchemeModule::SchemeModule() )); this->_addBuiltinFunction( - "parabolicheat", - std::function( + "parabolicheat", std::function( - [](const std::shared_ptr<const IDiscreteFunction>& alpha, - const std::shared_ptr<const IDiscreteFunction>& mub_dual, - const std::shared_ptr<const IDiscreteFunction>& mu_dual, const std::shared_ptr<const IDiscreteFunction>& f, - const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) - -> std::shared_ptr<const IDiscreteFunction> { - return ScalarDiamondSchemeHandler{alpha, mub_dual, mu_dual, f, bc_descriptor_list}.solution(); - } + [](const std::shared_ptr<const DiscreteFunctionVariant>& alpha, + const std::shared_ptr<const DiscreteFunctionVariant>& mub_dual, + const std::shared_ptr<const DiscreteFunctionVariant>& mu_dual, + const std::shared_ptr<const DiscreteFunctionVariant>& f, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) + -> std::shared_ptr<const DiscreteFunctionVariant> { + return ScalarDiamondSchemeHandler{alpha, mub_dual, mu_dual, f, bc_descriptor_list}.solution(); + } - )); + )); this->_addBuiltinFunction("unsteadyelasticity", std::function( - [](const std::shared_ptr<const IDiscreteFunction> alpha, - const std::shared_ptr<const IDiscreteFunction> lambdab, - const std::shared_ptr<const IDiscreteFunction> mub, - const std::shared_ptr<const IDiscreteFunction> lambda, - const std::shared_ptr<const IDiscreteFunction> mu, - const std::shared_ptr<const IDiscreteFunction> f, + [](const std::shared_ptr<const DiscreteFunctionVariant> alpha, + const std::shared_ptr<const DiscreteFunctionVariant> lambdab, + const std::shared_ptr<const DiscreteFunctionVariant> mub, + const std::shared_ptr<const DiscreteFunctionVariant> lambda, + const std::shared_ptr<const DiscreteFunctionVariant> mu, + const std::shared_ptr<const DiscreteFunctionVariant> f, const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& - bc_descriptor_list) -> std::shared_ptr<const IDiscreteFunction> { + bc_descriptor_list) -> std::shared_ptr<const DiscreteFunctionVariant> { return VectorDiamondSchemeHandler{alpha, lambdab, mub, lambda, mu, f, bc_descriptor_list} .solution(); @@ -469,15 +494,15 @@ SchemeModule::SchemeModule() this->_addBuiltinFunction("moleculardiffusion", std::function( - [](const std::shared_ptr<const IDiscreteFunction> alpha, - const std::shared_ptr<const IDiscreteFunction> lambdab, - const std::shared_ptr<const IDiscreteFunction> mub, - const std::shared_ptr<const IDiscreteFunction> lambda, - const std::shared_ptr<const IDiscreteFunction> mu, - const std::shared_ptr<const IDiscreteFunction> f, + [](const std::shared_ptr<const DiscreteFunctionVariant> alpha, + const std::shared_ptr<const DiscreteFunctionVariant> lambdab, + const std::shared_ptr<const DiscreteFunctionVariant> mub, + const std::shared_ptr<const DiscreteFunctionVariant> lambda, + const std::shared_ptr<const DiscreteFunctionVariant> mu, + const std::shared_ptr<const DiscreteFunctionVariant> f, const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& - bc_descriptor_list) -> std::tuple<std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>> { + bc_descriptor_list) -> std::tuple<std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> { return VectorDiamondSchemeHandler{alpha, lambdab, mub, lambda, mu, f, bc_descriptor_list} .apply(); @@ -488,76 +513,196 @@ SchemeModule::SchemeModule() this->_addBuiltinFunction("energybalance", std::function( - [](const std::shared_ptr<const IDiscreteFunction> lambdab, - const std::shared_ptr<const IDiscreteFunction> mub, - const std::shared_ptr<const IDiscreteFunction> U, - const std::shared_ptr<const IDiscreteFunction> dual_U, - const std::shared_ptr<const IDiscreteFunction> source, + [](const std::shared_ptr<const DiscreteFunctionVariant> lambdab, + const std::shared_ptr<const DiscreteFunctionVariant> mub, + const std::shared_ptr<const DiscreteFunctionVariant> U, + const std::shared_ptr<const DiscreteFunctionVariant> dual_U, + const std::shared_ptr<const DiscreteFunctionVariant> source, const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& - bc_descriptor_list) -> std::tuple<std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>> { + bc_descriptor_list) -> std::tuple<std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> { return EnergyComputerHandler{lambdab, mub, U, dual_U, source, bc_descriptor_list} .computeEnergyUpdate(); } )); - this->_addBuiltinFunction("lagrangian", + this->_addBuiltinFunction("hyperelastic_eucclhyd_fluxes", std::function( - [](const std::shared_ptr<const IMesh>& mesh, - const std::shared_ptr<const IDiscreteFunction>& v) - -> std::shared_ptr<const IDiscreteFunction> { return shallowCopy(mesh, v); } + [](const std::shared_ptr<const DiscreteFunctionVariant>& rho, + const std::shared_ptr<const DiscreteFunctionVariant>& aL, + const std::shared_ptr<const DiscreteFunctionVariant>& aT, + const std::shared_ptr<const DiscreteFunctionVariant>& u, + const std::shared_ptr<const DiscreteFunctionVariant>& sigma, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& + bc_descriptor_list) + -> std::tuple<std::shared_ptr<const ItemValueVariant>, + std::shared_ptr<const SubItemValuePerItemVariant>> { + return HyperelasticSolverHandler{getCommonMesh({rho, aL, aT, u, sigma})} + .solver() + .compute_fluxes(HyperelasticSolverHandler::SolverType::Eucclhyd, rho, aL, aT, u, + sigma, bc_descriptor_list); + } )); - this->_addBuiltinFunction("acoustic_dt", + this->_addBuiltinFunction("hyperelastic_eucclhyd_solver", std::function( - [](const std::shared_ptr<const IDiscreteFunction>& c) -> double { return acoustic_dt(c); } + [](const std::shared_ptr<const DiscreteFunctionVariant>& rho, + const std::shared_ptr<const DiscreteFunctionVariant>& u, + const std::shared_ptr<const DiscreteFunctionVariant>& E, + const std::shared_ptr<const DiscreteFunctionVariant>& CG, + const std::shared_ptr<const DiscreteFunctionVariant>& aL, + const std::shared_ptr<const DiscreteFunctionVariant>& aT, + const std::shared_ptr<const DiscreteFunctionVariant>& sigma, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& + bc_descriptor_list, + const double& dt) -> std::tuple<std::shared_ptr<const IMesh>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> { + return HyperelasticSolverHandler{getCommonMesh({rho, u, E, CG, aL, aT, sigma})} + .solver() + .apply(HyperelasticSolverHandler::SolverType::Eucclhyd, dt, rho, u, E, CG, aL, aT, + sigma, bc_descriptor_list); + } )); - this - ->_addBuiltinFunction("cell_volume", - std::function( - - [](const std::shared_ptr<const IMesh>& i_mesh) -> std::shared_ptr<const IDiscreteFunction> { - switch (i_mesh->dimension()) { - case 1: { - constexpr size_t Dimension = 1; - using MeshType = Mesh<Connectivity<Dimension>>; - std::shared_ptr<const MeshType> mesh = - std::dynamic_pointer_cast<const Mesh<Connectivity<Dimension>>>(i_mesh); + this->_addBuiltinFunction("hyperelastic_glace_fluxes", + std::function( - return std::make_shared<const DiscreteFunctionP0< - Dimension, double>>(mesh, copy(MeshDataManager::instance().getMeshData(*mesh).Vj())); - } - case 2: { - constexpr size_t Dimension = 2; - using MeshType = Mesh<Connectivity<Dimension>>; - std::shared_ptr<const MeshType> mesh = - std::dynamic_pointer_cast<const Mesh<Connectivity<Dimension>>>(i_mesh); - - return std::make_shared<const DiscreteFunctionP0< - Dimension, double>>(mesh, copy(MeshDataManager::instance().getMeshData(*mesh).Vj())); + [](const std::shared_ptr<const DiscreteFunctionVariant>& rho, + const std::shared_ptr<const DiscreteFunctionVariant>& aL, + const std::shared_ptr<const DiscreteFunctionVariant>& aT, + const std::shared_ptr<const DiscreteFunctionVariant>& u, + const std::shared_ptr<const DiscreteFunctionVariant>& sigma, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& + bc_descriptor_list) + -> std::tuple<std::shared_ptr<const ItemValueVariant>, + std::shared_ptr<const SubItemValuePerItemVariant>> { + return HyperelasticSolverHandler{getCommonMesh({rho, aL, aT, u, sigma})} + .solver() + .compute_fluxes(HyperelasticSolverHandler::SolverType::Glace, // + rho, aL, aT, u, sigma, bc_descriptor_list); } - case 3: { - constexpr size_t Dimension = 3; - using MeshType = Mesh<Connectivity<Dimension>>; - std::shared_ptr<const MeshType> mesh = - std::dynamic_pointer_cast<const Mesh<Connectivity<Dimension>>>(i_mesh); - - return std::make_shared<const DiscreteFunctionP0< - Dimension, double>>(mesh, copy(MeshDataManager::instance().getMeshData(*mesh).Vj())); + + )); + + this->_addBuiltinFunction("hyperelastic_glace_solver", + std::function( + + [](const std::shared_ptr<const DiscreteFunctionVariant>& rho, + const std::shared_ptr<const DiscreteFunctionVariant>& u, + const std::shared_ptr<const DiscreteFunctionVariant>& E, + const std::shared_ptr<const DiscreteFunctionVariant>& CG, + const std::shared_ptr<const DiscreteFunctionVariant>& aL, + const std::shared_ptr<const DiscreteFunctionVariant>& aT, + const std::shared_ptr<const DiscreteFunctionVariant>& sigma, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& + bc_descriptor_list, + const double& dt) -> std::tuple<std::shared_ptr<const IMesh>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> { + return HyperelasticSolverHandler{getCommonMesh({rho, u, E, CG, aL, aT, sigma})} + .solver() + .apply(HyperelasticSolverHandler::SolverType::Glace, dt, rho, u, E, CG, aL, aT, sigma, + bc_descriptor_list); } - default: { - throw UnexpectedError("invalid mesh dimension"); + + )); + + this->_addBuiltinFunction("apply_hyperelastic_fluxes", + std::function( + + [](const std::shared_ptr<const DiscreteFunctionVariant>& rho, // + const std::shared_ptr<const DiscreteFunctionVariant>& u, // + const std::shared_ptr<const DiscreteFunctionVariant>& E, // + const std::shared_ptr<const DiscreteFunctionVariant>& CG, // + const std::shared_ptr<const ItemValueVariant>& ur, // + const std::shared_ptr<const SubItemValuePerItemVariant>& Fjr, // + const double& dt) -> std::tuple<std::shared_ptr<const IMesh>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> { + return HyperelasticSolverHandler{getCommonMesh({rho, u, E, CG})} // + .solver() + .apply_fluxes(dt, rho, u, E, CG, ur, Fjr); } + + )); + + this->_addBuiltinFunction("lagrangian", + std::function( + + [](const std::shared_ptr<const IMesh>& mesh, + const std::shared_ptr<const DiscreteFunctionVariant>& v) + -> std::shared_ptr<const DiscreteFunctionVariant> { return shallowCopy(mesh, v); } + + )); + + this->_addBuiltinFunction("acoustic_dt", std::function( + + [](const std::shared_ptr<const DiscreteFunctionVariant>& c) -> double { + return acoustic_dt(c); + } + + )); + + this->_addBuiltinFunction("cell_volume", + std::function( + + [](const std::shared_ptr<const IMesh>& i_mesh) + -> std::shared_ptr<const DiscreteFunctionVariant> { + switch (i_mesh->dimension()) { + case 1: { + constexpr size_t Dimension = 1; + using MeshType = Mesh<Connectivity<Dimension>>; + std::shared_ptr<const MeshType> mesh = + std::dynamic_pointer_cast<const Mesh<Connectivity<Dimension>>>(i_mesh); + + return std::make_shared<DiscreteFunctionVariant>( + DiscreteFunctionP0(mesh, MeshDataManager::instance().getMeshData(*mesh).Vj())); + } + case 2: { + constexpr size_t Dimension = 2; + using MeshType = Mesh<Connectivity<Dimension>>; + std::shared_ptr<const MeshType> mesh = + std::dynamic_pointer_cast<const Mesh<Connectivity<Dimension>>>(i_mesh); + + return std::make_shared<DiscreteFunctionVariant>( + DiscreteFunctionP0(mesh, MeshDataManager::instance().getMeshData(*mesh).Vj())); + } + case 3: { + constexpr size_t Dimension = 3; + using MeshType = Mesh<Connectivity<Dimension>>; + std::shared_ptr<const MeshType> mesh = + std::dynamic_pointer_cast<const Mesh<Connectivity<Dimension>>>(i_mesh); + + return std::make_shared<DiscreteFunctionVariant>( + DiscreteFunctionP0(mesh, MeshDataManager::instance().getMeshData(*mesh).Vj())); + } + default: { + throw UnexpectedError("invalid mesh dimension"); + } + } } - } - )); + )); + + this->_addBuiltinFunction("hyperelastic_dt", std::function( + + [](const std::shared_ptr<const DiscreteFunctionVariant>& c) -> double { + return hyperelastic_dt(c); + } + + )); MathFunctionRegisterForVh{*this}; } diff --git a/src/language/modules/SchemeModule.hpp b/src/language/modules/SchemeModule.hpp index 6c1f0324aa2858437ec8d7f49434c2d8ac718a45..d56a5ec74069bd23d8169f25ff8a829c7c4a53ff 100644 --- a/src/language/modules/SchemeModule.hpp +++ b/src/language/modules/SchemeModule.hpp @@ -10,9 +10,9 @@ template <> inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<const IBoundaryConditionDescriptor>> = ASTNodeDataType::build<ASTNodeDataType::type_id_t>("boundary_condition"); -class IDiscreteFunction; +class DiscreteFunctionVariant; template <> -inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<const IDiscreteFunction>> = +inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<const DiscreteFunctionVariant>> = ASTNodeDataType::build<ASTNodeDataType::type_id_t>("Vh"); class IDiscreteFunctionDescriptor; diff --git a/src/language/modules/UnaryOperatorRegisterForVh.cpp b/src/language/modules/UnaryOperatorRegisterForVh.cpp index b1dc85aa9dd11be2f5a6d159d8f1a70254d68c7b..e2e9c2db9b72a9a687806d24dee836cfd37a22e8 100644 --- a/src/language/modules/UnaryOperatorRegisterForVh.cpp +++ b/src/language/modules/UnaryOperatorRegisterForVh.cpp @@ -3,10 +3,9 @@ #include <language/modules/SchemeModule.hpp> #include <language/utils/DataHandler.hpp> #include <language/utils/DataVariant.hpp> -#include <language/utils/EmbeddedIDiscreteFunctionOperators.hpp> +#include <language/utils/EmbeddedDiscreteFunctionOperators.hpp> #include <language/utils/OperatorRepository.hpp> #include <language/utils/UnaryOperatorProcessorBuilder.hpp> -#include <scheme/IDiscreteFunction.hpp> void UnaryOperatorRegisterForVh::_register_unary_minus() @@ -14,8 +13,9 @@ UnaryOperatorRegisterForVh::_register_unary_minus() OperatorRepository& repository = OperatorRepository::instance(); repository.addUnaryOperator<language::unary_minus>( - std::make_shared<UnaryOperatorProcessorBuilder<language::unary_minus, std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>>>()); + std::make_shared< + UnaryOperatorProcessorBuilder<language::unary_minus, std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>>>()); } UnaryOperatorRegisterForVh::UnaryOperatorRegisterForVh() diff --git a/src/language/modules/WriterModule.cpp b/src/language/modules/WriterModule.cpp index 6523d56a93d4fe0b4f953fb6065cd4a15be7330c..aa479c0eb94005d59000d98dd460d8fedb89ab21 100644 --- a/src/language/modules/WriterModule.cpp +++ b/src/language/modules/WriterModule.cpp @@ -12,9 +12,7 @@ #include <output/NamedDiscreteFunction.hpp> #include <output/NamedItemValueVariant.hpp> #include <output/VTKWriter.hpp> -#include <scheme/DiscreteFunctionP0.hpp> -#include <scheme/IDiscreteFunction.hpp> -#include <scheme/IDiscreteFunctionDescriptor.hpp> +#include <scheme/DiscreteFunctionVariant.hpp> WriterModule::WriterModule() { @@ -75,7 +73,7 @@ WriterModule::WriterModule() this->_addBuiltinFunction("name_output", std::function( - [](std::shared_ptr<const IDiscreteFunction> discrete_function, + [](std::shared_ptr<const DiscreteFunctionVariant> discrete_function, const std::string& name) -> std::shared_ptr<const INamedDiscreteData> { return std::make_shared<const NamedDiscreteFunction>(discrete_function, name); diff --git a/src/language/modules/WriterModule.hpp b/src/language/modules/WriterModule.hpp index f61eafb0e4847c248e9def011bf269b3b9a4022e..97bef5a78ac6f90cff1af303bed901c4c46c665a 100644 --- a/src/language/modules/WriterModule.hpp +++ b/src/language/modules/WriterModule.hpp @@ -7,7 +7,6 @@ class OutputNamedItemValueSet; class INamedDiscreteData; -class IDiscreteFunction; #include <string> diff --git a/src/language/node_processor/ASTNodeListProcessor.hpp b/src/language/node_processor/ASTNodeListProcessor.hpp index df29d82de3cf317aa02ddb3f49838ec0a0325c0e..5a9d8c0b8be23ad9c563ce7d8ed30f25df29505f 100644 --- a/src/language/node_processor/ASTNodeListProcessor.hpp +++ b/src/language/node_processor/ASTNodeListProcessor.hpp @@ -1,8 +1,10 @@ #ifndef AST_NODE_LIST_PROCESSOR_HPP #define AST_NODE_LIST_PROCESSOR_HPP +#include <language/PEGGrammar.hpp> #include <language/ast/ASTNode.hpp> #include <language/node_processor/INodeProcessor.hpp> +#include <language/utils/SymbolTable.hpp> class ASTNodeListProcessor final : public INodeProcessor { diff --git a/src/language/node_processor/FunctionArgumentConverter.hpp b/src/language/node_processor/FunctionArgumentConverter.hpp index bb125b821361989e6e8bb898ba0b56208c32ef84..6a4075307e3af9f225cd493176fbd0a7873a3c75 100644 --- a/src/language/node_processor/FunctionArgumentConverter.hpp +++ b/src/language/node_processor/FunctionArgumentConverter.hpp @@ -116,10 +116,23 @@ class FunctionTinyVectorArgumentConverter final : public IFunctionArgumentConver value); } else if constexpr (std::is_same_v<ProvidedValueType, ZeroType>) { exec_policy.currentContext()[m_argument_id] = ExpectedValueType{ZeroType::zero}; + } else if constexpr (std::is_same_v<ExpectedValueType, TinyVector<1>>) { + if constexpr (std::is_same_v<ProvidedValueType, bool>) { + exec_policy.currentContext()[m_argument_id] = ExpectedValueType(std::get<ProvidedValueType>(value)); + } else if constexpr (std::is_same_v<ProvidedValueType, int64_t>) { + exec_policy.currentContext()[m_argument_id] = ExpectedValueType(std::get<ProvidedValueType>(value)); + } else if constexpr (std::is_same_v<ProvidedValueType, uint64_t>) { + exec_policy.currentContext()[m_argument_id] = ExpectedValueType(std::get<ProvidedValueType>(value)); + } else if constexpr (std::is_same_v<ProvidedValueType, double>) { + exec_policy.currentContext()[m_argument_id] = ExpectedValueType(std::get<ProvidedValueType>(value)); + } else { + static_assert(std::is_same_v<ExpectedValueType, TinyVector<1>>); + exec_policy.currentContext()[m_argument_id] = + std::move(static_cast<ExpectedValueType>(std::get<ProvidedValueType>(value))); + } } else { - static_assert(std::is_same_v<ExpectedValueType, TinyVector<1>>); - exec_policy.currentContext()[m_argument_id] = - std::move(static_cast<ExpectedValueType>(std::get<ProvidedValueType>(value))); + throw UnexpectedError(std::string{"cannot convert '"} + demangle<ProvidedValueType>() + "' to '" + + demangle<ExpectedValueType>() + "'"); } return {}; } @@ -165,11 +178,25 @@ class FunctionTinyMatrixArgumentConverter final : public IFunctionArgumentConver value); } else if constexpr (std::is_same_v<ProvidedValueType, ZeroType>) { exec_policy.currentContext()[m_argument_id] = ExpectedValueType{ZeroType::zero}; + } else if constexpr (std::is_same_v<ExpectedValueType, TinyMatrix<1>>) { + if constexpr (std::is_same_v<ProvidedValueType, bool>) { + exec_policy.currentContext()[m_argument_id] = ExpectedValueType(std::get<ProvidedValueType>(value)); + } else if constexpr (std::is_same_v<ProvidedValueType, int64_t>) { + exec_policy.currentContext()[m_argument_id] = ExpectedValueType(std::get<ProvidedValueType>(value)); + } else if constexpr (std::is_same_v<ProvidedValueType, uint64_t>) { + exec_policy.currentContext()[m_argument_id] = ExpectedValueType(std::get<ProvidedValueType>(value)); + } else if constexpr (std::is_same_v<ProvidedValueType, double>) { + exec_policy.currentContext()[m_argument_id] = ExpectedValueType(std::get<ProvidedValueType>(value)); + } else { + static_assert(std::is_same_v<ExpectedValueType, TinyMatrix<1>>); + exec_policy.currentContext()[m_argument_id] = + std::move(static_cast<ExpectedValueType>(std::get<ProvidedValueType>(value))); + } } else { - static_assert(std::is_same_v<ExpectedValueType, TinyMatrix<1>>); - exec_policy.currentContext()[m_argument_id] = - std::move(static_cast<ExpectedValueType>(std::get<ProvidedValueType>(value))); + throw UnexpectedError(std::string{"cannot convert '"} + demangle<ProvidedValueType>() + "' to '" + + demangle<ExpectedValueType>() + "'"); } + return {}; } diff --git a/src/language/utils/ASTNodeDataType.hpp b/src/language/utils/ASTNodeDataType.hpp index 4ef3a80c188faa5898fd29e0bc35cce651c7f6c8..f148e99f1396c125ad21277b3d29a0fdd2b2d782 100644 --- a/src/language/utils/ASTNodeDataType.hpp +++ b/src/language/utils/ASTNodeDataType.hpp @@ -176,7 +176,7 @@ class ASTNodeDataType { static_assert((data_type == list_t), "incorrect data_type construction: cannot provide a list of data types"); - for (auto i : list_of_types) { + for (const auto& i : list_of_types) { Assert(i->m_data_type != ASTNodeDataType::undefined_t, "cannot build a type list containing undefined types"); } diff --git a/src/language/utils/BuiltinFunctionEmbedder.hpp b/src/language/utils/BuiltinFunctionEmbedder.hpp index c3f015c5b61fbdfda66ee78bbf928fe3a24f3de0..460ec3e866be479633e5bf9a9a416c1f84fc09e6 100644 --- a/src/language/utils/BuiltinFunctionEmbedder.hpp +++ b/src/language/utils/BuiltinFunctionEmbedder.hpp @@ -40,19 +40,25 @@ template <typename FX, typename... Args> class BuiltinFunctionEmbedderBase<FX(Args...)> : public IBuiltinFunctionEmbedder { protected: - template <size_t I> - PUGS_INLINE void constexpr _check_value() const + template <typename ValueT> + PUGS_INLINE void constexpr _check_value_type() const { - using ValueN_T = std::tuple_element_t<I, FX>; - if constexpr (std::is_lvalue_reference_v<ValueN_T>) { - static_assert(std::is_const_v<std::remove_reference_t<ValueN_T>>, + if constexpr (std::is_lvalue_reference_v<ValueT>) { + static_assert(std::is_const_v<std::remove_reference_t<ValueT>>, "builtin function return values are non mutable use 'const' when passing references"); } - if constexpr (is_std_ptr_v<ValueN_T>) { - static_assert(std::is_const_v<typename ValueN_T::element_type>, + if constexpr (is_std_ptr_v<ValueT>) { + static_assert(std::is_const_v<typename ValueT::element_type>, "builtin function return values are non mutable. For instance use std::shared_ptr<const T>"); } + } + + template <size_t I> + PUGS_INLINE void constexpr _check_value() const + { + using ValueN_T = std::tuple_element_t<I, FX>; + _check_value_type<ValueN_T>(); if (ast_node_data_type_from<std::remove_cv_t<std::remove_reference_t<ValueN_T>>> == ASTNodeDataType::undefined_t) { throw std::invalid_argument(std::string{"cannot bind C++ to language.\nnote: return value number "} + @@ -79,6 +85,7 @@ class BuiltinFunctionEmbedderBase<FX(Args...)> : public IBuiltinFunctionEmbedder std::string{"cannot bind C++ to language.\nnote: return value has no associated language type: "} + demangle<FX>()); } + _check_value_type<FX>(); } } @@ -99,8 +106,7 @@ class BuiltinFunctionEmbedderBase<FX(Args...)> : public IBuiltinFunctionEmbedder } template <size_t... I> - PUGS_INLINE std::vector<std::shared_ptr<const ASTNodeDataType>> - _getCompoundDataTypes(std::index_sequence<I...>) const + PUGS_INLINE std::vector<std::shared_ptr<const ASTNodeDataType>> _getCompoundDataTypes(std::index_sequence<I...>) const { std::vector<std::shared_ptr<const ASTNodeDataType>> compound_type_list; (compound_type_list.push_back(std::make_shared<ASTNodeDataType>(this->_getOneElementDataType<FX, I>())), ...); @@ -266,8 +272,7 @@ class BuiltinFunctionEmbedder<FX(Args...)> : public BuiltinFunctionEmbedderBase< } template <size_t... I> - PUGS_INLINE std::vector<ASTNodeDataType> - _getParameterDataTypes(std::index_sequence<I...>) const + PUGS_INLINE std::vector<ASTNodeDataType> _getParameterDataTypes(std::index_sequence<I...>) const { std::vector<ASTNodeDataType> parameter_type_list; (parameter_type_list.push_back(this->template _getOneElementDataType<ArgsTuple, I>()), ...); diff --git a/src/language/utils/BuiltinFunctionEmbedderUtils.cpp b/src/language/utils/BuiltinFunctionEmbedderUtils.cpp index be3474ef7ae4e657d7553715c8414180ddc15d52..f4259526fb10a7d1977eec7c575e69c0837a4a26 100644 --- a/src/language/utils/BuiltinFunctionEmbedderUtils.cpp +++ b/src/language/utils/BuiltinFunctionEmbedderUtils.cpp @@ -135,7 +135,7 @@ getBuiltinFunctionEmbedder(ASTNode& n) switch (tuple_content_type) { case ASTNodeDataType::vector_t: { if (arg_type == ASTNodeDataType::list_t) { - for (auto element_type : arg_type.contentTypeList()) { + for (const auto& element_type : arg_type.contentTypeList()) { is_castable &= is_castable_to_vector(*element_type, tuple_content_type); } } else { @@ -145,7 +145,7 @@ getBuiltinFunctionEmbedder(ASTNode& n) } case ASTNodeDataType::matrix_t: { if (arg_type == ASTNodeDataType::list_t) { - for (auto element_type : arg_type.contentTypeList()) { + for (const auto& element_type : arg_type.contentTypeList()) { is_castable &= is_castable_to_matrix(*element_type, tuple_content_type); } } else { @@ -155,7 +155,7 @@ getBuiltinFunctionEmbedder(ASTNode& n) } default: if (arg_type == ASTNodeDataType::list_t) { - for (auto element_type : arg_type.contentTypeList()) { + for (const auto& element_type : arg_type.contentTypeList()) { is_castable &= isNaturalConversion(*element_type, tuple_content_type); } } else { diff --git a/src/language/utils/CMakeLists.txt b/src/language/utils/CMakeLists.txt index 0fe1c798ba77d98b4453ded4d4c3334c0d2199e5..a81ffa8aecdf7af0085296b181f2b3ec4d63238f 100644 --- a/src/language/utils/CMakeLists.txt +++ b/src/language/utils/CMakeLists.txt @@ -23,9 +23,8 @@ add_library(PugsLanguageUtils BuiltinFunctionEmbedderUtils.cpp DataVariant.cpp EmbeddedData.cpp - EmbeddedIDiscreteFunctionMathFunctions.cpp - EmbeddedIDiscreteFunctionOperators.cpp - EmbeddedIDiscreteFunctionUtils.cpp + EmbeddedDiscreteFunctionMathFunctions.cpp + EmbeddedDiscreteFunctionOperators.cpp FunctionSymbolId.cpp IncDecOperatorRegisterForN.cpp IncDecOperatorRegisterForZ.cpp diff --git a/src/language/utils/EmbeddedDiscreteFunctionMathFunctions.cpp b/src/language/utils/EmbeddedDiscreteFunctionMathFunctions.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3d820c561f623d01967c6a4d947eaa91a531e183 --- /dev/null +++ b/src/language/utils/EmbeddedDiscreteFunctionMathFunctions.cpp @@ -0,0 +1,647 @@ +#include <language/utils/EmbeddedDiscreteFunctionMathFunctions.hpp> + +#include <language/utils/EmbeddedDiscreteFunctionUtils.hpp> +#include <mesh/IMesh.hpp> +#include <scheme/DiscreteFunctionP0.hpp> +#include <scheme/DiscreteFunctionP0Vector.hpp> +#include <scheme/DiscreteFunctionUtils.hpp> +#include <scheme/DiscreteFunctionVariant.hpp> +#include <scheme/IDiscreteFunctionDescriptor.hpp> + +#include <utils/Demangle.hpp> + +#define DISCRETE_VH_TO_VH_REAL_FUNCTION_CALL(FUNCTION, ARG) \ + return std::visit( \ + [&](auto&& discrete_function) -> std::shared_ptr<DiscreteFunctionVariant> { \ + using DiscreteFunctionType = std::decay_t<decltype(discrete_function)>; \ + if constexpr (std::is_same_v<DiscreteFunctionType, DiscreteFunctionP0<1, const double>> or \ + std::is_same_v<DiscreteFunctionType, DiscreteFunctionP0<2, const double>> or \ + std::is_same_v<DiscreteFunctionType, DiscreteFunctionP0<3, const double>>) { \ + return std::make_shared<DiscreteFunctionVariant>(FUNCTION(discrete_function)); \ + } else { \ + throw NormalError(EmbeddedDiscreteFunctionUtils::invalidOperandType(ARG)); \ + } \ + }, \ + ARG->discreteFunction()); + +#define DISCRETE_VH_TO_R_CALL(FUNCTION, ARG) \ + return std::visit( \ + [&](auto&& discrete_function) -> double { \ + using DiscreteFunctionType = std::decay_t<decltype(discrete_function)>; \ + if constexpr (std::is_same_v<DiscreteFunctionType, DiscreteFunctionP0<1, const double>> or \ + std::is_same_v<DiscreteFunctionType, DiscreteFunctionP0<2, const double>> or \ + std::is_same_v<DiscreteFunctionType, DiscreteFunctionP0<3, const double>>) { \ + return FUNCTION(discrete_function); \ + } else { \ + throw NormalError(EmbeddedDiscreteFunctionUtils::invalidOperandType(ARG)); \ + } \ + }, \ + ARG->discreteFunction()); + +#define DISCRETE_VH_VH_TO_VH_REAL_FUNCTION_CALL(FUNCTION, ARG0, ARG1) \ + if (not hasSameMesh({ARG0, ARG1})) { \ + throw NormalError("operands are defined on different meshes"); \ + } \ + return std::visit( \ + [&](auto&& f, auto&& g) -> std::shared_ptr<DiscreteFunctionVariant> { \ + using TypeOfF = std::decay_t<decltype(f)>; \ + using TypeOfG = std::decay_t<decltype(g)>; \ + if constexpr (std::is_same_v<TypeOfF, DiscreteFunctionP0<1, const double>> or \ + std::is_same_v<TypeOfF, DiscreteFunctionP0<2, const double>> or \ + std::is_same_v<TypeOfF, DiscreteFunctionP0<3, const double>>) { \ + if constexpr (std::is_same_v<TypeOfF, TypeOfG>) { \ + return std::make_shared<DiscreteFunctionVariant>(FUNCTION(f, g)); \ + } else { \ + throw NormalError(EmbeddedDiscreteFunctionUtils::incompatibleOperandTypes(f, g)); \ + } \ + } else { \ + throw NormalError(EmbeddedDiscreteFunctionUtils::incompatibleOperandTypes(f, g)); \ + } \ + }, \ + ARG0->discreteFunction(), ARG1->discreteFunction()); + +#define DISCRETE_R_VH_TO_VH_REAL_FUNCTION_CALL(FUNCTION, ARG0, ARG1) \ + return std::visit( \ + [&](auto&& discrete_function) -> std::shared_ptr<DiscreteFunctionVariant> { \ + using DiscreteFunctionType = std::decay_t<decltype(discrete_function)>; \ + if constexpr (std::is_same_v<DiscreteFunctionType, DiscreteFunctionP0<1, const double>> or \ + std::is_same_v<DiscreteFunctionType, DiscreteFunctionP0<2, const double>> or \ + std::is_same_v<DiscreteFunctionType, DiscreteFunctionP0<3, const double>>) { \ + return std::make_shared<DiscreteFunctionVariant>(FUNCTION(ARG0, discrete_function)); \ + } else { \ + throw NormalError(EmbeddedDiscreteFunctionUtils::incompatibleOperandTypes(ARG0, discrete_function)); \ + } \ + }, \ + ARG1->discreteFunction()); + +#define DISCRETE_VH_R_TO_VH_REAL_FUNCTION_CALL(FUNCTION, ARG0, ARG1) \ + return std::visit( \ + [&](auto&& discrete_function) -> std::shared_ptr<DiscreteFunctionVariant> { \ + using DiscreteFunctionType = std::decay_t<decltype(discrete_function)>; \ + if constexpr (std::is_same_v<DiscreteFunctionType, DiscreteFunctionP0<1, const double>> or \ + std::is_same_v<DiscreteFunctionType, DiscreteFunctionP0<2, const double>> or \ + std::is_same_v<DiscreteFunctionType, DiscreteFunctionP0<3, const double>>) { \ + return std::make_shared<DiscreteFunctionVariant>(FUNCTION(discrete_function, ARG1)); \ + } else { \ + throw NormalError(EmbeddedDiscreteFunctionUtils::incompatibleOperandTypes(discrete_function, ARG1)); \ + } \ + }, \ + ARG0->discreteFunction()); + +std::shared_ptr<const DiscreteFunctionVariant> +sqrt(const std::shared_ptr<const DiscreteFunctionVariant>& f) +{ + DISCRETE_VH_TO_VH_REAL_FUNCTION_CALL(sqrt, f); +} + +std::shared_ptr<const DiscreteFunctionVariant> +abs(const std::shared_ptr<const DiscreteFunctionVariant>& f) +{ + DISCRETE_VH_TO_VH_REAL_FUNCTION_CALL(abs, f); +} + +std::shared_ptr<const DiscreteFunctionVariant> +sin(const std::shared_ptr<const DiscreteFunctionVariant>& f) +{ + DISCRETE_VH_TO_VH_REAL_FUNCTION_CALL(sin, f); +} + +std::shared_ptr<const DiscreteFunctionVariant> +cos(const std::shared_ptr<const DiscreteFunctionVariant>& f) +{ + DISCRETE_VH_TO_VH_REAL_FUNCTION_CALL(cos, f); +} + +std::shared_ptr<const DiscreteFunctionVariant> +tan(const std::shared_ptr<const DiscreteFunctionVariant>& f) +{ + DISCRETE_VH_TO_VH_REAL_FUNCTION_CALL(tan, f); +} + +std::shared_ptr<const DiscreteFunctionVariant> +asin(const std::shared_ptr<const DiscreteFunctionVariant>& f) +{ + DISCRETE_VH_TO_VH_REAL_FUNCTION_CALL(asin, f); +} + +std::shared_ptr<const DiscreteFunctionVariant> +acos(const std::shared_ptr<const DiscreteFunctionVariant>& f) +{ + DISCRETE_VH_TO_VH_REAL_FUNCTION_CALL(acos, f); +} + +std::shared_ptr<const DiscreteFunctionVariant> +atan(const std::shared_ptr<const DiscreteFunctionVariant>& f) +{ + DISCRETE_VH_TO_VH_REAL_FUNCTION_CALL(atan, f); +} + +std::shared_ptr<const DiscreteFunctionVariant> +atan2(const std::shared_ptr<const DiscreteFunctionVariant>& f_v, + const std::shared_ptr<const DiscreteFunctionVariant>& g_v) +{ + DISCRETE_VH_VH_TO_VH_REAL_FUNCTION_CALL(atan2, f_v, g_v); +} + +std::shared_ptr<const DiscreteFunctionVariant> +atan2(const double a, const std::shared_ptr<const DiscreteFunctionVariant>& f) +{ + DISCRETE_R_VH_TO_VH_REAL_FUNCTION_CALL(atan2, a, f); +} + +std::shared_ptr<const DiscreteFunctionVariant> +atan2(const std::shared_ptr<const DiscreteFunctionVariant>& f, const double a) +{ + DISCRETE_VH_R_TO_VH_REAL_FUNCTION_CALL(atan2, f, a); +} + +std::shared_ptr<const DiscreteFunctionVariant> +sinh(const std::shared_ptr<const DiscreteFunctionVariant>& f) +{ + DISCRETE_VH_TO_VH_REAL_FUNCTION_CALL(sinh, f); +} + +std::shared_ptr<const DiscreteFunctionVariant> +cosh(const std::shared_ptr<const DiscreteFunctionVariant>& f) +{ + DISCRETE_VH_TO_VH_REAL_FUNCTION_CALL(cosh, f); +} + +std::shared_ptr<const DiscreteFunctionVariant> +tanh(const std::shared_ptr<const DiscreteFunctionVariant>& f) +{ + DISCRETE_VH_TO_VH_REAL_FUNCTION_CALL(tanh, f); +} + +std::shared_ptr<const DiscreteFunctionVariant> +asinh(const std::shared_ptr<const DiscreteFunctionVariant>& f) +{ + DISCRETE_VH_TO_VH_REAL_FUNCTION_CALL(asinh, f); +} + +std::shared_ptr<const DiscreteFunctionVariant> +acosh(const std::shared_ptr<const DiscreteFunctionVariant>& f) +{ + DISCRETE_VH_TO_VH_REAL_FUNCTION_CALL(acosh, f); +} + +std::shared_ptr<const DiscreteFunctionVariant> +atanh(const std::shared_ptr<const DiscreteFunctionVariant>& f) +{ + DISCRETE_VH_TO_VH_REAL_FUNCTION_CALL(atanh, f); +} + +std::shared_ptr<const DiscreteFunctionVariant> +exp(const std::shared_ptr<const DiscreteFunctionVariant>& f) +{ + DISCRETE_VH_TO_VH_REAL_FUNCTION_CALL(exp, f); +} + +std::shared_ptr<const DiscreteFunctionVariant> +log(const std::shared_ptr<const DiscreteFunctionVariant>& f) +{ + DISCRETE_VH_TO_VH_REAL_FUNCTION_CALL(log, f); +} + +std::shared_ptr<const DiscreteFunctionVariant> +pow(const std::shared_ptr<const DiscreteFunctionVariant>& f, const std::shared_ptr<const DiscreteFunctionVariant>& g) +{ + DISCRETE_VH_VH_TO_VH_REAL_FUNCTION_CALL(pow, f, g); +} + +std::shared_ptr<const DiscreteFunctionVariant> +pow(const double a, const std::shared_ptr<const DiscreteFunctionVariant>& f) +{ + DISCRETE_R_VH_TO_VH_REAL_FUNCTION_CALL(pow, a, f); +} + +std::shared_ptr<const DiscreteFunctionVariant> +pow(const std::shared_ptr<const DiscreteFunctionVariant>& f, const double a) +{ + DISCRETE_VH_R_TO_VH_REAL_FUNCTION_CALL(pow, f, a); +} + +std::shared_ptr<const DiscreteFunctionVariant> +dot(const std::shared_ptr<const DiscreteFunctionVariant>& f_v, + const std::shared_ptr<const DiscreteFunctionVariant>& g_v) +{ + if (not hasSameMesh({f_v, g_v})) { + throw NormalError("operands are defined on different meshes"); + } + + return std::visit( + [&](auto&& f, auto&& g) -> std::shared_ptr<DiscreteFunctionVariant> { + using TypeOfF = std::decay_t<decltype(f)>; + using TypeOfG = std::decay_t<decltype(g)>; + if constexpr (not std::is_same_v<TypeOfF, TypeOfG>) { + throw NormalError(EmbeddedDiscreteFunctionUtils::incompatibleOperandTypes(f, g)); + } else { + using DataType = std::decay_t<typename TypeOfF::data_type>; + if constexpr (is_discrete_function_P0_v<TypeOfF>) { + if constexpr (is_tiny_vector_v<DataType>) { + return std::make_shared<DiscreteFunctionVariant>(dot(f, g)); + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::invalidOperandType(f)); + } + } else if constexpr (is_discrete_function_P0_vector_v<TypeOfF>) { + if (f.size() == g.size()) { + return std::make_shared<DiscreteFunctionVariant>(dot(f, g)); + } else { + throw NormalError("operands have different dimension"); + } + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::invalidOperandType(f)); + } + } + }, + f_v->discreteFunction(), g_v->discreteFunction()); +} + +template <size_t VectorDimension> +std::shared_ptr<const DiscreteFunctionVariant> +dot(const std::shared_ptr<const DiscreteFunctionVariant>& f, const TinyVector<VectorDimension>& a) +{ + return std::visit( + [&](auto&& discrete_function0) -> std::shared_ptr<DiscreteFunctionVariant> { + using DiscreteFunction0Type = std::decay_t<decltype(discrete_function0)>; + if constexpr (is_discrete_function_P0_v<DiscreteFunction0Type>) { + using DataType = std::decay_t<typename DiscreteFunction0Type::data_type>; + if constexpr (is_tiny_vector_v<DataType>) { + if constexpr (std::is_same_v<DataType, TinyVector<VectorDimension>>) { + return std::make_shared<DiscreteFunctionVariant>(dot(discrete_function0, a)); + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::incompatibleOperandTypes(f, a)); + } + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::invalidOperandType(f)); + } + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::invalidOperandType(f)); + } + }, + f->discreteFunction()); +} + +template <size_t VectorDimension> +std::shared_ptr<const DiscreteFunctionVariant> +dot(const TinyVector<VectorDimension>& a, const std::shared_ptr<const DiscreteFunctionVariant>& f) +{ + return std::visit( + [&](auto&& discrete_function0) -> std::shared_ptr<DiscreteFunctionVariant> { + using DiscreteFunction0Type = std::decay_t<decltype(discrete_function0)>; + if constexpr (is_discrete_function_P0_v<DiscreteFunction0Type>) { + using DataType = std::decay_t<typename DiscreteFunction0Type::data_type>; + if constexpr (is_tiny_vector_v<DataType>) { + if constexpr (std::is_same_v<DataType, TinyVector<VectorDimension>>) { + return std::make_shared<DiscreteFunctionVariant>(dot(a, discrete_function0)); + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::incompatibleOperandTypes(a, f)); + } + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::invalidOperandType(f)); + } + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::invalidOperandType(f)); + } + }, + f->discreteFunction()); +} + +template std::shared_ptr<const DiscreteFunctionVariant> dot(const std::shared_ptr<const DiscreteFunctionVariant>&, + const TinyVector<1>&); + +template std::shared_ptr<const DiscreteFunctionVariant> dot(const std::shared_ptr<const DiscreteFunctionVariant>&, + const TinyVector<2>&); + +template std::shared_ptr<const DiscreteFunctionVariant> dot(const std::shared_ptr<const DiscreteFunctionVariant>&, + const TinyVector<3>&); + +template std::shared_ptr<const DiscreteFunctionVariant> dot(const TinyVector<1>&, + const std::shared_ptr<const DiscreteFunctionVariant>&); + +template std::shared_ptr<const DiscreteFunctionVariant> dot(const TinyVector<2>&, + const std::shared_ptr<const DiscreteFunctionVariant>&); + +template std::shared_ptr<const DiscreteFunctionVariant> dot(const TinyVector<3>&, + const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> +det(const std::shared_ptr<const DiscreteFunctionVariant>& A) +{ + return std::visit( + [&](auto&& discrete_function) -> std::shared_ptr<DiscreteFunctionVariant> { + using DiscreteFunctionType = std::decay_t<decltype(discrete_function)>; + if constexpr (is_discrete_function_P0_v<DiscreteFunctionType>) { + if constexpr (is_tiny_matrix_v<std::decay_t<typename DiscreteFunctionType::data_type>>) { + if constexpr (DiscreteFunctionType::data_type::NumberOfRows == + DiscreteFunctionType::data_type::NumberOfColumns) { + return std::make_shared<DiscreteFunctionVariant>(det(discrete_function)); + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::invalidOperandType(A)); + } + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::invalidOperandType(A)); + } + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::invalidOperandType(A)); + } + }, + A->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +trace(const std::shared_ptr<const DiscreteFunctionVariant>& A) +{ + return std::visit( + [&](auto&& discrete_function) -> std::shared_ptr<DiscreteFunctionVariant> { + using DiscreteFunctionType = std::decay_t<decltype(discrete_function)>; + if constexpr (is_discrete_function_P0_v<DiscreteFunctionType>) { + if constexpr (is_tiny_matrix_v<std::decay_t<typename DiscreteFunctionType::data_type>>) { + if constexpr (DiscreteFunctionType::data_type::NumberOfRows == + DiscreteFunctionType::data_type::NumberOfColumns) { + return std::make_shared<DiscreteFunctionVariant>(trace(discrete_function)); + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::invalidOperandType(A)); + } + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::invalidOperandType(A)); + } + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::invalidOperandType(A)); + } + }, + A->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +inverse(const std::shared_ptr<const DiscreteFunctionVariant>& A) +{ + return std::visit( + [&](auto&& discrete_function) -> std::shared_ptr<DiscreteFunctionVariant> { + using DiscreteFunctionType = std::decay_t<decltype(discrete_function)>; + if constexpr (is_discrete_function_P0_v<DiscreteFunctionType>) { + if constexpr (is_tiny_matrix_v<std::decay_t<typename DiscreteFunctionType::data_type>>) { + if constexpr (DiscreteFunctionType::data_type::NumberOfRows == + DiscreteFunctionType::data_type::NumberOfColumns) { + return std::make_shared<DiscreteFunctionVariant>(inverse(discrete_function)); + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::invalidOperandType(A)); + } + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::invalidOperandType(A)); + } + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::invalidOperandType(A)); + } + }, + A->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +transpose(const std::shared_ptr<const DiscreteFunctionVariant>& A) +{ + return std::visit( + [&](auto&& discrete_function) -> std::shared_ptr<DiscreteFunctionVariant> { + using DiscreteFunctionType = std::decay_t<decltype(discrete_function)>; + if constexpr (is_discrete_function_P0_v<DiscreteFunctionType>) { + if constexpr (is_tiny_matrix_v<std::decay_t<typename DiscreteFunctionType::data_type>>) { + if constexpr (DiscreteFunctionType::data_type::NumberOfRows == + DiscreteFunctionType::data_type::NumberOfColumns) { + return std::make_shared<DiscreteFunctionVariant>(transpose(discrete_function)); + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::invalidOperandType(A)); + } + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::invalidOperandType(A)); + } + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::invalidOperandType(A)); + } + }, + A->discreteFunction()); +} + +double +min(const std::shared_ptr<const DiscreteFunctionVariant>& f) +{ + DISCRETE_VH_TO_R_CALL(min, f); +} + +std::shared_ptr<const DiscreteFunctionVariant> +min(const std::shared_ptr<const DiscreteFunctionVariant>& f, const std::shared_ptr<const DiscreteFunctionVariant>& g) +{ + DISCRETE_VH_VH_TO_VH_REAL_FUNCTION_CALL(min, f, g); +} + +std::shared_ptr<const DiscreteFunctionVariant> +min(const double a, const std::shared_ptr<const DiscreteFunctionVariant>& f) +{ + DISCRETE_R_VH_TO_VH_REAL_FUNCTION_CALL(min, a, f); +} + +std::shared_ptr<const DiscreteFunctionVariant> +min(const std::shared_ptr<const DiscreteFunctionVariant>& f, const double a) +{ + DISCRETE_VH_R_TO_VH_REAL_FUNCTION_CALL(min, f, a); +} + +double +max(const std::shared_ptr<const DiscreteFunctionVariant>& f) +{ + DISCRETE_VH_TO_R_CALL(max, f); +} + +std::shared_ptr<const DiscreteFunctionVariant> +max(const std::shared_ptr<const DiscreteFunctionVariant>& f, const std::shared_ptr<const DiscreteFunctionVariant>& g) +{ + DISCRETE_VH_VH_TO_VH_REAL_FUNCTION_CALL(max, f, g); +} + +std::shared_ptr<const DiscreteFunctionVariant> +max(const double a, const std::shared_ptr<const DiscreteFunctionVariant>& f) +{ + DISCRETE_R_VH_TO_VH_REAL_FUNCTION_CALL(max, a, f); +} + +std::shared_ptr<const DiscreteFunctionVariant> +max(const std::shared_ptr<const DiscreteFunctionVariant>& f, const double a) +{ + DISCRETE_VH_R_TO_VH_REAL_FUNCTION_CALL(max, f, a); +} + +template <typename ValueT> +ValueT +sum_of(const std::shared_ptr<const DiscreteFunctionVariant>& f) +{ + ValueT value; + std::visit( + [&](auto&& discrete_function) { + using DiscreteFunctionType = std::decay_t<decltype(discrete_function)>; + if constexpr (is_discrete_function_P0_v<DiscreteFunctionType>) { + using DataType = std::decay_t<typename DiscreteFunctionType::data_type>; + if constexpr (std::is_same_v<ValueT, DataType>) { + value = sum(discrete_function); + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::invalidOperandType(f)); + } + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::invalidOperandType(f)); + } + }, + f->discreteFunction()); + + return value; +} + +std::shared_ptr<const DiscreteFunctionVariant> +sum_of_Vh_components(const std::shared_ptr<const DiscreteFunctionVariant>& f) +{ + return std::visit( + [&](auto&& discrete_function) -> std::shared_ptr<const DiscreteFunctionVariant> { + using DiscreteFunctionType = std::decay_t<decltype(discrete_function)>; + if constexpr (is_discrete_function_P0_vector_v<DiscreteFunctionType>) { + using DataType = std::decay_t<typename DiscreteFunctionType::data_type>; + static_assert(std::is_same_v<DataType, double>); + return std::make_shared<DiscreteFunctionVariant>(sumOfComponents(discrete_function)); + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::invalidOperandType(f)); + } + }, + f->discreteFunction()); +} + +template <size_t Dimension> +void +vectorize_to(const std::vector<std::shared_ptr<const DiscreteFunctionVariant>>& discrete_function_list, + const Mesh<Connectivity<Dimension>>& mesh, + DiscreteFunctionP0Vector<Dimension, double>& discrete_vector_function) +{ + if (hasSameMesh(discrete_function_list)) { + for (size_t i_discrete_function = 0; i_discrete_function < discrete_function_list.size(); ++i_discrete_function) { + std::visit( + [&](auto&& discrete_function) { + using DiscreteFunctionType = std::decay_t<decltype(discrete_function)>; + if constexpr (is_discrete_function_P0_v<DiscreteFunctionType>) { + using DataType = std::remove_const_t<typename DiscreteFunctionType::data_type>; + if constexpr (std::is_same_v<DataType, double> and + (Dimension == DiscreteFunctionType::MeshType::Dimension)) { + const auto& connectivity = mesh.connectivity(); + parallel_for( + connectivity.numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + discrete_vector_function[cell_id][i_discrete_function] = discrete_function[cell_id]; + }); + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::invalidOperandType(discrete_function)); + } + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::invalidOperandType(discrete_function)); + } + }, + discrete_function_list[i_discrete_function]->discreteFunction()); + } + + } else { + throw NormalError("discrete functions are not defined on the same mesh"); + } +} + +std::shared_ptr<const DiscreteFunctionVariant> +vectorize(const std::vector<std::shared_ptr<const DiscreteFunctionVariant>>& discrete_function_list) +{ + if (hasSameMesh(discrete_function_list)) { + std::shared_ptr p_i_mesh = getCommonMesh(discrete_function_list); + Assert(p_i_mesh.use_count() > 0); + + switch (p_i_mesh->dimension()) { + case 1: { + constexpr size_t Dimension = 1; + using DiscreteFunctionVectorType = DiscreteFunctionP0Vector<Dimension, double>; + std::shared_ptr<const Mesh<Connectivity<Dimension>>> p_mesh = + std::dynamic_pointer_cast<const Mesh<Connectivity<Dimension>>>(p_i_mesh); + + DiscreteFunctionVectorType vector_function(p_mesh, discrete_function_list.size()); + vectorize_to(discrete_function_list, *p_mesh, vector_function); + + return std::make_shared<DiscreteFunctionVariant>(vector_function); + } + case 2: { + constexpr size_t Dimension = 2; + using DiscreteFunctionVectorType = DiscreteFunctionP0Vector<Dimension, double>; + std::shared_ptr<const Mesh<Connectivity<Dimension>>> p_mesh = + std::dynamic_pointer_cast<const Mesh<Connectivity<Dimension>>>(p_i_mesh); + + DiscreteFunctionVectorType vector_function(p_mesh, discrete_function_list.size()); + vectorize_to(discrete_function_list, *p_mesh, vector_function); + + return std::make_shared<DiscreteFunctionVariant>(vector_function); + } + case 3: { + constexpr size_t Dimension = 3; + using DiscreteFunctionVectorType = DiscreteFunctionP0Vector<Dimension, double>; + std::shared_ptr<const Mesh<Connectivity<Dimension>>> p_mesh = + std::dynamic_pointer_cast<const Mesh<Connectivity<Dimension>>>(p_i_mesh); + + DiscreteFunctionVectorType vector_function(p_mesh, discrete_function_list.size()); + vectorize_to(discrete_function_list, *p_mesh, vector_function); + + return std::make_shared<DiscreteFunctionVariant>(vector_function); + } + // LCOV_EXCL_START + default: { + throw UnexpectedError("invalid mesh dimension"); + } + // LCOV_EXCL_STOP + } + } else { + throw NormalError("discrete functions are not defined on the same mesh"); + } +} + +template double sum_of<double>(const std::shared_ptr<const DiscreteFunctionVariant>&); + +template TinyVector<1> sum_of<TinyVector<1>>(const std::shared_ptr<const DiscreteFunctionVariant>&); + +template TinyVector<2> sum_of<TinyVector<2>>(const std::shared_ptr<const DiscreteFunctionVariant>&); + +template TinyVector<3> sum_of<TinyVector<3>>(const std::shared_ptr<const DiscreteFunctionVariant>&); + +template TinyMatrix<1> sum_of<TinyMatrix<1>>(const std::shared_ptr<const DiscreteFunctionVariant>&); + +template TinyMatrix<2> sum_of<TinyMatrix<2>>(const std::shared_ptr<const DiscreteFunctionVariant>&); + +template TinyMatrix<3> sum_of<TinyMatrix<3>>(const std::shared_ptr<const DiscreteFunctionVariant>&); + +template <typename ValueT> +ValueT +integral_of(const std::shared_ptr<const DiscreteFunctionVariant>& f) +{ + return std::visit( + [&](auto&& discrete_function) -> ValueT { + using DiscreteFunctionType = std::decay_t<decltype(discrete_function)>; + if constexpr (is_discrete_function_P0_v<DiscreteFunctionType>) { + using DataType = std::decay_t<typename DiscreteFunctionType::data_type>; + if constexpr (std::is_same_v<ValueT, DataType>) { + return integrate(discrete_function); + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::invalidOperandType(f)); + } + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::invalidOperandType(f)); + } + }, + f->discreteFunction()); +} + +template double integral_of<double>(const std::shared_ptr<const DiscreteFunctionVariant>&); + +template TinyVector<1> integral_of<TinyVector<1>>(const std::shared_ptr<const DiscreteFunctionVariant>&); + +template TinyVector<2> integral_of<TinyVector<2>>(const std::shared_ptr<const DiscreteFunctionVariant>&); + +template TinyVector<3> integral_of<TinyVector<3>>(const std::shared_ptr<const DiscreteFunctionVariant>&); + +template TinyMatrix<1> integral_of<TinyMatrix<1>>(const std::shared_ptr<const DiscreteFunctionVariant>&); + +template TinyMatrix<2> integral_of<TinyMatrix<2>>(const std::shared_ptr<const DiscreteFunctionVariant>&); + +template TinyMatrix<3> integral_of<TinyMatrix<3>>(const std::shared_ptr<const DiscreteFunctionVariant>&); diff --git a/src/language/utils/EmbeddedDiscreteFunctionMathFunctions.hpp b/src/language/utils/EmbeddedDiscreteFunctionMathFunctions.hpp new file mode 100644 index 0000000000000000000000000000000000000000..66b784921da372cc7dfa2d616b94d6fbfe403ee3 --- /dev/null +++ b/src/language/utils/EmbeddedDiscreteFunctionMathFunctions.hpp @@ -0,0 +1,110 @@ +#ifndef EMBEDDED_DISCRETE_FUNCTION_MATH_FUNCTIONS_HPP +#define EMBEDDED_DISCRETE_FUNCTION_MATH_FUNCTIONS_HPP + +#include <algebra/TinyMatrix.hpp> +#include <algebra/TinyVector.hpp> + +#include <memory> + +class DiscreteFunctionVariant; + +std::shared_ptr<const DiscreteFunctionVariant> sqrt(const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> sqrt(const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> abs(const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> sin(const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> cos(const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> tan(const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> asin(const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> acos(const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> atan(const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> atan2(const std::shared_ptr<const DiscreteFunctionVariant>&, + const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> atan2(const double, + const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> atan2(const std::shared_ptr<const DiscreteFunctionVariant>&, + const double); + +std::shared_ptr<const DiscreteFunctionVariant> sinh(const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> cosh(const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> tanh(const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> asinh(const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> acosh(const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> atanh(const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> exp(const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> log(const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> pow(const std::shared_ptr<const DiscreteFunctionVariant>&, + const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> pow(const double, const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> pow(const std::shared_ptr<const DiscreteFunctionVariant>&, const double); + +std::shared_ptr<const DiscreteFunctionVariant> dot(const std::shared_ptr<const DiscreteFunctionVariant>&, + const std::shared_ptr<const DiscreteFunctionVariant>&); + +template <size_t VectorDimension> +std::shared_ptr<const DiscreteFunctionVariant> dot(const std::shared_ptr<const DiscreteFunctionVariant>&, + const TinyVector<VectorDimension>&); + +template <size_t VectorDimension> +std::shared_ptr<const DiscreteFunctionVariant> dot(const TinyVector<VectorDimension>&, + const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> det(const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> trace(const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> inverse(const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> transpose(const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> sum_of_Vh_components( + const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> vectorize( + const std::vector<std::shared_ptr<const DiscreteFunctionVariant>>& discrete_function_list); + +double min(const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> min(const std::shared_ptr<const DiscreteFunctionVariant>&, + const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> min(const double, const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> min(const std::shared_ptr<const DiscreteFunctionVariant>&, const double); + +double max(const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> max(const std::shared_ptr<const DiscreteFunctionVariant>&, + const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> max(const double, const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> max(const std::shared_ptr<const DiscreteFunctionVariant>&, const double); + +template <typename ValueT> +ValueT sum_of(const std::shared_ptr<const DiscreteFunctionVariant>&); + +template <typename ValueT> +ValueT integral_of(const std::shared_ptr<const DiscreteFunctionVariant>&); + +#endif // EMBEDDED_DISCRETE_FUNCTION_MATH_FUNCTIONS_HPP diff --git a/src/language/utils/EmbeddedDiscreteFunctionOperators.cpp b/src/language/utils/EmbeddedDiscreteFunctionOperators.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0b47153cf0660abd807774d477e7fcd8ae712b62 --- /dev/null +++ b/src/language/utils/EmbeddedDiscreteFunctionOperators.cpp @@ -0,0 +1,671 @@ +#include <language/utils/EmbeddedDiscreteFunctionOperators.hpp> + +#include <language/node_processor/BinaryExpressionProcessor.hpp> +#include <language/node_processor/UnaryExpressionProcessor.hpp> +#include <language/utils/EmbeddedDiscreteFunctionUtils.hpp> +#include <scheme/DiscreteFunctionP0.hpp> +#include <scheme/DiscreteFunctionP0Vector.hpp> +#include <scheme/DiscreteFunctionUtils.hpp> +#include <utils/Exceptions.hpp> + +// unary operators + +template <typename UnaryOperatorT, typename DiscreteFunctionT> +std::shared_ptr<const DiscreteFunctionVariant> +applyUnaryOperation(const DiscreteFunctionT& f) +{ + return std::make_shared<DiscreteFunctionVariant>(UnaryOp<UnaryOperatorT>{}.eval(f)); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator-(const std::shared_ptr<const DiscreteFunctionVariant>& f_v) +{ + return std::visit( + [&](auto&& f) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyUnaryOperation<language::unary_minus>(f); + }, + f_v->discreteFunction()); +} + +// binary operators + +template <typename DiscreteFunctionT, typename BinOperatorT> +std::shared_ptr<const DiscreteFunctionVariant> +innerCompositionLaw(const DiscreteFunctionT& f, const DiscreteFunctionT& g) +{ + using data_type = std::decay_t<typename DiscreteFunctionT::data_type>; + if constexpr ((std::is_same_v<language::multiply_op, BinOperatorT> and is_tiny_vector_v<data_type>) or + (std::is_same_v<language::divide_op, BinOperatorT> and not std::is_arithmetic_v<data_type>)) { + throw NormalError(EmbeddedDiscreteFunctionUtils::incompatibleOperandTypes(f, g)); + } else { + if constexpr (is_discrete_function_P0_vector_v<DiscreteFunctionT>) { + if (f.size() != g.size()) { + std::ostringstream error_msg; + error_msg << EmbeddedDiscreteFunctionUtils::getOperandTypeName(f) << " spaces have different sizes"; + throw NormalError(error_msg.str()); + } else { + return std::make_shared<DiscreteFunctionVariant>(BinOp<BinOperatorT>{}.eval(f, g)); + } + } else { + return std::make_shared<DiscreteFunctionVariant>(BinOp<BinOperatorT>{}.eval(f, g)); + } + } +} + +template <typename DiscreteFunctionT1, typename DiscreteFunctionT2, typename BinOperatorT> +std::shared_ptr<const DiscreteFunctionVariant> +applyBinaryOperation(const DiscreteFunctionT1& f, const DiscreteFunctionT2& g) +{ + using f_data_type = std::decay_t<typename DiscreteFunctionT1::data_type>; + using g_data_type = std::decay_t<typename DiscreteFunctionT2::data_type>; + if constexpr (std::is_same_v<language::multiply_op, BinOperatorT>) { + if constexpr (is_discrete_function_P0_v<DiscreteFunctionT1> and + is_discrete_function_P0_vector_v<DiscreteFunctionT2> and std::is_same_v<double, f_data_type>) { + return std::make_shared<DiscreteFunctionVariant>(BinOp<BinOperatorT>{}.eval(f, g)); + } else if constexpr (is_discrete_function_P0_v<DiscreteFunctionT1> and + is_discrete_function_P0_v<DiscreteFunctionT2>) { + if constexpr (std::is_same_v<double, f_data_type> and + (is_tiny_vector_v<g_data_type> or is_tiny_matrix_v<g_data_type>)) { + return std::make_shared<DiscreteFunctionVariant>(BinOp<BinOperatorT>{}.eval(f, g)); + } else if constexpr (is_tiny_matrix_v<f_data_type> and is_tiny_vector_v<g_data_type>) { + if constexpr (f_data_type::NumberOfColumns == g_data_type::Dimension) { + return std::make_shared<DiscreteFunctionVariant>(BinOp<BinOperatorT>{}.eval(f, g)); + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::incompatibleOperandTypes(f, g)); + } + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::incompatibleOperandTypes(f, g)); + } + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::incompatibleOperandTypes(f, g)); + } + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::incompatibleOperandTypes(f, g)); + } +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator+(const std::shared_ptr<const DiscreteFunctionVariant>& f_v, + const std::shared_ptr<const DiscreteFunctionVariant>& g_v) +{ + if (not hasSameMesh({f_v, g_v})) { + throw NormalError("operands are defined on different meshes"); + } + + return std::visit( + [&](auto&& f, auto&& g) -> std::shared_ptr<const DiscreteFunctionVariant> { + using TypeOfF = std::decay_t<decltype(f)>; + using TypeOfG = std::decay_t<decltype(g)>; + if constexpr (std::is_same_v<TypeOfF, TypeOfG>) { + return innerCompositionLaw<TypeOfF, language::plus_op>(f, g); + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::incompatibleOperandTypes(f_v, g_v)); + } + }, + f_v->discreteFunction(), g_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator-(const std::shared_ptr<const DiscreteFunctionVariant>& f_v, + const std::shared_ptr<const DiscreteFunctionVariant>& g_v) +{ + if (not hasSameMesh({f_v, g_v})) { + throw NormalError("operands are defined on different meshes"); + } + + return std::visit( + [&](auto&& f, auto&& g) -> std::shared_ptr<const DiscreteFunctionVariant> { + using TypeOfF = std::decay_t<decltype(f)>; + using TypeOfG = std::decay_t<decltype(g)>; + if constexpr (std::is_same_v<TypeOfF, TypeOfG>) { + return innerCompositionLaw<TypeOfF, language::minus_op>(f, g); + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::incompatibleOperandTypes(f_v, g_v)); + } + }, + f_v->discreteFunction(), g_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator*(const std::shared_ptr<const DiscreteFunctionVariant>& f_v, + const std::shared_ptr<const DiscreteFunctionVariant>& g_v) +{ + if (not hasSameMesh({f_v, g_v})) { + throw NormalError("operands are defined on different meshes"); + } + + return std::visit( + [&](auto&& f, auto&& g) -> std::shared_ptr<const DiscreteFunctionVariant> { + using TypeOfF = std::decay_t<decltype(f)>; + using TypeOfG = std::decay_t<decltype(g)>; + if constexpr (std::is_same_v<TypeOfF, TypeOfG> and not is_discrete_function_P0_vector_v<TypeOfF>) { + return innerCompositionLaw<TypeOfF, language::multiply_op>(f, g); + } else { + if constexpr (std::is_same_v<typename TypeOfF::MeshType, typename TypeOfG::MeshType>) { + return applyBinaryOperation<TypeOfF, TypeOfG, language::multiply_op>(f, g); + } else { + // LCOV_EXCL_START + throw UnexpectedError("operands are defined on different meshes"); + // LCOV_EXCL_STOP + } + } + }, + f_v->discreteFunction(), g_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator/(const std::shared_ptr<const DiscreteFunctionVariant>& f_v, + const std::shared_ptr<const DiscreteFunctionVariant>& g_v) +{ + if (not hasSameMesh({f_v, g_v})) { + throw NormalError("operands are defined on different meshes"); + } + + return std::visit( + [&](auto&& f, auto&& g) -> std::shared_ptr<const DiscreteFunctionVariant> { + using TypeOfF = std::decay_t<decltype(f)>; + using TypeOfG = std::decay_t<decltype(g)>; + if constexpr (std::is_same_v<TypeOfF, TypeOfG> and not is_discrete_function_P0_vector_v<TypeOfF>) { + return innerCompositionLaw<TypeOfF, language::divide_op>(f, g); + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::incompatibleOperandTypes(f_v, g_v)); + } + }, + f_v->discreteFunction(), g_v->discreteFunction()); +} + +template <typename BinOperatorT, typename DataType, typename DiscreteFunctionT> +std::shared_ptr<const DiscreteFunctionVariant> +applyBinaryOperationWithLeftConstant(const DataType& a, const DiscreteFunctionT& f) +{ + if constexpr (is_discrete_function_P0_v<DiscreteFunctionT>) { + using lhs_data_type = std::decay_t<DataType>; + using rhs_data_type = std::decay_t<typename DiscreteFunctionT::data_type>; + + if constexpr (std::is_same_v<language::multiply_op, BinOperatorT>) { + if constexpr (std::is_same_v<lhs_data_type, double>) { + return std::make_shared<DiscreteFunctionVariant>(BinOp<BinOperatorT>{}.eval(a, f)); + } else if constexpr (is_tiny_matrix_v<lhs_data_type> and std::is_same_v<lhs_data_type, rhs_data_type>) { + return std::make_shared<DiscreteFunctionVariant>(BinOp<BinOperatorT>{}.eval(a, f)); + } else if constexpr (is_tiny_matrix_v<lhs_data_type> and is_tiny_vector_v<rhs_data_type>) { + if constexpr (lhs_data_type::NumberOfColumns == rhs_data_type::Dimension) { + return std::make_shared<DiscreteFunctionVariant>(BinOp<BinOperatorT>{}.eval(a, f)); + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::incompatibleOperandTypes(a, f)); + } + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::incompatibleOperandTypes(a, f)); + } + } else if constexpr (std::is_same_v<language::divide_op, BinOperatorT>) { + if constexpr (std::is_same_v<lhs_data_type, double> and std::is_same_v<rhs_data_type, double>) { + return std::make_shared<DiscreteFunctionVariant>(BinOp<BinOperatorT>{}.eval(a, f)); + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::incompatibleOperandTypes(a, f)); + } + } else if constexpr (std::is_same_v<language::plus_op, BinOperatorT> or + std::is_same_v<language::minus_op, BinOperatorT>) { + if constexpr ((std::is_same_v<rhs_data_type, lhs_data_type>) or + (std::is_arithmetic_v<rhs_data_type> and std::is_arithmetic_v<lhs_data_type>)) { + return std::make_shared<DiscreteFunctionVariant>(BinOp<BinOperatorT>{}.eval(a, f)); + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::incompatibleOperandTypes(a, f)); + } + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::incompatibleOperandTypes(a, f)); + } + } else if constexpr (is_discrete_function_P0_vector_v<DiscreteFunctionT> and + std::is_same_v<language::multiply_op, BinOperatorT>) { + using lhs_data_type = std::decay_t<DataType>; + if constexpr (std::is_same_v<lhs_data_type, double>) { + return std::make_shared<DiscreteFunctionVariant>(BinOp<BinOperatorT>{}.eval(a, f)); + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::incompatibleOperandTypes(a, f)); + } + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::incompatibleOperandTypes(a, f)); + } +} + +template <typename BinOperatorT, typename DataType, typename DiscreteFunctionT> +std::shared_ptr<const DiscreteFunctionVariant> +applyBinaryOperationWithRightConstant(const DiscreteFunctionT& f, const DataType& a) +{ + if constexpr (is_discrete_function_P0_v<DiscreteFunctionT>) { + using lhs_data_type = std::decay_t<typename DiscreteFunctionT::data_type>; + using rhs_data_type = std::decay_t<DataType>; + + if constexpr (std::is_same_v<language::multiply_op, BinOperatorT>) { + if constexpr (is_tiny_matrix_v<lhs_data_type> and is_tiny_matrix_v<rhs_data_type>) { + if constexpr (lhs_data_type::NumberOfColumns == rhs_data_type::NumberOfRows) { + return std::make_shared<DiscreteFunctionVariant>(BinOp<BinOperatorT>{}.eval(f, a)); + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::incompatibleOperandTypes(f, a)); + } + } else if constexpr (is_tiny_matrix_v<lhs_data_type> and is_tiny_vector_v<rhs_data_type>) { + if constexpr (lhs_data_type::NumberOfColumns == rhs_data_type::Dimension) { + return std::make_shared<DiscreteFunctionVariant>(BinOp<BinOperatorT>{}.eval(f, a)); + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::incompatibleOperandTypes(f, a)); + } + } else if constexpr (std::is_same_v<lhs_data_type, double> and + (is_tiny_matrix_v<rhs_data_type> or is_tiny_vector_v<rhs_data_type> or + std::is_arithmetic_v<rhs_data_type>)) { + return std::make_shared<DiscreteFunctionVariant>(BinOp<BinOperatorT>{}.eval(f, a)); + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::incompatibleOperandTypes(f, a)); + } + } else if constexpr (std::is_same_v<language::plus_op, BinOperatorT> or + std::is_same_v<language::minus_op, BinOperatorT>) { + if constexpr ((std::is_same_v<lhs_data_type, rhs_data_type>) or + (std::is_arithmetic_v<lhs_data_type> and std::is_arithmetic_v<rhs_data_type>)) { + return std::make_shared<DiscreteFunctionVariant>(BinOp<BinOperatorT>{}.eval(f, a)); + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::incompatibleOperandTypes(f, a)); + } + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::incompatibleOperandTypes(f, a)); + } + } else { + throw NormalError(EmbeddedDiscreteFunctionUtils::incompatibleOperandTypes(f, a)); + } +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator+(const double& f, const std::shared_ptr<const DiscreteFunctionVariant>& g_v) +{ + return std::visit( + [&](auto&& g) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithLeftConstant<language::plus_op>(f, g); + }, + g_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator+(const TinyVector<1>& v, const std::shared_ptr<const DiscreteFunctionVariant>& g_v) +{ + return std::visit( + [&](auto&& g) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithLeftConstant<language::plus_op>(v, g); + }, + g_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator+(const TinyVector<2>& v, const std::shared_ptr<const DiscreteFunctionVariant>& g_v) +{ + return std::visit( + [&](auto&& g) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithLeftConstant<language::plus_op>(v, g); + }, + g_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator+(const TinyVector<3>& v, const std::shared_ptr<const DiscreteFunctionVariant>& g_v) +{ + return std::visit( + [&](auto&& g) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithLeftConstant<language::plus_op>(v, g); + }, + g_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator+(const TinyMatrix<1>& A, const std::shared_ptr<const DiscreteFunctionVariant>& g_v) +{ + return std::visit( + [&](auto&& g) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithLeftConstant<language::plus_op>(A, g); + }, + g_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator+(const TinyMatrix<2>& A, const std::shared_ptr<const DiscreteFunctionVariant>& g_v) +{ + return std::visit( + [&](auto&& g) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithLeftConstant<language::plus_op>(A, g); + }, + g_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator+(const TinyMatrix<3>& A, const std::shared_ptr<const DiscreteFunctionVariant>& g_v) +{ + return std::visit( + [&](auto&& g) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithLeftConstant<language::plus_op>(A, g); + }, + g_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator+(const std::shared_ptr<const DiscreteFunctionVariant>& f_v, const double& g) +{ + return std::visit( + [&](auto&& f) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithRightConstant<language::plus_op>(f, g); + }, + f_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator+(const std::shared_ptr<const DiscreteFunctionVariant>& f_v, const TinyVector<1>& v) +{ + return std::visit( + [&](auto&& f) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithRightConstant<language::plus_op>(f, v); + }, + f_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator+(const std::shared_ptr<const DiscreteFunctionVariant>& f_v, const TinyVector<2>& v) +{ + return std::visit( + [&](auto&& f) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithRightConstant<language::plus_op>(f, v); + }, + f_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator+(const std::shared_ptr<const DiscreteFunctionVariant>& f_v, const TinyVector<3>& v) +{ + return std::visit( + [&](auto&& f) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithRightConstant<language::plus_op>(f, v); + }, + f_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator+(const std::shared_ptr<const DiscreteFunctionVariant>& f_v, const TinyMatrix<1>& A) +{ + return std::visit( + [&](auto&& f) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithRightConstant<language::plus_op>(f, A); + }, + f_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator+(const std::shared_ptr<const DiscreteFunctionVariant>& f_v, const TinyMatrix<2>& A) +{ + return std::visit( + [&](auto&& f) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithRightConstant<language::plus_op>(f, A); + }, + f_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator+(const std::shared_ptr<const DiscreteFunctionVariant>& f_v, const TinyMatrix<3>& A) +{ + return std::visit( + [&](auto&& f) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithRightConstant<language::plus_op>(f, A); + }, + f_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator-(const double& f, const std::shared_ptr<const DiscreteFunctionVariant>& g_v) +{ + return std::visit( + [&](auto&& g) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithLeftConstant<language::minus_op>(f, g); + }, + g_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator-(const TinyVector<1>& v, const std::shared_ptr<const DiscreteFunctionVariant>& g_v) +{ + return std::visit( + [&](auto&& g) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithLeftConstant<language::minus_op>(v, g); + }, + g_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator-(const TinyVector<2>& v, const std::shared_ptr<const DiscreteFunctionVariant>& g_v) +{ + return std::visit( + [&](auto&& g) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithLeftConstant<language::minus_op>(v, g); + }, + g_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator-(const TinyVector<3>& v, const std::shared_ptr<const DiscreteFunctionVariant>& g_v) +{ + return std::visit( + [&](auto&& g) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithLeftConstant<language::minus_op>(v, g); + }, + g_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator-(const TinyMatrix<1>& A, const std::shared_ptr<const DiscreteFunctionVariant>& g_v) +{ + return std::visit( + [&](auto&& g) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithLeftConstant<language::minus_op>(A, g); + }, + g_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator-(const TinyMatrix<2>& A, const std::shared_ptr<const DiscreteFunctionVariant>& g_v) +{ + return std::visit( + [&](auto&& g) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithLeftConstant<language::minus_op>(A, g); + }, + g_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator-(const TinyMatrix<3>& A, const std::shared_ptr<const DiscreteFunctionVariant>& g_v) +{ + return std::visit( + [&](auto&& g) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithLeftConstant<language::minus_op>(A, g); + }, + g_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator-(const std::shared_ptr<const DiscreteFunctionVariant>& f_v, const double& g) +{ + return std::visit( + [&](auto&& f) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithRightConstant<language::minus_op>(f, g); + }, + f_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator-(const std::shared_ptr<const DiscreteFunctionVariant>& f_v, const TinyVector<1>& v) +{ + return std::visit( + [&](auto&& f) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithRightConstant<language::minus_op>(f, v); + }, + f_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator-(const std::shared_ptr<const DiscreteFunctionVariant>& f_v, const TinyVector<2>& v) +{ + return std::visit( + [&](auto&& f) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithRightConstant<language::minus_op>(f, v); + }, + f_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator-(const std::shared_ptr<const DiscreteFunctionVariant>& f_v, const TinyVector<3>& v) +{ + return std::visit( + [&](auto&& f) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithRightConstant<language::minus_op>(f, v); + }, + f_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator-(const std::shared_ptr<const DiscreteFunctionVariant>& f_v, const TinyMatrix<1>& A) +{ + return std::visit( + [&](auto&& f) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithRightConstant<language::minus_op>(f, A); + }, + f_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator-(const std::shared_ptr<const DiscreteFunctionVariant>& f_v, const TinyMatrix<2>& A) +{ + return std::visit( + [&](auto&& f) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithRightConstant<language::minus_op>(f, A); + }, + f_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator-(const std::shared_ptr<const DiscreteFunctionVariant>& f_v, const TinyMatrix<3>& A) +{ + return std::visit( + [&](auto&& f) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithRightConstant<language::minus_op>(f, A); + }, + f_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator*(const double& f, const std::shared_ptr<const DiscreteFunctionVariant>& g_v) +{ + return std::visit( + [&](auto&& g) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithLeftConstant<language::multiply_op>(f, g); + }, + g_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator*(const TinyMatrix<1>& A, const std::shared_ptr<const DiscreteFunctionVariant>& g_v) +{ + return std::visit( + [&](auto&& g) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithLeftConstant<language::multiply_op>(A, g); + }, + g_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator*(const TinyMatrix<2>& A, const std::shared_ptr<const DiscreteFunctionVariant>& g_v) +{ + return std::visit( + [&](auto&& g) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithLeftConstant<language::multiply_op>(A, g); + }, + g_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator*(const TinyMatrix<3>& A, const std::shared_ptr<const DiscreteFunctionVariant>& g_v) +{ + return std::visit( + [&](auto&& g) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithLeftConstant<language::multiply_op>(A, g); + }, + g_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator*(const std::shared_ptr<const DiscreteFunctionVariant>& f_v, const double& g) +{ + return std::visit( + [&](auto&& f) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithRightConstant<language::multiply_op>(f, g); + }, + f_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator*(const std::shared_ptr<const DiscreteFunctionVariant>& f_v, const TinyVector<1>& v) +{ + return std::visit( + [&](auto&& f) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithRightConstant<language::multiply_op>(f, v); + }, + f_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator*(const std::shared_ptr<const DiscreteFunctionVariant>& f_v, const TinyVector<2>& v) +{ + return std::visit( + [&](auto&& f) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithRightConstant<language::multiply_op>(f, v); + }, + f_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator*(const std::shared_ptr<const DiscreteFunctionVariant>& f_v, const TinyVector<3>& v) +{ + return std::visit( + [&](auto&& f) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithRightConstant<language::multiply_op>(f, v); + }, + f_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator*(const std::shared_ptr<const DiscreteFunctionVariant>& f_v, const TinyMatrix<1>& A) +{ + return std::visit( + [&](auto&& f) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithRightConstant<language::multiply_op>(f, A); + }, + f_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator*(const std::shared_ptr<const DiscreteFunctionVariant>& f_v, const TinyMatrix<2>& A) +{ + return std::visit( + [&](auto&& f) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithRightConstant<language::multiply_op>(f, A); + }, + f_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator*(const std::shared_ptr<const DiscreteFunctionVariant>& f_v, const TinyMatrix<3>& A) +{ + return std::visit( + [&](auto&& f) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithRightConstant<language::multiply_op>(f, A); + }, + f_v->discreteFunction()); +} + +std::shared_ptr<const DiscreteFunctionVariant> +operator/(const double& a, const std::shared_ptr<const DiscreteFunctionVariant>& f_v) +{ + return std::visit( + [&](auto&& f) -> std::shared_ptr<const DiscreteFunctionVariant> { // + return applyBinaryOperationWithLeftConstant<language::divide_op>(a, f); + }, + f_v->discreteFunction()); +} diff --git a/src/language/utils/EmbeddedDiscreteFunctionOperators.hpp b/src/language/utils/EmbeddedDiscreteFunctionOperators.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a23ea91a0929a10148d703dd4ec13d703f48e2bf --- /dev/null +++ b/src/language/utils/EmbeddedDiscreteFunctionOperators.hpp @@ -0,0 +1,150 @@ +#ifndef EMBEDDED_DISCRETE_FUNCTION_OPERATORS_HPP +#define EMBEDDED_DISCRETE_FUNCTION_OPERATORS_HPP + +#include <algebra/TinyMatrix.hpp> +#include <algebra/TinyVector.hpp> + +#include <memory> + +class DiscreteFunctionVariant; + +// unary minus +std::shared_ptr<const DiscreteFunctionVariant> operator-(const std::shared_ptr<const DiscreteFunctionVariant>&); + +// sum +std::shared_ptr<const DiscreteFunctionVariant> operator+(const std::shared_ptr<const DiscreteFunctionVariant>&, + const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> operator+(const double&, + const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> operator+(const std::shared_ptr<const DiscreteFunctionVariant>&, + const double&); + +std::shared_ptr<const DiscreteFunctionVariant> operator+(const TinyVector<1>&, + const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> operator+(const TinyVector<2>&, + const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> operator+(const TinyVector<3>&, + const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> operator+(const TinyMatrix<1>&, + const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> operator+(const TinyMatrix<2>&, + const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> operator+(const TinyMatrix<3>&, + const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> operator+(const std::shared_ptr<const DiscreteFunctionVariant>&, + const TinyVector<1>&); + +std::shared_ptr<const DiscreteFunctionVariant> operator+(const std::shared_ptr<const DiscreteFunctionVariant>&, + const TinyVector<2>&); + +std::shared_ptr<const DiscreteFunctionVariant> operator+(const std::shared_ptr<const DiscreteFunctionVariant>&, + const TinyVector<3>&); + +std::shared_ptr<const DiscreteFunctionVariant> operator+(const std::shared_ptr<const DiscreteFunctionVariant>&, + const TinyMatrix<1>&); + +std::shared_ptr<const DiscreteFunctionVariant> operator+(const std::shared_ptr<const DiscreteFunctionVariant>&, + const TinyMatrix<2>&); + +std::shared_ptr<const DiscreteFunctionVariant> operator+(const std::shared_ptr<const DiscreteFunctionVariant>&, + const TinyMatrix<3>&); + +// difference +std::shared_ptr<const DiscreteFunctionVariant> operator-(const std::shared_ptr<const DiscreteFunctionVariant>&, + const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> operator-(const double&, + const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> operator-(const std::shared_ptr<const DiscreteFunctionVariant>&, + const double&); + +std::shared_ptr<const DiscreteFunctionVariant> operator-(const TinyVector<1>&, + const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> operator-(const TinyVector<2>&, + const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> operator-(const TinyVector<3>&, + const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> operator-(const TinyMatrix<1>&, + const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> operator-(const TinyMatrix<2>&, + const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> operator-(const TinyMatrix<3>&, + const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> operator-(const std::shared_ptr<const DiscreteFunctionVariant>&, + const TinyVector<1>&); + +std::shared_ptr<const DiscreteFunctionVariant> operator-(const std::shared_ptr<const DiscreteFunctionVariant>&, + const TinyVector<2>&); + +std::shared_ptr<const DiscreteFunctionVariant> operator-(const std::shared_ptr<const DiscreteFunctionVariant>&, + const TinyVector<3>&); + +std::shared_ptr<const DiscreteFunctionVariant> operator-(const std::shared_ptr<const DiscreteFunctionVariant>&, + const TinyMatrix<1>&); + +std::shared_ptr<const DiscreteFunctionVariant> operator-(const std::shared_ptr<const DiscreteFunctionVariant>&, + const TinyMatrix<2>&); + +std::shared_ptr<const DiscreteFunctionVariant> operator-(const std::shared_ptr<const DiscreteFunctionVariant>&, + const TinyMatrix<3>&); + +// product +std::shared_ptr<const DiscreteFunctionVariant> operator*(const std::shared_ptr<const DiscreteFunctionVariant>&, + const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> operator*(const double&, + const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> operator*(const std::shared_ptr<const DiscreteFunctionVariant>&, + const double&); + +std::shared_ptr<const DiscreteFunctionVariant> operator*(const TinyMatrix<1>&, + const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> operator*(const TinyMatrix<2>&, + const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> operator*(const TinyMatrix<3>&, + const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> operator*(const std::shared_ptr<const DiscreteFunctionVariant>&, + const TinyVector<1>&); + +std::shared_ptr<const DiscreteFunctionVariant> operator*(const std::shared_ptr<const DiscreteFunctionVariant>&, + const TinyVector<2>&); + +std::shared_ptr<const DiscreteFunctionVariant> operator*(const std::shared_ptr<const DiscreteFunctionVariant>&, + const TinyVector<3>&); + +std::shared_ptr<const DiscreteFunctionVariant> operator*(const std::shared_ptr<const DiscreteFunctionVariant>&, + const TinyMatrix<1>&); + +std::shared_ptr<const DiscreteFunctionVariant> operator*(const std::shared_ptr<const DiscreteFunctionVariant>&, + const TinyMatrix<2>&); + +std::shared_ptr<const DiscreteFunctionVariant> operator*(const std::shared_ptr<const DiscreteFunctionVariant>&, + const TinyMatrix<3>&); + +// ratio +std::shared_ptr<const DiscreteFunctionVariant> operator/(const double&, + const std::shared_ptr<const DiscreteFunctionVariant>&); + +std::shared_ptr<const DiscreteFunctionVariant> operator/(const std::shared_ptr<const DiscreteFunctionVariant>&, + const std::shared_ptr<const DiscreteFunctionVariant>&); + +#endif // EMBEDDED_DISCRETE_FUNCTION_OPERATORS_HPP diff --git a/src/language/utils/EmbeddedIDiscreteFunctionUtils.hpp b/src/language/utils/EmbeddedDiscreteFunctionUtils.hpp similarity index 53% rename from src/language/utils/EmbeddedIDiscreteFunctionUtils.hpp rename to src/language/utils/EmbeddedDiscreteFunctionUtils.hpp index 1e61f917dfa448add18b562dd403a70101dbec3b..bca3b6772b7913be46ebee9a7731aa26fb7f7a6d 100644 --- a/src/language/utils/EmbeddedIDiscreteFunctionUtils.hpp +++ b/src/language/utils/EmbeddedDiscreteFunctionUtils.hpp @@ -1,13 +1,15 @@ -#ifndef EMBEDDED_I_DISCRETE_FUNCTION_UTILS_HPP -#define EMBEDDED_I_DISCRETE_FUNCTION_UTILS_HPP +#ifndef EMBEDDED_DISCRETE_FUNCTION_UTILS_HPP +#define EMBEDDED_DISCRETE_FUNCTION_UTILS_HPP #include <language/utils/ASTNodeDataType.hpp> -#include <scheme/IDiscreteFunction.hpp> +#include <scheme/DiscreteFunctionVariant.hpp> #include <scheme/IDiscreteFunctionDescriptor.hpp> +#include <utils/Demangle.hpp> + #include <string> -struct EmbeddedIDiscreteFunctionUtils +struct EmbeddedDiscreteFunctionUtils { template <typename T> static PUGS_INLINE std::string @@ -16,22 +18,16 @@ struct EmbeddedIDiscreteFunctionUtils if constexpr (is_shared_ptr_v<T>) { Assert(t.use_count() > 0, "dangling shared_ptr"); return getOperandTypeName(*t); - } else if constexpr (std::is_base_of_v<IDiscreteFunction, std::decay_t<T>>) { - return "Vh(" + name(t.descriptor().type()) + ':' + dataTypeName(t.dataType()) + ')'; + } else if constexpr (std::is_same_v<DiscreteFunctionVariant, std::decay_t<T>>) { + return std::visit([](auto&& v) -> std::string { return getOperandTypeName(v); }, t.discreteFunction()); + } else if constexpr (is_discrete_function_v<std::decay_t<T>>) { + std::string type_name = "Vh(" + name(t.descriptor().type()) + ':' + dataTypeName(t.dataType()) + ')'; + return type_name; } else { return dataTypeName(ast_node_data_type_from<T>); } } - static bool isSameDiscretization(const IDiscreteFunction& f, const IDiscreteFunction& g); - - static PUGS_INLINE bool - isSameDiscretization(const std::shared_ptr<const IDiscreteFunction>& f, - const std::shared_ptr<const IDiscreteFunction>& g) - { - return isSameDiscretization(*f, *g); - } - template <typename T1, typename T2> PUGS_INLINE static std::string incompatibleOperandTypes(const T1& t1, const T2& t2) @@ -47,4 +43,4 @@ struct EmbeddedIDiscreteFunctionUtils } }; -#endif // EMBEDDED_I_DISCRETE_FUNCTION_UTILS_HPP +#endif // EMBEDDED_DISCRETE_FUNCTION_UTILS_HPP diff --git a/src/language/utils/EmbeddedIDiscreteFunctionMathFunctions.cpp b/src/language/utils/EmbeddedIDiscreteFunctionMathFunctions.cpp deleted file mode 100644 index f49c4c033251bf46d7cd91e7c524af4d146db9d3..0000000000000000000000000000000000000000 --- a/src/language/utils/EmbeddedIDiscreteFunctionMathFunctions.cpp +++ /dev/null @@ -1,834 +0,0 @@ -#include <language/utils/EmbeddedIDiscreteFunctionMathFunctions.hpp> - -#include <language/utils/EmbeddedIDiscreteFunctionUtils.hpp> -#include <mesh/IMesh.hpp> -#include <scheme/DiscreteFunctionP0.hpp> -#include <scheme/DiscreteFunctionP0Vector.hpp> -#include <scheme/DiscreteFunctionUtils.hpp> -#include <scheme/IDiscreteFunction.hpp> -#include <scheme/IDiscreteFunctionDescriptor.hpp> - -#define DISCRETE_VH_TO_VH_REAL_FUNCTION_CALL(FUNCTION, ARG) \ - if (ARG->dataType() == ASTNodeDataType::double_t and ARG->descriptor().type() == DiscreteFunctionType::P0) { \ - switch (ARG->mesh()->dimension()) { \ - case 1: { \ - using DiscreteFunctionType = DiscreteFunctionP0<1, double>; \ - return std::make_shared<const DiscreteFunctionType>(FUNCTION(dynamic_cast<const DiscreteFunctionType&>(*ARG))); \ - } \ - case 2: { \ - using DiscreteFunctionType = DiscreteFunctionP0<2, double>; \ - return std::make_shared<const DiscreteFunctionType>(FUNCTION(dynamic_cast<const DiscreteFunctionType&>(*ARG))); \ - } \ - case 3: { \ - using DiscreteFunctionType = DiscreteFunctionP0<3, double>; \ - return std::make_shared<const DiscreteFunctionType>(FUNCTION(dynamic_cast<const DiscreteFunctionType&>(*ARG))); \ - } \ - default: { \ - throw UnexpectedError("invalid mesh dimension"); \ - } \ - } \ - } else { \ - throw NormalError(EmbeddedIDiscreteFunctionUtils::invalidOperandType(ARG)); \ - } - -std::shared_ptr<const IDiscreteFunction> -sqrt(const std::shared_ptr<const IDiscreteFunction>& f) -{ - DISCRETE_VH_TO_VH_REAL_FUNCTION_CALL(sqrt, f); -} - -std::shared_ptr<const IDiscreteFunction> -abs(const std::shared_ptr<const IDiscreteFunction>& f) -{ - DISCRETE_VH_TO_VH_REAL_FUNCTION_CALL(abs, f); -} - -std::shared_ptr<const IDiscreteFunction> -sin(const std::shared_ptr<const IDiscreteFunction>& f) -{ - DISCRETE_VH_TO_VH_REAL_FUNCTION_CALL(sin, f); -} - -std::shared_ptr<const IDiscreteFunction> -cos(const std::shared_ptr<const IDiscreteFunction>& f) -{ - DISCRETE_VH_TO_VH_REAL_FUNCTION_CALL(cos, f); -} - -std::shared_ptr<const IDiscreteFunction> -tan(const std::shared_ptr<const IDiscreteFunction>& f) -{ - DISCRETE_VH_TO_VH_REAL_FUNCTION_CALL(tan, f); -} - -std::shared_ptr<const IDiscreteFunction> -asin(const std::shared_ptr<const IDiscreteFunction>& f) -{ - DISCRETE_VH_TO_VH_REAL_FUNCTION_CALL(asin, f); -} - -std::shared_ptr<const IDiscreteFunction> -acos(const std::shared_ptr<const IDiscreteFunction>& f) -{ - DISCRETE_VH_TO_VH_REAL_FUNCTION_CALL(acos, f); -} - -std::shared_ptr<const IDiscreteFunction> -atan(const std::shared_ptr<const IDiscreteFunction>& f) -{ - DISCRETE_VH_TO_VH_REAL_FUNCTION_CALL(atan, f); -} - -std::shared_ptr<const IDiscreteFunction> -atan2(const std::shared_ptr<const IDiscreteFunction>& f, const std::shared_ptr<const IDiscreteFunction>& g) -{ - if ((f->dataType() == ASTNodeDataType::double_t and f->descriptor().type() == DiscreteFunctionType::P0) and - (g->dataType() == ASTNodeDataType::double_t and g->descriptor().type() == DiscreteFunctionType::P0)) { - std::shared_ptr mesh = getCommonMesh({f, g}); - - if (mesh.use_count() == 0) { - throw NormalError("operands are defined on different meshes"); - } - - switch (mesh->dimension()) { - case 1: { - using DiscreteFunctionType = DiscreteFunctionP0<1, double>; - return std::make_shared<const DiscreteFunctionType>( - atan2(dynamic_cast<const DiscreteFunctionType&>(*f), dynamic_cast<const DiscreteFunctionType&>(*g))); - } - case 2: { - using DiscreteFunctionType = DiscreteFunctionP0<2, double>; - return std::make_shared<const DiscreteFunctionType>( - atan2(dynamic_cast<const DiscreteFunctionType&>(*f), dynamic_cast<const DiscreteFunctionType&>(*g))); - } - case 3: { - using DiscreteFunctionType = DiscreteFunctionP0<3, double>; - return std::make_shared<const DiscreteFunctionType>( - atan2(dynamic_cast<const DiscreteFunctionType&>(*f), dynamic_cast<const DiscreteFunctionType&>(*g))); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid mesh dimension"); - } - // LCOV_EXCL_STOP - } - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(f, g)); - } -} - -std::shared_ptr<const IDiscreteFunction> -atan2(const double a, const std::shared_ptr<const IDiscreteFunction>& f) -{ - if (f->dataType() == ASTNodeDataType::double_t and f->descriptor().type() == DiscreteFunctionType::P0) { - switch (f->mesh()->dimension()) { - case 1: { - using DiscreteFunctionType = DiscreteFunctionP0<1, double>; - return std::make_shared<const DiscreteFunctionType>(atan2(a, dynamic_cast<const DiscreteFunctionType&>(*f))); - } - case 2: { - using DiscreteFunctionType = DiscreteFunctionP0<2, double>; - return std::make_shared<const DiscreteFunctionType>(atan2(a, dynamic_cast<const DiscreteFunctionType&>(*f))); - } - case 3: { - using DiscreteFunctionType = DiscreteFunctionP0<3, double>; - return std::make_shared<const DiscreteFunctionType>(atan2(a, dynamic_cast<const DiscreteFunctionType&>(*f))); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid mesh dimension"); - } - // LCOV_EXCL_STOP - } - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(a, f)); - } -} - -std::shared_ptr<const IDiscreteFunction> -atan2(const std::shared_ptr<const IDiscreteFunction>& f, const double a) -{ - if (f->dataType() == ASTNodeDataType::double_t and f->descriptor().type() == DiscreteFunctionType::P0) { - switch (f->mesh()->dimension()) { - case 1: { - using DiscreteFunctionType = DiscreteFunctionP0<1, double>; - return std::make_shared<const DiscreteFunctionType>(atan2(dynamic_cast<const DiscreteFunctionType&>(*f), a)); - } - case 2: { - using DiscreteFunctionType = DiscreteFunctionP0<2, double>; - return std::make_shared<const DiscreteFunctionType>(atan2(dynamic_cast<const DiscreteFunctionType&>(*f), a)); - } - case 3: { - using DiscreteFunctionType = DiscreteFunctionP0<3, double>; - return std::make_shared<const DiscreteFunctionType>(atan2(dynamic_cast<const DiscreteFunctionType&>(*f), a)); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid mesh dimension"); - } - // LCOV_EXCL_STOP - } - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(f, a)); - } -} - -std::shared_ptr<const IDiscreteFunction> -sinh(const std::shared_ptr<const IDiscreteFunction>& f) -{ - DISCRETE_VH_TO_VH_REAL_FUNCTION_CALL(sinh, f); -} - -std::shared_ptr<const IDiscreteFunction> -cosh(const std::shared_ptr<const IDiscreteFunction>& f) -{ - DISCRETE_VH_TO_VH_REAL_FUNCTION_CALL(cosh, f); -} - -std::shared_ptr<const IDiscreteFunction> -tanh(const std::shared_ptr<const IDiscreteFunction>& f) -{ - DISCRETE_VH_TO_VH_REAL_FUNCTION_CALL(tanh, f); -} - -std::shared_ptr<const IDiscreteFunction> -asinh(const std::shared_ptr<const IDiscreteFunction>& f) -{ - DISCRETE_VH_TO_VH_REAL_FUNCTION_CALL(asinh, f); -} - -std::shared_ptr<const IDiscreteFunction> -acosh(const std::shared_ptr<const IDiscreteFunction>& f) -{ - DISCRETE_VH_TO_VH_REAL_FUNCTION_CALL(acosh, f); -} - -std::shared_ptr<const IDiscreteFunction> -atanh(const std::shared_ptr<const IDiscreteFunction>& f) -{ - DISCRETE_VH_TO_VH_REAL_FUNCTION_CALL(atanh, f); -} - -std::shared_ptr<const IDiscreteFunction> -exp(const std::shared_ptr<const IDiscreteFunction>& f) -{ - DISCRETE_VH_TO_VH_REAL_FUNCTION_CALL(exp, f); -} - -std::shared_ptr<const IDiscreteFunction> -log(const std::shared_ptr<const IDiscreteFunction>& f) -{ - DISCRETE_VH_TO_VH_REAL_FUNCTION_CALL(log, f); -} - -std::shared_ptr<const IDiscreteFunction> -pow(const std::shared_ptr<const IDiscreteFunction>& f, const std::shared_ptr<const IDiscreteFunction>& g) -{ - if ((f->dataType() == ASTNodeDataType::double_t and f->descriptor().type() == DiscreteFunctionType::P0) and - (g->dataType() == ASTNodeDataType::double_t and g->descriptor().type() == DiscreteFunctionType::P0)) { - std::shared_ptr mesh = getCommonMesh({f, g}); - - if (mesh.use_count() == 0) { - throw NormalError("operands are defined on different meshes"); - } - - switch (mesh->dimension()) { - case 1: { - using DiscreteFunctionType = DiscreteFunctionP0<1, double>; - return std::make_shared<const DiscreteFunctionType>( - pow(dynamic_cast<const DiscreteFunctionType&>(*f), dynamic_cast<const DiscreteFunctionType&>(*g))); - } - case 2: { - using DiscreteFunctionType = DiscreteFunctionP0<2, double>; - return std::make_shared<const DiscreteFunctionType>( - pow(dynamic_cast<const DiscreteFunctionType&>(*f), dynamic_cast<const DiscreteFunctionType&>(*g))); - } - case 3: { - using DiscreteFunctionType = DiscreteFunctionP0<3, double>; - return std::make_shared<const DiscreteFunctionType>( - pow(dynamic_cast<const DiscreteFunctionType&>(*f), dynamic_cast<const DiscreteFunctionType&>(*g))); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid mesh dimension"); - } - // LCOV_EXCL_STOP - } - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(f, g)); - } -} - -std::shared_ptr<const IDiscreteFunction> -pow(const double a, const std::shared_ptr<const IDiscreteFunction>& f) -{ - if (f->dataType() == ASTNodeDataType::double_t and f->descriptor().type() == DiscreteFunctionType::P0) { - switch (f->mesh()->dimension()) { - case 1: { - using DiscreteFunctionType = DiscreteFunctionP0<1, double>; - return std::make_shared<const DiscreteFunctionType>(pow(a, dynamic_cast<const DiscreteFunctionType&>(*f))); - } - case 2: { - using DiscreteFunctionType = DiscreteFunctionP0<2, double>; - return std::make_shared<const DiscreteFunctionType>(pow(a, dynamic_cast<const DiscreteFunctionType&>(*f))); - } - case 3: { - using DiscreteFunctionType = DiscreteFunctionP0<3, double>; - return std::make_shared<const DiscreteFunctionType>(pow(a, dynamic_cast<const DiscreteFunctionType&>(*f))); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid mesh dimension"); - } - // LCOV_EXCL_STOP - } - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(a, f)); - } -} - -std::shared_ptr<const IDiscreteFunction> -pow(const std::shared_ptr<const IDiscreteFunction>& f, const double a) -{ - if (f->dataType() == ASTNodeDataType::double_t and f->descriptor().type() == DiscreteFunctionType::P0) { - switch (f->mesh()->dimension()) { - case 1: { - using DiscreteFunctionType = DiscreteFunctionP0<1, double>; - return std::make_shared<const DiscreteFunctionType>(pow(dynamic_cast<const DiscreteFunctionType&>(*f), a)); - } - case 2: { - using DiscreteFunctionType = DiscreteFunctionP0<2, double>; - return std::make_shared<const DiscreteFunctionType>(pow(dynamic_cast<const DiscreteFunctionType&>(*f), a)); - } - case 3: { - using DiscreteFunctionType = DiscreteFunctionP0<3, double>; - return std::make_shared<const DiscreteFunctionType>(pow(dynamic_cast<const DiscreteFunctionType&>(*f), a)); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid mesh dimension"); - } - // LCOV_EXCL_STOP - } - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(f, a)); - } -} - -template <size_t Dimension> -std::shared_ptr<const IDiscreteFunction> -dot(const std::shared_ptr<const IDiscreteFunction>& f, const std::shared_ptr<const IDiscreteFunction>& g) -{ - Assert(((f->descriptor().type() == DiscreteFunctionType::P0Vector) and - (g->descriptor().type() == DiscreteFunctionType::P0Vector)) or - ((f->dataType() == ASTNodeDataType::vector_t and f->descriptor().type() == DiscreteFunctionType::P0) and - (g->dataType() == ASTNodeDataType::vector_t and g->descriptor().type() == DiscreteFunctionType::P0) and - (f->dataType().dimension() == g->dataType().dimension()))); - - if ((f->descriptor().type() == DiscreteFunctionType::P0Vector) and - (g->descriptor().type() == DiscreteFunctionType::P0Vector)) { - using DiscreteFunctionResultType = DiscreteFunctionP0<Dimension, double>; - using DiscreteFunctionType = DiscreteFunctionP0Vector<Dimension, double>; - - const DiscreteFunctionType& f_vector = dynamic_cast<const DiscreteFunctionType&>(*f); - const DiscreteFunctionType& g_vector = dynamic_cast<const DiscreteFunctionType&>(*g); - - if (f_vector.size() != g_vector.size()) { - throw NormalError("operands have different dimension"); - } else { - return std::make_shared<const DiscreteFunctionResultType>(dot(f_vector, g_vector)); - } - - } else { - using DiscreteFunctionResultType = DiscreteFunctionP0<Dimension, double>; - - switch (f->dataType().dimension()) { - case 1: { - using Rd = TinyVector<1>; - using DiscreteFunctionType = DiscreteFunctionP0<Dimension, Rd>; - return std::make_shared<const DiscreteFunctionResultType>( - dot(dynamic_cast<const DiscreteFunctionType&>(*f), dynamic_cast<const DiscreteFunctionType&>(*g))); - } - case 2: { - using Rd = TinyVector<2>; - using DiscreteFunctionType = DiscreteFunctionP0<Dimension, Rd>; - return std::make_shared<const DiscreteFunctionResultType>( - dot(dynamic_cast<const DiscreteFunctionType&>(*f), dynamic_cast<const DiscreteFunctionType&>(*g))); - } - case 3: { - using Rd = TinyVector<3>; - using DiscreteFunctionType = DiscreteFunctionP0<Dimension, Rd>; - return std::make_shared<const DiscreteFunctionResultType>( - dot(dynamic_cast<const DiscreteFunctionType&>(*f), dynamic_cast<const DiscreteFunctionType&>(*g))); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError(EmbeddedIDiscreteFunctionUtils::invalidOperandType(f)); - } - // LCOV_EXCL_STOP - } - } -} - -std::shared_ptr<const IDiscreteFunction> -dot(const std::shared_ptr<const IDiscreteFunction>& f, const std::shared_ptr<const IDiscreteFunction>& g) -{ - if (((f->descriptor().type() == DiscreteFunctionType::P0Vector) and - (g->descriptor().type() == DiscreteFunctionType::P0Vector)) or - ((f->dataType() == ASTNodeDataType::vector_t and f->descriptor().type() == DiscreteFunctionType::P0) and - (g->dataType() == ASTNodeDataType::vector_t and g->descriptor().type() == DiscreteFunctionType::P0) and - (f->dataType().dimension() == g->dataType().dimension()))) { - std::shared_ptr mesh = getCommonMesh({f, g}); - - if (mesh.use_count() == 0) { - throw NormalError("operands are defined on different meshes"); - } - - switch (mesh->dimension()) { - case 1: { - return dot<1>(f, g); - } - case 2: { - return dot<2>(f, g); - } - case 3: { - return dot<3>(f, g); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid mesh dimension"); - } - // LCOV_EXCL_STOP - } - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(f, g)); - } -} - -template <size_t Dimension, size_t VectorDimension> -std::shared_ptr<const IDiscreteFunction> -dot(const std::shared_ptr<const IDiscreteFunction>& f, const TinyVector<VectorDimension>& a) -{ - Assert((f->dataType() == ASTNodeDataType::vector_t and f->descriptor().type() == DiscreteFunctionType::P0) and - (f->dataType().dimension() == a.dimension())); - - using DiscreteFunctionResultType = DiscreteFunctionP0<Dimension, double>; - using DiscreteFunctionType = DiscreteFunctionP0<Dimension, TinyVector<VectorDimension>>; - - return std::make_shared<const DiscreteFunctionResultType>(dot(dynamic_cast<const DiscreteFunctionType&>(*f), a)); -} - -template <size_t VectorDimension> -std::shared_ptr<const IDiscreteFunction> -dot(const std::shared_ptr<const IDiscreteFunction>& f, const TinyVector<VectorDimension>& a) -{ - if ((f->dataType() == ASTNodeDataType::vector_t and f->descriptor().type() == DiscreteFunctionType::P0) and - (f->dataType().dimension() == a.dimension())) { - switch (f->mesh()->dimension()) { - case 1: { - return dot<1, VectorDimension>(f, a); - } - case 2: { - return dot<2, VectorDimension>(f, a); - } - case 3: { - return dot<3, VectorDimension>(f, a); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid mesh dimension"); - } - // LCOV_EXCL_STOP - } - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(f, a)); - } -} - -template <size_t Dimension, size_t VectorDimension> -std::shared_ptr<const IDiscreteFunction> -dot(const TinyVector<VectorDimension>& a, const std::shared_ptr<const IDiscreteFunction>& f) -{ - Assert((f->dataType() == ASTNodeDataType::vector_t and f->descriptor().type() == DiscreteFunctionType::P0) and - (f->dataType().dimension() == a.dimension())); - - using DiscreteFunctionResultType = DiscreteFunctionP0<Dimension, double>; - using DiscreteFunctionType = DiscreteFunctionP0<Dimension, TinyVector<VectorDimension>>; - - return std::make_shared<const DiscreteFunctionResultType>(dot(a, dynamic_cast<const DiscreteFunctionType&>(*f))); -} - -template <size_t VectorDimension> -std::shared_ptr<const IDiscreteFunction> -dot(const TinyVector<VectorDimension>& a, const std::shared_ptr<const IDiscreteFunction>& f) -{ - if ((f->dataType() == ASTNodeDataType::vector_t and f->descriptor().type() == DiscreteFunctionType::P0) and - (f->dataType().dimension() == a.dimension())) { - switch (f->mesh()->dimension()) { - case 1: { - return dot<1, VectorDimension>(a, f); - } - case 2: { - return dot<2, VectorDimension>(a, f); - } - case 3: { - return dot<3, VectorDimension>(a, f); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid mesh dimension"); - } - // LCOV_EXCL_STOP - } - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(a, f)); - } -} - -template std::shared_ptr<const IDiscreteFunction> dot(const std::shared_ptr<const IDiscreteFunction>&, - const TinyVector<1>&); - -template std::shared_ptr<const IDiscreteFunction> dot(const std::shared_ptr<const IDiscreteFunction>&, - const TinyVector<2>&); - -template std::shared_ptr<const IDiscreteFunction> dot(const std::shared_ptr<const IDiscreteFunction>&, - const TinyVector<3>&); - -template std::shared_ptr<const IDiscreteFunction> dot(const TinyVector<1>&, - const std::shared_ptr<const IDiscreteFunction>&); - -template std::shared_ptr<const IDiscreteFunction> dot(const TinyVector<2>&, - const std::shared_ptr<const IDiscreteFunction>&); - -template std::shared_ptr<const IDiscreteFunction> dot(const TinyVector<3>&, - const std::shared_ptr<const IDiscreteFunction>&); - -double -min(const std::shared_ptr<const IDiscreteFunction>& f) -{ - if (f->dataType() == ASTNodeDataType::double_t and f->descriptor().type() == DiscreteFunctionType::P0) { - switch (f->mesh()->dimension()) { - case 1: { - using DiscreteFunctionType = DiscreteFunctionP0<1, double>; - return min(dynamic_cast<const DiscreteFunctionType&>(*f)); - } - case 2: { - using DiscreteFunctionType = DiscreteFunctionP0<2, double>; - return min(dynamic_cast<const DiscreteFunctionType&>(*f)); - } - case 3: { - using DiscreteFunctionType = DiscreteFunctionP0<3, double>; - return min(dynamic_cast<const DiscreteFunctionType&>(*f)); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid mesh dimension"); - } - // LCOV_EXCL_STOP - } - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::invalidOperandType(f)); - } -} - -std::shared_ptr<const IDiscreteFunction> -min(const std::shared_ptr<const IDiscreteFunction>& f, const std::shared_ptr<const IDiscreteFunction>& g) -{ - if ((f->dataType() == ASTNodeDataType::double_t and f->descriptor().type() == DiscreteFunctionType::P0) and - (g->dataType() == ASTNodeDataType::double_t and g->descriptor().type() == DiscreteFunctionType::P0)) { - std::shared_ptr mesh = getCommonMesh({f, g}); - - if (mesh.use_count() == 0) { - throw NormalError("operands are defined on different meshes"); - } - - switch (mesh->dimension()) { - case 1: { - using DiscreteFunctionType = DiscreteFunctionP0<1, double>; - return std::make_shared<const DiscreteFunctionType>( - min(dynamic_cast<const DiscreteFunctionType&>(*f), dynamic_cast<const DiscreteFunctionType&>(*g))); - } - case 2: { - using DiscreteFunctionType = DiscreteFunctionP0<2, double>; - return std::make_shared<const DiscreteFunctionType>( - min(dynamic_cast<const DiscreteFunctionType&>(*f), dynamic_cast<const DiscreteFunctionType&>(*g))); - } - case 3: { - using DiscreteFunctionType = DiscreteFunctionP0<3, double>; - return std::make_shared<const DiscreteFunctionType>( - min(dynamic_cast<const DiscreteFunctionType&>(*f), dynamic_cast<const DiscreteFunctionType&>(*g))); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid mesh dimension"); - } - // LCOV_EXCL_STOP - } - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(f, g)); - } -} - -std::shared_ptr<const IDiscreteFunction> -min(const double a, const std::shared_ptr<const IDiscreteFunction>& f) -{ - if (f->dataType() == ASTNodeDataType::double_t and f->descriptor().type() == DiscreteFunctionType::P0) { - switch (f->mesh()->dimension()) { - case 1: { - using DiscreteFunctionType = DiscreteFunctionP0<1, double>; - return std::make_shared<const DiscreteFunctionType>(min(a, dynamic_cast<const DiscreteFunctionType&>(*f))); - } - case 2: { - using DiscreteFunctionType = DiscreteFunctionP0<2, double>; - return std::make_shared<const DiscreteFunctionType>(min(a, dynamic_cast<const DiscreteFunctionType&>(*f))); - } - case 3: { - using DiscreteFunctionType = DiscreteFunctionP0<3, double>; - return std::make_shared<const DiscreteFunctionType>(min(a, dynamic_cast<const DiscreteFunctionType&>(*f))); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid mesh dimension"); - } - // LCOV_EXCL_STOP - } - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(a, f)); - } -} - -std::shared_ptr<const IDiscreteFunction> -min(const std::shared_ptr<const IDiscreteFunction>& f, const double a) -{ - if (f->dataType() == ASTNodeDataType::double_t and f->descriptor().type() == DiscreteFunctionType::P0) { - switch (f->mesh()->dimension()) { - case 1: { - using DiscreteFunctionType = DiscreteFunctionP0<1, double>; - return std::make_shared<const DiscreteFunctionType>(min(dynamic_cast<const DiscreteFunctionType&>(*f), a)); - } - case 2: { - using DiscreteFunctionType = DiscreteFunctionP0<2, double>; - return std::make_shared<const DiscreteFunctionType>(min(dynamic_cast<const DiscreteFunctionType&>(*f), a)); - } - case 3: { - using DiscreteFunctionType = DiscreteFunctionP0<3, double>; - return std::make_shared<const DiscreteFunctionType>(min(dynamic_cast<const DiscreteFunctionType&>(*f), a)); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid mesh dimension"); - } - // LCOV_EXCL_STOP - } - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(f, a)); - } -} - -double -max(const std::shared_ptr<const IDiscreteFunction>& f) -{ - if (f->dataType() == ASTNodeDataType::double_t and f->descriptor().type() == DiscreteFunctionType::P0) { - switch (f->mesh()->dimension()) { - case 1: { - using DiscreteFunctionType = DiscreteFunctionP0<1, double>; - return max(dynamic_cast<const DiscreteFunctionType&>(*f)); - } - case 2: { - using DiscreteFunctionType = DiscreteFunctionP0<2, double>; - return max(dynamic_cast<const DiscreteFunctionType&>(*f)); - } - case 3: { - using DiscreteFunctionType = DiscreteFunctionP0<3, double>; - return max(dynamic_cast<const DiscreteFunctionType&>(*f)); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid mesh dimension"); - } - // LCOV_EXCL_STOP - } - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::invalidOperandType(f)); - } -} - -std::shared_ptr<const IDiscreteFunction> -max(const std::shared_ptr<const IDiscreteFunction>& f, const std::shared_ptr<const IDiscreteFunction>& g) -{ - if ((f->dataType() == ASTNodeDataType::double_t and f->descriptor().type() == DiscreteFunctionType::P0) and - (g->dataType() == ASTNodeDataType::double_t and g->descriptor().type() == DiscreteFunctionType::P0)) { - std::shared_ptr mesh = getCommonMesh({f, g}); - - if (mesh.use_count() == 0) { - throw NormalError("operands are defined on different meshes"); - } - - switch (mesh->dimension()) { - case 1: { - using DiscreteFunctionType = DiscreteFunctionP0<1, double>; - return std::make_shared<const DiscreteFunctionType>( - max(dynamic_cast<const DiscreteFunctionType&>(*f), dynamic_cast<const DiscreteFunctionType&>(*g))); - } - case 2: { - using DiscreteFunctionType = DiscreteFunctionP0<2, double>; - return std::make_shared<const DiscreteFunctionType>( - max(dynamic_cast<const DiscreteFunctionType&>(*f), dynamic_cast<const DiscreteFunctionType&>(*g))); - } - case 3: { - using DiscreteFunctionType = DiscreteFunctionP0<3, double>; - return std::make_shared<const DiscreteFunctionType>( - max(dynamic_cast<const DiscreteFunctionType&>(*f), dynamic_cast<const DiscreteFunctionType&>(*g))); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid mesh dimension"); - } - // LCOV_EXCL_STOP - } - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(f, g)); - } -} - -std::shared_ptr<const IDiscreteFunction> -max(const double a, const std::shared_ptr<const IDiscreteFunction>& f) -{ - if (f->dataType() == ASTNodeDataType::double_t and f->descriptor().type() == DiscreteFunctionType::P0) { - switch (f->mesh()->dimension()) { - case 1: { - using DiscreteFunctionType = DiscreteFunctionP0<1, double>; - return std::make_shared<const DiscreteFunctionType>(max(a, dynamic_cast<const DiscreteFunctionType&>(*f))); - } - case 2: { - using DiscreteFunctionType = DiscreteFunctionP0<2, double>; - return std::make_shared<const DiscreteFunctionType>(max(a, dynamic_cast<const DiscreteFunctionType&>(*f))); - } - case 3: { - using DiscreteFunctionType = DiscreteFunctionP0<3, double>; - return std::make_shared<const DiscreteFunctionType>(max(a, dynamic_cast<const DiscreteFunctionType&>(*f))); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid mesh dimension"); - } - // LCOV_EXCL_STOP - } - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(a, f)); - } -} - -std::shared_ptr<const IDiscreteFunction> -max(const std::shared_ptr<const IDiscreteFunction>& f, const double a) -{ - if (f->dataType() == ASTNodeDataType::double_t and f->descriptor().type() == DiscreteFunctionType::P0) { - switch (f->mesh()->dimension()) { - case 1: { - using DiscreteFunctionType = DiscreteFunctionP0<1, double>; - return std::make_shared<const DiscreteFunctionType>(max(dynamic_cast<const DiscreteFunctionType&>(*f), a)); - } - case 2: { - using DiscreteFunctionType = DiscreteFunctionP0<2, double>; - return std::make_shared<const DiscreteFunctionType>(max(dynamic_cast<const DiscreteFunctionType&>(*f), a)); - } - case 3: { - using DiscreteFunctionType = DiscreteFunctionP0<3, double>; - return std::make_shared<const DiscreteFunctionType>(max(dynamic_cast<const DiscreteFunctionType&>(*f), a)); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid mesh dimension"); - } - // LCOV_EXCL_STOP - } - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(f, a)); - } -} - -template <typename ValueT> -ValueT -sum_of(const std::shared_ptr<const IDiscreteFunction>& f) -{ - if (f->dataType() == ast_node_data_type_from<ValueT> and f->descriptor().type() == DiscreteFunctionType::P0) { - switch (f->mesh()->dimension()) { - case 1: { - using DiscreteFunctionType = DiscreteFunctionP0<1, ValueT>; - return sum(dynamic_cast<const DiscreteFunctionType&>(*f)); - } - case 2: { - using DiscreteFunctionType = DiscreteFunctionP0<2, ValueT>; - return sum(dynamic_cast<const DiscreteFunctionType&>(*f)); - } - case 3: { - using DiscreteFunctionType = DiscreteFunctionP0<3, ValueT>; - return sum(dynamic_cast<const DiscreteFunctionType&>(*f)); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid mesh dimension"); - } - // LCOV_EXCL_STOP - } - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::invalidOperandType(f)); - } -} - -template double sum_of<double>(const std::shared_ptr<const IDiscreteFunction>&); - -template TinyVector<1> sum_of<TinyVector<1>>(const std::shared_ptr<const IDiscreteFunction>&); - -template TinyVector<2> sum_of<TinyVector<2>>(const std::shared_ptr<const IDiscreteFunction>&); - -template TinyVector<3> sum_of<TinyVector<3>>(const std::shared_ptr<const IDiscreteFunction>&); - -template TinyMatrix<1> sum_of<TinyMatrix<1>>(const std::shared_ptr<const IDiscreteFunction>&); - -template TinyMatrix<2> sum_of<TinyMatrix<2>>(const std::shared_ptr<const IDiscreteFunction>&); - -template TinyMatrix<3> sum_of<TinyMatrix<3>>(const std::shared_ptr<const IDiscreteFunction>&); - -template <typename ValueT> -ValueT -integral_of(const std::shared_ptr<const IDiscreteFunction>& f) -{ - if (f->dataType() == ast_node_data_type_from<ValueT> and f->descriptor().type() == DiscreteFunctionType::P0) { - switch (f->mesh()->dimension()) { - case 1: { - using DiscreteFunctionType = DiscreteFunctionP0<1, ValueT>; - return integrate(dynamic_cast<const DiscreteFunctionType&>(*f)); - } - case 2: { - using DiscreteFunctionType = DiscreteFunctionP0<2, ValueT>; - return integrate(dynamic_cast<const DiscreteFunctionType&>(*f)); - } - case 3: { - using DiscreteFunctionType = DiscreteFunctionP0<3, ValueT>; - return integrate(dynamic_cast<const DiscreteFunctionType&>(*f)); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid mesh dimension"); - } - // LCOV_EXCL_STOP - } - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::invalidOperandType(f)); - } -} - -template double integral_of<double>(const std::shared_ptr<const IDiscreteFunction>&); - -template TinyVector<1> integral_of<TinyVector<1>>(const std::shared_ptr<const IDiscreteFunction>&); - -template TinyVector<2> integral_of<TinyVector<2>>(const std::shared_ptr<const IDiscreteFunction>&); - -template TinyVector<3> integral_of<TinyVector<3>>(const std::shared_ptr<const IDiscreteFunction>&); - -template TinyMatrix<1> integral_of<TinyMatrix<1>>(const std::shared_ptr<const IDiscreteFunction>&); - -template TinyMatrix<2> integral_of<TinyMatrix<2>>(const std::shared_ptr<const IDiscreteFunction>&); - -template TinyMatrix<3> integral_of<TinyMatrix<3>>(const std::shared_ptr<const IDiscreteFunction>&); diff --git a/src/language/utils/EmbeddedIDiscreteFunctionMathFunctions.hpp b/src/language/utils/EmbeddedIDiscreteFunctionMathFunctions.hpp deleted file mode 100644 index 582e63d8551842e9f93e3962a08669ba34baf756..0000000000000000000000000000000000000000 --- a/src/language/utils/EmbeddedIDiscreteFunctionMathFunctions.hpp +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef EMBEDDED_I_DISCRETE_FUNCTION_MATH_FUNCTIONS_HPP -#define EMBEDDED_I_DISCRETE_FUNCTION_MATH_FUNCTIONS_HPP - -#include <algebra/TinyMatrix.hpp> -#include <algebra/TinyVector.hpp> - -#include <memory> - -class IDiscreteFunction; - -std::shared_ptr<const IDiscreteFunction> sqrt(const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> abs(const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> sin(const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> cos(const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> tan(const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> asin(const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> acos(const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> atan(const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> atan2(const std::shared_ptr<const IDiscreteFunction>&, - const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> atan2(const double, const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> atan2(const std::shared_ptr<const IDiscreteFunction>&, const double); - -std::shared_ptr<const IDiscreteFunction> sinh(const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> cosh(const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> tanh(const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> asinh(const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> acosh(const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> atanh(const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> exp(const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> log(const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> pow(const std::shared_ptr<const IDiscreteFunction>&, - const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> pow(const double, const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> pow(const std::shared_ptr<const IDiscreteFunction>&, const double); - -std::shared_ptr<const IDiscreteFunction> dot(const std::shared_ptr<const IDiscreteFunction>&, - const std::shared_ptr<const IDiscreteFunction>&); - -template <size_t VectorDimension> -std::shared_ptr<const IDiscreteFunction> dot(const std::shared_ptr<const IDiscreteFunction>&, - const TinyVector<VectorDimension>&); - -template <size_t VectorDimension> -std::shared_ptr<const IDiscreteFunction> dot(const TinyVector<VectorDimension>&, - const std::shared_ptr<const IDiscreteFunction>&); - -double min(const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> min(const std::shared_ptr<const IDiscreteFunction>&, - const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> min(const double, const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> min(const std::shared_ptr<const IDiscreteFunction>&, const double); - -double max(const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> max(const std::shared_ptr<const IDiscreteFunction>&, - const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> max(const double, const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> max(const std::shared_ptr<const IDiscreteFunction>&, const double); - -template <typename ValueT> -ValueT sum_of(const std::shared_ptr<const IDiscreteFunction>&); - -template <typename ValueT> -ValueT integral_of(const std::shared_ptr<const IDiscreteFunction>&); - -#endif // EMBEDDED_I_DISCRETE_FUNCTION_MATH_FUNCTIONS_HPP diff --git a/src/language/utils/EmbeddedIDiscreteFunctionOperators.cpp b/src/language/utils/EmbeddedIDiscreteFunctionOperators.cpp deleted file mode 100644 index 656164d6fc012ef2469f846d3e54f32a9c1d4927..0000000000000000000000000000000000000000 --- a/src/language/utils/EmbeddedIDiscreteFunctionOperators.cpp +++ /dev/null @@ -1,1097 +0,0 @@ -#include <language/utils/EmbeddedIDiscreteFunctionOperators.hpp> - -#include <language/node_processor/BinaryExpressionProcessor.hpp> -#include <language/node_processor/UnaryExpressionProcessor.hpp> -#include <language/utils/EmbeddedIDiscreteFunctionUtils.hpp> -#include <scheme/DiscreteFunctionP0.hpp> -#include <scheme/DiscreteFunctionP0Vector.hpp> -#include <scheme/DiscreteFunctionUtils.hpp> -#include <scheme/IDiscreteFunction.hpp> -#include <utils/Exceptions.hpp> - -// unary operators -template <typename UnaryOperatorT, typename DiscreteFunctionT> -std::shared_ptr<const IDiscreteFunction> -applyUnaryOperation(const DiscreteFunctionT& f) -{ - return std::make_shared<decltype(UnaryOp<UnaryOperatorT>{}.eval(f))>(UnaryOp<UnaryOperatorT>{}.eval(f)); -} - -template <typename UnaryOperatorT, size_t Dimension> -std::shared_ptr<const IDiscreteFunction> -applyUnaryOperation(const std::shared_ptr<const IDiscreteFunction>& f) -{ - switch (f->descriptor().type()) { - case DiscreteFunctionType::P0: { - switch (f->dataType()) { - case ASTNodeDataType::double_t: { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*f); - return applyUnaryOperation<UnaryOperatorT>(fh); - } - case ASTNodeDataType::vector_t: { - switch (f->dataType().dimension()) { - case 1: { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyVector<1>>&>(*f); - return applyUnaryOperation<UnaryOperatorT>(fh); - } - case 2: { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyVector<2>>&>(*f); - return applyUnaryOperation<UnaryOperatorT>(fh); - } - case 3: { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyVector<3>>&>(*f); - return applyUnaryOperation<UnaryOperatorT>(fh); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError(EmbeddedIDiscreteFunctionUtils::invalidOperandType(f)); - } - // LCOV_EXCL_STOP - } - } - case ASTNodeDataType::matrix_t: { - Assert(f->dataType().numberOfRows() == f->dataType().numberOfColumns()); - switch (f->dataType().numberOfRows()) { - case 1: { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>&>(*f); - return applyUnaryOperation<UnaryOperatorT>(fh); - } - case 2: { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>&>(*f); - return applyUnaryOperation<UnaryOperatorT>(fh); - } - case 3: { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>&>(*f); - return applyUnaryOperation<UnaryOperatorT>(fh); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError(EmbeddedIDiscreteFunctionUtils::invalidOperandType(f)); - } - // LCOV_EXCL_STOP - } - } - // LCOV_EXCL_START - default: { - throw UnexpectedError(EmbeddedIDiscreteFunctionUtils::invalidOperandType(f)); - } - // LCOV_EXCL_STOP - } - break; - } - case DiscreteFunctionType::P0Vector: { - switch (f->dataType()) { - case ASTNodeDataType::double_t: { - auto fh = dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*f); - return applyUnaryOperation<UnaryOperatorT>(fh); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError(EmbeddedIDiscreteFunctionUtils::invalidOperandType(f)); - } - // LCOV_EXCL_STOP - } - break; - } - // LCOV_EXCL_START - default: { - throw UnexpectedError(EmbeddedIDiscreteFunctionUtils::invalidOperandType(f)); - } - // LCOV_EXCL_STOP - } -} - -template <typename UnaryOperatorT> -std::shared_ptr<const IDiscreteFunction> -applyUnaryOperation(const std::shared_ptr<const IDiscreteFunction>& f) -{ - switch (f->mesh()->dimension()) { - case 1: { - return applyUnaryOperation<UnaryOperatorT, 1>(f); - } - case 2: { - return applyUnaryOperation<UnaryOperatorT, 2>(f); - } - case 3: { - return applyUnaryOperation<UnaryOperatorT, 3>(f); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid mesh dimension"); - } - // LCOV_EXCL_STOP - } -} - -std::shared_ptr<const IDiscreteFunction> -operator-(const std::shared_ptr<const IDiscreteFunction>& f) -{ - return applyUnaryOperation<language::unary_minus>(f); -} - -// binary operators - -template <typename BinOperatorT, typename DiscreteFunctionT> -std::shared_ptr<const IDiscreteFunction> -innerCompositionLaw(const DiscreteFunctionT& lhs, const DiscreteFunctionT& rhs) -{ - Assert(lhs.mesh() == rhs.mesh()); - using data_type = typename DiscreteFunctionT::data_type; - if constexpr ((std::is_same_v<language::multiply_op, BinOperatorT> and is_tiny_vector_v<data_type>) or - (std::is_same_v<language::divide_op, BinOperatorT> and not std::is_arithmetic_v<data_type>)) { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(lhs, rhs)); - } else { - return std::make_shared<decltype(BinOp<BinOperatorT>{}.eval(lhs, rhs))>(BinOp<BinOperatorT>{}.eval(lhs, rhs)); - } -} - -template <typename BinOperatorT, size_t Dimension> -std::shared_ptr<const IDiscreteFunction> -innerCompositionLaw(const std::shared_ptr<const IDiscreteFunction>& f, - const std::shared_ptr<const IDiscreteFunction>& g) -{ - Assert(f->mesh() == g->mesh()); - Assert(EmbeddedIDiscreteFunctionUtils::isSameDiscretization(f, g)); - - switch (f->dataType()) { - case ASTNodeDataType::double_t: { - if (f->descriptor().type() == DiscreteFunctionType::P0) { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*f); - auto gh = dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*g); - - return innerCompositionLaw<BinOperatorT>(fh, gh); - - } else if (f->descriptor().type() == DiscreteFunctionType::P0Vector) { - if constexpr (std::is_same_v<BinOperatorT, language::plus_op> or - std::is_same_v<BinOperatorT, language::minus_op>) { - auto fh = dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*f); - auto gh = dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*g); - - if (fh.size() != gh.size()) { - throw NormalError(EmbeddedIDiscreteFunctionUtils::getOperandTypeName(f) + " spaces have different sizes"); - } - - return innerCompositionLaw<BinOperatorT>(fh, gh); - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(f, g)); - } - } else { - // LCOV_EXCL_START - throw UnexpectedError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(f, g)); - // LCOV_EXCL_STOP - } - } - case ASTNodeDataType::vector_t: { - Assert(f->descriptor().type() == DiscreteFunctionType::P0); - switch (f->dataType().dimension()) { - case 1: { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyVector<1>>&>(*f); - auto gh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyVector<1>>&>(*g); - - return innerCompositionLaw<BinOperatorT>(fh, gh); - } - case 2: { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyVector<2>>&>(*f); - auto gh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyVector<2>>&>(*g); - - return innerCompositionLaw<BinOperatorT>(fh, gh); - } - case 3: { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyVector<3>>&>(*f); - auto gh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyVector<3>>&>(*g); - - return innerCompositionLaw<BinOperatorT>(fh, gh); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(f, g)); - } - // LCOV_EXCL_STOP - } - } - case ASTNodeDataType::matrix_t: { - Assert(f->descriptor().type() == DiscreteFunctionType::P0); - Assert(f->dataType().numberOfRows() == f->dataType().numberOfColumns()); - switch (f->dataType().numberOfRows()) { - case 1: { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>&>(*f); - auto gh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>&>(*g); - - return innerCompositionLaw<BinOperatorT>(fh, gh); - } - case 2: { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>&>(*f); - auto gh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>&>(*g); - - return innerCompositionLaw<BinOperatorT>(fh, gh); - } - case 3: { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>&>(*f); - auto gh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>&>(*g); - - return innerCompositionLaw<BinOperatorT>(fh, gh); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError(EmbeddedIDiscreteFunctionUtils::invalidOperandType(f)); - } - // LCOV_EXCL_STOP - } - } - // LCOV_EXCL_START - default: { - throw UnexpectedError(EmbeddedIDiscreteFunctionUtils::invalidOperandType(f)); - } - // LCOV_EXCL_STOP - } -} - -template <typename BinOperatorT> -std::shared_ptr<const IDiscreteFunction> -innerCompositionLaw(const std::shared_ptr<const IDiscreteFunction>& f, - const std::shared_ptr<const IDiscreteFunction>& g) -{ - std::shared_ptr mesh = getCommonMesh({f, g}); - if (mesh.use_count() == 0) { - throw NormalError("operands are defined on different meshes"); - } - - Assert(EmbeddedIDiscreteFunctionUtils::isSameDiscretization(f, g)); - - switch (mesh->dimension()) { - case 1: { - return innerCompositionLaw<BinOperatorT, 1>(f, g); - } - case 2: { - return innerCompositionLaw<BinOperatorT, 2>(f, g); - } - case 3: { - return innerCompositionLaw<BinOperatorT, 3>(f, g); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid mesh dimension"); - } - // LCOV_EXCL_STOP - } -} - -template <typename BinOperatorT, typename LeftDiscreteFunctionT, typename RightDiscreteFunctionT> -std::shared_ptr<const IDiscreteFunction> -applyBinaryOperation(const LeftDiscreteFunctionT& lhs, const RightDiscreteFunctionT& rhs) -{ - Assert(lhs.mesh() == rhs.mesh()); - - static_assert(not std::is_same_v<LeftDiscreteFunctionT, RightDiscreteFunctionT>, - "use innerCompositionLaw when data types are the same"); - - return std::make_shared<decltype(BinOp<BinOperatorT>{}.eval(lhs, rhs))>(BinOp<BinOperatorT>{}.eval(lhs, rhs)); -} - -template <typename BinOperatorT, size_t Dimension, typename DiscreteFunctionT> -std::shared_ptr<const IDiscreteFunction> -applyBinaryOperation(const DiscreteFunctionT& fh, const std::shared_ptr<const IDiscreteFunction>& g) -{ - Assert(fh.mesh() == g->mesh()); - Assert(not EmbeddedIDiscreteFunctionUtils::isSameDiscretization(fh, *g)); - using lhs_data_type = std::decay_t<typename DiscreteFunctionT::data_type>; - - switch (g->dataType()) { - case ASTNodeDataType::double_t: { - if constexpr (std::is_same_v<BinOperatorT, language::multiply_op> and - std::is_same_v<DiscreteFunctionT, DiscreteFunctionP0<Dimension, double>>) { - if (g->descriptor().type() == DiscreteFunctionType::P0Vector) { - auto gh = dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*g); - return applyBinaryOperation<BinOperatorT>(fh, gh); - } else { - // LCOV_EXCL_START - throw UnexpectedError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(fh, g)); - // LCOV_EXCL_STOP - } - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(fh, g)); - } - } - case ASTNodeDataType::vector_t: { - if constexpr (std::is_same_v<language::multiply_op, BinOperatorT>) { - switch (g->dataType().dimension()) { - case 1: { - if constexpr (not is_tiny_vector_v<lhs_data_type> and - (std::is_same_v<lhs_data_type, TinyMatrix<1>> or std::is_same_v<lhs_data_type, double>)) { - auto gh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyVector<1>>&>(*g); - - return applyBinaryOperation<BinOperatorT>(fh, gh); - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(fh, g)); - } - } - case 2: { - if constexpr (not is_tiny_vector_v<lhs_data_type> and - (std::is_same_v<lhs_data_type, TinyMatrix<2>> or std::is_same_v<lhs_data_type, double>)) { - auto gh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyVector<2>>&>(*g); - - return applyBinaryOperation<BinOperatorT>(fh, gh); - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(fh, g)); - } - } - case 3: { - if constexpr (not is_tiny_vector_v<lhs_data_type> and - (std::is_same_v<lhs_data_type, TinyMatrix<3>> or std::is_same_v<lhs_data_type, double>)) { - auto gh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyVector<3>>&>(*g); - - return applyBinaryOperation<BinOperatorT>(fh, gh); - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(fh, g)); - } - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid rhs data type " + EmbeddedIDiscreteFunctionUtils::getOperandTypeName(g)); - } - // LCOV_EXCL_STOP - } - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(fh, g)); - } - } - case ASTNodeDataType::matrix_t: { - Assert(g->dataType().numberOfRows() == g->dataType().numberOfColumns()); - if constexpr (std::is_same_v<lhs_data_type, double> and std::is_same_v<language::multiply_op, BinOperatorT>) { - switch (g->dataType().numberOfRows()) { - case 1: { - auto gh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>&>(*g); - - return applyBinaryOperation<BinOperatorT>(fh, gh); - } - case 2: { - auto gh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>&>(*g); - - return applyBinaryOperation<BinOperatorT>(fh, gh); - } - case 3: { - auto gh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>&>(*g); - - return applyBinaryOperation<BinOperatorT>(fh, gh); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid rhs data type " + EmbeddedIDiscreteFunctionUtils::getOperandTypeName(g)); - } - // LCOV_EXCL_STOP - } - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(fh, g)); - } - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid rhs data type " + EmbeddedIDiscreteFunctionUtils::getOperandTypeName(g)); - } - // LCOV_EXCL_STOP - } -} - -template <typename BinOperatorT, size_t Dimension> -std::shared_ptr<const IDiscreteFunction> -applyBinaryOperation(const std::shared_ptr<const IDiscreteFunction>& f, - const std::shared_ptr<const IDiscreteFunction>& g) -{ - Assert(f->mesh() == g->mesh()); - Assert(not EmbeddedIDiscreteFunctionUtils::isSameDiscretization(f, g)); - - if (f->descriptor().type() == DiscreteFunctionType::P0) { - switch (f->dataType()) { - case ASTNodeDataType::double_t: { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*f); - return applyBinaryOperation<BinOperatorT, Dimension>(fh, g); - } - case ASTNodeDataType::matrix_t: { - Assert(f->dataType().numberOfRows() == f->dataType().numberOfColumns()); - switch (f->dataType().numberOfRows()) { - case 1: { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>&>(*f); - - return applyBinaryOperation<BinOperatorT, Dimension>(fh, g); - } - case 2: { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>&>(*f); - - return applyBinaryOperation<BinOperatorT, Dimension>(fh, g); - } - case 3: { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>&>(*f); - - return applyBinaryOperation<BinOperatorT, Dimension>(fh, g); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid lhs data type " + EmbeddedIDiscreteFunctionUtils::getOperandTypeName(f)); - } - // LCOV_EXCL_STOP - } - } - default: { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(f, g)); - } - } - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(f, g)); - } -} - -template <typename BinOperatorT> -std::shared_ptr<const IDiscreteFunction> -applyBinaryOperation(const std::shared_ptr<const IDiscreteFunction>& f, - const std::shared_ptr<const IDiscreteFunction>& g) -{ - std::shared_ptr mesh = getCommonMesh({f, g}); - if (mesh.use_count() == 0) { - throw NormalError("operands are defined on different meshes"); - } - - Assert(not EmbeddedIDiscreteFunctionUtils::isSameDiscretization(f, g), "should call inner composition instead"); - - switch (mesh->dimension()) { - case 1: { - return applyBinaryOperation<BinOperatorT, 1>(f, g); - } - case 2: { - return applyBinaryOperation<BinOperatorT, 2>(f, g); - } - case 3: { - return applyBinaryOperation<BinOperatorT, 3>(f, g); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid mesh dimension"); - } - // LCOV_EXCL_STOP - } -} - -std::shared_ptr<const IDiscreteFunction> -operator+(const std::shared_ptr<const IDiscreteFunction>& f, const std::shared_ptr<const IDiscreteFunction>& g) -{ - if (EmbeddedIDiscreteFunctionUtils::isSameDiscretization(f, g)) { - return innerCompositionLaw<language::plus_op>(f, g); - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(f, g)); - } -} - -std::shared_ptr<const IDiscreteFunction> -operator-(const std::shared_ptr<const IDiscreteFunction>& f, const std::shared_ptr<const IDiscreteFunction>& g) -{ - if (EmbeddedIDiscreteFunctionUtils::isSameDiscretization(f, g)) { - return innerCompositionLaw<language::minus_op>(f, g); - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(f, g)); - } -} - -std::shared_ptr<const IDiscreteFunction> -operator*(const std::shared_ptr<const IDiscreteFunction>& f, const std::shared_ptr<const IDiscreteFunction>& g) -{ - if (EmbeddedIDiscreteFunctionUtils::isSameDiscretization(f, g)) { - return innerCompositionLaw<language::multiply_op>(f, g); - } else { - return applyBinaryOperation<language::multiply_op>(f, g); - } -} - -std::shared_ptr<const IDiscreteFunction> -operator/(const std::shared_ptr<const IDiscreteFunction>& f, const std::shared_ptr<const IDiscreteFunction>& g) -{ - if (EmbeddedIDiscreteFunctionUtils::isSameDiscretization(f, g)) { - return innerCompositionLaw<language::divide_op>(f, g); - } else { - return applyBinaryOperation<language::divide_op>(f, g); - } -} - -template <typename BinOperatorT, typename DataType, typename DiscreteFunctionT> -std::shared_ptr<const IDiscreteFunction> -applyBinaryOperationWithLeftConstant(const DataType& a, const DiscreteFunctionT& f) -{ - using lhs_data_type = std::decay_t<DataType>; - using rhs_data_type = std::decay_t<typename DiscreteFunctionT::data_type>; - - if constexpr (std::is_same_v<language::multiply_op, BinOperatorT>) { - if constexpr (std::is_same_v<lhs_data_type, double>) { - return std::make_shared<decltype(BinOp<BinOperatorT>{}.eval(a, f))>(BinOp<BinOperatorT>{}.eval(a, f)); - } else if constexpr (is_tiny_matrix_v<lhs_data_type> and - (is_tiny_matrix_v<rhs_data_type> or is_tiny_vector_v<rhs_data_type>)) { - return std::make_shared<decltype(BinOp<BinOperatorT>{}.eval(a, f))>(BinOp<BinOperatorT>{}.eval(a, f)); - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(a, f)); - } - } else if constexpr (std::is_same_v<language::plus_op, BinOperatorT> or - std::is_same_v<language::minus_op, BinOperatorT>) { - if constexpr (std::is_same_v<lhs_data_type, double> and std::is_arithmetic_v<rhs_data_type>) { - return std::make_shared<decltype(BinOp<BinOperatorT>{}.eval(a, f))>(BinOp<BinOperatorT>{}.eval(a, f)); - } else if constexpr (std::is_same_v<lhs_data_type, rhs_data_type>) { - return std::make_shared<decltype(BinOp<BinOperatorT>{}.eval(a, f))>(BinOp<BinOperatorT>{}.eval(a, f)); - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(a, f)); - } - } else if constexpr (std::is_same_v<language::divide_op, BinOperatorT>) { - if constexpr (std::is_same_v<lhs_data_type, double> and std::is_arithmetic_v<rhs_data_type>) { - return std::make_shared<decltype(BinOp<BinOperatorT>{}.eval(a, f))>(BinOp<BinOperatorT>{}.eval(a, f)); - } else { - // LCOV_EXCL_START - throw UnexpectedError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(a, f)); - // LCOV_EXCL_STOP - } - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(a, f)); - } -} - -template <typename BinOperatorT, typename DataType, typename DiscreteFunctionT> -std::shared_ptr<const IDiscreteFunction> -applyBinaryOperationToVectorWithLeftConstant(const DataType& a, const DiscreteFunctionT& f) -{ - using lhs_data_type = std::decay_t<DataType>; - using rhs_data_type = std::decay_t<typename DiscreteFunctionT::data_type>; - - if constexpr (std::is_same_v<language::multiply_op, BinOperatorT>) { - if constexpr (std::is_same_v<lhs_data_type, double>) { - return std::make_shared<decltype(BinOp<BinOperatorT>{}.eval(a, f))>(BinOp<BinOperatorT>{}.eval(a, f)); - } else if constexpr (is_tiny_matrix_v<lhs_data_type> and - (is_tiny_matrix_v<rhs_data_type> or is_tiny_vector_v<rhs_data_type>)) { - return std::make_shared<decltype(BinOp<BinOperatorT>{}.eval(a, f))>(BinOp<BinOperatorT>{}.eval(a, f)); - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(a, f)); - } - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(a, f)); - } -} - -template <typename BinOperatorT, size_t Dimension, typename DataType> -std::shared_ptr<const IDiscreteFunction> -applyBinaryOperationWithLeftConstant(const DataType& a, const std::shared_ptr<const IDiscreteFunction>& f) -{ - switch (f->dataType()) { - case ASTNodeDataType::bool_t: - case ASTNodeDataType::unsigned_int_t: - case ASTNodeDataType::int_t: - case ASTNodeDataType::double_t: { - if (f->descriptor().type() == DiscreteFunctionType::P0) { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*f); - return applyBinaryOperationWithLeftConstant<BinOperatorT>(a, fh); - } else if (f->descriptor().type() == DiscreteFunctionType::P0Vector) { - auto fh = dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*f); - return applyBinaryOperationToVectorWithLeftConstant<BinOperatorT>(a, fh); - } else { - // LCOV_EXCL_START - throw UnexpectedError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(a, f)); - // LCOV_EXCL_STOP - } - } - case ASTNodeDataType::vector_t: { - if constexpr (is_tiny_matrix_v<DataType>) { - switch (f->dataType().dimension()) { - case 1: { - if constexpr (std::is_same_v<DataType, TinyMatrix<1>>) { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyVector<1>>&>(*f); - return applyBinaryOperationWithLeftConstant<BinOperatorT>(a, fh); - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(a, f)); - } - } - case 2: { - if constexpr (std::is_same_v<DataType, TinyMatrix<2>>) { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyVector<2>>&>(*f); - return applyBinaryOperationWithLeftConstant<BinOperatorT>(a, fh); - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(a, f)); - } - } - case 3: { - if constexpr (std::is_same_v<DataType, TinyMatrix<3>>) { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyVector<3>>&>(*f); - return applyBinaryOperationWithLeftConstant<BinOperatorT>(a, fh); - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(a, f)); - } - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid lhs data type " + EmbeddedIDiscreteFunctionUtils::getOperandTypeName(f)); - } - // LCOV_EXCL_STOP - } - } else { - switch (f->dataType().dimension()) { - case 1: { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyVector<1>>&>(*f); - return applyBinaryOperationWithLeftConstant<BinOperatorT>(a, fh); - } - case 2: { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyVector<2>>&>(*f); - return applyBinaryOperationWithLeftConstant<BinOperatorT>(a, fh); - } - case 3: { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyVector<3>>&>(*f); - return applyBinaryOperationWithLeftConstant<BinOperatorT>(a, fh); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid lhs data type " + EmbeddedIDiscreteFunctionUtils::getOperandTypeName(f)); - } - // LCOV_EXCL_STOP - } - } - } - case ASTNodeDataType::matrix_t: { - Assert(f->dataType().numberOfRows() == f->dataType().numberOfColumns()); - if constexpr (is_tiny_matrix_v<DataType>) { - switch (f->dataType().numberOfRows()) { - case 1: { - if constexpr (std::is_same_v<DataType, TinyMatrix<1>>) { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>&>(*f); - return applyBinaryOperationWithLeftConstant<BinOperatorT>(a, fh); - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(a, f)); - } - } - case 2: { - if constexpr (std::is_same_v<DataType, TinyMatrix<2>>) { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>&>(*f); - return applyBinaryOperationWithLeftConstant<BinOperatorT>(a, fh); - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(a, f)); - } - } - case 3: { - if constexpr (std::is_same_v<DataType, TinyMatrix<3>>) { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>&>(*f); - return applyBinaryOperationWithLeftConstant<BinOperatorT>(a, fh); - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(a, f)); - } - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid lhs data type " + EmbeddedIDiscreteFunctionUtils::getOperandTypeName(f)); - } - // LCOV_EXCL_STOP - } - } else { - switch (f->dataType().numberOfRows()) { - case 1: { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>&>(*f); - return applyBinaryOperationWithLeftConstant<BinOperatorT>(a, fh); - } - case 2: { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>&>(*f); - return applyBinaryOperationWithLeftConstant<BinOperatorT>(a, fh); - } - case 3: { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>&>(*f); - return applyBinaryOperationWithLeftConstant<BinOperatorT>(a, fh); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid lhs data type " + EmbeddedIDiscreteFunctionUtils::getOperandTypeName(f)); - } - // LCOV_EXCL_STOP - } - } - } - // LCOV_EXCL_START - default: { - throw UnexpectedError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(a, f)); - } - // LCOV_EXCL_STOP - } -} - -template <typename BinOperatorT, typename DataType> -std::shared_ptr<const IDiscreteFunction> -applyBinaryOperationWithLeftConstant(const DataType& a, const std::shared_ptr<const IDiscreteFunction>& f) -{ - switch (f->mesh()->dimension()) { - case 1: { - return applyBinaryOperationWithLeftConstant<BinOperatorT, 1>(a, f); - } - case 2: { - return applyBinaryOperationWithLeftConstant<BinOperatorT, 2>(a, f); - } - case 3: { - return applyBinaryOperationWithLeftConstant<BinOperatorT, 3>(a, f); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid mesh dimension"); - } - // LCOV_EXCL_STOP - } -} - -template <typename BinOperatorT, typename DataType, typename DiscreteFunctionT> -std::shared_ptr<const IDiscreteFunction> -applyBinaryOperationWithRightConstant(const DiscreteFunctionT& f, const DataType& a) -{ - Assert(f.descriptor().type() == DiscreteFunctionType::P0); - - using lhs_data_type = std::decay_t<typename DiscreteFunctionT::data_type>; - using rhs_data_type = std::decay_t<DataType>; - - if constexpr (std::is_same_v<language::multiply_op, BinOperatorT>) { - if constexpr (is_tiny_matrix_v<lhs_data_type> and is_tiny_matrix_v<rhs_data_type>) { - if constexpr (lhs_data_type::NumberOfColumns == rhs_data_type::NumberOfRows) { - return std::make_shared<decltype(BinOp<BinOperatorT>{}.eval(f, a))>(BinOp<BinOperatorT>{}.eval(f, a)); - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(f, a)); - } - } else if constexpr (std::is_same_v<lhs_data_type, double> and - (is_tiny_matrix_v<rhs_data_type> or is_tiny_vector_v<rhs_data_type> or - std::is_arithmetic_v<rhs_data_type>)) { - return std::make_shared<decltype(BinOp<BinOperatorT>{}.eval(f, a))>(BinOp<BinOperatorT>{}.eval(f, a)); - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(f, a)); - } - } else if constexpr (std::is_same_v<language::plus_op, BinOperatorT> or - std::is_same_v<language::minus_op, BinOperatorT>) { - if constexpr ((std::is_same_v<lhs_data_type, rhs_data_type>) or - (std::is_arithmetic_v<lhs_data_type> and std::is_arithmetic_v<rhs_data_type>)) { - return std::make_shared<decltype(BinOp<BinOperatorT>{}.eval(f, a))>(BinOp<BinOperatorT>{}.eval(f, a)); - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(f, a)); - } - } else { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(f, a)); - } -} - -template <typename BinOperatorT, size_t Dimension, typename DataType> -std::shared_ptr<const IDiscreteFunction> -applyBinaryOperationWithRightConstant(const std::shared_ptr<const IDiscreteFunction>& f, const DataType& a) -{ - if (f->descriptor().type() != DiscreteFunctionType::P0) { - throw NormalError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(f, a)); - } - - switch (f->dataType()) { - case ASTNodeDataType::bool_t: - case ASTNodeDataType::unsigned_int_t: - case ASTNodeDataType::int_t: - case ASTNodeDataType::double_t: { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*f); - return applyBinaryOperationWithRightConstant<BinOperatorT>(fh, a); - } - case ASTNodeDataType::vector_t: { - switch (f->dataType().dimension()) { - case 1: { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyVector<1>>&>(*f); - return applyBinaryOperationWithRightConstant<BinOperatorT>(fh, a); - } - case 2: { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyVector<2>>&>(*f); - return applyBinaryOperationWithRightConstant<BinOperatorT>(fh, a); - } - case 3: { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyVector<3>>&>(*f); - return applyBinaryOperationWithRightConstant<BinOperatorT>(fh, a); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid lhs data type " + EmbeddedIDiscreteFunctionUtils::getOperandTypeName(f)); - } - // LCOV_EXCL_STOP - } - } - case ASTNodeDataType::matrix_t: { - Assert(f->dataType().numberOfRows() == f->dataType().numberOfColumns()); - switch (f->dataType().numberOfRows()) { - case 1: { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>&>(*f); - return applyBinaryOperationWithRightConstant<BinOperatorT>(fh, a); - } - case 2: { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>&>(*f); - return applyBinaryOperationWithRightConstant<BinOperatorT>(fh, a); - } - case 3: { - auto fh = dynamic_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>&>(*f); - return applyBinaryOperationWithRightConstant<BinOperatorT>(fh, a); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid lhs data type " + EmbeddedIDiscreteFunctionUtils::getOperandTypeName(f)); - } - // LCOV_EXCL_STOP - } - } - // LCOV_EXCL_START - default: { - throw UnexpectedError(EmbeddedIDiscreteFunctionUtils::incompatibleOperandTypes(f, a)); - } - // LCOV_EXCL_STOP - } -} - -template <typename BinOperatorT, typename DataType> -std::shared_ptr<const IDiscreteFunction> -applyBinaryOperationWithRightConstant(const std::shared_ptr<const IDiscreteFunction>& f, const DataType& a) -{ - switch (f->mesh()->dimension()) { - case 1: { - return applyBinaryOperationWithRightConstant<BinOperatorT, 1>(f, a); - } - case 2: { - return applyBinaryOperationWithRightConstant<BinOperatorT, 2>(f, a); - } - case 3: { - return applyBinaryOperationWithRightConstant<BinOperatorT, 3>(f, a); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid mesh dimension"); - } - // LCOV_EXCL_STOP - } -} - -std::shared_ptr<const IDiscreteFunction> -operator+(const double& f, const std::shared_ptr<const IDiscreteFunction>& g) -{ - return applyBinaryOperationWithLeftConstant<language::plus_op>(f, g); -} - -std::shared_ptr<const IDiscreteFunction> -operator+(const std::shared_ptr<const IDiscreteFunction>& f, const double& g) -{ - return applyBinaryOperationWithRightConstant<language::plus_op>(f, g); -} - -std::shared_ptr<const IDiscreteFunction> -operator+(const TinyVector<1>& f, const std::shared_ptr<const IDiscreteFunction>& g) -{ - return applyBinaryOperationWithLeftConstant<language::plus_op>(f, g); -} - -std::shared_ptr<const IDiscreteFunction> -operator+(const TinyVector<2>& f, const std::shared_ptr<const IDiscreteFunction>& g) -{ - return applyBinaryOperationWithLeftConstant<language::plus_op>(f, g); -} - -std::shared_ptr<const IDiscreteFunction> -operator+(const TinyVector<3>& f, const std::shared_ptr<const IDiscreteFunction>& g) -{ - return applyBinaryOperationWithLeftConstant<language::plus_op>(f, g); -} - -std::shared_ptr<const IDiscreteFunction> -operator+(const TinyMatrix<1>& f, const std::shared_ptr<const IDiscreteFunction>& g) -{ - return applyBinaryOperationWithLeftConstant<language::plus_op>(f, g); -} - -std::shared_ptr<const IDiscreteFunction> -operator+(const TinyMatrix<2>& f, const std::shared_ptr<const IDiscreteFunction>& g) -{ - return applyBinaryOperationWithLeftConstant<language::plus_op>(f, g); -} - -std::shared_ptr<const IDiscreteFunction> -operator+(const TinyMatrix<3>& f, const std::shared_ptr<const IDiscreteFunction>& g) -{ - return applyBinaryOperationWithLeftConstant<language::plus_op>(f, g); -} - -std::shared_ptr<const IDiscreteFunction> -operator+(const std::shared_ptr<const IDiscreteFunction>& f, const TinyVector<1>& g) -{ - return applyBinaryOperationWithRightConstant<language::plus_op>(f, g); -} - -std::shared_ptr<const IDiscreteFunction> -operator+(const std::shared_ptr<const IDiscreteFunction>& f, const TinyVector<2>& g) -{ - return applyBinaryOperationWithRightConstant<language::plus_op>(f, g); -} - -std::shared_ptr<const IDiscreteFunction> -operator+(const std::shared_ptr<const IDiscreteFunction>& f, const TinyVector<3>& g) -{ - return applyBinaryOperationWithRightConstant<language::plus_op>(f, g); -} - -std::shared_ptr<const IDiscreteFunction> -operator+(const std::shared_ptr<const IDiscreteFunction>& f, const TinyMatrix<1>& g) -{ - return applyBinaryOperationWithRightConstant<language::plus_op>(f, g); -} - -std::shared_ptr<const IDiscreteFunction> -operator+(const std::shared_ptr<const IDiscreteFunction>& f, const TinyMatrix<2>& g) -{ - return applyBinaryOperationWithRightConstant<language::plus_op>(f, g); -} - -std::shared_ptr<const IDiscreteFunction> -operator+(const std::shared_ptr<const IDiscreteFunction>& f, const TinyMatrix<3>& g) -{ - return applyBinaryOperationWithRightConstant<language::plus_op>(f, g); -} - -std::shared_ptr<const IDiscreteFunction> -operator-(const double& f, const std::shared_ptr<const IDiscreteFunction>& g) -{ - return applyBinaryOperationWithLeftConstant<language::minus_op>(f, g); -} - -std::shared_ptr<const IDiscreteFunction> -operator-(const std::shared_ptr<const IDiscreteFunction>& f, const double& g) -{ - return applyBinaryOperationWithRightConstant<language::minus_op>(f, g); -} - -std::shared_ptr<const IDiscreteFunction> -operator-(const TinyVector<1>& f, const std::shared_ptr<const IDiscreteFunction>& g) -{ - return applyBinaryOperationWithLeftConstant<language::minus_op>(f, g); -} - -std::shared_ptr<const IDiscreteFunction> -operator-(const TinyVector<2>& f, const std::shared_ptr<const IDiscreteFunction>& g) -{ - return applyBinaryOperationWithLeftConstant<language::minus_op>(f, g); -} - -std::shared_ptr<const IDiscreteFunction> -operator-(const TinyVector<3>& f, const std::shared_ptr<const IDiscreteFunction>& g) -{ - return applyBinaryOperationWithLeftConstant<language::minus_op>(f, g); -} - -std::shared_ptr<const IDiscreteFunction> -operator-(const TinyMatrix<1>& f, const std::shared_ptr<const IDiscreteFunction>& g) -{ - return applyBinaryOperationWithLeftConstant<language::minus_op>(f, g); -} - -std::shared_ptr<const IDiscreteFunction> -operator-(const TinyMatrix<2>& f, const std::shared_ptr<const IDiscreteFunction>& g) -{ - return applyBinaryOperationWithLeftConstant<language::minus_op>(f, g); -} - -std::shared_ptr<const IDiscreteFunction> -operator-(const TinyMatrix<3>& f, const std::shared_ptr<const IDiscreteFunction>& g) -{ - return applyBinaryOperationWithLeftConstant<language::minus_op>(f, g); -} - -std::shared_ptr<const IDiscreteFunction> -operator-(const std::shared_ptr<const IDiscreteFunction>& f, const TinyVector<1>& g) -{ - return applyBinaryOperationWithRightConstant<language::minus_op>(f, g); -} - -std::shared_ptr<const IDiscreteFunction> -operator-(const std::shared_ptr<const IDiscreteFunction>& f, const TinyVector<2>& g) -{ - return applyBinaryOperationWithRightConstant<language::minus_op>(f, g); -} - -std::shared_ptr<const IDiscreteFunction> -operator-(const std::shared_ptr<const IDiscreteFunction>& f, const TinyVector<3>& g) -{ - return applyBinaryOperationWithRightConstant<language::minus_op>(f, g); -} - -std::shared_ptr<const IDiscreteFunction> -operator-(const std::shared_ptr<const IDiscreteFunction>& f, const TinyMatrix<1>& g) -{ - return applyBinaryOperationWithRightConstant<language::minus_op>(f, g); -} - -std::shared_ptr<const IDiscreteFunction> -operator-(const std::shared_ptr<const IDiscreteFunction>& f, const TinyMatrix<2>& g) -{ - return applyBinaryOperationWithRightConstant<language::minus_op>(f, g); -} - -std::shared_ptr<const IDiscreteFunction> -operator-(const std::shared_ptr<const IDiscreteFunction>& f, const TinyMatrix<3>& g) -{ - return applyBinaryOperationWithRightConstant<language::minus_op>(f, g); -} - -std::shared_ptr<const IDiscreteFunction> -operator*(const double& a, const std::shared_ptr<const IDiscreteFunction>& f) -{ - return applyBinaryOperationWithLeftConstant<language::multiply_op>(a, f); -} - -std::shared_ptr<const IDiscreteFunction> -operator*(const std::shared_ptr<const IDiscreteFunction>& f, const double& a) -{ - return applyBinaryOperationWithRightConstant<language::multiply_op>(f, a); -} - -std::shared_ptr<const IDiscreteFunction> -operator*(const TinyMatrix<1>& A, const std::shared_ptr<const IDiscreteFunction>& B) -{ - return applyBinaryOperationWithLeftConstant<language::multiply_op>(A, B); -} - -std::shared_ptr<const IDiscreteFunction> -operator*(const TinyMatrix<2>& A, const std::shared_ptr<const IDiscreteFunction>& B) -{ - return applyBinaryOperationWithLeftConstant<language::multiply_op>(A, B); -} - -std::shared_ptr<const IDiscreteFunction> -operator*(const TinyMatrix<3>& A, const std::shared_ptr<const IDiscreteFunction>& B) -{ - return applyBinaryOperationWithLeftConstant<language::multiply_op>(A, B); -} - -std::shared_ptr<const IDiscreteFunction> -operator*(const std::shared_ptr<const IDiscreteFunction>& a, const TinyVector<1>& u) -{ - return applyBinaryOperationWithRightConstant<language::multiply_op>(a, u); -} - -std::shared_ptr<const IDiscreteFunction> -operator*(const std::shared_ptr<const IDiscreteFunction>& a, const TinyVector<2>& u) -{ - return applyBinaryOperationWithRightConstant<language::multiply_op>(a, u); -} - -std::shared_ptr<const IDiscreteFunction> -operator*(const std::shared_ptr<const IDiscreteFunction>& a, const TinyVector<3>& u) -{ - return applyBinaryOperationWithRightConstant<language::multiply_op>(a, u); -} - -std::shared_ptr<const IDiscreteFunction> -operator*(const std::shared_ptr<const IDiscreteFunction>& a, const TinyMatrix<1>& A) -{ - return applyBinaryOperationWithRightConstant<language::multiply_op>(a, A); -} - -std::shared_ptr<const IDiscreteFunction> -operator*(const std::shared_ptr<const IDiscreteFunction>& a, const TinyMatrix<2>& A) -{ - return applyBinaryOperationWithRightConstant<language::multiply_op>(a, A); -} - -std::shared_ptr<const IDiscreteFunction> -operator*(const std::shared_ptr<const IDiscreteFunction>& a, const TinyMatrix<3>& A) -{ - return applyBinaryOperationWithRightConstant<language::multiply_op>(a, A); -} - -std::shared_ptr<const IDiscreteFunction> -operator/(const double& a, const std::shared_ptr<const IDiscreteFunction>& f) -{ - return applyBinaryOperationWithLeftConstant<language::divide_op>(a, f); -} diff --git a/src/language/utils/EmbeddedIDiscreteFunctionOperators.hpp b/src/language/utils/EmbeddedIDiscreteFunctionOperators.hpp deleted file mode 100644 index f797a95d03e19a796d9af965d81bbd3970c6cddd..0000000000000000000000000000000000000000 --- a/src/language/utils/EmbeddedIDiscreteFunctionOperators.hpp +++ /dev/null @@ -1,143 +0,0 @@ -#ifndef EMBEDDED_I_DISCRETE_FUNCTION_OPERATORS_HPP -#define EMBEDDED_I_DISCRETE_FUNCTION_OPERATORS_HPP - -#include <algebra/TinyMatrix.hpp> -#include <algebra/TinyVector.hpp> - -#include <memory> - -class IDiscreteFunction; - -// unary minus -std::shared_ptr<const IDiscreteFunction> operator-(const std::shared_ptr<const IDiscreteFunction>&); - -// sum -std::shared_ptr<const IDiscreteFunction> operator+(const std::shared_ptr<const IDiscreteFunction>&, - const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> operator+(const double&, const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> operator+(const std::shared_ptr<const IDiscreteFunction>&, const double&); - -std::shared_ptr<const IDiscreteFunction> operator+(const TinyVector<1>&, - const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> operator+(const TinyVector<2>&, - const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> operator+(const TinyVector<3>&, - const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> operator+(const TinyMatrix<1>&, - const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> operator+(const TinyMatrix<2>&, - const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> operator+(const TinyMatrix<3>&, - const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> operator+(const std::shared_ptr<const IDiscreteFunction>&, - const TinyVector<1>&); - -std::shared_ptr<const IDiscreteFunction> operator+(const std::shared_ptr<const IDiscreteFunction>&, - const TinyVector<2>&); - -std::shared_ptr<const IDiscreteFunction> operator+(const std::shared_ptr<const IDiscreteFunction>&, - const TinyVector<3>&); - -std::shared_ptr<const IDiscreteFunction> operator+(const std::shared_ptr<const IDiscreteFunction>&, - const TinyMatrix<1>&); - -std::shared_ptr<const IDiscreteFunction> operator+(const std::shared_ptr<const IDiscreteFunction>&, - const TinyMatrix<2>&); - -std::shared_ptr<const IDiscreteFunction> operator+(const std::shared_ptr<const IDiscreteFunction>&, - const TinyMatrix<3>&); - -// difference -std::shared_ptr<const IDiscreteFunction> operator-(const std::shared_ptr<const IDiscreteFunction>&, - const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> operator-(const double&, const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> operator-(const std::shared_ptr<const IDiscreteFunction>&, const double&); - -std::shared_ptr<const IDiscreteFunction> operator-(const TinyVector<1>&, - const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> operator-(const TinyVector<2>&, - const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> operator-(const TinyVector<3>&, - const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> operator-(const TinyMatrix<1>&, - const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> operator-(const TinyMatrix<2>&, - const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> operator-(const TinyMatrix<3>&, - const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> operator-(const std::shared_ptr<const IDiscreteFunction>&, - const TinyVector<1>&); - -std::shared_ptr<const IDiscreteFunction> operator-(const std::shared_ptr<const IDiscreteFunction>&, - const TinyVector<2>&); - -std::shared_ptr<const IDiscreteFunction> operator-(const std::shared_ptr<const IDiscreteFunction>&, - const TinyVector<3>&); - -std::shared_ptr<const IDiscreteFunction> operator-(const std::shared_ptr<const IDiscreteFunction>&, - const TinyMatrix<1>&); - -std::shared_ptr<const IDiscreteFunction> operator-(const std::shared_ptr<const IDiscreteFunction>&, - const TinyMatrix<2>&); - -std::shared_ptr<const IDiscreteFunction> operator-(const std::shared_ptr<const IDiscreteFunction>&, - const TinyMatrix<3>&); - -// product -std::shared_ptr<const IDiscreteFunction> operator*(const std::shared_ptr<const IDiscreteFunction>&, - const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> operator*(const double&, const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> operator*(const std::shared_ptr<const IDiscreteFunction>&, const double&); - -std::shared_ptr<const IDiscreteFunction> operator*(const TinyMatrix<1>&, - const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> operator*(const TinyMatrix<2>&, - const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> operator*(const TinyMatrix<3>&, - const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> operator*(const std::shared_ptr<const IDiscreteFunction>&, - const TinyVector<1>&); - -std::shared_ptr<const IDiscreteFunction> operator*(const std::shared_ptr<const IDiscreteFunction>&, - const TinyVector<2>&); - -std::shared_ptr<const IDiscreteFunction> operator*(const std::shared_ptr<const IDiscreteFunction>&, - const TinyVector<3>&); - -std::shared_ptr<const IDiscreteFunction> operator*(const std::shared_ptr<const IDiscreteFunction>&, - const TinyMatrix<1>&); - -std::shared_ptr<const IDiscreteFunction> operator*(const std::shared_ptr<const IDiscreteFunction>&, - const TinyMatrix<2>&); - -std::shared_ptr<const IDiscreteFunction> operator*(const std::shared_ptr<const IDiscreteFunction>&, - const TinyMatrix<3>&); - -// ratio -std::shared_ptr<const IDiscreteFunction> operator/(const double&, const std::shared_ptr<const IDiscreteFunction>&); - -std::shared_ptr<const IDiscreteFunction> operator/(const std::shared_ptr<const IDiscreteFunction>&, - const std::shared_ptr<const IDiscreteFunction>&); - -#endif // EMBEDDED_I_DISCRETE_FUNCTION_OPERATORS_HPP diff --git a/src/language/utils/EmbeddedIDiscreteFunctionUtils.cpp b/src/language/utils/EmbeddedIDiscreteFunctionUtils.cpp deleted file mode 100644 index 286988b9b2849fb34dc84948be05414ebbad6d5b..0000000000000000000000000000000000000000 --- a/src/language/utils/EmbeddedIDiscreteFunctionUtils.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include <language/utils/EmbeddedIDiscreteFunctionUtils.hpp> - -#include <utils/Exceptions.hpp> - -bool -EmbeddedIDiscreteFunctionUtils::isSameDiscretization(const IDiscreteFunction& f, const IDiscreteFunction& g) -{ - if ((f.dataType() == g.dataType()) and (f.descriptor().type() == g.descriptor().type())) { - switch (f.dataType()) { - case ASTNodeDataType::double_t: { - return true; - } - case ASTNodeDataType::vector_t: { - return f.dataType().dimension() == g.dataType().dimension(); - } - case ASTNodeDataType::matrix_t: { - return (f.dataType().numberOfRows() == g.dataType().numberOfRows()) and - (f.dataType().numberOfColumns() == g.dataType().numberOfColumns()); - } - default: { - throw UnexpectedError("invalid data type " + getOperandTypeName(f)); - } - } - } else { - return false; - } -} diff --git a/src/mesh/CMakeLists.txt b/src/mesh/CMakeLists.txt index 66ce42ae6f9e490a0b3e6e406934478b0f026f4a..62dbd50536ad2e725e67a25d9cddf481a62b40c6 100644 --- a/src/mesh/CMakeLists.txt +++ b/src/mesh/CMakeLists.txt @@ -7,6 +7,7 @@ add_library( ConnectivityBuilderBase.cpp ConnectivityComputer.cpp ConnectivityDispatcher.cpp + ConnectivityUtils.cpp DiamondDualConnectivityBuilder.cpp DiamondDualMeshBuilder.cpp Dual1DConnectivityBuilder.cpp diff --git a/src/mesh/Connectivity.cpp b/src/mesh/Connectivity.cpp index 5622294b2af633f38b1cc283eaf0b1576498f0d4..dc03c1ee65224a07466e5f08352b53004ad3c1ea 100644 --- a/src/mesh/Connectivity.cpp +++ b/src/mesh/Connectivity.cpp @@ -13,44 +13,36 @@ template <size_t Dimension> void Connectivity<Dimension>::_buildFrom(const ConnectivityDescriptor& descriptor) { - Assert(descriptor.cell_to_node_vector.size() == descriptor.cell_type_vector.size()); - Assert(descriptor.cell_number_vector.size() == descriptor.cell_type_vector.size()); + Assert(descriptor.cellToNodeMatrix().numberOfRows() == descriptor.cellTypeVector().size()); + Assert(descriptor.cellNumberVector().size() == descriptor.cellTypeVector().size()); if constexpr (Dimension > 1) { - Assert(descriptor.cell_to_face_vector.size() == descriptor.cell_type_vector.size()); - Assert(descriptor.face_to_node_vector.size() == descriptor.face_number_vector.size()); - Assert(descriptor.face_owner_vector.size() == descriptor.face_number_vector.size()); + Assert(descriptor.cellToFaceMatrix().numberOfRows() == descriptor.cellTypeVector().size()); + Assert(descriptor.faceToNodeMatrix().numberOfRows() == descriptor.faceNumberVector().size()); + Assert(descriptor.faceOwnerVector().size() == descriptor.faceNumberVector().size()); } - m_number_of_cells = descriptor.cell_number_vector.size(); - m_number_of_nodes = descriptor.node_number_vector.size(); + m_number_of_cells = descriptor.cellNumberVector().size(); + m_number_of_nodes = descriptor.nodeNumberVector().size(); if constexpr (Dimension == 1) { m_number_of_edges = m_number_of_nodes; m_number_of_faces = m_number_of_nodes; } else { - m_number_of_faces = descriptor.face_number_vector.size(); + m_number_of_faces = descriptor.faceNumberVector().size(); if constexpr (Dimension == 2) { m_number_of_edges = m_number_of_faces; } else { static_assert(Dimension == 3, "unexpected dimension"); - m_number_of_edges = descriptor.edge_number_vector.size(); + m_number_of_edges = descriptor.edgeNumberVector().size(); } } auto& cell_to_node_matrix = m_item_to_item_matrix[itemTId(ItemType::cell)][itemTId(ItemType::node)]; - cell_to_node_matrix = descriptor.cell_to_node_vector; + cell_to_node_matrix = descriptor.cellToNodeMatrix(); - { - WeakCellValue<CellType> cell_type(*this); - parallel_for( - this->numberOfCells(), PUGS_LAMBDA(CellId j) { cell_type[j] = descriptor.cell_type_vector[j]; }); - m_cell_type = cell_type; - } - - m_cell_number = WeakCellValue<int>(*this, convert_to_array(descriptor.cell_number_vector)); - - Array node_number_array = convert_to_array(descriptor.node_number_vector); - m_node_number = WeakNodeValue<int>(*this, node_number_array); + m_cell_type = WeakCellValue<const CellType>(*this, descriptor.cellTypeVector()); + m_cell_number = WeakCellValue<const int>(*this, descriptor.cellNumberVector()); + m_node_number = WeakNodeValue<const int>(*this, descriptor.nodeNumberVector()); { WeakCellValue<int> cell_global_index(*this); @@ -60,7 +52,7 @@ Connectivity<Dimension>::_buildFrom(const ConnectivityDescriptor& descriptor) m_cell_global_index = cell_global_index; } - m_cell_owner = WeakCellValue<int>(*this, convert_to_array(descriptor.cell_owner_vector)); + m_cell_owner = WeakCellValue<const int>(*this, descriptor.cellOwnerVector()); { const int rank = parallel::rank(); @@ -70,8 +62,7 @@ Connectivity<Dimension>::_buildFrom(const ConnectivityDescriptor& descriptor) m_cell_is_owned = cell_is_owned; } - Array node_owner_array = convert_to_array(descriptor.node_owner_vector); - m_node_owner = WeakNodeValue<int>{*this, node_owner_array}; + m_node_owner = WeakNodeValue<const int>{*this, descriptor.nodeOwnerVector()}; Array<bool> node_is_owned_array(this->numberOfNodes()); { @@ -87,19 +78,19 @@ Connectivity<Dimension>::_buildFrom(const ConnectivityDescriptor& descriptor) if constexpr (Dimension == 1) { // faces are similar to nodes - m_face_number = WeakFaceValue<int>(*this, node_number_array); - m_face_owner = WeakFaceValue<int>(*this, node_owner_array); + m_face_number = WeakFaceValue<const int>(*this, descriptor.nodeNumberVector()); + m_face_owner = WeakFaceValue<const int>(*this, descriptor.nodeOwnerVector()); m_face_is_owned = WeakFaceValue<bool>(*this, node_is_owned_array); // edges are similar to nodes - m_edge_number = WeakEdgeValue<int>(*this, node_number_array); - m_edge_owner = WeakEdgeValue<int>(*this, node_owner_array); + m_edge_number = WeakEdgeValue<const int>(*this, descriptor.nodeNumberVector()); + m_edge_owner = WeakEdgeValue<const int>(*this, descriptor.nodeOwnerVector()); m_edge_is_owned = WeakEdgeValue<bool>(*this, node_is_owned_array); // edge and face references are set equal to node references m_ref_edge_list_vector.reserve(descriptor.template refItemListVector<ItemType::node>().size()); m_ref_face_list_vector.reserve(descriptor.template refItemListVector<ItemType::node>().size()); - for (auto ref_node_list : descriptor.template refItemListVector<ItemType::node>()) { + for (const auto& ref_node_list : descriptor.template refItemListVector<ItemType::node>()) { const RefId ref_id = ref_node_list.refId(); Array<const NodeId> node_list = ref_node_list.list(); Array<EdgeId> edge_list(node_list.size()); @@ -114,26 +105,15 @@ Connectivity<Dimension>::_buildFrom(const ConnectivityDescriptor& descriptor) } } else { - m_item_to_item_matrix[itemTId(ItemType::face)][itemTId(ItemType::node)] = descriptor.face_to_node_vector; + m_item_to_item_matrix[itemTId(ItemType::face)][itemTId(ItemType::node)] = descriptor.faceToNodeMatrix(); - m_item_to_item_matrix[itemTId(ItemType::cell)][itemTId(ItemType::face)] = descriptor.cell_to_face_vector; + m_item_to_item_matrix[itemTId(ItemType::cell)][itemTId(ItemType::face)] = descriptor.cellToFaceMatrix(); - { - FaceValuePerCell<bool> cell_face_is_reversed(*this); - for (CellId j = 0; j < descriptor.cell_face_is_reversed_vector.size(); ++j) { - const auto& face_cells_vector = descriptor.cell_face_is_reversed_vector[j]; - for (unsigned short lj = 0; lj < face_cells_vector.size(); ++lj) { - cell_face_is_reversed(j, lj) = face_cells_vector[lj]; - } - } - m_cell_face_is_reversed = cell_face_is_reversed; - } + m_cell_face_is_reversed = FaceValuePerCell<const bool>(*this, descriptor.cellFaceIsReversed()); - Array face_number_array = convert_to_array(descriptor.face_number_vector); - m_face_number = WeakFaceValue<int>(*this, face_number_array); + m_face_number = WeakFaceValue<const int>(*this, descriptor.faceNumberVector()); - Array face_owner_array = convert_to_array(descriptor.face_owner_vector); - m_face_owner = WeakFaceValue<int>(*this, face_owner_array); + m_face_owner = WeakFaceValue<const int>(*this, descriptor.faceOwnerVector()); Array<bool> face_is_owned_array(this->numberOfFaces()); { @@ -148,13 +128,13 @@ Connectivity<Dimension>::_buildFrom(const ConnectivityDescriptor& descriptor) if constexpr (Dimension == 2) { // edges are similar to faces - m_edge_number = WeakEdgeValue<int>(*this, face_number_array); - m_edge_owner = WeakEdgeValue<int>(*this, face_owner_array); + m_edge_number = WeakEdgeValue<const int>(*this, descriptor.faceNumberVector()); + m_edge_owner = WeakEdgeValue<const int>(*this, descriptor.faceOwnerVector()); m_edge_is_owned = WeakEdgeValue<bool>(*this, face_is_owned_array); // edge references are set equal to face references m_ref_edge_list_vector.reserve(descriptor.template refItemListVector<ItemType::face>().size()); - for (auto ref_face_list : descriptor.template refItemListVector<ItemType::face>()) { + for (const auto& ref_face_list : descriptor.template refItemListVector<ItemType::face>()) { const RefId ref_id = ref_face_list.refId(); Array<const FaceId> face_list = ref_face_list.list(); Array<EdgeId> edge_list(face_list.size()); @@ -166,25 +146,16 @@ Connectivity<Dimension>::_buildFrom(const ConnectivityDescriptor& descriptor) } } else { - m_item_to_item_matrix[itemTId(ItemType::edge)][itemTId(ItemType::node)] = descriptor.edge_to_node_vector; + m_item_to_item_matrix[itemTId(ItemType::edge)][itemTId(ItemType::node)] = descriptor.edgeToNodeMatrix(); - m_item_to_item_matrix[itemTId(ItemType::face)][itemTId(ItemType::edge)] = descriptor.face_to_edge_vector; + m_item_to_item_matrix[itemTId(ItemType::face)][itemTId(ItemType::edge)] = descriptor.faceToEdgeMatrix(); - m_item_to_item_matrix[itemTId(ItemType::cell)][itemTId(ItemType::edge)] = descriptor.cell_to_edge_vector; + m_item_to_item_matrix[itemTId(ItemType::cell)][itemTId(ItemType::edge)] = descriptor.cellToEdgeMatrix(); - { - EdgeValuePerFace<bool> face_edge_is_reversed(*this); - for (FaceId l = 0; l < descriptor.face_edge_is_reversed_vector.size(); ++l) { - const auto& edge_faces_vector = descriptor.face_edge_is_reversed_vector[l]; - for (unsigned short el = 0; el < edge_faces_vector.size(); ++el) { - face_edge_is_reversed(l, el) = edge_faces_vector[el]; - } - } - m_face_edge_is_reversed = face_edge_is_reversed; - } + m_face_edge_is_reversed = EdgeValuePerFace<const bool>(*this, descriptor.faceEdgeIsReversed()); - m_edge_number = WeakEdgeValue<int>(*this, convert_to_array(descriptor.edge_number_vector)); - m_edge_owner = WeakEdgeValue<int>(*this, convert_to_array(descriptor.edge_owner_vector)); + m_edge_number = WeakEdgeValue<const int>(*this, descriptor.edgeNumberVector()); + m_edge_owner = WeakEdgeValue<const int>(*this, descriptor.edgeOwnerVector()); { const int rank = parallel::rank(); diff --git a/src/mesh/Connectivity.hpp b/src/mesh/Connectivity.hpp index b0279507ee41e6f6d3433bda2b5dd7beaf406265..ee7b07fe043a44262c23afc053e748bcac448b50 100644 --- a/src/mesh/Connectivity.hpp +++ b/src/mesh/Connectivity.hpp @@ -122,7 +122,7 @@ class Connectivity final : public IConnectivity const ConnectivityMatrix& connectivity_matrix = m_item_to_item_matrix[itemTId(item_type_0)][itemTId(item_type_1)]; if (not connectivity_matrix.isBuilt()) { const_cast<ConnectivityMatrix&>(connectivity_matrix) = - m_connectivity_computer.computeConnectivityMatrix(*this, item_type_0, item_type_1); + m_connectivity_computer.computeInverseConnectivityMatrix(*this, item_type_0, item_type_1); } return connectivity_matrix; } diff --git a/src/mesh/ConnectivityBuilderBase.cpp b/src/mesh/ConnectivityBuilderBase.cpp index 55c56b3a4b78f28ecdf8613d04d4d0348b9e5c4a..e7eb95fc6ed064805d12b5a8ece6e2844c37b9e9 100644 --- a/src/mesh/ConnectivityBuilderBase.cpp +++ b/src/mesh/ConnectivityBuilderBase.cpp @@ -7,8 +7,6 @@ #include <utils/PugsAssert.hpp> #include <utils/PugsMacros.hpp> -#include <map> -#include <unordered_map> #include <vector> template <size_t Dimension> @@ -16,240 +14,583 @@ void ConnectivityBuilderBase::_computeCellFaceAndFaceNodeConnectivities(ConnectivityDescriptor& descriptor) { static_assert((Dimension == 2) or (Dimension == 3), "Invalid dimension to compute cell-face connectivities"); - using CellFaceInfo = std::tuple<CellId, unsigned short, bool>; - using Face = ConnectivityFace<Dimension>; - const auto& node_number_vector = descriptor.node_number_vector; - Array<unsigned short> cell_nb_faces(descriptor.cell_to_node_vector.size()); - std::map<Face, std::vector<CellFaceInfo>> face_cells_map; - for (CellId j = 0; j < descriptor.cell_to_node_vector.size(); ++j) { - const auto& cell_nodes = descriptor.cell_to_node_vector[j]; + const auto& node_number_vector = descriptor.nodeNumberVector(); + const auto& cell_to_node_matrix = descriptor.cellToNodeMatrix(); + const auto& cell_type_vector = descriptor.cellTypeVector(); + + size_t total_number_of_faces = 0; + + for (CellId j = 0; j < cell_to_node_matrix.numberOfRows(); ++j) { + const auto& cell_nodes = cell_to_node_matrix[j]; if constexpr (Dimension == 2) { - switch (descriptor.cell_type_vector[j]) { - case CellType::Triangle: { - cell_nb_faces[j] = 3; - // face 0 - Face f0({cell_nodes[1], cell_nodes[2]}, node_number_vector); - face_cells_map[f0].emplace_back(std::make_tuple(j, 0, f0.reversed())); - - // face 1 - Face f1({cell_nodes[2], cell_nodes[0]}, node_number_vector); - face_cells_map[f1].emplace_back(std::make_tuple(j, 1, f1.reversed())); - - // face 2 - Face f2({cell_nodes[0], cell_nodes[1]}, node_number_vector); - face_cells_map[f2].emplace_back(std::make_tuple(j, 2, f2.reversed())); + total_number_of_faces += cell_nodes.size(); + } else if constexpr (Dimension == 3) { + switch (cell_type_vector[j]) { + case CellType::Hexahedron: { + total_number_of_faces += 6; break; } - case CellType::Quadrangle: { - cell_nb_faces[j] = 4; - // face 0 - Face f0({cell_nodes[0], cell_nodes[1]}, node_number_vector); - face_cells_map[f0].emplace_back(std::make_tuple(j, 0, f0.reversed())); - - // face 1 - Face f1({cell_nodes[1], cell_nodes[2]}, node_number_vector); - face_cells_map[f1].emplace_back(std::make_tuple(j, 1, f1.reversed())); - - // face 2 - Face f2({cell_nodes[2], cell_nodes[3]}, node_number_vector); - face_cells_map[f2].emplace_back(std::make_tuple(j, 2, f2.reversed())); - - // face 3 - Face f3({cell_nodes[3], cell_nodes[0]}, node_number_vector); - face_cells_map[f3].emplace_back(std::make_tuple(j, 3, f3.reversed())); + case CellType::Tetrahedron: { + total_number_of_faces += 4; break; } - case CellType::Polygon: { - cell_nb_faces[j] = cell_nodes.size(); - for (size_t i = 0; i < cell_nodes.size(); ++i) { - Face f({cell_nodes[i], cell_nodes[(i + 1) % cell_nodes.size()]}, node_number_vector); - face_cells_map[f].emplace_back(std::make_tuple(j, i, f.reversed())); - } + case CellType::Prism: { + total_number_of_faces += 5; + break; + } + case CellType::Pyramid: { + total_number_of_faces += cell_nodes.size(); + break; + } + case CellType::Diamond: { + total_number_of_faces += 2 * (cell_nodes.size() - 2); break; } default: { std::ostringstream error_msg; - error_msg << name(descriptor.cell_type_vector[j]) << ": unexpected cell type in dimension 2"; + error_msg << name(cell_type_vector[j]) << ": unexpected cell type in dimension 3"; throw UnexpectedError(error_msg.str()); } } - } else if constexpr (Dimension == 3) { - switch (descriptor.cell_type_vector[j]) { - case CellType::Hexahedron: { - // face 0 - Face f0({cell_nodes[3], cell_nodes[2], cell_nodes[1], cell_nodes[0]}, node_number_vector); - face_cells_map[f0].emplace_back(std::make_tuple(j, 0, f0.reversed())); + } + } - // face 1 - Face f1({cell_nodes[4], cell_nodes[5], cell_nodes[6], cell_nodes[7]}, node_number_vector); - face_cells_map[f1].emplace_back(std::make_tuple(j, 1, f1.reversed())); + const size_t total_number_of_face_by_node = [&] { + if constexpr (Dimension == 2) { + return 2 * total_number_of_faces; + } else { + Assert(Dimension == 3); + size_t count_number_of_face_by_node = 0; + for (CellId j = 0; j < cell_to_node_matrix.numberOfRows(); ++j) { + switch (cell_type_vector[j]) { + case CellType::Hexahedron: { + count_number_of_face_by_node += 6 * 4; + break; + } + case CellType::Tetrahedron: { + count_number_of_face_by_node += 4 * 3; + break; + } + case CellType::Prism: { + count_number_of_face_by_node += 3 * 4 + 2 * 3; + break; + } + case CellType::Pyramid: { + const auto& cell_nodes = cell_to_node_matrix[j]; + count_number_of_face_by_node += 1 * cell_nodes.size() + cell_nodes.size() * 3; + break; + } + case CellType::Diamond: { + const auto& cell_nodes = cell_to_node_matrix[j]; + count_number_of_face_by_node += cell_nodes.size() * 3 * 2; + break; + } + default: { + std::ostringstream error_msg; + error_msg << name(cell_type_vector[j]) << ": unexpected cell type in dimension 3"; + throw UnexpectedError(error_msg.str()); + } + } + } + return count_number_of_face_by_node; + } + }(); - // face 2 - Face f2({cell_nodes[0], cell_nodes[4], cell_nodes[7], cell_nodes[3]}, node_number_vector); - face_cells_map[f2].emplace_back(std::make_tuple(j, 2, f2.reversed())); + Array<unsigned int> dup_faces_to_node_list(total_number_of_face_by_node); + Array<unsigned int> dup_face_to_node_row(total_number_of_faces + 1); + size_t i_face = 0; + dup_face_to_node_row[0] = 0; - // face 3 - Face f3({cell_nodes[1], cell_nodes[2], cell_nodes[6], cell_nodes[5]}, node_number_vector); - face_cells_map[f3].emplace_back(std::make_tuple(j, 3, f3.reversed())); + Array<unsigned short> cell_nb_faces(cell_to_node_matrix.numberOfRows()); + { + size_t i_face_node = 0; + for (CellId j = 0; j < cell_to_node_matrix.numberOfRows(); ++j) { + const auto& cell_nodes = cell_to_node_matrix[j]; + + if constexpr (Dimension == 2) { + switch (cell_type_vector[j]) { + case CellType::Triangle: { + dup_faces_to_node_list[i_face_node++] = cell_nodes[1]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[2]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[2]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[0]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[0]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[1]; + + dup_face_to_node_row[i_face + 1] = dup_face_to_node_row[i_face] + 2; + i_face++; + dup_face_to_node_row[i_face + 1] = dup_face_to_node_row[i_face] + 2; + i_face++; + dup_face_to_node_row[i_face + 1] = dup_face_to_node_row[i_face] + 2; + i_face++; + cell_nb_faces[j] = 3; + break; + } + case CellType::Quadrangle: { + dup_faces_to_node_list[i_face_node++] = cell_nodes[0]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[1]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[1]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[2]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[2]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[3]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[3]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[0]; + + dup_face_to_node_row[i_face + 1] = dup_face_to_node_row[i_face] + 2; + i_face++; + dup_face_to_node_row[i_face + 1] = dup_face_to_node_row[i_face] + 2; + i_face++; + dup_face_to_node_row[i_face + 1] = dup_face_to_node_row[i_face] + 2; + i_face++; + dup_face_to_node_row[i_face + 1] = dup_face_to_node_row[i_face] + 2; + i_face++; + cell_nb_faces[j] = 4; + break; + } + case CellType::Polygon: { + for (size_t i = 0; i < cell_nodes.size(); ++i) { + dup_faces_to_node_list[i_face_node] = cell_nodes[i]; + i_face_node++; + dup_faces_to_node_list[i_face_node] = cell_nodes[(i + 1) % cell_nodes.size()]; + i_face_node++; + + dup_face_to_node_row[i_face + 1] = dup_face_to_node_row[i_face] + 2; + i_face++; + } - // face 4 - Face f4({cell_nodes[0], cell_nodes[1], cell_nodes[5], cell_nodes[4]}, node_number_vector); - face_cells_map[f4].emplace_back(std::make_tuple(j, 4, f4.reversed())); + cell_nb_faces[j] = cell_nodes.size(); + break; + } + default: { + std::ostringstream error_msg; + error_msg << name(cell_type_vector[j]) << ": unexpected cell type in dimension 2"; + throw UnexpectedError(error_msg.str()); + } + } + } else if constexpr (Dimension == 3) { + switch (cell_type_vector[j]) { + case CellType::Hexahedron: { + dup_faces_to_node_list[i_face_node++] = cell_nodes[3]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[2]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[1]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[0]; + + dup_face_to_node_row[i_face + 1] = dup_face_to_node_row[i_face] + 4; + i_face++; + + dup_faces_to_node_list[i_face_node++] = cell_nodes[4]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[5]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[6]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[7]; + + dup_face_to_node_row[i_face + 1] = dup_face_to_node_row[i_face] + 4; + i_face++; + + dup_faces_to_node_list[i_face_node++] = cell_nodes[0]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[4]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[7]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[3]; + + dup_face_to_node_row[i_face + 1] = dup_face_to_node_row[i_face] + 4; + i_face++; + + dup_faces_to_node_list[i_face_node++] = cell_nodes[1]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[2]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[6]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[5]; + + dup_face_to_node_row[i_face + 1] = dup_face_to_node_row[i_face] + 4; + i_face++; + + dup_faces_to_node_list[i_face_node++] = cell_nodes[0]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[1]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[5]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[4]; + + dup_face_to_node_row[i_face + 1] = dup_face_to_node_row[i_face] + 4; + i_face++; + + dup_faces_to_node_list[i_face_node++] = cell_nodes[3]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[7]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[6]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[2]; + + dup_face_to_node_row[i_face + 1] = dup_face_to_node_row[i_face] + 4; + i_face++; + + cell_nb_faces[j] = 6; + break; + } + case CellType::Tetrahedron: { + dup_faces_to_node_list[i_face_node++] = cell_nodes[1]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[2]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[3]; - // face 5 - Face f5({cell_nodes[3], cell_nodes[7], cell_nodes[6], cell_nodes[2]}, node_number_vector); - face_cells_map[f5].emplace_back(std::make_tuple(j, 5, f5.reversed())); + dup_face_to_node_row[i_face + 1] = dup_face_to_node_row[i_face] + 3; + i_face++; - cell_nb_faces[j] = 6; - break; - } - case CellType::Tetrahedron: { - cell_nb_faces[j] = 4; - // face 0 - Face f0({cell_nodes[1], cell_nodes[2], cell_nodes[3]}, node_number_vector); - face_cells_map[f0].emplace_back(std::make_tuple(j, 0, f0.reversed())); - - // face 1 - Face f1({cell_nodes[0], cell_nodes[3], cell_nodes[2]}, node_number_vector); - face_cells_map[f1].emplace_back(std::make_tuple(j, 1, f1.reversed())); - - // face 2 - Face f2({cell_nodes[0], cell_nodes[1], cell_nodes[3]}, node_number_vector); - face_cells_map[f2].emplace_back(std::make_tuple(j, 2, f2.reversed())); - - // face 3 - Face f3({cell_nodes[0], cell_nodes[2], cell_nodes[1]}, node_number_vector); - face_cells_map[f3].emplace_back(std::make_tuple(j, 3, f3.reversed())); - break; - } - case CellType::Prism: { - // face 0 - Face f0({cell_nodes[2], cell_nodes[1], cell_nodes[0]}, node_number_vector); - face_cells_map[f0].emplace_back(std::make_tuple(j, 0, f0.reversed())); + dup_faces_to_node_list[i_face_node++] = cell_nodes[0]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[3]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[2]; - // face 1 - Face f1({cell_nodes[3], cell_nodes[4], cell_nodes[5]}, node_number_vector); - face_cells_map[f1].emplace_back(std::make_tuple(j, 1, f1.reversed())); + dup_face_to_node_row[i_face + 1] = dup_face_to_node_row[i_face] + 3; + i_face++; - // face 2 - Face f2({cell_nodes[1], cell_nodes[2], cell_nodes[5], cell_nodes[4]}, node_number_vector); - face_cells_map[f2].emplace_back(std::make_tuple(j, 2, f2.reversed())); + dup_faces_to_node_list[i_face_node++] = cell_nodes[0]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[1]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[3]; - // face 3 - Face f3({cell_nodes[0], cell_nodes[1], cell_nodes[4], cell_nodes[3]}, node_number_vector); - face_cells_map[f3].emplace_back(std::make_tuple(j, 3, f3.reversed())); + dup_face_to_node_row[i_face + 1] = dup_face_to_node_row[i_face] + 3; + i_face++; - // face 4 - Face f4({cell_nodes[2], cell_nodes[0], cell_nodes[3], cell_nodes[5]}, node_number_vector); - face_cells_map[f4].emplace_back(std::make_tuple(j, 4, f4.reversed())); + dup_faces_to_node_list[i_face_node++] = cell_nodes[0]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[2]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[1]; - cell_nb_faces[j] = 5; - break; - } - case CellType::Pyramid: { - cell_nb_faces[j] = cell_nodes.size(); - std::vector<unsigned int> base_nodes(cell_nodes.size() - 1); - for (size_t i = 0; i < base_nodes.size(); ++i) { - base_nodes[base_nodes.size() - 1 - i] = cell_nodes[i]; - } + dup_face_to_node_row[i_face + 1] = dup_face_to_node_row[i_face] + 3; + i_face++; - // base face - { - Face base_face(base_nodes, node_number_vector); - face_cells_map[base_face].emplace_back(std::make_tuple(j, 0, base_face.reversed())); + cell_nb_faces[j] = 4; + break; } - // side faces - const auto pyramid_vertex = cell_nodes[cell_nodes.size() - 1]; - for (size_t i_node = 0; i_node < base_nodes.size(); ++i_node) { - Face side_face({base_nodes[(i_node + 1) % base_nodes.size()], base_nodes[i_node], pyramid_vertex}, - node_number_vector); - face_cells_map[side_face].emplace_back(std::make_tuple(j, i_node + 1, side_face.reversed())); + case CellType::Prism: { + dup_faces_to_node_list[i_face_node++] = cell_nodes[2]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[1]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[0]; + + dup_face_to_node_row[i_face + 1] = dup_face_to_node_row[i_face] + 3; + i_face++; + + dup_faces_to_node_list[i_face_node++] = cell_nodes[3]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[4]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[5]; + + dup_face_to_node_row[i_face + 1] = dup_face_to_node_row[i_face] + 3; + i_face++; + + dup_faces_to_node_list[i_face_node++] = cell_nodes[1]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[2]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[5]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[4]; + + dup_face_to_node_row[i_face + 1] = dup_face_to_node_row[i_face] + 4; + i_face++; + + dup_faces_to_node_list[i_face_node++] = cell_nodes[0]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[1]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[4]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[3]; + + dup_face_to_node_row[i_face + 1] = dup_face_to_node_row[i_face] + 4; + i_face++; + + dup_faces_to_node_list[i_face_node++] = cell_nodes[2]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[0]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[3]; + dup_faces_to_node_list[i_face_node++] = cell_nodes[5]; + + dup_face_to_node_row[i_face + 1] = dup_face_to_node_row[i_face] + 4; + i_face++; + + cell_nb_faces[j] = 5; + break; } - break; - } - case CellType::Diamond: { - cell_nb_faces[j] = 2 * (cell_nodes.size() - 2); - std::vector<unsigned int> base_nodes; - std::copy_n(cell_nodes.begin() + 1, cell_nodes.size() - 2, std::back_inserter(base_nodes)); + case CellType::Pyramid: { + cell_nb_faces[j] = cell_nodes.size(); + std::vector<unsigned int> base_nodes(cell_nodes.size() - 1); + for (size_t i = 0; i < base_nodes.size(); ++i) { + base_nodes[base_nodes.size() - 1 - i] = cell_nodes[i]; + } - { // top faces - const auto top_vertex = cell_nodes[cell_nodes.size() - 1]; + for (size_t i = 0; i < base_nodes.size(); ++i) { + dup_faces_to_node_list[i_face_node++] = base_nodes[i]; + } + + dup_face_to_node_row[i_face + 1] = dup_face_to_node_row[i_face] + base_nodes.size(); + i_face++; + + // side faces + const auto pyramid_vertex = cell_nodes[cell_nodes.size() - 1]; for (size_t i_node = 0; i_node < base_nodes.size(); ++i_node) { - Face top_face({base_nodes[i_node], base_nodes[(i_node + 1) % base_nodes.size()], top_vertex}, - node_number_vector); - face_cells_map[top_face].emplace_back(std::make_tuple(j, i_node, top_face.reversed())); + dup_faces_to_node_list[i_face_node++] = base_nodes[(i_node + 1) % base_nodes.size()]; + dup_faces_to_node_list[i_face_node++] = base_nodes[i_node]; + dup_faces_to_node_list[i_face_node++] = pyramid_vertex; + + dup_face_to_node_row[i_face + 1] = dup_face_to_node_row[i_face] + 3; + i_face++; } + break; } + case CellType::Diamond: { + auto base_nodes = [&](size_t i) { return cell_nodes[i + 1]; }; + + { // top faces + const auto top_vertex = cell_nodes[cell_nodes.size() - 1]; + for (size_t i_node = 0; i_node < cell_nodes.size() - 2; ++i_node) { + dup_faces_to_node_list[i_face_node++] = base_nodes(i_node); + dup_faces_to_node_list[i_face_node++] = base_nodes((i_node + 1) % (cell_nodes.size() - 2)); + dup_faces_to_node_list[i_face_node++] = top_vertex; + + dup_face_to_node_row[i_face + 1] = dup_face_to_node_row[i_face] + 3; + i_face++; + } + } - { // bottom faces - const auto bottom_vertex = cell_nodes[0]; - for (size_t i_node = 0; i_node < base_nodes.size(); ++i_node) { - Face bottom_face({base_nodes[(i_node + 1) % base_nodes.size()], base_nodes[i_node], bottom_vertex}, - node_number_vector); - face_cells_map[bottom_face].emplace_back( - std::make_tuple(j, i_node + base_nodes.size(), bottom_face.reversed())); + { // bottom faces + const auto bottom_vertex = cell_nodes[0]; + for (size_t i_node = 0; i_node < cell_nodes.size() - 2; ++i_node) { + dup_faces_to_node_list[i_face_node++] = base_nodes((i_node + 1) % (cell_nodes.size() - 2)); + dup_faces_to_node_list[i_face_node++] = base_nodes(i_node); + dup_faces_to_node_list[i_face_node++] = bottom_vertex; + + dup_face_to_node_row[i_face + 1] = dup_face_to_node_row[i_face] + 3; + i_face++; + } } + cell_nb_faces[j] = 2 * (cell_nodes.size() - 2); + break; + } + default: { + std::ostringstream error_msg; + error_msg << name(cell_type_vector[j]) << ": unexpected cell type in dimension 3"; + throw UnexpectedError(error_msg.str()); + } } - break; } - default: { - std::ostringstream error_msg; - error_msg << name(descriptor.cell_type_vector[j]) << ": unexpected cell type in dimension 3"; - throw UnexpectedError(error_msg.str()); + } + } + + Array<bool> cell_face_is_reversed(total_number_of_faces); + + if constexpr (Dimension == 2) { + for (size_t i_face = 0; i_face < total_number_of_faces; ++i_face) { + if (node_number_vector[dup_faces_to_node_list[2 * i_face]] > + node_number_vector[dup_faces_to_node_list[2 * i_face + 1]]) { + std::swap(dup_faces_to_node_list[2 * i_face], dup_faces_to_node_list[2 * i_face + 1]); + cell_face_is_reversed[i_face] = true; + } else { + cell_face_is_reversed[i_face] = false; } + } + } else if constexpr (Dimension == 3) { + std::vector<int> buffer; + + for (size_t i_face = 0; i_face < total_number_of_faces; ++i_face) { + const size_t face_node_number = dup_face_to_node_row[i_face + 1] - dup_face_to_node_row[i_face]; + size_t i_face_node_smallest_number = 0; + for (size_t i_face_node = 1; i_face_node < face_node_number; ++i_face_node) { + if (node_number_vector[dup_faces_to_node_list[dup_face_to_node_row[i_face] + i_face_node]] < + node_number_vector[dup_faces_to_node_list[dup_face_to_node_row[i_face] + i_face_node_smallest_number]]) { + i_face_node_smallest_number = i_face_node; + } } + + if (i_face_node_smallest_number != 0) { + buffer.resize(face_node_number); + for (size_t i_node = i_face_node_smallest_number; i_node < face_node_number; ++i_node) { + buffer[i_node - i_face_node_smallest_number] = dup_faces_to_node_list[dup_face_to_node_row[i_face] + i_node]; + } + for (size_t i_node = 0; i_node < i_face_node_smallest_number; ++i_node) { + buffer[i_node + face_node_number - i_face_node_smallest_number] = + dup_faces_to_node_list[dup_face_to_node_row[i_face] + i_node]; + } + + for (size_t i_node = 0; i_node < face_node_number; ++i_node) { + dup_faces_to_node_list[dup_face_to_node_row[i_face] + i_node] = buffer[i_node]; + } + } + + if (node_number_vector[dup_faces_to_node_list[dup_face_to_node_row[i_face] + 1]] > + node_number_vector[dup_faces_to_node_list[dup_face_to_node_row[i_face + 1] - 1]]) { + for (size_t i_node = 1; i_node <= (face_node_number + 1) / 2 - 1; ++i_node) { + std::swap(dup_faces_to_node_list[dup_face_to_node_row[i_face] + i_node], + dup_faces_to_node_list[dup_face_to_node_row[i_face + 1] - i_node]); + } + + cell_face_is_reversed[i_face] = true; + } else { + cell_face_is_reversed[i_face] = false; + } + } + } + + Array<unsigned int> node_to_duplicate_face_row(node_number_vector.size() + 1); + node_to_duplicate_face_row.fill(0); + for (size_t i_face = 0; i_face < total_number_of_faces; ++i_face) { + for (size_t i_node_face = dup_face_to_node_row[i_face]; i_node_face < dup_face_to_node_row[i_face + 1]; + ++i_node_face) { + node_to_duplicate_face_row[dup_faces_to_node_list[i_node_face] + 1]++; } } + for (size_t i_node = 1; i_node < node_to_duplicate_face_row.size(); ++i_node) { + node_to_duplicate_face_row[i_node] += node_to_duplicate_face_row[i_node - 1]; + } + + Array<unsigned int> node_duplicate_face_list(node_to_duplicate_face_row[node_to_duplicate_face_row.size() - 1]); + { - descriptor.cell_to_face_vector.resize(descriptor.cell_to_node_vector.size()); - for (CellId j = 0; j < descriptor.cell_to_face_vector.size(); ++j) { - descriptor.cell_to_face_vector[j].resize(cell_nb_faces[j]); + Array<unsigned int> node_duplicate_face_row_idx(node_number_vector.size()); + node_duplicate_face_row_idx.fill(0); + + for (size_t i_face = 0; i_face < total_number_of_faces; ++i_face) { + for (size_t i_node_face = dup_face_to_node_row[i_face]; i_node_face < dup_face_to_node_row[i_face + 1]; + ++i_node_face) { + const size_t node_id = dup_faces_to_node_list[i_node_face]; + node_duplicate_face_list[node_to_duplicate_face_row[node_id] + node_duplicate_face_row_idx[node_id]] = i_face; + node_duplicate_face_row_idx[node_id]++; + } } - FaceId l = 0; - for (const auto& face_cells_vector : face_cells_map) { - const auto& cells_vector = face_cells_vector.second; - for (unsigned short lj = 0; lj < cells_vector.size(); ++lj) { - const auto& [cell_number, cell_local_face, reversed] = cells_vector[lj]; - descriptor.cell_to_face_vector[cell_number][cell_local_face] = l; - } - ++l; + } + + Array<unsigned int> dup_face_to_face(total_number_of_faces); + parallel_for( + total_number_of_faces, PUGS_LAMBDA(size_t i_face) { dup_face_to_face[i_face] = i_face; }); + + auto is_same_face = [=](const size_t i_face, const size_t j_face) { + if ((dup_face_to_node_row[i_face + 1] - dup_face_to_node_row[i_face]) != + (dup_face_to_node_row[j_face + 1] - dup_face_to_node_row[j_face])) { + return false; + } else { + auto i_face_node = dup_face_to_node_row[i_face]; + auto j_face_node = dup_face_to_node_row[j_face]; + while (i_face_node < dup_face_to_node_row[i_face + 1]) { + if (dup_faces_to_node_list[i_face_node] != dup_faces_to_node_list[j_face_node]) { + return false; + } + i_face_node++; + j_face_node++; + } + return true; + } + }; + + size_t nb_dup_faces = 0; + for (size_t i_node = 0; i_node < node_number_vector.size(); ++i_node) { + for (size_t i_node_face = node_to_duplicate_face_row[i_node]; + i_node_face < node_to_duplicate_face_row[i_node + 1] - 1; ++i_node_face) { + for (size_t j_node_face = i_node_face + 1; j_node_face < node_to_duplicate_face_row[i_node + 1]; ++j_node_face) { + if (dup_face_to_face[node_duplicate_face_list[i_node_face]] == + dup_face_to_face[node_duplicate_face_list[j_node_face]]) + continue; + if (is_same_face(node_duplicate_face_list[i_node_face], node_duplicate_face_list[j_node_face])) { + dup_face_to_face[node_duplicate_face_list[j_node_face]] = + dup_face_to_face[node_duplicate_face_list[i_node_face]]; + nb_dup_faces++; + } + } } } + // compute face_id + Array<FaceId> dup_face_to_face_id(total_number_of_faces); { - descriptor.cell_face_is_reversed_vector.resize(descriptor.cell_to_node_vector.size()); - for (CellId j = 0; j < descriptor.cell_face_is_reversed_vector.size(); ++j) { - descriptor.cell_face_is_reversed_vector[j] = Array<bool>(cell_nb_faces[j]); + FaceId face_id = 0; + for (size_t i_dup_face = 0; i_dup_face < total_number_of_faces; ++i_dup_face) { + if (dup_face_to_face[i_dup_face] == i_dup_face) { + dup_face_to_face_id[i_dup_face] = face_id; + ++face_id; + } else { + size_t i_face = dup_face_to_face[i_dup_face]; + while (i_face != dup_face_to_face[i_face]) { + i_face = dup_face_to_face[i_face]; + } + dup_face_to_face_id[i_dup_face] = dup_face_to_face_id[i_face]; + } } - for (const auto& face_cells_vector : face_cells_map) { - const auto& cells_vector = face_cells_vector.second; - for (unsigned short lj = 0; lj < cells_vector.size(); ++lj) { - const auto& [cell_number, cell_local_face, reversed] = cells_vector[lj]; - descriptor.cell_face_is_reversed_vector[cell_number][cell_local_face] = reversed; + } + + Array<unsigned int> node_to_face_row(node_to_duplicate_face_row.size()); + { + unsigned int nb_faces = 0; + for (size_t i_node = 0; i_node < node_to_duplicate_face_row.size() - 1; ++i_node) { + node_to_face_row[i_node] = nb_faces; + for (size_t i_face = node_to_duplicate_face_row[i_node]; i_face < node_to_duplicate_face_row[i_node + 1]; + ++i_face) { + if (dup_face_to_face[node_duplicate_face_list[i_face]] == node_duplicate_face_list[i_face]) { + ++nb_faces; + } + } + } + node_to_face_row[node_to_duplicate_face_row.size() - 1] = nb_faces; + } + + Array<unsigned int> node_to_face_list(node_to_face_row[node_to_duplicate_face_row.size() - 1]); + { + unsigned int i_node_to_face = 0; + for (size_t i_node = 0; i_node < node_to_duplicate_face_row.size() - 1; ++i_node) { + for (size_t i_face = node_to_duplicate_face_row[i_node]; i_face < node_to_duplicate_face_row[i_node + 1]; + ++i_face) { + if (dup_face_to_face[node_duplicate_face_list[i_face]] == node_duplicate_face_list[i_face]) { + node_to_face_list[i_node_to_face++] = dup_face_to_face_id[node_duplicate_face_list[i_face]]; + } + } + } + } + + descriptor.setNodeToFaceMatrix(ConnectivityMatrix(node_to_face_row, node_to_face_list)); + + Array<unsigned int> cell_to_face_row(cell_nb_faces.size() + 1); + cell_to_face_row[0] = 0; + for (size_t i = 0; i < cell_nb_faces.size(); ++i) { + cell_to_face_row[i + 1] = cell_to_face_row[i] + cell_nb_faces[i]; + } + + Array<unsigned int> cell_to_face_list(cell_to_face_row[cell_to_face_row.size() - 1]); + { + size_t i_cell_face = 0; + for (CellId cell_id = 0; cell_id < cell_nb_faces.size(); ++cell_id) { + for (size_t i_face = 0; i_face < cell_nb_faces[cell_id]; ++i_face) { + cell_to_face_list[i_cell_face++] = dup_face_to_face_id[cell_to_face_row[cell_id] + i_face]; } } } + descriptor.setCellToFaceMatrix(ConnectivityMatrix(cell_to_face_row, cell_to_face_list)); + + descriptor.setFaceNumberVector([&] { + Array<int> face_number_vector(total_number_of_faces - nb_dup_faces); + parallel_for( + face_number_vector.size(), PUGS_LAMBDA(const size_t l) { face_number_vector[l] = l; }); + return face_number_vector; + }()); + + Array<unsigned int> face_ending(total_number_of_faces - nb_dup_faces + 1); { - descriptor.face_to_node_vector.resize(face_cells_map.size()); - int l = 0; - for (const auto& face_info : face_cells_map) { - const Face& face = face_info.first; - descriptor.face_to_node_vector[l] = face.nodeIdList(); - ++l; + size_t i_face = 0; + face_ending[0] = 0; + for (size_t i_dup_face = 0; i_dup_face < dup_face_to_face.size(); ++i_dup_face) { + if (dup_face_to_face[i_dup_face] == i_dup_face) { + face_ending[i_face + 1] = + dup_face_to_node_row[i_dup_face + 1] - dup_face_to_node_row[i_dup_face] + face_ending[i_face]; + ++i_face; + } } } + Array<unsigned int> faces_node_list(face_ending[face_ending.size() - 1]); { - // Face numbers may change if numbers are provided in the file - descriptor.face_number_vector.resize(face_cells_map.size()); - for (size_t l = 0; l < face_cells_map.size(); ++l) { - descriptor.face_number_vector[l] = l; + size_t i_face = 0; + face_ending[0] = 0; + for (size_t i_dup_face = 0; i_dup_face < dup_face_to_face.size(); ++i_dup_face) { + if (dup_face_to_face[i_dup_face] == i_dup_face) { + size_t dup_face_node_begin = dup_face_to_node_row[i_dup_face]; + size_t face_node_begin = face_ending[i_face]; + + for (size_t i_face_node = 0; + i_face_node < dup_face_to_node_row[i_dup_face + 1] - dup_face_to_node_row[i_dup_face]; ++i_face_node) { + faces_node_list[face_node_begin + i_face_node] = dup_faces_to_node_list[dup_face_node_begin + i_face_node]; + } + ++i_face; + } } } + + descriptor.setFaceToNodeMatrix(ConnectivityMatrix(face_ending, faces_node_list)); + + descriptor.setCellFaceIsReversed(cell_face_is_reversed); } template <size_t Dimension> @@ -257,206 +598,331 @@ void ConnectivityBuilderBase::_computeFaceEdgeAndEdgeNodeAndCellEdgeConnectivities(ConnectivityDescriptor& descriptor) { static_assert(Dimension == 3, "Invalid dimension to compute face-edge connectivities"); - using FaceEdgeInfo = std::tuple<FaceId, unsigned short, bool>; - using Edge = ConnectivityFace<2>; - - const auto& node_number_vector = descriptor.node_number_vector; - Array<unsigned short> face_nb_edges(descriptor.face_to_node_vector.size()); - std::map<Edge, std::vector<FaceEdgeInfo>> edge_faces_map; - for (FaceId l = 0; l < descriptor.face_to_node_vector.size(); ++l) { - const auto& face_nodes = descriptor.face_to_node_vector[l]; - - face_nb_edges[l] = face_nodes.size(); - for (size_t r = 0; r < face_nodes.size() - 1; ++r) { - Edge e({face_nodes[r], face_nodes[r + 1]}, node_number_vector); - edge_faces_map[e].emplace_back(std::make_tuple(l, r, e.reversed())); - } - { - Edge e({face_nodes[face_nodes.size() - 1], face_nodes[0]}, node_number_vector); - edge_faces_map[e].emplace_back(std::make_tuple(l, face_nodes.size() - 1, e.reversed())); + + const auto& face_to_node_matrix = descriptor.faceToNodeMatrix(); + + Array<const unsigned int> face_to_edge_row = face_to_node_matrix.rowsMap(); + + const size_t total_number_of_face_edges = face_to_edge_row[face_to_edge_row.size() - 1]; + + const size_t total_number_of_node_by_face_edges = 2 * total_number_of_face_edges; + + Array<unsigned int> face_edge_to_node_list(total_number_of_node_by_face_edges); + { + size_t i_edge_node = 0; + for (size_t i_face = 0; i_face < face_to_edge_row.size() - 1; ++i_face) { + const auto& face_node_list = face_to_node_matrix[i_face]; + for (size_t i_node = 0; i_node < face_node_list.size() - 1; ++i_node) { + face_edge_to_node_list[i_edge_node++] = face_node_list[i_node]; + face_edge_to_node_list[i_edge_node++] = face_node_list[i_node + 1]; + } + face_edge_to_node_list[i_edge_node++] = face_node_list[face_node_list.size() - 1]; + face_edge_to_node_list[i_edge_node++] = face_node_list[0]; } } - std::unordered_map<Edge, EdgeId, typename Edge::Hash> edge_id_map; - { - descriptor.face_to_edge_vector.resize(descriptor.face_to_node_vector.size()); - for (FaceId l = 0; l < descriptor.face_to_node_vector.size(); ++l) { - descriptor.face_to_edge_vector[l].resize(face_nb_edges[l]); + auto node_number_vector = descriptor.nodeNumberVector(); + Array<bool> face_edge_is_reversed(total_number_of_face_edges); + for (size_t i_edge = 0; i_edge < total_number_of_face_edges; ++i_edge) { + if (node_number_vector[face_edge_to_node_list[2 * i_edge]] > + node_number_vector[face_edge_to_node_list[2 * i_edge + 1]]) { + std::swap(face_edge_to_node_list[2 * i_edge], face_edge_to_node_list[2 * i_edge + 1]); + face_edge_is_reversed[i_edge] = true; + } else { + face_edge_is_reversed[i_edge] = false; } - EdgeId e = 0; - for (const auto& edge_faces_vector : edge_faces_map) { - const auto& faces_vector = edge_faces_vector.second; - for (unsigned short l = 0; l < faces_vector.size(); ++l) { - const auto& [face_number, face_local_edge, reversed] = faces_vector[l]; - descriptor.face_to_edge_vector[face_number][face_local_edge] = e; - } - edge_id_map[edge_faces_vector.first] = e; - ++e; + } + + const size_t total_number_of_edges = face_edge_is_reversed.size(); + Array<unsigned int> node_to_face_edge_row(node_number_vector.size() + 1); + node_to_face_edge_row.fill(0); + for (size_t i_edge = 0; i_edge < total_number_of_edges; ++i_edge) { + for (size_t i_edge_node = 0; i_edge_node < 2; ++i_edge_node) { + node_to_face_edge_row[face_edge_to_node_list[2 * i_edge + i_edge_node] + 1]++; } } + for (size_t i_node = 1; i_node < node_to_face_edge_row.size(); ++i_node) { + node_to_face_edge_row[i_node] += node_to_face_edge_row[i_node - 1]; + } + + Array<unsigned int> node_to_face_edge_list(node_to_face_edge_row[node_to_face_edge_row.size() - 1]); { - descriptor.face_edge_is_reversed_vector.resize(descriptor.face_to_node_vector.size()); - for (FaceId j = 0; j < descriptor.face_edge_is_reversed_vector.size(); ++j) { - descriptor.face_edge_is_reversed_vector[j] = Array<bool>(face_nb_edges[j]); + Array<unsigned int> node_to_face_edge_row_idx(node_number_vector.size()); + node_to_face_edge_row_idx.fill(0); + + for (size_t i_edge = 0; i_edge < total_number_of_edges; ++i_edge) { + for (size_t i_edge_node = 0; i_edge_node < 2; ++i_edge_node) { + const size_t node_id = face_edge_to_node_list[2 * i_edge + i_edge_node]; + + node_to_face_edge_list[node_to_face_edge_row[node_id] + node_to_face_edge_row_idx[node_id]] = i_edge; + node_to_face_edge_row_idx[node_id]++; + } } - for (const auto& edge_faces_vector : edge_faces_map) { - const auto& faces_vector = edge_faces_vector.second; - for (unsigned short lj = 0; lj < faces_vector.size(); ++lj) { - const auto& [face_number, face_local_edge, reversed] = faces_vector[lj]; - descriptor.face_edge_is_reversed_vector[face_number][face_local_edge] = reversed; + } + + Array<unsigned int> face_edge_to_edge(total_number_of_edges); + parallel_for( + total_number_of_edges, PUGS_LAMBDA(size_t i_edge) { face_edge_to_edge[i_edge] = i_edge; }); + + auto is_same_face = [=](const size_t i_edge, const size_t j_edge) { + auto i_edge_first_node = 2 * i_edge; + auto j_edge_first_node = 2 * j_edge; + return ((face_edge_to_node_list[i_edge_first_node] == face_edge_to_node_list[j_edge_first_node]) and + (face_edge_to_node_list[i_edge_first_node + 1] == face_edge_to_node_list[j_edge_first_node + 1])); + }; + + size_t nb_duplicate_edges = 0; + for (size_t i_node = 0; i_node < node_number_vector.size(); ++i_node) { + for (size_t i_node_face = node_to_face_edge_row[i_node]; i_node_face < node_to_face_edge_row[i_node + 1] - 1; + ++i_node_face) { + const unsigned int i_edge = node_to_face_edge_list[i_node_face]; + const unsigned int i_edge_id = face_edge_to_edge[i_edge]; + for (size_t j_node_face = i_node_face + 1; j_node_face < node_to_face_edge_row[i_node + 1]; ++j_node_face) { + const unsigned int j_edge = node_to_face_edge_list[j_node_face]; + unsigned int& j_edge_id = face_edge_to_edge[j_edge]; + if (i_edge_id != j_edge_id) { + if (is_same_face(i_edge, j_edge)) { + j_edge_id = i_edge_id; + nb_duplicate_edges++; + } + } } } } + // compute edge_id + Array<EdgeId> dup_edge_to_edge_id(total_number_of_edges); { - descriptor.edge_to_node_vector.resize(edge_faces_map.size()); - int e = 0; - for (const auto& edge_info : edge_faces_map) { - const Edge& edge = edge_info.first; - descriptor.edge_to_node_vector[e] = edge.nodeIdList(); - ++e; + EdgeId edge_id = 0; + for (size_t i_dup_edge = 0; i_dup_edge < total_number_of_edges; ++i_dup_edge) { + if (face_edge_to_edge[i_dup_edge] == i_dup_edge) { + dup_edge_to_edge_id[i_dup_edge] = edge_id++; + } else { + size_t i_edge = i_dup_edge; + do { + i_edge = face_edge_to_edge[i_edge]; + } while (i_edge != face_edge_to_edge[i_edge]); + + dup_edge_to_edge_id[i_dup_edge] = dup_edge_to_edge_id[i_edge]; + } } } + Array<unsigned int> edge_to_node_list(2 * (total_number_of_edges - nb_duplicate_edges)); { - // Edge numbers may change if numbers are provided in the file - descriptor.edge_number_vector.resize(edge_faces_map.size()); - for (size_t e = 0; e < edge_faces_map.size(); ++e) { - descriptor.edge_number_vector[e] = e; + for (size_t i_dup_edge = 0; i_dup_edge < total_number_of_edges; ++i_dup_edge) { + if (face_edge_to_edge[i_dup_edge] == i_dup_edge) { + const EdgeId edge_id = dup_edge_to_edge_id[i_dup_edge]; + edge_to_node_list[2 * edge_id] = face_edge_to_node_list[2 * i_dup_edge]; + edge_to_node_list[2 * edge_id + 1] = face_edge_to_node_list[2 * i_dup_edge + 1]; + } } } - { - descriptor.cell_to_edge_vector.reserve(descriptor.cell_to_node_vector.size()); - for (CellId j = 0; j < descriptor.cell_to_node_vector.size(); ++j) { - const auto& cell_nodes = descriptor.cell_to_node_vector[j]; + descriptor.setEdgeNumberVector([&] { + Array<int> edge_number_vector(total_number_of_edges - nb_duplicate_edges); + parallel_for( + edge_number_vector.size(), PUGS_LAMBDA(const size_t i_edge) { edge_number_vector[i_edge] = i_edge; }); + return edge_number_vector; + }()); - switch (descriptor.cell_type_vector[j]) { - case CellType::Tetrahedron: { - constexpr int local_edge[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {2, 3}, {3, 1}}; - std::vector<unsigned int> cell_edge_vector; - cell_edge_vector.reserve(6); - for (int i_edge = 0; i_edge < 6; ++i_edge) { - const auto e = local_edge[i_edge]; - Edge edge{{cell_nodes[e[0]], cell_nodes[e[1]]}, node_number_vector}; - auto i = edge_id_map.find(edge); - if (i == edge_id_map.end()) { - throw NormalError("could not find this edge"); + Array<unsigned int> edge_to_node_row(total_number_of_edges - nb_duplicate_edges + 1); + parallel_for( + edge_to_node_row.size(), PUGS_LAMBDA(const size_t i_edge) { edge_to_node_row[i_edge] = 2 * i_edge; }); + + descriptor.setEdgeToNodeMatrix(ConnectivityMatrix(edge_to_node_row, edge_to_node_list)); + + // Use real edge ids + for (size_t i_edge = 0; i_edge < face_edge_to_edge.size(); ++i_edge) { + face_edge_to_edge[i_edge] = dup_edge_to_edge_id[face_edge_to_edge[i_edge]]; + } + + descriptor.setFaceToEdgeMatrix(ConnectivityMatrix(face_to_edge_row, face_edge_to_edge)); + descriptor.setFaceEdgeIsReversed(face_edge_is_reversed); + + Array<size_t> node_to_duplicated_edge_id_list(node_to_face_edge_list.size()); + for (size_t i_node_edge = 0; i_node_edge < node_to_duplicated_edge_id_list.size(); ++i_node_edge) { + node_to_duplicated_edge_id_list[i_node_edge] = dup_edge_to_edge_id[node_to_face_edge_list[i_node_edge]]; + } + + Array<bool> node_to_edge_is_duplicated(node_to_face_edge_list.size()); + node_to_edge_is_duplicated.fill(false); + + Array<unsigned int> node_nb_edges(node_number_vector.size()); + node_nb_edges.fill(0); + + for (size_t node_id = 0; node_id < node_number_vector.size(); ++node_id) { + size_t nb_dup_edges = 0; + for (EdgeId i_edge = node_to_face_edge_row[node_id]; i_edge < node_to_face_edge_row[node_id + 1] - 1; ++i_edge) { + if (not node_to_edge_is_duplicated[i_edge]) { + for (EdgeId j_edge = i_edge + 1; j_edge < node_to_face_edge_row[node_id + 1]; ++j_edge) { + if (node_to_duplicated_edge_id_list[i_edge] == node_to_duplicated_edge_id_list[j_edge]) { + node_to_edge_is_duplicated[j_edge] = true; + nb_dup_edges++; } - cell_edge_vector.push_back(i->second); } - descriptor.cell_to_edge_vector.emplace_back(cell_edge_vector); - break; } - case CellType::Hexahedron: { - constexpr int local_edge[12][2] = {{0, 1}, {1, 2}, {2, 3}, {3, 0}, {4, 5}, {5, 6}, - {6, 7}, {7, 4}, {0, 4}, {1, 5}, {2, 6}, {3, 7}}; - std::vector<unsigned int> cell_edge_vector; - cell_edge_vector.reserve(12); - for (int i_edge = 0; i_edge < 12; ++i_edge) { - const auto e = local_edge[i_edge]; - Edge edge{{cell_nodes[e[0]], cell_nodes[e[1]]}, node_number_vector}; - auto i = edge_id_map.find(edge); - if (i == edge_id_map.end()) { - throw NormalError("could not find this edge"); - } - cell_edge_vector.push_back(i->second); - } - descriptor.cell_to_edge_vector.emplace_back(cell_edge_vector); - break; + } + node_nb_edges[node_id] = node_to_face_edge_row[node_id + 1] - node_to_face_edge_row[node_id] - nb_dup_edges; + } + + Array<unsigned int> node_to_edge_row(node_number_vector.size() + 1); + node_to_edge_row[0] = 0; + for (size_t node_id = 0; node_id < node_number_vector.size(); ++node_id) { + node_to_edge_row[node_id + 1] = node_to_edge_row[node_id] + node_nb_edges[node_id]; + } + + Array<unsigned int> node_to_edge_list(node_to_edge_row[node_to_edge_row.size() - 1]); + { + size_t l = 0; + for (size_t i_edge_id = 0; i_edge_id < node_to_duplicated_edge_id_list.size(); ++i_edge_id) { + if (not node_to_edge_is_duplicated[i_edge_id]) { + node_to_edge_list[l++] = node_to_duplicated_edge_id_list[i_edge_id]; } - case CellType::Prism: { - constexpr int local_edge[12][2] = {{0, 1}, {1, 2}, {2, 0}, {3, 4}, {4, 5}, {5, 3}, {0, 3}, {1, 4}, {2, 5}}; - std::vector<unsigned int> cell_edge_vector; - cell_edge_vector.reserve(9); - for (int i_edge = 0; i_edge < 9; ++i_edge) { - const auto e = local_edge[i_edge]; - Edge edge{{cell_nodes[e[0]], cell_nodes[e[1]]}, node_number_vector}; - auto i = edge_id_map.find(edge); - if (i == edge_id_map.end()) { - throw NormalError("could not find this edge"); - } - cell_edge_vector.push_back(i->second); + } + } + + descriptor.setNodeToEdgeMatrix(ConnectivityMatrix(node_to_edge_row, node_to_edge_list)); + + auto find_edge = [=](const NodeId& node0_id, const NodeId& node1_id) -> EdgeId { + auto [first_node_id, second_node_id] = [&] { + if (node_number_vector[node0_id] < node_number_vector[node1_id]) { + return std::make_pair(node0_id, node1_id); + } else { + return std::make_pair(node1_id, node0_id); + } + }(); + + for (size_t i_node_edge = node_to_edge_row[first_node_id]; i_node_edge < node_to_edge_row[first_node_id + 1]; + ++i_node_edge) { + EdgeId edge_id = node_to_edge_list[i_node_edge]; + if (edge_to_node_list[2 * edge_id + 1] == second_node_id) { + return edge_id; + } + } + throw UnexpectedError("Cannot find cell edge in edge list"); + }; + + const auto& cell_to_node_matrix = descriptor.cellToNodeMatrix(); + const auto& cell_type_vector = descriptor.cellTypeVector(); + { + Array<unsigned int> cell_to_edge_row(cell_to_node_matrix.numberOfRows() + 1); + { + cell_to_edge_row[0] = 0; + + for (CellId cell_id = 0; cell_id < cell_to_node_matrix.numberOfRows(); ++cell_id) { + switch (cell_type_vector[cell_id]) { + case CellType::Tetrahedron: { + cell_to_edge_row[cell_id + 1] = cell_to_edge_row[cell_id] + 6; + break; + } + case CellType::Hexahedron: { + cell_to_edge_row[cell_id + 1] = cell_to_edge_row[cell_id] + 12; + break; + } + case CellType::Prism: { + cell_to_edge_row[cell_id + 1] = cell_to_edge_row[cell_id] + 9; + break; + } + case CellType::Pyramid: { + cell_to_edge_row[cell_id + 1] = cell_to_edge_row[cell_id] + 2 * (cell_to_node_matrix[cell_id].size() - 1); + break; + } + case CellType::Diamond: { + cell_to_edge_row[cell_id + 1] = cell_to_edge_row[cell_id] + 3 * (cell_to_node_matrix[cell_id].size() - 2); + break; + } + default: { + std::stringstream error_msg; + error_msg << name(cell_type_vector[cell_id]) << ": unexpected cell type in dimension 3"; + throw NotImplementedError(error_msg.str()); + } } - descriptor.cell_to_edge_vector.emplace_back(cell_edge_vector); - break; } - case CellType::Pyramid: { - const size_t number_of_edges = 2 * cell_nodes.size(); - std::vector<unsigned int> base_nodes; - std::copy_n(cell_nodes.begin(), cell_nodes.size() - 1, std::back_inserter(base_nodes)); - - std::vector<unsigned int> cell_edge_vector; - cell_edge_vector.reserve(number_of_edges); - for (size_t i_edge = 0; i_edge < base_nodes.size(); ++i_edge) { - Edge edge{{base_nodes[i_edge], base_nodes[(i_edge + 1) % base_nodes.size()]}, node_number_vector}; - auto i = edge_id_map.find(edge); - if (i == edge_id_map.end()) { - throw NormalError("could not find this edge"); + } + + Array<unsigned int> cell_to_edge_list(cell_to_edge_row[cell_to_edge_row.size() - 1]); + { + size_t i_cell_edge = 0; + for (CellId cell_id = 0; cell_id < cell_to_node_matrix.numberOfRows(); ++cell_id) { + const auto& cell_nodes = cell_to_node_matrix[cell_id]; + + switch (cell_type_vector[cell_id]) { + case CellType::Tetrahedron: { + constexpr int local_edge[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {2, 3}, {3, 1}}; + for (int i_edge = 0; i_edge < 6; ++i_edge) { + const auto& e = local_edge[i_edge]; + cell_to_edge_list[i_cell_edge++] = find_edge(cell_nodes[e[0]], cell_nodes[e[1]]); } - cell_edge_vector.push_back(i->second); + break; } + case CellType::Hexahedron: { + constexpr int local_edge[12][2] = {{0, 1}, {1, 2}, {2, 3}, {3, 0}, {4, 5}, {5, 6}, + {6, 7}, {7, 4}, {0, 4}, {1, 5}, {2, 6}, {3, 7}}; - const unsigned int top_vertex = cell_nodes[cell_nodes.size() - 1]; - for (size_t i_edge = 0; i_edge < base_nodes.size(); ++i_edge) { - Edge edge{{base_nodes[i_edge], top_vertex}, node_number_vector}; - auto i = edge_id_map.find(edge); - if (i == edge_id_map.end()) { - throw NormalError("could not find this edge"); + for (int i_edge = 0; i_edge < 12; ++i_edge) { + const auto& e = local_edge[i_edge]; + cell_to_edge_list[i_cell_edge++] = find_edge(cell_nodes[e[0]], cell_nodes[e[1]]); } - cell_edge_vector.push_back(i->second); + break; } - descriptor.cell_to_edge_vector.emplace_back(cell_edge_vector); - break; - } - case CellType::Diamond: { - const size_t number_of_edges = 3 * cell_nodes.size(); - std::vector<unsigned int> base_nodes; - std::copy_n(cell_nodes.begin() + 1, cell_nodes.size() - 2, std::back_inserter(base_nodes)); - - std::vector<unsigned int> cell_edge_vector; - cell_edge_vector.reserve(number_of_edges); - for (size_t i_edge = 0; i_edge < base_nodes.size(); ++i_edge) { - Edge edge{{base_nodes[i_edge], base_nodes[(i_edge + 1) % base_nodes.size()]}, node_number_vector}; - auto i = edge_id_map.find(edge); - if (i == edge_id_map.end()) { - throw NormalError("could not find this edge"); + case CellType::Prism: { + constexpr int local_edge[9][2] = {{0, 1}, {1, 2}, {2, 0}, {3, 4}, {4, 5}, {5, 3}, {0, 3}, {1, 4}, {2, 5}}; + for (int i_edge = 0; i_edge < 9; ++i_edge) { + const auto& e = local_edge[i_edge]; + cell_to_edge_list[i_cell_edge++] = find_edge(cell_nodes[e[0]], cell_nodes[e[1]]); } - cell_edge_vector.push_back(i->second); + break; } + case CellType::Pyramid: { + auto base_nodes = [&](size_t i) { return cell_nodes[i]; }; - const unsigned int top_vertex = cell_nodes[cell_nodes.size() - 1]; - for (size_t i_edge = 0; i_edge < base_nodes.size(); ++i_edge) { - Edge edge{{base_nodes[i_edge], top_vertex}, node_number_vector}; - auto i = edge_id_map.find(edge); - if (i == edge_id_map.end()) { - throw NormalError("could not find this edge"); + for (size_t i_edge = 0; i_edge < cell_nodes.size() - 1; ++i_edge) { + cell_to_edge_list[i_cell_edge++] = + find_edge(base_nodes(i_edge), base_nodes((i_edge + 1) % (cell_nodes.size() - 1))); } - cell_edge_vector.push_back(i->second); - } - const unsigned int bottom_vertex = cell_nodes[0]; - for (size_t i_edge = 0; i_edge < base_nodes.size(); ++i_edge) { - Edge edge{{base_nodes[i_edge], bottom_vertex}, node_number_vector}; - auto i = edge_id_map.find(edge); - if (i == edge_id_map.end()) { - throw NormalError("could not find this edge"); + const unsigned int top_vertex = cell_nodes[cell_nodes.size() - 1]; + for (size_t i_edge = 0; i_edge < cell_nodes.size() - 1; ++i_edge) { + cell_to_edge_list[i_cell_edge++] = find_edge(base_nodes(i_edge), top_vertex); } - cell_edge_vector.push_back(i->second); + break; } + case CellType::Diamond: { + auto base_nodes = [&](size_t i) { return cell_nodes[i + 1]; }; - descriptor.cell_to_edge_vector.emplace_back(cell_edge_vector); + for (size_t i_edge = 0; i_edge < cell_nodes.size() - 2; ++i_edge) { + cell_to_edge_list[i_cell_edge++] = + find_edge(base_nodes(i_edge), base_nodes((i_edge + 1) % (cell_nodes.size() - 2))); + } - break; - } - default: { - std::stringstream error_msg; - error_msg << name(descriptor.cell_type_vector[j]) << ": unexpected cell type in dimension 3"; - throw NotImplementedError(error_msg.str()); - } + { + const unsigned int top_vertex = cell_nodes[cell_nodes.size() - 1]; + for (size_t i_edge = 0; i_edge < cell_nodes.size() - 2; ++i_edge) { + cell_to_edge_list[i_cell_edge++] = find_edge(base_nodes(i_edge), top_vertex); + } + } + + { + const unsigned int bottom_vertex = cell_nodes[0]; + for (size_t i_edge = 0; i_edge < cell_nodes.size() - 2; ++i_edge) { + cell_to_edge_list[i_cell_edge++] = find_edge(base_nodes(i_edge), bottom_vertex); + } + } + + break; + } + default: { + std::stringstream error_msg; + error_msg << name(cell_type_vector[cell_id]) << ": unexpected cell type in dimension 3"; + throw NotImplementedError(error_msg.str()); + } + } } } + + descriptor.setCellToEdgeMatrix(ConnectivityMatrix(cell_to_edge_row, cell_to_edge_list)); } } diff --git a/src/mesh/ConnectivityBuilderBase.hpp b/src/mesh/ConnectivityBuilderBase.hpp index f9b0d28a7a9389093348648573c85875f1e4a7de..a621e91f46ffe7e6ecb5ea6d496934a03571ba6e 100644 --- a/src/mesh/ConnectivityBuilderBase.hpp +++ b/src/mesh/ConnectivityBuilderBase.hpp @@ -15,9 +15,6 @@ class ConnectivityDescriptor; class ConnectivityBuilderBase { protected: - template <size_t Dimension> - class ConnectivityFace; - std::shared_ptr<const IConnectivity> m_connectivity; template <size_t Dimension> @@ -37,190 +34,4 @@ class ConnectivityBuilderBase ~ConnectivityBuilderBase() = default; }; -template <> -class ConnectivityBuilderBase::ConnectivityFace<2> -{ - public: - friend struct Hash; - - struct Hash - { - size_t - operator()(const ConnectivityFace& f) const - { - size_t hash = 0; - hash ^= std::hash<unsigned int>()(f.m_node0_id); - hash ^= std::hash<unsigned int>()(f.m_node1_id) >> 1; - return hash; - } - }; - - private: - const std::vector<int>& m_node_number_vector; - - unsigned int m_node0_id; - unsigned int m_node1_id; - - bool m_reversed; - - public: - std::vector<unsigned int> - nodeIdList() const - { - return {m_node0_id, m_node1_id}; - } - - bool - reversed() const - { - return m_reversed; - } - - PUGS_INLINE - bool - operator==(const ConnectivityFace& f) const - { - return ((m_node0_id == f.m_node0_id) and (m_node1_id == f.m_node1_id)); - } - - PUGS_INLINE - bool - operator<(const ConnectivityFace& f) const - { - return ((m_node_number_vector[m_node0_id] < m_node_number_vector[f.m_node0_id]) or - ((m_node_number_vector[m_node0_id] == m_node_number_vector[f.m_node0_id]) and - (m_node_number_vector[m_node1_id] < m_node_number_vector[f.m_node1_id]))); - } - - PUGS_INLINE - ConnectivityFace(const std::vector<unsigned int>& node_id_list, const std::vector<int>& node_number_vector) - : m_node_number_vector(node_number_vector) - { - Assert(node_id_list.size() == 2); - - if (m_node_number_vector[node_id_list[0]] < m_node_number_vector[node_id_list[1]]) { - m_node0_id = node_id_list[0]; - m_node1_id = node_id_list[1]; - m_reversed = false; - } else { - m_node0_id = node_id_list[1]; - m_node1_id = node_id_list[0]; - m_reversed = true; - } - } - - PUGS_INLINE - ConnectivityFace(const ConnectivityFace&) = default; - - PUGS_INLINE - ~ConnectivityFace() = default; -}; - -template <> -class ConnectivityBuilderBase::ConnectivityFace<3> -{ - public: - friend struct Hash; - - struct Hash - { - size_t - operator()(const ConnectivityFace& f) const - { - size_t hash = 0; - for (size_t i = 0; i < f.m_node_id_list.size(); ++i) { - hash ^= std::hash<unsigned int>()(f.m_node_id_list[i]) >> i; - } - return hash; - } - }; - - private: - bool m_reversed; - std::vector<NodeId::base_type> m_node_id_list; - const std::vector<int>& m_node_number_vector; - - PUGS_INLINE - std::vector<unsigned int> - _sort(const std::vector<unsigned int>& node_list) - { - const auto min_id = std::min_element(node_list.begin(), node_list.end()); - const int shift = std::distance(node_list.begin(), min_id); - - std::vector<unsigned int> rotated_node_list(node_list.size()); - if (node_list[(shift + 1) % node_list.size()] > node_list[(shift + node_list.size() - 1) % node_list.size()]) { - for (size_t i = 0; i < node_list.size(); ++i) { - rotated_node_list[i] = node_list[(shift + node_list.size() - i) % node_list.size()]; - m_reversed = true; - } - } else { - for (size_t i = 0; i < node_list.size(); ++i) { - rotated_node_list[i] = node_list[(shift + i) % node_list.size()]; - } - } - - return rotated_node_list; - } - - public: - PUGS_INLINE - const bool& - reversed() const - { - return m_reversed; - } - - PUGS_INLINE - const std::vector<unsigned int>& - nodeIdList() const - { - return m_node_id_list; - } - - PUGS_INLINE - ConnectivityFace(const std::vector<unsigned int>& given_node_id_list, const std::vector<int>& node_number_vector) - : m_reversed(false), m_node_id_list(_sort(given_node_id_list)), m_node_number_vector(node_number_vector) - { - ; - } - - public: - bool - operator==(const ConnectivityFace& f) const - { - if (m_node_id_list.size() == f.nodeIdList().size()) { - for (size_t j = 0; j < m_node_id_list.size(); ++j) { - if (m_node_id_list[j] != f.nodeIdList()[j]) { - return false; - } - } - return true; - } - return false; - } - - PUGS_INLINE - bool - operator<(const ConnectivityFace& f) const - { - const size_t min_nb_nodes = std::min(f.m_node_id_list.size(), m_node_id_list.size()); - for (size_t i = 0; i < min_nb_nodes; ++i) { - if (m_node_id_list[i] < f.m_node_id_list[i]) - return true; - if (m_node_id_list[i] != f.m_node_id_list[i]) - return false; - } - return m_node_id_list.size() < f.m_node_id_list.size(); - } - - PUGS_INLINE - ConnectivityFace(const ConnectivityFace&) = default; - - PUGS_INLINE - ConnectivityFace() = delete; - - PUGS_INLINE - ~ConnectivityFace() = default; -}; - #endif // CONNECTIVITY_BUILDER_BASE_HPP diff --git a/src/mesh/ConnectivityComputer.cpp b/src/mesh/ConnectivityComputer.cpp index aa8ca779cfb965ffb3e85e4feb1b4b9feabb79ca..1d5514627a5dac75d41ba5e4d08fa182d37e552f 100644 --- a/src/mesh/ConnectivityComputer.cpp +++ b/src/mesh/ConnectivityComputer.cpp @@ -7,62 +7,90 @@ template <typename ConnectivityType> PUGS_INLINE ConnectivityMatrix -ConnectivityComputer::computeConnectivityMatrix(const ConnectivityType& connectivity, - ItemType item_type, - ItemType child_item_type) const +ConnectivityComputer::computeInverseConnectivityMatrix(const ConnectivityType& connectivity, + ItemType item_type, + ItemType child_item_type) const { - ConnectivityMatrix item_to_child_item_matrix; - if (connectivity.isConnectivityMatrixBuilt(child_item_type, item_type)) { - const ConnectivityMatrix& child_to_item_matrix = connectivity.getMatrix(child_item_type, item_type); + if (item_type < child_item_type) { + ConnectivityMatrix item_to_child_item_matrix; + if (connectivity.isConnectivityMatrixBuilt(child_item_type, item_type)) { + const ConnectivityMatrix& child_to_item_matrix = connectivity.getMatrix(child_item_type, item_type); + + switch (child_item_type) { + case ItemType::cell: { + item_to_child_item_matrix = + this->_computeInverseConnectivity<ConnectivityType, ItemType::cell>(connectivity, child_to_item_matrix); + break; + } + case ItemType::face: { + item_to_child_item_matrix = + this->_computeInverseConnectivity<ConnectivityType, ItemType::face>(connectivity, child_to_item_matrix); + break; + } + case ItemType::edge: { + item_to_child_item_matrix = + this->_computeInverseConnectivity<ConnectivityType, ItemType::edge>(connectivity, child_to_item_matrix); + break; + } + // LCOV_EXCL_START + default: { + throw UnexpectedError("node cannot be child item when computing inverse connectivity"); + } + // LCOV_EXCL_STOP + } + } else { + std::stringstream error_msg; + error_msg << "unable to compute connectivity " << itemName(item_type) << " -> " << itemName(child_item_type); + throw UnexpectedError(error_msg.str()); + } - item_to_child_item_matrix = this->_computeInverse(child_to_item_matrix); + return item_to_child_item_matrix; } else { std::stringstream error_msg; - error_msg << "unable to compute connectivity " << itemName(item_type) << " -> " << itemName(child_item_type); + error_msg << "cannot deduce " << itemName(item_type) << " -> " << itemName(child_item_type) << " connectivity"; throw UnexpectedError(error_msg.str()); } - - return item_to_child_item_matrix; } -template ConnectivityMatrix ConnectivityComputer::computeConnectivityMatrix(const Connectivity1D&, - ItemType, - ItemType) const; +template ConnectivityMatrix ConnectivityComputer::computeInverseConnectivityMatrix(const Connectivity1D&, + ItemType, + ItemType) const; -template ConnectivityMatrix ConnectivityComputer::computeConnectivityMatrix(const Connectivity2D&, - ItemType, - ItemType) const; +template ConnectivityMatrix ConnectivityComputer::computeInverseConnectivityMatrix(const Connectivity2D&, + ItemType, + ItemType) const; -template ConnectivityMatrix ConnectivityComputer::computeConnectivityMatrix(const Connectivity3D&, - ItemType, - ItemType) const; +template ConnectivityMatrix ConnectivityComputer::computeInverseConnectivityMatrix(const Connectivity3D&, + ItemType, + ItemType) const; +template <typename ConnectivityType, ItemType child_item_type> ConnectivityMatrix -ConnectivityComputer::_computeInverse(const ConnectivityMatrix& item_to_child_matrix) const +ConnectivityComputer::_computeInverseConnectivity(const ConnectivityType& connectivity, + const ConnectivityMatrix& child_to_item_matrix) const { - const size_t& number_of_rows = item_to_child_matrix.numberOfRows(); + const size_t number_of_transposed_columns = child_to_item_matrix.numberOfRows(); - if ((item_to_child_matrix.values().size() > 0)) { - const size_t& number_of_columns = max(item_to_child_matrix.values()); + if ((child_to_item_matrix.values().size() > 0)) { + const size_t number_of_transposed_rows = max(child_to_item_matrix.values()) + 1; - Array<uint32_t> transposed_next_free_column_index(number_of_columns + 1); + Array<uint32_t> transposed_next_free_column_index(number_of_transposed_rows); transposed_next_free_column_index.fill(0); Array<uint32_t> transposed_rows_map(transposed_next_free_column_index.size() + 1); transposed_rows_map.fill(0); - for (size_t i = 0; i < number_of_rows; ++i) { - for (size_t j = item_to_child_matrix.rowsMap()[i]; j < item_to_child_matrix.rowsMap()[i + 1]; ++j) { - transposed_rows_map[item_to_child_matrix.values()[j] + 1]++; + for (size_t i = 0; i < number_of_transposed_columns; ++i) { + for (size_t j = child_to_item_matrix.rowsMap()[i]; j < child_to_item_matrix.rowsMap()[i + 1]; ++j) { + transposed_rows_map[child_to_item_matrix.values()[j] + 1]++; } } for (size_t i = 1; i < transposed_rows_map.size(); ++i) { transposed_rows_map[i] += transposed_rows_map[i - 1]; } Array<uint32_t> transposed_column_indices(transposed_rows_map[transposed_rows_map.size() - 1]); - - for (size_t i = 0; i < number_of_rows; ++i) { - for (size_t j = item_to_child_matrix.rowsMap()[i]; j < item_to_child_matrix.rowsMap()[i + 1]; ++j) { - size_t i_column_index = item_to_child_matrix.values()[j]; + for (size_t i = 0; i < number_of_transposed_columns; ++i) { + for (size_t j = child_to_item_matrix.rowsMap()[i]; j < child_to_item_matrix.rowsMap()[i + 1]; ++j) { + size_t i_column_index = child_to_item_matrix.values()[j]; uint32_t& shift = transposed_next_free_column_index[i_column_index]; transposed_column_indices[transposed_rows_map[i_column_index] + shift] = i; @@ -71,6 +99,18 @@ ConnectivityComputer::_computeInverse(const ConnectivityMatrix& item_to_child_ma } } + auto target_item_number = connectivity.template number<child_item_type>(); + // Finally one sorts target item_ids for parallel reproducibility + for (size_t i = 0; i < number_of_transposed_rows; ++i) { + auto row_begining = &(transposed_column_indices[transposed_rows_map[i]]); + auto row_size = (transposed_rows_map[i + 1] - transposed_rows_map[i]); + std::sort(row_begining, row_begining + row_size, + [&target_item_number](const ItemIdT<child_item_type> item0_id, + const ItemIdT<child_item_type> item1_id) { + return target_item_number[item0_id] < target_item_number[item1_id]; + }); + } + return ConnectivityMatrix{transposed_rows_map, transposed_column_indices}; } else { // empty connectivity diff --git a/src/mesh/ConnectivityComputer.hpp b/src/mesh/ConnectivityComputer.hpp index b033a25d5ccc04db84c194e79e492a081216a49e..7093aeef17707c37452b5e6874f6ed50a285dbb3 100644 --- a/src/mesh/ConnectivityComputer.hpp +++ b/src/mesh/ConnectivityComputer.hpp @@ -7,13 +7,15 @@ class ConnectivityComputer { private: - ConnectivityMatrix _computeInverse(const ConnectivityMatrix& item_to_child_matrix) const; + template <typename ConnectivityType, ItemType child_item_type> + ConnectivityMatrix _computeInverseConnectivity(const ConnectivityType& connectivity, + const ConnectivityMatrix& item_to_child_matrix) const; public: template <typename ConnectivityType> - ConnectivityMatrix computeConnectivityMatrix(const ConnectivityType& connectivity, - ItemType item_type, - ItemType child_item_type) const; + ConnectivityMatrix computeInverseConnectivityMatrix(const ConnectivityType& connectivity, + ItemType item_type, + ItemType child_item_type) const; template <typename ItemOfItem, typename ConnectivityType> void computeLocalItemNumberInChildItem(const ConnectivityType& connectivity) const; diff --git a/src/mesh/ConnectivityDescriptor.hpp b/src/mesh/ConnectivityDescriptor.hpp index 8f26988eadaa01dfec8aa0f14404a82819273475..dacf84d3cc84ab13629c09f163a16739db70dba3 100644 --- a/src/mesh/ConnectivityDescriptor.hpp +++ b/src/mesh/ConnectivityDescriptor.hpp @@ -2,6 +2,7 @@ #define CONNECTIVITY_DESCRIPTOR_HPP #include <mesh/CellType.hpp> +#include <mesh/ConnectivityMatrix.hpp> #include <mesh/ItemOfItemType.hpp> #include <mesh/RefItemList.hpp> #include <utils/PugsTraits.hpp> @@ -16,68 +17,337 @@ class ConnectivityDescriptor std::vector<RefEdgeList> m_ref_edge_list_vector; std::vector<RefNodeList> m_ref_node_list_vector; + ConnectivityMatrix m_cell_to_face_matrix = ConnectivityMatrix{true}; + ConnectivityMatrix m_cell_to_edge_matrix = ConnectivityMatrix{true}; + ConnectivityMatrix m_cell_to_node_matrix = ConnectivityMatrix{true}; + + ConnectivityMatrix m_face_to_edge_matrix = ConnectivityMatrix{true}; + ConnectivityMatrix m_face_to_node_matrix = ConnectivityMatrix{true}; + + ConnectivityMatrix m_edge_to_node_matrix = ConnectivityMatrix{true}; + + ConnectivityMatrix m_node_to_face_matrix = ConnectivityMatrix{true}; + ConnectivityMatrix m_node_to_edge_matrix = ConnectivityMatrix{true}; + + Array<const bool> m_cell_face_is_reversed; + Array<const bool> m_face_edge_is_reversed; + + Array<const CellType> m_cell_type_vector; + + Array<const int> m_cell_number_vector; + Array<const int> m_face_number_vector; + Array<const int> m_edge_number_vector; + Array<const int> m_node_number_vector; + + Array<const int> m_cell_owner_vector; + Array<const int> m_face_owner_vector; + Array<const int> m_edge_owner_vector; + Array<const int> m_node_owner_vector; + public: - std::vector<std::vector<unsigned int>> cell_to_node_vector; - std::vector<std::vector<unsigned int>> cell_to_face_vector; - std::vector<std::vector<unsigned int>> cell_to_edge_vector; + void + setCellNumberVector(const Array<const int>& cell_number_vector) + { + // No check since it can change reading file for instance + m_cell_number_vector = cell_number_vector; + } - std::vector<std::vector<unsigned int>> face_to_node_vector; - std::vector<std::vector<unsigned int>> face_to_edge_vector; + PUGS_INLINE + const Array<const int>& + cellNumberVector() const + { + return m_cell_number_vector; + } - std::vector<std::vector<unsigned int>> edge_to_node_vector; + void + setFaceNumberVector(const Array<const int>& face_number_vector) + { + // No check since it can change reading file for instance + m_face_number_vector = face_number_vector; + } - template <typename ItemOfItemT> - auto& - itemOfItemVector() + PUGS_INLINE + const Array<const int>& + faceNumberVector() const { - if constexpr (std::is_same_v<ItemOfItemT, NodeOfCell>) { - return cell_to_node_vector; - } else if constexpr (std::is_same_v<ItemOfItemT, FaceOfCell>) { - return cell_to_face_vector; - } else if constexpr (std::is_same_v<ItemOfItemT, EdgeOfCell>) { - return cell_to_edge_vector; - } else if constexpr (std::is_same_v<ItemOfItemT, EdgeOfFace>) { - return face_to_edge_vector; - } else if constexpr (std::is_same_v<ItemOfItemT, NodeOfFace>) { - return face_to_node_vector; - } else if constexpr (std::is_same_v<ItemOfItemT, NodeOfEdge>) { - return edge_to_node_vector; - } else { - static_assert(is_false_v<ItemOfItemT>, "Unexpected item of item type"); - } + return m_face_number_vector; + } + + void + setEdgeNumberVector(const Array<const int>& edge_number_vector) + { + // No check since it can change reading file for instance + m_edge_number_vector = edge_number_vector; } - std::vector<Array<bool>> cell_face_is_reversed_vector; - std::vector<Array<bool>> face_edge_is_reversed_vector; + PUGS_INLINE + const Array<const int>& + edgeNumberVector() const + { + return m_edge_number_vector; + } - std::vector<CellType> cell_type_vector; + void + setNodeNumberVector(const Array<const int>& node_number_vector) + { + // No check since it can change reading file for instance + m_node_number_vector = node_number_vector; + } - std::vector<int> cell_number_vector; - std::vector<int> face_number_vector; - std::vector<int> edge_number_vector; - std::vector<int> node_number_vector; + PUGS_INLINE + const Array<const int>& + nodeNumberVector() const + { + return m_node_number_vector; + } template <ItemType item_type> - const std::vector<int>& + Array<const int> itemNumberVector() const { if constexpr (item_type == ItemType::cell) { - return cell_number_vector; + return m_cell_number_vector; } else if constexpr (item_type == ItemType::face) { - return face_number_vector; + return m_face_number_vector; } else if constexpr (item_type == ItemType::edge) { - return edge_number_vector; + return m_edge_number_vector; } else if constexpr (item_type == ItemType::node) { - return node_number_vector; + return m_node_number_vector; } else { static_assert(is_false_item_type_v<item_type>, "Unexpected item type"); } } - std::vector<int> cell_owner_vector; - std::vector<int> face_owner_vector; - std::vector<int> edge_owner_vector; - std::vector<int> node_owner_vector; + void + setCellOwnerVector(const Array<const int>& cell_owner_vector) + { + Assert(m_cell_owner_vector.size() == 0); + m_cell_owner_vector = cell_owner_vector; + } + + PUGS_INLINE + const Array<const int>& + cellOwnerVector() const + { + return m_cell_owner_vector; + } + + void + setFaceOwnerVector(const Array<const int>& face_owner_vector) + { + Assert(m_face_owner_vector.size() == 0); + m_face_owner_vector = face_owner_vector; + } + + PUGS_INLINE + const Array<const int>& + faceOwnerVector() const + { + return m_face_owner_vector; + } + + void + setEdgeOwnerVector(const Array<const int>& edge_owner_vector) + { + Assert(m_edge_owner_vector.size() == 0); + m_edge_owner_vector = edge_owner_vector; + } + + PUGS_INLINE + const Array<const int>& + edgeOwnerVector() const + { + return m_edge_owner_vector; + } + + void + setNodeOwnerVector(const Array<const int>& node_owner_vector) + { + Assert(m_node_owner_vector.size() == 0); + m_node_owner_vector = node_owner_vector; + } + + PUGS_INLINE + const Array<const int>& + nodeOwnerVector() const + { + return m_node_owner_vector; + } + + void + setCellFaceIsReversed(const Array<const bool>& cell_face_is_reversed) + { + Assert(m_cell_face_is_reversed.size() == 0); + m_cell_face_is_reversed = cell_face_is_reversed; + } + + PUGS_INLINE + const Array<const bool>& + cellFaceIsReversed() const + { + return m_cell_face_is_reversed; + } + + void + setFaceEdgeIsReversed(const Array<const bool>& face_edge_is_reversed) + { + Assert(m_face_edge_is_reversed.size() == 0); + m_face_edge_is_reversed = face_edge_is_reversed; + } + + PUGS_INLINE + const Array<const bool>& + faceEdgeIsReversed() const + { + return m_face_edge_is_reversed; + } + + void + setCellTypeVector(const Array<const CellType>& cell_type_vector) + { + Assert(m_face_edge_is_reversed.size() == 0); + m_cell_type_vector = cell_type_vector; + } + + PUGS_INLINE + const Array<const CellType>& + cellTypeVector() const + { + return m_cell_type_vector; + } + + void + setCellToFaceMatrix(const ConnectivityMatrix& cell_to_face_matrix) + { + Assert(m_cell_to_face_matrix.numberOfRows() == 0); + m_cell_to_face_matrix = cell_to_face_matrix; + } + + void + setCellToEdgeMatrix(const ConnectivityMatrix& cell_to_edge_matrix) + { + Assert(m_cell_to_edge_matrix.numberOfRows() == 0); + m_cell_to_edge_matrix = cell_to_edge_matrix; + } + + void + setCellToNodeMatrix(const ConnectivityMatrix& cell_to_node_matrix) + { + Assert(m_cell_to_node_matrix.numberOfRows() == 0); + m_cell_to_node_matrix = cell_to_node_matrix; + } + + void + setFaceToEdgeMatrix(const ConnectivityMatrix& face_to_edge_matrix) + { + Assert(m_face_to_edge_matrix.numberOfRows() == 0); + m_face_to_edge_matrix = face_to_edge_matrix; + } + + void + setFaceToNodeMatrix(const ConnectivityMatrix& face_to_node_matrix) + { + Assert(m_face_to_node_matrix.numberOfRows() == 0); + m_face_to_node_matrix = face_to_node_matrix; + } + + void + setEdgeToNodeMatrix(const ConnectivityMatrix& edge_to_node_matrix) + { + Assert(m_edge_to_node_matrix.numberOfRows() == 0); + m_edge_to_node_matrix = edge_to_node_matrix; + } + + void + setNodeToFaceMatrix(const ConnectivityMatrix& node_to_face_matrix) + { + Assert(m_node_to_face_matrix.numberOfRows() == 0); + m_node_to_face_matrix = node_to_face_matrix; + } + + void + setNodeToEdgeMatrix(const ConnectivityMatrix& node_to_edge_matrix) + { + Assert(m_node_to_edge_matrix.numberOfRows() == 0); + m_node_to_edge_matrix = node_to_edge_matrix; + } + + PUGS_INLINE + const ConnectivityMatrix& + cellToFaceMatrix() const + { + return m_cell_to_face_matrix; + } + + PUGS_INLINE + const ConnectivityMatrix& + cellToEdgeMatrix() const + { + return m_cell_to_edge_matrix; + } + + PUGS_INLINE + const ConnectivityMatrix& + cellToNodeMatrix() const + { + return m_cell_to_node_matrix; + } + + PUGS_INLINE + const ConnectivityMatrix& + faceToEdgeMatrix() const + { + return m_face_to_edge_matrix; + } + + PUGS_INLINE + const ConnectivityMatrix& + faceToNodeMatrix() const + { + return m_face_to_node_matrix; + } + + PUGS_INLINE + const ConnectivityMatrix& + edgeToNodeMatrix() const + { + return m_edge_to_node_matrix; + } + + PUGS_INLINE + const ConnectivityMatrix& + nodeToFaceMatrix() const + { + return m_node_to_face_matrix; + } + + PUGS_INLINE + const ConnectivityMatrix& + nodeToEdgeMatrix() const + { + return m_node_to_edge_matrix; + } + + template <typename ItemOfItemT> + auto& + itemOfItemVector() + { + if constexpr (std::is_same_v<ItemOfItemT, NodeOfCell>) { + return m_cell_to_node_matrix; + } else if constexpr (std::is_same_v<ItemOfItemT, FaceOfCell>) { + return m_cell_to_face_matrix; + } else if constexpr (std::is_same_v<ItemOfItemT, EdgeOfCell>) { + return m_cell_to_edge_matrix; + } else if constexpr (std::is_same_v<ItemOfItemT, EdgeOfFace>) { + return m_face_to_edge_matrix; + } else if constexpr (std::is_same_v<ItemOfItemT, NodeOfFace>) { + return m_face_to_node_matrix; + } else if constexpr (std::is_same_v<ItemOfItemT, NodeOfEdge>) { + return m_edge_to_node_matrix; + } else { + static_assert(is_false_v<ItemOfItemT>, "Unexpected item of item type"); + } + } template <ItemType item_type> const std::vector<RefItemList<item_type>>& @@ -114,7 +384,7 @@ class ConnectivityDescriptor } ConnectivityDescriptor& operator=(const ConnectivityDescriptor&) = delete; - ConnectivityDescriptor& operator=(ConnectivityDescriptor&&) = delete; + ConnectivityDescriptor& operator=(ConnectivityDescriptor&&) = delete; ConnectivityDescriptor() = default; ConnectivityDescriptor(const ConnectivityDescriptor&) = default; diff --git a/src/mesh/ConnectivityDispatcher.cpp b/src/mesh/ConnectivityDispatcher.cpp index fd5b58c6daaf5fd44c0cb440e7af472b9f9aebbf..641d7f8666946a448d98e0a3311d5bd2a94329fc 100644 --- a/src/mesh/ConnectivityDispatcher.cpp +++ b/src/mesh/ConnectivityDispatcher.cpp @@ -145,19 +145,19 @@ template <int Dimension> template <typename DataType, ItemType item_type, typename ConnectivityPtr> void ConnectivityDispatcher<Dimension>::_gatherFrom(const ItemValue<DataType, item_type, ConnectivityPtr>& data_to_gather, - std::vector<std::remove_const_t<DataType>>& gathered_vector) + Array<std::remove_const_t<DataType>>& gathered_array) { std::vector<Array<const DataType>> recv_item_data_by_proc = this->exchange(data_to_gather); const auto& recv_id_correspondance_by_proc = this->_dispatchedInfo<item_type>().m_recv_id_correspondance_by_proc; Assert(recv_id_correspondance_by_proc.size() == parallel::size()); - gathered_vector.resize(this->_dispatchedInfo<item_type>().m_number_to_id_map.size()); + gathered_array = Array<std::remove_const_t<DataType>>(this->_dispatchedInfo<item_type>().m_number_to_id_map.size()); for (size_t i_rank = 0; i_rank < parallel::size(); ++i_rank) { Assert(recv_id_correspondance_by_proc[i_rank].size() == recv_item_data_by_proc[i_rank].size()); for (size_t r = 0; r < recv_id_correspondance_by_proc[i_rank].size(); ++r) { - const auto& item_id = recv_id_correspondance_by_proc[i_rank][r]; - gathered_vector[item_id] = recv_item_data_by_proc[i_rank][r]; + const auto& item_id = recv_id_correspondance_by_proc[i_rank][r]; + gathered_array[item_id] = recv_item_data_by_proc[i_rank][r]; } } } @@ -167,7 +167,7 @@ template <typename DataType, typename ItemOfItem, typename ConnectivityPtr> void ConnectivityDispatcher<Dimension>::_gatherFrom( const SubItemValuePerItem<DataType, ItemOfItem, ConnectivityPtr>& data_to_gather, - std::vector<Array<std::remove_const_t<DataType>>>& gathered_vector) + Array<std::remove_const_t<DataType>>& gathered_array) { using MutableDataType = std::remove_const_t<DataType>; @@ -201,17 +201,23 @@ ConnectivityDispatcher<Dimension>::_gatherFrom( parallel::exchange(data_to_send_by_proc, recv_data_to_gather_by_proc); - const auto& item_list_to_recv_size_by_proc = this->_dispatchedInfo<item_type>().m_list_to_recv_size_by_proc; + const size_t recv_array_size = [&] { + size_t size = 0; + for (size_t i_rank = 0; i_rank < parallel::size(); ++i_rank) { + size += recv_data_to_gather_by_proc[i_rank].size(); + } + return size; + }(); - for (size_t i_rank = 0; i_rank < parallel::size(); ++i_rank) { - int l = 0; - for (size_t i = 0; i < item_list_to_recv_size_by_proc[i_rank]; ++i) { - Array<MutableDataType> data_vector(number_of_sub_item_per_item_to_recv_by_proc[i_rank][i]); - for (size_t k = 0; k < data_vector.size(); ++k) { - data_vector[k] = recv_data_to_gather_by_proc[i_rank][l++]; + gathered_array = Array<std::remove_const_t<DataType>>(recv_array_size); + { + size_t l = 0; + for (size_t i_rank = 0; i_rank < parallel::size(); ++i_rank) { + for (size_t j = 0; j < recv_data_to_gather_by_proc[i_rank].size(); ++j) { + gathered_array[l++] = recv_data_to_gather_by_proc[i_rank][j]; } - gathered_vector.emplace_back(data_vector); } + Assert(gathered_array.size() == l); } } @@ -342,6 +348,8 @@ ConnectivityDispatcher<Dimension>::_buildItemToSubItemDescriptor() const auto& recv_item_of_item_numbers_by_proc = this->_dispatchedInfo<ItemOfItemT>().m_sub_item_numbers_to_recv_by_proc; + std::vector<std::vector<unsigned int>> item_to_subitem_legacy; + size_t number_of_node_by_cell = 0; for (size_t i_rank = 0; i_rank < parallel::size(); ++i_rank) { int l = 0; for (size_t i = 0; i < item_list_to_recv_size_by_proc[i_rank]; ++i) { @@ -351,9 +359,30 @@ ConnectivityDispatcher<Dimension>::_buildItemToSubItemDescriptor() Assert(searched_sub_item_id != sub_item_number_id_map.end()); sub_item_vector.push_back(searched_sub_item_id->second); } - m_new_descriptor.itemOfItemVector<ItemOfItemT>().emplace_back(sub_item_vector); + number_of_node_by_cell += sub_item_vector.size(); + + item_to_subitem_legacy.emplace_back(sub_item_vector); + } + } + Array<unsigned int> item_to_subitem_row_map(item_to_subitem_legacy.size() + 1); + Array<unsigned int> item_to_subitem_list(number_of_node_by_cell); + + item_to_subitem_row_map.fill(10000000); + item_to_subitem_list.fill(10000000); + + item_to_subitem_row_map[0] = 0; + for (size_t i = 0; i < item_to_subitem_legacy.size(); ++i) { + item_to_subitem_row_map[i + 1] = item_to_subitem_row_map[i] + item_to_subitem_legacy[i].size(); + } + size_t l = 0; + for (size_t i = 0; i < item_to_subitem_legacy.size(); ++i) { + const auto& subitem_list = item_to_subitem_legacy[i]; + for (size_t j = 0; j < subitem_list.size(); ++j, ++l) { + item_to_subitem_list[l] = subitem_list[j]; } } + + m_new_descriptor.itemOfItemVector<ItemOfItemT>() = ConnectivityMatrix(item_to_subitem_row_map, item_to_subitem_list); } template <int Dimension> @@ -582,7 +611,11 @@ ConnectivityDispatcher<Dimension>::_dispatchEdges() this->_buildSubItemNumberToIdMap<EdgeOfCell>(); this->_buildItemToExchangeLists<ItemType::edge>(); - this->_gatherFrom(m_connectivity.template number<ItemType::edge>(), m_new_descriptor.edge_number_vector); + m_new_descriptor.setEdgeNumberVector([&] { + Array<int> edge_number_vector; + this->_gatherFrom(m_connectivity.template number<ItemType::edge>(), edge_number_vector); + return edge_number_vector; + }()); this->_buildItemToSubItemDescriptor<EdgeOfCell>(); @@ -594,9 +627,17 @@ ConnectivityDispatcher<Dimension>::_dispatchEdges() this->_buildSubItemNumbersToRecvByProc<EdgeOfFace>(); this->_buildItemToSubItemDescriptor<EdgeOfFace>(); - this->_gatherFrom(m_connectivity.faceEdgeIsReversed(), m_new_descriptor.face_edge_is_reversed_vector); + m_new_descriptor.setFaceEdgeIsReversed([&] { + Array<bool> face_edge_is_reversed; + this->_gatherFrom(m_connectivity.faceEdgeIsReversed(), face_edge_is_reversed); + return face_edge_is_reversed; + }()); - this->_gatherFrom(this->_dispatchedInfo<ItemType::edge>().m_new_owner, m_new_descriptor.edge_owner_vector); + m_new_descriptor.setEdgeOwnerVector([&] { + Array<int> edge_owner_vector; + this->_gatherFrom(this->_dispatchedInfo<ItemType::edge>().m_new_owner, edge_owner_vector); + return edge_owner_vector; + }()); this->_buildItemReferenceList<ItemType::edge>(); } @@ -616,13 +657,25 @@ ConnectivityDispatcher<Dimension>::_dispatchFaces() this->_buildSubItemNumbersToRecvByProc<NodeOfFace>(); this->_buildItemToSubItemDescriptor<NodeOfFace>(); - this->_gatherFrom(m_connectivity.template number<ItemType::face>(), m_new_descriptor.face_number_vector); + m_new_descriptor.setFaceNumberVector([&] { + Array<int> face_number_vector; + this->_gatherFrom(m_connectivity.template number<ItemType::face>(), face_number_vector); + return face_number_vector; + }()); this->_buildItemToSubItemDescriptor<FaceOfCell>(); - this->_gatherFrom(m_connectivity.cellFaceIsReversed(), m_new_descriptor.cell_face_is_reversed_vector); + m_new_descriptor.setCellFaceIsReversed([&] { + Array<bool> cell_face_is_reversed; + this->_gatherFrom(m_connectivity.cellFaceIsReversed(), cell_face_is_reversed); + return cell_face_is_reversed; + }()); - this->_gatherFrom(this->_dispatchedInfo<ItemType::face>().m_new_owner, m_new_descriptor.face_owner_vector); + m_new_descriptor.setFaceOwnerVector([&] { + Array<int> face_owner_vector; + this->_gatherFrom(this->_dispatchedInfo<ItemType::face>().m_new_owner, face_owner_vector); + return face_owner_vector; + }()); this->_buildItemReferenceList<ItemType::face>(); } @@ -647,18 +700,39 @@ ConnectivityDispatcher<Dimension>::ConnectivityDispatcher(const ConnectivityType this->_buildSubItemNumbersToRecvByProc<NodeOfCell>(); - this->_gatherFrom(m_connectivity.template number<ItemType::cell>(), m_new_descriptor.cell_number_vector); + m_new_descriptor.setCellNumberVector([&] { + Array<int> cell_number_vector; + this->_gatherFrom(m_connectivity.template number<ItemType::cell>(), cell_number_vector); + return cell_number_vector; + }()); this->_buildSubItemNumberToIdMap<NodeOfCell>(); this->_buildItemToExchangeLists<ItemType::node>(); - // Fill new descriptor - this->_gatherFrom(m_connectivity.cellType(), m_new_descriptor.cell_type_vector); - this->_gatherFrom(this->_dispatchedInfo<ItemType::cell>().m_new_owner, m_new_descriptor.cell_owner_vector); - - this->_gatherFrom(m_connectivity.template number<ItemType::node>(), m_new_descriptor.node_number_vector); - this->_gatherFrom(this->_dispatchedInfo<ItemType::node>().m_new_owner, m_new_descriptor.node_owner_vector); + m_new_descriptor.setCellTypeVector([&] { + Array<CellType> cell_type_vector; + this->_gatherFrom(m_connectivity.cellType(), cell_type_vector); + return cell_type_vector; + }()); + + m_new_descriptor.setCellOwnerVector([&] { + Array<int> cell_owner_vector; + this->_gatherFrom(this->_dispatchedInfo<ItemType::cell>().m_new_owner, cell_owner_vector); + return cell_owner_vector; + }()); + + m_new_descriptor.setNodeNumberVector([&] { + Array<int> node_number_vector; + this->_gatherFrom(m_connectivity.template number<ItemType::node>(), node_number_vector); + return node_number_vector; + }()); + + m_new_descriptor.setNodeOwnerVector([&] { + Array<int> node_owner_vector; + this->_gatherFrom(this->_dispatchedInfo<ItemType::node>().m_new_owner, node_owner_vector); + return node_owner_vector; + }()); this->_buildItemToSubItemDescriptor<NodeOfCell>(); diff --git a/src/mesh/ConnectivityDispatcher.hpp b/src/mesh/ConnectivityDispatcher.hpp index 73ebc548d98a01e4999611927272206df4af1c23..9ff5913b60799148f99bb6fdf4cff2cedd56973c 100644 --- a/src/mesh/ConnectivityDispatcher.hpp +++ b/src/mesh/ConnectivityDispatcher.hpp @@ -180,11 +180,11 @@ class ConnectivityDispatcher template <typename DataType, ItemType item_type, typename ConnectivityPtr> void _gatherFrom(const ItemValue<DataType, item_type, ConnectivityPtr>& data_to_gather, - std::vector<std::remove_const_t<DataType>>& gathered_vector); + Array<std::remove_const_t<DataType>>& gathered_array); template <typename DataType, typename ItemOfItem, typename ConnectivityPtr> void _gatherFrom(const SubItemValuePerItem<DataType, ItemOfItem, ConnectivityPtr>& data_to_gather, - std::vector<Array<std::remove_const_t<DataType>>>& gathered_vector); + Array<std::remove_const_t<DataType>>& gathered_array); template <typename SubItemOfItemT> void _buildNumberOfSubItemPerItemToRecvByProc(); diff --git a/src/mesh/ConnectivityMatrix.hpp b/src/mesh/ConnectivityMatrix.hpp index 6b777288cd6b8e3793a9addff6629c661d45d82d..eadc85347cb756932616e655d7b625a2a15505b7 100644 --- a/src/mesh/ConnectivityMatrix.hpp +++ b/src/mesh/ConnectivityMatrix.hpp @@ -70,34 +70,22 @@ class ConnectivityMatrix #endif // NDEBUG } - PUGS_INLINE - ConnectivityMatrix(const std::vector<std::vector<unsigned int>>& initializer) noexcept : m_is_built{true} - { - m_row_map = [&] { - Array<uint32_t> row_map(initializer.size() + 1); - row_map[0] = 0; - for (size_t i = 0; i < initializer.size(); ++i) { - row_map[i + 1] = row_map[i] + initializer[i].size(); - } - return row_map; - }(); - - m_column_indices = [&] { - Array<uint32_t> column_indices(m_row_map[m_row_map.size() - 1]); - size_t index = 0; - for (const auto& row : initializer) { - for (const auto& col_index : row) { - column_indices[index++] = col_index; - } - } - return column_indices; - }(); - } - ConnectivityMatrix& operator=(const ConnectivityMatrix&) = default; - ConnectivityMatrix& operator=(ConnectivityMatrix&&) = default; + ConnectivityMatrix& operator=(ConnectivityMatrix&&) = default; - ConnectivityMatrix() = default; + ConnectivityMatrix(bool is_built = false) : m_is_built{is_built} + { + // this is useful to build + if (is_built) { + m_row_map = [&] { + Array<uint32_t> row_map(1); + row_map[0] = 0; + return row_map; + }(); + + m_column_indices = Array<uint32_t>(0); + } + } ConnectivityMatrix(const ConnectivityMatrix&) = default; ConnectivityMatrix(ConnectivityMatrix&&) = default; ~ConnectivityMatrix() = default; diff --git a/src/mesh/ConnectivityUtils.cpp b/src/mesh/ConnectivityUtils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..af0220ac448b76fb2e0101c278719cc07da989bc --- /dev/null +++ b/src/mesh/ConnectivityUtils.cpp @@ -0,0 +1,88 @@ +#include <mesh/ConnectivityUtils.hpp> + +#include <mesh/Connectivity.hpp> +#include <utils/Messenger.hpp> + +template <size_t Dimension, ItemType SourceItemType, ItemType TargetItemType> +bool +checkItemToHigherDimensionItem(const Connectivity<Dimension>& connectivity) +{ + static_assert(SourceItemType < TargetItemType); + bool is_valid = true; + + const auto& item_to_item_matrix = connectivity.template getItemToItemMatrix<SourceItemType, TargetItemType>(); + const auto& item_number = connectivity.template number<TargetItemType>(); + + for (ItemIdT<SourceItemType> source_item_id = 0; source_item_id < connectivity.template numberOf<SourceItemType>(); + ++source_item_id) { + auto target_item_list = item_to_item_matrix[source_item_id]; + for (size_t i = 0; i < target_item_list.size() - 1; ++i) { + is_valid &= (item_number[target_item_list[i + 1]] > item_number[target_item_list[i]]); + } + } + + return is_valid; +} + +template <size_t Dimension> +bool checkConnectivityOrdering(const Connectivity<Dimension>&); + +template <> +bool +checkConnectivityOrdering(const Connectivity<1>& connectivity) +{ + bool is_valid = true; + is_valid &= checkItemToHigherDimensionItem<1, ItemType::node, ItemType::cell>(connectivity); + + return is_valid; +} +template <> + +bool +checkConnectivityOrdering(const Connectivity<2>& connectivity) +{ + bool is_valid = true; + is_valid &= checkItemToHigherDimensionItem<2, ItemType::node, ItemType::face>(connectivity); + is_valid &= checkItemToHigherDimensionItem<2, ItemType::node, ItemType::cell>(connectivity); + + is_valid &= checkItemToHigherDimensionItem<2, ItemType::face, ItemType::cell>(connectivity); + + return is_valid; +} + +bool +checkConnectivityOrdering(const Connectivity<3>& connectivity) +{ + bool is_valid = true; + is_valid &= checkItemToHigherDimensionItem<3, ItemType::node, ItemType::edge>(connectivity); + is_valid &= checkItemToHigherDimensionItem<3, ItemType::node, ItemType::face>(connectivity); + is_valid &= checkItemToHigherDimensionItem<3, ItemType::node, ItemType::cell>(connectivity); + + is_valid &= checkItemToHigherDimensionItem<3, ItemType::edge, ItemType::face>(connectivity); + is_valid &= checkItemToHigherDimensionItem<3, ItemType::edge, ItemType::cell>(connectivity); + + is_valid &= checkItemToHigherDimensionItem<3, ItemType::face, ItemType::cell>(connectivity); + + return parallel::allReduceAnd(is_valid); +} + +bool +checkConnectivityOrdering(const IConnectivity& connecticity) +{ + switch (connecticity.dimension()) { + case 1: { + return checkConnectivityOrdering(dynamic_cast<const Connectivity<1>&>(connecticity)); + } + case 2: { + return checkConnectivityOrdering(dynamic_cast<const Connectivity<2>&>(connecticity)); + } + case 3: { + return checkConnectivityOrdering(dynamic_cast<const Connectivity<3>&>(connecticity)); + } + // LCOV_EXCL_START + default: { + throw UnexpectedError("invalid dimension"); + } + // LCOV_EXCL_STOP + } +} diff --git a/src/mesh/ConnectivityUtils.hpp b/src/mesh/ConnectivityUtils.hpp new file mode 100644 index 0000000000000000000000000000000000000000..fa359a7e1c532e3b83c91d3e42d1bd8e3d7a45d8 --- /dev/null +++ b/src/mesh/ConnectivityUtils.hpp @@ -0,0 +1,8 @@ +#ifndef CONNECTIVITY_UTILS_HPP +#define CONNECTIVITY_UTILS_HPP + +#include "mesh/IConnectivity.hpp" + +bool checkConnectivityOrdering(const IConnectivity&); + +#endif // CONNECTIVITY_UTILS_HPP diff --git a/src/mesh/DiamondDualConnectivityBuilder.cpp b/src/mesh/DiamondDualConnectivityBuilder.cpp index 71e316461d94a0891b721a0fff85e85c145ef26f..c6a8fd78a9774dc63cbc5e5398ce721c5cfb9acb 100644 --- a/src/mesh/DiamondDualConnectivityBuilder.cpp +++ b/src/mesh/DiamondDualConnectivityBuilder.cpp @@ -11,6 +11,7 @@ #include <utils/Messenger.hpp> #include <utils/Stringify.hpp> +#include <optional> #include <vector> template <size_t Dimension> @@ -44,21 +45,21 @@ DiamondDualConnectivityBuilder::_buildDiamondConnectivityDescriptor(const Connec } } - diamond_descriptor.node_number_vector.resize(diamond_number_of_nodes); + Array<int> node_number_vector(diamond_number_of_nodes); parallel_for(m_primal_node_to_dual_node_map.size(), [&](size_t i) { const auto [primal_node_id, diamond_dual_node_id] = m_primal_node_to_dual_node_map[i]; - diamond_descriptor.node_number_vector[diamond_dual_node_id] = primal_node_number[primal_node_id]; + node_number_vector[diamond_dual_node_id] = primal_node_number[primal_node_id]; }); const size_t cell_number_shift = max(primal_node_number) + 1; parallel_for(primal_number_of_cells, [&](size_t i) { const auto [primal_cell_id, diamond_dual_node_id] = m_primal_cell_to_dual_node_map[i]; - diamond_descriptor.node_number_vector[diamond_dual_node_id] = - primal_cell_number[primal_cell_id] + cell_number_shift; + node_number_vector[diamond_dual_node_id] = primal_cell_number[primal_cell_id] + cell_number_shift; }); + diamond_descriptor.setNodeNumberVector(node_number_vector); { m_primal_face_to_dual_cell_map = FaceIdToCellIdMap{primal_number_of_faces}; @@ -68,14 +69,17 @@ DiamondDualConnectivityBuilder::_buildDiamondConnectivityDescriptor(const Connec } } - diamond_descriptor.cell_number_vector.resize(diamond_number_of_cells); - const auto& primal_face_number = primal_connectivity.faceNumber(); - parallel_for(diamond_number_of_cells, [&](size_t i) { - const auto [primal_face_id, dual_cell_id] = m_primal_face_to_dual_cell_map[i]; - diamond_descriptor.cell_number_vector[dual_cell_id] = primal_face_number[primal_face_id]; - }); + diamond_descriptor.setCellNumberVector([&] { + Array<int> cell_number_vector(diamond_number_of_cells); + const auto& primal_face_number = primal_connectivity.faceNumber(); + parallel_for(diamond_number_of_cells, [&](size_t i) { + const auto [primal_face_id, dual_cell_id] = m_primal_face_to_dual_cell_map[i]; + cell_number_vector[dual_cell_id] = primal_face_number[primal_face_id]; + }); + return cell_number_vector; + }()); - diamond_descriptor.cell_type_vector.resize(diamond_number_of_cells); + Array<CellType> cell_type_vector(diamond_number_of_cells); const auto& primal_face_to_cell_matrix = primal_connectivity.faceToCellMatrix(); const auto& primal_face_to_node_matrix = primal_connectivity.faceToNodeMatrix(); @@ -87,97 +91,108 @@ DiamondDualConnectivityBuilder::_buildDiamondConnectivityDescriptor(const Connec if constexpr (Dimension == 2) { if (primal_face_cell_list.size() == 1) { - diamond_descriptor.cell_type_vector[i_cell] = CellType::Triangle; + cell_type_vector[i_cell] = CellType::Triangle; } else { Assert(primal_face_cell_list.size() == 2); - diamond_descriptor.cell_type_vector[i_cell] = CellType::Quadrangle; + cell_type_vector[i_cell] = CellType::Quadrangle; } } else if constexpr (Dimension == 3) { if (primal_face_cell_list.size() == 1) { if (primal_face_to_node_matrix[face_id].size() == 3) { - diamond_descriptor.cell_type_vector[i_cell] = CellType::Tetrahedron; + cell_type_vector[i_cell] = CellType::Tetrahedron; } else { - diamond_descriptor.cell_type_vector[i_cell] = CellType::Pyramid; + cell_type_vector[i_cell] = CellType::Pyramid; } } else { Assert(primal_face_cell_list.size() == 2); - diamond_descriptor.cell_type_vector[i_cell] = CellType::Diamond; + cell_type_vector[i_cell] = CellType::Diamond; } } }); - diamond_descriptor.cell_to_node_vector.resize(diamond_number_of_cells); + diamond_descriptor.setCellTypeVector(cell_type_vector); - const auto& primal_face_local_number_in_their_cells = primal_connectivity.faceLocalNumbersInTheirCells(); - const auto& cell_face_is_reversed = primal_connectivity.cellFaceIsReversed(); - parallel_for(primal_number_of_faces, [&](FaceId face_id) { - const size_t& i_diamond_cell = face_id; - const auto& primal_face_cell_list = primal_face_to_cell_matrix[face_id]; - const auto& primal_face_node_list = primal_face_to_node_matrix[face_id]; - if (primal_face_cell_list.size() == 1) { - diamond_descriptor.cell_to_node_vector[i_diamond_cell].resize(primal_face_node_list.size() + 1); - - const CellId cell_id = primal_face_cell_list[0]; - const auto i_face_in_cell = primal_face_local_number_in_their_cells(face_id, 0); + Array<const unsigned int> cell_to_node_row = [&] { + Array<unsigned int> tmp_cell_to_node_row(primal_number_of_faces + 1); + tmp_cell_to_node_row[0] = 0; + for (FaceId face_id = 0; face_id < primal_number_of_faces; ++face_id) { + tmp_cell_to_node_row[face_id + 1] = tmp_cell_to_node_row[face_id] + primal_face_to_node_matrix[face_id].size() + + primal_face_to_cell_matrix[face_id].size(); + } - for (size_t i_node = 0; i_node < primal_face_node_list.size(); ++i_node) { - diamond_descriptor.cell_to_node_vector[i_diamond_cell][i_node] = primal_face_node_list[i_node]; - } - diamond_descriptor.cell_to_node_vector[i_diamond_cell][primal_face_node_list.size()] = - primal_number_of_nodes + cell_id; + return tmp_cell_to_node_row; + }(); + + Array<const unsigned int> cell_to_node_list = [&] { + Array<unsigned int> tmp_cell_to_node_list(cell_to_node_row[cell_to_node_row.size() - 1]); + const auto& primal_face_local_number_in_their_cells = primal_connectivity.faceLocalNumbersInTheirCells(); + const auto& cell_face_is_reversed = primal_connectivity.cellFaceIsReversed(); + parallel_for(primal_number_of_faces, [&](FaceId face_id) { + const auto& primal_face_cell_list = primal_face_to_cell_matrix[face_id]; + const auto& primal_face_node_list = primal_face_to_node_matrix[face_id]; + const size_t first_node = cell_to_node_row[face_id]; + if (primal_face_cell_list.size() == 1) { + const CellId cell_id = primal_face_cell_list[0]; + const auto i_face_in_cell = primal_face_local_number_in_their_cells(face_id, 0); - if constexpr (Dimension == 2) { - if (cell_face_is_reversed(cell_id, i_face_in_cell)) { - std::swap(diamond_descriptor.cell_to_node_vector[i_diamond_cell][0], - diamond_descriptor.cell_to_node_vector[i_diamond_cell][1]); + for (size_t i_node = 0; i_node < primal_face_node_list.size(); ++i_node) { + tmp_cell_to_node_list[first_node + i_node] = primal_face_node_list[i_node]; } - } else { - if (not cell_face_is_reversed(cell_id, i_face_in_cell)) { - // In 3D the basis of the pyramid is described in the - // indirect way IF the face is not reversed. In other words - // the "topological normal" must point to the "top" of the - // pyramid. - for (size_t i_node = 0; i_node < primal_face_node_list.size() / 2; ++i_node) { - std::swap(diamond_descriptor.cell_to_node_vector[i_diamond_cell][i_node], - diamond_descriptor - .cell_to_node_vector[i_diamond_cell][primal_face_node_list.size() - 1 - i_node]); + tmp_cell_to_node_list[first_node + primal_face_node_list.size()] = primal_number_of_nodes + cell_id; + + if constexpr (Dimension == 2) { + if (cell_face_is_reversed(cell_id, i_face_in_cell)) { + std::swap(tmp_cell_to_node_list[first_node], tmp_cell_to_node_list[first_node + 1]); + } + } else { + if (not cell_face_is_reversed(cell_id, i_face_in_cell)) { + // In 3D the basis of the pyramid is described in the + // indirect way IF the face is not reversed. In other words + // the "topological normal" must point to the "top" of the + // pyramid. + for (size_t i_node = 0; i_node < primal_face_node_list.size() / 2; ++i_node) { + std::swap(tmp_cell_to_node_list[first_node + i_node], + tmp_cell_to_node_list[first_node + primal_face_node_list.size() - 1 - i_node]); + } } - } - } - } else { - Assert(primal_face_cell_list.size() == 2); - diamond_descriptor.cell_to_node_vector[i_diamond_cell].resize(primal_face_node_list.size() + 2); - - const CellId cell0_id = primal_face_cell_list[0]; - const CellId cell1_id = primal_face_cell_list[1]; - const auto i_face_in_cell0 = primal_face_local_number_in_their_cells(face_id, 0); - - if constexpr (Dimension == 2) { - Assert(primal_face_node_list.size() == 2); - diamond_descriptor.cell_to_node_vector[i_diamond_cell][0] = primal_number_of_nodes + cell0_id; - diamond_descriptor.cell_to_node_vector[i_diamond_cell][1] = primal_face_node_list[0]; - diamond_descriptor.cell_to_node_vector[i_diamond_cell][2] = primal_number_of_nodes + cell1_id; - diamond_descriptor.cell_to_node_vector[i_diamond_cell][3] = primal_face_node_list[1]; - - if (cell_face_is_reversed(cell0_id, i_face_in_cell0)) { - std::swap(diamond_descriptor.cell_to_node_vector[i_diamond_cell][1], - diamond_descriptor.cell_to_node_vector[i_diamond_cell][3]); } } else { - diamond_descriptor.cell_to_node_vector[i_diamond_cell][0] = primal_number_of_nodes + cell0_id; - for (size_t i_node = 0; i_node < primal_face_node_list.size(); ++i_node) { - diamond_descriptor.cell_to_node_vector[i_diamond_cell][i_node + 1] = primal_face_node_list[i_node]; - } - diamond_descriptor.cell_to_node_vector[i_diamond_cell][primal_face_node_list.size() + 1] = - primal_number_of_nodes + cell1_id; + Assert(primal_face_cell_list.size() == 2); - if (cell_face_is_reversed(cell0_id, i_face_in_cell0)) { - std::swap(diamond_descriptor.cell_to_node_vector[i_diamond_cell][0], - diamond_descriptor.cell_to_node_vector[i_diamond_cell][primal_face_node_list.size() + 1]); + const CellId cell0_id = primal_face_cell_list[0]; + const CellId cell1_id = primal_face_cell_list[1]; + const auto i_face_in_cell0 = primal_face_local_number_in_their_cells(face_id, 0); + + if constexpr (Dimension == 2) { + Assert(primal_face_node_list.size() == 2); + + tmp_cell_to_node_list[first_node + 0] = primal_number_of_nodes + cell0_id; + tmp_cell_to_node_list[first_node + 1] = primal_face_node_list[0]; + tmp_cell_to_node_list[first_node + 2] = primal_number_of_nodes + cell1_id; + tmp_cell_to_node_list[first_node + 3] = primal_face_node_list[1]; + + if (cell_face_is_reversed(cell0_id, i_face_in_cell0)) { + std::swap(tmp_cell_to_node_list[first_node + 1], tmp_cell_to_node_list[first_node + 3]); + } + } else { + tmp_cell_to_node_list[first_node + 0] = primal_number_of_nodes + cell0_id; + for (size_t i_node = 0; i_node < primal_face_node_list.size(); ++i_node) { + tmp_cell_to_node_list[first_node + i_node + 1] = primal_face_node_list[i_node]; + } + tmp_cell_to_node_list[first_node + primal_face_node_list.size() + 1] = primal_number_of_nodes + cell1_id; + + if (cell_face_is_reversed(cell0_id, i_face_in_cell0)) { + std::swap(tmp_cell_to_node_list[first_node], + tmp_cell_to_node_list[first_node + primal_face_node_list.size() + 1]); + } } } - } - }); + }); + + return tmp_cell_to_node_list; + }(); + + diamond_descriptor.setCellToNodeMatrix(ConnectivityMatrix(cell_to_node_row, cell_to_node_list)); } template <size_t Dimension> @@ -198,11 +213,12 @@ DiamondDualConnectivityBuilder::_buildDiamondConnectivityFrom(const IConnectivit ConnectivityBuilderBase::_computeFaceEdgeAndEdgeNodeAndCellEdgeConnectivities<Dimension>(diamond_descriptor); } + const auto& node_number_vector = diamond_descriptor.nodeNumberVector(); { const std::unordered_map<unsigned int, NodeId> node_to_id_map = [&] { std::unordered_map<unsigned int, NodeId> node_to_id_map; - for (size_t i_node = 0; i_node < diamond_descriptor.node_number_vector.size(); ++i_node) { - node_to_id_map[diamond_descriptor.node_number_vector[i_node]] = i_node; + for (size_t i_node = 0; i_node < node_number_vector.size(); ++i_node) { + node_to_id_map[node_number_vector[i_node]] = i_node; } return node_to_id_map; }(); @@ -238,20 +254,32 @@ DiamondDualConnectivityBuilder::_buildDiamondConnectivityFrom(const IConnectivit } { - const auto& primal_face_to_node_matrix = primal_connectivity.faceToNodeMatrix(); - - using Face = ConnectivityFace<Dimension>; - - const std::unordered_map<Face, FaceId, typename Face::Hash> face_to_id_map = [&] { - std::unordered_map<Face, FaceId, typename Face::Hash> face_to_id_map; - for (FaceId l = 0; l < diamond_descriptor.face_to_node_vector.size(); ++l) { - const auto& node_vector = diamond_descriptor.face_to_node_vector[l]; - - face_to_id_map[Face(node_vector, diamond_descriptor.node_number_vector)] = l; + const auto& primal_face_to_node_matrix = primal_connectivity.faceToNodeMatrix(); + const auto& diamond_node_to_face_matrix = diamond_descriptor.nodeToFaceMatrix(); + const auto& diamond_face_to_node_matrix = diamond_descriptor.faceToNodeMatrix(); + + const auto find_face = [&](std::vector<uint32_t> node_list) -> std::optional<FaceId> { + // The node list of already sorted correctly + const auto& face_id_vector = diamond_node_to_face_matrix[node_list[0]]; + + for (size_t i_face = 0; i_face < face_id_vector.size(); ++i_face) { + const FaceId face_id = face_id_vector[i_face]; + const auto& face_node_id_list = diamond_face_to_node_matrix[face_id]; + if (face_node_id_list.size() == node_list.size()) { + bool is_same = true; + for (size_t i_node = 1; i_node < face_node_id_list.size(); ++i_node) { + is_same &= (face_node_id_list[i_node] == node_list[i_node]); + } + if (is_same) { + return face_id; + } + } } - return face_to_id_map; - }(); + return std::nullopt; + }; + + std::vector<unsigned int> face_node_list; for (size_t i_face_list = 0; i_face_list < primal_connectivity.template numberOfRefItemList<ItemType::face>(); ++i_face_list) { const auto& primal_ref_face_list = primal_connectivity.template refItemList<ItemType::face>(i_face_list); @@ -265,16 +293,15 @@ DiamondDualConnectivityBuilder::_buildDiamondConnectivityFrom(const IConnectivit const auto& primal_face_node_list = primal_face_to_node_matrix[primal_face_id]; - const auto i_diamond_face = [&]() { - std::vector<unsigned int> node_list(primal_face_node_list.size()); - for (size_t i = 0; i < primal_face_node_list.size(); ++i) { - node_list[i] = primal_face_node_list[i]; - } - return face_to_id_map.find(Face(node_list, diamond_descriptor.node_number_vector)); - }(); + face_node_list.clear(); + + for (size_t i = 0; i < primal_face_node_list.size(); ++i) { + face_node_list.push_back(primal_face_node_list[i]); + } - if (i_diamond_face != face_to_id_map.end()) { - diamond_face_list.push_back(i_diamond_face->second); + auto face_id = find_face(face_node_list); + if (face_id.has_value()) { + diamond_face_list.push_back(face_id.value()); } } return diamond_face_list; @@ -293,29 +320,40 @@ DiamondDualConnectivityBuilder::_buildDiamondConnectivityFrom(const IConnectivit if constexpr (Dimension == 3) { const auto& primal_edge_to_node_matrix = primal_connectivity.edgeToNodeMatrix(); - using Edge = ConnectivityFace<2>; - - const std::unordered_map<Edge, EdgeId, typename Edge::Hash> edge_to_id_map = [&] { - std::unordered_map<Edge, EdgeId, typename Edge::Hash> edge_to_id_map; - for (EdgeId l = 0; l < diamond_descriptor.edge_to_node_vector.size(); ++l) { - const auto& node_vector = diamond_descriptor.edge_to_node_vector[l]; - edge_to_id_map[Edge(node_vector, diamond_descriptor.node_number_vector)] = l; - } - return edge_to_id_map; - }(); { - const size_t number_of_edges = diamond_descriptor.edge_to_node_vector.size(); - diamond_descriptor.edge_number_vector.resize(number_of_edges); - for (size_t i_edge = 0; i_edge < number_of_edges; ++i_edge) { - diamond_descriptor.edge_number_vector[i_edge] = i_edge; - } + const size_t number_of_edges = diamond_descriptor.edgeToNodeMatrix().numberOfRows(); + diamond_descriptor.setEdgeNumberVector([&] { + Array<int> edge_number_vector(number_of_edges); + parallel_for( + number_of_edges, PUGS_LAMBDA(size_t i_edge) { edge_number_vector[i_edge] = i_edge; }); + return edge_number_vector; + }()); + // LCOV_EXCL_START if (parallel::size() > 1) { throw NotImplementedError("parallel edge numbering is undefined"); } // LCOV_EXCL_STOP } + const auto& diamond_node_to_edge_matrix = diamond_descriptor.nodeToEdgeMatrix(); + const auto& diamond_edge_to_node_matrix = diamond_descriptor.edgeToNodeMatrix(); + + const auto find_edge = [&](uint32_t node0, uint32_t node1) -> std::optional<EdgeId> { + if (node_number_vector[node0] > node_number_vector[node1]) { + std::swap(node0, node1); + } + const auto& edge_id_vector = diamond_node_to_edge_matrix[node0]; + + for (size_t i_edge = 0; i_edge < edge_id_vector.size(); ++i_edge) { + const EdgeId edge_id = edge_id_vector[i_edge]; + if (diamond_edge_to_node_matrix[edge_id][1] == node1) { + return edge_id; + } + } + + return std::nullopt; + }; for (size_t i_edge_list = 0; i_edge_list < primal_connectivity.template numberOfRefItemList<ItemType::edge>(); ++i_edge_list) { @@ -330,16 +368,10 @@ DiamondDualConnectivityBuilder::_buildDiamondConnectivityFrom(const IConnectivit const auto& primal_edge_node_list = primal_edge_to_node_matrix[primal_edge_id]; - const auto i_diamond_edge = [&]() { - std::vector<unsigned int> node_list(primal_edge_node_list.size()); - for (size_t i = 0; i < primal_edge_node_list.size(); ++i) { - node_list[i] = primal_edge_node_list[i]; - } - return edge_to_id_map.find(Edge(node_list, diamond_descriptor.node_number_vector)); - }(); + const auto diamond_edge_id = find_edge(primal_edge_node_list[0], primal_edge_node_list[1]); - if (i_diamond_edge != edge_to_id_map.end()) { - diamond_edge_list.push_back(i_diamond_edge->second); + if (diamond_edge_id.has_value()) { + diamond_edge_list.push_back(diamond_edge_id.value()); } } return diamond_edge_list; @@ -359,62 +391,64 @@ DiamondDualConnectivityBuilder::_buildDiamondConnectivityFrom(const IConnectivit const size_t primal_number_of_nodes = primal_connectivity.numberOfNodes(); const size_t primal_number_of_cells = primal_connectivity.numberOfCells(); - diamond_descriptor.node_owner_vector.resize(diamond_descriptor.node_number_vector.size()); - - { + diamond_descriptor.setNodeOwnerVector([&] { + Array<int> node_owner_vector(node_number_vector.size()); const auto& primal_node_owner = primal_connectivity.nodeOwner(); for (NodeId primal_node_id = 0; primal_node_id < primal_connectivity.numberOfNodes(); ++primal_node_id) { - diamond_descriptor.node_owner_vector[primal_node_id] = primal_node_owner[primal_node_id]; + node_owner_vector[primal_node_id] = primal_node_owner[primal_node_id]; } const auto& primal_cell_owner = primal_connectivity.cellOwner(); for (CellId primal_cell_id = 0; primal_cell_id < primal_number_of_cells; ++primal_cell_id) { - diamond_descriptor.node_owner_vector[primal_number_of_nodes + primal_cell_id] = primal_cell_owner[primal_cell_id]; + node_owner_vector[primal_number_of_nodes + primal_cell_id] = primal_cell_owner[primal_cell_id]; } - } + return node_owner_vector; + }()); - { - diamond_descriptor.cell_owner_vector.resize(diamond_descriptor.cell_number_vector.size()); + diamond_descriptor.setCellOwnerVector([&] { + Array<int> cell_owner_vector(diamond_descriptor.cellNumberVector().size()); const size_t primal_number_of_faces = primal_connectivity.numberOfFaces(); const auto& primal_face_owner = primal_connectivity.faceOwner(); - for (FaceId primal_face_id = 0; primal_face_id < primal_number_of_faces; ++primal_face_id) { - diamond_descriptor.cell_owner_vector[primal_face_id] = primal_face_owner[primal_face_id]; - } - } - - { - std::vector<int> face_cell_owner(diamond_descriptor.face_number_vector.size()); - std::fill(std::begin(face_cell_owner), std::end(face_cell_owner), parallel::size()); - - for (size_t i_cell = 0; i_cell < diamond_descriptor.cell_to_face_vector.size(); ++i_cell) { - const auto& cell_face_list = diamond_descriptor.cell_to_face_vector[i_cell]; + parallel_for( + primal_number_of_faces, PUGS_LAMBDA(const FaceId primal_face_id) { + cell_owner_vector[primal_face_id] = primal_face_owner[primal_face_id]; + }); + return cell_owner_vector; + }()); + + const auto& diamond_cell_owner_vector = diamond_descriptor.cellOwnerVector(); + const auto& diamond_cell_to_face_matrix = diamond_descriptor.cellToFaceMatrix(); + + diamond_descriptor.setFaceOwnerVector([&] { + Array<int> face_owner_vector(diamond_descriptor.faceNumberVector().size()); + face_owner_vector.fill(parallel::rank()); + + for (size_t i_cell = 0; i_cell < diamond_cell_to_face_matrix.numberOfRows(); ++i_cell) { + const auto& cell_face_list = diamond_cell_to_face_matrix[i_cell]; for (size_t i_face = 0; i_face < cell_face_list.size(); ++i_face) { - const size_t face_id = cell_face_list[i_face]; - face_cell_owner[face_id] = std::min(face_cell_owner[face_id], diamond_descriptor.cell_number_vector[i_cell]); + const size_t face_id = cell_face_list[i_face]; + face_owner_vector[face_id] = std::min(face_owner_vector[face_id], diamond_cell_owner_vector[i_cell]); } } - - diamond_descriptor.face_owner_vector.resize(face_cell_owner.size()); - for (size_t i_face = 0; i_face < face_cell_owner.size(); ++i_face) { - diamond_descriptor.face_owner_vector[i_face] = diamond_descriptor.cell_owner_vector[face_cell_owner[i_face]]; - } - } + return face_owner_vector; + }()); if constexpr (Dimension == 3) { - std::vector<int> edge_cell_owner(diamond_descriptor.edge_number_vector.size()); - std::fill(std::begin(edge_cell_owner), std::end(edge_cell_owner), parallel::size()); - - for (size_t i_cell = 0; i_cell < diamond_descriptor.cell_to_face_vector.size(); ++i_cell) { - const auto& cell_edge_list = diamond_descriptor.cell_to_edge_vector[i_cell]; - for (size_t i_edge = 0; i_edge < cell_edge_list.size(); ++i_edge) { - const size_t edge_id = cell_edge_list[i_edge]; - edge_cell_owner[edge_id] = std::min(edge_cell_owner[edge_id], diamond_descriptor.cell_number_vector[i_cell]); + const auto& diamond_cell_to_edge_matrix = diamond_descriptor.cellToEdgeMatrix(); + + diamond_descriptor.setEdgeOwnerVector([&] { + Array<int> edge_owner_vector(diamond_descriptor.edgeNumberVector().size()); + edge_owner_vector.fill(parallel::rank()); + + for (size_t i_cell = 0; i_cell < diamond_cell_to_edge_matrix.numberOfRows(); ++i_cell) { + const auto& cell_edge_list = diamond_cell_to_edge_matrix[i_cell]; + for (size_t i_edge = 0; i_edge < cell_edge_list.size(); ++i_edge) { + const size_t edge_id = cell_edge_list[i_edge]; + edge_owner_vector[edge_id] = std::min(edge_owner_vector[edge_id], diamond_cell_owner_vector[i_cell]); + } } - } - diamond_descriptor.edge_owner_vector.resize(edge_cell_owner.size()); - for (size_t i_edge = 0; i_edge < edge_cell_owner.size(); ++i_edge) { - diamond_descriptor.edge_owner_vector[i_edge] = diamond_descriptor.cell_owner_vector[edge_cell_owner[i_edge]]; - } + return edge_owner_vector; + }()); } m_connectivity = ConnectivityType::build(diamond_descriptor); diff --git a/src/mesh/DiamondDualMeshBuilder.cpp b/src/mesh/DiamondDualMeshBuilder.cpp index 21e413ff4e94519b79fbc26e87d742e67c0436c2..64711edc72055effd9e5608bc01b71ea184ee1fc 100644 --- a/src/mesh/DiamondDualMeshBuilder.cpp +++ b/src/mesh/DiamondDualMeshBuilder.cpp @@ -43,8 +43,6 @@ DiamondDualMeshBuilder::_buildDualDiamondMeshFrom(const IMesh& i_mesh) DiamondDualMeshBuilder::DiamondDualMeshBuilder(const IMesh& i_mesh) { - std::cout << "building DiamondDualMesh\n"; - switch (i_mesh.dimension()) { case 2: { this->_buildDualDiamondMeshFrom<2>(i_mesh); diff --git a/src/mesh/Dual1DConnectivityBuilder.cpp b/src/mesh/Dual1DConnectivityBuilder.cpp index 30c465b8b07375fce9f82fb76a26ac24848f3c67..52f3ddc977adc531496bf02b10e2b3ef36dfa5f1 100644 --- a/src/mesh/Dual1DConnectivityBuilder.cpp +++ b/src/mesh/Dual1DConnectivityBuilder.cpp @@ -28,14 +28,14 @@ Dual1DConnectivityBuilder::_buildConnectivityDescriptor(const Connectivity<1>& p const auto& primal_node_to_cell_matrix = primal_connectivity.nodeToCellMatrix(); size_t next_kept_node_id = 0; - dual_descriptor.node_number_vector.resize(dual_number_of_nodes); + Array<int> node_number_vector(dual_number_of_nodes); const auto& primal_node_number = primal_connectivity.nodeNumber(); for (NodeId primal_node_id = 0; primal_node_id < primal_connectivity.numberOfNodes(); ++primal_node_id) { const auto& primal_node_cell_list = primal_node_to_cell_matrix[primal_node_id]; if (primal_node_cell_list.size() == 1) { - dual_descriptor.node_number_vector[next_kept_node_id++] = primal_node_number[primal_node_id]; + node_number_vector[next_kept_node_id++] = primal_node_number[primal_node_id]; } } @@ -46,43 +46,56 @@ Dual1DConnectivityBuilder::_buildConnectivityDescriptor(const Connectivity<1>& p const size_t cell_number_shift = max(primal_node_number) + 1; for (CellId primal_cell_id = 0; primal_cell_id < primal_number_of_cells; ++primal_cell_id) { - dual_descriptor.node_number_vector[primal_number_of_kept_nodes + primal_cell_id] = + node_number_vector[primal_number_of_kept_nodes + primal_cell_id] = primal_cell_number[primal_cell_id] + cell_number_shift; } + dual_descriptor.setNodeNumberVector(node_number_vector); Assert(number_of_kept_nodes == next_kept_node_id, "unexpected number of kept nodes"); - dual_descriptor.cell_number_vector.resize(dual_number_of_cells); - for (NodeId primal_node_id = 0; primal_node_id < primal_number_of_nodes; ++primal_node_id) { - dual_descriptor.cell_number_vector[primal_node_id] = primal_node_number[primal_node_id]; - } - - dual_descriptor.cell_type_vector = std::vector<CellType>(dual_number_of_cells, CellType::Line); + dual_descriptor.setCellNumberVector([&] { + Array<int> cell_number_vector(dual_number_of_cells); + parallel_for( + primal_number_of_nodes, PUGS_LAMBDA(const NodeId primal_node_id) { + cell_number_vector[primal_node_id] = primal_node_number[primal_node_id]; + }); + return cell_number_vector; + }()); - dual_descriptor.cell_to_node_vector.resize(dual_number_of_cells); + Array<CellType> cell_type_vector(dual_number_of_cells); + cell_type_vector.fill(CellType::Line); + dual_descriptor.setCellTypeVector(cell_type_vector); const auto& primal_node_local_number_in_their_cells = primal_connectivity.nodeLocalNumbersInTheirCells(); + Array<unsigned int> cell_to_node_row(dual_number_of_cells + 1); + parallel_for( + cell_to_node_row.size(), PUGS_LAMBDA(const CellId cell_id) { cell_to_node_row[cell_id] = 2 * cell_id; }); + + Array<unsigned int> cell_to_node_list(cell_to_node_row[cell_to_node_row.size() - 1]); { size_t next_kept_node_id = 0; + size_t i_cell_node = 0; for (NodeId i_node = 0; i_node < primal_connectivity.numberOfNodes(); ++i_node) { - const size_t& i_dual_cell = i_node; const auto& primal_node_cell_list = primal_node_to_cell_matrix[i_node]; - dual_descriptor.cell_to_node_vector[i_dual_cell].resize(2); if (primal_node_cell_list.size() == 1) { const auto i_node_in_cell = primal_node_local_number_in_their_cells(i_node, 0); - dual_descriptor.cell_to_node_vector[i_dual_cell][i_node_in_cell] = next_kept_node_id++; - dual_descriptor.cell_to_node_vector[i_dual_cell][1 - i_node_in_cell] = - number_of_kept_nodes + primal_node_cell_list[0]; + cell_to_node_list[i_cell_node + i_node_in_cell] = next_kept_node_id++; + cell_to_node_list[i_cell_node + 1 - i_node_in_cell] = number_of_kept_nodes + primal_node_cell_list[0]; + + i_cell_node += 2; + } else { const auto i0 = primal_node_local_number_in_their_cells(i_node, 0); - dual_descriptor.cell_to_node_vector[i_dual_cell][0] = number_of_kept_nodes + primal_node_cell_list[1 - i0]; - dual_descriptor.cell_to_node_vector[i_dual_cell][1] = number_of_kept_nodes + primal_node_cell_list[i0]; + cell_to_node_list[i_cell_node++] = number_of_kept_nodes + primal_node_cell_list[1 - i0]; + cell_to_node_list[i_cell_node++] = number_of_kept_nodes + primal_node_cell_list[i0]; } } } + + dual_descriptor.setCellToNodeMatrix(ConnectivityMatrix(cell_to_node_row, cell_to_node_list)); } void @@ -97,10 +110,12 @@ Dual1DConnectivityBuilder::_buildConnectivityFrom(const IConnectivity& i_primal_ this->_buildConnectivityDescriptor(primal_connectivity, dual_descriptor); { + const auto& dual_node_number_vector = dual_descriptor.nodeNumberVector(); + const std::unordered_map<unsigned int, NodeId> node_to_id_map = [&] { std::unordered_map<unsigned int, NodeId> node_to_id_map; - for (size_t i_node = 0; i_node < dual_descriptor.node_number_vector.size(); ++i_node) { - node_to_id_map[dual_descriptor.node_number_vector[i_node]] = i_node; + for (size_t i_node = 0; i_node < dual_node_number_vector.size(); ++i_node) { + node_to_id_map[dual_node_number_vector[i_node]] = i_node; } return node_to_id_map; }(); @@ -138,31 +153,33 @@ Dual1DConnectivityBuilder::_buildConnectivityFrom(const IConnectivity& i_primal_ const size_t primal_number_of_nodes = primal_connectivity.numberOfNodes(); const size_t primal_number_of_cells = primal_connectivity.numberOfCells(); - dual_descriptor.node_owner_vector.resize(dual_descriptor.node_number_vector.size()); - - { + dual_descriptor.setNodeOwnerVector([&] { + Array<int> node_owner_vector(dual_descriptor.nodeNumberVector().size()); const auto& node_to_cell_matrix = primal_connectivity.nodeToCellMatrix(); const auto& primal_node_owner = primal_connectivity.nodeOwner(); size_t next_kept_node_id = 0; for (NodeId primal_node_id = 0; primal_node_id < primal_connectivity.numberOfNodes(); ++primal_node_id) { if (node_to_cell_matrix[primal_node_id].size() == 1) { - dual_descriptor.node_owner_vector[next_kept_node_id++] = primal_node_owner[primal_node_id]; + node_owner_vector[next_kept_node_id++] = primal_node_owner[primal_node_id]; } } const size_t number_of_kept_nodes = next_kept_node_id; const auto& primal_cell_owner = primal_connectivity.cellOwner(); for (CellId primal_cell_id = 0; primal_cell_id < primal_number_of_cells; ++primal_cell_id) { - dual_descriptor.node_owner_vector[number_of_kept_nodes + primal_cell_id] = primal_cell_owner[primal_cell_id]; + node_owner_vector[number_of_kept_nodes + primal_cell_id] = primal_cell_owner[primal_cell_id]; } - } - { - dual_descriptor.cell_owner_vector.resize(dual_descriptor.cell_number_vector.size()); + return node_owner_vector; + }()); + + dual_descriptor.setCellOwnerVector([&] { + Array<int> cell_owner_vector(dual_descriptor.cellNumberVector().size()); const auto& primal_node_owner = primal_connectivity.nodeOwner(); - for (NodeId primal_node_id = 0; primal_node_id < primal_number_of_nodes; ++primal_node_id) { - dual_descriptor.cell_owner_vector[primal_node_id] = primal_node_owner[primal_node_id]; - } - } + parallel_for( + primal_number_of_nodes, + PUGS_LAMBDA(NodeId primal_node_id) { cell_owner_vector[primal_node_id] = primal_node_owner[primal_node_id]; }); + return cell_owner_vector; + }()); m_connectivity = ConnectivityType::build(dual_descriptor); diff --git a/src/mesh/GmshReader.cpp b/src/mesh/GmshReader.cpp index e555ca224c1d02f11e11696542774f2e470b6432..e4ae59ea7cbb6fa2ec3f622c0868ff79ff9f8bbf 100644 --- a/src/mesh/GmshReader.cpp +++ b/src/mesh/GmshReader.cpp @@ -35,19 +35,29 @@ GmshConnectivityBuilder<1>::GmshConnectivityBuilder(const GmshReader::GmshData& { ConnectivityDescriptor descriptor; - descriptor.node_number_vector = gmsh_data.__verticesNumbers; - descriptor.cell_type_vector.resize(nb_cells); - descriptor.cell_number_vector.resize(nb_cells); - descriptor.cell_to_node_vector.resize(nb_cells); + descriptor.setNodeNumberVector(convert_to_array(gmsh_data.__verticesNumbers)); + Array<CellType> cell_type_vector(nb_cells); + Array<int> cell_number_vector(nb_cells); - for (size_t j = 0; j < nb_cells; ++j) { - descriptor.cell_to_node_vector[j].resize(2); - for (int r = 0; r < 2; ++r) { - descriptor.cell_to_node_vector[j][r] = gmsh_data.__edges[j][r]; + Array<unsigned int> cell_to_node_row(nb_cells + 1); + parallel_for( + cell_to_node_row.size(), PUGS_LAMBDA(const CellId cell_id) { cell_to_node_row[cell_id] = 2 * cell_id; }); + + Array<unsigned int> cell_to_node_list(cell_to_node_row[cell_to_node_row.size() - 1]); + for (CellId cell_id = 0; cell_id < nb_cells; ++cell_id) { + for (int i_node = 0; i_node < 2; ++i_node) { + cell_to_node_list[2 * cell_id + i_node] = gmsh_data.__edges[cell_id][i_node]; } - descriptor.cell_type_vector[j] = CellType::Line; - descriptor.cell_number_vector[j] = gmsh_data.__edges_number[j]; } + descriptor.setCellToNodeMatrix(ConnectivityMatrix(cell_to_node_row, cell_to_node_list)); + + cell_type_vector.fill(CellType::Line); + descriptor.setCellTypeVector(cell_type_vector); + + for (size_t j = 0; j < nb_cells; ++j) { + cell_number_vector[j] = gmsh_data.__edges_number[j]; + } + descriptor.setCellNumberVector(cell_number_vector); std::map<unsigned int, std::vector<unsigned int>> ref_points_map; for (unsigned int r = 0; r < gmsh_data.__points.size(); ++r) { @@ -56,12 +66,14 @@ GmshConnectivityBuilder<1>::GmshConnectivityBuilder(const GmshReader::GmshData& ref_points_map[ref].push_back(point_number); } - Array<size_t> node_nb_cell(descriptor.node_number_vector.size()); + Array<size_t> node_nb_cell(descriptor.nodeNumberVector().size()); node_nb_cell.fill(0); + const auto& cell_to_node_matrix = descriptor.cellToNodeMatrix(); for (size_t j = 0; j < nb_cells; ++j) { + const auto& cell_node_list = cell_to_node_matrix[j]; for (int r = 0; r < 2; ++r) { - node_nb_cell[descriptor.cell_to_node_vector[j][r]] += 1; + node_nb_cell[cell_node_list[r]] += 1; } } @@ -116,12 +128,18 @@ GmshConnectivityBuilder<1>::GmshConnectivityBuilder(const GmshReader::GmshData& descriptor.addRefItemList(RefCellList(ref_id, cell_list, false)); } - descriptor.cell_owner_vector.resize(nb_cells); - std::fill(descriptor.cell_owner_vector.begin(), descriptor.cell_owner_vector.end(), parallel::rank()); - - descriptor.node_owner_vector.resize(descriptor.node_number_vector.size()); - std::fill(descriptor.node_owner_vector.begin(), descriptor.node_owner_vector.end(), parallel::rank()); - + descriptor.setCellOwnerVector([&] { + Array<int> cell_owner_vector(nb_cells); + cell_owner_vector.fill(parallel::rank()); + return cell_owner_vector; + }()); + + descriptor.setNodeOwnerVector([&] { + Array<int> node_owner_vector(descriptor.nodeNumberVector().size()); + node_owner_vector.fill(parallel::rank()); + return node_owner_vector; + }()); + ; m_connectivity = Connectivity1D::build(descriptor); } @@ -130,32 +148,56 @@ GmshConnectivityBuilder<2>::GmshConnectivityBuilder(const GmshReader::GmshData& { ConnectivityDescriptor descriptor; - descriptor.node_number_vector = gmsh_data.__verticesNumbers; - descriptor.cell_type_vector.resize(nb_cells); - descriptor.cell_number_vector.resize(nb_cells); - descriptor.cell_to_node_vector.resize(nb_cells); + descriptor.setNodeNumberVector(convert_to_array(gmsh_data.__verticesNumbers)); + Array<CellType> cell_type_vector(nb_cells); + Array<int> cell_number_vector(nb_cells); - const size_t nb_triangles = gmsh_data.__triangles.size(); - for (size_t j = 0; j < nb_triangles; ++j) { - descriptor.cell_to_node_vector[j].resize(3); - for (int r = 0; r < 3; ++r) { - descriptor.cell_to_node_vector[j][r] = gmsh_data.__triangles[j][r]; + Array<unsigned int> cell_to_node_row(gmsh_data.__triangles.size() + gmsh_data.__quadrangles.size() + 1); + { + cell_to_node_row[0] = 0; + size_t i_cell = 0; + for (size_t i_triangle = 0; i_triangle < gmsh_data.__triangles.size(); ++i_triangle, ++i_cell) { + cell_to_node_row[i_cell + 1] = cell_to_node_row[i_cell] + 3; + } + for (size_t i_quadrangle = 0; i_quadrangle < gmsh_data.__quadrangles.size(); ++i_quadrangle, ++i_cell) { + cell_to_node_row[i_cell + 1] = cell_to_node_row[i_cell] + 4; } - descriptor.cell_type_vector[j] = CellType::Triangle; - descriptor.cell_number_vector[j] = gmsh_data.__triangles_number[j]; + } + + Array<unsigned int> cell_to_node_list(cell_to_node_row[cell_to_node_row.size() - 1]); + { + size_t i_cell_node = 0; + for (size_t i_triangle = 0; i_triangle < gmsh_data.__triangles.size(); ++i_triangle) { + cell_to_node_list[i_cell_node++] = gmsh_data.__triangles[i_triangle][0]; + cell_to_node_list[i_cell_node++] = gmsh_data.__triangles[i_triangle][1]; + cell_to_node_list[i_cell_node++] = gmsh_data.__triangles[i_triangle][2]; + } + for (size_t i_quadrangle = 0; i_quadrangle < gmsh_data.__quadrangles.size(); ++i_quadrangle) { + cell_to_node_list[i_cell_node++] = gmsh_data.__quadrangles[i_quadrangle][0]; + cell_to_node_list[i_cell_node++] = gmsh_data.__quadrangles[i_quadrangle][1]; + cell_to_node_list[i_cell_node++] = gmsh_data.__quadrangles[i_quadrangle][2]; + cell_to_node_list[i_cell_node++] = gmsh_data.__quadrangles[i_quadrangle][3]; + } + } + descriptor.setCellToNodeMatrix(ConnectivityMatrix(cell_to_node_row, cell_to_node_list)); + + const size_t nb_triangles = gmsh_data.__triangles.size(); + for (size_t i_triangle = 0; i_triangle < nb_triangles; ++i_triangle) { + cell_type_vector[i_triangle] = CellType::Triangle; + cell_number_vector[i_triangle] = gmsh_data.__triangles_number[i_triangle]; } const size_t nb_quadrangles = gmsh_data.__quadrangles.size(); - for (size_t j = 0; j < nb_quadrangles; ++j) { - const size_t jq = j + nb_triangles; - descriptor.cell_to_node_vector[jq].resize(4); - for (int r = 0; r < 4; ++r) { - descriptor.cell_to_node_vector[jq][r] = gmsh_data.__quadrangles[j][r]; - } - descriptor.cell_type_vector[jq] = CellType::Quadrangle; - descriptor.cell_number_vector[jq] = gmsh_data.__quadrangles_number[j]; + for (size_t i_quadrangle = 0; i_quadrangle < nb_quadrangles; ++i_quadrangle) { + const size_t i_cell = i_quadrangle + nb_triangles; + + cell_type_vector[i_cell] = CellType::Quadrangle; + cell_number_vector[i_cell] = gmsh_data.__quadrangles_number[i_quadrangle]; } + descriptor.setCellNumberVector(cell_number_vector); + descriptor.setCellTypeVector(cell_type_vector); + std::map<unsigned int, std::vector<unsigned int>> ref_cells_map; for (unsigned int j = 0; j < gmsh_data.__triangles_ref.size(); ++j) { const unsigned int elem_number = j; @@ -189,64 +231,73 @@ GmshConnectivityBuilder<2>::GmshConnectivityBuilder(const GmshReader::GmshData& ConnectivityBuilderBase::_computeCellFaceAndFaceNodeConnectivities<2>(descriptor); - using Face = ConnectivityFace<2>; - const auto& node_number_vector = descriptor.node_number_vector; - const std::unordered_map<Face, FaceId, typename Face::Hash> face_to_id_map = [&] { - std::unordered_map<Face, FaceId, typename Face::Hash> face_to_id_map; - for (FaceId l = 0; l < descriptor.face_to_node_vector.size(); ++l) { - const auto& node_vector = descriptor.face_to_node_vector[l]; - face_to_id_map[Face(node_vector, node_number_vector)] = l; - } - return face_to_id_map; - }(); - std::unordered_map<int, FaceId> face_number_id_map = [&] { + const auto& face_number_vector = descriptor.faceNumberVector(); std::unordered_map<int, FaceId> face_number_id_map; - for (size_t l = 0; l < descriptor.face_number_vector.size(); ++l) { - face_number_id_map[descriptor.face_number_vector[l]] = l; + for (size_t l = 0; l < face_number_vector.size(); ++l) { + face_number_id_map[face_number_vector[l]] = l; } - Assert(face_number_id_map.size() == descriptor.face_number_vector.size()); + Assert(face_number_id_map.size() == face_number_vector.size()); return face_number_id_map; }(); + const auto& node_number_vector = descriptor.nodeNumberVector(); + const auto& node_to_face_matrix = descriptor.nodeToFaceMatrix(); + const auto& face_to_node_matrix = descriptor.faceToNodeMatrix(); + + const auto find_face = [&](uint32_t node0, uint32_t node1) { + if (node_number_vector[node0] > node_number_vector[node1]) { + std::swap(node0, node1); + } + const auto& face_id_vector = node_to_face_matrix[node0]; + + for (size_t i_face = 0; i_face < face_id_vector.size(); ++i_face) { + const FaceId face_id = face_id_vector[i_face]; + if (face_to_node_matrix[face_id][1] == node1) { + return face_id; + } + } + + std::stringstream error_msg; + error_msg << "face (" << node0 << ',' << node1 << ") not found"; + throw NormalError(error_msg.str()); + }; + + Array<int> face_number_vector = copy(descriptor.faceNumberVector()); std::map<unsigned int, std::vector<unsigned int>> ref_faces_map; for (unsigned int e = 0; e < gmsh_data.__edges.size(); ++e) { - const unsigned int edge_id = [&] { - auto i = face_to_id_map.find(Face({gmsh_data.__edges[e][0], gmsh_data.__edges[e][1]}, node_number_vector)); - if (i == face_to_id_map.end()) { - std::stringstream error_msg; - error_msg << "face " << gmsh_data.__edges[e][0] << " not found"; - throw NormalError(error_msg.str()); - } - return i->second; - }(); + const unsigned int edge_id = find_face(gmsh_data.__edges[e][0], gmsh_data.__edges[e][1]); + const unsigned int& ref = gmsh_data.__edges_ref[e]; ref_faces_map[ref].push_back(edge_id); - if (descriptor.face_number_vector[edge_id] != gmsh_data.__edges_number[e]) { + if (face_number_vector[edge_id] != gmsh_data.__edges_number[e]) { if (auto i_face = face_number_id_map.find(gmsh_data.__edges_number[e]); i_face != face_number_id_map.end()) { const int other_edge_id = i_face->second; - std::swap(descriptor.face_number_vector[edge_id], descriptor.face_number_vector[other_edge_id]); + std::swap(face_number_vector[edge_id], face_number_vector[other_edge_id]); - face_number_id_map.erase(descriptor.face_number_vector[edge_id]); - face_number_id_map.erase(descriptor.face_number_vector[other_edge_id]); + face_number_id_map.erase(face_number_vector[edge_id]); + face_number_id_map.erase(face_number_vector[other_edge_id]); - face_number_id_map[descriptor.face_number_vector[edge_id]] = edge_id; - face_number_id_map[descriptor.face_number_vector[other_edge_id]] = other_edge_id; + face_number_id_map[face_number_vector[edge_id]] = edge_id; + face_number_id_map[face_number_vector[other_edge_id]] = other_edge_id; } else { - face_number_id_map.erase(descriptor.face_number_vector[edge_id]); - descriptor.face_number_vector[edge_id] = gmsh_data.__edges_number[e]; - face_number_id_map[descriptor.face_number_vector[edge_id]] = edge_id; + face_number_id_map.erase(face_number_vector[edge_id]); + face_number_vector[edge_id] = gmsh_data.__edges_number[e]; + face_number_id_map[face_number_vector[edge_id]] = edge_id; } } } + descriptor.setFaceNumberVector(face_number_vector); - Array<size_t> face_nb_cell(descriptor.face_number_vector.size()); + Array<size_t> face_nb_cell(descriptor.faceNumberVector().size()); face_nb_cell.fill(0); - for (size_t j = 0; j < descriptor.cell_to_face_vector.size(); ++j) { - for (size_t l = 0; l < descriptor.cell_to_face_vector[j].size(); ++l) { - face_nb_cell[descriptor.cell_to_face_vector[j][l]] += 1; + const auto& cell_to_face_matrix = descriptor.cellToFaceMatrix(); + for (size_t j = 0; j < cell_to_face_matrix.numberOfRows(); ++j) { + const auto& cell_face_list = cell_to_face_matrix[j]; + for (size_t l = 0; l < cell_face_list.size(); ++l) { + face_nb_cell[cell_face_list[l]] += 1; } } @@ -276,13 +327,14 @@ GmshConnectivityBuilder<2>::GmshConnectivityBuilder(const GmshReader::GmshData& descriptor.addRefItemList(RefFaceList{ref_id, face_list, is_boundary}); } - Array<bool> is_boundary_node(descriptor.node_number_vector.size()); + Array<bool> is_boundary_node(node_number_vector.size()); is_boundary_node.fill(false); for (size_t i_face = 0; i_face < face_nb_cell.size(); ++i_face) { if (face_nb_cell[i_face] == 1) { - for (size_t node_id : descriptor.face_to_node_vector[i_face]) { - is_boundary_node[node_id] = true; + const auto& face_node_list = face_to_node_matrix[i_face]; + for (size_t i_node = 0; i_node < face_node_list.size(); ++i_node) { + is_boundary_node[face_node_list[i_node]] = true; } } } @@ -319,14 +371,23 @@ GmshConnectivityBuilder<2>::GmshConnectivityBuilder(const GmshReader::GmshData& descriptor.addRefItemList(RefNodeList(ref_id, point_list, is_boundary)); } - descriptor.cell_owner_vector.resize(nb_cells); - std::fill(descriptor.cell_owner_vector.begin(), descriptor.cell_owner_vector.end(), parallel::rank()); + descriptor.setCellOwnerVector([&] { + Array<int> cell_owner_vector(nb_cells); + cell_owner_vector.fill(parallel::rank()); + return cell_owner_vector; + }()); - descriptor.face_owner_vector.resize(descriptor.face_number_vector.size()); - std::fill(descriptor.face_owner_vector.begin(), descriptor.face_owner_vector.end(), parallel::rank()); + descriptor.setFaceOwnerVector([&] { + Array<int> face_owner_vector(descriptor.faceNumberVector().size()); + face_owner_vector.fill(parallel::rank()); + return face_owner_vector; + }()); - descriptor.node_owner_vector.resize(descriptor.node_number_vector.size()); - std::fill(descriptor.node_owner_vector.begin(), descriptor.node_owner_vector.end(), parallel::rank()); + descriptor.setNodeOwnerVector([&] { + Array<int> node_owner_vector(node_number_vector.size()); + node_owner_vector.fill(parallel::rank()); + return node_owner_vector; + }()); m_connectivity = Connectivity2D::build(descriptor); } @@ -336,54 +397,99 @@ GmshConnectivityBuilder<3>::GmshConnectivityBuilder(const GmshReader::GmshData& { ConnectivityDescriptor descriptor; - descriptor.node_number_vector = gmsh_data.__verticesNumbers; - descriptor.cell_type_vector.resize(nb_cells); - descriptor.cell_number_vector.resize(nb_cells); - descriptor.cell_to_node_vector.resize(nb_cells); + descriptor.setNodeNumberVector(convert_to_array(gmsh_data.__verticesNumbers)); + Array<CellType> cell_type_vector(nb_cells); + Array<int> cell_number_vector(nb_cells); const size_t nb_tetrahedra = gmsh_data.__tetrahedra.size(); - for (size_t j = 0; j < nb_tetrahedra; ++j) { - descriptor.cell_to_node_vector[j].resize(4); - for (int r = 0; r < 4; ++r) { - descriptor.cell_to_node_vector[j][r] = gmsh_data.__tetrahedra[j][r]; + const size_t nb_hexahedra = gmsh_data.__hexahedra.size(); + const size_t nb_prisms = gmsh_data.__prisms.size(); + const size_t nb_pyramids = gmsh_data.__pyramids.size(); + + Array<unsigned int> cell_to_node_row(nb_cells + 1); + { + cell_to_node_row[0] = 0; + size_t i_cell = 0; + for (size_t i_tetrahedron = 0; i_tetrahedron < nb_tetrahedra; ++i_tetrahedron, ++i_cell) { + cell_to_node_row[i_cell + 1] = cell_to_node_row[i_cell] + 4; + } + for (size_t i_hexahedron = 0; i_hexahedron < nb_hexahedra; ++i_hexahedron, ++i_cell) { + cell_to_node_row[i_cell + 1] = cell_to_node_row[i_cell] + 8; + } + for (size_t i_prism = 0; i_prism < nb_prisms; ++i_prism, ++i_cell) { + cell_to_node_row[i_cell + 1] = cell_to_node_row[i_cell] + 6; + } + for (size_t i_pyramid = 0; i_pyramid < nb_pyramids; ++i_pyramid, ++i_cell) { + cell_to_node_row[i_cell + 1] = cell_to_node_row[i_cell] + 5; + } + } + + Array<unsigned int> cell_to_node_list(cell_to_node_row[cell_to_node_row.size() - 1]); + { + size_t i_cell_node = 0; + for (size_t i_tetrahedron = 0; i_tetrahedron < nb_tetrahedra; ++i_tetrahedron) { + cell_to_node_list[i_cell_node++] = gmsh_data.__tetrahedra[i_tetrahedron][0]; + cell_to_node_list[i_cell_node++] = gmsh_data.__tetrahedra[i_tetrahedron][1]; + cell_to_node_list[i_cell_node++] = gmsh_data.__tetrahedra[i_tetrahedron][2]; + cell_to_node_list[i_cell_node++] = gmsh_data.__tetrahedra[i_tetrahedron][3]; + } + for (size_t i_hexahedron = 0; i_hexahedron < nb_hexahedra; ++i_hexahedron) { + cell_to_node_list[i_cell_node++] = gmsh_data.__hexahedra[i_hexahedron][0]; + cell_to_node_list[i_cell_node++] = gmsh_data.__hexahedra[i_hexahedron][1]; + cell_to_node_list[i_cell_node++] = gmsh_data.__hexahedra[i_hexahedron][2]; + cell_to_node_list[i_cell_node++] = gmsh_data.__hexahedra[i_hexahedron][3]; + cell_to_node_list[i_cell_node++] = gmsh_data.__hexahedra[i_hexahedron][4]; + cell_to_node_list[i_cell_node++] = gmsh_data.__hexahedra[i_hexahedron][5]; + cell_to_node_list[i_cell_node++] = gmsh_data.__hexahedra[i_hexahedron][6]; + cell_to_node_list[i_cell_node++] = gmsh_data.__hexahedra[i_hexahedron][7]; + } + for (size_t i_prism = 0; i_prism < nb_prisms; ++i_prism) { + cell_to_node_list[i_cell_node++] = gmsh_data.__prisms[i_prism][0]; + cell_to_node_list[i_cell_node++] = gmsh_data.__prisms[i_prism][1]; + cell_to_node_list[i_cell_node++] = gmsh_data.__prisms[i_prism][2]; + cell_to_node_list[i_cell_node++] = gmsh_data.__prisms[i_prism][3]; + cell_to_node_list[i_cell_node++] = gmsh_data.__prisms[i_prism][4]; + cell_to_node_list[i_cell_node++] = gmsh_data.__prisms[i_prism][5]; + } + for (size_t i_pyramid = 0; i_pyramid < nb_pyramids; ++i_pyramid) { + cell_to_node_list[i_cell_node++] = gmsh_data.__pyramids[i_pyramid][0]; + cell_to_node_list[i_cell_node++] = gmsh_data.__pyramids[i_pyramid][1]; + cell_to_node_list[i_cell_node++] = gmsh_data.__pyramids[i_pyramid][2]; + cell_to_node_list[i_cell_node++] = gmsh_data.__pyramids[i_pyramid][3]; + cell_to_node_list[i_cell_node++] = gmsh_data.__pyramids[i_pyramid][4]; } - descriptor.cell_type_vector[j] = CellType::Tetrahedron; - descriptor.cell_number_vector[j] = gmsh_data.__tetrahedra_number[j]; } - const size_t nb_hexahedra = gmsh_data.__hexahedra.size(); + for (size_t j = 0; j < nb_tetrahedra; ++j) { + cell_type_vector[j] = CellType::Tetrahedron; + cell_number_vector[j] = gmsh_data.__tetrahedra_number[j]; + } + for (size_t j = 0; j < nb_hexahedra; ++j) { const size_t jh = nb_tetrahedra + j; - descriptor.cell_to_node_vector[jh].resize(8); - for (int r = 0; r < 8; ++r) { - descriptor.cell_to_node_vector[jh][r] = gmsh_data.__hexahedra[j][r]; - } - descriptor.cell_type_vector[jh] = CellType::Hexahedron; - descriptor.cell_number_vector[jh] = gmsh_data.__hexahedra_number[j]; + + cell_type_vector[jh] = CellType::Hexahedron; + cell_number_vector[jh] = gmsh_data.__hexahedra_number[j]; } - const size_t nb_prisms = gmsh_data.__prisms.size(); for (size_t j = 0; j < nb_prisms; ++j) { const size_t jp = nb_tetrahedra + nb_hexahedra + j; - descriptor.cell_to_node_vector[jp].resize(6); - for (int r = 0; r < 6; ++r) { - descriptor.cell_to_node_vector[jp][r] = gmsh_data.__prisms[j][r]; - } - descriptor.cell_type_vector[jp] = CellType::Prism; - descriptor.cell_number_vector[jp] = gmsh_data.__prisms_number[j]; + + cell_type_vector[jp] = CellType::Prism; + cell_number_vector[jp] = gmsh_data.__prisms_number[j]; } - const size_t nb_pyramids = gmsh_data.__pyramids.size(); for (size_t j = 0; j < nb_pyramids; ++j) { const size_t jh = nb_tetrahedra + nb_hexahedra + nb_prisms + j; - descriptor.cell_to_node_vector[jh].resize(5); - for (int r = 0; r < 5; ++r) { - descriptor.cell_to_node_vector[jh][r] = gmsh_data.__pyramids[j][r]; - } - descriptor.cell_type_vector[jh] = CellType::Pyramid; - descriptor.cell_number_vector[jh] = gmsh_data.__pyramids_number[j]; + + cell_type_vector[jh] = CellType::Pyramid; + cell_number_vector[jh] = gmsh_data.__pyramids_number[j]; } + descriptor.setCellNumberVector(cell_number_vector); + descriptor.setCellTypeVector(cell_type_vector); + descriptor.setCellToNodeMatrix(ConnectivityMatrix(cell_to_node_row, cell_to_node_list)); + std::map<unsigned int, std::vector<unsigned int>> ref_cells_map; for (unsigned int j = 0; j < gmsh_data.__tetrahedra_ref.size(); ++j) { const unsigned int elem_number = j; @@ -429,103 +535,140 @@ GmshConnectivityBuilder<3>::GmshConnectivityBuilder(const GmshReader::GmshData& ConnectivityBuilderBase::_computeCellFaceAndFaceNodeConnectivities<3>(descriptor); - const auto& node_number_vector = descriptor.node_number_vector; + const auto& node_number_vector = descriptor.nodeNumberVector(); - Array<size_t> face_nb_cell(descriptor.face_number_vector.size()); + Array<size_t> face_nb_cell(descriptor.faceNumberVector().size()); face_nb_cell.fill(0); - for (size_t j = 0; j < descriptor.cell_to_face_vector.size(); ++j) { - for (size_t l = 0; l < descriptor.cell_to_face_vector[j].size(); ++l) { - face_nb_cell[descriptor.cell_to_face_vector[j][l]] += 1; + const auto& cell_to_face_matrix = descriptor.cellToFaceMatrix(); + + for (size_t j = 0; j < cell_to_face_matrix.numberOfRows(); ++j) { + const auto& cell_face_list = cell_to_face_matrix[j]; + for (size_t l = 0; l < cell_face_list.size(); ++l) { + face_nb_cell[cell_face_list[l]] += 1; } } + const auto& face_number_vector = descriptor.faceNumberVector(); { - using Face = ConnectivityFace<3>; - const std::unordered_map<Face, FaceId, typename Face::Hash> face_to_id_map = [&] { - std::unordered_map<Face, FaceId, typename Face::Hash> face_to_id_map; - for (FaceId l = 0; l < descriptor.face_to_node_vector.size(); ++l) { - const auto& node_vector = descriptor.face_to_node_vector[l]; - face_to_id_map[Face(node_vector, node_number_vector)] = l; - } - return face_to_id_map; - }(); - std::unordered_map<int, FaceId> face_number_id_map = [&] { std::unordered_map<int, FaceId> face_number_id_map; - for (size_t l = 0; l < descriptor.face_number_vector.size(); ++l) { - face_number_id_map[descriptor.face_number_vector[l]] = l; + for (size_t l = 0; l < face_number_vector.size(); ++l) { + face_number_id_map[face_number_vector[l]] = l; } - Assert(face_number_id_map.size() == descriptor.face_number_vector.size()); + Assert(face_number_id_map.size() == face_number_vector.size()); return face_number_id_map; }(); + const auto& node_to_face_matrix = descriptor.nodeToFaceMatrix(); + const auto& face_to_node_matrix = descriptor.faceToNodeMatrix(); + + const auto find_face = [&](std::vector<uint32_t> node_list) { + size_t i_node_smallest_number = 0; + for (size_t i_node = 1; i_node < node_list.size(); ++i_node) { + if (node_number_vector[node_list[i_node]] < node_number_vector[node_list[i_node_smallest_number]]) { + i_node_smallest_number = i_node; + } + } + + if (i_node_smallest_number != 0) { + std::vector<uint64_t> buffer(node_list.size()); + for (size_t i_node = i_node_smallest_number; i_node < buffer.size(); ++i_node) { + buffer[i_node - i_node_smallest_number] = node_list[i_node]; + } + for (size_t i_node = 0; i_node < i_node_smallest_number; ++i_node) { + buffer[i_node + node_list.size() - i_node_smallest_number] = node_list[i_node]; + } + + for (size_t i_node = 0; i_node < node_list.size(); ++i_node) { + node_list[i_node] = buffer[i_node]; + } + } + + if (node_number_vector[node_list[1]] > node_number_vector[node_list[node_list.size() - 1]]) { + for (size_t i_node = 1; i_node <= (node_list.size() + 1) / 2 - 1; ++i_node) { + std::swap(node_list[i_node], node_list[node_list.size() - i_node]); + } + } + + const auto& face_id_vector = node_to_face_matrix[node_list[0]]; + + for (size_t i_face = 0; i_face < face_id_vector.size(); ++i_face) { + const FaceId face_id = face_id_vector[i_face]; + const auto& face_node_id_list = face_to_node_matrix[face_id]; + if (face_node_id_list.size() == node_list.size()) { + bool is_same = true; + for (size_t i_node = 1; i_node < face_node_id_list.size(); ++i_node) { + is_same &= (face_node_id_list[i_node] == node_list[i_node]); + } + if (is_same) { + return face_id; + } + } + } + + std::stringstream error_msg; + error_msg << "face (" << node_list[0]; + for (size_t i = 1; i < node_list.size(); ++i) { + error_msg << ',' << node_list[i]; + } + error_msg << ") not found"; + throw NormalError(error_msg.str()); + }; + + Array<int> face_number_vector = copy(descriptor.faceNumberVector()); std::map<unsigned int, std::vector<unsigned int>> ref_faces_map; for (unsigned int f = 0; f < gmsh_data.__triangles.size(); ++f) { - const unsigned int face_id = [&] { - auto i = face_to_id_map.find( - Face({gmsh_data.__triangles[f][0], gmsh_data.__triangles[f][1], gmsh_data.__triangles[f][2]}, - node_number_vector)); - if (i == face_to_id_map.end()) { - throw NormalError("face not found"); - } - return i->second; - }(); + const unsigned int face_id = + find_face({gmsh_data.__triangles[f][0], gmsh_data.__triangles[f][1], gmsh_data.__triangles[f][2]}); const unsigned int& ref = gmsh_data.__triangles_ref[f]; ref_faces_map[ref].push_back(face_id); - if (descriptor.face_number_vector[face_id] != gmsh_data.__triangles_number[f]) { + if (face_number_vector[face_id] != gmsh_data.__triangles_number[f]) { if (auto i_face = face_number_id_map.find(gmsh_data.__triangles_number[f]); i_face != face_number_id_map.end()) { const int other_face_id = i_face->second; - std::swap(descriptor.face_number_vector[face_id], descriptor.face_number_vector[other_face_id]); + std::swap(face_number_vector[face_id], face_number_vector[other_face_id]); - face_number_id_map.erase(descriptor.face_number_vector[face_id]); - face_number_id_map.erase(descriptor.face_number_vector[other_face_id]); + face_number_id_map.erase(face_number_vector[face_id]); + face_number_id_map.erase(face_number_vector[other_face_id]); - face_number_id_map[descriptor.face_number_vector[face_id]] = face_id; - face_number_id_map[descriptor.face_number_vector[other_face_id]] = other_face_id; + face_number_id_map[face_number_vector[face_id]] = face_id; + face_number_id_map[face_number_vector[other_face_id]] = other_face_id; } else { - face_number_id_map.erase(descriptor.face_number_vector[face_id]); - descriptor.face_number_vector[face_id] = gmsh_data.__triangles_number[f]; - face_number_id_map[descriptor.face_number_vector[face_id]] = face_id; + face_number_id_map.erase(face_number_vector[face_id]); + face_number_vector[face_id] = gmsh_data.__triangles_number[f]; + face_number_id_map[face_number_vector[face_id]] = face_id; } } } for (unsigned int f = 0; f < gmsh_data.__quadrangles.size(); ++f) { - const unsigned int face_id = [&] { - auto i = face_to_id_map.find(Face({gmsh_data.__quadrangles[f][0], gmsh_data.__quadrangles[f][1], - gmsh_data.__quadrangles[f][2], gmsh_data.__quadrangles[f][3]}, - node_number_vector)); - if (i == face_to_id_map.end()) { - throw NormalError("face not found"); - } - return i->second; - }(); + const unsigned int face_id = find_face({gmsh_data.__quadrangles[f][0], gmsh_data.__quadrangles[f][1], + gmsh_data.__quadrangles[f][2], gmsh_data.__quadrangles[f][3]}); const unsigned int& ref = gmsh_data.__quadrangles_ref[f]; ref_faces_map[ref].push_back(face_id); - - if (descriptor.face_number_vector[face_id] != gmsh_data.__quadrangles_number[f]) { + if (face_number_vector[face_id] != gmsh_data.__quadrangles_number[f]) { if (auto i_face = face_number_id_map.find(gmsh_data.__quadrangles_number[f]); i_face != face_number_id_map.end()) { const int other_face_id = i_face->second; - std::swap(descriptor.face_number_vector[face_id], descriptor.face_number_vector[other_face_id]); + std::swap(face_number_vector[face_id], face_number_vector[other_face_id]); - face_number_id_map.erase(descriptor.face_number_vector[face_id]); - face_number_id_map.erase(descriptor.face_number_vector[other_face_id]); + face_number_id_map.erase(face_number_vector[face_id]); + face_number_id_map.erase(face_number_vector[other_face_id]); - face_number_id_map[descriptor.face_number_vector[face_id]] = face_id; - face_number_id_map[descriptor.face_number_vector[other_face_id]] = other_face_id; + face_number_id_map[face_number_vector[face_id]] = face_id; + face_number_id_map[face_number_vector[other_face_id]] = other_face_id; } else { - face_number_id_map.erase(descriptor.face_number_vector[face_id]); - descriptor.face_number_vector[face_id] = gmsh_data.__quadrangles_number[f]; - face_number_id_map[descriptor.face_number_vector[face_id]] = face_id; + face_number_id_map.erase(face_number_vector[face_id]); + face_number_vector[face_id] = gmsh_data.__quadrangles_number[f]; + face_number_id_map[face_number_vector[face_id]] = face_id; } } } + descriptor.setFaceNumberVector(face_number_vector); for (const auto& ref_face_list : ref_faces_map) { Array<FaceId> face_list(ref_face_list.second.size()); @@ -556,68 +699,76 @@ GmshConnectivityBuilder<3>::GmshConnectivityBuilder(const GmshReader::GmshData& ConnectivityBuilderBase::_computeFaceEdgeAndEdgeNodeAndCellEdgeConnectivities<3>(descriptor); { - Array<bool> is_boundary_edge(descriptor.edge_number_vector.size()); + Array<bool> is_boundary_edge(descriptor.edgeNumberVector().size()); is_boundary_edge.fill(false); + const auto& face_to_edge_matrix = descriptor.faceToEdgeMatrix(); + for (size_t i_face = 0; i_face < face_nb_cell.size(); ++i_face) { if (face_nb_cell[i_face] == 1) { - for (size_t node_id : descriptor.face_to_edge_vector[i_face]) { - is_boundary_edge[node_id] = true; + auto face_edge_list = face_to_edge_matrix[i_face]; + for (size_t i_edge = 0; i_edge < face_edge_list.size(); ++i_edge) { + is_boundary_edge[face_edge_list[i_edge]] = true; } } } - using Edge = ConnectivityFace<2>; - const auto& node_number_vector = descriptor.node_number_vector; - const std::unordered_map<Edge, EdgeId, typename Edge::Hash> edge_to_id_map = [&] { - std::unordered_map<Edge, EdgeId, typename Edge::Hash> edge_to_id_map; - for (EdgeId l = 0; l < descriptor.edge_to_node_vector.size(); ++l) { - const auto& node_vector = descriptor.edge_to_node_vector[l]; - edge_to_id_map[Edge(node_vector, node_number_vector)] = l; + const auto& node_to_edge_matrix = descriptor.nodeToEdgeMatrix(); + const auto& edge_to_node_matrix = descriptor.edgeToNodeMatrix(); + + const auto find_edge = [&](uint32_t node0, uint32_t node1) { + if (node_number_vector[node0] > node_number_vector[node1]) { + std::swap(node0, node1); } - return edge_to_id_map; - }(); + const auto& edge_id_vector = node_to_edge_matrix[node0]; + + for (size_t i_edge = 0; i_edge < edge_id_vector.size(); ++i_edge) { + const EdgeId edge_id = edge_id_vector[i_edge]; + if (edge_to_node_matrix[edge_id][1] == node1) { + return edge_id; + } + } + + std::stringstream error_msg; + error_msg << "edge (" << node0 << ',' << node1 << ") not found"; + throw NormalError(error_msg.str()); + }; std::unordered_map<int, EdgeId> edge_number_id_map = [&] { + const auto& edge_number_vector = descriptor.edgeNumberVector(); std::unordered_map<int, EdgeId> edge_number_id_map; - for (size_t l = 0; l < descriptor.edge_number_vector.size(); ++l) { - edge_number_id_map[descriptor.edge_number_vector[l]] = l; + for (size_t l = 0; l < edge_number_vector.size(); ++l) { + edge_number_id_map[edge_number_vector[l]] = l; } - Assert(edge_number_id_map.size() == descriptor.edge_number_vector.size()); + Assert(edge_number_id_map.size() == edge_number_vector.size()); return edge_number_id_map; }(); + Array<int> edge_number_vector = copy(descriptor.edgeNumberVector()); std::map<unsigned int, std::vector<unsigned int>> ref_edges_map; for (unsigned int e = 0; e < gmsh_data.__edges.size(); ++e) { - const unsigned int edge_id = [&] { - auto i = edge_to_id_map.find(Edge({gmsh_data.__edges[e][0], gmsh_data.__edges[e][1]}, node_number_vector)); - if (i == edge_to_id_map.end()) { - std::stringstream error_msg; - error_msg << "edge " << gmsh_data.__edges[e][0] << " not found"; - throw NormalError(error_msg.str()); - } - return i->second; - }(); - const unsigned int& ref = gmsh_data.__edges_ref[e]; + const unsigned int edge_id = find_edge(gmsh_data.__edges[e][0], gmsh_data.__edges[e][1]); + const unsigned int& ref = gmsh_data.__edges_ref[e]; ref_edges_map[ref].push_back(edge_id); - if (descriptor.edge_number_vector[edge_id] != gmsh_data.__edges_number[e]) { + if (edge_number_vector[edge_id] != gmsh_data.__edges_number[e]) { if (auto i_edge = edge_number_id_map.find(gmsh_data.__edges_number[e]); i_edge != edge_number_id_map.end()) { const int other_edge_id = i_edge->second; - std::swap(descriptor.edge_number_vector[edge_id], descriptor.edge_number_vector[other_edge_id]); + std::swap(edge_number_vector[edge_id], edge_number_vector[other_edge_id]); - edge_number_id_map.erase(descriptor.edge_number_vector[edge_id]); - edge_number_id_map.erase(descriptor.edge_number_vector[other_edge_id]); + edge_number_id_map.erase(edge_number_vector[edge_id]); + edge_number_id_map.erase(edge_number_vector[other_edge_id]); - edge_number_id_map[descriptor.edge_number_vector[edge_id]] = edge_id; - edge_number_id_map[descriptor.edge_number_vector[other_edge_id]] = other_edge_id; + edge_number_id_map[edge_number_vector[edge_id]] = edge_id; + edge_number_id_map[edge_number_vector[other_edge_id]] = other_edge_id; } else { - edge_number_id_map.erase(descriptor.edge_number_vector[edge_id]); - descriptor.edge_number_vector[edge_id] = gmsh_data.__edges_number[e]; - edge_number_id_map[descriptor.edge_number_vector[edge_id]] = edge_id; + edge_number_id_map.erase(edge_number_vector[edge_id]); + edge_number_vector[edge_id] = gmsh_data.__edges_number[e]; + edge_number_id_map[edge_number_vector[edge_id]] = edge_id; } } } + descriptor.setEdgeNumberVector(edge_number_vector); for (const auto& ref_edge_list : ref_edges_map) { Array<EdgeId> edge_list(ref_edge_list.second.size()); @@ -645,12 +796,16 @@ GmshConnectivityBuilder<3>::GmshConnectivityBuilder(const GmshReader::GmshData& } } - Array<bool> is_boundary_node(descriptor.node_number_vector.size()); + Array<bool> is_boundary_node(node_number_vector.size()); is_boundary_node.fill(false); + const auto& face_to_node_matrix = descriptor.faceToNodeMatrix(); + for (size_t i_face = 0; i_face < face_nb_cell.size(); ++i_face) { if (face_nb_cell[i_face] == 1) { - for (size_t node_id : descriptor.face_to_node_vector[i_face]) { + const auto& face_node_list = face_to_node_matrix[i_face]; + for (size_t i_node = 0; i_node < face_node_list.size(); ++i_node) { + const NodeId node_id = face_node_list[i_node]; is_boundary_node[node_id] = true; } } @@ -688,17 +843,29 @@ GmshConnectivityBuilder<3>::GmshConnectivityBuilder(const GmshReader::GmshData& descriptor.addRefItemList(RefNodeList(ref_id, point_list, is_boundary)); } - descriptor.cell_owner_vector.resize(nb_cells); - std::fill(descriptor.cell_owner_vector.begin(), descriptor.cell_owner_vector.end(), parallel::rank()); - - descriptor.face_owner_vector.resize(descriptor.face_number_vector.size()); - std::fill(descriptor.face_owner_vector.begin(), descriptor.face_owner_vector.end(), parallel::rank()); - - descriptor.edge_owner_vector.resize(descriptor.edge_number_vector.size()); - std::fill(descriptor.edge_owner_vector.begin(), descriptor.edge_owner_vector.end(), parallel::rank()); - - descriptor.node_owner_vector.resize(descriptor.node_number_vector.size()); - std::fill(descriptor.node_owner_vector.begin(), descriptor.node_owner_vector.end(), parallel::rank()); + descriptor.setCellOwnerVector([&] { + Array<int> cell_owner_vector(nb_cells); + cell_owner_vector.fill(parallel::rank()); + return cell_owner_vector; + }()); + + descriptor.setFaceOwnerVector([&] { + Array<int> face_owner_vector(descriptor.faceNumberVector().size()); + face_owner_vector.fill(parallel::rank()); + return face_owner_vector; + }()); + + descriptor.setEdgeOwnerVector([&] { + Array<int> edge_owner_vector(descriptor.edgeNumberVector().size()); + edge_owner_vector.fill(parallel::rank()); + return edge_owner_vector; + }()); + + descriptor.setNodeOwnerVector([&] { + Array<int> node_owner_vector(node_number_vector.size()); + node_owner_vector.fill(parallel::rank()); + return node_owner_vector; + }()); m_connectivity = Connectivity3D::build(descriptor); } @@ -958,255 +1125,6 @@ GmshReader::__readPeriodic2_2() } } -// std::shared_ptr<IConnectivity> -// GmshReader::_buildConnectivity3D(const size_t nb_cells) -// { -// ConnectivityDescriptor descriptor; - -// descriptor.node_number_vector = m_mesh_data.__verticesNumbers; -// descriptor.cell_type_vector.resize(nb_cells); -// descriptor.cell_number_vector.resize(nb_cells); -// descriptor.cell_to_node_vector.resize(nb_cells); - -// const size_t nb_tetrahedra = m_mesh_data.__tetrahedra.size(); -// for (size_t j = 0; j < nb_tetrahedra; ++j) { -// descriptor.cell_to_node_vector[j].resize(4); -// for (int r = 0; r < 4; ++r) { -// descriptor.cell_to_node_vector[j][r] = m_mesh_data.__tetrahedra[j][r]; -// } -// descriptor.cell_type_vector[j] = CellType::Tetrahedron; -// descriptor.cell_number_vector[j] = m_mesh_data.__tetrahedra_number[j]; -// } -// const size_t nb_hexahedra = m_mesh_data.__hexahedra.size(); -// for (size_t j = 0; j < nb_hexahedra; ++j) { -// const size_t jh = nb_tetrahedra + j; -// descriptor.cell_to_node_vector[jh].resize(8); -// for (int r = 0; r < 8; ++r) { -// descriptor.cell_to_node_vector[jh][r] = m_mesh_data.__hexahedra[j][r]; -// } -// descriptor.cell_type_vector[jh] = CellType::Hexahedron; -// descriptor.cell_number_vector[jh] = m_mesh_data.__hexahedra_number[j]; -// } - -// std::map<unsigned int, std::vector<unsigned int>> ref_cells_map; -// for (unsigned int r = 0; r < m_mesh_data.__tetrahedra_ref.size(); ++r) { -// const unsigned int elem_number = m_mesh_data.__tetrahedra_ref[r]; -// const unsigned int& ref = m_mesh_data.__tetrahedra_ref[r]; -// ref_cells_map[ref].push_back(elem_number); -// } - -// for (unsigned int j = 0; j < m_mesh_data.__hexahedra_ref.size(); ++j) { -// const size_t elem_number = nb_tetrahedra + j; -// const unsigned int& ref = m_mesh_data.__hexahedra_ref[j]; -// ref_cells_map[ref].push_back(elem_number); -// } - -// for (const auto& ref_cell_list : ref_cells_map) { -// Array<CellId> cell_list(ref_cell_list.second.size()); -// for (size_t j = 0; j < ref_cell_list.second.size(); ++j) { -// cell_list[j] = ref_cell_list.second[j]; -// } -// const PhysicalRefId& physical_ref_id = m_mesh_data.m_physical_ref_map.at(ref_cell_list.first); -// descriptor.addRefItemList(RefCellList(physical_ref_id.refId(), cell_list)); -// } - -// ConnectivityBuilderBase::_computeCellFaceAndFaceNodeConnectivities<3>(descriptor); - -// const auto& node_number_vector = descriptor.node_number_vector; - -// { -// using Face = ConnectivityFace<3>; -// const std::unordered_map<Face, FaceId, typename Face::Hash> face_to_id_map = [&] { -// std::unordered_map<Face, FaceId, typename Face::Hash> face_to_id_map; -// for (FaceId l = 0; l < descriptor.face_to_node_vector.size(); ++l) { -// const auto& node_vector = descriptor.face_to_node_vector[l]; -// face_to_id_map[Face(node_vector, node_number_vector)] = l; -// } -// return face_to_id_map; -// }(); - -// std::unordered_map<int, FaceId> face_number_id_map = [&] { -// std::unordered_map<int, FaceId> face_number_id_map; -// for (size_t l = 0; l < descriptor.face_number_vector.size(); ++l) { -// face_number_id_map[descriptor.face_number_vector[l]] = l; -// } -// Assert(face_number_id_map.size() == descriptor.face_number_vector.size()); -// return face_number_id_map; -// }(); - -// std::map<unsigned int, std::vector<unsigned int>> ref_faces_map; -// for (unsigned int f = 0; f < m_mesh_data.__triangles.size(); ++f) { -// const unsigned int face_id = [&] { -// auto i = face_to_id_map.find( -// Face({m_mesh_data.__triangles[f][0], m_mesh_data.__triangles[f][1], m_mesh_data.__triangles[f][2]}, -// node_number_vector)); -// if (i == face_to_id_map.end()) { -// throw NormalError("face not found"); -// } -// return i->second; -// }(); - -// const unsigned int& ref = m_mesh_data.__triangles_ref[f]; -// ref_faces_map[ref].push_back(face_id); - -// if (descriptor.face_number_vector[face_id] != m_mesh_data.__quadrangles_number[f]) { -// if (auto i_face = face_number_id_map.find(m_mesh_data.__quadrangles_number[f]); -// i_face != face_number_id_map.end()) { -// const int other_face_id = i_face->second; -// std::swap(descriptor.face_number_vector[face_id], descriptor.face_number_vector[other_face_id]); - -// face_number_id_map.erase(descriptor.face_number_vector[face_id]); -// face_number_id_map.erase(descriptor.face_number_vector[other_face_id]); - -// face_number_id_map[descriptor.face_number_vector[face_id]] = face_id; -// face_number_id_map[descriptor.face_number_vector[other_face_id]] = other_face_id; -// } else { -// face_number_id_map.erase(descriptor.face_number_vector[face_id]); -// descriptor.face_number_vector[face_id] = m_mesh_data.__quadrangles_number[f]; -// face_number_id_map[descriptor.face_number_vector[face_id]] = face_id; -// } -// } -// } - -// for (unsigned int f = 0; f < m_mesh_data.__quadrangles.size(); ++f) { -// const unsigned int face_id = [&] { -// auto i = face_to_id_map.find(Face({m_mesh_data.__quadrangles[f][0], m_mesh_data.__quadrangles[f][1], -// m_mesh_data.__quadrangles[f][2], m_mesh_data.__quadrangles[f][3]}, -// node_number_vector)); -// if (i == face_to_id_map.end()) { -// throw NormalError("face not found"); -// } -// return i->second; -// }(); - -// const unsigned int& ref = m_mesh_data.__quadrangles_ref[f]; -// ref_faces_map[ref].push_back(face_id); - -// if (descriptor.face_number_vector[face_id] != m_mesh_data.__quadrangles_number[f]) { -// if (auto i_face = face_number_id_map.find(m_mesh_data.__quadrangles_number[f]); -// i_face != face_number_id_map.end()) { -// const int other_face_id = i_face->second; -// std::swap(descriptor.face_number_vector[face_id], descriptor.face_number_vector[other_face_id]); - -// face_number_id_map.erase(descriptor.face_number_vector[face_id]); -// face_number_id_map.erase(descriptor.face_number_vector[other_face_id]); - -// face_number_id_map[descriptor.face_number_vector[face_id]] = face_id; -// face_number_id_map[descriptor.face_number_vector[other_face_id]] = other_face_id; -// } else { -// face_number_id_map.erase(descriptor.face_number_vector[face_id]); -// descriptor.face_number_vector[face_id] = m_mesh_data.__quadrangles_number[f]; -// face_number_id_map[descriptor.face_number_vector[face_id]] = face_id; -// } -// } -// } - -// for (const auto& ref_face_list : ref_faces_map) { -// Array<FaceId> face_list(ref_face_list.second.size()); -// for (size_t j = 0; j < ref_face_list.second.size(); ++j) { -// face_list[j] = ref_face_list.second[j]; -// } -// const PhysicalRefId& physical_ref_id = m_mesh_data.m_physical_ref_map.at(ref_face_list.first); -// descriptor.addRefItemList(RefFaceList{physical_ref_id.refId(), face_list}); -// } -// } - -// ConnectivityBuilderBase::_computeFaceEdgeAndEdgeNodeAndCellEdgeConnectivities<3>(descriptor); - -// { -// using Edge = ConnectivityFace<2>; -// const auto& node_number_vector = descriptor.node_number_vector; -// const std::unordered_map<Edge, EdgeId, typename Edge::Hash> edge_to_id_map = [&] { -// std::unordered_map<Edge, EdgeId, typename Edge::Hash> edge_to_id_map; -// for (EdgeId l = 0; l < descriptor.edge_to_node_vector.size(); ++l) { -// const auto& node_vector = descriptor.edge_to_node_vector[l]; -// edge_to_id_map[Edge(node_vector, node_number_vector)] = l; -// } -// return edge_to_id_map; -// }(); - -// std::unordered_map<int, EdgeId> edge_number_id_map = [&] { -// std::unordered_map<int, EdgeId> edge_number_id_map; -// for (size_t l = 0; l < descriptor.edge_number_vector.size(); ++l) { -// edge_number_id_map[descriptor.edge_number_vector[l]] = l; -// } -// Assert(edge_number_id_map.size() == descriptor.edge_number_vector.size()); -// return edge_number_id_map; -// }(); - -// std::map<unsigned int, std::vector<unsigned int>> ref_edges_map; -// for (unsigned int e = 0; e < m_mesh_data.__edges.size(); ++e) { -// const unsigned int edge_id = [&] { -// auto i = edge_to_id_map.find(Edge({m_mesh_data.__edges[e][0], m_mesh_data.__edges[e][1]}, -// node_number_vector)); if (i == edge_to_id_map.end()) { -// std::stringstream error_msg; -// error_msg << "edge " << m_mesh_data.__edges[e][0] << " not found"; -// throw NormalError(error_msg.str()); -// } -// return i->second; -// }(); -// const unsigned int& ref = m_mesh_data.__edges_ref[e]; -// ref_edges_map[ref].push_back(edge_id); - -// if (descriptor.edge_number_vector[edge_id] != m_mesh_data.__edges_number[e]) { -// if (auto i_edge = edge_number_id_map.find(m_mesh_data.__edges_number[e]); i_edge != edge_number_id_map.end()) -// { -// const int other_edge_id = i_edge->second; -// std::swap(descriptor.edge_number_vector[edge_id], descriptor.edge_number_vector[other_edge_id]); - -// edge_number_id_map.erase(descriptor.edge_number_vector[edge_id]); -// edge_number_id_map.erase(descriptor.edge_number_vector[other_edge_id]); - -// edge_number_id_map[descriptor.edge_number_vector[edge_id]] = edge_id; -// edge_number_id_map[descriptor.edge_number_vector[other_edge_id]] = other_edge_id; -// } else { -// edge_number_id_map.erase(descriptor.edge_number_vector[edge_id]); -// descriptor.edge_number_vector[edge_id] = m_mesh_data.__edges_number[e]; -// edge_number_id_map[descriptor.edge_number_vector[edge_id]] = edge_id; -// } -// } -// } - -// for (const auto& ref_edge_list : ref_edges_map) { -// Array<EdgeId> edge_list(ref_edge_list.second.size()); -// for (size_t j = 0; j < ref_edge_list.second.size(); ++j) { -// edge_list[j] = ref_edge_list.second[j]; -// } -// const PhysicalRefId& physical_ref_id = m_mesh_data.m_physical_ref_map.at(ref_edge_list.first); -// descriptor.addRefItemList(RefEdgeList{physical_ref_id.refId(), edge_list}); -// } -// } - -// std::map<unsigned int, std::vector<unsigned int>> ref_points_map; -// for (unsigned int r = 0; r < m_mesh_data.__points.size(); ++r) { -// const unsigned int point_number = m_mesh_data.__points[r]; -// const unsigned int& ref = m_mesh_data.__points_ref[r]; -// ref_points_map[ref].push_back(point_number); -// } - -// for (const auto& ref_point_list : ref_points_map) { -// Array<NodeId> point_list(ref_point_list.second.size()); -// for (size_t j = 0; j < ref_point_list.second.size(); ++j) { -// point_list[j] = ref_point_list.second[j]; -// } -// const PhysicalRefId& physical_ref_id = m_mesh_data.m_physical_ref_map.at(ref_point_list.first); -// descriptor.addRefItemList(RefNodeList(physical_ref_id.refId(), point_list)); -// } - -// descriptor.cell_owner_vector.resize(nb_cells); -// std::fill(descriptor.cell_owner_vector.begin(), descriptor.cell_owner_vector.end(), parallel::rank()); - -// descriptor.face_owner_vector.resize(descriptor.face_number_vector.size()); -// std::fill(descriptor.face_owner_vector.begin(), descriptor.face_owner_vector.end(), parallel::rank());// -// descriptor.edge_owner_vector.resize(descriptor.edge_number_vector.size()); -// std::fill(descriptor.edge_owner_vector.begin(), descriptor.edge_owner_vector.end(), parallel::rank()); - -// descriptor.node_owner_vector.resize(descriptor.node_number_vector.size()); -// std::fill(descriptor.node_owner_vector.begin(), descriptor.node_owner_vector.end(), parallel::rank()); - -// return Connectivity3D::build(descriptor); -// } - void GmshReader::__proceedData() { diff --git a/src/mesh/LogicalConnectivityBuilder.cpp b/src/mesh/LogicalConnectivityBuilder.cpp index 41092faaf90a9a3f9a24ac1c561304373ba748d0..dbc41d0681e9ceda822a5896af97ace2e3572f03 100644 --- a/src/mesh/LogicalConnectivityBuilder.cpp +++ b/src/mesh/LogicalConnectivityBuilder.cpp @@ -141,28 +141,27 @@ void LogicalConnectivityBuilder::_buildBoundaryEdgeList(const TinyVector<3, uint64_t>& cell_size, ConnectivityDescriptor& descriptor) { - using Edge = ConnectivityFace<2>; - const auto& node_number_vector = descriptor.node_number_vector; - const std::unordered_map<Edge, EdgeId, typename Edge::Hash> edge_to_id_map = [&] { - std::unordered_map<Edge, EdgeId, typename Edge::Hash> edge_to_id_map; - for (EdgeId l = 0; l < descriptor.edge_to_node_vector.size(); ++l) { - const auto& node_vector = descriptor.edge_to_node_vector[l]; - edge_to_id_map[Edge(node_vector, node_number_vector)] = l; + const auto& node_number_vector = descriptor.nodeNumberVector(); + const auto& node_to_edge_matrix = descriptor.nodeToEdgeMatrix(); + const auto& edge_to_node_matrix = descriptor.edgeToNodeMatrix(); + + const auto find_edge = [&](uint32_t node0, uint32_t node1) { + if (node_number_vector[node0] > node_number_vector[node1]) { + std::swap(node0, node1); } - return edge_to_id_map; - }(); + const auto& node_edge_list = node_to_edge_matrix[node0]; - std::unordered_map<int, EdgeId> edge_number_id_map = [&] { - std::unordered_map<int, EdgeId> edge_number_id_map; - for (size_t l = 0; l < descriptor.edge_number_vector.size(); ++l) { - edge_number_id_map[descriptor.edge_number_vector[l]] = l; + for (size_t i_edge = 0; i_edge < node_edge_list.size(); ++i_edge) { + const EdgeId edge_id = node_edge_list[i_edge]; + if (edge_to_node_matrix[edge_id][1] == node1) { + return edge_id; + } } - Assert(edge_number_id_map.size() == descriptor.edge_number_vector.size()); - return edge_number_id_map; - }(); + throw UnexpectedError("Cannot find edge"); + }; const TinyVector<3, uint64_t> node_size{cell_size[0] + 1, cell_size[1] + 1, cell_size[2] + 1}; - const auto node_number = [&](const TinyVector<3, uint64_t>& node_logic_id) { + const auto get_node_id = [&](const TinyVector<3, uint64_t>& node_logic_id) { return (node_logic_id[0] * node_size[1] + node_logic_id[1]) * node_size[2] + node_logic_id[2]; }; @@ -172,13 +171,10 @@ LogicalConnectivityBuilder::_buildBoundaryEdgeList(const TinyVector<3, uint64_t> Array<EdgeId> boundary_edges(cell_size[2]); size_t l = 0; for (size_t k = 0; k < cell_size[2]; ++k) { - const uint32_t node_0_id = node_number(TinyVector<3, uint64_t>{i, j, k}); - const uint32_t node_1_id = node_number(TinyVector<3, uint64_t>{i, j, k + 1}); - - auto i_edge = edge_to_id_map.find(Edge{{node_0_id, node_1_id}, descriptor.node_number_vector}); - Assert(i_edge != edge_to_id_map.end()); + const uint32_t node_0_id = get_node_id(TinyVector<3, uint64_t>{i, j, k}); + const uint32_t node_1_id = get_node_id(TinyVector<3, uint64_t>{i, j, k + 1}); - boundary_edges[l++] = i_edge->second; + boundary_edges[l++] = find_edge(node_0_id, node_1_id); } Assert(l == cell_size[2]); descriptor.addRefItemList(RefEdgeList{RefId{ref_id, ref_name}, boundary_edges, true}); @@ -196,13 +192,10 @@ LogicalConnectivityBuilder::_buildBoundaryEdgeList(const TinyVector<3, uint64_t> Array<EdgeId> boundary_edges(cell_size[1]); size_t l = 0; for (size_t j = 0; j < cell_size[1]; ++j) { - const uint32_t node_0_id = node_number(TinyVector<3, uint64_t>{i, j, k}); - const uint32_t node_1_id = node_number(TinyVector<3, uint64_t>{i, j + 1, k}); - - auto i_edge = edge_to_id_map.find(Edge{{node_0_id, node_1_id}, descriptor.node_number_vector}); - Assert(i_edge != edge_to_id_map.end()); + const uint32_t node_0_id = get_node_id(TinyVector<3, uint64_t>{i, j, k}); + const uint32_t node_1_id = get_node_id(TinyVector<3, uint64_t>{i, j + 1, k}); - boundary_edges[l++] = i_edge->second; + boundary_edges[l++] = find_edge(node_0_id, node_1_id); } Assert(l == cell_size[1]); descriptor.addRefItemList(RefEdgeList{RefId{ref_id, ref_name}, boundary_edges, true}); @@ -220,13 +213,10 @@ LogicalConnectivityBuilder::_buildBoundaryEdgeList(const TinyVector<3, uint64_t> Array<EdgeId> boundary_edges(cell_size[0]); size_t l = 0; for (size_t i = 0; i < cell_size[0]; ++i) { - const uint32_t node_0_id = node_number(TinyVector<3, uint64_t>{i, j, k}); - const uint32_t node_1_id = node_number(TinyVector<3, uint64_t>{i + 1, j, k}); + const uint32_t node_0_id = get_node_id(TinyVector<3, uint64_t>{i, j, k}); + const uint32_t node_1_id = get_node_id(TinyVector<3, uint64_t>{i + 1, j, k}); - auto i_edge = edge_to_id_map.find(Edge{{node_0_id, node_1_id}, descriptor.node_number_vector}); - Assert(i_edge != edge_to_id_map.end()); - - boundary_edges[l++] = i_edge->second; + boundary_edges[l++] = find_edge(node_0_id, node_1_id); } Assert(l == cell_size[0]); descriptor.addRefItemList(RefEdgeList{RefId{ref_id, ref_name}, boundary_edges, true}); @@ -256,6 +246,8 @@ LogicalConnectivityBuilder::_buildBoundaryFaceList( return cell_logic_id[0] * cell_size[1] + cell_logic_id[1]; }; + const auto& cell_to_face_matrix = descriptor.cellToFaceMatrix(); + { // xmin const size_t i = 0; Array<FaceId> boundary_faces(cell_size[1]); @@ -263,7 +255,7 @@ LogicalConnectivityBuilder::_buildBoundaryFaceList( constexpr size_t left_face = 3; const size_t cell_id = cell_number(TinyVector<2, uint64_t>{i, j}); - const size_t face_id = descriptor.cell_to_face_vector[cell_id][left_face]; + const size_t face_id = cell_to_face_matrix[cell_id][left_face]; boundary_faces[j] = face_id; } @@ -277,7 +269,7 @@ LogicalConnectivityBuilder::_buildBoundaryFaceList( constexpr size_t right_face = 1; const size_t cell_id = cell_number(TinyVector<2, uint64_t>{i, j}); - const size_t face_id = descriptor.cell_to_face_vector[cell_id][right_face]; + const size_t face_id = cell_to_face_matrix[cell_id][right_face]; boundary_faces[j] = face_id; } @@ -291,7 +283,7 @@ LogicalConnectivityBuilder::_buildBoundaryFaceList( constexpr size_t bottom_face = 0; const size_t cell_id = cell_number(TinyVector<2, uint64_t>{i, j}); - const size_t face_id = descriptor.cell_to_face_vector[cell_id][bottom_face]; + const size_t face_id = cell_to_face_matrix[cell_id][bottom_face]; boundary_faces[i] = face_id; } @@ -305,7 +297,7 @@ LogicalConnectivityBuilder::_buildBoundaryFaceList( constexpr size_t top_face = 2; const size_t cell_id = cell_number(TinyVector<2, uint64_t>{i, j}); - const size_t face_id = descriptor.cell_to_face_vector[cell_id][top_face]; + const size_t face_id = cell_to_face_matrix[cell_id][top_face]; boundary_faces[i] = face_id; } @@ -318,28 +310,53 @@ void LogicalConnectivityBuilder::_buildBoundaryFaceList(const TinyVector<3, uint64_t>& cell_size, ConnectivityDescriptor& descriptor) { - using Face = ConnectivityFace<3>; + const auto& node_number_vector = descriptor.nodeNumberVector(); + const auto& face_to_node_matrix = descriptor.faceToNodeMatrix(); + const auto& node_to_face_matrix = descriptor.nodeToFaceMatrix(); + + const auto find_face = [&](std::array<uint32_t, 4> node_list) { + size_t i_node_smallest_number = 0; + for (size_t i_node = 1; i_node < node_list.size(); ++i_node) { + if (node_number_vector[node_list[i_node]] < node_number_vector[node_list[i_node_smallest_number]]) { + i_node_smallest_number = i_node; + } + } + + if (i_node_smallest_number != 0) { + std::array<uint64_t, 4> buffer; + for (size_t i_node = i_node_smallest_number; i_node < buffer.size(); ++i_node) { + buffer[i_node - i_node_smallest_number] = node_list[i_node]; + } + for (size_t i_node = 0; i_node < i_node_smallest_number; ++i_node) { + buffer[i_node + node_list.size() - i_node_smallest_number] = node_list[i_node]; + } - const std::unordered_map<Face, FaceId, typename Face::Hash> face_to_id_map = [&] { - std::unordered_map<Face, FaceId, typename Face::Hash> face_to_id_map; - for (FaceId l = 0; l < descriptor.face_to_node_vector.size(); ++l) { - const auto& node_vector = descriptor.face_to_node_vector[l]; - face_to_id_map[Face(node_vector, descriptor.node_number_vector)] = l; + for (size_t i_node = 0; i_node < node_list.size(); ++i_node) { + node_list[i_node] = buffer[i_node]; + } } - return face_to_id_map; - }(); - const std::unordered_map<int, FaceId> face_number_id_map = [&] { - std::unordered_map<int, FaceId> face_number_id_map; - for (size_t l = 0; l < descriptor.face_number_vector.size(); ++l) { - face_number_id_map[descriptor.face_number_vector[l]] = l; + if (node_number_vector[node_list[1]] > node_number_vector[node_list[node_list.size() - 1]]) { + for (size_t i_node = 1; i_node <= (node_list.size() + 1) / 2 - 1; ++i_node) { + std::swap(node_list[i_node], node_list[node_list.size() - i_node]); + } } - Assert(face_number_id_map.size() == descriptor.face_number_vector.size()); - return face_number_id_map; - }(); + + const auto& node_face_list = node_to_face_matrix[node_list[0]]; + + for (size_t i_face = 0; i_face < node_face_list.size(); ++i_face) { + const FaceId face_id = node_face_list[i_face]; + const auto& face_node_list = face_to_node_matrix[face_id]; + if ((face_node_list[1] == node_list[1]) and (face_node_list[2] == node_list[2]) and + (face_node_list[3] == node_list[3])) { + return face_id; + } + } + throw UnexpectedError("Cannot find edge"); + }; const TinyVector<3, uint64_t> node_size{cell_size[0] + 1, cell_size[1] + 1, cell_size[2] + 1}; - const auto node_number = [&](const TinyVector<3, uint64_t>& node_logic_id) { + const auto get_node_id = [&](const TinyVector<3, uint64_t>& node_logic_id) { return (node_logic_id[0] * node_size[1] + node_logic_id[1]) * node_size[2] + node_logic_id[2]; }; @@ -349,16 +366,12 @@ LogicalConnectivityBuilder::_buildBoundaryFaceList(const TinyVector<3, uint64_t> size_t l = 0; for (size_t j = 0; j < cell_size[1]; ++j) { for (size_t k = 0; k < cell_size[2]; ++k) { - const uint32_t node_0_id = node_number(TinyVector<3, uint64_t>{i, j, k}); - const uint32_t node_1_id = node_number(TinyVector<3, uint64_t>{i, j + 1, k}); - const uint32_t node_2_id = node_number(TinyVector<3, uint64_t>{i, j + 1, k + 1}); - const uint32_t node_3_id = node_number(TinyVector<3, uint64_t>{i, j, k + 1}); + const uint32_t node_0_id = get_node_id(TinyVector<3, uint64_t>{i, j, k}); + const uint32_t node_1_id = get_node_id(TinyVector<3, uint64_t>{i, j + 1, k}); + const uint32_t node_2_id = get_node_id(TinyVector<3, uint64_t>{i, j + 1, k + 1}); + const uint32_t node_3_id = get_node_id(TinyVector<3, uint64_t>{i, j, k + 1}); - auto i_face = - face_to_id_map.find(Face{{node_0_id, node_1_id, node_2_id, node_3_id}, descriptor.node_number_vector}); - Assert(i_face != face_to_id_map.end()); - - boundary_faces[l++] = i_face->second; + boundary_faces[l++] = find_face({node_0_id, node_1_id, node_2_id, node_3_id}); } } Assert(l == cell_size[1] * cell_size[2]); @@ -375,16 +388,12 @@ LogicalConnectivityBuilder::_buildBoundaryFaceList(const TinyVector<3, uint64_t> size_t l = 0; for (size_t i = 0; i < cell_size[0]; ++i) { for (size_t k = 0; k < cell_size[2]; ++k) { - const uint32_t node_0_id = node_number(TinyVector<3, uint64_t>{i, j, k}); - const uint32_t node_1_id = node_number(TinyVector<3, uint64_t>{i + 1, j, k}); - const uint32_t node_2_id = node_number(TinyVector<3, uint64_t>{i + 1, j, k + 1}); - const uint32_t node_3_id = node_number(TinyVector<3, uint64_t>{i, j, k + 1}); - - auto i_face = - face_to_id_map.find(Face{{node_0_id, node_1_id, node_2_id, node_3_id}, descriptor.node_number_vector}); - Assert(i_face != face_to_id_map.end()); + const uint32_t node_0_id = get_node_id(TinyVector<3, uint64_t>{i, j, k}); + const uint32_t node_1_id = get_node_id(TinyVector<3, uint64_t>{i + 1, j, k}); + const uint32_t node_2_id = get_node_id(TinyVector<3, uint64_t>{i + 1, j, k + 1}); + const uint32_t node_3_id = get_node_id(TinyVector<3, uint64_t>{i, j, k + 1}); - boundary_faces[l++] = i_face->second; + boundary_faces[l++] = find_face({node_0_id, node_1_id, node_2_id, node_3_id}); } } Assert(l == cell_size[0] * cell_size[2]); @@ -401,16 +410,12 @@ LogicalConnectivityBuilder::_buildBoundaryFaceList(const TinyVector<3, uint64_t> size_t l = 0; for (size_t i = 0; i < cell_size[0]; ++i) { for (size_t j = 0; j < cell_size[1]; ++j) { - const uint32_t node_0_id = node_number(TinyVector<3, uint64_t>{i, j, k}); - const uint32_t node_1_id = node_number(TinyVector<3, uint64_t>{i + 1, j, k}); - const uint32_t node_2_id = node_number(TinyVector<3, uint64_t>{i + 1, j + 1, k}); - const uint32_t node_3_id = node_number(TinyVector<3, uint64_t>{i, j + 1, k}); + const uint32_t node_0_id = get_node_id(TinyVector<3, uint64_t>{i, j, k}); + const uint32_t node_1_id = get_node_id(TinyVector<3, uint64_t>{i + 1, j, k}); + const uint32_t node_2_id = get_node_id(TinyVector<3, uint64_t>{i + 1, j + 1, k}); + const uint32_t node_3_id = get_node_id(TinyVector<3, uint64_t>{i, j + 1, k}); - auto i_face = - face_to_id_map.find(Face{{node_0_id, node_1_id, node_2_id, node_3_id}, descriptor.node_number_vector}); - Assert(i_face != face_to_id_map.end()); - - boundary_faces[l++] = i_face->second; + boundary_faces[l++] = find_face({node_0_id, node_1_id, node_2_id, node_3_id}); } } Assert(l == cell_size[0] * cell_size[1]); @@ -431,36 +436,50 @@ LogicalConnectivityBuilder::_buildConnectivity( const size_t number_of_nodes = cell_size[0] + 1; ConnectivityDescriptor descriptor; - descriptor.node_number_vector.resize(number_of_nodes); - for (size_t i = 0; i < number_of_nodes; ++i) { - descriptor.node_number_vector[i] = i; - } + descriptor.setNodeNumberVector([&] { + Array<int> node_number_vector(number_of_nodes); + parallel_for( + number_of_nodes, PUGS_LAMBDA(const size_t i) { node_number_vector[i] = i; }); + return node_number_vector; + }()); + + descriptor.setCellNumberVector([&] { + Array<int> cell_number_vector(number_of_cells); + for (size_t i = 0; i < number_of_cells; ++i) { + cell_number_vector[i] = i; + } + return cell_number_vector; + }()); - descriptor.cell_number_vector.resize(number_of_cells); + Array<CellType> cell_type_vector(number_of_cells); + cell_type_vector.fill(CellType::Line); + descriptor.setCellTypeVector(cell_type_vector); + + Array<unsigned int> cell_to_node_row_map(number_of_cells + 1); + for (size_t i = 0; i < cell_to_node_row_map.size(); ++i) { + cell_to_node_row_map[i] = 2 * i; + } + Array<unsigned int> cell_to_node_list(2 * number_of_cells); for (size_t i = 0; i < number_of_cells; ++i) { - descriptor.cell_number_vector[i] = i; + cell_to_node_list[2 * i] = i; + cell_to_node_list[2 * i + 1] = i + 1; } - descriptor.cell_type_vector.resize(number_of_cells); - std::fill(descriptor.cell_type_vector.begin(), descriptor.cell_type_vector.end(), CellType::Line); - - descriptor.cell_to_node_vector.resize(number_of_cells); - constexpr size_t nb_node_per_cell = 2; - for (size_t j = 0; j < number_of_cells; ++j) { - descriptor.cell_to_node_vector[j].resize(nb_node_per_cell); - for (size_t r = 0; r < nb_node_per_cell; ++r) { - descriptor.cell_to_node_vector[j][0] = j; - descriptor.cell_to_node_vector[j][1] = j + 1; - } - } + descriptor.setCellToNodeMatrix(ConnectivityMatrix(cell_to_node_row_map, cell_to_node_list)); this->_buildBoundaryNodeList(cell_size, descriptor); - descriptor.cell_owner_vector.resize(number_of_cells); - std::fill(descriptor.cell_owner_vector.begin(), descriptor.cell_owner_vector.end(), parallel::rank()); + descriptor.setCellOwnerVector([&] { + Array<int> cell_owner_vector(number_of_cells); + cell_owner_vector.fill(parallel::rank()); + return cell_owner_vector; + }()); - descriptor.node_owner_vector.resize(descriptor.node_number_vector.size()); - std::fill(descriptor.node_owner_vector.begin(), descriptor.node_owner_vector.end(), parallel::rank()); + descriptor.setNodeOwnerVector([&] { + Array<int> node_owner_vector(number_of_nodes); + node_owner_vector.fill(parallel::rank()); + return node_owner_vector; + }()); m_connectivity = Connectivity1D::build(descriptor); } @@ -478,18 +497,23 @@ LogicalConnectivityBuilder::_buildConnectivity( const size_t number_of_nodes = node_size[0] * node_size[1]; ConnectivityDescriptor descriptor; - descriptor.node_number_vector.resize(number_of_nodes); - for (size_t i = 0; i < number_of_nodes; ++i) { - descriptor.node_number_vector[i] = i; - } - - descriptor.cell_number_vector.resize(number_of_cells); - for (size_t i = 0; i < number_of_cells; ++i) { - descriptor.cell_number_vector[i] = i; - } - - descriptor.cell_type_vector.resize(number_of_cells); - std::fill(descriptor.cell_type_vector.begin(), descriptor.cell_type_vector.end(), CellType::Quadrangle); + descriptor.setNodeNumberVector([&] { + Array<int> node_number_vector(number_of_nodes); + parallel_for( + number_of_nodes, PUGS_LAMBDA(const size_t i) { node_number_vector[i] = i; }); + return node_number_vector; + }()); + + descriptor.setCellNumberVector([&] { + Array<int> cell_number_vector(number_of_cells); + parallel_for( + number_of_cells, PUGS_LAMBDA(size_t i) { cell_number_vector[i] = i; }); + return cell_number_vector; + }()); + + Array<CellType> cell_type_vector(number_of_cells); + cell_type_vector.fill(CellType::Quadrangle); + descriptor.setCellTypeVector(cell_type_vector); const auto node_number = [&](const TinyVector<Dimension, uint64_t> node_logic_id) { return node_logic_id[0] * node_size[1] + node_logic_id[1]; @@ -501,32 +525,44 @@ LogicalConnectivityBuilder::_buildConnectivity( return TinyVector<Dimension, uint64_t>{j0, j1}; }; - descriptor.cell_to_node_vector.resize(number_of_cells); - constexpr size_t nb_node_per_cell = 1 << Dimension; + Array<unsigned int> cell_to_node_row_map(number_of_cells + 1); + for (size_t i = 0; i < cell_to_node_row_map.size(); ++i) { + cell_to_node_row_map[i] = 4 * i; + } + Array<unsigned int> cell_to_node_list(4 * number_of_cells); for (size_t j = 0; j < number_of_cells; ++j) { TinyVector<Dimension, size_t> cell_index = cell_logic_id(j); - descriptor.cell_to_node_vector[j].resize(nb_node_per_cell); - for (size_t r = 0; r < nb_node_per_cell; ++r) { - descriptor.cell_to_node_vector[j][0] = node_number(cell_index + TinyVector<Dimension, uint64_t>{0, 0}); - descriptor.cell_to_node_vector[j][1] = node_number(cell_index + TinyVector<Dimension, uint64_t>{1, 0}); - descriptor.cell_to_node_vector[j][2] = node_number(cell_index + TinyVector<Dimension, uint64_t>{1, 1}); - descriptor.cell_to_node_vector[j][3] = node_number(cell_index + TinyVector<Dimension, uint64_t>{0, 1}); - } + + cell_to_node_list[4 * j] = node_number(cell_index + TinyVector<Dimension, uint64_t>{0, 0}); + cell_to_node_list[4 * j + 1] = node_number(cell_index + TinyVector<Dimension, uint64_t>{1, 0}); + cell_to_node_list[4 * j + 2] = node_number(cell_index + TinyVector<Dimension, uint64_t>{1, 1}); + cell_to_node_list[4 * j + 3] = node_number(cell_index + TinyVector<Dimension, uint64_t>{0, 1}); } + descriptor.setCellToNodeMatrix(ConnectivityMatrix(cell_to_node_row_map, cell_to_node_list)); + ConnectivityBuilderBase::_computeCellFaceAndFaceNodeConnectivities<Dimension>(descriptor); this->_buildBoundaryNodeList(cell_size, descriptor); this->_buildBoundaryFaceList(cell_size, descriptor); - descriptor.cell_owner_vector.resize(number_of_cells); - std::fill(descriptor.cell_owner_vector.begin(), descriptor.cell_owner_vector.end(), parallel::rank()); + descriptor.setCellOwnerVector([&] { + Array<int> cell_owner_vector(number_of_cells); + cell_owner_vector.fill(parallel::rank()); + return cell_owner_vector; + }()); - descriptor.face_owner_vector.resize(descriptor.face_number_vector.size()); - std::fill(descriptor.face_owner_vector.begin(), descriptor.face_owner_vector.end(), parallel::rank()); + descriptor.setFaceOwnerVector([&] { + Array<int> face_owner_vector(descriptor.faceNumberVector().size()); + face_owner_vector.fill(parallel::rank()); + return face_owner_vector; + }()); - descriptor.node_owner_vector.resize(descriptor.node_number_vector.size()); - std::fill(descriptor.node_owner_vector.begin(), descriptor.node_owner_vector.end(), parallel::rank()); + descriptor.setNodeOwnerVector([&] { + Array<int> node_owner_vector(descriptor.nodeNumberVector().size()); + node_owner_vector.fill(parallel::rank()); + return node_owner_vector; + }()); m_connectivity = Connectivity<Dimension>::build(descriptor); } @@ -560,18 +596,23 @@ LogicalConnectivityBuilder::_buildConnectivity(const TinyVector<3, uint64_t>& ce const size_t number_of_nodes = count_items(node_size); ConnectivityDescriptor descriptor; - descriptor.node_number_vector.resize(number_of_nodes); - for (size_t i = 0; i < number_of_nodes; ++i) { - descriptor.node_number_vector[i] = i; - } - - descriptor.cell_number_vector.resize(number_of_cells); - for (size_t i = 0; i < number_of_cells; ++i) { - descriptor.cell_number_vector[i] = i; - } - - descriptor.cell_type_vector.resize(number_of_cells); - std::fill(descriptor.cell_type_vector.begin(), descriptor.cell_type_vector.end(), CellType::Hexahedron); + descriptor.setNodeNumberVector([&] { + Array<int> node_number_vector(number_of_nodes); + parallel_for( + number_of_nodes, PUGS_LAMBDA(const size_t i) { node_number_vector[i] = i; }); + return node_number_vector; + }()); + + descriptor.setCellNumberVector([&] { + Array<int> cell_number_vector(number_of_cells); + parallel_for( + number_of_cells, PUGS_LAMBDA(size_t i) { cell_number_vector[i] = i; }); + return cell_number_vector; + }()); + + Array<CellType> cell_type_vector(number_of_cells); + cell_type_vector.fill(CellType::Hexahedron); + descriptor.setCellTypeVector(cell_type_vector); const auto cell_logic_id = [&](size_t j) { const size_t slice1 = cell_size[1] * cell_size[2]; @@ -586,24 +627,26 @@ LogicalConnectivityBuilder::_buildConnectivity(const TinyVector<3, uint64_t>& ce return (node_logic_id[0] * node_size[1] + node_logic_id[1]) * node_size[2] + node_logic_id[2]; }; - descriptor.cell_to_node_vector.resize(number_of_cells); - constexpr size_t nb_node_per_cell = 1 << Dimension; + Array<unsigned int> cell_to_node_row_map(number_of_cells + 1); + for (size_t i = 0; i < cell_to_node_row_map.size(); ++i) { + cell_to_node_row_map[i] = 8 * i; + } + Array<unsigned int> cell_to_node_list(8 * number_of_cells); for (size_t j = 0; j < number_of_cells; ++j) { TinyVector<Dimension, size_t> cell_index = cell_logic_id(j); - descriptor.cell_to_node_vector[j].resize(nb_node_per_cell); - for (size_t r = 0; r < nb_node_per_cell; ++r) { - static_assert(Dimension == 3, "unexpected dimension"); - descriptor.cell_to_node_vector[j][0] = node_number(cell_index + TinyVector<Dimension, uint64_t>{0, 0, 0}); - descriptor.cell_to_node_vector[j][1] = node_number(cell_index + TinyVector<Dimension, uint64_t>{1, 0, 0}); - descriptor.cell_to_node_vector[j][2] = node_number(cell_index + TinyVector<Dimension, uint64_t>{1, 1, 0}); - descriptor.cell_to_node_vector[j][3] = node_number(cell_index + TinyVector<Dimension, uint64_t>{0, 1, 0}); - descriptor.cell_to_node_vector[j][4] = node_number(cell_index + TinyVector<Dimension, uint64_t>{0, 0, 1}); - descriptor.cell_to_node_vector[j][5] = node_number(cell_index + TinyVector<Dimension, uint64_t>{1, 0, 1}); - descriptor.cell_to_node_vector[j][6] = node_number(cell_index + TinyVector<Dimension, uint64_t>{1, 1, 1}); - descriptor.cell_to_node_vector[j][7] = node_number(cell_index + TinyVector<Dimension, uint64_t>{0, 1, 1}); - } + + cell_to_node_list[8 * j] = node_number(cell_index + TinyVector<Dimension, uint64_t>{0, 0, 0}); + cell_to_node_list[8 * j + 1] = node_number(cell_index + TinyVector<Dimension, uint64_t>{1, 0, 0}); + cell_to_node_list[8 * j + 2] = node_number(cell_index + TinyVector<Dimension, uint64_t>{1, 1, 0}); + cell_to_node_list[8 * j + 3] = node_number(cell_index + TinyVector<Dimension, uint64_t>{0, 1, 0}); + cell_to_node_list[8 * j + 4] = node_number(cell_index + TinyVector<Dimension, uint64_t>{0, 0, 1}); + cell_to_node_list[8 * j + 5] = node_number(cell_index + TinyVector<Dimension, uint64_t>{1, 0, 1}); + cell_to_node_list[8 * j + 6] = node_number(cell_index + TinyVector<Dimension, uint64_t>{1, 1, 1}); + cell_to_node_list[8 * j + 7] = node_number(cell_index + TinyVector<Dimension, uint64_t>{0, 1, 1}); } + descriptor.setCellToNodeMatrix(ConnectivityMatrix(cell_to_node_row_map, cell_to_node_list)); + ConnectivityBuilderBase::_computeCellFaceAndFaceNodeConnectivities<Dimension>(descriptor); ConnectivityBuilderBase::_computeFaceEdgeAndEdgeNodeAndCellEdgeConnectivities<Dimension>(descriptor); @@ -611,17 +654,29 @@ LogicalConnectivityBuilder::_buildConnectivity(const TinyVector<3, uint64_t>& ce this->_buildBoundaryEdgeList(cell_size, descriptor); this->_buildBoundaryFaceList(cell_size, descriptor); - descriptor.cell_owner_vector.resize(number_of_cells); - std::fill(descriptor.cell_owner_vector.begin(), descriptor.cell_owner_vector.end(), parallel::rank()); - - descriptor.face_owner_vector.resize(descriptor.face_number_vector.size()); - std::fill(descriptor.face_owner_vector.begin(), descriptor.face_owner_vector.end(), parallel::rank()); - - descriptor.edge_owner_vector.resize(descriptor.edge_number_vector.size()); - std::fill(descriptor.edge_owner_vector.begin(), descriptor.edge_owner_vector.end(), parallel::rank()); - - descriptor.node_owner_vector.resize(descriptor.node_number_vector.size()); - std::fill(descriptor.node_owner_vector.begin(), descriptor.node_owner_vector.end(), parallel::rank()); + descriptor.setCellOwnerVector([&] { + Array<int> cell_owner_vector(number_of_cells); + cell_owner_vector.fill(parallel::rank()); + return cell_owner_vector; + }()); + + descriptor.setFaceOwnerVector([&] { + Array<int> face_owner_vector(descriptor.faceNumberVector().size()); + face_owner_vector.fill(parallel::rank()); + return face_owner_vector; + }()); + + descriptor.setEdgeOwnerVector([&] { + Array<int> edge_owner_vector(descriptor.edgeNumberVector().size()); + edge_owner_vector.fill(parallel::rank()); + return edge_owner_vector; + }()); + + descriptor.setNodeOwnerVector([&] { + Array<int> node_owner_vector(descriptor.nodeNumberVector().size()); + node_owner_vector.fill(parallel::rank()); + return node_owner_vector; + }()); m_connectivity = Connectivity<Dimension>::build(descriptor); } diff --git a/src/mesh/MedianDualConnectivityBuilder.cpp b/src/mesh/MedianDualConnectivityBuilder.cpp index c6770d05ee1d93891d560bd1b1373fd2e68da5eb..1986c4a826a0a3ba2754e6204dafb4f9151bd5f7 100644 --- a/src/mesh/MedianDualConnectivityBuilder.cpp +++ b/src/mesh/MedianDualConnectivityBuilder.cpp @@ -92,33 +92,37 @@ MedianDualConnectivityBuilder::_buildConnectivityDescriptor<2>(const Connectivit Assert(i_boundary_node == primal_number_of_boundary_nodes); } - dual_descriptor.node_number_vector.resize(dual_number_of_nodes); + Array<int> node_number_vector(dual_number_of_nodes); { parallel_for(m_primal_cell_to_dual_node_map.size(), [&](size_t i) { - const auto [primal_cell_id, dual_node_id] = m_primal_cell_to_dual_node_map[i]; - dual_descriptor.node_number_vector[dual_node_id] = primal_cell_number[primal_cell_id]; + const auto [primal_cell_id, dual_node_id] = m_primal_cell_to_dual_node_map[i]; + node_number_vector[dual_node_id] = primal_cell_number[primal_cell_id]; }); const size_t face_number_shift = max(primal_cell_number) + 1; parallel_for(primal_number_of_faces, [&](size_t i) { - const auto [primal_face_id, dual_node_id] = m_primal_face_to_dual_node_map[i]; - dual_descriptor.node_number_vector[dual_node_id] = primal_face_number[primal_face_id] + face_number_shift; + const auto [primal_face_id, dual_node_id] = m_primal_face_to_dual_node_map[i]; + node_number_vector[dual_node_id] = primal_face_number[primal_face_id] + face_number_shift; }); const size_t node_number_shift = face_number_shift + max(primal_face_number) + 1; parallel_for(m_primal_boundary_node_to_dual_node_map.size(), [&](size_t i) { - const auto [primal_node_id, dual_node_id] = m_primal_boundary_node_to_dual_node_map[i]; - dual_descriptor.node_number_vector[dual_node_id] = primal_node_number[primal_node_id] + node_number_shift; + const auto [primal_node_id, dual_node_id] = m_primal_boundary_node_to_dual_node_map[i]; + node_number_vector[dual_node_id] = primal_node_number[primal_node_id] + node_number_shift; }); } + dual_descriptor.setNodeNumberVector(node_number_vector); - dual_descriptor.cell_number_vector.resize(dual_number_of_cells); - parallel_for(dual_number_of_cells, [&](size_t i) { - const auto [primal_node_id, dual_cell_id] = m_primal_node_to_dual_cell_map[i]; - dual_descriptor.cell_number_vector[dual_cell_id] = primal_node_number[primal_node_id]; - }); + { + Array<int> cell_number_vector(dual_number_of_cells); + parallel_for(dual_number_of_cells, [&](size_t i) { + const auto [primal_node_id, dual_cell_id] = m_primal_node_to_dual_cell_map[i]; + cell_number_vector[dual_cell_id] = primal_node_number[primal_node_id]; + }); + dual_descriptor.setCellNumberVector(cell_number_vector); + } - dual_descriptor.cell_type_vector.resize(dual_number_of_cells); + Array<CellType> cell_type_vector(dual_number_of_cells); const auto& primal_node_to_cell_matrix = primal_connectivity.nodeToCellMatrix(); @@ -127,13 +131,13 @@ MedianDualConnectivityBuilder::_buildConnectivityDescriptor<2>(const Connectivit const auto& primal_node_cell_list = primal_node_to_cell_matrix[node_id]; if (primal_node_cell_list.size() == 1) { - dual_descriptor.cell_type_vector[i_dual_cell] = CellType::Quadrangle; + cell_type_vector[i_dual_cell] = CellType::Quadrangle; } else { - dual_descriptor.cell_type_vector[i_dual_cell] = CellType::Polygon; + cell_type_vector[i_dual_cell] = CellType::Polygon; } }); + dual_descriptor.setCellTypeVector(cell_type_vector); - dual_descriptor.cell_to_node_vector.resize(dual_number_of_cells); const auto& primal_cell_to_face_matrix = primal_connectivity.cellToFaceMatrix(); const auto& primal_node_to_face_matrix = primal_connectivity.nodeToFaceMatrix(); const auto& primal_face_to_cell_matrix = primal_connectivity.faceToCellMatrix(); @@ -170,16 +174,35 @@ MedianDualConnectivityBuilder::_buildConnectivityDescriptor<2>(const Connectivit // LCOV_EXCL_STOP }; + Array<unsigned int> cell_to_node_row(dual_number_of_cells + 1); + cell_to_node_row[0] = 0; + { + for (NodeId node_id = 0; node_id < primal_number_of_nodes; ++node_id) { + // const size_t i_dual_cell = node_id; + const auto& primal_node_to_cell_list = primal_node_to_cell_matrix[node_id]; + const auto& primal_node_to_face_list = primal_node_to_face_matrix[node_id]; + + if (primal_node_to_cell_list.size() != primal_node_to_face_list.size()) { + // boundary cell + cell_to_node_row[node_id + 1] = + cell_to_node_row[node_id] + 1 + primal_node_to_cell_list.size() + primal_node_to_face_list.size(); + } else { + // inner cell + cell_to_node_row[node_id + 1] = + cell_to_node_row[node_id] + primal_node_to_cell_list.size() + primal_node_to_face_list.size(); + } + } + } + + Array<unsigned int> cell_to_node_list(cell_to_node_row[cell_to_node_row.size() - 1]); parallel_for(primal_number_of_nodes, [&](NodeId node_id) { - const size_t i_dual_cell = node_id; const auto& primal_node_to_cell_list = primal_node_to_cell_matrix[node_id]; const auto& primal_node_to_face_list = primal_node_to_face_matrix[node_id]; - auto& dual_cell_node_list = dual_descriptor.cell_to_node_vector[i_dual_cell]; + size_t i_dual_cell_node = cell_to_node_row[node_id]; if (primal_node_to_cell_list.size() != primal_node_to_face_list.size()) { // boundary cell - dual_cell_node_list.reserve(1 + primal_node_to_cell_list.size() + primal_node_to_face_list.size()); auto [face_id, cell_id] = [&]() -> std::pair<FaceId, CellId> { for (size_t i_face = 0; i_face < primal_node_to_face_list.size(); ++i_face) { @@ -200,24 +223,24 @@ MedianDualConnectivityBuilder::_buildConnectivityDescriptor<2>(const Connectivit // LCOV_EXCL_STOP }(); - dual_cell_node_list.push_back(m_primal_face_to_dual_node_map[face_id].second); - dual_cell_node_list.push_back(m_primal_cell_to_dual_node_map[cell_id].second); + cell_to_node_list[i_dual_cell_node++] = m_primal_face_to_dual_node_map[face_id].second; + cell_to_node_list[i_dual_cell_node++] = m_primal_cell_to_dual_node_map[cell_id].second; face_id = next_face(cell_id, face_id, node_id); while (primal_face_to_cell_matrix[face_id].size() > 1) { - dual_cell_node_list.push_back(m_primal_face_to_dual_node_map[face_id].second); - cell_id = next_cell(cell_id, face_id); - dual_cell_node_list.push_back(m_primal_cell_to_dual_node_map[cell_id].second); + cell_to_node_list[i_dual_cell_node++] = m_primal_face_to_dual_node_map[face_id].second; + + cell_id = next_cell(cell_id, face_id); + cell_to_node_list[i_dual_cell_node++] = m_primal_cell_to_dual_node_map[cell_id].second; + face_id = next_face(cell_id, face_id, node_id); } - dual_cell_node_list.push_back(m_primal_face_to_dual_node_map[face_id].second); - dual_cell_node_list.push_back(node_to_dual_node_correpondance[node_id]); + cell_to_node_list[i_dual_cell_node++] = m_primal_face_to_dual_node_map[face_id].second; + cell_to_node_list[i_dual_cell_node++] = node_to_dual_node_correpondance[node_id]; - Assert(dual_cell_node_list.size() == 1 + primal_node_to_cell_list.size() + primal_node_to_face_list.size()); } else { // inner cell - dual_cell_node_list.reserve(primal_node_to_cell_list.size() + primal_node_to_face_list.size()); auto [face_id, cell_id] = [&]() -> std::pair<FaceId, CellId> { const FaceId face_id = primal_node_to_face_list[0]; @@ -237,14 +260,16 @@ MedianDualConnectivityBuilder::_buildConnectivityDescriptor<2>(const Connectivit const FaceId first_face_id = face_id; do { - dual_cell_node_list.push_back(m_primal_face_to_dual_node_map[face_id].second); - dual_cell_node_list.push_back(m_primal_cell_to_dual_node_map[cell_id].second); + cell_to_node_list[i_dual_cell_node++] = m_primal_face_to_dual_node_map[face_id].second; + cell_to_node_list[i_dual_cell_node++] = m_primal_cell_to_dual_node_map[cell_id].second; face_id = next_face(cell_id, face_id, node_id); cell_id = next_cell(cell_id, face_id); } while (face_id != first_face_id); } }); + + dual_descriptor.setCellToNodeMatrix(ConnectivityMatrix(cell_to_node_row, cell_to_node_list)); } template <> @@ -277,39 +302,28 @@ MedianDualConnectivityBuilder::_buildConnectivityFrom<2>(const IConnectivity& i_ const auto& primal_node_list = primal_ref_node_list.list(); const std::vector<NodeId> dual_node_list = [&]() { - std::vector<NodeId> dual_node_list; + std::vector<NodeId> tmp_dual_node_list; for (size_t i_primal_node = 0; i_primal_node < primal_node_list.size(); ++i_primal_node) { auto primal_node_id = primal_node_list[i_primal_node]; const auto i_dual_node = primal_boundary_node_id_to_dual_node_id_map.find(primal_connectivity.nodeNumber()[primal_node_id]); if (i_dual_node != primal_boundary_node_id_to_dual_node_id_map.end()) { - dual_node_list.push_back(i_dual_node->second); + tmp_dual_node_list.push_back(i_dual_node->second); } } - return dual_node_list; + return tmp_dual_node_list; }(); if (parallel::allReduceOr(dual_node_list.size() > 0)) { - dual_descriptor.addRefItemList(RefNodeList{primal_ref_node_list.refId(), convert_to_array(dual_node_list), - primal_ref_node_list.isBoundary()}); + auto dual_node_array = convert_to_array(dual_node_list); + dual_descriptor.addRefItemList( + RefNodeList{primal_ref_node_list.refId(), dual_node_array, primal_ref_node_list.isBoundary()}); } } } - using Face = ConnectivityFace<2>; - - const std::unordered_map<Face, FaceId, typename Face::Hash> face_to_id_map = [&] { - std::unordered_map<Face, FaceId, typename Face::Hash> face_to_id_map; - for (FaceId l = 0; l < dual_descriptor.face_to_node_vector.size(); ++l) { - const auto& node_vector = dual_descriptor.face_to_node_vector[l]; - - face_to_id_map[Face(node_vector, dual_descriptor.node_number_vector)] = l; - } - return face_to_id_map; - }(); - for (size_t i_face_list = 0; i_face_list < primal_connectivity.template numberOfRefItemList<ItemType::face>(); ++i_face_list) { const auto& primal_ref_face_list = primal_connectivity.template refItemList<ItemType::face>(i_face_list); @@ -321,21 +335,23 @@ MedianDualConnectivityBuilder::_buildConnectivityFrom<2>(const IConnectivity& i_ bounday_face_dual_node_id_list[i_face] = m_primal_face_to_dual_node_map[primal_face_list[i_face]].second; } - std::vector<bool> is_dual_node_from_boundary_face(dual_descriptor.node_number_vector.size(), false); + std::vector<bool> is_dual_node_from_boundary_face(dual_descriptor.nodeNumberVector().size(), false); for (size_t i_face = 0; i_face < bounday_face_dual_node_id_list.size(); ++i_face) { is_dual_node_from_boundary_face[bounday_face_dual_node_id_list[i_face]] = true; } - std::vector<bool> is_dual_node_from_boundary_node(dual_descriptor.node_number_vector.size(), false); + std::vector<bool> is_dual_node_from_boundary_node(dual_descriptor.nodeNumberVector().size(), false); for (size_t i_node = 0; i_node < m_primal_boundary_node_to_dual_node_map.size(); ++i_node) { is_dual_node_from_boundary_node[m_primal_boundary_node_to_dual_node_map[i_node].second] = true; } + const auto& dual_face_to_node_matrix = dual_descriptor.faceToNodeMatrix(); + std::vector<FaceId> dual_face_list; dual_face_list.reserve(2 * primal_face_list.size()); - for (size_t i_dual_face = 0; i_dual_face < dual_descriptor.face_to_node_vector.size(); ++i_dual_face) { - const NodeId dual_node_0 = dual_descriptor.face_to_node_vector[i_dual_face][0]; - const NodeId dual_node_1 = dual_descriptor.face_to_node_vector[i_dual_face][1]; + for (size_t i_dual_face = 0; i_dual_face < dual_face_to_node_matrix.numberOfRows(); ++i_dual_face) { + const NodeId dual_node_0 = dual_face_to_node_matrix[i_dual_face][0]; + const NodeId dual_node_1 = dual_face_to_node_matrix[i_dual_face][1]; if ((is_dual_node_from_boundary_face[dual_node_0] and is_dual_node_from_boundary_node[dual_node_1]) or (is_dual_node_from_boundary_node[dual_node_0] and is_dual_node_from_boundary_face[dual_node_1])) { @@ -352,42 +368,61 @@ MedianDualConnectivityBuilder::_buildConnectivityFrom<2>(const IConnectivity& i_ } } - const size_t primal_number_of_nodes = primal_connectivity.numberOfNodes(); - const size_t primal_number_of_cells = primal_connectivity.numberOfCells(); + const auto& primal_node_owner = primal_connectivity.nodeOwner(); - dual_descriptor.node_owner_vector.resize(dual_descriptor.node_number_vector.size()); + dual_descriptor.setNodeOwnerVector([&] { + Array<int> node_owner_vector(dual_descriptor.nodeNumberVector().size()); - const auto& primal_node_owner = primal_connectivity.nodeOwner(); - for (NodeId primal_node_id = 0; primal_node_id < primal_connectivity.numberOfNodes(); ++primal_node_id) { - dual_descriptor.node_owner_vector[primal_node_id] = primal_node_owner[primal_node_id]; - } - const auto& primal_cell_owner = primal_connectivity.cellOwner(); - for (CellId primal_cell_id = 0; primal_cell_id < primal_number_of_cells; ++primal_cell_id) { - dual_descriptor.node_owner_vector[primal_number_of_nodes + primal_cell_id] = primal_cell_owner[primal_cell_id]; - } + node_owner_vector.fill(-1); + for (size_t i_primal_node_to_dual_node = 0; + i_primal_node_to_dual_node < m_primal_boundary_node_to_dual_node_map.size(); ++i_primal_node_to_dual_node) { + const auto& [primal_node_id, dual_node_id] = m_primal_boundary_node_to_dual_node_map[i_primal_node_to_dual_node]; + node_owner_vector[dual_node_id] = primal_node_owner[primal_node_id]; + } - dual_descriptor.cell_owner_vector.resize(dual_descriptor.cell_number_vector.size()); - for (NodeId primal_node_id = 0; primal_node_id < primal_number_of_nodes; ++primal_node_id) { - dual_descriptor.cell_owner_vector[primal_node_id] = primal_node_owner[primal_node_id]; - } + const auto& primal_face_owner = primal_connectivity.faceOwner(); + for (size_t i_primal_face_to_dual_node = 0; i_primal_face_to_dual_node < m_primal_face_to_dual_node_map.size(); + ++i_primal_face_to_dual_node) { + const auto& [primal_face_id, dual_node_id] = m_primal_face_to_dual_node_map[i_primal_face_to_dual_node]; + node_owner_vector[dual_node_id] = primal_face_owner[primal_face_id]; + } - { - std::vector<int> face_cell_owner(dual_descriptor.face_number_vector.size()); - std::fill(std::begin(face_cell_owner), std::end(face_cell_owner), parallel::size()); + const auto& primal_cell_owner = primal_connectivity.cellOwner(); + for (size_t i_primal_cell_to_dual_node = 0; i_primal_cell_to_dual_node < m_primal_cell_to_dual_node_map.size(); + ++i_primal_cell_to_dual_node) { + const auto& [primal_cell_id, dual_node_id] = m_primal_cell_to_dual_node_map[i_primal_cell_to_dual_node]; + node_owner_vector[dual_node_id] = primal_cell_owner[primal_cell_id]; + } - for (size_t i_cell = 0; i_cell < dual_descriptor.cell_to_face_vector.size(); ++i_cell) { - const auto& cell_face_list = dual_descriptor.cell_to_face_vector[i_cell]; - for (size_t i_face = 0; i_face < cell_face_list.size(); ++i_face) { - const size_t face_id = cell_face_list[i_face]; - face_cell_owner[face_id] = std::min(face_cell_owner[face_id], dual_descriptor.cell_number_vector[i_cell]); - } + return node_owner_vector; + }()); + + dual_descriptor.setCellOwnerVector([&] { + Array<int> cell_owner_vector(dual_descriptor.cellNumberVector().size()); + cell_owner_vector.fill(-1); + for (size_t i_primal_cell_to_dual_node = 0; i_primal_cell_to_dual_node < m_primal_node_to_dual_cell_map.size(); + ++i_primal_cell_to_dual_node) { + const auto& [primal_node_id, dual_cell_id] = m_primal_node_to_dual_cell_map[i_primal_cell_to_dual_node]; + cell_owner_vector[dual_cell_id] = primal_node_owner[primal_node_id]; } + return cell_owner_vector; + }()); - dual_descriptor.face_owner_vector.resize(face_cell_owner.size()); - for (size_t i_face = 0; i_face < face_cell_owner.size(); ++i_face) { - dual_descriptor.face_owner_vector[i_face] = dual_descriptor.cell_owner_vector[face_cell_owner[i_face]]; + dual_descriptor.setFaceOwnerVector([&] { + const auto& dual_cell_to_face_matrix = dual_descriptor.cellToFaceMatrix(); + const auto& dual_cell_owner_vector = dual_descriptor.cellOwnerVector(); + + Array<int> face_owner_vector(dual_descriptor.faceNumberVector().size()); + face_owner_vector.fill(parallel::size()); + for (size_t i_cell = 0; i_cell < dual_cell_to_face_matrix.numberOfRows(); ++i_cell) { + const auto& cell_face_list = dual_cell_to_face_matrix[i_cell]; + for (size_t i_face = 0; i_face < cell_face_list.size(); ++i_face) { + const size_t face_id = cell_face_list[i_face]; + face_owner_vector[face_id] = std::min(face_owner_vector[face_id], dual_cell_owner_vector[i_cell]); + } } - } + return face_owner_vector; + }()); m_connectivity = ConnectivityType::build(dual_descriptor); diff --git a/src/mesh/MeshBuilderBase.cpp b/src/mesh/MeshBuilderBase.cpp index a3a8440bd25499d8aea34a08e7c836b66a4c3a32..973a6099afb49595d02403c697bbb927d2a7ba63 100644 --- a/src/mesh/MeshBuilderBase.cpp +++ b/src/mesh/MeshBuilderBase.cpp @@ -132,8 +132,14 @@ MeshBuilderBase::_checkMesh() const if (intersection.size() > 1) { std::ostringstream error_msg; error_msg << "invalid mesh.\n\tFollowing faces\n"; - for (FaceId face_id : intersection) { - error_msg << "\t - id=" << face_id << " number=" << connectivity.faceNumber()[face_id] << '\n'; + for (FaceId intersection_face_id : intersection) { + error_msg << "\t - id=" << intersection_face_id + << " number=" << connectivity.faceNumber()[intersection_face_id] << '\n'; + error_msg << "\t nodes:"; + for (size_t i = 0; i < face_to_node_matrix[intersection_face_id].size(); ++i) { + error_msg << ' ' << face_to_node_matrix[intersection_face_id][i]; + } + error_msg << '\n'; } error_msg << "\tare duplicated"; throw NormalError(error_msg.str()); diff --git a/src/output/GnuplotWriter.cpp b/src/output/GnuplotWriter.cpp index 4a346cf33e4c7f475a0abb8f0c3136ed88a72cc0..50969799eeb4250b28d21722e8476ab86a88d9eb 100644 --- a/src/output/GnuplotWriter.cpp +++ b/src/output/GnuplotWriter.cpp @@ -162,7 +162,7 @@ GnuplotWriter::_writeDataAtNodes(const MeshType& mesh, const NodeId& node_id = cell_nodes[i_node]; const TinyVector<MeshType::Dimension>& xr = mesh.xr()[node_id]; fout << xr[0]; - for (auto [name, item_data_variant] : output_named_item_data_set) { + for (const auto& [name, item_data_variant] : output_named_item_data_set) { std::visit([&](auto&& item_data) { _writeData(item_data, cell_id, node_id, fout); }, item_data_variant); } fout << '\n'; @@ -182,7 +182,7 @@ GnuplotWriter::_writeDataAtNodes(const MeshType& mesh, const NodeId& node_id = cell_nodes[i_node]; const TinyVector<MeshType::Dimension>& xr = mesh.xr()[node_id]; fout << xr[0] << ' ' << xr[1]; - for (auto [name, item_data_variant] : output_named_item_data_set) { + for (const auto& [name, item_data_variant] : output_named_item_data_set) { std::visit([&](auto&& item_data) { _writeData(item_data, cell_id, node_id, fout); }, item_data_variant); } fout << '\n'; @@ -190,7 +190,7 @@ GnuplotWriter::_writeDataAtNodes(const MeshType& mesh, const NodeId& node_id = cell_nodes[0]; const TinyVector<MeshType::Dimension>& xr = mesh.xr()[node_id]; fout << xr[0] << ' ' << xr[1]; - for (auto [name, item_data_variant] : output_named_item_data_set) { + for (const auto& [name, item_data_variant] : output_named_item_data_set) { std::visit([&](auto&& item_data) { _writeData(item_data, cell_id, node_id, fout); }, item_data_variant); } fout << "\n\n\n"; diff --git a/src/output/GnuplotWriter1D.cpp b/src/output/GnuplotWriter1D.cpp index ad398126c4f075bf8c092ebb0aaac6ed1e4c0fd9..a3156904843bdeb77be718de6a10614a3333afae 100644 --- a/src/output/GnuplotWriter1D.cpp +++ b/src/output/GnuplotWriter1D.cpp @@ -149,7 +149,7 @@ GnuplotWriter1D::_writeItemDatas(const MeshType& mesh, const size_t& number_of_columns = [&] { size_t number_of_columns = 1; - for (auto [name, item_data] : output_named_item_data_set) { + for (const auto& [name, item_data] : output_named_item_data_set) { std::visit([&](auto&& value) { number_of_columns += _itemDataNbRow(value); }, item_data); } return number_of_columns; @@ -198,7 +198,7 @@ GnuplotWriter1D::_writeItemDatas(const MeshType& mesh, } size_t column_number = 1; - for (auto [name, output_item_data] : output_named_item_data_set) { + for (const auto& [name, output_item_data] : output_named_item_data_set) { std::visit( [&](auto&& item_data) { using ItemDataT = std::decay_t<decltype(item_data)>; diff --git a/src/output/NamedDiscreteFunction.hpp b/src/output/NamedDiscreteFunction.hpp index d56d44369bb2e5492c078a35a0cf0a01e5524d42..305db7be68d5a2ca6a4790c1d4bde525297e8999 100644 --- a/src/output/NamedDiscreteFunction.hpp +++ b/src/output/NamedDiscreteFunction.hpp @@ -6,12 +6,12 @@ #include <memory> #include <string> -class IDiscreteFunction; +class DiscreteFunctionVariant; class NamedDiscreteFunction final : public INamedDiscreteData { private: - std::shared_ptr<const IDiscreteFunction> m_discrete_function; + std::shared_ptr<const DiscreteFunctionVariant> m_discrete_function_variant; std::string m_name; public: @@ -27,14 +27,15 @@ class NamedDiscreteFunction final : public INamedDiscreteData return m_name; } - const std::shared_ptr<const IDiscreteFunction> - discreteFunction() const + const std::shared_ptr<const DiscreteFunctionVariant> + discreteFunctionVariant() const { - return m_discrete_function; + return m_discrete_function_variant; } - NamedDiscreteFunction(const std::shared_ptr<const IDiscreteFunction>& discrete_function, const std::string& name) - : m_discrete_function{discrete_function}, m_name{name} + NamedDiscreteFunction(const std::shared_ptr<const DiscreteFunctionVariant>& discrete_function, + const std::string& name) + : m_discrete_function_variant{discrete_function}, m_name{name} {} NamedDiscreteFunction(const NamedDiscreteFunction&) = default; diff --git a/src/output/VTKWriter.cpp b/src/output/VTKWriter.cpp index f68607d7da6daf5afe8980a36e669e87b013dd3e..0a40c7265e05a17d31e59bd41eeb10cb63935821 100644 --- a/src/output/VTKWriter.cpp +++ b/src/output/VTKWriter.cpp @@ -116,7 +116,7 @@ class VTKWriter::SerializedDataList void write(std::ostream& os) const { - for (auto serialized_data : m_serialized_data_list) { + for (const auto& serialized_data : m_serialized_data_list) { serialized_data->write(os); } } diff --git a/src/output/WriterBase.cpp b/src/output/WriterBase.cpp index fcb2cf78f21f3bebc878b0343826c3abab4636c1..83d890c2ab8bf31e60d7ed09e4e2da7770ebbfb8 100644 --- a/src/output/WriterBase.cpp +++ b/src/output/WriterBase.cpp @@ -7,7 +7,7 @@ #include <output/OutputNamedItemValueSet.hpp> #include <scheme/DiscreteFunctionP0.hpp> #include <scheme/DiscreteFunctionP0Vector.hpp> -#include <scheme/IDiscreteFunction.hpp> +#include <scheme/DiscreteFunctionVariant.hpp> #include <scheme/IDiscreteFunctionDescriptor.hpp> #include <utils/Exceptions.hpp> @@ -17,142 +17,14 @@ WriterBase::_registerDiscreteFunction(const std::string& name, const DiscreteFunctionType& discrete_function, OutputNamedItemDataSet& named_item_data_set) { - if constexpr (DiscreteFunctionType::handled_data_type == IDiscreteFunction::HandledItemDataType::value) { + if constexpr (is_discrete_function_P0_v<DiscreteFunctionType>) { named_item_data_set.add(NamedItemData{name, discrete_function.cellValues()}); } else { + static_assert(is_discrete_function_P0_vector_v<DiscreteFunctionType>, "unexpected discrete function type"); named_item_data_set.add(NamedItemData{name, discrete_function.cellArrays()}); } } -template <size_t Dimension, template <size_t DimensionT, typename DataTypeT> typename DiscreteFunctionType> -void -WriterBase::_registerDiscreteFunction(const std::string& name, - const IDiscreteFunction& i_discrete_function, - OutputNamedItemDataSet& named_item_data_set) -{ - const ASTNodeDataType& data_type = i_discrete_function.dataType(); - switch (data_type) { - case ASTNodeDataType::bool_t: { - _registerDiscreteFunction(name, dynamic_cast<const DiscreteFunctionType<Dimension, bool>&>(i_discrete_function), - named_item_data_set); - break; - } - case ASTNodeDataType::unsigned_int_t: { - _registerDiscreteFunction(name, dynamic_cast<const DiscreteFunctionType<Dimension, uint64_t>&>(i_discrete_function), - named_item_data_set); - break; - } - case ASTNodeDataType::int_t: { - _registerDiscreteFunction(name, dynamic_cast<const DiscreteFunctionType<Dimension, int64_t>&>(i_discrete_function), - named_item_data_set); - break; - } - case ASTNodeDataType::double_t: { - _registerDiscreteFunction(name, dynamic_cast<const DiscreteFunctionType<Dimension, double>&>(i_discrete_function), - named_item_data_set); - break; - } - case ASTNodeDataType::vector_t: { - if constexpr (DiscreteFunctionType<Dimension, double>::handled_data_type == - IDiscreteFunction::HandledItemDataType::vector) { - throw UnexpectedError("invalid data type for vector data"); - } else { - switch (data_type.dimension()) { - case 1: { - _registerDiscreteFunction(name, - dynamic_cast<const DiscreteFunctionType<Dimension, TinyVector<1, double>>&>( - i_discrete_function), - named_item_data_set); - break; - } - case 2: { - _registerDiscreteFunction(name, - dynamic_cast<const DiscreteFunctionType<Dimension, TinyVector<2, double>>&>( - i_discrete_function), - named_item_data_set); - break; - } - case 3: { - _registerDiscreteFunction(name, - dynamic_cast<const DiscreteFunctionType<Dimension, TinyVector<3, double>>&>( - i_discrete_function), - named_item_data_set); - break; - } - default: { - throw UnexpectedError("invalid vector dimension"); - } - } - } - break; - } - case ASTNodeDataType::matrix_t: { - if constexpr (DiscreteFunctionType<Dimension, double>::handled_data_type == - IDiscreteFunction::HandledItemDataType::vector) { - throw UnexpectedError("invalid data type for vector data"); - } else { - Assert(data_type.numberOfRows() == data_type.numberOfColumns(), "invalid matrix dimensions"); - switch (data_type.numberOfRows()) { - case 1: { - _registerDiscreteFunction(name, - dynamic_cast<const DiscreteFunctionType<Dimension, TinyMatrix<1, 1, double>>&>( - i_discrete_function), - named_item_data_set); - break; - } - case 2: { - _registerDiscreteFunction(name, - dynamic_cast<const DiscreteFunctionType<Dimension, TinyMatrix<2, 2, double>>&>( - i_discrete_function), - named_item_data_set); - break; - } - case 3: { - _registerDiscreteFunction(name, - dynamic_cast<const DiscreteFunctionType<Dimension, TinyMatrix<3, 3, double>>&>( - i_discrete_function), - named_item_data_set); - break; - } - default: { - throw UnexpectedError("invalid matrix dimension"); - } - } - } - break; - } - default: { - throw UnexpectedError("invalid data type " + dataTypeName(data_type)); - } - } -} - -template <template <size_t Dimension, typename DataType> typename DiscreteFunctionType> -void -WriterBase::_registerDiscreteFunction(const NamedDiscreteFunction& named_discrete_function, - OutputNamedItemDataSet& named_item_data_set) -{ - const IDiscreteFunction& i_discrete_function = *named_discrete_function.discreteFunction(); - const std::string& name = named_discrete_function.name(); - switch (i_discrete_function.mesh()->dimension()) { - case 1: { - _registerDiscreteFunction<1, DiscreteFunctionType>(name, i_discrete_function, named_item_data_set); - break; - } - case 2: { - _registerDiscreteFunction<2, DiscreteFunctionType>(name, i_discrete_function, named_item_data_set); - break; - } - case 3: { - _registerDiscreteFunction<3, DiscreteFunctionType>(name, i_discrete_function, named_item_data_set); - break; - } - default: { - throw UnexpectedError("invalid mesh dimension"); - } - } -} - void WriterBase::_checkConnectivity( const std::shared_ptr<const IMesh>& mesh, @@ -211,7 +83,11 @@ WriterBase::_checkMesh(const std::shared_ptr<const IMesh>& mesh, const NamedDiscreteFunction& named_discrete_function = dynamic_cast<const NamedDiscreteFunction&>(*named_discrete_data); - if (mesh != named_discrete_function.discreteFunction()->mesh()) { + std::shared_ptr<const IMesh> discrete_function_mesh = + std::visit([](auto&& f) { return f.mesh(); }, + named_discrete_function.discreteFunctionVariant()->discreteFunction()); + + if (mesh != discrete_function_mesh) { std::ostringstream error_msg; error_msg << "The variable " << rang::fgB::yellow << named_discrete_function.name() << rang::fg::reset << " is not defined on the provided mesh\n"; @@ -237,7 +113,8 @@ WriterBase::_getMesh(const std::vector<std::shared_ptr<const INamedDiscreteData> const NamedDiscreteFunction& named_discrete_function = dynamic_cast<const NamedDiscreteFunction&>(*named_discrete_data); - std::shared_ptr mesh = named_discrete_function.discreteFunction()->mesh(); + std::shared_ptr mesh = std::visit([&](auto&& f) { return f.mesh(); }, + named_discrete_function.discreteFunctionVariant()->discreteFunction()); mesh_set[mesh] = named_discrete_function.name(); switch (mesh->dimension()) { @@ -317,24 +194,12 @@ WriterBase::_getOutputNamedItemDataSet( const NamedDiscreteFunction& named_discrete_function = dynamic_cast<const NamedDiscreteFunction&>(*named_discrete_data); - const IDiscreteFunction& i_discrete_function = *named_discrete_function.discreteFunction(); + const std::string& name = named_discrete_function.name(); - switch (i_discrete_function.descriptor().type()) { - case DiscreteFunctionType::P0: { - WriterBase::_registerDiscreteFunction<DiscreteFunctionP0>(named_discrete_function, named_item_data_set); - break; - } - case DiscreteFunctionType::P0Vector: { - WriterBase::_registerDiscreteFunction<DiscreteFunctionP0Vector>(named_discrete_function, named_item_data_set); - break; - } - default: { - std::ostringstream error_msg; - error_msg << "the type of discrete function of " << rang::fgB::blue << named_discrete_data->name() - << rang::style::reset << " is not supported"; - throw NormalError(error_msg.str()); - } - } + const DiscreteFunctionVariant& discrete_function_variant = *named_discrete_function.discreteFunctionVariant(); + + std::visit([&](auto&& f) { WriterBase::_registerDiscreteFunction(name, f, named_item_data_set); }, + discrete_function_variant.discreteFunction()); break; } case INamedDiscreteData::Type::item_value: { diff --git a/src/output/WriterBase.hpp b/src/output/WriterBase.hpp index 339cd7645c8cbdc903357cee6000d1c6ab45dda3..7fae994d78ed0e97be8f10d63097464280c739fc 100644 --- a/src/output/WriterBase.hpp +++ b/src/output/WriterBase.hpp @@ -10,7 +10,6 @@ class IMesh; class OutputNamedItemDataSet; -class IDiscreteFunction; class NamedDiscreteFunction; class WriterBase : public IWriter @@ -90,12 +89,6 @@ class WriterBase : public IWriter template <typename DiscreteFunctionType> static void _registerDiscreteFunction(const std::string& name, const DiscreteFunctionType&, OutputNamedItemDataSet&); - template <size_t Dimension, template <size_t DimensionT, typename DataTypeT> typename DiscreteFunctionType> - static void _registerDiscreteFunction(const std::string& name, const IDiscreteFunction&, OutputNamedItemDataSet&); - - template <template <size_t DimensionT, typename DataTypeT> typename DiscreteFunctionType> - static void _registerDiscreteFunction(const NamedDiscreteFunction&, OutputNamedItemDataSet&); - protected: void _checkConnectivity(const std::shared_ptr<const IMesh>& mesh, const std::vector<std::shared_ptr<const INamedDiscreteData>>& named_discrete_data_list) const; diff --git a/src/scheme/AcousticSolver.cpp b/src/scheme/AcousticSolver.cpp index 589b1d380d6ba1fbac10a61290552fe85ab1d193..f61f27cb46c4ed9dbee0481c433e6f9aa3ea4da0 100644 --- a/src/scheme/AcousticSolver.cpp +++ b/src/scheme/AcousticSolver.cpp @@ -13,7 +13,6 @@ #include <scheme/ExternalBoundaryConditionDescriptor.hpp> #include <scheme/FixedBoundaryConditionDescriptor.hpp> #include <scheme/IBoundaryConditionDescriptor.hpp> -#include <scheme/IDiscreteFunction.hpp> #include <scheme/IDiscreteFunctionDescriptor.hpp> #include <scheme/SymmetryBoundaryConditionDescriptor.hpp> #include <utils/Socket.hpp> @@ -23,7 +22,7 @@ template <size_t Dimension> double -acoustic_dt(const DiscreteFunctionP0<Dimension, double>& c) +acoustic_dt(const DiscreteFunctionP0<Dimension, const double>& c) { const Mesh<Connectivity<Dimension>>& mesh = dynamic_cast<const Mesh<Connectivity<Dimension>>&>(*c.mesh()); @@ -38,23 +37,19 @@ acoustic_dt(const DiscreteFunctionP0<Dimension, double>& c) } double -acoustic_dt(const std::shared_ptr<const IDiscreteFunction>& c) +acoustic_dt(const std::shared_ptr<const DiscreteFunctionVariant>& c) { - if ((c->descriptor().type() != DiscreteFunctionType::P0) or (c->dataType() != ASTNodeDataType::double_t)) { - throw NormalError("invalid discrete function type"); - } - - std::shared_ptr mesh = c->mesh(); + std::shared_ptr mesh = getCommonMesh({c}); switch (mesh->dimension()) { case 1: { - return acoustic_dt(dynamic_cast<const DiscreteFunctionP0<1, double>&>(*c)); + return acoustic_dt(c->get<DiscreteFunctionP0<1, const double>>()); } case 2: { - return acoustic_dt(dynamic_cast<const DiscreteFunctionP0<2, double>&>(*c)); + return acoustic_dt(c->get<DiscreteFunctionP0<2, const double>>()); } case 3: { - return acoustic_dt(dynamic_cast<const DiscreteFunctionP0<3, double>&>(*c)); + return acoustic_dt(c->get<DiscreteFunctionP0<3, const double>>()); } default: { throw UnexpectedError("invalid mesh dimension"); @@ -72,8 +67,8 @@ class AcousticSolverHandler::AcousticSolver final : public AcousticSolverHandler using MeshType = Mesh<Connectivity<Dimension>>; using MeshDataType = MeshData<Dimension>; - using DiscreteScalarFunction = DiscreteFunctionP0<Dimension, double>; - using DiscreteVectorFunction = DiscreteFunctionP0<Dimension, Rd>; + using DiscreteScalarFunction = DiscreteFunctionP0<Dimension, const double>; + using DiscreteVectorFunction = DiscreteFunctionP0<Dimension, const Rd>; class FixedBoundaryCondition; class PressureBoundaryCondition; @@ -381,26 +376,26 @@ class AcousticSolverHandler::AcousticSolver final : public AcousticSolverHandler public: std::tuple<const std::shared_ptr<const ItemValueVariant>, const std::shared_ptr<const SubItemValuePerItemVariant>> compute_fluxes(const SolverType& solver_type, - const std::shared_ptr<const IDiscreteFunction>& i_rho, - const std::shared_ptr<const IDiscreteFunction>& i_c, - const std::shared_ptr<const IDiscreteFunction>& i_u, - const std::shared_ptr<const IDiscreteFunction>& i_p, + const std::shared_ptr<const DiscreteFunctionVariant>& rho_v, + const std::shared_ptr<const DiscreteFunctionVariant>& c_v, + const std::shared_ptr<const DiscreteFunctionVariant>& u_v, + const std::shared_ptr<const DiscreteFunctionVariant>& p_v, const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) const { - std::shared_ptr i_mesh = getCommonMesh({i_rho, i_c, i_u, i_p}); + std::shared_ptr i_mesh = getCommonMesh({rho_v, c_v, u_v, p_v}); if (not i_mesh) { throw NormalError("discrete functions are not defined on the same mesh"); } - if (not checkDiscretizationType({i_rho, i_c, i_u, i_p}, DiscreteFunctionType::P0)) { + if (not checkDiscretizationType({rho_v, c_v, u_v, p_v}, DiscreteFunctionType::P0)) { throw NormalError("acoustic solver expects P0 functions"); } const MeshType& mesh = dynamic_cast<const MeshType&>(*i_mesh); - const DiscreteScalarFunction& rho = dynamic_cast<const DiscreteScalarFunction&>(*i_rho); - const DiscreteScalarFunction& c = dynamic_cast<const DiscreteScalarFunction&>(*i_c); - const DiscreteVectorFunction& u = dynamic_cast<const DiscreteVectorFunction&>(*i_u); - const DiscreteScalarFunction& p = dynamic_cast<const DiscreteScalarFunction&>(*i_p); + const DiscreteScalarFunction& rho = rho_v->get<DiscreteScalarFunction>(); + const DiscreteScalarFunction& c = c_v->get<DiscreteScalarFunction>(); + const DiscreteVectorFunction& u = u_v->get<DiscreteVectorFunction>(); + const DiscreteScalarFunction& p = p_v->get<DiscreteScalarFunction>(); NodeValuePerCell<const Rdxd> Ajr = this->_computeAjr(solver_type, mesh, rho * c); @@ -422,14 +417,14 @@ class AcousticSolverHandler::AcousticSolver final : public AcousticSolverHandler } std::tuple<std::shared_ptr<const IMesh>, - std::shared_ptr<const DiscreteFunctionP0<Dimension, double>>, - std::shared_ptr<const DiscreteFunctionP0<Dimension, Rd>>, - std::shared_ptr<const DiscreteFunctionP0<Dimension, double>>> + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> apply_fluxes(const double& dt, const MeshType& mesh, - const DiscreteFunctionP0<Dimension, double>& rho, - const DiscreteFunctionP0<Dimension, Rd>& u, - const DiscreteFunctionP0<Dimension, double>& E, + const DiscreteScalarFunction& rho, + const DiscreteVectorFunction& u, + const DiscreteScalarFunction& E, const NodeValue<const Rd>& ur, const NodeValuePerCell<const Rd>& Fjr) const { @@ -473,51 +468,51 @@ class AcousticSolverHandler::AcousticSolver final : public AcousticSolverHandler parallel_for( mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { new_rho[j] *= Vj[j] / new_Vj[j]; }); - return {new_mesh, std::make_shared<DiscreteScalarFunction>(new_mesh, new_rho), - std::make_shared<DiscreteVectorFunction>(new_mesh, new_u), - std::make_shared<DiscreteScalarFunction>(new_mesh, new_E)}; + return {new_mesh, std::make_shared<DiscreteFunctionVariant>(DiscreteScalarFunction(new_mesh, new_rho)), + std::make_shared<DiscreteFunctionVariant>(DiscreteVectorFunction(new_mesh, new_u)), + std::make_shared<DiscreteFunctionVariant>(DiscreteScalarFunction(new_mesh, new_E))}; } std::tuple<std::shared_ptr<const IMesh>, - std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>> + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> apply_fluxes(const double& dt, - const std::shared_ptr<const IDiscreteFunction>& rho, - const std::shared_ptr<const IDiscreteFunction>& u, - const std::shared_ptr<const IDiscreteFunction>& E, + const std::shared_ptr<const DiscreteFunctionVariant>& rho_v, + const std::shared_ptr<const DiscreteFunctionVariant>& u_v, + const std::shared_ptr<const DiscreteFunctionVariant>& E_v, const std::shared_ptr<const ItemValueVariant>& ur, const std::shared_ptr<const SubItemValuePerItemVariant>& Fjr) const { - std::shared_ptr i_mesh = getCommonMesh({rho, u, E}); + std::shared_ptr i_mesh = getCommonMesh({rho_v, u_v, E_v}); if (not i_mesh) { throw NormalError("discrete functions are not defined on the same mesh"); } - if (not checkDiscretizationType({rho, u, E}, DiscreteFunctionType::P0)) { + if (not checkDiscretizationType({rho_v, u_v, E_v}, DiscreteFunctionType::P0)) { throw NormalError("acoustic solver expects P0 functions"); } - return this->apply_fluxes(dt, // - dynamic_cast<const MeshType&>(*i_mesh), // - dynamic_cast<const DiscreteScalarFunction&>(*rho), // - dynamic_cast<const DiscreteVectorFunction&>(*u), // - dynamic_cast<const DiscreteScalarFunction&>(*E), // - ur->get<NodeValue<const Rd>>(), // + return this->apply_fluxes(dt, // + dynamic_cast<const MeshType&>(*i_mesh), // + rho_v->get<DiscreteScalarFunction>(), // + u_v->get<DiscreteVectorFunction>(), // + E_v->get<DiscreteScalarFunction>(), // + ur->get<NodeValue<const Rd>>(), // Fjr->get<NodeValuePerCell<const Rd>>()); } std::tuple<std::shared_ptr<const IMesh>, - std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>> + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> apply(const SolverType& solver_type, const double& dt, - const std::shared_ptr<const IDiscreteFunction>& rho, - const std::shared_ptr<const IDiscreteFunction>& u, - const std::shared_ptr<const IDiscreteFunction>& E, - const std::shared_ptr<const IDiscreteFunction>& c, - const std::shared_ptr<const IDiscreteFunction>& p, + const std::shared_ptr<const DiscreteFunctionVariant>& rho, + const std::shared_ptr<const DiscreteFunctionVariant>& u, + const std::shared_ptr<const DiscreteFunctionVariant>& E, + const std::shared_ptr<const DiscreteFunctionVariant>& c, + const std::shared_ptr<const DiscreteFunctionVariant>& p, const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) const { auto [ur, Fjr] = compute_fluxes(solver_type, rho, c, u, p, bc_descriptor_list); diff --git a/src/scheme/AcousticSolver.hpp b/src/scheme/AcousticSolver.hpp index 489b8e795d843f9677daf562214bd0266f803baa..36b62a32a1442b18cbe014a9e90ee28ffad08c8a 100644 --- a/src/scheme/AcousticSolver.hpp +++ b/src/scheme/AcousticSolver.hpp @@ -5,13 +5,13 @@ #include <tuple> #include <vector> -class IDiscreteFunction; +class DiscreteFunctionVariant; class IBoundaryConditionDescriptor; class IMesh; class ItemValueVariant; class SubItemValuePerItemVariant; -double acoustic_dt(const std::shared_ptr<const IDiscreteFunction>& c); +double acoustic_dt(const std::shared_ptr<const DiscreteFunctionVariant>& c); class AcousticSolverHandler { @@ -29,34 +29,34 @@ class AcousticSolverHandler const std::shared_ptr<const SubItemValuePerItemVariant>> compute_fluxes( const SolverType& solver_type, - const std::shared_ptr<const IDiscreteFunction>& rho, - const std::shared_ptr<const IDiscreteFunction>& c, - const std::shared_ptr<const IDiscreteFunction>& u, - const std::shared_ptr<const IDiscreteFunction>& p, + const std::shared_ptr<const DiscreteFunctionVariant>& rho, + const std::shared_ptr<const DiscreteFunctionVariant>& c, + const std::shared_ptr<const DiscreteFunctionVariant>& u, + const std::shared_ptr<const DiscreteFunctionVariant>& p, const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) const = 0; virtual std::tuple<std::shared_ptr<const IMesh>, - std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>> + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> apply_fluxes(const double& dt, - const std::shared_ptr<const IDiscreteFunction>& rho, - const std::shared_ptr<const IDiscreteFunction>& u, - const std::shared_ptr<const IDiscreteFunction>& E, + const std::shared_ptr<const DiscreteFunctionVariant>& rho, + const std::shared_ptr<const DiscreteFunctionVariant>& u, + const std::shared_ptr<const DiscreteFunctionVariant>& E, const std::shared_ptr<const ItemValueVariant>& ur, const std::shared_ptr<const SubItemValuePerItemVariant>& Fjr) const = 0; virtual std::tuple<std::shared_ptr<const IMesh>, - std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>, - std::shared_ptr<const IDiscreteFunction>> + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> apply(const SolverType& solver_type, const double& dt, - const std::shared_ptr<const IDiscreteFunction>& rho, - const std::shared_ptr<const IDiscreteFunction>& u, - const std::shared_ptr<const IDiscreteFunction>& E, - const std::shared_ptr<const IDiscreteFunction>& c, - const std::shared_ptr<const IDiscreteFunction>& p, + const std::shared_ptr<const DiscreteFunctionVariant>& rho, + const std::shared_ptr<const DiscreteFunctionVariant>& u, + const std::shared_ptr<const DiscreteFunctionVariant>& E, + const std::shared_ptr<const DiscreteFunctionVariant>& c, + const std::shared_ptr<const DiscreteFunctionVariant>& p, const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) const = 0; IAcousticSolver() = default; diff --git a/src/scheme/CMakeLists.txt b/src/scheme/CMakeLists.txt index 25e1405a5e9d2f9603a5f50a6abf04350596c58b..88fb5d99cebb75af47c515126165d91a5370b23f 100644 --- a/src/scheme/CMakeLists.txt +++ b/src/scheme/CMakeLists.txt @@ -3,6 +3,7 @@ add_library( PugsScheme AcousticSolver.cpp + HyperelasticSolver.cpp DiscreteFunctionIntegrator.cpp DiscreteFunctionInterpoler.cpp DiscreteFunctionUtils.cpp diff --git a/src/scheme/DiscreteFunctionIntegrator.cpp b/src/scheme/DiscreteFunctionIntegrator.cpp index 93c836461ce14ae05b51b879cf90525f73a793eb..c77f7a2c87ece74da4f48902855e9f3a5f6742bc 100644 --- a/src/scheme/DiscreteFunctionIntegrator.cpp +++ b/src/scheme/DiscreteFunctionIntegrator.cpp @@ -3,10 +3,11 @@ #include <language/utils/IntegrateCellValue.hpp> #include <mesh/MeshCellZone.hpp> #include <scheme/DiscreteFunctionP0.hpp> +#include <scheme/DiscreteFunctionVariant.hpp> #include <utils/Exceptions.hpp> template <size_t Dimension, typename DataType, typename ValueType> -std::shared_ptr<IDiscreteFunction> +DiscreteFunctionVariant DiscreteFunctionIntegrator::_integrateOnZoneList() const { static_assert(std::is_convertible_v<DataType, ValueType>); @@ -61,11 +62,11 @@ DiscreteFunctionIntegrator::_integrateOnZoneList() const parallel_for( zone_cell_list.size(), PUGS_LAMBDA(const size_t i_cell) { cell_value[zone_cell_list[i_cell]] = array[i_cell]; }); - return std::make_shared<DiscreteFunctionP0<Dimension, ValueType>>(p_mesh, cell_value); + return DiscreteFunctionP0<Dimension, ValueType>(p_mesh, cell_value); } template <size_t Dimension, typename DataType, typename ValueType> -std::shared_ptr<IDiscreteFunction> +DiscreteFunctionVariant DiscreteFunctionIntegrator::_integrateGlobally() const { Assert(m_zone_list.size() == 0, "invalid call when zones are defined"); @@ -75,14 +76,13 @@ DiscreteFunctionIntegrator::_integrateGlobally() const static_assert(std::is_convertible_v<DataType, ValueType>); - return std::make_shared< - DiscreteFunctionP0<Dimension, ValueType>>(mesh, - IntegrateCellValue<ValueType(TinyVector<Dimension>)>::template integrate< - MeshType>(m_function_id, *m_quadrature_descriptor, *mesh)); + return DiscreteFunctionP0<Dimension, + ValueType>(mesh, IntegrateCellValue<ValueType(TinyVector<Dimension>)>::template integrate< + MeshType>(m_function_id, *m_quadrature_descriptor, *mesh)); } template <size_t Dimension, typename DataType, typename ValueType> -std::shared_ptr<IDiscreteFunction> +DiscreteFunctionVariant DiscreteFunctionIntegrator::_integrate() const { if (m_zone_list.size() == 0) { @@ -93,7 +93,7 @@ DiscreteFunctionIntegrator::_integrate() const } template <size_t Dimension> -std::shared_ptr<IDiscreteFunction> +DiscreteFunctionVariant DiscreteFunctionIntegrator::_integrate() const { const auto& function_descriptor = m_function_id.descriptor(); @@ -168,10 +168,9 @@ DiscreteFunctionIntegrator::_integrate() const } } -std::shared_ptr<IDiscreteFunction> +DiscreteFunctionVariant DiscreteFunctionIntegrator::integrate() const { - std::shared_ptr<IDiscreteFunction> discrete_function; switch (m_mesh->dimension()) { case 1: { return this->_integrate<1>(); diff --git a/src/scheme/DiscreteFunctionIntegrator.hpp b/src/scheme/DiscreteFunctionIntegrator.hpp index 21a461d54561d67f1f745d3257ec76ee514d264a..e21beabf704b6ed1a7cd3ef4277f751036d274da 100644 --- a/src/scheme/DiscreteFunctionIntegrator.hpp +++ b/src/scheme/DiscreteFunctionIntegrator.hpp @@ -5,10 +5,11 @@ #include <language/utils/FunctionSymbolId.hpp> #include <mesh/IMesh.hpp> #include <mesh/IZoneDescriptor.hpp> -#include <scheme/IDiscreteFunction.hpp> #include <memory> +class DiscreteFunctionVariant; + class DiscreteFunctionIntegrator { private: @@ -18,19 +19,19 @@ class DiscreteFunctionIntegrator const FunctionSymbolId m_function_id; template <size_t Dimension, typename DataType, typename ValueType = DataType> - std::shared_ptr<IDiscreteFunction> _integrateOnZoneList() const; + DiscreteFunctionVariant _integrateOnZoneList() const; template <size_t Dimension, typename DataType, typename ValueType = DataType> - std::shared_ptr<IDiscreteFunction> _integrateGlobally() const; + DiscreteFunctionVariant _integrateGlobally() const; template <size_t Dimension, typename DataType, typename ValueType = DataType> - std::shared_ptr<IDiscreteFunction> _integrate() const; + DiscreteFunctionVariant _integrate() const; template <size_t Dimension> - std::shared_ptr<IDiscreteFunction> _integrate() const; + DiscreteFunctionVariant _integrate() const; public: - std::shared_ptr<IDiscreteFunction> integrate() const; + DiscreteFunctionVariant integrate() const; DiscreteFunctionIntegrator(const std::shared_ptr<const IMesh>& mesh, const std::shared_ptr<const IQuadratureDescriptor>& quadrature_descriptor, diff --git a/src/scheme/DiscreteFunctionInterpoler.cpp b/src/scheme/DiscreteFunctionInterpoler.cpp index e19073f1e93bd70d649f66f7ca0bd2f49ef8a102..c570e67e5ae9b417a60096e5ccb34a025e7a94a4 100644 --- a/src/scheme/DiscreteFunctionInterpoler.cpp +++ b/src/scheme/DiscreteFunctionInterpoler.cpp @@ -3,10 +3,11 @@ #include <language/utils/InterpolateItemValue.hpp> #include <mesh/MeshCellZone.hpp> #include <scheme/DiscreteFunctionP0.hpp> +#include <scheme/DiscreteFunctionVariant.hpp> #include <utils/Exceptions.hpp> template <size_t Dimension, typename DataType, typename ValueType> -std::shared_ptr<IDiscreteFunction> +DiscreteFunctionVariant DiscreteFunctionInterpoler::_interpolateOnZoneList() const { static_assert(std::is_convertible_v<DataType, ValueType>); @@ -61,11 +62,11 @@ DiscreteFunctionInterpoler::_interpolateOnZoneList() const parallel_for( zone_cell_list.size(), PUGS_LAMBDA(const size_t i_cell) { cell_value[zone_cell_list[i_cell]] = array[i_cell]; }); - return std::make_shared<DiscreteFunctionP0<Dimension, ValueType>>(p_mesh, cell_value); + return DiscreteFunctionP0<Dimension, ValueType>(p_mesh, cell_value); } template <size_t Dimension, typename DataType, typename ValueType> -std::shared_ptr<IDiscreteFunction> +DiscreteFunctionVariant DiscreteFunctionInterpoler::_interpolateGlobally() const { Assert(m_zone_list.size() == 0, "invalid call when zones are defined"); @@ -75,10 +76,9 @@ DiscreteFunctionInterpoler::_interpolateGlobally() const MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(*p_mesh); if constexpr (std::is_same_v<DataType, ValueType>) { - return std::make_shared< - DiscreteFunctionP0<Dimension, ValueType>>(p_mesh, - InterpolateItemValue<DataType(TinyVector<Dimension>)>:: - template interpolate<ItemType::cell>(m_function_id, mesh_data.xj())); + return DiscreteFunctionP0<Dimension, ValueType>(p_mesh, InterpolateItemValue<DataType(TinyVector<Dimension>)>:: + template interpolate<ItemType::cell>(m_function_id, + mesh_data.xj())); } else { static_assert(std::is_convertible_v<DataType, ValueType>); @@ -91,12 +91,12 @@ DiscreteFunctionInterpoler::_interpolateGlobally() const parallel_for( p_mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { cell_value[cell_id] = cell_data[cell_id]; }); - return std::make_shared<DiscreteFunctionP0<Dimension, ValueType>>(p_mesh, cell_value); + return DiscreteFunctionP0<Dimension, ValueType>(p_mesh, cell_value); } } template <size_t Dimension, typename DataType, typename ValueType> -std::shared_ptr<IDiscreteFunction> +DiscreteFunctionVariant DiscreteFunctionInterpoler::_interpolate() const { if (m_zone_list.size() == 0) { @@ -107,7 +107,7 @@ DiscreteFunctionInterpoler::_interpolate() const } template <size_t Dimension> -std::shared_ptr<IDiscreteFunction> +DiscreteFunctionVariant DiscreteFunctionInterpoler::_interpolate() const { const auto& function_descriptor = m_function_id.descriptor(); @@ -182,7 +182,7 @@ DiscreteFunctionInterpoler::_interpolate() const } } -std::shared_ptr<IDiscreteFunction> +DiscreteFunctionVariant DiscreteFunctionInterpoler::interpolate() const { switch (m_mesh->dimension()) { diff --git a/src/scheme/DiscreteFunctionInterpoler.hpp b/src/scheme/DiscreteFunctionInterpoler.hpp index 295c2fd9a540269bf484f485716131b1346964e1..0f436d43cf2c347fc437e05016d798bc28aeed77 100644 --- a/src/scheme/DiscreteFunctionInterpoler.hpp +++ b/src/scheme/DiscreteFunctionInterpoler.hpp @@ -4,9 +4,10 @@ #include <language/utils/FunctionSymbolId.hpp> #include <mesh/IMesh.hpp> #include <mesh/IZoneDescriptor.hpp> -#include <scheme/IDiscreteFunction.hpp> #include <scheme/IDiscreteFunctionDescriptor.hpp> +class DiscreteFunctionVariant; + #include <memory> class DiscreteFunctionInterpoler @@ -18,19 +19,19 @@ class DiscreteFunctionInterpoler const FunctionSymbolId m_function_id; template <size_t Dimension, typename DataType, typename ValueType = DataType> - std::shared_ptr<IDiscreteFunction> _interpolateOnZoneList() const; + DiscreteFunctionVariant _interpolateOnZoneList() const; template <size_t Dimension, typename DataType, typename ValueType = DataType> - std::shared_ptr<IDiscreteFunction> _interpolateGlobally() const; + DiscreteFunctionVariant _interpolateGlobally() const; template <size_t Dimension, typename DataType, typename ValueType = DataType> - std::shared_ptr<IDiscreteFunction> _interpolate() const; + DiscreteFunctionVariant _interpolate() const; template <size_t Dimension> - std::shared_ptr<IDiscreteFunction> _interpolate() const; + DiscreteFunctionVariant _interpolate() const; public: - std::shared_ptr<IDiscreteFunction> interpolate() const; + DiscreteFunctionVariant interpolate() const; DiscreteFunctionInterpoler(const std::shared_ptr<const IMesh>& mesh, const std::shared_ptr<const IDiscreteFunctionDescriptor>& discrete_function_descriptor, diff --git a/src/scheme/DiscreteFunctionP0.hpp b/src/scheme/DiscreteFunctionP0.hpp index bb6b484a6bc10bd803e16b8bb54a7cba25a349de..1fb2ce14cee3f42e6c27c262e3ba6deefb5b555d 100644 --- a/src/scheme/DiscreteFunctionP0.hpp +++ b/src/scheme/DiscreteFunctionP0.hpp @@ -1,7 +1,7 @@ #ifndef DISCRETE_FUNCTION_P0_HPP #define DISCRETE_FUNCTION_P0_HPP -#include <scheme/IDiscreteFunction.hpp> +#include <language/utils/ASTNodeDataTypeTraits.hpp> #include <mesh/Connectivity.hpp> #include <mesh/ItemValueUtils.hpp> @@ -11,14 +11,12 @@ #include <scheme/DiscreteFunctionDescriptorP0.hpp> template <size_t Dimension, typename DataType> -class DiscreteFunctionP0 : public IDiscreteFunction +class DiscreteFunctionP0 { public: using data_type = DataType; using MeshType = Mesh<Connectivity<Dimension>>; - static constexpr HandledItemDataType handled_data_type = HandledItemDataType::value; - friend class DiscreteFunctionP0<Dimension, std::add_const_t<DataType>>; friend class DiscreteFunctionP0<Dimension, std::remove_const_t<DataType>>; @@ -31,9 +29,9 @@ class DiscreteFunctionP0 : public IDiscreteFunction public: PUGS_INLINE ASTNodeDataType - dataType() const final + dataType() const { - return ast_node_data_type_from<DataType>; + return ast_node_data_type_from<std::remove_const_t<DataType>>; } PUGS_INLINE @@ -52,7 +50,7 @@ class DiscreteFunctionP0 : public IDiscreteFunction PUGS_INLINE const IDiscreteFunctionDescriptor& - descriptor() const final + descriptor() const { return m_discrete_function_descriptor; } @@ -450,7 +448,7 @@ class DiscreteFunctionP0 : public IDiscreteFunction return result; } - PUGS_INLINE friend DiscreteFunctionP0 + PUGS_INLINE friend DiscreteFunctionP0<Dimension, double> atan2(const DiscreteFunctionP0& f, const DiscreteFunctionP0& g) { static_assert(std::is_arithmetic_v<DataType>); @@ -463,7 +461,7 @@ class DiscreteFunctionP0 : public IDiscreteFunction return result; } - PUGS_INLINE friend DiscreteFunctionP0 + PUGS_INLINE friend DiscreteFunctionP0<Dimension, double> atan2(const double a, const DiscreteFunctionP0& f) { static_assert(std::is_arithmetic_v<DataType>); @@ -475,7 +473,7 @@ class DiscreteFunctionP0 : public IDiscreteFunction return result; } - PUGS_INLINE friend DiscreteFunctionP0 + PUGS_INLINE friend DiscreteFunctionP0<Dimension, double> atan2(const DiscreteFunctionP0& f, const double a) { static_assert(std::is_arithmetic_v<DataType>); @@ -487,7 +485,7 @@ class DiscreteFunctionP0 : public IDiscreteFunction return result; } - PUGS_INLINE friend DiscreteFunctionP0 + PUGS_INLINE friend DiscreteFunctionP0<Dimension, double> pow(const DiscreteFunctionP0& f, const DiscreteFunctionP0& g) { static_assert(std::is_arithmetic_v<DataType>); @@ -500,7 +498,7 @@ class DiscreteFunctionP0 : public IDiscreteFunction return result; } - PUGS_INLINE friend DiscreteFunctionP0 + PUGS_INLINE friend DiscreteFunctionP0<Dimension, double> pow(const double a, const DiscreteFunctionP0& f) { static_assert(std::is_arithmetic_v<DataType>); @@ -512,7 +510,7 @@ class DiscreteFunctionP0 : public IDiscreteFunction return result; } - PUGS_INLINE friend DiscreteFunctionP0 + PUGS_INLINE friend DiscreteFunctionP0<Dimension, double> pow(const DiscreteFunctionP0& f, const double a) { static_assert(std::is_arithmetic_v<DataType>); @@ -524,11 +522,62 @@ class DiscreteFunctionP0 : public IDiscreteFunction return result; } + PUGS_INLINE friend DiscreteFunctionP0<Dimension, double> + det(const DiscreteFunctionP0& A) + { + static_assert(is_tiny_matrix_v<std::decay_t<DataType>>); + Assert(A.m_cell_values.isBuilt()); + DiscreteFunctionP0<Dimension, double> result{A.m_mesh}; + parallel_for( + A.m_mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { result[cell_id] = det(A[cell_id]); }); + + return result; + } + + PUGS_INLINE friend DiscreteFunctionP0<Dimension, double> + trace(const DiscreteFunctionP0& A) + { + static_assert(is_tiny_matrix_v<std::decay_t<DataType>>); + Assert(A.m_cell_values.isBuilt()); + DiscreteFunctionP0<Dimension, double> result{A.m_mesh}; + parallel_for( + A.m_mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { result[cell_id] = trace(A[cell_id]); }); + + return result; + } + + PUGS_INLINE friend DiscreteFunctionP0<Dimension, std::remove_const_t<DataType>> + inverse(const DiscreteFunctionP0& A) + { + static_assert(is_tiny_matrix_v<std::decay_t<DataType>>); + static_assert(DataType::NumberOfRows == DataType::NumberOfColumns, "cannot compute inverse of non square matrices"); + Assert(A.m_cell_values.isBuilt()); + DiscreteFunctionP0<Dimension, std::remove_const_t<DataType>> result{A.m_mesh}; + parallel_for( + A.m_mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { result[cell_id] = inverse(A[cell_id]); }); + + return result; + } + + PUGS_INLINE friend DiscreteFunctionP0<Dimension, std::remove_const_t<DataType>> + transpose(const DiscreteFunctionP0& A) + { + static_assert(is_tiny_matrix_v<std::decay_t<DataType>>); + static_assert(DataType::NumberOfRows == DataType::NumberOfColumns, "cannot compute inverse of non square matrices"); + Assert(A.m_cell_values.isBuilt()); + DiscreteFunctionP0<Dimension, std::remove_const_t<DataType>> result{A.m_mesh}; + parallel_for( + A.m_mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { result[cell_id] = transpose(A[cell_id]); }); + + return result; + } + PUGS_INLINE friend DiscreteFunctionP0<Dimension, double> dot(const DiscreteFunctionP0& f, const DiscreteFunctionP0& g) { - static_assert(is_tiny_vector_v<DataType>); + static_assert(is_tiny_vector_v<std::decay_t<DataType>>); Assert(f.m_cell_values.isBuilt() and g.m_cell_values.isBuilt()); + Assert(f.m_mesh == g.m_mesh); DiscreteFunctionP0<Dimension, double> result{f.m_mesh}; parallel_for( f.m_mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { result[cell_id] = dot(f[cell_id], g[cell_id]); }); @@ -539,7 +588,7 @@ class DiscreteFunctionP0 : public IDiscreteFunction PUGS_INLINE friend DiscreteFunctionP0<Dimension, double> dot(const DiscreteFunctionP0& f, const DataType& a) { - static_assert(is_tiny_vector_v<DataType>); + static_assert(is_tiny_vector_v<std::decay_t<DataType>>); Assert(f.m_cell_values.isBuilt()); DiscreteFunctionP0<Dimension, double> result{f.m_mesh}; parallel_for( @@ -551,7 +600,7 @@ class DiscreteFunctionP0 : public IDiscreteFunction PUGS_INLINE friend DiscreteFunctionP0<Dimension, double> dot(const DataType& a, const DiscreteFunctionP0& f) { - static_assert(is_tiny_vector_v<DataType>); + static_assert(is_tiny_vector_v<std::decay_t<DataType>>); Assert(f.m_cell_values.isBuilt()); DiscreteFunctionP0<Dimension, double> result{f.m_mesh}; parallel_for( @@ -569,7 +618,7 @@ class DiscreteFunctionP0 : public IDiscreteFunction return min(f.m_cell_values); } - PUGS_INLINE friend DiscreteFunctionP0 + PUGS_INLINE friend DiscreteFunctionP0<Dimension, std::remove_const_t<DataType>> min(const DiscreteFunctionP0& f, const DiscreteFunctionP0& g) { static_assert(std::is_arithmetic_v<DataType>); @@ -582,7 +631,7 @@ class DiscreteFunctionP0 : public IDiscreteFunction return result; } - PUGS_INLINE friend DiscreteFunctionP0 + PUGS_INLINE friend DiscreteFunctionP0<Dimension, std::remove_const_t<DataType>> min(const double a, const DiscreteFunctionP0& f) { static_assert(std::is_arithmetic_v<DataType>); @@ -594,7 +643,7 @@ class DiscreteFunctionP0 : public IDiscreteFunction return result; } - PUGS_INLINE friend DiscreteFunctionP0 + PUGS_INLINE friend DiscreteFunctionP0<Dimension, std::remove_const_t<DataType>> min(const DiscreteFunctionP0& f, const double a) { static_assert(std::is_arithmetic_v<DataType>); @@ -615,7 +664,7 @@ class DiscreteFunctionP0 : public IDiscreteFunction return max(f.m_cell_values); } - PUGS_INLINE friend DiscreteFunctionP0 + PUGS_INLINE friend DiscreteFunctionP0<Dimension, std::remove_const_t<DataType>> max(const DiscreteFunctionP0& f, const DiscreteFunctionP0& g) { static_assert(std::is_arithmetic_v<DataType>); @@ -628,7 +677,7 @@ class DiscreteFunctionP0 : public IDiscreteFunction return result; } - PUGS_INLINE friend DiscreteFunctionP0 + PUGS_INLINE friend DiscreteFunctionP0<Dimension, std::remove_const_t<DataType>> max(const double a, const DiscreteFunctionP0& f) { static_assert(std::is_arithmetic_v<DataType>); @@ -640,7 +689,7 @@ class DiscreteFunctionP0 : public IDiscreteFunction return result; } - PUGS_INLINE friend DiscreteFunctionP0 + PUGS_INLINE friend DiscreteFunctionP0<Dimension, std::remove_const_t<DataType>> max(const DiscreteFunctionP0& f, const double a) { static_assert(std::is_arithmetic_v<DataType>); @@ -669,16 +718,23 @@ class DiscreteFunctionP0 : public IDiscreteFunction public: PUGS_INLINE - operator data_type() + operator std::decay_t<data_type>() { - data_type reduced_value; + std::decay_t<data_type> reduced_value; + if constexpr (std::is_arithmetic_v<std::decay_t<data_type>>) { + reduced_value = 0; + } else { + static_assert(is_tiny_vector_v<std::decay_t<data_type>> or is_tiny_matrix_v<std::decay_t<data_type>>, + "invalid data type"); + reduced_value = zero; + } parallel_reduce(m_cell_volume.numberOfItems(), *this, reduced_value); return reduced_value; } PUGS_INLINE void - operator()(const CellId& cell_id, data_type& data) const + operator()(const CellId& cell_id, std::decay_t<data_type>& data) const { if (m_cell_is_owned[cell_id]) { data += m_cell_volume[cell_id] * m_function[cell_id]; @@ -687,19 +743,20 @@ class DiscreteFunctionP0 : public IDiscreteFunction PUGS_INLINE void - join(volatile data_type& dst, const volatile data_type& src) const + join(volatile std::decay_t<data_type>& dst, const volatile std::decay_t<data_type>& src) const { dst += src; } PUGS_INLINE void - init(data_type& value) const + init(std::decay_t<data_type>& value) const { if constexpr (std::is_arithmetic_v<data_type>) { value = 0; } else { - static_assert(is_tiny_vector_v<data_type> or is_tiny_matrix_v<data_type>, "invalid data type"); + static_assert(is_tiny_vector_v<std::decay_t<data_type>> or is_tiny_matrix_v<std::decay_t<data_type>>, + "invalid data type"); value = zero; } } diff --git a/src/scheme/DiscreteFunctionP0Vector.hpp b/src/scheme/DiscreteFunctionP0Vector.hpp index 8eaa5d0a7580ddc65cb17e82d6f5551f86114e1c..7bd833f344ffd29f6f47f6fa0d0bff13a2407339 100644 --- a/src/scheme/DiscreteFunctionP0Vector.hpp +++ b/src/scheme/DiscreteFunctionP0Vector.hpp @@ -1,8 +1,6 @@ #ifndef DISCRETE_FUNCTION_P0_VECTOR_HPP #define DISCRETE_FUNCTION_P0_VECTOR_HPP -#include <scheme/IDiscreteFunction.hpp> - #include <algebra/Vector.hpp> #include <mesh/Connectivity.hpp> #include <mesh/ItemArray.hpp> @@ -14,14 +12,12 @@ #include <utils/Exceptions.hpp> template <size_t Dimension, typename DataType> -class DiscreteFunctionP0Vector : public IDiscreteFunction +class DiscreteFunctionP0Vector { public: using data_type = DataType; using MeshType = Mesh<Connectivity<Dimension>>; - static constexpr HandledItemDataType handled_data_type = HandledItemDataType::vector; - friend class DiscreteFunctionP0Vector<Dimension, std::add_const_t<DataType>>; friend class DiscreteFunctionP0Vector<Dimension, std::remove_const_t<DataType>>; @@ -36,9 +32,9 @@ class DiscreteFunctionP0Vector : public IDiscreteFunction public: PUGS_INLINE ASTNodeDataType - dataType() const final + dataType() const { - return ast_node_data_type_from<data_type>; + return ast_node_data_type_from<std::remove_const_t<data_type>>; } PUGS_INLINE @@ -64,7 +60,7 @@ class DiscreteFunctionP0Vector : public IDiscreteFunction PUGS_INLINE const IDiscreteFunctionDescriptor& - descriptor() const final + descriptor() const { return m_discrete_function_descriptor; } @@ -195,6 +191,26 @@ class DiscreteFunctionP0Vector : public IDiscreteFunction return product; } + PUGS_INLINE friend DiscreteFunctionP0<Dimension, double> + sumOfComponents(const DiscreteFunctionP0Vector& f) + { + DiscreteFunctionP0<Dimension, double> result{f.m_mesh}; + + parallel_for( + f.m_mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const auto& f_cell_id = f[cell_id]; + + double sum = 0; + for (size_t i = 0; i < f.size(); ++i) { + sum += f_cell_id[i]; + } + + result[cell_id] = sum; + }); + + return result; + } + PUGS_INLINE friend DiscreteFunctionP0<Dimension, double> dot(const DiscreteFunctionP0Vector& f, const DiscreteFunctionP0Vector& g) { diff --git a/src/scheme/DiscreteFunctionUtils.cpp b/src/scheme/DiscreteFunctionUtils.cpp index fe861c0868b6bf620696cba09d8ac72bcf6aa948..ba2416a9ab08e03e75bb0824f32930c105cd366c 100644 --- a/src/scheme/DiscreteFunctionUtils.cpp +++ b/src/scheme/DiscreteFunctionUtils.cpp @@ -4,128 +4,106 @@ #include <mesh/IMesh.hpp> #include <mesh/Mesh.hpp> #include <scheme/DiscreteFunctionP0.hpp> +#include <scheme/DiscreteFunctionVariant.hpp> #include <utils/Stringify.hpp> -template <size_t Dimension, typename DataType> -std::shared_ptr<const IDiscreteFunction> -shallowCopy(const std::shared_ptr<const Mesh<Connectivity<Dimension>>>& mesh, - const std::shared_ptr<const DiscreteFunctionP0<Dimension, DataType>>& discrete_function) +std::shared_ptr<const IMesh> +getCommonMesh(const std::vector<std::shared_ptr<const DiscreteFunctionVariant>>& discrete_function_variant_list) { - Assert(mesh->shared_connectivity() == - dynamic_cast<const Mesh<Connectivity<Dimension>>&>(*discrete_function->mesh()).shared_connectivity(), - "connectivities should be the same"); + std::shared_ptr<const IMesh> i_mesh; + bool is_same_mesh = true; + for (const auto& discrete_function_variant : discrete_function_variant_list) { + std::visit( + [&](auto&& discrete_function) { + if (not i_mesh.use_count()) { + i_mesh = discrete_function.mesh(); + } else { + if (i_mesh != discrete_function.mesh()) { + is_same_mesh = false; + } + } + }, + discrete_function_variant->discreteFunction()); + } + if (not is_same_mesh) { + i_mesh.reset(); + } + return i_mesh; +} + +bool +hasSameMesh(const std::vector<std::shared_ptr<const DiscreteFunctionVariant>>& discrete_function_variant_list) +{ + std::shared_ptr<const IMesh> i_mesh; + bool is_same_mesh = true; + for (const auto& discrete_function_variant : discrete_function_variant_list) { + std::visit( + [&](auto&& discrete_function) { + if (not i_mesh.use_count()) { + i_mesh = discrete_function.mesh(); + } else { + if (i_mesh != discrete_function.mesh()) { + is_same_mesh = false; + } + } + }, + discrete_function_variant->discreteFunction()); + } - return std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh, discrete_function->cellValues()); + return is_same_mesh; } -template <size_t Dimension> -std::shared_ptr<const IDiscreteFunction> -shallowCopy(const std::shared_ptr<const Mesh<Connectivity<Dimension>>>& mesh, - const std::shared_ptr<const IDiscreteFunction>& discrete_function) +template <typename MeshType, typename DiscreteFunctionT> +std::shared_ptr<const DiscreteFunctionVariant> +shallowCopy(const std::shared_ptr<const MeshType>& mesh, const DiscreteFunctionT& f) { - const std::shared_ptr function_mesh = - std::dynamic_pointer_cast<const Mesh<Connectivity<Dimension>>>(discrete_function->mesh()); + const std::shared_ptr function_mesh = std::dynamic_pointer_cast<const MeshType>(f.mesh()); if (mesh->shared_connectivity() != function_mesh->shared_connectivity()) { throw NormalError("cannot shallow copy when connectivity changes"); } - switch (discrete_function->descriptor().type()) { - case DiscreteFunctionType::P0: { - switch (discrete_function->dataType()) { - case ASTNodeDataType::double_t: { - return shallowCopy(mesh, - std::dynamic_pointer_cast<const DiscreteFunctionP0<Dimension, double>>(discrete_function)); + if constexpr (std::is_same_v<MeshType, typename DiscreteFunctionT::MeshType>) { + if constexpr (is_discrete_function_P0_v<DiscreteFunctionT>) { + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionT(mesh, f.cellValues())); + } else if constexpr (is_discrete_function_P0_vector_v<DiscreteFunctionT>) { + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionT(mesh, f.cellArrays())); + } else { + throw UnexpectedError("invalid discrete function type"); } - case ASTNodeDataType::vector_t: { - switch (discrete_function->dataType().dimension()) { - case 1: { - return shallowCopy(mesh, std::dynamic_pointer_cast<const DiscreteFunctionP0<Dimension, TinyVector<1>>>( - discrete_function)); - } - case 2: { - return shallowCopy(mesh, std::dynamic_pointer_cast<const DiscreteFunctionP0<Dimension, TinyVector<2>>>( - discrete_function)); - } - case 3: { - return shallowCopy(mesh, std::dynamic_pointer_cast<const DiscreteFunctionP0<Dimension, TinyVector<3>>>( - discrete_function)); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid data vector dimension: " + stringify(discrete_function->dataType().dimension())); - } - // LCOV_EXCL_STOP - } - } - case ASTNodeDataType::matrix_t: { - if (discrete_function->dataType().numberOfRows() != discrete_function->dataType().numberOfColumns()) { - // LCOV_EXCL_START - throw UnexpectedError( - "invalid data matrix dimensions: " + stringify(discrete_function->dataType().numberOfRows()) + "x" + - stringify(discrete_function->dataType().numberOfColumns())); - // LCOV_EXCL_STOP + } else { + throw UnexpectedError("invalid mesh types"); + } +} + +std::shared_ptr<const DiscreteFunctionVariant> +shallowCopy(const std::shared_ptr<const IMesh>& mesh, + const std::shared_ptr<const DiscreteFunctionVariant>& discrete_function_variant) +{ + return std::visit( + [&](auto&& f) { + if (mesh == f.mesh()) { + return discrete_function_variant; + } else if (mesh->dimension() != f.mesh()->dimension()) { + throw NormalError("incompatible mesh dimensions"); } - switch (discrete_function->dataType().numberOfRows()) { + + switch (mesh->dimension()) { case 1: { - return shallowCopy(mesh, std::dynamic_pointer_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>( - discrete_function)); + return shallowCopy(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(mesh), f); } case 2: { - return shallowCopy(mesh, std::dynamic_pointer_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>( - discrete_function)); + return shallowCopy(std::dynamic_pointer_cast<const Mesh<Connectivity<2>>>(mesh), f); } case 3: { - return shallowCopy(mesh, std::dynamic_pointer_cast<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>( - discrete_function)); + return shallowCopy(std::dynamic_pointer_cast<const Mesh<Connectivity<3>>>(mesh), f); } // LCOV_EXCL_START default: { - throw UnexpectedError( - "invalid data matrix dimensions: " + stringify(discrete_function->dataType().numberOfRows()) + "x" + - stringify(discrete_function->dataType().numberOfColumns())); + throw UnexpectedError("invalid mesh dimension"); } // LCOV_EXCL_STOP } - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid kind of P0 function: invalid data type"); - } - // LCOV_EXCL_STOP - } - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid discretization type"); - } - // LCOV_EXCL_STOP - } -} - -std::shared_ptr<const IDiscreteFunction> -shallowCopy(const std::shared_ptr<const IMesh>& mesh, const std::shared_ptr<const IDiscreteFunction>& discrete_function) -{ - if (mesh == discrete_function->mesh()) { - return discrete_function; - } else if (mesh->dimension() != discrete_function->mesh()->dimension()) { - throw NormalError("incompatible mesh dimensions"); - } - - switch (mesh->dimension()) { - case 1: { - return shallowCopy(std::dynamic_pointer_cast<const Mesh<Connectivity<1>>>(mesh), discrete_function); - } - case 2: { - return shallowCopy(std::dynamic_pointer_cast<const Mesh<Connectivity<2>>>(mesh), discrete_function); - } - case 3: { - return shallowCopy(std::dynamic_pointer_cast<const Mesh<Connectivity<3>>>(mesh), discrete_function); - } - // LCOV_EXCL_START - default: { - throw UnexpectedError("invalid mesh dimension"); - } - // LCOV_EXCL_STOP - } + }, + discrete_function_variant->discreteFunction()); } diff --git a/src/scheme/DiscreteFunctionUtils.hpp b/src/scheme/DiscreteFunctionUtils.hpp index 1eea93a7eae8db4c592b6bbec35341ad33e35bdc..91acbccb7c1444e2adfbc55333b1ee2a0e89d3b9 100644 --- a/src/scheme/DiscreteFunctionUtils.hpp +++ b/src/scheme/DiscreteFunctionUtils.hpp @@ -2,42 +2,32 @@ #define DISCRETE_FUNCTION_UTILS_HPP #include <scheme/DiscreteFunctionType.hpp> -#include <scheme/IDiscreteFunction.hpp> +#include <scheme/DiscreteFunctionVariant.hpp> #include <scheme/IDiscreteFunctionDescriptor.hpp> #include <vector> PUGS_INLINE bool -checkDiscretizationType(const std::vector<std::shared_ptr<const IDiscreteFunction>>& discrete_function_list, +checkDiscretizationType(const std::vector<std::shared_ptr<const DiscreteFunctionVariant>>& discrete_function_list, const DiscreteFunctionType& discrete_function_type) { - for (auto discrete_function : discrete_function_list) { - if (discrete_function->descriptor().type() != discrete_function_type) { + for (const auto& discrete_function_variant : discrete_function_list) { + if (not std::visit([&](auto&& f) { return f.descriptor().type() == discrete_function_type; }, + discrete_function_variant->discreteFunction())) { return false; } } return true; } -PUGS_INLINE -std::shared_ptr<const IMesh> -getCommonMesh(const std::vector<std::shared_ptr<const IDiscreteFunction>>& discrete_function_list) -{ - std::shared_ptr<const IMesh> i_mesh; - for (auto discrete_function : discrete_function_list) { - if (not i_mesh.use_count()) { - i_mesh = discrete_function->mesh(); - } else { - if (i_mesh != discrete_function->mesh()) { - return {}; - } - } - } - return i_mesh; -} +std::shared_ptr<const IMesh> getCommonMesh( + const std::vector<std::shared_ptr<const DiscreteFunctionVariant>>& discrete_function_variant_list); + +bool hasSameMesh(const std::vector<std::shared_ptr<const DiscreteFunctionVariant>>& discrete_function_variant_list); -std::shared_ptr<const IDiscreteFunction> shallowCopy(const std::shared_ptr<const IMesh>& mesh, - const std::shared_ptr<const IDiscreteFunction>& discrete_function); +std::shared_ptr<const DiscreteFunctionVariant> shallowCopy( + const std::shared_ptr<const IMesh>& mesh, + const std::shared_ptr<const DiscreteFunctionVariant>& discrete_function); #endif // DISCRETE_FUNCTION_UTILS_HPP diff --git a/src/scheme/DiscreteFunctionVariant.hpp b/src/scheme/DiscreteFunctionVariant.hpp new file mode 100644 index 0000000000000000000000000000000000000000..6feb86bcbc564898ae7801a0f3ca2bab8d370097 --- /dev/null +++ b/src/scheme/DiscreteFunctionVariant.hpp @@ -0,0 +1,105 @@ +#ifndef DISCRETE_FUNCTION_VARIANT_HPP +#define DISCRETE_FUNCTION_VARIANT_HPP + +#include <algebra/TinyMatrix.hpp> +#include <algebra/TinyVector.hpp> +#include <scheme/DiscreteFunctionP0.hpp> +#include <scheme/DiscreteFunctionP0Vector.hpp> +#include <utils/Demangle.hpp> +#include <utils/Exceptions.hpp> + +class DiscreteFunctionVariant +{ + private: + using Variant = std::variant<DiscreteFunctionP0<1, const double>, + DiscreteFunctionP0<1, const TinyVector<1>>, + DiscreteFunctionP0<1, const TinyVector<2>>, + DiscreteFunctionP0<1, const TinyVector<3>>, + DiscreteFunctionP0<1, const TinyMatrix<1>>, + DiscreteFunctionP0<1, const TinyMatrix<2>>, + DiscreteFunctionP0<1, const TinyMatrix<3>>, + + DiscreteFunctionP0<2, const double>, + DiscreteFunctionP0<2, const TinyVector<1>>, + DiscreteFunctionP0<2, const TinyVector<2>>, + DiscreteFunctionP0<2, const TinyVector<3>>, + DiscreteFunctionP0<2, const TinyMatrix<1>>, + DiscreteFunctionP0<2, const TinyMatrix<2>>, + DiscreteFunctionP0<2, const TinyMatrix<3>>, + + DiscreteFunctionP0<3, const double>, + DiscreteFunctionP0<3, const TinyVector<1>>, + DiscreteFunctionP0<3, const TinyVector<2>>, + DiscreteFunctionP0<3, const TinyVector<3>>, + DiscreteFunctionP0<3, const TinyMatrix<1>>, + DiscreteFunctionP0<3, const TinyMatrix<2>>, + DiscreteFunctionP0<3, const TinyMatrix<3>>, + + DiscreteFunctionP0Vector<1, const double>, + DiscreteFunctionP0Vector<2, const double>, + DiscreteFunctionP0Vector<3, const double>>; + + Variant m_discrete_function; + + public: + PUGS_INLINE + const Variant& + discreteFunction() const + { + return m_discrete_function; + } + + template <typename DiscreteFunctionT> + PUGS_INLINE auto + get() const + { + static_assert(is_discrete_function_v<DiscreteFunctionT>, "invalid template argument"); + using DataType = typename DiscreteFunctionT::data_type; + static_assert(std::is_const_v<DataType>, "data type of extracted discrete function must be const"); + + if (not std::holds_alternative<DiscreteFunctionT>(this->m_discrete_function)) { + std::ostringstream error_msg; + error_msg << "invalid discrete function type\n"; + error_msg << "- required " << rang::fgB::red << demangle<DiscreteFunctionT>() << rang::fg::reset << '\n'; + error_msg << "- contains " << rang::fgB::yellow + << std::visit([](auto&& f) -> std::string { return demangle<decltype(f)>(); }, + this->m_discrete_function) + << rang::fg::reset; + throw NormalError(error_msg.str()); + } + return std::get<DiscreteFunctionT>(this->discreteFunction()); + } + + template <size_t Dimension, typename DataType> + DiscreteFunctionVariant(const DiscreteFunctionP0<Dimension, DataType>& discrete_function) + : m_discrete_function{DiscreteFunctionP0<Dimension, const DataType>{discrete_function}} + { + static_assert(std::is_same_v<std::remove_const_t<DataType>, double> or // + std::is_same_v<std::remove_const_t<DataType>, TinyVector<1, double>> or // + std::is_same_v<std::remove_const_t<DataType>, TinyVector<2, double>> or // + std::is_same_v<std::remove_const_t<DataType>, TinyVector<3, double>> or // + std::is_same_v<std::remove_const_t<DataType>, TinyMatrix<1, 1, double>> or // + std::is_same_v<std::remove_const_t<DataType>, TinyMatrix<2, 2, double>> or // + std::is_same_v<std::remove_const_t<DataType>, TinyMatrix<3, 3, double>>, + "DiscreteFunctionP0 with this DataType is not allowed in variant"); + } + + template <size_t Dimension, typename DataType> + DiscreteFunctionVariant(const DiscreteFunctionP0Vector<Dimension, DataType>& discrete_function) + : m_discrete_function{DiscreteFunctionP0Vector<Dimension, const DataType>{discrete_function}} + { + static_assert(std::is_same_v<std::remove_const_t<DataType>, double>, + "DiscreteFunctionP0Vector with this DataType is not allowed in variant"); + } + + DiscreteFunctionVariant& operator=(DiscreteFunctionVariant&&) = default; + DiscreteFunctionVariant& operator=(const DiscreteFunctionVariant&) = default; + + DiscreteFunctionVariant(const DiscreteFunctionVariant&) = default; + DiscreteFunctionVariant(DiscreteFunctionVariant&&) = default; + + DiscreteFunctionVariant() = delete; + ~DiscreteFunctionVariant() = default; +}; + +#endif // DISCRETE_FUNCTION_VARIANT_HPP diff --git a/src/scheme/DiscreteFunctionVectorIntegrator.cpp b/src/scheme/DiscreteFunctionVectorIntegrator.cpp index cfa65b1787090a06c6de0ac6bf774b3771a4a1eb..80b9e711ebfe9e45297e1a01a1d63ad37da72914 100644 --- a/src/scheme/DiscreteFunctionVectorIntegrator.cpp +++ b/src/scheme/DiscreteFunctionVectorIntegrator.cpp @@ -3,10 +3,11 @@ #include <language/utils/IntegrateCellArray.hpp> #include <mesh/MeshCellZone.hpp> #include <scheme/DiscreteFunctionP0Vector.hpp> +#include <scheme/DiscreteFunctionVariant.hpp> #include <utils/Exceptions.hpp> template <size_t Dimension, typename DataType> -std::shared_ptr<IDiscreteFunction> +DiscreteFunctionVariant DiscreteFunctionVectorIntegrator::_integrateOnZoneList() const { Assert(m_zone_list.size() > 0, "no zone list provided"); @@ -62,25 +63,24 @@ DiscreteFunctionVectorIntegrator::_integrateOnZoneList() const } }); - return std::make_shared<DiscreteFunctionP0Vector<Dimension, DataType>>(p_mesh, cell_array); + return DiscreteFunctionP0Vector<Dimension, DataType>(p_mesh, cell_array); } template <size_t Dimension, typename DataType> -std::shared_ptr<IDiscreteFunction> +DiscreteFunctionVariant DiscreteFunctionVectorIntegrator::_integrateGlobally() const { Assert(m_zone_list.size() == 0, "invalid call when zones are defined"); std::shared_ptr mesh = std::dynamic_pointer_cast<const Mesh<Connectivity<Dimension>>>(m_mesh); - return std::make_shared< - DiscreteFunctionP0Vector<Dimension, DataType>>(mesh, IntegrateCellArray<DataType(TinyVector<Dimension>)>:: - template integrate(m_function_id_list, - *m_quadrature_descriptor, *mesh)); + return DiscreteFunctionP0Vector<Dimension, DataType>(mesh, IntegrateCellArray<DataType(TinyVector<Dimension>)>:: + template integrate(m_function_id_list, + *m_quadrature_descriptor, *mesh)); } template <size_t Dimension, typename DataType> -std::shared_ptr<IDiscreteFunction> +DiscreteFunctionVariant DiscreteFunctionVectorIntegrator::_integrate() const { if (m_zone_list.size() == 0) { @@ -91,7 +91,7 @@ DiscreteFunctionVectorIntegrator::_integrate() const } template <size_t Dimension> -std::shared_ptr<IDiscreteFunction> +DiscreteFunctionVariant DiscreteFunctionVectorIntegrator::_integrate() const { for (const auto& function_id : m_function_id_list) { @@ -117,7 +117,7 @@ DiscreteFunctionVectorIntegrator::_integrate() const return this->_integrate<Dimension, double>(); } -std::shared_ptr<IDiscreteFunction> +DiscreteFunctionVariant DiscreteFunctionVectorIntegrator::integrate() const { if (m_discrete_function_descriptor->type() != DiscreteFunctionType::P0Vector) { diff --git a/src/scheme/DiscreteFunctionVectorIntegrator.hpp b/src/scheme/DiscreteFunctionVectorIntegrator.hpp index 55f5fe3572cbb237e28b9bf86ff7bda19db20a98..44b192bc985888325a691db1433737d5c5a03ca0 100644 --- a/src/scheme/DiscreteFunctionVectorIntegrator.hpp +++ b/src/scheme/DiscreteFunctionVectorIntegrator.hpp @@ -5,12 +5,13 @@ #include <language/utils/FunctionSymbolId.hpp> #include <mesh/IMesh.hpp> #include <mesh/IZoneDescriptor.hpp> -#include <scheme/IDiscreteFunction.hpp> #include <scheme/IDiscreteFunctionDescriptor.hpp> #include <memory> #include <vector> +class DiscreteFunctionVariant; + class DiscreteFunctionVectorIntegrator { private: @@ -21,19 +22,19 @@ class DiscreteFunctionVectorIntegrator const std::vector<FunctionSymbolId> m_function_id_list; template <size_t Dimension, typename DataType> - std::shared_ptr<IDiscreteFunction> _integrateOnZoneList() const; + DiscreteFunctionVariant _integrateOnZoneList() const; template <size_t Dimension, typename DataType> - std::shared_ptr<IDiscreteFunction> _integrateGlobally() const; + DiscreteFunctionVariant _integrateGlobally() const; template <size_t Dimension, typename DataType> - std::shared_ptr<IDiscreteFunction> _integrate() const; + DiscreteFunctionVariant _integrate() const; template <size_t Dimension> - std::shared_ptr<IDiscreteFunction> _integrate() const; + DiscreteFunctionVariant _integrate() const; public: - std::shared_ptr<IDiscreteFunction> integrate() const; + DiscreteFunctionVariant integrate() const; DiscreteFunctionVectorIntegrator( const std::shared_ptr<const IMesh>& mesh, diff --git a/src/scheme/DiscreteFunctionVectorInterpoler.cpp b/src/scheme/DiscreteFunctionVectorInterpoler.cpp index 128c735e4ae8e158f3dc42bf3d5ed47b17ac3fb5..b416400c65a719614be50a53f167a44d859c9497 100644 --- a/src/scheme/DiscreteFunctionVectorInterpoler.cpp +++ b/src/scheme/DiscreteFunctionVectorInterpoler.cpp @@ -3,10 +3,11 @@ #include <language/utils/InterpolateItemArray.hpp> #include <mesh/MeshCellZone.hpp> #include <scheme/DiscreteFunctionP0Vector.hpp> +#include <scheme/DiscreteFunctionVariant.hpp> #include <utils/Exceptions.hpp> template <size_t Dimension, typename DataType> -std::shared_ptr<IDiscreteFunction> +DiscreteFunctionVariant DiscreteFunctionVectorInterpoler::_interpolateOnZoneList() const { Assert(m_zone_list.size() > 0, "no zone list provided"); @@ -60,11 +61,11 @@ DiscreteFunctionVectorInterpoler::_interpolateOnZoneList() const } }); - return std::make_shared<DiscreteFunctionP0Vector<Dimension, DataType>>(p_mesh, cell_array); + return DiscreteFunctionP0Vector<Dimension, DataType>(p_mesh, cell_array); } template <size_t Dimension, typename DataType> -std::shared_ptr<IDiscreteFunction> +DiscreteFunctionVariant DiscreteFunctionVectorInterpoler::_interpolateGlobally() const { Assert(m_zone_list.size() == 0, "invalid call when zones are defined"); @@ -74,14 +75,14 @@ DiscreteFunctionVectorInterpoler::_interpolateGlobally() const using MeshDataType = MeshData<Dimension>; MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(*p_mesh); - return std::make_shared< - DiscreteFunctionP0Vector<Dimension, DataType>>(p_mesh, InterpolateItemArray<DataType(TinyVector<Dimension>)>:: - template interpolate<ItemType::cell>(m_function_id_list, - mesh_data.xj())); + return DiscreteFunctionP0Vector<Dimension, DataType>(p_mesh, + InterpolateItemArray<DataType(TinyVector<Dimension>)>:: + template interpolate<ItemType::cell>(m_function_id_list, + mesh_data.xj())); } template <size_t Dimension, typename DataType> -std::shared_ptr<IDiscreteFunction> +DiscreteFunctionVariant DiscreteFunctionVectorInterpoler::_interpolate() const { if (m_zone_list.size() == 0) { @@ -92,7 +93,7 @@ DiscreteFunctionVectorInterpoler::_interpolate() const } template <size_t Dimension> -std::shared_ptr<IDiscreteFunction> +DiscreteFunctionVariant DiscreteFunctionVectorInterpoler::_interpolate() const { for (const auto& function_id : m_function_id_list) { @@ -118,7 +119,7 @@ DiscreteFunctionVectorInterpoler::_interpolate() const return this->_interpolate<Dimension, double>(); } -std::shared_ptr<IDiscreteFunction> +DiscreteFunctionVariant DiscreteFunctionVectorInterpoler::interpolate() const { if (m_discrete_function_descriptor->type() != DiscreteFunctionType::P0Vector) { diff --git a/src/scheme/DiscreteFunctionVectorInterpoler.hpp b/src/scheme/DiscreteFunctionVectorInterpoler.hpp index 4bd917264fcfdb8992d6096db824bc17951c2603..8cec9d09e7f9ce0fd03e98dbdaed0edf6afee900 100644 --- a/src/scheme/DiscreteFunctionVectorInterpoler.hpp +++ b/src/scheme/DiscreteFunctionVectorInterpoler.hpp @@ -4,9 +4,10 @@ #include <language/utils/FunctionSymbolId.hpp> #include <mesh/IMesh.hpp> #include <mesh/IZoneDescriptor.hpp> -#include <scheme/IDiscreteFunction.hpp> #include <scheme/IDiscreteFunctionDescriptor.hpp> +class DiscreteFunctionVariant; + #include <memory> #include <vector> @@ -19,19 +20,19 @@ class DiscreteFunctionVectorInterpoler const std::vector<FunctionSymbolId> m_function_id_list; template <size_t Dimension, typename DataType> - std::shared_ptr<IDiscreteFunction> _interpolateOnZoneList() const; + DiscreteFunctionVariant _interpolateOnZoneList() const; template <size_t Dimension, typename DataType> - std::shared_ptr<IDiscreteFunction> _interpolateGlobally() const; + DiscreteFunctionVariant _interpolateGlobally() const; template <size_t Dimension, typename DataType> - std::shared_ptr<IDiscreteFunction> _interpolate() const; + DiscreteFunctionVariant _interpolate() const; template <size_t Dimension> - std::shared_ptr<IDiscreteFunction> _interpolate() const; + DiscreteFunctionVariant _interpolate() const; public: - std::shared_ptr<IDiscreteFunction> interpolate() const; + DiscreteFunctionVariant interpolate() const; DiscreteFunctionVectorInterpoler( const std::shared_ptr<const IMesh>& mesh, diff --git a/src/scheme/HyperelasticSolver.cpp b/src/scheme/HyperelasticSolver.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2f683fa805aa2741b003acff8cb5f39040dafd29 --- /dev/null +++ b/src/scheme/HyperelasticSolver.cpp @@ -0,0 +1,982 @@ +#include <scheme/HyperelasticSolver.hpp> + +#include <language/utils/InterpolateItemValue.hpp> +#include <mesh/ItemValueUtils.hpp> +#include <mesh/ItemValueVariant.hpp> +#include <mesh/MeshFaceBoundary.hpp> +#include <mesh/MeshFlatNodeBoundary.hpp> +#include <mesh/MeshNodeBoundary.hpp> +#include <mesh/SubItemValuePerItemVariant.hpp> +#include <scheme/DirichletBoundaryConditionDescriptor.hpp> +#include <scheme/DiscreteFunctionP0.hpp> +#include <scheme/DiscreteFunctionUtils.hpp> +#include <scheme/DiscreteFunctionVariant.hpp> +#include <scheme/ExternalBoundaryConditionDescriptor.hpp> +#include <scheme/FixedBoundaryConditionDescriptor.hpp> +#include <scheme/IBoundaryConditionDescriptor.hpp> +#include <scheme/IDiscreteFunctionDescriptor.hpp> +#include <scheme/SymmetryBoundaryConditionDescriptor.hpp> +#include <utils/Socket.hpp> + +#include <variant> +#include <vector> + +template <size_t Dimension> +double +hyperelastic_dt(const DiscreteFunctionP0<Dimension, const double>& c) +{ + const Mesh<Connectivity<Dimension>>& mesh = dynamic_cast<const Mesh<Connectivity<Dimension>>&>(*c.mesh()); + + const auto Vj = MeshDataManager::instance().getMeshData(mesh).Vj(); + const auto Sj = MeshDataManager::instance().getMeshData(mesh).sumOverRLjr(); + + CellValue<double> local_dt{mesh.connectivity()}; + parallel_for( + mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { local_dt[j] = 2 * Vj[j] / (Sj[j] * c[j]); }); + + return min(local_dt); +} + +double +hyperelastic_dt(const std::shared_ptr<const DiscreteFunctionVariant>& c) +{ + std::shared_ptr mesh = getCommonMesh({c}); + + switch (mesh->dimension()) { + case 1: { + return hyperelastic_dt(c->get<DiscreteFunctionP0<1, const double>>()); + } + case 2: { + return hyperelastic_dt(c->get<DiscreteFunctionP0<2, const double>>()); + } + case 3: { + return hyperelastic_dt(c->get<DiscreteFunctionP0<3, const double>>()); + } + default: { + throw UnexpectedError("invalid mesh dimension"); + } + } +} + +template <size_t Dimension> +class HyperelasticSolverHandler::HyperelasticSolver final : public HyperelasticSolverHandler::IHyperelasticSolver +{ + private: + using Rdxd = TinyMatrix<Dimension>; + using Rd = TinyVector<Dimension>; + + using MeshType = Mesh<Connectivity<Dimension>>; + using MeshDataType = MeshData<Dimension>; + + using DiscreteScalarFunction = DiscreteFunctionP0<Dimension, const double>; + using DiscreteVectorFunction = DiscreteFunctionP0<Dimension, const Rd>; + using DiscreteTensorFunction = DiscreteFunctionP0<Dimension, const Rdxd>; + + class FixedBoundaryCondition; + class PressureBoundaryCondition; + class NormalStressBoundaryCondition; + class SymmetryBoundaryCondition; + class VelocityBoundaryCondition; + + using BoundaryCondition = std::variant<FixedBoundaryCondition, + PressureBoundaryCondition, + NormalStressBoundaryCondition, + SymmetryBoundaryCondition, + VelocityBoundaryCondition>; + + using BoundaryConditionList = std::vector<BoundaryCondition>; + + NodeValuePerCell<const Rdxd> + _computeGlaceAjr(const MeshType& mesh, const DiscreteScalarFunction& rhoaL, const DiscreteScalarFunction& rhoaT) const + { + MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(mesh); + + const NodeValuePerCell<const Rd> Cjr = mesh_data.Cjr(); + const NodeValuePerCell<const Rd> njr = mesh_data.njr(); + + NodeValuePerCell<Rdxd> Ajr{mesh.connectivity()}; + const Rdxd I = identity; + parallel_for( + mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { + const size_t& nb_nodes = Ajr.numberOfSubValues(j); + const double& rhoaL_j = rhoaL[j]; + const double& rhoaT_j = rhoaT[j]; + for (size_t r = 0; r < nb_nodes; ++r) { + const Rdxd& M = tensorProduct(Cjr(j, r), njr(j, r)); + Ajr(j, r) = rhoaL_j * M + rhoaT_j * (l2Norm(Cjr(j, r)) * I - M); + } + }); + + return Ajr; + } + + NodeValuePerCell<const Rdxd> + _computeEucclhydAjr(const MeshType& mesh, + const DiscreteScalarFunction& rhoaL, + const DiscreteScalarFunction& rhoaT) const + { + MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(mesh); + + const NodeValuePerFace<const Rd> Nlr = mesh_data.Nlr(); + const NodeValuePerFace<const Rd> nlr = mesh_data.nlr(); + + const auto& face_to_node_matrix = mesh.connectivity().faceToNodeMatrix(); + const auto& cell_to_node_matrix = mesh.connectivity().cellToNodeMatrix(); + const auto& cell_to_face_matrix = mesh.connectivity().cellToFaceMatrix(); + + NodeValuePerCell<Rdxd> Ajr{mesh.connectivity()}; + + parallel_for( + Ajr.numberOfValues(), PUGS_LAMBDA(size_t jr) { Ajr[jr] = zero; }); + const Rdxd I = identity; + parallel_for( + mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { + const auto& cell_nodes = cell_to_node_matrix[j]; + + const auto& cell_faces = cell_to_face_matrix[j]; + + const double& rho_aL = rhoaL[j]; + const double& rho_aT = rhoaT[j]; + + for (size_t L = 0; L < cell_faces.size(); ++L) { + const FaceId& l = cell_faces[L]; + const auto& face_nodes = face_to_node_matrix[l]; + + auto local_node_number_in_cell = [&](NodeId node_number) { + for (size_t i_node = 0; i_node < cell_nodes.size(); ++i_node) { + if (node_number == cell_nodes[i_node]) { + return i_node; + } + } + return std::numeric_limits<size_t>::max(); + }; + + for (size_t rl = 0; rl < face_nodes.size(); ++rl) { + const size_t R = local_node_number_in_cell(face_nodes[rl]); + const Rdxd& M = tensorProduct(Nlr(l, rl), nlr(l, rl)); + Ajr(j, R) += rho_aL * M + rho_aT * (l2Norm(Nlr(l, rl)) * I - M); + } + } + }); + + return Ajr; + } + + NodeValuePerCell<const Rdxd> + _computeAjr(const SolverType& solver_type, + const MeshType& mesh, + const DiscreteScalarFunction& rhoaL, + const DiscreteScalarFunction& rhoaT) const + { + if constexpr (Dimension == 1) { + return _computeGlaceAjr(mesh, rhoaL, rhoaT); + } else { + switch (solver_type) { + case SolverType::Glace: { + return _computeGlaceAjr(mesh, rhoaL, rhoaT); + } + case SolverType::Eucclhyd: { + return _computeEucclhydAjr(mesh, rhoaL, rhoaT); + } + default: { + throw UnexpectedError("invalid solver type"); + } + } + } + } + + NodeValue<Rdxd> + _computeAr(const MeshType& mesh, const NodeValuePerCell<const Rdxd>& Ajr) const + { + const auto& node_to_cell_matrix = mesh.connectivity().nodeToCellMatrix(); + const auto& node_local_numbers_in_their_cells = mesh.connectivity().nodeLocalNumbersInTheirCells(); + + NodeValue<Rdxd> Ar{mesh.connectivity()}; + + parallel_for( + mesh.numberOfNodes(), PUGS_LAMBDA(NodeId r) { + Rdxd sum = zero; + const auto& node_to_cell = node_to_cell_matrix[r]; + const auto& node_local_number_in_its_cells = node_local_numbers_in_their_cells.itemArray(r); + + for (size_t j = 0; j < node_to_cell.size(); ++j) { + const CellId J = node_to_cell[j]; + const unsigned int R = node_local_number_in_its_cells[j]; + sum += Ajr(J, R); + } + Ar[r] = sum; + }); + + return Ar; + } + + NodeValue<Rd> + _computeBr(const Mesh<Connectivity<Dimension>>& mesh, + const NodeValuePerCell<const Rdxd>& Ajr, + const DiscreteVectorFunction& u, + const DiscreteTensorFunction& sigma) const + { + MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(mesh); + + const NodeValuePerCell<const Rd>& Cjr = mesh_data.Cjr(); + + const auto& node_to_cell_matrix = mesh.connectivity().nodeToCellMatrix(); + const auto& node_local_numbers_in_their_cells = mesh.connectivity().nodeLocalNumbersInTheirCells(); + + NodeValue<Rd> b{mesh.connectivity()}; + + parallel_for( + mesh.numberOfNodes(), PUGS_LAMBDA(NodeId r) { + const auto& node_to_cell = node_to_cell_matrix[r]; + const auto& node_local_number_in_its_cells = node_local_numbers_in_their_cells.itemArray(r); + + Rd br = zero; + for (size_t j = 0; j < node_to_cell.size(); ++j) { + const CellId J = node_to_cell[j]; + const unsigned int R = node_local_number_in_its_cells[j]; + br += Ajr(J, R) * u[J] - sigma[J] * Cjr(J, R); + } + + b[r] = br; + }); + + return b; + } + + BoundaryConditionList + _getBCList(const MeshType& mesh, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) const + { + BoundaryConditionList bc_list; + + for (const auto& bc_descriptor : bc_descriptor_list) { + bool is_valid_boundary_condition = true; + + switch (bc_descriptor->type()) { + case IBoundaryConditionDescriptor::Type::symmetry: { + bc_list.emplace_back( + SymmetryBoundaryCondition(getMeshFlatNodeBoundary(mesh, bc_descriptor->boundaryDescriptor()))); + break; + } + case IBoundaryConditionDescriptor::Type::fixed: { + bc_list.emplace_back(FixedBoundaryCondition(getMeshNodeBoundary(mesh, bc_descriptor->boundaryDescriptor()))); + break; + } + case IBoundaryConditionDescriptor::Type::dirichlet: { + const DirichletBoundaryConditionDescriptor& dirichlet_bc_descriptor = + dynamic_cast<const DirichletBoundaryConditionDescriptor&>(*bc_descriptor); + if (dirichlet_bc_descriptor.name() == "velocity") { + MeshNodeBoundary<Dimension> mesh_node_boundary = + getMeshNodeBoundary(mesh, dirichlet_bc_descriptor.boundaryDescriptor()); + + Array<const Rd> value_list = + InterpolateItemValue<Rd(Rd)>::template interpolate<ItemType::node>(dirichlet_bc_descriptor.rhsSymbolId(), + mesh.xr(), + mesh_node_boundary.nodeList()); + + bc_list.emplace_back(VelocityBoundaryCondition{mesh_node_boundary, value_list}); + } else if (dirichlet_bc_descriptor.name() == "pressure") { + const FunctionSymbolId pressure_id = dirichlet_bc_descriptor.rhsSymbolId(); + + if constexpr (Dimension == 1) { + MeshNodeBoundary<Dimension> mesh_node_boundary = + getMeshNodeBoundary(mesh, bc_descriptor->boundaryDescriptor()); + + Array<const double> node_values = + InterpolateItemValue<double(Rd)>::template interpolate<ItemType::node>(pressure_id, mesh.xr(), + mesh_node_boundary.nodeList()); + + bc_list.emplace_back(PressureBoundaryCondition{mesh_node_boundary, node_values}); + } else { + MeshFaceBoundary<Dimension> mesh_face_boundary = + getMeshFaceBoundary(mesh, bc_descriptor->boundaryDescriptor()); + + MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(mesh); + Array<const double> face_values = + InterpolateItemValue<double(Rd)>::template interpolate<ItemType::face>(pressure_id, mesh_data.xl(), + mesh_face_boundary.faceList()); + bc_list.emplace_back(PressureBoundaryCondition{mesh_face_boundary, face_values}); + } + + } else if (dirichlet_bc_descriptor.name() == "normal-stress") { + const FunctionSymbolId normal_stress_id = dirichlet_bc_descriptor.rhsSymbolId(); + + if constexpr (Dimension == 1) { + MeshNodeBoundary<Dimension> mesh_node_boundary = + getMeshNodeBoundary(mesh, bc_descriptor->boundaryDescriptor()); + + Array<const Rdxd> node_values = + InterpolateItemValue<Rdxd(Rd)>::template interpolate<ItemType::node>(normal_stress_id, mesh.xr(), + mesh_node_boundary.nodeList()); + + bc_list.emplace_back(NormalStressBoundaryCondition{mesh_node_boundary, node_values}); + } else { + MeshFaceBoundary<Dimension> mesh_face_boundary = + getMeshFaceBoundary(mesh, bc_descriptor->boundaryDescriptor()); + + MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(mesh); + Array<const Rdxd> face_values = + InterpolateItemValue<Rdxd(Rd)>::template interpolate<ItemType::face>(normal_stress_id, mesh_data.xl(), + mesh_face_boundary.faceList()); + bc_list.emplace_back(NormalStressBoundaryCondition{mesh_face_boundary, face_values}); + } + + } else { + is_valid_boundary_condition = false; + } + break; + } + default: { + is_valid_boundary_condition = false; + } + } + if (not is_valid_boundary_condition) { + std::ostringstream error_msg; + error_msg << *bc_descriptor << " is an invalid boundary condition for hyperelastic solver"; + throw NormalError(error_msg.str()); + } + } + + return bc_list; + } + + void _applyPressureBC(const BoundaryConditionList& bc_list, const MeshType& mesh, NodeValue<Rd>& br) const; + void _applyNormalStressBC(const BoundaryConditionList& bc_list, const MeshType& mesh, NodeValue<Rd>& br) const; + void _applySymmetryBC(const BoundaryConditionList& bc_list, NodeValue<Rdxd>& Ar, NodeValue<Rd>& br) const; + void _applyVelocityBC(const BoundaryConditionList& bc_list, NodeValue<Rdxd>& Ar, NodeValue<Rd>& br) const; + void + _applyBoundaryConditions(const BoundaryConditionList& bc_list, + const MeshType& mesh, + NodeValue<Rdxd>& Ar, + NodeValue<Rd>& br) const + { + this->_applyPressureBC(bc_list, mesh, br); + this->_applyNormalStressBC(bc_list, mesh, br); + this->_applySymmetryBC(bc_list, Ar, br); + this->_applyVelocityBC(bc_list, Ar, br); + } + + NodeValue<const Rd> + _computeUr(const MeshType& mesh, const NodeValue<Rdxd>& Ar, const NodeValue<Rd>& br) const + { + NodeValue<Rd> u{mesh.connectivity()}; + parallel_for( + mesh.numberOfNodes(), PUGS_LAMBDA(NodeId r) { u[r] = inverse(Ar[r]) * br[r]; }); + + return u; + } + + NodeValuePerCell<Rd> + _computeFjr(const MeshType& mesh, + const NodeValuePerCell<const Rdxd>& Ajr, + const NodeValue<const Rd>& ur, + const DiscreteVectorFunction& u, + const DiscreteTensorFunction& sigma) const + { + MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(mesh); + + const NodeValuePerCell<const Rd> Cjr = mesh_data.Cjr(); + + const auto& cell_to_node_matrix = mesh.connectivity().cellToNodeMatrix(); + + NodeValuePerCell<Rd> F{mesh.connectivity()}; + parallel_for( + mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { + const auto& cell_nodes = cell_to_node_matrix[j]; + + for (size_t r = 0; r < cell_nodes.size(); ++r) { + F(j, r) = -Ajr(j, r) * (u[j] - ur[cell_nodes[r]]) + sigma[j] * Cjr(j, r); + } + }); + + return F; + } + + public: + std::tuple<const std::shared_ptr<const ItemValueVariant>, const std::shared_ptr<const SubItemValuePerItemVariant>> + compute_fluxes(const SolverType& solver_type, + const std::shared_ptr<const DiscreteFunctionVariant>& rho_v, + const std::shared_ptr<const DiscreteFunctionVariant>& aL_v, + const std::shared_ptr<const DiscreteFunctionVariant>& aT_v, + const std::shared_ptr<const DiscreteFunctionVariant>& u_v, + const std::shared_ptr<const DiscreteFunctionVariant>& sigma_v, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) const + { + std::shared_ptr i_mesh = getCommonMesh({rho_v, aL_v, aT_v, u_v, sigma_v}); + if (not i_mesh) { + throw NormalError("discrete functions are not defined on the same mesh"); + } + + if (not checkDiscretizationType({rho_v, aL_v, u_v, sigma_v}, DiscreteFunctionType::P0)) { + throw NormalError("hyperelastic solver expects P0 functions"); + } + + const MeshType& mesh = dynamic_cast<const MeshType&>(*i_mesh); + const DiscreteScalarFunction& rho = rho_v->get<DiscreteScalarFunction>(); + const DiscreteVectorFunction& u = u_v->get<DiscreteVectorFunction>(); + const DiscreteScalarFunction& aL = aL_v->get<DiscreteScalarFunction>(); + const DiscreteScalarFunction& aT = aT_v->get<DiscreteScalarFunction>(); + const DiscreteTensorFunction& sigma = sigma_v->get<DiscreteTensorFunction>(); + + NodeValuePerCell<const Rdxd> Ajr = this->_computeAjr(solver_type, mesh, rho * aL, rho * aT); + + NodeValue<Rdxd> Ar = this->_computeAr(mesh, Ajr); + NodeValue<Rd> br = this->_computeBr(mesh, Ajr, u, sigma); + + const BoundaryConditionList bc_list = this->_getBCList(mesh, bc_descriptor_list); + this->_applyBoundaryConditions(bc_list, mesh, Ar, br); + + synchronize(Ar); + synchronize(br); + + NodeValue<const Rd> ur = this->_computeUr(mesh, Ar, br); + NodeValuePerCell<const Rd> Fjr = this->_computeFjr(mesh, Ajr, ur, u, sigma); + + return std::make_tuple(std::make_shared<const ItemValueVariant>(ur), + std::make_shared<const SubItemValuePerItemVariant>(Fjr)); + } + + std::tuple<std::shared_ptr<const IMesh>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> + apply_fluxes(const double& dt, + const MeshType& mesh, + const DiscreteScalarFunction& rho, + const DiscreteVectorFunction& u, + const DiscreteScalarFunction& E, + const DiscreteTensorFunction& CG, + const NodeValue<const Rd>& ur, + const NodeValuePerCell<const Rd>& Fjr) const + { + const auto& cell_to_node_matrix = mesh.connectivity().cellToNodeMatrix(); + + if ((mesh.shared_connectivity() != ur.connectivity_ptr()) or + (mesh.shared_connectivity() != Fjr.connectivity_ptr())) { + throw NormalError("fluxes are not defined on the same connectivity than the mesh"); + } + + NodeValue<Rd> new_xr = copy(mesh.xr()); + parallel_for( + mesh.numberOfNodes(), PUGS_LAMBDA(NodeId r) { new_xr[r] += dt * ur[r]; }); + + std::shared_ptr<const MeshType> new_mesh = std::make_shared<MeshType>(mesh.shared_connectivity(), new_xr); + + CellValue<const double> Vj = MeshDataManager::instance().getMeshData(mesh).Vj(); + const NodeValuePerCell<const Rd> Cjr = MeshDataManager::instance().getMeshData(mesh).Cjr(); + + CellValue<double> new_rho = copy(rho.cellValues()); + CellValue<Rd> new_u = copy(u.cellValues()); + CellValue<double> new_E = copy(E.cellValues()); + CellValue<Rdxd> new_CG = copy(CG.cellValues()); + + parallel_for( + mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { + const auto& cell_nodes = cell_to_node_matrix[j]; + + Rd momentum_fluxes = zero; + double energy_fluxes = 0; + Rdxd gradv = zero; + for (size_t R = 0; R < cell_nodes.size(); ++R) { + const NodeId r = cell_nodes[R]; + gradv += tensorProduct(ur[r], Cjr(j, R)); + momentum_fluxes += Fjr(j, R); + energy_fluxes += dot(Fjr(j, R), ur[r]); + } + const Rdxd cauchy_green_fluxes = gradv * CG[j] + CG[j] * transpose(gradv); + const double dt_over_Mj = dt / (rho[j] * Vj[j]); + const double dt_over_Vj = dt / Vj[j]; + new_u[j] += dt_over_Mj * momentum_fluxes; + new_E[j] += dt_over_Mj * energy_fluxes; + new_CG[j] += dt_over_Vj * cauchy_green_fluxes; + new_CG[j] += transpose(new_CG[j]); + new_CG[j] *= 0.5; + }); + + CellValue<const double> new_Vj = MeshDataManager::instance().getMeshData(*new_mesh).Vj(); + + parallel_for( + mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { new_rho[j] *= Vj[j] / new_Vj[j]; }); + + return {new_mesh, std::make_shared<DiscreteFunctionVariant>(DiscreteScalarFunction(new_mesh, new_rho)), + std::make_shared<DiscreteFunctionVariant>(DiscreteVectorFunction(new_mesh, new_u)), + std::make_shared<DiscreteFunctionVariant>(DiscreteScalarFunction(new_mesh, new_E)), + std::make_shared<DiscreteFunctionVariant>(DiscreteTensorFunction(new_mesh, new_CG))}; + } + + std::tuple<std::shared_ptr<const IMesh>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> + apply_fluxes(const double& dt, + const std::shared_ptr<const DiscreteFunctionVariant>& rho, + const std::shared_ptr<const DiscreteFunctionVariant>& u, + const std::shared_ptr<const DiscreteFunctionVariant>& E, + const std::shared_ptr<const DiscreteFunctionVariant>& CG, + const std::shared_ptr<const ItemValueVariant>& ur, + const std::shared_ptr<const SubItemValuePerItemVariant>& Fjr) const + { + std::shared_ptr i_mesh = getCommonMesh({rho, u, E}); + if (not i_mesh) { + throw NormalError("discrete functions are not defined on the same mesh"); + } + + if (not checkDiscretizationType({rho, u, E}, DiscreteFunctionType::P0)) { + throw NormalError("hyperelastic solver expects P0 functions"); + } + + return this->apply_fluxes(dt, // + dynamic_cast<const MeshType&>(*i_mesh), // + rho->get<DiscreteScalarFunction>(), // + u->get<DiscreteVectorFunction>(), // + E->get<DiscreteScalarFunction>(), // + CG->get<DiscreteTensorFunction>(), // + ur->get<NodeValue<const Rd>>(), // + Fjr->get<NodeValuePerCell<const Rd>>()); + } + + std::tuple<std::shared_ptr<const IMesh>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> + apply(const SolverType& solver_type, + const double& dt, + const std::shared_ptr<const DiscreteFunctionVariant>& rho, + const std::shared_ptr<const DiscreteFunctionVariant>& u, + const std::shared_ptr<const DiscreteFunctionVariant>& E, + const std::shared_ptr<const DiscreteFunctionVariant>& CG, + const std::shared_ptr<const DiscreteFunctionVariant>& aL, + const std::shared_ptr<const DiscreteFunctionVariant>& aT, + const std::shared_ptr<const DiscreteFunctionVariant>& sigma, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) const + { + auto [ur, Fjr] = compute_fluxes(solver_type, rho, aL, aT, u, sigma, bc_descriptor_list); + return apply_fluxes(dt, rho, u, E, CG, ur, Fjr); + } + + HyperelasticSolver() = default; + HyperelasticSolver(HyperelasticSolver&&) = default; + ~HyperelasticSolver() = default; +}; + +template <size_t Dimension> +void +HyperelasticSolverHandler::HyperelasticSolver<Dimension>::_applyPressureBC(const BoundaryConditionList& bc_list, + const MeshType& mesh, + NodeValue<Rd>& br) const +{ + for (const auto& boundary_condition : bc_list) { + std::visit( + [&](auto&& bc) { + using T = std::decay_t<decltype(bc)>; + if constexpr (std::is_same_v<PressureBoundaryCondition, T>) { + MeshData<Dimension>& mesh_data = MeshDataManager::instance().getMeshData(mesh); + if constexpr (Dimension == 1) { + const NodeValuePerCell<const Rd> Cjr = mesh_data.Cjr(); + + const auto& node_to_cell_matrix = mesh.connectivity().nodeToCellMatrix(); + const auto& node_local_numbers_in_their_cells = mesh.connectivity().nodeLocalNumbersInTheirCells(); + + const auto& node_list = bc.nodeList(); + const auto& value_list = bc.valueList(); + parallel_for( + node_list.size(), PUGS_LAMBDA(size_t i_node) { + const NodeId node_id = node_list[i_node]; + const auto& node_cell_list = node_to_cell_matrix[node_id]; + Assert(node_cell_list.size() == 1); + + CellId node_cell_id = node_cell_list[0]; + size_t node_local_number_in_cell = node_local_numbers_in_their_cells(node_id, 0); + + br[node_id] -= value_list[i_node] * Cjr(node_cell_id, node_local_number_in_cell); + }); + } else { + const NodeValuePerFace<const Rd> Nlr = mesh_data.Nlr(); + + const auto& face_to_cell_matrix = mesh.connectivity().faceToCellMatrix(); + const auto& face_to_node_matrix = mesh.connectivity().faceToNodeMatrix(); + const auto& face_local_numbers_in_their_cells = mesh.connectivity().faceLocalNumbersInTheirCells(); + const auto& face_cell_is_reversed = mesh.connectivity().cellFaceIsReversed(); + + const auto& face_list = bc.faceList(); + const auto& value_list = bc.valueList(); + for (size_t i_face = 0; i_face < face_list.size(); ++i_face) { + const FaceId face_id = face_list[i_face]; + const auto& face_cell_list = face_to_cell_matrix[face_id]; + Assert(face_cell_list.size() == 1); + + CellId face_cell_id = face_cell_list[0]; + size_t face_local_number_in_cell = face_local_numbers_in_their_cells(face_id, 0); + + const double sign = face_cell_is_reversed(face_cell_id, face_local_number_in_cell) ? -1 : 1; + + const auto& face_nodes = face_to_node_matrix[face_id]; + + for (size_t i_node = 0; i_node < face_nodes.size(); ++i_node) { + NodeId node_id = face_nodes[i_node]; + br[node_id] -= sign * value_list[i_face] * Nlr(face_id, i_node); + } + } + } + } + }, + boundary_condition); + } +} + +template <size_t Dimension> +void +HyperelasticSolverHandler::HyperelasticSolver<Dimension>::_applyNormalStressBC(const BoundaryConditionList& bc_list, + const MeshType& mesh, + NodeValue<Rd>& br) const +{ + for (const auto& boundary_condition : bc_list) { + std::visit( + [&](auto&& bc) { + using T = std::decay_t<decltype(bc)>; + if constexpr (std::is_same_v<NormalStressBoundaryCondition, T>) { + MeshData<Dimension>& mesh_data = MeshDataManager::instance().getMeshData(mesh); + if constexpr (Dimension == 1) { + const NodeValuePerCell<const Rd> Cjr = mesh_data.Cjr(); + + const auto& node_to_cell_matrix = mesh.connectivity().nodeToCellMatrix(); + const auto& node_local_numbers_in_their_cells = mesh.connectivity().nodeLocalNumbersInTheirCells(); + + const auto& node_list = bc.nodeList(); + const auto& value_list = bc.valueList(); + parallel_for( + node_list.size(), PUGS_LAMBDA(size_t i_node) { + const NodeId node_id = node_list[i_node]; + const auto& node_cell_list = node_to_cell_matrix[node_id]; + Assert(node_cell_list.size() == 1); + + CellId node_cell_id = node_cell_list[0]; + size_t node_local_number_in_cell = node_local_numbers_in_their_cells(node_id, 0); + + br[node_id] += value_list[i_node] * Cjr(node_cell_id, node_local_number_in_cell); + }); + } else { + const NodeValuePerFace<const Rd> Nlr = mesh_data.Nlr(); + + const auto& face_to_cell_matrix = mesh.connectivity().faceToCellMatrix(); + const auto& face_to_node_matrix = mesh.connectivity().faceToNodeMatrix(); + const auto& face_local_numbers_in_their_cells = mesh.connectivity().faceLocalNumbersInTheirCells(); + const auto& face_cell_is_reversed = mesh.connectivity().cellFaceIsReversed(); + + const auto& face_list = bc.faceList(); + const auto& value_list = bc.valueList(); + for (size_t i_face = 0; i_face < face_list.size(); ++i_face) { + const FaceId face_id = face_list[i_face]; + const auto& face_cell_list = face_to_cell_matrix[face_id]; + Assert(face_cell_list.size() == 1); + + CellId face_cell_id = face_cell_list[0]; + size_t face_local_number_in_cell = face_local_numbers_in_their_cells(face_id, 0); + + const double sign = face_cell_is_reversed(face_cell_id, face_local_number_in_cell) ? -1 : 1; + + const auto& face_nodes = face_to_node_matrix[face_id]; + + for (size_t i_node = 0; i_node < face_nodes.size(); ++i_node) { + NodeId node_id = face_nodes[i_node]; + br[node_id] += sign * value_list[i_face] * Nlr(face_id, i_node); + } + } + } + } + }, + boundary_condition); + } +} + +template <size_t Dimension> +void +HyperelasticSolverHandler::HyperelasticSolver<Dimension>::_applySymmetryBC(const BoundaryConditionList& bc_list, + NodeValue<Rdxd>& Ar, + NodeValue<Rd>& br) const +{ + for (const auto& boundary_condition : bc_list) { + std::visit( + [&](auto&& bc) { + using T = std::decay_t<decltype(bc)>; + if constexpr (std::is_same_v<SymmetryBoundaryCondition, T>) { + const Rd& n = bc.outgoingNormal(); + + const Rdxd I = identity; + const Rdxd nxn = tensorProduct(n, n); + const Rdxd P = I - nxn; + + const Array<const NodeId>& node_list = bc.nodeList(); + parallel_for( + bc.numberOfNodes(), PUGS_LAMBDA(int r_number) { + const NodeId r = node_list[r_number]; + + Ar[r] = P * Ar[r] * P + nxn; + br[r] = P * br[r]; + }); + } + }, + boundary_condition); + } +} + +template <size_t Dimension> +void +HyperelasticSolverHandler::HyperelasticSolver<Dimension>::_applyVelocityBC(const BoundaryConditionList& bc_list, + NodeValue<Rdxd>& Ar, + NodeValue<Rd>& br) const +{ + for (const auto& boundary_condition : bc_list) { + std::visit( + [&](auto&& bc) { + using T = std::decay_t<decltype(bc)>; + if constexpr (std::is_same_v<VelocityBoundaryCondition, T>) { + const auto& node_list = bc.nodeList(); + const auto& value_list = bc.valueList(); + + parallel_for( + node_list.size(), PUGS_LAMBDA(size_t i_node) { + NodeId node_id = node_list[i_node]; + const auto& value = value_list[i_node]; + + Ar[node_id] = identity; + br[node_id] = value; + }); + } else if constexpr (std::is_same_v<FixedBoundaryCondition, T>) { + const auto& node_list = bc.nodeList(); + parallel_for( + node_list.size(), PUGS_LAMBDA(size_t i_node) { + NodeId node_id = node_list[i_node]; + + Ar[node_id] = identity; + br[node_id] = zero; + }); + } + }, + boundary_condition); + } +} + +template <size_t Dimension> +class HyperelasticSolverHandler::HyperelasticSolver<Dimension>::FixedBoundaryCondition +{ + private: + const MeshNodeBoundary<Dimension> m_mesh_node_boundary; + + public: + const Array<const NodeId>& + nodeList() const + { + return m_mesh_node_boundary.nodeList(); + } + + FixedBoundaryCondition(const MeshNodeBoundary<Dimension> mesh_node_boundary) + : m_mesh_node_boundary{mesh_node_boundary} + {} + + ~FixedBoundaryCondition() = default; +}; + +template <size_t Dimension> +class HyperelasticSolverHandler::HyperelasticSolver<Dimension>::PressureBoundaryCondition +{ + private: + const MeshFaceBoundary<Dimension> m_mesh_face_boundary; + const Array<const double> m_value_list; + + public: + const Array<const FaceId>& + faceList() const + { + return m_mesh_face_boundary.faceList(); + } + + const Array<const double>& + valueList() const + { + return m_value_list; + } + + PressureBoundaryCondition(const MeshFaceBoundary<Dimension>& mesh_face_boundary, + const Array<const double>& value_list) + : m_mesh_face_boundary{mesh_face_boundary}, m_value_list{value_list} + {} + + ~PressureBoundaryCondition() = default; +}; + +template <> +class HyperelasticSolverHandler::HyperelasticSolver<1>::PressureBoundaryCondition +{ + private: + const MeshNodeBoundary<1> m_mesh_node_boundary; + const Array<const double> m_value_list; + + public: + const Array<const NodeId>& + nodeList() const + { + return m_mesh_node_boundary.nodeList(); + } + + const Array<const double>& + valueList() const + { + return m_value_list; + } + + PressureBoundaryCondition(const MeshNodeBoundary<1>& mesh_node_boundary, const Array<const double>& value_list) + : m_mesh_node_boundary{mesh_node_boundary}, m_value_list{value_list} + {} + + ~PressureBoundaryCondition() = default; +}; + +template <size_t Dimension> +class HyperelasticSolverHandler::HyperelasticSolver<Dimension>::NormalStressBoundaryCondition +{ + private: + const MeshFaceBoundary<Dimension> m_mesh_face_boundary; + const Array<const Rdxd> m_value_list; + + public: + const Array<const FaceId>& + faceList() const + { + return m_mesh_face_boundary.faceList(); + } + + const Array<const Rdxd>& + valueList() const + { + return m_value_list; + } + + NormalStressBoundaryCondition(const MeshFaceBoundary<Dimension>& mesh_face_boundary, + const Array<const Rdxd>& value_list) + : m_mesh_face_boundary{mesh_face_boundary}, m_value_list{value_list} + {} + + ~NormalStressBoundaryCondition() = default; +}; + +template <> +class HyperelasticSolverHandler::HyperelasticSolver<1>::NormalStressBoundaryCondition +{ + private: + const MeshNodeBoundary<1> m_mesh_node_boundary; + const Array<const Rdxd> m_value_list; + + public: + const Array<const NodeId>& + nodeList() const + { + return m_mesh_node_boundary.nodeList(); + } + + const Array<const Rdxd>& + valueList() const + { + return m_value_list; + } + + NormalStressBoundaryCondition(const MeshNodeBoundary<1>& mesh_node_boundary, const Array<const Rdxd>& value_list) + : m_mesh_node_boundary{mesh_node_boundary}, m_value_list{value_list} + {} + + ~NormalStressBoundaryCondition() = default; +}; + +template <size_t Dimension> +class HyperelasticSolverHandler::HyperelasticSolver<Dimension>::VelocityBoundaryCondition +{ + private: + const MeshNodeBoundary<Dimension> m_mesh_node_boundary; + + const Array<const TinyVector<Dimension>> m_value_list; + + public: + const Array<const NodeId>& + nodeList() const + { + return m_mesh_node_boundary.nodeList(); + } + + const Array<const TinyVector<Dimension>>& + valueList() const + { + return m_value_list; + } + + VelocityBoundaryCondition(const MeshNodeBoundary<Dimension>& mesh_node_boundary, + const Array<const TinyVector<Dimension>>& value_list) + : m_mesh_node_boundary{mesh_node_boundary}, m_value_list{value_list} + {} + + ~VelocityBoundaryCondition() = default; +}; + +template <size_t Dimension> +class HyperelasticSolverHandler::HyperelasticSolver<Dimension>::SymmetryBoundaryCondition +{ + public: + using Rd = TinyVector<Dimension, double>; + + private: + const MeshFlatNodeBoundary<Dimension> m_mesh_flat_node_boundary; + + public: + const Rd& + outgoingNormal() const + { + return m_mesh_flat_node_boundary.outgoingNormal(); + } + + size_t + numberOfNodes() const + { + return m_mesh_flat_node_boundary.nodeList().size(); + } + + const Array<const NodeId>& + nodeList() const + { + return m_mesh_flat_node_boundary.nodeList(); + } + + SymmetryBoundaryCondition(const MeshFlatNodeBoundary<Dimension>& mesh_flat_node_boundary) + : m_mesh_flat_node_boundary(mesh_flat_node_boundary) + { + ; + } + + ~SymmetryBoundaryCondition() = default; +}; + +HyperelasticSolverHandler::HyperelasticSolverHandler(const std::shared_ptr<const IMesh>& i_mesh) +{ + if (not i_mesh) { + throw NormalError("discrete functions are not defined on the same mesh"); + } + + switch (i_mesh->dimension()) { + case 1: { + m_hyperelastic_solver = std::make_unique<HyperelasticSolver<1>>(); + break; + } + case 2: { + m_hyperelastic_solver = std::make_unique<HyperelasticSolver<2>>(); + break; + } + case 3: { + m_hyperelastic_solver = std::make_unique<HyperelasticSolver<3>>(); + break; + } + default: { + throw UnexpectedError("invalid mesh dimension"); + } + } +} diff --git a/src/scheme/HyperelasticSolver.hpp b/src/scheme/HyperelasticSolver.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f82cbe361051efc64a3e413d60c830febd62d907 --- /dev/null +++ b/src/scheme/HyperelasticSolver.hpp @@ -0,0 +1,90 @@ +#ifndef HYPERELASTIC_SOLVER_HPP +#define HYPERELASTIC_SOLVER_HPP + +#include <memory> +#include <tuple> +#include <vector> + +class IBoundaryConditionDescriptor; +class IMesh; +class ItemValueVariant; +class SubItemValuePerItemVariant; +class DiscreteFunctionVariant; + +double hyperelastic_dt(const std::shared_ptr<const DiscreteFunctionVariant>& c); + +class HyperelasticSolverHandler +{ + public: + enum class SolverType + { + Glace, + Eucclhyd + }; + + private: + struct IHyperelasticSolver + { + virtual std::tuple<const std::shared_ptr<const ItemValueVariant>, + const std::shared_ptr<const SubItemValuePerItemVariant>> + compute_fluxes( + const SolverType& solver_type, + const std::shared_ptr<const DiscreteFunctionVariant>& rho, + const std::shared_ptr<const DiscreteFunctionVariant>& aL, + const std::shared_ptr<const DiscreteFunctionVariant>& aT, + const std::shared_ptr<const DiscreteFunctionVariant>& u, + const std::shared_ptr<const DiscreteFunctionVariant>& sigma, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) const = 0; + + virtual std::tuple<std::shared_ptr<const IMesh>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> + apply_fluxes(const double& dt, + const std::shared_ptr<const DiscreteFunctionVariant>& rho, + const std::shared_ptr<const DiscreteFunctionVariant>& u, + const std::shared_ptr<const DiscreteFunctionVariant>& E, + const std::shared_ptr<const DiscreteFunctionVariant>& CG, + const std::shared_ptr<const ItemValueVariant>& ur, + const std::shared_ptr<const SubItemValuePerItemVariant>& Fjr) const = 0; + + virtual std::tuple<std::shared_ptr<const IMesh>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>, + std::shared_ptr<const DiscreteFunctionVariant>> + apply(const SolverType& solver_type, + const double& dt, + const std::shared_ptr<const DiscreteFunctionVariant>& rho, + const std::shared_ptr<const DiscreteFunctionVariant>& u, + const std::shared_ptr<const DiscreteFunctionVariant>& E, + const std::shared_ptr<const DiscreteFunctionVariant>& CG, + const std::shared_ptr<const DiscreteFunctionVariant>& aL, + const std::shared_ptr<const DiscreteFunctionVariant>& aT, + const std::shared_ptr<const DiscreteFunctionVariant>& p, + const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) const = 0; + + IHyperelasticSolver() = default; + IHyperelasticSolver(IHyperelasticSolver&&) = default; + IHyperelasticSolver& operator=(IHyperelasticSolver&&) = default; + + virtual ~IHyperelasticSolver() = default; + }; + + template <size_t Dimension> + class HyperelasticSolver; + + std::unique_ptr<IHyperelasticSolver> m_hyperelastic_solver; + + public: + const IHyperelasticSolver& + solver() const + { + return *m_hyperelastic_solver; + } + + HyperelasticSolverHandler(const std::shared_ptr<const IMesh>& mesh); +}; + +#endif // HYPERELASTIC_SOLVER_HPP diff --git a/src/scheme/IDiscreteFunction.hpp b/src/scheme/IDiscreteFunction.hpp deleted file mode 100644 index be6ca66278de95265e9a301ebc8f2fe0fa7ee5db..0000000000000000000000000000000000000000 --- a/src/scheme/IDiscreteFunction.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef I_DISCRETE_FUNCTION_HPP -#define I_DISCRETE_FUNCTION_HPP - -class IMesh; -class IDiscreteFunctionDescriptor; - -#include <language/utils/ASTNodeDataTypeTraits.hpp> -#include <memory> - -class IDiscreteFunction -{ - public: - enum class HandledItemDataType - { - value, - vector, - }; - - virtual std::shared_ptr<const IMesh> mesh() const = 0; - virtual const IDiscreteFunctionDescriptor& descriptor() const = 0; - virtual ASTNodeDataType dataType() const = 0; - - IDiscreteFunction() = default; - - IDiscreteFunction(const IDiscreteFunction&) = default; - - IDiscreteFunction(IDiscreteFunction&&) noexcept = default; - - virtual ~IDiscreteFunction() noexcept = default; -}; - -#endif // I_DISCRETE_FUNCTION_HPP diff --git a/src/scheme/ScalarDiamondScheme.cpp b/src/scheme/ScalarDiamondScheme.cpp index 07561e6f5abfee4461cd72d2e634bce94f7f12e8..d0a9f7e48f7f93b9224a197312dbb2a0b2829847 100644 --- a/src/scheme/ScalarDiamondScheme.cpp +++ b/src/scheme/ScalarDiamondScheme.cpp @@ -138,7 +138,7 @@ class ScalarDiamondSchemeHandler::InterpolationWeightsManager class ScalarDiamondSchemeHandler::IScalarDiamondScheme { public: - virtual std::shared_ptr<const IDiscreteFunction> getSolution() const = 0; + virtual std::shared_ptr<const DiscreteFunctionVariant> getSolution() const = 0; IScalarDiamondScheme() = default; virtual ~IScalarDiamondScheme() = default; @@ -152,7 +152,7 @@ class ScalarDiamondSchemeHandler::ScalarDiamondScheme : public ScalarDiamondSche using MeshType = Mesh<ConnectivityType>; using MeshDataType = MeshData<Dimension>; - std::shared_ptr<const DiscreteFunctionP0<Dimension, double>> m_solution; + DiscreteFunctionP0<Dimension, double> m_solution; class DirichletBoundaryCondition { @@ -268,22 +268,23 @@ class ScalarDiamondSchemeHandler::ScalarDiamondScheme : public ScalarDiamondSche }; public: - std::shared_ptr<const IDiscreteFunction> + std::shared_ptr<const DiscreteFunctionVariant> getSolution() const final { - return m_solution; + return std::make_shared<DiscreteFunctionVariant>(m_solution); } ScalarDiamondScheme(const std::shared_ptr<const MeshType>& mesh, - const std::shared_ptr<const DiscreteFunctionP0<Dimension, double>>& alpha, - const std::shared_ptr<const DiscreteFunctionP0<Dimension, double>>& dual_mub, - const std::shared_ptr<const DiscreteFunctionP0<Dimension, double>>& dual_mu, - const std::shared_ptr<const DiscreteFunctionP0<Dimension, double>>& f, + const DiscreteFunctionP0<Dimension, const double>& alpha, + const DiscreteFunctionP0<Dimension, const double>& dual_mub, + const DiscreteFunctionP0<Dimension, const double>& dual_mu, + const DiscreteFunctionP0<Dimension, const double>& f, const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) + : m_solution(mesh) { - Assert(DualMeshManager::instance().getDiamondDualMesh(*mesh) == dual_mu->mesh(), + Assert(DualMeshManager::instance().getDiamondDualMesh(*mesh) == dual_mu.mesh(), "diffusion coefficient is not defined on the dual mesh!"); - Assert(DualMeshManager::instance().getDiamondDualMesh(*mesh) == dual_mub->mesh(), + Assert(DualMeshManager::instance().getDiamondDualMesh(*mesh) == dual_mub.mesh(), "boundary diffusion coefficient is not defined on the dual mesh!"); using BoundaryCondition = std::variant<DirichletBoundaryCondition, FourierBoundaryCondition, @@ -485,8 +486,8 @@ class ScalarDiamondSchemeHandler::ScalarDiamondScheme : public ScalarDiamondSche std::shared_ptr mapper = DualConnectivityManager::instance().getPrimalToDiamondDualConnectivityDataMapper(mesh->connectivity()); - CellValue<const double> dual_kappaj = dual_mu->cellValues(); - CellValue<const double> dual_kappajb = dual_mub->cellValues(); + CellValue<const double> dual_kappaj = dual_mu.cellValues(); + CellValue<const double> dual_kappajb = dual_mub.cellValues(); const CellValue<const double> dual_Vj = diamond_mesh_data.Vj(); @@ -641,7 +642,7 @@ class ScalarDiamondSchemeHandler::ScalarDiamondScheme : public ScalarDiamondSche for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { const size_t j = cell_dof_number[cell_id]; - S(j, j) += (*alpha)[cell_id] * primal_Vj[cell_id]; + S(j, j) += alpha[cell_id] * primal_Vj[cell_id]; } const auto& dual_cell_to_node_matrix = diamond_mesh->connectivity().cellToNodeMatrix(); @@ -705,7 +706,7 @@ class ScalarDiamondSchemeHandler::ScalarDiamondScheme : public ScalarDiamondSche } } - CellValue<const double> fj = f->cellValues(); + CellValue<const double> fj = f.cellValues(); CRSMatrix A{S.getCRSMatrix()}; Vector<double> b{number_of_dof}; @@ -755,26 +756,24 @@ class ScalarDiamondSchemeHandler::ScalarDiamondScheme : public ScalarDiamondSche LinearSolver solver; solver.solveLocalSystem(A, T, b); - m_solution = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); - auto& solution = *m_solution; parallel_for( - mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { solution[cell_id] = T[cell_dof_number[cell_id]]; }); + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { m_solution[cell_id] = T[cell_dof_number[cell_id]]; }); } } } }; -std::shared_ptr<const IDiscreteFunction> +std::shared_ptr<const DiscreteFunctionVariant> ScalarDiamondSchemeHandler::solution() const { return m_scheme->getSolution(); } ScalarDiamondSchemeHandler::ScalarDiamondSchemeHandler( - const std::shared_ptr<const IDiscreteFunction>& alpha, - const std::shared_ptr<const IDiscreteFunction>& dual_mub, - const std::shared_ptr<const IDiscreteFunction>& dual_mu, - const std::shared_ptr<const IDiscreteFunction>& f, + const std::shared_ptr<const DiscreteFunctionVariant>& alpha, + const std::shared_ptr<const DiscreteFunctionVariant>& dual_mub, + const std::shared_ptr<const DiscreteFunctionVariant>& dual_mu, + const std::shared_ptr<const DiscreteFunctionVariant>& f, const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) { const std::shared_ptr i_mesh = getCommonMesh({alpha, f}); @@ -790,7 +789,7 @@ ScalarDiamondSchemeHandler::ScalarDiamondSchemeHandler( switch (i_mesh->dimension()) { case 1: { using MeshType = Mesh<Connectivity<1>>; - using DiscreteScalarFunctionType = DiscreteFunctionP0<1, double>; + using DiscreteScalarFunctionType = DiscreteFunctionP0<1, const double>; std::shared_ptr mesh = std::dynamic_pointer_cast<const MeshType>(i_mesh); @@ -798,17 +797,15 @@ ScalarDiamondSchemeHandler::ScalarDiamondSchemeHandler( throw NormalError("dual variables are is not defined on the diamond dual of the primal mesh"); } - m_scheme = - std::make_unique<ScalarDiamondScheme<1>>(mesh, std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(alpha), - std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(dual_mub), - std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(dual_mu), - std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(f), - bc_descriptor_list); + m_scheme = std::make_unique<ScalarDiamondScheme<1>>(mesh, alpha->get<DiscreteScalarFunctionType>(), + dual_mub->get<DiscreteScalarFunctionType>(), + dual_mu->get<DiscreteScalarFunctionType>(), + f->get<DiscreteScalarFunctionType>(), bc_descriptor_list); break; } case 2: { using MeshType = Mesh<Connectivity<2>>; - using DiscreteScalarFunctionType = DiscreteFunctionP0<2, double>; + using DiscreteScalarFunctionType = DiscreteFunctionP0<2, const double>; std::shared_ptr mesh = std::dynamic_pointer_cast<const MeshType>(i_mesh); @@ -816,17 +813,15 @@ ScalarDiamondSchemeHandler::ScalarDiamondSchemeHandler( throw NormalError("dual variables are is not defined on the diamond dual of the primal mesh"); } - m_scheme = - std::make_unique<ScalarDiamondScheme<2>>(mesh, std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(alpha), - std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(dual_mub), - std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(dual_mu), - std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(f), - bc_descriptor_list); + m_scheme = std::make_unique<ScalarDiamondScheme<2>>(mesh, alpha->get<DiscreteScalarFunctionType>(), + dual_mub->get<DiscreteScalarFunctionType>(), + dual_mu->get<DiscreteScalarFunctionType>(), + f->get<DiscreteScalarFunctionType>(), bc_descriptor_list); break; } case 3: { using MeshType = Mesh<Connectivity<3>>; - using DiscreteScalarFunctionType = DiscreteFunctionP0<3, double>; + using DiscreteScalarFunctionType = DiscreteFunctionP0<3, const double>; std::shared_ptr mesh = std::dynamic_pointer_cast<const MeshType>(i_mesh); @@ -834,12 +829,10 @@ ScalarDiamondSchemeHandler::ScalarDiamondSchemeHandler( throw NormalError("dual variables are is not defined on the diamond dual of the primal mesh"); } - m_scheme = - std::make_unique<ScalarDiamondScheme<3>>(mesh, std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(alpha), - std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(dual_mub), - std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(dual_mu), - std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(f), - bc_descriptor_list); + m_scheme = std::make_unique<ScalarDiamondScheme<3>>(mesh, alpha->get<DiscreteScalarFunctionType>(), + dual_mub->get<DiscreteScalarFunctionType>(), + dual_mu->get<DiscreteScalarFunctionType>(), + f->get<DiscreteScalarFunctionType>(), bc_descriptor_list); break; } default: { diff --git a/src/scheme/ScalarDiamondScheme.hpp b/src/scheme/ScalarDiamondScheme.hpp index 47b66177b5628bb8b13a0ea2d92ede5e41a84950..4040fe1ade92e3b599dcdf724e924057feacaf63 100644 --- a/src/scheme/ScalarDiamondScheme.hpp +++ b/src/scheme/ScalarDiamondScheme.hpp @@ -19,8 +19,8 @@ #include <mesh/PrimalToDiamondDualConnectivityDataMapper.hpp> #include <mesh/SubItemValuePerItem.hpp> #include <scheme/DirichletBoundaryConditionDescriptor.hpp> +#include <scheme/DiscreteFunctionVariant.hpp> #include <scheme/FourierBoundaryConditionDescriptor.hpp> -#include <scheme/IDiscreteFunction.hpp> #include <scheme/NeumannBoundaryConditionDescriptor.hpp> #include <scheme/SymmetryBoundaryConditionDescriptor.hpp> @@ -38,13 +38,13 @@ class ScalarDiamondSchemeHandler public: std::unique_ptr<IScalarDiamondScheme> m_scheme; - std::shared_ptr<const IDiscreteFunction> solution() const; + std::shared_ptr<const DiscreteFunctionVariant> solution() const; ScalarDiamondSchemeHandler( - const std::shared_ptr<const IDiscreteFunction>& alpha, - const std::shared_ptr<const IDiscreteFunction>& mu_dualb, - const std::shared_ptr<const IDiscreteFunction>& mu_dual, - const std::shared_ptr<const IDiscreteFunction>& f, + const std::shared_ptr<const DiscreteFunctionVariant>& alpha, + const std::shared_ptr<const DiscreteFunctionVariant>& mu_dualb, + const std::shared_ptr<const DiscreteFunctionVariant>& mu_dual, + const std::shared_ptr<const DiscreteFunctionVariant>& f, const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list); ~ScalarDiamondSchemeHandler(); diff --git a/src/scheme/VectorDiamondScheme.cpp b/src/scheme/VectorDiamondScheme.cpp index ac1345a0818e50dd6275d5380363522b2160a4a3..95177642047f849456193cfccb97a50276bf525c 100644 --- a/src/scheme/VectorDiamondScheme.cpp +++ b/src/scheme/VectorDiamondScheme.cpp @@ -13,7 +13,7 @@ class VectorDiamondSchemeHandler::InterpolationWeightsManager FaceValue<const bool> m_primal_face_is_symmetry; CellValuePerNode<double> m_w_rj; FaceValuePerNode<double> m_w_rl; - + public: InterpolationWeightsManager(std::shared_ptr<const Mesh<Connectivity<Dimension>>> mesh, FaceValue<const bool> primal_face_is_on_boundary, @@ -156,12 +156,10 @@ class VectorDiamondSchemeHandler::InterpolationWeightsManager class VectorDiamondSchemeHandler::IVectorDiamondScheme { public: - virtual std::shared_ptr<const IDiscreteFunction> getSolution() const = 0; - virtual std::shared_ptr<const IDiscreteFunction> getDualSolution() const = 0; - virtual std::tuple<std::shared_ptr<const IDiscreteFunction>, std::shared_ptr<const IDiscreteFunction>> apply() - const = 0; - // virtual std::tuple<std::shared_ptr<const IDiscreteFunction>, std::shared_ptr<const IDiscreteFunction>> - // computeEnergyUpdate() const = 0; + virtual std::shared_ptr<const DiscreteFunctionVariant> getSolution() const = 0; + virtual std::shared_ptr<const DiscreteFunctionVariant> getDualSolution() const = 0; + virtual std::tuple<std::shared_ptr<const DiscreteFunctionVariant>, std::shared_ptr<const DiscreteFunctionVariant>> + apply() const = 0; IVectorDiamondScheme() = default; virtual ~IVectorDiamondScheme() = default; @@ -175,9 +173,8 @@ class VectorDiamondSchemeHandler::VectorDiamondScheme : public VectorDiamondSche using MeshType = Mesh<ConnectivityType>; using MeshDataType = MeshData<Dimension>; - std::shared_ptr<const DiscreteFunctionP0<Dimension, TinyVector<Dimension>>> m_solution; - std::shared_ptr<const DiscreteFunctionP0<Dimension, TinyVector<Dimension>>> m_dual_solution; - // std::shared_ptr<const DiscreteFunctionP0<Dimension, double>> m_energy_delta; + DiscreteFunctionP0<Dimension, TinyVector<Dimension>> m_solution; + DiscreteFunctionP0<Dimension, TinyVector<Dimension>> m_dual_solution; class DirichletBoundaryCondition { @@ -257,39 +254,41 @@ class VectorDiamondSchemeHandler::VectorDiamondScheme : public VectorDiamondSche }; public: - std::shared_ptr<const IDiscreteFunction> + std::shared_ptr<const DiscreteFunctionVariant> getSolution() const final { - return m_solution; + return std::make_shared<DiscreteFunctionVariant>(m_solution); } - std::shared_ptr<const IDiscreteFunction> + std::shared_ptr<const DiscreteFunctionVariant> getDualSolution() const final { - return m_dual_solution; + return std::make_shared<DiscreteFunctionVariant>(m_dual_solution); } - std::tuple<std::shared_ptr<const IDiscreteFunction>, std::shared_ptr<const IDiscreteFunction>> + std::tuple<std::shared_ptr<const DiscreteFunctionVariant>, std::shared_ptr<const DiscreteFunctionVariant>> apply() const final { - return {m_solution, m_dual_solution}; + return {std::make_shared<DiscreteFunctionVariant>(m_solution), + std::make_shared<DiscreteFunctionVariant>(m_dual_solution)}; } VectorDiamondScheme(const std::shared_ptr<const MeshType>& mesh, - const std::shared_ptr<const DiscreteFunctionP0<Dimension, double>>& alpha, - const std::shared_ptr<const DiscreteFunctionP0<Dimension, double>>& dual_lambdab, - const std::shared_ptr<const DiscreteFunctionP0<Dimension, double>>& dual_mub, - const std::shared_ptr<const DiscreteFunctionP0<Dimension, double>>& dual_lambda, - const std::shared_ptr<const DiscreteFunctionP0<Dimension, double>>& dual_mu, - const std::shared_ptr<const DiscreteFunctionP0<Dimension, TinyVector<Dimension>>>& source, + const DiscreteFunctionP0<Dimension, const double>& alpha, + const DiscreteFunctionP0<Dimension, const double>& dual_lambdab, + const DiscreteFunctionP0<Dimension, const double>& dual_mub, + const DiscreteFunctionP0<Dimension, const double>& dual_lambda, + const DiscreteFunctionP0<Dimension, const double>& dual_mu, + const DiscreteFunctionP0<Dimension, const TinyVector<Dimension>>& source, const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) + : m_solution(mesh), m_dual_solution(DualMeshManager::instance().getDiamondDualMesh(*mesh)) { - Assert(mesh == alpha->mesh()); - Assert(mesh == source->mesh()); - Assert(dual_lambda->mesh() == dual_mu->mesh()); - Assert(dual_lambdab->mesh() == dual_mu->mesh()); - Assert(dual_mub->mesh() == dual_mu->mesh()); - Assert(DualMeshManager::instance().getDiamondDualMesh(*mesh) == dual_mu->mesh(), + Assert(mesh == alpha.mesh()); + Assert(mesh == source.mesh()); + Assert(dual_lambda.mesh() == dual_mu.mesh()); + Assert(dual_lambdab.mesh() == dual_mu.mesh()); + Assert(dual_mub.mesh() == dual_mu.mesh()); + Assert(DualMeshManager::instance().getDiamondDualMesh(*mesh) == dual_mu.mesh(), "diffusion coefficient is not defined on the dual mesh!"); using MeshDataType = MeshData<Dimension>; @@ -526,15 +525,12 @@ class VectorDiamondSchemeHandler::VectorDiamondScheme : public VectorDiamondSche std::shared_ptr mapper = DualConnectivityManager::instance().getPrimalToDiamondDualConnectivityDataMapper(mesh->connectivity()); - CellValue<const double> dual_muj = dual_mu->cellValues(); - CellValue<const double> dual_lambdaj = dual_lambda->cellValues(); - CellValue<const double> dual_mubj = dual_mub->cellValues(); - CellValue<const double> dual_lambdabj = dual_lambdab->cellValues(); + CellValue<const double> dual_muj = dual_mu.cellValues(); + CellValue<const double> dual_lambdaj = dual_lambda.cellValues(); + CellValue<const double> dual_mubj = dual_mub.cellValues(); + CellValue<const double> dual_lambdabj = dual_lambdab.cellValues(); - CellValue<const TinyVector<Dimension>> fj = source->cellValues(); - // for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { - // std::cout << xj[cell_id] << "-> fj[" << cell_id << "]=" << fj[cell_id] << '\n'; - // } + CellValue<const TinyVector<Dimension>> fj = source.cellValues(); const CellValue<const double> dual_Vj = diamond_mesh_data.Vj(); @@ -763,7 +759,7 @@ class VectorDiamondSchemeHandler::VectorDiamondScheme : public VectorDiamondSche for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { for (size_t i = 0; i < Dimension; ++i) { const size_t j = cell_dof_number[cell_id] * Dimension + i; - S(j, j) += (*alpha)[cell_id] * primal_Vj[cell_id]; + S(j, j) += alpha[cell_id] * primal_Vj[cell_id]; } } @@ -915,30 +911,26 @@ class VectorDiamondSchemeHandler::VectorDiamondScheme : public VectorDiamondSche std::cout << "final (real) residu = " << std::sqrt(dot(r, r)) << '\n'; - m_solution = std::make_shared<DiscreteFunctionP0<Dimension, TinyVector<Dimension>>>(mesh); - auto& solution = *m_solution; parallel_for( mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { for (size_t i = 0; i < Dimension; ++i) { - solution[cell_id][i] = U[(cell_dof_number[cell_id] * Dimension) + i]; + m_solution[cell_id][i] = U[(cell_dof_number[cell_id] * Dimension) + i]; } }); - m_dual_solution = std::make_shared<DiscreteFunctionP0<Dimension, TinyVector<Dimension>>>(diamond_mesh); - auto& dual_solution = *m_dual_solution; - dual_solution.fill(zero); + m_dual_solution.fill(zero); const auto& face_to_cell_matrix = mesh->connectivity().faceToCellMatrix(); for (CellId cell_id = 0; cell_id < diamond_mesh->numberOfCells(); ++cell_id) { const FaceId face_id = dual_cell_face_id[cell_id]; if (primal_face_is_on_boundary[face_id]) { for (size_t i = 0; i < Dimension; ++i) { - dual_solution[cell_id][i] = U[(face_dof_number[face_id] * Dimension) + i]; + m_dual_solution[cell_id][i] = U[(face_dof_number[face_id] * Dimension) + i]; } } else { CellId cell_id1 = face_to_cell_matrix[face_id][0]; CellId cell_id2 = face_to_cell_matrix[face_id][1]; for (size_t i = 0; i < Dimension; ++i) { - dual_solution[cell_id][i] = + m_dual_solution[cell_id][i] = 0.5 * (U[(cell_dof_number[cell_id1] * Dimension) + i] + U[(cell_dof_number[cell_id2] * Dimension) + i]); } } @@ -1109,11 +1101,8 @@ class EnergyComputerHandler::InterpolationWeightsManager class EnergyComputerHandler::IEnergyComputer { public: - // virtual std::shared_ptr<const IDiscreteFunction> getSolution() const = 0; - // virtual std::shared_ptr<const IDiscreteFunction> getDualSolution() const = 0; - // virtual std::shared_ptr<const IDiscreteFunction> apply() const = 0; - virtual std::tuple<std::shared_ptr<const IDiscreteFunction>, std::shared_ptr<const IDiscreteFunction>> apply() - const = 0; + virtual std::tuple<std::shared_ptr<const DiscreteFunctionVariant>, std::shared_ptr<const DiscreteFunctionVariant>> + apply() const = 0; IEnergyComputer() = default; virtual ~IEnergyComputer() = default; @@ -1127,9 +1116,9 @@ class EnergyComputerHandler::EnergyComputer : public EnergyComputerHandler::IEne using MeshType = Mesh<ConnectivityType>; using MeshDataType = MeshData<Dimension>; - std::shared_ptr<const DiscreteFunctionP0<Dimension, TinyVector<Dimension>>> m_solution; - std::shared_ptr<const DiscreteFunctionP0<Dimension, TinyVector<Dimension>>> m_dual_solution; - std::shared_ptr<const DiscreteFunctionP0<Dimension, double>> m_energy_delta; + DiscreteFunctionP0<Dimension, TinyVector<Dimension>> m_solution; + DiscreteFunctionP0<Dimension, TinyVector<Dimension>> m_dual_solution; + DiscreteFunctionP0<Dimension, double> m_energy_delta; class DirichletBoundaryCondition { @@ -1209,41 +1198,28 @@ class EnergyComputerHandler::EnergyComputer : public EnergyComputerHandler::IEne }; public: - std::tuple<std::shared_ptr<const IDiscreteFunction>, std::shared_ptr<const IDiscreteFunction>> + std::tuple<std::shared_ptr<const DiscreteFunctionVariant>, std::shared_ptr<const DiscreteFunctionVariant>> apply() const final { - return {m_energy_delta, m_dual_solution}; + return {std::make_shared<DiscreteFunctionVariant>(m_energy_delta), + std::make_shared<DiscreteFunctionVariant>(m_dual_solution)}; } - // std::tuple<std::shared_ptr<const IDiscreteFunction>, std::shared_ptr<const IDiscreteFunction>> - // computeEnergyUpdate() const final - // { - // m_scheme->computeEnergyUpdate(mesh, dual_lambdab, dual_mub, m_solution, - // m_dual_solution, // f, - // bc_descriptor_list); - - // return {m_dual_solution, m_energy_delta}; - // } - // compute the fluxes - // std::shared_ptr<const DiscreteFunctionP0<Dimension, double>> EnergyComputer(const std::shared_ptr<const MeshType>& mesh, - // const std::shared_ptr<const DiscreteFunctionP0<Dimension, double>>& alpha, - const std::shared_ptr<const DiscreteFunctionP0<Dimension, double>>& dual_lambdab, - const std::shared_ptr<const DiscreteFunctionP0<Dimension, double>>& dual_mub, - // const std::shared_ptr<const DiscreteFunctionP0<Dimension, double>>& dual_lambda, - const std::shared_ptr<const DiscreteFunctionP0<Dimension, TinyVector<Dimension>>>& U, - const std::shared_ptr<const DiscreteFunctionP0<Dimension, TinyVector<Dimension>>>& dual_U, - const std::shared_ptr<const DiscreteFunctionP0<Dimension, TinyVector<Dimension>>>& source, + const DiscreteFunctionP0<Dimension, const double>& dual_lambdab, + const DiscreteFunctionP0<Dimension, const double>& dual_mub, + const DiscreteFunctionP0<Dimension, const TinyVector<Dimension>>& U, + const DiscreteFunctionP0<Dimension, const TinyVector<Dimension>>& dual_U, + const DiscreteFunctionP0<Dimension, const TinyVector<Dimension>>& source, const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) + : m_solution(mesh), m_dual_solution(DualMeshManager::instance().getDiamondDualMesh(*mesh)), m_energy_delta(mesh) { - // Assert(mesh == alpha->mesh()); - Assert(mesh == U->mesh()); - // Assert(dual_lambda->mesh() == dual_mu->mesh()); - Assert(dual_lambdab->mesh() == dual_U->mesh()); - Assert(U->mesh() == source->mesh()); - Assert(dual_lambdab->mesh() == dual_mub->mesh()); - Assert(DualMeshManager::instance().getDiamondDualMesh(*mesh) == dual_mub->mesh(), + Assert(mesh == U.mesh()); + Assert(dual_lambdab.mesh() == dual_U.mesh()); + Assert(U.mesh() == source.mesh()); + Assert(dual_lambdab.mesh() == dual_mub.mesh()); + Assert(DualMeshManager::instance().getDiamondDualMesh(*mesh) == dual_mub.mesh(), "diffusion coefficient is not defined on the dual mesh!"); using MeshDataType = MeshData<Dimension>; @@ -1480,11 +1456,10 @@ class EnergyComputerHandler::EnergyComputer : public EnergyComputerHandler::IEne std::shared_ptr mapper = DualConnectivityManager::instance().getPrimalToDiamondDualConnectivityDataMapper(mesh->connectivity()); - CellValue<const double> dual_mubj = dual_mub->cellValues(); - CellValue<const double> dual_lambdabj = dual_lambdab->cellValues(); - // attention, fj not in this context - CellValue<const TinyVector<Dimension>> velocity = U->cellValues(); - // CellValue<const TinyVector<Dimension>> dual_velocity = dual_U->cellValues(); + CellValue<const double> dual_mubj = dual_mub.cellValues(); + CellValue<const double> dual_lambdabj = dual_lambdab.cellValues(); + + CellValue<const TinyVector<Dimension>> velocity = U.cellValues(); const CellValue<const double> dual_Vj = diamond_mesh_data.Vj(); @@ -1650,40 +1625,13 @@ class EnergyComputerHandler::EnergyComputer : public EnergyComputerHandler::IEne return computed_dual_cell_face_id; }(); - m_dual_solution = std::make_shared<DiscreteFunctionP0<Dimension, TinyVector<Dimension>>>(diamond_mesh); - // m_solution = std::make_shared<DiscreteFunctionP0<Dimension, TinyVector<Dimension>>>(mesh); - // const auto& solution = *U; - auto& dual_solution = *dual_U; - // dual_solution.fill(zero); - // const auto& face_to_cell_matrix = mesh->connectivity().faceToCellMatrix(); - // for (CellId cell_id = 0; cell_id < diamond_mesh->numberOfCells(); ++cell_id) { - // const FaceId face_id = dual_cell_face_id[cell_id]; - // CellId cell_id1 = face_to_cell_matrix[face_id][0]; - // if (primal_face_is_on_boundary[face_id]) { - // for (size_t i = 0; i < Dimension; ++i) { - // // A revoir!! - // dual_solution[cell_id][i] = solution[cell_id1][i]; - // } - // } else { - // CellId cell_id1 = face_to_cell_matrix[face_id][0]; - // CellId cell_id2 = face_to_cell_matrix[face_id][1]; - // for (size_t i = 0; i < Dimension; ++i) { - // dual_solution[cell_id][i] = 0.5 * (solution[cell_id1][i] + solution[cell_id2][i]); - // } - // } - // } + auto& dual_solution = dual_U; - // const Array<int> non_zeros{number_of_dof * Dimension}; - // non_zeros.fill(Dimension * Dimension); - // CRSMatrixDescriptor<double> S(number_of_dof * Dimension, number_of_dof * Dimension, non_zeros); - // Begining of main CellValuePerFace<double> flux{mesh->connectivity()}; parallel_for( flux.numberOfValues(), PUGS_LAMBDA(size_t jl) { flux[jl] = 0; }); for (FaceId face_id = 0; face_id < mesh->numberOfFaces(); ++face_id) { - // const double beta_mu_l = l2Norm(dualClj[face_id]) * alpha_mu_l[face_id] * mes_l[face_id]; - // const double beta_lambda_l = l2Norm(dualClj[face_id]) * alpha_lambda_l[face_id] * mes_l[face_id]; const double beta_mub_l = l2Norm(dualClj[face_id]) * alpha_mub_l[face_id] * mes_l[face_id]; const double beta_lambdab_l = l2Norm(dualClj[face_id]) * alpha_lambdab_l[face_id] * mes_l[face_id]; const auto& primal_face_to_cell = face_to_cell_matrix[face_id]; @@ -1802,20 +1750,18 @@ class EnergyComputerHandler::EnergyComputer : public EnergyComputerHandler::IEne // // exit(0); // } // Assemble - m_energy_delta = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); - auto& energy_delta = *m_energy_delta; // CellValue<const TinyVector<Dimension>> fj = source->cellValues(); double sum_deltae = 0.; for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { - energy_delta[cell_id] = 0.; // dot(fj[cell_id], velocity[cell_id]); - sum_deltae += energy_delta[cell_id]; + m_energy_delta[cell_id] = 0.; // dot(fj[cell_id], velocity[cell_id]); + sum_deltae += m_energy_delta[cell_id]; } // CellValue<double>& deltae = m_energy_delta->cellValues(); for (FaceId face_id = 0; face_id < mesh->numberOfFaces(); ++face_id) { for (size_t j = 0; j < face_to_cell_matrix[face_id].size(); j++) { CellId i_id = face_to_cell_matrix[face_id][j]; - energy_delta[i_id] -= flux(face_id, j) / primal_Vj[i_id]; + m_energy_delta[i_id] -= flux(face_id, j) / primal_Vj[i_id]; sum_deltae -= flux(face_id, j); } // exit(0); @@ -1830,37 +1776,37 @@ class EnergyComputerHandler::EnergyComputer : public EnergyComputerHandler::IEne } }; -std::tuple<std::shared_ptr<const IDiscreteFunction>, std::shared_ptr<const IDiscreteFunction>> +std::tuple<std::shared_ptr<const DiscreteFunctionVariant>, std::shared_ptr<const DiscreteFunctionVariant>> VectorDiamondSchemeHandler::apply() const { return m_scheme->apply(); } -std::tuple<std::shared_ptr<const IDiscreteFunction>, std::shared_ptr<const IDiscreteFunction>> +std::tuple<std::shared_ptr<const DiscreteFunctionVariant>, std::shared_ptr<const DiscreteFunctionVariant>> EnergyComputerHandler::computeEnergyUpdate() const { return m_energy_computer->apply(); } -std::shared_ptr<const IDiscreteFunction> +std::shared_ptr<const DiscreteFunctionVariant> VectorDiamondSchemeHandler::solution() const { return m_scheme->getSolution(); } -std::shared_ptr<const IDiscreteFunction> +std::shared_ptr<const DiscreteFunctionVariant> VectorDiamondSchemeHandler::dual_solution() const { return m_scheme->getDualSolution(); } VectorDiamondSchemeHandler::VectorDiamondSchemeHandler( - const std::shared_ptr<const IDiscreteFunction>& alpha, - const std::shared_ptr<const IDiscreteFunction>& dual_lambdab, - const std::shared_ptr<const IDiscreteFunction>& dual_mub, - const std::shared_ptr<const IDiscreteFunction>& dual_lambda, - const std::shared_ptr<const IDiscreteFunction>& dual_mu, - const std::shared_ptr<const IDiscreteFunction>& f, + const std::shared_ptr<const DiscreteFunctionVariant>& alpha, + const std::shared_ptr<const DiscreteFunctionVariant>& dual_lambdab, + const std::shared_ptr<const DiscreteFunctionVariant>& dual_mub, + const std::shared_ptr<const DiscreteFunctionVariant>& dual_lambda, + const std::shared_ptr<const DiscreteFunctionVariant>& dual_mu, + const std::shared_ptr<const DiscreteFunctionVariant>& f, const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) { const std::shared_ptr i_mesh = getCommonMesh({alpha, f}); @@ -1876,26 +1822,23 @@ VectorDiamondSchemeHandler::VectorDiamondSchemeHandler( switch (i_mesh->dimension()) { case 1: { using MeshType = Mesh<Connectivity<1>>; - using DiscreteScalarFunctionType = DiscreteFunctionP0<1, double>; - using DiscreteVectorFunctionType = DiscreteFunctionP0<1, TinyVector<1>>; + using DiscreteScalarFunctionType = DiscreteFunctionP0<1, const double>; + using DiscreteVectorFunctionType = DiscreteFunctionP0<1, const TinyVector<1>>; std::shared_ptr mesh = std::dynamic_pointer_cast<const MeshType>(i_mesh); - m_scheme = - std::make_unique<VectorDiamondScheme<1>>(mesh, std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(alpha), - std::dynamic_pointer_cast<const DiscreteScalarFunctionType>( - dual_lambdab), - std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(dual_mub), - std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(dual_lambda), - std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(dual_mu), - std::dynamic_pointer_cast<const DiscreteVectorFunctionType>(f), - bc_descriptor_list); + m_scheme = std::make_unique<VectorDiamondScheme<1>>(mesh, alpha->get<DiscreteScalarFunctionType>(), + dual_lambdab->get<DiscreteScalarFunctionType>(), + dual_mub->get<DiscreteScalarFunctionType>(), + dual_lambda->get<DiscreteScalarFunctionType>(), + dual_mu->get<DiscreteScalarFunctionType>(), + f->get<DiscreteVectorFunctionType>(), bc_descriptor_list); break; } case 2: { using MeshType = Mesh<Connectivity<2>>; - using DiscreteScalarFunctionType = DiscreteFunctionP0<2, double>; - using DiscreteVectorFunctionType = DiscreteFunctionP0<2, TinyVector<2>>; + using DiscreteScalarFunctionType = DiscreteFunctionP0<2, const double>; + using DiscreteVectorFunctionType = DiscreteFunctionP0<2, const TinyVector<2>>; std::shared_ptr mesh = std::dynamic_pointer_cast<const MeshType>(i_mesh); @@ -1903,21 +1846,18 @@ VectorDiamondSchemeHandler::VectorDiamondSchemeHandler( throw NormalError("dual variables are is not defined on the diamond dual of the primal mesh"); } - m_scheme = - std::make_unique<VectorDiamondScheme<2>>(mesh, std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(alpha), - std::dynamic_pointer_cast<const DiscreteScalarFunctionType>( - dual_lambdab), - std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(dual_mub), - std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(dual_lambda), - std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(dual_mu), - std::dynamic_pointer_cast<const DiscreteVectorFunctionType>(f), - bc_descriptor_list); + m_scheme = std::make_unique<VectorDiamondScheme<2>>(mesh, alpha->get<DiscreteScalarFunctionType>(), + dual_lambdab->get<DiscreteScalarFunctionType>(), + dual_mub->get<DiscreteScalarFunctionType>(), + dual_lambda->get<DiscreteScalarFunctionType>(), + dual_mu->get<DiscreteScalarFunctionType>(), + f->get<DiscreteVectorFunctionType>(), bc_descriptor_list); break; } case 3: { using MeshType = Mesh<Connectivity<3>>; - using DiscreteScalarFunctionType = DiscreteFunctionP0<3, double>; - using DiscreteVectorFunctionType = DiscreteFunctionP0<3, TinyVector<3>>; + using DiscreteScalarFunctionType = DiscreteFunctionP0<3, const double>; + using DiscreteVectorFunctionType = DiscreteFunctionP0<3, const TinyVector<3>>; std::shared_ptr mesh = std::dynamic_pointer_cast<const MeshType>(i_mesh); @@ -1925,15 +1865,12 @@ VectorDiamondSchemeHandler::VectorDiamondSchemeHandler( throw NormalError("dual variables are is not defined on the diamond dual of the primal mesh"); } - m_scheme = - std::make_unique<VectorDiamondScheme<3>>(mesh, std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(alpha), - std::dynamic_pointer_cast<const DiscreteScalarFunctionType>( - dual_lambdab), - std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(dual_mub), - std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(dual_lambda), - std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(dual_mu), - std::dynamic_pointer_cast<const DiscreteVectorFunctionType>(f), - bc_descriptor_list); + m_scheme = std::make_unique<VectorDiamondScheme<3>>(mesh, alpha->get<DiscreteScalarFunctionType>(), + dual_lambdab->get<DiscreteScalarFunctionType>(), + dual_mub->get<DiscreteScalarFunctionType>(), + dual_lambda->get<DiscreteScalarFunctionType>(), + dual_mu->get<DiscreteScalarFunctionType>(), + f->get<DiscreteVectorFunctionType>(), bc_descriptor_list); break; } default: { @@ -1945,11 +1882,11 @@ VectorDiamondSchemeHandler::VectorDiamondSchemeHandler( VectorDiamondSchemeHandler::~VectorDiamondSchemeHandler() = default; EnergyComputerHandler::EnergyComputerHandler( - const std::shared_ptr<const IDiscreteFunction>& dual_lambdab, - const std::shared_ptr<const IDiscreteFunction>& dual_mub, - const std::shared_ptr<const IDiscreteFunction>& U, - const std::shared_ptr<const IDiscreteFunction>& dual_U, - const std::shared_ptr<const IDiscreteFunction>& source, + const std::shared_ptr<const DiscreteFunctionVariant>& dual_lambdab, + const std::shared_ptr<const DiscreteFunctionVariant>& dual_mub, + const std::shared_ptr<const DiscreteFunctionVariant>& U, + const std::shared_ptr<const DiscreteFunctionVariant>& dual_U, + const std::shared_ptr<const DiscreteFunctionVariant>& source, const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) { const std::shared_ptr i_mesh = getCommonMesh({U, source}); @@ -1965,8 +1902,8 @@ EnergyComputerHandler::EnergyComputerHandler( switch (i_mesh->dimension()) { case 1: { using MeshType = Mesh<Connectivity<1>>; - using DiscreteScalarFunctionType = DiscreteFunctionP0<1, double>; - using DiscreteVectorFunctionType = DiscreteFunctionP0<1, TinyVector<1>>; + using DiscreteScalarFunctionType = DiscreteFunctionP0<1, const double>; + using DiscreteVectorFunctionType = DiscreteFunctionP0<1, const TinyVector<1>>; std::shared_ptr mesh = std::dynamic_pointer_cast<const MeshType>(i_mesh); @@ -1975,19 +1912,17 @@ EnergyComputerHandler::EnergyComputerHandler( } m_energy_computer = - std::make_unique<EnergyComputer<1>>(mesh, - std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(dual_lambdab), - std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(dual_mub), - std::dynamic_pointer_cast<const DiscreteVectorFunctionType>(U), - std::dynamic_pointer_cast<const DiscreteVectorFunctionType>(dual_U), - std::dynamic_pointer_cast<const DiscreteVectorFunctionType>(source), - bc_descriptor_list); + std::make_unique<EnergyComputer<1>>(mesh, dual_lambdab->get<DiscreteScalarFunctionType>(), + dual_mub->get<DiscreteScalarFunctionType>(), + U->get<DiscreteVectorFunctionType>(), + dual_U->get<DiscreteVectorFunctionType>(), + source->get<DiscreteVectorFunctionType>(), bc_descriptor_list); break; } case 2: { using MeshType = Mesh<Connectivity<2>>; - using DiscreteScalarFunctionType = DiscreteFunctionP0<2, double>; - using DiscreteVectorFunctionType = DiscreteFunctionP0<2, TinyVector<2>>; + using DiscreteScalarFunctionType = DiscreteFunctionP0<2, const double>; + using DiscreteVectorFunctionType = DiscreteFunctionP0<2, const TinyVector<2>>; std::shared_ptr mesh = std::dynamic_pointer_cast<const MeshType>(i_mesh); @@ -1996,19 +1931,18 @@ EnergyComputerHandler::EnergyComputerHandler( } m_energy_computer = - std::make_unique<EnergyComputer<2>>(mesh, - std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(dual_lambdab), - std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(dual_mub), - std::dynamic_pointer_cast<const DiscreteVectorFunctionType>(U), - std::dynamic_pointer_cast<const DiscreteVectorFunctionType>(dual_U), - std::dynamic_pointer_cast<const DiscreteVectorFunctionType>(source), - bc_descriptor_list); + std::make_unique<EnergyComputer<2>>(mesh, dual_lambdab->get<DiscreteScalarFunctionType>(), + dual_mub->get<DiscreteScalarFunctionType>(), + U->get<DiscreteVectorFunctionType>(), + dual_U->get<DiscreteVectorFunctionType>(), + source->get<DiscreteVectorFunctionType>(), bc_descriptor_list); + break; } case 3: { using MeshType = Mesh<Connectivity<3>>; - using DiscreteScalarFunctionType = DiscreteFunctionP0<3, double>; - using DiscreteVectorFunctionType = DiscreteFunctionP0<3, TinyVector<3>>; + using DiscreteScalarFunctionType = DiscreteFunctionP0<3, const double>; + using DiscreteVectorFunctionType = DiscreteFunctionP0<3, const TinyVector<3>>; std::shared_ptr mesh = std::dynamic_pointer_cast<const MeshType>(i_mesh); @@ -2017,13 +1951,12 @@ EnergyComputerHandler::EnergyComputerHandler( } m_energy_computer = - std::make_unique<EnergyComputer<3>>(mesh, - std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(dual_lambdab), - std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(dual_mub), - std::dynamic_pointer_cast<const DiscreteVectorFunctionType>(U), - std::dynamic_pointer_cast<const DiscreteVectorFunctionType>(dual_U), - std::dynamic_pointer_cast<const DiscreteVectorFunctionType>(source), - bc_descriptor_list); + std::make_unique<EnergyComputer<3>>(mesh, dual_lambdab->get<DiscreteScalarFunctionType>(), + dual_mub->get<DiscreteScalarFunctionType>(), + U->get<DiscreteVectorFunctionType>(), + dual_U->get<DiscreteVectorFunctionType>(), + source->get<DiscreteVectorFunctionType>(), bc_descriptor_list); + break; } default: { diff --git a/src/scheme/VectorDiamondScheme.hpp b/src/scheme/VectorDiamondScheme.hpp index 20bbadfa3934cabf213d201e47397c97d56047e0..16bee0ffbf1493e3b56b1a260189fe95157803cf 100644 --- a/src/scheme/VectorDiamondScheme.hpp +++ b/src/scheme/VectorDiamondScheme.hpp @@ -18,6 +18,7 @@ #include <mesh/PrimalToDiamondDualConnectivityDataMapper.hpp> #include <output/VTKWriter.hpp> #include <scheme/DirichletBoundaryConditionDescriptor.hpp> +#include <scheme/DiscreteFunctionVariant.hpp> #include <scheme/NeumannBoundaryConditionDescriptor.hpp> #include <scheme/SymmetryBoundaryConditionDescriptor.hpp> @@ -34,19 +35,20 @@ class VectorDiamondSchemeHandler public: std::unique_ptr<IVectorDiamondScheme> m_scheme; - std::shared_ptr<const IDiscreteFunction> solution() const; + std::shared_ptr<const DiscreteFunctionVariant> solution() const; - std::shared_ptr<const IDiscreteFunction> dual_solution() const; + std::shared_ptr<const DiscreteFunctionVariant> dual_solution() const; - std::tuple<std::shared_ptr<const IDiscreteFunction>, std::shared_ptr<const IDiscreteFunction>> apply() const; + std::tuple<std::shared_ptr<const DiscreteFunctionVariant>, std::shared_ptr<const DiscreteFunctionVariant>> apply() + const; VectorDiamondSchemeHandler( - const std::shared_ptr<const IDiscreteFunction>& alphab, - const std::shared_ptr<const IDiscreteFunction>& lambdab, - const std::shared_ptr<const IDiscreteFunction>& alpha, - const std::shared_ptr<const IDiscreteFunction>& lambda, - const std::shared_ptr<const IDiscreteFunction>& mu, - const std::shared_ptr<const IDiscreteFunction>& f, + const std::shared_ptr<const DiscreteFunctionVariant>& alphab, + const std::shared_ptr<const DiscreteFunctionVariant>& lambdab, + const std::shared_ptr<const DiscreteFunctionVariant>& alpha, + const std::shared_ptr<const DiscreteFunctionVariant>& lambda, + const std::shared_ptr<const DiscreteFunctionVariant>& mu, + const std::shared_ptr<const DiscreteFunctionVariant>& f, const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list); ~VectorDiamondSchemeHandler(); @@ -64,16 +66,16 @@ class EnergyComputerHandler public: std::unique_ptr<IEnergyComputer> m_energy_computer; - std::shared_ptr<const IDiscreteFunction> dual_solution() const; + std::shared_ptr<const DiscreteFunctionVariant> dual_solution() const; - std::tuple<std::shared_ptr<const IDiscreteFunction>, std::shared_ptr<const IDiscreteFunction>> computeEnergyUpdate() - const; + std::tuple<std::shared_ptr<const DiscreteFunctionVariant>, std::shared_ptr<const DiscreteFunctionVariant>> + computeEnergyUpdate() const; - EnergyComputerHandler(const std::shared_ptr<const IDiscreteFunction>& lambdab, - const std::shared_ptr<const IDiscreteFunction>& mub, - const std::shared_ptr<const IDiscreteFunction>& U, - const std::shared_ptr<const IDiscreteFunction>& dual_U, - const std::shared_ptr<const IDiscreteFunction>& source, + EnergyComputerHandler(const std::shared_ptr<const DiscreteFunctionVariant>& lambdab, + const std::shared_ptr<const DiscreteFunctionVariant>& mub, + const std::shared_ptr<const DiscreteFunctionVariant>& U, + const std::shared_ptr<const DiscreteFunctionVariant>& dual_U, + const std::shared_ptr<const DiscreteFunctionVariant>& source, const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list); ~EnergyComputerHandler(); diff --git a/src/utils/Array.hpp b/src/utils/Array.hpp index 7535b673565fa04aadba3935420f6946f5ad5544..3ee64824a650e18714a9b4b8523afb78cc89f643 100644 --- a/src/utils/Array.hpp +++ b/src/utils/Array.hpp @@ -24,6 +24,18 @@ class [[nodiscard]] Array const size_t m_size; public: + friend std::ostream& + operator<<(std::ostream& os, const UnsafeArrayView& x) + { + if (x.size() > 0) { + os << 0 << ':' << NaNHelper(x[0]); + } + for (size_t i = 1; i < x.size(); ++i) { + os << ' ' << i << ':' << NaNHelper(x[i]); + } + return os; + } + [[nodiscard]] PUGS_INLINE size_t size() const { diff --git a/src/utils/PugsTraits.hpp b/src/utils/PugsTraits.hpp index 46a2b1d6dc5923d8ee12668d88484875f404944c..285d7978d8a8f05e784534d0fb475bc01da75042 100644 --- a/src/utils/PugsTraits.hpp +++ b/src/utils/PugsTraits.hpp @@ -20,6 +20,12 @@ class ItemValue; template <typename DataType, ItemType item_type, typename ConnectivityPtr> class ItemArray; +template <size_t Dimension, typename DataType> +class DiscreteFunctionP0; + +template <size_t Dimension, typename DataType> +class DiscreteFunctionP0Vector; + // Traits is_trivially_castable template <typename T> @@ -116,7 +122,7 @@ constexpr inline bool is_item_value_v = false; template <typename DataType, ItemType item_type, typename ConnectivityPtr> constexpr inline bool is_item_value_v<ItemValue<DataType, item_type, ConnectivityPtr>> = true; -// Trais is ItemValue +// Trais is ItemArray template <typename T> constexpr inline bool is_item_array_v = false; @@ -124,6 +130,27 @@ constexpr inline bool is_item_array_v = false; template <typename DataType, ItemType item_type, typename ConnectivityPtr> constexpr inline bool is_item_array_v<ItemArray<DataType, item_type, ConnectivityPtr>> = true; +// Trais is DiscreteFunctionP0 + +template <typename T> +constexpr inline bool is_discrete_function_P0_v = false; + +template <size_t Dimension, typename DataType> +constexpr inline bool is_discrete_function_P0_v<DiscreteFunctionP0<Dimension, DataType>> = true; + +// Trais is DiscreteFunctionP0Vector + +template <typename T> +constexpr inline bool is_discrete_function_P0_vector_v = false; + +template <size_t Dimension, typename DataType> +constexpr inline bool is_discrete_function_P0_vector_v<DiscreteFunctionP0Vector<Dimension, DataType>> = true; + +// Trais is DiscreteFunction + +template <typename T> +constexpr inline bool is_discrete_function_v = is_discrete_function_P0_v<T> or is_discrete_function_P0_vector_v<T>; + // helper to check if a type is part of a variant template <typename T, typename V> diff --git a/src/utils/Table.hpp b/src/utils/Table.hpp index 6972ea1030dedbdd30c039e0880a3773024603dc..a4a134dfd1d5838766b062eb429c725eb66bbb33 100644 --- a/src/utils/Table.hpp +++ b/src/utils/Table.hpp @@ -63,6 +63,19 @@ class [[nodiscard]] Table Assert(row < table.numberOfRows(), "required row view is not contained in the Table"); } + friend std::ostream& + operator<<(std::ostream& os, const UnsafeRowView& x) + { + if (x.size() > 0) { + os << 0 << ':' << NaNHelper(x[0]); + } + for (size_t i = 1; i < x.size(); ++i) { + os << ' ' << i << ':' << NaNHelper(x[i]); + } + + return os; + } + // To try to keep these views close to the initial array one // forbids copy constructor and take benefits of C++-17 copy // elisions. @@ -113,6 +126,19 @@ class [[nodiscard]] Table } } + friend std::ostream& + operator<<(std::ostream& os, const RowView& x) + { + if (x.size() > 0) { + os << 0 << ':' << NaNHelper(x[0]); + } + for (size_t i = 1; i < x.size(); ++i) { + os << ' ' << i << ':' << NaNHelper(x[i]); + } + + return os; + } + RowView(const UnsafeTableView& table_view, index_type row) : m_table_view{table_view}, m_row{row} { Assert(row < m_table_view.numberOfRows(), "required row view is not contained in the Table view"); @@ -155,6 +181,19 @@ class [[nodiscard]] Table return m_table(m_row_begin + i, m_column_begin + j); } + friend std::ostream& + operator<<(std::ostream& os, const UnsafeTableView& t) + { + for (size_t i = 0; i < t.numberOfRows(); ++i) { + os << i << '|'; + for (size_t j = 0; j < t.numberOfColumns(); ++j) { + os << ' ' << j << ':' << NaNHelper(t(i, j)); + } + os << '\n'; + } + return os; + } + PUGS_INLINE void fill(const DataType& data) const { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3f174398186c2b5fd0bcc56aef017f40936f9704..0e585acac5ba1e5b7656ffa29411567e0f0d54f4 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -82,7 +82,7 @@ add_executable (unit_tests test_EdgeIntegrator.cpp test_EigenvalueSolver.cpp test_EmbeddedData.cpp - test_EmbeddedIDiscreteFunctionUtils.cpp + test_EmbeddedDiscreteFunctionUtils.cpp test_EscapedString.cpp test_Exceptions.cpp test_ExecutionPolicy.cpp @@ -167,8 +167,12 @@ add_executable (mpi_unit_tests test_DiscreteFunctionVectorIntegratorByZone.cpp test_DiscreteFunctionVectorInterpoler.cpp test_DiscreteFunctionVectorInterpolerByZone.cpp - test_EmbeddedIDiscreteFunctionMathFunctions.cpp - test_EmbeddedIDiscreteFunctionOperators.cpp + test_EmbeddedDiscreteFunctionMathFunctions1D.cpp + test_EmbeddedDiscreteFunctionMathFunctions2D.cpp + test_EmbeddedDiscreteFunctionMathFunctions3D.cpp + test_EmbeddedDiscreteFunctionOperators1D.cpp + test_EmbeddedDiscreteFunctionOperators2D.cpp + test_EmbeddedDiscreteFunctionOperators3D.cpp test_InterpolateItemArray.cpp test_InterpolateItemValue.cpp test_ItemArray.cpp diff --git a/tests/FixturesForBuiltinT.hpp b/tests/FixturesForBuiltinT.hpp index d2ff0fcb3b0db1e37a9a5f00487eb8288f1aec3d..52348a23daf00350de702f7978b46639a8bef41d 100644 --- a/tests/FixturesForBuiltinT.hpp +++ b/tests/FixturesForBuiltinT.hpp @@ -9,7 +9,7 @@ template <> inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<const double>> = ASTNodeDataType::build<ASTNodeDataType::type_id_t>("builtin_t"); -const auto builtin_data_type = ast_node_data_type_from<std::shared_ptr<const double>>; +inline const auto builtin_data_type = ast_node_data_type_from<std::shared_ptr<const double>>; inline std::shared_ptr<const double> operator-(const std::shared_ptr<const double>& p_a) diff --git a/tests/test_ASTNodeFunctionExpressionBuilder.cpp b/tests/test_ASTNodeFunctionExpressionBuilder.cpp index f19b6585613db943b77d684008974e737140686d..762202a671b1f7708b193ca8cd6c7aa599bfc780 100644 --- a/tests/test_ASTNodeFunctionExpressionBuilder.cpp +++ b/tests/test_ASTNodeFunctionExpressionBuilder.cpp @@ -370,13 +370,30 @@ cat("foo", 2.5e-3); let f : R^1 -> R^1, x -> x+x; let x : R^1, x = 1; f(x); +let n:N, n=1; +f(true); +f(n); +f(2); +f(1.4); )"; std::string_view result = R"( (root:ASTNodeListProcessor) + +-(language::function_evaluation:FunctionProcessor) + | +-(language::name:f:NameProcessor) + | `-(language::name:x:NameProcessor) + +-(language::function_evaluation:FunctionProcessor) + | +-(language::name:f:NameProcessor) + | `-(language::true_kw:ValueProcessor) + +-(language::function_evaluation:FunctionProcessor) + | +-(language::name:f:NameProcessor) + | `-(language::name:n:NameProcessor) + +-(language::function_evaluation:FunctionProcessor) + | +-(language::name:f:NameProcessor) + | `-(language::integer:2:ValueProcessor) `-(language::function_evaluation:FunctionProcessor) +-(language::name:f:NameProcessor) - `-(language::name:x:NameProcessor) + `-(language::real:1.4:ValueProcessor) )"; CHECK_AST(data, result); @@ -424,13 +441,30 @@ f(x); let f : R^1x1 -> R^1x1, x -> x+x; let x : R^1x1, x = 1; f(x); +let n:N, n=1; +f(true); +f(n); +f(2); +f(1.4); )"; std::string_view result = R"( (root:ASTNodeListProcessor) + +-(language::function_evaluation:FunctionProcessor) + | +-(language::name:f:NameProcessor) + | `-(language::name:x:NameProcessor) + +-(language::function_evaluation:FunctionProcessor) + | +-(language::name:f:NameProcessor) + | `-(language::true_kw:ValueProcessor) + +-(language::function_evaluation:FunctionProcessor) + | +-(language::name:f:NameProcessor) + | `-(language::name:n:NameProcessor) + +-(language::function_evaluation:FunctionProcessor) + | +-(language::name:f:NameProcessor) + | `-(language::integer:2:ValueProcessor) `-(language::function_evaluation:FunctionProcessor) +-(language::name:f:NameProcessor) - `-(language::name:x:NameProcessor) + `-(language::real:1.4:ValueProcessor) )"; CHECK_AST(data, result); @@ -1115,6 +1149,170 @@ prev(3 + .24); CHECK_EXPRESSION_BUILDER_THROWS_WITH(data, std::string{"invalid implicit conversion: R -> Z"}); } + + SECTION("B -> R^2") + { + std::string_view data = R"( +let f : R^2 -> R^2, x -> x; +f(true); +)"; + + CHECK_EXPRESSION_BUILDER_THROWS_WITH(data, std::string{"invalid implicit conversion: B -> R^2"}); + } + + SECTION("N -> R^2") + { + std::string_view data = R"( +let f : R^2 -> R^2, x -> x; +let n : N, n = 2; +f(n); +)"; + + CHECK_EXPRESSION_BUILDER_THROWS_WITH(data, std::string{"invalid implicit conversion: N -> R^2"}); + } + + SECTION("Z -> R^2") + { + std::string_view data = R"( +let f : R^2 -> R^2, x -> x; +f(-2); +)"; + + CHECK_EXPRESSION_BUILDER_THROWS_WITH(data, std::string{"invalid implicit conversion: Z -> R^2"}); + } + + SECTION("R -> R^2") + { + std::string_view data = R"( +let f : R^2 -> R^2, x -> x; +f(1.3); +)"; + + CHECK_EXPRESSION_BUILDER_THROWS_WITH(data, std::string{"invalid implicit conversion: R -> R^2"}); + } + + SECTION("B -> R^3") + { + std::string_view data = R"( +let f : R^3 -> R^3, x -> x; +f(true); +)"; + + CHECK_EXPRESSION_BUILDER_THROWS_WITH(data, std::string{"invalid implicit conversion: B -> R^3"}); + } + + SECTION("N -> R^3") + { + std::string_view data = R"( +let f : R^3 -> R^3, x -> x; +let n : N, n = 2; +f(n); +)"; + + CHECK_EXPRESSION_BUILDER_THROWS_WITH(data, std::string{"invalid implicit conversion: N -> R^3"}); + } + + SECTION("Z -> R^3") + { + std::string_view data = R"( +let f : R^3 -> R^3, x -> x; +f(-2); +)"; + + CHECK_EXPRESSION_BUILDER_THROWS_WITH(data, std::string{"invalid implicit conversion: Z -> R^3"}); + } + + SECTION("R -> R^3") + { + std::string_view data = R"( +let f : R^3 -> R^3, x -> x; +f(1.3); +)"; + + CHECK_EXPRESSION_BUILDER_THROWS_WITH(data, std::string{"invalid implicit conversion: R -> R^3"}); + } + + SECTION("B -> R^2x2") + { + std::string_view data = R"( +let f : R^2x2 -> R^2x2, x -> x; +f(true); +)"; + + CHECK_EXPRESSION_BUILDER_THROWS_WITH(data, std::string{"invalid implicit conversion: B -> R^2x2"}); + } + + SECTION("N -> R^2x2") + { + std::string_view data = R"( +let f : R^2x2 -> R^2x2, x -> x; +let n : N, n = 2; +f(n); +)"; + + CHECK_EXPRESSION_BUILDER_THROWS_WITH(data, std::string{"invalid implicit conversion: N -> R^2x2"}); + } + + SECTION("Z -> R^2x2") + { + std::string_view data = R"( +let f : R^2x2 -> R^2x2, x -> x; +f(-2); +)"; + + CHECK_EXPRESSION_BUILDER_THROWS_WITH(data, std::string{"invalid implicit conversion: Z -> R^2x2"}); + } + + SECTION("R -> R^2x2") + { + std::string_view data = R"( +let f : R^2x2 -> R^2x2, x -> x; +f(1.3); +)"; + + CHECK_EXPRESSION_BUILDER_THROWS_WITH(data, std::string{"invalid implicit conversion: R -> R^2x2"}); + } + + SECTION("B -> R^3x3") + { + std::string_view data = R"( +let f : R^3x3 -> R^3x3, x -> x; +f(true); +)"; + + CHECK_EXPRESSION_BUILDER_THROWS_WITH(data, std::string{"invalid implicit conversion: B -> R^3x3"}); + } + + SECTION("N -> R^3x3") + { + std::string_view data = R"( +let f : R^3x3 -> R^3x3, x -> x; +let n : N, n = 2; +f(n); +)"; + + CHECK_EXPRESSION_BUILDER_THROWS_WITH(data, std::string{"invalid implicit conversion: N -> R^3x3"}); + } + + SECTION("Z -> R^3x3") + { + std::string_view data = R"( +let f : R^3x3 -> R^3x3, x -> x; +f(-2); +)"; + + CHECK_EXPRESSION_BUILDER_THROWS_WITH(data, std::string{"invalid implicit conversion: Z -> R^3x3"}); + } + + SECTION("R -> R^3x3") + { + std::string_view data = R"( +let f : R^3x3 -> R^3x3, x -> x; +f(1.3); +)"; + + CHECK_EXPRESSION_BUILDER_THROWS_WITH(data, std::string{"invalid implicit conversion: R -> R^3x3"}); + } } SECTION("arguments invalid tuple -> R^d conversion") diff --git a/tests/test_BuiltinFunctionEmbedder.cpp b/tests/test_BuiltinFunctionEmbedder.cpp index 7fd481e163a77f73b32a0d08fba3f49224cdc130..2e56fe228bc4b5d0ae863ae177b3633efbfa6e90 100644 --- a/tests/test_BuiltinFunctionEmbedder.cpp +++ b/tests/test_BuiltinFunctionEmbedder.cpp @@ -10,12 +10,8 @@ inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<const double>> = ASTNodeDataType::build<ASTNodeDataType::type_id_t>("shared_const_double"); template <> -inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<double>> = - ASTNodeDataType::build<ASTNodeDataType::type_id_t>("shared_double"); - -template <> -inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<uint64_t>> = - ASTNodeDataType::build<ASTNodeDataType::type_id_t>("shared_uint64_t"); +inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<const uint64_t>> = + ASTNodeDataType::build<ASTNodeDataType::type_id_t>("shared_const_uint64_t"); TEST_CASE("BuiltinFunctionEmbedder", "[language]") { @@ -177,7 +173,7 @@ TEST_CASE("BuiltinFunctionEmbedder", "[language]") REQUIRE(*data.data_ptr() == (2.3 + 4ul)); } - SECTION("double(std::shared_ptr<double>) BuiltinFunctionEmbedder") + SECTION("double(std::shared_ptr<const double>) BuiltinFunctionEmbedder") { std::function abs = [&](std::shared_ptr<const double> x) -> double { return std::abs(*x); }; @@ -237,7 +233,7 @@ TEST_CASE("BuiltinFunctionEmbedder", "[language]") SECTION("uint64_t(std::vector<EmbeddedData>) BuiltinFunctionEmbedder") { - std::function sum = [&](const std::vector<std::shared_ptr<uint64_t>>& x) -> uint64_t { + std::function sum = [&](const std::vector<std::shared_ptr<const uint64_t>>& x) -> uint64_t { uint64_t sum = 0; for (size_t i = 0; i < x.size(); ++i) { sum += *x[i]; @@ -246,7 +242,7 @@ TEST_CASE("BuiltinFunctionEmbedder", "[language]") }; std::unique_ptr<IBuiltinFunctionEmbedder> i_embedded_c = - std::make_unique<BuiltinFunctionEmbedder<uint64_t(const std::vector<std::shared_ptr<uint64_t>>&)>>(sum); + std::make_unique<BuiltinFunctionEmbedder<uint64_t(const std::vector<std::shared_ptr<const uint64_t>>&)>>(sum); REQUIRE(i_embedded_c->numberOfParameters() == 1); REQUIRE(i_embedded_c->getParameterDataTypes().size() == 1); @@ -255,21 +251,21 @@ TEST_CASE("BuiltinFunctionEmbedder", "[language]") std::vector<EmbeddedData> embedded_data; REQUIRE(std::get<uint64_t>(i_embedded_c->apply({embedded_data})) == 0); - embedded_data.emplace_back(std::make_shared<DataHandler<uint64_t>>(std::make_shared<uint64_t>(1))); - embedded_data.emplace_back(std::make_shared<DataHandler<uint64_t>>(std::make_shared<uint64_t>(2))); - embedded_data.emplace_back(std::make_shared<DataHandler<uint64_t>>(std::make_shared<uint64_t>(3))); + embedded_data.emplace_back(std::make_shared<DataHandler<const uint64_t>>(std::make_shared<const uint64_t>(1))); + embedded_data.emplace_back(std::make_shared<DataHandler<const uint64_t>>(std::make_shared<const uint64_t>(2))); + embedded_data.emplace_back(std::make_shared<DataHandler<const uint64_t>>(std::make_shared<const uint64_t>(3))); REQUIRE(std::get<uint64_t>(i_embedded_c->apply({embedded_data})) == 6); - embedded_data.emplace_back(std::make_shared<DataHandler<double>>(std::make_shared<double>(4))); + embedded_data.emplace_back(std::make_shared<DataHandler<const double>>(std::make_shared<const double>(4))); REQUIRE_THROWS_WITH(i_embedded_c->apply({embedded_data}), "unexpected error: unexpected argument types while casting: invalid" " EmbeddedData type, expecting " + - demangle<DataHandler<uint64_t>>()); + demangle<DataHandler<const uint64_t>>()); REQUIRE_THROWS_WITH(i_embedded_c->apply({TinyVector<1>{13}}), "unexpected error: unexpected argument types while casting \"" + demangle<TinyVector<1>>() + - "\" to \"" + demangle<std::vector<std::shared_ptr<uint64_t>>>() + '"'); + "\" to \"" + demangle<std::vector<std::shared_ptr<const uint64_t>>>() + '"'); } SECTION("double(void) BuiltinFunctionEmbedder") @@ -286,9 +282,9 @@ TEST_CASE("BuiltinFunctionEmbedder", "[language]") REQUIRE(i_embedded_c->getReturnDataType() == ASTNodeDataType::double_t); } - SECTION("R*R -> R*R^2*shared_double BuiltinFunctionEmbedder") + SECTION("R*R -> R*R^2*shared_const_double BuiltinFunctionEmbedder") { - std::function c = [](double a, double b) -> std::tuple<double, TinyVector<2>, std::shared_ptr<double>> { + std::function c = [](double a, double b) -> std::tuple<double, TinyVector<2>, std::shared_ptr<const double>> { return std::make_tuple(a + b, TinyVector<2>{b, -a}, std::make_shared<double>(a - b)); }; @@ -311,15 +307,15 @@ TEST_CASE("BuiltinFunctionEmbedder", "[language]") REQUIRE(*data_type.contentTypeList()[0] == ASTNodeDataType::double_t); REQUIRE(*data_type.contentTypeList()[1] == ASTNodeDataType::build<ASTNodeDataType::vector_t>(2)); - REQUIRE(*data_type.contentTypeList()[2] == ast_node_data_type_from<std::shared_ptr<double>>); + REQUIRE(*data_type.contentTypeList()[2] == ast_node_data_type_from<std::shared_ptr<const double>>); } - SECTION("void -> N*R*shared_double BuiltinFunctionEmbedder") + SECTION("void -> N*R*shared_const_double BuiltinFunctionEmbedder") { - std::function c = [](void) -> std::tuple<uint64_t, double, std::shared_ptr<double>> { + std::function c = [](void) -> std::tuple<uint64_t, double, std::shared_ptr<const double>> { uint64_t a = 1; double b = 3.5; - return std::make_tuple(a, b, std::make_shared<double>(a + b)); + return std::make_tuple(a, b, std::make_shared<const double>(a + b)); }; std::unique_ptr<IBuiltinFunctionEmbedder> i_embedded_c = @@ -357,19 +353,19 @@ TEST_CASE("BuiltinFunctionEmbedder", "[language]") SECTION("EmbeddedData(void) BuiltinFunctionEmbedder") { - std::function c = [](void) -> std::shared_ptr<double> { return std::make_shared<double>(1.5); }; + std::function c = [](void) -> std::shared_ptr<const double> { return std::make_shared<const double>(1.5); }; std::unique_ptr<IBuiltinFunctionEmbedder> i_embedded_c = - std::make_unique<BuiltinFunctionEmbedder<std::shared_ptr<double>(void)>>(c); + std::make_unique<BuiltinFunctionEmbedder<std::shared_ptr<const double>(void)>>(c); REQUIRE(i_embedded_c->numberOfParameters() == 0); REQUIRE(i_embedded_c->getParameterDataTypes().size() == 0); - REQUIRE(i_embedded_c->getReturnDataType() == ast_node_data_type_from<std::shared_ptr<double>>); + REQUIRE(i_embedded_c->getReturnDataType() == ast_node_data_type_from<std::shared_ptr<const double>>); - const auto embedded_data = std::get<EmbeddedData>(i_embedded_c->apply(std::vector<DataVariant>{})); - const IDataHandler& handled_data = embedded_data.get(); - const DataHandler<double>& data = dynamic_cast<const DataHandler<double>&>(handled_data); + const auto embedded_data = std::get<EmbeddedData>(i_embedded_c->apply(std::vector<DataVariant>{})); + const IDataHandler& handled_data = embedded_data.get(); + const DataHandler<const double>& data = dynamic_cast<const DataHandler<const double>&>(handled_data); REQUIRE(*data.data_ptr() == 1.5); } diff --git a/tests/test_BuiltinFunctionProcessor.cpp b/tests/test_BuiltinFunctionProcessor.cpp index 60a4bd491f392b7cc0c303d94531edcf8634edbc..8de9ec2c2ed9e61479aa2d7165bf6e506fd6caf6 100644 --- a/tests/test_BuiltinFunctionProcessor.cpp +++ b/tests/test_BuiltinFunctionProcessor.cpp @@ -358,6 +358,158 @@ let s:R, s = dot(x,y); CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "s", dot(TinyVector<3>{-2, 3, 4}, TinyVector<3>{4, 3, 5})); } + { // det + tested_function_set.insert("det:R^1x1"); + std::string_view data = R"( +import math; +let A:R^1x1, A = -2; +let d:R, d = det(A); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "d", det(TinyMatrix<1>{-2})); + } + + { // det + tested_function_set.insert("det:R^2x2"); + std::string_view data = R"( +import math; +let A:R^2x2, A = [[-2.5, 3.2], + [ 3.2, 2.3]]; +let d:R, d = det(A); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "d", + det(TinyMatrix<2>{-2.5, 3.2, // + +3.2, 2.3})); + } + + { // det + tested_function_set.insert("det:R^3x3"); + std::string_view data = R"( +import math; +let A:R^3x3, A = [[-2, 2,-1], + [ 3, 2, 2], + [-2, 5,-3]]; +let d:R, d = det(A); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "d", + det(TinyMatrix<3>{-2, 2, -1, // + +3, 2, +2, // + -2, 5, -3})); + } + + { // trace + tested_function_set.insert("trace:R^1x1"); + std::string_view data = R"( +import math; +let A:R^1x1, A = -2; +let t:R, t = trace(A); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "t", trace(TinyMatrix<1>{-2})); + } + + { // trace + tested_function_set.insert("trace:R^2x2"); + std::string_view data = R"( +import math; +let A:R^2x2, A = [[-2.5, 3.2], + [ 3.2, 2.3]]; +let t:R, t = trace(A); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "t", + trace(TinyMatrix<2>{-2.5, 3.2, // + +3.2, 2.3})); + } + + { // trace + tested_function_set.insert("trace:R^3x3"); + std::string_view data = R"( +import math; +let A:R^3x3, A = [[-2.5, 2.9,-1.3], + [ 3.2, 2.3, 2.7], + [-2.6, 5.2,-3.5]]; +let t:R, t = trace(A); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "t", + trace(TinyMatrix<3>{-2.5, 2.9, -1.3, // + +3.2, 2.3, +2.7, // + -2.6, 5.2, -3.5})); + } + + { // inverse + tested_function_set.insert("inverse:R^1x1"); + std::string_view data = R"( +import math; +let A:R^1x1, A = -2; +let invA:R^1x1, invA = inverse(A); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "invA", inverse(TinyMatrix<1>{-2})); + } + + { // inverse + tested_function_set.insert("inverse:R^2x2"); + std::string_view data = R"( +import math; +let A:R^2x2, A = [[-2.5, 3.2], + [ 3.2, 2.3]]; +let invA:R^2x2, invA = inverse(A); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "invA", + inverse(TinyMatrix<2>{-2.5, 3.2, // + +3.2, 2.3})); + } + + { // inverse + tested_function_set.insert("inverse:R^3x3"); + std::string_view data = R"( +import math; +let A:R^3x3, A = [[-2, 2,-1], + [ 3, 2, 2], + [-2, 5,-3]]; +let invA:R^3x3, invA = inverse(A); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "invA", + inverse(TinyMatrix<3>{-2, 2, -1, // + +3, 2, +2, // + -2, 5, -3})); + } + + { // transpose + tested_function_set.insert("transpose:R^1x1"); + std::string_view data = R"( +import math; +let A:R^1x1, A = -2; +let tA:R^1x1, tA = transpose(A); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "tA", transpose(TinyMatrix<1>{-2})); + } + + { // transpose + tested_function_set.insert("transpose:R^2x2"); + std::string_view data = R"( +import math; +let A:R^2x2, A = [[-2.5, 3.2], + [ 3.2, 2.3]]; +let tA:R^2x2, tA = transpose(A); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "tA", + transpose(TinyMatrix<2>{-2.5, 3.2, // + +3.2, 2.3})); + } + + { // transpose + tested_function_set.insert("transpose:R^3x3"); + std::string_view data = R"( +import math; +let A:R^3x3, A = [[-2.5, 2.9,-1.3], + [ 3.2, 2.3, 2.7], + [-2.6, 5.2,-3.5]]; +let tA:R^3x3, tA = transpose(A); +)"; + CHECK_BUILTIN_FUNCTION_EVALUATION_RESULT(data, "tA", + transpose(TinyMatrix<3>{-2.5, 2.9, -1.3, // + +3.2, 2.3, +2.7, // + -2.6, 5.2, -3.5})); + } + MathModule math_module; bool missing_test = false; diff --git a/tests/test_BuiltinFunctionRegister.hpp b/tests/test_BuiltinFunctionRegister.hpp index 03a847bc2f805d4d883a060709b232c6f64e4a3a..dfc7da319d00260c22a23fdba6b66e9ecb0ca437 100644 --- a/tests/test_BuiltinFunctionRegister.hpp +++ b/tests/test_BuiltinFunctionRegister.hpp @@ -4,6 +4,7 @@ #include <language/utils/ASTNodeDataTypeTraits.hpp> #include <language/utils/BuiltinFunctionEmbedder.hpp> #include <language/utils/ParseError.hpp> +#include <language/utils/SymbolTable.hpp> #include <language/utils/TypeDescriptor.hpp> #include <utils/Exceptions.hpp> @@ -12,7 +13,7 @@ template <> inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<const double>> = ASTNodeDataType::build<ASTNodeDataType::type_id_t>("builtin_t"); -const auto builtin_data_type = ast_node_data_type_from<std::shared_ptr<const double>>; +inline const auto builtin_data_type = ast_node_data_type_from<std::shared_ptr<const double>>; namespace test_only { @@ -116,25 +117,25 @@ class test_BuiltinFunctionRegister m_name_builtin_function_map.insert( std::make_pair("tuple_BtoR:(B)", std::make_shared<BuiltinFunctionEmbedder<double(std::vector<bool>)>>( - [](const std::vector<bool>&) -> double { return 0.5; }))); + [](const std::vector<bool>&) -> double { return 0.5; }))); m_name_builtin_function_map.insert( std::make_pair("tuple_NtoR:(N)", std::make_shared<BuiltinFunctionEmbedder<double(std::vector<uint64_t>)>>( - [](const std::vector<uint64_t>&) -> double { return 0.5; }))); + [](const std::vector<uint64_t>&) -> double { return 0.5; }))); m_name_builtin_function_map.insert( std::make_pair("tuple_ZtoR:(Z)", std::make_shared<BuiltinFunctionEmbedder<double(std::vector<int64_t>)>>( - [](const std::vector<int64_t>& v) -> double { - int64_t sum = 0; - for (auto vi : v) { - sum += vi; - } - return 0.5 * sum; - }))); + [](const std::vector<int64_t>& v) -> double { + int64_t sum = 0; + for (auto vi : v) { + sum += vi; + } + return 0.5 * sum; + }))); m_name_builtin_function_map.insert( std::make_pair("tuple_RtoB:(R)", std::make_shared<BuiltinFunctionEmbedder<bool(std::vector<double>)>>( - [](const std::vector<double>&) -> bool { return false; }))); + [](const std::vector<double>&) -> bool { return false; }))); m_name_builtin_function_map.insert( std::make_pair("tuple_stringtoB:(string)", diff --git a/tests/test_CellIntegrator.cpp b/tests/test_CellIntegrator.cpp index ebd322d14c8ea5df4053163dcae9b60d02318a53..7c70d19fd2a538f831507d7eeb41392b0686f158 100644 --- a/tests/test_CellIntegrator.cpp +++ b/tests/test_CellIntegrator.cpp @@ -497,7 +497,7 @@ TEST_CASE("CellIntegrator", "[scheme]") mesh_list.push_back(std::make_pair("hybrid mesh", hybrid_mesh)); mesh_list.push_back(std::make_pair("diamond mesh", DualMeshManager::instance().getDiamondDualMesh(*hybrid_mesh))); - for (auto mesh_info : mesh_list) { + for (const auto& mesh_info : mesh_list) { auto mesh_name = mesh_info.first; auto mesh = mesh_info.second; @@ -1418,7 +1418,7 @@ TEST_CASE("CellIntegrator", "[scheme]") mesh_list.push_back(std::make_pair("hybrid mesh", hybrid_mesh)); mesh_list.push_back(std::make_pair("diamond mesh", DualMeshManager::instance().getDiamondDualMesh(*hybrid_mesh))); - for (auto mesh_info : mesh_list) { + for (const auto& mesh_info : mesh_list) { auto mesh_name = mesh_info.first; auto mesh = mesh_info.second; @@ -2345,7 +2345,7 @@ TEST_CASE("CellIntegrator", "[scheme]") mesh_list.push_back(std::make_pair("hybrid mesh", hybrid_mesh)); mesh_list.push_back(std::make_pair("diamond mesh", DualMeshManager::instance().getDiamondDualMesh(*hybrid_mesh))); - for (auto mesh_info : mesh_list) { + for (const auto& mesh_info : mesh_list) { auto mesh_name = mesh_info.first; auto mesh = mesh_info.second; diff --git a/tests/test_Connectivity.cpp b/tests/test_Connectivity.cpp index f7d2ab7de77a04e3f5eb46efd458d5299740fc36..b0465d08489c644685500d59b145e12594966522 100644 --- a/tests/test_Connectivity.cpp +++ b/tests/test_Connectivity.cpp @@ -3,6 +3,7 @@ #include <MeshDataBaseForTests.hpp> #include <mesh/Connectivity.hpp> +#include <mesh/ConnectivityUtils.hpp> #include <mesh/ItemValue.hpp> #include <mesh/ItemValueUtils.hpp> #include <mesh/Mesh.hpp> @@ -132,7 +133,7 @@ TEST_CASE("Connectivity", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -223,7 +224,7 @@ TEST_CASE("Connectivity", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -326,7 +327,7 @@ TEST_CASE("Connectivity", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -443,7 +444,7 @@ TEST_CASE("Connectivity", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -492,7 +493,7 @@ TEST_CASE("Connectivity", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -570,7 +571,7 @@ TEST_CASE("Connectivity", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -670,6 +671,318 @@ TEST_CASE("Connectivity", "[mesh]") } } + SECTION("item ordering") + { + SECTION("1D") + { + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); + + for (const auto& named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + SECTION("cell -> nodes") + { + auto mesh = named_mesh.mesh(); + auto xr = mesh->xr(); + + const Connectivity<1>& connectivity = mesh->connectivity(); + + auto cell_to_node_matrix = connectivity.cellToNodeMatrix(); + + bool is_correct = true; + + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + if (xr[cell_to_node_matrix[cell_id][1]][0] < xr[cell_to_node_matrix[cell_id][0]][0]) { + is_correct = false; + } + } + REQUIRE(is_correct); + } + + SECTION("node -> cells") + { + auto mesh = named_mesh.mesh(); + + const Connectivity<1>& connectivity = mesh->connectivity(); + + auto node_to_cell_matrix = connectivity.nodeToCellMatrix(); + auto cell_number = connectivity.cellNumber(); + + bool is_correct = true; + for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { + auto cell_node_list = node_to_cell_matrix[node_id]; + for (size_t i_node = 0; i_node < cell_node_list.size() - 1; ++i_node) { + is_correct &= (cell_number[cell_node_list[i_node]] < cell_number[cell_node_list[i_node + 1]]); + } + } + REQUIRE(is_correct); + } + } + } + } + + SECTION("2D") + { + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); + + for (const auto& named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + SECTION("face -> nodes") + { + auto mesh = named_mesh.mesh(); + + const Connectivity<2>& connectivity = mesh->connectivity(); + + auto face_to_node_matrix = connectivity.faceToNodeMatrix(); + auto node_number = connectivity.nodeNumber(); + + bool is_correct = true; + + for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { + auto face_node_list = face_to_node_matrix[face_id]; + if (node_number[face_node_list[1]] < node_number[face_node_list[0]]) { + is_correct = false; + } + } + REQUIRE(is_correct); + } + + SECTION("node -> faces") + { + auto mesh = named_mesh.mesh(); + + const Connectivity<2>& connectivity = mesh->connectivity(); + + auto node_to_face_matrix = connectivity.nodeToFaceMatrix(); + auto face_number = connectivity.faceNumber(); + + bool is_correct = true; + for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { + auto face_node_list = node_to_face_matrix[node_id]; + for (size_t i_node = 0; i_node < face_node_list.size() - 1; ++i_node) { + is_correct &= (face_number[face_node_list[i_node]] < face_number[face_node_list[i_node + 1]]); + } + } + REQUIRE(is_correct); + } + + SECTION("node -> cells") + { + auto mesh = named_mesh.mesh(); + + const Connectivity<2>& connectivity = mesh->connectivity(); + + auto node_to_cell_matrix = connectivity.nodeToCellMatrix(); + auto cell_number = connectivity.cellNumber(); + + bool is_correct = true; + for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { + auto cell_node_list = node_to_cell_matrix[node_id]; + for (size_t i_node = 0; i_node < cell_node_list.size() - 1; ++i_node) { + is_correct &= (cell_number[cell_node_list[i_node]] < cell_number[cell_node_list[i_node + 1]]); + } + } + REQUIRE(is_correct); + } + + SECTION("face -> cells") + { + auto mesh = named_mesh.mesh(); + + const Connectivity<2>& connectivity = mesh->connectivity(); + + auto face_to_cell_matrix = connectivity.faceToCellMatrix(); + auto cell_number = connectivity.cellNumber(); + + bool is_correct = true; + for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { + auto cell_face_list = face_to_cell_matrix[face_id]; + for (size_t i_face = 0; i_face < cell_face_list.size() - 1; ++i_face) { + is_correct &= (cell_number[cell_face_list[i_face]] < cell_number[cell_face_list[i_face + 1]]); + } + } + REQUIRE(is_correct); + } + } + } + } + + SECTION("3D") + { + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); + + for (const auto& named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + SECTION("edge -> nodes") + { + auto mesh = named_mesh.mesh(); + + const Connectivity<3>& connectivity = mesh->connectivity(); + + auto edge_to_node_matrix = connectivity.edgeToNodeMatrix(); + auto node_number = connectivity.nodeNumber(); + + bool is_correct = true; + + for (EdgeId edge_id = 0; edge_id < connectivity.numberOfEdges(); ++edge_id) { + auto edge_node_list = edge_to_node_matrix[edge_id]; + if (node_number[edge_node_list[1]] < node_number[edge_node_list[0]]) { + is_correct = false; + } + } + REQUIRE(is_correct); + } + + SECTION("face -> nodes") + { + auto mesh = named_mesh.mesh(); + + const Connectivity<3>& connectivity = mesh->connectivity(); + + auto face_to_node_matrix = connectivity.faceToNodeMatrix(); + auto node_number = connectivity.nodeNumber(); + + bool is_correct = true; + + for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { + auto face_node_list = face_to_node_matrix[face_id]; + for (size_t i = 1; i < face_node_list.size() - 1; ++i) { + if (node_number[face_node_list[i]] < node_number[face_node_list[0]]) { + is_correct = false; + } + } + for (size_t i = 2; i < face_node_list.size() - 1; ++i) { + if (node_number[face_node_list[i]] < node_number[face_node_list[1]]) { + is_correct = false; + } + } + } + REQUIRE(is_correct); + } + + SECTION("node -> edges") + { + auto mesh = named_mesh.mesh(); + + const Connectivity<3>& connectivity = mesh->connectivity(); + + REQUIRE(checkConnectivityOrdering(connectivity)); + + auto node_to_edge_matrix = connectivity.nodeToEdgeMatrix(); + auto edge_number = connectivity.edgeNumber(); + + bool is_correct = true; + for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { + auto edge_node_list = node_to_edge_matrix[node_id]; + for (size_t i_node = 0; i_node < edge_node_list.size() - 1; ++i_node) { + is_correct &= (edge_number[edge_node_list[i_node]] < edge_number[edge_node_list[i_node + 1]]); + } + } + + REQUIRE(is_correct); + } + + SECTION("node -> faces") + { + auto mesh = named_mesh.mesh(); + + const Connectivity<3>& connectivity = mesh->connectivity(); + + auto node_to_face_matrix = connectivity.nodeToFaceMatrix(); + auto face_number = connectivity.faceNumber(); + + bool is_correct = true; + for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { + auto face_node_list = node_to_face_matrix[node_id]; + for (size_t i_node = 0; i_node < face_node_list.size() - 1; ++i_node) { + is_correct &= (face_number[face_node_list[i_node]] < face_number[face_node_list[i_node + 1]]); + } + } + REQUIRE(is_correct); + } + + SECTION("node -> cells") + { + auto mesh = named_mesh.mesh(); + + const Connectivity<3>& connectivity = mesh->connectivity(); + + auto node_to_cell_matrix = connectivity.nodeToCellMatrix(); + auto cell_number = connectivity.cellNumber(); + + bool is_correct = true; + for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { + auto cell_node_list = node_to_cell_matrix[node_id]; + for (size_t i_node = 0; i_node < cell_node_list.size() - 1; ++i_node) { + is_correct &= (cell_number[cell_node_list[i_node]] < cell_number[cell_node_list[i_node + 1]]); + } + } + REQUIRE(is_correct); + } + + SECTION("edge -> faces") + { + auto mesh = named_mesh.mesh(); + + const Connectivity<3>& connectivity = mesh->connectivity(); + + auto edge_to_face_matrix = connectivity.edgeToFaceMatrix(); + auto face_number = connectivity.faceNumber(); + + bool is_correct = true; + for (EdgeId edge_id = 0; edge_id < connectivity.numberOfEdges(); ++edge_id) { + auto face_edge_list = edge_to_face_matrix[edge_id]; + for (size_t i_edge = 0; i_edge < face_edge_list.size() - 1; ++i_edge) { + is_correct &= (face_number[face_edge_list[i_edge]] < face_number[face_edge_list[i_edge + 1]]); + } + } + REQUIRE(is_correct); + } + + SECTION("edge -> cells") + { + auto mesh = named_mesh.mesh(); + + const Connectivity<3>& connectivity = mesh->connectivity(); + + auto edge_to_cell_matrix = connectivity.edgeToCellMatrix(); + auto cell_number = connectivity.cellNumber(); + + bool is_correct = true; + for (EdgeId edge_id = 0; edge_id < connectivity.numberOfEdges(); ++edge_id) { + auto cell_edge_list = edge_to_cell_matrix[edge_id]; + for (size_t i_edge = 0; i_edge < cell_edge_list.size() - 1; ++i_edge) { + is_correct &= (cell_number[cell_edge_list[i_edge]] < cell_number[cell_edge_list[i_edge + 1]]); + } + } + REQUIRE(is_correct); + } + + SECTION("face -> cells") + { + auto mesh = named_mesh.mesh(); + + const Connectivity<3>& connectivity = mesh->connectivity(); + + auto face_to_cell_matrix = connectivity.faceToCellMatrix(); + auto cell_number = connectivity.cellNumber(); + + bool is_correct = true; + for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { + auto cell_face_list = face_to_cell_matrix[face_id]; + for (size_t i_face = 0; i_face < cell_face_list.size() - 1; ++i_face) { + is_correct &= (cell_number[cell_face_list[i_face]] < cell_number[cell_face_list[i_face + 1]]); + } + } + REQUIRE(is_correct); + } + } + } + } + } + SECTION("ItemLocalNumbersInTheirSubItems") { auto check_item_local_numbers_in_their_subitems = [](auto item_to_subitem_matrix, auto subitem_to_item_matrix, @@ -703,7 +1016,7 @@ TEST_CASE("Connectivity", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); @@ -775,7 +1088,7 @@ TEST_CASE("Connectivity", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); @@ -877,7 +1190,7 @@ TEST_CASE("Connectivity", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); diff --git a/tests/test_DiamondDualConnectivityBuilder.cpp b/tests/test_DiamondDualConnectivityBuilder.cpp index 70b8f75440061530f386654a4bbf9e3f5342d33e..45d9cd700ca7b5ae73e6c6fd22db024e7de3126c 100644 --- a/tests/test_DiamondDualConnectivityBuilder.cpp +++ b/tests/test_DiamondDualConnectivityBuilder.cpp @@ -5,6 +5,7 @@ #include <mesh/DualConnectivityManager.hpp> #include <mesh/Connectivity.hpp> +#include <mesh/ConnectivityUtils.hpp> #include <mesh/ItemValueUtils.hpp> #include <mesh/Mesh.hpp> @@ -54,6 +55,8 @@ TEST_CASE("DiamondDualConnectivityBuilder", "[mesh]") REQUIRE(dual_connectivity.numberOfFaces() == 220); REQUIRE(dual_connectivity.numberOfCells() == 110); + REQUIRE(checkConnectivityOrdering(dual_connectivity)); + SECTION("ref node list") { REQUIRE(primal_connectivity.numberOfRefItemList<ItemType::node>() == 4); @@ -159,6 +162,8 @@ TEST_CASE("DiamondDualConnectivityBuilder", "[mesh]") DualConnectivityManager::instance().getDiamondDualConnectivity(primal_connectivity); const ConnectivityType& dual_connectivity = *p_diamond_dual_connectivity; + REQUIRE(checkConnectivityOrdering(dual_connectivity)); + REQUIRE(dual_connectivity.numberOfNodes() == 331); REQUIRE(dual_connectivity.numberOfEdges() == 1461); REQUIRE(dual_connectivity.numberOfFaces() == 1651); diff --git a/tests/test_DiscreteFunctionIntegrator.cpp b/tests/test_DiscreteFunctionIntegrator.cpp index 031f6c62bd4f123e0a001eacdea0721716325978..b3ba2efba4ae8fe3dc90b8b54f6df6032d622e8c 100644 --- a/tests/test_DiscreteFunctionIntegrator.cpp +++ b/tests/test_DiscreteFunctionIntegrator.cpp @@ -23,6 +23,7 @@ #include <scheme/DiscreteFunctionDescriptorP0.hpp> #include <scheme/DiscreteFunctionIntegrator.hpp> #include <scheme/DiscreteFunctionP0.hpp> +#include <scheme/DiscreteFunctionVariant.hpp> #include <pegtl/string_input.hpp> @@ -49,7 +50,7 @@ TEST_CASE("DiscreteFunctionIntegrator", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -98,10 +99,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( IntegrateCellValue<double(TinyVector<1>)>::integrate(function_symbol_id, *quadrature_descriptor, *mesh_1d); DiscreteFunctionIntegrator integrator(mesh_1d, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("N_scalar_non_linear_1d") @@ -116,10 +116,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( IntegrateCellValue<double(TinyVector<1>)>::integrate(function_symbol_id, *quadrature_descriptor, *mesh_1d); DiscreteFunctionIntegrator integrator(mesh_1d, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("Z_scalar_non_linear_1d") @@ -134,10 +133,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( IntegrateCellValue<double(TinyVector<1>)>::integrate(function_symbol_id, *quadrature_descriptor, *mesh_1d); DiscreteFunctionIntegrator integrator(mesh_1d, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("R_scalar_non_linear_1d") @@ -152,10 +150,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( IntegrateCellValue<double(TinyVector<1>)>::integrate(function_symbol_id, *quadrature_descriptor, *mesh_1d); DiscreteFunctionIntegrator integrator(mesh_1d, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("R1_non_linear_1d") @@ -173,10 +170,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( *mesh_1d); DiscreteFunctionIntegrator integrator(mesh_1d, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R2_non_linear_1d") @@ -194,10 +190,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( *mesh_1d); DiscreteFunctionIntegrator integrator(mesh_1d, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R3_non_linear_1d") @@ -215,10 +210,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( *mesh_1d); DiscreteFunctionIntegrator integrator(mesh_1d, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R1x1_non_linear_1d") @@ -236,10 +230,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( *mesh_1d); DiscreteFunctionIntegrator integrator(mesh_1d, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R2x2_non_linear_1d") @@ -257,10 +250,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( *mesh_1d); DiscreteFunctionIntegrator integrator(mesh_1d, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R3x3_non_linear_1d") @@ -278,10 +270,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( *mesh_1d); DiscreteFunctionIntegrator integrator(mesh_1d, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } } } @@ -295,7 +286,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -344,10 +335,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( IntegrateCellValue<double(TinyVector<2>)>::integrate(function_symbol_id, *quadrature_descriptor, *mesh_2d); DiscreteFunctionIntegrator integrator(mesh_2d, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("N_scalar_non_linear_2d") @@ -362,10 +352,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( IntegrateCellValue<double(TinyVector<2>)>::integrate(function_symbol_id, *quadrature_descriptor, *mesh_2d); DiscreteFunctionIntegrator integrator(mesh_2d, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("Z_scalar_non_linear_2d") @@ -380,10 +369,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( IntegrateCellValue<double(TinyVector<2>)>::integrate(function_symbol_id, *quadrature_descriptor, *mesh_2d); DiscreteFunctionIntegrator integrator(mesh_2d, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("R_scalar_non_linear_2d") @@ -398,10 +386,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( IntegrateCellValue<double(TinyVector<2>)>::integrate(function_symbol_id, *quadrature_descriptor, *mesh_2d); DiscreteFunctionIntegrator integrator(mesh_2d, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("R1_non_linear_2d") @@ -419,10 +406,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( *mesh_2d); DiscreteFunctionIntegrator integrator(mesh_2d, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R2_non_linear_2d") @@ -440,10 +426,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( *mesh_2d); DiscreteFunctionIntegrator integrator(mesh_2d, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R3_non_linear_2d") @@ -461,10 +446,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( *mesh_2d); DiscreteFunctionIntegrator integrator(mesh_2d, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R1x1_non_linear_2d") @@ -482,10 +466,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( *mesh_2d); DiscreteFunctionIntegrator integrator(mesh_2d, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R2x2_non_linear_2d") @@ -503,10 +486,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( *mesh_2d); DiscreteFunctionIntegrator integrator(mesh_2d, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R3x3_non_linear_2d") @@ -524,10 +506,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( *mesh_2d); DiscreteFunctionIntegrator integrator(mesh_2d, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } } } @@ -541,7 +522,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -590,10 +571,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( IntegrateCellValue<double(TinyVector<3>)>::integrate(function_symbol_id, *quadrature_descriptor, *mesh_3d); DiscreteFunctionIntegrator integrator(mesh_3d, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("N_scalar_non_linear_3d") @@ -608,10 +588,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( IntegrateCellValue<double(TinyVector<3>)>::integrate(function_symbol_id, *quadrature_descriptor, *mesh_3d); DiscreteFunctionIntegrator integrator(mesh_3d, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("Z_scalar_non_linear_3d") @@ -626,10 +605,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( IntegrateCellValue<double(TinyVector<3>)>::integrate(function_symbol_id, *quadrature_descriptor, *mesh_3d); DiscreteFunctionIntegrator integrator(mesh_3d, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("R_scalar_non_linear_3d") @@ -644,10 +622,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( IntegrateCellValue<double(TinyVector<3>)>::integrate(function_symbol_id, *quadrature_descriptor, *mesh_3d); DiscreteFunctionIntegrator integrator(mesh_3d, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("R1_non_linear_3d") @@ -665,10 +642,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( *mesh_3d); DiscreteFunctionIntegrator integrator(mesh_3d, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R2_non_linear_3d") @@ -686,10 +662,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( *mesh_3d); DiscreteFunctionIntegrator integrator(mesh_3d, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R3_non_linear_3d") @@ -707,10 +682,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( *mesh_3d); DiscreteFunctionIntegrator integrator(mesh_3d, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R1x1_non_linear_3d") @@ -728,10 +702,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( *mesh_3d); DiscreteFunctionIntegrator integrator(mesh_3d, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R2x2_non_linear_3d") @@ -749,10 +722,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( *mesh_3d); DiscreteFunctionIntegrator integrator(mesh_3d, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R3x3_non_linear_3d") @@ -770,10 +742,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( *mesh_3d); DiscreteFunctionIntegrator integrator(mesh_3d, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } } } diff --git a/tests/test_DiscreteFunctionIntegratorByZone.cpp b/tests/test_DiscreteFunctionIntegratorByZone.cpp index 19c0ac87c1d941e4c5f0026e154087be305c55f2..217c15b38d17195f2e3baa56d0a698f0b2c9c2a4 100644 --- a/tests/test_DiscreteFunctionIntegratorByZone.cpp +++ b/tests/test_DiscreteFunctionIntegratorByZone.cpp @@ -25,6 +25,7 @@ #include <scheme/DiscreteFunctionDescriptorP0.hpp> #include <scheme/DiscreteFunctionIntegrator.hpp> #include <scheme/DiscreteFunctionP0.hpp> +#include <scheme/DiscreteFunctionVariant.hpp> #include <pegtl/string_input.hpp> @@ -111,10 +112,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( }); DiscreteFunctionIntegrator integrator(mesh_1d, zone_list, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("N_scalar_non_linear_1d") @@ -139,10 +139,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( }); DiscreteFunctionIntegrator integrator(mesh_1d, zone_list, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("Z_scalar_non_linear_1d") @@ -167,10 +166,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( }); DiscreteFunctionIntegrator integrator(mesh_1d, zone_list, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("R_scalar_non_linear_1d") @@ -195,10 +193,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( }); DiscreteFunctionIntegrator integrator(mesh_1d, zone_list, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("R1_non_linear_1d") @@ -225,10 +222,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( }); DiscreteFunctionIntegrator integrator(mesh_1d, zone_list, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R2_non_linear_1d") @@ -255,10 +251,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( }); DiscreteFunctionIntegrator integrator(mesh_1d, zone_list, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R3_non_linear_1d") @@ -285,10 +280,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( }); DiscreteFunctionIntegrator integrator(mesh_1d, zone_list, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R1x1_non_linear_1d") @@ -315,10 +309,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( }); DiscreteFunctionIntegrator integrator(mesh_1d, zone_list, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R2x2_non_linear_1d") @@ -345,10 +338,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( }); DiscreteFunctionIntegrator integrator(mesh_1d, zone_list, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R3x3_non_linear_1d") @@ -375,10 +367,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( }); DiscreteFunctionIntegrator integrator(mesh_1d, zone_list, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } } @@ -450,10 +441,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( }); DiscreteFunctionIntegrator integrator(mesh_2d, zone_list, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("N_scalar_non_linear_2d") @@ -478,10 +468,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( }); DiscreteFunctionIntegrator integrator(mesh_2d, zone_list, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("Z_scalar_non_linear_2d") @@ -506,10 +495,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( }); DiscreteFunctionIntegrator integrator(mesh_2d, zone_list, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("R_scalar_non_linear_2d") @@ -534,10 +522,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( }); DiscreteFunctionIntegrator integrator(mesh_2d, zone_list, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("R1_non_linear_2d") @@ -564,10 +551,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( }); DiscreteFunctionIntegrator integrator(mesh_2d, zone_list, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R2_non_linear_2d") @@ -594,10 +580,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( }); DiscreteFunctionIntegrator integrator(mesh_2d, zone_list, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R3_non_linear_2d") @@ -624,10 +609,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( }); DiscreteFunctionIntegrator integrator(mesh_2d, zone_list, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R1x1_non_linear_2d") @@ -654,10 +638,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( }); DiscreteFunctionIntegrator integrator(mesh_2d, zone_list, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R2x2_non_linear_2d") @@ -684,10 +667,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( }); DiscreteFunctionIntegrator integrator(mesh_2d, zone_list, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R3x3_non_linear_2d") @@ -714,10 +696,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( }); DiscreteFunctionIntegrator integrator(mesh_2d, zone_list, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } } @@ -789,10 +770,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( }); DiscreteFunctionIntegrator integrator(mesh_3d, zone_list, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("N_scalar_non_linear_3d") @@ -817,10 +797,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( }); DiscreteFunctionIntegrator integrator(mesh_3d, zone_list, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("Z_scalar_non_linear_3d") @@ -845,10 +824,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( }); DiscreteFunctionIntegrator integrator(mesh_3d, zone_list, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("R_scalar_non_linear_3d") @@ -873,10 +851,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( }); DiscreteFunctionIntegrator integrator(mesh_3d, zone_list, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("R1_non_linear_3d") @@ -903,10 +880,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( }); DiscreteFunctionIntegrator integrator(mesh_3d, zone_list, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R2_non_linear_3d") @@ -933,10 +909,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( }); DiscreteFunctionIntegrator integrator(mesh_3d, zone_list, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R3_non_linear_3d") @@ -963,10 +938,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( }); DiscreteFunctionIntegrator integrator(mesh_3d, zone_list, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R1x1_non_linear_3d") @@ -993,10 +967,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( }); DiscreteFunctionIntegrator integrator(mesh_3d, zone_list, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R2x2_non_linear_3d") @@ -1023,10 +996,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( }); DiscreteFunctionIntegrator integrator(mesh_3d, zone_list, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R3x3_non_linear_3d") @@ -1053,10 +1025,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( }); DiscreteFunctionIntegrator integrator(mesh_3d, zone_list, quadrature_descriptor, function_symbol_id); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } } } diff --git a/tests/test_DiscreteFunctionInterpoler.cpp b/tests/test_DiscreteFunctionInterpoler.cpp index f9d870d29dbd53f6eef9f49bf114be2566475d0d..0287d97c89ef966f5a4d68ecd091875b3e19e14b 100644 --- a/tests/test_DiscreteFunctionInterpoler.cpp +++ b/tests/test_DiscreteFunctionInterpoler.cpp @@ -21,6 +21,7 @@ #include <scheme/DiscreteFunctionDescriptorP0.hpp> #include <scheme/DiscreteFunctionInterpoler.hpp> #include <scheme/DiscreteFunctionP0.hpp> +#include <scheme/DiscreteFunctionVariant.hpp> #include <pegtl/string_input.hpp> @@ -45,7 +46,7 @@ TEST_CASE("DiscreteFunctionInterpoler", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -101,10 +102,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("N_scalar_non_linear_1d") @@ -124,10 +124,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("Z_scalar_non_linear_1d") @@ -147,10 +146,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("R_scalar_non_linear_1d") @@ -170,10 +168,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("R1_non_linear_1d") @@ -195,10 +192,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R2_non_linear_1d") @@ -220,10 +216,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R3_non_linear_1d") @@ -245,10 +240,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R1x1_non_linear_1d") @@ -270,10 +264,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R2x2_non_linear_1d") @@ -296,10 +289,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R3x3_non_linear_1d") @@ -329,10 +321,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } } } @@ -344,7 +335,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -400,10 +391,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("N_scalar_non_linear_2d") @@ -423,10 +413,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("Z_scalar_non_linear_2d") @@ -446,10 +435,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("R_scalar_non_linear_2d") @@ -469,10 +457,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("R1_non_linear_2d") @@ -494,10 +481,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R2_non_linear_2d") @@ -519,10 +505,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R3_non_linear_2d") @@ -544,10 +529,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R1x1_non_linear_2d") @@ -569,10 +553,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R2x2_non_linear_2d") @@ -595,10 +578,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R3x3_non_linear_2d") @@ -629,10 +611,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } } } @@ -644,7 +625,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -700,10 +681,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("N_scalar_non_linear_3d") @@ -723,10 +703,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("Z_scalar_non_linear_3d") @@ -746,10 +725,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("R_scalar_non_linear_3d") @@ -769,10 +747,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("R1_non_linear_3d") @@ -794,10 +771,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R2_non_linear_3d") @@ -819,10 +795,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R3_non_linear_3d") @@ -844,10 +819,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R1x1_non_linear_3d") @@ -869,10 +843,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R2x2_non_linear_3d") @@ -895,10 +868,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R3x3_non_linear_3d") @@ -929,10 +901,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE(same_cell_value(cell_value, - dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } } } diff --git a/tests/test_DiscreteFunctionInterpolerByZone.cpp b/tests/test_DiscreteFunctionInterpolerByZone.cpp index dce3b645a7e98ee91b41f8cd5f158edb019d94ed..c4e6f0a00a15a8921615bb0540adf3c3668e7300 100644 --- a/tests/test_DiscreteFunctionInterpolerByZone.cpp +++ b/tests/test_DiscreteFunctionInterpolerByZone.cpp @@ -23,6 +23,7 @@ #include <scheme/DiscreteFunctionDescriptorP0.hpp> #include <scheme/DiscreteFunctionInterpoler.hpp> #include <scheme/DiscreteFunctionP0.hpp> +#include <scheme/DiscreteFunctionVariant.hpp> #include <pegtl/string_input.hpp> @@ -113,10 +114,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_1d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("N_scalar_non_linear_1d") @@ -140,10 +140,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_1d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("Z_scalar_non_linear_1d") @@ -167,10 +166,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_1d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("R_scalar_non_linear_1d") @@ -194,10 +192,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_1d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("R1_non_linear_1d") @@ -223,10 +220,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_1d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R2_non_linear_1d") @@ -252,10 +248,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_1d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R3_non_linear_1d") @@ -281,10 +276,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_1d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R1x1_non_linear_1d") @@ -310,10 +304,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_1d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R2x2_non_linear_1d") @@ -340,10 +333,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_1d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R3x3_non_linear_1d") @@ -377,10 +369,9 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_1d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } } @@ -456,10 +447,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_2d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("N_scalar_non_linear_2d") @@ -483,10 +473,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_2d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("Z_scalar_non_linear_2d") @@ -510,10 +499,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_2d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("R_scalar_non_linear_2d") @@ -537,10 +525,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_2d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("R1_non_linear_2d") @@ -566,10 +553,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_2d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R2_non_linear_2d") @@ -595,10 +581,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_2d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R3_non_linear_2d") @@ -624,10 +609,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_2d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R1x1_non_linear_2d") @@ -653,10 +637,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_2d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R2x2_non_linear_2d") @@ -683,10 +666,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_2d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R3x3_non_linear_2d") @@ -721,10 +703,9 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_2d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } } @@ -800,10 +781,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_3d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("N_scalar_non_linear_3d") @@ -827,10 +807,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_3d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("Z_scalar_non_linear_3d") @@ -854,10 +833,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_3d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("R_scalar_non_linear_3d") @@ -881,10 +859,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_3d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const double>>())); } SECTION("R1_non_linear_3d") @@ -910,10 +887,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_3d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R2_non_linear_3d") @@ -939,10 +915,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_3d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R3_non_linear_3d") @@ -968,10 +943,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_3d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R1x1_non_linear_3d") @@ -997,10 +971,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_3d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R2x2_non_linear_3d") @@ -1027,10 +1000,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_3d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } SECTION("R3x3_non_linear_3d") @@ -1065,10 +1037,9 @@ let R3x3_non_linear_3d: R^3 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( DiscreteFunctionInterpoler interpoler(mesh_3d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0>(), function_symbol_id); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); - REQUIRE( - same_cell_value(cell_value, dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, discrete_function.get<DiscreteFunctionP0<Dimension, const DataType>>())); } } } diff --git a/tests/test_DiscreteFunctionP0.cpp b/tests/test_DiscreteFunctionP0.cpp index 7073def1e438a3a19df04723ba88349d3bb7d7b1..48c107e4ad2f07391a49270a04c9a3dc20d2db4a 100644 --- a/tests/test_DiscreteFunctionP0.cpp +++ b/tests/test_DiscreteFunctionP0.cpp @@ -26,7 +26,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); @@ -74,7 +74,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); @@ -122,7 +122,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); @@ -184,7 +184,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); @@ -213,7 +213,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); @@ -242,7 +242,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); @@ -284,7 +284,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); @@ -386,7 +386,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); @@ -488,7 +488,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); @@ -592,7 +592,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") constexpr size_t Dimension = 1; std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); @@ -677,7 +677,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); @@ -1258,7 +1258,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); @@ -1844,7 +1844,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); @@ -2493,7 +2493,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") constexpr size_t Dimension = 1; std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); @@ -2837,7 +2837,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); @@ -3181,7 +3181,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); @@ -3428,6 +3428,94 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") CHECK_STD_BINARY_MATH_FUNCTION_WITH_LHS_VALUE(u, vh, dot); } + SECTION("det(Ah)") + { + DiscreteFunctionP0<Dimension, TinyMatrix<2>> Ah{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double x = xj[cell_id][0]; + Ah[cell_id] = TinyMatrix<2>{x + 1, 2 * x - 3, // + -0.2 * x - 1, 2 + x}; + }); + + { + DiscreteFunctionP0 result = det(Ah); + bool is_same = true; + parallel_for(Ah.cellValues().numberOfItems(), [&](const CellId cell_id) { + if (result[cell_id] != det(Ah[cell_id])) { + is_same = false; + } + }); + REQUIRE(is_same); + } + } + + SECTION("trace(Ah)") + { + DiscreteFunctionP0<Dimension, TinyMatrix<2>> Ah{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double x = xj[cell_id][0]; + Ah[cell_id] = TinyMatrix<2>{x + 1, 2 * x - 3, // + -0.2 * x - 1, 2 + x}; + }); + + { + DiscreteFunctionP0 result = trace(Ah); + bool is_same = true; + parallel_for(Ah.cellValues().numberOfItems(), [&](const CellId cell_id) { + if (result[cell_id] != trace(Ah[cell_id])) { + is_same = false; + } + }); + REQUIRE(is_same); + } + } + + SECTION("inverse(Ah)") + { + DiscreteFunctionP0<Dimension, TinyMatrix<2>> Ah{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double x = xj[cell_id][0]; + Ah[cell_id] = TinyMatrix<2>{x + 1, 2 * x - 3, // + -0.2 * x - 1, 2 + x}; + }); + + { + DiscreteFunctionP0 result = inverse(Ah); + bool is_same = true; + parallel_for(Ah.cellValues().numberOfItems(), [&](const CellId cell_id) { + if (result[cell_id] != inverse(Ah[cell_id])) { + is_same = false; + } + }); + REQUIRE(is_same); + } + } + + SECTION("transpose(Ah)") + { + DiscreteFunctionP0<Dimension, TinyMatrix<2>> Ah{mesh}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(const CellId cell_id) { + const double x = xj[cell_id][0]; + Ah[cell_id] = TinyMatrix<2>{x + 1, 2 * x - 3, // + -0.2 * x - 1, 2 + x}; + }); + + { + DiscreteFunctionP0 result = transpose(Ah); + bool is_same = true; + parallel_for(Ah.cellValues().numberOfItems(), [&](const CellId cell_id) { + if (result[cell_id] != transpose(Ah[cell_id])) { + is_same = false; + } + }); + REQUIRE(is_same); + } + } + SECTION("scalar sum") { const CellValue<const double> cell_value = positive_function.cellValues(); @@ -3531,7 +3619,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1 = named_mesh.mesh(); @@ -3558,7 +3646,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1 = named_mesh.mesh(); @@ -3585,7 +3673,7 @@ TEST_CASE("DiscreteFunctionP0", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1 = named_mesh.mesh(); diff --git a/tests/test_DiscreteFunctionP0Vector.cpp b/tests/test_DiscreteFunctionP0Vector.cpp index 6e351c404a7b5f57d7b39e5a3f70d43cf62a5635..d2da3d84ef517f28dc0bd0ba60149be7c4fba725 100644 --- a/tests/test_DiscreteFunctionP0Vector.cpp +++ b/tests/test_DiscreteFunctionP0Vector.cpp @@ -31,7 +31,7 @@ TEST_CASE("DiscreteFunctionP0Vector", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); @@ -79,7 +79,7 @@ TEST_CASE("DiscreteFunctionP0Vector", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); @@ -127,7 +127,7 @@ TEST_CASE("DiscreteFunctionP0Vector", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); @@ -189,7 +189,7 @@ TEST_CASE("DiscreteFunctionP0Vector", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); @@ -211,7 +211,7 @@ TEST_CASE("DiscreteFunctionP0Vector", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); @@ -231,7 +231,7 @@ TEST_CASE("DiscreteFunctionP0Vector", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); @@ -266,7 +266,7 @@ TEST_CASE("DiscreteFunctionP0Vector", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); @@ -312,7 +312,7 @@ TEST_CASE("DiscreteFunctionP0Vector", "[scheme]") constexpr size_t Dimension = 2; std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); @@ -359,7 +359,7 @@ TEST_CASE("DiscreteFunctionP0Vector", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); @@ -410,7 +410,7 @@ TEST_CASE("DiscreteFunctionP0Vector", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); @@ -453,7 +453,7 @@ TEST_CASE("DiscreteFunctionP0Vector", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); @@ -497,7 +497,7 @@ TEST_CASE("DiscreteFunctionP0Vector", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); @@ -535,6 +535,258 @@ TEST_CASE("DiscreteFunctionP0Vector", "[scheme]") } } + SECTION("functions") + { + SECTION("1D") + { + const size_t size = 3; + + constexpr size_t Dimension = 1; + + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); + + for (const auto& named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh = named_mesh.mesh(); + + auto xj = MeshDataManager::instance().getMeshData(*mesh).xj(); + + DiscreteFunctionP0Vector<Dimension, double> f{mesh, size}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + f[cell_id][0] = 2 * x + 1; + f[cell_id][1] = x * x - 1; + f[cell_id][2] = 2 + x; + }); + + DiscreteFunctionP0Vector<Dimension, double> g{mesh, size}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + g[cell_id][0] = (x + 1) * (x - 2) + 1; + g[cell_id][1] = 3 * (x + 2) - 1; + g[cell_id][2] = (x + 3) * 5; + }); + + DiscreteFunctionP0Vector<Dimension, const double> const_f = f; + DiscreteFunctionP0Vector<Dimension, const double> const_g{g}; + + auto same_data = [](const auto& f, const auto& g) { + const size_t number_of_cells = g.size(); + for (CellId cell_id = 0; cell_id < number_of_cells; ++cell_id) { + if (f[cell_id] != g[cell_id]) { + return false; + } + } + return true; + }; + + SECTION("dot") + { + Array<double> dot_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + double sum = 0; + for (size_t i = 0; i < size; ++i) { + sum += f[cell_id][i] * g[cell_id][i]; + } + dot_values[cell_id] = sum; + }); + + REQUIRE(same_data(dot(f, g), dot_values)); + REQUIRE(same_data(dot(const_f, g), dot_values)); + REQUIRE(same_data(dot(f, const_g), dot_values)); + REQUIRE(same_data(dot(const_f, const_g), dot_values)); + } + + SECTION("sumOfComponents") + { + Array<double> sum_of_components{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + double sum = 0; + for (size_t i = 0; i < size; ++i) { + sum += f[cell_id][i]; + } + sum_of_components[cell_id] = sum; + }); + + REQUIRE(same_data(sumOfComponents(f), sum_of_components)); + REQUIRE(same_data(sumOfComponents(const_f), sum_of_components)); + } + } + } + } + + SECTION("2D") + { + const size_t size = 3; + + constexpr size_t Dimension = 2; + + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); + + for (const auto& named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh = named_mesh.mesh(); + + auto xj = MeshDataManager::instance().getMeshData(*mesh).xj(); + + DiscreteFunctionP0Vector<Dimension, double> f{mesh, size}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + f[cell_id][0] = 2 * x + 1; + f[cell_id][1] = x * x - 1; + f[cell_id][2] = 2 + x; + }); + + DiscreteFunctionP0Vector<Dimension, double> g{mesh, size}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + g[cell_id][0] = (x + 1) * (x - 2) + 1; + g[cell_id][1] = 3 * (x + 2) - 1; + g[cell_id][2] = (x + 3) * 5; + }); + + DiscreteFunctionP0Vector<Dimension, const double> const_f = f; + DiscreteFunctionP0Vector<Dimension, const double> const_g{g}; + + auto same_data = [](const auto& f, const auto& g) { + const size_t number_of_cells = g.size(); + for (CellId cell_id = 0; cell_id < number_of_cells; ++cell_id) { + if (f[cell_id] != g[cell_id]) { + return false; + } + } + return true; + }; + + SECTION("dot") + { + Array<double> dot_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + double sum = 0; + for (size_t i = 0; i < size; ++i) { + sum += f[cell_id][i] * g[cell_id][i]; + } + dot_values[cell_id] = sum; + }); + + REQUIRE(same_data(dot(f, g), dot_values)); + REQUIRE(same_data(dot(const_f, g), dot_values)); + REQUIRE(same_data(dot(f, const_g), dot_values)); + REQUIRE(same_data(dot(const_f, const_g), dot_values)); + } + + SECTION("sumOfComponents") + { + Array<double> sum_of_components{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + double sum = 0; + for (size_t i = 0; i < size; ++i) { + sum += f[cell_id][i]; + } + sum_of_components[cell_id] = sum; + }); + + REQUIRE(same_data(sumOfComponents(f), sum_of_components)); + REQUIRE(same_data(sumOfComponents(const_f), sum_of_components)); + } + } + } + } + + SECTION("3D") + { + const size_t size = 3; + + constexpr size_t Dimension = 3; + + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); + + for (const auto& named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh = named_mesh.mesh(); + + auto xj = MeshDataManager::instance().getMeshData(*mesh).xj(); + + DiscreteFunctionP0Vector<Dimension, double> f{mesh, size}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + f[cell_id][0] = 2 * x + 1; + f[cell_id][1] = x * x - 1; + f[cell_id][2] = 2 + x; + }); + + DiscreteFunctionP0Vector<Dimension, double> g{mesh, size}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + const double x = xj[cell_id][0]; + g[cell_id][0] = (x + 1) * (x - 2) + 1; + g[cell_id][1] = 3 * (x + 2) - 1; + g[cell_id][2] = (x + 3) * 5; + }); + + DiscreteFunctionP0Vector<Dimension, const double> const_f = f; + DiscreteFunctionP0Vector<Dimension, const double> const_g{g}; + + auto same_data = [](const auto& f, const auto& g) { + const size_t number_of_cells = g.size(); + for (CellId cell_id = 0; cell_id < number_of_cells; ++cell_id) { + if (f[cell_id] != g[cell_id]) { + return false; + } + } + return true; + }; + + SECTION("dot") + { + Array<double> dot_values{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + double sum = 0; + for (size_t i = 0; i < size; ++i) { + sum += f[cell_id][i] * g[cell_id][i]; + } + dot_values[cell_id] = sum; + }); + + REQUIRE(same_data(dot(f, g), dot_values)); + REQUIRE(same_data(dot(const_f, g), dot_values)); + REQUIRE(same_data(dot(f, const_g), dot_values)); + REQUIRE(same_data(dot(const_f, const_g), dot_values)); + } + + SECTION("sumOfComponents") + { + Array<double> sum_of_components{mesh->numberOfCells()}; + parallel_for( + mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + double sum = 0; + for (size_t i = 0; i < size; ++i) { + sum += f[cell_id][i]; + } + sum_of_components[cell_id] = sum; + }); + + REQUIRE(same_data(sumOfComponents(f), sum_of_components)); + REQUIRE(same_data(sumOfComponents(const_f), sum_of_components)); + } + } + } + } + } + SECTION("binary operators") { SECTION("1D") @@ -545,7 +797,7 @@ TEST_CASE("DiscreteFunctionP0Vector", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); @@ -679,7 +931,7 @@ TEST_CASE("DiscreteFunctionP0Vector", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); @@ -817,7 +1069,7 @@ TEST_CASE("DiscreteFunctionP0Vector", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); diff --git a/tests/test_DiscreteFunctionUtils.cpp b/tests/test_DiscreteFunctionUtils.cpp index 3783a19c99cb67066565c507abfeca6ce0f5d61f..85c916c4cf559ca4c2ceef612d1da03db779715e 100644 --- a/tests/test_DiscreteFunctionUtils.cpp +++ b/tests/test_DiscreteFunctionUtils.cpp @@ -18,7 +18,7 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); @@ -28,39 +28,50 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]") SECTION("common mesh") { - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); - std::shared_ptr vh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); - std::shared_ptr wh = std::make_shared<DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh); + DiscreteFunctionP0<Dimension, double> uh(mesh); + DiscreteFunctionP0<Dimension, double> vh(mesh); + DiscreteFunctionP0<Dimension, TinyVector<2>> wh(mesh); - std::shared_ptr qh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh_copy); + DiscreteFunctionP0<Dimension, double> qh(mesh_copy); - REQUIRE(getCommonMesh({uh, vh, wh}).get() == mesh.get()); - REQUIRE(getCommonMesh({uh, vh, wh, qh}).use_count() == 0); + std::shared_ptr uh_v = std::make_shared<DiscreteFunctionVariant>(uh); + std::shared_ptr vh_v = std::make_shared<DiscreteFunctionVariant>(vh); + std::shared_ptr wh_v = std::make_shared<DiscreteFunctionVariant>(wh); + std::shared_ptr qh_v = std::make_shared<DiscreteFunctionVariant>(qh); + + REQUIRE(getCommonMesh({uh_v, vh_v, wh_v}).get() == mesh.get()); + REQUIRE(getCommonMesh({uh_v, vh_v, wh_v, qh_v}).use_count() == 0); } SECTION("check discretization type") { - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); - std::shared_ptr vh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); - - std::shared_ptr qh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh_copy); - - std::shared_ptr Uh = std::make_shared<DiscreteFunctionP0Vector<Dimension, double>>(mesh, 3); - std::shared_ptr Vh = std::make_shared<DiscreteFunctionP0Vector<Dimension, double>>(mesh, 3); - - REQUIRE(checkDiscretizationType({uh}, DiscreteFunctionType::P0)); - REQUIRE(checkDiscretizationType({uh, vh, qh}, DiscreteFunctionType::P0)); - REQUIRE(not checkDiscretizationType({uh}, DiscreteFunctionType::P0Vector)); - REQUIRE(not checkDiscretizationType({uh, vh, qh}, DiscreteFunctionType::P0Vector)); - REQUIRE(checkDiscretizationType({Uh}, DiscreteFunctionType::P0Vector)); - REQUIRE(checkDiscretizationType({Uh, Vh}, DiscreteFunctionType::P0Vector)); - REQUIRE(not checkDiscretizationType({Uh, Vh}, DiscreteFunctionType::P0)); - REQUIRE(not checkDiscretizationType({Uh}, DiscreteFunctionType::P0)); + DiscreteFunctionP0<Dimension, double> uh(mesh); + DiscreteFunctionP0<Dimension, double> vh(mesh); + DiscreteFunctionP0<Dimension, double> qh(mesh_copy); + + DiscreteFunctionP0Vector<Dimension, double> Uh(mesh, 3); + DiscreteFunctionP0Vector<Dimension, double> Vh(mesh, 3); + + auto uh_v = std::make_shared<DiscreteFunctionVariant>(uh); + auto vh_v = std::make_shared<DiscreteFunctionVariant>(vh); + auto qh_v = std::make_shared<DiscreteFunctionVariant>(qh); + auto Uh_v = std::make_shared<DiscreteFunctionVariant>(Uh); + auto Vh_v = std::make_shared<DiscreteFunctionVariant>(Vh); + + REQUIRE(checkDiscretizationType({uh_v}, DiscreteFunctionType::P0)); + REQUIRE(checkDiscretizationType({uh_v, vh_v, qh_v}, DiscreteFunctionType::P0)); + REQUIRE(not checkDiscretizationType({uh_v}, DiscreteFunctionType::P0Vector)); + REQUIRE(not checkDiscretizationType({uh_v, vh_v, qh_v}, DiscreteFunctionType::P0Vector)); + REQUIRE(checkDiscretizationType({Uh_v}, DiscreteFunctionType::P0Vector)); + REQUIRE(checkDiscretizationType({Uh_v, Vh_v}, DiscreteFunctionType::P0Vector)); + REQUIRE(not checkDiscretizationType({Uh_v, Vh_v}, DiscreteFunctionType::P0)); + REQUIRE(not checkDiscretizationType({Uh_v}, DiscreteFunctionType::P0)); } SECTION("scalar function shallow copy") { - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); + using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const double>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, double>(mesh)); std::shared_ptr vh = shallowCopy(mesh, uh); REQUIRE(uh == vh); @@ -68,14 +79,15 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]") std::shared_ptr wh = shallowCopy(mesh_copy, uh); REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*wh).cellValues()[CellId{0}])); + REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) == + &(wh->get<DiscreteFunctionT>().cellValues()[CellId{0}])); } SECTION("R^1 function shallow copy") { - using DataType = TinyVector<1>; - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); + using DataType = TinyVector<1>; + using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const DataType>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, DataType>(mesh)); std::shared_ptr vh = shallowCopy(mesh, uh); REQUIRE(uh == vh); @@ -83,14 +95,15 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]") std::shared_ptr wh = shallowCopy(mesh_copy, uh); REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) == + &(wh->get<DiscreteFunctionT>().cellValues()[CellId{0}])); } SECTION("R^2 function shallow copy") { - using DataType = TinyVector<2>; - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); + using DataType = TinyVector<2>; + using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const DataType>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, DataType>(mesh)); std::shared_ptr vh = shallowCopy(mesh, uh); REQUIRE(uh == vh); @@ -98,14 +111,15 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]") std::shared_ptr wh = shallowCopy(mesh_copy, uh); REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) == + &(wh->get<DiscreteFunctionT>().cellValues()[CellId{0}])); } SECTION("R^3 function shallow copy") { - using DataType = TinyVector<3>; - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); + using DataType = TinyVector<3>; + using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const DataType>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, DataType>(mesh)); std::shared_ptr vh = shallowCopy(mesh, uh); REQUIRE(uh == vh); @@ -113,14 +127,15 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]") std::shared_ptr wh = shallowCopy(mesh_copy, uh); REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) == + &(wh->get<DiscreteFunctionT>().cellValues()[CellId{0}])); } SECTION("R^1x1 function shallow copy") { - using DataType = TinyMatrix<1>; - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); + using DataType = TinyMatrix<1>; + using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const DataType>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, DataType>(mesh)); std::shared_ptr vh = shallowCopy(mesh, uh); REQUIRE(uh == vh); @@ -128,14 +143,15 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]") std::shared_ptr wh = shallowCopy(mesh_copy, uh); REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) == + &(wh->get<DiscreteFunctionT>().cellValues()[CellId{0}])); } SECTION("R^2x2 function shallow copy") { - using DataType = TinyMatrix<2>; - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); + using DataType = TinyMatrix<2>; + using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const DataType>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, DataType>(mesh)); std::shared_ptr vh = shallowCopy(mesh, uh); REQUIRE(uh == vh); @@ -143,14 +159,15 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]") std::shared_ptr wh = shallowCopy(mesh_copy, uh); REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) == + &(wh->get<DiscreteFunctionT>().cellValues()[CellId{0}])); } SECTION("R^3x3 function shallow copy") { - using DataType = TinyMatrix<3>; - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); + using DataType = TinyMatrix<3>; + using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const DataType>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, DataType>(mesh)); std::shared_ptr vh = shallowCopy(mesh, uh); REQUIRE(uh == vh); @@ -158,8 +175,24 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]") std::shared_ptr wh = shallowCopy(mesh_copy, uh); REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) == + &(wh->get<DiscreteFunctionT>().cellValues()[CellId{0}])); + } + + SECTION("P0Vector function shallow copy") + { + using DiscreteFunctionT = DiscreteFunctionP0Vector<Dimension, const double>; + std::shared_ptr uh = + std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0Vector<Dimension, double>(mesh, 2)); + std::shared_ptr vh = shallowCopy(mesh, uh); + + REQUIRE(uh == vh); + + std::shared_ptr wh = shallowCopy(mesh_copy, uh); + + REQUIRE(uh != wh); + REQUIRE(&(uh->get<DiscreteFunctionT>().cellArrays()[CellId{0}][0]) == + &(wh->get<DiscreteFunctionT>().cellArrays()[CellId{0}][0])); } } } @@ -171,7 +204,7 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); @@ -181,39 +214,50 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]") SECTION("common mesh") { - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); - std::shared_ptr vh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); - std::shared_ptr wh = std::make_shared<DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh); + DiscreteFunctionP0<Dimension, double> uh(mesh); + DiscreteFunctionP0<Dimension, double> vh(mesh); + DiscreteFunctionP0<Dimension, TinyVector<2>> wh(mesh); - std::shared_ptr qh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh_copy); + DiscreteFunctionP0<Dimension, double> qh(mesh_copy); - REQUIRE(getCommonMesh({uh, vh, wh}).get() == mesh.get()); - REQUIRE(getCommonMesh({uh, vh, wh, qh}).use_count() == 0); + std::shared_ptr uh_v = std::make_shared<DiscreteFunctionVariant>(uh); + std::shared_ptr vh_v = std::make_shared<DiscreteFunctionVariant>(vh); + std::shared_ptr wh_v = std::make_shared<DiscreteFunctionVariant>(wh); + std::shared_ptr qh_v = std::make_shared<DiscreteFunctionVariant>(qh); + + REQUIRE(getCommonMesh({uh_v, vh_v, wh_v}).get() == mesh.get()); + REQUIRE(getCommonMesh({uh_v, vh_v, wh_v, qh_v}).use_count() == 0); } SECTION("check discretization type") { - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); - std::shared_ptr vh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); - - std::shared_ptr qh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh_copy); - - std::shared_ptr Uh = std::make_shared<DiscreteFunctionP0Vector<Dimension, double>>(mesh, 3); - std::shared_ptr Vh = std::make_shared<DiscreteFunctionP0Vector<Dimension, double>>(mesh, 3); - - REQUIRE(checkDiscretizationType({uh}, DiscreteFunctionType::P0)); - REQUIRE(checkDiscretizationType({uh, vh, qh}, DiscreteFunctionType::P0)); - REQUIRE(not checkDiscretizationType({uh}, DiscreteFunctionType::P0Vector)); - REQUIRE(not checkDiscretizationType({uh, vh, qh}, DiscreteFunctionType::P0Vector)); - REQUIRE(checkDiscretizationType({Uh}, DiscreteFunctionType::P0Vector)); - REQUIRE(checkDiscretizationType({Uh, Vh}, DiscreteFunctionType::P0Vector)); - REQUIRE(not checkDiscretizationType({Uh, Vh}, DiscreteFunctionType::P0)); - REQUIRE(not checkDiscretizationType({Uh}, DiscreteFunctionType::P0)); + DiscreteFunctionP0<Dimension, double> uh(mesh); + DiscreteFunctionP0<Dimension, double> vh(mesh); + DiscreteFunctionP0<Dimension, double> qh(mesh_copy); + + DiscreteFunctionP0Vector<Dimension, double> Uh(mesh, 3); + DiscreteFunctionP0Vector<Dimension, double> Vh(mesh, 3); + + auto uh_v = std::make_shared<DiscreteFunctionVariant>(uh); + auto vh_v = std::make_shared<DiscreteFunctionVariant>(vh); + auto qh_v = std::make_shared<DiscreteFunctionVariant>(qh); + auto Uh_v = std::make_shared<DiscreteFunctionVariant>(Uh); + auto Vh_v = std::make_shared<DiscreteFunctionVariant>(Vh); + + REQUIRE(checkDiscretizationType({uh_v}, DiscreteFunctionType::P0)); + REQUIRE(checkDiscretizationType({uh_v, vh_v, qh_v}, DiscreteFunctionType::P0)); + REQUIRE(not checkDiscretizationType({uh_v}, DiscreteFunctionType::P0Vector)); + REQUIRE(not checkDiscretizationType({uh_v, vh_v, qh_v}, DiscreteFunctionType::P0Vector)); + REQUIRE(checkDiscretizationType({Uh_v}, DiscreteFunctionType::P0Vector)); + REQUIRE(checkDiscretizationType({Uh_v, Vh_v}, DiscreteFunctionType::P0Vector)); + REQUIRE(not checkDiscretizationType({Uh_v, Vh_v}, DiscreteFunctionType::P0)); + REQUIRE(not checkDiscretizationType({Uh_v}, DiscreteFunctionType::P0)); } SECTION("scalar function shallow copy") { - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); + using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const double>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, double>(mesh)); std::shared_ptr vh = shallowCopy(mesh, uh); REQUIRE(uh == vh); @@ -221,14 +265,15 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]") std::shared_ptr wh = shallowCopy(mesh_copy, uh); REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*wh).cellValues()[CellId{0}])); + REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) == + &(wh->get<DiscreteFunctionT>().cellValues()[CellId{0}])); } SECTION("R^1 function shallow copy") { - using DataType = TinyVector<1>; - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); + using DataType = TinyVector<1>; + using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const DataType>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, DataType>(mesh)); std::shared_ptr vh = shallowCopy(mesh, uh); REQUIRE(uh == vh); @@ -236,14 +281,15 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]") std::shared_ptr wh = shallowCopy(mesh_copy, uh); REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) == + &(wh->get<DiscreteFunctionT>().cellValues()[CellId{0}])); } SECTION("R^2 function shallow copy") { - using DataType = TinyVector<2>; - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); + using DataType = TinyVector<2>; + using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const DataType>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, DataType>(mesh)); std::shared_ptr vh = shallowCopy(mesh, uh); REQUIRE(uh == vh); @@ -251,14 +297,15 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]") std::shared_ptr wh = shallowCopy(mesh_copy, uh); REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) == + &(wh->get<DiscreteFunctionT>().cellValues()[CellId{0}])); } SECTION("R^3 function shallow copy") { - using DataType = TinyVector<3>; - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); + using DataType = TinyVector<3>; + using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const DataType>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, DataType>(mesh)); std::shared_ptr vh = shallowCopy(mesh, uh); REQUIRE(uh == vh); @@ -266,14 +313,15 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]") std::shared_ptr wh = shallowCopy(mesh_copy, uh); REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) == + &(wh->get<DiscreteFunctionT>().cellValues()[CellId{0}])); } SECTION("R^1x1 function shallow copy") { - using DataType = TinyMatrix<1>; - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); + using DataType = TinyMatrix<1>; + using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const DataType>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, DataType>(mesh)); std::shared_ptr vh = shallowCopy(mesh, uh); REQUIRE(uh == vh); @@ -281,14 +329,15 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]") std::shared_ptr wh = shallowCopy(mesh_copy, uh); REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) == + &(wh->get<DiscreteFunctionT>().cellValues()[CellId{0}])); } SECTION("R^2x2 function shallow copy") { - using DataType = TinyMatrix<2>; - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); + using DataType = TinyMatrix<2>; + using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const DataType>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, DataType>(mesh)); std::shared_ptr vh = shallowCopy(mesh, uh); REQUIRE(uh == vh); @@ -296,14 +345,15 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]") std::shared_ptr wh = shallowCopy(mesh_copy, uh); REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) == + &(wh->get<DiscreteFunctionT>().cellValues()[CellId{0}])); } SECTION("R^3x3 function shallow copy") { - using DataType = TinyMatrix<3>; - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); + using DataType = TinyMatrix<3>; + using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const DataType>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, DataType>(mesh)); std::shared_ptr vh = shallowCopy(mesh, uh); REQUIRE(uh == vh); @@ -311,8 +361,24 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]") std::shared_ptr wh = shallowCopy(mesh_copy, uh); REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) == + &(wh->get<DiscreteFunctionT>().cellValues()[CellId{0}])); + } + + SECTION("P0Vector function shallow copy") + { + using DiscreteFunctionT = DiscreteFunctionP0Vector<Dimension, const double>; + std::shared_ptr uh = + std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0Vector<Dimension, double>(mesh, 2)); + std::shared_ptr vh = shallowCopy(mesh, uh); + + REQUIRE(uh == vh); + + std::shared_ptr wh = shallowCopy(mesh_copy, uh); + + REQUIRE(uh != wh); + REQUIRE(&(uh->get<DiscreteFunctionT>().cellArrays()[CellId{0}][0]) == + &(wh->get<DiscreteFunctionT>().cellArrays()[CellId{0}][0])); } } } @@ -324,7 +390,7 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); @@ -334,39 +400,50 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]") SECTION("common mesh") { - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); - std::shared_ptr vh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); - std::shared_ptr wh = std::make_shared<DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh); + DiscreteFunctionP0<Dimension, double> uh(mesh); + DiscreteFunctionP0<Dimension, double> vh(mesh); + DiscreteFunctionP0<Dimension, TinyVector<2>> wh(mesh); + + DiscreteFunctionP0<Dimension, double> qh(mesh_copy); - std::shared_ptr qh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh_copy); + std::shared_ptr uh_v = std::make_shared<DiscreteFunctionVariant>(uh); + std::shared_ptr vh_v = std::make_shared<DiscreteFunctionVariant>(vh); + std::shared_ptr wh_v = std::make_shared<DiscreteFunctionVariant>(wh); + std::shared_ptr qh_v = std::make_shared<DiscreteFunctionVariant>(qh); - REQUIRE(getCommonMesh({uh, vh, wh}).get() == mesh.get()); - REQUIRE(getCommonMesh({uh, vh, wh, qh}).use_count() == 0); + REQUIRE(getCommonMesh({uh_v, vh_v, wh_v}).get() == mesh.get()); + REQUIRE(getCommonMesh({uh_v, vh_v, wh_v, qh_v}).use_count() == 0); } SECTION("check discretization type") { - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); - std::shared_ptr vh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); - - std::shared_ptr qh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh_copy); - - std::shared_ptr Uh = std::make_shared<DiscreteFunctionP0Vector<Dimension, double>>(mesh, 3); - std::shared_ptr Vh = std::make_shared<DiscreteFunctionP0Vector<Dimension, double>>(mesh, 3); - - REQUIRE(checkDiscretizationType({uh}, DiscreteFunctionType::P0)); - REQUIRE(checkDiscretizationType({uh, vh, qh}, DiscreteFunctionType::P0)); - REQUIRE(not checkDiscretizationType({uh}, DiscreteFunctionType::P0Vector)); - REQUIRE(not checkDiscretizationType({uh, vh, qh}, DiscreteFunctionType::P0Vector)); - REQUIRE(checkDiscretizationType({Uh}, DiscreteFunctionType::P0Vector)); - REQUIRE(checkDiscretizationType({Uh, Vh}, DiscreteFunctionType::P0Vector)); - REQUIRE(not checkDiscretizationType({Uh, Vh}, DiscreteFunctionType::P0)); - REQUIRE(not checkDiscretizationType({Uh}, DiscreteFunctionType::P0)); + DiscreteFunctionP0<Dimension, double> uh(mesh); + DiscreteFunctionP0<Dimension, double> vh(mesh); + DiscreteFunctionP0<Dimension, double> qh(mesh_copy); + + DiscreteFunctionP0Vector<Dimension, double> Uh(mesh, 3); + DiscreteFunctionP0Vector<Dimension, double> Vh(mesh, 3); + + auto uh_v = std::make_shared<DiscreteFunctionVariant>(uh); + auto vh_v = std::make_shared<DiscreteFunctionVariant>(vh); + auto qh_v = std::make_shared<DiscreteFunctionVariant>(qh); + auto Uh_v = std::make_shared<DiscreteFunctionVariant>(Uh); + auto Vh_v = std::make_shared<DiscreteFunctionVariant>(Vh); + + REQUIRE(checkDiscretizationType({uh_v}, DiscreteFunctionType::P0)); + REQUIRE(checkDiscretizationType({uh_v, vh_v, qh_v}, DiscreteFunctionType::P0)); + REQUIRE(not checkDiscretizationType({uh_v}, DiscreteFunctionType::P0Vector)); + REQUIRE(not checkDiscretizationType({uh_v, vh_v, qh_v}, DiscreteFunctionType::P0Vector)); + REQUIRE(checkDiscretizationType({Uh_v}, DiscreteFunctionType::P0Vector)); + REQUIRE(checkDiscretizationType({Uh_v, Vh_v}, DiscreteFunctionType::P0Vector)); + REQUIRE(not checkDiscretizationType({Uh_v, Vh_v}, DiscreteFunctionType::P0)); + REQUIRE(not checkDiscretizationType({Uh_v}, DiscreteFunctionType::P0)); } SECTION("scalar function shallow copy") { - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); + using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const double>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, double>(mesh)); std::shared_ptr vh = shallowCopy(mesh, uh); REQUIRE(uh == vh); @@ -374,14 +451,15 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]") std::shared_ptr wh = shallowCopy(mesh_copy, uh); REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*wh).cellValues()[CellId{0}])); + REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) == + &(wh->get<DiscreteFunctionT>().cellValues()[CellId{0}])); } SECTION("R^1 function shallow copy") { - using DataType = TinyVector<1>; - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); + using DataType = TinyVector<1>; + using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const DataType>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, DataType>(mesh)); std::shared_ptr vh = shallowCopy(mesh, uh); REQUIRE(uh == vh); @@ -389,14 +467,15 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]") std::shared_ptr wh = shallowCopy(mesh_copy, uh); REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) == + &(wh->get<DiscreteFunctionT>().cellValues()[CellId{0}])); } SECTION("R^2 function shallow copy") { - using DataType = TinyVector<2>; - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); + using DataType = TinyVector<2>; + using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const DataType>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, DataType>(mesh)); std::shared_ptr vh = shallowCopy(mesh, uh); REQUIRE(uh == vh); @@ -404,14 +483,15 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]") std::shared_ptr wh = shallowCopy(mesh_copy, uh); REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) == + &(wh->get<DiscreteFunctionT>().cellValues()[CellId{0}])); } SECTION("R^3 function shallow copy") { - using DataType = TinyVector<3>; - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); + using DataType = TinyVector<3>; + using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const DataType>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, DataType>(mesh)); std::shared_ptr vh = shallowCopy(mesh, uh); REQUIRE(uh == vh); @@ -419,14 +499,15 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]") std::shared_ptr wh = shallowCopy(mesh_copy, uh); REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) == + &(wh->get<DiscreteFunctionT>().cellValues()[CellId{0}])); } SECTION("R^1x1 function shallow copy") { - using DataType = TinyMatrix<1>; - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); + using DataType = TinyMatrix<1>; + using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const DataType>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, DataType>(mesh)); std::shared_ptr vh = shallowCopy(mesh, uh); REQUIRE(uh == vh); @@ -434,14 +515,15 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]") std::shared_ptr wh = shallowCopy(mesh_copy, uh); REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) == + &(wh->get<DiscreteFunctionT>().cellValues()[CellId{0}])); } SECTION("R^2x2 function shallow copy") { - using DataType = TinyMatrix<2>; - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); + using DataType = TinyMatrix<2>; + using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const DataType>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, DataType>(mesh)); std::shared_ptr vh = shallowCopy(mesh, uh); REQUIRE(uh == vh); @@ -449,14 +531,31 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]") std::shared_ptr wh = shallowCopy(mesh_copy, uh); REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) == + &(wh->get<DiscreteFunctionT>().cellValues()[CellId{0}])); } SECTION("R^3x3 function shallow copy") { - using DataType = TinyMatrix<3>; - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, DataType>>(mesh); + using DataType = TinyMatrix<3>; + using DiscreteFunctionT = DiscreteFunctionP0<Dimension, const DataType>; + std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, DataType>(mesh)); + std::shared_ptr vh = shallowCopy(mesh, uh); + + REQUIRE(uh == vh); + + std::shared_ptr wh = shallowCopy(mesh_copy, uh); + + REQUIRE(uh != wh); + REQUIRE(&(uh->get<DiscreteFunctionT>().cellValues()[CellId{0}]) == + &(wh->get<DiscreteFunctionT>().cellValues()[CellId{0}])); + } + + SECTION("P0Vector function shallow copy") + { + using DiscreteFunctionT = DiscreteFunctionP0Vector<Dimension, const double>; + std::shared_ptr uh = + std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0Vector<Dimension, double>(mesh, 2)); std::shared_ptr vh = shallowCopy(mesh, uh); REQUIRE(uh == vh); @@ -464,8 +563,8 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]") std::shared_ptr wh = shallowCopy(mesh_copy, uh); REQUIRE(uh != wh); - REQUIRE(&(uh->cellValues()[CellId{0}]) == - &(dynamic_cast<const DiscreteFunctionP0<Dimension, DataType>&>(*wh).cellValues()[CellId{0}])); + REQUIRE(&(uh->get<DiscreteFunctionT>().cellArrays()[CellId{0}][0]) == + &(wh->get<DiscreteFunctionT>().cellArrays()[CellId{0}][0])); } } } @@ -479,7 +578,7 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh = named_mesh.mesh(); @@ -487,7 +586,7 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]") std::shared_ptr other_mesh = CartesianMeshBuilder{TinyVector<1>{-1}, TinyVector<1>{3}, TinyVector<1, size_t>{19}}.mesh(); - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh); + std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, double>(mesh)); REQUIRE_THROWS_WITH(shallowCopy(other_mesh, uh), "error: cannot shallow copy when connectivity changes"); } @@ -501,7 +600,7 @@ TEST_CASE("DiscreteFunctionUtils", "[scheme]") std::shared_ptr mesh_1d = MeshDataBaseForTests::get().cartesian1DMesh(); std::shared_ptr mesh_2d = MeshDataBaseForTests::get().cartesian2DMesh(); - std::shared_ptr uh = std::make_shared<DiscreteFunctionP0<Dimension, double>>(mesh_1d); + std::shared_ptr uh = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionP0<Dimension, double>(mesh_1d)); REQUIRE_THROWS_WITH(shallowCopy(mesh_2d, uh), "error: incompatible mesh dimensions"); } diff --git a/tests/test_DiscreteFunctionVectorIntegrator.cpp b/tests/test_DiscreteFunctionVectorIntegrator.cpp index 31fd447f525f2b002ead1246219319454c792588..4c510542ba9b244d505b7531db8d49f0c106bc2d 100644 --- a/tests/test_DiscreteFunctionVectorIntegrator.cpp +++ b/tests/test_DiscreteFunctionVectorIntegrator.cpp @@ -23,6 +23,7 @@ #include <scheme/DiscreteFunctionDescriptorP0Vector.hpp> #include <scheme/DiscreteFunctionP0Vector.hpp> +#include <scheme/DiscreteFunctionVariant.hpp> #include <scheme/DiscreteFunctionVectorIntegrator.hpp> #include <pegtl/string_input.hpp> @@ -60,7 +61,7 @@ TEST_CASE("DiscreteFunctionVectorIntegrator", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -100,7 +101,7 @@ let R_scalar_non_linear_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3; DiscreteFunctionVectorIntegrator integrator(mesh_1d, quadrature_descriptor, std::make_shared<DiscreteFunctionDescriptorP0Vector>(), function_id_list); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); size_t i = 0; @@ -108,36 +109,32 @@ let R_scalar_non_linear_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3; CellValue<double> cell_value = IntegrateCellValue<double(TinyVector<1>)>::integrate(function_id_list[i], *quadrature_descriptor, *mesh_1d); - REQUIRE( - same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, i++, + discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } { CellValue<double> cell_value = IntegrateCellValue<double(TinyVector<1>)>::integrate(function_id_list[i], *quadrature_descriptor, *mesh_1d); - REQUIRE( - same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, i++, + discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } { CellValue<double> cell_value = IntegrateCellValue<double(TinyVector<1>)>::integrate(function_id_list[i], *quadrature_descriptor, *mesh_1d); - REQUIRE( - same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, i++, + discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } { CellValue<double> cell_value = IntegrateCellValue<double(TinyVector<1>)>::integrate(function_id_list[i], *quadrature_descriptor, *mesh_1d); - REQUIRE( - same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, i++, + discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } REQUIRE(i == function_id_list.size()); @@ -153,7 +150,7 @@ let R_scalar_non_linear_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3; std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -193,7 +190,7 @@ let R_scalar_non_linear_2d: R^2 -> R, x -> 2 * exp(x[0] + x[1]) + 3; DiscreteFunctionVectorIntegrator integrator(mesh_2d, quadrature_descriptor, std::make_shared<DiscreteFunctionDescriptorP0Vector>(), function_id_list); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); size_t i = 0; @@ -201,36 +198,32 @@ let R_scalar_non_linear_2d: R^2 -> R, x -> 2 * exp(x[0] + x[1]) + 3; CellValue<double> cell_value = IntegrateCellValue<double(TinyVector<2>)>::integrate(function_id_list[i], *quadrature_descriptor, *mesh_2d); - REQUIRE( - same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, i++, + discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } { CellValue<double> cell_value = IntegrateCellValue<double(TinyVector<2>)>::integrate(function_id_list[i], *quadrature_descriptor, *mesh_2d); - REQUIRE( - same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, i++, + discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } { CellValue<double> cell_value = IntegrateCellValue<double(TinyVector<2>)>::integrate(function_id_list[i], *quadrature_descriptor, *mesh_2d); - REQUIRE( - same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, i++, + discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } { CellValue<double> cell_value = IntegrateCellValue<double(TinyVector<2>)>::integrate(function_id_list[i], *quadrature_descriptor, *mesh_2d); - REQUIRE( - same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, i++, + discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } REQUIRE(i == function_id_list.size()); @@ -246,7 +239,7 @@ let R_scalar_non_linear_2d: R^2 -> R, x -> 2 * exp(x[0] + x[1]) + 3; std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -286,7 +279,7 @@ let R_scalar_non_linear_3d: R^3 -> R, x -> 2 * exp(x[0] + x[1]) + 3 * x[2]; DiscreteFunctionVectorIntegrator integrator(mesh_3d, quadrature_descriptor, std::make_shared<DiscreteFunctionDescriptorP0Vector>(), function_id_list); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); size_t i = 0; @@ -294,36 +287,32 @@ let R_scalar_non_linear_3d: R^3 -> R, x -> 2 * exp(x[0] + x[1]) + 3 * x[2]; CellValue<double> cell_value = IntegrateCellValue<double(TinyVector<3>)>::integrate(function_id_list[i], *quadrature_descriptor, *mesh_3d); - REQUIRE( - same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, i++, + discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } { CellValue<double> cell_value = IntegrateCellValue<double(TinyVector<3>)>::integrate(function_id_list[i], *quadrature_descriptor, *mesh_3d); - REQUIRE( - same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, i++, + discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } { CellValue<double> cell_value = IntegrateCellValue<double(TinyVector<3>)>::integrate(function_id_list[i], *quadrature_descriptor, *mesh_3d); - REQUIRE( - same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, i++, + discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } { CellValue<double> cell_value = IntegrateCellValue<double(TinyVector<3>)>::integrate(function_id_list[i], *quadrature_descriptor, *mesh_3d); - REQUIRE( - same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, i++, + discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } REQUIRE(i == function_id_list.size()); @@ -337,7 +326,7 @@ let R_scalar_non_linear_3d: R^3 -> R, x -> 2 * exp(x[0] + x[1]) + 3 * x[2]; std::shared_ptr<const IQuadratureDescriptor> quadrature_descriptor = std::make_shared<GaussQuadratureDescriptor>(3); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); diff --git a/tests/test_DiscreteFunctionVectorIntegratorByZone.cpp b/tests/test_DiscreteFunctionVectorIntegratorByZone.cpp index 98111d4c6b7f1dd4788745db480e72c06c083945..ac516d3ff9b7d20e3cedd152f522c7f7263e8acd 100644 --- a/tests/test_DiscreteFunctionVectorIntegratorByZone.cpp +++ b/tests/test_DiscreteFunctionVectorIntegratorByZone.cpp @@ -25,6 +25,7 @@ #include <scheme/DiscreteFunctionDescriptorP0Vector.hpp> #include <scheme/DiscreteFunctionP0Vector.hpp> +#include <scheme/DiscreteFunctionVariant.hpp> #include <scheme/DiscreteFunctionVectorIntegrator.hpp> #include <pegtl/string_input.hpp> @@ -103,7 +104,7 @@ let R_scalar_non_linear_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3; DiscreteFunctionVectorIntegrator integrator(mesh_1d, zone_list, quadrature_descriptor, std::make_shared<DiscreteFunctionDescriptorP0Vector>(), function_id_list); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); size_t i = 0; @@ -121,8 +122,8 @@ let R_scalar_non_linear_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3; cell_value[cell_id] = array[j]; }); - REQUIRE(same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE( + same_cell_value(cell_value, i++, discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } { @@ -139,8 +140,8 @@ let R_scalar_non_linear_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3; cell_value[cell_id] = array[j]; }); - REQUIRE(same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE( + same_cell_value(cell_value, i++, discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } { @@ -157,8 +158,8 @@ let R_scalar_non_linear_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3; cell_value[cell_id] = array[j]; }); - REQUIRE(same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE( + same_cell_value(cell_value, i++, discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } { @@ -175,8 +176,8 @@ let R_scalar_non_linear_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3; cell_value[cell_id] = array[j]; }); - REQUIRE(same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE( + same_cell_value(cell_value, i++, discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } REQUIRE(i == function_id_list.size()); @@ -231,7 +232,7 @@ let R_scalar_non_linear_2d: R^2 -> R, x -> 2 * exp(x[0] + x[1]) + 3; DiscreteFunctionVectorIntegrator integrator(mesh_2d, zone_list, quadrature_descriptor, std::make_shared<DiscreteFunctionDescriptorP0Vector>(), function_id_list); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); size_t i = 0; @@ -249,8 +250,8 @@ let R_scalar_non_linear_2d: R^2 -> R, x -> 2 * exp(x[0] + x[1]) + 3; cell_value[cell_id] = array[j]; }); - REQUIRE(same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE( + same_cell_value(cell_value, i++, discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } { @@ -267,8 +268,8 @@ let R_scalar_non_linear_2d: R^2 -> R, x -> 2 * exp(x[0] + x[1]) + 3; cell_value[cell_id] = array[j]; }); - REQUIRE(same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE( + same_cell_value(cell_value, i++, discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } { @@ -285,8 +286,8 @@ let R_scalar_non_linear_2d: R^2 -> R, x -> 2 * exp(x[0] + x[1]) + 3; cell_value[cell_id] = array[j]; }); - REQUIRE(same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE( + same_cell_value(cell_value, i++, discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } { @@ -303,8 +304,8 @@ let R_scalar_non_linear_2d: R^2 -> R, x -> 2 * exp(x[0] + x[1]) + 3; cell_value[cell_id] = array[j]; }); - REQUIRE(same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE( + same_cell_value(cell_value, i++, discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } REQUIRE(i == function_id_list.size()); @@ -359,7 +360,7 @@ let R_scalar_non_linear_3d: R^3 -> R, x -> 2 * exp(x[0] + x[1]) + 3 * x[2]; DiscreteFunctionVectorIntegrator integrator(mesh_3d, zone_list, quadrature_descriptor, std::make_shared<DiscreteFunctionDescriptorP0Vector>(), function_id_list); - std::shared_ptr discrete_function = integrator.integrate(); + DiscreteFunctionVariant discrete_function = integrator.integrate(); size_t i = 0; @@ -377,8 +378,8 @@ let R_scalar_non_linear_3d: R^3 -> R, x -> 2 * exp(x[0] + x[1]) + 3 * x[2]; cell_value[cell_id] = array[j]; }); - REQUIRE(same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE( + same_cell_value(cell_value, i++, discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } { @@ -395,8 +396,8 @@ let R_scalar_non_linear_3d: R^3 -> R, x -> 2 * exp(x[0] + x[1]) + 3 * x[2]; cell_value[cell_id] = array[j]; }); - REQUIRE(same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE( + same_cell_value(cell_value, i++, discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } { @@ -413,8 +414,8 @@ let R_scalar_non_linear_3d: R^3 -> R, x -> 2 * exp(x[0] + x[1]) + 3 * x[2]; cell_value[cell_id] = array[j]; }); - REQUIRE(same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE( + same_cell_value(cell_value, i++, discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } { @@ -431,8 +432,8 @@ let R_scalar_non_linear_3d: R^3 -> R, x -> 2 * exp(x[0] + x[1]) + 3 * x[2]; cell_value[cell_id] = array[j]; }); - REQUIRE(same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE( + same_cell_value(cell_value, i++, discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } REQUIRE(i == function_id_list.size()); diff --git a/tests/test_DiscreteFunctionVectorInterpoler.cpp b/tests/test_DiscreteFunctionVectorInterpoler.cpp index 3c3fefc38aba5b7377a86eb28ce4c6439ed82164..e47b8754d7ff7fe46d8f90d903af2efaed06be51 100644 --- a/tests/test_DiscreteFunctionVectorInterpoler.cpp +++ b/tests/test_DiscreteFunctionVectorInterpoler.cpp @@ -20,6 +20,7 @@ #include <scheme/DiscreteFunctionDescriptorP0Vector.hpp> #include <scheme/DiscreteFunctionP0Vector.hpp> +#include <scheme/DiscreteFunctionVariant.hpp> #include <scheme/DiscreteFunctionVectorInterpoler.hpp> #include <pegtl/string_input.hpp> @@ -55,7 +56,7 @@ TEST_CASE("DiscreteFunctionVectorInterpoler", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -96,7 +97,7 @@ let R_scalar_non_linear_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3; DiscreteFunctionVectorInterpoler interpoler(mesh_1d, std::make_shared<DiscreteFunctionDescriptorP0Vector>(), function_id_list); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); size_t i = 0; @@ -108,9 +109,8 @@ let R_scalar_non_linear_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3; cell_value[cell_id] = std::exp(2 * x[0]) + 3 > 4; }); - REQUIRE( - same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, i++, + discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } { @@ -121,9 +121,8 @@ let R_scalar_non_linear_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3; cell_value[cell_id] = std::floor(3 * x[0] * x[0] + 2); }); - REQUIRE( - same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, i++, + discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } { @@ -134,9 +133,8 @@ let R_scalar_non_linear_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3; cell_value[cell_id] = std::floor(std::exp(2 * x[0]) - 1); }); - REQUIRE( - same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, i++, + discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } { @@ -147,9 +145,8 @@ let R_scalar_non_linear_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3; cell_value[cell_id] = 2 * std::exp(x[0]) + 3; }); - REQUIRE( - same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, i++, + discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } REQUIRE(i == function_id_list.size()); @@ -163,7 +160,7 @@ let R_scalar_non_linear_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3; std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -204,7 +201,7 @@ let R_scalar_non_linear_2d: R^2 -> R, x -> 2 * exp(x[0] + x[1]) + 3; DiscreteFunctionVectorInterpoler interpoler(mesh_2d, std::make_shared<DiscreteFunctionDescriptorP0Vector>(), function_id_list); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); size_t i = 0; @@ -216,9 +213,8 @@ let R_scalar_non_linear_2d: R^2 -> R, x -> 2 * exp(x[0] + x[1]) + 3; cell_value[cell_id] = std::exp(2 * x[0]) + 3 > 4; }); - REQUIRE( - same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, i++, + discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } { @@ -229,9 +225,8 @@ let R_scalar_non_linear_2d: R^2 -> R, x -> 2 * exp(x[0] + x[1]) + 3; cell_value[cell_id] = std::floor(3 * (x[0] * x[1]) * (x[0] * x[1]) + 2); }); - REQUIRE( - same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, i++, + discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } { @@ -242,9 +237,8 @@ let R_scalar_non_linear_2d: R^2 -> R, x -> 2 * exp(x[0] + x[1]) + 3; cell_value[cell_id] = std::floor(std::exp(2 * x[1]) - 1); }); - REQUIRE( - same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, i++, + discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } { @@ -255,9 +249,8 @@ let R_scalar_non_linear_2d: R^2 -> R, x -> 2 * exp(x[0] + x[1]) + 3; cell_value[cell_id] = 2 * std::exp(x[0] + x[1]) + 3; }); - REQUIRE( - same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, i++, + discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } REQUIRE(i == function_id_list.size()); @@ -271,7 +264,7 @@ let R_scalar_non_linear_2d: R^2 -> R, x -> 2 * exp(x[0] + x[1]) + 3; std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -312,7 +305,7 @@ let R_scalar_non_linear_3d: R^3 -> R, x -> 2 * exp(x[0] + x[1]) + 3 * x[2]; DiscreteFunctionVectorInterpoler interpoler(mesh_3d, std::make_shared<DiscreteFunctionDescriptorP0Vector>(), function_id_list); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); size_t i = 0; @@ -324,9 +317,8 @@ let R_scalar_non_linear_3d: R^3 -> R, x -> 2 * exp(x[0] + x[1]) + 3 * x[2]; cell_value[cell_id] = std::exp(2 * x[0] + x[2]) + 3 > 4; }); - REQUIRE( - same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, i++, + discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } { @@ -337,9 +329,8 @@ let R_scalar_non_linear_3d: R^3 -> R, x -> 2 * exp(x[0] + x[1]) + 3 * x[2]; cell_value[cell_id] = std::floor(3 * (x[0] * x[1]) * (x[0] * x[1]) + 2); }); - REQUIRE( - same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, i++, + discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } { @@ -350,9 +341,8 @@ let R_scalar_non_linear_3d: R^3 -> R, x -> 2 * exp(x[0] + x[1]) + 3 * x[2]; cell_value[cell_id] = std::floor(std::exp(2 * x[1]) - x[2]); }); - REQUIRE( - same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, i++, + discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } { @@ -363,9 +353,8 @@ let R_scalar_non_linear_3d: R^3 -> R, x -> 2 * exp(x[0] + x[1]) + 3 * x[2]; cell_value[cell_id] = 2 * std::exp(x[0] + x[1]) + 3 * x[2]; }); - REQUIRE( - same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE(same_cell_value(cell_value, i++, + discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } REQUIRE(i == function_id_list.size()); @@ -377,7 +366,7 @@ let R_scalar_non_linear_3d: R^3 -> R, x -> 2 * exp(x[0] + x[1]) + 3 * x[2]; { std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); diff --git a/tests/test_DiscreteFunctionVectorInterpolerByZone.cpp b/tests/test_DiscreteFunctionVectorInterpolerByZone.cpp index c3605a232c7b032ad4215db72cdf711695818c6e..2fe9849341741d0483202621f40cb45dbc4acc81 100644 --- a/tests/test_DiscreteFunctionVectorInterpolerByZone.cpp +++ b/tests/test_DiscreteFunctionVectorInterpolerByZone.cpp @@ -22,6 +22,7 @@ #include <scheme/DiscreteFunctionDescriptorP0Vector.hpp> #include <scheme/DiscreteFunctionP0Vector.hpp> +#include <scheme/DiscreteFunctionVariant.hpp> #include <scheme/DiscreteFunctionVectorInterpoler.hpp> #include <pegtl/string_input.hpp> @@ -105,7 +106,7 @@ let R_scalar_non_linear_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3; DiscreteFunctionVectorInterpoler interpoler(mesh_1d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0Vector>(), function_id_list); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); size_t i = 0; @@ -121,8 +122,8 @@ let R_scalar_non_linear_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3; } }); - REQUIRE(same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE( + same_cell_value(cell_value, i++, discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } { @@ -137,8 +138,8 @@ let R_scalar_non_linear_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3; } }); - REQUIRE(same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE( + same_cell_value(cell_value, i++, discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } { @@ -153,8 +154,8 @@ let R_scalar_non_linear_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3; } }); - REQUIRE(same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE( + same_cell_value(cell_value, i++, discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } { @@ -169,8 +170,8 @@ let R_scalar_non_linear_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3; } }); - REQUIRE(same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE( + same_cell_value(cell_value, i++, discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } REQUIRE(i == function_id_list.size()); @@ -230,7 +231,7 @@ let R_scalar_non_linear_2d: R^2 -> R, x -> 2 * exp(x[0] + x[1]) + 3; DiscreteFunctionVectorInterpoler interpoler(mesh_2d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0Vector>(), function_id_list); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); size_t i = 0; @@ -246,8 +247,8 @@ let R_scalar_non_linear_2d: R^2 -> R, x -> 2 * exp(x[0] + x[1]) + 3; } }); - REQUIRE(same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE( + same_cell_value(cell_value, i++, discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } { @@ -262,8 +263,8 @@ let R_scalar_non_linear_2d: R^2 -> R, x -> 2 * exp(x[0] + x[1]) + 3; } }); - REQUIRE(same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE( + same_cell_value(cell_value, i++, discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } { @@ -278,8 +279,8 @@ let R_scalar_non_linear_2d: R^2 -> R, x -> 2 * exp(x[0] + x[1]) + 3; } }); - REQUIRE(same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE( + same_cell_value(cell_value, i++, discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } { @@ -294,8 +295,8 @@ let R_scalar_non_linear_2d: R^2 -> R, x -> 2 * exp(x[0] + x[1]) + 3; } }); - REQUIRE(same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE( + same_cell_value(cell_value, i++, discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } REQUIRE(i == function_id_list.size()); @@ -355,7 +356,7 @@ let R_scalar_non_linear_3d: R^3 -> R, x -> 2 * exp(x[0] + x[1]) + 3 * x[2]; DiscreteFunctionVectorInterpoler interpoler(mesh_3d, zone_list, std::make_shared<DiscreteFunctionDescriptorP0Vector>(), function_id_list); - std::shared_ptr discrete_function = interpoler.interpolate(); + DiscreteFunctionVariant discrete_function = interpoler.interpolate(); size_t i = 0; @@ -371,8 +372,8 @@ let R_scalar_non_linear_3d: R^3 -> R, x -> 2 * exp(x[0] + x[1]) + 3 * x[2]; } }); - REQUIRE(same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE( + same_cell_value(cell_value, i++, discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } { @@ -387,8 +388,8 @@ let R_scalar_non_linear_3d: R^3 -> R, x -> 2 * exp(x[0] + x[1]) + 3 * x[2]; } }); - REQUIRE(same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE( + same_cell_value(cell_value, i++, discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } { @@ -403,8 +404,8 @@ let R_scalar_non_linear_3d: R^3 -> R, x -> 2 * exp(x[0] + x[1]) + 3 * x[2]; } }); - REQUIRE(same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE( + same_cell_value(cell_value, i++, discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } { @@ -419,8 +420,8 @@ let R_scalar_non_linear_3d: R^3 -> R, x -> 2 * exp(x[0] + x[1]) + 3 * x[2]; } }); - REQUIRE(same_cell_value(cell_value, i++, - dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*discrete_function))); + REQUIRE( + same_cell_value(cell_value, i++, discrete_function.get<DiscreteFunctionP0Vector<Dimension, const double>>())); } REQUIRE(i == function_id_list.size()); @@ -430,7 +431,7 @@ let R_scalar_non_linear_3d: R^3 -> R, x -> 2 * exp(x[0] + x[1]) + 3 * x[2]; { std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); diff --git a/tests/test_Dual1DConnectivityBuilder.cpp b/tests/test_Dual1DConnectivityBuilder.cpp index 2b194a92baa821d6da4bac1e6277aaea6c1ddb1b..b7a35abfc577d93f729a0befc166c16c04f47fd3 100644 --- a/tests/test_Dual1DConnectivityBuilder.cpp +++ b/tests/test_Dual1DConnectivityBuilder.cpp @@ -5,6 +5,7 @@ #include <mesh/DualConnectivityManager.hpp> #include <mesh/Connectivity.hpp> +#include <mesh/ConnectivityUtils.hpp> #include <mesh/ItemValueUtils.hpp> #include <mesh/Mesh.hpp> @@ -48,6 +49,8 @@ TEST_CASE("Dual1DConnectivityBuilder", "[mesh]") DualConnectivityManager::instance().getDual1DConnectivity(primal_connectivity); const ConnectivityType& dual_connectivity = *p_dual_1d_connectivity; + REQUIRE(checkConnectivityOrdering(dual_connectivity)); + REQUIRE(dual_connectivity.numberOfNodes() == 36); REQUIRE(dual_connectivity.numberOfCells() == 35); diff --git a/tests/test_EdgeIntegrator.cpp b/tests/test_EdgeIntegrator.cpp index 5dfccbc6c7427a2bd27634c49957209c61c6f3ce..46f4d423d933a97faeffcaa762cdd210e36a74d0 100644 --- a/tests/test_EdgeIntegrator.cpp +++ b/tests/test_EdgeIntegrator.cpp @@ -35,7 +35,7 @@ TEST_CASE("EdgeIntegrator", "[scheme]") mesh_list.push_back(std::make_pair("hybrid mesh", hybrid_mesh)); mesh_list.push_back(std::make_pair("diamond mesh", DualMeshManager::instance().getDiamondDualMesh(*hybrid_mesh))); - for (auto mesh_info : mesh_list) { + for (const auto& mesh_info : mesh_list) { auto mesh_name = mesh_info.first; auto mesh = mesh_info.second; @@ -284,7 +284,7 @@ TEST_CASE("EdgeIntegrator", "[scheme]") mesh_list.push_back(std::make_pair("hybrid mesh", hybrid_mesh)); mesh_list.push_back(std::make_pair("diamond mesh", DualMeshManager::instance().getDiamondDualMesh(*hybrid_mesh))); - for (auto mesh_info : mesh_list) { + for (const auto& mesh_info : mesh_list) { auto mesh_name = mesh_info.first; auto mesh = mesh_info.second; @@ -535,7 +535,7 @@ TEST_CASE("EdgeIntegrator", "[scheme]") mesh_list.push_back(std::make_pair("hybrid mesh", hybrid_mesh)); mesh_list.push_back(std::make_pair("diamond mesh", DualMeshManager::instance().getDiamondDualMesh(*hybrid_mesh))); - for (auto mesh_info : mesh_list) { + for (const auto& mesh_info : mesh_list) { auto mesh_name = mesh_info.first; auto mesh = mesh_info.second; diff --git a/tests/test_EmbeddedDiscreteFunctionMathFunctions.hpp b/tests/test_EmbeddedDiscreteFunctionMathFunctions.hpp new file mode 100644 index 0000000000000000000000000000000000000000..bfa17ffc7609a8a304ee5dd36b3574782fbba464 --- /dev/null +++ b/tests/test_EmbeddedDiscreteFunctionMathFunctions.hpp @@ -0,0 +1,93 @@ +#ifndef TEST_EMBEDDED_DISCRETE_FUNCTION_MATH_FUNCTIONS_HPP +#define TEST_EMBEDDED_DISCRETE_FUNCTION_MATH_FUNCTIONS_HPP + +#define CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(P_U, FCT, U_TYPE, FU_TYPE) \ + { \ + std::shared_ptr p_fu = ::FCT(P_U); \ + \ + REQUIRE(p_fu.use_count() > 0); \ + \ + const U_TYPE& u = P_U->get<U_TYPE>(); \ + const FU_TYPE& fu = p_fu->get<FU_TYPE>(); \ + \ + bool is_same = true; \ + auto values = u.cellValues(); \ + for (CellId cell_id = 0; cell_id < values.numberOfItems(); ++cell_id) { \ + using namespace std; \ + if (fu[cell_id] != FCT(values[cell_id])) { \ + is_same = false; \ + break; \ + } \ + } \ + \ + REQUIRE(is_same); \ + } + +#define CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(P_U, P_V, FCT, U_TYPE, V_TYPE, FUV_TYPE) \ + { \ + std::shared_ptr p_fuv = ::FCT(P_U, P_V); \ + \ + REQUIRE(p_fuv.use_count() > 0); \ + \ + const U_TYPE& u = P_U->get<U_TYPE>(); \ + const V_TYPE& v = P_V->get<V_TYPE>(); \ + const FUV_TYPE& fuv = p_fuv->get<FUV_TYPE>(); \ + \ + bool is_same = true; \ + auto u_values = u.cellValues(); \ + auto v_values = v.cellValues(); \ + for (CellId cell_id = 0; cell_id < values.numberOfItems(); ++cell_id) { \ + using namespace std; \ + if (fuv[cell_id] != FCT(u_values[cell_id], v_values[cell_id])) { \ + is_same = false; \ + break; \ + } \ + } \ + \ + REQUIRE(is_same); \ + } + +#define CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(P_U, V, FCT, U_TYPE, FUV_TYPE) \ + { \ + std::shared_ptr p_fuv = ::FCT(P_U, V); \ + \ + REQUIRE(p_fuv.use_count() > 0); \ + const U_TYPE& u = P_U->get<U_TYPE>(); \ + const FUV_TYPE& fuv = p_fuv->get<FUV_TYPE>(); \ + \ + bool is_same = true; \ + auto u_values = u.cellValues(); \ + for (CellId cell_id = 0; cell_id < values.numberOfItems(); ++cell_id) { \ + using namespace std; \ + if (fuv[cell_id] != FCT(u_values[cell_id], V)) { \ + is_same = false; \ + break; \ + } \ + } \ + \ + REQUIRE(is_same); \ + } + +#define CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(U, P_V, FCT, V_TYPE, FUV_TYPE) \ + { \ + std::shared_ptr p_fuv = ::FCT(U, P_V); \ + \ + REQUIRE(p_fuv.use_count() > 0); \ + \ + const V_TYPE& v = P_V->get<V_TYPE>(); \ + const FUV_TYPE& fuv = p_fuv->get<FUV_TYPE>(); \ + \ + bool is_same = true; \ + auto v_values = v.cellValues(); \ + for (CellId cell_id = 0; cell_id < values.numberOfItems(); ++cell_id) { \ + using namespace std; \ + if (fuv[cell_id] != FCT(U, v_values[cell_id])) { \ + is_same = false; \ + break; \ + } \ + } \ + \ + REQUIRE(is_same); \ + } + +#endif // TEST_EMBEDDED_DISCRETE_FUNCTION_MATH_FUNCTIONS_HPP diff --git a/tests/test_EmbeddedDiscreteFunctionMathFunctions1D.cpp b/tests/test_EmbeddedDiscreteFunctionMathFunctions1D.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ed0331dde90ba7270c0050a633a84982545a5e7b --- /dev/null +++ b/tests/test_EmbeddedDiscreteFunctionMathFunctions1D.cpp @@ -0,0 +1,715 @@ +#include <catch2/catch_test_macros.hpp> +#include <catch2/matchers/catch_matchers_all.hpp> + +#include <MeshDataBaseForTests.hpp> + +#include <scheme/DiscreteFunctionP0.hpp> + +#include <language/utils/EmbeddedDiscreteFunctionMathFunctions.hpp> +#include <scheme/DiscreteFunctionP0Vector.hpp> +#include <scheme/DiscreteFunctionVariant.hpp> + +#include <test_EmbeddedDiscreteFunctionMathFunctions.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("EmbeddedDiscreteFunctionVariantMathFunctions1D", "[scheme]") +{ + constexpr size_t Dimension = 1; + + using Rd = TinyVector<Dimension>; + + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); + + using DiscreteFunctionR = DiscreteFunctionP0<Dimension, const double>; + using DiscreteFunctionR1 = DiscreteFunctionP0<Dimension, const TinyVector<1>>; + using DiscreteFunctionR2 = DiscreteFunctionP0<Dimension, const TinyVector<2>>; + using DiscreteFunctionR3 = DiscreteFunctionP0<Dimension, const TinyVector<3>>; + using DiscreteFunctionR1x1 = DiscreteFunctionP0<Dimension, const TinyMatrix<1>>; + using DiscreteFunctionR2x2 = DiscreteFunctionP0<Dimension, const TinyMatrix<2>>; + using DiscreteFunctionR3x3 = DiscreteFunctionP0<Dimension, const TinyMatrix<3>>; + + using DiscreteFunctionVector = DiscreteFunctionP0Vector<Dimension, const double>; + + for (const auto& named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh = named_mesh.mesh(); + + std::shared_ptr other_mesh = + std::make_shared<Mesh<Connectivity<Dimension>>>(mesh->shared_connectivity(), mesh->xr()); + + CellValue<const Rd> xj = MeshDataManager::instance().getMeshData(*mesh).xj(); + + CellValue<double> values = [=] { + CellValue<double> build_values{mesh->connectivity()}; + parallel_for( + build_values.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.2 + std::cos(l2Norm(xj[cell_id])); }); + return build_values; + }(); + + CellValue<double> positive_values = [=] { + CellValue<double> build_values{mesh->connectivity()}; + parallel_for( + build_values.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 2 + std::sin(l2Norm(xj[cell_id])); }); + return build_values; + }(); + + CellValue<double> bounded_values = [=] { + CellValue<double> build_values{mesh->connectivity()}; + parallel_for( + build_values.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.9 * std::sin(l2Norm(xj[cell_id])); }); + return build_values; + }(); + + std::shared_ptr p_u = std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR(mesh, values)); + std::shared_ptr p_other_mesh_u = + std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR(other_mesh, values)); + std::shared_ptr p_positive_u = + std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR(mesh, positive_values)); + std::shared_ptr p_bounded_u = + std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR(mesh, bounded_values)); + + std::shared_ptr p_R1_u = [=] { + CellValue<TinyVector<1>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id][0] = 2 * xj[cell_id][0] + 1; }); + + return std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR1(mesh, uj)); + }(); + + std::shared_ptr p_R1_v = [=] { + CellValue<TinyVector<1>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { vj[cell_id][0] = xj[cell_id][0] * xj[cell_id][0] + 1; }); + + return std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR1(mesh, vj)); + }(); + + std::shared_ptr p_other_mesh_R1_u = std::make_shared<const DiscreteFunctionVariant>( + DiscreteFunctionR1(other_mesh, p_R1_u->get<DiscreteFunctionR1>().cellValues())); + + constexpr auto to_2d = [&](const TinyVector<Dimension>& x) -> TinyVector<2> { + if constexpr (Dimension == 1) { + return TinyVector<2>{x[0], 1 + x[0] * x[0]}; + } else if constexpr (Dimension == 2) { + return TinyVector<2>{x[0], x[1]}; + } else if constexpr (Dimension == 3) { + return TinyVector<2>{x[0], x[1] + x[2]}; + } + }; + + std::shared_ptr p_R2_u = [=] { + CellValue<TinyVector<2>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + uj[cell_id] = TinyVector<2>{2 * x[0] + 1, 1 - x[1]}; + }); + + return std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR2(mesh, uj)); + }(); + + std::shared_ptr p_R2_v = [=] { + CellValue<TinyVector<2>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + vj[cell_id] = TinyVector<2>{x[0] * x[1] + 1, 2 * x[1]}; + }); + + return std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR2(mesh, vj)); + }(); + + std::shared_ptr p_other_mesh_R2_u = std::make_shared<const DiscreteFunctionVariant>( + DiscreteFunctionR2(other_mesh, p_R2_u->get<DiscreteFunctionR2>().cellValues())); + + constexpr auto to_3d = [&](const TinyVector<Dimension>& x) -> TinyVector<3> { + if constexpr (Dimension == 1) { + return TinyVector<3>{x[0], 1 + x[0] * x[0], 2 - x[0]}; + } else if constexpr (Dimension == 2) { + return TinyVector<3>{x[0], x[1], x[0] + x[1]}; + } else if constexpr (Dimension == 3) { + return TinyVector<3>{x[0], x[1], x[2]}; + } + }; + + std::shared_ptr p_R3_u = [=] { + CellValue<TinyVector<3>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + uj[cell_id] = TinyVector<3>{2 * x[0] + 1, 1 - x[1] * x[2], x[0] + x[2]}; + }); + + return std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR3(mesh, uj)); + }(); + + std::shared_ptr p_R3_v = [=] { + CellValue<TinyVector<3>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + vj[cell_id] = TinyVector<3>{x[0] * x[1] + 1, 2 * x[1], x[2] * x[0]}; + }); + + return std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR3(mesh, vj)); + }(); + + std::shared_ptr p_other_mesh_R3_u = std::make_shared<const DiscreteFunctionVariant>( + DiscreteFunctionR3(other_mesh, p_R3_u->get<DiscreteFunctionR3>().cellValues())); + + std::shared_ptr p_R1x1_u = [=] { + CellValue<TinyMatrix<1>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { uj[cell_id] = TinyMatrix<1>{2 * xj[cell_id][0] + 1}; }); + + return std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR1x1(mesh, uj)); + }(); + + std::shared_ptr p_R2x2_u = [=] { + CellValue<TinyMatrix<2>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + + uj[cell_id] = TinyMatrix<2>{2 * x[0] + 1, 1 - x[1], // + 2 * x[1], -x[0]}; + }); + + return std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR2x2(mesh, uj)); + }(); + + std::shared_ptr p_R3x3_u = [=] { + CellValue<TinyMatrix<3>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + + uj[cell_id] = TinyMatrix<3>{2 * x[0] + 1, 1 - x[1], 3, // + 2 * x[1], -x[0], x[0] - x[1], // + 3 * x[2] - x[1], x[1] - 2 * x[2], x[2] - x[0]}; + }); + + return std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR3x3(mesh, uj)); + }(); + + std::shared_ptr p_Vector3_u = [=] { + CellArray<double> uj_vector{mesh->connectivity(), 3}; + parallel_for( + uj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + uj_vector[cell_id][0] = 2 * x[0] + 1; + uj_vector[cell_id][1] = 1 - x[1] * x[2]; + uj_vector[cell_id][2] = x[0] + x[2]; + }); + + return std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionVector(mesh, uj_vector)); + }(); + + std::shared_ptr p_Vector3_v = [=] { + CellArray<double> vj_vector{mesh->connectivity(), 3}; + parallel_for( + vj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + vj_vector[cell_id][0] = x[0] * x[1] + 1; + vj_vector[cell_id][1] = 2 * x[1]; + vj_vector[cell_id][2] = x[2] * x[0]; + }); + + return std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionVector(mesh, vj_vector)); + }(); + + std::shared_ptr p_Vector2_w = [=] { + CellArray<double> wj_vector{mesh->connectivity(), 2}; + parallel_for( + wj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + wj_vector[cell_id][0] = x[0] + x[1] * 2; + wj_vector[cell_id][1] = x[0] * x[1]; + }); + + return std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionVector(mesh, wj_vector)); + }(); + + SECTION("sqrt Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_positive_u, sqrt, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(sqrt(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("abs Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_u, abs, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(abs(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("sin Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_u, sin, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(sin(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("cos Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_u, cos, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(cos(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("tan Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_u, tan, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(tan(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("asin Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_bounded_u, asin, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(asin(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("acos Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_bounded_u, acos, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(acos(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("atan Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_bounded_u, atan, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(atan(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("sinh Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_u, sinh, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(sinh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("cosh Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_u, cosh, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(cosh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("tanh Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_u, tanh, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(tanh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("asinh Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_positive_u, asinh, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(asinh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("acosh Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_positive_u, acosh, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(acosh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("atanh Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_bounded_u, atanh, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(atanh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("exp Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_u, exp, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(exp(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("log Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_positive_u, log, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(log(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("atan2 Vh*Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_positive_u, p_bounded_u, atan2, // + DiscreteFunctionR, DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(atan2(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(atan2(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); + REQUIRE_THROWS_WITH(atan2(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); + } + + SECTION("atan2 Vh*R -> Vh") + { + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_u, 3.6, atan2, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(atan2(p_R1_u, 2.1), "error: incompatible operand types Vh(P0:R^1) and R"); + } + + SECTION("atan2 R*Vh -> Vh") + { + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(2.4, p_u, atan2, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(atan2(2.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); + } + + SECTION("min Vh*Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_u, p_bounded_u, min, // + DiscreteFunctionR, DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(::min(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(::min(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(::min(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); + } + + SECTION("min Vh*R -> Vh") + { + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_u, 1.2, min, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(min(p_R1_u, 2.1), "error: incompatible operand types Vh(P0:R^1) and R"); + } + + SECTION("min R*Vh -> Vh") + { + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(0.4, p_u, min, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(min(3.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); + } + + SECTION("min Vh -> R") + { + REQUIRE(min(p_u) == min(p_u->get<DiscreteFunctionR>().cellValues())); + REQUIRE_THROWS_WITH(min(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("max Vh*Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_u, p_bounded_u, max, // + DiscreteFunctionR, DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(::max(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(::max(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(::max(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); + } + + SECTION("max Vh*R -> Vh") + { + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_u, 1.2, max, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(max(p_R1_u, 2.1), "error: incompatible operand types Vh(P0:R^1) and R"); + } + + SECTION("max Vh -> R") + { + REQUIRE(max(p_u) == max(p_u->get<DiscreteFunctionR>().cellValues())); + REQUIRE_THROWS_WITH(max(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("max R*Vh -> Vh") + { + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(0.4, p_u, max, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(max(3.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); + } + + SECTION("pow Vh*Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_positive_u, p_bounded_u, pow, // + DiscreteFunctionR, DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(pow(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(pow(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(pow(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); + } + + SECTION("pow Vh*R -> Vh") + { + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_positive_u, 3.3, pow, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(pow(p_R1_u, 3.1), "error: incompatible operand types Vh(P0:R^1) and R"); + } + + SECTION("pow R*Vh -> Vh") + { + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(2.1, p_u, pow, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(pow(3.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); + } + + SECTION("dot Vh*Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R1_u, p_R1_v, dot, // + DiscreteFunctionR1, DiscreteFunctionR1, DiscreteFunctionR); + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R2_u, p_R2_v, dot, // + DiscreteFunctionR2, DiscreteFunctionR2, DiscreteFunctionR); + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R3_u, p_R3_v, dot, // + DiscreteFunctionR3, DiscreteFunctionR3, DiscreteFunctionR); + + { + std::shared_ptr p_fuv = ::dot(p_Vector3_u, p_Vector3_v); + + REQUIRE(p_fuv.use_count() > 0); + + const DiscreteFunctionVector& u = p_Vector3_u->get<DiscreteFunctionVector>(); + const DiscreteFunctionVector& v = p_Vector3_v->get<DiscreteFunctionVector>(); + const DiscreteFunctionR& fuv = p_fuv->get<DiscreteFunctionR>(); + + bool is_same = true; + auto u_arrays = u.cellArrays(); + auto v_arrays = v.cellArrays(); + for (CellId cell_id = 0; cell_id < values.numberOfItems(); ++cell_id) { + using namespace std; + double dot_u_v = [&](auto&& a, auto&& b) { + double sum = 0; + for (size_t i = 0; i < a.size(); ++i) { + sum += a[i] * b[i]; + } + return sum; + }(u_arrays[cell_id], v_arrays[cell_id]); + if (fuv[cell_id] != dot_u_v) { + is_same = false; + break; + } + } + + REQUIRE(is_same); + } + + REQUIRE_THROWS_WITH(dot(p_R1_u, p_other_mesh_R1_u), "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(dot(p_R2_u, p_other_mesh_R2_u), "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(dot(p_R3_u, p_other_mesh_R3_u), "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(dot(p_R1_u, p_R3_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^3)"); + REQUIRE_THROWS_WITH(dot(p_Vector3_u, p_Vector2_w), "error: operands have different dimension"); + } + + SECTION("det Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R1x1_u, det, // + DiscreteFunctionR1x1, DiscreteFunctionR); + + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R2x2_u, det, // + DiscreteFunctionR2x2, DiscreteFunctionR); + + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R3x3_u, det, // + DiscreteFunctionR3x3, DiscreteFunctionR); + + REQUIRE_THROWS_WITH(det(p_u), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(det(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(det(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(det(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); + } + + SECTION("trace Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R1x1_u, trace, // + DiscreteFunctionR1x1, DiscreteFunctionR); + + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R2x2_u, trace, // + DiscreteFunctionR2x2, DiscreteFunctionR); + + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R3x3_u, trace, // + DiscreteFunctionR3x3, DiscreteFunctionR); + + REQUIRE_THROWS_WITH(trace(p_u), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(trace(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(trace(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(trace(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); + } + + SECTION("inverse Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R1x1_u, inverse, // + DiscreteFunctionR1x1, DiscreteFunctionR1x1); + + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R2x2_u, inverse, // + DiscreteFunctionR2x2, DiscreteFunctionR2x2); + + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R3x3_u, inverse, // + DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + REQUIRE_THROWS_WITH(inverse(p_u), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(inverse(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(inverse(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(inverse(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); + } + + SECTION("transpose Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R1x1_u, transpose, // + DiscreteFunctionR1x1, DiscreteFunctionR1x1); + + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R2x2_u, transpose, // + DiscreteFunctionR2x2, DiscreteFunctionR2x2); + + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R3x3_u, transpose, // + DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + REQUIRE_THROWS_WITH(transpose(p_u), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(transpose(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(transpose(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(transpose(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); + } + + SECTION("sum_of_Vh Vh -> Vh") + { + { + auto p_sum_components = sum_of_Vh_components(p_Vector3_u); + REQUIRE(p_sum_components.use_count() == 1); + + const DiscreteFunctionR& sum_components = p_sum_components->get<DiscreteFunctionR>(); + const DiscreteFunctionVector& vector3_u = p_Vector3_u->get<DiscreteFunctionVector>(); + DiscreteFunctionP0<Dimension, double> direct_sum(mesh); + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { + double sum = 0; + for (size_t i = 0; i < vector3_u.size(); ++i) { + sum += vector3_u[cell_id][i]; + } + + direct_sum[cell_id] = sum; + } + + bool is_same = true; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { + if (sum_components[cell_id] != direct_sum[cell_id]) { + is_same = false; + break; + } + } + + REQUIRE(is_same); + } + + REQUIRE_THROWS_WITH(sum_of_Vh_components(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); + } + + SECTION("vectorize (Vh) -> Vh") + { + { + std::shared_ptr p_vector3 = vectorize(std::vector{p_u, p_positive_u, p_bounded_u}); + REQUIRE(p_vector3.use_count() == 1); + + const DiscreteFunctionVector vector3 = p_vector3->get<DiscreteFunctionVector>(); + + const DiscreteFunctionR& u = p_u->get<DiscreteFunctionR>(); + const DiscreteFunctionR& positive_u = p_positive_u->get<DiscreteFunctionR>(); + const DiscreteFunctionR& bounded_u = p_bounded_u->get<DiscreteFunctionR>(); + + REQUIRE(vector3.size() == 3); + + bool is_same = true; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { + is_same &= (u[cell_id] == vector3[cell_id][0]); + is_same &= (positive_u[cell_id] == vector3[cell_id][1]); + is_same &= (bounded_u[cell_id] == vector3[cell_id][2]); + } + REQUIRE(is_same); + } + + REQUIRE_THROWS_WITH(vectorize(std::vector{p_u, p_other_mesh_u}), + "error: discrete functions are not defined on the same mesh"); + REQUIRE_THROWS_WITH(vectorize(std::vector{p_R1_u}), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("dot Vh*Rd -> Vh") + { + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R1_u, (TinyVector<1>{3}), dot, // + DiscreteFunctionR1, DiscreteFunctionR); + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R2_u, (TinyVector<2>{-6, 2}), dot, // + DiscreteFunctionR2, DiscreteFunctionR); + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R3_u, (TinyVector<3>{-1, 5, 2}), dot, // + DiscreteFunctionR3, DiscreteFunctionR); + REQUIRE_THROWS_WITH(dot(p_R1_u, (TinyVector<2>{-6, 2})), + "error: incompatible operand types Vh(P0:R^1) and R^2"); + REQUIRE_THROWS_WITH(dot(p_R2_u, (TinyVector<3>{-1, 5, 2})), + "error: incompatible operand types Vh(P0:R^2) and R^3"); + REQUIRE_THROWS_WITH(dot(p_R3_u, (TinyVector<1>{-1})), "error: incompatible operand types Vh(P0:R^3) and R^1"); + } + + SECTION("dot Rd*Vh -> Vh") + { + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<1>{3}), p_R1_u, dot, // + DiscreteFunctionR1, DiscreteFunctionR); + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<2>{-6, 2}), p_R2_u, dot, // + DiscreteFunctionR2, DiscreteFunctionR); + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<3>{-1, 5, 2}), p_R3_u, dot, // + DiscreteFunctionR3, DiscreteFunctionR); + REQUIRE_THROWS_WITH(dot((TinyVector<2>{-6, 2}), p_R1_u), + "error: incompatible operand types R^2 and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(dot((TinyVector<3>{-1, 5, 2}), p_R2_u), + "error: incompatible operand types R^3 and Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(dot((TinyVector<1>{-1}), p_R3_u), "error: incompatible operand types R^1 and Vh(P0:R^3)"); + } + + SECTION("sum_of_R* Vh -> R*") + { + REQUIRE(sum_of<double>(p_u) == sum(p_u->get<DiscreteFunctionR>().cellValues())); + REQUIRE(sum_of<TinyVector<1>>(p_R1_u) == sum(p_R1_u->get<DiscreteFunctionR1>().cellValues())); + REQUIRE(sum_of<TinyVector<2>>(p_R2_u) == sum(p_R2_u->get<DiscreteFunctionR2>().cellValues())); + REQUIRE(sum_of<TinyVector<3>>(p_R3_u) == sum(p_R3_u->get<DiscreteFunctionR3>().cellValues())); + REQUIRE(sum_of<TinyMatrix<1>>(p_R1x1_u) == sum(p_R1x1_u->get<DiscreteFunctionR1x1>().cellValues())); + REQUIRE(sum_of<TinyMatrix<2>>(p_R2x2_u) == sum(p_R2x2_u->get<DiscreteFunctionR2x2>().cellValues())); + REQUIRE(sum_of<TinyMatrix<3>>(p_R3x3_u) == sum(p_R3x3_u->get<DiscreteFunctionR3x3>().cellValues())); + + REQUIRE_THROWS_WITH(sum_of<TinyVector<1>>(p_u), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(sum_of<double>(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(sum_of<double>(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(sum_of<double>(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); + REQUIRE_THROWS_WITH(sum_of<double>(p_R1x1_u), "error: invalid operand type Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(sum_of<double>(p_R2x2_u), "error: invalid operand type Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(sum_of<double>(p_R3x3_u), "error: invalid operand type Vh(P0:R^3x3)"); + } + + SECTION("integral_of_R* Vh -> R*") + { + auto integrate_locally = [&](const auto& cell_values) { + const auto& Vj = MeshDataManager::instance().getMeshData(*mesh).Vj(); + using DataType = decltype(double{} * cell_values[CellId{0}]); + CellValue<DataType> local_integral{mesh->connectivity()}; + parallel_for( + local_integral.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { local_integral[cell_id] = Vj[cell_id] * cell_values[cell_id]; }); + return local_integral; + }; + + REQUIRE(integral_of<double>(p_u) == sum(integrate_locally(p_u->get<DiscreteFunctionR>().cellValues()))); + REQUIRE(integral_of<TinyVector<1>>(p_R1_u) == + sum(integrate_locally(p_R1_u->get<DiscreteFunctionR1>().cellValues()))); + REQUIRE(integral_of<TinyVector<2>>(p_R2_u) == + sum(integrate_locally(p_R2_u->get<DiscreteFunctionR2>().cellValues()))); + REQUIRE(integral_of<TinyVector<3>>(p_R3_u) == + sum(integrate_locally(p_R3_u->get<DiscreteFunctionR3>().cellValues()))); + REQUIRE(integral_of<TinyMatrix<1>>(p_R1x1_u) == + sum(integrate_locally(p_R1x1_u->get<DiscreteFunctionR1x1>().cellValues()))); + REQUIRE(integral_of<TinyMatrix<2>>(p_R2x2_u) == + sum(integrate_locally(p_R2x2_u->get<DiscreteFunctionR2x2>().cellValues()))); + REQUIRE(integral_of<TinyMatrix<3>>(p_R3x3_u) == + sum(integrate_locally(p_R3x3_u->get<DiscreteFunctionR3x3>().cellValues()))); + + REQUIRE_THROWS_WITH(integral_of<TinyVector<1>>(p_u), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(integral_of<double>(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(integral_of<double>(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(integral_of<double>(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); + REQUIRE_THROWS_WITH(integral_of<double>(p_R1x1_u), "error: invalid operand type Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(integral_of<double>(p_R2x2_u), "error: invalid operand type Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(integral_of<double>(p_R3x3_u), "error: invalid operand type Vh(P0:R^3x3)"); + } + } + } +} diff --git a/tests/test_EmbeddedDiscreteFunctionMathFunctions2D.cpp b/tests/test_EmbeddedDiscreteFunctionMathFunctions2D.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dfbdb01500b08f73dd9804d4d4581aafe4c4ba63 --- /dev/null +++ b/tests/test_EmbeddedDiscreteFunctionMathFunctions2D.cpp @@ -0,0 +1,718 @@ +#include <catch2/catch_test_macros.hpp> +#include <catch2/matchers/catch_matchers_all.hpp> + +#include <MeshDataBaseForTests.hpp> + +#include <scheme/DiscreteFunctionP0.hpp> + +#include <language/utils/EmbeddedDiscreteFunctionMathFunctions.hpp> +#include <scheme/DiscreteFunctionP0Vector.hpp> +#include <scheme/DiscreteFunctionVariant.hpp> + +#include <test_EmbeddedDiscreteFunctionMathFunctions.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("EmbeddedDiscreteFunctionVariantMathFunctions2D", "[scheme]") +{ + SECTION("2D") + { + constexpr size_t Dimension = 2; + + using Rd = TinyVector<Dimension>; + + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); + + using DiscreteFunctionR = DiscreteFunctionP0<Dimension, const double>; + using DiscreteFunctionR1 = DiscreteFunctionP0<Dimension, const TinyVector<1>>; + using DiscreteFunctionR2 = DiscreteFunctionP0<Dimension, const TinyVector<2>>; + using DiscreteFunctionR3 = DiscreteFunctionP0<Dimension, const TinyVector<3>>; + using DiscreteFunctionR1x1 = DiscreteFunctionP0<Dimension, const TinyMatrix<1>>; + using DiscreteFunctionR2x2 = DiscreteFunctionP0<Dimension, const TinyMatrix<2>>; + using DiscreteFunctionR3x3 = DiscreteFunctionP0<Dimension, const TinyMatrix<3>>; + + using DiscreteFunctionVector = DiscreteFunctionP0Vector<Dimension, const double>; + + for (const auto& named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh = named_mesh.mesh(); + + std::shared_ptr other_mesh = + std::make_shared<Mesh<Connectivity<Dimension>>>(mesh->shared_connectivity(), mesh->xr()); + + CellValue<const Rd> xj = MeshDataManager::instance().getMeshData(*mesh).xj(); + + CellValue<double> values = [=] { + CellValue<double> build_values{mesh->connectivity()}; + parallel_for( + build_values.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.2 + std::cos(l2Norm(xj[cell_id])); }); + return build_values; + }(); + + CellValue<double> positive_values = [=] { + CellValue<double> build_values{mesh->connectivity()}; + parallel_for( + build_values.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 2 + std::sin(l2Norm(xj[cell_id])); }); + return build_values; + }(); + + CellValue<double> bounded_values = [=] { + CellValue<double> build_values{mesh->connectivity()}; + parallel_for( + build_values.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.9 * std::sin(l2Norm(xj[cell_id])); }); + return build_values; + }(); + + std::shared_ptr p_u = std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR(mesh, values)); + std::shared_ptr p_other_mesh_u = + std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR(other_mesh, values)); + std::shared_ptr p_positive_u = + std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR(mesh, positive_values)); + std::shared_ptr p_bounded_u = + std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR(mesh, bounded_values)); + + std::shared_ptr p_R1_u = [=] { + CellValue<TinyVector<1>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id][0] = 2 * xj[cell_id][0] + 1; }); + + return std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR1(mesh, uj)); + }(); + + std::shared_ptr p_R1_v = [=] { + CellValue<TinyVector<1>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { vj[cell_id][0] = xj[cell_id][0] * xj[cell_id][0] + 1; }); + + return std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR1(mesh, vj)); + }(); + + std::shared_ptr p_other_mesh_R1_u = std::make_shared<const DiscreteFunctionVariant>( + DiscreteFunctionR1(other_mesh, p_R1_u->get<DiscreteFunctionR1>().cellValues())); + + constexpr auto to_2d = [&](const TinyVector<Dimension>& x) -> TinyVector<2> { + if constexpr (Dimension == 1) { + return TinyVector<2>{x[0], 1 + x[0] * x[0]}; + } else if constexpr (Dimension == 2) { + return TinyVector<2>{x[0], x[1]}; + } else if constexpr (Dimension == 3) { + return TinyVector<2>{x[0], x[1] + x[2]}; + } + }; + + std::shared_ptr p_R2_u = [=] { + CellValue<TinyVector<2>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + uj[cell_id] = TinyVector<2>{2 * x[0] + 1, 1 - x[1]}; + }); + + return std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR2(mesh, uj)); + }(); + + std::shared_ptr p_R2_v = [=] { + CellValue<TinyVector<2>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + vj[cell_id] = TinyVector<2>{x[0] * x[1] + 1, 2 * x[1]}; + }); + + return std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR2(mesh, vj)); + }(); + + std::shared_ptr p_other_mesh_R2_u = std::make_shared<const DiscreteFunctionVariant>( + DiscreteFunctionR2(other_mesh, p_R2_u->get<DiscreteFunctionR2>().cellValues())); + + constexpr auto to_3d = [&](const TinyVector<Dimension>& x) -> TinyVector<3> { + if constexpr (Dimension == 1) { + return TinyVector<3>{x[0], 1 + x[0] * x[0], 2 - x[0]}; + } else if constexpr (Dimension == 2) { + return TinyVector<3>{x[0], x[1], x[0] + x[1]}; + } else if constexpr (Dimension == 3) { + return TinyVector<3>{x[0], x[1], x[2]}; + } + }; + + std::shared_ptr p_R3_u = [=] { + CellValue<TinyVector<3>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + uj[cell_id] = TinyVector<3>{2 * x[0] + 1, 1 - x[1] * x[2], x[0] + x[2]}; + }); + + return std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR3(mesh, uj)); + }(); + + std::shared_ptr p_R3_v = [=] { + CellValue<TinyVector<3>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + vj[cell_id] = TinyVector<3>{x[0] * x[1] + 1, 2 * x[1], x[2] * x[0]}; + }); + + return std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR3(mesh, vj)); + }(); + + std::shared_ptr p_other_mesh_R3_u = std::make_shared<const DiscreteFunctionVariant>( + DiscreteFunctionR3(other_mesh, p_R3_u->get<DiscreteFunctionR3>().cellValues())); + + std::shared_ptr p_R1x1_u = [=] { + CellValue<TinyMatrix<1>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { uj[cell_id] = TinyMatrix<1>{2 * xj[cell_id][0] + 1}; }); + + return std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR1x1(mesh, uj)); + }(); + + std::shared_ptr p_R2x2_u = [=] { + CellValue<TinyMatrix<2>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + + uj[cell_id] = TinyMatrix<2>{2 * x[0] + 1, 1 - x[1], // + 2 * x[1], -x[0]}; + }); + + return std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR2x2(mesh, uj)); + }(); + + std::shared_ptr p_R3x3_u = [=] { + CellValue<TinyMatrix<3>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + + uj[cell_id] = TinyMatrix<3>{2 * x[0] + 1, 1 - x[1], 3, // + 2 * x[1], -x[0], x[0] - x[1], // + 3 * x[2] - x[1], x[1] - 2 * x[2], x[2] - x[0]}; + }); + + return std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR3x3(mesh, uj)); + }(); + + std::shared_ptr p_Vector3_u = [=] { + CellArray<double> uj_vector{mesh->connectivity(), 3}; + parallel_for( + uj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + uj_vector[cell_id][0] = 2 * x[0] + 1; + uj_vector[cell_id][1] = 1 - x[1] * x[2]; + uj_vector[cell_id][2] = x[0] + x[2]; + }); + + return std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionVector(mesh, uj_vector)); + }(); + + std::shared_ptr p_Vector3_v = [=] { + CellArray<double> vj_vector{mesh->connectivity(), 3}; + parallel_for( + vj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + vj_vector[cell_id][0] = x[0] * x[1] + 1; + vj_vector[cell_id][1] = 2 * x[1]; + vj_vector[cell_id][2] = x[2] * x[0]; + }); + + return std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionVector(mesh, vj_vector)); + }(); + + std::shared_ptr p_Vector2_w = [=] { + CellArray<double> wj_vector{mesh->connectivity(), 2}; + parallel_for( + wj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + wj_vector[cell_id][0] = x[0] + x[1] * 2; + wj_vector[cell_id][1] = x[0] * x[1]; + }); + + return std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionVector(mesh, wj_vector)); + }(); + + SECTION("sqrt Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_positive_u, sqrt, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(sqrt(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("abs Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_u, abs, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(abs(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("sin Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_u, sin, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(sin(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("cos Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_u, cos, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(cos(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("tan Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_u, tan, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(tan(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("asin Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_bounded_u, asin, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(asin(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("acos Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_bounded_u, acos, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(acos(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("atan Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_bounded_u, atan, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(atan(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("sinh Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_u, sinh, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(sinh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("cosh Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_u, cosh, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(cosh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("tanh Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_u, tanh, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(tanh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("asinh Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_positive_u, asinh, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(asinh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("acosh Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_positive_u, acosh, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(acosh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("atanh Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_bounded_u, atanh, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(atanh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("exp Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_u, exp, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(exp(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("log Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_positive_u, log, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(log(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("atan2 Vh*Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_positive_u, p_bounded_u, atan2, // + DiscreteFunctionR, DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(atan2(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(atan2(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); + REQUIRE_THROWS_WITH(atan2(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); + } + + SECTION("atan2 Vh*R -> Vh") + { + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_u, 3.6, atan2, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(atan2(p_R1_u, 2.1), "error: incompatible operand types Vh(P0:R^1) and R"); + } + + SECTION("atan2 R*Vh -> Vh") + { + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(2.4, p_u, atan2, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(atan2(2.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); + } + + SECTION("min Vh*Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_u, p_bounded_u, min, // + DiscreteFunctionR, DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(::min(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(::min(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(::min(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); + } + + SECTION("min Vh*R -> Vh") + { + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_u, 1.2, min, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(min(p_R1_u, 2.1), "error: incompatible operand types Vh(P0:R^1) and R"); + } + + SECTION("min R*Vh -> Vh") + { + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(0.4, p_u, min, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(min(3.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); + } + + SECTION("min Vh -> R") + { + REQUIRE(min(p_u) == min(p_u->get<DiscreteFunctionR>().cellValues())); + REQUIRE_THROWS_WITH(min(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("max Vh*Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_u, p_bounded_u, max, // + DiscreteFunctionR, DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(::max(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(::max(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(::max(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); + } + + SECTION("max Vh*R -> Vh") + { + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_u, 1.2, max, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(max(p_R1_u, 2.1), "error: incompatible operand types Vh(P0:R^1) and R"); + } + + SECTION("max Vh -> R") + { + REQUIRE(max(p_u) == max(p_u->get<DiscreteFunctionR>().cellValues())); + REQUIRE_THROWS_WITH(max(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("max R*Vh -> Vh") + { + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(0.4, p_u, max, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(max(3.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); + } + + SECTION("pow Vh*Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_positive_u, p_bounded_u, pow, // + DiscreteFunctionR, DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(pow(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(pow(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(pow(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); + } + + SECTION("pow Vh*R -> Vh") + { + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_positive_u, 3.3, pow, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(pow(p_R1_u, 3.1), "error: incompatible operand types Vh(P0:R^1) and R"); + } + + SECTION("pow R*Vh -> Vh") + { + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(2.1, p_u, pow, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(pow(3.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); + } + + SECTION("dot Vh*Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R1_u, p_R1_v, dot, // + DiscreteFunctionR1, DiscreteFunctionR1, DiscreteFunctionR); + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R2_u, p_R2_v, dot, // + DiscreteFunctionR2, DiscreteFunctionR2, DiscreteFunctionR); + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R3_u, p_R3_v, dot, // + DiscreteFunctionR3, DiscreteFunctionR3, DiscreteFunctionR); + + { + std::shared_ptr p_fuv = ::dot(p_Vector3_u, p_Vector3_v); + + REQUIRE(p_fuv.use_count() > 0); + + const DiscreteFunctionVector& u = p_Vector3_u->get<DiscreteFunctionVector>(); + const DiscreteFunctionVector& v = p_Vector3_v->get<DiscreteFunctionVector>(); + const DiscreteFunctionR& fuv = p_fuv->get<DiscreteFunctionR>(); + + bool is_same = true; + auto u_arrays = u.cellArrays(); + auto v_arrays = v.cellArrays(); + for (CellId cell_id = 0; cell_id < values.numberOfItems(); ++cell_id) { + using namespace std; + double dot_u_v = [&](auto&& a, auto&& b) { + double sum = 0; + for (size_t i = 0; i < a.size(); ++i) { + sum += a[i] * b[i]; + } + return sum; + }(u_arrays[cell_id], v_arrays[cell_id]); + if (fuv[cell_id] != dot_u_v) { + is_same = false; + break; + } + } + + REQUIRE(is_same); + } + + REQUIRE_THROWS_WITH(dot(p_R1_u, p_other_mesh_R1_u), "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(dot(p_R2_u, p_other_mesh_R2_u), "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(dot(p_R3_u, p_other_mesh_R3_u), "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(dot(p_R1_u, p_R3_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^3)"); + REQUIRE_THROWS_WITH(dot(p_Vector3_u, p_Vector2_w), "error: operands have different dimension"); + } + + SECTION("det Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R1x1_u, det, // + DiscreteFunctionR1x1, DiscreteFunctionR); + + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R2x2_u, det, // + DiscreteFunctionR2x2, DiscreteFunctionR); + + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R3x3_u, det, // + DiscreteFunctionR3x3, DiscreteFunctionR); + + REQUIRE_THROWS_WITH(det(p_u), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(det(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(det(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(det(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); + } + + SECTION("trace Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R1x1_u, trace, // + DiscreteFunctionR1x1, DiscreteFunctionR); + + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R2x2_u, trace, // + DiscreteFunctionR2x2, DiscreteFunctionR); + + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R3x3_u, trace, // + DiscreteFunctionR3x3, DiscreteFunctionR); + + REQUIRE_THROWS_WITH(trace(p_u), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(trace(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(trace(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(trace(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); + } + + SECTION("inverse Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R1x1_u, inverse, // + DiscreteFunctionR1x1, DiscreteFunctionR1x1); + + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R2x2_u, inverse, // + DiscreteFunctionR2x2, DiscreteFunctionR2x2); + + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R3x3_u, inverse, // + DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + REQUIRE_THROWS_WITH(inverse(p_u), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(inverse(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(inverse(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(inverse(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); + } + + SECTION("transpose Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R1x1_u, transpose, // + DiscreteFunctionR1x1, DiscreteFunctionR1x1); + + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R2x2_u, transpose, // + DiscreteFunctionR2x2, DiscreteFunctionR2x2); + + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R3x3_u, transpose, // + DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + REQUIRE_THROWS_WITH(transpose(p_u), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(transpose(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(transpose(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(transpose(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); + } + + SECTION("sum_of_Vh Vh -> Vh") + { + { + auto p_sum_components = sum_of_Vh_components(p_Vector3_u); + REQUIRE(p_sum_components.use_count() == 1); + + const DiscreteFunctionR& sum_components = p_sum_components->get<DiscreteFunctionR>(); + const DiscreteFunctionVector& vector3_u = p_Vector3_u->get<DiscreteFunctionVector>(); + DiscreteFunctionP0<Dimension, double> direct_sum(mesh); + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { + double sum = 0; + for (size_t i = 0; i < vector3_u.size(); ++i) { + sum += vector3_u[cell_id][i]; + } + + direct_sum[cell_id] = sum; + } + + bool is_same = true; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { + if (sum_components[cell_id] != direct_sum[cell_id]) { + is_same = false; + break; + } + } + + REQUIRE(is_same); + } + + REQUIRE_THROWS_WITH(sum_of_Vh_components(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); + } + + SECTION("vectorize (Vh) -> Vh") + { + { + std::shared_ptr p_vector3 = vectorize(std::vector{p_u, p_positive_u, p_bounded_u}); + REQUIRE(p_vector3.use_count() == 1); + + const DiscreteFunctionVector vector3 = p_vector3->get<DiscreteFunctionVector>(); + + const DiscreteFunctionR& u = p_u->get<DiscreteFunctionR>(); + const DiscreteFunctionR& positive_u = p_positive_u->get<DiscreteFunctionR>(); + const DiscreteFunctionR& bounded_u = p_bounded_u->get<DiscreteFunctionR>(); + + REQUIRE(vector3.size() == 3); + + bool is_same = true; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { + is_same &= (u[cell_id] == vector3[cell_id][0]); + is_same &= (positive_u[cell_id] == vector3[cell_id][1]); + is_same &= (bounded_u[cell_id] == vector3[cell_id][2]); + } + REQUIRE(is_same); + } + + REQUIRE_THROWS_WITH(vectorize(std::vector{p_u, p_other_mesh_u}), + "error: discrete functions are not defined on the same mesh"); + REQUIRE_THROWS_WITH(vectorize(std::vector{p_R1_u}), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("dot Vh*Rd -> Vh") + { + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R1_u, (TinyVector<1>{3}), dot, // + DiscreteFunctionR1, DiscreteFunctionR); + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R2_u, (TinyVector<2>{-6, 2}), dot, // + DiscreteFunctionR2, DiscreteFunctionR); + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R3_u, (TinyVector<3>{-1, 5, 2}), dot, // + DiscreteFunctionR3, DiscreteFunctionR); + REQUIRE_THROWS_WITH(dot(p_R1_u, (TinyVector<2>{-6, 2})), + "error: incompatible operand types Vh(P0:R^1) and R^2"); + REQUIRE_THROWS_WITH(dot(p_R2_u, (TinyVector<3>{-1, 5, 2})), + "error: incompatible operand types Vh(P0:R^2) and R^3"); + REQUIRE_THROWS_WITH(dot(p_R3_u, (TinyVector<1>{-1})), "error: incompatible operand types Vh(P0:R^3) and R^1"); + } + + SECTION("dot Rd*Vh -> Vh") + { + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<1>{3}), p_R1_u, dot, // + DiscreteFunctionR1, DiscreteFunctionR); + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<2>{-6, 2}), p_R2_u, dot, // + DiscreteFunctionR2, DiscreteFunctionR); + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<3>{-1, 5, 2}), p_R3_u, dot, // + DiscreteFunctionR3, DiscreteFunctionR); + REQUIRE_THROWS_WITH(dot((TinyVector<2>{-6, 2}), p_R1_u), + "error: incompatible operand types R^2 and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(dot((TinyVector<3>{-1, 5, 2}), p_R2_u), + "error: incompatible operand types R^3 and Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(dot((TinyVector<1>{-1}), p_R3_u), "error: incompatible operand types R^1 and Vh(P0:R^3)"); + } + + SECTION("sum_of_R* Vh -> R*") + { + REQUIRE(sum_of<double>(p_u) == sum(p_u->get<DiscreteFunctionR>().cellValues())); + REQUIRE(sum_of<TinyVector<1>>(p_R1_u) == sum(p_R1_u->get<DiscreteFunctionR1>().cellValues())); + REQUIRE(sum_of<TinyVector<2>>(p_R2_u) == sum(p_R2_u->get<DiscreteFunctionR2>().cellValues())); + REQUIRE(sum_of<TinyVector<3>>(p_R3_u) == sum(p_R3_u->get<DiscreteFunctionR3>().cellValues())); + REQUIRE(sum_of<TinyMatrix<1>>(p_R1x1_u) == sum(p_R1x1_u->get<DiscreteFunctionR1x1>().cellValues())); + REQUIRE(sum_of<TinyMatrix<2>>(p_R2x2_u) == sum(p_R2x2_u->get<DiscreteFunctionR2x2>().cellValues())); + REQUIRE(sum_of<TinyMatrix<3>>(p_R3x3_u) == sum(p_R3x3_u->get<DiscreteFunctionR3x3>().cellValues())); + + REQUIRE_THROWS_WITH(sum_of<TinyVector<1>>(p_u), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(sum_of<double>(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(sum_of<double>(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(sum_of<double>(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); + REQUIRE_THROWS_WITH(sum_of<double>(p_R1x1_u), "error: invalid operand type Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(sum_of<double>(p_R2x2_u), "error: invalid operand type Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(sum_of<double>(p_R3x3_u), "error: invalid operand type Vh(P0:R^3x3)"); + } + + SECTION("integral_of_R* Vh -> R*") + { + auto integrate_locally = [&](const auto& cell_values) { + const auto& Vj = MeshDataManager::instance().getMeshData(*mesh).Vj(); + using DataType = decltype(double{} * cell_values[CellId{0}]); + CellValue<DataType> local_integral{mesh->connectivity()}; + parallel_for( + local_integral.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { local_integral[cell_id] = Vj[cell_id] * cell_values[cell_id]; }); + return local_integral; + }; + + REQUIRE(integral_of<double>(p_u) == sum(integrate_locally(p_u->get<DiscreteFunctionR>().cellValues()))); + REQUIRE(integral_of<TinyVector<1>>(p_R1_u) == + sum(integrate_locally(p_R1_u->get<DiscreteFunctionR1>().cellValues()))); + REQUIRE(integral_of<TinyVector<2>>(p_R2_u) == + sum(integrate_locally(p_R2_u->get<DiscreteFunctionR2>().cellValues()))); + REQUIRE(integral_of<TinyVector<3>>(p_R3_u) == + sum(integrate_locally(p_R3_u->get<DiscreteFunctionR3>().cellValues()))); + REQUIRE(integral_of<TinyMatrix<1>>(p_R1x1_u) == + sum(integrate_locally(p_R1x1_u->get<DiscreteFunctionR1x1>().cellValues()))); + REQUIRE(integral_of<TinyMatrix<2>>(p_R2x2_u) == + sum(integrate_locally(p_R2x2_u->get<DiscreteFunctionR2x2>().cellValues()))); + REQUIRE(integral_of<TinyMatrix<3>>(p_R3x3_u) == + sum(integrate_locally(p_R3x3_u->get<DiscreteFunctionR3x3>().cellValues()))); + + REQUIRE_THROWS_WITH(integral_of<TinyVector<1>>(p_u), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(integral_of<double>(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(integral_of<double>(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(integral_of<double>(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); + REQUIRE_THROWS_WITH(integral_of<double>(p_R1x1_u), "error: invalid operand type Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(integral_of<double>(p_R2x2_u), "error: invalid operand type Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(integral_of<double>(p_R3x3_u), "error: invalid operand type Vh(P0:R^3x3)"); + } + } + } + } +} diff --git a/tests/test_EmbeddedDiscreteFunctionMathFunctions3D.cpp b/tests/test_EmbeddedDiscreteFunctionMathFunctions3D.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5f9896ad64df5601f54f9d701fc5bfe94f4d51b9 --- /dev/null +++ b/tests/test_EmbeddedDiscreteFunctionMathFunctions3D.cpp @@ -0,0 +1,715 @@ +#include <catch2/catch_test_macros.hpp> +#include <catch2/matchers/catch_matchers_all.hpp> + +#include <MeshDataBaseForTests.hpp> + +#include <scheme/DiscreteFunctionP0.hpp> + +#include <language/utils/EmbeddedDiscreteFunctionMathFunctions.hpp> +#include <scheme/DiscreteFunctionP0Vector.hpp> +#include <scheme/DiscreteFunctionVariant.hpp> + +#include <test_EmbeddedDiscreteFunctionMathFunctions.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("EmbeddedDiscreteFunctionVariantMathFunctions3D", "[scheme]") +{ + constexpr size_t Dimension = 3; + + using Rd = TinyVector<Dimension>; + + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); + + using DiscreteFunctionR = DiscreteFunctionP0<Dimension, const double>; + using DiscreteFunctionR1 = DiscreteFunctionP0<Dimension, const TinyVector<1>>; + using DiscreteFunctionR2 = DiscreteFunctionP0<Dimension, const TinyVector<2>>; + using DiscreteFunctionR3 = DiscreteFunctionP0<Dimension, const TinyVector<3>>; + using DiscreteFunctionR1x1 = DiscreteFunctionP0<Dimension, const TinyMatrix<1>>; + using DiscreteFunctionR2x2 = DiscreteFunctionP0<Dimension, const TinyMatrix<2>>; + using DiscreteFunctionR3x3 = DiscreteFunctionP0<Dimension, const TinyMatrix<3>>; + + using DiscreteFunctionVector = DiscreteFunctionP0Vector<Dimension, const double>; + + for (const auto& named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh = named_mesh.mesh(); + + std::shared_ptr other_mesh = + std::make_shared<Mesh<Connectivity<Dimension>>>(mesh->shared_connectivity(), mesh->xr()); + + CellValue<const Rd> xj = MeshDataManager::instance().getMeshData(*mesh).xj(); + + CellValue<double> values = [=] { + CellValue<double> build_values{mesh->connectivity()}; + parallel_for( + build_values.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.2 + std::cos(l2Norm(xj[cell_id])); }); + return build_values; + }(); + + CellValue<double> positive_values = [=] { + CellValue<double> build_values{mesh->connectivity()}; + parallel_for( + build_values.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 2 + std::sin(l2Norm(xj[cell_id])); }); + return build_values; + }(); + + CellValue<double> bounded_values = [=] { + CellValue<double> build_values{mesh->connectivity()}; + parallel_for( + build_values.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.9 * std::sin(l2Norm(xj[cell_id])); }); + return build_values; + }(); + + std::shared_ptr p_u = std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR(mesh, values)); + std::shared_ptr p_other_mesh_u = + std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR(other_mesh, values)); + std::shared_ptr p_positive_u = + std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR(mesh, positive_values)); + std::shared_ptr p_bounded_u = + std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR(mesh, bounded_values)); + + std::shared_ptr p_R1_u = [=] { + CellValue<TinyVector<1>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id][0] = 2 * xj[cell_id][0] + 1; }); + + return std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR1(mesh, uj)); + }(); + + std::shared_ptr p_R1_v = [=] { + CellValue<TinyVector<1>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { vj[cell_id][0] = xj[cell_id][0] * xj[cell_id][0] + 1; }); + + return std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR1(mesh, vj)); + }(); + + std::shared_ptr p_other_mesh_R1_u = std::make_shared<const DiscreteFunctionVariant>( + DiscreteFunctionR1(other_mesh, p_R1_u->get<DiscreteFunctionR1>().cellValues())); + + constexpr auto to_2d = [&](const TinyVector<Dimension>& x) -> TinyVector<2> { + if constexpr (Dimension == 1) { + return TinyVector<2>{x[0], 1 + x[0] * x[0]}; + } else if constexpr (Dimension == 2) { + return TinyVector<2>{x[0], x[1]}; + } else if constexpr (Dimension == 3) { + return TinyVector<2>{x[0], x[1] + x[2]}; + } + }; + + std::shared_ptr p_R2_u = [=] { + CellValue<TinyVector<2>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + uj[cell_id] = TinyVector<2>{2 * x[0] + 1, 1 - x[1]}; + }); + + return std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR2(mesh, uj)); + }(); + + std::shared_ptr p_R2_v = [=] { + CellValue<TinyVector<2>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + vj[cell_id] = TinyVector<2>{x[0] * x[1] + 1, 2 * x[1]}; + }); + + return std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR2(mesh, vj)); + }(); + + std::shared_ptr p_other_mesh_R2_u = std::make_shared<const DiscreteFunctionVariant>( + DiscreteFunctionR2(other_mesh, p_R2_u->get<DiscreteFunctionR2>().cellValues())); + + constexpr auto to_3d = [&](const TinyVector<Dimension>& x) -> TinyVector<3> { + if constexpr (Dimension == 1) { + return TinyVector<3>{x[0], 1 + x[0] * x[0], 2 - x[0]}; + } else if constexpr (Dimension == 2) { + return TinyVector<3>{x[0], x[1], x[0] + x[1]}; + } else if constexpr (Dimension == 3) { + return TinyVector<3>{x[0], x[1], x[2]}; + } + }; + + std::shared_ptr p_R3_u = [=] { + CellValue<TinyVector<3>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + uj[cell_id] = TinyVector<3>{2 * x[0] + 1, 1 - x[1] * x[2], x[0] + x[2]}; + }); + + return std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR3(mesh, uj)); + }(); + + std::shared_ptr p_R3_v = [=] { + CellValue<TinyVector<3>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + vj[cell_id] = TinyVector<3>{x[0] * x[1] + 1, 2 * x[1], x[2] * x[0]}; + }); + + return std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR3(mesh, vj)); + }(); + + std::shared_ptr p_other_mesh_R3_u = std::make_shared<const DiscreteFunctionVariant>( + DiscreteFunctionR3(other_mesh, p_R3_u->get<DiscreteFunctionR3>().cellValues())); + + std::shared_ptr p_R1x1_u = [=] { + CellValue<TinyMatrix<1>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { uj[cell_id] = TinyMatrix<1>{2 * xj[cell_id][0] + 1}; }); + + return std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR1x1(mesh, uj)); + }(); + + std::shared_ptr p_R2x2_u = [=] { + CellValue<TinyMatrix<2>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + + uj[cell_id] = TinyMatrix<2>{2 * x[0] + 1, 1 - x[1], // + 2 * x[1], -x[0]}; + }); + + return std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR2x2(mesh, uj)); + }(); + + std::shared_ptr p_R3x3_u = [=] { + CellValue<TinyMatrix<3>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + + uj[cell_id] = TinyMatrix<3>{2 * x[0] + 1, 1 - x[1], 3, // + 2 * x[1], -x[0], x[0] - x[1], // + 3 * x[2] - x[1], x[1] - 2 * x[2], x[2] - x[0]}; + }); + + return std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionR3x3(mesh, uj)); + }(); + + std::shared_ptr p_Vector3_u = [=] { + CellArray<double> uj_vector{mesh->connectivity(), 3}; + parallel_for( + uj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + uj_vector[cell_id][0] = 2 * x[0] + 1; + uj_vector[cell_id][1] = 1 - x[1] * x[2]; + uj_vector[cell_id][2] = x[0] + x[2]; + }); + + return std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionVector(mesh, uj_vector)); + }(); + + std::shared_ptr p_Vector3_v = [=] { + CellArray<double> vj_vector{mesh->connectivity(), 3}; + parallel_for( + vj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + vj_vector[cell_id][0] = x[0] * x[1] + 1; + vj_vector[cell_id][1] = 2 * x[1]; + vj_vector[cell_id][2] = x[2] * x[0]; + }); + + return std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionVector(mesh, vj_vector)); + }(); + + std::shared_ptr p_Vector2_w = [=] { + CellArray<double> wj_vector{mesh->connectivity(), 2}; + parallel_for( + wj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + wj_vector[cell_id][0] = x[0] + x[1] * 2; + wj_vector[cell_id][1] = x[0] * x[1]; + }); + + return std::make_shared<const DiscreteFunctionVariant>(DiscreteFunctionVector(mesh, wj_vector)); + }(); + + SECTION("sqrt Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_positive_u, sqrt, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(sqrt(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("abs Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_u, abs, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(abs(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("sin Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_u, sin, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(sin(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("cos Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_u, cos, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(cos(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("tan Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_u, tan, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(tan(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("asin Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_bounded_u, asin, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(asin(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("acos Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_bounded_u, acos, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(acos(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("atan Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_bounded_u, atan, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(atan(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("sinh Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_u, sinh, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(sinh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("cosh Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_u, cosh, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(cosh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("tanh Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_u, tanh, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(tanh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("asinh Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_positive_u, asinh, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(asinh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("acosh Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_positive_u, acosh, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(acosh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("atanh Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_bounded_u, atanh, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(atanh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("exp Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_u, exp, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(exp(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("log Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_positive_u, log, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(log(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("atan2 Vh*Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_positive_u, p_bounded_u, atan2, // + DiscreteFunctionR, DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(atan2(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(atan2(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); + REQUIRE_THROWS_WITH(atan2(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); + } + + SECTION("atan2 Vh*R -> Vh") + { + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_u, 3.6, atan2, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(atan2(p_R1_u, 2.1), "error: incompatible operand types Vh(P0:R^1) and R"); + } + + SECTION("atan2 R*Vh -> Vh") + { + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(2.4, p_u, atan2, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(atan2(2.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); + } + + SECTION("min Vh*Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_u, p_bounded_u, min, // + DiscreteFunctionR, DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(::min(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(::min(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(::min(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); + } + + SECTION("min Vh*R -> Vh") + { + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_u, 1.2, min, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(min(p_R1_u, 2.1), "error: incompatible operand types Vh(P0:R^1) and R"); + } + + SECTION("min R*Vh -> Vh") + { + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(0.4, p_u, min, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(min(3.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); + } + + SECTION("min Vh -> R") + { + REQUIRE(min(p_u) == min(p_u->get<DiscreteFunctionR>().cellValues())); + REQUIRE_THROWS_WITH(min(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("max Vh*Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_u, p_bounded_u, max, // + DiscreteFunctionR, DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(::max(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(::max(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(::max(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); + } + + SECTION("max Vh*R -> Vh") + { + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_u, 1.2, max, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(max(p_R1_u, 2.1), "error: incompatible operand types Vh(P0:R^1) and R"); + } + + SECTION("max Vh -> R") + { + REQUIRE(max(p_u) == max(p_u->get<DiscreteFunctionR>().cellValues())); + REQUIRE_THROWS_WITH(max(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("max R*Vh -> Vh") + { + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(0.4, p_u, max, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(max(3.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); + } + + SECTION("pow Vh*Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_positive_u, p_bounded_u, pow, // + DiscreteFunctionR, DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(pow(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(pow(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(pow(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); + } + + SECTION("pow Vh*R -> Vh") + { + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_positive_u, 3.3, pow, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(pow(p_R1_u, 3.1), "error: incompatible operand types Vh(P0:R^1) and R"); + } + + SECTION("pow R*Vh -> Vh") + { + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(2.1, p_u, pow, // + DiscreteFunctionR, DiscreteFunctionR); + REQUIRE_THROWS_WITH(pow(3.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); + } + + SECTION("dot Vh*Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R1_u, p_R1_v, dot, // + DiscreteFunctionR1, DiscreteFunctionR1, DiscreteFunctionR); + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R2_u, p_R2_v, dot, // + DiscreteFunctionR2, DiscreteFunctionR2, DiscreteFunctionR); + CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R3_u, p_R3_v, dot, // + DiscreteFunctionR3, DiscreteFunctionR3, DiscreteFunctionR); + + { + std::shared_ptr p_fuv = ::dot(p_Vector3_u, p_Vector3_v); + + REQUIRE(p_fuv.use_count() > 0); + + const DiscreteFunctionVector& u = p_Vector3_u->get<DiscreteFunctionVector>(); + const DiscreteFunctionVector& v = p_Vector3_v->get<DiscreteFunctionVector>(); + const DiscreteFunctionR& fuv = p_fuv->get<DiscreteFunctionR>(); + + bool is_same = true; + auto u_arrays = u.cellArrays(); + auto v_arrays = v.cellArrays(); + for (CellId cell_id = 0; cell_id < values.numberOfItems(); ++cell_id) { + using namespace std; + double dot_u_v = [&](auto&& a, auto&& b) { + double sum = 0; + for (size_t i = 0; i < a.size(); ++i) { + sum += a[i] * b[i]; + } + return sum; + }(u_arrays[cell_id], v_arrays[cell_id]); + if (fuv[cell_id] != dot_u_v) { + is_same = false; + break; + } + } + + REQUIRE(is_same); + } + + REQUIRE_THROWS_WITH(dot(p_R1_u, p_other_mesh_R1_u), "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(dot(p_R2_u, p_other_mesh_R2_u), "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(dot(p_R3_u, p_other_mesh_R3_u), "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(dot(p_R1_u, p_R3_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^3)"); + REQUIRE_THROWS_WITH(dot(p_Vector3_u, p_Vector2_w), "error: operands have different dimension"); + } + + SECTION("det Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R1x1_u, det, // + DiscreteFunctionR1x1, DiscreteFunctionR); + + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R2x2_u, det, // + DiscreteFunctionR2x2, DiscreteFunctionR); + + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R3x3_u, det, // + DiscreteFunctionR3x3, DiscreteFunctionR); + + REQUIRE_THROWS_WITH(det(p_u), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(det(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(det(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(det(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); + } + + SECTION("trace Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R1x1_u, trace, // + DiscreteFunctionR1x1, DiscreteFunctionR); + + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R2x2_u, trace, // + DiscreteFunctionR2x2, DiscreteFunctionR); + + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R3x3_u, trace, // + DiscreteFunctionR3x3, DiscreteFunctionR); + + REQUIRE_THROWS_WITH(trace(p_u), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(trace(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(trace(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(trace(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); + } + + SECTION("inverse Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R1x1_u, inverse, // + DiscreteFunctionR1x1, DiscreteFunctionR1x1); + + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R2x2_u, inverse, // + DiscreteFunctionR2x2, DiscreteFunctionR2x2); + + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R3x3_u, inverse, // + DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + REQUIRE_THROWS_WITH(inverse(p_u), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(inverse(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(inverse(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(inverse(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); + } + + SECTION("transpose Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R1x1_u, transpose, // + DiscreteFunctionR1x1, DiscreteFunctionR1x1); + + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R2x2_u, transpose, // + DiscreteFunctionR2x2, DiscreteFunctionR2x2); + + CHECK_EMBEDDED_VH_TO_VH_FUNCTION_EVALUATION(p_R3x3_u, transpose, // + DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + REQUIRE_THROWS_WITH(transpose(p_u), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(transpose(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(transpose(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(transpose(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); + } + + SECTION("sum_of_Vh Vh -> Vh") + { + { + auto p_sum_components = sum_of_Vh_components(p_Vector3_u); + REQUIRE(p_sum_components.use_count() == 1); + + const DiscreteFunctionR& sum_components = p_sum_components->get<DiscreteFunctionR>(); + const DiscreteFunctionVector& vector3_u = p_Vector3_u->get<DiscreteFunctionVector>(); + DiscreteFunctionP0<Dimension, double> direct_sum(mesh); + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { + double sum = 0; + for (size_t i = 0; i < vector3_u.size(); ++i) { + sum += vector3_u[cell_id][i]; + } + + direct_sum[cell_id] = sum; + } + + bool is_same = true; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { + if (sum_components[cell_id] != direct_sum[cell_id]) { + is_same = false; + break; + } + } + + REQUIRE(is_same); + } + + REQUIRE_THROWS_WITH(sum_of_Vh_components(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); + } + + SECTION("vectorize (Vh) -> Vh") + { + { + std::shared_ptr p_vector3 = vectorize(std::vector{p_u, p_positive_u, p_bounded_u}); + REQUIRE(p_vector3.use_count() == 1); + + const DiscreteFunctionVector vector3 = p_vector3->get<DiscreteFunctionVector>(); + + const DiscreteFunctionR& u = p_u->get<DiscreteFunctionR>(); + const DiscreteFunctionR& positive_u = p_positive_u->get<DiscreteFunctionR>(); + const DiscreteFunctionR& bounded_u = p_bounded_u->get<DiscreteFunctionR>(); + + REQUIRE(vector3.size() == 3); + + bool is_same = true; + for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { + is_same &= (u[cell_id] == vector3[cell_id][0]); + is_same &= (positive_u[cell_id] == vector3[cell_id][1]); + is_same &= (bounded_u[cell_id] == vector3[cell_id][2]); + } + REQUIRE(is_same); + } + + REQUIRE_THROWS_WITH(vectorize(std::vector{p_u, p_other_mesh_u}), + "error: discrete functions are not defined on the same mesh"); + REQUIRE_THROWS_WITH(vectorize(std::vector{p_R1_u}), "error: invalid operand type Vh(P0:R^1)"); + } + + SECTION("dot Vh*Rd -> Vh") + { + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R1_u, (TinyVector<1>{3}), dot, // + DiscreteFunctionR1, DiscreteFunctionR); + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R2_u, (TinyVector<2>{-6, 2}), dot, // + DiscreteFunctionR2, DiscreteFunctionR); + CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R3_u, (TinyVector<3>{-1, 5, 2}), dot, // + DiscreteFunctionR3, DiscreteFunctionR); + REQUIRE_THROWS_WITH(dot(p_R1_u, (TinyVector<2>{-6, 2})), + "error: incompatible operand types Vh(P0:R^1) and R^2"); + REQUIRE_THROWS_WITH(dot(p_R2_u, (TinyVector<3>{-1, 5, 2})), + "error: incompatible operand types Vh(P0:R^2) and R^3"); + REQUIRE_THROWS_WITH(dot(p_R3_u, (TinyVector<1>{-1})), "error: incompatible operand types Vh(P0:R^3) and R^1"); + } + + SECTION("dot Rd*Vh -> Vh") + { + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<1>{3}), p_R1_u, dot, // + DiscreteFunctionR1, DiscreteFunctionR); + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<2>{-6, 2}), p_R2_u, dot, // + DiscreteFunctionR2, DiscreteFunctionR); + CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<3>{-1, 5, 2}), p_R3_u, dot, // + DiscreteFunctionR3, DiscreteFunctionR); + REQUIRE_THROWS_WITH(dot((TinyVector<2>{-6, 2}), p_R1_u), + "error: incompatible operand types R^2 and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(dot((TinyVector<3>{-1, 5, 2}), p_R2_u), + "error: incompatible operand types R^3 and Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(dot((TinyVector<1>{-1}), p_R3_u), "error: incompatible operand types R^1 and Vh(P0:R^3)"); + } + + SECTION("sum_of_R* Vh -> R*") + { + REQUIRE(sum_of<double>(p_u) == sum(p_u->get<DiscreteFunctionR>().cellValues())); + REQUIRE(sum_of<TinyVector<1>>(p_R1_u) == sum(p_R1_u->get<DiscreteFunctionR1>().cellValues())); + REQUIRE(sum_of<TinyVector<2>>(p_R2_u) == sum(p_R2_u->get<DiscreteFunctionR2>().cellValues())); + REQUIRE(sum_of<TinyVector<3>>(p_R3_u) == sum(p_R3_u->get<DiscreteFunctionR3>().cellValues())); + REQUIRE(sum_of<TinyMatrix<1>>(p_R1x1_u) == sum(p_R1x1_u->get<DiscreteFunctionR1x1>().cellValues())); + REQUIRE(sum_of<TinyMatrix<2>>(p_R2x2_u) == sum(p_R2x2_u->get<DiscreteFunctionR2x2>().cellValues())); + REQUIRE(sum_of<TinyMatrix<3>>(p_R3x3_u) == sum(p_R3x3_u->get<DiscreteFunctionR3x3>().cellValues())); + + REQUIRE_THROWS_WITH(sum_of<TinyVector<1>>(p_u), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(sum_of<double>(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(sum_of<double>(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(sum_of<double>(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); + REQUIRE_THROWS_WITH(sum_of<double>(p_R1x1_u), "error: invalid operand type Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(sum_of<double>(p_R2x2_u), "error: invalid operand type Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(sum_of<double>(p_R3x3_u), "error: invalid operand type Vh(P0:R^3x3)"); + } + + SECTION("integral_of_R* Vh -> R*") + { + auto integrate_locally = [&](const auto& cell_values) { + const auto& Vj = MeshDataManager::instance().getMeshData(*mesh).Vj(); + using DataType = decltype(double{} * cell_values[CellId{0}]); + CellValue<DataType> local_integral{mesh->connectivity()}; + parallel_for( + local_integral.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { local_integral[cell_id] = Vj[cell_id] * cell_values[cell_id]; }); + return local_integral; + }; + + REQUIRE(integral_of<double>(p_u) == sum(integrate_locally(p_u->get<DiscreteFunctionR>().cellValues()))); + REQUIRE(integral_of<TinyVector<1>>(p_R1_u) == + sum(integrate_locally(p_R1_u->get<DiscreteFunctionR1>().cellValues()))); + REQUIRE(integral_of<TinyVector<2>>(p_R2_u) == + sum(integrate_locally(p_R2_u->get<DiscreteFunctionR2>().cellValues()))); + REQUIRE(integral_of<TinyVector<3>>(p_R3_u) == + sum(integrate_locally(p_R3_u->get<DiscreteFunctionR3>().cellValues()))); + REQUIRE(integral_of<TinyMatrix<1>>(p_R1x1_u) == + sum(integrate_locally(p_R1x1_u->get<DiscreteFunctionR1x1>().cellValues()))); + REQUIRE(integral_of<TinyMatrix<2>>(p_R2x2_u) == + sum(integrate_locally(p_R2x2_u->get<DiscreteFunctionR2x2>().cellValues()))); + REQUIRE(integral_of<TinyMatrix<3>>(p_R3x3_u) == + sum(integrate_locally(p_R3x3_u->get<DiscreteFunctionR3x3>().cellValues()))); + + REQUIRE_THROWS_WITH(integral_of<TinyVector<1>>(p_u), "error: invalid operand type Vh(P0:R)"); + REQUIRE_THROWS_WITH(integral_of<double>(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(integral_of<double>(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(integral_of<double>(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); + REQUIRE_THROWS_WITH(integral_of<double>(p_R1x1_u), "error: invalid operand type Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(integral_of<double>(p_R2x2_u), "error: invalid operand type Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(integral_of<double>(p_R3x3_u), "error: invalid operand type Vh(P0:R^3x3)"); + } + } + } +} diff --git a/tests/test_EmbeddedDiscreteFunctionOperators.hpp b/tests/test_EmbeddedDiscreteFunctionOperators.hpp new file mode 100644 index 0000000000000000000000000000000000000000..93faf56eb06d16469a89bd54206620ee98e0e74d --- /dev/null +++ b/tests/test_EmbeddedDiscreteFunctionOperators.hpp @@ -0,0 +1,177 @@ +#ifndef TEST_EMBEDDED_DISCRETE_FUNCTION_OPERATORS_HPP +#define TEST_EMBEDDED_DISCRETE_FUNCTION_OPERATORS_HPP + +#include <catch2/catch_test_macros.hpp> +#include <catch2/matchers/catch_matchers_all.hpp> + +#include <MeshDataBaseForTests.hpp> + +#include <language/utils/EmbeddedDiscreteFunctionOperators.hpp> +#include <scheme/DiscreteFunctionP0.hpp> +#include <scheme/DiscreteFunctionP0Vector.hpp> +#include <scheme/DiscreteFunctionVariant.hpp> + +// clazy:excludeall=non-pod-global-static + +#define CHECK_EMBEDDED_VH2_TO_VH(P_U, OPERATOR, P_V, U_TYPE, V_TYPE, U_OP_V_TYPE) \ + { \ + std::shared_ptr p_u_op_v = P_U OPERATOR P_V; \ + \ + REQUIRE(p_u_op_v.use_count() > 0); \ + \ + auto u_op_v = p_u_op_v->get<U_OP_V_TYPE>().cellValues(); \ + \ + auto u_values = P_U->get<U_TYPE>().cellValues(); \ + auto v_values = P_V->get<V_TYPE>().cellValues(); \ + bool is_same = true; \ + for (CellId cell_id = 0; cell_id < u_values.numberOfItems(); ++cell_id) { \ + if (u_op_v[cell_id] != (u_values[cell_id] OPERATOR v_values[cell_id])) { \ + is_same = false; \ + break; \ + } \ + } \ + \ + REQUIRE(is_same); \ + } + +#define CHECK_EMBEDDED_VECTOR_VH2_TO_VH(P_U, OPERATOR, P_V, TYPE) \ + { \ + std::shared_ptr p_u_op_v = P_U OPERATOR P_V; \ + \ + REQUIRE(p_u_op_v.use_count() > 0); \ + \ + auto u_op_v_arrays = p_u_op_v->get<TYPE>().cellArrays(); \ + \ + auto u_arrays = P_U->get<TYPE>().cellArrays(); \ + auto v_arrays = P_V->get<TYPE>().cellArrays(); \ + \ + REQUIRE(u_arrays.sizeOfArrays() > 0); \ + REQUIRE(u_arrays.sizeOfArrays() == v_arrays.sizeOfArrays()); \ + REQUIRE(u_arrays.sizeOfArrays() == u_op_v_arrays.sizeOfArrays()); \ + \ + bool is_same = true; \ + for (CellId cell_id = 0; cell_id < u_arrays.numberOfItems(); ++cell_id) { \ + for (size_t i = 0; i < u_arrays.sizeOfArrays(); ++i) { \ + if (u_op_v_arrays[cell_id][i] != (u_arrays[cell_id][i] OPERATOR v_arrays[cell_id][i])) { \ + is_same = false; \ + break; \ + } \ + } \ + } \ + \ + REQUIRE(is_same); \ + } + +#define CHECK_EMBEDDED_VHxX_TO_VH(P_U, OPERATOR, V, U_TYPE, U_OP_V_TYPE) \ + { \ + std::shared_ptr p_u_op_v = P_U OPERATOR V; \ + \ + REQUIRE(p_u_op_v.use_count() > 0); \ + \ + auto u_op_v = p_u_op_v->get<U_OP_V_TYPE>().cellValues(); \ + \ + auto u_values = P_U->get<U_TYPE>().cellValues(); \ + bool is_same = true; \ + for (CellId cell_id = 0; cell_id < u_values.numberOfItems(); ++cell_id) { \ + if (u_op_v[cell_id] != (u_values[cell_id] OPERATOR V)) { \ + is_same = false; \ + break; \ + } \ + } \ + \ + REQUIRE(is_same); \ + } + +#define CHECK_EMBEDDED_XxVH_TO_VH(U, OPERATOR, P_V, V_TYPE, U_OP_V_TYPE) \ + { \ + std::shared_ptr p_u_op_v = U OPERATOR P_V; \ + \ + REQUIRE(p_u_op_v.use_count() > 0); \ + \ + auto u_op_v = p_u_op_v->get<U_OP_V_TYPE>().cellValues(); \ + \ + auto v_values = P_V->get<V_TYPE>().cellValues(); \ + bool is_same = true; \ + for (CellId cell_id = 0; cell_id < v_values.numberOfItems(); ++cell_id) { \ + if (u_op_v[cell_id] != (U OPERATOR v_values[cell_id])) { \ + is_same = false; \ + break; \ + } \ + } \ + \ + REQUIRE(is_same); \ + } + +#define CHECK_EMBEDDED_VECTOR_XxVH_TO_VH(U, OPERATOR, P_V, TYPE) \ + { \ + std::shared_ptr p_u_op_v = U OPERATOR P_V; \ + \ + REQUIRE(p_u_op_v.use_count() > 0); \ + \ + auto u_op_v = p_u_op_v->get<TYPE>().cellArrays(); \ + \ + auto v_arrays = P_V->get<TYPE>().cellArrays(); \ + \ + REQUIRE(v_arrays.numberOfItems() == u_op_v.numberOfItems()); \ + REQUIRE(v_arrays.sizeOfArrays() == u_op_v.sizeOfArrays()); \ + \ + bool is_same = true; \ + for (CellId cell_id = 0; cell_id < v_arrays.numberOfItems(); ++cell_id) { \ + for (size_t i = 0; i < v_arrays.sizeOfArrays(); ++i) { \ + if (u_op_v[cell_id][i] != (U OPERATOR v_arrays[cell_id][i])) { \ + is_same = false; \ + std::clog << u_op_v[cell_id][i] << " !=" << (U OPERATOR v_arrays[cell_id][i]) << '\n'; \ + } \ + } \ + } \ + \ + REQUIRE(is_same); \ + } + +#define CHECK_EMBEDDED_VH_TO_VH(OPERATOR, P_U, U_TYPE) \ + { \ + std::shared_ptr p_op_u = OPERATOR P_U; \ + \ + REQUIRE(p_op_u.use_count() > 0); \ + \ + auto op_u = p_op_u->get<U_TYPE>().cellValues(); \ + \ + auto u_values = P_U->get<U_TYPE>().cellValues(); \ + bool is_same = true; \ + for (CellId cell_id = 0; cell_id < u_values.numberOfItems(); ++cell_id) { \ + if (op_u[cell_id] != (OPERATOR u_values[cell_id])) { \ + is_same = false; \ + break; \ + } \ + } \ + \ + REQUIRE(is_same); \ + } + +#define CHECK_EMBEDDED_VECTOR_VH_TO_VH(OPERATOR, P_U, TYPE) \ + { \ + std::shared_ptr p_op_u = OPERATOR P_U; \ + \ + REQUIRE(p_op_u.use_count() > 0); \ + \ + auto op_u_arrays = p_op_u->get<TYPE>().cellArrays(); \ + \ + auto u_arrays = P_U->get<TYPE>().cellArrays(); \ + \ + REQUIRE(u_arrays.sizeOfArrays() == op_u_arrays.sizeOfArrays()); \ + REQUIRE(u_arrays.numberOfItems() == op_u_arrays.numberOfItems()); \ + \ + bool is_same = true; \ + for (CellId cell_id = 0; cell_id < u_arrays.numberOfItems(); ++cell_id) { \ + for (size_t i = 0; i < u_arrays.sizeOfArrays(); ++i) { \ + if (op_u_arrays[cell_id][i] != (OPERATOR u_arrays[cell_id][i])) { \ + is_same = false; \ + break; \ + } \ + } \ + } \ + \ + REQUIRE(is_same); \ + } + +#endif // TEST_EMBEDDED_DISCRETE_FUNCTION_OPERATORS_HPP diff --git a/tests/test_EmbeddedDiscreteFunctionOperators1D.cpp b/tests/test_EmbeddedDiscreteFunctionOperators1D.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5538543de393bd2fb8009e3d2cbd04d57107ead3 --- /dev/null +++ b/tests/test_EmbeddedDiscreteFunctionOperators1D.cpp @@ -0,0 +1,862 @@ +#include <test_EmbeddedDiscreteFunctionOperators.hpp> + +#ifdef __clang__ +#pragma clang optimize off +#endif // __clang__ + +TEST_CASE("EmbeddedDiscreteFunctionOperators1D", "[scheme]") +{ + constexpr size_t Dimension = 1; + + using Rd = TinyVector<Dimension>; + + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); + + using DiscreteFunctionR = DiscreteFunctionP0<Dimension, const double>; + using DiscreteFunctionR1 = DiscreteFunctionP0<Dimension, const TinyVector<1>>; + using DiscreteFunctionR2 = DiscreteFunctionP0<Dimension, const TinyVector<2>>; + using DiscreteFunctionR3 = DiscreteFunctionP0<Dimension, const TinyVector<3>>; + using DiscreteFunctionR1x1 = DiscreteFunctionP0<Dimension, const TinyMatrix<1>>; + using DiscreteFunctionR2x2 = DiscreteFunctionP0<Dimension, const TinyMatrix<2>>; + using DiscreteFunctionR3x3 = DiscreteFunctionP0<Dimension, const TinyMatrix<3>>; + + using DiscreteFunctionVector = DiscreteFunctionP0Vector<Dimension, const double>; + + for (const auto& named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh = named_mesh.mesh(); + + std::shared_ptr other_mesh = + std::make_shared<Mesh<Connectivity<Dimension>>>(mesh->shared_connectivity(), mesh->xr()); + + CellValue<const Rd> xj = MeshDataManager::instance().getMeshData(*mesh).xj(); + + CellValue<double> u_R_values = [=] { + CellValue<double> build_values{mesh->connectivity()}; + parallel_for( + build_values.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.2 + std::cos(l2Norm(xj[cell_id])); }); + return build_values; + }(); + + CellValue<double> v_R_values = [=] { + CellValue<double> build_values{mesh->connectivity()}; + parallel_for( + build_values.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.6 + std::sin(l2Norm(xj[cell_id])); }); + return build_values; + }(); + + std::shared_ptr p_R_u = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR(mesh, u_R_values)); + std::shared_ptr p_other_mesh_R_u = + std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR(other_mesh, u_R_values)); + std::shared_ptr p_R_v = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR(mesh, v_R_values)); + + std::shared_ptr p_R1_u = [=] { + CellValue<TinyVector<1>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id][0] = 2 * xj[cell_id][0] + 1; }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR1(mesh, uj)); + }(); + + std::shared_ptr p_R1_v = [=] { + CellValue<TinyVector<1>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { vj[cell_id][0] = xj[cell_id][0] * xj[cell_id][0] + 1; }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR1(mesh, vj)); + }(); + + std::shared_ptr p_other_mesh_R1_u = std::make_shared<DiscreteFunctionVariant>( + DiscreteFunctionR1(other_mesh, p_R1_u->get<DiscreteFunctionR1>().cellValues())); + + constexpr auto to_2d = [&](const TinyVector<Dimension>& x) -> TinyVector<2> { + if constexpr (Dimension == 1) { + return TinyVector<2>{x[0], 1 + x[0] * x[0]}; + } else if constexpr (Dimension == 2) { + return TinyVector<2>{x[0], x[1]}; + } else if constexpr (Dimension == 3) { + return TinyVector<2>{x[0], x[1] + x[2]}; + } + }; + + std::shared_ptr p_R2_u = [=] { + CellValue<TinyVector<2>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + uj[cell_id] = TinyVector<2>{2 * x[0] + 1, 1 - x[1]}; + }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR2(mesh, uj)); + }(); + + std::shared_ptr p_R2_v = [=] { + CellValue<TinyVector<2>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + vj[cell_id] = TinyVector<2>{x[0] * x[1] + 1, 2 * x[1]}; + }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR2(mesh, vj)); + }(); + + std::shared_ptr p_other_mesh_R2_u = std::make_shared<DiscreteFunctionVariant>( + DiscreteFunctionR2(other_mesh, p_R2_u->get<DiscreteFunctionR2>().cellValues())); + + constexpr auto to_3d = [&](const TinyVector<Dimension>& x) -> TinyVector<3> { + if constexpr (Dimension == 1) { + return TinyVector<3>{x[0], 1 + x[0] * x[0], 2 - x[0]}; + } else if constexpr (Dimension == 2) { + return TinyVector<3>{x[0], x[1], x[0] + x[1]}; + } else if constexpr (Dimension == 3) { + return TinyVector<3>{x[0], x[1], x[2]}; + } + }; + + std::shared_ptr p_R3_u = [=] { + CellValue<TinyVector<3>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + uj[cell_id] = TinyVector<3>{2 * x[0] + 1, 1 - x[1] * x[2], x[0] + x[2]}; + }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR3(mesh, uj)); + }(); + + std::shared_ptr p_R3_v = [=] { + CellValue<TinyVector<3>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + vj[cell_id] = TinyVector<3>{x[0] * x[1] + 1, 2 * x[1], x[2] * x[0]}; + }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR3(mesh, vj)); + }(); + + std::shared_ptr p_other_mesh_R3_u = std::make_shared<DiscreteFunctionVariant>( + DiscreteFunctionR3(other_mesh, p_R3_u->get<DiscreteFunctionR3>().cellValues())); + + std::shared_ptr p_R1x1_u = [=] { + CellValue<TinyMatrix<1>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { uj[cell_id] = TinyMatrix<1>{2 * xj[cell_id][0] + 1}; }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR1x1(mesh, uj)); + }(); + + std::shared_ptr p_other_mesh_R1x1_u = std::make_shared<DiscreteFunctionVariant>( + DiscreteFunctionR1x1(other_mesh, p_R1x1_u->get<DiscreteFunctionR1x1>().cellValues())); + + std::shared_ptr p_R1x1_v = [=] { + CellValue<TinyMatrix<1>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { vj[cell_id] = TinyMatrix<1>{0.3 - xj[cell_id][0]}; }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR1x1(mesh, vj)); + }(); + + std::shared_ptr p_R2x2_u = [=] { + CellValue<TinyMatrix<2>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + + uj[cell_id] = TinyMatrix<2>{2 * x[0] + 1, 1 - x[1], // + 2 * x[1], -x[0]}; + }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR2x2(mesh, uj)); + }(); + + std::shared_ptr p_other_mesh_R2x2_u = std::make_shared<DiscreteFunctionVariant>( + DiscreteFunctionR2x2(other_mesh, p_R2x2_u->get<DiscreteFunctionR2x2>().cellValues())); + + std::shared_ptr p_R2x2_v = [=] { + CellValue<TinyMatrix<2>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + + vj[cell_id] = TinyMatrix<2>{x[0] + 0.3, 1 - x[1] - x[0], // + 2 * x[1] + x[0], x[1] - x[0]}; + }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR2x2(mesh, vj)); + }(); + + std::shared_ptr p_R3x3_u = [=] { + CellValue<TinyMatrix<3>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + + uj[cell_id] = TinyMatrix<3>{2 * x[0] + 1, 1 - x[1], 3, // + 2 * x[1], -x[0], x[0] - x[1], // + 3 * x[2] - x[1], x[1] - 2 * x[2], x[2] - x[0]}; + }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR3x3(mesh, uj)); + }(); + + std::shared_ptr p_other_mesh_R3x3_u = std::make_shared<DiscreteFunctionVariant>( + DiscreteFunctionR3x3(other_mesh, p_R3x3_u->get<DiscreteFunctionR3x3>().cellValues())); + + std::shared_ptr p_R3x3_v = [=] { + CellValue<TinyMatrix<3>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + + vj[cell_id] = TinyMatrix<3>{0.2 * x[0] + 1, 2 + x[1], 3 - x[2], // + 2.3 * x[2], x[1] - x[0], x[2] - x[1], // + 2 * x[2] + x[0], x[1] + 0.2 * x[2], x[2] - 2 * x[0]}; + }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR3x3(mesh, vj)); + }(); + + std::shared_ptr p_Vector3_u = [=] { + CellArray<double> uj_vector{mesh->connectivity(), 3}; + parallel_for( + uj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + uj_vector[cell_id][0] = 2 * x[0] + 1; + uj_vector[cell_id][1] = 1 - x[1] * x[2]; + uj_vector[cell_id][2] = x[0] + x[2]; + }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionVector(mesh, uj_vector)); + }(); + + std::shared_ptr p_other_mesh_Vector3_u = std::make_shared<DiscreteFunctionVariant>( + DiscreteFunctionVector(other_mesh, p_Vector3_u->get<DiscreteFunctionVector>().cellArrays())); + + std::shared_ptr p_Vector3_v = [=] { + CellArray<double> vj_vector{mesh->connectivity(), 3}; + parallel_for( + vj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + vj_vector[cell_id][0] = x[0] * x[1] + 1; + vj_vector[cell_id][1] = 2 * x[1]; + vj_vector[cell_id][2] = x[2] * x[0]; + }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionVector(mesh, vj_vector)); + }(); + + std::shared_ptr p_Vector2_w = [=] { + CellArray<double> wj_vector{mesh->connectivity(), 2}; + parallel_for( + wj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + wj_vector[cell_id][0] = x[0] + x[1] * 2; + wj_vector[cell_id][1] = x[0] * x[1]; + }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionVector(mesh, wj_vector)); + }(); + + SECTION("binary operators") + { + SECTION("sum") + { + SECTION("Vh + Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH(p_R_u, +, p_R_v, // + DiscreteFunctionR, DiscreteFunctionR, DiscreteFunctionR); + + CHECK_EMBEDDED_VH2_TO_VH(p_R1_u, +, p_R1_v, // + DiscreteFunctionR1, DiscreteFunctionR1, DiscreteFunctionR1); + CHECK_EMBEDDED_VH2_TO_VH(p_R2_u, +, p_R2_v, // + DiscreteFunctionR2, DiscreteFunctionR2, DiscreteFunctionR2); + CHECK_EMBEDDED_VH2_TO_VH(p_R3_u, +, p_R3_v, // + DiscreteFunctionR3, DiscreteFunctionR3, DiscreteFunctionR3); + + CHECK_EMBEDDED_VH2_TO_VH(p_R1x1_u, +, p_R1x1_v, // + DiscreteFunctionR1x1, DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_VH2_TO_VH(p_R2x2_u, +, p_R2x2_v, // + DiscreteFunctionR2x2, DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_VH2_TO_VH(p_R3x3_u, +, p_R3x3_v, // + DiscreteFunctionR3x3, DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + CHECK_EMBEDDED_VECTOR_VH2_TO_VH(p_Vector3_u, +, p_Vector3_v, DiscreteFunctionVector); + + REQUIRE_THROWS_WITH(p_R_u + p_R1_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R2_u + p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R3_u + p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(p_R_u + p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(p_R_u + p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(p_Vector3_u + p_R_v, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R)"); + REQUIRE_THROWS_WITH(p_Vector3_u + p_Vector2_w, "error: Vh(P0Vector:R) spaces have different sizes"); + + REQUIRE_THROWS_WITH(p_R_u + p_other_mesh_R_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R1_u + p_other_mesh_R1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R2_u + p_other_mesh_R2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R3_u + p_other_mesh_R3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R1x1_u + p_other_mesh_R1x1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R2x2_u + p_other_mesh_R2x2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R3x3_u + p_other_mesh_R3x3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_Vector3_u + p_other_mesh_Vector3_u, + "error: operands are defined on different meshes"); + } + + SECTION("Vh + X -> Vh") + { + CHECK_EMBEDDED_VHxX_TO_VH(p_R_u, +, bool{true}, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_VHxX_TO_VH(p_R_u, +, uint64_t{1}, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_VHxX_TO_VH(p_R_u, +, int64_t{2}, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_VHxX_TO_VH(p_R_u, +, double{1.3}, // + DiscreteFunctionR, DiscreteFunctionR); + + CHECK_EMBEDDED_VHxX_TO_VH(p_R1_u, +, (TinyVector<1>{1.3}), // + DiscreteFunctionR1, DiscreteFunctionR1); + CHECK_EMBEDDED_VHxX_TO_VH(p_R2_u, +, (TinyVector<2>{1.2, 2.3}), // + DiscreteFunctionR2, DiscreteFunctionR2); + CHECK_EMBEDDED_VHxX_TO_VH(p_R3_u, +, (TinyVector<3>{3.2, 7.1, 5.2}), // + DiscreteFunctionR3, DiscreteFunctionR3); + + CHECK_EMBEDDED_VHxX_TO_VH(p_R1x1_u, +, (TinyMatrix<1>{1.3}), // + DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_VHxX_TO_VH(p_R2x2_u, +, (TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), // + DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_VHxX_TO_VH(p_R3x3_u, +, + (TinyMatrix<3>{3.2, 7.1, 5.2, // + 4.7, 2.3, 7.1, // + 9.7, 3.2, 6.8}), // + DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + REQUIRE_THROWS_WITH(p_R_u + (TinyVector<1>{1}), "error: incompatible operand types Vh(P0:R) and R^1"); + REQUIRE_THROWS_WITH(p_R_u + (TinyVector<2>{1, 2}), "error: incompatible operand types Vh(P0:R) and R^2"); + REQUIRE_THROWS_WITH(p_R_u + (TinyVector<3>{2, 3, 2}), "error: incompatible operand types Vh(P0:R) and R^3"); + REQUIRE_THROWS_WITH(p_R_u + (TinyMatrix<1>{2}), "error: incompatible operand types Vh(P0:R) and R^1x1"); + REQUIRE_THROWS_WITH(p_R_u + (TinyMatrix<2>{2, 3, 1, 4}), + "error: incompatible operand types Vh(P0:R) and R^2x2"); + REQUIRE_THROWS_WITH(p_R_u + (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), + "error: incompatible operand types Vh(P0:R) and R^3x3"); + + REQUIRE_THROWS_WITH(p_Vector3_u + (double{1}), "error: incompatible operand types Vh(P0Vector:R) and R"); + REQUIRE_THROWS_WITH(p_Vector3_u + (TinyVector<1>{1}), + "error: incompatible operand types Vh(P0Vector:R) and R^1"); + REQUIRE_THROWS_WITH(p_Vector3_u + (TinyVector<2>{1, 2}), + "error: incompatible operand types Vh(P0Vector:R) and R^2"); + } + + SECTION("X + Vh -> Vh") + { + CHECK_EMBEDDED_XxVH_TO_VH(bool{true}, +, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_XxVH_TO_VH(uint64_t{1}, +, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_XxVH_TO_VH(int64_t{2}, +, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_XxVH_TO_VH(double{1.3}, +, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + + CHECK_EMBEDDED_XxVH_TO_VH((TinyVector<1>{1.3}), +, p_R1_u, // + DiscreteFunctionR1, DiscreteFunctionR1); + CHECK_EMBEDDED_XxVH_TO_VH((TinyVector<2>{1.2, 2.3}), +, p_R2_u, // + DiscreteFunctionR2, DiscreteFunctionR2); + CHECK_EMBEDDED_XxVH_TO_VH((TinyVector<3>{3.2, 7.1, 5.2}), +, p_R3_u, // + DiscreteFunctionR3, DiscreteFunctionR3); + + CHECK_EMBEDDED_XxVH_TO_VH((TinyMatrix<1>{1.3}), +, p_R1x1_u, // + DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), +, p_R2x2_u, // + DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // + 4.7, 2.3, 7.1, // + 9.7, 3.2, 6.8}), + +, p_R3x3_u, // + DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + REQUIRE_THROWS_WITH((TinyVector<1>{1}) + p_R_u, "error: incompatible operand types R^1 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) + p_R_u, "error: incompatible operand types R^2 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyVector<3>{2, 3, 2}) + p_R_u, "error: incompatible operand types R^3 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) + p_R_u, "error: incompatible operand types R^1x1 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) + p_R_u, + "error: incompatible operand types R^2x2 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) + p_R_u, + "error: incompatible operand types R^3x3 and Vh(P0:R)"); + + REQUIRE_THROWS_WITH((double{1}) + p_Vector3_u, "error: incompatible operand types R and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH((TinyVector<1>{1}) + p_Vector3_u, + "error: incompatible operand types R^1 and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) + p_Vector3_u, + "error: incompatible operand types R^2 and Vh(P0Vector:R)"); + } + } + + SECTION("difference") + { + SECTION("Vh - Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH(p_R_u, -, p_R_v, // + DiscreteFunctionR, DiscreteFunctionR, DiscreteFunctionR); + + CHECK_EMBEDDED_VH2_TO_VH(p_R1_u, -, p_R1_v, // + DiscreteFunctionR1, DiscreteFunctionR1, DiscreteFunctionR1); + CHECK_EMBEDDED_VH2_TO_VH(p_R2_u, -, p_R2_v, // + DiscreteFunctionR2, DiscreteFunctionR2, DiscreteFunctionR2); + CHECK_EMBEDDED_VH2_TO_VH(p_R3_u, -, p_R3_v, // + DiscreteFunctionR3, DiscreteFunctionR3, DiscreteFunctionR3); + + CHECK_EMBEDDED_VH2_TO_VH(p_R1x1_u, -, p_R1x1_v, // + DiscreteFunctionR1x1, DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_VH2_TO_VH(p_R2x2_u, -, p_R2x2_v, // + DiscreteFunctionR2x2, DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_VH2_TO_VH(p_R3x3_u, -, p_R3x3_v, // + DiscreteFunctionR3x3, DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + CHECK_EMBEDDED_VECTOR_VH2_TO_VH(p_Vector3_u, -, p_Vector3_v, DiscreteFunctionVector); + + REQUIRE_THROWS_WITH(p_R_u - p_R1_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R2_u - p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R3_u - p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(p_R_u - p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(p_Vector3_u - p_R_v, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R)"); + REQUIRE_THROWS_WITH(p_Vector3_u - p_Vector2_w, "error: Vh(P0Vector:R) spaces have different sizes"); + + REQUIRE_THROWS_WITH(p_R_u - p_other_mesh_R_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R1_u - p_other_mesh_R1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R2_u - p_other_mesh_R2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R3_u - p_other_mesh_R3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R1x1_u - p_other_mesh_R1x1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R2x2_u - p_other_mesh_R2x2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R3x3_u - p_other_mesh_R3x3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_Vector3_u - p_other_mesh_Vector3_u, + "error: operands are defined on different meshes"); + } + + SECTION("Vh - X -> Vh") + { + CHECK_EMBEDDED_VHxX_TO_VH(p_R_u, -, bool{true}, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_VHxX_TO_VH(p_R_u, -, uint64_t{1}, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_VHxX_TO_VH(p_R_u, -, int64_t{2}, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_VHxX_TO_VH(p_R_u, -, double{1.3}, // + DiscreteFunctionR, DiscreteFunctionR); + + CHECK_EMBEDDED_VHxX_TO_VH(p_R1_u, -, (TinyVector<1>{1.3}), // + DiscreteFunctionR1, DiscreteFunctionR1); + CHECK_EMBEDDED_VHxX_TO_VH(p_R2_u, -, (TinyVector<2>{1.2, 2.3}), // + DiscreteFunctionR2, DiscreteFunctionR2); + CHECK_EMBEDDED_VHxX_TO_VH(p_R3_u, -, (TinyVector<3>{3.2, 7.1, 5.2}), // + DiscreteFunctionR3, DiscreteFunctionR3); + + CHECK_EMBEDDED_VHxX_TO_VH(p_R1x1_u, -, (TinyMatrix<1>{1.3}), // + DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_VHxX_TO_VH(p_R2x2_u, -, (TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), // + DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_VHxX_TO_VH(p_R3x3_u, -, + (TinyMatrix<3>{3.2, 7.1, 5.2, // + 4.7, 2.3, 7.1, // + 9.7, 3.2, 6.8}), // + DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + REQUIRE_THROWS_WITH(p_R_u - (TinyVector<1>{1}), "error: incompatible operand types Vh(P0:R) and R^1"); + REQUIRE_THROWS_WITH(p_R_u - (TinyVector<2>{1, 2}), "error: incompatible operand types Vh(P0:R) and R^2"); + REQUIRE_THROWS_WITH(p_R_u - (TinyVector<3>{2, 3, 2}), "error: incompatible operand types Vh(P0:R) and R^3"); + REQUIRE_THROWS_WITH(p_R_u - (TinyMatrix<1>{2}), "error: incompatible operand types Vh(P0:R) and R^1x1"); + REQUIRE_THROWS_WITH(p_R_u - (TinyMatrix<2>{2, 3, 1, 4}), + "error: incompatible operand types Vh(P0:R) and R^2x2"); + REQUIRE_THROWS_WITH(p_R_u - (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), + "error: incompatible operand types Vh(P0:R) and R^3x3"); + + REQUIRE_THROWS_WITH(p_Vector3_u - (double{1}), "error: incompatible operand types Vh(P0Vector:R) and R"); + REQUIRE_THROWS_WITH(p_Vector3_u - (TinyVector<1>{1}), + "error: incompatible operand types Vh(P0Vector:R) and R^1"); + REQUIRE_THROWS_WITH(p_Vector3_u - (TinyVector<2>{1, 2}), + "error: incompatible operand types Vh(P0Vector:R) and R^2"); + } + + SECTION("X - Vh -> Vh") + { + CHECK_EMBEDDED_XxVH_TO_VH(bool{true}, -, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_XxVH_TO_VH(uint64_t{1}, -, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_XxVH_TO_VH(int64_t{2}, -, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_XxVH_TO_VH(double{1.3}, -, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + + CHECK_EMBEDDED_XxVH_TO_VH((TinyVector<1>{1.3}), -, p_R1_u, // + DiscreteFunctionR1, DiscreteFunctionR1); + CHECK_EMBEDDED_XxVH_TO_VH((TinyVector<2>{1.2, 2.3}), -, p_R2_u, // + DiscreteFunctionR2, DiscreteFunctionR2); + CHECK_EMBEDDED_XxVH_TO_VH((TinyVector<3>{3.2, 7.1, 5.2}), -, p_R3_u, // + DiscreteFunctionR3, DiscreteFunctionR3); + + CHECK_EMBEDDED_XxVH_TO_VH((TinyMatrix<1>{1.3}), -, p_R1x1_u, // + DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), -, p_R2x2_u, // + DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // + 4.7, 2.3, 7.1, // + 9.7, 3.2, 6.8}), + -, p_R3x3_u, // + DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + REQUIRE_THROWS_WITH((TinyVector<1>{1}) - p_R_u, "error: incompatible operand types R^1 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) - p_R_u, "error: incompatible operand types R^2 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyVector<3>{2, 3, 2}) - p_R_u, "error: incompatible operand types R^3 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) - p_R_u, "error: incompatible operand types R^1x1 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) - p_R_u, + "error: incompatible operand types R^2x2 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) - p_R_u, + "error: incompatible operand types R^3x3 and Vh(P0:R)"); + + REQUIRE_THROWS_WITH((double{1}) - p_Vector3_u, "error: incompatible operand types R and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH((TinyVector<1>{1}) - p_Vector3_u, + "error: incompatible operand types R^1 and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) - p_Vector3_u, + "error: incompatible operand types R^2 and Vh(P0Vector:R)"); + } + } + + SECTION("product") + { + SECTION("Vh * Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH(p_R_u, *, p_R_v, // + DiscreteFunctionR, DiscreteFunctionR, DiscreteFunctionR); + + CHECK_EMBEDDED_VH2_TO_VH(p_R1x1_u, *, p_R1x1_v, // + DiscreteFunctionR1x1, DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_VH2_TO_VH(p_R2x2_u, *, p_R2x2_v, // + DiscreteFunctionR2x2, DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_VH2_TO_VH(p_R3x3_u, *, p_R3x3_v, // + DiscreteFunctionR3x3, DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + CHECK_EMBEDDED_VH2_TO_VH(p_R_u, *, p_R1_v, // + DiscreteFunctionR, DiscreteFunctionR1, DiscreteFunctionR1); + CHECK_EMBEDDED_VH2_TO_VH(p_R_u, *, p_R2_v, // + DiscreteFunctionR, DiscreteFunctionR2, DiscreteFunctionR2); + CHECK_EMBEDDED_VH2_TO_VH(p_R_u, *, p_R3_v, // + DiscreteFunctionR, DiscreteFunctionR3, DiscreteFunctionR3); + + CHECK_EMBEDDED_VH2_TO_VH(p_R_u, *, p_R1x1_v, // + DiscreteFunctionR, DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_VH2_TO_VH(p_R_u, *, p_R2x2_v, // + DiscreteFunctionR, DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_VH2_TO_VH(p_R_u, *, p_R3x3_v, // + DiscreteFunctionR, DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + CHECK_EMBEDDED_VH2_TO_VH(p_R1x1_u, *, p_R1_v, // + DiscreteFunctionR1x1, DiscreteFunctionR1, DiscreteFunctionR1); + CHECK_EMBEDDED_VH2_TO_VH(p_R2x2_u, *, p_R2_v, // + DiscreteFunctionR2x2, DiscreteFunctionR2, DiscreteFunctionR2); + CHECK_EMBEDDED_VH2_TO_VH(p_R3x3_u, *, p_R3_v, // + DiscreteFunctionR3x3, DiscreteFunctionR3, DiscreteFunctionR3); + + { + std::shared_ptr p_u_op_v = p_R_u * p_Vector3_v; + + REQUIRE(p_u_op_v.use_count() > 0); + DiscreteFunctionVector u_op_v = p_u_op_v->get<DiscreteFunctionVector>(); + + auto u_values = p_R_u->get<DiscreteFunctionR>().cellValues(); + auto v_arrays = p_Vector3_v->get<DiscreteFunctionVector>().cellArrays(); + bool is_same = true; + for (CellId cell_id = 0; cell_id < u_values.numberOfItems(); ++cell_id) { + for (size_t i = 0; i < u_op_v.size(); ++i) { + if (u_op_v[cell_id][i] != (u_values[cell_id] * v_arrays[cell_id][i])) { + is_same = false; + break; + } + } + } + + REQUIRE(is_same); + } + + REQUIRE_THROWS_WITH(p_R1_u * p_R1_v, "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R2_u * p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R3_u * p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(p_R1_u * p_R2x2_v, "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^2x2)"); + + REQUIRE_THROWS_WITH(p_R1x1_u * p_R2x2_v, "error: incompatible operand types Vh(P0:R^1x1) and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(p_R2x2_u * p_R3x3_v, "error: incompatible operand types Vh(P0:R^2x2) and Vh(P0:R^3x3)"); + REQUIRE_THROWS_WITH(p_R3x3_u * p_R1x1_v, "error: incompatible operand types Vh(P0:R^3x3) and Vh(P0:R^1x1)"); + + REQUIRE_THROWS_WITH(p_R1x1_u * p_R2_v, "error: incompatible operand types Vh(P0:R^1x1) and Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(p_R2x2_u * p_R3_v, "error: incompatible operand types Vh(P0:R^2x2) and Vh(P0:R^3)"); + REQUIRE_THROWS_WITH(p_R3x3_u * p_R1_v, "error: incompatible operand types Vh(P0:R^3x3) and Vh(P0:R^1)"); + + REQUIRE_THROWS_WITH(p_R1_u * p_Vector3_v, + "error: incompatible operand types Vh(P0:R^1) and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH(p_R2_u * p_Vector3_v, + "error: incompatible operand types Vh(P0:R^2) and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH(p_R3_u * p_Vector3_v, + "error: incompatible operand types Vh(P0:R^3) and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH(p_R1x1_u * p_Vector3_v, + "error: incompatible operand types Vh(P0:R^1x1) and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH(p_R2x2_u * p_Vector3_v, + "error: incompatible operand types Vh(P0:R^2x2) and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH(p_R3x3_u * p_Vector3_v, + "error: incompatible operand types Vh(P0:R^3x3) and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH(p_Vector3_u * p_Vector3_v, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0Vector:R)"); + + REQUIRE_THROWS_WITH(p_Vector3_v * p_R_u, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R)"); + REQUIRE_THROWS_WITH(p_Vector3_v * p_R1_u, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_Vector3_v * p_R2_u, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(p_Vector3_v * p_R3_u, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^3)"); + REQUIRE_THROWS_WITH(p_Vector3_v * p_R1x1_u, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(p_Vector3_v * p_R2x2_u, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(p_Vector3_v * p_R3x3_u, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^3x3)"); + + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R1x1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R2x2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R3x3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R1x1_u * p_other_mesh_R1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R2x2_u * p_other_mesh_R2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R3x3_u * p_other_mesh_R3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_Vector3_u, "error: operands are defined on different meshes"); + } + + SECTION("Vh * X -> Vh") + { + CHECK_EMBEDDED_VHxX_TO_VH(p_R_u, *, bool{true}, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_VHxX_TO_VH(p_R_u, *, uint64_t{1}, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_VHxX_TO_VH(p_R_u, *, int64_t{2}, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_VHxX_TO_VH(p_R_u, *, double{1.3}, // + DiscreteFunctionR, DiscreteFunctionR); + + CHECK_EMBEDDED_VHxX_TO_VH(p_R1x1_u, *, (TinyMatrix<1>{1.3}), // + DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_VHxX_TO_VH(p_R2x2_u, *, (TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), // + DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_VHxX_TO_VH(p_R3x3_u, *, + (TinyMatrix<3>{3.2, 7.1, 5.2, // + 4.7, 2.3, 7.1, // + 9.7, 3.2, 6.8}), // + DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + CHECK_EMBEDDED_VHxX_TO_VH(p_R1x1_u, *, (TinyVector<1>{1.3}), // + DiscreteFunctionR1x1, DiscreteFunctionR1); + CHECK_EMBEDDED_VHxX_TO_VH(p_R2x2_u, *, (TinyVector<2>{1.2, 2.3}), // + DiscreteFunctionR2x2, DiscreteFunctionR2); + CHECK_EMBEDDED_VHxX_TO_VH(p_R3x3_u, *, (TinyVector<3>{3.2, 7.1, 5.2}), // + DiscreteFunctionR3x3, DiscreteFunctionR3); + + REQUIRE_THROWS_WITH(p_R1_u * (TinyVector<1>{1}), "error: incompatible operand types Vh(P0:R^1) and R^1"); + REQUIRE_THROWS_WITH(p_R2_u * (TinyVector<2>{1, 2}), "error: incompatible operand types Vh(P0:R^2) and R^2"); + REQUIRE_THROWS_WITH(p_R3_u * (TinyVector<3>{2, 3, 2}), + "error: incompatible operand types Vh(P0:R^3) and R^3"); + REQUIRE_THROWS_WITH(p_R1_u * (TinyMatrix<1>{2}), "error: incompatible operand types Vh(P0:R^1) and R^1x1"); + REQUIRE_THROWS_WITH(p_R2_u * (TinyMatrix<2>{2, 3, 1, 4}), + "error: incompatible operand types Vh(P0:R^2) and R^2x2"); + REQUIRE_THROWS_WITH(p_R3_u * (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), + "error: incompatible operand types Vh(P0:R^3) and R^3x3"); + REQUIRE_THROWS_WITH(p_R2x2_u * (TinyMatrix<1>{2}), + "error: incompatible operand types Vh(P0:R^2x2) and R^1x1"); + REQUIRE_THROWS_WITH(p_R1x1_u * (TinyMatrix<2>{2, 3, 1, 4}), + "error: incompatible operand types Vh(P0:R^1x1) and R^2x2"); + REQUIRE_THROWS_WITH(p_R2x2_u * (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), + "error: incompatible operand types Vh(P0:R^2x2) and R^3x3"); + + REQUIRE_THROWS_WITH(p_Vector3_u * (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), + "error: incompatible operand types Vh(P0Vector:R) and R^3x3"); + REQUIRE_THROWS_WITH(p_Vector3_u * (double{2}), "error: incompatible operand types Vh(P0Vector:R) and R"); + } + + SECTION("X * Vh -> Vh") + { + CHECK_EMBEDDED_XxVH_TO_VH(bool{true}, *, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_XxVH_TO_VH(uint64_t{1}, *, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_XxVH_TO_VH(int64_t{2}, *, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_XxVH_TO_VH(double{1.3}, *, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + + CHECK_EMBEDDED_XxVH_TO_VH(bool{true}, *, p_R1_u, // + DiscreteFunctionR1, DiscreteFunctionR1); + CHECK_EMBEDDED_XxVH_TO_VH(uint64_t{1}, *, p_R1_u, // + DiscreteFunctionR1, DiscreteFunctionR1); + CHECK_EMBEDDED_XxVH_TO_VH(int64_t{2}, *, p_R1_u, // + DiscreteFunctionR1, DiscreteFunctionR1); + CHECK_EMBEDDED_XxVH_TO_VH(double{1.3}, *, p_R1_u, // + DiscreteFunctionR1, DiscreteFunctionR1); + + CHECK_EMBEDDED_XxVH_TO_VH(bool{true}, *, p_R2_u, // + DiscreteFunctionR2, DiscreteFunctionR2); + CHECK_EMBEDDED_XxVH_TO_VH(uint64_t{1}, *, p_R2_u, // + DiscreteFunctionR2, DiscreteFunctionR2); + CHECK_EMBEDDED_XxVH_TO_VH(int64_t{2}, *, p_R2_u, // + DiscreteFunctionR2, DiscreteFunctionR2); + CHECK_EMBEDDED_XxVH_TO_VH(double{1.3}, *, p_R2_u, // + DiscreteFunctionR2, DiscreteFunctionR2); + + CHECK_EMBEDDED_XxVH_TO_VH(bool{true}, *, p_R3_u, // + DiscreteFunctionR3, DiscreteFunctionR3); + CHECK_EMBEDDED_XxVH_TO_VH(uint64_t{1}, *, p_R3_u, // + DiscreteFunctionR3, DiscreteFunctionR3); + CHECK_EMBEDDED_XxVH_TO_VH(int64_t{2}, *, p_R3_u, // + DiscreteFunctionR3, DiscreteFunctionR3); + CHECK_EMBEDDED_XxVH_TO_VH(double{1.3}, *, p_R3_u, // + DiscreteFunctionR3, DiscreteFunctionR3); + + CHECK_EMBEDDED_XxVH_TO_VH(bool{true}, *, p_R1x1_u, // + DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_XxVH_TO_VH(uint64_t{1}, *, p_R1x1_u, // + DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_XxVH_TO_VH(int64_t{2}, *, p_R1x1_u, // + DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_XxVH_TO_VH(double{1.3}, *, p_R1x1_u, // + DiscreteFunctionR1x1, DiscreteFunctionR1x1); + + CHECK_EMBEDDED_XxVH_TO_VH(bool{true}, *, p_R2x2_u, // + DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_XxVH_TO_VH(uint64_t{1}, *, p_R2x2_u, // + DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_XxVH_TO_VH(int64_t{2}, *, p_R2x2_u, // + DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_XxVH_TO_VH(double{1.3}, *, p_R2x2_u, // + DiscreteFunctionR2x2, DiscreteFunctionR2x2); + + CHECK_EMBEDDED_XxVH_TO_VH(bool{true}, *, p_R3x3_u, // + DiscreteFunctionR3x3, DiscreteFunctionR3x3); + CHECK_EMBEDDED_XxVH_TO_VH(uint64_t{1}, *, p_R3x3_u, // + DiscreteFunctionR3x3, DiscreteFunctionR3x3); + CHECK_EMBEDDED_XxVH_TO_VH(int64_t{2}, *, p_R3x3_u, // + DiscreteFunctionR3x3, DiscreteFunctionR3x3); + CHECK_EMBEDDED_XxVH_TO_VH(double{1.3}, *, p_R3x3_u, // + DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + CHECK_EMBEDDED_XxVH_TO_VH((TinyMatrix<1>{1.3}), *, p_R1_u, // + DiscreteFunctionR1, DiscreteFunctionR1); + CHECK_EMBEDDED_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), *, p_R2_u, // + DiscreteFunctionR2, DiscreteFunctionR2); + CHECK_EMBEDDED_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // + 4.7, 2.3, 7.1, // + 9.7, 3.2, 6.8}), *, p_R3_u, // + DiscreteFunctionR3, DiscreteFunctionR3); + + CHECK_EMBEDDED_XxVH_TO_VH((TinyMatrix<1>{1.3}), *, p_R1x1_u, // + DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), *, p_R2x2_u, // + DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // + 4.7, 2.3, 7.1, // + 9.7, 3.2, 6.8}), *, p_R3x3_u, // + DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + CHECK_EMBEDDED_VECTOR_XxVH_TO_VH(bool{true}, *, p_Vector3_u, DiscreteFunctionVector); + CHECK_EMBEDDED_VECTOR_XxVH_TO_VH(uint64_t{1}, *, p_Vector3_u, DiscreteFunctionVector); + CHECK_EMBEDDED_VECTOR_XxVH_TO_VH(int64_t{2}, *, p_Vector3_u, DiscreteFunctionVector); + CHECK_EMBEDDED_VECTOR_XxVH_TO_VH(double{1.3}, *, p_Vector3_u, DiscreteFunctionVector); + + REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_R_u, "error: incompatible operand types R^1x1 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R_u, + "error: incompatible operand types R^2x2 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R_u, + "error: incompatible operand types R^3x3 and Vh(P0:R)"); + + REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_R2_u, "error: incompatible operand types R^1x1 and Vh(P0:R^2)"); + REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R3_u, + "error: incompatible operand types R^2x2 and Vh(P0:R^3)"); + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R2_u, + "error: incompatible operand types R^3x3 and Vh(P0:R^2)"); + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R1_u, + "error: incompatible operand types R^3x3 and Vh(P0:R^1)"); + + REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_R2x2_u, + "error: incompatible operand types R^1x1 and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R3x3_u, + "error: incompatible operand types R^2x2 and Vh(P0:R^3x3)"); + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R2x2_u, + "error: incompatible operand types R^3x3 and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R1x1_u, + "error: incompatible operand types R^2x2 and Vh(P0:R^1x1)"); + + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_Vector3_u, + "error: incompatible operand types R^3x3 and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_Vector3_u, + "error: incompatible operand types R^1x1 and Vh(P0Vector:R)"); + } + } + + SECTION("ratio") + { + SECTION("Vh / Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH(p_R_u, /, p_R_v, // + DiscreteFunctionR, DiscreteFunctionR, DiscreteFunctionR); + + REQUIRE_THROWS_WITH(p_R_u / p_R1_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R2_u / p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R3_u / p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(p_R_u / p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); + + REQUIRE_THROWS_WITH(p_R_u / p_other_mesh_R_u, "error: operands are defined on different meshes"); + } + + SECTION("X / Vh -> Vh") + { + CHECK_EMBEDDED_XxVH_TO_VH(bool{true}, /, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_XxVH_TO_VH(uint64_t{1}, /, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_XxVH_TO_VH(int64_t{2}, /, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_XxVH_TO_VH(double{1.3}, /, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + } + } + } + + SECTION("unary operators") + { + SECTION("unary minus") + { + SECTION("- Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH(-, p_R_u, DiscreteFunctionR); + + CHECK_EMBEDDED_VH_TO_VH(-, p_R1_u, DiscreteFunctionR1); + CHECK_EMBEDDED_VH_TO_VH(-, p_R2_u, DiscreteFunctionR2); + CHECK_EMBEDDED_VH_TO_VH(-, p_R3_u, DiscreteFunctionR3); + + CHECK_EMBEDDED_VH_TO_VH(-, p_R1x1_u, DiscreteFunctionR1x1); + CHECK_EMBEDDED_VH_TO_VH(-, p_R2x2_u, DiscreteFunctionR2x2); + CHECK_EMBEDDED_VH_TO_VH(-, p_R3x3_u, DiscreteFunctionR3x3); + + CHECK_EMBEDDED_VECTOR_VH_TO_VH(-, p_Vector3_u, DiscreteFunctionVector); + } + } + } + } + } +} + +#ifdef __clang__ +#pragma clang optimize on +#endif // __clang__ diff --git a/tests/test_EmbeddedDiscreteFunctionOperators2D.cpp b/tests/test_EmbeddedDiscreteFunctionOperators2D.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fbf114d085d04a76da6715d3493516c9ead57044 --- /dev/null +++ b/tests/test_EmbeddedDiscreteFunctionOperators2D.cpp @@ -0,0 +1,864 @@ +#include <test_EmbeddedDiscreteFunctionOperators.hpp> + +#ifdef __clang__ +#pragma clang optimize off +#endif // __clang__ + +TEST_CASE("EmbeddedDiscreteFunctionOperators2D", "[scheme]") +{ + constexpr size_t Dimension = 2; + + using Rd = TinyVector<Dimension>; + + std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); + + using DiscreteFunctionR = DiscreteFunctionP0<Dimension, const double>; + using DiscreteFunctionR1 = DiscreteFunctionP0<Dimension, const TinyVector<1>>; + using DiscreteFunctionR2 = DiscreteFunctionP0<Dimension, const TinyVector<2>>; + using DiscreteFunctionR3 = DiscreteFunctionP0<Dimension, const TinyVector<3>>; + using DiscreteFunctionR1x1 = DiscreteFunctionP0<Dimension, const TinyMatrix<1>>; + using DiscreteFunctionR2x2 = DiscreteFunctionP0<Dimension, const TinyMatrix<2>>; + using DiscreteFunctionR3x3 = DiscreteFunctionP0<Dimension, const TinyMatrix<3>>; + + using DiscreteFunctionVector = DiscreteFunctionP0Vector<Dimension, const double>; + + for (const auto& named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh = named_mesh.mesh(); + + std::shared_ptr other_mesh = + std::make_shared<Mesh<Connectivity<Dimension>>>(mesh->shared_connectivity(), mesh->xr()); + + CellValue<const Rd> xj = MeshDataManager::instance().getMeshData(*mesh).xj(); + + CellValue<double> u_R_values = [=] { + CellValue<double> build_values{mesh->connectivity()}; + parallel_for( + build_values.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.2 + std::cos(l2Norm(xj[cell_id])); }); + return build_values; + }(); + + CellValue<double> v_R_values = [=] { + CellValue<double> build_values{mesh->connectivity()}; + parallel_for( + build_values.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.6 + std::sin(l2Norm(xj[cell_id])); }); + return build_values; + }(); + + std::shared_ptr p_R_u = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR(mesh, u_R_values)); + std::shared_ptr p_other_mesh_R_u = + std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR(other_mesh, u_R_values)); + std::shared_ptr p_R_v = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR(mesh, v_R_values)); + + std::shared_ptr p_R1_u = [=] { + CellValue<TinyVector<1>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id][0] = 2 * xj[cell_id][0] + 1; }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR1(mesh, uj)); + }(); + + std::shared_ptr p_R1_v = [=] { + CellValue<TinyVector<1>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { vj[cell_id][0] = xj[cell_id][0] * xj[cell_id][0] + 1; }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR1(mesh, vj)); + }(); + + std::shared_ptr p_other_mesh_R1_u = std::make_shared<DiscreteFunctionVariant>( + DiscreteFunctionR1(other_mesh, p_R1_u->get<DiscreteFunctionR1>().cellValues())); + + constexpr auto to_2d = [&](const TinyVector<Dimension>& x) -> TinyVector<2> { + if constexpr (Dimension == 1) { + return TinyVector<2>{x[0], 1 + x[0] * x[0]}; + } else if constexpr (Dimension == 2) { + return TinyVector<2>{x[0], x[1]}; + } else if constexpr (Dimension == 3) { + return TinyVector<2>{x[0], x[1] + x[2]}; + } + }; + + std::shared_ptr p_R2_u = [=] { + CellValue<TinyVector<2>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + uj[cell_id] = TinyVector<2>{2 * x[0] + 1, 1 - x[1]}; + }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR2(mesh, uj)); + }(); + + std::shared_ptr p_R2_v = [=] { + CellValue<TinyVector<2>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + vj[cell_id] = TinyVector<2>{x[0] * x[1] + 1, 2 * x[1]}; + }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR2(mesh, vj)); + }(); + + std::shared_ptr p_other_mesh_R2_u = std::make_shared<DiscreteFunctionVariant>( + DiscreteFunctionR2(other_mesh, p_R2_u->get<DiscreteFunctionR2>().cellValues())); + + constexpr auto to_3d = [&](const TinyVector<Dimension>& x) -> TinyVector<3> { + if constexpr (Dimension == 1) { + return TinyVector<3>{x[0], 1 + x[0] * x[0], 2 - x[0]}; + } else if constexpr (Dimension == 2) { + return TinyVector<3>{x[0], x[1], x[0] + x[1]}; + } else if constexpr (Dimension == 3) { + return TinyVector<3>{x[0], x[1], x[2]}; + } + }; + + std::shared_ptr p_R3_u = [=] { + CellValue<TinyVector<3>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + uj[cell_id] = TinyVector<3>{2 * x[0] + 1, 1 - x[1] * x[2], x[0] + x[2]}; + }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR3(mesh, uj)); + }(); + + std::shared_ptr p_R3_v = [=] { + CellValue<TinyVector<3>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + vj[cell_id] = TinyVector<3>{x[0] * x[1] + 1, 2 * x[1], x[2] * x[0]}; + }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR3(mesh, vj)); + }(); + + std::shared_ptr p_other_mesh_R3_u = std::make_shared<DiscreteFunctionVariant>( + DiscreteFunctionR3(other_mesh, p_R3_u->get<DiscreteFunctionR3>().cellValues())); + + std::shared_ptr p_R1x1_u = [=] { + CellValue<TinyMatrix<1>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { uj[cell_id] = TinyMatrix<1>{2 * xj[cell_id][0] + 1}; }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR1x1(mesh, uj)); + }(); + + std::shared_ptr p_other_mesh_R1x1_u = std::make_shared<DiscreteFunctionVariant>( + DiscreteFunctionR1x1(other_mesh, p_R1x1_u->get<DiscreteFunctionR1x1>().cellValues())); + + std::shared_ptr p_R1x1_v = [=] { + CellValue<TinyMatrix<1>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { vj[cell_id] = TinyMatrix<1>{0.3 - xj[cell_id][0]}; }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR1x1(mesh, vj)); + }(); + + std::shared_ptr p_R2x2_u = [=] { + CellValue<TinyMatrix<2>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + + uj[cell_id] = TinyMatrix<2>{2 * x[0] + 1, 1 - x[1], // + 2 * x[1], -x[0]}; + }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR2x2(mesh, uj)); + }(); + + std::shared_ptr p_other_mesh_R2x2_u = std::make_shared<DiscreteFunctionVariant>( + DiscreteFunctionR2x2(other_mesh, p_R2x2_u->get<DiscreteFunctionR2x2>().cellValues())); + + std::shared_ptr p_R2x2_v = [=] { + CellValue<TinyMatrix<2>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + + vj[cell_id] = TinyMatrix<2>{x[0] + 0.3, 1 - x[1] - x[0], // + 2 * x[1] + x[0], x[1] - x[0]}; + }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR2x2(mesh, vj)); + }(); + + std::shared_ptr p_R3x3_u = [=] { + CellValue<TinyMatrix<3>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + + uj[cell_id] = TinyMatrix<3>{2 * x[0] + 1, 1 - x[1], 3, // + 2 * x[1], -x[0], x[0] - x[1], // + 3 * x[2] - x[1], x[1] - 2 * x[2], x[2] - x[0]}; + }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR3x3(mesh, uj)); + }(); + + std::shared_ptr p_other_mesh_R3x3_u = std::make_shared<DiscreteFunctionVariant>( + DiscreteFunctionR3x3(other_mesh, p_R3x3_u->get<DiscreteFunctionR3x3>().cellValues())); + + std::shared_ptr p_R3x3_v = [=] { + CellValue<TinyMatrix<3>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + + vj[cell_id] = TinyMatrix<3>{0.2 * x[0] + 1, 2 + x[1], 3 - x[2], // + 2.3 * x[2], x[1] - x[0], x[2] - x[1], // + 2 * x[2] + x[0], x[1] + 0.2 * x[2], x[2] - 2 * x[0]}; + }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR3x3(mesh, vj)); + }(); + + std::shared_ptr p_Vector3_u = [=] { + CellArray<double> uj_vector{mesh->connectivity(), 3}; + parallel_for( + uj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + uj_vector[cell_id][0] = 2 * x[0] + 1; + uj_vector[cell_id][1] = 1 - x[1] * x[2]; + uj_vector[cell_id][2] = x[0] + x[2]; + }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionVector(mesh, uj_vector)); + }(); + + std::shared_ptr p_other_mesh_Vector3_u = std::make_shared<DiscreteFunctionVariant>( + DiscreteFunctionVector(other_mesh, p_Vector3_u->get<DiscreteFunctionVector>().cellArrays())); + + std::shared_ptr p_Vector3_v = [=] { + CellArray<double> vj_vector{mesh->connectivity(), 3}; + parallel_for( + vj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + vj_vector[cell_id][0] = x[0] * x[1] + 1; + vj_vector[cell_id][1] = 2 * x[1]; + vj_vector[cell_id][2] = x[2] * x[0]; + }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionVector(mesh, vj_vector)); + }(); + + std::shared_ptr p_Vector2_w = [=] { + CellArray<double> wj_vector{mesh->connectivity(), 2}; + parallel_for( + wj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + wj_vector[cell_id][0] = x[0] + x[1] * 2; + wj_vector[cell_id][1] = x[0] * x[1]; + }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionVector(mesh, wj_vector)); + }(); + + SECTION("binary operators") + { + SECTION("sum") + { + SECTION("Vh + Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH(p_R_u, +, p_R_v, // + DiscreteFunctionR, DiscreteFunctionR, DiscreteFunctionR); + + CHECK_EMBEDDED_VH2_TO_VH(p_R1_u, +, p_R1_v, // + DiscreteFunctionR1, DiscreteFunctionR1, DiscreteFunctionR1); + CHECK_EMBEDDED_VH2_TO_VH(p_R2_u, +, p_R2_v, // + DiscreteFunctionR2, DiscreteFunctionR2, DiscreteFunctionR2); + CHECK_EMBEDDED_VH2_TO_VH(p_R3_u, +, p_R3_v, // + DiscreteFunctionR3, DiscreteFunctionR3, DiscreteFunctionR3); + + CHECK_EMBEDDED_VH2_TO_VH(p_R1x1_u, +, p_R1x1_v, // + DiscreteFunctionR1x1, DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_VH2_TO_VH(p_R2x2_u, +, p_R2x2_v, // + DiscreteFunctionR2x2, DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_VH2_TO_VH(p_R3x3_u, +, p_R3x3_v, // + DiscreteFunctionR3x3, DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + CHECK_EMBEDDED_VECTOR_VH2_TO_VH(p_Vector3_u, +, p_Vector3_v, DiscreteFunctionVector); + + REQUIRE_THROWS_WITH(p_R_u + p_R1_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R2_u + p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R3_u + p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(p_R_u + p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(p_R_u + p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(p_Vector3_u + p_R_v, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R)"); + REQUIRE_THROWS_WITH(p_Vector3_u + p_Vector2_w, "error: Vh(P0Vector:R) spaces have different sizes"); + + REQUIRE_THROWS_WITH(p_R_u + p_other_mesh_R_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R1_u + p_other_mesh_R1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R2_u + p_other_mesh_R2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R3_u + p_other_mesh_R3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R1x1_u + p_other_mesh_R1x1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R2x2_u + p_other_mesh_R2x2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R3x3_u + p_other_mesh_R3x3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_Vector3_u + p_other_mesh_Vector3_u, + "error: operands are defined on different meshes"); + } + + SECTION("Vh + X -> Vh") + { + CHECK_EMBEDDED_VHxX_TO_VH(p_R_u, +, bool{true}, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_VHxX_TO_VH(p_R_u, +, uint64_t{1}, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_VHxX_TO_VH(p_R_u, +, int64_t{2}, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_VHxX_TO_VH(p_R_u, +, double{1.3}, // + DiscreteFunctionR, DiscreteFunctionR); + + CHECK_EMBEDDED_VHxX_TO_VH(p_R1_u, +, (TinyVector<1>{1.3}), // + DiscreteFunctionR1, DiscreteFunctionR1); + CHECK_EMBEDDED_VHxX_TO_VH(p_R2_u, +, (TinyVector<2>{1.2, 2.3}), // + DiscreteFunctionR2, DiscreteFunctionR2); + CHECK_EMBEDDED_VHxX_TO_VH(p_R3_u, +, (TinyVector<3>{3.2, 7.1, 5.2}), // + DiscreteFunctionR3, DiscreteFunctionR3); + + CHECK_EMBEDDED_VHxX_TO_VH(p_R1x1_u, +, (TinyMatrix<1>{1.3}), // + DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_VHxX_TO_VH(p_R2x2_u, +, (TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), // + DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_VHxX_TO_VH(p_R3x3_u, +, + (TinyMatrix<3>{3.2, 7.1, 5.2, // + 4.7, 2.3, 7.1, // + 9.7, 3.2, 6.8}), // + DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + REQUIRE_THROWS_WITH(p_R_u + (TinyVector<1>{1}), "error: incompatible operand types Vh(P0:R) and R^1"); + REQUIRE_THROWS_WITH(p_R_u + (TinyVector<2>{1, 2}), "error: incompatible operand types Vh(P0:R) and R^2"); + REQUIRE_THROWS_WITH(p_R_u + (TinyVector<3>{2, 3, 2}), "error: incompatible operand types Vh(P0:R) and R^3"); + REQUIRE_THROWS_WITH(p_R_u + (TinyMatrix<1>{2}), "error: incompatible operand types Vh(P0:R) and R^1x1"); + REQUIRE_THROWS_WITH(p_R_u + (TinyMatrix<2>{2, 3, 1, 4}), + "error: incompatible operand types Vh(P0:R) and R^2x2"); + REQUIRE_THROWS_WITH(p_R_u + (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), + "error: incompatible operand types Vh(P0:R) and R^3x3"); + + REQUIRE_THROWS_WITH(p_Vector3_u + (double{1}), "error: incompatible operand types Vh(P0Vector:R) and R"); + REQUIRE_THROWS_WITH(p_Vector3_u + (TinyVector<1>{1}), + "error: incompatible operand types Vh(P0Vector:R) and R^1"); + REQUIRE_THROWS_WITH(p_Vector3_u + (TinyVector<2>{1, 2}), + "error: incompatible operand types Vh(P0Vector:R) and R^2"); + } + + SECTION("X + Vh -> Vh") + { + CHECK_EMBEDDED_XxVH_TO_VH(bool{true}, +, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_XxVH_TO_VH(uint64_t{1}, +, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_XxVH_TO_VH(int64_t{2}, +, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_XxVH_TO_VH(double{1.3}, +, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + + CHECK_EMBEDDED_XxVH_TO_VH((TinyVector<1>{1.3}), +, p_R1_u, // + DiscreteFunctionR1, DiscreteFunctionR1); + CHECK_EMBEDDED_XxVH_TO_VH((TinyVector<2>{1.2, 2.3}), +, p_R2_u, // + DiscreteFunctionR2, DiscreteFunctionR2); + CHECK_EMBEDDED_XxVH_TO_VH((TinyVector<3>{3.2, 7.1, 5.2}), +, p_R3_u, // + DiscreteFunctionR3, DiscreteFunctionR3); + + CHECK_EMBEDDED_XxVH_TO_VH((TinyMatrix<1>{1.3}), +, p_R1x1_u, // + DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), +, p_R2x2_u, // + DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // + 4.7, 2.3, 7.1, // + 9.7, 3.2, 6.8}), + +, p_R3x3_u, // + DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + REQUIRE_THROWS_WITH((TinyVector<1>{1}) + p_R_u, "error: incompatible operand types R^1 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) + p_R_u, "error: incompatible operand types R^2 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyVector<3>{2, 3, 2}) + p_R_u, "error: incompatible operand types R^3 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) + p_R_u, "error: incompatible operand types R^1x1 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) + p_R_u, + "error: incompatible operand types R^2x2 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) + p_R_u, + "error: incompatible operand types R^3x3 and Vh(P0:R)"); + + REQUIRE_THROWS_WITH((double{1}) + p_Vector3_u, "error: incompatible operand types R and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH((TinyVector<1>{1}) + p_Vector3_u, + "error: incompatible operand types R^1 and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) + p_Vector3_u, + "error: incompatible operand types R^2 and Vh(P0Vector:R)"); + } + } + + SECTION("difference") + { + SECTION("Vh - Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH(p_R_u, -, p_R_v, // + DiscreteFunctionR, DiscreteFunctionR, DiscreteFunctionR); + + CHECK_EMBEDDED_VH2_TO_VH(p_R1_u, -, p_R1_v, // + DiscreteFunctionR1, DiscreteFunctionR1, DiscreteFunctionR1); + CHECK_EMBEDDED_VH2_TO_VH(p_R2_u, -, p_R2_v, // + DiscreteFunctionR2, DiscreteFunctionR2, DiscreteFunctionR2); + CHECK_EMBEDDED_VH2_TO_VH(p_R3_u, -, p_R3_v, // + DiscreteFunctionR3, DiscreteFunctionR3, DiscreteFunctionR3); + + CHECK_EMBEDDED_VH2_TO_VH(p_R1x1_u, -, p_R1x1_v, // + DiscreteFunctionR1x1, DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_VH2_TO_VH(p_R2x2_u, -, p_R2x2_v, // + DiscreteFunctionR2x2, DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_VH2_TO_VH(p_R3x3_u, -, p_R3x3_v, // + DiscreteFunctionR3x3, DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + CHECK_EMBEDDED_VECTOR_VH2_TO_VH(p_Vector3_u, -, p_Vector3_v, DiscreteFunctionVector); + + REQUIRE_THROWS_WITH(p_R_u - p_R1_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R2_u - p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R3_u - p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(p_R_u - p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(p_Vector3_u - p_R_v, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R)"); + REQUIRE_THROWS_WITH(p_Vector3_u - p_Vector2_w, "error: Vh(P0Vector:R) spaces have different sizes"); + + REQUIRE_THROWS_WITH(p_R_u - p_other_mesh_R_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R1_u - p_other_mesh_R1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R2_u - p_other_mesh_R2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R3_u - p_other_mesh_R3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R1x1_u - p_other_mesh_R1x1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R2x2_u - p_other_mesh_R2x2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R3x3_u - p_other_mesh_R3x3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_Vector3_u - p_other_mesh_Vector3_u, + "error: operands are defined on different meshes"); + } + + SECTION("Vh - X -> Vh") + { + CHECK_EMBEDDED_VHxX_TO_VH(p_R_u, -, bool{true}, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_VHxX_TO_VH(p_R_u, -, uint64_t{1}, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_VHxX_TO_VH(p_R_u, -, int64_t{2}, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_VHxX_TO_VH(p_R_u, -, double{1.3}, // + DiscreteFunctionR, DiscreteFunctionR); + + CHECK_EMBEDDED_VHxX_TO_VH(p_R1_u, -, (TinyVector<1>{1.3}), // + DiscreteFunctionR1, DiscreteFunctionR1); + CHECK_EMBEDDED_VHxX_TO_VH(p_R2_u, -, (TinyVector<2>{1.2, 2.3}), // + DiscreteFunctionR2, DiscreteFunctionR2); + CHECK_EMBEDDED_VHxX_TO_VH(p_R3_u, -, (TinyVector<3>{3.2, 7.1, 5.2}), // + DiscreteFunctionR3, DiscreteFunctionR3); + + CHECK_EMBEDDED_VHxX_TO_VH(p_R1x1_u, -, (TinyMatrix<1>{1.3}), // + DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_VHxX_TO_VH(p_R2x2_u, -, (TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), // + DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_VHxX_TO_VH(p_R3x3_u, -, + (TinyMatrix<3>{3.2, 7.1, 5.2, // + 4.7, 2.3, 7.1, // + 9.7, 3.2, 6.8}), // + DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + REQUIRE_THROWS_WITH(p_R_u - (TinyVector<1>{1}), "error: incompatible operand types Vh(P0:R) and R^1"); + REQUIRE_THROWS_WITH(p_R_u - (TinyVector<2>{1, 2}), "error: incompatible operand types Vh(P0:R) and R^2"); + REQUIRE_THROWS_WITH(p_R_u - (TinyVector<3>{2, 3, 2}), "error: incompatible operand types Vh(P0:R) and R^3"); + REQUIRE_THROWS_WITH(p_R_u - (TinyMatrix<1>{2}), "error: incompatible operand types Vh(P0:R) and R^1x1"); + REQUIRE_THROWS_WITH(p_R_u - (TinyMatrix<2>{2, 3, 1, 4}), + "error: incompatible operand types Vh(P0:R) and R^2x2"); + REQUIRE_THROWS_WITH(p_R_u - (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), + "error: incompatible operand types Vh(P0:R) and R^3x3"); + + REQUIRE_THROWS_WITH(p_Vector3_u - (double{1}), "error: incompatible operand types Vh(P0Vector:R) and R"); + REQUIRE_THROWS_WITH(p_Vector3_u - (TinyVector<1>{1}), + "error: incompatible operand types Vh(P0Vector:R) and R^1"); + REQUIRE_THROWS_WITH(p_Vector3_u - (TinyVector<2>{1, 2}), + "error: incompatible operand types Vh(P0Vector:R) and R^2"); + } + + SECTION("X - Vh -> Vh") + { + CHECK_EMBEDDED_XxVH_TO_VH(bool{true}, -, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_XxVH_TO_VH(uint64_t{1}, -, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_XxVH_TO_VH(int64_t{2}, -, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_XxVH_TO_VH(double{1.3}, -, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + + CHECK_EMBEDDED_XxVH_TO_VH((TinyVector<1>{1.3}), -, p_R1_u, // + DiscreteFunctionR1, DiscreteFunctionR1); + CHECK_EMBEDDED_XxVH_TO_VH((TinyVector<2>{1.2, 2.3}), -, p_R2_u, // + DiscreteFunctionR2, DiscreteFunctionR2); + CHECK_EMBEDDED_XxVH_TO_VH((TinyVector<3>{3.2, 7.1, 5.2}), -, p_R3_u, // + DiscreteFunctionR3, DiscreteFunctionR3); + + CHECK_EMBEDDED_XxVH_TO_VH((TinyMatrix<1>{1.3}), -, p_R1x1_u, // + DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), -, p_R2x2_u, // + DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // + 4.7, 2.3, 7.1, // + 9.7, 3.2, 6.8}), + -, p_R3x3_u, // + DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + REQUIRE_THROWS_WITH((TinyVector<1>{1}) - p_R_u, "error: incompatible operand types R^1 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) - p_R_u, "error: incompatible operand types R^2 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyVector<3>{2, 3, 2}) - p_R_u, "error: incompatible operand types R^3 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) - p_R_u, "error: incompatible operand types R^1x1 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) - p_R_u, + "error: incompatible operand types R^2x2 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) - p_R_u, + "error: incompatible operand types R^3x3 and Vh(P0:R)"); + + REQUIRE_THROWS_WITH((double{1}) - p_Vector3_u, "error: incompatible operand types R and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH((TinyVector<1>{1}) - p_Vector3_u, + "error: incompatible operand types R^1 and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) - p_Vector3_u, + "error: incompatible operand types R^2 and Vh(P0Vector:R)"); + } + } + + SECTION("product") + { + SECTION("Vh * Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH(p_R_u, *, p_R_v, // + DiscreteFunctionR, DiscreteFunctionR, DiscreteFunctionR); + + CHECK_EMBEDDED_VH2_TO_VH(p_R1x1_u, *, p_R1x1_v, // + DiscreteFunctionR1x1, DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_VH2_TO_VH(p_R2x2_u, *, p_R2x2_v, // + DiscreteFunctionR2x2, DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_VH2_TO_VH(p_R3x3_u, *, p_R3x3_v, // + DiscreteFunctionR3x3, DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + CHECK_EMBEDDED_VH2_TO_VH(p_R_u, *, p_R1_v, // + DiscreteFunctionR, DiscreteFunctionR1, DiscreteFunctionR1); + CHECK_EMBEDDED_VH2_TO_VH(p_R_u, *, p_R2_v, // + DiscreteFunctionR, DiscreteFunctionR2, DiscreteFunctionR2); + CHECK_EMBEDDED_VH2_TO_VH(p_R_u, *, p_R3_v, // + DiscreteFunctionR, DiscreteFunctionR3, DiscreteFunctionR3); + + CHECK_EMBEDDED_VH2_TO_VH(p_R_u, *, p_R1x1_v, // + DiscreteFunctionR, DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_VH2_TO_VH(p_R_u, *, p_R2x2_v, // + DiscreteFunctionR, DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_VH2_TO_VH(p_R_u, *, p_R3x3_v, // + DiscreteFunctionR, DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + CHECK_EMBEDDED_VH2_TO_VH(p_R1x1_u, *, p_R1_v, // + DiscreteFunctionR1x1, DiscreteFunctionR1, DiscreteFunctionR1); + CHECK_EMBEDDED_VH2_TO_VH(p_R2x2_u, *, p_R2_v, // + DiscreteFunctionR2x2, DiscreteFunctionR2, DiscreteFunctionR2); + CHECK_EMBEDDED_VH2_TO_VH(p_R3x3_u, *, p_R3_v, // + DiscreteFunctionR3x3, DiscreteFunctionR3, DiscreteFunctionR3); + + { + std::shared_ptr p_u_op_v = p_R_u * p_Vector3_v; + + REQUIRE(p_u_op_v.use_count() > 0); + DiscreteFunctionVector u_op_v = p_u_op_v->get<DiscreteFunctionVector>(); + + auto u_values = p_R_u->get<DiscreteFunctionR>().cellValues(); + auto v_arrays = p_Vector3_v->get<DiscreteFunctionVector>().cellArrays(); + bool is_same = true; + for (CellId cell_id = 0; cell_id < u_values.numberOfItems(); ++cell_id) { + for (size_t i = 0; i < u_op_v.size(); ++i) { + if (u_op_v[cell_id][i] != (u_values[cell_id] * v_arrays[cell_id][i])) { + is_same = false; + break; + } + } + } + + REQUIRE(is_same); + } + + REQUIRE_THROWS_WITH(p_R1_u * p_R1_v, "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R2_u * p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R3_u * p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(p_R1_u * p_R2x2_v, "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^2x2)"); + + REQUIRE_THROWS_WITH(p_R1x1_u * p_R2x2_v, "error: incompatible operand types Vh(P0:R^1x1) and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(p_R2x2_u * p_R3x3_v, "error: incompatible operand types Vh(P0:R^2x2) and Vh(P0:R^3x3)"); + REQUIRE_THROWS_WITH(p_R3x3_u * p_R1x1_v, "error: incompatible operand types Vh(P0:R^3x3) and Vh(P0:R^1x1)"); + + REQUIRE_THROWS_WITH(p_R1x1_u * p_R2_v, "error: incompatible operand types Vh(P0:R^1x1) and Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(p_R2x2_u * p_R3_v, "error: incompatible operand types Vh(P0:R^2x2) and Vh(P0:R^3)"); + REQUIRE_THROWS_WITH(p_R3x3_u * p_R1_v, "error: incompatible operand types Vh(P0:R^3x3) and Vh(P0:R^1)"); + + REQUIRE_THROWS_WITH(p_R1_u * p_Vector3_v, + "error: incompatible operand types Vh(P0:R^1) and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH(p_R2_u * p_Vector3_v, + "error: incompatible operand types Vh(P0:R^2) and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH(p_R3_u * p_Vector3_v, + "error: incompatible operand types Vh(P0:R^3) and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH(p_R1x1_u * p_Vector3_v, + "error: incompatible operand types Vh(P0:R^1x1) and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH(p_R2x2_u * p_Vector3_v, + "error: incompatible operand types Vh(P0:R^2x2) and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH(p_R3x3_u * p_Vector3_v, + "error: incompatible operand types Vh(P0:R^3x3) and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH(p_Vector3_u * p_Vector3_v, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0Vector:R)"); + + REQUIRE_THROWS_WITH(p_Vector3_v * p_R_u, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R)"); + REQUIRE_THROWS_WITH(p_Vector3_v * p_R1_u, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_Vector3_v * p_R2_u, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(p_Vector3_v * p_R3_u, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^3)"); + REQUIRE_THROWS_WITH(p_Vector3_v * p_R1x1_u, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(p_Vector3_v * p_R2x2_u, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(p_Vector3_v * p_R3x3_u, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^3x3)"); + + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R1x1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R2x2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R3x3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R1x1_u * p_other_mesh_R1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R2x2_u * p_other_mesh_R2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R3x3_u * p_other_mesh_R3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_Vector3_u, "error: operands are defined on different meshes"); + } + + SECTION("Vh * X -> Vh") + { + CHECK_EMBEDDED_VHxX_TO_VH(p_R_u, *, bool{true}, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_VHxX_TO_VH(p_R_u, *, uint64_t{1}, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_VHxX_TO_VH(p_R_u, *, int64_t{2}, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_VHxX_TO_VH(p_R_u, *, double{1.3}, // + DiscreteFunctionR, DiscreteFunctionR); + + CHECK_EMBEDDED_VHxX_TO_VH(p_R1x1_u, *, (TinyMatrix<1>{1.3}), // + DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_VHxX_TO_VH(p_R2x2_u, *, (TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), // + DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_VHxX_TO_VH(p_R3x3_u, *, + (TinyMatrix<3>{3.2, 7.1, 5.2, // + 4.7, 2.3, 7.1, // + 9.7, 3.2, 6.8}), // + DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + CHECK_EMBEDDED_VHxX_TO_VH(p_R1x1_u, *, (TinyVector<1>{1.3}), // + DiscreteFunctionR1x1, DiscreteFunctionR1); + CHECK_EMBEDDED_VHxX_TO_VH(p_R2x2_u, *, (TinyVector<2>{1.2, 2.3}), // + DiscreteFunctionR2x2, DiscreteFunctionR2); + CHECK_EMBEDDED_VHxX_TO_VH(p_R3x3_u, *, (TinyVector<3>{3.2, 7.1, 5.2}), // + DiscreteFunctionR3x3, DiscreteFunctionR3); + + REQUIRE_THROWS_WITH(p_R1_u * (TinyVector<1>{1}), "error: incompatible operand types Vh(P0:R^1) and R^1"); + REQUIRE_THROWS_WITH(p_R2_u * (TinyVector<2>{1, 2}), "error: incompatible operand types Vh(P0:R^2) and R^2"); + REQUIRE_THROWS_WITH(p_R3_u * (TinyVector<3>{2, 3, 2}), + "error: incompatible operand types Vh(P0:R^3) and R^3"); + REQUIRE_THROWS_WITH(p_R1_u * (TinyMatrix<1>{2}), "error: incompatible operand types Vh(P0:R^1) and R^1x1"); + REQUIRE_THROWS_WITH(p_R2_u * (TinyMatrix<2>{2, 3, 1, 4}), + "error: incompatible operand types Vh(P0:R^2) and R^2x2"); + REQUIRE_THROWS_WITH(p_R3_u * (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), + "error: incompatible operand types Vh(P0:R^3) and R^3x3"); + REQUIRE_THROWS_WITH(p_R2x2_u * (TinyMatrix<1>{2}), + "error: incompatible operand types Vh(P0:R^2x2) and R^1x1"); + REQUIRE_THROWS_WITH(p_R1x1_u * (TinyMatrix<2>{2, 3, 1, 4}), + "error: incompatible operand types Vh(P0:R^1x1) and R^2x2"); + REQUIRE_THROWS_WITH(p_R2x2_u * (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), + "error: incompatible operand types Vh(P0:R^2x2) and R^3x3"); + + REQUIRE_THROWS_WITH(p_Vector3_u * (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), + "error: incompatible operand types Vh(P0Vector:R) and R^3x3"); + REQUIRE_THROWS_WITH(p_Vector3_u * (double{2}), "error: incompatible operand types Vh(P0Vector:R) and R"); + } + + SECTION("X * Vh -> Vh") + { + CHECK_EMBEDDED_XxVH_TO_VH(bool{true}, *, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_XxVH_TO_VH(uint64_t{1}, *, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_XxVH_TO_VH(int64_t{2}, *, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_XxVH_TO_VH(double{1.3}, *, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + + CHECK_EMBEDDED_XxVH_TO_VH(bool{true}, *, p_R1_u, // + DiscreteFunctionR1, DiscreteFunctionR1); + CHECK_EMBEDDED_XxVH_TO_VH(uint64_t{1}, *, p_R1_u, // + DiscreteFunctionR1, DiscreteFunctionR1); + CHECK_EMBEDDED_XxVH_TO_VH(int64_t{2}, *, p_R1_u, // + DiscreteFunctionR1, DiscreteFunctionR1); + CHECK_EMBEDDED_XxVH_TO_VH(double{1.3}, *, p_R1_u, // + DiscreteFunctionR1, DiscreteFunctionR1); + + CHECK_EMBEDDED_XxVH_TO_VH(bool{true}, *, p_R2_u, // + DiscreteFunctionR2, DiscreteFunctionR2); + CHECK_EMBEDDED_XxVH_TO_VH(uint64_t{1}, *, p_R2_u, // + DiscreteFunctionR2, DiscreteFunctionR2); + CHECK_EMBEDDED_XxVH_TO_VH(int64_t{2}, *, p_R2_u, // + DiscreteFunctionR2, DiscreteFunctionR2); + CHECK_EMBEDDED_XxVH_TO_VH(double{1.3}, *, p_R2_u, // + DiscreteFunctionR2, DiscreteFunctionR2); + + CHECK_EMBEDDED_XxVH_TO_VH(bool{true}, *, p_R3_u, // + DiscreteFunctionR3, DiscreteFunctionR3); + CHECK_EMBEDDED_XxVH_TO_VH(uint64_t{1}, *, p_R3_u, // + DiscreteFunctionR3, DiscreteFunctionR3); + CHECK_EMBEDDED_XxVH_TO_VH(int64_t{2}, *, p_R3_u, // + DiscreteFunctionR3, DiscreteFunctionR3); + CHECK_EMBEDDED_XxVH_TO_VH(double{1.3}, *, p_R3_u, // + DiscreteFunctionR3, DiscreteFunctionR3); + + CHECK_EMBEDDED_XxVH_TO_VH(bool{true}, *, p_R1x1_u, // + DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_XxVH_TO_VH(uint64_t{1}, *, p_R1x1_u, // + DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_XxVH_TO_VH(int64_t{2}, *, p_R1x1_u, // + DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_XxVH_TO_VH(double{1.3}, *, p_R1x1_u, // + DiscreteFunctionR1x1, DiscreteFunctionR1x1); + + CHECK_EMBEDDED_XxVH_TO_VH(bool{true}, *, p_R2x2_u, // + DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_XxVH_TO_VH(uint64_t{1}, *, p_R2x2_u, // + DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_XxVH_TO_VH(int64_t{2}, *, p_R2x2_u, // + DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_XxVH_TO_VH(double{1.3}, *, p_R2x2_u, // + DiscreteFunctionR2x2, DiscreteFunctionR2x2); + + CHECK_EMBEDDED_XxVH_TO_VH(bool{true}, *, p_R3x3_u, // + DiscreteFunctionR3x3, DiscreteFunctionR3x3); + CHECK_EMBEDDED_XxVH_TO_VH(uint64_t{1}, *, p_R3x3_u, // + DiscreteFunctionR3x3, DiscreteFunctionR3x3); + CHECK_EMBEDDED_XxVH_TO_VH(int64_t{2}, *, p_R3x3_u, // + DiscreteFunctionR3x3, DiscreteFunctionR3x3); + CHECK_EMBEDDED_XxVH_TO_VH(double{1.3}, *, p_R3x3_u, // + DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + CHECK_EMBEDDED_XxVH_TO_VH((TinyMatrix<1>{1.3}), *, p_R1_u, // + DiscreteFunctionR1, DiscreteFunctionR1); + CHECK_EMBEDDED_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), *, p_R2_u, // + DiscreteFunctionR2, DiscreteFunctionR2); + CHECK_EMBEDDED_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // + 4.7, 2.3, 7.1, // + 9.7, 3.2, 6.8}), + *, p_R3_u, // + DiscreteFunctionR3, DiscreteFunctionR3); + + CHECK_EMBEDDED_XxVH_TO_VH((TinyMatrix<1>{1.3}), *, p_R1x1_u, // + DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), *, p_R2x2_u, // + DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // + 4.7, 2.3, 7.1, // + 9.7, 3.2, 6.8}), + *, p_R3x3_u, // + DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + CHECK_EMBEDDED_VECTOR_XxVH_TO_VH(bool{true}, *, p_Vector3_u, DiscreteFunctionVector); + CHECK_EMBEDDED_VECTOR_XxVH_TO_VH(uint64_t{1}, *, p_Vector3_u, DiscreteFunctionVector); + CHECK_EMBEDDED_VECTOR_XxVH_TO_VH(int64_t{2}, *, p_Vector3_u, DiscreteFunctionVector); + CHECK_EMBEDDED_VECTOR_XxVH_TO_VH(double{1.3}, *, p_Vector3_u, DiscreteFunctionVector); + + REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_R_u, "error: incompatible operand types R^1x1 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R_u, + "error: incompatible operand types R^2x2 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R_u, + "error: incompatible operand types R^3x3 and Vh(P0:R)"); + + REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_R2_u, "error: incompatible operand types R^1x1 and Vh(P0:R^2)"); + REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R3_u, + "error: incompatible operand types R^2x2 and Vh(P0:R^3)"); + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R2_u, + "error: incompatible operand types R^3x3 and Vh(P0:R^2)"); + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R1_u, + "error: incompatible operand types R^3x3 and Vh(P0:R^1)"); + + REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_R2x2_u, + "error: incompatible operand types R^1x1 and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R3x3_u, + "error: incompatible operand types R^2x2 and Vh(P0:R^3x3)"); + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R2x2_u, + "error: incompatible operand types R^3x3 and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R1x1_u, + "error: incompatible operand types R^2x2 and Vh(P0:R^1x1)"); + + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_Vector3_u, + "error: incompatible operand types R^3x3 and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_Vector3_u, + "error: incompatible operand types R^1x1 and Vh(P0Vector:R)"); + } + } + + SECTION("ratio") + { + SECTION("Vh / Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH(p_R_u, /, p_R_v, // + DiscreteFunctionR, DiscreteFunctionR, DiscreteFunctionR); + + REQUIRE_THROWS_WITH(p_R_u / p_R1_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R2_u / p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R3_u / p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(p_R_u / p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); + + REQUIRE_THROWS_WITH(p_R_u / p_other_mesh_R_u, "error: operands are defined on different meshes"); + } + + SECTION("X / Vh -> Vh") + { + CHECK_EMBEDDED_XxVH_TO_VH(bool{true}, /, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_XxVH_TO_VH(uint64_t{1}, /, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_XxVH_TO_VH(int64_t{2}, /, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_XxVH_TO_VH(double{1.3}, /, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + } + } + } + + SECTION("unary operators") + { + SECTION("unary minus") + { + SECTION("- Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH(-, p_R_u, DiscreteFunctionR); + + CHECK_EMBEDDED_VH_TO_VH(-, p_R1_u, DiscreteFunctionR1); + CHECK_EMBEDDED_VH_TO_VH(-, p_R2_u, DiscreteFunctionR2); + CHECK_EMBEDDED_VH_TO_VH(-, p_R3_u, DiscreteFunctionR3); + + CHECK_EMBEDDED_VH_TO_VH(-, p_R1x1_u, DiscreteFunctionR1x1); + CHECK_EMBEDDED_VH_TO_VH(-, p_R2x2_u, DiscreteFunctionR2x2); + CHECK_EMBEDDED_VH_TO_VH(-, p_R3x3_u, DiscreteFunctionR3x3); + + CHECK_EMBEDDED_VECTOR_VH_TO_VH(-, p_Vector3_u, DiscreteFunctionVector); + } + } + } + } + } +} + +#ifdef __clang__ +#pragma clang optimize on +#endif // __clang__ diff --git a/tests/test_EmbeddedDiscreteFunctionOperators3D.cpp b/tests/test_EmbeddedDiscreteFunctionOperators3D.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1b24d0a9128db6bcc8d4c3eff70a38a3c5fc9ee4 --- /dev/null +++ b/tests/test_EmbeddedDiscreteFunctionOperators3D.cpp @@ -0,0 +1,864 @@ +#include <test_EmbeddedDiscreteFunctionOperators.hpp> + +#ifdef __clang__ +#pragma clang optimize off +#endif // __clang__ + +TEST_CASE("EmbeddedDiscreteFunctionOperators3D", "[scheme]") +{ + constexpr size_t Dimension = 3; + + using Rd = TinyVector<Dimension>; + + std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); + + using DiscreteFunctionR = DiscreteFunctionP0<Dimension, const double>; + using DiscreteFunctionR1 = DiscreteFunctionP0<Dimension, const TinyVector<1>>; + using DiscreteFunctionR2 = DiscreteFunctionP0<Dimension, const TinyVector<2>>; + using DiscreteFunctionR3 = DiscreteFunctionP0<Dimension, const TinyVector<3>>; + using DiscreteFunctionR1x1 = DiscreteFunctionP0<Dimension, const TinyMatrix<1>>; + using DiscreteFunctionR2x2 = DiscreteFunctionP0<Dimension, const TinyMatrix<2>>; + using DiscreteFunctionR3x3 = DiscreteFunctionP0<Dimension, const TinyMatrix<3>>; + + using DiscreteFunctionVector = DiscreteFunctionP0Vector<Dimension, const double>; + + for (const auto& named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh = named_mesh.mesh(); + + std::shared_ptr other_mesh = + std::make_shared<Mesh<Connectivity<Dimension>>>(mesh->shared_connectivity(), mesh->xr()); + + CellValue<const Rd> xj = MeshDataManager::instance().getMeshData(*mesh).xj(); + + CellValue<double> u_R_values = [=] { + CellValue<double> build_values{mesh->connectivity()}; + parallel_for( + build_values.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.2 + std::cos(l2Norm(xj[cell_id])); }); + return build_values; + }(); + + CellValue<double> v_R_values = [=] { + CellValue<double> build_values{mesh->connectivity()}; + parallel_for( + build_values.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.6 + std::sin(l2Norm(xj[cell_id])); }); + return build_values; + }(); + + std::shared_ptr p_R_u = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR(mesh, u_R_values)); + std::shared_ptr p_other_mesh_R_u = + std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR(other_mesh, u_R_values)); + std::shared_ptr p_R_v = std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR(mesh, v_R_values)); + + std::shared_ptr p_R1_u = [=] { + CellValue<TinyVector<1>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id][0] = 2 * xj[cell_id][0] + 1; }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR1(mesh, uj)); + }(); + + std::shared_ptr p_R1_v = [=] { + CellValue<TinyVector<1>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { vj[cell_id][0] = xj[cell_id][0] * xj[cell_id][0] + 1; }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR1(mesh, vj)); + }(); + + std::shared_ptr p_other_mesh_R1_u = std::make_shared<DiscreteFunctionVariant>( + DiscreteFunctionR1(other_mesh, p_R1_u->get<DiscreteFunctionR1>().cellValues())); + + constexpr auto to_2d = [&](const TinyVector<Dimension>& x) -> TinyVector<2> { + if constexpr (Dimension == 1) { + return TinyVector<2>{x[0], 1 + x[0] * x[0]}; + } else if constexpr (Dimension == 2) { + return TinyVector<2>{x[0], x[1]}; + } else if constexpr (Dimension == 3) { + return TinyVector<2>{x[0], x[1] + x[2]}; + } + }; + + std::shared_ptr p_R2_u = [=] { + CellValue<TinyVector<2>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + uj[cell_id] = TinyVector<2>{2 * x[0] + 1, 1 - x[1]}; + }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR2(mesh, uj)); + }(); + + std::shared_ptr p_R2_v = [=] { + CellValue<TinyVector<2>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + vj[cell_id] = TinyVector<2>{x[0] * x[1] + 1, 2 * x[1]}; + }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR2(mesh, vj)); + }(); + + std::shared_ptr p_other_mesh_R2_u = std::make_shared<DiscreteFunctionVariant>( + DiscreteFunctionR2(other_mesh, p_R2_u->get<DiscreteFunctionR2>().cellValues())); + + constexpr auto to_3d = [&](const TinyVector<Dimension>& x) -> TinyVector<3> { + if constexpr (Dimension == 1) { + return TinyVector<3>{x[0], 1 + x[0] * x[0], 2 - x[0]}; + } else if constexpr (Dimension == 2) { + return TinyVector<3>{x[0], x[1], x[0] + x[1]}; + } else if constexpr (Dimension == 3) { + return TinyVector<3>{x[0], x[1], x[2]}; + } + }; + + std::shared_ptr p_R3_u = [=] { + CellValue<TinyVector<3>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + uj[cell_id] = TinyVector<3>{2 * x[0] + 1, 1 - x[1] * x[2], x[0] + x[2]}; + }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR3(mesh, uj)); + }(); + + std::shared_ptr p_R3_v = [=] { + CellValue<TinyVector<3>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + vj[cell_id] = TinyVector<3>{x[0] * x[1] + 1, 2 * x[1], x[2] * x[0]}; + }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR3(mesh, vj)); + }(); + + std::shared_ptr p_other_mesh_R3_u = std::make_shared<DiscreteFunctionVariant>( + DiscreteFunctionR3(other_mesh, p_R3_u->get<DiscreteFunctionR3>().cellValues())); + + std::shared_ptr p_R1x1_u = [=] { + CellValue<TinyMatrix<1>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), + PUGS_LAMBDA(const CellId cell_id) { uj[cell_id] = TinyMatrix<1>{2 * xj[cell_id][0] + 1}; }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR1x1(mesh, uj)); + }(); + + std::shared_ptr p_other_mesh_R1x1_u = std::make_shared<DiscreteFunctionVariant>( + DiscreteFunctionR1x1(other_mesh, p_R1x1_u->get<DiscreteFunctionR1x1>().cellValues())); + + std::shared_ptr p_R1x1_v = [=] { + CellValue<TinyMatrix<1>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { vj[cell_id] = TinyMatrix<1>{0.3 - xj[cell_id][0]}; }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR1x1(mesh, vj)); + }(); + + std::shared_ptr p_R2x2_u = [=] { + CellValue<TinyMatrix<2>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + + uj[cell_id] = TinyMatrix<2>{2 * x[0] + 1, 1 - x[1], // + 2 * x[1], -x[0]}; + }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR2x2(mesh, uj)); + }(); + + std::shared_ptr p_other_mesh_R2x2_u = std::make_shared<DiscreteFunctionVariant>( + DiscreteFunctionR2x2(other_mesh, p_R2x2_u->get<DiscreteFunctionR2x2>().cellValues())); + + std::shared_ptr p_R2x2_v = [=] { + CellValue<TinyMatrix<2>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<2> x = to_2d(xj[cell_id]); + + vj[cell_id] = TinyMatrix<2>{x[0] + 0.3, 1 - x[1] - x[0], // + 2 * x[1] + x[0], x[1] - x[0]}; + }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR2x2(mesh, vj)); + }(); + + std::shared_ptr p_R3x3_u = [=] { + CellValue<TinyMatrix<3>> uj{mesh->connectivity()}; + parallel_for( + uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + + uj[cell_id] = TinyMatrix<3>{2 * x[0] + 1, 1 - x[1], 3, // + 2 * x[1], -x[0], x[0] - x[1], // + 3 * x[2] - x[1], x[1] - 2 * x[2], x[2] - x[0]}; + }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR3x3(mesh, uj)); + }(); + + std::shared_ptr p_other_mesh_R3x3_u = std::make_shared<DiscreteFunctionVariant>( + DiscreteFunctionR3x3(other_mesh, p_R3x3_u->get<DiscreteFunctionR3x3>().cellValues())); + + std::shared_ptr p_R3x3_v = [=] { + CellValue<TinyMatrix<3>> vj{mesh->connectivity()}; + parallel_for( + vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + + vj[cell_id] = TinyMatrix<3>{0.2 * x[0] + 1, 2 + x[1], 3 - x[2], // + 2.3 * x[2], x[1] - x[0], x[2] - x[1], // + 2 * x[2] + x[0], x[1] + 0.2 * x[2], x[2] - 2 * x[0]}; + }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionR3x3(mesh, vj)); + }(); + + std::shared_ptr p_Vector3_u = [=] { + CellArray<double> uj_vector{mesh->connectivity(), 3}; + parallel_for( + uj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + uj_vector[cell_id][0] = 2 * x[0] + 1; + uj_vector[cell_id][1] = 1 - x[1] * x[2]; + uj_vector[cell_id][2] = x[0] + x[2]; + }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionVector(mesh, uj_vector)); + }(); + + std::shared_ptr p_other_mesh_Vector3_u = std::make_shared<DiscreteFunctionVariant>( + DiscreteFunctionVector(other_mesh, p_Vector3_u->get<DiscreteFunctionVector>().cellArrays())); + + std::shared_ptr p_Vector3_v = [=] { + CellArray<double> vj_vector{mesh->connectivity(), 3}; + parallel_for( + vj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + vj_vector[cell_id][0] = x[0] * x[1] + 1; + vj_vector[cell_id][1] = 2 * x[1]; + vj_vector[cell_id][2] = x[2] * x[0]; + }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionVector(mesh, vj_vector)); + }(); + + std::shared_ptr p_Vector2_w = [=] { + CellArray<double> wj_vector{mesh->connectivity(), 2}; + parallel_for( + wj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { + const TinyVector<3> x = to_3d(xj[cell_id]); + wj_vector[cell_id][0] = x[0] + x[1] * 2; + wj_vector[cell_id][1] = x[0] * x[1]; + }); + + return std::make_shared<DiscreteFunctionVariant>(DiscreteFunctionVector(mesh, wj_vector)); + }(); + + SECTION("binary operators") + { + SECTION("sum") + { + SECTION("Vh + Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH(p_R_u, +, p_R_v, // + DiscreteFunctionR, DiscreteFunctionR, DiscreteFunctionR); + + CHECK_EMBEDDED_VH2_TO_VH(p_R1_u, +, p_R1_v, // + DiscreteFunctionR1, DiscreteFunctionR1, DiscreteFunctionR1); + CHECK_EMBEDDED_VH2_TO_VH(p_R2_u, +, p_R2_v, // + DiscreteFunctionR2, DiscreteFunctionR2, DiscreteFunctionR2); + CHECK_EMBEDDED_VH2_TO_VH(p_R3_u, +, p_R3_v, // + DiscreteFunctionR3, DiscreteFunctionR3, DiscreteFunctionR3); + + CHECK_EMBEDDED_VH2_TO_VH(p_R1x1_u, +, p_R1x1_v, // + DiscreteFunctionR1x1, DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_VH2_TO_VH(p_R2x2_u, +, p_R2x2_v, // + DiscreteFunctionR2x2, DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_VH2_TO_VH(p_R3x3_u, +, p_R3x3_v, // + DiscreteFunctionR3x3, DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + CHECK_EMBEDDED_VECTOR_VH2_TO_VH(p_Vector3_u, +, p_Vector3_v, DiscreteFunctionVector); + + REQUIRE_THROWS_WITH(p_R_u + p_R1_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R2_u + p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R3_u + p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(p_R_u + p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(p_R_u + p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(p_Vector3_u + p_R_v, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R)"); + REQUIRE_THROWS_WITH(p_Vector3_u + p_Vector2_w, "error: Vh(P0Vector:R) spaces have different sizes"); + + REQUIRE_THROWS_WITH(p_R_u + p_other_mesh_R_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R1_u + p_other_mesh_R1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R2_u + p_other_mesh_R2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R3_u + p_other_mesh_R3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R1x1_u + p_other_mesh_R1x1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R2x2_u + p_other_mesh_R2x2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R3x3_u + p_other_mesh_R3x3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_Vector3_u + p_other_mesh_Vector3_u, + "error: operands are defined on different meshes"); + } + + SECTION("Vh + X -> Vh") + { + CHECK_EMBEDDED_VHxX_TO_VH(p_R_u, +, bool{true}, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_VHxX_TO_VH(p_R_u, +, uint64_t{1}, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_VHxX_TO_VH(p_R_u, +, int64_t{2}, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_VHxX_TO_VH(p_R_u, +, double{1.3}, // + DiscreteFunctionR, DiscreteFunctionR); + + CHECK_EMBEDDED_VHxX_TO_VH(p_R1_u, +, (TinyVector<1>{1.3}), // + DiscreteFunctionR1, DiscreteFunctionR1); + CHECK_EMBEDDED_VHxX_TO_VH(p_R2_u, +, (TinyVector<2>{1.2, 2.3}), // + DiscreteFunctionR2, DiscreteFunctionR2); + CHECK_EMBEDDED_VHxX_TO_VH(p_R3_u, +, (TinyVector<3>{3.2, 7.1, 5.2}), // + DiscreteFunctionR3, DiscreteFunctionR3); + + CHECK_EMBEDDED_VHxX_TO_VH(p_R1x1_u, +, (TinyMatrix<1>{1.3}), // + DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_VHxX_TO_VH(p_R2x2_u, +, (TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), // + DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_VHxX_TO_VH(p_R3x3_u, +, + (TinyMatrix<3>{3.2, 7.1, 5.2, // + 4.7, 2.3, 7.1, // + 9.7, 3.2, 6.8}), // + DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + REQUIRE_THROWS_WITH(p_R_u + (TinyVector<1>{1}), "error: incompatible operand types Vh(P0:R) and R^1"); + REQUIRE_THROWS_WITH(p_R_u + (TinyVector<2>{1, 2}), "error: incompatible operand types Vh(P0:R) and R^2"); + REQUIRE_THROWS_WITH(p_R_u + (TinyVector<3>{2, 3, 2}), "error: incompatible operand types Vh(P0:R) and R^3"); + REQUIRE_THROWS_WITH(p_R_u + (TinyMatrix<1>{2}), "error: incompatible operand types Vh(P0:R) and R^1x1"); + REQUIRE_THROWS_WITH(p_R_u + (TinyMatrix<2>{2, 3, 1, 4}), + "error: incompatible operand types Vh(P0:R) and R^2x2"); + REQUIRE_THROWS_WITH(p_R_u + (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), + "error: incompatible operand types Vh(P0:R) and R^3x3"); + + REQUIRE_THROWS_WITH(p_Vector3_u + (double{1}), "error: incompatible operand types Vh(P0Vector:R) and R"); + REQUIRE_THROWS_WITH(p_Vector3_u + (TinyVector<1>{1}), + "error: incompatible operand types Vh(P0Vector:R) and R^1"); + REQUIRE_THROWS_WITH(p_Vector3_u + (TinyVector<2>{1, 2}), + "error: incompatible operand types Vh(P0Vector:R) and R^2"); + } + + SECTION("X + Vh -> Vh") + { + CHECK_EMBEDDED_XxVH_TO_VH(bool{true}, +, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_XxVH_TO_VH(uint64_t{1}, +, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_XxVH_TO_VH(int64_t{2}, +, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_XxVH_TO_VH(double{1.3}, +, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + + CHECK_EMBEDDED_XxVH_TO_VH((TinyVector<1>{1.3}), +, p_R1_u, // + DiscreteFunctionR1, DiscreteFunctionR1); + CHECK_EMBEDDED_XxVH_TO_VH((TinyVector<2>{1.2, 2.3}), +, p_R2_u, // + DiscreteFunctionR2, DiscreteFunctionR2); + CHECK_EMBEDDED_XxVH_TO_VH((TinyVector<3>{3.2, 7.1, 5.2}), +, p_R3_u, // + DiscreteFunctionR3, DiscreteFunctionR3); + + CHECK_EMBEDDED_XxVH_TO_VH((TinyMatrix<1>{1.3}), +, p_R1x1_u, // + DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), +, p_R2x2_u, // + DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // + 4.7, 2.3, 7.1, // + 9.7, 3.2, 6.8}), + +, p_R3x3_u, // + DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + REQUIRE_THROWS_WITH((TinyVector<1>{1}) + p_R_u, "error: incompatible operand types R^1 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) + p_R_u, "error: incompatible operand types R^2 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyVector<3>{2, 3, 2}) + p_R_u, "error: incompatible operand types R^3 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) + p_R_u, "error: incompatible operand types R^1x1 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) + p_R_u, + "error: incompatible operand types R^2x2 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) + p_R_u, + "error: incompatible operand types R^3x3 and Vh(P0:R)"); + + REQUIRE_THROWS_WITH((double{1}) + p_Vector3_u, "error: incompatible operand types R and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH((TinyVector<1>{1}) + p_Vector3_u, + "error: incompatible operand types R^1 and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) + p_Vector3_u, + "error: incompatible operand types R^2 and Vh(P0Vector:R)"); + } + } + + SECTION("difference") + { + SECTION("Vh - Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH(p_R_u, -, p_R_v, // + DiscreteFunctionR, DiscreteFunctionR, DiscreteFunctionR); + + CHECK_EMBEDDED_VH2_TO_VH(p_R1_u, -, p_R1_v, // + DiscreteFunctionR1, DiscreteFunctionR1, DiscreteFunctionR1); + CHECK_EMBEDDED_VH2_TO_VH(p_R2_u, -, p_R2_v, // + DiscreteFunctionR2, DiscreteFunctionR2, DiscreteFunctionR2); + CHECK_EMBEDDED_VH2_TO_VH(p_R3_u, -, p_R3_v, // + DiscreteFunctionR3, DiscreteFunctionR3, DiscreteFunctionR3); + + CHECK_EMBEDDED_VH2_TO_VH(p_R1x1_u, -, p_R1x1_v, // + DiscreteFunctionR1x1, DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_VH2_TO_VH(p_R2x2_u, -, p_R2x2_v, // + DiscreteFunctionR2x2, DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_VH2_TO_VH(p_R3x3_u, -, p_R3x3_v, // + DiscreteFunctionR3x3, DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + CHECK_EMBEDDED_VECTOR_VH2_TO_VH(p_Vector3_u, -, p_Vector3_v, DiscreteFunctionVector); + + REQUIRE_THROWS_WITH(p_R_u - p_R1_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R2_u - p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R3_u - p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(p_R_u - p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(p_Vector3_u - p_R_v, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R)"); + REQUIRE_THROWS_WITH(p_Vector3_u - p_Vector2_w, "error: Vh(P0Vector:R) spaces have different sizes"); + + REQUIRE_THROWS_WITH(p_R_u - p_other_mesh_R_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R1_u - p_other_mesh_R1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R2_u - p_other_mesh_R2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R3_u - p_other_mesh_R3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R1x1_u - p_other_mesh_R1x1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R2x2_u - p_other_mesh_R2x2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R3x3_u - p_other_mesh_R3x3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_Vector3_u - p_other_mesh_Vector3_u, + "error: operands are defined on different meshes"); + } + + SECTION("Vh - X -> Vh") + { + CHECK_EMBEDDED_VHxX_TO_VH(p_R_u, -, bool{true}, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_VHxX_TO_VH(p_R_u, -, uint64_t{1}, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_VHxX_TO_VH(p_R_u, -, int64_t{2}, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_VHxX_TO_VH(p_R_u, -, double{1.3}, // + DiscreteFunctionR, DiscreteFunctionR); + + CHECK_EMBEDDED_VHxX_TO_VH(p_R1_u, -, (TinyVector<1>{1.3}), // + DiscreteFunctionR1, DiscreteFunctionR1); + CHECK_EMBEDDED_VHxX_TO_VH(p_R2_u, -, (TinyVector<2>{1.2, 2.3}), // + DiscreteFunctionR2, DiscreteFunctionR2); + CHECK_EMBEDDED_VHxX_TO_VH(p_R3_u, -, (TinyVector<3>{3.2, 7.1, 5.2}), // + DiscreteFunctionR3, DiscreteFunctionR3); + + CHECK_EMBEDDED_VHxX_TO_VH(p_R1x1_u, -, (TinyMatrix<1>{1.3}), // + DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_VHxX_TO_VH(p_R2x2_u, -, (TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), // + DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_VHxX_TO_VH(p_R3x3_u, -, + (TinyMatrix<3>{3.2, 7.1, 5.2, // + 4.7, 2.3, 7.1, // + 9.7, 3.2, 6.8}), // + DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + REQUIRE_THROWS_WITH(p_R_u - (TinyVector<1>{1}), "error: incompatible operand types Vh(P0:R) and R^1"); + REQUIRE_THROWS_WITH(p_R_u - (TinyVector<2>{1, 2}), "error: incompatible operand types Vh(P0:R) and R^2"); + REQUIRE_THROWS_WITH(p_R_u - (TinyVector<3>{2, 3, 2}), "error: incompatible operand types Vh(P0:R) and R^3"); + REQUIRE_THROWS_WITH(p_R_u - (TinyMatrix<1>{2}), "error: incompatible operand types Vh(P0:R) and R^1x1"); + REQUIRE_THROWS_WITH(p_R_u - (TinyMatrix<2>{2, 3, 1, 4}), + "error: incompatible operand types Vh(P0:R) and R^2x2"); + REQUIRE_THROWS_WITH(p_R_u - (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), + "error: incompatible operand types Vh(P0:R) and R^3x3"); + + REQUIRE_THROWS_WITH(p_Vector3_u - (double{1}), "error: incompatible operand types Vh(P0Vector:R) and R"); + REQUIRE_THROWS_WITH(p_Vector3_u - (TinyVector<1>{1}), + "error: incompatible operand types Vh(P0Vector:R) and R^1"); + REQUIRE_THROWS_WITH(p_Vector3_u - (TinyVector<2>{1, 2}), + "error: incompatible operand types Vh(P0Vector:R) and R^2"); + } + + SECTION("X - Vh -> Vh") + { + CHECK_EMBEDDED_XxVH_TO_VH(bool{true}, -, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_XxVH_TO_VH(uint64_t{1}, -, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_XxVH_TO_VH(int64_t{2}, -, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_XxVH_TO_VH(double{1.3}, -, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + + CHECK_EMBEDDED_XxVH_TO_VH((TinyVector<1>{1.3}), -, p_R1_u, // + DiscreteFunctionR1, DiscreteFunctionR1); + CHECK_EMBEDDED_XxVH_TO_VH((TinyVector<2>{1.2, 2.3}), -, p_R2_u, // + DiscreteFunctionR2, DiscreteFunctionR2); + CHECK_EMBEDDED_XxVH_TO_VH((TinyVector<3>{3.2, 7.1, 5.2}), -, p_R3_u, // + DiscreteFunctionR3, DiscreteFunctionR3); + + CHECK_EMBEDDED_XxVH_TO_VH((TinyMatrix<1>{1.3}), -, p_R1x1_u, // + DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), -, p_R2x2_u, // + DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // + 4.7, 2.3, 7.1, // + 9.7, 3.2, 6.8}), + -, p_R3x3_u, // + DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + REQUIRE_THROWS_WITH((TinyVector<1>{1}) - p_R_u, "error: incompatible operand types R^1 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) - p_R_u, "error: incompatible operand types R^2 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyVector<3>{2, 3, 2}) - p_R_u, "error: incompatible operand types R^3 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) - p_R_u, "error: incompatible operand types R^1x1 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) - p_R_u, + "error: incompatible operand types R^2x2 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) - p_R_u, + "error: incompatible operand types R^3x3 and Vh(P0:R)"); + + REQUIRE_THROWS_WITH((double{1}) - p_Vector3_u, "error: incompatible operand types R and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH((TinyVector<1>{1}) - p_Vector3_u, + "error: incompatible operand types R^1 and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) - p_Vector3_u, + "error: incompatible operand types R^2 and Vh(P0Vector:R)"); + } + } + + SECTION("product") + { + SECTION("Vh * Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH(p_R_u, *, p_R_v, // + DiscreteFunctionR, DiscreteFunctionR, DiscreteFunctionR); + + CHECK_EMBEDDED_VH2_TO_VH(p_R1x1_u, *, p_R1x1_v, // + DiscreteFunctionR1x1, DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_VH2_TO_VH(p_R2x2_u, *, p_R2x2_v, // + DiscreteFunctionR2x2, DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_VH2_TO_VH(p_R3x3_u, *, p_R3x3_v, // + DiscreteFunctionR3x3, DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + CHECK_EMBEDDED_VH2_TO_VH(p_R_u, *, p_R1_v, // + DiscreteFunctionR, DiscreteFunctionR1, DiscreteFunctionR1); + CHECK_EMBEDDED_VH2_TO_VH(p_R_u, *, p_R2_v, // + DiscreteFunctionR, DiscreteFunctionR2, DiscreteFunctionR2); + CHECK_EMBEDDED_VH2_TO_VH(p_R_u, *, p_R3_v, // + DiscreteFunctionR, DiscreteFunctionR3, DiscreteFunctionR3); + + CHECK_EMBEDDED_VH2_TO_VH(p_R_u, *, p_R1x1_v, // + DiscreteFunctionR, DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_VH2_TO_VH(p_R_u, *, p_R2x2_v, // + DiscreteFunctionR, DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_VH2_TO_VH(p_R_u, *, p_R3x3_v, // + DiscreteFunctionR, DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + CHECK_EMBEDDED_VH2_TO_VH(p_R1x1_u, *, p_R1_v, // + DiscreteFunctionR1x1, DiscreteFunctionR1, DiscreteFunctionR1); + CHECK_EMBEDDED_VH2_TO_VH(p_R2x2_u, *, p_R2_v, // + DiscreteFunctionR2x2, DiscreteFunctionR2, DiscreteFunctionR2); + CHECK_EMBEDDED_VH2_TO_VH(p_R3x3_u, *, p_R3_v, // + DiscreteFunctionR3x3, DiscreteFunctionR3, DiscreteFunctionR3); + + { + std::shared_ptr p_u_op_v = p_R_u * p_Vector3_v; + + REQUIRE(p_u_op_v.use_count() > 0); + DiscreteFunctionVector u_op_v = p_u_op_v->get<DiscreteFunctionVector>(); + + auto u_values = p_R_u->get<DiscreteFunctionR>().cellValues(); + auto v_arrays = p_Vector3_v->get<DiscreteFunctionVector>().cellArrays(); + bool is_same = true; + for (CellId cell_id = 0; cell_id < u_values.numberOfItems(); ++cell_id) { + for (size_t i = 0; i < u_op_v.size(); ++i) { + if (u_op_v[cell_id][i] != (u_values[cell_id] * v_arrays[cell_id][i])) { + is_same = false; + break; + } + } + } + + REQUIRE(is_same); + } + + REQUIRE_THROWS_WITH(p_R1_u * p_R1_v, "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R2_u * p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R3_u * p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(p_R1_u * p_R2x2_v, "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^2x2)"); + + REQUIRE_THROWS_WITH(p_R1x1_u * p_R2x2_v, "error: incompatible operand types Vh(P0:R^1x1) and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(p_R2x2_u * p_R3x3_v, "error: incompatible operand types Vh(P0:R^2x2) and Vh(P0:R^3x3)"); + REQUIRE_THROWS_WITH(p_R3x3_u * p_R1x1_v, "error: incompatible operand types Vh(P0:R^3x3) and Vh(P0:R^1x1)"); + + REQUIRE_THROWS_WITH(p_R1x1_u * p_R2_v, "error: incompatible operand types Vh(P0:R^1x1) and Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(p_R2x2_u * p_R3_v, "error: incompatible operand types Vh(P0:R^2x2) and Vh(P0:R^3)"); + REQUIRE_THROWS_WITH(p_R3x3_u * p_R1_v, "error: incompatible operand types Vh(P0:R^3x3) and Vh(P0:R^1)"); + + REQUIRE_THROWS_WITH(p_R1_u * p_Vector3_v, + "error: incompatible operand types Vh(P0:R^1) and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH(p_R2_u * p_Vector3_v, + "error: incompatible operand types Vh(P0:R^2) and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH(p_R3_u * p_Vector3_v, + "error: incompatible operand types Vh(P0:R^3) and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH(p_R1x1_u * p_Vector3_v, + "error: incompatible operand types Vh(P0:R^1x1) and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH(p_R2x2_u * p_Vector3_v, + "error: incompatible operand types Vh(P0:R^2x2) and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH(p_R3x3_u * p_Vector3_v, + "error: incompatible operand types Vh(P0:R^3x3) and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH(p_Vector3_u * p_Vector3_v, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0Vector:R)"); + + REQUIRE_THROWS_WITH(p_Vector3_v * p_R_u, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R)"); + REQUIRE_THROWS_WITH(p_Vector3_v * p_R1_u, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_Vector3_v * p_R2_u, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^2)"); + REQUIRE_THROWS_WITH(p_Vector3_v * p_R3_u, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^3)"); + REQUIRE_THROWS_WITH(p_Vector3_v * p_R1x1_u, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(p_Vector3_v * p_R2x2_u, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH(p_Vector3_v * p_R3x3_u, + "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^3x3)"); + + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R1x1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R2x2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R3x3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R1x1_u * p_other_mesh_R1_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R2x2_u * p_other_mesh_R2_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R3x3_u * p_other_mesh_R3_u, "error: operands are defined on different meshes"); + REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_Vector3_u, "error: operands are defined on different meshes"); + } + + SECTION("Vh * X -> Vh") + { + CHECK_EMBEDDED_VHxX_TO_VH(p_R_u, *, bool{true}, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_VHxX_TO_VH(p_R_u, *, uint64_t{1}, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_VHxX_TO_VH(p_R_u, *, int64_t{2}, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_VHxX_TO_VH(p_R_u, *, double{1.3}, // + DiscreteFunctionR, DiscreteFunctionR); + + CHECK_EMBEDDED_VHxX_TO_VH(p_R1x1_u, *, (TinyMatrix<1>{1.3}), // + DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_VHxX_TO_VH(p_R2x2_u, *, (TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), // + DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_VHxX_TO_VH(p_R3x3_u, *, + (TinyMatrix<3>{3.2, 7.1, 5.2, // + 4.7, 2.3, 7.1, // + 9.7, 3.2, 6.8}), // + DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + CHECK_EMBEDDED_VHxX_TO_VH(p_R1x1_u, *, (TinyVector<1>{1.3}), // + DiscreteFunctionR1x1, DiscreteFunctionR1); + CHECK_EMBEDDED_VHxX_TO_VH(p_R2x2_u, *, (TinyVector<2>{1.2, 2.3}), // + DiscreteFunctionR2x2, DiscreteFunctionR2); + CHECK_EMBEDDED_VHxX_TO_VH(p_R3x3_u, *, (TinyVector<3>{3.2, 7.1, 5.2}), // + DiscreteFunctionR3x3, DiscreteFunctionR3); + + REQUIRE_THROWS_WITH(p_R1_u * (TinyVector<1>{1}), "error: incompatible operand types Vh(P0:R^1) and R^1"); + REQUIRE_THROWS_WITH(p_R2_u * (TinyVector<2>{1, 2}), "error: incompatible operand types Vh(P0:R^2) and R^2"); + REQUIRE_THROWS_WITH(p_R3_u * (TinyVector<3>{2, 3, 2}), + "error: incompatible operand types Vh(P0:R^3) and R^3"); + REQUIRE_THROWS_WITH(p_R1_u * (TinyMatrix<1>{2}), "error: incompatible operand types Vh(P0:R^1) and R^1x1"); + REQUIRE_THROWS_WITH(p_R2_u * (TinyMatrix<2>{2, 3, 1, 4}), + "error: incompatible operand types Vh(P0:R^2) and R^2x2"); + REQUIRE_THROWS_WITH(p_R3_u * (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), + "error: incompatible operand types Vh(P0:R^3) and R^3x3"); + REQUIRE_THROWS_WITH(p_R2x2_u * (TinyMatrix<1>{2}), + "error: incompatible operand types Vh(P0:R^2x2) and R^1x1"); + REQUIRE_THROWS_WITH(p_R1x1_u * (TinyMatrix<2>{2, 3, 1, 4}), + "error: incompatible operand types Vh(P0:R^1x1) and R^2x2"); + REQUIRE_THROWS_WITH(p_R2x2_u * (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), + "error: incompatible operand types Vh(P0:R^2x2) and R^3x3"); + + REQUIRE_THROWS_WITH(p_Vector3_u * (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), + "error: incompatible operand types Vh(P0Vector:R) and R^3x3"); + REQUIRE_THROWS_WITH(p_Vector3_u * (double{2}), "error: incompatible operand types Vh(P0Vector:R) and R"); + } + + SECTION("X * Vh -> Vh") + { + CHECK_EMBEDDED_XxVH_TO_VH(bool{true}, *, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_XxVH_TO_VH(uint64_t{1}, *, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_XxVH_TO_VH(int64_t{2}, *, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_XxVH_TO_VH(double{1.3}, *, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + + CHECK_EMBEDDED_XxVH_TO_VH(bool{true}, *, p_R1_u, // + DiscreteFunctionR1, DiscreteFunctionR1); + CHECK_EMBEDDED_XxVH_TO_VH(uint64_t{1}, *, p_R1_u, // + DiscreteFunctionR1, DiscreteFunctionR1); + CHECK_EMBEDDED_XxVH_TO_VH(int64_t{2}, *, p_R1_u, // + DiscreteFunctionR1, DiscreteFunctionR1); + CHECK_EMBEDDED_XxVH_TO_VH(double{1.3}, *, p_R1_u, // + DiscreteFunctionR1, DiscreteFunctionR1); + + CHECK_EMBEDDED_XxVH_TO_VH(bool{true}, *, p_R2_u, // + DiscreteFunctionR2, DiscreteFunctionR2); + CHECK_EMBEDDED_XxVH_TO_VH(uint64_t{1}, *, p_R2_u, // + DiscreteFunctionR2, DiscreteFunctionR2); + CHECK_EMBEDDED_XxVH_TO_VH(int64_t{2}, *, p_R2_u, // + DiscreteFunctionR2, DiscreteFunctionR2); + CHECK_EMBEDDED_XxVH_TO_VH(double{1.3}, *, p_R2_u, // + DiscreteFunctionR2, DiscreteFunctionR2); + + CHECK_EMBEDDED_XxVH_TO_VH(bool{true}, *, p_R3_u, // + DiscreteFunctionR3, DiscreteFunctionR3); + CHECK_EMBEDDED_XxVH_TO_VH(uint64_t{1}, *, p_R3_u, // + DiscreteFunctionR3, DiscreteFunctionR3); + CHECK_EMBEDDED_XxVH_TO_VH(int64_t{2}, *, p_R3_u, // + DiscreteFunctionR3, DiscreteFunctionR3); + CHECK_EMBEDDED_XxVH_TO_VH(double{1.3}, *, p_R3_u, // + DiscreteFunctionR3, DiscreteFunctionR3); + + CHECK_EMBEDDED_XxVH_TO_VH(bool{true}, *, p_R1x1_u, // + DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_XxVH_TO_VH(uint64_t{1}, *, p_R1x1_u, // + DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_XxVH_TO_VH(int64_t{2}, *, p_R1x1_u, // + DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_XxVH_TO_VH(double{1.3}, *, p_R1x1_u, // + DiscreteFunctionR1x1, DiscreteFunctionR1x1); + + CHECK_EMBEDDED_XxVH_TO_VH(bool{true}, *, p_R2x2_u, // + DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_XxVH_TO_VH(uint64_t{1}, *, p_R2x2_u, // + DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_XxVH_TO_VH(int64_t{2}, *, p_R2x2_u, // + DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_XxVH_TO_VH(double{1.3}, *, p_R2x2_u, // + DiscreteFunctionR2x2, DiscreteFunctionR2x2); + + CHECK_EMBEDDED_XxVH_TO_VH(bool{true}, *, p_R3x3_u, // + DiscreteFunctionR3x3, DiscreteFunctionR3x3); + CHECK_EMBEDDED_XxVH_TO_VH(uint64_t{1}, *, p_R3x3_u, // + DiscreteFunctionR3x3, DiscreteFunctionR3x3); + CHECK_EMBEDDED_XxVH_TO_VH(int64_t{2}, *, p_R3x3_u, // + DiscreteFunctionR3x3, DiscreteFunctionR3x3); + CHECK_EMBEDDED_XxVH_TO_VH(double{1.3}, *, p_R3x3_u, // + DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + CHECK_EMBEDDED_XxVH_TO_VH((TinyMatrix<1>{1.3}), *, p_R1_u, // + DiscreteFunctionR1, DiscreteFunctionR1); + CHECK_EMBEDDED_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), *, p_R2_u, // + DiscreteFunctionR2, DiscreteFunctionR2); + CHECK_EMBEDDED_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // + 4.7, 2.3, 7.1, // + 9.7, 3.2, 6.8}), + *, p_R3_u, // + DiscreteFunctionR3, DiscreteFunctionR3); + + CHECK_EMBEDDED_XxVH_TO_VH((TinyMatrix<1>{1.3}), *, p_R1x1_u, // + DiscreteFunctionR1x1, DiscreteFunctionR1x1); + CHECK_EMBEDDED_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), *, p_R2x2_u, // + DiscreteFunctionR2x2, DiscreteFunctionR2x2); + CHECK_EMBEDDED_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // + 4.7, 2.3, 7.1, // + 9.7, 3.2, 6.8}), + *, p_R3x3_u, // + DiscreteFunctionR3x3, DiscreteFunctionR3x3); + + CHECK_EMBEDDED_VECTOR_XxVH_TO_VH(bool{true}, *, p_Vector3_u, DiscreteFunctionVector); + CHECK_EMBEDDED_VECTOR_XxVH_TO_VH(uint64_t{1}, *, p_Vector3_u, DiscreteFunctionVector); + CHECK_EMBEDDED_VECTOR_XxVH_TO_VH(int64_t{2}, *, p_Vector3_u, DiscreteFunctionVector); + CHECK_EMBEDDED_VECTOR_XxVH_TO_VH(double{1.3}, *, p_Vector3_u, DiscreteFunctionVector); + + REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_R_u, "error: incompatible operand types R^1x1 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R_u, + "error: incompatible operand types R^2x2 and Vh(P0:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R_u, + "error: incompatible operand types R^3x3 and Vh(P0:R)"); + + REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_R2_u, "error: incompatible operand types R^1x1 and Vh(P0:R^2)"); + REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R3_u, + "error: incompatible operand types R^2x2 and Vh(P0:R^3)"); + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R2_u, + "error: incompatible operand types R^3x3 and Vh(P0:R^2)"); + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R1_u, + "error: incompatible operand types R^3x3 and Vh(P0:R^1)"); + + REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_R2x2_u, + "error: incompatible operand types R^1x1 and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R3x3_u, + "error: incompatible operand types R^2x2 and Vh(P0:R^3x3)"); + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R2x2_u, + "error: incompatible operand types R^3x3 and Vh(P0:R^2x2)"); + REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R1x1_u, + "error: incompatible operand types R^2x2 and Vh(P0:R^1x1)"); + + REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_Vector3_u, + "error: incompatible operand types R^3x3 and Vh(P0Vector:R)"); + REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_Vector3_u, + "error: incompatible operand types R^1x1 and Vh(P0Vector:R)"); + } + } + + SECTION("ratio") + { + SECTION("Vh / Vh -> Vh") + { + CHECK_EMBEDDED_VH2_TO_VH(p_R_u, /, p_R_v, // + DiscreteFunctionR, DiscreteFunctionR, DiscreteFunctionR); + + REQUIRE_THROWS_WITH(p_R_u / p_R1_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R2_u / p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); + REQUIRE_THROWS_WITH(p_R3_u / p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); + REQUIRE_THROWS_WITH(p_R_u / p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); + + REQUIRE_THROWS_WITH(p_R_u / p_other_mesh_R_u, "error: operands are defined on different meshes"); + } + + SECTION("X / Vh -> Vh") + { + CHECK_EMBEDDED_XxVH_TO_VH(bool{true}, /, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_XxVH_TO_VH(uint64_t{1}, /, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_XxVH_TO_VH(int64_t{2}, /, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + CHECK_EMBEDDED_XxVH_TO_VH(double{1.3}, /, p_R_u, // + DiscreteFunctionR, DiscreteFunctionR); + } + } + } + + SECTION("unary operators") + { + SECTION("unary minus") + { + SECTION("- Vh -> Vh") + { + CHECK_EMBEDDED_VH_TO_VH(-, p_R_u, DiscreteFunctionR); + + CHECK_EMBEDDED_VH_TO_VH(-, p_R1_u, DiscreteFunctionR1); + CHECK_EMBEDDED_VH_TO_VH(-, p_R2_u, DiscreteFunctionR2); + CHECK_EMBEDDED_VH_TO_VH(-, p_R3_u, DiscreteFunctionR3); + + CHECK_EMBEDDED_VH_TO_VH(-, p_R1x1_u, DiscreteFunctionR1x1); + CHECK_EMBEDDED_VH_TO_VH(-, p_R2x2_u, DiscreteFunctionR2x2); + CHECK_EMBEDDED_VH_TO_VH(-, p_R3x3_u, DiscreteFunctionR3x3); + + CHECK_EMBEDDED_VECTOR_VH_TO_VH(-, p_Vector3_u, DiscreteFunctionVector); + } + } + } + } + } +} + +#ifdef __clang__ +#pragma clang optimize on +#endif // __clang__ diff --git a/tests/test_EmbeddedDiscreteFunctionUtils.cpp b/tests/test_EmbeddedDiscreteFunctionUtils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dd2fe97b69541189d1eb859bad6d952e9d705605 --- /dev/null +++ b/tests/test_EmbeddedDiscreteFunctionUtils.cpp @@ -0,0 +1,83 @@ +#include <catch2/catch_test_macros.hpp> +#include <catch2/matchers/catch_matchers_all.hpp> + +#include <language/utils/EmbeddedDiscreteFunctionUtils.hpp> +#include <scheme/DiscreteFunctionP0.hpp> +#include <scheme/DiscreteFunctionP0Vector.hpp> + +#include <MeshDataBaseForTests.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("EmbeddedDiscreteFunctionUtils", "[language]") +{ + using R1 = TinyVector<1, double>; + using R2 = TinyVector<2, double>; + using R3 = TinyVector<3, double>; + + using R1x1 = TinyMatrix<1, 1, double>; + using R2x2 = TinyMatrix<2, 2, double>; + using R3x3 = TinyMatrix<3, 3, double>; + + SECTION("operand type name") + { + SECTION("basic types") + { + REQUIRE(EmbeddedDiscreteFunctionUtils::getOperandTypeName(double{1}) == "R"); + REQUIRE(EmbeddedDiscreteFunctionUtils::getOperandTypeName(std::make_shared<double>(1)) == "R"); + } + + SECTION("discrete P0 function") + { + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); + + for (const auto& named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_1d = named_mesh.mesh(); + + REQUIRE(EmbeddedDiscreteFunctionUtils::getOperandTypeName(DiscreteFunctionP0<1, double>{mesh_1d}) == + "Vh(P0:R)"); + + REQUIRE(EmbeddedDiscreteFunctionUtils::getOperandTypeName(DiscreteFunctionP0<1, R1>{mesh_1d}) == + "Vh(P0:R^1)"); + REQUIRE(EmbeddedDiscreteFunctionUtils::getOperandTypeName(DiscreteFunctionP0<1, R2>{mesh_1d}) == + "Vh(P0:R^2)"); + REQUIRE(EmbeddedDiscreteFunctionUtils::getOperandTypeName(DiscreteFunctionP0<1, R3>{mesh_1d}) == + "Vh(P0:R^3)"); + + REQUIRE(EmbeddedDiscreteFunctionUtils::getOperandTypeName(DiscreteFunctionP0<1, R1x1>{mesh_1d}) == + "Vh(P0:R^1x1)"); + REQUIRE(EmbeddedDiscreteFunctionUtils::getOperandTypeName(DiscreteFunctionP0<1, R2x2>{mesh_1d}) == + "Vh(P0:R^2x2)"); + REQUIRE(EmbeddedDiscreteFunctionUtils::getOperandTypeName(DiscreteFunctionP0<1, R3x3>{mesh_1d}) == + "Vh(P0:R^3x3)"); + } + } + } + + SECTION("discrete P0Vector function") + { + std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); + + for (const auto& named_mesh : mesh_list) { + SECTION(named_mesh.name()) + { + auto mesh_1d = named_mesh.mesh(); + + REQUIRE(EmbeddedDiscreteFunctionUtils::getOperandTypeName(DiscreteFunctionP0Vector<1, double>{mesh_1d, 2}) == + "Vh(P0Vector:R)"); + } + } + } + } + +#ifndef NDEBUG + SECTION("errors") + { + REQUIRE_THROWS_WITH(EmbeddedDiscreteFunctionUtils::getOperandTypeName(std::shared_ptr<double>()), + "dangling shared_ptr"); + } + +#endif // NDEBUG +} diff --git a/tests/test_EmbeddedIDiscreteFunctionMathFunctions.cpp b/tests/test_EmbeddedIDiscreteFunctionMathFunctions.cpp deleted file mode 100644 index a7f0cc0d74eb79f0897e2ea2a2a4b7212dbc306e..0000000000000000000000000000000000000000 --- a/tests/test_EmbeddedIDiscreteFunctionMathFunctions.cpp +++ /dev/null @@ -1,1635 +0,0 @@ -#include <catch2/catch_test_macros.hpp> -#include <catch2/matchers/catch_matchers_all.hpp> - -#include <MeshDataBaseForTests.hpp> - -#include <language/utils/EmbeddedIDiscreteFunctionMathFunctions.hpp> -#include <scheme/DiscreteFunctionP0.hpp> -#include <scheme/DiscreteFunctionP0Vector.hpp> - -// clazy:excludeall=non-pod-global-static - -#define CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(P_U, FCT) \ - { \ - using DiscreteFunctionType = const std::decay_t<decltype(*P_U)>; \ - std::shared_ptr p_fu = ::FCT(P_U); \ - \ - REQUIRE(p_fu.use_count() > 0); \ - REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionType&>(*p_fu)); \ - \ - const auto& fu = dynamic_cast<const DiscreteFunctionType&>(*p_fu); \ - \ - auto values = P_U->cellValues(); \ - bool is_same = true; \ - for (CellId cell_id = 0; cell_id < values.numberOfItems(); ++cell_id) { \ - if (fu[cell_id] != std::FCT(values[cell_id])) { \ - is_same = false; \ - break; \ - } \ - } \ - \ - REQUIRE(is_same); \ - } - -#define CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(P_LHS, P_RHS, FCT) \ - { \ - using DiscreteFunctionType = const std::decay_t<decltype(FCT(*P_LHS, *P_RHS))>; \ - std::shared_ptr p_fuv = ::FCT(P_LHS, P_RHS); \ - \ - REQUIRE(p_fuv.use_count() > 0); \ - REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionType&>(*p_fuv)); \ - \ - const auto& fuv = dynamic_cast<const DiscreteFunctionType&>(*p_fuv); \ - \ - auto lhs_values = P_LHS->cellValues(); \ - auto rhs_values = P_RHS->cellValues(); \ - bool is_same = true; \ - for (CellId cell_id = 0; cell_id < lhs_values.numberOfItems(); ++cell_id) { \ - using namespace std; \ - if (fuv[cell_id] != FCT(lhs_values[cell_id], rhs_values[cell_id])) { \ - is_same = false; \ - break; \ - } \ - } \ - \ - REQUIRE(is_same); \ - } - -#define CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(P_LHS, RHS, FCT) \ - { \ - using DiscreteFunctionType = const std::decay_t<decltype(FCT(*P_LHS, RHS))>; \ - std::shared_ptr p_fuv = ::FCT(P_LHS, RHS); \ - \ - REQUIRE(p_fuv.use_count() > 0); \ - REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionType&>(*p_fuv)); \ - \ - const auto& fuv = dynamic_cast<const DiscreteFunctionType&>(*p_fuv); \ - \ - auto lhs_values = P_LHS->cellValues(); \ - bool is_same = true; \ - for (CellId cell_id = 0; cell_id < lhs_values.numberOfItems(); ++cell_id) { \ - using namespace std; \ - if (fuv[cell_id] != FCT(lhs_values[cell_id], RHS)) { \ - is_same = false; \ - break; \ - } \ - } \ - \ - REQUIRE(is_same); \ - } - -#define CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(LHS, P_RHS, FCT) \ - { \ - using DiscreteFunctionType = const std::decay_t<decltype(FCT(LHS, *P_RHS))>; \ - std::shared_ptr p_fuv = ::FCT(LHS, P_RHS); \ - \ - REQUIRE(p_fuv.use_count() > 0); \ - REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionType&>(*p_fuv)); \ - \ - const auto& fuv = dynamic_cast<const DiscreteFunctionType&>(*p_fuv); \ - \ - auto rhs_values = P_RHS->cellValues(); \ - bool is_same = true; \ - for (CellId cell_id = 0; cell_id < rhs_values.numberOfItems(); ++cell_id) { \ - using namespace std; \ - if (fuv[cell_id] != FCT(LHS, rhs_values[cell_id])) { \ - is_same = false; \ - break; \ - } \ - } \ - \ - REQUIRE(is_same); \ - } - -TEST_CASE("EmbeddedIDiscreteFunctionMathFunctions", "[scheme]") -{ - SECTION("1D") - { - constexpr size_t Dimension = 1; - - using Rd = TinyVector<Dimension>; - - std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - - for (auto named_mesh : mesh_list) { - SECTION(named_mesh.name()) - { - auto mesh = named_mesh.mesh(); - - std::shared_ptr other_mesh = - std::make_shared<Mesh<Connectivity<Dimension>>>(mesh->shared_connectivity(), mesh->xr()); - - CellValue<const Rd> xj = MeshDataManager::instance().getMeshData(*mesh).xj(); - - CellValue<double> values = [=] { - CellValue<double> build_values{mesh->connectivity()}; - parallel_for( - build_values.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.2 + std::cos(l2Norm(xj[cell_id])); }); - return build_values; - }(); - - CellValue<double> positive_values = [=] { - CellValue<double> build_values{mesh->connectivity()}; - parallel_for( - build_values.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 2 + std::sin(l2Norm(xj[cell_id])); }); - return build_values; - }(); - - CellValue<double> bounded_values = [=] { - CellValue<double> build_values{mesh->connectivity()}; - parallel_for( - build_values.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.9 * std::sin(l2Norm(xj[cell_id])); }); - return build_values; - }(); - - std::shared_ptr p_u = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, values); - std::shared_ptr p_other_mesh_u = - std::make_shared<const DiscreteFunctionP0<Dimension, double>>(other_mesh, values); - std::shared_ptr p_positive_u = - std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, positive_values); - std::shared_ptr p_bounded_u = - std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, bounded_values); - - std::shared_ptr p_R1_u = [=] { - CellValue<TinyVector<1>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id][0] = 2 * xj[cell_id][0] + 1; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, uj); - }(); - - std::shared_ptr p_R1_v = [=] { - CellValue<TinyVector<1>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { vj[cell_id][0] = xj[cell_id][0] * xj[cell_id][0] + 1; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, vj); - }(); - - std::shared_ptr p_other_mesh_R1_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(other_mesh, p_R1_u->cellValues()); - - constexpr auto to_2d = [&](const TinyVector<Dimension>& x) -> TinyVector<2> { - if constexpr (Dimension == 1) { - return TinyVector<2>{x[0], 1 + x[0] * x[0]}; - } else if constexpr (Dimension == 2) { - return TinyVector<2>{x[0], x[1]}; - } else if constexpr (Dimension == 3) { - return TinyVector<2>{x[0], x[1] + x[2]}; - } - }; - - std::shared_ptr p_R2_u = [=] { - CellValue<TinyVector<2>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - uj[cell_id] = TinyVector<2>{2 * x[0] + 1, 1 - x[1]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, uj); - }(); - - std::shared_ptr p_R2_v = [=] { - CellValue<TinyVector<2>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - vj[cell_id] = TinyVector<2>{x[0] * x[1] + 1, 2 * x[1]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, vj); - }(); - - std::shared_ptr p_other_mesh_R2_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(other_mesh, p_R2_u->cellValues()); - - constexpr auto to_3d = [&](const TinyVector<Dimension>& x) -> TinyVector<3> { - if constexpr (Dimension == 1) { - return TinyVector<3>{x[0], 1 + x[0] * x[0], 2 - x[0]}; - } else if constexpr (Dimension == 2) { - return TinyVector<3>{x[0], x[1], x[0] + x[1]}; - } else if constexpr (Dimension == 3) { - return TinyVector<3>{x[0], x[1], x[2]}; - } - }; - - std::shared_ptr p_R3_u = [=] { - CellValue<TinyVector<3>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - uj[cell_id] = TinyVector<3>{2 * x[0] + 1, 1 - x[1] * x[2], x[0] + x[2]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, uj); - }(); - - std::shared_ptr p_R3_v = [=] { - CellValue<TinyVector<3>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - vj[cell_id] = TinyVector<3>{x[0] * x[1] + 1, 2 * x[1], x[2] * x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, vj); - }(); - - std::shared_ptr p_other_mesh_R3_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(other_mesh, p_R3_u->cellValues()); - - std::shared_ptr p_R1x1_u = [=] { - CellValue<TinyMatrix<1>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { uj[cell_id] = TinyMatrix<1>{2 * xj[cell_id][0] + 1}; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(mesh, uj); - }(); - - std::shared_ptr p_R2x2_u = [=] { - CellValue<TinyMatrix<2>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - - uj[cell_id] = TinyMatrix<2>{2 * x[0] + 1, 1 - x[1], // - 2 * x[1], -x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(mesh, uj); - }(); - - std::shared_ptr p_R3x3_u = [=] { - CellValue<TinyMatrix<3>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - - uj[cell_id] = TinyMatrix<3>{2 * x[0] + 1, 1 - x[1], 3, // - 2 * x[1], -x[0], x[0] - x[1], // - 3 * x[2] - x[1], x[1] - 2 * x[2], x[2] - x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(mesh, uj); - }(); - - std::shared_ptr p_Vector3_u = [=] { - CellArray<double> uj_vector{mesh->connectivity(), 3}; - parallel_for( - uj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - uj_vector[cell_id][0] = 2 * x[0] + 1; - uj_vector[cell_id][1] = 1 - x[1] * x[2]; - uj_vector[cell_id][2] = x[0] + x[2]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, uj_vector); - }(); - - std::shared_ptr p_Vector3_v = [=] { - CellArray<double> vj_vector{mesh->connectivity(), 3}; - parallel_for( - vj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - vj_vector[cell_id][0] = x[0] * x[1] + 1; - vj_vector[cell_id][1] = 2 * x[1]; - vj_vector[cell_id][2] = x[2] * x[0]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, vj_vector); - }(); - - std::shared_ptr p_Vector2_w = [=] { - CellArray<double> wj_vector{mesh->connectivity(), 2}; - parallel_for( - wj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - wj_vector[cell_id][0] = x[0] + x[1] * 2; - wj_vector[cell_id][1] = x[0] * x[1]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, wj_vector); - }(); - - SECTION("sqrt Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_positive_u, sqrt); - REQUIRE_THROWS_WITH(sqrt(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("abs Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, abs); - REQUIRE_THROWS_WITH(abs(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("sin Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, sin); - REQUIRE_THROWS_WITH(sin(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("cos Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, cos); - REQUIRE_THROWS_WITH(cos(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("tan Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, tan); - REQUIRE_THROWS_WITH(tan(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("asin Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_bounded_u, asin); - REQUIRE_THROWS_WITH(asin(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("acos Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_bounded_u, acos); - REQUIRE_THROWS_WITH(acos(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("atan Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_bounded_u, atan); - REQUIRE_THROWS_WITH(atan(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("sinh Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, sinh); - REQUIRE_THROWS_WITH(sinh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("cosh Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, cosh); - REQUIRE_THROWS_WITH(cosh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("tanh Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, tanh); - REQUIRE_THROWS_WITH(tanh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("asinh Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_positive_u, asinh); - REQUIRE_THROWS_WITH(asinh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("acosh Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_positive_u, acosh); - REQUIRE_THROWS_WITH(acosh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("atanh Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_bounded_u, atanh); - REQUIRE_THROWS_WITH(atanh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("exp Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, exp); - REQUIRE_THROWS_WITH(exp(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("log Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_positive_u, log); - REQUIRE_THROWS_WITH(log(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("atan2 Vh*Vh -> Vh") - { - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_positive_u, p_bounded_u, atan2); - REQUIRE_THROWS_WITH(atan2(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(atan2(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); - REQUIRE_THROWS_WITH(atan2(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); - } - - SECTION("atan2 Vh*R -> Vh") - { - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_u, 3.6, atan2); - REQUIRE_THROWS_WITH(atan2(p_R1_u, 2.1), "error: incompatible operand types Vh(P0:R^1) and R"); - } - - SECTION("atan2 R*Vh -> Vh") - { - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(2.4, p_u, atan2); - REQUIRE_THROWS_WITH(atan2(2.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); - } - - SECTION("min Vh*Vh -> Vh") - { - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_u, p_bounded_u, min); - REQUIRE_THROWS_WITH(::min(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(::min(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(::min(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); - } - - SECTION("min Vh*R -> Vh") - { - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_u, 1.2, min); - REQUIRE_THROWS_WITH(min(p_R1_u, 2.1), "error: incompatible operand types Vh(P0:R^1) and R"); - } - - SECTION("min R*Vh -> Vh") - { - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(0.4, p_u, min); - REQUIRE_THROWS_WITH(min(3.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); - } - - SECTION("min Vh -> R") - { - REQUIRE(min(std::shared_ptr<const IDiscreteFunction>{p_u}) == min(p_u->cellValues())); - REQUIRE_THROWS_WITH(min(std::shared_ptr<const IDiscreteFunction>{p_R1_u}), - "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("max Vh*Vh -> Vh") - { - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_u, p_bounded_u, max); - REQUIRE_THROWS_WITH(::max(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(::max(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(::max(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); - } - - SECTION("max Vh*R -> Vh") - { - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_u, 1.2, max); - REQUIRE_THROWS_WITH(max(p_R1_u, 2.1), "error: incompatible operand types Vh(P0:R^1) and R"); - } - - SECTION("max Vh -> R") - { - REQUIRE(max(std::shared_ptr<const IDiscreteFunction>{p_u}) == max(p_u->cellValues())); - REQUIRE_THROWS_WITH(max(std::shared_ptr<const IDiscreteFunction>{p_R1_u}), - "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("max R*Vh -> Vh") - { - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(0.4, p_u, max); - REQUIRE_THROWS_WITH(max(3.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); - } - - SECTION("pow Vh*Vh -> Vh") - { - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_positive_u, p_bounded_u, pow); - REQUIRE_THROWS_WITH(pow(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(pow(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(pow(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); - } - - SECTION("pow Vh*R -> Vh") - { - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_positive_u, 3.3, pow); - REQUIRE_THROWS_WITH(pow(p_R1_u, 3.1), "error: incompatible operand types Vh(P0:R^1) and R"); - } - - SECTION("pow R*Vh -> Vh") - { - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(2.1, p_u, pow); - REQUIRE_THROWS_WITH(pow(3.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); - } - - SECTION("dot Vh*Vh -> Vh") - { - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R1_u, p_R1_v, dot); - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R2_u, p_R2_v, dot); - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R3_u, p_R3_v, dot); - - { - auto p_UV = dot(p_Vector3_u, p_Vector3_v); - REQUIRE(p_UV.use_count() == 1); - - auto UV = dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*p_UV); - auto direct_UV = dot(*p_Vector3_u, *p_Vector3_v); - - bool is_same = true; - for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { - if (UV[cell_id] != direct_UV[cell_id]) { - is_same = false; - break; - } - } - - REQUIRE(is_same); - } - - REQUIRE_THROWS_WITH(dot(p_R1_u, p_other_mesh_R1_u), "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(dot(p_R2_u, p_other_mesh_R2_u), "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(dot(p_R3_u, p_other_mesh_R3_u), "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(dot(p_R1_u, p_R3_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^3)"); - REQUIRE_THROWS_WITH(dot(p_Vector3_u, p_Vector2_w), "error: operands have different dimension"); - } - - SECTION("dot Vh*Rd -> Vh") - { - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R1_u, (TinyVector<1>{3}), dot); - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R2_u, (TinyVector<2>{-6, 2}), dot); - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R3_u, (TinyVector<3>{-1, 5, 2}), dot); - REQUIRE_THROWS_WITH(dot(p_R1_u, (TinyVector<2>{-6, 2})), - "error: incompatible operand types Vh(P0:R^1) and R^2"); - REQUIRE_THROWS_WITH(dot(p_R2_u, (TinyVector<3>{-1, 5, 2})), - "error: incompatible operand types Vh(P0:R^2) and R^3"); - REQUIRE_THROWS_WITH(dot(p_R3_u, (TinyVector<1>{-1})), "error: incompatible operand types Vh(P0:R^3) and R^1"); - } - - SECTION("dot Rd*Vh -> Vh") - { - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<1>{3}), p_R1_u, dot); - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<2>{-6, 2}), p_R2_u, dot); - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<3>{-1, 5, 2}), p_R3_u, dot); - REQUIRE_THROWS_WITH(dot((TinyVector<2>{-6, 2}), p_R1_u), - "error: incompatible operand types R^2 and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(dot((TinyVector<3>{-1, 5, 2}), p_R2_u), - "error: incompatible operand types R^3 and Vh(P0:R^2)"); - REQUIRE_THROWS_WITH(dot((TinyVector<1>{-1}), p_R3_u), "error: incompatible operand types R^1 and Vh(P0:R^3)"); - } - - SECTION("sum_of_R* Vh -> R*") - { - REQUIRE(sum_of<double>(p_u) == sum(p_u->cellValues())); - REQUIRE(sum_of<TinyVector<1>>(p_R1_u) == sum(p_R1_u->cellValues())); - REQUIRE(sum_of<TinyVector<2>>(p_R2_u) == sum(p_R2_u->cellValues())); - REQUIRE(sum_of<TinyVector<3>>(p_R3_u) == sum(p_R3_u->cellValues())); - REQUIRE(sum_of<TinyMatrix<1>>(p_R1x1_u) == sum(p_R1x1_u->cellValues())); - REQUIRE(sum_of<TinyMatrix<2>>(p_R2x2_u) == sum(p_R2x2_u->cellValues())); - REQUIRE(sum_of<TinyMatrix<3>>(p_R3x3_u) == sum(p_R3x3_u->cellValues())); - - REQUIRE_THROWS_WITH(sum_of<TinyVector<1>>(p_u), "error: invalid operand type Vh(P0:R)"); - REQUIRE_THROWS_WITH(sum_of<double>(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(sum_of<double>(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); - REQUIRE_THROWS_WITH(sum_of<double>(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); - REQUIRE_THROWS_WITH(sum_of<double>(p_R1x1_u), "error: invalid operand type Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(sum_of<double>(p_R2x2_u), "error: invalid operand type Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(sum_of<double>(p_R3x3_u), "error: invalid operand type Vh(P0:R^3x3)"); - } - - SECTION("integral_of_R* Vh -> R*") - { - auto integrate_locally = [&](const auto& cell_values) { - const auto& Vj = MeshDataManager::instance().getMeshData(*mesh).Vj(); - using DataType = decltype(double{} * cell_values[CellId{0}]); - CellValue<DataType> local_integral{mesh->connectivity()}; - parallel_for( - local_integral.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { local_integral[cell_id] = Vj[cell_id] * cell_values[cell_id]; }); - return local_integral; - }; - - REQUIRE(integral_of<double>(p_u) == sum(integrate_locally(p_u->cellValues()))); - REQUIRE(integral_of<TinyVector<1>>(p_R1_u) == sum(integrate_locally(p_R1_u->cellValues()))); - REQUIRE(integral_of<TinyVector<2>>(p_R2_u) == sum(integrate_locally(p_R2_u->cellValues()))); - REQUIRE(integral_of<TinyVector<3>>(p_R3_u) == sum(integrate_locally(p_R3_u->cellValues()))); - REQUIRE(integral_of<TinyMatrix<1>>(p_R1x1_u) == sum(integrate_locally(p_R1x1_u->cellValues()))); - REQUIRE(integral_of<TinyMatrix<2>>(p_R2x2_u) == sum(integrate_locally(p_R2x2_u->cellValues()))); - REQUIRE(integral_of<TinyMatrix<3>>(p_R3x3_u) == sum(integrate_locally(p_R3x3_u->cellValues()))); - - REQUIRE_THROWS_WITH(integral_of<TinyVector<1>>(p_u), "error: invalid operand type Vh(P0:R)"); - REQUIRE_THROWS_WITH(integral_of<double>(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(integral_of<double>(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); - REQUIRE_THROWS_WITH(integral_of<double>(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); - REQUIRE_THROWS_WITH(integral_of<double>(p_R1x1_u), "error: invalid operand type Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(integral_of<double>(p_R2x2_u), "error: invalid operand type Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(integral_of<double>(p_R3x3_u), "error: invalid operand type Vh(P0:R^3x3)"); - } - } - } - } - - SECTION("2D") - { - constexpr size_t Dimension = 2; - - using Rd = TinyVector<Dimension>; - - std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - - for (auto named_mesh : mesh_list) { - SECTION(named_mesh.name()) - { - auto mesh = named_mesh.mesh(); - - std::shared_ptr other_mesh = - std::make_shared<Mesh<Connectivity<Dimension>>>(mesh->shared_connectivity(), mesh->xr()); - - CellValue<const Rd> xj = MeshDataManager::instance().getMeshData(*mesh).xj(); - - CellValue<double> values = [=] { - CellValue<double> build_values{mesh->connectivity()}; - parallel_for( - build_values.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.2 + std::cos(l2Norm(xj[cell_id])); }); - return build_values; - }(); - - CellValue<double> positive_values = [=] { - CellValue<double> build_values{mesh->connectivity()}; - parallel_for( - build_values.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 2 + std::sin(l2Norm(xj[cell_id])); }); - return build_values; - }(); - - CellValue<double> bounded_values = [=] { - CellValue<double> build_values{mesh->connectivity()}; - parallel_for( - build_values.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.9 * std::sin(l2Norm(xj[cell_id])); }); - return build_values; - }(); - - std::shared_ptr p_u = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, values); - std::shared_ptr p_other_mesh_u = - std::make_shared<const DiscreteFunctionP0<Dimension, double>>(other_mesh, values); - std::shared_ptr p_positive_u = - std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, positive_values); - std::shared_ptr p_bounded_u = - std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, bounded_values); - - std::shared_ptr p_R1_u = [=] { - CellValue<TinyVector<1>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id][0] = 2 * xj[cell_id][0] + 1; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, uj); - }(); - - std::shared_ptr p_R1_v = [=] { - CellValue<TinyVector<1>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { vj[cell_id][0] = xj[cell_id][0] * xj[cell_id][0] + 1; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, vj); - }(); - - std::shared_ptr p_other_mesh_R1_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(other_mesh, p_R1_u->cellValues()); - - constexpr auto to_2d = [&](const TinyVector<Dimension>& x) -> TinyVector<2> { - if constexpr (Dimension == 1) { - return TinyVector<2>{x[0], 1 + x[0] * x[0]}; - } else if constexpr (Dimension == 2) { - return TinyVector<2>{x[0], x[1]}; - } else if constexpr (Dimension == 3) { - return TinyVector<2>{x[0], x[1] + x[2]}; - } - }; - - std::shared_ptr p_R2_u = [=] { - CellValue<TinyVector<2>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - uj[cell_id] = TinyVector<2>{2 * x[0] + 1, 1 - x[1]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, uj); - }(); - - std::shared_ptr p_R2_v = [=] { - CellValue<TinyVector<2>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - vj[cell_id] = TinyVector<2>{x[0] * x[1] + 1, 2 * x[1]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, vj); - }(); - - std::shared_ptr p_other_mesh_R2_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(other_mesh, p_R2_u->cellValues()); - - constexpr auto to_3d = [&](const TinyVector<Dimension>& x) -> TinyVector<3> { - if constexpr (Dimension == 1) { - return TinyVector<3>{x[0], 1 + x[0] * x[0], 2 - x[0]}; - } else if constexpr (Dimension == 2) { - return TinyVector<3>{x[0], x[1], x[0] + x[1]}; - } else if constexpr (Dimension == 3) { - return TinyVector<3>{x[0], x[1], x[2]}; - } - }; - - std::shared_ptr p_R3_u = [=] { - CellValue<TinyVector<3>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - uj[cell_id] = TinyVector<3>{2 * x[0] + 1, 1 - x[1] * x[2], x[0] + x[2]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, uj); - }(); - - std::shared_ptr p_R3_v = [=] { - CellValue<TinyVector<3>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - vj[cell_id] = TinyVector<3>{x[0] * x[1] + 1, 2 * x[1], x[2] * x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, vj); - }(); - - std::shared_ptr p_other_mesh_R3_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(other_mesh, p_R3_u->cellValues()); - - std::shared_ptr p_R1x1_u = [=] { - CellValue<TinyMatrix<1>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { uj[cell_id] = TinyMatrix<1>{2 * xj[cell_id][0] + 1}; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(mesh, uj); - }(); - - std::shared_ptr p_R2x2_u = [=] { - CellValue<TinyMatrix<2>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - - uj[cell_id] = TinyMatrix<2>{2 * x[0] + 1, 1 - x[1], // - 2 * x[1], -x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(mesh, uj); - }(); - - std::shared_ptr p_R3x3_u = [=] { - CellValue<TinyMatrix<3>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - - uj[cell_id] = TinyMatrix<3>{2 * x[0] + 1, 1 - x[1], 3, // - 2 * x[1], -x[0], x[0] - x[1], // - 3 * x[2] - x[1], x[1] - 2 * x[2], x[2] - x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(mesh, uj); - }(); - - std::shared_ptr p_Vector3_u = [=] { - CellArray<double> uj_vector{mesh->connectivity(), 3}; - parallel_for( - uj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - uj_vector[cell_id][0] = 2 * x[0] + 1; - uj_vector[cell_id][1] = 1 - x[1] * x[2]; - uj_vector[cell_id][2] = x[0] + x[2]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, uj_vector); - }(); - - std::shared_ptr p_Vector3_v = [=] { - CellArray<double> vj_vector{mesh->connectivity(), 3}; - parallel_for( - vj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - vj_vector[cell_id][0] = x[0] * x[1] + 1; - vj_vector[cell_id][1] = 2 * x[1]; - vj_vector[cell_id][2] = x[2] * x[0]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, vj_vector); - }(); - - std::shared_ptr p_Vector2_w = [=] { - CellArray<double> wj_vector{mesh->connectivity(), 2}; - parallel_for( - wj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - wj_vector[cell_id][0] = x[0] + x[1] * 2; - wj_vector[cell_id][1] = x[0] * x[1]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, wj_vector); - }(); - - SECTION("sqrt Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_positive_u, sqrt); - REQUIRE_THROWS_WITH(sqrt(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("abs Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, abs); - REQUIRE_THROWS_WITH(abs(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("sin Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, sin); - REQUIRE_THROWS_WITH(sin(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("cos Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, cos); - REQUIRE_THROWS_WITH(cos(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("tan Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, tan); - REQUIRE_THROWS_WITH(tan(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("asin Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_bounded_u, asin); - REQUIRE_THROWS_WITH(asin(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("acos Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_bounded_u, acos); - REQUIRE_THROWS_WITH(acos(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("atan Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_bounded_u, atan); - REQUIRE_THROWS_WITH(atan(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("sinh Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, sinh); - REQUIRE_THROWS_WITH(sinh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("cosh Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, cosh); - REQUIRE_THROWS_WITH(cosh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("tanh Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, tanh); - REQUIRE_THROWS_WITH(tanh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("asinh Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_positive_u, asinh); - REQUIRE_THROWS_WITH(asinh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("acosh Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_positive_u, acosh); - REQUIRE_THROWS_WITH(acosh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("atanh Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_bounded_u, atanh); - REQUIRE_THROWS_WITH(atanh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("exp Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, exp); - REQUIRE_THROWS_WITH(exp(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("log Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_positive_u, log); - REQUIRE_THROWS_WITH(log(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("atan2 Vh*Vh -> Vh") - { - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_positive_u, p_bounded_u, atan2); - REQUIRE_THROWS_WITH(atan2(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(atan2(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); - REQUIRE_THROWS_WITH(atan2(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); - } - - SECTION("atan2 Vh*R -> Vh") - { - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_u, 3.6, atan2); - REQUIRE_THROWS_WITH(atan2(p_R1_u, 2.1), "error: incompatible operand types Vh(P0:R^1) and R"); - } - - SECTION("atan2 R*Vh -> Vh") - { - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(2.4, p_u, atan2); - REQUIRE_THROWS_WITH(atan2(2.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); - } - - SECTION("min Vh*Vh -> Vh") - { - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_u, p_bounded_u, min); - REQUIRE_THROWS_WITH(::min(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(::min(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(::min(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); - } - - SECTION("min Vh*R -> Vh") - { - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_u, 1.2, min); - REQUIRE_THROWS_WITH(min(p_R1_u, 2.1), "error: incompatible operand types Vh(P0:R^1) and R"); - } - - SECTION("min R*Vh -> Vh") - { - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(0.4, p_u, min); - REQUIRE_THROWS_WITH(min(3.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); - } - - SECTION("min Vh -> R") - { - REQUIRE(min(std::shared_ptr<const IDiscreteFunction>{p_u}) == min(p_u->cellValues())); - REQUIRE_THROWS_WITH(min(std::shared_ptr<const IDiscreteFunction>{p_R1_u}), - "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("max Vh*Vh -> Vh") - { - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_u, p_bounded_u, max); - REQUIRE_THROWS_WITH(::max(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(::max(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(::max(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); - } - - SECTION("max Vh*R -> Vh") - { - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_u, 1.2, max); - REQUIRE_THROWS_WITH(max(p_R1_u, 2.1), "error: incompatible operand types Vh(P0:R^1) and R"); - } - - SECTION("max Vh -> R") - { - REQUIRE(max(std::shared_ptr<const IDiscreteFunction>{p_u}) == max(p_u->cellValues())); - REQUIRE_THROWS_WITH(max(std::shared_ptr<const IDiscreteFunction>{p_R1_u}), - "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("max R*Vh -> Vh") - { - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(0.4, p_u, max); - REQUIRE_THROWS_WITH(max(3.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); - } - - SECTION("pow Vh*Vh -> Vh") - { - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_positive_u, p_bounded_u, pow); - REQUIRE_THROWS_WITH(pow(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(pow(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(pow(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); - } - - SECTION("pow Vh*R -> Vh") - { - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_positive_u, 3.3, pow); - REQUIRE_THROWS_WITH(pow(p_R1_u, 3.1), "error: incompatible operand types Vh(P0:R^1) and R"); - } - - SECTION("pow R*Vh -> Vh") - { - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(2.1, p_u, pow); - REQUIRE_THROWS_WITH(pow(3.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); - } - - SECTION("dot Vh*Vh -> Vh") - { - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R1_u, p_R1_v, dot); - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R2_u, p_R2_v, dot); - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R3_u, p_R3_v, dot); - - { - auto p_UV = dot(p_Vector3_u, p_Vector3_v); - REQUIRE(p_UV.use_count() == 1); - - auto UV = dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*p_UV); - auto direct_UV = dot(*p_Vector3_u, *p_Vector3_v); - - bool is_same = true; - for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { - if (UV[cell_id] != direct_UV[cell_id]) { - is_same = false; - break; - } - } - - REQUIRE(is_same); - } - - REQUIRE_THROWS_WITH(dot(p_R1_u, p_other_mesh_R1_u), "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(dot(p_R2_u, p_other_mesh_R2_u), "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(dot(p_R3_u, p_other_mesh_R3_u), "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(dot(p_R1_u, p_R3_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^3)"); - REQUIRE_THROWS_WITH(dot(p_Vector3_u, p_Vector2_w), "error: operands have different dimension"); - } - - SECTION("dot Vh*Rd -> Vh") - { - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R1_u, (TinyVector<1>{3}), dot); - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R2_u, (TinyVector<2>{-6, 2}), dot); - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R3_u, (TinyVector<3>{-1, 5, 2}), dot); - REQUIRE_THROWS_WITH(dot(p_R1_u, (TinyVector<2>{-6, 2})), - "error: incompatible operand types Vh(P0:R^1) and R^2"); - REQUIRE_THROWS_WITH(dot(p_R2_u, (TinyVector<3>{-1, 5, 2})), - "error: incompatible operand types Vh(P0:R^2) and R^3"); - REQUIRE_THROWS_WITH(dot(p_R3_u, (TinyVector<1>{-1})), "error: incompatible operand types Vh(P0:R^3) and R^1"); - } - - SECTION("dot Rd*Vh -> Vh") - { - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<1>{3}), p_R1_u, dot); - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<2>{-6, 2}), p_R2_u, dot); - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<3>{-1, 5, 2}), p_R3_u, dot); - REQUIRE_THROWS_WITH(dot((TinyVector<2>{-6, 2}), p_R1_u), - "error: incompatible operand types R^2 and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(dot((TinyVector<3>{-1, 5, 2}), p_R2_u), - "error: incompatible operand types R^3 and Vh(P0:R^2)"); - REQUIRE_THROWS_WITH(dot((TinyVector<1>{-1}), p_R3_u), "error: incompatible operand types R^1 and Vh(P0:R^3)"); - } - - SECTION("sum_of_R* Vh -> R*") - { - REQUIRE(sum_of<double>(p_u) == sum(p_u->cellValues())); - REQUIRE(sum_of<TinyVector<1>>(p_R1_u) == sum(p_R1_u->cellValues())); - REQUIRE(sum_of<TinyVector<2>>(p_R2_u) == sum(p_R2_u->cellValues())); - REQUIRE(sum_of<TinyVector<3>>(p_R3_u) == sum(p_R3_u->cellValues())); - REQUIRE(sum_of<TinyMatrix<1>>(p_R1x1_u) == sum(p_R1x1_u->cellValues())); - REQUIRE(sum_of<TinyMatrix<2>>(p_R2x2_u) == sum(p_R2x2_u->cellValues())); - REQUIRE(sum_of<TinyMatrix<3>>(p_R3x3_u) == sum(p_R3x3_u->cellValues())); - - REQUIRE_THROWS_WITH(sum_of<TinyVector<1>>(p_u), "error: invalid operand type Vh(P0:R)"); - REQUIRE_THROWS_WITH(sum_of<double>(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(sum_of<double>(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); - REQUIRE_THROWS_WITH(sum_of<double>(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); - REQUIRE_THROWS_WITH(sum_of<double>(p_R1x1_u), "error: invalid operand type Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(sum_of<double>(p_R2x2_u), "error: invalid operand type Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(sum_of<double>(p_R3x3_u), "error: invalid operand type Vh(P0:R^3x3)"); - } - - SECTION("integral_of_R* Vh -> R*") - { - auto integrate_locally = [&](const auto& cell_values) { - const auto& Vj = MeshDataManager::instance().getMeshData(*mesh).Vj(); - using DataType = decltype(double{} * cell_values[CellId{0}]); - CellValue<DataType> local_integral{mesh->connectivity()}; - parallel_for( - local_integral.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { local_integral[cell_id] = Vj[cell_id] * cell_values[cell_id]; }); - return local_integral; - }; - - REQUIRE(integral_of<double>(p_u) == sum(integrate_locally(p_u->cellValues()))); - REQUIRE(integral_of<TinyVector<1>>(p_R1_u) == sum(integrate_locally(p_R1_u->cellValues()))); - REQUIRE(integral_of<TinyVector<2>>(p_R2_u) == sum(integrate_locally(p_R2_u->cellValues()))); - REQUIRE(integral_of<TinyVector<3>>(p_R3_u) == sum(integrate_locally(p_R3_u->cellValues()))); - REQUIRE(integral_of<TinyMatrix<1>>(p_R1x1_u) == sum(integrate_locally(p_R1x1_u->cellValues()))); - REQUIRE(integral_of<TinyMatrix<2>>(p_R2x2_u) == sum(integrate_locally(p_R2x2_u->cellValues()))); - REQUIRE(integral_of<TinyMatrix<3>>(p_R3x3_u) == sum(integrate_locally(p_R3x3_u->cellValues()))); - - REQUIRE_THROWS_WITH(integral_of<TinyVector<1>>(p_u), "error: invalid operand type Vh(P0:R)"); - REQUIRE_THROWS_WITH(integral_of<double>(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(integral_of<double>(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); - REQUIRE_THROWS_WITH(integral_of<double>(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); - REQUIRE_THROWS_WITH(integral_of<double>(p_R1x1_u), "error: invalid operand type Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(integral_of<double>(p_R2x2_u), "error: invalid operand type Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(integral_of<double>(p_R3x3_u), "error: invalid operand type Vh(P0:R^3x3)"); - } - } - } - } - - SECTION("3D") - { - constexpr size_t Dimension = 3; - - using Rd = TinyVector<Dimension>; - - std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - - for (auto named_mesh : mesh_list) { - SECTION(named_mesh.name()) - { - auto mesh = named_mesh.mesh(); - - std::shared_ptr other_mesh = - std::make_shared<Mesh<Connectivity<Dimension>>>(mesh->shared_connectivity(), mesh->xr()); - - CellValue<const Rd> xj = MeshDataManager::instance().getMeshData(*mesh).xj(); - - CellValue<double> values = [=] { - CellValue<double> build_values{mesh->connectivity()}; - parallel_for( - build_values.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.2 + std::cos(l2Norm(xj[cell_id])); }); - return build_values; - }(); - - CellValue<double> positive_values = [=] { - CellValue<double> build_values{mesh->connectivity()}; - parallel_for( - build_values.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 2 + std::sin(l2Norm(xj[cell_id])); }); - return build_values; - }(); - - CellValue<double> bounded_values = [=] { - CellValue<double> build_values{mesh->connectivity()}; - parallel_for( - build_values.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.9 * std::sin(l2Norm(xj[cell_id])); }); - return build_values; - }(); - - std::shared_ptr p_u = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, values); - std::shared_ptr p_other_mesh_u = - std::make_shared<const DiscreteFunctionP0<Dimension, double>>(other_mesh, values); - std::shared_ptr p_positive_u = - std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, positive_values); - std::shared_ptr p_bounded_u = - std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, bounded_values); - - std::shared_ptr p_R1_u = [=] { - CellValue<TinyVector<1>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id][0] = 2 * xj[cell_id][0] + 1; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, uj); - }(); - - std::shared_ptr p_R1_v = [=] { - CellValue<TinyVector<1>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { vj[cell_id][0] = xj[cell_id][0] * xj[cell_id][0] + 1; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, vj); - }(); - - std::shared_ptr p_other_mesh_R1_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(other_mesh, p_R1_u->cellValues()); - - constexpr auto to_2d = [&](const TinyVector<Dimension>& x) -> TinyVector<2> { - if constexpr (Dimension == 1) { - return TinyVector<2>{x[0], 1 + x[0] * x[0]}; - } else if constexpr (Dimension == 2) { - return TinyVector<2>{x[0], x[1]}; - } else if constexpr (Dimension == 3) { - return TinyVector<2>{x[0], x[1] + x[2]}; - } - }; - - std::shared_ptr p_R2_u = [=] { - CellValue<TinyVector<2>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - uj[cell_id] = TinyVector<2>{2 * x[0] + 1, 1 - x[1]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, uj); - }(); - - std::shared_ptr p_R2_v = [=] { - CellValue<TinyVector<2>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - vj[cell_id] = TinyVector<2>{x[0] * x[1] + 1, 2 * x[1]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, vj); - }(); - - std::shared_ptr p_other_mesh_R2_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(other_mesh, p_R2_u->cellValues()); - - constexpr auto to_3d = [&](const TinyVector<Dimension>& x) -> TinyVector<3> { - if constexpr (Dimension == 1) { - return TinyVector<3>{x[0], 1 + x[0] * x[0], 2 - x[0]}; - } else if constexpr (Dimension == 2) { - return TinyVector<3>{x[0], x[1], x[0] + x[1]}; - } else if constexpr (Dimension == 3) { - return TinyVector<3>{x[0], x[1], x[2]}; - } - }; - - std::shared_ptr p_R3_u = [=] { - CellValue<TinyVector<3>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - uj[cell_id] = TinyVector<3>{2 * x[0] + 1, 1 - x[1] * x[2], x[0] + x[2]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, uj); - }(); - - std::shared_ptr p_R3_v = [=] { - CellValue<TinyVector<3>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - vj[cell_id] = TinyVector<3>{x[0] * x[1] + 1, 2 * x[1], x[2] * x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, vj); - }(); - - std::shared_ptr p_other_mesh_R3_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(other_mesh, p_R3_u->cellValues()); - - std::shared_ptr p_R1x1_u = [=] { - CellValue<TinyMatrix<1>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { uj[cell_id] = TinyMatrix<1>{2 * xj[cell_id][0] + 1}; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(mesh, uj); - }(); - - std::shared_ptr p_R2x2_u = [=] { - CellValue<TinyMatrix<2>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - - uj[cell_id] = TinyMatrix<2>{2 * x[0] + 1, 1 - x[1], // - 2 * x[1], -x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(mesh, uj); - }(); - - std::shared_ptr p_R3x3_u = [=] { - CellValue<TinyMatrix<3>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - - uj[cell_id] = TinyMatrix<3>{2 * x[0] + 1, 1 - x[1], 3, // - 2 * x[1], -x[0], x[0] - x[1], // - 3 * x[2] - x[1], x[1] - 2 * x[2], x[2] - x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(mesh, uj); - }(); - - std::shared_ptr p_Vector3_u = [=] { - CellArray<double> uj_vector{mesh->connectivity(), 3}; - parallel_for( - uj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - uj_vector[cell_id][0] = 2 * x[0] + 1; - uj_vector[cell_id][1] = 1 - x[1] * x[2]; - uj_vector[cell_id][2] = x[0] + x[2]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, uj_vector); - }(); - - std::shared_ptr p_Vector3_v = [=] { - CellArray<double> vj_vector{mesh->connectivity(), 3}; - parallel_for( - vj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - vj_vector[cell_id][0] = x[0] * x[1] + 1; - vj_vector[cell_id][1] = 2 * x[1]; - vj_vector[cell_id][2] = x[2] * x[0]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, vj_vector); - }(); - - std::shared_ptr p_Vector2_w = [=] { - CellArray<double> wj_vector{mesh->connectivity(), 2}; - parallel_for( - wj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - wj_vector[cell_id][0] = x[0] + x[1] * 2; - wj_vector[cell_id][1] = x[0] * x[1]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, wj_vector); - }(); - - SECTION("sqrt Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_positive_u, sqrt); - REQUIRE_THROWS_WITH(sqrt(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("abs Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, abs); - REQUIRE_THROWS_WITH(abs(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("sin Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, sin); - REQUIRE_THROWS_WITH(sin(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("cos Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, cos); - REQUIRE_THROWS_WITH(cos(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("tan Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, tan); - REQUIRE_THROWS_WITH(tan(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("asin Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_bounded_u, asin); - REQUIRE_THROWS_WITH(asin(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("acos Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_bounded_u, acos); - REQUIRE_THROWS_WITH(acos(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("atan Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_bounded_u, atan); - REQUIRE_THROWS_WITH(atan(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("sinh Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, sinh); - REQUIRE_THROWS_WITH(sinh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("cosh Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, cosh); - REQUIRE_THROWS_WITH(cosh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("tanh Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, tanh); - REQUIRE_THROWS_WITH(tanh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("asinh Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_positive_u, asinh); - REQUIRE_THROWS_WITH(asinh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("acosh Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_positive_u, acosh); - REQUIRE_THROWS_WITH(acosh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("atanh Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_bounded_u, atanh); - REQUIRE_THROWS_WITH(atanh(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("exp Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_u, exp); - REQUIRE_THROWS_WITH(exp(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("log Vh -> Vh") - { - CHECK_EMBEDDED_VH_TO_VH_REAL_FUNCTION_EVALUATION(p_positive_u, log); - REQUIRE_THROWS_WITH(log(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("atan2 Vh*Vh -> Vh") - { - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_positive_u, p_bounded_u, atan2); - REQUIRE_THROWS_WITH(atan2(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(atan2(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); - REQUIRE_THROWS_WITH(atan2(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); - } - - SECTION("atan2 Vh*R -> Vh") - { - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_u, 3.6, atan2); - REQUIRE_THROWS_WITH(atan2(p_R1_u, 2.1), "error: incompatible operand types Vh(P0:R^1) and R"); - } - - SECTION("atan2 R*Vh -> Vh") - { - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(2.4, p_u, atan2); - REQUIRE_THROWS_WITH(atan2(2.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); - } - - SECTION("min Vh*Vh -> Vh") - { - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_u, p_bounded_u, min); - REQUIRE_THROWS_WITH(::min(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(::min(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(::min(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); - } - - SECTION("min Vh*R -> Vh") - { - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_u, 1.2, min); - REQUIRE_THROWS_WITH(min(p_R1_u, 2.1), "error: incompatible operand types Vh(P0:R^1) and R"); - } - - SECTION("min R*Vh -> Vh") - { - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(0.4, p_u, min); - REQUIRE_THROWS_WITH(min(3.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); - } - - SECTION("min Vh -> R") - { - REQUIRE(min(std::shared_ptr<const IDiscreteFunction>{p_u}) == min(p_u->cellValues())); - REQUIRE_THROWS_WITH(min(std::shared_ptr<const IDiscreteFunction>{p_R1_u}), - "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("max Vh*Vh -> Vh") - { - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_u, p_bounded_u, max); - REQUIRE_THROWS_WITH(::max(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(::max(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(::max(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); - } - - SECTION("max Vh*R -> Vh") - { - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_u, 1.2, max); - REQUIRE_THROWS_WITH(max(p_R1_u, 2.1), "error: incompatible operand types Vh(P0:R^1) and R"); - } - - SECTION("max Vh -> R") - { - REQUIRE(max(std::shared_ptr<const IDiscreteFunction>{p_u}) == max(p_u->cellValues())); - REQUIRE_THROWS_WITH(max(std::shared_ptr<const IDiscreteFunction>{p_R1_u}), - "error: invalid operand type Vh(P0:R^1)"); - } - - SECTION("max R*Vh -> Vh") - { - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(0.4, p_u, max); - REQUIRE_THROWS_WITH(max(3.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); - } - - SECTION("pow Vh*Vh -> Vh") - { - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_positive_u, p_bounded_u, pow); - REQUIRE_THROWS_WITH(pow(p_u, p_other_mesh_u), "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(pow(p_u, p_R1_u), "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(pow(p_R1_u, p_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R)"); - } - - SECTION("pow Vh*R -> Vh") - { - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_positive_u, 3.3, pow); - REQUIRE_THROWS_WITH(pow(p_R1_u, 3.1), "error: incompatible operand types Vh(P0:R^1) and R"); - } - - SECTION("pow R*Vh -> Vh") - { - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION(2.1, p_u, pow); - REQUIRE_THROWS_WITH(pow(3.1, p_R1_u), "error: incompatible operand types R and Vh(P0:R^1)"); - } - - SECTION("dot Vh*Vh -> Vh") - { - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R1_u, p_R1_v, dot); - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R2_u, p_R2_v, dot); - CHECK_EMBEDDED_VH2_TO_VH_FUNCTION_EVALUATION(p_R3_u, p_R3_v, dot); - - { - auto p_UV = dot(p_Vector3_u, p_Vector3_v); - REQUIRE(p_UV.use_count() == 1); - - auto UV = dynamic_cast<const DiscreteFunctionP0<Dimension, double>&>(*p_UV); - auto direct_UV = dot(*p_Vector3_u, *p_Vector3_v); - - bool is_same = true; - for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) { - if (UV[cell_id] != direct_UV[cell_id]) { - is_same = false; - break; - } - } - - REQUIRE(is_same); - } - - REQUIRE_THROWS_WITH(dot(p_R1_u, p_other_mesh_R1_u), "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(dot(p_R2_u, p_other_mesh_R2_u), "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(dot(p_R3_u, p_other_mesh_R3_u), "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(dot(p_R1_u, p_R3_u), "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^3)"); - REQUIRE_THROWS_WITH(dot(p_Vector3_u, p_Vector2_w), "error: operands have different dimension"); - } - - SECTION("dot Vh*Rd -> Vh") - { - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R1_u, (TinyVector<1>{3}), dot); - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R2_u, (TinyVector<2>{-6, 2}), dot); - CHECK_EMBEDDED_VHxW_TO_VH_FUNCTION_EVALUATION(p_R3_u, (TinyVector<3>{-1, 5, 2}), dot); - REQUIRE_THROWS_WITH(dot(p_R1_u, (TinyVector<2>{-6, 2})), - "error: incompatible operand types Vh(P0:R^1) and R^2"); - REQUIRE_THROWS_WITH(dot(p_R2_u, (TinyVector<3>{-1, 5, 2})), - "error: incompatible operand types Vh(P0:R^2) and R^3"); - REQUIRE_THROWS_WITH(dot(p_R3_u, (TinyVector<1>{-1})), "error: incompatible operand types Vh(P0:R^3) and R^1"); - } - - SECTION("dot Rd*Vh -> Vh") - { - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<1>{3}), p_R1_u, dot); - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<2>{-6, 2}), p_R2_u, dot); - CHECK_EMBEDDED_WxVH_TO_VH_FUNCTION_EVALUATION((TinyVector<3>{-1, 5, 2}), p_R3_u, dot); - REQUIRE_THROWS_WITH(dot((TinyVector<2>{-6, 2}), p_R1_u), - "error: incompatible operand types R^2 and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(dot((TinyVector<3>{-1, 5, 2}), p_R2_u), - "error: incompatible operand types R^3 and Vh(P0:R^2)"); - REQUIRE_THROWS_WITH(dot((TinyVector<1>{-1}), p_R3_u), "error: incompatible operand types R^1 and Vh(P0:R^3)"); - } - - SECTION("sum_of_R* Vh -> R*") - { - REQUIRE(sum_of<double>(p_u) == sum(p_u->cellValues())); - REQUIRE(sum_of<TinyVector<1>>(p_R1_u) == sum(p_R1_u->cellValues())); - REQUIRE(sum_of<TinyVector<2>>(p_R2_u) == sum(p_R2_u->cellValues())); - REQUIRE(sum_of<TinyVector<3>>(p_R3_u) == sum(p_R3_u->cellValues())); - REQUIRE(sum_of<TinyMatrix<1>>(p_R1x1_u) == sum(p_R1x1_u->cellValues())); - REQUIRE(sum_of<TinyMatrix<2>>(p_R2x2_u) == sum(p_R2x2_u->cellValues())); - REQUIRE(sum_of<TinyMatrix<3>>(p_R3x3_u) == sum(p_R3x3_u->cellValues())); - - REQUIRE_THROWS_WITH(sum_of<TinyVector<1>>(p_u), "error: invalid operand type Vh(P0:R)"); - REQUIRE_THROWS_WITH(sum_of<double>(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(sum_of<double>(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); - REQUIRE_THROWS_WITH(sum_of<double>(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); - REQUIRE_THROWS_WITH(sum_of<double>(p_R1x1_u), "error: invalid operand type Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(sum_of<double>(p_R2x2_u), "error: invalid operand type Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(sum_of<double>(p_R3x3_u), "error: invalid operand type Vh(P0:R^3x3)"); - } - - SECTION("integral_of_R* Vh -> R*") - { - auto integrate_locally = [&](const auto& cell_values) { - const auto& Vj = MeshDataManager::instance().getMeshData(*mesh).Vj(); - using DataType = decltype(double{} * cell_values[CellId{0}]); - CellValue<DataType> local_integral{mesh->connectivity()}; - parallel_for( - local_integral.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { local_integral[cell_id] = Vj[cell_id] * cell_values[cell_id]; }); - return local_integral; - }; - - REQUIRE(integral_of<double>(p_u) == sum(integrate_locally(p_u->cellValues()))); - REQUIRE(integral_of<TinyVector<1>>(p_R1_u) == sum(integrate_locally(p_R1_u->cellValues()))); - REQUIRE(integral_of<TinyVector<2>>(p_R2_u) == sum(integrate_locally(p_R2_u->cellValues()))); - REQUIRE(integral_of<TinyVector<3>>(p_R3_u) == sum(integrate_locally(p_R3_u->cellValues()))); - REQUIRE(integral_of<TinyMatrix<1>>(p_R1x1_u) == sum(integrate_locally(p_R1x1_u->cellValues()))); - REQUIRE(integral_of<TinyMatrix<2>>(p_R2x2_u) == sum(integrate_locally(p_R2x2_u->cellValues()))); - REQUIRE(integral_of<TinyMatrix<3>>(p_R3x3_u) == sum(integrate_locally(p_R3x3_u->cellValues()))); - - REQUIRE_THROWS_WITH(integral_of<TinyVector<1>>(p_u), "error: invalid operand type Vh(P0:R)"); - REQUIRE_THROWS_WITH(integral_of<double>(p_R1_u), "error: invalid operand type Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(integral_of<double>(p_R2_u), "error: invalid operand type Vh(P0:R^2)"); - REQUIRE_THROWS_WITH(integral_of<double>(p_R3_u), "error: invalid operand type Vh(P0:R^3)"); - REQUIRE_THROWS_WITH(integral_of<double>(p_R1x1_u), "error: invalid operand type Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(integral_of<double>(p_R2x2_u), "error: invalid operand type Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(integral_of<double>(p_R3x3_u), "error: invalid operand type Vh(P0:R^3x3)"); - } - } - } - } -} diff --git a/tests/test_EmbeddedIDiscreteFunctionOperators.cpp b/tests/test_EmbeddedIDiscreteFunctionOperators.cpp deleted file mode 100644 index b955ba24b785a83c3be6f73360fa9ea0026cc56e..0000000000000000000000000000000000000000 --- a/tests/test_EmbeddedIDiscreteFunctionOperators.cpp +++ /dev/null @@ -1,2735 +0,0 @@ -#include <catch2/catch_test_macros.hpp> -#include <catch2/matchers/catch_matchers_all.hpp> - -#include <MeshDataBaseForTests.hpp> - -#include <language/utils/EmbeddedIDiscreteFunctionOperators.hpp> -#include <scheme/DiscreteFunctionP0.hpp> -#include <scheme/DiscreteFunctionP0Vector.hpp> - -// clazy:excludeall=non-pod-global-static - -#define CHECK_SCALAR_VH2_TO_VH(P_LHS, OPERATOR, P_RHS) \ - { \ - using DiscreteFunctionType = const std::decay_t<decltype(*P_LHS OPERATOR * P_RHS)>; \ - \ - std::shared_ptr p_fuv = P_LHS OPERATOR P_RHS; \ - \ - REQUIRE(p_fuv.use_count() > 0); \ - REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionType&>(*p_fuv)); \ - \ - const auto& fuv = dynamic_cast<const DiscreteFunctionType&>(*p_fuv); \ - \ - auto lhs_values = P_LHS->cellValues(); \ - auto rhs_values = P_RHS->cellValues(); \ - bool is_same = true; \ - for (CellId cell_id = 0; cell_id < lhs_values.numberOfItems(); ++cell_id) { \ - if (fuv[cell_id] != (lhs_values[cell_id] OPERATOR rhs_values[cell_id])) { \ - is_same = false; \ - break; \ - } \ - } \ - \ - REQUIRE(is_same); \ - } - -#define CHECK_SCALAR_VHxX_TO_VH(P_LHS, OPERATOR, RHS) \ - { \ - using DiscreteFunctionType = const std::decay_t<decltype(*P_LHS OPERATOR RHS)>; \ - \ - std::shared_ptr p_fuv = P_LHS OPERATOR RHS; \ - \ - REQUIRE(p_fuv.use_count() > 0); \ - REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionType&>(*p_fuv)); \ - \ - const auto& fuv = dynamic_cast<const DiscreteFunctionType&>(*p_fuv); \ - \ - auto lhs_values = P_LHS->cellValues(); \ - bool is_same = true; \ - for (CellId cell_id = 0; cell_id < lhs_values.numberOfItems(); ++cell_id) { \ - if (fuv[cell_id] != (lhs_values[cell_id] OPERATOR RHS)) { \ - is_same = false; \ - break; \ - } \ - } \ - \ - REQUIRE(is_same); \ - } - -#define CHECK_SCALAR_XxVH_TO_VH(LHS, OPERATOR, P_RHS) \ - { \ - using DiscreteFunctionType = const std::decay_t<decltype(LHS OPERATOR * P_RHS)>; \ - \ - std::shared_ptr p_fuv = LHS OPERATOR P_RHS; \ - \ - REQUIRE(p_fuv.use_count() > 0); \ - REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionType&>(*p_fuv)); \ - \ - const auto& fuv = dynamic_cast<const DiscreteFunctionType&>(*p_fuv); \ - \ - auto rhs_values = P_RHS->cellValues(); \ - bool is_same = true; \ - for (CellId cell_id = 0; cell_id < rhs_values.numberOfItems(); ++cell_id) { \ - if (fuv[cell_id] != (LHS OPERATOR rhs_values[cell_id])) { \ - is_same = false; \ - break; \ - } \ - } \ - \ - REQUIRE(is_same); \ - } - -#define CHECK_VECTOR_VH2_TO_VH(P_LHS, OPERATOR, P_RHS) \ - { \ - using DiscreteFunctionType = const std::decay_t<decltype(*P_LHS OPERATOR * P_RHS)>; \ - \ - std::shared_ptr p_fuv = P_LHS OPERATOR P_RHS; \ - \ - REQUIRE(p_fuv.use_count() > 0); \ - REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionType&>(*p_fuv)); \ - \ - const auto& fuv = dynamic_cast<const DiscreteFunctionType&>(*p_fuv); \ - \ - auto lhs_arrays = P_LHS->cellArrays(); \ - auto rhs_arrays = P_RHS->cellArrays(); \ - bool is_same = true; \ - REQUIRE(rhs_arrays.sizeOfArrays() > 0); \ - REQUIRE(lhs_arrays.sizeOfArrays() == rhs_arrays.sizeOfArrays()); \ - REQUIRE(lhs_arrays.sizeOfArrays() == fuv.size()); \ - for (CellId cell_id = 0; cell_id < lhs_arrays.numberOfItems(); ++cell_id) { \ - for (size_t i = 0; i < fuv.size(); ++i) { \ - if (fuv[cell_id][i] != (lhs_arrays[cell_id][i] OPERATOR rhs_arrays[cell_id][i])) { \ - is_same = false; \ - break; \ - } \ - } \ - } \ - \ - REQUIRE(is_same); \ - } - -#define CHECK_VECTOR_XxVH_TO_VH(LHS, OPERATOR, P_RHS) \ - { \ - using DiscreteFunctionType = const std::decay_t<decltype(LHS OPERATOR * P_RHS)>; \ - \ - std::shared_ptr p_fuv = LHS OPERATOR P_RHS; \ - \ - REQUIRE(p_fuv.use_count() > 0); \ - REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionType&>(*p_fuv)); \ - \ - const auto& fuv = dynamic_cast<const DiscreteFunctionType&>(*p_fuv); \ - \ - auto rhs_arrays = P_RHS->cellArrays(); \ - bool is_same = true; \ - REQUIRE(rhs_arrays.sizeOfArrays() > 0); \ - REQUIRE(fuv.size() == rhs_arrays.sizeOfArrays()); \ - for (CellId cell_id = 0; cell_id < rhs_arrays.numberOfItems(); ++cell_id) { \ - for (size_t i = 0; i < fuv.size(); ++i) { \ - if (fuv[cell_id][i] != (LHS OPERATOR rhs_arrays[cell_id][i])) { \ - is_same = false; \ - break; \ - } \ - } \ - } \ - \ - REQUIRE(is_same); \ - } - -#define CHECK_SCALAR_VH_TO_VH(OPERATOR, P_RHS) \ - { \ - using DiscreteFunctionType = const std::decay_t<decltype(OPERATOR * P_RHS)>; \ - \ - std::shared_ptr p_fu = OPERATOR P_RHS; \ - \ - REQUIRE(p_fu.use_count() > 0); \ - REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionType&>(*p_fu)); \ - \ - const auto& fu = dynamic_cast<const DiscreteFunctionType&>(*p_fu); \ - \ - auto rhs_values = P_RHS->cellValues(); \ - bool is_same = true; \ - for (CellId cell_id = 0; cell_id < rhs_values.numberOfItems(); ++cell_id) { \ - if (fu[cell_id] != (OPERATOR rhs_values[cell_id])) { \ - is_same = false; \ - break; \ - } \ - } \ - \ - REQUIRE(is_same); \ - } - -#define CHECK_VECTOR_VH_TO_VH(OPERATOR, P_RHS) \ - { \ - using DiscreteFunctionType = const std::decay_t<decltype(OPERATOR * P_RHS)>; \ - \ - std::shared_ptr p_fu = OPERATOR P_RHS; \ - \ - REQUIRE(p_fu.use_count() > 0); \ - REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionType&>(*p_fu)); \ - \ - const auto& fu = dynamic_cast<const DiscreteFunctionType&>(*p_fu); \ - \ - auto rhs_arrays = P_RHS->cellArrays(); \ - REQUIRE(rhs_arrays.sizeOfArrays() > 0); \ - REQUIRE(rhs_arrays.sizeOfArrays() == fu.size()); \ - bool is_same = true; \ - for (CellId cell_id = 0; cell_id < rhs_arrays.numberOfItems(); ++cell_id) { \ - for (size_t i = 0; i < rhs_arrays.sizeOfArrays(); ++i) { \ - if (fu[cell_id][i] != (OPERATOR rhs_arrays[cell_id][i])) { \ - is_same = false; \ - break; \ - } \ - } \ - } \ - \ - REQUIRE(is_same); \ - } - -#ifdef __clang__ -#pragma clang optimize off -#endif // __clang__ - -TEST_CASE("EmbeddedIDiscreteFunctionOperators", "[scheme]") -{ - SECTION("binary operators") - { - SECTION("1D") - { - constexpr size_t Dimension = 1; - - using Rd = TinyVector<Dimension>; - - std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - - for (auto named_mesh : mesh_list) { - SECTION(named_mesh.name()) - { - auto mesh = named_mesh.mesh(); - - std::shared_ptr other_mesh = - std::make_shared<Mesh<Connectivity<Dimension>>>(mesh->shared_connectivity(), mesh->xr()); - - CellValue<const Rd> xj = MeshDataManager::instance().getMeshData(*mesh).xj(); - - CellValue<double> u_R_values = [=] { - CellValue<double> build_values{mesh->connectivity()}; - parallel_for( - build_values.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.2 + std::cos(l2Norm(xj[cell_id])); }); - return build_values; - }(); - - CellValue<double> v_R_values = [=] { - CellValue<double> build_values{mesh->connectivity()}; - parallel_for( - build_values.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.6 + std::sin(l2Norm(xj[cell_id])); }); - return build_values; - }(); - - std::shared_ptr p_R_u = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, u_R_values); - std::shared_ptr p_other_mesh_R_u = - std::make_shared<const DiscreteFunctionP0<Dimension, double>>(other_mesh, u_R_values); - std::shared_ptr p_R_v = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, v_R_values); - - std::shared_ptr p_R1_u = [=] { - CellValue<TinyVector<1>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id][0] = 2 * xj[cell_id][0] + 1; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, uj); - }(); - - std::shared_ptr p_R1_v = [=] { - CellValue<TinyVector<1>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { vj[cell_id][0] = xj[cell_id][0] * xj[cell_id][0] + 1; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, vj); - }(); - - std::shared_ptr p_other_mesh_R1_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(other_mesh, p_R1_u->cellValues()); - - constexpr auto to_2d = [&](const TinyVector<Dimension>& x) -> TinyVector<2> { - if constexpr (Dimension == 1) { - return TinyVector<2>{x[0], 1 + x[0] * x[0]}; - } else if constexpr (Dimension == 2) { - return TinyVector<2>{x[0], x[1]}; - } else if constexpr (Dimension == 3) { - return TinyVector<2>{x[0], x[1] + x[2]}; - } - }; - - std::shared_ptr p_R2_u = [=] { - CellValue<TinyVector<2>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - uj[cell_id] = TinyVector<2>{2 * x[0] + 1, 1 - x[1]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, uj); - }(); - - std::shared_ptr p_R2_v = [=] { - CellValue<TinyVector<2>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - vj[cell_id] = TinyVector<2>{x[0] * x[1] + 1, 2 * x[1]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, vj); - }(); - - std::shared_ptr p_other_mesh_R2_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(other_mesh, p_R2_u->cellValues()); - - constexpr auto to_3d = [&](const TinyVector<Dimension>& x) -> TinyVector<3> { - if constexpr (Dimension == 1) { - return TinyVector<3>{x[0], 1 + x[0] * x[0], 2 - x[0]}; - } else if constexpr (Dimension == 2) { - return TinyVector<3>{x[0], x[1], x[0] + x[1]}; - } else if constexpr (Dimension == 3) { - return TinyVector<3>{x[0], x[1], x[2]}; - } - }; - - std::shared_ptr p_R3_u = [=] { - CellValue<TinyVector<3>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - uj[cell_id] = TinyVector<3>{2 * x[0] + 1, 1 - x[1] * x[2], x[0] + x[2]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, uj); - }(); - - std::shared_ptr p_R3_v = [=] { - CellValue<TinyVector<3>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - vj[cell_id] = TinyVector<3>{x[0] * x[1] + 1, 2 * x[1], x[2] * x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, vj); - }(); - - std::shared_ptr p_other_mesh_R3_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(other_mesh, p_R3_u->cellValues()); - - std::shared_ptr p_R1x1_u = [=] { - CellValue<TinyMatrix<1>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { uj[cell_id] = TinyMatrix<1>{2 * xj[cell_id][0] + 1}; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(mesh, uj); - }(); - - std::shared_ptr p_other_mesh_R1x1_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(other_mesh, p_R1x1_u->cellValues()); - - std::shared_ptr p_R1x1_v = [=] { - CellValue<TinyMatrix<1>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { vj[cell_id] = TinyMatrix<1>{0.3 - xj[cell_id][0]}; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(mesh, vj); - }(); - - std::shared_ptr p_R2x2_u = [=] { - CellValue<TinyMatrix<2>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - - uj[cell_id] = TinyMatrix<2>{2 * x[0] + 1, 1 - x[1], // - 2 * x[1], -x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(mesh, uj); - }(); - - std::shared_ptr p_other_mesh_R2x2_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(other_mesh, p_R2x2_u->cellValues()); - - std::shared_ptr p_R2x2_v = [=] { - CellValue<TinyMatrix<2>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - - vj[cell_id] = TinyMatrix<2>{x[0] + 0.3, 1 - x[1] - x[0], // - 2 * x[1] + x[0], x[1] - x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(mesh, vj); - }(); - - std::shared_ptr p_R3x3_u = [=] { - CellValue<TinyMatrix<3>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - - uj[cell_id] = TinyMatrix<3>{2 * x[0] + 1, 1 - x[1], 3, // - 2 * x[1], -x[0], x[0] - x[1], // - 3 * x[2] - x[1], x[1] - 2 * x[2], x[2] - x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(mesh, uj); - }(); - - std::shared_ptr p_other_mesh_R3x3_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(other_mesh, p_R3x3_u->cellValues()); - - std::shared_ptr p_R3x3_v = [=] { - CellValue<TinyMatrix<3>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - - vj[cell_id] = TinyMatrix<3>{0.2 * x[0] + 1, 2 + x[1], 3 - x[2], // - 2.3 * x[2], x[1] - x[0], x[2] - x[1], // - 2 * x[2] + x[0], x[1] + 0.2 * x[2], x[2] - 2 * x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(mesh, vj); - }(); - - std::shared_ptr p_Vector3_u = [=] { - CellArray<double> uj_vector{mesh->connectivity(), 3}; - parallel_for( - uj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - uj_vector[cell_id][0] = 2 * x[0] + 1; - uj_vector[cell_id][1] = 1 - x[1] * x[2]; - uj_vector[cell_id][2] = x[0] + x[2]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, uj_vector); - }(); - - std::shared_ptr p_other_mesh_Vector3_u = - std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(other_mesh, p_Vector3_u->cellArrays()); - - std::shared_ptr p_Vector3_v = [=] { - CellArray<double> vj_vector{mesh->connectivity(), 3}; - parallel_for( - vj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - vj_vector[cell_id][0] = x[0] * x[1] + 1; - vj_vector[cell_id][1] = 2 * x[1]; - vj_vector[cell_id][2] = x[2] * x[0]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, vj_vector); - }(); - - std::shared_ptr p_Vector2_w = [=] { - CellArray<double> wj_vector{mesh->connectivity(), 2}; - parallel_for( - wj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - wj_vector[cell_id][0] = x[0] + x[1] * 2; - wj_vector[cell_id][1] = x[0] * x[1]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, wj_vector); - }(); - - SECTION("sum") - { - SECTION("Vh + Vh -> Vh") - { - CHECK_SCALAR_VH2_TO_VH(p_R_u, +, p_R_v); - - CHECK_SCALAR_VH2_TO_VH(p_R1_u, +, p_R1_v); - CHECK_SCALAR_VH2_TO_VH(p_R2_u, +, p_R2_v); - CHECK_SCALAR_VH2_TO_VH(p_R3_u, +, p_R3_v); - - CHECK_SCALAR_VH2_TO_VH(p_R1x1_u, +, p_R1x1_v); - CHECK_SCALAR_VH2_TO_VH(p_R2x2_u, +, p_R2x2_v); - CHECK_SCALAR_VH2_TO_VH(p_R3x3_u, +, p_R3x3_v); - - CHECK_VECTOR_VH2_TO_VH(p_Vector3_u, +, p_Vector3_v); - - REQUIRE_THROWS_WITH(p_R_u + p_R1_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R2_u + p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R3_u + p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(p_R_u + p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(p_R_u + p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(p_Vector3_u + p_R_v, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R)"); - REQUIRE_THROWS_WITH(p_Vector3_u + p_Vector2_w, "error: Vh(P0Vector:R) spaces have different sizes"); - - REQUIRE_THROWS_WITH(p_R_u + p_other_mesh_R_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R1_u + p_other_mesh_R1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R2_u + p_other_mesh_R2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R3_u + p_other_mesh_R3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R1x1_u + p_other_mesh_R1x1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R2x2_u + p_other_mesh_R2x2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R3x3_u + p_other_mesh_R3x3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_Vector3_u + p_other_mesh_Vector3_u, - "error: operands are defined on different meshes"); - } - - SECTION("Vh + X -> Vh") - { - CHECK_SCALAR_VHxX_TO_VH(p_R_u, +, bool{true}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, +, uint64_t{1}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, +, int64_t{2}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, +, double{1.3}); - - CHECK_SCALAR_VHxX_TO_VH(p_R1_u, +, (TinyVector<1>{1.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R2_u, +, (TinyVector<2>{1.2, 2.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R3_u, +, (TinyVector<3>{3.2, 7.1, 5.2})); - - CHECK_SCALAR_VHxX_TO_VH(p_R1x1_u, +, (TinyMatrix<1>{1.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R2x2_u, +, (TinyMatrix<2>{1.2, 2.3, 4.2, 5.1})); - CHECK_SCALAR_VHxX_TO_VH(p_R3x3_u, +, - (TinyMatrix<3>{3.2, 7.1, 5.2, // - 4.7, 2.3, 7.1, // - 9.7, 3.2, 6.8})); - - REQUIRE_THROWS_WITH(p_R_u + (TinyVector<1>{1}), "error: incompatible operand types Vh(P0:R) and R^1"); - REQUIRE_THROWS_WITH(p_R_u + (TinyVector<2>{1, 2}), "error: incompatible operand types Vh(P0:R) and R^2"); - REQUIRE_THROWS_WITH(p_R_u + (TinyVector<3>{2, 3, 2}), - "error: incompatible operand types Vh(P0:R) and R^3"); - REQUIRE_THROWS_WITH(p_R_u + (TinyMatrix<1>{2}), "error: incompatible operand types Vh(P0:R) and R^1x1"); - REQUIRE_THROWS_WITH(p_R_u + (TinyMatrix<2>{2, 3, 1, 4}), - "error: incompatible operand types Vh(P0:R) and R^2x2"); - REQUIRE_THROWS_WITH(p_R_u + (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), - "error: incompatible operand types Vh(P0:R) and R^3x3"); - - REQUIRE_THROWS_WITH(p_Vector3_u + (double{1}), "error: incompatible operand types Vh(P0Vector:R) and R"); - REQUIRE_THROWS_WITH(p_Vector3_u + (TinyVector<1>{1}), - "error: incompatible operand types Vh(P0Vector:R) and R^1"); - REQUIRE_THROWS_WITH(p_Vector3_u + (TinyVector<2>{1, 2}), - "error: incompatible operand types Vh(P0Vector:R) and R^2"); - } - - SECTION("X + Vh -> Vh") - { - CHECK_SCALAR_XxVH_TO_VH(bool{true}, +, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, +, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, +, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, +, p_R_u); - - CHECK_SCALAR_XxVH_TO_VH((TinyVector<1>{1.3}), +, p_R1_u); - CHECK_SCALAR_XxVH_TO_VH((TinyVector<2>{1.2, 2.3}), +, p_R2_u); - CHECK_SCALAR_XxVH_TO_VH((TinyVector<3>{3.2, 7.1, 5.2}), +, p_R3_u); - - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<1>{1.3}), +, p_R1x1_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), +, p_R2x2_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // - 4.7, 2.3, 7.1, // - 9.7, 3.2, 6.8}), - +, p_R3x3_u); - - REQUIRE_THROWS_WITH((TinyVector<1>{1}) + p_R_u, "error: incompatible operand types R^1 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) + p_R_u, "error: incompatible operand types R^2 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyVector<3>{2, 3, 2}) + p_R_u, - "error: incompatible operand types R^3 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) + p_R_u, "error: incompatible operand types R^1x1 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) + p_R_u, - "error: incompatible operand types R^2x2 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) + p_R_u, - "error: incompatible operand types R^3x3 and Vh(P0:R)"); - - REQUIRE_THROWS_WITH((double{1}) + p_Vector3_u, "error: incompatible operand types R and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH((TinyVector<1>{1}) + p_Vector3_u, - "error: incompatible operand types R^1 and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) + p_Vector3_u, - "error: incompatible operand types R^2 and Vh(P0Vector:R)"); - } - } - - SECTION("difference") - { - SECTION("Vh - Vh -> Vh") - { - CHECK_SCALAR_VH2_TO_VH(p_R_u, -, p_R_v); - - CHECK_SCALAR_VH2_TO_VH(p_R1_u, -, p_R1_v); - CHECK_SCALAR_VH2_TO_VH(p_R2_u, -, p_R2_v); - CHECK_SCALAR_VH2_TO_VH(p_R3_u, -, p_R3_v); - - CHECK_SCALAR_VH2_TO_VH(p_R1x1_u, -, p_R1x1_v); - CHECK_SCALAR_VH2_TO_VH(p_R2x2_u, -, p_R2x2_v); - CHECK_SCALAR_VH2_TO_VH(p_R3x3_u, -, p_R3x3_v); - - CHECK_VECTOR_VH2_TO_VH(p_Vector3_u, -, p_Vector3_v); - - REQUIRE_THROWS_WITH(p_R_u - p_R1_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R2_u - p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R3_u - p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(p_R_u - p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(p_Vector3_u - p_R_v, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R)"); - REQUIRE_THROWS_WITH(p_Vector3_u - p_Vector2_w, "error: Vh(P0Vector:R) spaces have different sizes"); - - REQUIRE_THROWS_WITH(p_R_u - p_other_mesh_R_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R1_u - p_other_mesh_R1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R2_u - p_other_mesh_R2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R3_u - p_other_mesh_R3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R1x1_u - p_other_mesh_R1x1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R2x2_u - p_other_mesh_R2x2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R3x3_u - p_other_mesh_R3x3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_Vector3_u - p_other_mesh_Vector3_u, - "error: operands are defined on different meshes"); - } - - SECTION("Vh - X -> Vh") - { - CHECK_SCALAR_VHxX_TO_VH(p_R_u, -, bool{true}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, -, uint64_t{1}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, -, int64_t{2}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, -, double{1.3}); - - CHECK_SCALAR_VHxX_TO_VH(p_R1_u, -, (TinyVector<1>{1.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R2_u, -, (TinyVector<2>{1.2, 2.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R3_u, -, (TinyVector<3>{3.2, 7.1, 5.2})); - - CHECK_SCALAR_VHxX_TO_VH(p_R1x1_u, -, (TinyMatrix<1>{1.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R2x2_u, -, (TinyMatrix<2>{1.2, 2.3, 4.2, 5.1})); - CHECK_SCALAR_VHxX_TO_VH(p_R3x3_u, -, - (TinyMatrix<3>{3.2, 7.1, 5.2, // - 4.7, 2.3, 7.1, // - 9.7, 3.2, 6.8})); - - REQUIRE_THROWS_WITH(p_R_u - (TinyVector<1>{1}), "error: incompatible operand types Vh(P0:R) and R^1"); - REQUIRE_THROWS_WITH(p_R_u - (TinyVector<2>{1, 2}), "error: incompatible operand types Vh(P0:R) and R^2"); - REQUIRE_THROWS_WITH(p_R_u - (TinyVector<3>{2, 3, 2}), - "error: incompatible operand types Vh(P0:R) and R^3"); - REQUIRE_THROWS_WITH(p_R_u - (TinyMatrix<1>{2}), "error: incompatible operand types Vh(P0:R) and R^1x1"); - REQUIRE_THROWS_WITH(p_R_u - (TinyMatrix<2>{2, 3, 1, 4}), - "error: incompatible operand types Vh(P0:R) and R^2x2"); - REQUIRE_THROWS_WITH(p_R_u - (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), - "error: incompatible operand types Vh(P0:R) and R^3x3"); - - REQUIRE_THROWS_WITH(p_Vector3_u - (double{1}), "error: incompatible operand types Vh(P0Vector:R) and R"); - REQUIRE_THROWS_WITH(p_Vector3_u - (TinyVector<1>{1}), - "error: incompatible operand types Vh(P0Vector:R) and R^1"); - REQUIRE_THROWS_WITH(p_Vector3_u - (TinyVector<2>{1, 2}), - "error: incompatible operand types Vh(P0Vector:R) and R^2"); - } - - SECTION("X - Vh -> Vh") - { - CHECK_SCALAR_XxVH_TO_VH(bool{true}, -, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, -, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, -, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, -, p_R_u); - - CHECK_SCALAR_XxVH_TO_VH((TinyVector<1>{1.3}), -, p_R1_u); - CHECK_SCALAR_XxVH_TO_VH((TinyVector<2>{1.2, 2.3}), -, p_R2_u); - CHECK_SCALAR_XxVH_TO_VH((TinyVector<3>{3.2, 7.1, 5.2}), -, p_R3_u); - - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<1>{1.3}), -, p_R1x1_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), -, p_R2x2_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // - 4.7, 2.3, 7.1, // - 9.7, 3.2, 6.8}), - -, p_R3x3_u); - - REQUIRE_THROWS_WITH((TinyVector<1>{1}) - p_R_u, "error: incompatible operand types R^1 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) - p_R_u, "error: incompatible operand types R^2 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyVector<3>{2, 3, 2}) - p_R_u, - "error: incompatible operand types R^3 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) - p_R_u, "error: incompatible operand types R^1x1 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) - p_R_u, - "error: incompatible operand types R^2x2 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) - p_R_u, - "error: incompatible operand types R^3x3 and Vh(P0:R)"); - - REQUIRE_THROWS_WITH((double{1}) - p_Vector3_u, "error: incompatible operand types R and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH((TinyVector<1>{1}) - p_Vector3_u, - "error: incompatible operand types R^1 and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) - p_Vector3_u, - "error: incompatible operand types R^2 and Vh(P0Vector:R)"); - } - } - - SECTION("product") - { - SECTION("Vh * Vh -> Vh") - { - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R_v); - - CHECK_SCALAR_VH2_TO_VH(p_R1x1_u, *, p_R1x1_v); - CHECK_SCALAR_VH2_TO_VH(p_R2x2_u, *, p_R2x2_v); - CHECK_SCALAR_VH2_TO_VH(p_R3x3_u, *, p_R3x3_v); - - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R1_v); - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R2_v); - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R3_v); - - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R1x1_v); - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R2x2_v); - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R3x3_v); - - CHECK_SCALAR_VH2_TO_VH(p_R1x1_u, *, p_R1_v); - CHECK_SCALAR_VH2_TO_VH(p_R2x2_u, *, p_R2_v); - CHECK_SCALAR_VH2_TO_VH(p_R3x3_u, *, p_R3_v); - - { - std::shared_ptr p_fuv = p_R_u * p_Vector3_v; - - REQUIRE(p_fuv.use_count() > 0); - REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*p_fuv)); - - const auto& fuv = dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*p_fuv); - - auto lhs_values = p_R_u->cellValues(); - auto rhs_arrays = p_Vector3_v->cellArrays(); - bool is_same = true; - for (CellId cell_id = 0; cell_id < lhs_values.numberOfItems(); ++cell_id) { - for (size_t i = 0; i < fuv.size(); ++i) { - if (fuv[cell_id][i] != (lhs_values[cell_id] * rhs_arrays[cell_id][i])) { - is_same = false; - break; - } - } - } - - REQUIRE(is_same); - } - - REQUIRE_THROWS_WITH(p_R1_u * p_R1_v, "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R2_u * p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R3_u * p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(p_R1_u * p_R2x2_v, "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^2x2)"); - - REQUIRE_THROWS_WITH(p_R1x1_u * p_R2x2_v, - "error: incompatible operand types Vh(P0:R^1x1) and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(p_R2x2_u * p_R3x3_v, - "error: incompatible operand types Vh(P0:R^2x2) and Vh(P0:R^3x3)"); - REQUIRE_THROWS_WITH(p_R3x3_u * p_R1x1_v, - "error: incompatible operand types Vh(P0:R^3x3) and Vh(P0:R^1x1)"); - - REQUIRE_THROWS_WITH(p_R1x1_u * p_R2_v, "error: incompatible operand types Vh(P0:R^1x1) and Vh(P0:R^2)"); - REQUIRE_THROWS_WITH(p_R2x2_u * p_R3_v, "error: incompatible operand types Vh(P0:R^2x2) and Vh(P0:R^3)"); - REQUIRE_THROWS_WITH(p_R3x3_u * p_R1_v, "error: incompatible operand types Vh(P0:R^3x3) and Vh(P0:R^1)"); - - REQUIRE_THROWS_WITH(p_R1_u * p_Vector3_v, - "error: incompatible operand types Vh(P0:R^1) and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH(p_R2_u * p_Vector3_v, - "error: incompatible operand types Vh(P0:R^2) and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH(p_R3_u * p_Vector3_v, - "error: incompatible operand types Vh(P0:R^3) and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH(p_R1x1_u * p_Vector3_v, - "error: incompatible operand types Vh(P0:R^1x1) and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH(p_R2x2_u * p_Vector3_v, - "error: incompatible operand types Vh(P0:R^2x2) and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH(p_R3x3_u * p_Vector3_v, - "error: incompatible operand types Vh(P0:R^3x3) and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH(p_Vector3_u * p_Vector3_v, - "error: incompatible operand types Vh(P0Vector:R) and Vh(P0Vector:R)"); - - REQUIRE_THROWS_WITH(p_Vector3_v * p_R_u, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R)"); - REQUIRE_THROWS_WITH(p_Vector3_v * p_R1_u, - "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_Vector3_v * p_R2_u, - "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^2)"); - REQUIRE_THROWS_WITH(p_Vector3_v * p_R3_u, - "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^3)"); - REQUIRE_THROWS_WITH(p_Vector3_v * p_R1x1_u, - "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(p_Vector3_v * p_R2x2_u, - "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(p_Vector3_v * p_R3x3_u, - "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^3x3)"); - - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R1x1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R2x2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R3x3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R1x1_u * p_other_mesh_R1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R2x2_u * p_other_mesh_R2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R3x3_u * p_other_mesh_R3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_Vector3_u, "error: operands are defined on different meshes"); - } - - SECTION("Vh * X -> Vh") - { - CHECK_SCALAR_VHxX_TO_VH(p_R_u, *, bool{true}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, *, uint64_t{1}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, *, int64_t{2}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, *, double{1.3}); - - CHECK_SCALAR_VHxX_TO_VH(p_R1x1_u, *, (TinyMatrix<1>{1.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R2x2_u, *, (TinyMatrix<2>{1.2, 2.3, 4.2, 5.1})); - CHECK_SCALAR_VHxX_TO_VH(p_R3x3_u, *, - (TinyMatrix<3>{3.2, 7.1, 5.2, // - 4.7, 2.3, 7.1, // - 9.7, 3.2, 6.8})); - - REQUIRE_THROWS_WITH(p_R1_u * (TinyVector<1>{1}), "error: incompatible operand types Vh(P0:R^1) and R^1"); - REQUIRE_THROWS_WITH(p_R2_u * (TinyVector<2>{1, 2}), - "error: incompatible operand types Vh(P0:R^2) and R^2"); - REQUIRE_THROWS_WITH(p_R3_u * (TinyVector<3>{2, 3, 2}), - "error: incompatible operand types Vh(P0:R^3) and R^3"); - REQUIRE_THROWS_WITH(p_R1_u * (TinyMatrix<1>{2}), - "error: incompatible operand types Vh(P0:R^1) and R^1x1"); - REQUIRE_THROWS_WITH(p_R2_u * (TinyMatrix<2>{2, 3, 1, 4}), - "error: incompatible operand types Vh(P0:R^2) and R^2x2"); - REQUIRE_THROWS_WITH(p_R3_u * (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), - "error: incompatible operand types Vh(P0:R^3) and R^3x3"); - REQUIRE_THROWS_WITH(p_R2x2_u * (TinyMatrix<1>{2}), - "error: incompatible operand types Vh(P0:R^2x2) and R^1x1"); - REQUIRE_THROWS_WITH(p_R1x1_u * (TinyMatrix<2>{2, 3, 1, 4}), - "error: incompatible operand types Vh(P0:R^1x1) and R^2x2"); - REQUIRE_THROWS_WITH(p_R2x2_u * (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), - "error: incompatible operand types Vh(P0:R^2x2) and R^3x3"); - - REQUIRE_THROWS_WITH(p_Vector3_u * (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), - "error: incompatible operand types Vh(P0Vector:R) and R^3x3"); - REQUIRE_THROWS_WITH(p_Vector3_u * (double{2}), "error: incompatible operand types Vh(P0Vector:R) and R"); - } - - SECTION("X * Vh -> Vh") - { - CHECK_SCALAR_XxVH_TO_VH(bool{true}, *, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, *, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, *, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, *, p_R_u); - - CHECK_SCALAR_XxVH_TO_VH(bool{true}, *, p_R1x1_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, *, p_R1x1_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, *, p_R1x1_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, *, p_R1x1_u); - - CHECK_SCALAR_XxVH_TO_VH(bool{true}, *, p_R2x2_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, *, p_R2x2_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, *, p_R2x2_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, *, p_R2x2_u); - - CHECK_SCALAR_XxVH_TO_VH(bool{true}, *, p_R3x3_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, *, p_R3x3_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, *, p_R3x3_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, *, p_R3x3_u); - - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<1>{1.3}), *, p_R1_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), *, p_R2_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // - 4.7, 2.3, 7.1, // - 9.7, 3.2, 6.8}), - *, p_R3_u); - - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<1>{1.3}), *, p_R1x1_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), *, p_R2x2_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // - 4.7, 2.3, 7.1, // - 9.7, 3.2, 6.8}), - *, p_R3x3_u); - - CHECK_VECTOR_XxVH_TO_VH(bool{true}, *, p_Vector3_u); - CHECK_VECTOR_XxVH_TO_VH(uint64_t{1}, *, p_Vector3_u); - CHECK_VECTOR_XxVH_TO_VH(int64_t{2}, *, p_Vector3_u); - CHECK_VECTOR_XxVH_TO_VH(double{1.3}, *, p_Vector3_u); - - REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_R_u, "error: incompatible operand types R^1x1 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R_u, - "error: incompatible operand types R^2x2 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R_u, - "error: incompatible operand types R^3x3 and Vh(P0:R)"); - - REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_R2_u, - "error: incompatible operand types R^1x1 and Vh(P0:R^2)"); - REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R3_u, - "error: incompatible operand types R^2x2 and Vh(P0:R^3)"); - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R2_u, - "error: incompatible operand types R^3x3 and Vh(P0:R^2)"); - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R1_u, - "error: incompatible operand types R^3x3 and Vh(P0:R^1)"); - - REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_R2x2_u, - "error: incompatible operand types R^1x1 and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R3x3_u, - "error: incompatible operand types R^2x2 and Vh(P0:R^3x3)"); - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R2x2_u, - "error: incompatible operand types R^3x3 and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R1x1_u, - "error: incompatible operand types R^2x2 and Vh(P0:R^1x1)"); - - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_Vector3_u, - "error: incompatible operand types R^3x3 and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_Vector3_u, - "error: incompatible operand types R^1x1 and Vh(P0Vector:R)"); - } - } - - SECTION("ratio") - { - SECTION("Vh / Vh -> Vh") - { - CHECK_SCALAR_VH2_TO_VH(p_R_u, /, p_R_v); - - REQUIRE_THROWS_WITH(p_R_u / p_R1_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R2_u / p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R3_u / p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(p_R_u / p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); - - REQUIRE_THROWS_WITH(p_R_u / p_other_mesh_R_u, "error: operands are defined on different meshes"); - } - - SECTION("X / Vh -> Vh") - { - CHECK_SCALAR_XxVH_TO_VH(bool{true}, /, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, /, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, /, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, /, p_R_u); - } - } - } - } - } - - SECTION("2D") - { - constexpr size_t Dimension = 2; - - using Rd = TinyVector<Dimension>; - - std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - - for (auto named_mesh : mesh_list) { - SECTION(named_mesh.name()) - { - auto mesh = named_mesh.mesh(); - - std::shared_ptr other_mesh = - std::make_shared<Mesh<Connectivity<Dimension>>>(mesh->shared_connectivity(), mesh->xr()); - - CellValue<const Rd> xj = MeshDataManager::instance().getMeshData(*mesh).xj(); - - CellValue<double> u_R_values = [=] { - CellValue<double> build_values{mesh->connectivity()}; - parallel_for( - build_values.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.2 + std::cos(l2Norm(xj[cell_id])); }); - return build_values; - }(); - - CellValue<double> v_R_values = [=] { - CellValue<double> build_values{mesh->connectivity()}; - parallel_for( - build_values.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.6 + std::sin(l2Norm(xj[cell_id])); }); - return build_values; - }(); - - std::shared_ptr p_R_u = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, u_R_values); - std::shared_ptr p_other_mesh_R_u = - std::make_shared<const DiscreteFunctionP0<Dimension, double>>(other_mesh, u_R_values); - std::shared_ptr p_R_v = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, v_R_values); - - std::shared_ptr p_R1_u = [=] { - CellValue<TinyVector<1>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id][0] = 2 * xj[cell_id][0] + 1; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, uj); - }(); - - std::shared_ptr p_R1_v = [=] { - CellValue<TinyVector<1>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { vj[cell_id][0] = xj[cell_id][0] * xj[cell_id][0] + 1; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, vj); - }(); - - std::shared_ptr p_other_mesh_R1_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(other_mesh, p_R1_u->cellValues()); - - constexpr auto to_2d = [&](const TinyVector<Dimension>& x) -> TinyVector<2> { - if constexpr (Dimension == 1) { - return TinyVector<2>{x[0], 1 + x[0] * x[0]}; - } else if constexpr (Dimension == 2) { - return TinyVector<2>{x[0], x[1]}; - } else if constexpr (Dimension == 3) { - return TinyVector<2>{x[0], x[1] + x[2]}; - } - }; - - std::shared_ptr p_R2_u = [=] { - CellValue<TinyVector<2>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - uj[cell_id] = TinyVector<2>{2 * x[0] + 1, 1 - x[1]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, uj); - }(); - - std::shared_ptr p_R2_v = [=] { - CellValue<TinyVector<2>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - vj[cell_id] = TinyVector<2>{x[0] * x[1] + 1, 2 * x[1]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, vj); - }(); - - std::shared_ptr p_other_mesh_R2_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(other_mesh, p_R2_u->cellValues()); - - constexpr auto to_3d = [&](const TinyVector<Dimension>& x) -> TinyVector<3> { - if constexpr (Dimension == 1) { - return TinyVector<3>{x[0], 1 + x[0] * x[0], 2 - x[0]}; - } else if constexpr (Dimension == 2) { - return TinyVector<3>{x[0], x[1], x[0] + x[1]}; - } else if constexpr (Dimension == 3) { - return TinyVector<3>{x[0], x[1], x[2]}; - } - }; - - std::shared_ptr p_R3_u = [=] { - CellValue<TinyVector<3>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - uj[cell_id] = TinyVector<3>{2 * x[0] + 1, 1 - x[1] * x[2], x[0] + x[2]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, uj); - }(); - - std::shared_ptr p_R3_v = [=] { - CellValue<TinyVector<3>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - vj[cell_id] = TinyVector<3>{x[0] * x[1] + 1, 2 * x[1], x[2] * x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, vj); - }(); - - std::shared_ptr p_other_mesh_R3_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(other_mesh, p_R3_u->cellValues()); - - std::shared_ptr p_R1x1_u = [=] { - CellValue<TinyMatrix<1>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { uj[cell_id] = TinyMatrix<1>{2 * xj[cell_id][0] + 1}; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(mesh, uj); - }(); - - std::shared_ptr p_other_mesh_R1x1_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(other_mesh, p_R1x1_u->cellValues()); - - std::shared_ptr p_R1x1_v = [=] { - CellValue<TinyMatrix<1>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { vj[cell_id] = TinyMatrix<1>{0.3 - xj[cell_id][0]}; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(mesh, vj); - }(); - - std::shared_ptr p_R2x2_u = [=] { - CellValue<TinyMatrix<2>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - - uj[cell_id] = TinyMatrix<2>{2 * x[0] + 1, 1 - x[1], // - 2 * x[1], -x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(mesh, uj); - }(); - - std::shared_ptr p_other_mesh_R2x2_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(other_mesh, p_R2x2_u->cellValues()); - - std::shared_ptr p_R2x2_v = [=] { - CellValue<TinyMatrix<2>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - - vj[cell_id] = TinyMatrix<2>{x[0] + 0.3, 1 - x[1] - x[0], // - 2 * x[1] + x[0], x[1] - x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(mesh, vj); - }(); - - std::shared_ptr p_R3x3_u = [=] { - CellValue<TinyMatrix<3>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - - uj[cell_id] = TinyMatrix<3>{2 * x[0] + 1, 1 - x[1], 3, // - 2 * x[1], -x[0], x[0] - x[1], // - 3 * x[2] - x[1], x[1] - 2 * x[2], x[2] - x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(mesh, uj); - }(); - - std::shared_ptr p_other_mesh_R3x3_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(other_mesh, p_R3x3_u->cellValues()); - - std::shared_ptr p_R3x3_v = [=] { - CellValue<TinyMatrix<3>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - - vj[cell_id] = TinyMatrix<3>{0.2 * x[0] + 1, 2 + x[1], 3 - x[2], // - 2.3 * x[2], x[1] - x[0], x[2] - x[1], // - 2 * x[2] + x[0], x[1] + 0.2 * x[2], x[2] - 2 * x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(mesh, vj); - }(); - - std::shared_ptr p_Vector3_u = [=] { - CellArray<double> uj_vector{mesh->connectivity(), 3}; - parallel_for( - uj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - uj_vector[cell_id][0] = 2 * x[0] + 1; - uj_vector[cell_id][1] = 1 - x[1] * x[2]; - uj_vector[cell_id][2] = x[0] + x[2]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, uj_vector); - }(); - - std::shared_ptr p_other_mesh_Vector3_u = - std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(other_mesh, p_Vector3_u->cellArrays()); - - std::shared_ptr p_Vector3_v = [=] { - CellArray<double> vj_vector{mesh->connectivity(), 3}; - parallel_for( - vj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - vj_vector[cell_id][0] = x[0] * x[1] + 1; - vj_vector[cell_id][1] = 2 * x[1]; - vj_vector[cell_id][2] = x[2] * x[0]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, vj_vector); - }(); - - std::shared_ptr p_Vector2_w = [=] { - CellArray<double> wj_vector{mesh->connectivity(), 2}; - parallel_for( - wj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - wj_vector[cell_id][0] = x[0] + x[1] * 2; - wj_vector[cell_id][1] = x[0] * x[1]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, wj_vector); - }(); - - SECTION("sum") - { - SECTION("Vh + Vh -> Vh") - { - CHECK_SCALAR_VH2_TO_VH(p_R_u, +, p_R_v); - - CHECK_SCALAR_VH2_TO_VH(p_R1_u, +, p_R1_v); - CHECK_SCALAR_VH2_TO_VH(p_R2_u, +, p_R2_v); - CHECK_SCALAR_VH2_TO_VH(p_R3_u, +, p_R3_v); - - CHECK_SCALAR_VH2_TO_VH(p_R1x1_u, +, p_R1x1_v); - CHECK_SCALAR_VH2_TO_VH(p_R2x2_u, +, p_R2x2_v); - CHECK_SCALAR_VH2_TO_VH(p_R3x3_u, +, p_R3x3_v); - - CHECK_VECTOR_VH2_TO_VH(p_Vector3_u, +, p_Vector3_v); - - REQUIRE_THROWS_WITH(p_R_u + p_R1_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R2_u + p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R3_u + p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(p_R_u + p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(p_R_u + p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(p_Vector3_u + p_R_v, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R)"); - REQUIRE_THROWS_WITH(p_Vector3_u + p_Vector2_w, "error: Vh(P0Vector:R) spaces have different sizes"); - - REQUIRE_THROWS_WITH(p_R_u + p_other_mesh_R_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R1_u + p_other_mesh_R1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R2_u + p_other_mesh_R2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R3_u + p_other_mesh_R3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R1x1_u + p_other_mesh_R1x1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R2x2_u + p_other_mesh_R2x2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R3x3_u + p_other_mesh_R3x3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_Vector3_u + p_other_mesh_Vector3_u, - "error: operands are defined on different meshes"); - } - - SECTION("Vh + X -> Vh") - { - CHECK_SCALAR_VHxX_TO_VH(p_R_u, +, bool{true}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, +, uint64_t{1}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, +, int64_t{2}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, +, double{1.3}); - - CHECK_SCALAR_VHxX_TO_VH(p_R1_u, +, (TinyVector<1>{1.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R2_u, +, (TinyVector<2>{1.2, 2.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R3_u, +, (TinyVector<3>{3.2, 7.1, 5.2})); - - CHECK_SCALAR_VHxX_TO_VH(p_R1x1_u, +, (TinyMatrix<1>{1.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R2x2_u, +, (TinyMatrix<2>{1.2, 2.3, 4.2, 5.1})); - CHECK_SCALAR_VHxX_TO_VH(p_R3x3_u, +, - (TinyMatrix<3>{3.2, 7.1, 5.2, // - 4.7, 2.3, 7.1, // - 9.7, 3.2, 6.8})); - - REQUIRE_THROWS_WITH(p_R_u + (TinyVector<1>{1}), "error: incompatible operand types Vh(P0:R) and R^1"); - REQUIRE_THROWS_WITH(p_R_u + (TinyVector<2>{1, 2}), "error: incompatible operand types Vh(P0:R) and R^2"); - REQUIRE_THROWS_WITH(p_R_u + (TinyVector<3>{2, 3, 2}), - "error: incompatible operand types Vh(P0:R) and R^3"); - REQUIRE_THROWS_WITH(p_R_u + (TinyMatrix<1>{2}), "error: incompatible operand types Vh(P0:R) and R^1x1"); - REQUIRE_THROWS_WITH(p_R_u + (TinyMatrix<2>{2, 3, 1, 4}), - "error: incompatible operand types Vh(P0:R) and R^2x2"); - REQUIRE_THROWS_WITH(p_R_u + (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), - "error: incompatible operand types Vh(P0:R) and R^3x3"); - - REQUIRE_THROWS_WITH(p_Vector3_u + (double{1}), "error: incompatible operand types Vh(P0Vector:R) and R"); - REQUIRE_THROWS_WITH(p_Vector3_u + (TinyVector<1>{1}), - "error: incompatible operand types Vh(P0Vector:R) and R^1"); - REQUIRE_THROWS_WITH(p_Vector3_u + (TinyVector<2>{1, 2}), - "error: incompatible operand types Vh(P0Vector:R) and R^2"); - } - - SECTION("X + Vh -> Vh") - { - CHECK_SCALAR_XxVH_TO_VH(bool{true}, +, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, +, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, +, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, +, p_R_u); - - CHECK_SCALAR_XxVH_TO_VH((TinyVector<1>{1.3}), +, p_R1_u); - CHECK_SCALAR_XxVH_TO_VH((TinyVector<2>{1.2, 2.3}), +, p_R2_u); - CHECK_SCALAR_XxVH_TO_VH((TinyVector<3>{3.2, 7.1, 5.2}), +, p_R3_u); - - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<1>{1.3}), +, p_R1x1_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), +, p_R2x2_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // - 4.7, 2.3, 7.1, // - 9.7, 3.2, 6.8}), - +, p_R3x3_u); - - REQUIRE_THROWS_WITH((TinyVector<1>{1}) + p_R_u, "error: incompatible operand types R^1 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) + p_R_u, "error: incompatible operand types R^2 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyVector<3>{2, 3, 2}) + p_R_u, - "error: incompatible operand types R^3 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) + p_R_u, "error: incompatible operand types R^1x1 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) + p_R_u, - "error: incompatible operand types R^2x2 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) + p_R_u, - "error: incompatible operand types R^3x3 and Vh(P0:R)"); - - REQUIRE_THROWS_WITH((double{1}) + p_Vector3_u, "error: incompatible operand types R and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH((TinyVector<1>{1}) + p_Vector3_u, - "error: incompatible operand types R^1 and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) + p_Vector3_u, - "error: incompatible operand types R^2 and Vh(P0Vector:R)"); - } - } - - SECTION("difference") - { - SECTION("Vh - Vh -> Vh") - { - CHECK_SCALAR_VH2_TO_VH(p_R_u, -, p_R_v); - - CHECK_SCALAR_VH2_TO_VH(p_R1_u, -, p_R1_v); - CHECK_SCALAR_VH2_TO_VH(p_R2_u, -, p_R2_v); - CHECK_SCALAR_VH2_TO_VH(p_R3_u, -, p_R3_v); - - CHECK_SCALAR_VH2_TO_VH(p_R1x1_u, -, p_R1x1_v); - CHECK_SCALAR_VH2_TO_VH(p_R2x2_u, -, p_R2x2_v); - CHECK_SCALAR_VH2_TO_VH(p_R3x3_u, -, p_R3x3_v); - - CHECK_VECTOR_VH2_TO_VH(p_Vector3_u, -, p_Vector3_v); - - REQUIRE_THROWS_WITH(p_R_u - p_R1_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R2_u - p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R3_u - p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(p_R_u - p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(p_Vector3_u - p_R_v, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R)"); - REQUIRE_THROWS_WITH(p_Vector3_u - p_Vector2_w, "error: Vh(P0Vector:R) spaces have different sizes"); - - REQUIRE_THROWS_WITH(p_R_u - p_other_mesh_R_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R1_u - p_other_mesh_R1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R2_u - p_other_mesh_R2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R3_u - p_other_mesh_R3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R1x1_u - p_other_mesh_R1x1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R2x2_u - p_other_mesh_R2x2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R3x3_u - p_other_mesh_R3x3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_Vector3_u - p_other_mesh_Vector3_u, - "error: operands are defined on different meshes"); - } - - SECTION("Vh - X -> Vh") - { - CHECK_SCALAR_VHxX_TO_VH(p_R_u, -, bool{true}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, -, uint64_t{1}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, -, int64_t{2}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, -, double{1.3}); - - CHECK_SCALAR_VHxX_TO_VH(p_R1_u, -, (TinyVector<1>{1.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R2_u, -, (TinyVector<2>{1.2, 2.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R3_u, -, (TinyVector<3>{3.2, 7.1, 5.2})); - - CHECK_SCALAR_VHxX_TO_VH(p_R1x1_u, -, (TinyMatrix<1>{1.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R2x2_u, -, (TinyMatrix<2>{1.2, 2.3, 4.2, 5.1})); - CHECK_SCALAR_VHxX_TO_VH(p_R3x3_u, -, - (TinyMatrix<3>{3.2, 7.1, 5.2, // - 4.7, 2.3, 7.1, // - 9.7, 3.2, 6.8})); - - REQUIRE_THROWS_WITH(p_R_u - (TinyVector<1>{1}), "error: incompatible operand types Vh(P0:R) and R^1"); - REQUIRE_THROWS_WITH(p_R_u - (TinyVector<2>{1, 2}), "error: incompatible operand types Vh(P0:R) and R^2"); - REQUIRE_THROWS_WITH(p_R_u - (TinyVector<3>{2, 3, 2}), - "error: incompatible operand types Vh(P0:R) and R^3"); - REQUIRE_THROWS_WITH(p_R_u - (TinyMatrix<1>{2}), "error: incompatible operand types Vh(P0:R) and R^1x1"); - REQUIRE_THROWS_WITH(p_R_u - (TinyMatrix<2>{2, 3, 1, 4}), - "error: incompatible operand types Vh(P0:R) and R^2x2"); - REQUIRE_THROWS_WITH(p_R_u - (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), - "error: incompatible operand types Vh(P0:R) and R^3x3"); - - REQUIRE_THROWS_WITH(p_Vector3_u - (double{1}), "error: incompatible operand types Vh(P0Vector:R) and R"); - REQUIRE_THROWS_WITH(p_Vector3_u - (TinyVector<1>{1}), - "error: incompatible operand types Vh(P0Vector:R) and R^1"); - REQUIRE_THROWS_WITH(p_Vector3_u - (TinyVector<2>{1, 2}), - "error: incompatible operand types Vh(P0Vector:R) and R^2"); - } - - SECTION("X - Vh -> Vh") - { - CHECK_SCALAR_XxVH_TO_VH(bool{true}, -, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, -, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, -, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, -, p_R_u); - - CHECK_SCALAR_XxVH_TO_VH((TinyVector<1>{1.3}), -, p_R1_u); - CHECK_SCALAR_XxVH_TO_VH((TinyVector<2>{1.2, 2.3}), -, p_R2_u); - CHECK_SCALAR_XxVH_TO_VH((TinyVector<3>{3.2, 7.1, 5.2}), -, p_R3_u); - - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<1>{1.3}), -, p_R1x1_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), -, p_R2x2_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // - 4.7, 2.3, 7.1, // - 9.7, 3.2, 6.8}), - -, p_R3x3_u); - - REQUIRE_THROWS_WITH((TinyVector<1>{1}) - p_R_u, "error: incompatible operand types R^1 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) - p_R_u, "error: incompatible operand types R^2 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyVector<3>{2, 3, 2}) - p_R_u, - "error: incompatible operand types R^3 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) - p_R_u, "error: incompatible operand types R^1x1 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) - p_R_u, - "error: incompatible operand types R^2x2 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) - p_R_u, - "error: incompatible operand types R^3x3 and Vh(P0:R)"); - - REQUIRE_THROWS_WITH((double{1}) - p_Vector3_u, "error: incompatible operand types R and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH((TinyVector<1>{1}) - p_Vector3_u, - "error: incompatible operand types R^1 and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) - p_Vector3_u, - "error: incompatible operand types R^2 and Vh(P0Vector:R)"); - } - } - - SECTION("product") - { - SECTION("Vh * Vh -> Vh") - { - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R_v); - - CHECK_SCALAR_VH2_TO_VH(p_R1x1_u, *, p_R1x1_v); - CHECK_SCALAR_VH2_TO_VH(p_R2x2_u, *, p_R2x2_v); - CHECK_SCALAR_VH2_TO_VH(p_R3x3_u, *, p_R3x3_v); - - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R1_v); - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R2_v); - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R3_v); - - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R1x1_v); - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R2x2_v); - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R3x3_v); - - CHECK_SCALAR_VH2_TO_VH(p_R1x1_u, *, p_R1_v); - CHECK_SCALAR_VH2_TO_VH(p_R2x2_u, *, p_R2_v); - CHECK_SCALAR_VH2_TO_VH(p_R3x3_u, *, p_R3_v); - - { - std::shared_ptr p_fuv = p_R_u * p_Vector3_v; - - REQUIRE(p_fuv.use_count() > 0); - REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*p_fuv)); - - const auto& fuv = dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*p_fuv); - - auto lhs_values = p_R_u->cellValues(); - auto rhs_arrays = p_Vector3_v->cellArrays(); - bool is_same = true; - for (CellId cell_id = 0; cell_id < lhs_values.numberOfItems(); ++cell_id) { - for (size_t i = 0; i < fuv.size(); ++i) { - if (fuv[cell_id][i] != (lhs_values[cell_id] * rhs_arrays[cell_id][i])) { - is_same = false; - break; - } - } - } - - REQUIRE(is_same); - } - - REQUIRE_THROWS_WITH(p_R1_u * p_R1_v, "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R2_u * p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R3_u * p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(p_R1_u * p_R2x2_v, "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^2x2)"); - - REQUIRE_THROWS_WITH(p_R1x1_u * p_R2x2_v, - "error: incompatible operand types Vh(P0:R^1x1) and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(p_R2x2_u * p_R3x3_v, - "error: incompatible operand types Vh(P0:R^2x2) and Vh(P0:R^3x3)"); - REQUIRE_THROWS_WITH(p_R3x3_u * p_R1x1_v, - "error: incompatible operand types Vh(P0:R^3x3) and Vh(P0:R^1x1)"); - - REQUIRE_THROWS_WITH(p_R1x1_u * p_R2_v, "error: incompatible operand types Vh(P0:R^1x1) and Vh(P0:R^2)"); - REQUIRE_THROWS_WITH(p_R2x2_u * p_R3_v, "error: incompatible operand types Vh(P0:R^2x2) and Vh(P0:R^3)"); - REQUIRE_THROWS_WITH(p_R3x3_u * p_R1_v, "error: incompatible operand types Vh(P0:R^3x3) and Vh(P0:R^1)"); - - REQUIRE_THROWS_WITH(p_R1_u * p_Vector3_v, - "error: incompatible operand types Vh(P0:R^1) and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH(p_R2_u * p_Vector3_v, - "error: incompatible operand types Vh(P0:R^2) and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH(p_R3_u * p_Vector3_v, - "error: incompatible operand types Vh(P0:R^3) and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH(p_R1x1_u * p_Vector3_v, - "error: incompatible operand types Vh(P0:R^1x1) and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH(p_R2x2_u * p_Vector3_v, - "error: incompatible operand types Vh(P0:R^2x2) and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH(p_R3x3_u * p_Vector3_v, - "error: incompatible operand types Vh(P0:R^3x3) and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH(p_Vector3_u * p_Vector3_v, - "error: incompatible operand types Vh(P0Vector:R) and Vh(P0Vector:R)"); - - REQUIRE_THROWS_WITH(p_Vector3_v * p_R_u, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R)"); - REQUIRE_THROWS_WITH(p_Vector3_v * p_R1_u, - "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_Vector3_v * p_R2_u, - "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^2)"); - REQUIRE_THROWS_WITH(p_Vector3_v * p_R3_u, - "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^3)"); - REQUIRE_THROWS_WITH(p_Vector3_v * p_R1x1_u, - "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(p_Vector3_v * p_R2x2_u, - "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(p_Vector3_v * p_R3x3_u, - "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^3x3)"); - - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R1x1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R2x2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R3x3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R1x1_u * p_other_mesh_R1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R2x2_u * p_other_mesh_R2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R3x3_u * p_other_mesh_R3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_Vector3_u, "error: operands are defined on different meshes"); - } - - SECTION("Vh * X -> Vh") - { - CHECK_SCALAR_VHxX_TO_VH(p_R_u, *, bool{true}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, *, uint64_t{1}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, *, int64_t{2}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, *, double{1.3}); - - CHECK_SCALAR_VHxX_TO_VH(p_R1x1_u, *, (TinyMatrix<1>{1.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R2x2_u, *, (TinyMatrix<2>{1.2, 2.3, 4.2, 5.1})); - CHECK_SCALAR_VHxX_TO_VH(p_R3x3_u, *, - (TinyMatrix<3>{3.2, 7.1, 5.2, // - 4.7, 2.3, 7.1, // - 9.7, 3.2, 6.8})); - - REQUIRE_THROWS_WITH(p_R1_u * (TinyVector<1>{1}), "error: incompatible operand types Vh(P0:R^1) and R^1"); - REQUIRE_THROWS_WITH(p_R2_u * (TinyVector<2>{1, 2}), - "error: incompatible operand types Vh(P0:R^2) and R^2"); - REQUIRE_THROWS_WITH(p_R3_u * (TinyVector<3>{2, 3, 2}), - "error: incompatible operand types Vh(P0:R^3) and R^3"); - REQUIRE_THROWS_WITH(p_R1_u * (TinyMatrix<1>{2}), - "error: incompatible operand types Vh(P0:R^1) and R^1x1"); - REQUIRE_THROWS_WITH(p_R2_u * (TinyMatrix<2>{2, 3, 1, 4}), - "error: incompatible operand types Vh(P0:R^2) and R^2x2"); - REQUIRE_THROWS_WITH(p_R3_u * (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), - "error: incompatible operand types Vh(P0:R^3) and R^3x3"); - REQUIRE_THROWS_WITH(p_R2x2_u * (TinyMatrix<1>{2}), - "error: incompatible operand types Vh(P0:R^2x2) and R^1x1"); - REQUIRE_THROWS_WITH(p_R1x1_u * (TinyMatrix<2>{2, 3, 1, 4}), - "error: incompatible operand types Vh(P0:R^1x1) and R^2x2"); - REQUIRE_THROWS_WITH(p_R2x2_u * (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), - "error: incompatible operand types Vh(P0:R^2x2) and R^3x3"); - - REQUIRE_THROWS_WITH(p_Vector3_u * (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), - "error: incompatible operand types Vh(P0Vector:R) and R^3x3"); - REQUIRE_THROWS_WITH(p_Vector3_u * (double{2}), "error: incompatible operand types Vh(P0Vector:R) and R"); - } - - SECTION("X * Vh -> Vh") - { - CHECK_SCALAR_XxVH_TO_VH(bool{true}, *, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, *, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, *, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, *, p_R_u); - - CHECK_SCALAR_XxVH_TO_VH(bool{true}, *, p_R1x1_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, *, p_R1x1_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, *, p_R1x1_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, *, p_R1x1_u); - - CHECK_SCALAR_XxVH_TO_VH(bool{true}, *, p_R2x2_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, *, p_R2x2_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, *, p_R2x2_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, *, p_R2x2_u); - - CHECK_SCALAR_XxVH_TO_VH(bool{true}, *, p_R3x3_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, *, p_R3x3_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, *, p_R3x3_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, *, p_R3x3_u); - - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<1>{1.3}), *, p_R1_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), *, p_R2_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // - 4.7, 2.3, 7.1, // - 9.7, 3.2, 6.8}), - *, p_R3_u); - - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<1>{1.3}), *, p_R1x1_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), *, p_R2x2_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // - 4.7, 2.3, 7.1, // - 9.7, 3.2, 6.8}), - *, p_R3x3_u); - - CHECK_VECTOR_XxVH_TO_VH(bool{true}, *, p_Vector3_u); - CHECK_VECTOR_XxVH_TO_VH(uint64_t{1}, *, p_Vector3_u); - CHECK_VECTOR_XxVH_TO_VH(int64_t{2}, *, p_Vector3_u); - CHECK_VECTOR_XxVH_TO_VH(double{1.3}, *, p_Vector3_u); - - REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_R_u, "error: incompatible operand types R^1x1 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R_u, - "error: incompatible operand types R^2x2 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R_u, - "error: incompatible operand types R^3x3 and Vh(P0:R)"); - - REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_R2_u, - "error: incompatible operand types R^1x1 and Vh(P0:R^2)"); - REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R3_u, - "error: incompatible operand types R^2x2 and Vh(P0:R^3)"); - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R2_u, - "error: incompatible operand types R^3x3 and Vh(P0:R^2)"); - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R1_u, - "error: incompatible operand types R^3x3 and Vh(P0:R^1)"); - - REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_R2x2_u, - "error: incompatible operand types R^1x1 and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R3x3_u, - "error: incompatible operand types R^2x2 and Vh(P0:R^3x3)"); - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R2x2_u, - "error: incompatible operand types R^3x3 and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R1x1_u, - "error: incompatible operand types R^2x2 and Vh(P0:R^1x1)"); - - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_Vector3_u, - "error: incompatible operand types R^3x3 and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_Vector3_u, - "error: incompatible operand types R^1x1 and Vh(P0Vector:R)"); - } - } - - SECTION("ratio") - { - SECTION("Vh / Vh -> Vh") - { - CHECK_SCALAR_VH2_TO_VH(p_R_u, /, p_R_v); - - REQUIRE_THROWS_WITH(p_R_u / p_R1_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R2_u / p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R3_u / p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(p_R_u / p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); - - REQUIRE_THROWS_WITH(p_R_u / p_other_mesh_R_u, "error: operands are defined on different meshes"); - } - - SECTION("X / Vh -> Vh") - { - CHECK_SCALAR_XxVH_TO_VH(bool{true}, /, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, /, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, /, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, /, p_R_u); - } - } - } - } - } - - SECTION("3D") - { - constexpr size_t Dimension = 3; - - using Rd = TinyVector<Dimension>; - - std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - - for (auto named_mesh : mesh_list) { - SECTION(named_mesh.name()) - { - auto mesh = named_mesh.mesh(); - - std::shared_ptr other_mesh = - std::make_shared<Mesh<Connectivity<Dimension>>>(mesh->shared_connectivity(), mesh->xr()); - - CellValue<const Rd> xj = MeshDataManager::instance().getMeshData(*mesh).xj(); - - CellValue<double> u_R_values = [=] { - CellValue<double> build_values{mesh->connectivity()}; - parallel_for( - build_values.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.2 + std::cos(l2Norm(xj[cell_id])); }); - return build_values; - }(); - - CellValue<double> v_R_values = [=] { - CellValue<double> build_values{mesh->connectivity()}; - parallel_for( - build_values.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.6 + std::sin(l2Norm(xj[cell_id])); }); - return build_values; - }(); - - std::shared_ptr p_R_u = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, u_R_values); - std::shared_ptr p_other_mesh_R_u = - std::make_shared<const DiscreteFunctionP0<Dimension, double>>(other_mesh, u_R_values); - std::shared_ptr p_R_v = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, v_R_values); - - std::shared_ptr p_R1_u = [=] { - CellValue<TinyVector<1>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id][0] = 2 * xj[cell_id][0] + 1; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, uj); - }(); - - std::shared_ptr p_R1_v = [=] { - CellValue<TinyVector<1>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { vj[cell_id][0] = xj[cell_id][0] * xj[cell_id][0] + 1; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, vj); - }(); - - std::shared_ptr p_other_mesh_R1_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(other_mesh, p_R1_u->cellValues()); - - constexpr auto to_2d = [&](const TinyVector<Dimension>& x) -> TinyVector<2> { - if constexpr (Dimension == 1) { - return TinyVector<2>{x[0], 1 + x[0] * x[0]}; - } else if constexpr (Dimension == 2) { - return TinyVector<2>{x[0], x[1]}; - } else if constexpr (Dimension == 3) { - return TinyVector<2>{x[0], x[1] + x[2]}; - } - }; - - std::shared_ptr p_R2_u = [=] { - CellValue<TinyVector<2>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - uj[cell_id] = TinyVector<2>{2 * x[0] + 1, 1 - x[1]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, uj); - }(); - - std::shared_ptr p_R2_v = [=] { - CellValue<TinyVector<2>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - vj[cell_id] = TinyVector<2>{x[0] * x[1] + 1, 2 * x[1]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, vj); - }(); - - std::shared_ptr p_other_mesh_R2_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(other_mesh, p_R2_u->cellValues()); - - constexpr auto to_3d = [&](const TinyVector<Dimension>& x) -> TinyVector<3> { - if constexpr (Dimension == 1) { - return TinyVector<3>{x[0], 1 + x[0] * x[0], 2 - x[0]}; - } else if constexpr (Dimension == 2) { - return TinyVector<3>{x[0], x[1], x[0] + x[1]}; - } else if constexpr (Dimension == 3) { - return TinyVector<3>{x[0], x[1], x[2]}; - } - }; - - std::shared_ptr p_R3_u = [=] { - CellValue<TinyVector<3>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - uj[cell_id] = TinyVector<3>{2 * x[0] + 1, 1 - x[1] * x[2], x[0] + x[2]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, uj); - }(); - - std::shared_ptr p_R3_v = [=] { - CellValue<TinyVector<3>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - vj[cell_id] = TinyVector<3>{x[0] * x[1] + 1, 2 * x[1], x[2] * x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, vj); - }(); - - std::shared_ptr p_other_mesh_R3_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(other_mesh, p_R3_u->cellValues()); - - std::shared_ptr p_R1x1_u = [=] { - CellValue<TinyMatrix<1>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { uj[cell_id] = TinyMatrix<1>{2 * xj[cell_id][0] + 1}; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(mesh, uj); - }(); - - std::shared_ptr p_other_mesh_R1x1_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(other_mesh, p_R1x1_u->cellValues()); - - std::shared_ptr p_R1x1_v = [=] { - CellValue<TinyMatrix<1>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { vj[cell_id] = TinyMatrix<1>{0.3 - xj[cell_id][0]}; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(mesh, vj); - }(); - - std::shared_ptr p_R2x2_u = [=] { - CellValue<TinyMatrix<2>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - - uj[cell_id] = TinyMatrix<2>{2 * x[0] + 1, 1 - x[1], // - 2 * x[1], -x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(mesh, uj); - }(); - - std::shared_ptr p_other_mesh_R2x2_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(other_mesh, p_R2x2_u->cellValues()); - - std::shared_ptr p_R2x2_v = [=] { - CellValue<TinyMatrix<2>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - - vj[cell_id] = TinyMatrix<2>{x[0] + 0.3, 1 - x[1] - x[0], // - 2 * x[1] + x[0], x[1] - x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(mesh, vj); - }(); - - std::shared_ptr p_R3x3_u = [=] { - CellValue<TinyMatrix<3>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - - uj[cell_id] = TinyMatrix<3>{2 * x[0] + 1, 1 - x[1], 3, // - 2 * x[1], -x[0], x[0] - x[1], // - 3 * x[2] - x[1], x[1] - 2 * x[2], x[2] - x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(mesh, uj); - }(); - - std::shared_ptr p_other_mesh_R3x3_u = - std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(other_mesh, p_R3x3_u->cellValues()); - - std::shared_ptr p_R3x3_v = [=] { - CellValue<TinyMatrix<3>> vj{mesh->connectivity()}; - parallel_for( - vj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - - vj[cell_id] = TinyMatrix<3>{0.2 * x[0] + 1, 2 + x[1], 3 - x[2], // - 2.3 * x[2], x[1] - x[0], x[2] - x[1], // - 2 * x[2] + x[0], x[1] + 0.2 * x[2], x[2] - 2 * x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(mesh, vj); - }(); - - std::shared_ptr p_Vector3_u = [=] { - CellArray<double> uj_vector{mesh->connectivity(), 3}; - parallel_for( - uj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - uj_vector[cell_id][0] = 2 * x[0] + 1; - uj_vector[cell_id][1] = 1 - x[1] * x[2]; - uj_vector[cell_id][2] = x[0] + x[2]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, uj_vector); - }(); - - std::shared_ptr p_other_mesh_Vector3_u = - std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(other_mesh, p_Vector3_u->cellArrays()); - - std::shared_ptr p_Vector3_v = [=] { - CellArray<double> vj_vector{mesh->connectivity(), 3}; - parallel_for( - vj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - vj_vector[cell_id][0] = x[0] * x[1] + 1; - vj_vector[cell_id][1] = 2 * x[1]; - vj_vector[cell_id][2] = x[2] * x[0]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, vj_vector); - }(); - - std::shared_ptr p_Vector2_w = [=] { - CellArray<double> wj_vector{mesh->connectivity(), 2}; - parallel_for( - wj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - wj_vector[cell_id][0] = x[0] + x[1] * 2; - wj_vector[cell_id][1] = x[0] * x[1]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, wj_vector); - }(); - - SECTION("sum") - { - SECTION("Vh + Vh -> Vh") - { - CHECK_SCALAR_VH2_TO_VH(p_R_u, +, p_R_v); - - CHECK_SCALAR_VH2_TO_VH(p_R1_u, +, p_R1_v); - CHECK_SCALAR_VH2_TO_VH(p_R2_u, +, p_R2_v); - CHECK_SCALAR_VH2_TO_VH(p_R3_u, +, p_R3_v); - - CHECK_SCALAR_VH2_TO_VH(p_R1x1_u, +, p_R1x1_v); - CHECK_SCALAR_VH2_TO_VH(p_R2x2_u, +, p_R2x2_v); - CHECK_SCALAR_VH2_TO_VH(p_R3x3_u, +, p_R3x3_v); - - CHECK_VECTOR_VH2_TO_VH(p_Vector3_u, +, p_Vector3_v); - - REQUIRE_THROWS_WITH(p_R_u + p_R1_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R2_u + p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R3_u + p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(p_R_u + p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(p_R_u + p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(p_Vector3_u + p_R_v, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R)"); - REQUIRE_THROWS_WITH(p_Vector3_u + p_Vector2_w, "error: Vh(P0Vector:R) spaces have different sizes"); - - REQUIRE_THROWS_WITH(p_R_u + p_other_mesh_R_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R1_u + p_other_mesh_R1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R2_u + p_other_mesh_R2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R3_u + p_other_mesh_R3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R1x1_u + p_other_mesh_R1x1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R2x2_u + p_other_mesh_R2x2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R3x3_u + p_other_mesh_R3x3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_Vector3_u + p_other_mesh_Vector3_u, - "error: operands are defined on different meshes"); - } - - SECTION("Vh + X -> Vh") - { - CHECK_SCALAR_VHxX_TO_VH(p_R_u, +, bool{true}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, +, uint64_t{1}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, +, int64_t{2}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, +, double{1.3}); - - CHECK_SCALAR_VHxX_TO_VH(p_R1_u, +, (TinyVector<1>{1.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R2_u, +, (TinyVector<2>{1.2, 2.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R3_u, +, (TinyVector<3>{3.2, 7.1, 5.2})); - - CHECK_SCALAR_VHxX_TO_VH(p_R1x1_u, +, (TinyMatrix<1>{1.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R2x2_u, +, (TinyMatrix<2>{1.2, 2.3, 4.2, 5.1})); - CHECK_SCALAR_VHxX_TO_VH(p_R3x3_u, +, - (TinyMatrix<3>{3.2, 7.1, 5.2, // - 4.7, 2.3, 7.1, // - 9.7, 3.2, 6.8})); - - REQUIRE_THROWS_WITH(p_R_u + (TinyVector<1>{1}), "error: incompatible operand types Vh(P0:R) and R^1"); - REQUIRE_THROWS_WITH(p_R_u + (TinyVector<2>{1, 2}), "error: incompatible operand types Vh(P0:R) and R^2"); - REQUIRE_THROWS_WITH(p_R_u + (TinyVector<3>{2, 3, 2}), - "error: incompatible operand types Vh(P0:R) and R^3"); - REQUIRE_THROWS_WITH(p_R_u + (TinyMatrix<1>{2}), "error: incompatible operand types Vh(P0:R) and R^1x1"); - REQUIRE_THROWS_WITH(p_R_u + (TinyMatrix<2>{2, 3, 1, 4}), - "error: incompatible operand types Vh(P0:R) and R^2x2"); - REQUIRE_THROWS_WITH(p_R_u + (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), - "error: incompatible operand types Vh(P0:R) and R^3x3"); - - REQUIRE_THROWS_WITH(p_Vector3_u + (double{1}), "error: incompatible operand types Vh(P0Vector:R) and R"); - REQUIRE_THROWS_WITH(p_Vector3_u + (TinyVector<1>{1}), - "error: incompatible operand types Vh(P0Vector:R) and R^1"); - REQUIRE_THROWS_WITH(p_Vector3_u + (TinyVector<2>{1, 2}), - "error: incompatible operand types Vh(P0Vector:R) and R^2"); - } - - SECTION("X + Vh -> Vh") - { - CHECK_SCALAR_XxVH_TO_VH(bool{true}, +, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, +, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, +, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, +, p_R_u); - - CHECK_SCALAR_XxVH_TO_VH((TinyVector<1>{1.3}), +, p_R1_u); - CHECK_SCALAR_XxVH_TO_VH((TinyVector<2>{1.2, 2.3}), +, p_R2_u); - CHECK_SCALAR_XxVH_TO_VH((TinyVector<3>{3.2, 7.1, 5.2}), +, p_R3_u); - - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<1>{1.3}), +, p_R1x1_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), +, p_R2x2_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // - 4.7, 2.3, 7.1, // - 9.7, 3.2, 6.8}), - +, p_R3x3_u); - - REQUIRE_THROWS_WITH((TinyVector<1>{1}) + p_R_u, "error: incompatible operand types R^1 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) + p_R_u, "error: incompatible operand types R^2 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyVector<3>{2, 3, 2}) + p_R_u, - "error: incompatible operand types R^3 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) + p_R_u, "error: incompatible operand types R^1x1 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) + p_R_u, - "error: incompatible operand types R^2x2 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) + p_R_u, - "error: incompatible operand types R^3x3 and Vh(P0:R)"); - - REQUIRE_THROWS_WITH((double{1}) + p_Vector3_u, "error: incompatible operand types R and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH((TinyVector<1>{1}) + p_Vector3_u, - "error: incompatible operand types R^1 and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) + p_Vector3_u, - "error: incompatible operand types R^2 and Vh(P0Vector:R)"); - } - } - - SECTION("difference") - { - SECTION("Vh - Vh -> Vh") - { - CHECK_SCALAR_VH2_TO_VH(p_R_u, -, p_R_v); - - CHECK_SCALAR_VH2_TO_VH(p_R1_u, -, p_R1_v); - CHECK_SCALAR_VH2_TO_VH(p_R2_u, -, p_R2_v); - CHECK_SCALAR_VH2_TO_VH(p_R3_u, -, p_R3_v); - - CHECK_SCALAR_VH2_TO_VH(p_R1x1_u, -, p_R1x1_v); - CHECK_SCALAR_VH2_TO_VH(p_R2x2_u, -, p_R2x2_v); - CHECK_SCALAR_VH2_TO_VH(p_R3x3_u, -, p_R3x3_v); - - CHECK_VECTOR_VH2_TO_VH(p_Vector3_u, -, p_Vector3_v); - - REQUIRE_THROWS_WITH(p_R_u - p_R1_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R2_u - p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R3_u - p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(p_R_u - p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(p_Vector3_u - p_R_v, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R)"); - REQUIRE_THROWS_WITH(p_Vector3_u - p_Vector2_w, "error: Vh(P0Vector:R) spaces have different sizes"); - - REQUIRE_THROWS_WITH(p_R_u - p_other_mesh_R_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R1_u - p_other_mesh_R1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R2_u - p_other_mesh_R2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R3_u - p_other_mesh_R3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R1x1_u - p_other_mesh_R1x1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R2x2_u - p_other_mesh_R2x2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R3x3_u - p_other_mesh_R3x3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_Vector3_u - p_other_mesh_Vector3_u, - "error: operands are defined on different meshes"); - } - - SECTION("Vh - X -> Vh") - { - CHECK_SCALAR_VHxX_TO_VH(p_R_u, -, bool{true}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, -, uint64_t{1}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, -, int64_t{2}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, -, double{1.3}); - - CHECK_SCALAR_VHxX_TO_VH(p_R1_u, -, (TinyVector<1>{1.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R2_u, -, (TinyVector<2>{1.2, 2.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R3_u, -, (TinyVector<3>{3.2, 7.1, 5.2})); - - CHECK_SCALAR_VHxX_TO_VH(p_R1x1_u, -, (TinyMatrix<1>{1.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R2x2_u, -, (TinyMatrix<2>{1.2, 2.3, 4.2, 5.1})); - CHECK_SCALAR_VHxX_TO_VH(p_R3x3_u, -, - (TinyMatrix<3>{3.2, 7.1, 5.2, // - 4.7, 2.3, 7.1, // - 9.7, 3.2, 6.8})); - - REQUIRE_THROWS_WITH(p_R_u - (TinyVector<1>{1}), "error: incompatible operand types Vh(P0:R) and R^1"); - REQUIRE_THROWS_WITH(p_R_u - (TinyVector<2>{1, 2}), "error: incompatible operand types Vh(P0:R) and R^2"); - REQUIRE_THROWS_WITH(p_R_u - (TinyVector<3>{2, 3, 2}), - "error: incompatible operand types Vh(P0:R) and R^3"); - REQUIRE_THROWS_WITH(p_R_u - (TinyMatrix<1>{2}), "error: incompatible operand types Vh(P0:R) and R^1x1"); - REQUIRE_THROWS_WITH(p_R_u - (TinyMatrix<2>{2, 3, 1, 4}), - "error: incompatible operand types Vh(P0:R) and R^2x2"); - REQUIRE_THROWS_WITH(p_R_u - (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), - "error: incompatible operand types Vh(P0:R) and R^3x3"); - - REQUIRE_THROWS_WITH(p_Vector3_u - (double{1}), "error: incompatible operand types Vh(P0Vector:R) and R"); - REQUIRE_THROWS_WITH(p_Vector3_u - (TinyVector<1>{1}), - "error: incompatible operand types Vh(P0Vector:R) and R^1"); - REQUIRE_THROWS_WITH(p_Vector3_u - (TinyVector<2>{1, 2}), - "error: incompatible operand types Vh(P0Vector:R) and R^2"); - } - - SECTION("X - Vh -> Vh") - { - CHECK_SCALAR_XxVH_TO_VH(bool{true}, -, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, -, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, -, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, -, p_R_u); - - CHECK_SCALAR_XxVH_TO_VH((TinyVector<1>{1.3}), -, p_R1_u); - CHECK_SCALAR_XxVH_TO_VH((TinyVector<2>{1.2, 2.3}), -, p_R2_u); - CHECK_SCALAR_XxVH_TO_VH((TinyVector<3>{3.2, 7.1, 5.2}), -, p_R3_u); - - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<1>{1.3}), -, p_R1x1_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), -, p_R2x2_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // - 4.7, 2.3, 7.1, // - 9.7, 3.2, 6.8}), - -, p_R3x3_u); - - REQUIRE_THROWS_WITH((TinyVector<1>{1}) - p_R_u, "error: incompatible operand types R^1 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) - p_R_u, "error: incompatible operand types R^2 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyVector<3>{2, 3, 2}) - p_R_u, - "error: incompatible operand types R^3 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) - p_R_u, "error: incompatible operand types R^1x1 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) - p_R_u, - "error: incompatible operand types R^2x2 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) - p_R_u, - "error: incompatible operand types R^3x3 and Vh(P0:R)"); - - REQUIRE_THROWS_WITH((double{1}) - p_Vector3_u, "error: incompatible operand types R and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH((TinyVector<1>{1}) - p_Vector3_u, - "error: incompatible operand types R^1 and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH((TinyVector<2>{1, 2}) - p_Vector3_u, - "error: incompatible operand types R^2 and Vh(P0Vector:R)"); - } - } - - SECTION("product") - { - SECTION("Vh * Vh -> Vh") - { - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R_v); - - CHECK_SCALAR_VH2_TO_VH(p_R1x1_u, *, p_R1x1_v); - CHECK_SCALAR_VH2_TO_VH(p_R2x2_u, *, p_R2x2_v); - CHECK_SCALAR_VH2_TO_VH(p_R3x3_u, *, p_R3x3_v); - - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R1_v); - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R2_v); - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R3_v); - - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R1x1_v); - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R2x2_v); - CHECK_SCALAR_VH2_TO_VH(p_R_u, *, p_R3x3_v); - - CHECK_SCALAR_VH2_TO_VH(p_R1x1_u, *, p_R1_v); - CHECK_SCALAR_VH2_TO_VH(p_R2x2_u, *, p_R2_v); - CHECK_SCALAR_VH2_TO_VH(p_R3x3_u, *, p_R3_v); - - { - std::shared_ptr p_fuv = p_R_u * p_Vector3_v; - - REQUIRE(p_fuv.use_count() > 0); - REQUIRE_NOTHROW(dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*p_fuv)); - - const auto& fuv = dynamic_cast<const DiscreteFunctionP0Vector<Dimension, double>&>(*p_fuv); - - auto lhs_values = p_R_u->cellValues(); - auto rhs_arrays = p_Vector3_v->cellArrays(); - bool is_same = true; - for (CellId cell_id = 0; cell_id < lhs_values.numberOfItems(); ++cell_id) { - for (size_t i = 0; i < fuv.size(); ++i) { - if (fuv[cell_id][i] != (lhs_values[cell_id] * rhs_arrays[cell_id][i])) { - is_same = false; - break; - } - } - } - - REQUIRE(is_same); - } - - REQUIRE_THROWS_WITH(p_R1_u * p_R1_v, "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R2_u * p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R3_u * p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(p_R1_u * p_R2x2_v, "error: incompatible operand types Vh(P0:R^1) and Vh(P0:R^2x2)"); - - REQUIRE_THROWS_WITH(p_R1x1_u * p_R2x2_v, - "error: incompatible operand types Vh(P0:R^1x1) and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(p_R2x2_u * p_R3x3_v, - "error: incompatible operand types Vh(P0:R^2x2) and Vh(P0:R^3x3)"); - REQUIRE_THROWS_WITH(p_R3x3_u * p_R1x1_v, - "error: incompatible operand types Vh(P0:R^3x3) and Vh(P0:R^1x1)"); - - REQUIRE_THROWS_WITH(p_R1x1_u * p_R2_v, "error: incompatible operand types Vh(P0:R^1x1) and Vh(P0:R^2)"); - REQUIRE_THROWS_WITH(p_R2x2_u * p_R3_v, "error: incompatible operand types Vh(P0:R^2x2) and Vh(P0:R^3)"); - REQUIRE_THROWS_WITH(p_R3x3_u * p_R1_v, "error: incompatible operand types Vh(P0:R^3x3) and Vh(P0:R^1)"); - - REQUIRE_THROWS_WITH(p_R1_u * p_Vector3_v, - "error: incompatible operand types Vh(P0:R^1) and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH(p_R2_u * p_Vector3_v, - "error: incompatible operand types Vh(P0:R^2) and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH(p_R3_u * p_Vector3_v, - "error: incompatible operand types Vh(P0:R^3) and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH(p_R1x1_u * p_Vector3_v, - "error: incompatible operand types Vh(P0:R^1x1) and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH(p_R2x2_u * p_Vector3_v, - "error: incompatible operand types Vh(P0:R^2x2) and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH(p_R3x3_u * p_Vector3_v, - "error: incompatible operand types Vh(P0:R^3x3) and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH(p_Vector3_u * p_Vector3_v, - "error: incompatible operand types Vh(P0Vector:R) and Vh(P0Vector:R)"); - - REQUIRE_THROWS_WITH(p_Vector3_v * p_R_u, "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R)"); - REQUIRE_THROWS_WITH(p_Vector3_v * p_R1_u, - "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_Vector3_v * p_R2_u, - "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^2)"); - REQUIRE_THROWS_WITH(p_Vector3_v * p_R3_u, - "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^3)"); - REQUIRE_THROWS_WITH(p_Vector3_v * p_R1x1_u, - "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(p_Vector3_v * p_R2x2_u, - "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH(p_Vector3_v * p_R3x3_u, - "error: incompatible operand types Vh(P0Vector:R) and Vh(P0:R^3x3)"); - - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R1x1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R2x2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_R3x3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R1x1_u * p_other_mesh_R1_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R2x2_u * p_other_mesh_R2_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R3x3_u * p_other_mesh_R3_u, "error: operands are defined on different meshes"); - REQUIRE_THROWS_WITH(p_R_u * p_other_mesh_Vector3_u, "error: operands are defined on different meshes"); - } - - SECTION("Vh * X -> Vh") - { - CHECK_SCALAR_VHxX_TO_VH(p_R_u, *, bool{true}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, *, uint64_t{1}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, *, int64_t{2}); - CHECK_SCALAR_VHxX_TO_VH(p_R_u, *, double{1.3}); - - CHECK_SCALAR_VHxX_TO_VH(p_R1x1_u, *, (TinyMatrix<1>{1.3})); - CHECK_SCALAR_VHxX_TO_VH(p_R2x2_u, *, (TinyMatrix<2>{1.2, 2.3, 4.2, 5.1})); - CHECK_SCALAR_VHxX_TO_VH(p_R3x3_u, *, - (TinyMatrix<3>{3.2, 7.1, 5.2, // - 4.7, 2.3, 7.1, // - 9.7, 3.2, 6.8})); - - REQUIRE_THROWS_WITH(p_R1_u * (TinyVector<1>{1}), "error: incompatible operand types Vh(P0:R^1) and R^1"); - REQUIRE_THROWS_WITH(p_R2_u * (TinyVector<2>{1, 2}), - "error: incompatible operand types Vh(P0:R^2) and R^2"); - REQUIRE_THROWS_WITH(p_R3_u * (TinyVector<3>{2, 3, 2}), - "error: incompatible operand types Vh(P0:R^3) and R^3"); - REQUIRE_THROWS_WITH(p_R1_u * (TinyMatrix<1>{2}), - "error: incompatible operand types Vh(P0:R^1) and R^1x1"); - REQUIRE_THROWS_WITH(p_R2_u * (TinyMatrix<2>{2, 3, 1, 4}), - "error: incompatible operand types Vh(P0:R^2) and R^2x2"); - REQUIRE_THROWS_WITH(p_R3_u * (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), - "error: incompatible operand types Vh(P0:R^3) and R^3x3"); - REQUIRE_THROWS_WITH(p_R2x2_u * (TinyMatrix<1>{2}), - "error: incompatible operand types Vh(P0:R^2x2) and R^1x1"); - REQUIRE_THROWS_WITH(p_R1x1_u * (TinyMatrix<2>{2, 3, 1, 4}), - "error: incompatible operand types Vh(P0:R^1x1) and R^2x2"); - REQUIRE_THROWS_WITH(p_R2x2_u * (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), - "error: incompatible operand types Vh(P0:R^2x2) and R^3x3"); - - REQUIRE_THROWS_WITH(p_Vector3_u * (TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}), - "error: incompatible operand types Vh(P0Vector:R) and R^3x3"); - REQUIRE_THROWS_WITH(p_Vector3_u * (double{2}), "error: incompatible operand types Vh(P0Vector:R) and R"); - } - - SECTION("X * Vh -> Vh") - { - CHECK_SCALAR_XxVH_TO_VH(bool{true}, *, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, *, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, *, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, *, p_R_u); - - CHECK_SCALAR_XxVH_TO_VH(bool{true}, *, p_R1x1_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, *, p_R1x1_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, *, p_R1x1_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, *, p_R1x1_u); - - CHECK_SCALAR_XxVH_TO_VH(bool{true}, *, p_R2x2_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, *, p_R2x2_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, *, p_R2x2_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, *, p_R2x2_u); - - CHECK_SCALAR_XxVH_TO_VH(bool{true}, *, p_R3x3_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, *, p_R3x3_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, *, p_R3x3_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, *, p_R3x3_u); - - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<1>{1.3}), *, p_R1_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), *, p_R2_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // - 4.7, 2.3, 7.1, // - 9.7, 3.2, 6.8}), - *, p_R3_u); - - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<1>{1.3}), *, p_R1x1_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<2>{1.2, 2.3, 4.2, 5.1}), *, p_R2x2_u); - CHECK_SCALAR_XxVH_TO_VH((TinyMatrix<3>{3.2, 7.1, 5.2, // - 4.7, 2.3, 7.1, // - 9.7, 3.2, 6.8}), - *, p_R3x3_u); - - CHECK_VECTOR_XxVH_TO_VH(bool{true}, *, p_Vector3_u); - CHECK_VECTOR_XxVH_TO_VH(uint64_t{1}, *, p_Vector3_u); - CHECK_VECTOR_XxVH_TO_VH(int64_t{2}, *, p_Vector3_u); - CHECK_VECTOR_XxVH_TO_VH(double{1.3}, *, p_Vector3_u); - - REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_R_u, "error: incompatible operand types R^1x1 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R_u, - "error: incompatible operand types R^2x2 and Vh(P0:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R_u, - "error: incompatible operand types R^3x3 and Vh(P0:R)"); - - REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_R2_u, - "error: incompatible operand types R^1x1 and Vh(P0:R^2)"); - REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R3_u, - "error: incompatible operand types R^2x2 and Vh(P0:R^3)"); - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R2_u, - "error: incompatible operand types R^3x3 and Vh(P0:R^2)"); - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R1_u, - "error: incompatible operand types R^3x3 and Vh(P0:R^1)"); - - REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_R2x2_u, - "error: incompatible operand types R^1x1 and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R3x3_u, - "error: incompatible operand types R^2x2 and Vh(P0:R^3x3)"); - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_R2x2_u, - "error: incompatible operand types R^3x3 and Vh(P0:R^2x2)"); - REQUIRE_THROWS_WITH((TinyMatrix<2>{2, 3, 1, 4}) * p_R1x1_u, - "error: incompatible operand types R^2x2 and Vh(P0:R^1x1)"); - - REQUIRE_THROWS_WITH((TinyMatrix<3>{1, 3, 6, 4, 7, 2, 5, 9, 8}) * p_Vector3_u, - "error: incompatible operand types R^3x3 and Vh(P0Vector:R)"); - REQUIRE_THROWS_WITH((TinyMatrix<1>{2}) * p_Vector3_u, - "error: incompatible operand types R^1x1 and Vh(P0Vector:R)"); - } - } - - SECTION("ratio") - { - SECTION("Vh / Vh -> Vh") - { - CHECK_SCALAR_VH2_TO_VH(p_R_u, /, p_R_v); - - REQUIRE_THROWS_WITH(p_R_u / p_R1_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R2_u / p_R1_v, "error: incompatible operand types Vh(P0:R^2) and Vh(P0:R^1)"); - REQUIRE_THROWS_WITH(p_R3_u / p_R1x1_v, "error: incompatible operand types Vh(P0:R^3) and Vh(P0:R^1x1)"); - REQUIRE_THROWS_WITH(p_R_u / p_R2x2_v, "error: incompatible operand types Vh(P0:R) and Vh(P0:R^2x2)"); - - REQUIRE_THROWS_WITH(p_R_u / p_other_mesh_R_u, "error: operands are defined on different meshes"); - } - - SECTION("X / Vh -> Vh") - { - CHECK_SCALAR_XxVH_TO_VH(bool{true}, /, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(uint64_t{1}, /, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(int64_t{2}, /, p_R_u); - CHECK_SCALAR_XxVH_TO_VH(double{1.3}, /, p_R_u); - } - } - } - } - } - } - - SECTION("unary operators") - { - SECTION("1D") - { - constexpr size_t Dimension = 1; - - using Rd = TinyVector<Dimension>; - - std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - - for (auto named_mesh : mesh_list) { - SECTION(named_mesh.name()) - { - auto mesh = named_mesh.mesh(); - - CellValue<const Rd> xj = MeshDataManager::instance().getMeshData(*mesh).xj(); - - CellValue<double> u_R_values = [=] { - CellValue<double> build_values{mesh->connectivity()}; - parallel_for( - build_values.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.2 + std::cos(l2Norm(xj[cell_id])); }); - return build_values; - }(); - - std::shared_ptr p_R_u = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, u_R_values); - - std::shared_ptr p_R1_u = [=] { - CellValue<TinyVector<1>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id][0] = 2 * xj[cell_id][0] + 1; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, uj); - }(); - - constexpr auto to_2d = [&](const TinyVector<Dimension>& x) -> TinyVector<2> { - if constexpr (Dimension == 1) { - return TinyVector<2>{x[0], 1 + x[0] * x[0]}; - } else if constexpr (Dimension == 2) { - return TinyVector<2>{x[0], x[1]}; - } else if constexpr (Dimension == 3) { - return TinyVector<2>{x[0], x[1] + x[2]}; - } - }; - - std::shared_ptr p_R2_u = [=] { - CellValue<TinyVector<2>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - uj[cell_id] = TinyVector<2>{2 * x[0] + 1, 1 - x[1]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, uj); - }(); - - constexpr auto to_3d = [&](const TinyVector<Dimension>& x) -> TinyVector<3> { - if constexpr (Dimension == 1) { - return TinyVector<3>{x[0], 1 + x[0] * x[0], 2 - x[0]}; - } else if constexpr (Dimension == 2) { - return TinyVector<3>{x[0], x[1], x[0] + x[1]}; - } else if constexpr (Dimension == 3) { - return TinyVector<3>{x[0], x[1], x[2]}; - } - }; - - std::shared_ptr p_R3_u = [=] { - CellValue<TinyVector<3>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - uj[cell_id] = TinyVector<3>{2 * x[0] + 1, 1 - x[1] * x[2], x[0] + x[2]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, uj); - }(); - - std::shared_ptr p_R1x1_u = [=] { - CellValue<TinyMatrix<1>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { uj[cell_id] = TinyMatrix<1>{2 * xj[cell_id][0] + 1}; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(mesh, uj); - }(); - - std::shared_ptr p_R2x2_u = [=] { - CellValue<TinyMatrix<2>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - - uj[cell_id] = TinyMatrix<2>{2 * x[0] + 1, 1 - x[1], // - 2 * x[1], -x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(mesh, uj); - }(); - - std::shared_ptr p_R3x3_u = [=] { - CellValue<TinyMatrix<3>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - - uj[cell_id] = TinyMatrix<3>{2 * x[0] + 1, 1 - x[1], 3, // - 2 * x[1], -x[0], x[0] - x[1], // - 3 * x[2] - x[1], x[1] - 2 * x[2], x[2] - x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(mesh, uj); - }(); - - std::shared_ptr p_Vector3_u = [=] { - CellArray<double> uj_vector{mesh->connectivity(), 3}; - parallel_for( - uj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - uj_vector[cell_id][0] = 2 * x[0] + 1; - uj_vector[cell_id][1] = 1 - x[1] * x[2]; - uj_vector[cell_id][2] = x[0] + x[2]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, uj_vector); - }(); - - SECTION("unary minus") - { - SECTION("- Vh -> Vh") - { - CHECK_SCALAR_VH_TO_VH(-, p_R_u); - - CHECK_SCALAR_VH_TO_VH(-, p_R1_u); - CHECK_SCALAR_VH_TO_VH(-, p_R2_u); - CHECK_SCALAR_VH_TO_VH(-, p_R3_u); - - CHECK_SCALAR_VH_TO_VH(-, p_R1x1_u); - CHECK_SCALAR_VH_TO_VH(-, p_R2x2_u); - CHECK_SCALAR_VH_TO_VH(-, p_R3x3_u); - - CHECK_VECTOR_VH_TO_VH(-, p_Vector3_u); - } - } - } - } - } - - SECTION("2D") - { - constexpr size_t Dimension = 2; - - using Rd = TinyVector<Dimension>; - - std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - - for (auto named_mesh : mesh_list) { - SECTION(named_mesh.name()) - { - auto mesh = named_mesh.mesh(); - - CellValue<const Rd> xj = MeshDataManager::instance().getMeshData(*mesh).xj(); - - CellValue<double> u_R_values = [=] { - CellValue<double> build_values{mesh->connectivity()}; - parallel_for( - build_values.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.2 + std::cos(l2Norm(xj[cell_id])); }); - return build_values; - }(); - - std::shared_ptr p_R_u = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, u_R_values); - - std::shared_ptr p_R1_u = [=] { - CellValue<TinyVector<1>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id][0] = 2 * xj[cell_id][0] + 1; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, uj); - }(); - - constexpr auto to_2d = [&](const TinyVector<Dimension>& x) -> TinyVector<2> { - if constexpr (Dimension == 1) { - return TinyVector<2>{x[0], 1 + x[0] * x[0]}; - } else if constexpr (Dimension == 2) { - return TinyVector<2>{x[0], x[1]}; - } else if constexpr (Dimension == 3) { - return TinyVector<2>{x[0], x[1] + x[2]}; - } - }; - - std::shared_ptr p_R2_u = [=] { - CellValue<TinyVector<2>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - uj[cell_id] = TinyVector<2>{2 * x[0] + 1, 1 - x[1]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, uj); - }(); - - constexpr auto to_3d = [&](const TinyVector<Dimension>& x) -> TinyVector<3> { - if constexpr (Dimension == 1) { - return TinyVector<3>{x[0], 1 + x[0] * x[0], 2 - x[0]}; - } else if constexpr (Dimension == 2) { - return TinyVector<3>{x[0], x[1], x[0] + x[1]}; - } else if constexpr (Dimension == 3) { - return TinyVector<3>{x[0], x[1], x[2]}; - } - }; - - std::shared_ptr p_R3_u = [=] { - CellValue<TinyVector<3>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - uj[cell_id] = TinyVector<3>{2 * x[0] + 1, 1 - x[1] * x[2], x[0] + x[2]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, uj); - }(); - - std::shared_ptr p_R1x1_u = [=] { - CellValue<TinyMatrix<1>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { uj[cell_id] = TinyMatrix<1>{2 * xj[cell_id][0] + 1}; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(mesh, uj); - }(); - - std::shared_ptr p_R2x2_u = [=] { - CellValue<TinyMatrix<2>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - - uj[cell_id] = TinyMatrix<2>{2 * x[0] + 1, 1 - x[1], // - 2 * x[1], -x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(mesh, uj); - }(); - - std::shared_ptr p_R3x3_u = [=] { - CellValue<TinyMatrix<3>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - - uj[cell_id] = TinyMatrix<3>{2 * x[0] + 1, 1 - x[1], 3, // - 2 * x[1], -x[0], x[0] - x[1], // - 3 * x[2] - x[1], x[1] - 2 * x[2], x[2] - x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(mesh, uj); - }(); - - std::shared_ptr p_Vector3_u = [=] { - CellArray<double> uj_vector{mesh->connectivity(), 3}; - parallel_for( - uj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - uj_vector[cell_id][0] = 2 * x[0] + 1; - uj_vector[cell_id][1] = 1 - x[1] * x[2]; - uj_vector[cell_id][2] = x[0] + x[2]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, uj_vector); - }(); - - SECTION("unary minus") - { - SECTION("- Vh -> Vh") - { - CHECK_SCALAR_VH_TO_VH(-, p_R_u); - - CHECK_SCALAR_VH_TO_VH(-, p_R1_u); - CHECK_SCALAR_VH_TO_VH(-, p_R2_u); - CHECK_SCALAR_VH_TO_VH(-, p_R3_u); - - CHECK_SCALAR_VH_TO_VH(-, p_R1x1_u); - CHECK_SCALAR_VH_TO_VH(-, p_R2x2_u); - CHECK_SCALAR_VH_TO_VH(-, p_R3x3_u); - - CHECK_VECTOR_VH_TO_VH(-, p_Vector3_u); - } - } - } - } - } - - SECTION("3D") - { - constexpr size_t Dimension = 3; - - using Rd = TinyVector<Dimension>; - - std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - - for (auto named_mesh : mesh_list) { - SECTION(named_mesh.name()) - { - auto mesh = named_mesh.mesh(); - - CellValue<const Rd> xj = MeshDataManager::instance().getMeshData(*mesh).xj(); - - CellValue<double> u_R_values = [=] { - CellValue<double> build_values{mesh->connectivity()}; - parallel_for( - build_values.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { build_values[cell_id] = 0.2 + std::cos(l2Norm(xj[cell_id])); }); - return build_values; - }(); - - std::shared_ptr p_R_u = std::make_shared<const DiscreteFunctionP0<Dimension, double>>(mesh, u_R_values); - - std::shared_ptr p_R1_u = [=] { - CellValue<TinyVector<1>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { uj[cell_id][0] = 2 * xj[cell_id][0] + 1; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<1>>>(mesh, uj); - }(); - - constexpr auto to_2d = [&](const TinyVector<Dimension>& x) -> TinyVector<2> { - if constexpr (Dimension == 1) { - return TinyVector<2>{x[0], 1 + x[0] * x[0]}; - } else if constexpr (Dimension == 2) { - return TinyVector<2>{x[0], x[1]}; - } else if constexpr (Dimension == 3) { - return TinyVector<2>{x[0], x[1] + x[2]}; - } - }; - - std::shared_ptr p_R2_u = [=] { - CellValue<TinyVector<2>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - uj[cell_id] = TinyVector<2>{2 * x[0] + 1, 1 - x[1]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<2>>>(mesh, uj); - }(); - - constexpr auto to_3d = [&](const TinyVector<Dimension>& x) -> TinyVector<3> { - if constexpr (Dimension == 1) { - return TinyVector<3>{x[0], 1 + x[0] * x[0], 2 - x[0]}; - } else if constexpr (Dimension == 2) { - return TinyVector<3>{x[0], x[1], x[0] + x[1]}; - } else if constexpr (Dimension == 3) { - return TinyVector<3>{x[0], x[1], x[2]}; - } - }; - - std::shared_ptr p_R3_u = [=] { - CellValue<TinyVector<3>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - uj[cell_id] = TinyVector<3>{2 * x[0] + 1, 1 - x[1] * x[2], x[0] + x[2]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyVector<3>>>(mesh, uj); - }(); - - std::shared_ptr p_R1x1_u = [=] { - CellValue<TinyMatrix<1>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), - PUGS_LAMBDA(const CellId cell_id) { uj[cell_id] = TinyMatrix<1>{2 * xj[cell_id][0] + 1}; }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<1>>>(mesh, uj); - }(); - - std::shared_ptr p_R2x2_u = [=] { - CellValue<TinyMatrix<2>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<2> x = to_2d(xj[cell_id]); - - uj[cell_id] = TinyMatrix<2>{2 * x[0] + 1, 1 - x[1], // - 2 * x[1], -x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<2>>>(mesh, uj); - }(); - - std::shared_ptr p_R3x3_u = [=] { - CellValue<TinyMatrix<3>> uj{mesh->connectivity()}; - parallel_for( - uj.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - - uj[cell_id] = TinyMatrix<3>{2 * x[0] + 1, 1 - x[1], 3, // - 2 * x[1], -x[0], x[0] - x[1], // - 3 * x[2] - x[1], x[1] - 2 * x[2], x[2] - x[0]}; - }); - - return std::make_shared<const DiscreteFunctionP0<Dimension, TinyMatrix<3>>>(mesh, uj); - }(); - - std::shared_ptr p_Vector3_u = [=] { - CellArray<double> uj_vector{mesh->connectivity(), 3}; - parallel_for( - uj_vector.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { - const TinyVector<3> x = to_3d(xj[cell_id]); - uj_vector[cell_id][0] = 2 * x[0] + 1; - uj_vector[cell_id][1] = 1 - x[1] * x[2]; - uj_vector[cell_id][2] = x[0] + x[2]; - }); - - return std::make_shared<const DiscreteFunctionP0Vector<Dimension, double>>(mesh, uj_vector); - }(); - - SECTION("unary minus") - { - SECTION("- Vh -> Vh") - { - CHECK_SCALAR_VH_TO_VH(-, p_R_u); - - CHECK_SCALAR_VH_TO_VH(-, p_R1_u); - CHECK_SCALAR_VH_TO_VH(-, p_R2_u); - CHECK_SCALAR_VH_TO_VH(-, p_R3_u); - - CHECK_SCALAR_VH_TO_VH(-, p_R1x1_u); - CHECK_SCALAR_VH_TO_VH(-, p_R2x2_u); - CHECK_SCALAR_VH_TO_VH(-, p_R3x3_u); - - CHECK_VECTOR_VH_TO_VH(-, p_Vector3_u); - } - } - } - } - } - } -} - -#ifdef __clang__ -#pragma clang optimize on -#endif // __clang__ diff --git a/tests/test_EmbeddedIDiscreteFunctionUtils.cpp b/tests/test_EmbeddedIDiscreteFunctionUtils.cpp deleted file mode 100644 index e7d0e8eea200cb115be60a2ba789999155cf5fab..0000000000000000000000000000000000000000 --- a/tests/test_EmbeddedIDiscreteFunctionUtils.cpp +++ /dev/null @@ -1,167 +0,0 @@ -#include <catch2/catch_test_macros.hpp> -#include <catch2/matchers/catch_matchers_all.hpp> - -#include <language/utils/EmbeddedIDiscreteFunctionUtils.hpp> -#include <scheme/DiscreteFunctionP0.hpp> -#include <scheme/DiscreteFunctionP0Vector.hpp> - -#include <MeshDataBaseForTests.hpp> - -// clazy:excludeall=non-pod-global-static - -TEST_CASE("EmbeddedIDiscreteFunctionUtils", "[language]") -{ - using R1 = TinyVector<1, double>; - using R2 = TinyVector<2, double>; - using R3 = TinyVector<3, double>; - - using R1x1 = TinyMatrix<1, 1, double>; - using R2x2 = TinyMatrix<2, 2, double>; - using R3x3 = TinyMatrix<3, 3, double>; - - SECTION("operand type name") - { - SECTION("basic types") - { - REQUIRE(EmbeddedIDiscreteFunctionUtils::getOperandTypeName(double{1}) == "R"); - REQUIRE(EmbeddedIDiscreteFunctionUtils::getOperandTypeName(std::make_shared<double>(1)) == "R"); - } - - SECTION("discrete P0 function") - { - std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - - for (auto named_mesh : mesh_list) { - SECTION(named_mesh.name()) - { - auto mesh_1d = named_mesh.mesh(); - - REQUIRE(EmbeddedIDiscreteFunctionUtils::getOperandTypeName(DiscreteFunctionP0<1, double>{mesh_1d}) == - "Vh(P0:R)"); - - REQUIRE(EmbeddedIDiscreteFunctionUtils::getOperandTypeName(DiscreteFunctionP0<1, R1>{mesh_1d}) == - "Vh(P0:R^1)"); - REQUIRE(EmbeddedIDiscreteFunctionUtils::getOperandTypeName(DiscreteFunctionP0<1, R2>{mesh_1d}) == - "Vh(P0:R^2)"); - REQUIRE(EmbeddedIDiscreteFunctionUtils::getOperandTypeName(DiscreteFunctionP0<1, R3>{mesh_1d}) == - "Vh(P0:R^3)"); - - REQUIRE(EmbeddedIDiscreteFunctionUtils::getOperandTypeName(DiscreteFunctionP0<1, R1x1>{mesh_1d}) == - "Vh(P0:R^1x1)"); - REQUIRE(EmbeddedIDiscreteFunctionUtils::getOperandTypeName(DiscreteFunctionP0<1, R2x2>{mesh_1d}) == - "Vh(P0:R^2x2)"); - REQUIRE(EmbeddedIDiscreteFunctionUtils::getOperandTypeName(DiscreteFunctionP0<1, R3x3>{mesh_1d}) == - "Vh(P0:R^3x3)"); - } - } - } - - SECTION("discrete P0Vector function") - { - std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - - for (auto named_mesh : mesh_list) { - SECTION(named_mesh.name()) - { - auto mesh_1d = named_mesh.mesh(); - - REQUIRE(EmbeddedIDiscreteFunctionUtils::getOperandTypeName(DiscreteFunctionP0Vector<1, double>{mesh_1d, 2}) == - "Vh(P0Vector:R)"); - } - } - } - } - - SECTION("check if is same discretization") - { - SECTION("from shared_ptr") - { - std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - - for (auto named_mesh : mesh_list) { - SECTION(named_mesh.name()) - { - auto mesh_1d = named_mesh.mesh(); - - REQUIRE(EmbeddedIDiscreteFunctionUtils::isSameDiscretization(std::make_shared<DiscreteFunctionP0<1, double>>( - mesh_1d), - std::make_shared<DiscreteFunctionP0<1, double>>( - mesh_1d))); - - REQUIRE(not EmbeddedIDiscreteFunctionUtils:: - isSameDiscretization(std::make_shared<DiscreteFunctionP0<1, double>>(mesh_1d), - std::make_shared<DiscreteFunctionP0Vector<1, double>>(mesh_1d, 1))); - } - } - } - - SECTION("from value") - { - std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - - for (auto named_mesh : mesh_list) { - SECTION(named_mesh.name()) - { - auto mesh_1d = named_mesh.mesh(); - - REQUIRE(EmbeddedIDiscreteFunctionUtils::isSameDiscretization(DiscreteFunctionP0<1, double>{mesh_1d}, - DiscreteFunctionP0<1, double>{mesh_1d})); - - REQUIRE(EmbeddedIDiscreteFunctionUtils::isSameDiscretization(DiscreteFunctionP0<1, R1>{mesh_1d}, - DiscreteFunctionP0<1, R1>{mesh_1d})); - - REQUIRE(EmbeddedIDiscreteFunctionUtils::isSameDiscretization(DiscreteFunctionP0<1, R2>{mesh_1d}, - DiscreteFunctionP0<1, R2>{mesh_1d})); - - REQUIRE(EmbeddedIDiscreteFunctionUtils::isSameDiscretization(DiscreteFunctionP0<1, R3>{mesh_1d}, - DiscreteFunctionP0<1, R3>{mesh_1d})); - - REQUIRE(EmbeddedIDiscreteFunctionUtils::isSameDiscretization(DiscreteFunctionP0<1, R1x1>{mesh_1d}, - DiscreteFunctionP0<1, R1x1>{mesh_1d})); - - REQUIRE(EmbeddedIDiscreteFunctionUtils::isSameDiscretization(DiscreteFunctionP0<1, R2x2>{mesh_1d}, - DiscreteFunctionP0<1, R2x2>{mesh_1d})); - - REQUIRE(EmbeddedIDiscreteFunctionUtils::isSameDiscretization(DiscreteFunctionP0<1, R3x3>{mesh_1d}, - DiscreteFunctionP0<1, R3x3>{mesh_1d})); - - REQUIRE(not EmbeddedIDiscreteFunctionUtils::isSameDiscretization(DiscreteFunctionP0<1, double>{mesh_1d}, - DiscreteFunctionP0<1, R1>{mesh_1d})); - - REQUIRE(not EmbeddedIDiscreteFunctionUtils::isSameDiscretization(DiscreteFunctionP0<1, R2>{mesh_1d}, - DiscreteFunctionP0<1, R2x2>{mesh_1d})); - - REQUIRE(not EmbeddedIDiscreteFunctionUtils::isSameDiscretization(DiscreteFunctionP0<1, R3x3>{mesh_1d}, - DiscreteFunctionP0<1, R2x2>{mesh_1d})); - } - } - } - - SECTION("invalid data type") - { - std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - - for (auto named_mesh : mesh_list) { - SECTION(named_mesh.name()) - { - auto mesh_1d = named_mesh.mesh(); - - REQUIRE_THROWS_WITH(EmbeddedIDiscreteFunctionUtils::isSameDiscretization(DiscreteFunctionP0<1, - int64_t>{mesh_1d}, - DiscreteFunctionP0<1, int64_t>{ - mesh_1d}), - "unexpected error: invalid data type Vh(P0:Z)"); - } - } - } - } - -#ifndef NDEBUG - SECTION("errors") - { - REQUIRE_THROWS_WITH(EmbeddedIDiscreteFunctionUtils::getOperandTypeName(std::shared_ptr<double>()), - "dangling shared_ptr"); - } - -#endif // NDEBUG -} diff --git a/tests/test_FaceIntegrator.cpp b/tests/test_FaceIntegrator.cpp index 945d765a6d0a530c7c7babb5d8b5800d5af033d3..916dcf497b7dfdd9dba2200092286b2a6c6c2522 100644 --- a/tests/test_FaceIntegrator.cpp +++ b/tests/test_FaceIntegrator.cpp @@ -262,7 +262,7 @@ TEST_CASE("FaceIntegrator", "[scheme]") mesh_list.push_back(std::make_pair("hybrid mesh", hybrid_mesh)); mesh_list.push_back(std::make_pair("diamond mesh", DualMeshManager::instance().getDiamondDualMesh(*hybrid_mesh))); - for (auto mesh_info : mesh_list) { + for (const auto& mesh_info : mesh_list) { auto mesh_name = mesh_info.first; auto mesh = mesh_info.second; @@ -754,7 +754,7 @@ TEST_CASE("FaceIntegrator", "[scheme]") mesh_list.push_back(std::make_pair("hybrid mesh", hybrid_mesh)); mesh_list.push_back(std::make_pair("diamond mesh", DualMeshManager::instance().getDiamondDualMesh(*hybrid_mesh))); - for (auto mesh_info : mesh_list) { + for (const auto& mesh_info : mesh_list) { auto mesh_name = mesh_info.first; auto mesh = mesh_info.second; @@ -1249,7 +1249,7 @@ TEST_CASE("FaceIntegrator", "[scheme]") mesh_list.push_back(std::make_pair("hybrid mesh", hybrid_mesh)); mesh_list.push_back(std::make_pair("diamond mesh", DualMeshManager::instance().getDiamondDualMesh(*hybrid_mesh))); - for (auto mesh_info : mesh_list) { + for (const auto& mesh_info : mesh_list) { auto mesh_name = mesh_info.first; auto mesh = mesh_info.second; diff --git a/tests/test_FunctionProcessor.cpp b/tests/test_FunctionProcessor.cpp index 03c8baa8ed5509c19520bb04d2860402e7308984..97cc8d6be42199f684739dba21b1b3f9a2cab644 100644 --- a/tests/test_FunctionProcessor.cpp +++ b/tests/test_FunctionProcessor.cpp @@ -374,6 +374,43 @@ let fx:R^1, fx = f(x); CHECK_FUNCTION_EVALUATION_RESULT(data, "fx", (2 * TinyVector<1>{3})); } + SECTION(" R^1 -> R^1 called with B argument") + { + std::string_view data = R"( +let f : R^1 -> R^1, x -> 2*x; +let fx:R^1, fx = f(true); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "fx", (2 * TinyVector<1>{true})); + } + + SECTION(" R^1 -> R^1 called with N argument") + { + std::string_view data = R"( +let f : R^1 -> R^1, x -> 2*x; +let n:N, n = 3; +let fx:R^1, fx = f(n); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "fx", (2 * TinyVector<1>{3})); + } + + SECTION(" R^1 -> R^1 called with Z argument") + { + std::string_view data = R"( +let f : R^1 -> R^1, x -> 2*x; +let fx:R^1, fx = f(-2); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "fx", (2 * TinyVector<1>{-2})); + } + + SECTION(" R^1 -> R^1 called with R argument") + { + std::string_view data = R"( +let f : R^1 -> R^1, x -> 2*x; +let fx:R^1, fx = f(1.3); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "fx", (2 * TinyVector<1>{1.3})); + } + SECTION(" R^2 -> R^2") { std::string_view data = R"( @@ -439,6 +476,43 @@ let fx:R^1x1, fx = f(x); CHECK_FUNCTION_EVALUATION_RESULT(data, "fx", (2 * TinyMatrix<1>{3})); } + SECTION(" R^1x1 -> R^1x1 called with B argument") + { + std::string_view data = R"( +let f : R^1x1 -> R^1x1, x -> 2*x; +let fx:R^1x1, fx = f(true); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "fx", (2 * TinyMatrix<1>{true})); + } + + SECTION(" R^1x1 -> R^1x1 called with N argument") + { + std::string_view data = R"( +let f : R^1x1 -> R^1x1, x -> 2*x; +let n:N, n = 3; +let fx:R^1x1, fx = f(n); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "fx", (2 * TinyMatrix<1>{3})); + } + + SECTION(" R^1x1 -> R^1x1 called with Z argument") + { + std::string_view data = R"( +let f : R^1x1 -> R^1x1, x -> 2*x; +let fx:R^1x1, fx = f(-4); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "fx", (2 * TinyMatrix<1>{-4})); + } + + SECTION(" R^1x1 -> R^1x1 called with R argument") + { + std::string_view data = R"( +let f : R^1x1 -> R^1x1, x -> 2*x; +let fx:R^1x1, fx = f(-2.3); +)"; + CHECK_FUNCTION_EVALUATION_RESULT(data, "fx", (2 * TinyMatrix<1>{-2.3})); + } + SECTION(" R^2x2 -> R^2x2") { std::string_view data = R"( diff --git a/tests/test_IntegrateCellArray.cpp b/tests/test_IntegrateCellArray.cpp index b6b8db8c8ca7bc0aa895f8be6b7d5f8dbccd89ff..0b64ca10e057803c4b8bd0befd06a27277239c9c 100644 --- a/tests/test_IntegrateCellArray.cpp +++ b/tests/test_IntegrateCellArray.cpp @@ -51,7 +51,7 @@ TEST_CASE("IntegrateCellArray", "[language]") std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -137,7 +137,7 @@ let g: R^1 -> R, x -> 2 * exp(x[0]) + 3; std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -234,7 +234,7 @@ let g: R^2 -> R, x -> 2*exp(x[0])*sin(x[1])+3; return extended_mesh_list; }(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -336,7 +336,7 @@ let g: R^3 -> R, x -> 2 * exp(x[0]) * sin(x[1]) * x[2] + 3; std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -429,7 +429,7 @@ let g: R^1 -> R, x -> 2 * exp(x[0]) + 3; std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -535,7 +535,7 @@ let g: R^2 -> R, x -> 2*exp(x[0])*sin(x[1])+3; return extended_mesh_list; }(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); diff --git a/tests/test_IntegrateCellValue.cpp b/tests/test_IntegrateCellValue.cpp index 5df4d0c447c50751db43c0ce2db5345612fc514f..c109c227c35eeb10362a339dd9aaa5e8a947114f 100644 --- a/tests/test_IntegrateCellValue.cpp +++ b/tests/test_IntegrateCellValue.cpp @@ -49,7 +49,7 @@ TEST_CASE("IntegrateCellValue", "[language]") std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -106,7 +106,7 @@ let R2x2_1d: R^1 -> R^2x2, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(x[0] - 2 * std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -175,7 +175,7 @@ let R3_2d: R^2 -> R^3, x -> [2*exp(x[0])*sin(x[1])+3, x[0]-2*x[1], 3]; return extended_mesh_list; }(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -244,7 +244,7 @@ let scalar_3d: R^3 -> R, x -> 2 * exp(x[0]) * sin(x[1]) * x[2] + 3; std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -307,7 +307,7 @@ let scalar_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3; std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -386,7 +386,7 @@ let R3_2d: R^2 -> R^3, x -> [2*exp(x[0])*sin(x[1])+3, x[0]-2*x[1], 3]; return extended_mesh_list; }(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); diff --git a/tests/test_IntegrateCellValue.hpp b/tests/test_IntegrateCellValue.hpp deleted file mode 100644 index f9a9e32a9a0bb69e61626eab69334c3248ee2b74..0000000000000000000000000000000000000000 --- a/tests/test_IntegrateCellValue.hpp +++ /dev/null @@ -1 +0,0 @@ -i_f_symboli_f_symboli_f_symbol diff --git a/tests/test_IntegrateOnCells.cpp b/tests/test_IntegrateOnCells.cpp index 80463f0831bc21c3c172bb62b0564c261629b7f0..5207325e8a4d36c1b8dd66ea24d3ddfa3be3af9f 100644 --- a/tests/test_IntegrateOnCells.cpp +++ b/tests/test_IntegrateOnCells.cpp @@ -51,7 +51,7 @@ TEST_CASE("IntegrateOnCells", "[language]") std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -151,7 +151,7 @@ let R2x2_1d: R^1 -> R^2x2, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(x[0] - 2 * std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -264,7 +264,7 @@ let R2x2_2d: R^2 -> R^2x2, x -> [[2*exp(x[0])*sin(x[1])+3, sin(x[0]-2*x[1])], [3 return extended_mesh_list; }(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -382,7 +382,7 @@ let R2x2_3d: R^3 -> R^2x2, x -> [[2 * exp(x[0]) * sin(x[1]) + 3 * cos(x[2]), sin std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -491,7 +491,7 @@ let R2x2_1d: R^1 -> R^2x2, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(x[0] - 2 * std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -614,7 +614,7 @@ let R2x2_2d: R^2 -> R^2x2, x -> [[2*exp(x[0])*sin(x[1])+3, sin(x[0]-2*x[1])], [3 return extended_mesh_list; }(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -747,7 +747,7 @@ let R2x2_3d: R^3 -> R^2x2, x -> [[2 * exp(x[0]) * sin(x[1]) + 3 * cos(x[2]), sin std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -847,7 +847,7 @@ let R2x2_1d: R^1 -> R^2x2, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(x[0] - 2 * std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -960,7 +960,7 @@ let R2x2_2d: R^2 -> R^2x2, x -> [[2*exp(x[0])*sin(x[1])+3, sin(x[0]-2*x[1])], [3 return extended_mesh_list; }(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -1078,7 +1078,7 @@ let R2x2_3d: R^3 -> R^2x2, x -> [[2 * exp(x[0]) * sin(x[1]) + 3 * cos(x[2]), sin std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -1187,7 +1187,7 @@ let R2x2_1d: R^1 -> R^2x2, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(x[0] - 2 * std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -1310,7 +1310,7 @@ let R2x2_2d: R^2 -> R^2x2, x -> [[2*exp(x[0])*sin(x[1])+3, sin(x[0]-2*x[1])], [3 return extended_mesh_list; }(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -1443,7 +1443,7 @@ let R2x2_3d: R^3 -> R^2x2, x -> [[2 * exp(x[0]) * sin(x[1]) + 3 * cos(x[2]), sin std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -1543,7 +1543,7 @@ let R2x2_1d: R^1 -> R^2x2, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(x[0] - 2 * std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -1656,7 +1656,7 @@ let R2x2_2d: R^2 -> R^2x2, x -> [[2*exp(x[0])*sin(x[1])+3, sin(x[0]-2*x[1])], [3 return extended_mesh_list; }(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -1774,7 +1774,7 @@ let R2x2_3d: R^3 -> R^2x2, x -> [[2 * exp(x[0]) * sin(x[1]) + 3 * cos(x[2]), sin std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -1883,7 +1883,7 @@ let R2x2_1d: R^1 -> R^2x2, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin(x[0] - 2 * std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -2006,7 +2006,7 @@ let R2x2_2d: R^2 -> R^2x2, x -> [[2*exp(x[0])*sin(x[1])+3, sin(x[0]-2*x[1])], [3 return extended_mesh_list; }(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); diff --git a/tests/test_InterpolateItemArray.cpp b/tests/test_InterpolateItemArray.cpp index 7fd968be9aaeed6cd7774353df69b2153eb68d51..ccee6e77877eadc359cc2c11313a7114081cc8c0 100644 --- a/tests/test_InterpolateItemArray.cpp +++ b/tests/test_InterpolateItemArray.cpp @@ -48,7 +48,7 @@ TEST_CASE("InterpolateItemArray", "[language]") std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -121,7 +121,7 @@ let scalar_non_linear_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3; std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -194,7 +194,7 @@ let scalar_non_linear_2d: R^2 -> R, x -> 2*exp(x[0])*sin(x[1])+3; std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -281,7 +281,7 @@ let scalar_non_linear_3d: R^3 -> R, x -> 2 * exp(x[0]) * sin(x[1]) * x[2] + 3; std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -362,7 +362,7 @@ let scalar_non_linear_1d: R^1 -> R, x -> 2 * exp(x[0]) + 3; std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -440,7 +440,7 @@ let scalar_non_linear_2d: R^2 -> R, x -> 2*exp(x[0])*sin(x[1])+3; std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); diff --git a/tests/test_InterpolateItemValue.cpp b/tests/test_InterpolateItemValue.cpp index 45832349fd50410aa70cadfb6df74ad59156c045..f53921ed19cfdd35549b2c032dd0ce8d27620ff3 100644 --- a/tests/test_InterpolateItemValue.cpp +++ b/tests/test_InterpolateItemValue.cpp @@ -45,7 +45,7 @@ TEST_CASE("InterpolateItemValue", "[language]") std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -216,7 +216,7 @@ let R2x2_non_linear_1d: R^1 -> R^2x2, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -381,7 +381,7 @@ let R2x2_non_linear_2d: R^2 -> R^2x2, x -> [[2*exp(x[0])*sin(x[1])+3, sin(x[0]-2 std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -530,7 +530,7 @@ let R2x2_non_linear_3d: R^3 -> R^2x2, x -> [[2 * exp(x[0]) * sin(x[1]) + 3 * cos cell_value.numberOfItems(), PUGS_LAMBDA(const CellId cell_id) { const TinyVector<Dimension>& x = xj[cell_id]; cell_value[cell_id] = TinyMatrix<2>{2 * exp(x[0]) * sin(x[1]) + 3 * cos(x[2]), - sin(x[0] - 2 * x[1] * x[2]), 3, x[0] * x[1] * x[2]}; + sin(x[0] - 2 * x[1] * x[2]), 3, x[0] * x[1] * x[2]}; }); CellValue<const TinyMatrix<2>> interpolate_value = InterpolateItemValue<TinyMatrix<2>(TinyVector<Dimension>)>::interpolate(function_symbol_id, xj); @@ -560,7 +560,7 @@ let R2x2_non_linear_3d: R^3 -> R^2x2, x -> [[2 * exp(x[0]) * sin(x[1]) + 3 * cos std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -742,7 +742,7 @@ let R2x2_non_linear_1d: R^1 -> R^2x2, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -916,7 +916,7 @@ let R2x2_non_linear_2d: R^2 -> R^2x2, x -> [[2*exp(x[0])*sin(x[1])+3, sin(x[0]-2 std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); diff --git a/tests/test_ItemArray.cpp b/tests/test_ItemArray.cpp index 997e327a1237752463e5b8ace7ef9bb1a167fcf7..2dbe964f3cdd5733aa77ddf5e1bc9204e9731998 100644 --- a/tests/test_ItemArray.cpp +++ b/tests/test_ItemArray.cpp @@ -30,7 +30,7 @@ TEST_CASE("ItemArray", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -68,7 +68,7 @@ TEST_CASE("ItemArray", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -104,7 +104,7 @@ TEST_CASE("ItemArray", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -138,7 +138,7 @@ TEST_CASE("ItemArray", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -189,7 +189,7 @@ TEST_CASE("ItemArray", "[mesh]") std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -224,7 +224,7 @@ TEST_CASE("ItemArray", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -313,7 +313,7 @@ TEST_CASE("ItemArray", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -343,7 +343,7 @@ TEST_CASE("ItemArray", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -360,7 +360,7 @@ TEST_CASE("ItemArray", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -369,7 +369,7 @@ TEST_CASE("ItemArray", "[mesh]") std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); diff --git a/tests/test_ItemArrayUtils.cpp b/tests/test_ItemArrayUtils.cpp index c08167d7ecef9bbb0592838c075624464c5c4a4a..8c832d16c1dac5ed7a84828303f68bceaf25c3d8 100644 --- a/tests/test_ItemArrayUtils.cpp +++ b/tests/test_ItemArrayUtils.cpp @@ -20,7 +20,7 @@ TEST_CASE("ItemArrayUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -294,7 +294,7 @@ TEST_CASE("ItemArrayUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -568,7 +568,7 @@ TEST_CASE("ItemArrayUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -845,7 +845,7 @@ TEST_CASE("ItemArrayUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -874,7 +874,7 @@ TEST_CASE("ItemArrayUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -903,7 +903,7 @@ TEST_CASE("ItemArrayUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -935,7 +935,7 @@ TEST_CASE("ItemArrayUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -964,7 +964,7 @@ TEST_CASE("ItemArrayUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -993,7 +993,7 @@ TEST_CASE("ItemArrayUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -1025,7 +1025,7 @@ TEST_CASE("ItemArrayUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -1054,7 +1054,7 @@ TEST_CASE("ItemArrayUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name() + " for size_t data") { auto mesh_2d = named_mesh.mesh(); @@ -1108,7 +1108,7 @@ TEST_CASE("ItemArrayUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name() + " for size_t data") { auto mesh_3d = named_mesh.mesh(); diff --git a/tests/test_ItemValue.cpp b/tests/test_ItemValue.cpp index 702110f7a906654bb5e60676e1e0e2d4c7a7fc03..4271db6c25f21dc7aa7db61d93d9280a22aaf561 100644 --- a/tests/test_ItemValue.cpp +++ b/tests/test_ItemValue.cpp @@ -28,7 +28,7 @@ TEST_CASE("ItemValue", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -61,7 +61,7 @@ TEST_CASE("ItemValue", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -90,7 +90,7 @@ TEST_CASE("ItemValue", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -114,7 +114,7 @@ TEST_CASE("ItemValue", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -144,7 +144,7 @@ TEST_CASE("ItemValue", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -182,7 +182,7 @@ TEST_CASE("ItemValue", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -257,7 +257,7 @@ TEST_CASE("ItemValue", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -287,7 +287,7 @@ TEST_CASE("ItemValue", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -304,7 +304,7 @@ TEST_CASE("ItemValue", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -313,7 +313,7 @@ TEST_CASE("ItemValue", "[mesh]") std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); diff --git a/tests/test_ItemValueUtils.cpp b/tests/test_ItemValueUtils.cpp index 42ed106fde72ca0a04c05ab25956c5807475f51c..755392515ae3078421375f71af8727aa8bff144e 100644 --- a/tests/test_ItemValueUtils.cpp +++ b/tests/test_ItemValueUtils.cpp @@ -18,7 +18,7 @@ TEST_CASE("ItemValueUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -71,7 +71,7 @@ TEST_CASE("ItemValueUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -98,7 +98,7 @@ TEST_CASE("ItemValueUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -125,7 +125,7 @@ TEST_CASE("ItemValueUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -155,7 +155,7 @@ TEST_CASE("ItemValueUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -182,7 +182,7 @@ TEST_CASE("ItemValueUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -209,7 +209,7 @@ TEST_CASE("ItemValueUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -239,7 +239,7 @@ TEST_CASE("ItemValueUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -268,7 +268,7 @@ TEST_CASE("ItemValueUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name() + "for size_t data") { auto mesh_2d = named_mesh.mesh(); @@ -321,7 +321,7 @@ TEST_CASE("ItemValueUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name() + " for size_t data") { auto mesh_3d = named_mesh.mesh(); diff --git a/tests/test_ItemValueVariantFunctionInterpoler.cpp b/tests/test_ItemValueVariantFunctionInterpoler.cpp index 8689b1086a816b10552b4b8c6f6ae78bcced7670..19f53e1085fb058960737b2543c2892e8d6d9fb2 100644 --- a/tests/test_ItemValueVariantFunctionInterpoler.cpp +++ b/tests/test_ItemValueVariantFunctionInterpoler.cpp @@ -43,7 +43,7 @@ TEST_CASE("ItemValueVariantFunctionInterpoler", "[scheme]") std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -323,7 +323,7 @@ let R3x3_non_linear_1d: R^1 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[0]) + 3, sin( std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -442,7 +442,7 @@ let R3x3_non_linear_2d: R^2 -> R^3x3, x -> [[2 * exp(x[0]) * sin(x[1]) + 3, sin( std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); diff --git a/tests/test_MathModule.cpp b/tests/test_MathModule.cpp index 99966d4bacebb938fce5bc686661b5c53e8d708e..2cb3481b1e6cde7561733d8ea03decd46153db9d 100644 --- a/tests/test_MathModule.cpp +++ b/tests/test_MathModule.cpp @@ -13,7 +13,7 @@ TEST_CASE("MathModule", "[language]") MathModule math_module; const auto& name_builtin_function = math_module.getNameBuiltinFunctionMap(); - REQUIRE(name_builtin_function.size() == 30); + REQUIRE(name_builtin_function.size() == 42); SECTION("Z -> N") { @@ -457,4 +457,210 @@ TEST_CASE("MathModule", "[language]") REQUIRE(std::get<double>(result_variant) == result); } } + + SECTION("R^dxd -> double") + { + SECTION("det:R^1x1") + { + TinyMatrix<1> arg{3}; + + DataVariant arg_variant = arg; + + auto i_function = name_builtin_function.find("det:R^1x1"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg_variant}); + + const double result = det(arg); + REQUIRE(std::get<double>(result_variant) == result); + } + + SECTION("det:R^2x2") + { + TinyMatrix<2> arg{3, 2, 1, -2}; + + DataVariant arg_variant = arg; + + auto i_function = name_builtin_function.find("det:R^2x2"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg_variant}); + + const double result = det(arg); + REQUIRE(std::get<double>(result_variant) == result); + } + + SECTION("det:R^3x3") + { + TinyMatrix<3> arg{3, 2, 4, // + -1, 4, 1, // + -4, -1, 5}; + + DataVariant arg_variant = arg; + + auto i_function = name_builtin_function.find("det:R^3x3"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg_variant}); + + const double result = det(arg); + REQUIRE(std::get<double>(result_variant) == result); + } + + SECTION("trace:R^1x1") + { + TinyMatrix<1> arg{3}; + + DataVariant arg_variant = arg; + + auto i_function = name_builtin_function.find("trace:R^1x1"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg_variant}); + + const double result = trace(arg); + REQUIRE(std::get<double>(result_variant) == result); + } + + SECTION("trace:R^2x2") + { + TinyMatrix<2> arg{3, 2, 1, -2}; + + DataVariant arg_variant = arg; + + auto i_function = name_builtin_function.find("trace:R^2x2"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg_variant}); + + const double result = trace(arg); + REQUIRE(std::get<double>(result_variant) == result); + } + + SECTION("trace:R^3x3") + { + TinyMatrix<3> arg{3, 2, 4, // + -1, 4, 1, // + -4, -1, 5}; + + DataVariant arg_variant = arg; + + auto i_function = name_builtin_function.find("trace:R^3x3"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg_variant}); + + const double result = trace(arg); + REQUIRE(std::get<double>(result_variant) == result); + } + } + + SECTION("R^dxd -> R^dxd") + { + SECTION("inverse:R^1x1") + { + TinyMatrix<1> arg{3}; + + DataVariant arg_variant = arg; + + auto i_function = name_builtin_function.find("inverse:R^1x1"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg_variant}); + + const TinyMatrix<1> result = inverse(arg); + REQUIRE(std::get<TinyMatrix<1>>(result_variant) == result); + } + + SECTION("inverse:R^2x2") + { + TinyMatrix<2> arg{3, 2, 1, -2}; + + DataVariant arg_variant = arg; + + auto i_function = name_builtin_function.find("inverse:R^2x2"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg_variant}); + + const TinyMatrix<2> result = inverse(arg); + REQUIRE(std::get<TinyMatrix<2>>(result_variant) == result); + } + + SECTION("inverse:R^3x3") + { + TinyMatrix<3> arg{3, 2, 4, // + -1, 4, 1, // + -4, -1, 5}; + + DataVariant arg_variant = arg; + + auto i_function = name_builtin_function.find("inverse:R^3x3"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg_variant}); + + const TinyMatrix<3> result = inverse(arg); + REQUIRE(std::get<TinyMatrix<3>>(result_variant) == result); + } + + SECTION("transpose:R^1x1") + { + TinyMatrix<1> arg{3}; + + DataVariant arg_variant = arg; + + auto i_function = name_builtin_function.find("transpose:R^1x1"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg_variant}); + + const TinyMatrix<1> result = transpose(arg); + REQUIRE(std::get<TinyMatrix<1>>(result_variant) == result); + } + + SECTION("transpose:R^2x2") + { + TinyMatrix<2> arg{3, 2, 1, -2}; + + DataVariant arg_variant = arg; + + auto i_function = name_builtin_function.find("transpose:R^2x2"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg_variant}); + + const TinyMatrix<2> result = transpose(arg); + REQUIRE(std::get<TinyMatrix<2>>(result_variant) == result); + } + + SECTION("transpose:R^3x3") + { + TinyMatrix<3> arg{3, 2, 4, // + -1, 4, 1, // + -4, -1, 5}; + + DataVariant arg_variant = arg; + + auto i_function = name_builtin_function.find("transpose:R^3x3"); + REQUIRE(i_function != name_builtin_function.end()); + + IBuiltinFunctionEmbedder& function_embedder = *i_function->second; + DataVariant result_variant = function_embedder.apply({arg_variant}); + + const TinyMatrix<3> result = transpose(arg); + REQUIRE(std::get<TinyMatrix<3>>(result_variant) == result); + } + } } diff --git a/tests/test_MedianDualConnectivityBuilder.cpp b/tests/test_MedianDualConnectivityBuilder.cpp index a95e6ad22f8a9b2605dec5c28e7c7704d40aed6f..6d091bd037e4ac57635757b98671eff9fe6eb643 100644 --- a/tests/test_MedianDualConnectivityBuilder.cpp +++ b/tests/test_MedianDualConnectivityBuilder.cpp @@ -5,6 +5,7 @@ #include <mesh/DualConnectivityManager.hpp> #include <mesh/Connectivity.hpp> +#include <mesh/ConnectivityUtils.hpp> #include <mesh/ItemValueUtils.hpp> #include <mesh/Mesh.hpp> @@ -50,6 +51,8 @@ TEST_CASE("MedianDualConnectivityBuilder", "[mesh]") DualConnectivityManager::instance().getMedianDualConnectivity(primal_connectivity); const ConnectivityType& dual_connectivity = *p_median_dual_connectivity; + REQUIRE(checkConnectivityOrdering(dual_connectivity)); + REQUIRE(dual_connectivity.numberOfNodes() == 192); REQUIRE(dual_connectivity.numberOfFaces() == 244); REQUIRE(dual_connectivity.numberOfCells() == 53); diff --git a/tests/test_MeshEdgeBoundary.cpp b/tests/test_MeshEdgeBoundary.cpp index 32c1d1c6e33c2c109b5c18f67172e3f15136f0f9..07711f27dc7aad4c4da9a18dafb2e8574e5e1cc6 100644 --- a/tests/test_MeshEdgeBoundary.cpp +++ b/tests/test_MeshEdgeBoundary.cpp @@ -72,7 +72,7 @@ TEST_CASE("MeshEdgeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& edge_boundary = getMeshEdgeBoundary(mesh, named_boundary_descriptor); @@ -105,7 +105,7 @@ TEST_CASE("MeshEdgeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& edge_boundary = getMeshEdgeBoundary(mesh, named_boundary_descriptor); @@ -145,7 +145,7 @@ TEST_CASE("MeshEdgeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor numbered_boundary_descriptor(name); const auto& edge_boundary = getMeshEdgeBoundary(mesh, numbered_boundary_descriptor); @@ -177,7 +177,7 @@ TEST_CASE("MeshEdgeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "YMIN", "XMAX", "YMIN"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor numbered_boundary_descriptor(name); const auto& edge_boundary = getMeshEdgeBoundary(mesh, numbered_boundary_descriptor); @@ -217,7 +217,7 @@ TEST_CASE("MeshEdgeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX", "ZMIN", "ZMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor numbered_boundary_descriptor(name); const auto& edge_boundary = getMeshEdgeBoundary(mesh, numbered_boundary_descriptor); @@ -249,7 +249,7 @@ TEST_CASE("MeshEdgeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX", "ZMIN", "ZMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor numbered_boundary_descriptor(name); const auto& edge_boundary = getMeshEdgeBoundary(mesh, numbered_boundary_descriptor); diff --git a/tests/test_MeshFaceBoundary.cpp b/tests/test_MeshFaceBoundary.cpp index 472427aaf0c7f9c85f566dd610020e91759aad84..aa4142d6b5fc9ca64c3f64f5cec9ed3a2b1fc993 100644 --- a/tests/test_MeshFaceBoundary.cpp +++ b/tests/test_MeshFaceBoundary.cpp @@ -72,7 +72,7 @@ TEST_CASE("MeshFaceBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& face_boundary = getMeshFaceBoundary(mesh, named_boundary_descriptor); @@ -105,7 +105,7 @@ TEST_CASE("MeshFaceBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& face_boundary = getMeshFaceBoundary(mesh, named_boundary_descriptor); @@ -145,7 +145,7 @@ TEST_CASE("MeshFaceBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor numbered_boundary_descriptor(name); const auto& face_boundary = getMeshFaceBoundary(mesh, numbered_boundary_descriptor); @@ -177,7 +177,7 @@ TEST_CASE("MeshFaceBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "YMIN", "XMAX", "YMIN"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor numbered_boundary_descriptor(name); const auto& face_boundary = getMeshFaceBoundary(mesh, numbered_boundary_descriptor); @@ -217,7 +217,7 @@ TEST_CASE("MeshFaceBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX", "ZMIN", "ZMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor numbered_boundary_descriptor(name); const auto& face_boundary = getMeshFaceBoundary(mesh, numbered_boundary_descriptor); @@ -249,7 +249,7 @@ TEST_CASE("MeshFaceBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX", "ZMIN", "ZMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor numbered_boundary_descriptor(name); const auto& face_boundary = getMeshFaceBoundary(mesh, numbered_boundary_descriptor); diff --git a/tests/test_MeshFlatEdgeBoundary.cpp b/tests/test_MeshFlatEdgeBoundary.cpp index 94700598238232b1e2a5e98692f57291f568dc39..16d843ade242d9105530fb04cfdbf4094085955e 100644 --- a/tests/test_MeshFlatEdgeBoundary.cpp +++ b/tests/test_MeshFlatEdgeBoundary.cpp @@ -95,7 +95,7 @@ TEST_CASE("MeshFlatEdgeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& edge_boundary = getMeshFlatEdgeBoundary(mesh, named_boundary_descriptor); @@ -158,7 +158,7 @@ TEST_CASE("MeshFlatEdgeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& edge_boundary = getMeshFlatEdgeBoundary(mesh, named_boundary_descriptor); @@ -250,7 +250,7 @@ TEST_CASE("MeshFlatEdgeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& edge_boundary = getMeshFlatEdgeBoundary(mesh, named_boundary_descriptor); @@ -346,7 +346,7 @@ TEST_CASE("MeshFlatEdgeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& edge_boundary = getMeshFlatEdgeBoundary(mesh, named_boundary_descriptor); @@ -494,7 +494,7 @@ TEST_CASE("MeshFlatEdgeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX", "ZMIN", "ZMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& edge_boundary = getMeshFlatEdgeBoundary(mesh, named_boundary_descriptor); @@ -669,7 +669,7 @@ TEST_CASE("MeshFlatEdgeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX", "ZMIN", "ZMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& edge_boundary = getMeshFlatEdgeBoundary(mesh, named_boundary_descriptor); @@ -817,7 +817,7 @@ TEST_CASE("MeshFlatEdgeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& edge_boundary = getMeshFlatEdgeBoundary(mesh, named_boundary_descriptor); @@ -898,7 +898,7 @@ TEST_CASE("MeshFlatEdgeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& edge_boundary = getMeshFlatEdgeBoundary(mesh, named_boundary_descriptor); @@ -1005,7 +1005,7 @@ TEST_CASE("MeshFlatEdgeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX", "ZMIN", "ZMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& edge_boundary = getMeshFlatEdgeBoundary(mesh, named_boundary_descriptor); @@ -1100,7 +1100,7 @@ TEST_CASE("MeshFlatEdgeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX", "ZMIN", "ZMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& edge_boundary = getMeshFlatEdgeBoundary(mesh, named_boundary_descriptor); @@ -1203,7 +1203,7 @@ TEST_CASE("MeshFlatEdgeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& edge_boundary = getMeshFlatEdgeBoundary(mesh, named_boundary_descriptor); @@ -1317,7 +1317,7 @@ TEST_CASE("MeshFlatEdgeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "ZMIN"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& edge_boundary = getMeshFlatEdgeBoundary(mesh, named_boundary_descriptor); @@ -1428,7 +1428,7 @@ TEST_CASE("MeshFlatEdgeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "ZMIN"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& edge_boundary = getMeshFlatEdgeBoundary(mesh, named_boundary_descriptor); diff --git a/tests/test_MeshFlatFaceBoundary.cpp b/tests/test_MeshFlatFaceBoundary.cpp index e01d79d1dc456f6f193d42db86c4f1f5ce08b75f..08e1779ce777bb4c6c3600bfd744c063f3359df5 100644 --- a/tests/test_MeshFlatFaceBoundary.cpp +++ b/tests/test_MeshFlatFaceBoundary.cpp @@ -95,7 +95,7 @@ TEST_CASE("MeshFlatFaceBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& face_boundary = getMeshFlatFaceBoundary(mesh, named_boundary_descriptor); @@ -158,7 +158,7 @@ TEST_CASE("MeshFlatFaceBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& face_boundary = getMeshFlatFaceBoundary(mesh, named_boundary_descriptor); @@ -239,7 +239,7 @@ TEST_CASE("MeshFlatFaceBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& face_boundary = getMeshFlatFaceBoundary(mesh, named_boundary_descriptor); @@ -313,7 +313,7 @@ TEST_CASE("MeshFlatFaceBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& face_boundary = getMeshFlatFaceBoundary(mesh, named_boundary_descriptor); @@ -406,7 +406,7 @@ TEST_CASE("MeshFlatFaceBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX", "ZMIN", "ZMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& face_boundary = getMeshFlatFaceBoundary(mesh, named_boundary_descriptor); @@ -493,7 +493,7 @@ TEST_CASE("MeshFlatFaceBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX", "ZMIN", "ZMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& face_boundary = getMeshFlatFaceBoundary(mesh, named_boundary_descriptor); @@ -597,7 +597,7 @@ TEST_CASE("MeshFlatFaceBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& face_boundary = getMeshFlatFaceBoundary(mesh, named_boundary_descriptor); @@ -678,7 +678,7 @@ TEST_CASE("MeshFlatFaceBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& face_boundary = getMeshFlatFaceBoundary(mesh, named_boundary_descriptor); @@ -785,7 +785,7 @@ TEST_CASE("MeshFlatFaceBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX", "ZMIN", "ZMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& face_boundary = getMeshFlatFaceBoundary(mesh, named_boundary_descriptor); @@ -880,7 +880,7 @@ TEST_CASE("MeshFlatFaceBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX", "ZMIN", "ZMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& face_boundary = getMeshFlatFaceBoundary(mesh, named_boundary_descriptor); @@ -983,7 +983,7 @@ TEST_CASE("MeshFlatFaceBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& face_boundary = getMeshFlatFaceBoundary(mesh, named_boundary_descriptor); @@ -1097,7 +1097,7 @@ TEST_CASE("MeshFlatFaceBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "ZMIN"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& face_boundary = getMeshFlatFaceBoundary(mesh, named_boundary_descriptor); @@ -1208,7 +1208,7 @@ TEST_CASE("MeshFlatFaceBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "ZMIN"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& face_boundary = getMeshFlatFaceBoundary(mesh, named_boundary_descriptor); diff --git a/tests/test_MeshFlatNodeBoundary.cpp b/tests/test_MeshFlatNodeBoundary.cpp index 29b0110569a14a6612a8b50cc76bc892c476d1ad..9b9169f73c4306f9591ba0a9c0f5c1c622f7ef69 100644 --- a/tests/test_MeshFlatNodeBoundary.cpp +++ b/tests/test_MeshFlatNodeBoundary.cpp @@ -95,7 +95,7 @@ TEST_CASE("MeshFlatNodeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& node_boundary = getMeshFlatNodeBoundary(mesh, named_boundary_descriptor); @@ -158,7 +158,7 @@ TEST_CASE("MeshFlatNodeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& node_boundary = getMeshFlatNodeBoundary(mesh, named_boundary_descriptor); @@ -250,7 +250,7 @@ TEST_CASE("MeshFlatNodeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& node_boundary = getMeshFlatNodeBoundary(mesh, named_boundary_descriptor); @@ -346,7 +346,7 @@ TEST_CASE("MeshFlatNodeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& node_boundary = getMeshFlatNodeBoundary(mesh, named_boundary_descriptor); @@ -494,7 +494,7 @@ TEST_CASE("MeshFlatNodeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX", "ZMIN", "ZMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& node_boundary = getMeshFlatNodeBoundary(mesh, named_boundary_descriptor); @@ -669,7 +669,7 @@ TEST_CASE("MeshFlatNodeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX", "ZMIN", "ZMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& node_boundary = getMeshFlatNodeBoundary(mesh, named_boundary_descriptor); @@ -817,7 +817,7 @@ TEST_CASE("MeshFlatNodeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& node_boundary = getMeshFlatNodeBoundary(mesh, named_boundary_descriptor); @@ -898,7 +898,7 @@ TEST_CASE("MeshFlatNodeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& node_boundary = getMeshFlatNodeBoundary(mesh, named_boundary_descriptor); @@ -1005,7 +1005,7 @@ TEST_CASE("MeshFlatNodeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX", "ZMIN", "ZMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& node_boundary = getMeshFlatNodeBoundary(mesh, named_boundary_descriptor); @@ -1100,7 +1100,7 @@ TEST_CASE("MeshFlatNodeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX", "ZMIN", "ZMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& node_boundary = getMeshFlatNodeBoundary(mesh, named_boundary_descriptor); @@ -1203,7 +1203,7 @@ TEST_CASE("MeshFlatNodeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& node_boundary = getMeshFlatNodeBoundary(mesh, named_boundary_descriptor); @@ -1317,7 +1317,7 @@ TEST_CASE("MeshFlatNodeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "ZMIN"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& node_boundary = getMeshFlatNodeBoundary(mesh, named_boundary_descriptor); @@ -1428,7 +1428,7 @@ TEST_CASE("MeshFlatNodeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "ZMIN"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& node_boundary = getMeshFlatNodeBoundary(mesh, named_boundary_descriptor); diff --git a/tests/test_MeshLineEdgeBoundary.cpp b/tests/test_MeshLineEdgeBoundary.cpp index b4b21d0dc7e692216f80d0119f97d423518eb884..31d9a578b956279ce52fdea6d165de1f13250a6d 100644 --- a/tests/test_MeshLineEdgeBoundary.cpp +++ b/tests/test_MeshLineEdgeBoundary.cpp @@ -114,7 +114,7 @@ TEST_CASE("MeshLineEdgeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& edge_boundary = getMeshLineEdgeBoundary(mesh, named_boundary_descriptor); @@ -210,7 +210,7 @@ TEST_CASE("MeshLineEdgeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& edge_boundary = getMeshLineEdgeBoundary(mesh, named_boundary_descriptor); @@ -487,7 +487,7 @@ TEST_CASE("MeshLineEdgeBoundary", "[mesh]") "XMINZMIN", "XMINZMAX", "XMAXZMAX", "XMINZMAX", "YMINZMIN", "YMINZMAX", "YMAXZMAX", "YMAXZMIN"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& edge_boundary = getMeshLineEdgeBoundary(mesh, named_boundary_descriptor); @@ -617,7 +617,7 @@ TEST_CASE("MeshLineEdgeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& edge_boundary = getMeshLineEdgeBoundary(mesh, named_boundary_descriptor); @@ -698,7 +698,7 @@ TEST_CASE("MeshLineEdgeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& edge_boundary = getMeshLineEdgeBoundary(mesh, named_boundary_descriptor); @@ -804,7 +804,7 @@ TEST_CASE("MeshLineEdgeBoundary", "[mesh]") "XMINZMIN", "XMINZMAX", "XMAXZMAX", "XMINZMAX", "YMINZMIN", "YMINZMAX", "YMAXZMAX", "YMAXZMIN"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& edge_boundary = getMeshLineEdgeBoundary(mesh, named_boundary_descriptor); @@ -892,7 +892,7 @@ TEST_CASE("MeshLineEdgeBoundary", "[mesh]") "XMINZMIN", "XMINZMAX", "XMAXZMAX", "XMINZMAX", "YMINZMIN", "YMINZMAX", "YMAXZMAX", "YMAXZMIN"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& edge_boundary = getMeshLineEdgeBoundary(mesh, named_boundary_descriptor); @@ -989,7 +989,7 @@ TEST_CASE("MeshLineEdgeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& edge_boundary = getMeshLineEdgeBoundary(mesh, named_boundary_descriptor); @@ -1105,7 +1105,7 @@ TEST_CASE("MeshLineEdgeBoundary", "[mesh]") const std::set<std::string> name_set = {"XMINYMIN", "XMINYMAX", "XMAXYMIN", "XMAXYMAX", "XMINZMIN", "XMINZMAX", "XMAXZMAX", "XMINZMAX", "YMINZMIN"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& edge_boundary = getMeshLineEdgeBoundary(mesh, named_boundary_descriptor); @@ -1218,7 +1218,7 @@ TEST_CASE("MeshLineEdgeBoundary", "[mesh]") const std::set<std::string> name_set = {"XMINYMIN", "XMINYMAX", "XMAXYMIN", "XMAXYMAX", "XMINZMIN", "XMINZMAX", "XMAXZMAX", "XMINZMAX", "YMINZMIN"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& edge_boundary = getMeshLineEdgeBoundary(mesh, named_boundary_descriptor); diff --git a/tests/test_MeshLineFaceBoundary.cpp b/tests/test_MeshLineFaceBoundary.cpp index f5cb9eb18714f668d63a0a4c2fd40a04b7cbeee9..86150aa40cb5fb82fd8718b56551dc7b52017c1d 100644 --- a/tests/test_MeshLineFaceBoundary.cpp +++ b/tests/test_MeshLineFaceBoundary.cpp @@ -114,7 +114,7 @@ TEST_CASE("MeshLineFaceBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& face_boundary = getMeshLineFaceBoundary(mesh, named_boundary_descriptor); @@ -210,7 +210,7 @@ TEST_CASE("MeshLineFaceBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& face_boundary = getMeshLineFaceBoundary(mesh, named_boundary_descriptor); @@ -321,7 +321,7 @@ TEST_CASE("MeshLineFaceBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& face_boundary = getMeshLineFaceBoundary(mesh, named_boundary_descriptor); @@ -402,7 +402,7 @@ TEST_CASE("MeshLineFaceBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& face_boundary = getMeshLineFaceBoundary(mesh, named_boundary_descriptor); @@ -501,7 +501,7 @@ TEST_CASE("MeshLineFaceBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& face_boundary = getMeshLineFaceBoundary(mesh, named_boundary_descriptor); diff --git a/tests/test_MeshLineNodeBoundary.cpp b/tests/test_MeshLineNodeBoundary.cpp index 36c151e2d4ddf14e21ad5defed6774a06cf6394e..f82f69b142df991b8c757ba2707be0bc045610d3 100644 --- a/tests/test_MeshLineNodeBoundary.cpp +++ b/tests/test_MeshLineNodeBoundary.cpp @@ -114,7 +114,7 @@ TEST_CASE("MeshLineNodeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& node_boundary = getMeshLineNodeBoundary(mesh, named_boundary_descriptor); @@ -210,7 +210,7 @@ TEST_CASE("MeshLineNodeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& node_boundary = getMeshLineNodeBoundary(mesh, named_boundary_descriptor); @@ -487,7 +487,7 @@ TEST_CASE("MeshLineNodeBoundary", "[mesh]") "XMINZMIN", "XMINZMAX", "XMAXZMAX", "XMINZMAX", "YMINZMIN", "YMINZMAX", "YMAXZMAX", "YMAXZMIN"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& node_boundary = getMeshLineNodeBoundary(mesh, named_boundary_descriptor); @@ -617,7 +617,7 @@ TEST_CASE("MeshLineNodeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& node_boundary = getMeshLineNodeBoundary(mesh, named_boundary_descriptor); @@ -698,7 +698,7 @@ TEST_CASE("MeshLineNodeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& node_boundary = getMeshLineNodeBoundary(mesh, named_boundary_descriptor); @@ -804,7 +804,7 @@ TEST_CASE("MeshLineNodeBoundary", "[mesh]") "XMINZMIN", "XMINZMAX", "XMAXZMAX", "XMINZMAX", "YMINZMIN", "YMINZMAX", "YMAXZMAX", "YMAXZMIN"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& node_boundary = getMeshLineNodeBoundary(mesh, named_boundary_descriptor); @@ -892,7 +892,7 @@ TEST_CASE("MeshLineNodeBoundary", "[mesh]") "XMINZMIN", "XMINZMAX", "XMAXZMAX", "XMINZMAX", "YMINZMIN", "YMINZMAX", "YMAXZMAX", "YMAXZMIN"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& node_boundary = getMeshLineNodeBoundary(mesh, named_boundary_descriptor); @@ -989,7 +989,7 @@ TEST_CASE("MeshLineNodeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& node_boundary = getMeshLineNodeBoundary(mesh, named_boundary_descriptor); @@ -1105,7 +1105,7 @@ TEST_CASE("MeshLineNodeBoundary", "[mesh]") const std::set<std::string> name_set = {"XMINYMIN", "XMINYMAX", "XMAXYMIN", "XMAXYMAX", "XMINZMIN", "XMINZMAX", "XMAXZMAX", "XMINZMAX", "YMINZMIN"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& node_boundary = getMeshLineNodeBoundary(mesh, named_boundary_descriptor); @@ -1218,7 +1218,7 @@ TEST_CASE("MeshLineNodeBoundary", "[mesh]") const std::set<std::string> name_set = {"XMINYMIN", "XMINYMAX", "XMAXYMIN", "XMAXYMAX", "XMINZMIN", "XMINZMAX", "XMAXZMAX", "XMINZMAX", "YMINZMIN"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& node_boundary = getMeshLineNodeBoundary(mesh, named_boundary_descriptor); diff --git a/tests/test_MeshNodeBoundary.cpp b/tests/test_MeshNodeBoundary.cpp index 2639e6370f9681024f0dab87367468a1df2a5002..c09276cee007b7ac073dae1aae80760c6e887d3c 100644 --- a/tests/test_MeshNodeBoundary.cpp +++ b/tests/test_MeshNodeBoundary.cpp @@ -72,7 +72,7 @@ TEST_CASE("MeshNodeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& node_boundary = getMeshNodeBoundary(mesh, named_boundary_descriptor); @@ -105,7 +105,7 @@ TEST_CASE("MeshNodeBoundary", "[mesh]") { const std::set<std::string> name_set = {"XMIN", "XMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor named_boundary_descriptor(name); const auto& node_boundary = getMeshNodeBoundary(mesh, named_boundary_descriptor); @@ -146,7 +146,7 @@ TEST_CASE("MeshNodeBoundary", "[mesh]") const std::set<std::string> name_set = {"XMIN", "XMAX", "YMIN", "YMAX", "XMINYMIN", "XMINYMAX", "XMAXYMIN", "XMAXYMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor numbered_boundary_descriptor(name); const auto& node_boundary = getMeshNodeBoundary(mesh, numbered_boundary_descriptor); @@ -179,7 +179,7 @@ TEST_CASE("MeshNodeBoundary", "[mesh]") const std::set<std::string> name_set = {"XMIN", "YMIN", "XMAX", "YMIN", "XMINYMIN", "XMINYMAX", "XMAXYMIN", "XMAXYMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor numbered_boundary_descriptor(name); const auto& node_boundary = getMeshNodeBoundary(mesh, numbered_boundary_descriptor); @@ -227,7 +227,7 @@ TEST_CASE("MeshNodeBoundary", "[mesh]") "XMINYMINZMIN", "XMINYMINZMAX", "XMINYMAXZMIN", "XMINYMAXZMAX", "XMAXYMINZMIN", "XMAXYMINZMAX", "XMAXYMAXZMIN", "XMAXYMAXZMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor numbered_boundary_descriptor(name); const auto& node_boundary = getMeshNodeBoundary(mesh, numbered_boundary_descriptor); @@ -267,7 +267,7 @@ TEST_CASE("MeshNodeBoundary", "[mesh]") "XMINYMINZMIN", "XMINYMINZMAX", "XMINYMAXZMIN", "XMINYMAXZMAX", "XMAXYMINZMIN", "XMAXYMINZMAX", "XMAXYMAXZMIN", "XMAXYMAXZMAX"}; - for (auto name : name_set) { + for (const auto& name : name_set) { NamedBoundaryDescriptor numbered_boundary_descriptor(name); const auto& node_boundary = getMeshNodeBoundary(mesh, numbered_boundary_descriptor); diff --git a/tests/test_SubItemArrayPerItem.cpp b/tests/test_SubItemArrayPerItem.cpp index aa8930269fcd03756cf69495ef4f77bc44869e62..ec4e06e0c31da2906333bd8a37ea390e7ee8d9c3 100644 --- a/tests/test_SubItemArrayPerItem.cpp +++ b/tests/test_SubItemArrayPerItem.cpp @@ -66,7 +66,7 @@ TEST_CASE("SubItemArrayPerItem", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -189,7 +189,7 @@ TEST_CASE("SubItemArrayPerItem", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -355,7 +355,7 @@ TEST_CASE("SubItemArrayPerItem", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -552,7 +552,7 @@ TEST_CASE("SubItemArrayPerItem", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -625,7 +625,7 @@ TEST_CASE("SubItemArrayPerItem", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -697,7 +697,7 @@ TEST_CASE("SubItemArrayPerItem", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -769,7 +769,7 @@ TEST_CASE("SubItemArrayPerItem", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -880,7 +880,7 @@ TEST_CASE("SubItemArrayPerItem", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -991,7 +991,7 @@ TEST_CASE("SubItemArrayPerItem", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -1087,7 +1087,7 @@ TEST_CASE("SubItemArrayPerItem", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); diff --git a/tests/test_SubItemArrayPerItemUtils.cpp b/tests/test_SubItemArrayPerItemUtils.cpp index d3f29a3814fb88cc1fe75c06214dd463ac406525..e534ec34600ef526336249a4b7d1cfc794721827 100644 --- a/tests/test_SubItemArrayPerItemUtils.cpp +++ b/tests/test_SubItemArrayPerItemUtils.cpp @@ -18,7 +18,7 @@ TEST_CASE("SubItemArrayPerItemUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -90,7 +90,7 @@ TEST_CASE("SubItemArrayPerItemUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -122,7 +122,7 @@ TEST_CASE("SubItemArrayPerItemUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -154,7 +154,7 @@ TEST_CASE("SubItemArrayPerItemUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -189,7 +189,7 @@ TEST_CASE("SubItemArrayPerItemUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -221,7 +221,7 @@ TEST_CASE("SubItemArrayPerItemUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -253,7 +253,7 @@ TEST_CASE("SubItemArrayPerItemUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -289,7 +289,7 @@ TEST_CASE("SubItemArrayPerItemUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -319,7 +319,7 @@ TEST_CASE("SubItemArrayPerItemUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name() + " for size_t data") { auto mesh_2d = named_mesh.mesh(); @@ -375,7 +375,7 @@ TEST_CASE("SubItemArrayPerItemUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name() + " for size_t data") { auto mesh_3d = named_mesh.mesh(); diff --git a/tests/test_SubItemValuePerItem.cpp b/tests/test_SubItemValuePerItem.cpp index 65741d70089785bb58b34230569afcd33a961c62..349de725023c5156bb05f75265d61d589cc48799 100644 --- a/tests/test_SubItemValuePerItem.cpp +++ b/tests/test_SubItemValuePerItem.cpp @@ -76,7 +76,7 @@ TEST_CASE("SubItemValuePerItem", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -212,7 +212,7 @@ TEST_CASE("SubItemValuePerItem", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -388,7 +388,7 @@ TEST_CASE("SubItemValuePerItem", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -593,7 +593,7 @@ TEST_CASE("SubItemValuePerItem", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -709,7 +709,7 @@ TEST_CASE("SubItemValuePerItem", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -895,7 +895,7 @@ TEST_CASE("SubItemValuePerItem", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -1116,7 +1116,7 @@ TEST_CASE("SubItemValuePerItem", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -1161,7 +1161,7 @@ TEST_CASE("SubItemValuePerItem", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -1205,7 +1205,7 @@ TEST_CASE("SubItemValuePerItem", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -1251,7 +1251,7 @@ TEST_CASE("SubItemValuePerItem", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -1350,7 +1350,7 @@ TEST_CASE("SubItemValuePerItem", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -1439,7 +1439,7 @@ TEST_CASE("SubItemValuePerItem", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); diff --git a/tests/test_SubItemValuePerItemUtils.cpp b/tests/test_SubItemValuePerItemUtils.cpp index ccda4722d7f5ac6c56bacb0d94c2ed0689166eec..aca9a14498e447b1cd6ffd21411f45e847b34ac5 100644 --- a/tests/test_SubItemValuePerItemUtils.cpp +++ b/tests/test_SubItemValuePerItemUtils.cpp @@ -18,7 +18,7 @@ TEST_CASE("SubItemValuePerItemUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -85,7 +85,7 @@ TEST_CASE("SubItemValuePerItemUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -115,7 +115,7 @@ TEST_CASE("SubItemValuePerItemUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -145,7 +145,7 @@ TEST_CASE("SubItemValuePerItemUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -178,7 +178,7 @@ TEST_CASE("SubItemValuePerItemUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -208,7 +208,7 @@ TEST_CASE("SubItemValuePerItemUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_2d = named_mesh.mesh(); @@ -238,7 +238,7 @@ TEST_CASE("SubItemValuePerItemUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_3d = named_mesh.mesh(); @@ -273,7 +273,7 @@ TEST_CASE("SubItemValuePerItemUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name()) { auto mesh_1d = named_mesh.mesh(); @@ -302,7 +302,7 @@ TEST_CASE("SubItemValuePerItemUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name() + " for size_t data") { auto mesh_2d = named_mesh.mesh(); @@ -356,7 +356,7 @@ TEST_CASE("SubItemValuePerItemUtils", "[mesh]") { std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes(); - for (auto named_mesh : mesh_list) { + for (const auto& named_mesh : mesh_list) { SECTION(named_mesh.name() + " for size_t data") { auto mesh_3d = named_mesh.mesh(); diff --git a/tests/test_TinyMatrix.cpp b/tests/test_TinyMatrix.cpp index 2f4c09d4ad9ce1dbb5e3d856d8737d27344459f2..f6f09cf55dd2ad1ffef55c9275b989c203598f7e 100644 --- a/tests/test_TinyMatrix.cpp +++ b/tests/test_TinyMatrix.cpp @@ -194,6 +194,17 @@ TEST_CASE("TinyMatrix", "[algebra]") REQUIRE(det(TinyMatrix<4>(1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 2, 0, 0, 2, 2)) == 0); } + SECTION("checking for trace calculations") + { + REQUIRE(trace(TinyMatrix<1, 1, int>(6)) == 6); + REQUIRE(trace(TinyMatrix<2, 2, int>(5, 1, -3, 6)) == 5 + 6); + REQUIRE(trace(TinyMatrix<3, 3, int>(1, 1, 1, 1, 2, 1, 2, 1, 3)) == 1 + 2 + 3); + REQUIRE(trace(TinyMatrix<3, 3, int>(6, 5, 3, 8, 34, 6, 35, 6, 7)) == 6 + 34 + 7); + REQUIRE(trace(TinyMatrix<4>(1, 2.3, 7, -6.2, 3, 4, 9, 1, 4.1, 5, 2, -3, 2, 27, 3, 17.5)) == + Catch::Approx(1 + 4 + 2 + 17.5).epsilon(1E-14)); + REQUIRE(trace(TinyMatrix<4>(1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 2, 0, 0, 2, 2)) == 1 + 0 + 1 + 2); + } + SECTION("checking for inverse calculations") { {