From 711657a7e9b84bbd4abad688d69950fdd98a1a14 Mon Sep 17 00:00:00 2001 From: Sam Mish Date: Wed, 11 Dec 2024 13:08:16 -0800 Subject: [PATCH 01/15] copy new element definitions in --- all_output.txt | 2442 +++++++++++++++++ data/meshes/one_tri.mesh | 29 + data/meshes/testAttr.e | Bin 0 -> 257681 bytes data/meshes/two_hexes.mesh | 39 + data/meshes/two_tets.mesh | 32 + data/meshes/two_tris.mesh | 35 + .../numerics/refactor/elements/h1_edge.hpp | 191 ++ .../refactor/elements/h1_hexahedron.hpp | 494 ++++ .../refactor/elements/h1_quadrilateral.hpp | 391 +++ .../refactor/elements/h1_tetrahedron.hpp | 401 +++ .../refactor/elements/h1_triangle.hpp | 331 +++ .../numerics/refactor/elements/h1_vertex.hpp | 18 + .../numerics/refactor/elements/hcurl_edge.hpp | 276 ++ .../refactor/elements/hcurl_hexahedron.hpp | 1061 +++++++ .../refactor/elements/hcurl_quadrilateral.hpp | 611 +++++ .../refactor/elements/hcurl_tetrahedron.hpp | 1686 ++++++++++++ .../refactor/elements/hcurl_triangle.hpp | 625 +++++ .../refactor/elements/hcurl_vertex.hpp | 24 + .../numerics/refactor/finite_element.hpp | 119 + src/serac/numerics/refactor/integrate.hpp | 1 + src/serac/numerics/refactor/interpolate.hpp | 0 21 files changed, 8806 insertions(+) create mode 100644 all_output.txt create mode 100644 data/meshes/one_tri.mesh create mode 100644 data/meshes/testAttr.e create mode 100755 data/meshes/two_hexes.mesh create mode 100644 data/meshes/two_tets.mesh create mode 100644 data/meshes/two_tris.mesh create mode 100644 src/serac/numerics/refactor/elements/h1_edge.hpp create mode 100644 src/serac/numerics/refactor/elements/h1_hexahedron.hpp create mode 100644 src/serac/numerics/refactor/elements/h1_quadrilateral.hpp create mode 100644 src/serac/numerics/refactor/elements/h1_tetrahedron.hpp create mode 100644 src/serac/numerics/refactor/elements/h1_triangle.hpp create mode 100644 src/serac/numerics/refactor/elements/h1_vertex.hpp create mode 100644 src/serac/numerics/refactor/elements/hcurl_edge.hpp create mode 100644 src/serac/numerics/refactor/elements/hcurl_hexahedron.hpp create mode 100644 src/serac/numerics/refactor/elements/hcurl_quadrilateral.hpp create mode 100644 src/serac/numerics/refactor/elements/hcurl_tetrahedron.hpp create mode 100644 src/serac/numerics/refactor/elements/hcurl_triangle.hpp create mode 100644 src/serac/numerics/refactor/elements/hcurl_vertex.hpp create mode 100644 src/serac/numerics/refactor/finite_element.hpp create mode 100644 src/serac/numerics/refactor/integrate.hpp create mode 100644 src/serac/numerics/refactor/interpolate.hpp diff --git a/all_output.txt b/all_output.txt new file mode 100644 index 0000000000..a57810688b --- /dev/null +++ b/all_output.txt @@ -0,0 +1,2442 @@ +[uberenv python: /usr/bin/python3] +[uberenv project settings: + package_name: serac + package_version: develop + package_final_phase: initconfig + package_source_dir: ../.. + spack_url: https://github.com/spack/spack.git + spack_commit: cfee88a5bb56a1c8ec892879e04cb6a17c4f9404 + spack_configs_path: scripts/spack/configs + spack_packages_path: ['scripts/spack/radiuss-spack-configs/packages', 'scripts/spack/packages'] + spack_concretizer: clingo + force_commandline_prefix: False +] +[uberenv command line options: + install: False + prefix: ../serac_libs_dec_24 + spec: %gcc@12.3.0+profiling + vcpkg_triplet: None + mirror: None + create_mirror: False + upstream: None + reuse: False + vcpkg_ports_path: None + package_name: None + spack_build_mode: None + spack_debug: False + spack_allow_deprecated: False + package_final_phase: None + package_source_dir: None + project_json: /home/sam/code/serac/.uberenv_config.json + build_jobs: None + ignore_ssl_errors: False + repo_pull: False + spack_clean: False + run_tests: False + macos_sdk_env_setup: False + setup_only: False + skip_setup: False + spack_externals: None + spack_compiler_paths: None + spack_env_name: spack_env + spack_env_file: spack.yaml +] +[uberenv spack build mode: dev-build] +[spack spec: @develop%gcc@12.3.0+profiling] +[Spack Environment file: /home/sam/code/serac/spack.yaml] +[installing to: /home/sam/code/serac_libs_dec_24] +[info: cloning spack develop branch from github] +[exe: git clone --single-branch --depth=1 -b develop https://github.com/spack/spack.git spack] +Cloning into 'spack'... +[info: using spack commit cfee88a5bb56a1c8ec892879e04cb6a17c4f9404] +[exe: git stash] +No local changes to save +[exe: git fetch --depth=1 origin cfee88a5bb56a1c8ec892879e04cb6a17c4f9404] +From https://github.com/spack/spack + * branch cfee88a5bb56a1c8ec892879e04cb6a17c4f9404 -> FETCH_HEAD +[exe: git checkout cfee88a5bb56a1c8ec892879e04cb6a17c4f9404] +Note: switching to 'cfee88a5bb56a1c8ec892879e04cb6a17c4f9404'. + +You are in 'detached HEAD' state. You can look around, make experimental +changes and commit them, and you can discard any commits you make in this +state without impacting any branches by switching back to a branch. + +If you want to create a new branch to retain commits you create, you may +do so (now or later) by using -c with the switch command. Example: + + git switch -c + +Or undo this operation with: + + git switch - + +Turn off this advice by setting config variable advice.detachedHead to false + +HEAD is now at cfee88a5 Docs/Windows: Clarify supported shells and caveats (#46381) +[spack python: /usr/bin/python3] +[Checking for concretizer options...] +[--fresh exists.] +[--reuse exists.] +[disabling config scope (except defaults) in: /home/sam/code/serac_libs_dec_24/spack/lib/spack/spack/config.py] +[exe: /home/sam/code/serac_libs_dec_24/spack/bin/spack config --scope defaults add config:concretizer:clingo] +==> Warning: Spack supports only clingo as a concretizer from v0.23. The config:concretizer config option is ignored. +[exe: /home/sam/code/serac_libs_dec_24/spack/bin/spack clean --misc-cache --failures --python-cache] +==> Warning: Spack supports only clingo as a concretizer from v0.23. The config:concretizer config option is ignored. +==> Removing install failure marks +==> Removing cached information on repositories +==> Removing python cache files +[creating spack env] +[exe: /home/sam/code/serac_libs_dec_24/spack/bin/spack env create -d /home/sam/code/serac_libs_dec_24/spack_env /home/sam/code/serac/spack.yaml] +==> Warning: Spack supports only clingo as a concretizer from v0.23. The config:concretizer config option is ignored. +==> Created independent environment in: /home/sam/code/serac_libs_dec_24/spack_env +==> Activate with: spack env activate /home/sam/code/serac_libs_dec_24/spack_env +[adding spack repo /home/sam/code/serac/scripts/spack/radiuss-spack-configs/packages/../] +[exe: /home/sam/code/serac_libs_dec_24/spack/bin/spack -D /home/sam/code/serac_libs_dec_24/spack_env repo add /home/sam/code/serac/scripts/spack/radiuss-spack-configs/packages/../] +==> Warning: Spack supports only clingo as a concretizer from v0.23. The config:concretizer config option is ignored. +==> Error: Repository is already registered with Spack: /home/sam/code/serac/scripts/spack/radiuss-spack-configs/packages/../ +[adding spack repo /home/sam/code/serac/scripts/spack/packages/../] +[exe: /home/sam/code/serac_libs_dec_24/spack/bin/spack -D /home/sam/code/serac_libs_dec_24/spack_env repo add /home/sam/code/serac/scripts/spack/packages/../] +==> Warning: Spack supports only clingo as a concretizer from v0.23. The config:concretizer config option is ignored. +==> Error: Repository is already registered with Spack: /home/sam/code/serac/scripts/spack/packages/../ +[adding spack package] +[exe: /home/sam/code/serac_libs_dec_24/spack/bin/spack -D /home/sam/code/serac_libs_dec_24/spack_env add 'serac@develop%gcc@12.3.0+profiling'] +==> Warning: Spack supports only clingo as a concretizer from v0.23. The config:concretizer config option is ignored. +==> Adding serac@develop%gcc@12.3.0+profiling to environment /home/sam/code/serac_libs_dec_24/spack_env +[calling spack develop] +[exe: /home/sam/code/serac_libs_dec_24/spack/bin/spack -D /home/sam/code/serac_libs_dec_24/spack_env develop --no-clone --path=/home/sam/code/serac 'serac@develop%gcc@12.3.0+profiling'] +==> Warning: Spack supports only clingo as a concretizer from v0.23. The config:concretizer config option is ignored. +[concretizing spack env] +[exe: /home/sam/code/serac_libs_dec_24/spack/bin/spack -D /home/sam/code/serac_libs_dec_24/spack_env concretize --fresh ] +==> Warning: Spack supports only clingo as a concretizer from v0.23. The config:concretizer config option is ignored. +==> Warning: duplicate found for clang@=14.0.0 on ubuntu22.04/x86_64. Edit your compilers.yaml configuration to remove it. +==> Warning: duplicate found for gcc@=9.5.0 on ubuntu22.04/x86_64. Edit your compilers.yaml configuration to remove it. +==> Warning: duplicate found for gcc@=10.5.0 on ubuntu22.04/x86_64. Edit your compilers.yaml configuration to remove it. +==> Warning: duplicate found for gcc@=11.4.0 on ubuntu22.04/x86_64. Edit your compilers.yaml configuration to remove it. +==> Warning: duplicate found for gcc@=12.3.0 on ubuntu22.04/x86_64. Edit your compilers.yaml configuration to remove it. +==> Warning: using "cmake@3.28.3" which is a deprecated version +==> Warning: using "perl@5.34.0" which is a deprecated version +==> Concretized 2 specs: + - l77xejh serac@develop%gcc@12.3.0~asan~cuda~devtools~ipo+openmp+petsc+profiling+raja~rocm~shared+slepc+strumpack+sundials+tribol+umpire build_system=cmake build_type=Release dev_path=/home/sam/code/serac generator=make arch=linux-ubuntu22.04-skylake + - kgt73cv ^adiak@0.4.0%gcc@12.3.0~ipo+mpi~shared build_system=cmake build_type=Release generator=make arch=linux-ubuntu22.04-skylake + - crlt4id ^axom@0.9.0.1%gcc@12.3.0+cpp14~cuda~devtools~examples~fortran+hdf5~ipo+lua+mfem+mpi+openmp~python+raja~rocm~scr~shared~tools+umpire build_system=cmake build_type=Release generator=make arch=linux-ubuntu22.04-skylake + - 2oxa6mf ^blt@0.6.2%gcc@12.3.0 build_system=generic arch=linux-ubuntu22.04-skylake + - julim3s ^caliper@2.10.0%gcc@12.3.0+adiak~cuda~fortran+gotcha~ipo+kokkos+libdw~libpfm+libunwind+mpi~papi~rocm+sampler~shared~sosflow~tests~variorum build_system=cmake build_type=Release generator=make arch=linux-ubuntu22.04-skylake + - vtbtqmz ^elfutils@0.191%gcc@12.3.0~debuginfod+exeprefix+nls build_system=autotools arch=linux-ubuntu22.04-skylake +[e] aac2civ ^bzip2@1.0.8%gcc@12.3.0~debug~pic+shared build_system=generic arch=linux-ubuntu22.04-skylake +[e] vjtarjv ^gettext@0.21%gcc@12.3.0+bzip2+curses+git~libunistring+libxml2+pic+shared+tar+xz build_system=autotools arch=linux-ubuntu22.04-skylake + - yurditi ^libiconv@1.17%gcc@12.3.0 build_system=autotools libs=shared,static arch=linux-ubuntu22.04-skylake +[e] d5ozks2 ^m4@1.4.18%gcc@12.3.0+sigsegv build_system=autotools patches=3877ab5,fc9b616 arch=linux-ubuntu22.04-skylake +[e] oa6rfve ^xz@5.2.5%gcc@12.3.0~pic build_system=autotools libs=shared,static arch=linux-ubuntu22.04-skylake + - dwvdelj ^zstd@1.5.6%gcc@12.3.0~programs build_system=makefile libs=shared,static arch=linux-ubuntu22.04-skylake + - 6otmcgj ^libunwind@1.6.2%gcc@12.3.0~block_signals~conservative_checks~cxx_exceptions~debug~debug_frame+docs~pic+tests+weak_backtrace~xz~zlib build_system=autotools components=none libs=shared,static arch=linux-ubuntu22.04-skylake +[e] vrnm5c2 ^python@3.10.14%gcc@12.3.0+bz2+crypt+ctypes+dbm~debug+libxml2+lzma+nis~optimizations+pic+pyexpat~pythoncmd+readline+shared+sqlite3+ssl+tix+tkinter+uuid+zlib build_system=generic patches=0d98e93,ebdca64,f2fd060 arch=linux-ubuntu22.04-skylake + - v5g75d7 ^camp@2024.02.0%gcc@12.3.0~cuda~ipo+openmp~rocm~tests build_system=cmake build_type=Release generator=make arch=linux-ubuntu22.04-skylake +[e] yl7xufq ^cmake@3.28.3%gcc@12.3.0~doc+ncurses+ownlibs build_system=generic build_type=Release patches=dbc3892 arch=linux-ubuntu22.04-skylake + - 7ymuqal ^conduit@0.9.2%gcc@12.3.0~adios+blt_find_mpi~caliper~doc~doxygen+examples~fortran+hdf5+hdf5_compat~ipo+mpi+parmetis~python+shared~silo~test+utilities~zfp build_system=cmake build_type=Release generator=make arch=linux-ubuntu22.04-skylake + - qupzzv7 ^gcc-runtime@12.3.0%gcc@12.3.0 build_system=generic arch=linux-ubuntu22.04-skylake +[e] d4i5knf ^glibc@2.35%gcc@12.3.0 build_system=autotools arch=linux-ubuntu22.04-skylake +[e] nizar4h ^gmake@4.3%gcc@12.3.0~guile build_system=generic patches=599f134 arch=linux-ubuntu22.04-skylake + - gpzjvgu ^hdf5@1.8.23%gcc@12.3.0~cxx~fortran+hl~ipo~mpi~shared~szip~threadsafe+tools api=default build_system=cmake build_type=Release generator=make arch=linux-ubuntu22.04-skylake + - yerv6on ^pkgconf@2.2.0%gcc@12.3.0 build_system=autotools arch=linux-ubuntu22.04-skylake + - 46skka2 ^zlib-ng@2.2.1%gcc@12.3.0+compat+new_strategies+opt+pic+shared build_system=autotools arch=linux-ubuntu22.04-skylake + - kwxuezs ^hypre@2.26.0%gcc@12.3.0~caliper~complex~cublas~cuda~debug+fortran~gptune~gpu-aware-mpi~int64~internal-superlu~magma~mixedint+mpi~openmp~rocblas~rocm~shared~superlu-dist~sycl~umpire~unified-memory build_system=autotools precision=double arch=linux-ubuntu22.04-skylake + - haeuwrx ^openblas@0.3.27%gcc@12.3.0~bignuma~consistent_fpcsr+dynamic_dispatch+fortran~ilp64+locking+pic+shared build_system=makefile symbol_suffix=none threads=openmp arch=linux-ubuntu22.04-skylake + - 4gqzkxq ^lua@5.4.6%gcc@12.3.0~pcfile+shared build_system=makefile fetcher=curl arch=linux-ubuntu22.04-skylake +[e] dkdfsjq ^curl@7.81.0%gcc@12.3.0+gssapi+ldap~libidn2~librtmp~libssh~libssh2+nghttp2 build_system=autotools libs=shared,static tls=openssl arch=linux-ubuntu22.04-skylake +[e] s6wsuoj ^ncurses@6.3.20211021%gcc@12.3.0+symlinks+termlib abi=6 build_system=autotools patches=7a351bc arch=linux-ubuntu22.04-skylake + - qyfndow ^readline@8.2%gcc@12.3.0 build_system=autotools patches=bbf97f1 arch=linux-ubuntu22.04-skylake + - shglyno ^unzip@6.0%gcc@12.3.0 build_system=makefile patches=881d2ed,f6f6236 arch=linux-ubuntu22.04-skylake + - 2g2acji ^metis@5.1.0%gcc@12.3.0~gdb~int64~ipo~real64~shared build_system=cmake build_type=Release generator=make patches=4991da9,93a7903,b1225da arch=linux-ubuntu22.04-skylake + - hg6gqwa ^mfem@4.7.0.1%gcc@12.3.0~amgx~asan~conduit~cuda~debug~examples~exceptions~fms~ginkgo~gnutls~gslib~hiop+lapack~libceed~libunwind+metis~miniapps~mpfr+mpi~mumps+netcdf~occa+openmp+petsc~pumi~raja~rocm~shared+slepc+static+strumpack~suite-sparse+sundials+superlu-dist~threadsafe~umpire+zlib build_system=generic cxxstd=auto patches=937da2a precision=double timer=auto arch=linux-ubuntu22.04-skylake + - o4h3fi5 ^netcdf-c@4.7.4%gcc@12.3.0~blosc~byterange~dap~fsync~hdf4~jna~logging~mpi~nczarr_zip+optimize~parallel-netcdf+pic~shared~szip~zstd build_system=autotools arch=linux-ubuntu22.04-skylake + - gyvgslw ^openmpi@5.0.5%gcc@12.3.0~atomics~cuda~debug~gpfs~internal-hwloc~internal-libevent~internal-pmix~java~lustre~memchecker~openshmem~romio+rsh~static+vt+wrapper-rpath build_system=autotools fabrics=none romio-filesystem=none schedulers=none arch=linux-ubuntu22.04-skylake +[e] s4xelvy ^autoconf@2.71%gcc@12.3.0 build_system=autotools arch=linux-ubuntu22.04-skylake +[e] 3shmde2 ^automake@1.16.5%gcc@12.3.0 build_system=autotools arch=linux-ubuntu22.04-skylake +[e] qjwrtgr ^hwloc@2.10.0%gcc@12.3.0~cairo~cuda~gl~libudev+libxml2~nvml~oneapi-level-zero~opencl+pci~rocm build_system=autotools libs=shared,static arch=linux-ubuntu22.04-skylake + - 73jyhsb ^libevent@2.1.12%gcc@12.3.0+openssl build_system=autotools arch=linux-ubuntu22.04-skylake +[e] v2nk7ea ^openssl@3.0.2%gcc@12.3.0~docs+shared build_system=generic certs=mozilla arch=linux-ubuntu22.04-skylake +[e] teurcse ^libtool@2.4.6%gcc@12.3.0 build_system=autotools arch=linux-ubuntu22.04-skylake + - maffne2 ^numactl@2.0.18%gcc@12.3.0 build_system=autotools arch=linux-ubuntu22.04-skylake +[e] 7mc7oea ^openssh@8.9p1%gcc@12.3.0+gssapi build_system=autotools arch=linux-ubuntu22.04-skylake +[e] h2ikxcy ^perl@5.34.0%gcc@12.3.0~cpanm+opcode+open+shared+threads build_system=generic arch=linux-ubuntu22.04-skylake + - 3dzzw34 ^pmix@5.0.3%gcc@12.3.0~munge~python~restful build_system=autotools arch=linux-ubuntu22.04-skylake + - njvbvvp ^parmetis@4.0.3%gcc@12.3.0~gdb~int64~ipo~shared build_system=cmake build_type=Release generator=make patches=4f89253,50ed208,704b84f arch=linux-ubuntu22.04-skylake + - hb3kxxh ^petsc@3.21.5%gcc@12.3.0~X~batch~cgns~complex~cuda~debug+double~exodusii~fftw+fortran~giflib~hdf5~hpddm~hwloc+hypre~int64~jpeg~knl~kokkos~libpng~libyaml~memkind+metis~mkl-pardiso~mmg~moab~mpfr+mpi~mumps+openmp~p4est~parmmg~ptscotch~random123~rocm~saws~scalapack~shared+strumpack~suite-sparse+superlu-dist~sycl~tetgen~trilinos~valgrind~zoltan build_system=generic clanguage=C memalign=none arch=linux-ubuntu22.04-skylake +[e] 5amzlzl ^diffutils@3.8%gcc@12.3.0 build_system=autotools arch=linux-ubuntu22.04-skylake + - feus7pk ^netlib-scalapack@2.2.0%gcc@12.3.0~ipo~pic+shared build_system=cmake build_type=Release generator=make patches=072b006,1c9ce5f,244a9aa arch=linux-ubuntu22.04-skylake + - 5pwfb3y ^raja@2024.02.0%gcc@12.3.0~cuda~desul~examples~exercises~ipo~omptask+openmp~rocm~run-all-tests~shared~tests+vectorization build_system=cmake build_type=Release generator=make arch=linux-ubuntu22.04-skylake + - hzaovye ^slepc@3.21.0%gcc@12.3.0+arpack~blopex~cuda~hpddm~rocm build_system=generic arch=linux-ubuntu22.04-skylake + - fq3up2e ^arpack-ng@3.9.0%gcc@12.3.0~icb~ipo+mpi+shared build_system=cmake build_type=Release generator=make arch=linux-ubuntu22.04-skylake + - 6rmybu6 ^strumpack@7.2.0%gcc@12.3.0~butterflypack+c_interface~count_flops~cuda~ipo~magma+mpi+openmp+parmetis~rocm~scotch~shared~slate~task_timers~zfp build_system=cmake build_type=Release generator=make arch=linux-ubuntu22.04-skylake + - t4m7tfi ^sundials@6.7.0%gcc@12.3.0+ARKODE+CVODE+CVODES+IDA+IDAS+KINSOL~asan~cuda~examples~examples-install~f2003~fcmix+generic-math~ginkgo+hypre~int64~ipo~klu~kokkos~kokkos-kernels~lapack~magma~monitoring+mpi~openmp~petsc~profiling~pthread~raja~rocm~shared+static~superlu-dist~superlu-mt~sycl~trilinos build_system=cmake build_type=Release cstd=99 cxxstd=14 generator=make logging-level=2 logging-mpi=OFF precision=double arch=linux-ubuntu22.04-skylake + - 2glyola ^superlu-dist@8.1.2%gcc@12.3.0~cuda~int64~ipo~openmp+parmetis~rocm~shared build_system=cmake build_type=Release generator=make arch=linux-ubuntu22.04-skylake + - 5rbkklt ^tribol@0.1.0.16%gcc@12.3.0~cuda~devtools~examples~fortran~ipo~raja+redecomp~rocm~tests~umpire build_system=cmake build_type=Release generator=make arch=linux-ubuntu22.04-skylake + - zapeqzp ^umpire@2024.02.0%gcc@12.3.0~asan~backtrace+c~cuda~dev_benchmarks~device_alloc~deviceconst~examples~fortran~ipc_shmem~ipo~mpi~numa+openmp~openmp_target~rocm~sanitizer_tests~shared~sqlite_experimental~tools+werror build_system=cmake build_type=Release generator=make tests=none arch=linux-ubuntu22.04-skylake + - i4xqurx ^fmt@10.2.1%gcc@12.3.0~ipo+pic~shared build_system=cmake build_type=Release cxxstd=11 generator=make arch=linux-ubuntu22.04-skylake + +[spack version: 0.23.0.dev0 (cfee88a5bb56a1c8ec892879e04cb6a17c4f9404) +] +[exe: /home/sam/code/serac_libs_dec_24/spack/bin/spack -D /home/sam/code/serac_libs_dec_24/spack_env spec --fresh --install-status --very-long] +==> Warning: Spack supports only clingo as a concretizer from v0.23. The config:concretizer config option is ignored. + - l77xejhejbbfmh5b4vqtxxw3paidppuo serac@develop%gcc@12.3.0~asan~cuda~devtools~ipo+openmp+petsc+profiling+raja~rocm~shared+slepc+strumpack+sundials+tribol+umpire build_system=cmake build_type=Release dev_path=/home/sam/code/serac generator=make arch=linux-ubuntu22.04-skylake + - kgt73cvn75plcq5fuk2cvxulzm4izttf ^adiak@0.4.0%gcc@12.3.0~ipo+mpi~shared build_system=cmake build_type=Release generator=make arch=linux-ubuntu22.04-skylake + - crlt4idlryebgcrsch46aoakm55a7jnf ^axom@0.9.0.1%gcc@12.3.0+cpp14~cuda~devtools~examples~fortran+hdf5~ipo+lua+mfem+mpi+openmp~python+raja~rocm~scr~shared~tools+umpire build_system=cmake build_type=Release generator=make arch=linux-ubuntu22.04-skylake + - 2oxa6mfgyufajnx7lccymostfdcgq3lp ^blt@0.6.2%gcc@12.3.0 build_system=generic arch=linux-ubuntu22.04-skylake + - julim3sed75ysjjl4xi2wqn2oui3gogn ^caliper@2.10.0%gcc@12.3.0+adiak~cuda~fortran+gotcha~ipo+kokkos+libdw~libpfm+libunwind+mpi~papi~rocm+sampler~shared~sosflow~tests~variorum build_system=cmake build_type=Release generator=make arch=linux-ubuntu22.04-skylake + - vtbtqmzvsgyoup5klhaeea2olssag5xo ^elfutils@0.191%gcc@12.3.0~debuginfod+exeprefix+nls build_system=autotools arch=linux-ubuntu22.04-skylake +[e] aac2civ6ci2uby6upmaa3m7sgmtvdbpg ^bzip2@1.0.8%gcc@12.3.0~debug~pic+shared build_system=generic arch=linux-ubuntu22.04-skylake +[e] vjtarjvd6hsfitnohpniv6hlw4or46rv ^gettext@0.21%gcc@12.3.0+bzip2+curses+git~libunistring+libxml2+pic+shared+tar+xz build_system=autotools arch=linux-ubuntu22.04-skylake + - yurditifflzptvup5hj7ytoaswco6aav ^libiconv@1.17%gcc@12.3.0 build_system=autotools libs=shared,static arch=linux-ubuntu22.04-skylake +[e] d5ozks2k43ljdiex2skxldizlcndlg6j ^m4@1.4.18%gcc@12.3.0+sigsegv build_system=autotools patches=3877ab5,fc9b616 arch=linux-ubuntu22.04-skylake +[e] oa6rfveivxlvxemjhxf3yoqfdvgz4ugi ^xz@5.2.5%gcc@12.3.0~pic build_system=autotools libs=shared,static arch=linux-ubuntu22.04-skylake + - dwvdelj5psbmp2y3rv4n7q7myybsagtv ^zstd@1.5.6%gcc@12.3.0~programs build_system=makefile libs=shared,static arch=linux-ubuntu22.04-skylake + - 6otmcgjqj3ksscic4ffhigbltvhdbwx3 ^libunwind@1.6.2%gcc@12.3.0~block_signals~conservative_checks~cxx_exceptions~debug~debug_frame+docs~pic+tests+weak_backtrace~xz~zlib build_system=autotools components=none libs=shared,static arch=linux-ubuntu22.04-skylake +[e] vrnm5c2htjzjygd2llzllhsf6qeocpl3 ^python@3.10.14%gcc@12.3.0+bz2+crypt+ctypes+dbm~debug+libxml2+lzma+nis~optimizations+pic+pyexpat~pythoncmd+readline+shared+sqlite3+ssl+tix+tkinter+uuid+zlib build_system=generic patches=0d98e93,ebdca64,f2fd060 arch=linux-ubuntu22.04-skylake + - v5g75d763xm5z5ohoqyp77effjwc6saz ^camp@2024.02.0%gcc@12.3.0~cuda~ipo+openmp~rocm~tests build_system=cmake build_type=Release generator=make arch=linux-ubuntu22.04-skylake +[e] yl7xufqmnkpmkpesokspgtdl2ra22qem ^cmake@3.28.3%gcc@12.3.0~doc+ncurses+ownlibs build_system=generic build_type=Release patches=dbc3892 arch=linux-ubuntu22.04-skylake + - 7ymuqal4duighrautwywbotvwk4kbcub ^conduit@0.9.2%gcc@12.3.0~adios+blt_find_mpi~caliper~doc~doxygen+examples~fortran+hdf5+hdf5_compat~ipo+mpi+parmetis~python+shared~silo~test+utilities~zfp build_system=cmake build_type=Release generator=make arch=linux-ubuntu22.04-skylake + - qupzzv7mylo3ksncvjw7preg334dwn6g ^gcc-runtime@12.3.0%gcc@12.3.0 build_system=generic arch=linux-ubuntu22.04-skylake +[e] d4i5knfmnmcjw3kbim4levymdzvsw6k6 ^glibc@2.35%gcc@12.3.0 build_system=autotools arch=linux-ubuntu22.04-skylake +[e] nizar4hq6pq6uhwx2na42tzq3rsilzgc ^gmake@4.3%gcc@12.3.0~guile build_system=generic patches=599f134 arch=linux-ubuntu22.04-skylake + - gpzjvgu5li5br7sy2f2otmenx3cr54oy ^hdf5@1.8.23%gcc@12.3.0~cxx~fortran+hl~ipo~mpi~shared~szip~threadsafe+tools api=default build_system=cmake build_type=Release generator=make arch=linux-ubuntu22.04-skylake + - yerv6onx7zaznqoipailrhm5wjj2goa2 ^pkgconf@2.2.0%gcc@12.3.0 build_system=autotools arch=linux-ubuntu22.04-skylake + - 46skka27gwzx4san5zkrunivcm7nz564 ^zlib-ng@2.2.1%gcc@12.3.0+compat+new_strategies+opt+pic+shared build_system=autotools arch=linux-ubuntu22.04-skylake + - kwxuezssmhwryylzr744fx3c5dnf6mn2 ^hypre@2.26.0%gcc@12.3.0~caliper~complex~cublas~cuda~debug+fortran~gptune~gpu-aware-mpi~int64~internal-superlu~magma~mixedint+mpi~openmp~rocblas~rocm~shared~superlu-dist~sycl~umpire~unified-memory build_system=autotools precision=double arch=linux-ubuntu22.04-skylake + - haeuwrx5wsiflbxtqpust2bgmpf2gnpl ^openblas@0.3.27%gcc@12.3.0~bignuma~consistent_fpcsr+dynamic_dispatch+fortran~ilp64+locking+pic+shared build_system=makefile symbol_suffix=none threads=openmp arch=linux-ubuntu22.04-skylake + - 4gqzkxqcx7g2nmoru6ks4awyyvkdsfwz ^lua@5.4.6%gcc@12.3.0~pcfile+shared build_system=makefile fetcher=curl arch=linux-ubuntu22.04-skylake +[e] dkdfsjqgkymgsvoxzvmisjmqccerwrzh ^curl@7.81.0%gcc@12.3.0+gssapi+ldap~libidn2~librtmp~libssh~libssh2+nghttp2 build_system=autotools libs=shared,static tls=openssl arch=linux-ubuntu22.04-skylake +[e] s6wsuojbpehnjguu5b2bruh2po4ckvhq ^ncurses@6.3.20211021%gcc@12.3.0+symlinks+termlib abi=6 build_system=autotools patches=7a351bc arch=linux-ubuntu22.04-skylake + - qyfndow76bgnuknlhqya72ipad7f3vh5 ^readline@8.2%gcc@12.3.0 build_system=autotools patches=bbf97f1 arch=linux-ubuntu22.04-skylake + - shglynoblvdrnsjdpcrqn6os3p4wrofa ^unzip@6.0%gcc@12.3.0 build_system=makefile patches=881d2ed,f6f6236 arch=linux-ubuntu22.04-skylake + - 2g2acji3wh53ez3bmun3glc7h3gqxtg3 ^metis@5.1.0%gcc@12.3.0~gdb~int64~ipo~real64~shared build_system=cmake build_type=Release generator=make patches=4991da9,93a7903,b1225da arch=linux-ubuntu22.04-skylake + - hg6gqwaz5i5qibpbj7f6qzq4gbf4az6i ^mfem@4.7.0.1%gcc@12.3.0~amgx~asan~conduit~cuda~debug~examples~exceptions~fms~ginkgo~gnutls~gslib~hiop+lapack~libceed~libunwind+metis~miniapps~mpfr+mpi~mumps+netcdf~occa+openmp+petsc~pumi~raja~rocm~shared+slepc+static+strumpack~suite-sparse+sundials+superlu-dist~threadsafe~umpire+zlib build_system=generic cxxstd=auto patches=937da2a precision=double timer=auto arch=linux-ubuntu22.04-skylake + - o4h3fi5jvtfrikv5zvt47mw7tiut4vk6 ^netcdf-c@4.7.4%gcc@12.3.0~blosc~byterange~dap~fsync~hdf4~jna~logging~mpi~nczarr_zip+optimize~parallel-netcdf+pic~shared~szip~zstd build_system=autotools arch=linux-ubuntu22.04-skylake + - gyvgslwg3a74emc456byyqhdcvrf3c7e ^openmpi@5.0.5%gcc@12.3.0~atomics~cuda~debug~gpfs~internal-hwloc~internal-libevent~internal-pmix~java~lustre~memchecker~openshmem~romio+rsh~static+vt+wrapper-rpath build_system=autotools fabrics=none romio-filesystem=none schedulers=none arch=linux-ubuntu22.04-skylake +[e] s4xelvym5xghrbblsn5d64j4q5cbzdvn ^autoconf@2.71%gcc@12.3.0 build_system=autotools arch=linux-ubuntu22.04-skylake +[e] 3shmde2nyksetqfqvugxj3gnopbuysd2 ^automake@1.16.5%gcc@12.3.0 build_system=autotools arch=linux-ubuntu22.04-skylake +[e] qjwrtgr5fanycnfnhvad7y3ovpsrc227 ^hwloc@2.10.0%gcc@12.3.0~cairo~cuda~gl~libudev+libxml2~nvml~oneapi-level-zero~opencl+pci~rocm build_system=autotools libs=shared,static arch=linux-ubuntu22.04-skylake + - 73jyhsbj4rgjg4mf4ydazdyn6d73dgoe ^libevent@2.1.12%gcc@12.3.0+openssl build_system=autotools arch=linux-ubuntu22.04-skylake +[e] v2nk7eanai3jquaxrh323plahs74dhmh ^openssl@3.0.2%gcc@12.3.0~docs+shared build_system=generic certs=mozilla arch=linux-ubuntu22.04-skylake +[e] teurcseg4faxdpkasgwv7wgmv5xkq5rx ^libtool@2.4.6%gcc@12.3.0 build_system=autotools arch=linux-ubuntu22.04-skylake + - maffne2uu3zxmwkvsojcdm53nrnpamdg ^numactl@2.0.18%gcc@12.3.0 build_system=autotools arch=linux-ubuntu22.04-skylake +[e] 7mc7oeaeksdrivorvckleagevraiq3y7 ^openssh@8.9p1%gcc@12.3.0+gssapi build_system=autotools arch=linux-ubuntu22.04-skylake +[e] h2ikxcyjhik64arwme2ca2ky2ftauoei ^perl@5.34.0%gcc@12.3.0~cpanm+opcode+open+shared+threads build_system=generic arch=linux-ubuntu22.04-skylake + - 3dzzw34om3f3egm2mvq2euhc57zsu6py ^pmix@5.0.3%gcc@12.3.0~munge~python~restful build_system=autotools arch=linux-ubuntu22.04-skylake + - njvbvvpjyx2hjvel7asmtlpugntv66lt ^parmetis@4.0.3%gcc@12.3.0~gdb~int64~ipo~shared build_system=cmake build_type=Release generator=make patches=4f89253,50ed208,704b84f arch=linux-ubuntu22.04-skylake + - hb3kxxheevzh3emk6qc6s346zmxnevj5 ^petsc@3.21.5%gcc@12.3.0~X~batch~cgns~complex~cuda~debug+double~exodusii~fftw+fortran~giflib~hdf5~hpddm~hwloc+hypre~int64~jpeg~knl~kokkos~libpng~libyaml~memkind+metis~mkl-pardiso~mmg~moab~mpfr+mpi~mumps+openmp~p4est~parmmg~ptscotch~random123~rocm~saws~scalapack~shared+strumpack~suite-sparse+superlu-dist~sycl~tetgen~trilinos~valgrind~zoltan build_system=generic clanguage=C memalign=none arch=linux-ubuntu22.04-skylake +[e] 5amzlzl3eeav4k4jmnesz7keno6xhfwf ^diffutils@3.8%gcc@12.3.0 build_system=autotools arch=linux-ubuntu22.04-skylake + - feus7pkj7yhgvqrrf635dcj6id4gpe46 ^netlib-scalapack@2.2.0%gcc@12.3.0~ipo~pic+shared build_system=cmake build_type=Release generator=make patches=072b006,1c9ce5f,244a9aa arch=linux-ubuntu22.04-skylake + - 5pwfb3yr4p575lhqtzhhvywvsghkdbfc ^raja@2024.02.0%gcc@12.3.0~cuda~desul~examples~exercises~ipo~omptask+openmp~rocm~run-all-tests~shared~tests+vectorization build_system=cmake build_type=Release generator=make arch=linux-ubuntu22.04-skylake + - hzaovye7lucyxctskz3arfluk6q75v7g ^slepc@3.21.0%gcc@12.3.0+arpack~blopex~cuda~hpddm~rocm build_system=generic arch=linux-ubuntu22.04-skylake + - fq3up2e27wezbrye23mrhb7hc6ktbxha ^arpack-ng@3.9.0%gcc@12.3.0~icb~ipo+mpi+shared build_system=cmake build_type=Release generator=make arch=linux-ubuntu22.04-skylake + - 6rmybu6moclr62zaoqs26m2sj4gvl4ru ^strumpack@7.2.0%gcc@12.3.0~butterflypack+c_interface~count_flops~cuda~ipo~magma+mpi+openmp+parmetis~rocm~scotch~shared~slate~task_timers~zfp build_system=cmake build_type=Release generator=make arch=linux-ubuntu22.04-skylake + - t4m7tfitf4lv7ebf5uax4mg7jqovgv4c ^sundials@6.7.0%gcc@12.3.0+ARKODE+CVODE+CVODES+IDA+IDAS+KINSOL~asan~cuda~examples~examples-install~f2003~fcmix+generic-math~ginkgo+hypre~int64~ipo~klu~kokkos~kokkos-kernels~lapack~magma~monitoring+mpi~openmp~petsc~profiling~pthread~raja~rocm~shared+static~superlu-dist~superlu-mt~sycl~trilinos build_system=cmake build_type=Release cstd=99 cxxstd=14 generator=make logging-level=2 logging-mpi=OFF precision=double arch=linux-ubuntu22.04-skylake + - 2glyola75o2amhmctein5g2oipuynvk4 ^superlu-dist@8.1.2%gcc@12.3.0~cuda~int64~ipo~openmp+parmetis~rocm~shared build_system=cmake build_type=Release generator=make arch=linux-ubuntu22.04-skylake + - 5rbkkltig563suvbqo4qstu7djugw5dd ^tribol@0.1.0.16%gcc@12.3.0~cuda~devtools~examples~fortran~ipo~raja+redecomp~rocm~tests~umpire build_system=cmake build_type=Release generator=make arch=linux-ubuntu22.04-skylake + - zapeqzpd4ambdf6nzl5r7micjyabnmta ^umpire@2024.02.0%gcc@12.3.0~asan~backtrace+c~cuda~dev_benchmarks~device_alloc~deviceconst~examples~fortran~ipc_shmem~ipo~mpi~numa+openmp~openmp_target~rocm~sanitizer_tests~shared~sqlite_experimental~tools+werror build_system=cmake build_type=Release generator=make tests=none arch=linux-ubuntu22.04-skylake + - i4xqurx3ohsd4qgoohzq4xvarh3bs43a ^fmt@10.2.1%gcc@12.3.0~ipo+pic~shared build_system=cmake build_type=Release cxxstd=11 generator=make arch=linux-ubuntu22.04-skylake + + +[exe: /home/sam/code/serac_libs_dec_24/spack/bin/spack -D /home/sam/code/serac_libs_dec_24/spack_env install --fresh --keep-stage -u initconfig ] +==> Warning: Spack supports only clingo as a concretizer from v0.23. The config:concretizer config option is ignored. +[+] /home/sam/.local (external cmake-3.28.3-yl7xufqmnkpmkpesokspgtdl2ra22qem) +[+] /usr (external glibc-2.35-d4i5knfmnmcjw3kbim4levymdzvsw6k6) +[+] /usr (external gmake-4.3-nizar4hq6pq6uhwx2na42tzq3rsilzgc) +[+] /usr (external autoconf-2.71-s4xelvym5xghrbblsn5d64j4q5cbzdvn) +[+] /usr (external automake-1.16.5-3shmde2nyksetqfqvugxj3gnopbuysd2) +[+] /usr (external hwloc-2.10.0-qjwrtgr5fanycnfnhvad7y3ovpsrc227) +[+] /usr (external openssl-3.0.2-v2nk7eanai3jquaxrh323plahs74dhmh) +[+] /usr (external libtool-2.4.6-teurcseg4faxdpkasgwv7wgmv5xkq5rx) +[+] /usr (external m4-1.4.18-d5ozks2k43ljdiex2skxldizlcndlg6j) +[+] /usr (external openssh-8.9p1-7mc7oeaeksdrivorvckleagevraiq3y7) +[+] /usr (external perl-5.34.0-h2ikxcyjhik64arwme2ca2ky2ftauoei) +[+] /usr (external curl-7.81.0-dkdfsjqgkymgsvoxzvmisjmqccerwrzh) +[+] /usr (external ncurses-6.3.20211021-s6wsuojbpehnjguu5b2bruh2po4ckvhq) +[+] /usr (external diffutils-3.8-5amzlzl3eeav4k4jmnesz7keno6xhfwf) +[+] /usr (external python-3.10.14-vrnm5c2htjzjygd2llzllhsf6qeocpl3) +[+] /usr (external bzip2-1.0.8-aac2civ6ci2uby6upmaa3m7sgmtvdbpg) +[+] /usr (external gettext-0.21-vjtarjvd6hsfitnohpniv6hlw4or46rv) +[+] /usr (external xz-5.2.5-oa6rfveivxlvxemjhxf3yoqfdvgz4ugi) +==> Installing gcc-runtime-12.3.0-qupzzv7mylo3ksncvjw7preg334dwn6g [19/57] +==> No binary for gcc-runtime-12.3.0-qupzzv7mylo3ksncvjw7preg334dwn6g found: installing from source +==> No patches needed for gcc-runtime +==> gcc-runtime: Executing phase: 'install' +==> gcc-runtime: Successfully installed gcc-runtime-12.3.0-qupzzv7mylo3ksncvjw7preg334dwn6g + Stage: 0.00s. Install: 0.09s. Post-install: 0.02s. Total: 0.12s +[+] /home/sam/code/serac_libs_dec_24/spack/opt/spack/linux-ubuntu22.04-skylake/gcc-12.3.0/gcc-runtime-12.3.0-qupzzv7mylo3ksncvjw7preg334dwn6g +==> Installing zstd-1.5.6-dwvdelj5psbmp2y3rv4n7q7myybsagtv [20/57] +==> No binary for zstd-1.5.6-dwvdelj5psbmp2y3rv4n7q7myybsagtv found: installing from source +==> Fetching https://mirror.spack.io/_source-cache/archive/30/30f35f71c1203369dc979ecde0400ffea93c27391bfd2ac5a9715d2173d92ff7.tar.gz +==> No patches needed for zstd +==> zstd: Executing phase: 'edit' +==> zstd: Executing phase: 'build' +==> zstd: Executing phase: 'install' +==> zstd: Successfully installed zstd-1.5.6-dwvdelj5psbmp2y3rv4n7q7myybsagtv + Stage: 0.18s. Edit: 0.00s. Build: 0.00s. Install: 5.48s. Post-install: 0.01s. Total: 5.70s +[+] /home/sam/code/serac_libs_dec_24/spack/opt/spack/linux-ubuntu22.04-skylake/gcc-12.3.0/zstd-1.5.6-dwvdelj5psbmp2y3rv4n7q7myybsagtv +==> Installing libiconv-1.17-yurditifflzptvup5hj7ytoaswco6aav [21/57] +==> No binary for libiconv-1.17-yurditifflzptvup5hj7ytoaswco6aav found: installing from source +==> Fetching https://mirror.spack.io/_source-cache/archive/8f/8f74213b56238c85a50a5329f77e06198771e70dd9a739779f4c02f65d971313.tar.gz +==> No patches needed for libiconv +==> libiconv: Executing phase: 'autoreconf' +==> libiconv: Executing phase: 'configure' +==> libiconv: Executing phase: 'build' +==> libiconv: Executing phase: 'install' +==> libiconv: Successfully installed libiconv-1.17-yurditifflzptvup5hj7ytoaswco6aav + Stage: 0.24s. Autoreconf: 0.00s. Configure: 17.99s. Build: 5.75s. Install: 1.54s. Post-install: 0.02s. Total: 25.61s +[+] /home/sam/code/serac_libs_dec_24/spack/opt/spack/linux-ubuntu22.04-skylake/gcc-12.3.0/libiconv-1.17-yurditifflzptvup5hj7ytoaswco6aav +==> Installing libunwind-1.6.2-6otmcgjqj3ksscic4ffhigbltvhdbwx3 [22/57] +==> No binary for libunwind-1.6.2-6otmcgjqj3ksscic4ffhigbltvhdbwx3 found: installing from source +==> Fetching https://mirror.spack.io/_source-cache/archive/4a/4a6aec666991fb45d0889c44aede8ad6eb108071c3554fcdff671f9c94794976.tar.gz +==> No patches needed for libunwind +==> libunwind: Executing phase: 'autoreconf' +==> libunwind: Executing phase: 'configure' +==> libunwind: Executing phase: 'build' +==> libunwind: Executing phase: 'install' +==> libunwind: Successfully installed libunwind-1.6.2-6otmcgjqj3ksscic4ffhigbltvhdbwx3 + Stage: 0.39s. Autoreconf: 0.00s. Configure: 15.95s. Build: 2.44s. Install: 0.81s. Post-install: 0.01s. Total: 19.68s +[+] /home/sam/code/serac_libs_dec_24/spack/opt/spack/linux-ubuntu22.04-skylake/gcc-12.3.0/libunwind-1.6.2-6otmcgjqj3ksscic4ffhigbltvhdbwx3 +==> Installing libevent-2.1.12-73jyhsbj4rgjg4mf4ydazdyn6d73dgoe [23/57] +==> No binary for libevent-2.1.12-73jyhsbj4rgjg4mf4ydazdyn6d73dgoe found: installing from source +==> Fetching https://mirror.spack.io/_source-cache/archive/92/92e6de1be9ec176428fd2367677e61ceffc2ee1cb119035037a27d346b0403bb.tar.gz +==> Ran patch() for libevent +==> libevent: Executing phase: 'autoreconf' +==> libevent: Executing phase: 'configure' +==> libevent: Executing phase: 'build' +==> libevent: Executing phase: 'install' +==> libevent: Successfully installed libevent-2.1.12-73jyhsbj4rgjg4mf4ydazdyn6d73dgoe + Stage: 0.13s. Autoreconf: 0.00s. Configure: 15.42s. Build: 2.14s. Install: 0.66s. Post-install: 0.02s. Total: 18.42s +[+] /home/sam/code/serac_libs_dec_24/spack/opt/spack/linux-ubuntu22.04-skylake/gcc-12.3.0/libevent-2.1.12-73jyhsbj4rgjg4mf4ydazdyn6d73dgoe +==> Installing readline-8.2-qyfndow76bgnuknlhqya72ipad7f3vh5 [24/57] +==> No binary for readline-8.2-qyfndow76bgnuknlhqya72ipad7f3vh5 found: installing from source +==> Fetching https://mirror.spack.io/_source-cache/archive/3f/3feb7171f16a84ee82ca18a36d7b9be109a52c04f492a053331d7d1095007c35.tar.gz +==> Fetching https://mirror.spack.io/_source-cache/archive/bb/bbf97f1ec40a929edab5aa81998c1e2ef435436c597754916e6a5868f273aff7 +==> Applied patch https://ftpmirror.gnu.org/readline/readline-8.2-patches/readline82-001 +==> readline: Executing phase: 'autoreconf' +==> readline: Executing phase: 'configure' +==> readline: Executing phase: 'build' +==> readline: Executing phase: 'install' +==> readline: Successfully installed readline-8.2-qyfndow76bgnuknlhqya72ipad7f3vh5 + Stage: 0.23s. Autoreconf: 0.00s. Configure: 7.10s. Build: 1.66s. Install: 0.22s. Post-install: 0.01s. Total: 9.26s +[+] /home/sam/code/serac_libs_dec_24/spack/opt/spack/linux-ubuntu22.04-skylake/gcc-12.3.0/readline-8.2-qyfndow76bgnuknlhqya72ipad7f3vh5 +==> Installing zlib-ng-2.2.1-46skka27gwzx4san5zkrunivcm7nz564 [25/57] +==> No binary for zlib-ng-2.2.1-46skka27gwzx4san5zkrunivcm7nz564 found: installing from source +==> Fetching https://mirror.spack.io/_source-cache/archive/ec/ec6a76169d4214e2e8b737e0850ba4acb806c69eeace6240ed4481b9f5c57cdf.tar.gz +==> No patches needed for zlib-ng +==> zlib-ng: Executing phase: 'autoreconf' +==> zlib-ng: Executing phase: 'configure' +==> zlib-ng: Executing phase: 'build' +==> zlib-ng: Executing phase: 'install' +==> zlib-ng: Successfully installed zlib-ng-2.2.1-46skka27gwzx4san5zkrunivcm7nz564 + Stage: 0.15s. Autoreconf: 0.00s. Configure: 4.63s. Build: 0.86s. Install: 0.09s. Post-install: 0.00s. Total: 5.77s +[+] /home/sam/code/serac_libs_dec_24/spack/opt/spack/linux-ubuntu22.04-skylake/gcc-12.3.0/zlib-ng-2.2.1-46skka27gwzx4san5zkrunivcm7nz564 +==> Installing unzip-6.0-shglynoblvdrnsjdpcrqn6os3p4wrofa [26/57] +==> No binary for unzip-6.0-shglynoblvdrnsjdpcrqn6os3p4wrofa found: installing from source +==> Fetching https://mirror.spack.io/_source-cache/archive/03/036d96991646d0449ed0aa952e4fbe21b476ce994abc276e49d30e686708bd37.tar.gz +==> Applied patch /home/sam/code/serac_libs_dec_24/spack/var/spack/repos/builtin/packages/unzip/configure-cflags.patch +==> Applied patch /home/sam/code/serac_libs_dec_24/spack/var/spack/repos/builtin/packages/unzip/strip.patch +==> unzip: Executing phase: 'edit' +==> unzip: Executing phase: 'build' +==> unzip: Executing phase: 'install' +==> unzip: Successfully installed unzip-6.0-shglynoblvdrnsjdpcrqn6os3p4wrofa + Stage: 0.17s. Edit: 0.00s. Build: 1.59s. Install: 0.03s. Post-install: 0.01s. Total: 1.83s +[+] /home/sam/code/serac_libs_dec_24/spack/opt/spack/linux-ubuntu22.04-skylake/gcc-12.3.0/unzip-6.0-shglynoblvdrnsjdpcrqn6os3p4wrofa +==> Installing blt-0.6.2-2oxa6mfgyufajnx7lccymostfdcgq3lp [27/57] +==> No binary for blt-0.6.2-2oxa6mfgyufajnx7lccymostfdcgq3lp found: installing from source +==> Fetching https://mirror.spack.io/_source-cache/archive/84/84b663162957c1fe0e896ac8e94cbf2b6def4a152ccfa12a293db14fb25191c8.tar.gz +==> No patches needed for blt +==> blt: Executing phase: 'install' +==> blt: Successfully installed blt-0.6.2-2oxa6mfgyufajnx7lccymostfdcgq3lp + Stage: 0.16s. Install: 0.03s. Post-install: 0.06s. Total: 0.27s +[+] /home/sam/code/serac_libs_dec_24/spack/opt/spack/linux-ubuntu22.04-skylake/gcc-12.3.0/blt-0.6.2-2oxa6mfgyufajnx7lccymostfdcgq3lp +==> Installing pkgconf-2.2.0-yerv6onx7zaznqoipailrhm5wjj2goa2 [28/57] +==> No binary for pkgconf-2.2.0-yerv6onx7zaznqoipailrhm5wjj2goa2 found: installing from source +==> Fetching https://mirror.spack.io/_source-cache/archive/b0/b06ff63a83536aa8c2f6422fa80ad45e4833f590266feb14eaddfe1d4c853c69.tar.xz +==> No patches needed for pkgconf +==> pkgconf: Executing phase: 'autoreconf' +==> pkgconf: Executing phase: 'configure' +==> pkgconf: Executing phase: 'build' +==> pkgconf: Executing phase: 'install' +==> pkgconf: Successfully installed pkgconf-2.2.0-yerv6onx7zaznqoipailrhm5wjj2goa2 + Stage: 0.14s. Autoreconf: 0.00s. Configure: 4.86s. Build: 0.92s. Install: 0.40s. Post-install: 0.01s. Total: 6.37s +[+] /home/sam/code/serac_libs_dec_24/spack/opt/spack/linux-ubuntu22.04-skylake/gcc-12.3.0/pkgconf-2.2.0-yerv6onx7zaznqoipailrhm5wjj2goa2 +==> Installing openblas-0.3.27-haeuwrx5wsiflbxtqpust2bgmpf2gnpl [29/57] +==> No binary for openblas-0.3.27-haeuwrx5wsiflbxtqpust2bgmpf2gnpl found: installing from source +==> Fetching https://mirror.spack.io/_source-cache/archive/aa/aa2d68b1564fe2b13bc292672608e9cdeeeb6dc34995512e65c3b10f4599e897.tar.gz +==> No patches needed for openblas +==> openblas: Executing phase: 'edit' +==> openblas: Executing phase: 'build' +==> openblas: Executing phase: 'install' +==> openblas: Successfully installed openblas-0.3.27-haeuwrx5wsiflbxtqpust2bgmpf2gnpl + Stage: 0.83s. Edit: 0.00s. Build: 2m 37.46s. Install: 3.23s. Post-install: 0.04s. Total: 2m 41.83s +[+] /home/sam/code/serac_libs_dec_24/spack/opt/spack/linux-ubuntu22.04-skylake/gcc-12.3.0/openblas-0.3.27-haeuwrx5wsiflbxtqpust2bgmpf2gnpl +==> Installing numactl-2.0.18-maffne2uu3zxmwkvsojcdm53nrnpamdg [30/57] +==> No binary for numactl-2.0.18-maffne2uu3zxmwkvsojcdm53nrnpamdg found: installing from source +==> Fetching https://mirror.spack.io/_source-cache/archive/8c/8cd6c13f3096e9c2293c1d732f56e2aa37a7ada1a98deed3fac7bd6da1aaaaf6.tar.gz +==> No patches needed for numactl +==> numactl: Executing phase: 'autoreconf' +==> numactl: Executing phase: 'configure' +==> numactl: Executing phase: 'build' +==> numactl: Executing phase: 'install' +==> numactl: Successfully installed numactl-2.0.18-maffne2uu3zxmwkvsojcdm53nrnpamdg + Stage: 0.12s. Autoreconf: 3.47s. Configure: 4.66s. Build: 1.02s. Install: 0.39s. Post-install: 0.01s. Total: 9.71s +[+] /home/sam/code/serac_libs_dec_24/spack/opt/spack/linux-ubuntu22.04-skylake/gcc-12.3.0/numactl-2.0.18-maffne2uu3zxmwkvsojcdm53nrnpamdg +==> Installing fmt-10.2.1-i4xqurx3ohsd4qgoohzq4xvarh3bs43a [31/57] +==> No binary for fmt-10.2.1-i4xqurx3ohsd4qgoohzq4xvarh3bs43a found: installing from source +==> Fetching https://mirror.spack.io/_source-cache/archive/31/312151a2d13c8327f5c9c586ac6cf7cddc1658e8f53edae0ec56509c8fa516c9.zip +==> No patches needed for fmt +==> fmt: Executing phase: 'cmake' +==> fmt: Executing phase: 'build' +==> fmt: Executing phase: 'install' +==> fmt: Successfully installed fmt-10.2.1-i4xqurx3ohsd4qgoohzq4xvarh3bs43a + Stage: 0.38s. Cmake: 0.27s. Build: 2.11s. Install: 0.05s. Post-install: 0.01s. Total: 2.85s +[+] /home/sam/code/serac_libs_dec_24/spack/opt/spack/linux-ubuntu22.04-skylake/gcc-12.3.0/fmt-10.2.1-i4xqurx3ohsd4qgoohzq4xvarh3bs43a +==> Installing metis-5.1.0-2g2acji3wh53ez3bmun3glc7h3gqxtg3 [32/57] +==> No binary for metis-5.1.0-2g2acji3wh53ez3bmun3glc7h3gqxtg3 found: installing from source +==> Fetching https://mirror.spack.io/_source-cache/archive/76/76faebe03f6c963127dbb73c13eab58c9a3faeae48779f049066a21c087c5db2.tar.gz +==> Applied patch /home/sam/code/serac_libs_dec_24/spack/var/spack/repos/builtin/packages/metis/gklib_path.patch +==> Applied patch /home/sam/code/serac_libs_dec_24/spack/var/spack/repos/builtin/packages/metis/install_gklib_defs_rename.patch +==> Applied patch /home/sam/code/serac_libs_dec_24/spack/var/spack/repos/builtin/packages/metis/gklib_nomisleadingindentation_warning.patch +==> Ran patch() for metis +==> metis: Executing phase: 'cmake' +==> metis: Executing phase: 'build' +==> metis: Executing phase: 'install' +==> metis: Successfully installed metis-5.1.0-2g2acji3wh53ez3bmun3glc7h3gqxtg3 + Stage: 0.21s. Cmake: 0.92s. Build: 1.03s. Install: 0.12s. Post-install: 0.02s. Total: 2.34s +[+] /home/sam/code/serac_libs_dec_24/spack/opt/spack/linux-ubuntu22.04-skylake/gcc-12.3.0/metis-5.1.0-2g2acji3wh53ez3bmun3glc7h3gqxtg3 +==> Installing lua-5.4.6-4gqzkxqcx7g2nmoru6ks4awyyvkdsfwz [33/57] +==> No binary for lua-5.4.6-4gqzkxqcx7g2nmoru6ks4awyyvkdsfwz found: installing from source +==> Fetching https://mirror.spack.io/_source-cache/archive/7d/7d5ea1b9cb6aa0b59ca3dde1c6adcb57ef83a1ba8e5432c0ecd06bf439b3ad88.tar.gz +==> Fetching https://mirror.spack.io/_source-cache/archive/56/56ab9b90f5acbc42eb7a94cf482e6c058a63e8a1effdf572b8b2a6323a06d923.tar.gz +==> Moving resource stage + source: /tmp/sam/spack-stage/resource-luarocks-4gqzkxqcx7g2nmoru6ks4awyyvkdsfwz/spack-src/ + destination: /tmp/sam/spack-stage/spack-stage-lua-5.4.6-4gqzkxqcx7g2nmoru6ks4awyyvkdsfwz/spack-src/luarocks/luarocks +==> No patches needed for lua +==> lua: Executing phase: 'edit' +==> lua: Executing phase: 'build' +==> lua: Executing phase: 'install' +==> lua: Successfully installed lua-5.4.6-4gqzkxqcx7g2nmoru6ks4awyyvkdsfwz + Stage: 0.23s. Edit: 0.00s. Build: 3.02s. Install: 0.37s. Post-install: 0.02s. Total: 3.67s +[+] /home/sam/code/serac_libs_dec_24/spack/opt/spack/linux-ubuntu22.04-skylake/gcc-12.3.0/lua-5.4.6-4gqzkxqcx7g2nmoru6ks4awyyvkdsfwz +==> Installing camp-2024.02.0-v5g75d763xm5z5ohoqyp77effjwc6saz [34/57] +==> No binary for camp-2024.02.0-v5g75d763xm5z5ohoqyp77effjwc6saz found: installing from source +==> No patches needed for camp +==> camp: Executing phase: 'cmake' +==> camp: Executing phase: 'build' +==> camp: Executing phase: 'install' +==> camp: Successfully installed camp-2024.02.0-v5g75d763xm5z5ohoqyp77effjwc6saz + Stage: 0.75s. Cmake: 0.96s. Build: 0.26s. Install: 0.04s. Post-install: 0.01s. Total: 2.06s +[+] /home/sam/code/serac_libs_dec_24/spack/opt/spack/linux-ubuntu22.04-skylake/gcc-12.3.0/camp-2024.02.0-v5g75d763xm5z5ohoqyp77effjwc6saz +==> Installing pmix-5.0.3-3dzzw34om3f3egm2mvq2euhc57zsu6py [35/57] +==> No binary for pmix-5.0.3-3dzzw34om3f3egm2mvq2euhc57zsu6py found: installing from source +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.lastuseddate#PS' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.lastuseddate#PS' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.lastuseddate#PS' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.creationtime' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.lastuseddate#PS' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.lastuseddate#PS' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.lastuseddate#PS' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.lastuseddate#PS' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemTextContentLanguage' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseVersion' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseLabels' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.metadata:kMDItemKeyphraseConfidences' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +/usr/bin/tar: Ignoring unknown extended header keyword 'LIBARCHIVE.xattr.com.apple.provenance' +==> Fetching https://mirror.spack.io/_source-cache/archive/3f/3f779434ed59fc3d63e4f77f170605ac3a80cd40b1f324112214b0efbdc34f13.tar.bz2 +==> No patches needed for pmix +==> pmix: Executing phase: 'autoreconf' +==> pmix: Executing phase: 'configure' +==> Error: ProcessError: Command exited with status 1: + '/tmp/sam/spack-stage/spack-stage-pmix-5.0.3-3dzzw34om3f3egm2mvq2euhc57zsu6py/spack-src/configure' '--prefix=/home/sam/code/serac_libs_dec_24/spack/opt/spack/linux-ubuntu22.04-skylake/gcc-12.3.0/pmix-5.0.3-3dzzw34om3f3egm2mvq2euhc57zsu6py' '--enable-shared' '--enable-static' '--disable-sphinx' '--with-zlib=/home/sam/code/serac_libs_dec_24/spack/opt/spack/linux-ubuntu22.04-skylake/gcc-12.3.0/zlib-ng-2.2.1-46skka27gwzx4san5zkrunivcm7nz564' '--with-libevent=/home/sam/code/serac_libs_dec_24/spack/opt/spack/linux-ubuntu22.04-skylake/gcc-12.3.0/libevent-2.1.12-73jyhsbj4rgjg4mf4ydazdyn6d73dgoe' '--with-hwloc=/usr' '--with-hwloc-libdir=' '--disable-python-bindings' '--without-munge' + +1 error found in build log: + 450 checking if hwloc pkg-config module exists... no + 451 checking for hwloc header at /usr/include... not found + 452 configure: WARNING: PMIx requires HWLOC topology library support, but + 453 configure: WARNING: an adequate version of that library was not found. + 454 configure: WARNING: Please reconfigure and point to a location where + 455 configure: WARNING: the HWLOC library can be found. + >> 456 configure: error: Cannot continue. + +See build log for details: + /tmp/sam/spack-stage/spack-stage-pmix-5.0.3-3dzzw34om3f3egm2mvq2euhc57zsu6py/spack-build-out.txt + +==> Warning: Skipping build of openmpi-5.0.5-gyvgslwg3a74emc456byyqhdcvrf3c7e since pmix-5.0.3-3dzzw34om3f3egm2mvq2euhc57zsu6py failed +==> Warning: Skipping build of tribol-0.1.0.16-5rbkkltig563suvbqo4qstu7djugw5dd since openmpi-5.0.5-gyvgslwg3a74emc456byyqhdcvrf3c7e failed +==> Warning: Skipping build of serac-develop-l77xejhejbbfmh5b4vqtxxw3paidppuo since tribol-0.1.0.16-5rbkkltig563suvbqo4qstu7djugw5dd failed +==> Warning: Skipping build of axom-0.9.0.1-crlt4idlryebgcrsch46aoakm55a7jnf since openmpi-5.0.5-gyvgslwg3a74emc456byyqhdcvrf3c7e failed +==> Warning: Skipping build of adiak-0.4.0-kgt73cvn75plcq5fuk2cvxulzm4izttf since openmpi-5.0.5-gyvgslwg3a74emc456byyqhdcvrf3c7e failed +==> Warning: Skipping build of caliper-2.10.0-julim3sed75ysjjl4xi2wqn2oui3gogn since adiak-0.4.0-kgt73cvn75plcq5fuk2cvxulzm4izttf failed +==> Warning: Skipping build of netlib-scalapack-2.2.0-feus7pkj7yhgvqrrf635dcj6id4gpe46 since openmpi-5.0.5-gyvgslwg3a74emc456byyqhdcvrf3c7e failed +==> Warning: Skipping build of strumpack-7.2.0-6rmybu6moclr62zaoqs26m2sj4gvl4ru since netlib-scalapack-2.2.0-feus7pkj7yhgvqrrf635dcj6id4gpe46 failed +==> Warning: Skipping build of mfem-4.7.0.1-hg6gqwaz5i5qibpbj7f6qzq4gbf4az6i since strumpack-7.2.0-6rmybu6moclr62zaoqs26m2sj4gvl4ru failed +==> Warning: Skipping build of petsc-3.21.5-hb3kxxheevzh3emk6qc6s346zmxnevj5 since strumpack-7.2.0-6rmybu6moclr62zaoqs26m2sj4gvl4ru failed +==> Warning: Skipping build of slepc-3.21.0-hzaovye7lucyxctskz3arfluk6q75v7g since petsc-3.21.5-hb3kxxheevzh3emk6qc6s346zmxnevj5 failed +==> Warning: Skipping build of superlu-dist-8.1.2-2glyola75o2amhmctein5g2oipuynvk4 since openmpi-5.0.5-gyvgslwg3a74emc456byyqhdcvrf3c7e failed +==> Warning: Skipping build of conduit-0.9.2-7ymuqal4duighrautwywbotvwk4kbcub since openmpi-5.0.5-gyvgslwg3a74emc456byyqhdcvrf3c7e failed +==> Warning: Skipping build of hypre-2.26.0-kwxuezssmhwryylzr744fx3c5dnf6mn2 since openmpi-5.0.5-gyvgslwg3a74emc456byyqhdcvrf3c7e failed +==> Warning: Skipping build of sundials-6.7.0-t4m7tfitf4lv7ebf5uax4mg7jqovgv4c since hypre-2.26.0-kwxuezssmhwryylzr744fx3c5dnf6mn2 failed +==> Warning: Skipping build of parmetis-4.0.3-njvbvvpjyx2hjvel7asmtlpugntv66lt since openmpi-5.0.5-gyvgslwg3a74emc456byyqhdcvrf3c7e failed +==> Warning: Skipping build of arpack-ng-3.9.0-fq3up2e27wezbrye23mrhb7hc6ktbxha since openmpi-5.0.5-gyvgslwg3a74emc456byyqhdcvrf3c7e failed +==> Installing elfutils-0.191-vtbtqmzvsgyoup5klhaeea2olssag5xo [36/57] +==> No binary for elfutils-0.191-vtbtqmzvsgyoup5klhaeea2olssag5xo found: installing from source +==> Fetching https://mirror.spack.io/_source-cache/archive/df/df76db71366d1d708365fc7a6c60ca48398f14367eb2b8954efc8897147ad871.tar.bz2 +==> Ran patch() for elfutils +==> elfutils: Executing phase: 'autoreconf' +==> elfutils: Executing phase: 'configure' +==> Error: ProcessError: Command exited with status 1: + '/tmp/sam/spack-stage/spack-stage-elfutils-0.191-vtbtqmzvsgyoup5klhaeea2olssag5xo/spack-src/configure' '--prefix=/home/sam/code/serac_libs_dec_24/spack/opt/spack/linux-ubuntu22.04-skylake/gcc-12.3.0/elfutils-0.191-vtbtqmzvsgyoup5klhaeea2olssag5xo' '--with-bzlib=/usr' '--with-lzma=/usr' '--with-zlib=/home/sam/code/serac_libs_dec_24/spack/opt/spack/linux-ubuntu22.04-skylake/gcc-12.3.0/zlib-ng-2.2.1-46skka27gwzx4san5zkrunivcm7nz564' '--program-prefix='"'"'eu-'"'"'' '--with-zstd=/home/sam/code/serac_libs_dec_24/spack/opt/spack/linux-ubuntu22.04-skylake/gcc-12.3.0/zstd-1.5.6-dwvdelj5psbmp2y3rv4n7q7myybsagtv' '--with-libiconv-prefix=/home/sam/code/serac_libs_dec_24/spack/opt/spack/linux-ubuntu22.04-skylake/gcc-12.3.0/libiconv-1.17-yurditifflzptvup5hj7ytoaswco6aav' '--without-libintl-prefix' '--disable-debuginfod' '--disable-libdebuginfod' + +1 error found in build log: + 60 checking for special C compiler options needed for large files... no + 61 checking for _FILE_OFFSET_BITS value needed for large files... no + 62 checking whether fts.h is bad when included (with LFS)... no + 63 checking whether to add -D_FORTIFY_SOURCE=2 or =3 to CFLAGS... yes -D_FORTIFY_SOURCE=3 + 64 checking for library containing gzdirect... -lz + 65 checking for library containing BZ2_bzdopen... no + >> 66 configure: error: missing -lbz2 for --with-bzlib + +See build log for details: + /tmp/sam/spack-stage/spack-stage-elfutils-0.191-vtbtqmzvsgyoup5klhaeea2olssag5xo/spack-build-out.txt + +==> Installing hdf5-1.8.23-gpzjvgu5li5br7sy2f2otmenx3cr54oy [37/57] +==> No binary for hdf5-1.8.23-gpzjvgu5li5br7sy2f2otmenx3cr54oy found: installing from source +==> Fetching https://mirror.spack.io/_source-cache/archive/37/37fa4eb6cd0e181eb49a10d54611cb00700e9537f805d03e6853503afe5abc27.tar.gz +==> Ran patch() for hdf5 +==> hdf5: Executing phase: 'cmake' +==> hdf5: Executing phase: 'build' +==> hdf5: Executing phase: 'install' +==> hdf5: Successfully installed hdf5-1.8.23-gpzjvgu5li5br7sy2f2otmenx3cr54oy + Stage: 0.43s. Cmake: 18.43s. Build: 11.49s. Install: 0.32s. Post-install: 0.04s. Total: 30.79s +[+] /home/sam/code/serac_libs_dec_24/spack/opt/spack/linux-ubuntu22.04-skylake/gcc-12.3.0/hdf5-1.8.23-gpzjvgu5li5br7sy2f2otmenx3cr54oy +==> Installing umpire-2024.02.0-zapeqzpd4ambdf6nzl5r7micjyabnmta [38/57] +==> No binary for umpire-2024.02.0-zapeqzpd4ambdf6nzl5r7micjyabnmta found: installing from source +==> No patches needed for umpire +==> umpire: Executing phase: 'initconfig' +==> umpire: Executing phase: 'cmake' +==> umpire: Executing phase: 'build' +==> umpire: Executing phase: 'install' +==> umpire: Successfully installed umpire-2024.02.0-zapeqzpd4ambdf6nzl5r7micjyabnmta + Stage: 0.99s. Initconfig: 0.01s. Cmake: 1.15s. Build: 4.82s. Install: 0.10s. Post-install: 0.02s. Total: 7.15s +[+] /home/sam/code/serac_libs_dec_24/spack/opt/spack/linux-ubuntu22.04-skylake/gcc-12.3.0/umpire-2024.02.0-zapeqzpd4ambdf6nzl5r7micjyabnmta +==> Installing raja-2024.02.0-5pwfb3yr4p575lhqtzhhvywvsghkdbfc [39/57] +==> No binary for raja-2024.02.0-5pwfb3yr4p575lhqtzhhvywvsghkdbfc found: installing from source +==> No patches needed for raja +==> raja: Executing phase: 'initconfig' +==> raja: Executing phase: 'cmake' +==> raja: Executing phase: 'build' +==> raja: Executing phase: 'install' +==> raja: Successfully installed raja-2024.02.0-5pwfb3yr4p575lhqtzhhvywvsghkdbfc + Stage: 1.05s. Initconfig: 0.01s. Cmake: 1.24s. Build: 0.66s. Install: 0.09s. Post-install: 0.05s. Total: 3.13s +[+] /home/sam/code/serac_libs_dec_24/spack/opt/spack/linux-ubuntu22.04-skylake/gcc-12.3.0/raja-2024.02.0-5pwfb3yr4p575lhqtzhhvywvsghkdbfc +==> Installing netcdf-c-4.7.4-o4h3fi5jvtfrikv5zvt47mw7tiut4vk6 [40/57] +==> No binary for netcdf-c-4.7.4-o4h3fi5jvtfrikv5zvt47mw7tiut4vk6 found: installing from source +==> Fetching https://mirror.spack.io/_source-cache/archive/99/99930ad7b3c4c1a8e8831fb061cb02b2170fc8e5ccaeda733bd99c3b9d31666b.tar.gz +==> No patches needed for netcdf-c +==> netcdf-c: Executing phase: 'autoreconf' +==> netcdf-c: Executing phase: 'configure' +==> netcdf-c: Executing phase: 'build' +==> netcdf-c: Executing phase: 'install' +==> netcdf-c: Successfully installed netcdf-c-4.7.4-o4h3fi5jvtfrikv5zvt47mw7tiut4vk6 + Stage: 1.27s. Autoreconf: 0.00s. Configure: 18.77s. Build: 4.50s. Install: 0.90s. Post-install: 0.02s. Total: 25.55s +[+] /home/sam/code/serac_libs_dec_24/spack/opt/spack/linux-ubuntu22.04-skylake/gcc-12.3.0/netcdf-c-4.7.4-o4h3fi5jvtfrikv5zvt47mw7tiut4vk6 +==> Error: serac-develop-l77xejhejbbfmh5b4vqtxxw3paidppuo: Package was not installed +==> Error: serac-develop-l77xejhejbbfmh5b4vqtxxw3paidppuo: Package was not installed +==> Error: Installation request failed. Refer to reported errors for failing package(s). +==> Updating view at /home/sam/code/serac_libs_dec_24/spack_env/.spack-env/view +[ERROR: Failure of spack install] diff --git a/data/meshes/one_tri.mesh b/data/meshes/one_tri.mesh new file mode 100644 index 0000000000..59d619c094 --- /dev/null +++ b/data/meshes/one_tri.mesh @@ -0,0 +1,29 @@ +MFEM mesh v1.0 + +# +# MFEM Geometry Types (see mesh/geom.hpp): +# +# POINT = 0 +# SEGMENT = 1 +# TRIANGLE = 2 +# SQUARE = 3 +# TETRAHEDRON = 4 +# CUBE = 5 +# + +dimension +2 + +elements +1 +1 2 0 1 2 + +boundary +0 + +vertices +3 +2 +0 0 +1 0 +0 1 diff --git a/data/meshes/testAttr.e b/data/meshes/testAttr.e new file mode 100644 index 0000000000000000000000000000000000000000..1d73cd3421da50d3d7a28b347086c94899599185 GIT binary patch literal 257681 zcmeF)1z;12y2bG+El{AidvTW*cXuf6QVK0lC@s+9?(XjH?(XjH?(XjIe=->sSoZG1 zyZiQXAHDatNprrY$(e~wrlEJyf`!9|juqO_m$S3sWJItXwf^(b{x$f4qwOT?dn>PP z9r=U9(nSlF3l?@&uwV&o1CA-|bBUsuN0!?U&)N?|2QwU$M2*8mF$~90Mq=|98!POG z=j?|@?O^6v{QB=-YQUwSVXO2n4gbp_my(7N{9jIdZ>Y-_;(LGSoAWNk4I|_?lOH>A z_oNpth07H!V>t8k!9KrnShs{Sw)K@z>#M%LJ~U4?LfH@h?0_G)&cVDX7|A*8U)cJ& z)S=gQ$zP#pK`s$DfQX#zoxFnmCqjMtEdv+N>1~?|rKzyyl)d8LraZcCI$5|p=Ve&e z!hU7!zuEeox=3Y=R$LOpo>b3aX0h!f)}ddD)wl9jC|Q_GH$o9-t($4(P;ny|!F0^N zeEc$;Ph)J*Z(~B2t7qNj8I82|6LfVvOT;Z3kjgmT3 zZ|=J|DBERwHzOKHjEwq^VWfYYrH^q&$0~4N!a?jUajy=Uo${$p`t|iUHDFu*p}trU zUo5vT){HL}&lfAe7YqN3b>)jS>5DaBS<*#K|E6p8>umpO1Lk9XB?pHX`UwXI-BxwP zJg^QOqv%+~1o7>6cdkZsXCrz?hJrgQ2^K7v?I$Aegv7}hn9uy_5B4*$o*#rTtoz}w z4_(r0)PXw}XZ}~9WWMs{`93oA499lX92P8As*p$dVx>Ji%NNL3vXJ3YTbTooZ~7^Z ze5DF8Wc#VS99lnBp@DCpEC2U$_4f%XP_VG8w{K$~|3KdWf7d$AgIxUsf_{rycs29& zs^jOA*46xS&y?A4;r>Zabix@f{1#6SpP;(l^)eRpZS2cEnGu2eGTj3jhO6zr)^D|a zW2DP7rM=m3<*yqy2R=3Orwu#)*05pR%Vz%gMf;VJyyTc6;H!pyCWaSg{_i4P(lkfE?d$xLp{t9P98;SK`m^CW0Gl z8=B`I&b}nAl{n1v!l-s@7Xsq*-lHu@L&0gvv=G_vkT|1y7=Ag*+tI;KYyBL@4$YUoL%($9J!df z0P;^E$;;b+cM8M$EsdQ@RkTfo&{TNN!8`fw zy4HDEQ>_BJpEfstq}D>>%YJ1(9h#?Fn?GFn)*NhMzXwTeAFvLGxEVWaFMorVS;F_kfsKH?iw#>`A-ytJL!(zNT-8l`6h@sC&(CSn>8*cZ()1+9mfc{ zJ9#IgHnXnA>Sn7u8xuJi*N8Oac~?V4$2OuBuF=g{WV;M0Jv#I<`f+BljocgW^fJoX zE<@D;Cx;q)Z3CB|m78ls`XGjrbLvCkM`D=Lo5w8O>&j>b2VmN|LaILgu3#;hoNt{Gu%7xL)L zT{n$Ywo?;N>wU|J$~m|i_d^x9Zxpv(ocIq%ywC|MBaI?TP)j*OQ>7b2gZreEnS1+7@6P{^@hkVD{&tk+e2CI)txeuKSm&n``Gk zvDVn`wG*4a|Ih!M`-5}Tzo(0bi~sp9Y!6v~xr;J&Moj;Ex;Pltd>sBK*9+Uz<-gp; zI+u=<%`QSZIwaS6Y{rXAs@4k1my%^DBftG*pP&x?458KuTr{Mb5cGTHPop5(< zR>SdMU;jTF&>Js?F+G=g?FU&Ue0ut6*q%mcwTZ&p7%@J*jZq*VpqaO?zgLh?pzUWq zf1RuotQYRq3T7Re+k7}zUY_a6Nf@5X^5#fkUq8P}UVhDO&t=SKGg?t?E33}#-NCmx zf88Y1#ILWvy8-hik-@$(;_tsnShuzByh&_+pXiSLCgJquqlE2gx>~Z|e17-+Uw)L( zPr|X)-`)9t`1!Z~55IhW_r+`TcmIO_@bfqC6873(5B~jk3D%?KcitsTE7N3jkpiVl z+HUu@2lh|*0X)c>Un}ezi>zN^ou0?OsmHpr`1*9)3u4Z~I(@SJ{H+J{uTQt`)vVLo z+P6DdTe7}B-TK}-wC1gCTh{5;<+L_(eSNz9o#juLvx0rV+U#Y`TbJM3{`K|g)`l?a zbnASqEn?Q`G3~$5UdN~3Yn^Vr47TR2^Rc~Z{jAUaww>P0r#@Oz*1UCk6rISIb^5~+ z=J#K3kuO`yJl(d3+-LLF>3U~HU)K37^)SD;y)X3H>7^=}r|TUVeOdF?>9Nd{Kb^j? zvU!5FkDxX0P|G|$&R6r+>2be0y{@NuLcFg|U*5<(A^snn?)uf~(Hom5B>3ud>wFS^ zb-Fd5=&RFP`6<>B>8IIIz8!Er(5f@{bZxIwL)4a{5t&Az^?{=HSnu} zUk&_f;8z2`8u-<~uLgcK@SP2mE>N_@?{?4A1_8Z*cUh(FdDE8 zLZ0T%chT4;pqH`UUO`@gK0$x_i}g}cFNZ$;U4;E7td~fCbOwL)UV(jcrM218aI{_{ z+s~-btM-Aqde%F;j(@z5L~Xsb^}V}3SerzwLtP$gCqwn}`S*HRKX=LX#f8h4FZAiJ z0v-4RyG6F29@jB&mMyaOm~&ve%6pxG0~;2eXd{b5YzO1I7D|l>{cmufFWbVizn^XG zT4}ZEa!P-Y`JcM%tj$K&VSQ`+fO*A?w$^q5`}aE%+K<=|>POAD^IO;cQ5tjL=eqU- zt*ssQYd6-~%3=S0rnPm${(X(m6Au4VYqmC|eZFREdse=A4VQguY5bh)VtCu$%J!-` zC~s}kvY)in+NNaxzEaXD$Ns6Mp{+`vFAZ&m4C`1qQQ@M+@*9b)jewlkzo2<(`{y?g zm;0KB*4;)$uPH-5UxewlnE9ol=AldNfA?LawcCMpm#GW8U`DEO=I{Hi|9*bKtt(`0 zFZ;P3!%kb<2kqB?k7JX@-@118zXddYuKPLbmZLRRU)H_4^}TiNt?yT-DOjm+(So0? z$vj$4{;+GjgOjzLJak?5Eb!EBje(zj+R1t%5YE4OV^1GHPhWq}I)07ZtZm~CPS!0v zyaxOOygi%vG-J@s+Dh)=WZiVWJPUVgv$%tkwIThhvv9XIkUKbi+N54Lz~A4eZjf8l zGUnBGaQd`W-5$BSm$f2m!@7$uTA;7Dk7r<@o3$0)!O6NW3a!|?oTI25+-g>2J@|z6_6-d3tmjoXNI#mwzF(Y!ll5Tq`6Y6T_SgDqr8KYbysO!BKPgJtzYYE9x<#-g1FZ)p2d7W(a*;J@7SP1adW>>#vfk(l6&Ps$G3&XN zgOmNeCn^s#f6RKC<=|x9U53!@$-9;HjKsmo{=S7_2Cc29CJs(|sL_`hw6UI}I5>TJ z%Zm$VyJ3F1**krD*NY2ai$2{0I3+UA&2Xw0(7c)T?h2>bmcR9RFSeO*5AwZmVDBQ^ zpGo`I&A`=c=3Cc%{qeik3ifl=I-#G5!s{5XCcd66e46Pmvu$Za*WdrSxdLmSBx`-L z4llPc@;UHIM(1Un&ySr)OfFFjqn=-YSCFrNea|KVzWza;E$N??rHzm6!ttNqT_Nc&F1C|e*X5`4O{E3b@+V^53cZE z((wOc9X6i^t-c;P>9-rU)?MrH`x*|Y_+QfS|6(0BpG__sWLz>Ej_BZ!T&-AtVPLJh zR>NO^@AyZ56>a|`19MNgS9#2)dzc5G{(|dYY_YYyl=^q=Wv=@|T>}@k9%?W1(6;9r zwii)Bt(#a+#Pn=IPxq~73q=c6$;!8VCRE?^ca{^zenbDK%F&HXtHBSI6UJfOv~O*{ zXlH+k{&Q`ev0lK_hV83n)NbLvb?sd3`OkUnto6I{fXgvHzjmufv-O3qzi*SEwwUO* zTbl&6ndH)-jom-L6xQ~=pK}eew)1esY+nP4tT^|rYv*duf37vix^~tYbg)|Cqu+jH zPHBJsZXJHlBeSECsfJn41A9x>^Y@?b^M>5g|M2GxncH%<9oQcG+YQgMZ)>p*zo%it zNL16T_NRY^l+itN#vgqCZf+8b(I8nXv*EA*0@+%3t;0WiuH$Tfr*?E2b6caeWURIK z|MKtEZCjaB+iyO9`5;DvweSADUF6IC&v#+lr2gGqgqz`#;@e$V%hfux-}3(WQ= z%kOn+xWjSU+s9R`o7_@3c0>@Z71b7Cw{KSZ0mg<>)M_1O`YZ2k0`V4Bi7;fJfb)nx9gif{?k8Z zySio0_JfZo=6fkCBNvMP?S`k>S4Hdadm1*3lMT#D~b&29gj z%da1^t##Kr{Hu@IDUO-<$<~tjC+?GNZ{dFT<5ZqQ1+#wpamwnzI{d3$>_73(cVTH1Z+BrWSL^V5AG4dDHal^(?-uY+tRJ@b>HqR$cC#saE99?G%)>0a`n(*gv4q+DXO! z8HCn8DfZ7zwDv)WgVQXmHmsIyWFiaaB#BL ze%t;_O}#vu`P8-k!uLe{3-TY2|OEMUM>eG>xN{ip@>U^Z)r@QMkIg{ordhb8ohJhX*A7cEjA#Y+u&l_cc7R*?&*NKf0aO zeEyj|Zkd(eZrHjDvkt$n;r4<5H4SI@(S3c)XLxHno*Za4e8#~+?_3)Wj^_P>b?;!U z!&cLOboy7H8)*L1Jl5x&_tH5#8r_Tn74sLfzjv*Ze*fi`Ic@r^Y198cuul1H2RrMO zuMYoouRH5?*uVIET-!zb(LD*wSADimy|P_2-CJmVR^u*B%)JS|@1yI#K1VGB>-|tI zm(Rb~gZJm(>$&TkoVW9R>zR(VY=5q2I@U7^u9)rX!qZf7zIE-)`;edQFBYw9r)8+G z;%QPA{noYXX2w6+-(y=THDm7&D%5N=c>ze#rw^HlLy?r$`b_WYHNb9tgyzb9*-xC}mVC`!aisO3m zrT4L2pl##Ydi(i3s5V7t`-3(*XiI}OFKC;BHY8~4fi@XvJApP1Xp4Y01L(ECD-uBW zkGfCPGSbTxy(-bm552}nfs{xEEk3<8Pm6TWLy{ZZkpUTz37L@vdhpDK?8t$f$c5a{ zu55Xc5BX651yKlvQ3OR%48>6bB~c0j0T_ru7>pqpieVUz5g3V47>zL)i*Xo_37CjUn2afy zifNdR8JLM#n2kA@i+Pxj1z3nhSd1lDie*@i6IJ8x>Iy710nKF%T26z@Nn%aS#{r5Ff5cfP_ed#7Kgq zNQUG{fs{xE{Yx)tpnm`(9r!~L!wv4pfQ-n5%*cYQ$cF65ft<*N+{lBx$cOwWfPyH5 z!YG2GCltvkpMLCp51yqDSvc58^pem}NI%=RMYQYn=;e|S=3vc+K z9_ph3e9;h%;D^TWM*y0jDViY=L1>N^Xo*&6jW%eDc4!a%n;;$037ydeUC|BQ(E~lv z3%$_?ebEp7F#rQG2!k;MLop1)F#;no3ZpRwV=)fnF#!`X36n7eQ!x$GF#|I(3$rl? zb1@I|u>cFP2#c`vcx3ahaOYq1XNu>l*g37fG6Td@t>u>(7?3%jugd$AAu zaR3K#2#0Y5M{x|taRMiC3a4=fXK@baaRC=`372sNS8)y3aRWDT3%79xcX1E*@c<9; z2#@guPw@=T@d7XL3a{}7Z}ATA@c|#92Yv_WA9r?y6M`cILc$rLz(4G6gnM5nTA(Fbp*7l|E!v?yI-nyup)xVVK??*FZN+S4&WdT;V_QiD30McPT(X? z;WWR&k)I)tVfG--N5&X~?{s=%5G(|H6A_&dV0xi)Btx01L4Qi?IYtu?)+x0xPi!tFZ=au@3980UNOio3RC3 zu?^d?13R$`yRip*u@C!k00(ghhj9c)aSX?C0w-|_r*Q^naSrEk0T*!zmvIGGaShjT z12=ICw{Zt|aS!+L01xp9kMRUg@eI%L0x$6juki+N@ec3t0Uu#Far;LwI6@zw5F8;8 z63z&P&jSDiCBn@IEagQh!0mJKtd!!VkALQBtvqf zfcD%@h15ucv`B~aaDzKCAS1MQKxSk?R%AnV=HB?6p)I=?KqBgux2X)~MAJjvAG=MJ}q7nSi z82-?X4NcG#%@BwnG)D`xL@TsL8?;3`v_}VYL??7c7j#88bVm>LL@)G4AM`~(^v3`U z#2^gD5DdjI495tJ#3+o$7>va@jK>5_#3W3{6imf5OvenOCl9L&W$%*O&O#3C%l z5-i0sEXNA0#44=D8mz@Stj7jy#3pRU7Hq{fY{w4l#4hZ{9_+X^{@;;RbhPKt^OjW@JHDWJ7l3 zKu+XBZsb8;8KuMH>2TG$1%Ay>~qXH_T5-Ot#s-haIqXufC z7CccKUZ{h*@P-fSp*|YG7Y)$}erODT1fU6;q8S1agyv|0mS~06XoI$BhxX`zj_8EW z=z^~3hVJNrp6G?%=!3rKhyECVff$6r7=ob~hT#~2kr;*17=y7Ghw+$ziI{}Rn1ZR8 zhUu7rnV5yyn1i{Phxu55g;<2eSc0WkhUHj+l~{$;hy6H!gE)l4ID(@%hT}MalQ@ObID@k|hx53Ai@1c#xPq&=hU>V2o4AGB zxP!a6hx>Sdhj@g?c!H;RhUa*Jmw1KOc!Rfihxhn^k1#@T`$sT1LLY<_93c=A&IpCj z2m=>{ML2{<1Vlt6L`D=uMKnZ548%k%#6}#%MLfiZD-s|f5+N~?ASsd|IZ_}cQXw_c zAT81%J>1}q49JK~$c!w=ifqV^9LR}W$c;S6i+sqB0w{<=D2yT~iee~^5-5pM@IYyl zL0ObTc~n3}R6=D`K~+>kb<{vj)Pg5!!wYp#7vAteJ=8}7_@W^i!4Hk$j{r15Q#3;$ zg3uf-&=RfC8g0-P?a&?_&=H-`8C}p7-OwF9&=bAT8-36h{m>r+Fc5<<7(*}=!!R5p zFcPCM8e=dP<1ii*FcFh58B;J7(=Z(~FcY&d8*?xh^DrL^un>!|7)!7e%di|PuoA1V z8f&l?>#!ahuo0WE8C$Rw+prxwuoJtm8+))9`>-Dea1e)Z7)Njv$8a1ca1y6*8fS18 z=Wreua1obq8CP%>*Ki#-a1*z18+ULQ_i!H%@DPvi7*FsN&+r^C@Di`^8gK9x@9-WU z@DWBxZvO}dN9cpjf+GY%!Wp3u8e!mqun33nh=7QQgvf}3sECH>h=G`hh1iILxQK`N za76+nL?R?c5+p@3Bu5IQL@K048l*)!q=y^akpUTz37L@vS&cSg7 zsE7J!0ADmjBlw{){1JdAXo_YCL=c*z1zMsNTB8lxq8-|!13ID;I-?7^q8qxS2YR9x zdZQ2eq96KW00v?Z24e_@Vi<;F1V&;MMq>=dVjRX}0w!V-CSwYwVj8An24-RwW@8TK zVjkvW0TyBr7GnvPVi}fW1y*7eR$~p;Vjb3F12$q4He(C6VjH$&2XEQ-< zWI#q_LS|$^R%AnV3WB4NgP0$q05Qrc&M+>w> zE3`%%v_(6#M+bC7Cv-*^bVWCGM-TKwFZ4zq^hH1P#{dk(APmM348<@E#|VtXD2&D! zjKw&N#{^8oBuvH>OvN-z#|+HGEX>9n%*8y+#{w+GA}q!dEX6V`#|o^(Dy+sDti?L4 z#|CV~CTzwQY{fQg#}4eoF6_o0?8QFp#{nF~AsogL9K|sl#|fOoDV)X`oW(hu#|2!( zC0xc8T*Wn9#|_-XE!@T(+{HcI#{)dXBRs|vJjF9S#|yl~E4;=Vyu~}b#|M0b5sKSC zg255`yi)#kX(I$e!Wp3u8e!mqun33nh=7QQgvf}3sECH>h=G`hh1iILxQK`Na76+n zL?R?c5+p@3Bu5IQL@K048l*)!q=y^akpUTz37L@vS&;G-(I-}&j+{0}b>xJ>Nd?vuxd$?JDuVVEvsL=HB?6p)I=?KqBgux z2X)~MAJjvAG=MJ}q7nSi82$)A6EsCL1R@B{(E=^e3a!xwZP5>6n3; zn1$JxgSnW8`B;F3ScJt`f~8o7*Bhbs~wArc`mk{~IPAvsbY zB~l?Z(jYC;AwAsSjtt0%OvsEZ$ck*pjvUB|T*!?)$cuc)j{+!&LMV(PD2iezjuI$| zQt&`<EdPLwQty?ocbCGOC~|s-Ze+peAa;6Sd)mI;ab8_@Ex@qXB%;5RKr6#_&e~ znxH9~ArL`mjuvQ%R%nejXp44ej}GXFPUws-=!$OWjvnZVUg(WJ=!<^nj{z8nK^Tl7 z7>Z#Sju9A%Q5cOe7>jWjj|rHFNtlc&n2Kqbjv1JVS(uGEn2ULsj|EtWMOcg_Sc+v> zjulvmRalKRSc`R7j}6#}P1uYr*otk~jvd&EUD%C1*o%GGj{`V}LpY2hIErI9juSYE zQ#g$?IE!;Qj|;enOSp_HxQc7IjvKg%TeyuoxQlzZj|X^&M|g}Uc#3Cuju&`|S9py# zc#C&Vj~XXA|B$y6$y|KiI5mckQB*~94U|zsgN3JkQV8X9&T_) z24qAgWJVTbMK)wd4&+2GN^Xo*&6 zjW%eDc4&_d=!j0}j4tSkZs?94=!stFjXvm$e&~+@7>Gd_j3F3`VHl1P7>Q9BjWHOD zaTt#Yn21T3j47CkX_$@~n2A}KjX9W$d6pfzIEhm@jWallb2yI+xQI)* zj4QZ`Yq*XZxQSc1jXSuDd$^AWc!)=Mj3;=CXLybmc!^hdjW>9UcX*Ev_z1&^+dqQA z5l#q>5C{opghFV9feXSS9Ks_4A|etZBMPD-8locxVj>n|BM#ys9^%6l36KzpkQhmj z6v>brDUcGWkQ!-_7U_^4Zg58iWJD%pMiyj6He^Q*@+!4tLNg*vDUZ}^}d>Z1XC(GZQ` zhsN+n0GgmFnjsKDXpRXpau)h)(E?F6fGG=#C!fiC*Z9KIn^n=#K#y zh(Q>PAsC8b7>*GbiBTAhF&K++7>@~Th(~ygCwPiyc#ao% ziC1`yH+YM8c#jYG2qQSRe*}XgoDdu#5E9M^h0q8C7lcJPghvEKL?lE;6huWdL`Mw7 zL@dNc9K=OD#D^;qAR!VVF_IuDk|8-#ASF^EHPRq0(jh(E;EoK)h)l?gEXay%$c`My ziCoByJjjcD$d3Xjh(aigA}EStD2@^+iBj-DX_P@(ltXz`Kt)tSWmG{`R6}*tKuy$w zCu+kBbx;@H@IgJ)M+5kxAsWFCjp2^~G(l4|Lm-0C94*iitvC9|JHDgD@CFFciZu93wCiqc9p{Fc#x59uqJTlQ0=mFcs4< z9WyW!voITTFcB>4ju?oEScr`{h>LiL4_72WLL@?BBtcRnLvo}*N~A(+q(NGw zLwdNu9T|`jnUEP-kQLdG9XXH_xsV%qkQe!o9|celg-{qpP!z>b93@Z^rQm_mD1)*n zhw`X^il~IjsDi4fhU%z+ny3X&)P@)8pf0@OgLxVVK??*FZN+S4&WdT;V_QiD30McPT(X?;WW^-v!T z;ERT61V1!}KLXGMP0KWK6+SOv7}{z)Z}-Y|O!2%)@*v zz(Op-Vl2T@EW>iFz)GybYOKLptiyV2z(#DsW^BP$Y{Pc!z)tMKZtTHc?8AN>z(E|s zVI09x9K&&(z)76KX`I1XoWprsz(ribWn95kT*GzTz)jr3ZQQ|K+{1l5z(YL3V?4oA zJi~Lmz)QTsYrMf*yu*8Zz(*L)-2M>^j&MS7gg{6*BNRd-3|tTv;Se4X5D}3O8Bq`w z(GVRm5EHQw8*va9@em)bNPvV$gv3aKq)3M3NP(0{h15ucv`B~aaDzKCAR{s%GqNBn zvLQQiASZGmH}W7a@*zJ8pdbpNFp8ikilI14pd?Dc1Eo<0Wl;|0Q2`ZE36)U=RZ$Jq zQ3Ewm3!bPAFVsO@c*6(vP#+E8i-u?fKQx9v0?-6a(F}nILUXi0OSD33v_V_6Lwj^U zM|47GbU{~iLwEE*PxL}>^g&!*QIzNu0uIoWWU~!+Bi5MO?yVT)|ab!*$%i zP29q5+`(Pk!+ku!Lp;J`Ji${u!*jgAOT5Bsyun+%!+U(dNBn=@>6 z8TPwHLvN2*`#xz#PnW{L1)5P77U2*Y%EBW8G@~pcB0)3CA|nbkqbw?-K{LvtBL+01 zEGA+>Gsb(FoqfEUQgl3ef_d?K&GWA{< zno*|Si$F8VTu~I7QI-(Jpcz-F_u|luGWA{pno*|SOF}csQlbb)E^qfE=DJT#+B%ccS}qh+GrE20v#Ow@a2RDm+}UKN^ArrxVT zGs@I^b!bLeUethQl&SZc&`e(BM=fYZnR@qxW|XP-+R%(L_3j1DC{yosP#enBdtGQo znR@qzW|XOSA81CIdann~C{yqCp&4cBy#X|%OuhR;Gs@I^Luf{sdT#{HC{yo#(2O$m z-WZxurr!Ob8D&~F0nm&xEt@9LjFyRdZ;EEnGEwh=2!b;8-W-}yrrujXGs@I^OK3)! zdT#~IC{ypPp&4cBy$v*@Oue^-W|Y-NJ7`9kdT$TS)P{QR0L>^ID>S1_y?29Vl&Sab(2O$m-UFIZrrvu(Gs@I^FK9-YdhZR*C{yo! zpc!RaHhrNPWm-1Km;)^n^*$H#piI5bhh~(i_XW_5GWEU?no*|S7eO=1)cay+MwxnF z0?jB>?@OT>W$JwyG^0$tFNbE7srMDoj577U5}Hw_-d900%GCR6XhxZOUjxl3Q}1h` z8D*2O4w_M>-q%Ajlc3%=Kr_nJ`$lL+nR?#@%_vjvo1qzH>U|3~L7A4#R%k|?M`vGW1nR-76 z%_vjvhoBi{>isY@qfEUYfo7Dc_oL8^GWC88no*|Sk3%!c)cXl&Mwxm)3C$=|@28*{ zW$OJjG^0$tpMhqSsrR$cjIvEQ2hAu`@8_YJO;GO_pc!RaHW#58Wm-0upcyR_^?n&w zpk<=oui_e%srT#9j576p1Da8$-fu!P%GCQUXhxZOzYWbOQ}1`68D;AIE;OS|z2Ado zl&Sao(2O$m{s5X$rrsYyGs@KaBWOmMdVdVfC{yoGpc!TA{V6n~OuavYW|XP-=g^EY z_5K2yQKsHsLNm(L`zvThnR%_vjvZ=e}vS~hQ?8D*F74w}(2QSa~Z0a_;N{UZzq zGgI#l9M_C8^&X7xHKR~ZHMwymP z4329?%S64$J9L9k%^&S_RQKsJGK{LwKdwgg{nR<7HW|XP-1kj8!^_~!# zQKsG#K{LwKdtzutnR-tG%_vjvNue2K>OC1WqfEUghh~(i_Y}~KGWDJkno*|SQ$aJz z)O%`ZMwxm~1I;K??`feKW$Ha0G^0$tr-x>gsdqPMMwxndhh~&%*<^rblxf*ygl4o% z)O#jmhL(wX&w{K_rrxtbGs@I^c4$VKdd~sPC{yn_p&4cBJr^{iOugrZW|XP-JkX3X z^_~}+QKsJWK{LwKdwys}nR+h(%_vjv1)&*b>b(#&qfEUQhGvwh_ae}YGWA{*no*|S zi$OEW)O&GgMwxmq0nI2=?4Q%_vjv zHK7@0>b({;qfEVfLNm(Ldu?b&nR@qvW|XP-I?#+V^1@Q0R(dJjMoC{yoE zp&4cBy%{v4OuYv}Gs@I^5HzDqy*Gzul&SX?(2O$m-V&NorrujYGs@I^YiLH9dT#^G zC{yokp&4cBy&W{8Oue^b)B@qfEVbhh~(i_a4xUGA)~)(2O!In_kdNa2`)WAS9g8o74KBFZw}Q7`Q+)%KBpf zG@~p$B0w|B24WC2qbxF_Kr_k)V+b^(EIML9Gs=cy7&N0SHsU}t%7$YEG@~p&T%j3d zBQXk^QI-ga;R7f~A6EO*zQI-K2 zp&4b9F$J1YmIYa%8D"Vuw1QSUjB6Iv$feL7}9nR?F+%_vjvGocw}>OC(sqfEWe zf@YMd_x#8UW$Jx4G^0$t7ldY%srNb1j576J7@AS0-seIy%3M(tno*|S=Rq^d)O&Gg zMwxn_56vi3?dS8lVP^R9iK{LwK`*LVTSzgqDW|XP-70`?_^U}>nqfE=DA2g#(%jN(yqh+Gr z2VxMkOw{{99D*|SJ_MRkrrr-jGs@KaFla`ZdOrfqC{ynvpc!TA{U|h}OudhSW|XP- zW6+E;^*#ogQKsIHLo>=cVH`B0Oue6gW|XP-3DAr(^?nkXQKsG}K{LwK`zdHfnR=gs zNl>QVPeU`x)cZ7OMwxm)1I;K??=zqoW$OJbG^0$*W)?J~Ov~mRG^1sr-sfT-v`p0d zd0c=p^}Ya_QKsH6LNm(L`yyyYnR>qj%_vjvOQ0EL>ise_qfEUogJzVe_bbqhGWEU! zno*|SuR=4*)cY!EMwxoQ2F)l_?`xnLW$OJpG^1=1)^C_t zW$JwsG^0$t--2e8srN0|1ZC>|HZ-G5%VrxiqfE=@4m6`>qTY967qm>&`(50FGWEU( zno*|S??W@n)cZbYMwxnl0L>^?M`#oqznR@>K%_vjv51<)k>ir`$qfEU&f@YMd zcO#fNqfE=@2{fZjy*rR=MwxnlrVPr|doVK1C{yn*pc!TA-H}W)%GCQSXhxZOcOuh_ zGWGrjwiz<@9-K@w$}Zs@G^0$*CIp#gv`o~ywyPPOu4SU$Ly|c|nR*Y#X_`@{-b0aT zMwxnd;xx@DQ}3b4G^0$thu}2LC{yoY$TXu&y*qQ7W|XOS7c$K#Q}3ZUO*6{0Y{HUh zMwxnd;WW)CQ}5xR8QU`9q;QC@&*Ldr@dcnR-ucpHZgXi$gQY)O#BHj576J5}Hw_-qYG= zl&NBrrw)DGs@I^K4?andJlqTl&Sap z(2O$m-U6CYrrrxcGs@I^D`-ZUdM^mgC{yokpc!TAy%02`Oue^*W|Y}_x6de3?;W5S zW$L{M3PYKC?*z>#Q}0Eg8D;9d3pArly%&RKl&SY_(2O$mUL2ZHrrvu%Gs@I^31~){ zmQ62cMwymPNob}wr}aT!^g}65^FV2ofwKM>0L>^Xi*nG6vVj-`%_u963eb$Q!59L~ zD65D{(2TO77zWKKtBfkpjI!Yv0nI3@ifYh|vXK}C%_ysm8qkcg(HH~GD65HD(2TON z7zfQL^F(cEM%j2wfM%3=p$;^oY$7H>Gs^118=6rz8B?GcWj?3}%_y6SY0!+a`e*>n zXql+@>6ig66ZP(khES&7XF@Z|)O#anMwxn_1b(gxqfEWehh~(i_omQ{GWEUyno*|Sn?Wb*HMqfEG6 z^}ZUKQKsJ8Lo>?M`xb)a0qfEW8gJzVe_fF7^GWEV5no*|S zJ3}+d)cXc#Mwxo=0?jB>?;D{RW$L{vG^0$*W)n1{Ov|PlG^1sr-Zx_lv`o}{cl3ZV z^}ZFFQKsH|LNm(L`!;AsnR@R9%_vjv+o2g{>b*BKqfEW;fM%4b_dd{!GWEU_no*|S z`$99y)cY=IMwxo=2hAu`@4KNHW$L{@G^0$t?}28NsrLcUj577U7n)I~-UmW6%GCQl zXhxZO9|X-PQ}6qs8D;8yFf^k~%jN(yqfEU)cX-=Mwxma0nI2=??<5-W$Jw-G^0$tAA@F;srOOPj576p9GX$4-bX_-%GCP_ zXhxZO9|O%OQ|~9C8D;8yEHtA`y`O?+l&SY|(2O$mej1ulrryUxGs@Ka8E8hCdY=Hz zC{yoep&4cBeIhiYOv~mRG^0$*W)d``Wuo5C;{voy)ca&ifim@e5t>n^-lsw{%GCQM zXhxZOp9ak+Q}36d8D;8yIy9q9yeo}x2 z4&Uzz(7@sQ$pIQTeE(~J1`gj(3DCgd``-dIaQJ>|fCdiV{~n-$!}lKrXyEYu9|0OT zd_OHf1BdVb4A8*g`{@B1IDEf5Km&*GX9Q^A@co_u4IIAzI6wnO-`pFZfunDJ5}=_^ z@cq8v{(wHg_cMc^25|WPK!64g--iJjIDCIFKm&*GKMT;n;rl}Y8aRCad4L8E-yaUp zz~TF}01X_zKN6sU!}nhVXyEXDN1aSC1S3aYG!}nhYXyEXD?tDfAhwm2#XyEXDo_t0Fhwm2!XyEXD z-h4&_hwm2$XyEXDzI;XlhwqmJXyEXD{s0XezF!)kfy4I&0yJ>=ep!G94&N6H(7@sQ z2_vHdKaQOb401X_zFCUes)funE!5ul+@@cpU5`T>1{@Ba+$ z4&d8n+5ag!}r<3p@GBq=LTrt@O}1hXyEXD^8gJTzRwX34II8dFF*r_?{kJj1BdTh1Zd#! zeXek5;PCzV0U9`bpF12HIDCIWfCdiV=Lv@f4&PrGpn=2pdBdTB!}l!%G;s9IeBsc* z;rojMG;sJne}D!K-?s|Tz~TD>0U9{^X6pbA9DTE3fM%QIZ5wPCyf|1Wc?$=N1d9f6 zFA25}(7-JgEFPeN+aY*qfCg@fV95Xt+>XJ^0yJ<-1xp8L;9efQB0vMTOt5T#2JV%? zs{%A|%LU5^XyA4Vb`H?Mtq`mjpn-dJ@R|S(+)Ba90UEeng4YIU;8qD%4bZ^t8tfLJ zfmRngJTPJ%ZN z;PCye0U9`be_DVB4&UDvpn=2p4FWW9`2O|)4II8dJwOA8@B0L3;PCw!0U9`b-#0)5 zhwsk}(7@sQegPUdeBUrY1BdVL2++Xc`$hp8IQr(D0U9{^=2-z6`UKzK6}&s3Pw;)? zV3Pn2-`^9Ufy4Jr12k~>{@wr$9KJt0Km&*G?+eht;rk#!1BdVL575Bj`(^g!}kvcXyEYuxd9qDeE(2@1`gjh575Bj`-cNGaQObb01X_zeOX=o5VZMDWRgKEd}bgBJyG z`2MK?4II926`+B`_fH3C;P8Fx01X_z?;oIn!}o0hG;sL-nE(wOzHb|#fy4LD258{$ zeY*e+9KL@pKm&*GFAmVa;rr(UG;sL-k^l`HzJDP=1BdV12Wa5%{eS=s9KP=mpn=2p zF9vAf@cpF$8aRCaQh){y-**hqz|l8f4$#2SH!lm&&?oqQU~o`CpWyq;gI5G_`2Lju z4II9|GC%`|?_Ukjz~TF=0yJ>=esF*W4&QeQ(7@sQ*8((f_`Y+11`gl99-x84_g4pK z;PCw$0U9`be@%b}4&M(6(7@sQE&&=ieE(*E1`gj}8=!&1_d^3TaQMD!fCdiVzZIZ? z!}r|+G;sL-?EnoNzP~O&14rK+7NCKnZ*~vR&?oqQc<`NoKEd}rg4YLd_&zm21BdT# z2++Xc`*#C0aQObl01X_ze=k4-hwpm^XyEYu`vDp_e1B7b1`gkk2++Xc`BehwncO(7@sQUI7|7d_OWk1BdT>2Wa5%{ipy99KOFbKm&*GM+a!&@cnH8 z8aRAECO`v+?{5##z|l9y258{un|%T_^a;Kn7aSkZC-}Z^uwMX&?ofCdiV-xHvL!}n7IG;sL- z-T)08zW*pd1BdVL3(&yf`)L6hIDCJ9fCdiVPY=+*;rj;yG;sKSMt}wm-#-|jfy4J7 z2Wa5%{X+p7IQr%%0U9{^=EDIR`UKz441OBWC;0x6;G+Q?z7GR5aQObQ01X_z|13ZQ zhwmQ`(7@sQ&jU1Y`2L9i4II8t3(&yf`zHf5aQOa<01X_ze=0x&hwr}((7@sQrvo%_ z_= z{`mk69DVbv01X^{^MwEneS+`j2NwkN3BDf?d@+E-_g@ES;PCxR0U9`bzc4@phwonw z(7@sQMFAQ(d_OQi1BdSy2Wa5%{h$C19KK%?pn=2puLNk|@cq&N4II9IH9!N0@0SH= z;PCz601X_zUml==!}qTRXyEYuiU189zJEPH1BdTd258{${Tl%qIDEeesh2Z4&T2Upn=2p-vnsj@cnxM z8aRCaZGZ+2-@hNAfy4LT1!&;#{fGb!9KQcPKm&*GKM2sk;rlHC8aRCaVSomXzPU9( z14rK+8K9w0@cj?LZ2^6P??(kk2XOfQ#{dl+z8@2yfy4Jd1!&;#{n!8v9KQcKKm&*G z#|3EM@cs4x4II87AE1H5_rC;a;PCx~01X_z-w~jJ!}k*dG;sKSXMhF{-%kqAz~TE{ z0U9`bKRG}Hhwpz4(7@sQDFGTdeE(a31`gj(4bZ^h``-gJaQObC01X^{^N#=x9DQ?I zfQCN7_kRX=2lNTPpB|hMz~TEn0U9`b|8al@4&Uz$(7@sQPXaV>_$-;PCyd01X^{Gjl$pfunEE4$#mi z_&!TM&l=Dt_ffCdiV=gMa^aQOb~01X_z&z;X`;PCyz01X_z&y&w+;PCyT01X_z&zsL^ z;PCz801X_z&zH|=;PCyD01X_z&mW+H!}m)AG;sL7K!64g-!BW$z|l7g258{uo67?< z3k3@Yiv)`XR|HoER|QuGaEk?t2Wa4~39b#$z%3Ch8K8l?F1S8G1GiMLbbto#hTz5k z4cs!pvH=>nn}VAIG;qrW%Li!SeiQsQKm)fzuwsA)?sviO12k|e1uF+=;BEQG-`5M!z~TEp0yJ>={?q^s z9KQcEKm&*G>j!Ay@cr%p4II8dEkFZ@@Am{~;P8Ee01X_z-y5KT!}q5LXyEYuz5opz zzCR;C1BdVT2Wa5%{h0w8IDCH~Km&*G8wP0L@cqF64II926rh2__lE*BaP-Zy0yJ>+ z&BFm2`UKxM4mJts6MTOpm@@11??d76eWq||=o5T@cCcvxhwn3oM+1lNg8&U2zRwa4 z4II927NCK{_gTZCfy4Lb1Zd#!eYS9D;PCyq0U9`bpFJEJIDFqcKm&*GbA&?!hwsk| z(7@sQoZ-;G;rkW=8aRBPD;yd)e1Cp`1`gln4u=K~-(L`*fy4KC!l8kqZ(bOnfunEc z4Tpw4p>MVfUKG$L_a`~e)kZxx_{!}kROG;sL7b$|vA-xmzfz~TEg0U9`bUnoEW zhws}4XyEXD;Q$RBzHb+xfy4Jj0yJ>={^9@)9KJ6apn=2pmjr0w@O`lW4II92AE1H5 z_r(J=aQMDMfCdiVmk7|n;rmMiG;sL7WPk<^-**hqz~TE+0U9{^=4AmIIQnMk01bVD z?=KHt5zr_2zD%%e0Eh3d4A8*g`*HyqIDCIqfCdiVmk-du;rmVj8aRAkAwUC%?>h%* z;P8FL01X_zzdAqzhwm!|XyEYuH31qpd|x?01BdUs1Zd#!eU$(W9KOFcKm&*Gs|IM` z@O{?+4II9&7NCK{_uT?CaQMD@fCdiVUl*W(!}m1;G;s9I?g1J&`ew}l4Sj;|djzi! z=o5TjD_A>#!}m7?XyEYuNdX!-e1Btr1`glX3DCgd`Km&*GZwk=B;ro*V zG;sL-<^T;GzCR^E1BdT#3DCgd`+5NyIDFqLKm&*GPYuw(;rreJ8aRAkKR^SA?{5vz zz~TGT0yJ>={eo%l04&Pr9pn=2puLNk|@coqm z8aRCaYJdg~-(MA=fy4KM12k~>zEgk(4&T2Ppn=2podYy*`2O_(4II9|IzR)5@81Z} zz~TFA0yJ>=en@}@4&QeP(7@3*-we>e(KoLR(9kFNerWKmfIh+ZU4z{MIDG$hfCdiV zUl*W(!}r4iG;sL7dw>QG-wzMaz~TEI0U9`b|4x7g4&PrNpn=2psR0@|e1AiL1`gl9 z8=!&1_csP;;PCx>0U9`b-!ni1hwtAH(7@sQn*ua&_2_a6jk;PCw| z0U9`b|6zaz4&V0*(7@3*M+Ru%=$pL*H1r9+9~B%O&?or**5GXc9KIhDpn=2pw+Cq8 z@cq~T4IIAj6QF^^_u~RIaQMD&fCdiVj}Oqm;ro688aRAEAwUC%@9zlEz~TFe0U9`b ze`kOO4&P4-(7@sQy8<+D_A@KReS+^F2tF9V;rovRG;sL-p#TjWzW*dZ z1BdS)4$#2i`eG2;MxEU+@Zm@0yJ>f1=j~?;JzIk z7NCK19y1vod6BoO~K6p8n~&!cLOwVzX^UDpn>~d@cjS{-0yKcT8|>fClc*!R-MWxZ{H312k}d z3GN8cz?~4B7@&c>Gq@{219wtza)5?D!S}xge+%dnd_N^PHGsqSzXxdG@cl;t8aRCa zM}P(n-%ktBz~TEp12k~>etLig4&Uz%(7@sQ837tNe7`3^1BdTF4$#2i`@I1gIDG#} zfCdiV?+eht;rp2Z8aRBvKR^SA?>`ODz~TD?0U9`b9|maP@cqF64IIAzEIeszEb z4&N6G(7@sQH31qpd|y031BdU|258{$eTe`K9KK%{pn=2pB?B~Y_ zKm&*Ge+|&U;ro*VG;sL-w*U;?+*oN;PCxf0U9`be>gw`hwmE)XyEYu zkpK-GzHbtsfy4JHvyC)x_`Yd?1`gk63XcX3-=7_zfy4Ki!=Zu0_d$RL4&P@9hXxMc zHw)0f;rp!N(7@sQa{@GQ_&!@WG;sL-+yD(6zRw;G4II929-x84_c_9$funDp7odTo zZ{`e#hCadfErRC<^a;Mt6>jbT4&Pr8pn=2pdBUNA!}k{kXyEXD-f(E(@O{ew4IF(l zUpO>y`2L~*4IIADAE1H5_pJgnaQMDJfCdiVw+_(2;roIC8aRC4CO`v+?+XQJ;P8Fh z01X_zFC3tO!}sk1G;sL7NPq?o-(MV{fy4Jj12k~>{*nL<9KJ6Wpn;=rwhz$2(Km|+ zXy_As-ywKuK%e0I62X!I9KP=upn=2pr2;f?`2Mm04II8N9iV~3_m>A~;P8E!01X_z zzal^bhwsYr(!d|xg=1BdUg3edpe`|<%AIDFqJKm&*GD+FlZ@O|e14II9& z7@&c}_g4pK;P8E=01X_zza~Hfhwm!~XyEXDmjDeMzONFXfunC;8=!%sZ&nS^&?or5 zYp`2DpWypy!Ri4VzP~O&1BdTx1Zd#!efIzj9KNp^pn=2pJpwdv_`X(v1`gj}AE1H5 z_q78waQOa)01X_zKPf;1hwpC;(7@sQIsqCueBU!b1BdVH258{${Y?QHIDCI{fCdiV z-yEQU!}q5IXyEYuEdd%hd|xj>1BdT>1!&;#{iy*OIQnMq01X^{vwnbvKEe0525$@K z6MTPKut5Na?{5##z~TGT12k~>zE6M#4&R>gw`hwsk|(7@sQM*=i(_`XGe1`gjp8lZv0_vZ&_;PCxp z0U9`be?fo-4&Of>pn=2p7Y1nH@ck138aRC4GC%`|@1G3Nz~TFg0yJ>={;2>B9KLTA zpn=2pPX}n=@O|q54IIAjAE1H5_iX|+aP-Y*0yJ>+&9(s=`UKxU8+={*?d?9KOFYKm&*G zUk%W};rpusG;sKSaDWC5-**boz|l8f3(&yPH#-MtzMi~q1cwCQ3|^hQ*95x+uMOZ1 z4Zanif!j6MEkFbJ?clHg4czO3-2*gmhX>yY(7^2xygon!H#PWffClaj!5afKaNi5Q zAE1HTGk8;g2JVR92LT$mHwSMC(7^pLI5I#3w^y)tfClcU;OGDi+*^aU1!&-o362fW zz`Z@#CqM&tTyT7V25#SAzW@!~3Bid08n|}^?+nnuofMoLpn-c=@a_N&eS+_&1g8e{ z3BJE4cy9oQ?>`FAz~TG*0yJ>=ep-MA4&UD&pn=2p(*rbc`2K+a4II9o5uky?_YVeW z;PCy&0U9`b|4@Ji4&Q$gpn=2p4+m)A@cqmH4II9IBtQd)?>`ODz~TEx12k~>J`B*n z;rqt|G;sL-vj7bozJEMG1BdTF575Bj`zHc4aP-Zz01X^{^T_}WeS+`52!0vRC;0xU z;L`ydzMmDKfy4Lx12k~>es+Kc4&Of$pn=2pa{@GQ`2N`d4II9o8=!&1_s<1r;PCyt z01X_ze?CA1hwr}%(7@sQ7XmbJ_8aRBvE?fCdiV{}7;o!}p^CG;sKSTYv@*-;WN^z~TEJ12k~>eoTM{4&VP2pn=2p zV*@mB`2Obr4II877odToZ*C9Jz|l9y2WaRMeE&;uM?jz8`w78`0UW;H8K8l~_mcuN zaQJ>#fCdiVPY%$);rm|$G;sKSN`M9q-~Se%fy4Jx12k~>{`UY49KQc3Km&*G{|L~) z;rnR;8aRCaXMhF{-%k(Fz~TGd0U9`bKO;Z`hwt|UXyEYu#{n8Re7`q91BdTF3DCgd z`+Wf#ID9`dKm$kL+#jHUqi=p1prKFj{ej@YfIh+ZVeqp64&NUN(7@sQ&jU1Y`2KK! z1`gk+1!&;#{gD6-9KQb|Km&*GQ}P)N9KQcDKm&*GGvzZHID9`VKm&*GGv_lJID9`l zKm&*Gv*a@xID9`RKm&*Gv*t4zID9`hKm&*Gv*j}yID9`ZKm&*Gv*$A!IDG$AfCdiV z=g4O?aQJ?HfCi4fnKPf!z|l7s1Ze0Je4i_y=MLx-eE)TDVE~8k^W-xcIDEe-Km&*G z^X4-eIDEf2Km&*G^W`%dIDEe(Km&*G^9N|)@cq&N4II8N5TJp>_saq_aQMDpfCdiV zFAvbb;rl`X8aRBvB0vL&?+XWL;PCy*01X_zFA|`E!}qHKG;sL7Xn+O|->(kPz~TF1 z0U9`bza~HfN8cBehwm!~XyEYu)&LD0zONFXfy4Jd z1Zd#sn^gleaP-Y>0UG)Q-&YG(59kwo|6}l{01n^R2++Xc`=0|eaQMDvfCdiVZx7JG z;rm(v8aRCaOMnIr-`5V%z~TEH0U9`be^P)34&Uz#(7@sQIsqCue7`F|1BdVH258{$ z{jUKUIDCI{fCdiV{}!Nu!}q5IXyEYu?*SS(d|xj>1BdVb2++Xc`%?onaQObu01X^{ zvwnaEj=s4&KtrG4`_qCA0{R5s?+NY=;PCzF0U9`bzb`-ohwsk_(7@sQ{Q(*{e1B$u z1`gjJ2++Xc`-TA;IDCIFKm&*G8wF_K@cp3x4II8dD?kH>?+*uP;P8Fp01X_zKN6sU z!}m=BG;sJnW%iK<4&OHo(7@sQOySYM;rp`#G;sJnb2v0`_&x~Gz~TEW;n2X*H=6}$ z;OLuK!=a&1@clW#a|8MW-)9RqdjN;;n+Is%@O_SOXyEYuc>x+Ye4jHM8aRC4B0vL& z?{kGi1BdU=575Bj``qEsz~TD~0yJ>=K2JC_aQObh01X_z&l?U69KLTEpn;=r<_m`g z4&PrCpn=2p`2#d?_`X$u1`gjB2++Xc`_=&(IDB6)Km&*G+XQIf@O_~G4IF*5ZGZ-j zzF9axL!aRLcEO7S`UKw>2^J0D@cktL8aRAkEIzEpq)4&PrEpn=2pr2{l@`2O+$4II8N6QF^^_g4gH z;P8Ff01X_zzcN4rhwsY;XyEYuRRJ0}d|y651BdTB1!&;#eT4uG9DTEMfCi4fSusE} z`oEip#%GqTk>wRokuJ3)z*L1C~rt9@; zea|lS4NAJUcU-#G|L>;Xwc8r++-;33hxwn0xL=9yC~0-(*YfXf`kLRTe{a(pYq@$o zd854LO&cd{-uRNC@py)1(#8{e(&~*>Z@y9fq;kEJTiSYzRbQ`jY%AyWOxN<)?0@Lh z`yYDlF#j_VYx>HTZ94g|d9U-GQtq&lww(D!uW$L9-)^XB-THUX z#>=3Mr$N=rf4y8sojkMq>iy3g7}c9@HVV}8B9y!EwxaL^auGunR#?`yH`tAn=BchP*Kd@XN1>P)wD z#dO#6I`T&IE#J-$U3qmA(|VEX2JQSaXy>*r-Of?drQ7+d%Wvnif%=+m=etf{>s4?4 z#y;I<6CHJ3SD*D(eLIg1{y!eO=LgTp^*n37=kw-MSFWC?>-oKwujlKkZ~fC zd;j~k^KBciLt|gQe49T*&$XVP+k6-ry^i{}E_CNx(`{Yo@=eRP^`bi`w{>M`^c-7t zp7;7f0&4n4ndh)}9vOOGGPd)~P~9>U19j@q^OO8KE&s_anr`Q+K}!$T9r4}y$#c-$Ex%oV z(9V0^`NeaN`JQ7u*LaTk!KnS+`NeaB=K;?d&8P1C(fk}3J*ODed!8`=@=^bG=YZC~ z-MOOf)AF7l+V~ilcHcKz-g54fbzgLUG`f%WMRmr$>$y+4|G7W*?PKPh>yv+b*&kZJcl(6tHjakw1FrY&+%`0AbbqkC`$%2yP4~TDXybjl zeZhR+PZ-@-+&8Xk>$&T=`+%|T1LjXGOL?zhIn!-^cl(F$4J`NNww||jXV})UVOz(# z_Xt01I`-(@h7Z2SZ z8b96s;PbEh$1J1r1NR4?UuSOl^S0=I;C^B>|ADoW`-J-TPd za6fQ=Q0IF8{P#DJew)X`8r?U1@9aLI&h_5s z0`~=@y!(Uu$QLFqF!?^&=Z3GeeD{mvTe_`xL*FO6U$k{`=zdYldmW!2+#lAP7#LHB z?OZ=}fAD$1{lRiI`kdjuVA}noy)PcL^uYa~z5nf=BOaO-pY&qK%iq#O1PosB^uq>%aSh z(ef9z{lV+Fj<@mKt>bMRcl&|w@ys_`zU~9^HQ)8W#x{?;_g|)suKPyI*L_0X=(^w5 zvw`V$zU}shwqA9->wY`;4&=R#<<0jwjF<9`4iD_tu}?bAbCoeLrNr>%RMf@12ZZ&+GeK(Z+4J?wcO>{NVa; zw47<*FPS#BdD!g_uH)_x?hCH>zCV(8f4HLv?hBSPZFHZpocqc=Z5?mv z?t3`bf1elbD*J%X3wN}9_XW$jKbUrZ@cmM2Z}j_cl~yK_c_An1HX5=xUKi{ZJZ1&e{ErYx%m~kK@PfKeayZ&-LH++~)-IUGLowT<1;u{NTQ!-s_pK zzK#E(&kODgrd`*~S6|;B)&1er_Inuf)w{kM-3R)j>%YAFKwAff7nOa&=LfG}_Xqa_ z*LU}eQ`>s)I`8v=-#Z-Dc%L8Idz9{Z!hOQ;4g6imrfq-Nq(#sDHP+viwDo&f_Xoe% zu)Ob$e12GARL{Wm-F@Shi2*yc%b&UFZY%kgGd|dOe}7S*AAC>r{gFQd_lFZ&`nVRq zSa_c|>V8n4CtUAc|J@&4-{pONa6fP#@cF=f#P?3_A7{7y!Rxypxcap zdQI>1LR$|9mh<}m?fs$M*L1&cb-nfZpsw$g_d4n;U(46^z4Enu)%Vrs`QG)s^>6on z$@Sj+s&jvkulkyH{cq!cy5|V_HqJZVe51T+pC4-e#4_K!y6y7x=1-Cer*(&^NjZ>;6|(ysrlKL@V+#>$)S z_W&)Ybj?){Sde`-8t5<^SdVROQE&m-l(W_1$zm_q)zl-u=So z4bzr4?Q@6gx%-3XeABM)e*fTeg=u;7O&h(A(R2N8+PUBNOZB~w?~~;HUc$7`3GM@R z|4`@iK#e{(xUT!0V7}i^`@CWF{gclR>dp82WuFJy@1}=75BPqlM)j`$HL5pX{d{eI z@VxIj?)xHtw>@#3Jz;A1du^WwR&3?ld$I2Ql;3;H`#UJtaepuE_sY$OZl9>n0qyr; z1D`Y6?*Rt2T)n>g!Ubg=Z_kb0@0i>d+H>Z>_fn?)-r95<9|Ny%+I^uuH<)hYy8C^w zX?e>V+qmz(w=m!6`tJJedhYur^NsQ~ZNASRM)QrX+ddbV_Bo)fTiy2#rd|I{tM_|` zwtjWrU#RtkIvO}Ftf zbp5Q+_bNuu)uw%)-rnyHjddOKcQ>woe($-~M2Al8es8mCOZz>lfB)j&&&)L92fnB9 z{d9XD(*1pj>x=I{+B)6+{f6%+Tqk_*VA}W4p7(sO;5;|&JU9Bjq0Ud|v$68dTc6jB z&R3)Pp4*&{b)Gm6oi9e`mGLpoqhTGtb$r+F->SZ*`}B@)&nJ$1=ZU=M4|&IbeXjIe zVQlMc_d997XYzX})2;uz-$6TH>bb!E-}iz>f2ZI)aR2x3y6X2pzAv1s%?scAneX>B z?$d2Q@BSXj{dJ8tZ=4s7cjtlQ-Tb=Gx-a{F%=cx^5Az-W&J)v)`{sA|d}P}3U!(h& z`;6b0I1kJ>%Db;PFC71-+c+Kg`>DrkKGgR)bv#$T-B-7tRDGQv>K*rvchBoa^J}c@ zzG=t5^TB-Q&n4|#-OfKl_kp(V4V@>>2lG#y_;BX1eSbLg_nQ8$-{^cWI?g?pnl_r> z&Y#`;@JA*(c;6#BKlORJ@@;;0 z^I_b6BHw%%ez5#b&V1*E^Tz1-_W9ItZ_V7#@>2Y(0fKua5ap7VFbKG*queU1L!%l*Q%&sS}o82DV& z)`RYO$nkHKZ~k__$2DEYzwgid9;UsI=)UKu`-S7*`QZNG_^z?7&)xHe>Bnn-sO$T< zwClak6LmkR^To8|+jEfnK+Ugd$9Ij+2lGukFMN;U`xT?_Q%w6l#d*=z)9!cuj(g{W z^Td4hb=`NooA3PaIYR#7HvVU8`$E$V{9TOiIh+rkr<@0$AMIz|-%GXUn(lo=-5=Wf zsP6ag?gO5mJU6xdvip0g=5zOa-!~uX{P24}$GOq*Z*>1~zi=O@>wg=6-F$GqJYMsm zj&H|r-*_K4{wr_Vc~E1W7tROs9pA<}?%g-!P5XT8Imxu+-sm~WbCd52-4~4R3#NVV z=zM73?|19Jzeh9rp07sFOa5NK-<3HZoF8>Q`2CFU-P+&R42p=VBq)X<~#oDJaImFUaIFK=Sdr{-TZj0=cPLSYr5T6 zcRq4_J6|gA`AFXLmgC%Wk>@0%eDkUM`{g?RYue{*_X*Rk`+d>*V01qC{c0O;!}hz8 zVf&q77k$2VemL%z8m;r)-}ky7`2M^-4|lx3d%1JM_^E^YTXf&>yyX0FUiiBfpA&q3 z_IHz}>wNJ1<8y=05#~EjYHaWK2A+o;?=|f?$>_NMQ2QN;?~#n|4>k79hdM9XczxXF zLml6Bzo^gC^*mL}_x*bSey`>GCC9(>qi^4E{5#%F`y5^KO?zH)yqor%WWH&iAKEzT z&P$GW_XnS^{ocs)lk2|cAm@is-n7xbJNJ3n*!Y3z8r$#a21d_MJ~ucI>hreygZqK& zfAga|A2~nFZ@zc$l}!6Q?ffv`bbD{u{hq3hd!HwaZ5(v}-bWqpZM+TYxk=q)-5=`s zt@ELd_nNNrqyBw^d>!w7Y0pW{7tcY?1Ecw#kDLdleNJ%P*L}i#qvs}nkLmXfJ~x=} zzTi2@`7-LDsl$!h{_w08H)zrCA=YbY_X*d3qwkrFo|k-%Xz#1K_ep-Q>H8+k-tLIVA zhjIIbyuUZ~+~mAy?H`(UemGxT_Z{b^jec)!+Wo=t-ukus{>^-&^The^nTZc)4nN-F z0WE&EMfZjJyG_^o<=VJky+nEEhxP`QW+8`C!`U_&4pmaJ;vE?VS(mTEBO{TXx*L z{+o8cFfHHK?e5<<_4(O-z~=|&f%Bt1Z+G9bxjz`)4{CJ0JI;;fyI&aP>v_m@jm`t3 zp$FXVO7dbAC zj_0|+)$EDA=j=z1ziV(@cE5XYJo#Me_%POS<2dMx_P4Q)1N+zW zvF8Bu?Z3YM9oMgY>yG{AdDG~6;kmNN}U?K9dg_s4cW-M`~t|Ms2Z zYWr$`x-ZoEWc%9sHLUGx+% zw%^g&Ewvt72+b=WwreRX`=e@5HqJaqoq zPS?BIKHpc{KHsxBKK&h5-Op^F>yqn_-;dia$7yX}ZBHGqk9PjqPTOTW+kW4DKjr>! z`|Ll*r~T&qYv-V@|6Es%j?2FG)%Mi(w(E4yEuOpVN844$r|)AOpQW7xe@|h%Y^Uuq z`rh7ldVcU+ZT}f-|2^9FIse?BU0-aU`?Bkb{n(yUhK^7BukFX(@AGT>#;q^*pZkLA zOl@ClclR7y(~eJ{KW$e%f4Gi1E^S|Fm;at$_wO#bt{7ck>_7X>b=3Yd+Aiaaw$Js` z=(^J0Uv$4aa(%H~#`gCdLw_gKzAqm5yU?cVe#c7$Up>K`{ zeQM*i`}+w0{kM7!@I9vW)qbq)tLGHgeb)=0vwXj6`y5ZUPk-yYcbqtGY@g%7`r5uY zZ0nK#j$Ze78f`vw&llEL+gHEGvOfFI_lDNz?*Kf1IKCWLw$E|o{CC_`Kb_zH-obgS zpYAWNyLF$e^;JLn#*6K9yjY*_Wjz1adE>ltd+vl$lmG5@ZJ+bKufDb(4Xw}l;CN~MFx~T@ z?W^mh`+)nK>x=uE=g9R&>tgrcqp5y6-~Ani_0{%SpY5|g$BXT2>u|T9xSrWQ`>&3d zR`1YpYBax%vteC#>UvPm*Zv;P{o$!2Km7f3_q$E!ljF{QF*+VxC!NeIhkpZ-{%&l~z+|M@+y8r1fPsfGh!TIid@OzlLe%im*=ecd1pY~sUKCu66pZlNZM%!oq z_0`w6Kh)<*>+|0Sbp7=GWZnO)uRaG>Ki!X-FT?7m^?81*^|gNJ{(D2UzB*p&`sw#@ z?zip_*5~+qw0@48f3{CQtz{-B?=KHKN-3!U$^egE$M;B$!WtNTNrpLKoFN1yxZcy)a?ZU%nUgdx82p9Q(iN2hJ<~YW+HJe{kKhzkKei>x%1V9iO!w-nZv@&)0Q-@P6w0 zQvK9NeYHOK2gi%gE7sTkK4Rc{=6S+)_pL8=K3JdYi@#T~KRlncdDzW|+CKgD``~eY z+P-$3ZX9^t)lb(K``PyS{7~zwe!4%@`EL7MU)=wypSAz$xT))>^|}8!UYzf?Pd^>U z)z7~EtL>}%gU?6S=lRq6Y@hqB>x=c(_SN}defsJ6v_8+D)@T1UUAKO=ao7DjrH+@{ zzIIbhX?^of7&3L}dmH_1=iTn_-u!*Vqpi>O zxgYs=QogUXeeMs=_u9U?zSQw)`|LmKtNVlJ7te!ryx4!WeXe8nqtSflhv!812Y)Z* z{TTJ#`*Zy>x<9yHxIY-%b-M4#oX^JQ$DrL;_j};_-0t|S^TG3k>!<6P^TG3(_viCN z?LXJgI{&JF&IiY*^Uw3V>x=bOA6!5C>Z|RuzwD=4pXYh^BkQZ})89H?`r2oGu4kSH zoe!;@-Ft59vtQjGYJK&5<~Vfz*?;<3*E7%8wLbl<^RM-1_kBn8)8}NLkKB)3KYc&p zIIiuh^;JJ>eYVf>>H6vWPy5fm`*nS>|LXXx?Q?z6PupjGoXY-?=Le&{IX-NU(S5<#*B3ny*`0shN zbBg1{ant!>`(0n^`!w6vSD)>(KIen$SzWLFeXI4^zWRLIeD3Ch&nvc1KV4t!fA_z> z_1gJ2u0F@3^|gNK{yU}ZxnZoIwy)0j>ZkLst}l*n*K5a%>t{O`cjs%zZ5^kzzIuMC z?W@lZ*5`Qf_YStNjsNa^UF)lU+JAMuuI;lv$4g)P>Uhyl&%4&=dgl0S>qYmz-1=NU z``TCQ^E^@Ob9{Q9aQ)QJy5HKq>SwL5w$J{veeOrKeXcLQA9THL{nho~xcXd=tD4ZdG;UohGqM)x&iTjvIKf2jV| zesle-`>pM<9p1O=wd2$I;QsFYI6kevo?rU>b3L;@{i)9nKCf7x^UwO)_~;!k&IjA) z^Sk54_0#oQ-yJWu&++2>JN>NftK*{Gceh^G_O*5oYWv(DYJIi;nh)K7U&Hmq^}6<- z?W^_qJYDyP+CJ;6e%gPvKHKO1;Pan;)^Xa`KI#azbzSdXyao4Z<8BN#r)be#cR({<5_k8cu z`B|@D)8p!^{?zjI{>G(i`I@eN)$vikXRi7gt-tE)e5!oC-*M?$zWQCuSH7m}_4?B8 zi|$vR<9wgtxxn*QU)uM%HL5qtTaRgZ@56l4M)TFT_g>xaHOx0!&UUJ|Jzh_pY1?l( zdCSS0Z}fXCb@kufvVQZe&vIVJ^0q@=&6oE+)fwgWTb=o))mwj!RcCp1mN&mI>YIAY z`}aDQGhe?<*K)S2Ms-GgGi`fn^gQgj-{&{~{;l$+)p_3Z9AA0!ja6^H(d&90qxn8p zn>PBMN#5(3R%iaWw7;WM_h_%<{Z_r#@jgv^Kl)#z*HKr?$y=|y(fTZ}|MHf%UekTo z^E#HV<>VbdUe9{vEpI)2`SR+$o@whb%6mPddU?}E>+w0*=MCR880G!Fg6SG9Z@%do zeJ=HRO5S|aebI8(Q}450r|N7+)%kk`^DSqTx4il4>wS3t>MU=5jrF>gGg?nACvU#@ zVY)B+?<{#=)^EP$(%-!=XHD^WI6Ti-!1EYFK52@XZc#r_L^@r-{^f9_0RXUma{(7M$6fc-k;Iys59UD zmiONgupaNjwDlP+=XH(prj6F;eX29xe~-|7>o@Iv8_l=hjPiaD(7u-))U>}7^uNpQ z_nNCrJdjNO_p{9RcUyiR;(N9l{r4IDJ9v42x9;ze&2PU$>;ByXe^2jysB8aSp633Q>zDCQn?;i*1{ktT6s=VL7o3Ah4Z{K}*U-pB#dL7g1y}o+y)B7{6 zKc+3G&g;t8wEoyH)@QWey{^}>J$@fo$C1~yf9GuDO8+hA{X1T)*Lu8;_pMG|zl^rK zM*n`I{a)PfxrgSr^3$bT|8{@p+I;BJ{;s&y*S&}CyRN@GnS11ie>c=!&%fhrJ`DYS zuldy7xB1P7PS^Yz`uhRz*Z*Es`}^bWI`uv+=kMXXzQ6x7?ftcW8Je~}zdyA-mh<}F zr{%2AelXv(rwA@9EXlC z>-T=td42f}+PLw0>W%v5{aeoQV!5_|4BP(HeXrr~b=y8NZ2MgIyLR<$zZv@Pnwqv; zjcp(8{+(d2YdO>YyQyuT?Ebs;?YuB-`(>B!b^UiQOk02b@4R{c^44#@zQ~(z{cT_F z{8DE*_1=e3UA<3v%d7J`roB(oUdOceXSBT6HDCYiXZfnPK6&f2ob`JD{yWd=EGKW; z`t5J;%lf>Jc5dzdolvhM?|;9^`r7Z{x^e3LS+8lYYg)cNUrhJ!*0txO?!T|2&e)zm zI^MLgJ>LvX8{6~Husy$Z|6WGrYkA96UCpoMtjG5F_c2DxtFwJZ^VNC%nr_c~)3w*@ z)cZCq@AYcz+!y;u1{}$Ms@mGujBRAnXWq1#;UWv_WeZn-*YqFz6a_4 zdnE1qknZ0VkZ<2-O!wc*ZQrYO|IU}?+xH@!-s`AWSJUQufAU82)tPU7^8UTO`R#k0 z>F(3}>MLiy_0;Hf&2QgB4UPW0&ZfOypPzmCmb0F|XuH*0Z@q3UFR!n*%lxW0Z9PWI zS+6={-}TJ5y!sk#pZSlrocCwB_PzFS;&CMZzIXc`y!-c<^ z`qpQDy^iI)o@t}y+wTR2?RN-Wy_Qqw_0`FnHrDIc@?OV$qt~;1jg~Xta;A;yjON#< zZ|2vu`L@gYOzT_Uef#gr$Xm|qc>Q{x-iLb28>`;5yw^2)pVn)%T#c3+r>pg~-+K+8 zh&XWb6Fy7~g#X|B(EX0B&5JI5{i%Chm;WCaNsu;<)A#Y$w(Ioq*4M|6EB~LmKd;+& ze>b#t8T;DrDNEnmk=z5a||ua>{D zjOTj2YYJb>+dl8J`d9VpELZuOuKJp;`kEehKUH7T-lx~8{EVjS{d-;Osn@G~EnoYq z>g)Aty4G9y8BNb<{o}4*$7j8MP1ox^-tDW`A6Nfl)z|*6*L%F%SI1NJzt&&VGwMez zU(=6w`|9<_-S0SlT>p%#Z${f!`(xbw)%t6?Ua#_XJls_FgId1oXS98_e7&D>>2c*} z)UR>ZvwdE7M(=M%$IrOy&nW+&ZlAvB(~REVe@g$OiN}E}2dA}oMvLb6MfEkRH-9uu zCa-@=yT17~TCT==U-GrSnm)a!J(f3G?&O~PQ)g6PqxY$YdQ5b+O8U_&U*C4w6W^Fp7(3IFV^y2*I0eDeMWWl z`ttSqHQ(}m(em=vW7=qbjg~j6uYOuiooQpu|MIF^=Kn7p99W|H|LJJG2etb9>Qg8G zXwy|^`Nu1MvE286y1vKjzW?3p*iW^cHQjf8%lGk5LmXojPue5c=Sb59!#adsVuIATrqvw+I2czew$=H`adJZ~&FnZpb z)Q_I0C(~Zf>x_$4Z+i6JcCtRNBR?+vXmz9K|MT1TER(U8ukDsM>W}yB{aMa9F2C|# z*Zi6`zeexN_F1mxo38g~zOi24wB_nJkT=Sk_I~>APn}Vn^_gFz*EL^#&97M zn)W*0pXsWzyivXWnzsDS69>Wb2l^&&d852(%c-x|uW9R3Z#3Un%UPei-$fS&w9WA>H6wAWqq~XHSK-sztQr>sx!ap z)ji&^-uLMH@+bcH2?w5V;0XtwaNr3C{?&oD9}e5TG5pfR^U{e!^G9)7<0s>2-xC-2|; z9<_h+KE03jdxYUgcinLGp6C?EC;Q2EwfBl$Ka701bUNSl+jdreZJ%-U{rt2xZYJAjJMHJu{are2zZ2=| zwI179>l>AyemsuyC;P9x$8GmeMal4?dzKlqjLTI=Qwd4u^yxK8Lh`y z+h@C+_oM4f>*js?-lLm`)>G$$^*JAmwLbgJdPi~EaCF|E*3EP49r2Un)Ahw@JtKYp z__RLTXTADpw0+iVyNuRntnC|>@9#h7K^-r(zS_RN`r30+Td$`L>vdfp>-hfH`$^T!pYx-yocoaVjq0CVA8R?=XML8lKK-q})cfr7v)0#F z&imBQTA%khij(8N{f?_!hx_W&7uN;bXMLmlpPU!gXF2;}bpMxj=ZL=g^wV;-ug_2G z``0+R-#X8Y-iPapj&!_#p&m}_gUAO+Hdx|_4SRj>dUAd zlYV-iwSCT`(ext2MVAN0B=Q`;6QmRc@D1i{%iZD4cqS?x^tMmj4LWD8j%&+RUz~rV@{|2%`})dR zUmY)_^rb`lZ`}T%FLm7Z`QmucOuJy(F=DJkJbzPTSCq{A7 z&swh5tDm;Z_SlYk-`;1fPd}~Cei(P3wS9f%^riN@^*JAEeXcM1Y5OeKH_qIrN4m*% z!tr9cI$jQF?_0c2=Y#e2wQt0q*u9r=Jk4l1{q#QVzv|1le)m4>y#3d5{riLW;W#qt zTfKg*$8lzT_CvjHU;FBKvERK9&r7xctZx)2pVuvCedEg2`YbnY{dC>6-}S5dQ}5Gq z^*%@YTi^cP-@dv|=;t_J#@(m$q26a-xjK(5=Xh)}g>z3og`>Oue`C$9>b5!r-xu=%*{zkFC-^Yz>>+}BYhf)6YBf>N?fe52JQW{~S=;HyRg{>-^|F@cG?) zT<3c&r!V?h@6&R9^IbnJ=X|i-I6p0?FP0nSPv7s=*IIw|Ys62U-+T`C`nBKs`l0r_ z{a5|0_vii8`>6F=uC}L^^S=A;v-;_M_SHA4xBvawjPCEwhjI5={dC_Pcc0Gp(S1*@ zOXJ2_tr*>zPnGjFF1Z2cXgi{Jzq@v=6utK>c8V`blu7K zJ^JE&cfYCS9oLRC`_FN0IqSDR%h{g3`l>IMvp&m>(wBDc75mmR%juit`ubtSPpvJBB^841$$>%uRXSv#c_WMXT`JUEtbv^CtKku{l`?&j@QD5}O z`!)KW%IN(Y?I+vg`>U%)9Y5XosiSg}{qB78dd{nH{XV+>3kShU!R}j))&WNU604j2kRTR z?z%tN|Lza<{gOU=ezyINU+0597@g-v``zo;>)L;#{K<96a*h|vc^{UmzSMF)r@BvD zu8vRr7{$ro1=Mo2owdFZKY1>9e;C*Au7kCGkG8(ieN3KbYdPDepY=ZVrIxdO`r@K?HlK(=ax~NJb#X^Gx>d7y-(Zceb)Bb4|SY5AO1B?>%KpB+&t> z)Asq?U(1cVPse91=Xh~^+CJ;EeYGEa-#V&y^4w$ltj}|T{ce5rcO9er$#K+opMB-* zzj~j}qrUs>E9ZS$ew3d4etJ~T`Q7hQynoxTZ}s~1{;Dt5V?TIZuUE^D_{npY^TGRY zJsY>b_tn?e59980M$73_EvNskgWl&TJ^8#+%T-@2r=O0`T5jaq4BYq6GaA3fS>~M* zV!=75Oqq3pSaHg1bCNUj%%cKxE==|;GoAP5nJ4(W)}07b7F%|rz$`OOd8Ft6=6x~B znWii-Wx**+PI=yz+ibDz4qI-w?Jiqyxx-7ROj#=2g256&D(~)ZbeEJH{U7o6wML&; zC#*C2{OJF8$8CQ6sqHp@;a0Z9+qEV0-Zo{*>=XC7U+#1JEuO!{_FHVb`4;Uy7f-Xf z&)s+3Z`XbI*l%pLwrBS}_u6CcefNCp-mL^}{J;I*|Lg&D_SdLa?42o74p{bIuX4z8 z|C&Bx`F~9xx96ze%w2E!=l^Prn7UE0LZ|~0*9<-q{5AO5z6+&q~}Nan;24C!U@7w8YgC-w@C87nE30& zy@N%A3xmaiivs%e;$Vs3l3>Z;(qO6JvS8`p@?e?ZieTB`%3!(Rs$luxYCfmF)l$zK z`TV8CYZBiY%o$u8%oSW0%pF`G%oE%Y%p2So%op4g%pcqwED-!ASTOi)uu$;3VBz5R z!Ii0R)ztGq@a5o^BLJCmr1-daoNPn5|>N7 zJaPHND-u^oyfSgc#7k1&3i&(?4h~jI-aAs?&+>WYeExajDv8q)S55py;%bS%Ok6$j zti&}E&rV!3@tnl963nEO`__V|`5;sWvapKbxf0Fo{70nfTMh4HGX)eaq$Z5y97k zjgt4S)c1pYepWvJFmdC=BNI1CJSuV1#G@0Rop?;*Ao1A5%@U7Gd`{x=iO)?uA#wA> z6BD18cwy>WHlGg(z7cGZymzO*Z|3v!^ZC%k7bJcw@r8-sPTVr_u*4T79-g>W;&&3a zPMn&!P2zVGw@v(B;&zGOPkeFWuT$SL`TViqqroYu>q)`K^ZC@oPbB^*@so+CC4MUL z^u$jmo{_kJ;*S$QllYUw&nBLk__@TNCVoC~nD~XnpCw+9`mPDqO8OnaOL7mpCV#(t z-aeoAP23@IpTw6YzCCfr#J45BEb*<0FHhV%@fC@CCB8E8Es3v6d~@PXiEm2WIq{s- zwRAqeI-hq-J+DdJC3tPHD|x}|g585Xg4YLc2;LYhm2!I~zAok7l=$Z0Ex}&F-oaag zw*_wx_6hb4_6wFwxpyS)o^tO@d{^-9;61^6gZBmR4?YllF!)gL;b4iB`$*y*DfiLD zj|CqOJ`sE}_*C%eVE^DV!DoZd1&gQL=M!I_a$iV1AoybNrQplKfx$t+SAwqw2M1pZ z7E8IWC%z%&zL9uH@Xg@R;9J4BgTsQugYN`WgYO25rrh@u-l;G6hN5N^q>A@MnkAt5C3#Z(fiEm1|pC%52 zp9Mb;rUkzUei@t# zV7`>QFY)CmcYopo!Gpm=!Nb8L0VnpEf|-L^f?0!kQ*O4zSEStRiE{*V26F{-2lE8; z2J;2;2MYuX2J@ucLW!?TxrGxK2^I|&3l4!PPye0UzKvpC$12z z7_1bm9IO(o8mtzq9;^|p8O)V(YbEZKa%(3(DOe|1H+XXJlwiH!sloce(}E3xIaBWG zi94s>Rv0 zculZN@Y-P4V7K6P!S2DVDYr-BYg6v^iEjwr80;CmDR^`6mSC@7@8GS$+k#nA?$DH3 zH~3cY?clKB@ZdYa)Zn|p_k!;SM+83zuFEibQp&zMczdq1W%72;=Y8^dr^I~|UzNCD z;wuy1k@$+lcP73(@m+~8OMG|Yj*0I{d}-o)6L&~_U*h(O?@v50bx z4}u>CM+Qd)M+Xn5+%bvUrrfcK#|6g+Cj=)3Cj}=5rv#@4|A(u)fcCX4w6~3vAdP|o z5{e4a-QC>+(%s!9A}t`GbV>_|sEBlfhzJOXh)S1AcZvGl*Z+GR1Ae#I12#+#YwtopD#(9rwhiz4x2WwR-Q~&fms; z@w>P`ejg9SgYi)OAs&u@_1+_$YxmxxoqvqS;!p8-{5hV8zr~;`MkV-i){6?RY2NjrZcC-h01u zz25tv^Fu!tAIB&0ulO|n9sh~{#u($2>-b^s%n?6|Q{vP(El!U!;>~9+<3D0 zX6tii?f6W8oyGgHwR#@2=QTUW>Rh99?9SCY$LU zJ5T9crt{R!r8`gST&nZ*&Lum~=v<=n%+AF-&+1&P^X$$=JJ0D{r1RX)-}j&ON}Sj8 zJpJdK-}&RXATErH;^Md@E{)6LCvkcFv-hs(oVWL`?EGn56+ers!S_r`DIzW80- zAHRw7U_gu5n--6+evg;)?in+!B_*erI6{o?RAG0u+5;+nWEz8VY1=VJL-J2s6SW8e5*{2fF=LjPHD-(1 zV~&_J=8Cyvo|rf0i!aA9{Z0Qu8+Up`Fi{!rtjn9IzNtEVun6G zzO%1Vjd5S+S2|DVoUHS)&aZYpJ#PP;idW*`e(dp>u^)fF^J|@Nbbh__lg@8+jvF(@ z{v6-z;}<$->3p+u*3N%*&er+am_0rpbHwYtw{`A`n6r;x?3}Cft0z7X@p8@;zd?k_QaAHUSOKf+ou7*(W6D@6-s-(2bAOAa`}psj%XGfmxoqcuJD2O6AeN6W#tQLv z@6DTgGFI&4e{`? ztQ}LuI`MArO;hISShtT~>0Gb#gU)Ytjv4F6#IZq49UI1by*EjjXX4v^{A%Y$oga2? z+&NZk5|hNHF->e1@AuwVWuA@A`}noaEjmBy+_H1**eZOjZtM7RY!e^!-iI-NEE)^M zim_m<8wsJ!j}zhtabnDuJE`;J_+k7gPKi@v=GGbe1W<#9z^89$Ay;-h}v7K@c)z1Sjl zi34JmIK6j&R_>zCt2?jm{CVe1oxkY3xAT{sk9J2J4Y6nL z#?G7K=C~zpjoV_|-0hur#GP?h+#UDCw{ySgyf=Ou_r>qx{#ZTt`_2dA!FVYC5D&-F zxkox5jX%a?@uzq^=Fk1P^NILN{5Ad-PsTTMPjx;W&&0FwTs$As=3eN0FikXT$DNOKe$x5(-Z`}AfA#!n{5$>={|)~Sf3MtUI>(H$V(b_v#*OWA zpY0qk#*fd%1TkT3l$)q?;+P~Rjmcv2SR?oO&M(9iF=c!)z7)&krs|wJrim}dv@u;Q zkej}9hWJW+HD-*j#Von6cYY&gikah^F-uIBo3(Scm_6o*Ib*JvJU4geJTY&~7xTvg zF>Y?b&V^#(SR@vW#p08G-j;|}V*S`Ec8h~zwm7wS7cX}~=MtS)buQU?L+4VR_jE4Z z`EchloiF#!cY9v8=jCGgSRq!7m16JQ%AKpksEu}AC~d&Ts*y*u}bePh4aKMsh`=ML;VC=QN8;yZC@d^Y#p&cot+ad;dNN5;SU zd0R48jSXV!*gX!8+2fSnJ*wP~JCE-CY3DJW*LNPv;^f#T_ruN~#VK)WoEE3Y4!JWr&y2I;>^LXRjZJdrb)FwTjtk<#xG2`jUEFy| zTpE|fPvY`eE_X%emGRTKDt;DM$3nTEcm5)N8P~+G;@X%k_v_B<;`+EDZj75^hTP4a zx5TY+TihOZ#20dRcHR|t$35|zxHrbj{kHSI_+8u|zmEsv(|+ETiq&Gn*e3RfLt>8j zQSUxj?)=V&Ib=U?M* z@nk#|PsfhAXF8va=i>QzAzqA4b1!wi9Dk30#6RPeSUdM>=WFqLyb*84Td{oZ?ap`N z-FPqFj}Kzu+=rbX#mDhU{3||<*>nHy{7?Kh{FkB6#F+7w+*qAs$2c)=d^X05DRSd? zel8}631gy|IL6OS(m82N7L&*4;|uZce%_Xj)#KZ-ZR{D}i8oca)Aao1m^P-1>0^f2FZY$suf~k=wfK5`BX-Ko)H!o} zGiHfdW472VH+$zCF=xybbH_ZfPHx`L`C|T9AQp^;Vujqoor}bxu~;k~OT;3%B|Ddj zrDK^`HkOMya?5wF5G%$?v2v^uU(K!Bxmv6qYs8wdR!o^&yK|jbH`a@9#rpBN+y%6>k^UiBKx9Gg1bIZ;LI=AY4 zzITr3dF!6HiEU%M*gkfM{c}5Z?i4%6F0pIu=HuM%oqNQdu~+OJ`^4tCeLMGy{o{Z* zFb;}!a|d@G65okK==izZg92rN&(XnXmn9gJ4`*BbjihzsMQxHv9}|Mv5?Y^)g@ z$M&&zd^hHflX~~ka_4kj*7=jppLG7J^YYHyJFn>cedm>(&-KocJ^!@ltKw&Ib^JVj z5eMXc*?CR;Dz1%R$91tw?)uIf;>NfsZjM`Gi`=c9x5e#oN8A~A#d^8BJMW3##J%y` zxGz@9{jT%=_U=!@98bhw;;-?w+}}E%jHlx1 zcqX2WFXf)=d_G=?7vrUPIVQ~gz4IUO&v+$Xjn`s~+;aWgtreTZ4zW)h7W2f3`Pa*x z-T6l6Wu0$!Ueozj=WU&Dci!LmPUo||b5zgo_WWMFA0Nbr@lhO@`?&Ly_*Z-y|BnB} zuDSnq`VFSf#F#Nwj2&C%#_1e4J{#l3`0=^;R&IjM31gy|I3|fnW98gros-As;|noG zOc{&kzS#Mtm@1}@Y2wQ0u_1E9Q=QV&0f9K9gI%pS!hV)7UZgjqk<0@q_&Q<<9C{p!3qs1v`J)xlre= zoeOvVu5*#jXL{%8o)_(Tu~4n|E#zTgFzgb!-#! z) z=fqFqS8;p%KK>jh#o2LLTobp&{qcC57-z+$@yob1eiwg=AH@%8vd%oJaV{m1$LPniRH-Z%c2-EVOJ zd*^?D9q-N@|NHBGv*%gje}COsd!8+1xY=Wlkm2Txxk84UJLU-)&aYFSBQo6lu|UXh z3&uhr!z~<(gbcT6EEY00>AiUP8mCQqFA+x#PVXf{hSPhgkm2-RI%GJ#mkAk8?`1=V z(|fs);q+cUWH`N72pLZA6+?#8d!>-!Y+E^GINMeU8JqN8HGJLFCcRe+Ur*)qUOi+u zz1IjCPVY5ChSPhkkm2-RJ7hS$*9jR;?{!0l(|f&;;q?Ai$Z&eEA2OV68-xsJ+lC=y zliuGBU$eDI?~TIOaXGy=4jE4GO+tp#d()8N^xiCFIK4Ly8BXslLWa|O%aGyp-YR4` zy|)e-PVa3(hO=$kkl}3GE@W)dd;9P;Wt;TgA$*;g(|gB|;q=}qWH`Nd4jE4GT|$P_ zd)JWR^xiFGIK6id8BXs#LWa|O&yeBt-YaA{+x89_&bEC*#wNY@4PW!NN$>r_*TFfx z_YWCP?*l@H)BC`X;q*QzWH`MK4jE4GLqdkr`#T}S>3wL(aC(0?WH`MK3mML~?}ZF! z+ueN4!3dLJ7yoZjCL8BXuxLWa}(_>kfB zJ|Sc{y?+ogoZcsf3}@R(A;Z~ra>&@E_YcFL6|hO~AB8_d!0CNT$Z&d}8Zw;Tr-cls z_vs3v4XaC)B^GMwILg$$?n*&)N}eNM=5dY>CIoNecY3}@T-aii+PVZlY45#-mLx$7)nvmi2{#D3udS4qd zoZi0<8BXu(LWa}(`jFxDz9D2d+inaQ&bFIE#wNXQjE%Jg46rfkm2;cEo3;o zZx0zx?>j<<)BDbl;q<;MWH`O=4jE4GdqRfO`!^xO>3wg=aJKz6WH{UI3mKdA{#{HS zHtBtTOctEpzYiHs?*~GL)BC}Y;q-neWH`P55Hg(J4~Gn=_ah<0>HTQPaC-kSWH`Ma z3mML~KZOiu+v6c)liq)h8Nw#LpNQ#$)B7(W!|DCkkm2+obm< zu~Be(`|tNMoZg#-45#;4IT=pxEkcIVd+eMHr}tJN!|6RvPKMKan~>r39yce$*|uHC zaJKoHn#|~Z+9thyt;e6`v`O!sVu#@L_B99@PVZephSS^cjmvO)?-nwg-hR(khSPhG zkm2<9dx4w4~YGO(|gh(!|8oc z$Z&d3He@)x4+$Ag@5zS@r}v>D!|Cnooid!>hlLEMx39y=aJC&DGMsI`J|r`GpSH<1 zU$^jQVQtd;=r}Ss+x&jI45#<8A;a0`_jzSFy^jkSPH(^eD8uP}LdbA>`+YGPPVW;# zhSPhRkl}1QIb=B7{23OR(fhPbdQThvtgcOZpBg_3PVec445#<$A;anIYtb^C-e-mk zr}qpY!|8o?$Z&dpC1g0g&kY$)@2`doXWRK9!`U`t$c)~nZL;la;m;7;r1wQ}L2!D1 zeaLWnUlKB$-rpE9oZgp(45#-@Lx$7)@{r;5o_WY{dS4kboZjCYGMsH!g$!rgEJJ4W zK5dh2v&MTp+obm|;_BdRn{CK&dS4SVoNcoY8BXtOLx!_$jv>S8eO<_Kw#_+YIK6KO z8O}CeACci~yD4Ni+vX0L(fhPbw#^e`mbXdo+v1ksY@2t;aC+YnGMsJm4H-`FyF!Mu zZT=y{>3vVgaC$E=WH`O=4H-`F1&0i0+kGL!*|yM-8LJ=D`~GnEw8^%GW73{Ey&nh} z&bCE{45#-)A;a0W=#b&`emG<}+kEXxhSU4ekl}1wJY+b%9}5}Iwk1M_v+ePa;cQzn zWNgy=iI_fYvTdoDu4hi~zlIEF+tNdZ)BDMg;q+c+$Z&c;9WtEW%MKY%?`K1X(|frg z!|DBe$Z&cuKV&%DUJMz|wiSlV=zV(6K0jB?trUCpJbItzR*qGM%;-^*|x!u;a-amh74!hhC_yXBmQ@v=4|`+km25nkA@6q+eSl%dnf*PpXO}a zc*u<2r){!rllWoJqxWgfwoQkO-T(JK&DplukQu#CbGB_hWbFRG_i4_yEr!hKeVVgv z%OPX;|GiIhwrw?JM(@)$*|v4~_mMv7{r`KP=4{($$c)~nIoq}!GN1PT|GiIhwrw|L zM(@*{ZQBo-|MdRhO=$gkm1IO2}6dnZMTr&#*K+WhO=$=kl{WX6Ne0E+a4h^dY`sQ z?>)o6&t;R|lg1>$>AhFTaC%P`GMwIfhYY9pqxWf>^gbZ``(`%j{l%CvIK2-H8BXsng$$?nK_SEGJypnXdLJAz zoZeH145#-YA;alCO~`P1e+p*{%Xi@dLJ1woNY6P3}@R>Av1cPwn^`! zv)c8#QY_>`7d1Id7^gbPVX~AhSPh&km2+`D`Ys^777{8wzETK%r@w~a7@~> zO?sablMGJpMM8$t``nP>^j45#-6 zA;a0WWXN!~T^KSp>Ah6APuryTMKSH*^j;ns|`LWcWgToW?f+ObZ^aKDOcLxx*7)(aW# z*Ku9QjNYeh();>2yl0#AUO&DSoZdHt45#-7A;al?W5{rNZx}M1-ZzB|r}wu*hSU4z zkm2;+C}cRjZwVRBwv9uEv+dT98NE;2r1x!ca?dvDy=iO`oZh#G45#;IA;al?N62t` zZyqw7-gkx!r}q{i!|8oj$Z&dZ88V#ScZUpT+g2gN*>+FJjNYeh()%}Ye$O`Py-jQ# zoZk0_45#X zX7oO7lim-+RXy9J_s+3XaC$!&GMwJKgbb(mLm|WIy=%yDdjBD0IK6iZ8BXtqLx$6P z_mJWAek5c#+x7?<&bCKGX7oO7liq)fn|iiM@4aHr;PiehWH`O|4jE4GKZOjZ_dX%R z>HT=faC+|>GMwIj4jE4G{X&M*`-za@Y}-F%INSabGNbotoAmx`_?`|n>3v`v5S-qB z3mH!DgF=SW`^k{u^gcLbIK7_=8BXs*LWa}(>5$>{{!YkndOs5~oNb4O3}@T3Av1cP zwn^{j;_;qs()+OZZg6@(A2OWY-wPQ|?-xRb)BEs{;q-nnWH`N#2pLZAmqLcq`^b>t z^nN*HINOd28P2x9hs@}G+9tjK5ij;^litU~(ZT8c&yeBtJ~m`HyGzZNo_-p7Xwr}yh2!`XI1$Z)p35i+CqX`A$ZGv4XhCcRIL9|WiOTOq^g zeNxD9dcPeqoZcsg45#-yA;anY!;s2Lz0V36 zPVaw(3}@TfA;a1BX~>M;r)|>v-!XB|HtBtCoD-bh{|OmR@AE>2)BC?6!|8o~$Z&d( z;oqU{7+J|ABgGTg7?+K}O0**5Kv;q<;GWH{TV8#0`2w}uR7+w?)B?QvUhwtZ#DaC+YnGMsH+9WtEWcZLjS+l)ho)BCQF;cWZbkm2;cJ7hT9 zzCL6)+wKV&&bDt1nbG^SO}5Px=k;up-uK3Dg0pSrA;anY+mPXG`{t10^u8}-INN3! zGMwJO3mML~S%(a#_x&Nm**4pd;cWYT$Z)pJK4eDk(>B>QNBp#BoAiD#9th61Ifo3V z_d_AW**4dZ;q?AP$Z)pJJ!Ck&9}XGLwt0pOr}rZv!`U|Pkl}25G-Np2<{L7j_i3AK zn?G*s*(SXoi$4Zu+X6#|)B8^$!`Zgrkm2-xJY+cA78){~-hU1m&bEbz45#-KA;a0W z$dKV|`%B1hwkBxOY+G{3 zaC$!-GMsHo4H-`FXF`UvZRsJy+4gM6aJDToWJd4PHrcjp{HbS~^nN~`3(mIXh770o z3n9bVw)~Lc^nNj9INMejGMwHog$!rgibICe`{j_~Y+Gr_aJKzDWH{Sa9x|i%X`5_Y zC0^*+CcXa|{|L^uRfi0x_bVa8*|yq{;q-nrWH{SaA2OWYuZ0X}+ZscL)BE+1;cQ!T z$Z)p35i*=@YYmyv`?O8AtsQUoY?Iz^#hby|w$6~@^nN>JINR18GMwJ;gbZifdP9cO z``wV?Z2Q)b;q-nlWH{T_A2OV6?}rR$+Xh2s^geBqZ5xK~*JqR7AI1m4+4k)r!|DA| z$Z)o8G-NovKMonrwvC4jr}rlz!`ZgUkm2rC&-5(A*|v4aaC(o~vkYh3 zHX*~=HdfCvoNe2N%;eR}8q{_Wb2?=iQHWHEWjaC^r-A;Wz>z7R6pzOi4(a8tyTA;aw-2ZRjw#rRUl za0kXgAv1cPwn^`U(tGNdDmc9l2^miBX+nn6`#T}S>HX!9;q*Q3vwpaJEe!GMsJS3z^aTv`u;+9w+u}lipv68G_UMh>+p*{%Xi@dLJ1w zoZd5r45#-|A;anYwUFWTK00JLy}uqZoZiQT3}@RnLgxQ%>O3}NM(@)$>HYmUw`ZI5 zo;hX;PVeJFhSU3-A;al?e8_Nm&k{16-Y0|%r}wNO!|DBlkm2;6Eo3;oPYfB(w%J35 zv+bmi8NE;2r1!~jWzRP0J!i}joZdeS8BXuHLWa}(Mbwq-(wv+a_Q z8NE;2r1z!qSkE@;y<99CoZgp(45#<vzLAiEvaC$!&GMsI@gbZifLm@MIpWd;* ze}Cx5AC8@R-nDc0*dule?vZ#jWVk(JuaM#X7>|Vvw|DFlGTfiy@sQ#6jr~G~`*S=I zGTi=gK*(@^iNA&ncVHY8GTh(d$&eYnPuryTQ}NxNZPNRYI5;@HpAH#L@9%^Rr}r}< z!|8o!$Z&c;8#0{U-whc~@8?2>)BCWH;q-n!WH{Tt7c!h}FNDltZP5GhaQC!H?-%0- zgVXznkm2-xDP%akj|>@3@0UY{)BC89;q?A{$Z&ce9WtEW{|FgQ?_)xS)BB$x!`XIh z$Z)p35;CLrX`A$ZHO}eTCcTe~?+2&%YazqweSFApdcPhroZcsd45#-SA;anYgOK6$ zeluh^y-y4oPVcuuhO_OYkl}25J7h-h(>Ce-PF&HmO?v+@P7Y4*cSDBL`$r+e>HS{F zaC)B-GMwJ;hYY9psUgGZ{XxiZdY=|DoZcUX3}@TvA;a1BQOJzmr)|>vc@R^!``KaC)B|GMwI@h770oIU&R8{qK3u=SaC(oKli~EfFl0Er$I8iYdS4VW zoZe&SWH`Mq4jE4GadI-8ZI^@$XWO_rnbG^SO?rPe{@AlkdS4co2B-IULx$7)Cn3Y> zJ^qm4^u9b~IK4kNWH`OA2pLZA35E=(_mv^T={@0);cWY9$Z)nzG-O8a(>B>QaXi<_JtucdY`t*wkhJxo^8_m+W1v)woN%?IK6)zGMsH+95S5V*M$sc+n0t6r}yY?~#f8t&S9|1Rze&bC>H45#<~A;Z}=+mPY({(Z=Bw#`0dIK3YT z8P2vjh770ogCWD&Hs_GxYHW`;;cQ!V$Z)p35;B}^s|}ga`?O8AtsZChY?I!v#jC;D zw#Ja*^nN{LINR17GMwITgbZifT0@4@`^}KyY+HNCaC*NLGMsJe3>nV0w?l@rZQUU= zdY`t*w)Nujo^8_m-FPQB+rBkqIKAHs8P2x#hYY9p`ys>Gw!x6$^!^}ZINLTHGMwHY zh74!hw}%X8+eab8*|yP;8NE;2WZTAZUC%b@{YiWroNb#78BXtig$!rgrbC9)`_qu& zY};(eaC-kcWH{S4A2OWY{|On+wk?JXXWM^6hO=$UAv1cPw#l}w;+~#u()%-gJVtP~ zZ5=Y4-edMG!`Ze?$Z&d()w2v|+qNOY={AiEvaC(0(WH`Nd2^miB2||X`d)JWR z^qw$eIK6iZ8P2weLWZ+#_mCOAPuryT9`S6?Ht9V{OdOovdxi|B_oN}i>AhFTaC%P` zGMwIfhYY9p6O__fMPj{#wi!oZd%=45#^{H-9V;GTa$)X2@_0#zG;(ofT(?47YGB5;EL5 zac;Hv+XA#GkTx4N$<x2xa_q8Fz*|u)TaJKzAWJd4PHtBs`{G?}_^!`??7o6VLhYY9p`XR&VeM87_ zdT$UioZdHv45#;oA;al?Q^;_7e>-G2y>AW~&bEz0hO_OKkQu#C+oboc@#~&#(tDHG zI5@p;3mH!DO+$v$`}UCG^xiCFIKA%(8BXubLx$7)&XD2s-Xdf;z3&Pc&bBQ>hO_PN zkQu#C+obnBGCkX*_tvphaC-kHWH`OI2^miBdqalPd)tuV^!{zgaC&bSGMwJ`g$$?n z_94UR{kxFiY}+AZINR*|vMgaJD@XGNbotoAiD(p6S^pz4wegg46qt zA;amtSIBUBKNd2a-g}1(r}v*ihSPhWkm2-xJY+b%_YE0N?>~nOXWM=u!`b#k$c)~n zZPNQM@p{iT>3u-#ADrHQ4H-`F14D+>`)?t`>3vYhaC$!(GMwHAhYY9pQz66YeMrb~ zdOsa9oNeC;8P2w6LT2B*p~30>T*z>G9~Ls4-p_{&r}y_lhSU3n zkm2+`JY+b%Ukn*e?;}En)BB~6;cPoHWH{Si4w=#Wv`u>dJ;v|;X_MYZ$5FxQ{g060 z^gbqJIKBTFGMwJWh770oDkdjdp%@E@6$Hv z{YHFoxNGbEgE%2Lz26KOPVW;#hSU44km2+`DP%ak-wqj0?~_A@)BBx};q?At$Z&eU z8#0`2KMEPnw)aA2^gg|HfB)X^$3KW|dOoG|v^YIZ4erDEC}g-Z;>?iYK8{a9hC3_H z4jJxW@oC6#=ft@o!~Hw{6EfU+ael~f|BW&HZ)tUMKaLARhWkuzO#k~@F?yf2N$;_8 zhxBZd-WSD%!RbAAUWU{A;*jC=9w#Tm>3vDaaC(oMli~EfG-NovKbw=`^u8=)IK9UU z8P2w!gbZif_#rcTpSDTw&&6>)+obmuad~ihPcURSy{`-zPVWha45#-`Lx$6Pq9McS zeO1VCdQUuLIK6)sGMwI%3>nV0t3!sfZPFn#dY`t*w#nkmo^8_m7xDApY@2+@aC-kT zWH{SCKV&$)uL&8>wl54BPVZlZ3}@RELx$7)+K}OFn{vo-w*5L}INQEBWJd4PHre*2 zxU6TJ^u9i>3(mHwh770o4I#tXHuaF<^u940**5Kv z;cUAlWH{TV8#1H!X`5`DKCbQACcSTqTZ6N0h9Sf0eS64owtZ#DaC+YnGMsH+9WtEW zcZLjS+l)ho)BCQF;cWZbkl}2*J7hT9zCL6|@6$Hf_Kmo!XPfl?P23ZlZ8HrSPVaj| zhO=$vA;anY+mPXG`{t10^u8}-INN3!GMwJO3mML~S%(Z~+x;QK**4pd8NE;2WZUfV zaL+dB{XqOaINRnJGMwHIh74!hoI{4w`=OBGY@2JyaC-kCWH{UA9x|NX4~GnA+dM;t zv+a?P;cT0C$c)~nZL)2?c)Dks^!{T!8k}wO4;fDH$3lj)ZGj=f>HVjW;cQ!Q$Z&c; z9x|M53k?}g?>~nOXWPOl-Y

{}); + + nd::array nodal_coords = get_nodal_coordinates(u); + +} + +TEST(nodal_coords, triangles) { nodal_coordinates_test<1>("patch2D_tris.mesh"); } + + +int main(int argc, char* argv[]) +{ + testing::InitGoogleTest(&argc, argv); + + serac::initialize(argc, argv); + + int result = RUN_ALL_TESTS(); + + serac::exitGracefully(result); +} From 66e53d9015eb9ffa9cd168541eafeda11f58ca22 Mon Sep 17 00:00:00 2001 From: Sam Mish Date: Fri, 10 Jan 2025 15:16:51 -0800 Subject: [PATCH 13/15] giant commit with more glue code, removing some duplicated abstractions --- .../functional/detail/metaprogramming.hpp | 13 + src/serac/numerics/functional/domain.hpp | 1 + src/serac/numerics/functional/family.hpp | 23 ++ .../numerics/functional/finite_element.hpp | 19 +- src/serac/numerics/functional/tensor.hpp | 7 + .../functional/tests/functional_basic_dg.cpp | 2 +- src/serac/numerics/refactor/CMakeLists.txt | 4 +- src/serac/numerics/refactor/common.cpp | 11 + src/serac/numerics/refactor/common.hpp | 58 ++-- .../numerics/refactor/containers/ndarray.hpp | 6 +- .../numerics/refactor/elements/hcurl_edge.hpp | 25 +- .../refactor/elements/hcurl_hexahedron.hpp | 2 +- .../refactor/elements/hcurl_quadrilateral.hpp | 2 +- .../refactor/elements/hcurl_tetrahedron.hpp | 2 +- .../refactor/elements/hcurl_triangle.hpp | 2 +- .../refactor/elements/hcurl_vertex.hpp | 2 +- src/serac/numerics/refactor/evaluate.cpp | 175 +++++------ src/serac/numerics/refactor/evaluate.hpp | 5 +- .../numerics/refactor/finite_element.hpp | 105 +------ src/serac/numerics/refactor/forall.hpp | 288 ++++++++++++++++++ .../refactor/get_nodal_coordinates.cpp | 35 ++- .../refactor/get_nodal_directions.cpp | 2 + .../numerics/refactor/integrate_diag.cpp | 10 +- .../numerics/refactor/integrate_residual.cpp | 6 +- .../numerics/refactor/integrate_spmat.cpp | 10 +- src/serac/numerics/refactor/interpolation.cpp | 20 +- src/serac/numerics/refactor/quadrature.cpp | 12 +- src/serac/numerics/refactor/quadrature.hpp | 3 + .../refactor/tests/h1_evaluation_tests.cpp | 113 ++++--- .../refactor/tests/hcurl_evaluation_tests.cpp | 2 +- .../integrate_residual_Hcurl_flux_tests.cpp | 2 +- .../integrate_residual_Hcurl_source_tests.cpp | 2 +- ...nodal_coordinates_and_directions_tests.cpp | 29 +- src/serac/physics/state/CMakeLists.txt | 3 +- .../physics/state/finite_element_dual.cpp | 27 ++ .../physics/state/finite_element_dual.hpp | 11 + .../physics/state/finite_element_state.cpp | 49 +++ .../physics/state/finite_element_state.hpp | 55 ++++ .../physics/state/finite_element_vector.hpp | 40 +++ 39 files changed, 838 insertions(+), 345 deletions(-) create mode 100644 src/serac/numerics/functional/family.hpp create mode 100644 src/serac/numerics/refactor/forall.hpp create mode 100644 src/serac/physics/state/finite_element_dual.cpp diff --git a/src/serac/numerics/functional/detail/metaprogramming.hpp b/src/serac/numerics/functional/detail/metaprogramming.hpp index 66b7d4be30..3bd7910f89 100644 --- a/src/serac/numerics/functional/detail/metaprogramming.hpp +++ b/src/serac/numerics/functional/detail/metaprogramming.hpp @@ -98,3 +98,16 @@ SERAC_HOST_DEVICE constexpr void for_constexpr(const lambda& f) { detail::for_constexpr(f, std::make_integer_sequence{}...); } + + +namespace impl { + template < auto x > + struct value{ + constexpr operator decltype(x)() { return x; } + }; +} + +template < auto ... args, typename T > +void foreach_constexpr(T && function) { + (function(impl::value{}), ...); +} diff --git a/src/serac/numerics/functional/domain.hpp b/src/serac/numerics/functional/domain.hpp index cc17d1b7ba..8721bfe0df 100644 --- a/src/serac/numerics/functional/domain.hpp +++ b/src/serac/numerics/functional/domain.hpp @@ -182,6 +182,7 @@ struct Domain { exit(1); } + /** * @brief returns how many elements of any type belong to this domain */ diff --git a/src/serac/numerics/functional/family.hpp b/src/serac/numerics/functional/family.hpp new file mode 100644 index 0000000000..e43254f28d --- /dev/null +++ b/src/serac/numerics/functional/family.hpp @@ -0,0 +1,23 @@ +#pragma once + +namespace serac { + +/** + * @brief Element conformity + * + * QOI denotes a "quantity of interest", implying integration with the test function "1" + * H1 denotes a function space where values are continuous across element boundaries + * HCURL denotes a vector-valued function space where only the tangential component is continuous across element + * boundaries HDIV denotes a vector-valued function space where only the normal component is continuous across element + * boundaries L2 denotes a function space where values are discontinuous across element boundaries + */ +enum class Family +{ + QOI, + H1, + HCURL, + HDIV, + L2 +}; + +} diff --git a/src/serac/numerics/functional/finite_element.hpp b/src/serac/numerics/functional/finite_element.hpp index dcbab1f8e0..15c682730f 100644 --- a/src/serac/numerics/functional/finite_element.hpp +++ b/src/serac/numerics/functional/finite_element.hpp @@ -12,6 +12,7 @@ */ #pragma once +#include "family.hpp" #include "tuple.hpp" #include "tensor.hpp" #include "geometry.hpp" @@ -169,23 +170,7 @@ SERAC_HOST_DEVICE constexpr int elements_per_block(int q) } } -/** - * @brief Element conformity - * - * QOI denotes a "quantity of interest", implying integration with the test function "1" - * H1 denotes a function space where values are continuous across element boundaries - * HCURL denotes a vector-valued function space where only the tangential component is continuous across element - * boundaries HDIV denotes a vector-valued function space where only the normal component is continuous across element - * boundaries L2 denotes a function space where values are discontinuous across element boundaries - */ -enum class Family -{ - QOI, - H1, - HCURL, - HDIV, - L2 -}; + /** * @brief H1 elements of order @p p diff --git a/src/serac/numerics/functional/tensor.hpp b/src/serac/numerics/functional/tensor.hpp index 0b9eac3996..eeb30b1948 100644 --- a/src/serac/numerics/functional/tensor.hpp +++ b/src/serac/numerics/functional/tensor.hpp @@ -1274,6 +1274,13 @@ SERAC_HOST_DEVICE constexpr auto I2(const tensor& A) * @param[in] A The matrix to obtain the determinant of */ template +SERAC_HOST_DEVICE constexpr auto det(const tensor& A) +{ + return A[0][0]; +} + +/// @overload +template SERAC_HOST_DEVICE constexpr auto det(const tensor& A) { return A[0][0] * A[1][1] - A[0][1] * A[1][0]; diff --git a/src/serac/numerics/functional/tests/functional_basic_dg.cpp b/src/serac/numerics/functional/tests/functional_basic_dg.cpp index 6f5c205ae6..7154233a72 100644 --- a/src/serac/numerics/functional/tests/functional_basic_dg.cpp +++ b/src/serac/numerics/functional/tests/functional_basic_dg.cpp @@ -71,7 +71,7 @@ void L2_test(std::string meshfile) double t = 0.0; auto value = residual(t, U); - // check_gradient(residual, t, U); + check_gradient(residual, t, U); } TEST(basic, L2_test_tris_and_quads_linear) { L2_test<2, 1>(SERAC_REPO_DIR "/data/meshes/patch2D_tris_and_quads.mesh"); } diff --git a/src/serac/numerics/refactor/CMakeLists.txt b/src/serac/numerics/refactor/CMakeLists.txt index 17a3c9731d..7e549e3671 100644 --- a/src/serac/numerics/refactor/CMakeLists.txt +++ b/src/serac/numerics/refactor/CMakeLists.txt @@ -34,12 +34,14 @@ set(refactor_sources integrate_diag.cpp integrate_spmat.cpp integrate_residual.cpp + interpolation.cpp + quadrature.cpp get_nodal_coordinates.cpp get_nodal_directions.cpp ) -set(refactor_depends serac_infrastructure serac_functional serac_refactor_containers) +set(refactor_depends serac_physics serac_infrastructure serac_functional serac_refactor_containers) blt_add_library( NAME serac_refactor diff --git a/src/serac/numerics/refactor/common.cpp b/src/serac/numerics/refactor/common.cpp index 562ddb5509..4d8c7cbd14 100644 --- a/src/serac/numerics/refactor/common.cpp +++ b/src/serac/numerics/refactor/common.cpp @@ -47,4 +47,15 @@ uint32_t elements_per_block(mfem::Geometry::Type geom, Family family, int p) { } +GeometryInfo geometry_counts(const Domain & domain) { + return { + 0, + uint32_t(domain.edge_ids_.size()), + uint32_t(domain.tri_ids_.size()), + uint32_t(domain.quad_ids_.size()), + uint32_t(domain.tet_ids_.size()), + uint32_t(domain.hex_ids_.size()) + }; +} + } // namespace refactor diff --git a/src/serac/numerics/refactor/common.hpp b/src/serac/numerics/refactor/common.hpp index 7ea3fe8bdb..764d55a8c2 100644 --- a/src/serac/numerics/refactor/common.hpp +++ b/src/serac/numerics/refactor/common.hpp @@ -8,6 +8,8 @@ namespace refactor { uint32_t elements_per_block(mfem::Geometry::Type geom, Family family, int p); +GeometryInfo geometry_counts(const Domain & domain); + template < typename T > struct array_rank; @@ -27,35 +29,37 @@ SERAC_HOST_DEVICE constexpr uint32_t round_up_to_multiple_of_128(uint32_t n) { constexpr uint32_t source_shape(Family f, uint32_t gdim) { switch(f) { + case Family::QOI: return 1; case Family::H1: return 1; - case Family::Hcurl: return gdim; - case Family::Hdiv: return gdim; - case Family::DG: return 1; + case Family::HCURL: return gdim; + case Family::HDIV: return gdim; + case Family::L2: return 1; } return (1u << 31); } constexpr uint32_t flux_shape(Family f, uint32_t gdim) { switch(f) { + case Family::QOI: return 0; case Family::H1: return gdim; - case Family::Hcurl: return (gdim == 2) ? 1 : gdim; - case Family::Hdiv: return (gdim == 2) ? 1 : gdim; - case Family::DG: return gdim; + case Family::HCURL: return (gdim == 2) ? 1 : gdim; + case Family::HDIV: return (gdim == 2) ? 1 : gdim; + case Family::L2: return gdim; } return (1u << 31); } -template < Family f, DerivedQuantity op, uint32_t dim > +template < Family f, DerivedQuantity op, int dim > auto piola_transformation(const mat & dX_dxi) { if constexpr ((f == Family::H1 && op == DerivedQuantity::DERIVATIVE) || - (f == Family::DG && op == DerivedQuantity::DERIVATIVE) || - (f == Family::Hcurl && op == DerivedQuantity::VALUE)) { + (f == Family::L2 && op == DerivedQuantity::DERIVATIVE) || + (f == Family::HCURL && op == DerivedQuantity::VALUE)) { return inv(dX_dxi); } - if constexpr ((f == Family::Hcurl && op == DerivedQuantity::DERIVATIVE) || - (f == Family::Hdiv && op == DerivedQuantity::VALUE)) { + if constexpr ((f == Family::HCURL && op == DerivedQuantity::DERIVATIVE) || + (f == Family::HDIV && op == DerivedQuantity::VALUE)) { if constexpr (dim == 2) { return mat<1,1>{1.0 / det(dX_dxi)}; } else { @@ -64,24 +68,24 @@ auto piola_transformation(const mat & dX_dxi) { } if constexpr ((f == Family::H1 && op == DerivedQuantity::VALUE) || - (f == Family::DG && op == DerivedQuantity::VALUE) || - (f == Family::Hdiv && op == DerivedQuantity::DERIVATIVE)) { + (f == Family::L2 && op == DerivedQuantity::VALUE) || + (f == Family::HDIV && op == DerivedQuantity::DERIVATIVE)) { // this should never be called, but we implement it here regardless // to suppress a compiler warning about incompatible return values return 1.0; } } -template < Family f, DerivedQuantity op, uint32_t dim > +template < Family f, DerivedQuantity op, int dim > auto weighted_piola_transformation(const mat & dX_dxi) { if constexpr ((f == Family::H1 && op == DerivedQuantity::DERIVATIVE) || - (f == Family::DG && op == DerivedQuantity::DERIVATIVE) || - (f == Family::Hcurl && op == DerivedQuantity::VALUE)) { + (f == Family::L2 && op == DerivedQuantity::DERIVATIVE) || + (f == Family::HCURL && op == DerivedQuantity::VALUE)) { return adj(dX_dxi); } - if constexpr ((f == Family::Hcurl && op == DerivedQuantity::DERIVATIVE) || - (f == Family::Hdiv && op == DerivedQuantity::VALUE)) { + if constexpr ((f == Family::HCURL && op == DerivedQuantity::DERIVATIVE) || + (f == Family::HDIV && op == DerivedQuantity::VALUE)) { if constexpr (dim == 2) { return mat<1,1>{1.0}; } else { @@ -90,8 +94,8 @@ auto weighted_piola_transformation(const mat & dX_dxi) { } if constexpr ((f == Family::H1 && op == DerivedQuantity::VALUE) || - (f == Family::DG && op == DerivedQuantity::VALUE) || - (f == Family::Hdiv && op == DerivedQuantity::DERIVATIVE)) { + (f == Family::L2 && op == DerivedQuantity::VALUE) || + (f == Family::HDIV && op == DerivedQuantity::DERIVATIVE)) { return det(dX_dxi); } } @@ -118,9 +122,9 @@ constexpr uint32_t qshape(Family f, DerivedQuantity op, uint32_t gdim) { } if (op == DerivedQuantity::DERIVATIVE) { - if (f == Family::H1 || f == Family::DG) { return gdim; } - if (f == Family::Hcurl) { return (gdim == 2) ? 1 : gdim; } - if (f == Family::Hdiv) { return 1; } + if (f == Family::H1 || f == Family::L2) { return gdim; } + if (f == Family::HCURL) { return (gdim == 2) ? 1 : gdim; } + if (f == Family::HDIV) { return 1; } } return (1u<<31); @@ -185,7 +189,7 @@ auto value_transformation(const mat & A) { if constexpr (family == Family::H1) { return mat1{1.0}; } - if constexpr (family == Family::Hcurl) { + if constexpr (family == Family::HCURL) { return inv(A); } } @@ -195,7 +199,7 @@ auto derivative_transformation(const mat & A) { if constexpr (family == Family::H1) { return contravariant_piola(A); } - if constexpr (family == Family::Hcurl) { + if constexpr (family == Family::HCURL) { return covariant_piola(A); } } @@ -205,7 +209,7 @@ auto source_transformation(const mat & A) { if constexpr (family == Family::H1) { return det(A); } - if constexpr (family == Family::Hcurl) { + if constexpr (family == Family::HCURL) { return inv(A) * det(A); } } @@ -215,7 +219,7 @@ auto flux_transformation(const mat & A) { if constexpr (family == Family::H1) { return inv(A) * det(A); } - if constexpr (family == Family::Hcurl) { + if constexpr (family == Family::HCURL) { if constexpr (n <= 2) { return vec1(1.0); } diff --git a/src/serac/numerics/refactor/containers/ndarray.hpp b/src/serac/numerics/refactor/containers/ndarray.hpp index c0bca4dbb7..899f1164b9 100644 --- a/src/serac/numerics/refactor/containers/ndarray.hpp +++ b/src/serac/numerics/refactor/containers/ndarray.hpp @@ -525,7 +525,7 @@ SERAC_HOST_DEVICE void print_recursive(nd::view< T, dim > arr, int depth) { if constexpr (dim == 1) { for (int i = 0; i < depth; i++) printf(" "); printf("{"); - for (int i = 0; i < arr.shape[0]; i++) { + for (uint32_t i = 0; i < arr.shape[0]; i++) { printer::print(arr(i)); if (i != arr.shape[0] - 1) { printf(","); } } @@ -534,7 +534,7 @@ SERAC_HOST_DEVICE void print_recursive(nd::view< T, dim > arr, int depth) { const T * ptr = arr.data(); stack::array< uint32_t, dim - 1 > shape; stack::array< uint32_t, dim - 1 > stride; - for (int i = 0; i < dim - 1; i++) { + for (uint32_t i = 0; i < dim - 1; i++) { shape[i] = arr.shape[i+1]; stride[i] = arr.stride[i+1]; } @@ -546,7 +546,7 @@ SERAC_HOST_DEVICE void print_recursive(nd::view< T, dim > arr, int depth) { print_recursive(slice, 0); } else { printf("\n"); - for (int i = 0; i < arr.shape[0]; i++) { + for (uint32_t i = 0; i < arr.shape[0]; i++) { print_recursive(slice, depth+1); if (i != arr.shape[0] - 1) { printf(","); } printf("\n"); diff --git a/src/serac/numerics/refactor/elements/hcurl_edge.hpp b/src/serac/numerics/refactor/elements/hcurl_edge.hpp index 4019251648..ca74c04ad7 100644 --- a/src/serac/numerics/refactor/elements/hcurl_edge.hpp +++ b/src/serac/numerics/refactor/elements/hcurl_edge.hpp @@ -5,7 +5,7 @@ namespace refactor { template <> -struct FiniteElement < mfem::Geometry::SEGMENT, Family::Hcurl >{ +struct FiniteElement < mfem::Geometry::SEGMENT, Family::HCURL >{ using source_type = vec1; using flux_type = vec1; @@ -94,13 +94,28 @@ struct FiniteElement < mfem::Geometry::SEGMENT, Family::Hcurl >{ } } - nd::array< double > evaluate_shape_function_curls(nd::view xi) { + void curl(nd::view values_q, nd::view values_e, nd::view shape_fn_curls, double * /*buffer*/) const { + uint32_t nnodes = num_nodes(); + uint32_t nqpts = values_q.shape[0]; + + for (uint32_t q = 0; q < nqpts; q++) { + flux_type sum{}; + for (uint32_t i = 0; i < nnodes; i++) { + sum[0] += shape_fn_curls(q, i) * values_e(i); + } + values_q(q) = sum; + } + } + + nd::array< double, 2 > evaluate_shape_function_curls(nd::view xi) const { uint32_t q = xi.shape[0]; - nd::array buffer({q * p}); + nd::array shape_fns({q, num_nodes()}); for (uint32_t i = 0; i < q; i++) { - GaussLegendreInterpolation(xi(i, 0), p, &buffer(p * i)); + for (uint32_t j = 0; j < num_nodes(); j++) { + shape_fns(i, j) = shape_function_curl(xi(i, 0), j); + } } - return buffer; + return shape_fns; } #if 0 diff --git a/src/serac/numerics/refactor/elements/hcurl_hexahedron.hpp b/src/serac/numerics/refactor/elements/hcurl_hexahedron.hpp index 3efb391df9..01476f85b5 100644 --- a/src/serac/numerics/refactor/elements/hcurl_hexahedron.hpp +++ b/src/serac/numerics/refactor/elements/hcurl_hexahedron.hpp @@ -6,7 +6,7 @@ namespace refactor { // clang-format off template <> -struct FiniteElement { +struct FiniteElement { using value_type = vec3; using derivative_type = vec3; diff --git a/src/serac/numerics/refactor/elements/hcurl_quadrilateral.hpp b/src/serac/numerics/refactor/elements/hcurl_quadrilateral.hpp index 1df2144378..b7d44200a2 100644 --- a/src/serac/numerics/refactor/elements/hcurl_quadrilateral.hpp +++ b/src/serac/numerics/refactor/elements/hcurl_quadrilateral.hpp @@ -8,7 +8,7 @@ using namespace serac; // clang-format off template <> -struct FiniteElement { +struct FiniteElement { using value_type = vec2; using derivative_type = vec1; diff --git a/src/serac/numerics/refactor/elements/hcurl_tetrahedron.hpp b/src/serac/numerics/refactor/elements/hcurl_tetrahedron.hpp index 5f3dcf7eae..c6f8e13d24 100644 --- a/src/serac/numerics/refactor/elements/hcurl_tetrahedron.hpp +++ b/src/serac/numerics/refactor/elements/hcurl_tetrahedron.hpp @@ -9,7 +9,7 @@ using namespace serac; // clang-format off template <> -struct FiniteElement { +struct FiniteElement { using value_type = vec3; using derivative_type = vec3; diff --git a/src/serac/numerics/refactor/elements/hcurl_triangle.hpp b/src/serac/numerics/refactor/elements/hcurl_triangle.hpp index f5a542ce26..70feba60cc 100644 --- a/src/serac/numerics/refactor/elements/hcurl_triangle.hpp +++ b/src/serac/numerics/refactor/elements/hcurl_triangle.hpp @@ -8,7 +8,7 @@ using namespace serac; // clang-format off template <> -struct FiniteElement { +struct FiniteElement { using value_type = vec2; using derivative_type = vec1; diff --git a/src/serac/numerics/refactor/elements/hcurl_vertex.hpp b/src/serac/numerics/refactor/elements/hcurl_vertex.hpp index c41524767f..1a7d6c2a28 100644 --- a/src/serac/numerics/refactor/elements/hcurl_vertex.hpp +++ b/src/serac/numerics/refactor/elements/hcurl_vertex.hpp @@ -5,7 +5,7 @@ namespace refactor { template <> -struct FiniteElement < mfem::Geometry::POINT, Family::Hcurl >{ +struct FiniteElement < mfem::Geometry::POINT, Family::HCURL >{ SERAC_HOST_DEVICE uint32_t num_nodes() const { return 0; } uint32_t p; diff --git a/src/serac/numerics/refactor/evaluate.cpp b/src/serac/numerics/refactor/evaluate.cpp index 2a2b9f2081..9e1e73b121 100644 --- a/src/serac/numerics/refactor/evaluate.cpp +++ b/src/serac/numerics/refactor/evaluate.cpp @@ -1,4 +1,4 @@ -#if 0 +#if 1 #include "evaluate.hpp" #include "common.hpp" @@ -23,16 +23,16 @@ namespace impl { template < mfem::Geometry::Type geom, Family family, DerivedQuantity op > void batched_interpolate(nd::view u_q, - const Field & u, - const Field & X, - DomainType type, - const nd::view elements, + const double * u, + uint32_t u_degree, + uint32_t u_components, + const std::vector & elements, const nd::view xi) { - uint32_t num_elements = elements.size(); + uint32_t num_elements = uint32_t(elements.size()); if (num_elements == 0) return; - FiniteElement< geom, family > u_el{get_degree(u)}; + FiniteElement< geom, family > u_el{u_degree}; using output_t = typename std::conditional< op == DerivedQuantity::VALUE, @@ -42,20 +42,16 @@ void batched_interpolate(nd::view u_q, nd::view output_q(reinterpret_cast(&u_q[0]), {u_q.shape[0], u_q.shape[1]}); - constexpr uint32_t gdim = dimension(geom); - constexpr uint32_t curl_components = source_shape(family, gdim); uint32_t qpts_per_element = impl::qpe(xi.shape[0]); - using A_type = decltype(piola_transformation(mat{})); - - uint32_t u_components = get_num_components(u); uint32_t u_nodes_per_element = u_el.num_nodes(); + uint32_t u_dofs_per_element = u_nodes_per_element * u_components; auto u_shape_fns = [&](){ if constexpr(op == DerivedQuantity::VALUE) { return u_el.evaluate_shape_functions(xi); } - if constexpr(op == DerivedQuantity::DERIVATIVE && family == Family::Hcurl) { + if constexpr(op == DerivedQuantity::DERIVATIVE && family == Family::HCURL) { return u_el.evaluate_shape_function_curls(xi); } @@ -64,43 +60,6 @@ void batched_interpolate(nd::view u_q, } }(); - FiniteElement< geom, Family::H1 > X_el{get_degree(X)}; - uint32_t X_components = get_num_components(X); - uint32_t X_nodes_per_element = X_el.num_nodes(); - auto X_shape_fn_grads = X_el.evaluate_shape_function_gradients(xi); - - // When do we need to calculate dX/dxi? - // - // ❌ : don't need to ✅ : need to - // +---------------------+------+-------+------+----+ - // | | H1 | Hcurl | Hdiv | DG | - // +---------------------+------+-------+------+----+ - // | isoparametric value | ❌ | ❌ | ❌ | ❌ | - // +---------------------+------+-------+------+----+ - // | isoparametric deriv | ❌ | ❌ | ❌ | ❌ | - // +---------------------+------+-------+------+----+ - // | spatial value | ❌ | ✅ | ✅ | ❌ | - // +---------------------+------+-------+------+----+ - // | spatial deriv | ✅ | ✅ | ✅ | ✅ | - // +---------------------+------+-------+------+----+ - const bool need_to_compute_dX_dxi = - (type == DomainType::SPATIAL && op == DerivedQuantity::DERIVATIVE) || - (type == DomainType::SPATIAL && is_vector_valued(family)); - - nd::array< A_type > A_q; - nd::array X_e; - nd::array X_ids; - nd::array< double > X_scratch; - nd::array< vec, 2 > dX_dxi_q; - - if (need_to_compute_dX_dxi) { - A_q.resize({qpts_per_element}); - X_e.resize(X_nodes_per_element); - X_ids.resize(X_nodes_per_element); - X_scratch.resize({X_el.batch_interpolation_scratch_space(xi)}); - dX_dxi_q.resize({X_components, qpts_per_element}); - } - // for each element with this geometry nd::array u_ids({u_nodes_per_element}); nd::array u_e({u_nodes_per_element}); @@ -108,35 +67,16 @@ void batched_interpolate(nd::view u_q, for (uint32_t i = 0; i < num_elements; i++) { - if (need_to_compute_dX_dxi) { - - for (uint32_t c = 0; c < X_components; c++) { - for (uint32_t j = 0; j < X_nodes_per_element; j++) { - X_e(j) = X.data(X_ids(j), c); - } - X_el.gradient(dX_dxi_q(c), X_e, X_shape_fn_grads, X_scratch.data()); - } - - for (uint32_t q = 0; q < qpts_per_element; q++) { - mat dX_dxi; - for (uint32_t c = 0; c < gdim; c++) { - dX_dxi[c] = dX_dxi_q(c, q); - } - A_q[q] = piola_transformation(dX_dxi); - } - - } - nd::array u_xi_q({qpts_per_element}); for (uint32_t c = 0; c < u_components; c++) { for (uint32_t j = 0; j < u_nodes_per_element; j++) { - u_e(j) = u.data(u_ids(j), c); + u_e(j) = u[i * u_dofs_per_element + c * u_nodes_per_element + j]; } - if constexpr (is_vector_valued(family)) { - u_el.reorient(TransformationType::PhysicalToParent, &connectivity(elements(i), 0), u_e.data()); - } + //if constexpr (is_vector_valued(family)) { + // u_el.reorient(TransformationType::PhysicalToParent, &connectivity(elements(i), 0), u_e.data()); + //} // carry out the appropriate kind of interpolation // for the requested family and differential operator @@ -148,18 +88,12 @@ void batched_interpolate(nd::view u_q, u_el.gradient(u_xi_q, u_e, u_shape_fns, u_scratch.data()); } - if constexpr (op == DerivedQuantity::DERIVATIVE && family == Family::Hcurl) { + if constexpr (op == DerivedQuantity::DERIVATIVE && family == Family::HCURL) { u_el.curl(u_xi_q, u_e, u_shape_fns, u_scratch.data()); } - if (need_to_compute_dX_dxi) { - for (uint32_t q = 0; q < qpts_per_element; q++) { - output_q(i*qpts_per_element+q, c) = serac::dot(u_xi_q[q], A_q[q]); - } - } else { - for (uint32_t q = 0; q < qpts_per_element; q++) { - output_q(i*qpts_per_element+q, c) = u_xi_q[q]; - } + for (uint32_t q = 0; q < qpts_per_element; q++) { + output_q(i*qpts_per_element+q, c) = u_xi_q[q]; } } @@ -173,19 +107,40 @@ void batched_interpolate(nd::view u_q, //////////////////////////////////////////////////////////////////////////////// template < Family family, DerivedQuantity op > -void evaluate(nd::array & output, const Field & u, const Domain & domain, const DomainType & type, const MeshQuadratureRule & qrule) { +void evaluate(nd::array & output, const Field & u_T, Domain & domain, const MeshQuadratureRule & qrule) { uint32_t gdim = static_cast(domain.dim_); - uint32_t num_components = output.shape[1]; - auto qranges = ranges(qrule.num_qpts); + auto qranges = ranges(qrule.num_qpts(domain)); + + uint32_t u_degree = get_degree(u_T); + uint32_t u_components = get_num_components(u_T); + mfem::FiniteElementSpace * u_fes = get_FES(u_T); + const mfem::Operator * P = u_fes->GetProlongationMatrix(); + + static mfem::Vector u_L; + u_L.SetSize(P->Height(), mfem::Device::GetMemoryType()); + P->Mult(u_T, u_L); + + // we just use this as a key to create/fetch the appropriate restriction operator + serac::FunctionSpace space{get_family(u_T), int(get_degree(u_T)), 1}; + + // insert_restriction is idempotent, so only the first call will do anything expensive + domain.insert_restriction(u_fes, space); + + const serac::BlockElementRestriction& G = domain.get_restriction(space); + + static mfem::Vector u_E_buffer; // persistent storage buffer to be used by u_E below + u_E_buffer.SetSize(int(G.ESize())); + mfem::BlockVector u_E(u_E_buffer, G.bOffsets()); + + G.Gather(u_L, u_E); - uint32_t offset = 0; foreach_geometry([&](auto geom){ - nd::view elements = domain.active_elements[geom]; + const std::vector & elements = domain.get(geom); if (gdim == dimension(geom) && elements.size() > 0) { nd::view xi = qrule[geom].points; - impl::batched_interpolate(output(qranges[geom]), u, domain.mesh.X, type, elements, xi); + impl::batched_interpolate(output(qranges[geom]), u_E.GetBlock(geom).ReadWrite(), u_degree, u_components, elements, xi); } }); @@ -193,31 +148,27 @@ void evaluate(nd::array & output, const Field & u, const Domain & doma } // namespace impl -nd::array evaluate(const FieldOp && input, const DomainWithType & d, const MeshQuadratureRule & qrule) { - - const Domain & domain = d.domain; - const DomainType & type = d.type; +nd::array evaluate(const FieldOp && input, Domain & domain, const MeshQuadratureRule & qrule) { Family f = get_family(input.field); uint32_t gdim = geometry_dimension(domain); uint32_t num_components = get_num_components(input.field); stack::array output_dimensions{ - total(qrule.num_qpts), + total(qrule.num_qpts(domain)), num_components, qshape(f, input.op, gdim) }; nd::array u_q(output_dimensions); - uint32_t offset = 0; - for_constexpr< Family::H1, Family::Hcurl >([&](auto family) { + foreach_constexpr< Family::H1, Family::HCURL >([&](auto family) { if (family == f) { if (input.op == DerivedQuantity::VALUE) { - impl::evaluate(u_q, input.field, domain, type); + impl::evaluate(u_q, input.field, domain, qrule); } if (input.op == DerivedQuantity::DERIVATIVE) { - impl::evaluate(u_q, input.field, domain, type); + impl::evaluate(u_q, input.field, domain, qrule); } } }); @@ -226,5 +177,35 @@ nd::array evaluate(const FieldOp && input, const DomainWithType & d, c } +FieldOp grad(const Field & f) { + SLIC_ERROR_IF(!is_scalar_valued(get_family(f)), "grad(Field) only supports scalar-valued function spaces"); + return {DerivedQuantity::DERIVATIVE, f}; +} + +FieldOp curl(const Field & f) { + SLIC_ERROR_IF(get_family(f) != Family::HCURL, "curl(Field) only supports Family::Hcurl"); + return {DerivedQuantity::DERIVATIVE, f}; +} + +FieldOp div(const Field & f) { + SLIC_ERROR_IF(get_family(f) != Family::HDIV, "div(Field) only supports Family::Hdiv"); + return {DerivedQuantity::DERIVATIVE, f}; +} + +BasisFunctionOp grad(const BasisFunction & f) { + SLIC_ERROR_IF(!is_scalar_valued(f.space.family), "grad(BasisFunction) only supports scalar-valued function spaces"); + return {DerivedQuantity::DERIVATIVE, f}; +} + +BasisFunctionOp curl(const BasisFunction & f) { + SLIC_ERROR_IF(f.space.family != Family::HCURL, "curl(BasisFunction) only supports Family::Hcurl"); + return {DerivedQuantity::DERIVATIVE, f}; +} + +BasisFunctionOp div(const BasisFunction & f) { + SLIC_ERROR_IF(f.space.family != Family::HDIV, "div(BasisFunction) only supports Family::Hdiv"); + return {DerivedQuantity::DERIVATIVE, f}; +} + } // namespace refactor #endif diff --git a/src/serac/numerics/refactor/evaluate.hpp b/src/serac/numerics/refactor/evaluate.hpp index 1adc447126..c9de42df82 100644 --- a/src/serac/numerics/refactor/evaluate.hpp +++ b/src/serac/numerics/refactor/evaluate.hpp @@ -1,8 +1,10 @@ #pragma once +#include "serac/numerics/functional/family.hpp" #include "serac/numerics/refactor/containers/ndarray.hpp" #include "serac/numerics/refactor/finite_element.hpp" #include "serac/physics/state/finite_element_state.hpp" +#include "serac/physics/state/finite_element_dual.hpp" namespace refactor { @@ -34,7 +36,6 @@ struct BasisFunctionOp { BasisFunctionOp(const Modifier & m, const DerivedQuantity & o, const BasisFunction & f) : mod(m), op(o), function(f){}; }; - //////////////////////////////////////////////////////////////////////////////// FieldOp grad(const Field & f); @@ -107,6 +108,6 @@ double dot(const Field & u, const Residual & r); //////////////////////////////////////////////////////////////////////////////// -nd::array evaluate(const FieldOp && input, const DomainWithType & d, const MeshQuadratureRule &); +nd::array evaluate(const FieldOp && input, Domain & domain, const MeshQuadratureRule &); } diff --git a/src/serac/numerics/refactor/finite_element.hpp b/src/serac/numerics/refactor/finite_element.hpp index f85a7653c9..0d35c5a390 100644 --- a/src/serac/numerics/refactor/finite_element.hpp +++ b/src/serac/numerics/refactor/finite_element.hpp @@ -1,119 +1,26 @@ #pragma once +#include "serac/numerics/functional/family.hpp" #include "serac/numerics/functional/tensor.hpp" #include "serac/numerics/refactor/geometry.hpp" #include "serac/numerics/refactor/quadrature.hpp" #include "serac/numerics/refactor/containers/ndarray.hpp" -#include "serac/physics/state/finite_element_dual.hpp" -#include "serac/physics/state/finite_element_state.hpp" - namespace refactor { -using Field = serac::FiniteElementState; -using Residual = serac::FiniteElementDual; - -enum class Family { - H1, - Hcurl, - Hdiv, - DG -}; - -inline Family get_family(const Field & f) { - switch(f.gridFunction().FESpace()->FEColl()->GetContType()) { - case mfem::FiniteElementCollection::CONTINUOUS: return Family::H1; - case mfem::FiniteElementCollection::TANGENTIAL: return Family::Hcurl; - case mfem::FiniteElementCollection::NORMAL: return Family::Hdiv; - case mfem::FiniteElementCollection::DISCONTINUOUS: return Family::DG; - } - return Family::H1; // unreachable -} - -inline Family get_family(const Residual & r) { - switch(r.linearForm().FESpace()->FEColl()->GetContType()) { - case mfem::FiniteElementCollection::CONTINUOUS: return Family::H1; - case mfem::FiniteElementCollection::TANGENTIAL: return Family::Hcurl; - case mfem::FiniteElementCollection::NORMAL: return Family::Hdiv; - case mfem::FiniteElementCollection::DISCONTINUOUS: return Family::DG; - } - return Family::H1; // unreachable -} - -inline uint32_t get_degree(const Field & f) { - return uint32_t(f.gridFunction().FESpace()->FEColl()->GetOrder()); -} - -inline uint32_t get_degree(const Residual & r) { - return uint32_t(r.linearForm().FESpace()->FEColl()->GetOrder()); -} - -inline uint32_t get_num_components(const Field & f) { - return uint32_t(f.gridFunction().VectorDim()); -} - -inline uint32_t get_num_components(const Residual & r) { - return uint32_t(r.linearForm().ParFESpace()->GetVDim()); -} - -inline uint32_t get_num_nodes(const Field & f) { - return uint32_t(f.gridFunction().FESpace()->GetNDofs()); -} - -inline uint32_t get_num_nodes(const Residual & r) { - return uint32_t(r.linearForm().FESpace()->GetNDofs()); -} - -nd::array< double, 2 > get_nodal_coordinates(const Field & f); -nd::array< double, 2 > get_nodal_directions(const Field & f); +using serac::Family; enum class Modifier { NONE, DIAGONAL, SYM }; enum class DerivedQuantity { VALUE, DERIVATIVE }; SERAC_HOST_DEVICE constexpr bool is_scalar_valued(Family f) { - return (f == Family::H1) || (f == Family::DG); + return (f == Family::H1) || (f == Family::L2); } SERAC_HOST_DEVICE constexpr bool is_vector_valued(Family f) { - return (f == Family::Hcurl) || (f == Family::Hdiv); + return (f == Family::HCURL) || (f == Family::HDIV); } -struct FunctionSpace { - Family family; - uint32_t degree; - uint32_t components; - FunctionSpace() : family{}, degree{}, components{} {} - FunctionSpace(Family f, uint32_t d = 2, uint32_t c = 1) : family{f}, degree{d}, components{c}{} - FunctionSpace(Field f) { - family = get_family(f); - degree = get_degree(f); - components = get_num_components(f); - } - - bool operator==(const FunctionSpace & other) const { - return (components == other.components) && - (degree == other.degree) && - (family == other.family); - } -}; - -struct BasisFunction { - FunctionSpace space; - BasisFunction(Field f) : space(f) {} - BasisFunction(FunctionSpace s) : space(s) {} - bool operator==(const BasisFunction & other) const { - return (space.components == other.space.components) && - (space.degree == other.space.degree) && - (space.family == other.space.family); - } -}; - -GeometryInfo nodes_per_geom(FunctionSpace space); -GeometryInfo interior_nodes_per_geom(FunctionSpace space); - -GeometryInfo dofs_per_geom(FunctionSpace space); -GeometryInfo interior_dofs_per_geom(FunctionSpace space); - enum class TransformationType { PhysicalToParent, TransposePhysicalToParent, @@ -129,7 +36,7 @@ auto shape_function_derivatives(FiniteElement< geom, family > element, return element.evaluate_shape_function_gradients(xi); } - if constexpr (family == Family::Hcurl) { + if constexpr (family == Family::HCURL) { return element.evaluate_shape_function_curls(xi); } } @@ -142,7 +49,7 @@ auto weighted_shape_function_derivatives(FiniteElement< geom, family > element, return element.evaluate_weighted_shape_function_gradients(xi, weights); } - if constexpr (family == Family::Hcurl) { + if constexpr (family == Family::HCURL) { return element.evaluate_weighted_shape_function_curls(xi, weights); } } diff --git a/src/serac/numerics/refactor/forall.hpp b/src/serac/numerics/refactor/forall.hpp new file mode 100644 index 0000000000..1f47089fb7 --- /dev/null +++ b/src/serac/numerics/refactor/forall.hpp @@ -0,0 +1,288 @@ + +#pragma once + +#include + +#include "serac/numerics/functional/tensor.hpp" +#include "serac/numerics/refactor/containers/ndarray.hpp" + +namespace refactor { + +template < typename ... T > +struct type_list{}; + +template < typename T > +struct FunctionSignature; + +template < typename ret_t, typename ... arg_t > +struct FunctionSignature< ret_t (*)(arg_t ...) > { + using return_type = ret_t; + using argument_types = type_list< arg_t ... >; +}; + +template < typename obj_t, typename ret_t, typename ... arg_t > +struct FunctionSignature< ret_t (obj_t::*)(arg_t ...) const > { + using return_type = ret_t; + using argument_types = type_list< arg_t ... >; +}; + +using serac::vec; +using serac::mat; + +template < typename T > +auto make_ndarray(uint32_t length, T) { + return nd::array({length}); +} + +auto make_ndarray(uint32_t length, double) { + return nd::array({length, 1}); +} + +template < int n > +auto make_ndarray(uint32_t length, vec) { + return nd::array({length, uint32_t(n)}); +} + +template < int m, int n > +auto make_ndarray(uint32_t length, mat) { + return nd::array({length, uint32_t(m), uint32_t(n)}); +} + +template < int m, int n, int p, int q > +auto make_ndarray(uint32_t length, mat >) { + return nd::array({length, m, n, p, q}); +} + +template < typename T > +static constexpr bool is_vec(T) { return false; } + +template < typename T, uint32_t n > +static constexpr bool is_vec(vec) { return true; } + +template < typename T > +static constexpr bool is_mat(T) { return false; } + +template < typename T, uint32_t m, int n > +static constexpr bool is_mat(mat) { return true; } + +template < typename T, uint32_t n, uint32_t rank > +auto load_vec(const nd::array< T, rank > & arr, int i, vec) { + vec output; + for (uint32_t j = 0; j < n; j++) { + if constexpr (rank == 2) { + output[j] = arr(i,j); + } + if constexpr (rank == 3) { + output[j] = arr(i,0,j); + } + } + return output; +} + +template < typename T, uint32_t m, uint32_t n > +auto load_mat(const nd::array< T, 3 > & arr, int i, mat) { + mat output; + for (uint32_t j = 0; j < m; j++) { + for (uint32_t k = 0; k < n; k++) { + output(j,k) = arr(i,j,k); + } + } + return output; +} + +template < typename T, typename arr_type, uint32_t rank > +auto load(const nd::array< arr_type, rank > & arr, int i) { + if constexpr (std::is_same::value || + std::is_same::value) { + static_assert(rank == 1 || rank == 2 || rank == 3); + if constexpr (rank == 1) { return arr(i); } + if constexpr (rank == 2) { return arr(i,0); } + if constexpr (rank == 3) { return arr(i,0,0); } + } + + if constexpr (is_vec(T{})) { + static_assert(rank == 2 || rank == 3); + return load_vec(arr, i, T{}); + } + + if constexpr (is_mat(T{})) { + static_assert(rank == 3); + return load_mat(arr, i, T{}); + } +} + +template < typename T, int n, uint32_t rank > +void save_vec(nd::array< T, rank > & arr, int i, const vec & value) { + for (uint32_t j = 0; j < n; j++) { + if constexpr (rank == 2) { + arr(i,j) = value[j]; + } + if constexpr (rank == 3) { + arr(i,0,j) = value[j]; + } + } +} + +template < typename T, int m, int n > +void save_mat(nd::array< T, 3 > & arr, uint32_t i, const mat & value) { + for (uint32_t j = 0; j < m; j++) { + for (uint32_t k = 0; k < n; k++) { + arr(i,j,k) = value(j,k); + } + } +} + +template < typename T, typename arr_type, uint32_t rank > +auto save(nd::array< arr_type, rank > & arr, uint32_t i, const T & value) { + if constexpr (std::is_same::value || + std::is_same::value) { + if constexpr (rank == 1) arr(i) = value; + if constexpr (rank == 2) arr(i, 0) = value; + } + + if constexpr (is_vec(T{})) { + static_assert(rank == 2 || rank == 3); + save_vec(arr, i, value); + } + + if constexpr (is_mat(T{})) { + static_assert(rank == 3); + save_mat(arr, i, value); + } +} + +namespace impl { + +template < typename T, typename return_type, typename ... parameter_types > +auto forall(uint32_t n, const T & f, return_type * output, const parameter_types * ... args) { + for (uint32_t i = 0; i < n; i++) { + output[i] = f(args[i] ... ); + } +} + +template < typename output_type, typename ... input_types, typename callable, typename ... arg_types > +auto forall(output_type, type_list< input_types ... >, callable func, const arg_types & ... args) { + + uint32_t leading_dimensions[] = {args.shape[0] ...}; + uint32_t n = leading_dimensions[0]; + auto output = make_ndarray(n, output_type{}); + + { + impl::forall( + n, + func, + reinterpret_cast< output_type * >(output.data()), + reinterpret_cast< const input_types * >(args.data()) ... + ); + } + + return output; +} + +} + +template < typename return_type, typename ... parameter_types, typename ... arg_types > +auto forall(std::function< return_type(const parameter_types & ...) > f, const arg_types & ... args) { + + uint32_t leading_dimensions[] = {args.shape[0] ...}; + uint32_t n = leading_dimensions[0]; + auto output = make_ndarray(n, return_type{}); + + impl::forall( + n, + f, + reinterpret_cast< return_type * >(output.data()), + reinterpret_cast< const parameter_types * >(args.data()) ... + ); + + return output; +} + +template < typename return_type, typename ... parameter_types, typename ... arg_types > +auto forall(return_type (*f)(const parameter_types & ...), const arg_types & ... args) { + + uint32_t leading_dimensions[] = {args.shape[0] ...}; + uint32_t n = leading_dimensions[0]; + auto output = make_ndarray(n, return_type{}); + + impl::forall( + n, + f, + reinterpret_cast< return_type * >(output.data()), + reinterpret_cast< const parameter_types * >(args.data()) ... + ); + + return output; +} + +template < typename callable, typename ... arg_types > +auto forall(callable func, const arg_types & ... args) { + + using signature = FunctionSignature< decltype(&callable::operator()) >; + + return impl::forall( + typename signature::return_type{}, + typename signature::argument_types{}, + func, + args ... + ); + +} + +#ifdef __CUDACC__ + +template < typename functor, typename return_type, typename ... input_types > +__global__ void forall_kernel( + uint32_t n, + functor f, + return_type * output, + const input_types * ... inputs) { + int tid = threadIdx.x + blockIdx.x * blockDim.x; + if (tid < n) { + output[tid] = f(inputs[tid] ...); + } +} + +namespace impl { + +template < typename output_type, typename ... input_types, typename callable, typename ... arg_types > +auto cuda_forall(output_type, type_list< input_types ... >, callable func, const arg_types & ... args) { + + uint32_t leading_dimensions[] = {args.shape[0] ...}; + int n = leading_dimensions[0]; + auto output = make_ndarray(n, output_type{}); + + { + MTR_SCOPE("cuda_forall", "apply functor kernel"); + int blocksize = 128; + int gridsize = (n + blocksize - 1) / blocksize; + forall_kernel<<< gridsize, blocksize >>>( + n, + func, + reinterpret_cast< output_type * >(output.data()), + reinterpret_cast< const input_types * >(args.data()) ... + ); + cudaDeviceSynchronize(); + } + + return output; +} + +} + +template < typename callable, typename ... arg_types > +auto cuda_forall(callable func, const arg_types & ... args) { + + using signature = FunctionSignature< decltype(&callable::operator()) >; + + return impl::cuda_forall( + typename signature::return_type{}, + typename signature::argument_types{}, + func, + args ... + ); + +} +#endif + +} // namespace refactor diff --git a/src/serac/numerics/refactor/get_nodal_coordinates.cpp b/src/serac/numerics/refactor/get_nodal_coordinates.cpp index d7027837a4..6123eea459 100644 --- a/src/serac/numerics/refactor/get_nodal_coordinates.cpp +++ b/src/serac/numerics/refactor/get_nodal_coordinates.cpp @@ -1,3 +1,4 @@ +#if 0 #include "serac/numerics/refactor/finite_element.hpp" namespace refactor { @@ -9,27 +10,30 @@ nd::array< double, 2 > get_nodal_coordinates(const Field & f) { mfem::ParGridFunction pgf = f.gridFunction(); + nd::array nodal_coords({num_nodes, spatial_dimension}); + if (refactor::is_scalar_valued(get_family(f))) { - // it seems there is no direct way to get the nodal coordinates - // for an mfem::GridFunction, so instead we proceed by asking pgf - // to evaluate the identity function at each of its nodes - mfem::VectorFunctionCoefficient identity_function( - static_cast(spatial_dimension), - [&](const mfem::Vector& x, mfem::Vector & output) { - output = x; - } - ); + for (uint32_t j = 0; j < spatial_dimension; j++) { - pgf.ProjectCoefficient(identity_function); + // it seems there is no direct way to get the nodal coordinates + // for an mfem::GridFunction, so instead we proceed by asking pgf + // to evaluate the identity function at each of its nodes + mfem::FunctionCoefficient identity_function( + static_cast(spatial_dimension), + [&](const mfem::Vector& x) { + output = x[j]; + } + ); - // then, we extract the nodal coordinates from the gridfunction - nd::array nodal_coords({num_nodes, spatial_dimension}); + pgf.ProjectCoefficient(identity_function); - for (uint32_t i = 0; i < num_nodes; i++) { - for (uint32_t j = 0; j < spatial_dimension; j++) { - nodal_coords(i, j) = pgf[static_cast(i * spatial_dimension + j)]; + // then, we extract the nodal coordinates from the gridfunction + for (uint32_t i = 0; i < num_nodes; i++) { + //nodal_coords(i, j) = pgf[static_cast(i * spatial_dimension + j)]; + nodal_coords(i, j) = pgf[static_cast(j * num_nodes + i)]; } + } return nodal_coords; @@ -82,3 +86,4 @@ nd::array< double, 2 > get_nodal_coordinates(const Field & f) { } } +#endif diff --git a/src/serac/numerics/refactor/get_nodal_directions.cpp b/src/serac/numerics/refactor/get_nodal_directions.cpp index 5478d52d95..c619461499 100644 --- a/src/serac/numerics/refactor/get_nodal_directions.cpp +++ b/src/serac/numerics/refactor/get_nodal_directions.cpp @@ -1,3 +1,4 @@ +#if 0 #include "serac/numerics/refactor/finite_element.hpp" namespace refactor { @@ -39,3 +40,4 @@ nd::array< double, 2 > get_nodal_directions(const Field & f) { } } +#endif diff --git a/src/serac/numerics/refactor/integrate_diag.cpp b/src/serac/numerics/refactor/integrate_diag.cpp index 56748408ae..89abacc99a 100644 --- a/src/serac/numerics/refactor/integrate_diag.cpp +++ b/src/serac/numerics/refactor/integrate_diag.cpp @@ -131,11 +131,11 @@ void batched_integrate_diag(nd::view D, phi_I = el.shape_function_gradient(xi_q, I); } - if constexpr (family == Family::Hcurl && test_op == DerivedQuantity::VALUE) { + if constexpr (family == Family::HCURL && test_op == DerivedQuantity::VALUE) { phi_I = el.reoriented_shape_function(xi_q, I, transformation[I]); } - if constexpr (family == Family::Hcurl && test_op == DerivedQuantity::DERIVATIVE) { + if constexpr (family == Family::HCURL && test_op == DerivedQuantity::DERIVATIVE) { phi_I = el.reoriented_shape_function_curl(xi_q, I, transformation[I]); } @@ -148,11 +148,11 @@ void batched_integrate_diag(nd::view D, psi_I = el.shape_function_gradient(xi_q, I); } - if constexpr (family == Family::Hcurl && trial_op == DerivedQuantity::VALUE) { + if constexpr (family == Family::HCURL && trial_op == DerivedQuantity::VALUE) { psi_I = el.reoriented_shape_function(xi_q, I, transformation[I]); } - if constexpr (family == Family::Hcurl && trial_op == DerivedQuantity::DERIVATIVE) { + if constexpr (family == Family::HCURL && trial_op == DerivedQuantity::DERIVATIVE) { psi_I = el.reoriented_shape_function_curl(xi_q, I, transformation[I]); } @@ -215,7 +215,7 @@ nd::array integrate_sparse_matrix_diagonal(BasisFunction test, const n const Domain::AssemblyLUT & table = domain.get(geom, phi.family, phi.degree); - foreach_constexpr< Family::H1, Family::Hcurl >([&](auto family) { + foreach_constexpr< Family::H1, Family::HCURL >([&](auto family) { if (family == phi.family) { batched_integrate_diag( output.data, diff --git a/src/serac/numerics/refactor/integrate_residual.cpp b/src/serac/numerics/refactor/integrate_residual.cpp index eef308ffef..89e8b4b568 100644 --- a/src/serac/numerics/refactor/integrate_residual.cpp +++ b/src/serac/numerics/refactor/integrate_residual.cpp @@ -43,7 +43,7 @@ void batched_integrate_residual(Residual & r, return r_el.evaluate_weighted_shape_functions(xi, weights); } - if constexpr(op == DerivedQuantity::DERIVATIVE && family == Family::Hcurl) { + if constexpr(op == DerivedQuantity::DERIVATIVE && family == Family::HCURL) { return r_el.evaluate_weighted_shape_function_curls(xi, weights); } @@ -187,8 +187,8 @@ void integrate_residual(Residual & r, BasisFunction phi, const nd::array(r, domain.mesh.X, type, integrand_geom, elements, xi, weights, element_residual_buffer); } - if (phi.space.family == Family::Hcurl) { - batched_integrate_residual(r, domain.mesh.X, type, integrand_geom, elements, xi, weights, element_residual_buffer); + if (phi.space.family == Family::HCURL) { + batched_integrate_residual(r, domain.mesh.X, type, integrand_geom, elements, xi, weights, element_residual_buffer); } } diff --git a/src/serac/numerics/refactor/integrate_spmat.cpp b/src/serac/numerics/refactor/integrate_spmat.cpp index e33f96617d..e5317a1755 100644 --- a/src/serac/numerics/refactor/integrate_spmat.cpp +++ b/src/serac/numerics/refactor/integrate_spmat.cpp @@ -49,7 +49,7 @@ void batched_integrate_spmat(nd::view values, return trial_el.evaluate_weighted_shape_functions(xi, weights); } - if constexpr(trial_op == DerivedQuantity::DERIVATIVE && trial_family == Family::Hcurl) { + if constexpr(trial_op == DerivedQuantity::DERIVATIVE && trial_family == Family::HCURL) { return trial_el.evaluate_weighted_shape_function_curls(xi, weights); } @@ -164,11 +164,11 @@ void batched_integrate_spmat(nd::view values, phi_I = test_el.shape_function_gradient(xi_q, I); } - if constexpr (test_family == Family::Hcurl && test_op == DerivedQuantity::VALUE) { + if constexpr (test_family == Family::HCURL && test_op == DerivedQuantity::VALUE) { phi_I = test_el.reoriented_shape_function(xi_q, I, transformation[I]); } - if constexpr (test_family == Family::Hcurl && test_op == DerivedQuantity::DERIVATIVE) { + if constexpr (test_family == Family::HCURL && test_op == DerivedQuantity::DERIVATIVE) { phi_I = test_el.reoriented_shape_function_curl(xi_q, I, transformation[I]); } @@ -263,8 +263,8 @@ std::function< void(refactor::sparse_matrix&) > integrate_sparse_matrix(BasisFun stack::array< uint32_t, 5 > qdata_shape{domain.num_qpts[geom], shape5D[1], shape5D[2], shape5D[3], shape5D[4]}; nd::view geom_qdata{&q5D(qoffset, 0, 0, 0, 0), qdata_shape}; - foreach_constexpr< Family::H1, Family::Hcurl >([&](auto test_family) { - foreach_constexpr< Family::H1, Family::Hcurl >([&](auto trial_family) { + foreach_constexpr< Family::H1, Family::HCURL >([&](auto test_family) { + foreach_constexpr< Family::H1, Family::HCURL >([&](auto trial_family) { if (test_family == phi.family && trial_family == psi.family) { batched_integrate_spmat( A.values, A.row_ptr, A.col_ind, diff --git a/src/serac/numerics/refactor/interpolation.cpp b/src/serac/numerics/refactor/interpolation.cpp index ea093e1140..c1f5fdf605 100644 --- a/src/serac/numerics/refactor/interpolation.cpp +++ b/src/serac/numerics/refactor/interpolation.cpp @@ -347,8 +347,8 @@ void GaussLobattoInterpolationQuadrilateral(const double * xi, uint32_t n, doub GaussLobattoInterpolation(xi[0], n, N[0]); GaussLobattoInterpolation(xi[1], n, N[1]); - for (int j = 0; j < n; j++) { - for (int i = 0; i < n; i++) { + for (uint32_t j = 0; j < n; j++) { + for (uint32_t i = 0; i < n; i++) { output[j * n + i] = N[0][i] * N[0][j]; } } @@ -367,8 +367,8 @@ void GaussLobattoInterpolationDerivativeQuadrilateral(const double * xi, uint32_ GaussLobattoInterpolation(xi[0], n, dN[0]); GaussLobattoInterpolation(xi[1], n, dN[1]); - for (int j = 0; j < n; j++) { - for (int i = 0; i < n; i++) { + for (uint32_t j = 0; j < n; j++) { + for (uint32_t i = 0; i < n; i++) { output[2 * (j * n + i) + 0] = dN[0][i] * N[0][j]; output[2 * (j * n + i) + 1] = N[0][i] * dN[0][j]; } @@ -559,9 +559,9 @@ void GaussLobattoInterpolationHexahedron(const double * xi, uint32_t n, double GaussLobattoInterpolation(xi[1], n, N[1]); GaussLobattoInterpolation(xi[2], n, N[2]); - for (int k = 0; k < n; k++) { - for (int j = 0; j < n; j++) { - for (int i = 0; i < n; i++) { + for (uint32_t k = 0; k < n; k++) { + for (uint32_t j = 0; j < n; j++) { + for (uint32_t i = 0; i < n; i++) { output[(k * n + j) * n + i] = N[0][i] * N[1][j] * N[2][k]; } } @@ -582,9 +582,9 @@ void GaussLobattoInterpolationDerivativeHexahedron(const double * xi, uint32_t n GaussLobattoInterpolation(xi[1], n, dN[1]); GaussLobattoInterpolation(xi[2], n, dN[2]); - for (int k = 0; k < n; k++) { - for (int j = 0; j < n; j++) { - for (int i = 0; i < n; i++) { + for (uint32_t k = 0; k < n; k++) { + for (uint32_t j = 0; j < n; j++) { + for (uint32_t i = 0; i < n; i++) { output[3 * ((k * n + j) * n + i) + 0] = dN[0][i] * N[1][j] * N[2][k]; output[3 * ((k * n + j) * n + i) + 1] = N[0][i] * dN[1][j] * N[2][k]; output[3 * ((k * n + j) * n + i) + 2] = N[0][i] * N[1][j] * dN[2][k]; diff --git a/src/serac/numerics/refactor/quadrature.cpp b/src/serac/numerics/refactor/quadrature.cpp index 510fead546..b0fd173ba1 100644 --- a/src/serac/numerics/refactor/quadrature.cpp +++ b/src/serac/numerics/refactor/quadrature.cpp @@ -1,4 +1,6 @@ -#include "refactor/quadrature.hpp" +#include "serac/numerics/refactor/quadrature.hpp" + +#include "serac/numerics/refactor/common.hpp" #include @@ -365,4 +367,12 @@ GeometryInfo qpts_per_geom(const MeshQuadratureRule & qrule, int dim) { }; } + +GeometryInfo MeshQuadratureRule::num_qpts(const serac::Domain & domain) const { + int gdim = domain.dim_; + GeometryInfo gcounts = refactor::geometry_counts(domain); + GeometryInfo qpts = qpts_per_geom(*this, gdim); + return gcounts * qpts; +}; + } // namespace refactor diff --git a/src/serac/numerics/refactor/quadrature.hpp b/src/serac/numerics/refactor/quadrature.hpp index 517d2f6e72..b8fe85f9b5 100644 --- a/src/serac/numerics/refactor/quadrature.hpp +++ b/src/serac/numerics/refactor/quadrature.hpp @@ -1,6 +1,7 @@ #pragma once #include "serac/numerics/refactor/geometry.hpp" +#include "serac/numerics/functional/domain.hpp" #include "serac/numerics/refactor/containers/ndarray.hpp" namespace refactor { @@ -16,6 +17,8 @@ enum class QuadratureRuleType { UniformStructured, UniformUnstructured, Nonunifo struct MeshQuadratureRule : public GeometryData< ElementQuadratureRule >{ MeshQuadratureRule(uint32_t q, bool compact = true); QuadratureRuleType type; + + GeometryInfo num_qpts(const serac::Domain & domain) const; }; void gauss_legendre_segment_rule(uint32_t q, double * qpts, double * qwts); diff --git a/src/serac/numerics/refactor/tests/h1_evaluation_tests.cpp b/src/serac/numerics/refactor/tests/h1_evaluation_tests.cpp index f49909997e..b2f0a9dc6e 100644 --- a/src/serac/numerics/refactor/tests/h1_evaluation_tests.cpp +++ b/src/serac/numerics/refactor/tests/h1_evaluation_tests.cpp @@ -3,6 +3,7 @@ #include #include +#include "serac/numerics/refactor/forall.hpp" #include "serac/numerics/refactor/evaluate.hpp" #include "serac/numerics/refactor/tests/common.hpp" @@ -13,6 +14,11 @@ constexpr int dimension(double) { return 1; } template < int dim > constexpr int dimension(vec < dim >) { return dim; } +template < typename grad_t, typename jac_t > +auto contravariant_piola(const grad_t & du_dxi, const jac_t & dx_dxi) { + return dot(du_dxi, inv(dx_dxi)); +}; + template < typename vec_t > void evaluation_test(std::string filename, std::function f, @@ -21,35 +27,50 @@ void evaluation_test(std::string filename, double tolerance) { constexpr int dim = dimension(vec_t{}); + constexpr int components = 1; using mat_t = mat; - auto mesh = Mesh::load(SERAC_MESH_DIR + filename); + mfem::ParMesh mesh = load_parmesh(SERAC_MESH_DIR + filename); + Domain domain = EntireDomain(mesh); + + Field u(mesh, refactor::Family::H1, p, components); - Field u = create_field(mesh, refactor::Family::H1, p); - nd::array nodes = nodes_for(u, mesh); + mfem::FunctionCoefficient mfem_f([&](const mfem::Vector & mfem_X) { + vec_t X; + for (int i = 0; i < dim; i++) { + X[i] = mfem_X[i]; + } + return f(X); + }); - u = forall(f, nodes); + u.project(mfem_f); - for (uint32_t q = 1; q <= 4; q++) { + Field X = mesh_coordinates(mesh); + + //for (uint32_t q = 1; q <= 4; q++) { + for (uint32_t q = 1; q <= 1; q++) { MeshQuadratureRule qrule(q); - Domain domain(mesh); - auto x_q = evaluate(mesh.X, domain); - auto dX_dxi_q = evaluate(grad(mesh.X), isoparametric(domain)); + auto X_q = evaluate(X, domain, qrule); + auto dX_dxi_q = evaluate(grad(X), domain, qrule); auto u_q = evaluate(u, domain, qrule); - auto du_dxi_q = evaluate(grad(u), isoparametric(domain), qrule); - auto du_dX_q_1 = evaluate(grad(u), domain, qrule); + auto du_dxi_q = evaluate(grad(u), domain, qrule); auto du_dX_q_2 = forall(contravariant_piola, du_dxi_q, dX_dxi_q); // evaluate f, df_dx directly at each quadrature point - auto f_q = forall(f, x_q); - auto df_dX_q = forall(grad_f, x_q); + auto f_q = forall(f, X_q); + auto df_dX_q = forall(grad_f, X_q); + + print(X_q); + print(f_q); + print(u_q); + + //return 3 * pow(x[0], p) + 2 * x[1] + x[2]; EXPECT_LT(relative_error(flatten(u_q), flatten(f_q)), tolerance); - EXPECT_LT(relative_error(flatten(du_dX_q_1), flatten(df_dX_q)), tolerance); EXPECT_LT(relative_error(du_dX_q_2, df_dX_q), tolerance); } @@ -67,23 +88,17 @@ TEST(InterpolationTest2D, NAME) { ); \ } -GENERATE_TEST_2D(AffineTestQuadP1, "one_quad_pure_shear.json", 1, 1.0e-15); - -GENERATE_TEST_2D(PatchTestQuadP1, "patch_test_quads.json", 1, 1.0e-15); -GENERATE_TEST_2D(PatchTestQuadP2, "patch_test_quads.json", 2, 1.0e-14); -GENERATE_TEST_2D(PatchTestQuadP3, "patch_test_quads.json", 3, 1.0e-14); - -GENERATE_TEST_2D(PatchTestTriP1, "patch_test_tris.json", 1, 1.0e-15); -GENERATE_TEST_2D(PatchTestTriP2, "patch_test_tris.json", 2, 1.0e-14); -GENERATE_TEST_2D(PatchTestTriP3, "patch_test_tris.json", 3, 1.5e-14); - -GENERATE_TEST_2D(PatchTestTriAndQuadP1, "patch_test_tris_and_quads.json", 1, 1.0e-15); -GENERATE_TEST_2D(PatchTestTriAndQuadP2, "patch_test_tris_and_quads.json", 2, 1.0e-14); -GENERATE_TEST_2D(PatchTestTriAndQuadP3, "patch_test_tris_and_quads.json", 3, 2.0e-14); - -GENERATE_TEST_2D(WrenchTestP1, "wrench.json", 1, 1.0e-12); -GENERATE_TEST_2D(WrenchTestP2, "wrench.json", 2, 1.0e-12); -GENERATE_TEST_2D(WrenchTestP3, "wrench.json", 3, 1.0e-12); +//GENERATE_TEST_2D(PatchTestTriP1, "patch2D_tris.mesh", 1, 1.0e-15); +//GENERATE_TEST_2D(PatchTestTriP2, "patch2D_tris.mesh", 2, 1.0e-14); +//GENERATE_TEST_2D(PatchTestTriP3, "patch2D_tris.mesh", 3, 1.5e-14); +// +//GENERATE_TEST_2D(PatchTestQuadP1, "patch2D_quads.mesh", 1, 1.0e-15); +//GENERATE_TEST_2D(PatchTestQuadP2, "patch2D_quads.mesh", 2, 1.0e-14); +//GENERATE_TEST_2D(PatchTestQuadP3, "patch2D_quads.mesh", 3, 1.0e-14); +// +//GENERATE_TEST_2D(PatchTestTriAndQuadP1, "patch2D_tris_and_quads.mesh", 1, 1.0e-15); +//GENERATE_TEST_2D(PatchTestTriAndQuadP2, "patch2D_tris_and_quads.mesh", 2, 1.0e-14); +//GENERATE_TEST_2D(PatchTestTriAndQuadP3, "patch2D_tris_and_quads.mesh", 3, 2.0e-14); ///////////////////////////////////////////////////////////////////////////////////////////////// @@ -98,14 +113,34 @@ TEST(InterpolationTest3D, NAME) { ); \ } -GENERATE_TEST_3D(PatchTestHexP1, "patch_test_hexes.json", 1, 2.0e-15); -GENERATE_TEST_3D(PatchTestHexP2, "patch_test_hexes.json", 2, 2.0e-14); -GENERATE_TEST_3D(PatchTestHexP3, "patch_test_hexes.json", 3, 4.5e-13); +GENERATE_TEST_3D(OneTetP1, "onetet.mesh", 1, 5.0e-16); + +//GENERATE_TEST_3D(PatchTestTetP1, "patch3D_tets.mesh", 1, 5.0e-16); +//GENERATE_TEST_3D(PatchTestTetP2, "patch3D_tets.mesh", 2, 5.0e-15); +//GENERATE_TEST_3D(PatchTestTetP3, "patch3D_tets.mesh", 3, 2.0e-14); +// +//GENERATE_TEST_3D(PatchTestHexP1, "patch3D_hexes.mesh", 1, 2.0e-15); +//GENERATE_TEST_3D(PatchTestHexP2, "patch3D_hexes.mesh", 2, 2.0e-14); +//GENERATE_TEST_3D(PatchTestHexP3, "patch3D_hexes.mesh", 3, 4.5e-13); +// +//GENERATE_TEST_3D(PatchTestTetAndHexP1, "patch3D_tets_and_hexes.mesh", 1, 1.5e-15); +//GENERATE_TEST_3D(PatchTestTetAndHexP2, "patch3D_tets_and_hexes.mesh", 2, 1.5e-14); +//GENERATE_TEST_3D(PatchTestTetAndHexP3, "patch3D_tets_and_hexes.mesh", 3, 3.5e-13); + +int main(int argc, char* argv[]) { + int num_procs, myid; + + ::testing::InitGoogleTest(&argc, argv); -GENERATE_TEST_3D(PatchTestTetP1, "patch_test_tets.json", 1, 5.0e-16); -GENERATE_TEST_3D(PatchTestTetP2, "patch_test_tets.json", 2, 5.0e-15); -GENERATE_TEST_3D(PatchTestTetP3, "patch_test_tets.json", 3, 2.0e-14); + MPI_Init(&argc, &argv); + MPI_Comm_size(MPI_COMM_WORLD, &num_procs); + MPI_Comm_rank(MPI_COMM_WORLD, &myid); -GENERATE_TEST_3D(PatchTestTetAndHexP1, "patch_test_tets_and_hexes.json", 1, 1.5e-15); -GENERATE_TEST_3D(PatchTestTetAndHexP2, "patch_test_tets_and_hexes.json", 2, 1.5e-14); -GENERATE_TEST_3D(PatchTestTetAndHexP3, "patch_test_tets_and_hexes.json", 3, 3.5e-13); + axom::slic::SimpleLogger logger; + + int result = RUN_ALL_TESTS(); + + MPI_Finalize(); + + return result; +} diff --git a/src/serac/numerics/refactor/tests/hcurl_evaluation_tests.cpp b/src/serac/numerics/refactor/tests/hcurl_evaluation_tests.cpp index 56227c1273..f72fc97a6d 100644 --- a/src/serac/numerics/refactor/tests/hcurl_evaluation_tests.cpp +++ b/src/serac/numerics/refactor/tests/hcurl_evaluation_tests.cpp @@ -31,7 +31,7 @@ void evaluation_test(std::string filename, auto mesh = Mesh::load(SERAC_MESH_DIR + filename); - Field u = create_field(mesh, Family::Hcurl, p); + Field u = create_field(mesh, Family::HCURL, p); nd::array nodes = nodes_for(u, mesh); nd::array directions = directions_for(u, mesh); diff --git a/src/serac/numerics/refactor/tests/integrate_residual_Hcurl_flux_tests.cpp b/src/serac/numerics/refactor/tests/integrate_residual_Hcurl_flux_tests.cpp index b6dfb6da62..f3a39cf5fc 100644 --- a/src/serac/numerics/refactor/tests/integrate_residual_Hcurl_flux_tests.cpp +++ b/src/serac/numerics/refactor/tests/integrate_residual_Hcurl_flux_tests.cpp @@ -48,7 +48,7 @@ void integrate_flux_test(std::string filename, return dot(f(x,p), n) ; }; - Field u = create_field(mesh, Family::Hcurl, p, 1); + Field u = create_field(mesh, Family::HCURL, p, 1); nd::array nodes = nodes_for(u, mesh); nd::array directions = directions_for(u, mesh); u = forall(f_p, nodes, directions); diff --git a/src/serac/numerics/refactor/tests/integrate_residual_Hcurl_source_tests.cpp b/src/serac/numerics/refactor/tests/integrate_residual_Hcurl_source_tests.cpp index a3a9db01ed..fbfca4b6a8 100644 --- a/src/serac/numerics/refactor/tests/integrate_residual_Hcurl_source_tests.cpp +++ b/src/serac/numerics/refactor/tests/integrate_residual_Hcurl_source_tests.cpp @@ -40,7 +40,7 @@ void integrate_source_test(std::string filename, std::function< double(vecd, vecd) > f_p = [f, p](vecd x, vecd n) { return dot(f(x,p), n) ; }; - Field u = create_field(mesh, Family::Hcurl, p, 1); + Field u = create_field(mesh, Family::HCURL, p, 1); nd::array nodes = nodes_for(u, mesh); nd::array directions = directions_for(u, mesh); u = forall(f_p, nodes, directions); diff --git a/src/serac/numerics/refactor/tests/nodal_coordinates_and_directions_tests.cpp b/src/serac/numerics/refactor/tests/nodal_coordinates_and_directions_tests.cpp index 6f4eaed26b..f381eabf1d 100644 --- a/src/serac/numerics/refactor/tests/nodal_coordinates_and_directions_tests.cpp +++ b/src/serac/numerics/refactor/tests/nodal_coordinates_and_directions_tests.cpp @@ -8,19 +8,36 @@ using namespace refactor; -template< int p > +template< int dim, int p > void nodal_coordinates_test(std::string mesh_filename) { - mfem::ParMesh pmesh = load_parmesh(SERAC_MESH_DIR + mesh_filename); + std::function< double(tensor) > f; - serac::FiniteElementState u(pmesh, H1

{}); + mfem::ParMesh pmesh = load_parmesh(SERAC_MESH_DIR + mesh_filename); - nd::array nodal_coords = get_nodal_coordinates(u); + serac::FiniteElementState u(pmesh, H1

{}); -} + nd::array nodal_coords = get_nodal_coordinates(u); + uint32_t num_nodes = nodal_coords.shape[0]; + + //void FiniteElementState::project(mfem::Coefficient& coef, const Domain& domain) + + mfem::FunctionCoefficient mfem_func([](mfem::Vector x, double /*t*/) { + return x[0] + 2 * x[1]; + }); + + u.project(mfem_func); -TEST(nodal_coords, triangles) { nodal_coordinates_test<1>("patch2D_tris.mesh"); } + std::cout << u.Size() << std::endl; + std::cout << num_nodes << std::endl; + + //for (uint32_t i = 0; i < num_nodes; i++) { + // std::cout << u[i] + //} + +} +TEST(nodal_coords, triangles) { nodal_coordinates_test<2, 1>("patch2D_tris.mesh"); } int main(int argc, char* argv[]) { diff --git a/src/serac/physics/state/CMakeLists.txt b/src/serac/physics/state/CMakeLists.txt index 863df13db3..5475745977 100644 --- a/src/serac/physics/state/CMakeLists.txt +++ b/src/serac/physics/state/CMakeLists.txt @@ -12,8 +12,9 @@ set(state_headers ) set(state_sources - finite_element_vector.cpp + finite_element_dual.cpp finite_element_state.cpp + finite_element_vector.cpp state_manager.cpp ) diff --git a/src/serac/physics/state/finite_element_dual.cpp b/src/serac/physics/state/finite_element_dual.cpp new file mode 100644 index 0000000000..294fb463ce --- /dev/null +++ b/src/serac/physics/state/finite_element_dual.cpp @@ -0,0 +1,27 @@ +#include "serac/physics/state/finite_element_dual.hpp" + +namespace refactor { + +Family get_family(const Residual & r) { + switch(r.linearForm().FESpace()->FEColl()->GetContType()) { + case mfem::FiniteElementCollection::CONTINUOUS: return Family::H1; + case mfem::FiniteElementCollection::TANGENTIAL: return Family::HCURL; + case mfem::FiniteElementCollection::NORMAL: return Family::HDIV; + case mfem::FiniteElementCollection::DISCONTINUOUS: return Family::L2; + } + return Family::H1; // unreachable +} + +uint32_t get_degree(const Residual & r) { + return uint32_t(r.linearForm().FESpace()->FEColl()->GetOrder()); +} + +uint32_t get_num_component(const Residual & r) { + return uint32_t(r.linearForm().ParFESpace()->GetVDim()); +} + +uint32_t get_num_nodes(const Residual & r) { + return uint32_t(r.linearForm().FESpace()->GetNDofs()); +} + +} diff --git a/src/serac/physics/state/finite_element_dual.hpp b/src/serac/physics/state/finite_element_dual.hpp index 8b144b5a05..af7aa89082 100644 --- a/src/serac/physics/state/finite_element_dual.hpp +++ b/src/serac/physics/state/finite_element_dual.hpp @@ -140,3 +140,14 @@ class FiniteElementDual : public FiniteElementVector { }; } // namespace serac + +namespace refactor { + + using Residual = serac::FiniteElementDual; + + Family get_family(const Residual & r); + uint32_t get_degree(const Residual & r); + uint32_t get_num_components(const Residual & r); + uint32_t get_num_nodes(const Residual & r); + +} diff --git a/src/serac/physics/state/finite_element_state.cpp b/src/serac/physics/state/finite_element_state.cpp index 257a893a7a..d9e44312d5 100644 --- a/src/serac/physics/state/finite_element_state.cpp +++ b/src/serac/physics/state/finite_element_state.cpp @@ -123,3 +123,52 @@ double computeL2Error(const FiniteElementState& state, mfem::Coefficient& exact_ } } // namespace serac + + +namespace refactor { + +serac::Family get_family(const Field & f) { + switch(f.gridFunction().FESpace()->FEColl()->GetContType()) { + case mfem::FiniteElementCollection::CONTINUOUS: return Family::H1; + case mfem::FiniteElementCollection::TANGENTIAL: return Family::HCURL; + case mfem::FiniteElementCollection::NORMAL: return Family::HDIV; + case mfem::FiniteElementCollection::DISCONTINUOUS: return Family::L2; + } + return Family::H1; // unreachable +} + +mfem::FiniteElementSpace * get_FES(const Field & f) { + return f.gridFunction().FESpace(); +} + +uint32_t get_degree(const Field & f) { + return uint32_t(f.gridFunction().FESpace()->FEColl()->GetOrder()); +} + +uint32_t get_num_components(const Field & f) { + return uint32_t(f.gridFunction().VectorDim()); +} + +uint32_t get_num_nodes(const Field & f) { + return uint32_t(f.gridFunction().FESpace()->GetNDofs()); +} + +Field mesh_coordinates(mfem::ParMesh & mesh) { + + // sam: as I understand it mfem::Mesh::GetNodes() requires mfem::Mesh::EnsureNodes() + // be called ahead of time, or else it will not return a valid (mfem::ParGridFunction *) + // + // this is also why the mesh is passed as non-const & + mesh.EnsureNodes(); + + mfem::ParGridFunction* mesh_nodes = dynamic_cast(mesh.GetNodes()); + + Field X(*mesh_nodes->ParFESpace()); + + X.setFromGridFunction(*mesh_nodes); + + return X; + +} + +} diff --git a/src/serac/physics/state/finite_element_state.hpp b/src/serac/physics/state/finite_element_state.hpp index ae8534c6c4..ccabd0502c 100644 --- a/src/serac/physics/state/finite_element_state.hpp +++ b/src/serac/physics/state/finite_element_state.hpp @@ -65,6 +65,8 @@ class FiniteElementState : public FiniteElementVector { */ FiniteElementState(FiniteElementState&& rhs) : FiniteElementVector(std::move(rhs)) {} + + /** * @brief Copy assignment * @@ -251,3 +253,56 @@ double computeL2Error(const FiniteElementState& state, mfem::VectorCoefficient& double computeL2Error(const FiniteElementState& state, mfem::Coefficient& exact_solution); } // namespace serac + +namespace refactor { + + using Field = serac::FiniteElementState; + + Family get_family(const Field & f); + uint32_t get_degree(const Field & f); + uint32_t get_num_components(const Field & f); + uint32_t get_num_nodes(const Field & f); + mfem::FiniteElementSpace * get_FES(const Field & f); + + Field mesh_coordinates(mfem::ParMesh & mesh); + + nd::array< double, 2 > get_nodal_coordinates(const Field & f); + nd::array< double, 2 > get_nodal_directions(const Field & f); + + struct FunctionSpace { + Family family; + uint32_t degree; + uint32_t components; + FunctionSpace() : family{}, degree{}, components{} {} + FunctionSpace(Family f, uint32_t d = 2, uint32_t c = 1) : family{f}, degree{d}, components{c}{} + FunctionSpace(Field f) { + family = get_family(f); + degree = get_degree(f); + components = get_num_components(f); + } + + bool operator==(const FunctionSpace & other) const { + return (components == other.components) && + (degree == other.degree) && + (family == other.family); + } + }; + + struct BasisFunction { + FunctionSpace space; + BasisFunction(Field f) : space(f) {} + BasisFunction(FunctionSpace s) : space(s) {} + bool operator==(const BasisFunction & other) const { + return (space.components == other.space.components) && + (space.degree == other.space.degree) && + (space.family == other.space.family); + } + }; + + GeometryInfo nodes_per_geom(FunctionSpace space); + GeometryInfo interior_nodes_per_geom(FunctionSpace space); + + GeometryInfo dofs_per_geom(FunctionSpace space); + GeometryInfo interior_dofs_per_geom(FunctionSpace space); + +} diff --git a/src/serac/physics/state/finite_element_vector.hpp b/src/serac/physics/state/finite_element_vector.hpp index 399b34ce5d..8b10690b55 100644 --- a/src/serac/physics/state/finite_element_vector.hpp +++ b/src/serac/physics/state/finite_element_vector.hpp @@ -20,6 +20,7 @@ #include "serac/serac_config.hpp" #include "serac/infrastructure/variant.hpp" #include "serac/numerics/functional/functional.hpp" +#include "serac/numerics/refactor/finite_element.hpp" namespace serac { @@ -81,6 +82,45 @@ class FiniteElementVector : public mfem::HypreParVector { HypreParVector::operator=(0.0); } + + FiniteElementVector(mfem::ParMesh& mesh, Family family, int p, int components, const std::string& name = "") + : mesh_(mesh), name_(name) + { + const int dim = mesh.Dimension(); + + switch (family) { + case Family::QOI: + SLIC_ERROR("invalid family choice for FiniteElementVector ctor"); + break; + + case Family::H1: + coll_ = std::make_unique(p, dim); + break; + case Family::HCURL: + coll_ = std::make_unique(p, dim); + break; + case Family::HDIV: + coll_ = std::make_unique(p, dim); + break; + case Family::L2: + // We use GaussLobatto basis functions as this is what is used for the serac::Functional FE kernels + coll_ = std::make_unique(p, dim, mfem::BasisType::GaussLobatto); + break; + } + + space_ = std::make_unique(&mesh, coll_.get(), components, serac::ordering); + + // Construct a hypre par vector based on the new finite element space + HypreParVector new_vector(space_.get()); + + // Move the data from this new hypre vector into this object without doubly allocating the data + auto* parallel_vec = new_vector.StealParVector(); + WrapHypreParVector(parallel_vec); + + // Initialize the vector to zero + HypreParVector::operator=(0.0); + } + /** * @brief Copy constructor * From 09f44797f4faafde55c76c48e2217ac52a83e903 Mon Sep 17 00:00:00 2001 From: Sam Mish Date: Fri, 10 Jan 2025 15:35:28 -0800 Subject: [PATCH 14/15] fix typo in evaluate.cpp, reenable H1_eval tests --- src/serac/numerics/refactor/evaluate.cpp | 2 +- .../refactor/tests/h1_evaluation_tests.cpp | 57 ++++++++----------- 2 files changed, 25 insertions(+), 34 deletions(-) diff --git a/src/serac/numerics/refactor/evaluate.cpp b/src/serac/numerics/refactor/evaluate.cpp index 9e1e73b121..450cfe45df 100644 --- a/src/serac/numerics/refactor/evaluate.cpp +++ b/src/serac/numerics/refactor/evaluate.cpp @@ -123,7 +123,7 @@ void evaluate(nd::array & output, const Field & u_T, Domain & domain, P->Mult(u_T, u_L); // we just use this as a key to create/fetch the appropriate restriction operator - serac::FunctionSpace space{get_family(u_T), int(get_degree(u_T)), 1}; + serac::FunctionSpace space{get_family(u_T), int(get_degree(u_T)), int(u_components)}; // insert_restriction is idempotent, so only the first call will do anything expensive domain.insert_restriction(u_fes, space); diff --git a/src/serac/numerics/refactor/tests/h1_evaluation_tests.cpp b/src/serac/numerics/refactor/tests/h1_evaluation_tests.cpp index b2f0a9dc6e..3ab889e55d 100644 --- a/src/serac/numerics/refactor/tests/h1_evaluation_tests.cpp +++ b/src/serac/numerics/refactor/tests/h1_evaluation_tests.cpp @@ -48,15 +48,14 @@ void evaluation_test(std::string filename, Field X = mesh_coordinates(mesh); - //for (uint32_t q = 1; q <= 4; q++) { - for (uint32_t q = 1; q <= 1; q++) { + for (uint32_t q = 1; q <= 4; q++) { MeshQuadratureRule qrule(q); auto X_q = evaluate(X, domain, qrule); auto dX_dxi_q = evaluate(grad(X), domain, qrule); - auto u_q = evaluate(u, domain, qrule); + auto du_dxi_q = evaluate(grad(u), domain, qrule); auto du_dX_q_2 = forall(contravariant_piola, du_dxi_q, dX_dxi_q); @@ -64,12 +63,6 @@ void evaluation_test(std::string filename, auto f_q = forall(f, X_q); auto df_dX_q = forall(grad_f, X_q); - print(X_q); - print(f_q); - print(u_q); - - //return 3 * pow(x[0], p) + 2 * x[1] + x[2]; - EXPECT_LT(relative_error(flatten(u_q), flatten(f_q)), tolerance); EXPECT_LT(relative_error(du_dX_q_2, df_dX_q), tolerance); @@ -88,17 +81,17 @@ TEST(InterpolationTest2D, NAME) { ); \ } -//GENERATE_TEST_2D(PatchTestTriP1, "patch2D_tris.mesh", 1, 1.0e-15); -//GENERATE_TEST_2D(PatchTestTriP2, "patch2D_tris.mesh", 2, 1.0e-14); -//GENERATE_TEST_2D(PatchTestTriP3, "patch2D_tris.mesh", 3, 1.5e-14); -// -//GENERATE_TEST_2D(PatchTestQuadP1, "patch2D_quads.mesh", 1, 1.0e-15); -//GENERATE_TEST_2D(PatchTestQuadP2, "patch2D_quads.mesh", 2, 1.0e-14); -//GENERATE_TEST_2D(PatchTestQuadP3, "patch2D_quads.mesh", 3, 1.0e-14); -// -//GENERATE_TEST_2D(PatchTestTriAndQuadP1, "patch2D_tris_and_quads.mesh", 1, 1.0e-15); -//GENERATE_TEST_2D(PatchTestTriAndQuadP2, "patch2D_tris_and_quads.mesh", 2, 1.0e-14); -//GENERATE_TEST_2D(PatchTestTriAndQuadP3, "patch2D_tris_and_quads.mesh", 3, 2.0e-14); +GENERATE_TEST_2D(PatchTestTriP1, "patch2D_tris.mesh", 1, 1.0e-15); +GENERATE_TEST_2D(PatchTestTriP2, "patch2D_tris.mesh", 2, 1.0e-14); +GENERATE_TEST_2D(PatchTestTriP3, "patch2D_tris.mesh", 3, 1.5e-14); + +GENERATE_TEST_2D(PatchTestQuadP1, "patch2D_quads.mesh", 1, 1.0e-15); +GENERATE_TEST_2D(PatchTestQuadP2, "patch2D_quads.mesh", 2, 1.0e-14); +GENERATE_TEST_2D(PatchTestQuadP3, "patch2D_quads.mesh", 3, 1.0e-14); + +GENERATE_TEST_2D(PatchTestTriAndQuadP1, "patch2D_tris_and_quads.mesh", 1, 1.0e-15); +GENERATE_TEST_2D(PatchTestTriAndQuadP2, "patch2D_tris_and_quads.mesh", 2, 1.0e-14); +GENERATE_TEST_2D(PatchTestTriAndQuadP3, "patch2D_tris_and_quads.mesh", 3, 2.0e-14); ///////////////////////////////////////////////////////////////////////////////////////////////// @@ -113,19 +106,17 @@ TEST(InterpolationTest3D, NAME) { ); \ } -GENERATE_TEST_3D(OneTetP1, "onetet.mesh", 1, 5.0e-16); - -//GENERATE_TEST_3D(PatchTestTetP1, "patch3D_tets.mesh", 1, 5.0e-16); -//GENERATE_TEST_3D(PatchTestTetP2, "patch3D_tets.mesh", 2, 5.0e-15); -//GENERATE_TEST_3D(PatchTestTetP3, "patch3D_tets.mesh", 3, 2.0e-14); -// -//GENERATE_TEST_3D(PatchTestHexP1, "patch3D_hexes.mesh", 1, 2.0e-15); -//GENERATE_TEST_3D(PatchTestHexP2, "patch3D_hexes.mesh", 2, 2.0e-14); -//GENERATE_TEST_3D(PatchTestHexP3, "patch3D_hexes.mesh", 3, 4.5e-13); -// -//GENERATE_TEST_3D(PatchTestTetAndHexP1, "patch3D_tets_and_hexes.mesh", 1, 1.5e-15); -//GENERATE_TEST_3D(PatchTestTetAndHexP2, "patch3D_tets_and_hexes.mesh", 2, 1.5e-14); -//GENERATE_TEST_3D(PatchTestTetAndHexP3, "patch3D_tets_and_hexes.mesh", 3, 3.5e-13); +GENERATE_TEST_3D(PatchTestTetP1, "patch3D_tets.mesh", 1, 5.0e-16); +GENERATE_TEST_3D(PatchTestTetP2, "patch3D_tets.mesh", 2, 5.0e-15); +GENERATE_TEST_3D(PatchTestTetP3, "patch3D_tets.mesh", 3, 2.0e-14); + +GENERATE_TEST_3D(PatchTestHexP1, "patch3D_hexes.mesh", 1, 2.0e-15); +GENERATE_TEST_3D(PatchTestHexP2, "patch3D_hexes.mesh", 2, 2.0e-14); +GENERATE_TEST_3D(PatchTestHexP3, "patch3D_hexes.mesh", 3, 4.5e-13); + +GENERATE_TEST_3D(PatchTestTetAndHexP1, "patch3D_tets_and_hexes.mesh", 1, 1.5e-15); +GENERATE_TEST_3D(PatchTestTetAndHexP2, "patch3D_tets_and_hexes.mesh", 2, 1.5e-14); +GENERATE_TEST_3D(PatchTestTetAndHexP3, "patch3D_tets_and_hexes.mesh", 3, 3.5e-13); int main(int argc, char* argv[]) { int num_procs, myid; From 4f0d8fc6ab9422c78b70ef21a381f7081848de7c Mon Sep 17 00:00:00 2001 From: Sam Mish Date: Mon, 13 Jan 2025 16:05:42 -0800 Subject: [PATCH 15/15] working on residual integration --- .../functional/element_restriction.hpp | 4 +- src/serac/numerics/functional/tensor.hpp | 23 ++ src/serac/numerics/functional/typedefs.hpp | 2 +- .../numerics/refactor/containers/ndarray.hpp | 4 +- src/serac/numerics/refactor/evaluate.cpp | 28 -- src/serac/numerics/refactor/evaluate.hpp | 69 ---- src/serac/numerics/refactor/geometry.hpp | 14 + src/serac/numerics/refactor/integrate.hpp | 305 ++++++++++++++++++ .../numerics/refactor/integrate_residual.cpp | 103 ++---- .../integrate_residual_H1_flux_tests.cpp | 67 ++-- src/serac/numerics/refactor/type_traits.hpp | 70 ++++ .../boundary_conditions.hpp | 22 ++ 12 files changed, 501 insertions(+), 210 deletions(-) create mode 100644 src/serac/numerics/refactor/type_traits.hpp create mode 100644 src/serac/physics/boundary_conditions/boundary_conditions.hpp diff --git a/src/serac/numerics/functional/element_restriction.hpp b/src/serac/numerics/functional/element_restriction.hpp index dc2e1c3360..25fa55f215 100644 --- a/src/serac/numerics/functional/element_restriction.hpp +++ b/src/serac/numerics/functional/element_restriction.hpp @@ -61,7 +61,7 @@ struct DoF { DoF() : bits{} {} /// copy ctor - DoF(const DoF& other) : bits{other.bits} {} + //DoF(const DoF& other) : bits{other.bits} {} /// create a `DoF` from the given index, sign and orientation values DoF(uint64_t index, uint64_t sign = 0, uint64_t orientation = 0) @@ -70,7 +70,7 @@ struct DoF { } /// copy assignment operator - void operator=(const DoF& other) { bits = other.bits; } + //void operator=(const DoF& other) { bits = other.bits; } /// get the sign field of this `DoF` int sign() const { return (bits & sign_mask) ? -1 : 1; } diff --git a/src/serac/numerics/functional/tensor.hpp b/src/serac/numerics/functional/tensor.hpp index eeb30b1948..22755d8172 100644 --- a/src/serac/numerics/functional/tensor.hpp +++ b/src/serac/numerics/functional/tensor.hpp @@ -626,6 +626,15 @@ SERAC_HOST_DEVICE constexpr auto& operator-=(tensor& A, zero) return A; } +/** + * @overload + * @note this overload implements the case where both arguments are scalars + */ +SERAC_HOST_DEVICE constexpr auto outer(double A, double B) +{ + return A * B; +} + /** * @overload * @note this overload implements the case where the left argument is a scalar, and the right argument is a tensor @@ -1269,6 +1278,11 @@ SERAC_HOST_DEVICE constexpr auto I2(const tensor& A) A[2][0] * A[0][2]; } +SERAC_HOST_DEVICE constexpr auto det(const double & A) +{ + return A; +} + /** * @brief Returns the determinant of a matrix * @param[in] A The matrix to obtain the determinant of @@ -1626,6 +1640,15 @@ SERAC_HOST_DEVICE constexpr auto linear_solve(const LuFactorization& /* lu return zero{}; } +/** + * @brief Inverts a (1x1) matrix + * @param[in] A The "matrix" to invert + */ +SERAC_HOST_DEVICE constexpr double inv(const double & A) +{ + return 1.0 / A; +} + /** * @brief Inverts a matrix * @param[in] A The matrix to invert diff --git a/src/serac/numerics/functional/typedefs.hpp b/src/serac/numerics/functional/typedefs.hpp index 7dbe070f9a..1515590c62 100644 --- a/src/serac/numerics/functional/typedefs.hpp +++ b/src/serac/numerics/functional/typedefs.hpp @@ -7,7 +7,7 @@ namespace serac { // interface change like that, so these typedefs mark the parts that would need to eventually change /// @cond -using mesh_t = mfem::Mesh; +using mesh_t = mfem::ParMesh; using fes_t = mfem::FiniteElementSpace; /// @endcond diff --git a/src/serac/numerics/refactor/containers/ndarray.hpp b/src/serac/numerics/refactor/containers/ndarray.hpp index 899f1164b9..d0dc692cb7 100644 --- a/src/serac/numerics/refactor/containers/ndarray.hpp +++ b/src/serac/numerics/refactor/containers/ndarray.hpp @@ -515,8 +515,8 @@ template <> struct printer{ static SERAC_HOST_DEVICE void print(int8_t x template <> struct printer{ static SERAC_HOST_DEVICE void print(uint8_t x) { printf("%u", x); } }; template <> struct printer{ static SERAC_HOST_DEVICE void print(int32_t x) { printf("%d", x); } }; template <> struct printer{ static SERAC_HOST_DEVICE void print(uint32_t x) { printf("%u", x); } }; -template <> struct printer{ static SERAC_HOST_DEVICE void print(int64_t x) { printf("%ld", x); } }; -template <> struct printer{ static SERAC_HOST_DEVICE void print(uint64_t x) { printf("%lu", x); } }; +template <> struct printer{ static SERAC_HOST_DEVICE void print(int64_t x) { printf("%lld", x); } }; +template <> struct printer{ static SERAC_HOST_DEVICE void print(uint64_t x) { printf("%llu", x); } }; template < typename T, uint32_t dim > SERAC_HOST_DEVICE void print_recursive(nd::view< T, dim > arr, int depth) { diff --git a/src/serac/numerics/refactor/evaluate.cpp b/src/serac/numerics/refactor/evaluate.cpp index 450cfe45df..5c6bf12008 100644 --- a/src/serac/numerics/refactor/evaluate.cpp +++ b/src/serac/numerics/refactor/evaluate.cpp @@ -5,20 +5,6 @@ namespace refactor { -inline GeometryData< nd::range > ranges(GeometryInfo a) { - GeometryData< nd::range > output; - - uint32_t total = 0; - output.vert = nd::range{total, total + a.vert}; total += a.vert; - output.edge = nd::range{total, total + a.edge}; total += a.edge; - output.tri = nd::range{total, total + a.tri}; total += a.tri; - output.quad = nd::range{total, total + a.quad}; total += a.quad; - output.tet = nd::range{total, total + a.tet}; total += a.tet; - output.hex = nd::range{total, total + a.hex}; total += a.hex; - - return output; -}; - namespace impl { template < mfem::Geometry::Type geom, Family family, DerivedQuantity op > @@ -192,20 +178,6 @@ FieldOp div(const Field & f) { return {DerivedQuantity::DERIVATIVE, f}; } -BasisFunctionOp grad(const BasisFunction & f) { - SLIC_ERROR_IF(!is_scalar_valued(f.space.family), "grad(BasisFunction) only supports scalar-valued function spaces"); - return {DerivedQuantity::DERIVATIVE, f}; -} - -BasisFunctionOp curl(const BasisFunction & f) { - SLIC_ERROR_IF(f.space.family != Family::HCURL, "curl(BasisFunction) only supports Family::Hcurl"); - return {DerivedQuantity::DERIVATIVE, f}; -} - -BasisFunctionOp div(const BasisFunction & f) { - SLIC_ERROR_IF(f.space.family != Family::HDIV, "div(BasisFunction) only supports Family::Hdiv"); - return {DerivedQuantity::DERIVATIVE, f}; -} } // namespace refactor #endif diff --git a/src/serac/numerics/refactor/evaluate.hpp b/src/serac/numerics/refactor/evaluate.hpp index c9de42df82..ee37d50e82 100644 --- a/src/serac/numerics/refactor/evaluate.hpp +++ b/src/serac/numerics/refactor/evaluate.hpp @@ -26,81 +26,12 @@ struct FieldOp { FieldOp(const DerivedQuantity & o, const Field & f) : op(o), field(f){}; }; -struct BasisFunctionOp { - const Modifier mod; - const DerivedQuantity op; - const BasisFunction function; - - BasisFunctionOp(const BasisFunction & f) : mod(Modifier::NONE), op(DerivedQuantity::VALUE), function(f){}; - BasisFunctionOp(const DerivedQuantity & o, const BasisFunction & f) : mod(Modifier::NONE), op(o), function(f){}; - BasisFunctionOp(const Modifier & m, const DerivedQuantity & o, const BasisFunction & f) : mod(m), op(o), function(f){}; -}; - //////////////////////////////////////////////////////////////////////////////// FieldOp grad(const Field & f); FieldOp curl(const Field & f); FieldOp div(const Field & f); -BasisFunctionOp grad(const BasisFunction & phi); -BasisFunctionOp curl(const BasisFunction & phi); -BasisFunctionOp div(const BasisFunction & phi); - -//////////////////////////////////////////////////////////////////////////////// - -// for integrating sparse matrices (e.g. mass, stiffness) -template < typename T1, typename T2, typename T3 > -struct WeightedIntegrand { - const T1 test; - const T2 & qdata; - const T3 trial; -}; - -// for integrating residual vectors -template < typename T1, typename T2 > -struct WeightedIntegrand< T1, T2, void > { - const T1 test; - const T2 & qdata; -}; - -template < typename T > -struct DiagonalOnly : public T {}; - -template < typename T > -DiagonalOnly(T) -> DiagonalOnly; - -template < typename T, uint32_t n > -auto operator*(const nd::array & data, const BasisFunction & phi) { - return WeightedIntegrand< BasisFunctionOp, nd::array, void >{phi, data}; -} - -template < typename T, uint32_t n > -auto operator*(const nd::array & data, const BasisFunctionOp & dphi) { - return WeightedIntegrand< BasisFunctionOp, nd::array, void >{dphi, data}; -} - -template < typename T, uint32_t n > -auto dot(const nd::array & data, const BasisFunctionOp & dphi) { - return WeightedIntegrand< BasisFunctionOp, nd::array, void >{dphi, data}; -} - -template < typename T, uint32_t n > -auto diagonal(WeightedIntegrand< BasisFunctionOp, nd::array, BasisFunctionOp > integrand) { - SERAC_ASSERT( - integrand.test.function == integrand.trial.function, - "diag(...) requires same test and trial space" - ); - - return DiagonalOnly{integrand}; -} - -//////////////////////////////////////////////////////////////////////////////// - -template < typename T, uint32_t n > -auto dot(BasisFunctionOp psi, const nd::array & data, BasisFunctionOp phi) { - return WeightedIntegrand< BasisFunctionOp, nd::array, BasisFunctionOp >{phi, data, psi}; -} - //////////////////////////////////////////////////////////////////////////////// double dot(const Residual & r, const Field & u); diff --git a/src/serac/numerics/refactor/geometry.hpp b/src/serac/numerics/refactor/geometry.hpp index d6cfb7ea72..8b541e740f 100644 --- a/src/serac/numerics/refactor/geometry.hpp +++ b/src/serac/numerics/refactor/geometry.hpp @@ -140,6 +140,20 @@ inline GeometryInfo operator*(GeometryInfo a, uint32_t scale) { }; }; +inline GeometryData< nd::range > ranges(GeometryInfo a) { + GeometryData< nd::range > output; + + uint32_t total = 0; + output.vert = nd::range{total, total + a.vert}; total += a.vert; + output.edge = nd::range{total, total + a.edge}; total += a.edge; + output.tri = nd::range{total, total + a.tri}; total += a.tri; + output.quad = nd::range{total, total + a.quad}; total += a.quad; + output.tet = nd::range{total, total + a.tet}; total += a.tet; + output.hex = nd::range{total, total + a.hex}; total += a.hex; + + return output; +}; + inline uint32_t total(GeometryInfo input){ return input.vert + input.edge + input.tri + input.quad + input.tet + input.hex; }; diff --git a/src/serac/numerics/refactor/integrate.hpp b/src/serac/numerics/refactor/integrate.hpp index c4f598f6c0..b3d8804fd8 100644 --- a/src/serac/numerics/refactor/integrate.hpp +++ b/src/serac/numerics/refactor/integrate.hpp @@ -1,4 +1,309 @@ #pragma once +#include + +#include "serac/numerics/functional/family.hpp" +#include "serac/numerics/refactor/type_traits.hpp" #include "serac/numerics/refactor/finite_element.hpp" #include "serac/physics/state/finite_element_state.hpp" +#include "serac/physics/state/finite_element_dual.hpp" + +//#include "misc/for_constexpr.hpp" + +namespace refactor { + +struct BasisFunctionOp { + const Modifier mod; + const DerivedQuantity op; + const BasisFunction function; + + BasisFunctionOp(const BasisFunction & f) : mod(Modifier::NONE), op(DerivedQuantity::VALUE), function(f){}; + BasisFunctionOp(const DerivedQuantity & o, const BasisFunction & f) : mod(Modifier::NONE), op(o), function(f){}; + BasisFunctionOp(const Modifier & m, const DerivedQuantity & o, const BasisFunction & f) : mod(m), op(o), function(f){}; +}; + +BasisFunctionOp grad(const BasisFunction & phi); +BasisFunctionOp curl(const BasisFunction & phi); +BasisFunctionOp div(const BasisFunction & phi); + +// for integrating sparse matrices (e.g. mass, stiffness) +template < typename T1, typename T2, typename T3 > +struct WeightedIntegrand { + const T1 test; + const T2 & qdata; + const T3 trial; +}; + +// for integrating residual vectors +template < typename T1, typename T2 > +struct WeightedIntegrand< T1, T2, void > { + const T1 test; + const T2 & qdata; +}; + +inline BasisFunctionOp grad(const BasisFunction & f) { + SLIC_ERROR_IF(!is_scalar_valued(f.space.family), "grad(BasisFunction) only supports scalar-valued function spaces"); + return {DerivedQuantity::DERIVATIVE, f}; +} + +inline BasisFunctionOp curl(const BasisFunction & f) { + SLIC_ERROR_IF(f.space.family != Family::HCURL, "curl(BasisFunction) only supports Family::Hcurl"); + return {DerivedQuantity::DERIVATIVE, f}; +} + +inline BasisFunctionOp div(const BasisFunction & f) { + SLIC_ERROR_IF(f.space.family != Family::HDIV, "div(BasisFunction) only supports Family::Hdiv"); + return {DerivedQuantity::DERIVATIVE, f}; +} + +template < typename T > +struct DiagonalOnly : public T {}; + +template < typename T > +DiagonalOnly(T) -> DiagonalOnly; + +template < typename T, uint32_t n > +auto operator*(const nd::array & data, const BasisFunction & phi) { + return WeightedIntegrand< BasisFunctionOp, nd::array, void >{phi, data}; +} + +template < typename T, uint32_t n > +auto operator*(const nd::array & data, const BasisFunctionOp & dphi) { + return WeightedIntegrand< BasisFunctionOp, nd::array, void >{dphi, data}; +} + +template < typename T, uint32_t n > +auto dot(const nd::array & data, const BasisFunctionOp & dphi) { + return WeightedIntegrand< BasisFunctionOp, nd::array, void >{dphi, data}; +} + +template < typename T, uint32_t n > +auto diagonal(WeightedIntegrand< BasisFunctionOp, nd::array, BasisFunctionOp > integrand) { + SERAC_ASSERT( + integrand.test.function == integrand.trial.function, + "diag(...) requires same test and trial space" + ); + + return DiagonalOnly{integrand}; +} + +//////////////////////////////////////////////////////////////////////////////// + +template < typename T, uint32_t n > +auto dot(BasisFunctionOp psi, const nd::array & data, BasisFunctionOp phi) { + return WeightedIntegrand< BasisFunctionOp, nd::array, BasisFunctionOp >{phi, data, psi}; +} + +namespace impl { + +template < typename T > +struct is_a_weighted_integrand { + static constexpr bool value = false; +}; + +template < typename T1, typename T2, typename T3 > +struct is_a_weighted_integrand < WeightedIntegrand< T1, T2, T3 > >{ + static constexpr bool value = true; +}; + +template < typename T1, typename T2, typename T3 > +struct is_a_weighted_integrand < DiagonalOnly< WeightedIntegrand< T1, T2, T3 > > >{ + static constexpr bool value = true; +}; + +template < typename return_type, typename T > +uint32_t dimension_of_first_argument(return_type (* /*integrand*/)(T)) { + return dimension(T{}); +} + +template < typename return_type, typename T > +uint32_t dimension_of_first_argument(std::function< return_type(T) > /*integrand*/) { + return dimension(T{}); +} + +//////////////////////////////////////////////////////////////////////////////// + +#if 0 +template < typename T > +T integrate_ndarray(const nd::array< T > & integrand, const Domain& domain); + +//////////////////////////////////////////////////////////////////////////////// + +template < typename return_type > +return_type integrate_function_pointer(return_type (*f)(vec2), const Domain& domain, const DomainType & type); + +template < typename return_type > +return_type integrate_function_pointer(return_type (*f)(vec3), const Domain& domain, const DomainType & type); + +//////////////////////////////////////////////////////////////////////////////// + +template < typename return_type > +return_type integrate_stdfunction(std::function< return_type(vec2) > integrand, const Domain& domain, const DomainType & type); + +template < typename return_type > +return_type integrate_stdfunction(std::function< return_type(vec3) > integrand, const Domain& domain, const DomainType & type); +#endif + +//////////////////////////////////////////////////////////////////////////////// + +template < serac::Family family > +void integrate_residual(Residual & r, BasisFunctionOp b, const nd::view f, Domain & domain); + +template < uint32_t n > +Residual integrate_weighted_integrand( + const WeightedIntegrand< BasisFunctionOp, nd::array, void > & integrand, + Domain & domain) { + + DerivedQuantity op = integrand.test.op; + BasisFunction phi = integrand.test.function; + Family test_family = phi.space.family; + uint32_t p = phi.space.degree; + uint32_t components = phi.space.components; + uint32_t gdim = geometry_dimension(domain); + + Residual r(domain.mesh_, test_family, p, components); + + const nd::array & qdata = integrand.qdata; + + stack::array shape3D{qdata.shape[0], components, qshape(test_family, op, gdim)}; + + refactor_ASSERT(compatible_shapes(qdata.shape, shape3D), "incompatible array shapes"); + + nd::view q3D{qdata.data(), shape3D}; + foreach_constexpr< serac::Family::H1, serac::Family::Hcurl >([&](auto family) { + if (family == test_family) { + integrate_residual< family >(r, integrand.test, q3D, domain, type); + } + }); + + return r; +} + +//////////////////////////////////////////////////////////////////////////////// + +#if 0 +template +std::function< void(refactor::sparse_matrix&) > integrate_sparse_matrix(BasisFunctionOp phi, const nd::view f, BasisFunctionOp psi, const Domain &domain); + +template < uint32_t n > +std::function< void(refactor::sparse_matrix&) > integrate_weighted_integrand( + const WeightedIntegrand< BasisFunctionOp, nd::array, BasisFunctionOp > & integrand, + const Domain & domain) { + + BasisFunctionOp phi = integrand.test; + BasisFunctionOp psi = integrand.trial; + const nd::array & qdata = integrand.qdata; + + DerivedQuantity test_op = phi.op; + DerivedQuantity trial_op = psi.op; + FunctionSpace test_space = phi.function.space; + FunctionSpace trial_space = psi.function.space; + uint32_t test_components = phi.function.space.components; + uint32_t trial_components = psi.function.space.components; + uint32_t sdim = domain.mesh.spatial_dimension; + uint32_t gdim = domain.mesh.geometry_dimension; + + stack::array shape5D = { + qdata.shape[0], + phi.function.space.components, qshape(test_space.family, test_op, gdim), + psi.function.space.components, qshape(trial_space.family, trial_op, gdim) + }; + + SLIC_ASSER_MSH(compatible_shapes(qdata.shape, shape5D), "incompatible array shapes"); + + std::function< void(refactor::sparse_matrix&) > output; + + nd::view q5D{qdata.data(), shape5D}; + foreach_constexpr< serac::Family::H1, serac::Family::Hcurl >([&](auto test_family) { + foreach_constexpr< serac::Family::H1, serac::Family::Hcurl >([&](auto trial_family) { + if (test_family == test_space.family && trial_family == trial_space.family) { + output = integrate_sparse_matrix< test_family, trial_family >(phi, q5D, psi, domain, type); + } + }); + }); + + return output; + +} + +//////////////////////////////////////////////////////////////////////////////// + +template +void integrate_sparse_matrix_diagonal(Residual & r, BasisFunctionOp phi, const nd::view f, BasisFunctionOp psi, const Domain &domain); + +template < uint32_t n > +nd::array integrate_weighted_integrand( + const DiagonalOnly < WeightedIntegrand< BasisFunctionOp, nd::array, BasisFunctionOp > > & integrand, + const Domain & domain) { + + BasisFunctionOp phi = integrand.test; + BasisFunctionOp psi = integrand.trial; + const nd::array & qdata = integrand.qdata; + + SLIC_ASSERT_MSG(phi.function.space == psi.function.space, "must have matching test and trial spaces for diag(...)"); + + DerivedQuantity test_op = phi.op; + DerivedQuantity trial_op = psi.op; + Family test_family = phi.function.space.family; + Family trial_family = psi.function.space.family; + uint32_t test_components = phi.function.space.components; + uint32_t trial_components = psi.function.space.components; + uint32_t sdim = domain.mesh.spatial_dimension; + uint32_t gdim = domain.mesh.geometry_dimension; + + stack::array shape5D = { + qdata.shape[0], + phi.function.space.components, qshape(test_family, test_op, gdim), + psi.function.space.components, qshape(trial_family, trial_op, gdim) + }; + + SLIC_ASSERT_MSG(compatible_shapes(qdata.shape, shape5D), "incompatible array shapes"); + + Residual output(phi.function.space, domain.mesh); + + nd::view q5D{qdata.data(), shape5D}; + foreach_constexpr< Family::H1, Family::Hcurl >([&](auto family) { + if (family == test_family) { + integrate_sparse_matrix_diagonal< family >(output, phi, q5D, psi, domain, type); + } + }); + + return output.data; + +} +#endif + +} // namespace impl + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +template < typename integrand_t > +auto integrate(const integrand_t & integrand, Domain & domain) { + + //if constexpr (is_a_1D_ndarray::value) { + // return impl::integrate_ndarray(integrand, d.domain, d.type); + //} + + //if constexpr (is_a_function_pointer::value) { + // uint32_t sdim = impl::dimension_of_first_argument(integrand); + // SLIC_ASSERT_MSG(d.domain.mesh.X.data.shape[1] != sdim, "integration function has invalid signature"); + // return impl::integrate_function_pointer(integrand, d.domain, d.type); + //} + + //if constexpr (is_a_stdfunction::value) { + // uint32_t sdim = impl::dimension_of_first_argument(integrand); + // SLIC_ASSERT_MSG(d.domain.mesh.X.data.shape[1] != sdim, "integration function has invalid signature"); + // return impl::integrate_stdfunction(integrand, d.domain, d.type); + //} + + if constexpr (impl::is_a_weighted_integrand::value) { + return impl::integrate_weighted_integrand(integrand, domain); + } + + static_assert(always_true::value, "error: unsupported integrand type"); + +} + +} \ No newline at end of file diff --git a/src/serac/numerics/refactor/integrate_residual.cpp b/src/serac/numerics/refactor/integrate_residual.cpp index 89e8b4b568..685125c7ce 100644 --- a/src/serac/numerics/refactor/integrate_residual.cpp +++ b/src/serac/numerics/refactor/integrate_residual.cpp @@ -1,7 +1,6 @@ -#if 0 -#include "common.hpp" +#include "serac/numerics/refactor/integrate.hpp" -#include "serac/numerics/functional/tensor.hpp" +#include "serac/numerics/refactor/common.hpp" namespace refactor { @@ -30,12 +29,8 @@ void batched_integrate_residual(Residual & r, nd::view input_q(reinterpret_cast(&f_q[0]), {f_q.shape[0], f_q.shape[1]}); - constexpr uint32_t gdim = dimension(geom); uint32_t qpts_per_element = impl::qpe(xi.shape[0]); - using A_type = decltype(weighted_piola_transformation(mat{})); - - uint32_t num_nodes = get_num_nodes(r); uint32_t r_components = get_num_components(r); uint32_t r_nodes_per_element = r_el.num_nodes(); auto r_shape_fns = [&](){ @@ -52,28 +47,6 @@ void batched_integrate_residual(Residual & r, } }(); - FiniteElement< geom, Family::H1 > X_el{get_degree(X)}; - uint32_t X_components = get_num_components(X); - uint32_t X_nodes_per_element = X_el.num_nodes(); - - auto X_shape_fn_grads = X_el.evaluate_shape_function_gradients(xi); - - // When do we need to calculate dX/dxi? - // - // ❌ : don't need to ✅ : need to - // +---------------------+------+-------+------+----+ - // | | H1 | Hcurl | Hdiv | DG | - // +---------------------+------+-------+------+----+ - // | isoparametric value | ❌ | ❌ | ❌ | ❌ | - // +---------------------+------+-------+------+----+ - // | isoparametric deriv | ❌ | ❌ | ❌ | ❌ | - // +---------------------+------+-------+------+----+ - // | spatial value | ✅ | ✅ | ✅ | ✅ | - // +---------------------+------+-------+------+----+ - // | spatial deriv | ✅ | ✅ | ✅ | ✅ | - // +---------------------+------+-------+------+----+ - const bool need_to_compute_dX_dxi = (type == DomainType::SPATIAL); - stack::array element_residual_shape = {num_elements * r_nodes_per_element, r_components}; if (element_residual_buffer.sz < nd::product(element_residual_shape)) { @@ -82,19 +55,6 @@ void batched_integrate_residual(Residual & r, nd::view element_residuals(element_residual_buffer.data(), element_residual_shape); - nd::array< A_type > A_q; - nd::array< vec, 2 > dX_dxi_q; - nd::array X_ids; - nd::array X_e; - nd::array< double > X_scratch; - - if (need_to_compute_dX_dxi) { - X_e.resize(X_nodes_per_element); - X_scratch.resize({X_el.batch_interpolation_scratch_space(xi)}); - A_q.resize({qpts_per_element}); - dX_dxi_q.resize({X_components, qpts_per_element}); - } - // for each element with this geometry for (uint32_t i = 0; i < num_elements; i++) { @@ -102,35 +62,11 @@ void batched_integrate_residual(Residual & r, nd::array r_e({r_nodes_per_element}); nd::array< double > r_scratch({r_el.batch_interpolation_scratch_space(xi)}); - if (need_to_compute_dX_dxi) { - - for (uint32_t c = 0; c < X_components; c++) { - for (uint32_t j = 0; j < X_nodes_per_element; j++) { - X_e(j) = X.data(X_ids(j), c); - } - X_el.gradient(dX_dxi_q(c), X_e, X_shape_fn_grads, X_scratch.data()); - } - - for (uint32_t q = 0; q < qpts_per_element; q++) { - mat dX_dxi; - for (uint32_t c = 0; c < gdim; c++) { - dX_dxi[c] = dX_dxi_q(c, q); - } - A_q[q] = weighted_piola_transformation(dX_dxi); - } - - } - nd::array input_xi_q({qpts_per_element}); for (uint32_t c = 0; c < r_components; c++) { - if (need_to_compute_dX_dxi) { - for (uint32_t q = 0; q < qpts_per_element; q++) { - input_xi_q(q) = serac::dot(A_q[q], input_q(i*qpts_per_element+q, c)); - } - } else { - for (uint32_t q = 0; q < qpts_per_element; q++) { - input_xi_q(q) = input_q(i*qpts_per_element+q, c); - } + + for (uint32_t q = 0; q < qpts_per_element; q++) { + input_xi_q(q) = input_q(i*qpts_per_element+q, c); } if constexpr (op == DerivedQuantity::VALUE) { @@ -141,9 +77,9 @@ void batched_integrate_residual(Residual & r, r_el.integrate_flux(r_e, input_xi_q, r_shape_fns, r_scratch.data()); } - if constexpr (is_vector_valued(family)) { - r_el.reorient(TransformationType::TransposePhysicalToParent, &connectivity(elements(i), 0), r_e.data()); - } + //if constexpr (is_vector_valued(family)) { + // r_el.reorient(TransformationType::TransposePhysicalToParent, &connectivity(elements(i), 0), r_e.data()); + //} for (uint32_t j = 0; j < r_nodes_per_element; j++) { element_residuals(i * r_nodes_per_element + j, c) = r_e(j); @@ -156,7 +92,7 @@ void batched_integrate_residual(Residual & r, } template < DerivedQuantity op, uint32_t n > -void integrate_residual(Residual & r, BasisFunction phi, const nd::array & f_q, const Domain & domain, const DomainType type) { +void integrate_residual(Residual & r, BasisFunction phi, const nd::array & f_q, Domain & domain, const MeshQuadratureRule & qrule) { r = 0.0; @@ -168,31 +104,33 @@ void integrate_residual(Residual & r, BasisFunction phi, const nd::array element_residual_buffer; nd::view f3D{f_q.data(), input_dimensions}; uint32_t offset = 0; foreach_geometry([&](auto geom){ - nd::view elements = domain.active_elements[geom]; - if (gdim == dimension(geom) && elements.shape[0] > 0) { - nd::view xi = domain.rule[geom].points; - nd::view weights = domain.rule[geom].weights; - nd::view connectivity = domain.mesh[geom]; + const std::vector & elements = domain.get(geom); + if (gdim == dimension(geom) && elements.size() > 0) { + nd::view xi = qrule[geom].points; + nd::view weights = qrule[geom].weights; - nd::view integrand_geom = {&f3D(offset, 0, 0), {domain.num_qpts[geom], f3D.shape[1], f3D.shape[2]}}; + nd::view integrand_geom = {&f3D(offset, 0, 0), {num_qpts[geom], f3D.shape[1], f3D.shape[2]}}; if (phi.space.family == Family::H1) { - batched_integrate_residual(r, domain.mesh.X, type, integrand_geom, elements, xi, weights, element_residual_buffer); + batched_integrate_residual(r, integrand_geom, elements, xi, weights, element_residual_buffer); } if (phi.space.family == Family::HCURL) { - batched_integrate_residual(r, domain.mesh.X, type, integrand_geom, elements, xi, weights, element_residual_buffer); + batched_integrate_residual(r, integrand_geom, elements, xi, weights, element_residual_buffer); } } - offset += domain.num_qpts[geom]; + offset += num_qpts[geom]; }); } @@ -212,4 +150,3 @@ template void integrate_residual(Residual&, Basi } // namespace impl } // namespace refactor -#endif diff --git a/src/serac/numerics/refactor/tests/integrate_residual_H1_flux_tests.cpp b/src/serac/numerics/refactor/tests/integrate_residual_H1_flux_tests.cpp index 9a77960eca..38f96eadf2 100644 --- a/src/serac/numerics/refactor/tests/integrate_residual_H1_flux_tests.cpp +++ b/src/serac/numerics/refactor/tests/integrate_residual_H1_flux_tests.cpp @@ -4,55 +4,72 @@ #include #include -#include "serac/numerics/functional/tensor.hpp" +#include "serac/numerics/refactor/forall.hpp" +#include "serac/numerics/refactor/evaluate.hpp" +#include "serac/numerics/refactor/tests/common.hpp" using namespace serac; using namespace refactor; // ---------------------------------------------------------------------------- -template < typename vecd > +template < typename vec_t > void flux_test(std::string filename, - std::function< double(vecd, int) > f, - std::function< vecd(vecd) > g, + std::function< double(vec_t, int) > f, + std::function< vec_t(vec_t) > g, std::function< double(int) > answer, double tolerance) { - using matd = decltype(outer(vecd{}, vecd{})); + constexpr int components = 1; + constexpr int dim = size(vec_t{}); + using mat_t = decltype(outer(vec_t{}, vec_t{})); - auto mesh = Mesh::load(SERAC_MESH_DIR + filename); + mfem::ParMesh mesh = load_parmesh(SERAC_MESH_DIR + filename); + Domain domain = EntireDomain(mesh); + + Field X = mesh_coordinates(mesh); // evaluate g at each quadrature point - std::function< vecd(vecd, matd) > g_xi = [g](vecd x, matd J) { + std::function< vec_t(vec_t, mat_t) > g_xi = [g](vec_t x, mat_t J) { return dot(serac::inv(J), g(x)) * det(J); }; for (int p = 1; p < 4; p++) { - std::function< double(vecd) > f_p = [f, p](vecd x) { return f(x, p); }; + std::function< double(vec_t) > f_p = [f, p](vec_t x) { return f(x, p); }; + + Field u(mesh, refactor::Family::H1, p, components); - Field u = create_field(mesh, Family::H1, p, 1); - nd::array nodes = nodes_for(u, mesh); - u = forall(f_p, nodes); + mfem::FunctionCoefficient mfem_f([&](const mfem::Vector & mfem_X) { + vec_t X; + if constexpr (dim == 1) { + X = mfem_X[0]; + } else { + for (int i = 0; i < dim; i++) { + X[i] = mfem_X[i]; + } + } + return f(X, p); + }); + + u.project(mfem_f); BasisFunction phi(u); for (int q = p + 1; q < 5; q++) { - Domain domain(mesh, MeshQuadratureRule(q)); + MeshQuadratureRule qrule(static_cast(q)); - auto x_q = evaluate(mesh.X, domain); - auto dx_dxi_q = evaluate(grad(mesh.X), isoparametric(domain)); + auto X_q = evaluate(X, domain, qrule); + auto dX_dxi_q = evaluate(grad(X), domain, qrule); - auto g_q = forall(g, x_q); - auto g_xi_q = forall(g_xi, x_q, dx_dxi_q); + auto g_q = forall(g, X_q); + auto g_xi_q = forall(g_xi, X_q, dX_dxi_q); - Residual r1 = integrate(dot(g_q, grad(phi)), domain); - Residual r2 = integrate(dot(g_xi_q, grad(phi)), isoparametric(domain)); + Residual r = integrate(dot(g_q, grad(phi)), domain, qrule); SCOPED_TRACE("p = " + std::to_string(p) + ", q = " + std::to_string(q)); - EXPECT_NEAR(dot(r1, u), answer(p), tolerance); - EXPECT_NEAR(dot(r2, u), answer(p), tolerance); + EXPECT_NEAR(dot(r, u), answer(p), tolerance); } } @@ -74,11 +91,11 @@ void flux_test(std::string filename, 1/2 */ -std::function f3([](double x, int p){ return pow(x, p); }); -std::function g3([](double x){ return x; }); -std::function answer3([](int p){ return double(p) / double(1 + p); }); - -TEST(IntegrateTest, FluxH1Edges) { flux_test("patch_test_edges.json", f3, g3, answer3, 3.0e-15); } +//std::function f3([](double x, int p){ return pow(x, p); }); +//std::function g3([](double x){ return x; }); +//std::function answer3([](int p){ return double(p) / double(1 + p); }); +// +//TEST(IntegrateTest, FluxH1Edges) { flux_test("patch_test_edges.json", f3, g3, answer3, 3.0e-15); } // ---------------------------------------------------------------------------- diff --git a/src/serac/numerics/refactor/type_traits.hpp b/src/serac/numerics/refactor/type_traits.hpp new file mode 100644 index 0000000000..fc5d944de4 --- /dev/null +++ b/src/serac/numerics/refactor/type_traits.hpp @@ -0,0 +1,70 @@ +#pragma once + +#include + +#include "serac/numerics/refactor/containers/ndarray.hpp" + +namespace refactor { + +template < typename T > +struct always_true { + static constexpr bool value = true; +}; + +//////////////////////////////////////////////////////////////////////////////// + +template < typename T > +struct is_a_1D_ndarray { + static constexpr bool value = false; +}; + +template < typename T > +struct is_a_1D_ndarray < nd::array< T, 1 > >{ + static constexpr bool value = true; +}; + +template < typename T > +struct is_a_1D_ndview { + static constexpr bool value = false; +}; + +template < typename T > +struct is_a_1D_ndview < nd::view< T, 1 > >{ + static constexpr bool value = true; +}; + +template < typename T > +struct is_ndarray { + static constexpr bool value = false; +}; + +template < typename T, uint32_t n > +struct is_ndarray< nd::array > { + static constexpr bool value = true; +}; + +//////////////////////////////////////////////////////////////////////////////// + +template < typename T > +struct is_a_function_pointer { + static constexpr bool value = false; +}; + +template < typename return_type, typename ... argument_types > +struct is_a_function_pointer < return_type (*)(argument_types ...) >{ + static constexpr bool value = true; +}; + +template < typename T > +struct is_a_stdfunction { + static constexpr bool value = false; +}; + +template < typename return_type, typename ... argument_types > +struct is_a_stdfunction < std::function< return_type(argument_types ...) > >{ + static constexpr bool value = true; +}; + +//////////////////////////////////////////////////////////////////////////////// + +} \ No newline at end of file diff --git a/src/serac/physics/boundary_conditions/boundary_conditions.hpp b/src/serac/physics/boundary_conditions/boundary_conditions.hpp new file mode 100644 index 0000000000..f25abe93b9 --- /dev/null +++ b/src/serac/physics/boundary_conditions/boundary_conditions.hpp @@ -0,0 +1,22 @@ +#include +#include + +#include "serac/numerics/functional/tensor.hpp" + +struct BC { + + BC(std::function< double(vec3, t) > f, Domain domain, mfem::FiniteElementSpace & fes) { + + } + + void evaluate(mfem::Vector & v, double t) { + + } + + mfem::Array< int > dof_ids; + + bool is_vector_valued; + std::unique_ptr< mfem::Coefficient > func; + std::unique_ptr< mfem::VectorCoefficient > vfunc; + +};

XWI%xhSU3{kl}1wamaAC zy&N)}Z7U6#(fhPbwyhlFb^o+U?|;PKgR^awA;anY&yeA4TXo2AdcP7foNcQO8BXt4 zLx!_$^&!LQ{aVOywyiN_INM$i8P2vfhs@}G+9uo9iYbS?w%%{X8^PJO_K@N9ek)`+ z+twK}oZfGT3}@TALx$7)osi*dTW`p4dcPYooNeD4GMsJig$!rg`a@>)KD}js|2D{N z7+dxHe(!u3AH@g3eLFT9GTg`UNyu;;$0kFD`&WD#GTf%I*^uG>9sda#Zu8h;$Z-FS zG5T1B+cLHa8SXQkV}=a3b!-zdqxWf>Y}+;t?%5{2$L`~?g0pSAkm2+mr)L??w(UcP z(|g>WWjNb*2pLZA&-N_C>AhpfaC(myGMwH!g$!rg_#yNEHg)bCGNbotoAll#zTdM= zdQT9a3r_D{Lx$6P!jR$g-YsM}y(bD8PVe1AhSPiEkm2;+BV;(eCkYu&?>$3?vu)Cl z;cVM0WJd4PHtD^0oYAvQdQTpc1*i8uA;anY`HopPZ=_t-UoyXXWJJ;hO_O!kQu#C+obnFacR#s={;3^DLB0k4jE4GsY8a-`;d^~ z^qwYUIK96UGMwID4jE4GLqmqsd)koU^!{$haJEesGMsIPh0N%E+9tif7r*M+CcS5f z>4Vez@Q~s3{z}MjdLI!ooZepz8BXsbLx$6P#*pFkJ}P85y}uSRoZd%=3}@TdLx!{M zn2;I0PuryTv2kb5Ht9W6d?Pr$zaKK3-ZO^`r}uFo!|DCakm2+`K4dt(X9*cj?-N3X z(|gvC;q?AN$Z)pJ7BZY|Cx*=EecC3yPl`YEY?Iz|#O%T8eR9Zfde0d$oZdeS8BXuH zLWa}(M_^{nIABSBaH_)BCEB z;q+cLWH`Nl7BZaPtAz}w_thc8>AiZ$aC-kdWH`Oo2pLZAUxW;2+nOQ6+4jqj8NE;2 zr1v#3#c7^GdjC3PIK9^k8BXu(LWa}(TOq^g zeSOGqwyhsBoNYIR%;^!{xe*t1P~ zZx`DJr}up!!|A+gSaJD@k zGNbotoAiDme%Z54dLJI&3r_DBLx$7)h>+p*eko))y^jnTPVbjPhSU3~km23w|2 zaC*NUGMwHggbb(m8zIB#{ezI<^nNpBINMGP8P2x1LT2HR^-aJHQmGMsH6hRo=F z+9tg}iof-2lip{<>A~s!ama9bpBXZo-k*dFr}tSQ!|DC6km2+`J7hS$KMfg9?{h+i z)BE2c!`XIj$Z)p(CuBzN(>Ce--}qXE?oo95S5VpUKN`dS4JS zoZe&RWH`Mq3>i-Ev2rq;-WP=or}x-78P2wgLx!_$oSe+)ecC45#?5`$vrT$m8kYp8 z_h&HWEo;q<;DWH`Mi2pP_{D?^5}ZNiWl zy-(Yu_e3#H_fMPjzAAnioZb@;8BXt?g$$?nBtwSN`|6P4^qzFcaC-kdWH`Mi8#0{U zzX%yl@5zS@XWK7BhO_PSLuT|oZIf+ZkQwgUdjBe}3C^}Dh770owIRdVHsz4v^!|0o zaJGGM$Z&dJ7c!h}Um7x;-q(i=XWLXmhO_O4kl}2bddQ64r#J2I-!!=|#}+-`*gH4J zEpbzD)5df|hPyRx3mIkBpSH=iZ^l7A+obn>@!Q~Rn`OvwdjBqDINN3&GMwJ`hYV-iY(s|A z`}ZNk**5!-;q-nWWH{UA7&4q~4~7h9+nhsY^geBqZF9x3J=>)BAL60lY@2(?aC$!+ zGMsJm3>i-EM?!|PZQdcn>HTQPaJJ1iWH`P57&4q~^A8!$w#Pz-vu%MPGkTx4$+iXK z^qy_f`|3~Ta>#IcKOHihZA%RqPVZ+zhO=$yA;anY zY{+o7Ei+^|y`Kvi&bDQT3}@T(A;a0W+>jZ)PupbM@^MYiHtGFhybzpiD-0P<@0UV` zvu(v8!|DBU$Z)o;G-Nov{~j`&Z7UBMPVaw&3}@RaLx!{MpCQB9w(5`>y-(X@+iGz~ z&o=4(YP=GhZL1F%PVd)3hO=#rA;anYddP6LtvO^kz268K&bGCN45#;-A;a0W_K@Lh zdn;r(+twK}qxWf>Y+E-T>e(i}--)+_vu(X0!|DBQ$Z)oOYsheVzZWu`ZR-yiPVe_a zhO=#hA;anYLCA2nZ8&5&+dd2#&bDt4nbG^SO}1?mPxfq+-XF(D!P&O)km2XS6-aCd2r}uav!|A*_C{CMpCJ9Hcs2gJ^?S*#t)#ey+QOdFHNSnWC2>X^7vG6JV(VBxR*uDD&iHCf z5#zEI+Pve@nG46=p#zXO^crspySK{sXC@zhw;#YA~+!^=9AL8+N zDqf6N!#5pTv@@pilu@5X!ae)x5;bSx9g#&WTItPm^4O0jaR6062);n%^L zeV(2bXU92lZk!kA$B*NJxG*k?i^H#jH~U&v+na>U&fi9#6$W{h27Ar)!n}Y4~UAmT^mbvFu*)V9Z?hh}8J)-(zP9d;0ttyZ0uG>0;Jc zD3*_PV)NJ~4veG2uY)yuXXDr*_Km~iq&PROi0k6+csQO4zYZ?#bMBhBJsya^#LMw+ zjFF!xrjD6nzVPed(>{O3&rcaM#$2&@tP&f+?jEQ5Km^tQ;Wn#_PBzBDb z;)pmo{5tS?I(N(xGsc%=ikLV)8)Jm;5952__&z_rmyyrYd1BW1T1*>L#w0Obd?tL) z7~dDi_x|zyjeMTY8?(jNW4icaOd8|InBn`#_+B}_ACT{P_@Bmj^j8mY@&c5D2l8i2q*$>ASfy-ilXep zCMbxqDk!b&2vrmWHxv}At)`0$iq&ewkGfvh_xAxFWGfHxFx%M9BkW)&k5bq7+86h+nl-Ft9qZY^MmBLjo7uu* zmavp%EaxunW(6y`hkIE?-9OYmyoI^U<5q5CJ`1>=h1|iNETZ=BL?$trDNJP=(`jS| zGnqx*pVYn|%hg=NwT$CBu4g7zQG$D;B{VOKdA?@2a3}S;j`h2(=^S$Mm#LO+=X`!)b`3rGq1i>$ zYpvJszZyAg{spR~k1&*aFSoVy;$5?gsrNssf1{qk5%VunE#1K|>iyl;(VO?oE}`C& zwEo}dOpcnbd+TcHPKNVqv+L=@kIXLRWZpJEi(}^N-nv@)C>QV>vm5Bk`(~HXiKf?A za84~^-CI{nALBxPYjz`N@nf^g>CCsx&Y?MVZ~bZRL+U>JCg;CQOCNI{-=V9&YXv`{ zzt3Sazo)JTb$>q2{EHl6hWWSXV0JO@(#z~xeo0+F>c0L8v-|i5lg#g@joJBpmu_b7 zXI2 zXZ8Fs*z8vR#Avg7_&XEKzeI!CxqO?t{?&6!KeLoWF9d`4_17<7zbjCUw26 z=bavASMvcw%x>e)j4`{HdXKV+=3k|*ul1aCs@awNlmTY9@CQbi-9^1`+x6zZLS2vR z`KqJYCA>#(v+MX3!_4lW-plSPv(Hi2?|Lq4Yjy$Oqh3>W6+dT?*$4R}qs;E6uJ^U) zYVXw^ti4!!vi4@}(b}uEXKU})9kLP;$mNYdv$K$^abhU5>|p9b7h>?xS-&{_Buy;_<&GW{v-|HLmC9$Qpds_Q3Ic=E=v-GxmRD4@j>+ zAJ(tIbIdwqALQpC9Y_b#fpj1pNC(n^bRZo_2hxFbARR~t(t&g!9Y_b#fpj1pNC(n^ zbRZo_2hxFbARR~t(t&g!9Y_b#fpj1pNC(n^bRZo_2hxFbARR~t(t&g!9Y_b#fpj1p zNC(n^bRZo_2hxFbARR~t(t&g!9Y_b#fpj1pNC(n^bRZo_2hxFbARR~t(t&g!9Y_b# zfpj1pNC(n^bRZo_2hxFbARR~t(t&g!9Y_b#fpj1pNC(n^bRZo_2hxFbARR~t(t&g! z9Y_b#fpj1pNC(n^bRZo_2hxFbARR~t(t&i~-|E1wmd%=NWev-i$7HTy1cT{GCtC8) zhGxy4a(sxjEaz6Ha4jP_mtJ(H6(2e0X~&0I$6egURK{^B=h2%}Xw5~`G7dhTXE z)3}aN451HQXv4?O+2gpK4Xj`R)486}oKIi6(w0NcdB*V(HnNi2X=FT?F_g17l@mDZ zoM#<(u!(zE$P8}aa)!~5(`d&L=j?Ud$^G2R9n9oL#xR_->Bfm1b9O?qn7d zxPlAl&*_}RG3R{I@iDgWITkUSo4Aq-8NeB|ry0-jIA7rNEM^Wja}^hH4&CWMbDrl3 z9^gKfa0?R|%f$@jOghqnFYzP~vYMsLWfE6&34`dt$u!W~rx;m-|K&Z +struct FiniteElement < Geometry::Edge, Family::H1 >{ + + using source_type = vec1; + using flux_type = vec1; + + using value_type = vec1; + using grad_type = vec1; + + __host__ __device__ constexpr uint32_t num_nodes() const { return p + 1; } + + constexpr double shape_function(vec<1> xi, uint32_t i) const { + if (p == 1 && i == 0) { return 1.0 - xi[0]; } + if (p == 1 && i == 1) { return xi[0]; } + + if (p == 2 && i == 0) { return (-1.0 + xi[0]) * (-1.0 + 2.0 * xi[0]); } + if (p == 2 && i == 1) { return -4.0 * (-1.0 + xi[0]) * xi[0]; } + if (p == 2 && i == 2) { return xi[0] * (-1.0 + 2.0 * xi[0]); } + + constexpr double sqrt5 = 2.23606797749978981; + if (p == 3 && i == 0) { return -(-1.0 + xi[0]) * (1.0 + 5.0 * (-1.0 + xi[0]) * xi[0]); } + if (p == 3 && i == 1) { return -0.5 * sqrt5 * (5.0 + sqrt5 - 10.0 * xi[0]) * (-1.0 + xi[0]) * xi[0]; } + if (p == 3 && i == 2) { return -0.5 * sqrt5 * (-1.0 + xi[0]) * xi[0] * (-5.0 + sqrt5 + 10.0 * xi[0]); } + if (p == 3 && i == 3) { return xi[0] * (1.0 + 5.0 * (-1.0 + xi[0]) * xi[0]); } + + return 7777.77; + } + + constexpr vec<1> shape_function_gradient(vec<1> xi, uint32_t i) const { + if (p == 1 && i == 0) { return -1.0; } + if (p == 1 && i == 1) { return +1.0; } + + if (p == 2 && i == 0) return -3.0 + 4.0 * xi[0]; + if (p == 2 && i == 1) return 4.0 - 8.0 * xi[0]; + if (p == 2 && i == 2) return -1.0 + 4.0 * xi[0]; + + constexpr double sqrt5 = 2.23606797749978981; + if (p == 3 && i == 0) return -6.0 + 5.0 * (4.0 - 3.0 * xi[0]) * xi[0]; + if (p == 3 && i == 1) return 2.5 * (1.0 + sqrt5 + 2.0 * xi[0] * (-1.0 - 3.0 * sqrt5 + 3.0 * sqrt5 * xi[0])); + if (p == 3 && i == 2) return -2.5 * (-1.0 + sqrt5 + 2.0 * xi[0] * (1.0 - 3.0 * sqrt5 + 3.0 * sqrt5 * xi[0])); + if (p == 3 && i == 3) return 1.0 + 5.0 * xi[0] * (-2.0 + 3.0 * xi[0]); + + return 7777.77; + } + + vec<1> shape_function_derivative(vec<1> xi, uint32_t i) const { + return shape_function_gradient(xi, i); + } + + __host__ __device__ uint32_t batch_interpolation_scratch_space(nd::view xi) const { + return 0; + } + + nd::array< double, 2 > evaluate_shape_functions(nd::view xi) const { + uint32_t q = xi.shape[0]; + nd::array shape_fns({q, p+1}); + for (int i = 0; i < q; i++) { + GaussLobattoInterpolation(xi(i, 0), p + 1, &shape_fns(i, 0)); + } + return shape_fns; + } + + nd::array< double, 2 > evaluate_shape_function_gradients(nd::view xi) const { + uint32_t q = xi.shape[0]; + nd::array shape_fn_grads({q, num_nodes()}); + for (int i = 0; i < q; i++) { + GaussLobattoInterpolationDerivative(xi(i, 0), p + 1, &shape_fn_grads(i, 0)); + } + return shape_fn_grads; + } + + __host__ __device__ void interpolate(nd::view values_q, nd::view values_e, nd::view shape_fns, double * /*buffer*/) const { + int nnodes = num_nodes(); + int nqpts = values_q.shape[0]; + + for (int q = 0; q < nqpts; q++) { + double sum = 0.0; + for (int i = 0; i < nnodes; i++) { + sum += shape_fns(q, i) * values_e(i); + } + values_q(q) = sum; + } + } + + __host__ __device__ void gradient(nd::view gradients_q, nd::view values_e, nd::view shape_fn_grads, double * /*buffer*/) const { + int nnodes = num_nodes(); + int nqpts = gradients_q.shape[0]; + for (int j = 0; j < nqpts; j++) { + double sum = 0.0; + for (int i = 0; i < nnodes; i++) { + sum += values_e(i) * shape_fn_grads(j, i); + } + gradients_q(j) = sum; + } + } + + nd::array< double, 2 > evaluate_weighted_shape_functions(nd::view xi, + nd::view weights) const { + uint32_t nnodes = num_nodes(); + uint32_t q = xi.shape[0]; + nd::array shape_fns({q, nnodes}); + for (uint32_t i = 0; i < q; i++) { + GaussLobattoInterpolation(xi(i, 0), p+1, &shape_fns(i, 0)); + for (uint32_t j = 0; j < nnodes; j++) { + shape_fns(i, j) = shape_fns(i, j) * weights(i); + } + } + return shape_fns; + } + + __host__ __device__ void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fn, double * /*buffer*/) const { + int nnodes = num_nodes(); + int nqpts = source_q.shape[0]; + + for (int i = 0; i < nnodes; i++) { + double sum = 0.0; + for (int q = 0; q < nqpts; q++) { + sum += shape_fn(q, i) * source_q(q); + } + residual_e(i) = sum; + } + } + + nd::array< double, 2 > evaluate_weighted_shape_function_gradients(nd::view xi, + nd::view weights) const { + uint32_t nnodes = num_nodes(); + uint32_t q = xi.shape[0]; + nd::array shape_fn_grads({q, num_nodes()}); + for (uint32_t i = 0; i < q; i++) { + GaussLobattoInterpolationDerivative(xi(i, 0), p + 1, &shape_fn_grads(i, 0)); + for (uint32_t j = 0; j < nnodes; j++) { + shape_fn_grads(i, j) = shape_fn_grads(i, j) * weights(i); + } + } + return shape_fn_grads; + } + + __host__ __device__ void integrate_flux(nd::view output_e, nd::view flux_q, nd::view shape_fn_grads, double * /*buffer*/) const { + int nnodes = num_nodes(); + int nqpts = flux_q.shape[0]; + for (int i = 0; i < nnodes; i++) { + double sum = 0.0; + for (int q = 0; q < nqpts; q++) { + sum += shape_fn_grads(q, i) * flux_q(q); + } + output_e(i) = sum; + } + } + + #ifdef __CUDACC__ + __device__ void cuda_gradient(nd::view gradients_q, nd::view values_e, nd::view shape_fn_grads, double * /*buffer*/) const { + int nnodes = num_nodes(); + int nqpts = gradients_q.shape[0]; + for (int j = threadIdx.x; j < nqpts; j += blockDim.x) { + double sum = 0.0; + for (int i = 0; i < nnodes; i++) { + sum += values_e(i) * shape_fn_grads(j, i); + } + gradients_q(j) = sum; + } + } + + __device__ void cuda_integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fn_grads, double * /*buffer*/) const { + int nnodes = num_nodes(); + int nqpts = flux_q.shape[0]; + + for (int i = threadIdx.x; i < nnodes; i += blockDim.x) { + double sum = 0.0; + for (int q = 0; q < nqpts; q++) { + sum += shape_fn_grads(q, i) * flux_q(q); + } + residual_e(i) = sum; + } + } + #endif + + uint32_t p; + +}; + +} // namespace refactor diff --git a/src/serac/numerics/refactor/elements/h1_hexahedron.hpp b/src/serac/numerics/refactor/elements/h1_hexahedron.hpp new file mode 100644 index 0000000000..8d11b522f5 --- /dev/null +++ b/src/serac/numerics/refactor/elements/h1_hexahedron.hpp @@ -0,0 +1,494 @@ +#pragma once + +#include "refactor/connection.hpp" + +namespace refactor { + +template <> +struct FiniteElement { + + using value_type = vec1; + using derivative_type = vec3; + + using source_type = vec1; + using flux_type = vec3; + + __host__ __device__ constexpr uint32_t num_nodes() const { return (p + 1) * (p + 1) * (p + 1); } + + void nodes(nd::view< double, 2 > xi) const { + double lobatto_nodes[4]; + GaussLobattoNodes(p + 1, lobatto_nodes); + + uint32_t count = 0; + for (uint32_t k = 0; k < (p+1); k++) { + for (uint32_t j = 0; j < (p+1); j++) { + for (uint32_t i = 0; i < (p+1); i++) { + xi(count, 0) = lobatto_nodes[i]; + xi(count, 1) = lobatto_nodes[j]; + xi(count, 2) = lobatto_nodes[k]; + count++; + } + } + } + } + + __host__ __device__ uint32_t num_interior_nodes() const { return (p == 1) ? 0 : (p - 1) * (p - 1) * (p - 1); } + + void interior_nodes(nd::view< double, 2 > xi) const { + if (p > 1) { + double lobatto_nodes[4]; + GaussLobattoNodes(p + 1, lobatto_nodes); + + uint32_t count = 0; + for (uint32_t k = 1; k < p; k++) { + for (uint32_t j = 1; j < p; j++) { + for (uint32_t i = 1; i < p; i++) { + xi(count, 0) = lobatto_nodes[i]; + xi(count, 1) = lobatto_nodes[j]; + xi(count, 2) = lobatto_nodes[k]; + count++; + } + } + } + + } + } + + __host__ __device__ inline void reorient(Connection c, uint32_t & i0, uint32_t & i1, uint32_t & i2, uint32_t & i3) const { + + uint8_t o = c.orientation(); + + uint32_t copy[4] = {i0, i1, i2, i3}; + + if (c.sign() == Sign::Negative) { + if (o == 0) { i0 = copy[0]; i1 = copy[2]; i2 = copy[1]; i3 = copy[3]; } // ok + if (o == 1) { i0 = copy[1]; i1 = copy[0]; i2 = copy[3]; i3 = copy[2]; } // ok + if (o == 2) { i0 = copy[3]; i1 = copy[1]; i2 = copy[2]; i3 = copy[0]; } // ok + if (o == 3) { i0 = copy[2]; i1 = copy[3]; i2 = copy[0]; i3 = copy[1]; } // ok + } else { + if (o == 0) { /* nothing to do */ } + if (o == 1) { /* should never occur */ } + if (o == 2) { /* should never occur */ } + if (o == 3) { /* should never occur */ } + } + } + + __host__ __device__ void indices(const GeometryInfo & offsets, + const Connection * connections, + uint32_t * ids) const { + + const Connection * vertex = connections; + const Connection * edge = connections + Hexahedron::edge_offset; + const Connection * quad = connections + Hexahedron::quad_offset; + const Connection * cell = connections + Hexahedron::cell_offset; + + if (p == 1) { + ids[0] = offsets.vert + vertex[0].index; + ids[1] = offsets.vert + vertex[1].index; + ids[2] = offsets.vert + vertex[3].index; + ids[3] = offsets.vert + vertex[2].index; + ids[4] = offsets.vert + vertex[4].index; + ids[5] = offsets.vert + vertex[5].index; + ids[6] = offsets.vert + vertex[7].index; + ids[7] = offsets.vert + vertex[6].index; + return; + } + + if (p == 2) { + #define VERTEX_ID(i) offsets.vert + vertex[i].index + #define EDGE_ID(i) offsets.edge + edge[i].index + #define QUAD_ID(i) offsets.quad + quad[i].index + #define HEX_ID offsets.hex + cell->index + + ids[ 6] = VERTEX_ID(3); ids[ 7] = EDGE_ID(2); ids[ 8] = VERTEX_ID(2); + ids[ 3] = EDGE_ID(3); ids[ 4] = QUAD_ID(0); ids[ 5] = EDGE_ID(1); + ids[ 0] = VERTEX_ID(0); ids[ 1] = EDGE_ID(0); ids[ 2] = VERTEX_ID(1); + + ids[15] = EDGE_ID(7); ids[16] = QUAD_ID(3); ids[17] = EDGE_ID(6); + ids[12] = QUAD_ID(4); ids[13] = HEX_ID; ids[14] = QUAD_ID(2); + ids[ 9] = EDGE_ID(4); ids[10] = QUAD_ID(1); ids[11] = EDGE_ID(5); + + ids[24] = VERTEX_ID(7); ids[25] = EDGE_ID(10); ids[26] = VERTEX_ID(6); + ids[21] = EDGE_ID(11); ids[22] = QUAD_ID(5); ids[23] = EDGE_ID(9); + ids[18] = VERTEX_ID(4); ids[19] = EDGE_ID(8); ids[20] = VERTEX_ID(5); + + #undef VERTEX_ID + #undef EDGE_ID + #undef QUAD_ID + #undef HEX_ID + return; + } + + if (p == 3) { + #define VERTEX_ID(i) offsets.vert + vertex[i].index + #define EDGE_ID(i, j) offsets.edge + 2 * edge[i].index + j + #define QUAD_ID(i, j) offsets.quad + 4 * quad[i].index + j + #define HEX_ID(j) offsets.hex + 8 * cell->index + j + + ids[12] = VERTEX_ID(3); ids[13] = EDGE_ID(2,0); ids[14] = EDGE_ID(2,1); ids[15] = VERTEX_ID(2); + ids[ 8] = EDGE_ID(3,1); ids[ 9] = QUAD_ID(0,3); ids[10] = QUAD_ID(0,2); ids[11] = EDGE_ID(1,1); + ids[ 4] = EDGE_ID(3,0); ids[ 5] = QUAD_ID(0,1); ids[ 6] = QUAD_ID(0,0); ids[ 7] = EDGE_ID(1,0); + ids[ 0] = VERTEX_ID(0); ids[ 1] = EDGE_ID(0,0); ids[ 2] = EDGE_ID(0,1); ids[ 3] = VERTEX_ID(1); + + ids[28] = EDGE_ID(7,0); ids[29] = QUAD_ID(3,1); ids[30] = QUAD_ID(3,0); ids[31] = EDGE_ID(6,0); + ids[24] = QUAD_ID(4,0); ids[25] = HEX_ID(2); ids[26] = HEX_ID(3); ids[27] = QUAD_ID(2,1); + ids[20] = QUAD_ID(4,1); ids[21] = HEX_ID(0); ids[22] = HEX_ID(1); ids[23] = QUAD_ID(2,0); + ids[16] = EDGE_ID(4,0); ids[17] = QUAD_ID(1,0); ids[18] = QUAD_ID(1,1); ids[19] = EDGE_ID(5,0); + + ids[44] = EDGE_ID(7,1); ids[45] = QUAD_ID(3,3); ids[46] = QUAD_ID(3,2); ids[47] = EDGE_ID(6,1); + ids[40] = QUAD_ID(4,2); ids[41] = HEX_ID(6); ids[42] = HEX_ID(7); ids[43] = QUAD_ID(2,3); + ids[36] = QUAD_ID(4,3); ids[37] = HEX_ID(4); ids[38] = HEX_ID(5); ids[39] = QUAD_ID(2,2); + ids[32] = EDGE_ID(4,1); ids[33] = QUAD_ID(1,2); ids[34] = QUAD_ID(1,3); ids[35] = EDGE_ID(5,1); + + ids[60] = VERTEX_ID(7); ids[61] = EDGE_ID(10,0); ids[62] = EDGE_ID(10,1); ids[63] = VERTEX_ID(6); + ids[56] = EDGE_ID(11,1); ids[57] = QUAD_ID(5,2); ids[58] = QUAD_ID(5,3); ids[59] = EDGE_ID(9,1); + ids[52] = EDGE_ID(11,0); ids[53] = QUAD_ID(5,0); ids[54] = QUAD_ID(5,1); ids[55] = EDGE_ID(9,0); + ids[48] = VERTEX_ID(4); ids[49] = EDGE_ID(8,0); ids[50] = EDGE_ID(8,1); ids[51] = VERTEX_ID(5); + + if (edge[ 0].sign() == Sign::Negative) { fm::swap(ids[ 1], ids[ 2]); } + if (edge[ 1].sign() == Sign::Negative) { fm::swap(ids[ 7], ids[11]); } + if (edge[ 2].sign() == Sign::Negative) { fm::swap(ids[14], ids[13]); } + if (edge[ 3].sign() == Sign::Negative) { fm::swap(ids[ 8], ids[ 4]); } + if (edge[ 4].sign() == Sign::Negative) { fm::swap(ids[16], ids[32]); } + if (edge[ 5].sign() == Sign::Negative) { fm::swap(ids[19], ids[35]); } + if (edge[ 6].sign() == Sign::Negative) { fm::swap(ids[31], ids[47]); } + if (edge[ 7].sign() == Sign::Negative) { fm::swap(ids[28], ids[44]); } + if (edge[ 8].sign() == Sign::Negative) { fm::swap(ids[49], ids[50]); } + if (edge[ 9].sign() == Sign::Negative) { fm::swap(ids[55], ids[59]); } + if (edge[10].sign() == Sign::Negative) { fm::swap(ids[62], ids[61]); } + if (edge[11].sign() == Sign::Negative) { fm::swap(ids[56], ids[52]); } + + reorient(quad[0], ids[ 9], ids[10], ids[ 5], ids[ 6]); + reorient(quad[1], ids[17], ids[18], ids[33], ids[34]); + reorient(quad[2], ids[23], ids[27], ids[39], ids[43]); + reorient(quad[3], ids[30], ids[29], ids[46], ids[45]); + reorient(quad[4], ids[24], ids[20], ids[40], ids[36]); + reorient(quad[5], ids[53], ids[54], ids[57], ids[58]); + + #undef VERTEX_ID + #undef EDGE_ID + #undef QUAD_ID + #undef HEX_ID + + return; + + } + + } + + constexpr double phi_1D(double xi, uint32_t i) const { + return GaussLobattoInterpolation(xi, p + 1, i); + } + + constexpr double dphi_1D(double xi, uint32_t i) const { + return GaussLobattoInterpolationDerivative(xi, p + 1, i); + } + + constexpr double shape_function(vec3 xi, uint32_t i) const { + uint32_t ix = i % (p + 1); + uint32_t iy = (i % ((p + 1) * (p + 1))) / (p + 1) ; + uint32_t iz = i / ((p + 1) * (p + 1)); + return phi_1D(xi[0], ix) * phi_1D(xi[1], iy) * phi_1D(xi[2], iz); + } + + constexpr vec3 shape_function_gradient(vec3 xi, uint32_t i) const { + uint32_t ix = i % (p + 1); + uint32_t iy = (i % ((p + 1) * (p + 1))) / (p + 1) ; + uint32_t iz = i / ((p + 1) * (p + 1)); + return { + dphi_1D(xi[0], ix) * phi_1D(xi[1], iy) * phi_1D(xi[2], iz), + phi_1D(xi[0], ix) * dphi_1D(xi[1], iy) * phi_1D(xi[2], iz), + phi_1D(xi[0], ix) * phi_1D(xi[1], iy) * dphi_1D(xi[2], iz) + }; + } + + vec3 shape_function_derivative(vec3 xi, uint32_t i) const { + return shape_function_gradient(xi, i); + } + + double interpolate(vec3 xi, double * values) const { + uint32_t count = 0; + double output = 0.0; + for (int iz = 0; iz < (p+1); iz++) { + double phi_z = phi_1D(xi[2], iz); + for (int iy = 0; iy < (p+1); iy++) { + double phi_y = phi_1D(xi[1], iy); + for (int ix = 0; ix < (p+1); ix++) { + double phi_x = phi_1D(xi[0], ix); + output += phi_x * phi_y * phi_z * values[count]; + count++; + } + } + } + return output; + } + + vec3 gradient(vec3 xi, double * values) const { + vec3 output{}; + uint32_t count = 0; + for (int iz = 0; iz < (p+1); iz++) { + double phi_z = phi_1D(xi[2], iz); + double dphi_z = dphi_1D(xi[2], iz); + for (int iy = 0; iy < (p+1); iy++) { + double phi_y = phi_1D(xi[1], iy); + double dphi_y = dphi_1D(xi[1], iy); + for (int ix = 0; ix < (p+1); ix++) { + double phi_x = phi_1D(xi[0], ix); + double dphi_x = dphi_1D(xi[0], ix); + output[0] += dphi_x * phi_y * phi_z * values[count]; + output[1] += phi_x * dphi_y * phi_z * values[count]; + output[2] += phi_x * phi_y * dphi_z * values[count]; + count++; + } + } + } + return output; + } + + __host__ __device__ uint32_t batch_interpolation_scratch_space(nd::view xi) const { + uint32_t n = p + 1; + uint32_t q = xi.shape[0]; + return q * n * (n + q); + } + + // note: the return value here includes the shape function evaluations as well as + // a buffer space to hold intermediate values in the `interpolation` function + nd::array< double, 3 > evaluate_shape_functions(nd::view xi) const { + uint32_t q = xi.shape[0]; + nd::array buffer({1, q, p+1}); + for (int i = 0; i < q; i++) { + GaussLobattoInterpolation(xi(i, 0), p+1, &buffer(0, i, 0)); + } + return buffer; + } + + __host__ __device__ void interpolate(nd::view values_q, nd::view values_e, nd::view shape_fns, double * buffer) const { + uint32_t n = p + 1; + uint32_t q = shape_fns.shape[1]; + + nd::view phi(&shape_fns(0,0,0), {q, n}); + nd::view A1(buffer, {q, n, n}); + nd::view A2(buffer + q * n * n, {q, q, n}); + + nd::view values_e_3D = nd::reshape<3>(values_e, {n, n, n}); + nd::view values_q_3D((double*)&values_q[0], {q, q, q}); + contract(values_e_3D, phi, A1); + contract( A1, phi, A2); + contract( A2, phi, values_q_3D); + } + + // note: the return value here includes the shape function evaluations as well as + // a buffer space to hold intermediate values in the `interpolation` function + nd::array< double, 3 > evaluate_shape_function_gradients(nd::view xi) const { + uint32_t q = xi.shape[0]; + nd::array shape_fn_grads({2, q, p+1}); + for (int i = 0; i < q; i++) { + GaussLobattoInterpolation(xi(i, 0), p+1, &shape_fn_grads(0, i, 0)); + GaussLobattoInterpolationDerivative(xi(i, 0), p+1, &shape_fn_grads(1, i, 0)); + } + return shape_fn_grads; + } + + __host__ __device__ void gradient(nd::view gradients_q, nd::view values_e, nd::view shape_fns, double * buffer) const { + uint32_t n = p + 1; + uint32_t q = shape_fns.shape[1]; + + nd::view B(&shape_fns(0,0,0), {q, n}); + nd::view G(&shape_fns(1,0,0), {q, n}); + nd::view A1(buffer, {q, n, n}); + nd::view A2(buffer + q * n * n, {q, q, n}); + + nd::range All{0u, gradients_q.shape[0]}; + + nd::view values_e_3D = nd::reshape<3>(values_e, {n, n, n}); + nd::view gradients_q_3D((double*)&gradients_q[0], {q, q, q}, {3*q*q, 3*q, 3}); + + // du_dxi + contract(values_e_3D, G, A1); + contract( A1, B, A2); + contract( A2, B, gradients_q_3D); + gradients_q_3D.values++; + + // du_deta + contract(values_e_3D, B, A1); + contract( A1, G, A2); + contract( A2, B, gradients_q_3D); + gradients_q_3D.values++; + + // du_dzeta + contract(A1, B, A2); + contract(A2, G, gradients_q_3D); + gradients_q_3D.values++; + + } + + // note: the return value here includes the shape function evaluations as well as + // a buffer space to hold intermediate values in the `interpolation` function + nd::array< double, 2 > evaluate_weighted_shape_functions(nd::view xi, + nd::view weights) const { + uint32_t q = xi.shape[0]; + nd::array buffer({p+1, q}); + nd::array tmp({p+1}); + for (int i = 0; i < q; i++) { + GaussLobattoInterpolation(xi(i, 0), p+1, &tmp(0)); + for (int j = 0; j < p+1; j++) { + buffer(j, i) = tmp(j) * weights(i); + } + } + return buffer; + } + + __host__ __device__ void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fn, double * buffer) const { + uint32_t n = p + 1; + uint32_t q = shape_fn.shape[1]; + + nd::view BT = shape_fn; + nd::view A1(buffer, {n, q, q}); + nd::view A2(buffer + n*q*q, {n, n, q}); + + nd::view s3D((double*)&source_q[0], {q, q, q}); + nd::view r3D = nd::reshape<3>(residual_e, {n, n, n}); + + // r(iz, iy, ix) = s(qz, qy, qx) * BT(ix, qx) * BT(iy, qy) * BT(iz, qz) + // + // A1(ix, qz, qy) = BT(ix, qx) * s(qz, qy, qx) + // A2(iy, ix, qz) = BT(iy, qy) * A1(ix, qz, qy) + // r(iz, iy, ix) = BT(iz, qz) * A2(iy, ix, qz) + contract(s3D, BT, A1); + contract( A1, BT, A2); + contract( A2, BT, r3D); + } + + // note: the return value here includes the shape function evaluations as well as + // a buffer space to hold intermediate values in the `interpolation` function + nd::array< double, 3 > evaluate_weighted_shape_function_gradients(nd::view xi, + nd::view weights) const { + uint32_t q = xi.shape[0]; + nd::array buffer({2, p+1, q}); + nd::array tmp({p+1}); + for (int i = 0; i < q; i++) { + GaussLobattoInterpolation(xi(i, 0), p+1, &tmp(0)); + for (int j = 0; j < p+1; j++) { + buffer(0, j, i) = tmp(j) * weights(i); + } + + GaussLobattoInterpolationDerivative(xi(i, 0), p+1, &tmp(0)); + for (int j = 0; j < p+1; j++) { + buffer(1, j, i) = tmp(j) * weights(i); + } + } + return buffer; + } + + void integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fns, double * buffer) const { + uint32_t n = p + 1; + uint32_t q = shape_fns.shape[2]; + + nd::view BT = shape_fns(0); + nd::view GT = shape_fns(1); + nd::view A1(buffer, {n, q, q}); + nd::view A2(buffer+n*q*q, {n, n, q}); + + nd::range All{0u, flux_q.shape[0]}; + + uint32_t s = flux_q.stride[0] * 3; + nd::view f3D(nullptr, {q, q, q}, {s*q*q, s*q, s}); + nd::view r3D = nd::reshape<3>(residual_e, {n, n, n}); + + f3D.values = &flux_q(0)[0]; + contract(f3D, GT, A1); + contract( A1, BT, A2); + contract( A2, BT, r3D, /* accumulate = */ false); + + f3D.values = &flux_q(0)[1]; + contract(f3D, BT, A1); + contract( A1, GT, A2); + contract( A2, BT, r3D, /* accumulate = */ true); + + f3D.values = &flux_q(0)[2]; + contract(f3D, BT, A1); + contract( A1, BT, A2); + contract( A2, GT, r3D, /* accumulate = */ true); + } + + #ifdef __CUDACC__ + __device__ void cuda_gradient(nd::view gradients_q, nd::view values_e, nd::view shape_fns, double * buffer) const { + uint32_t n = p + 1; + uint32_t q = shape_fns.shape[1]; + + nd::view B(&shape_fns(0,0,0), {q, n}); + nd::view G(&shape_fns(1,0,0), {q, n}); + nd::view A1(buffer, {q, n, n}); + nd::view A2(buffer + q * n * n, {q, q, n}); + + nd::range All{0u, gradients_q.shape[0]}; + + nd::view values_e_3D = nd::reshape<3>(values_e, {n, n, n}); + nd::view gradients_q_3D((double*)&gradients_q[0], {q, q, q}, {3*q*q, 3*q, 3}); + + threadid tid; + tid.x = threadIdx.x % q; + tid.y = (threadIdx.x % (q * q)) / q; + tid.z = threadIdx.x / (q * q); + tid.stride = q; + + // du_dxi + cuda_contract(tid, values_e_3D, G, A1); + cuda_contract(tid, A1, B, A2); + cuda_contract(tid, A2, B, gradients_q_3D); + gradients_q_3D.values++; + + // du_deta + cuda_contract(tid, values_e_3D, B, A1); + cuda_contract(tid, A1, G, A2); + cuda_contract(tid, A2, B, gradients_q_3D); + gradients_q_3D.values++; + + // du_dzeta + cuda_contract(tid, A1, B, A2); + cuda_contract(tid, A2, G, gradients_q_3D); + gradients_q_3D.values++; + + } + + __device__ void cuda_integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fns, double * buffer) const { + uint32_t n = p + 1; + uint32_t q = shape_fns.shape[2]; + + nd::view BT = shape_fns(0); + nd::view GT = shape_fns(1); + nd::view A1(buffer, {n, q, q}); + nd::view A2(buffer+n*q*q, {n, n, q}); + + uint32_t s = flux_q.stride[0] * 3; + nd::view f3D(nullptr, {q, q, q}, {s*q*q, s*q, s}); + nd::view r3D = nd::reshape<3>(residual_e, {n, n, n}); + + threadid tid; + tid.x = threadIdx.x % n; + tid.y = (threadIdx.x % (n * n)) / n; + tid.z = threadIdx.x / (n * n); + tid.stride = n; + + f3D.values = &flux_q(0)[0]; + cuda_contract(tid, f3D, GT, A1); + cuda_contract(tid, A1, BT, A2); + cuda_contract(tid, A2, BT, r3D, /* accumulate = */ false); + + f3D.values = &flux_q(0)[1]; + cuda_contract(tid, f3D, BT, A1); + cuda_contract(tid, A1, GT, A2); + cuda_contract(tid, A2, BT, r3D, /* accumulate = */ true); + + f3D.values = &flux_q(0)[2]; + cuda_contract(tid, f3D, BT, A1); + cuda_contract(tid, A1, BT, A2); + cuda_contract(tid, A2, GT, r3D, /* accumulate = */ true); + } + #endif + + uint32_t p; + +}; + +} // namespace refactor diff --git a/src/serac/numerics/refactor/elements/h1_quadrilateral.hpp b/src/serac/numerics/refactor/elements/h1_quadrilateral.hpp new file mode 100644 index 0000000000..ba9ce5b724 --- /dev/null +++ b/src/serac/numerics/refactor/elements/h1_quadrilateral.hpp @@ -0,0 +1,391 @@ +#pragma once + +#include "refactor/connection.hpp" +#include "refactor/tensor_contractions.hpp" + +namespace refactor { + +template <> +struct FiniteElement { + + using source_type = vec1; + using flux_type = vec2; + + using value_type = vec1; + using grad_type = vec2; + + __host__ __device__ constexpr uint32_t num_nodes() const { return (p + 1) * (p + 1); } + + void nodes(nd::view< double, 2 > xi) const { + double lobatto_nodes[4]; + GaussLobattoNodes(p + 1, lobatto_nodes); + + uint32_t count = 0; + for (uint32_t i = 0; i < (p+1); i++) { + for (uint32_t j = 0; j < (p+1); j++) { + xi(count, 0) = lobatto_nodes[j]; + xi(count, 1) = lobatto_nodes[i]; + count++; + } + } + } + + __host__ __device__ uint32_t num_interior_nodes() const { return (p < 2) ? 0 : (p - 1) * (p - 1); } + + void interior_nodes(nd::view< double, 2 > xi) const { + if (p > 1) { + double lobatto_nodes[4]; + GaussLobattoNodes(p + 1, lobatto_nodes); + + uint32_t count = 0; + for (uint32_t i = 1; i < p; i++) { + for (uint32_t j = 1; j < p; j++) { + xi(count, 0) = lobatto_nodes[j]; + xi(count, 1) = lobatto_nodes[i]; + count++; + } + } + } + } + + __host__ __device__ void indices(const GeometryInfo & offsets, const Connection * quad, uint32_t * indices) const { + + const Connection * vertex = quad; + const Connection * edge = quad + 4; + const Connection cell = *(quad + 8); + + if (p == 1) { + // 2 3 + // 0 1 + indices[0] = offsets.vert + vertex[0].index; + indices[1] = offsets.vert + vertex[1].index; + indices[2] = offsets.vert + vertex[3].index; + indices[3] = offsets.vert + vertex[2].index; + return; + } + + if (p == 2) { + // 6 7 8 + // 3 4 5 + // 0 1 2 + indices[0] = offsets.vert + quad[0].index; + indices[1] = offsets.edge + quad[4].index; + indices[2] = offsets.vert + quad[1].index; + indices[3] = offsets.edge + quad[7].index; + indices[4] = offsets.quad + quad[8].index; + indices[5] = offsets.edge + quad[5].index; + indices[6] = offsets.vert + quad[3].index; + indices[7] = offsets.edge + quad[6].index; + indices[8] = offsets.vert + quad[2].index; + } + + if (p == 3) { + // 12 13 14 15 + // 8 9 10 11 + // 4 5 6 7 + // 0 1 2 3 + indices[ 0] = offsets.vert + vertex[0].index; + indices[ 1] = offsets.edge + 2 * edge[0].index + 0; + indices[ 2] = offsets.edge + 2 * edge[0].index + 1; + indices[ 3] = offsets.vert + vertex[1].index; + indices[ 4] = offsets.edge + 2 * edge[3].index + 1; + indices[ 5] = offsets.quad + 4 * cell.index + 0; + indices[ 6] = offsets.quad + 4 * cell.index + 1; + indices[ 7] = offsets.edge + 2 * edge[1].index + 0; + indices[ 8] = offsets.edge + 2 * edge[3].index + 0; + indices[ 9] = offsets.quad + 4 * cell .index + 2; + indices[10] = offsets.quad + 4 * cell .index + 3; + indices[11] = offsets.edge + 2 * edge[1].index + 1; + indices[12] = offsets.vert + vertex[3].index; + indices[13] = offsets.edge + 2 * edge[2].index + 1; + indices[14] = offsets.edge + 2 * edge[2].index + 0; + indices[15] = offsets.vert + vertex[2].index; + + if (flip(edge[0])) { fm::swap(indices[ 1], indices[ 2]); } + if (flip(edge[1])) { fm::swap(indices[ 7], indices[11]); } + if (flip(edge[2])) { fm::swap(indices[14], indices[13]); } + if (flip(edge[3])) { fm::swap(indices[ 8], indices[ 4]); } + return; + } + + } + + constexpr double phi_1D(double xi, uint32_t i) const { + return GaussLobattoInterpolation(xi, p + 1, i); + } + + constexpr double dphi_1D(double xi, uint32_t i) const { + return GaussLobattoInterpolationDerivative(xi, p + 1, i); + } + + constexpr double shape_function(vec2 xi, uint32_t i) const { + uint32_t ix = i % (p + 1); + uint32_t iy = i / (p + 1); + return phi_1D(xi[0], ix) * phi_1D(xi[1], iy); + } + + vec2 shape_function_gradient(vec2 xi, uint32_t i) const { + uint32_t ix = i % (p + 1); + uint32_t iy = i / (p + 1); + return { + dphi_1D(xi[0], ix) * phi_1D(xi[1], iy), + phi_1D(xi[0], ix) * dphi_1D(xi[1], iy) + }; + } + + vec2 shape_function_derivative(vec2 xi, uint32_t i) const { + return shape_function_gradient(xi, i); + } + + double interpolate(vec2 xi, double * values) const { + double phi[4]; + GaussLobattoInterpolation(xi[0], p+1, phi); + + double interpolated_in_xi[4]{}; + for (int i = 0; i < (p+1); i++) { + for (int j = 0; j < (p+1); j++) { + interpolated_in_xi[i] += phi[j] * values[i*(p+1)+j]; + } + } + + GaussLobattoInterpolation(xi[1], p+1, phi); + double result{}; + for (int i = 0; i < (p+1); i++) { + result += phi[i] * interpolated_in_xi[i]; + } + return result; + } + + vec2 gradient(vec2 xi, double * values) const { + vec2 output{}; + + double phi[4]; + double partially_interpolated[4]{}; + + GaussLobattoInterpolationDerivative(xi[0], p+1, phi); + for (int i = 0; i < (p+1); i++) { + for (int j = 0; j < (p+1); j++) { + partially_interpolated[i] += phi[j] * values[i*(p+1)+j]; + } + } + + GaussLobattoInterpolation(xi[1], p+1, phi); + for (int i = 0; i < (p+1); i++) { + output[0] += phi[i] * partially_interpolated[i]; + } + + //-------------------------------------------------- + + GaussLobattoInterpolation(xi[0], p+1, phi); + for (int i = 0; i < (p+1); i++) { + for (int j = 0; j < (p+1); j++) { + partially_interpolated[i] += phi[j] * values[i*(p+1)+j]; + } + } + + GaussLobattoInterpolationDerivative(xi[1], p+1, phi); + for (int i = 0; i < (p+1); i++) { + output[1] += phi[i] * partially_interpolated[i]; + } + + return output; + } + + __host__ __device__ uint32_t batch_interpolation_scratch_space(nd::view xi) const { + uint32_t q = xi.shape[0]; + return q * (p + 1); + } + + // note: the return value here includes the shape function evaluations as well as + // a buffer space to hold intermediate values in the `interpolation` function + nd::array< double, 2 > evaluate_shape_functions(nd::view xi) const { + uint32_t q = xi.shape[0]; + nd::array shape_fns({q, p+1}); + for (int i = 0; i < q; i++) { + GaussLobattoInterpolation(xi(i, 0), p + 1, &shape_fns(i, 0)); + } + return shape_fns; + } + + void interpolate(nd::view< value_type > values_q, nd::view values_e, nd::view shape_fns, double * buffer) const { + uint32_t n = p + 1; + uint32_t q = shape_fns.shape[0]; + + nd::view A(buffer, {n, q}); + + nd::view values_e_2D = nd::reshape<2>(values_e, {n, n}); + nd::view values_q_2D((double*)&values_q[0], {q, q}, {1, q}); + contract<1>(values_e_2D, shape_fns, A); + contract<0>(A, shape_fns, values_q_2D); + } + + // note: the return value here includes the shape function evaluations as well as + // a buffer space to hold intermediate values in the `interpolation` function + nd::array< double, 3 > evaluate_shape_function_gradients(nd::view xi) const { + uint32_t q = xi.shape[0]; + nd::array shape_fn_grads({2, q, p+1}); + for (int i = 0; i < q; i++) { + GaussLobattoInterpolation(xi(i,0), p+1, &shape_fn_grads(0, i, 0)); + GaussLobattoInterpolationDerivative(xi(i,0), p+1, &shape_fn_grads(1, i, 0)); + } + return shape_fn_grads; + } + + void gradient(nd::view gradients_q, nd::view values_e, nd::view shape_fns, double * buffer) const { + uint32_t n = p + 1; + uint32_t q = shape_fns.shape[1]; + + nd::view B = shape_fns(0); + nd::view G = shape_fns(1); + nd::view A(buffer, {n, q}); + + nd::range All{0u, gradients_q.shape[0]}; + nd::view values_e_2D = nd::reshape<2>(values_e, {n, n}); + nd::view gradients_q_2D((double*)&gradients_q[0], {q, q}, {2, 2*q}); + + // du_dxi + contract<1>(values_e_2D, G, A); + contract<0>( A, B, gradients_q_2D); + gradients_q_2D.values++; + + // du_deta + contract<1>(values_e_2D, B, A); + contract<0>( A, G, gradients_q_2D); + gradients_q_2D.values++; + } + + // note: the return value here includes the shape function evaluations as well as + // a buffer space to hold intermediate values in the `interpolation` function + nd::array< double, 2 > evaluate_weighted_shape_functions(nd::view xi, + nd::view weights) const { + uint32_t q = xi.shape[0]; + nd::array buffer({p+1, q}); + nd::array tmp({p+1}); + for (int i = 0; i < q; i++) { + GaussLobattoInterpolation(xi(i, 0), p+1, &tmp(0)); + for (int j = 0; j < p+1; j++) { + buffer(j, i) = tmp(j) * weights(i); + } + } + return buffer; + } + + __host__ __device__ void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fns, double * buffer) const { + uint32_t n = p + 1; + uint32_t q = shape_fns.shape[1]; + + nd::view BT = shape_fns; + nd::view A(buffer, {q, n}); + + nd::view s2D((double*)&source_q[0], {q, q}, {1, q}); + nd::view r2D = nd::reshape<2>(residual_e, {n, n}); + + contract<1>(s2D, BT, A); + contract<0>(A, BT, r2D); + } + + // note: the return value here includes the shape function evaluations as well as + // a buffer space to hold intermediate values in the `interpolation` function + nd::array< double, 3 > evaluate_weighted_shape_function_gradients(nd::view xi, + nd::view weights) const { + uint32_t q = xi.shape[0]; + nd::array buffer({2, p+1, q}); + nd::array tmp({p+1}); + for (int i = 0; i < q; i++) { + GaussLobattoInterpolation(xi(i, 0), p+1, &tmp(0)); + for (int j = 0; j < p+1; j++) { + buffer(0, j, i) = tmp(j) * weights(i); + } + + GaussLobattoInterpolationDerivative(xi(i, 0), p+1, &tmp(0)); + for (int j = 0; j < p+1; j++) { + buffer(1, j, i) = tmp(j) * weights(i); + } + } + return buffer; + } + + void integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fns, double * buffer) const { + uint32_t n = p + 1; + uint32_t q = shape_fns.shape[2]; + + nd::view BT = shape_fns(0); + nd::view GT = shape_fns(1); + nd::view A(buffer, {q, n}); + + uint32_t s = 2 * flux_q.stride[0]; + nd::range All{0u, flux_q.shape[0]}; + nd::view f2D(&flux_q(0)[0], {q, q}, {s, s*q}); // ? + nd::view r2D = nd::reshape<2>(residual_e, {n, n}); + + contract<1>(f2D, BT, A); + contract<0>( A, GT, r2D); + + f2D.values = &(flux_q(0)[1]); + contract<1>(f2D, GT, A); + contract<0>( A, BT, r2D, true /* accumulate */); + } + + #ifdef __CUDACC__ + __device__ void cuda_gradient(nd::view gradients_q, nd::view values_e, nd::view shape_fns, double * buffer) const { + uint32_t n = p + 1; + uint32_t q = shape_fns.shape[1]; + + nd::view B = shape_fns(0); + nd::view G = shape_fns(1); + nd::view A(buffer, {n, q}); + + nd::range All{0u, gradients_q.shape[0]}; + nd::view values_e_2D = nd::reshape<2>(values_e, {n, n}); + nd::view gradients_q_2D((double*)&gradients_q[0], {q, q}, {2, 2*q}); + + threadid tid; + tid.x = threadIdx.x % q; + tid.y = threadIdx.x / q; + tid.stride = q; + + // du_dxi + cuda_contract<1>(tid, values_e_2D, G, A); + cuda_contract<0>(tid, A, B, gradients_q_2D); + gradients_q_2D.values++; + + // du_deta + cuda_contract<1>(tid, values_e_2D, B, A); + cuda_contract<0>(tid, A, G, gradients_q_2D); + gradients_q_2D.values++; + } + + __device__ void cuda_integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fns, double * buffer) const { + uint32_t n = p + 1; + uint32_t q = shape_fns.shape[2]; + + nd::view BT = shape_fns(0); + nd::view GT = shape_fns(1); + nd::view A(buffer, {q, n}); + + uint32_t s = 2 * flux_q.stride[0]; + nd::range All{0u, flux_q.shape[0]}; + nd::view f2D(&flux_q(0)[0], {q, q}, {s, s*q}); // ? + nd::view r2D = nd::reshape<2>(residual_e, {n, n}); + + threadid tid; + tid.x = threadIdx.x % n; + tid.y = threadIdx.x / n; + tid.stride = n; + + cuda_contract<1>(tid, f2D, BT, A); + cuda_contract<0>(tid, A, GT, r2D); + + f2D.values = &(flux_q(0)[1]); + cuda_contract<1>(tid, f2D, GT, A); + cuda_contract<0>(tid, A, BT, r2D, true /* accumulate */); + } + #endif + + + + uint32_t p; + +}; + +} // namespace refactor diff --git a/src/serac/numerics/refactor/elements/h1_tetrahedron.hpp b/src/serac/numerics/refactor/elements/h1_tetrahedron.hpp new file mode 100644 index 0000000000..8fef02fb9c --- /dev/null +++ b/src/serac/numerics/refactor/elements/h1_tetrahedron.hpp @@ -0,0 +1,401 @@ +#pragma once + +#include "refactor/connection.hpp" + +namespace refactor { + +template <> +struct FiniteElement { + + using source_type = vec1; + using flux_type = vec3; + + using value_type = vec1; + using grad_type = vec3; + + static constexpr int dim = 3; + + __host__ __device__ constexpr uint32_t num_nodes() const { return Tetrahedron::number(p + 1); } + + void nodes(nd::view< double, 2 > xi) const { + if (p == 1) { + xi(0, 0) = 0.0; xi(0, 1) = 0.0; xi(0, 2) = 0.0; + xi(1, 0) = 1.0; xi(1, 1) = 0.0; xi(1, 2) = 0.0; + xi(2, 0) = 0.0; xi(2, 1) = 1.0; xi(2, 2) = 0.0; + + xi(3, 0) = 0.0; xi(3, 1) = 0.0; xi(3, 2) = 1.0; + } + if (p == 2) { + xi(0, 0) = 0.0; xi(0, 1) = 0.0; xi(0, 2) = 0.0; + xi(1, 0) = 0.5; xi(1, 1) = 0.0; xi(1, 2) = 0.0; + xi(2, 0) = 1.0; xi(2, 1) = 0.0; xi(2, 2) = 0.0; + xi(3, 0) = 0.0; xi(3, 1) = 0.5; xi(3, 2) = 0.0; + xi(4, 0) = 0.5; xi(4, 1) = 0.5; xi(4, 2) = 0.0; + xi(5, 0) = 0.0; xi(5, 1) = 1.0; xi(5, 2) = 0.0; + + xi(6, 0) = 0.0; xi(6, 1) = 0.0; xi(6, 2) = 0.5; + xi(7, 0) = 0.5; xi(7, 1) = 0.0; xi(7, 2) = 0.5; + xi(8, 0) = 0.0; xi(8, 1) = 0.5; xi(8, 2) = 0.5; + + xi(9, 0) = 0.0; xi(9, 1) = 0.0; xi(9, 2) = 1.0; + } + if (p == 3) { + constexpr double s1 = 0.2763932022500210; + constexpr double s2 = 0.7236067977499790; + constexpr double s3 = 0.3333333333333333; + + xi( 0, 0) = 0.0; xi( 0, 1) = 0.0; xi( 0, 2) = 0.0; + xi( 1, 0) = s1; xi( 1, 1) = 0.0; xi( 1, 2) = 0.0; + xi( 2, 0) = s2; xi( 2, 1) = 0.0; xi( 2, 2) = 0.0; + xi( 3, 0) = 1.0; xi( 3, 1) = 0.0; xi( 3, 2) = 0.0; + xi( 4, 0) = 0.0; xi( 4, 1) = s1; xi( 4, 2) = 0.0; + xi( 5, 0) = s3; xi( 5, 1) = s3; xi( 5, 2) = 0.0; + xi( 6, 0) = s2; xi( 6, 1) = s1; xi( 6, 2) = 0.0; + xi( 7, 0) = 0.0; xi( 7, 1) = s2; xi( 7, 2) = 0.0; + xi( 8, 0) = s1; xi( 8, 1) = s2; xi( 8, 2) = 0.0; + xi( 9, 0) = 0.0; xi( 9, 1) = 1.0; xi( 9, 2) = 0.0; + + xi(10, 0) = 0.0; xi(10, 1) = 0.0; xi(10, 2) = s1; + xi(11, 0) = s3; xi(11, 1) = 0.0; xi(11, 2) = s3; + xi(12, 0) = s2; xi(12, 1) = 0.0; xi(12, 2) = s1; + xi(13, 0) = 0.0; xi(13, 1) = s3; xi(13, 2) = s3; + xi(14, 0) = s3; xi(14, 1) = s3; xi(14, 2) = s3; + xi(15, 0) = 0.0; xi(15, 1) = s2; xi(15, 2) = s1; + + xi(16, 0) = 0.0; xi(16, 1) = 0.0; xi(16, 2) = s2; + xi(17, 0) = s1; xi(17, 1) = 0.0; xi(17, 2) = s2; + xi(18, 0) = 0.0; xi(18, 1) = s1; xi(18, 2) = s2; + + xi(19, 0) = 0.0; xi(19, 1) = 0.0; xi(19, 2) = 1.0; + } + } + + // interior nodes only show up for tets when p >= 4, but this only supports p <= 3 + __host__ __device__ uint32_t num_interior_nodes() const { return 0; } + + void interior_nodes(nd::view< double, 2 > /* xi */) const {} + + __host__ __device__ void indices(const GeometryInfo & offsets, const Connection * tet, uint32_t * indices) const { + + const Connection * vertex = tet; + const Connection * edge = tet + Tetrahedron::edge_offset; + const Connection * face = tet + Tetrahedron::tri_offset; + + if (p == 1) { + indices[0] = offsets.vert + vertex[0].index; + indices[1] = offsets.vert + vertex[1].index; + indices[2] = offsets.vert + vertex[2].index; + indices[3] = offsets.vert + vertex[3].index; + return; + } + + if (p == 2) { + indices[0] = offsets.vert + vertex[0].index; + indices[1] = offsets.edge + edge[0].index; + indices[2] = offsets.vert + vertex[1].index; + indices[3] = offsets.edge + edge[2].index; + indices[4] = offsets.edge + edge[1].index; + indices[5] = offsets.vert + vertex[2].index; + indices[6] = offsets.edge + edge[3].index; + indices[7] = offsets.edge + edge[4].index; + indices[8] = offsets.edge + edge[5].index; + indices[9] = offsets.vert + vertex[3].index; + } + + if (p == 3) { + indices[ 0] = offsets.vert + vertex[0].index; + indices[ 1] = offsets.edge + 2 * edge[0].index + 0; + indices[ 2] = offsets.edge + 2 * edge[0].index + 1; + indices[ 3] = offsets.vert + vertex[1].index; + indices[ 4] = offsets.edge + 2 * edge[2].index + 1; + indices[ 5] = offsets.tri + face[0].index + 0; + indices[ 6] = offsets.edge + 2 * edge[1].index + 0; + indices[ 7] = offsets.edge + 2 * edge[2].index + 0; + indices[ 8] = offsets.edge + 2 * edge[1].index + 1; + indices[ 9] = offsets.vert + vertex[2].index + 0; + + indices[10] = offsets.edge + 2 * edge[3].index + 0; + indices[11] = offsets.tri + face[1].index; + indices[12] = offsets.edge + 2 * edge[4].index + 0; + indices[13] = offsets.tri + face[3].index; + indices[14] = offsets.tri + face[2].index; + indices[15] = offsets.edge + 2 * edge[5].index + 0; + + indices[16] = offsets.edge + 2 * edge[3].index + 1; + indices[17] = offsets.edge + 2 * edge[4].index + 1; + indices[18] = offsets.edge + 2 * edge[5].index + 1; + + indices[19] = offsets.vert + vertex[3].index; + + if (flip(edge[0])) { fm::swap(indices[ 1], indices[ 2]); } + if (flip(edge[1])) { fm::swap(indices[ 6], indices[ 8]); } + if (flip(edge[2])) { fm::swap(indices[ 7], indices[ 4]); } + if (flip(edge[3])) { fm::swap(indices[10], indices[16]); } + if (flip(edge[4])) { fm::swap(indices[12], indices[17]); } + if (flip(edge[5])) { fm::swap(indices[15], indices[18]); } + return; + } + + } + + constexpr double shape_function(vec3 xi, uint32_t i) const { + // expressions generated symbolically by mathematica + if (p == 1) { + if (i == 0) return 1-xi[0]-xi[1]-xi[2]; + if (i == 1) return xi[0]; + if (i == 2) return xi[1]; + if (i == 3) return xi[2]; + } + if (p == 2) { + if (i == 0) return (-1+xi[0]+xi[1]+xi[2])*(-1+2*xi[0]+2*xi[1]+2*xi[2]); + if (i == 1) return -4*xi[0]*(-1+xi[0]+xi[1]+xi[2]); + if (i == 2) return xi[0]*(-1+2*xi[0]); + if (i == 3) return -4*xi[1]*(-1+xi[0]+xi[1]+xi[2]); + if (i == 4) return 4*xi[0]*xi[1]; + if (i == 5) return xi[1]*(-1+2*xi[1]); + if (i == 6) return -4*xi[2]*(-1+xi[0]+xi[1]+xi[2]); + if (i == 7) return 4*xi[0]*xi[2]; + if (i == 8) return 4*xi[1]*xi[2]; + if (i == 9) return xi[2]*(-1+2*xi[2]); + } + if (p == 3) { + double sqrt5 = 2.23606797749978981; + if (i == 0) return -((-1+xi[0]+xi[1]+xi[2])*(1+5*xi[0]*xi[0]+5*xi[1]*xi[1]+5*(-1+xi[2])*xi[2]+xi[1]*(-5+11*xi[2])+xi[0]*(-5+11*xi[1]+11*xi[2]))); + if (i == 1) return (5*xi[0]*(-1+xi[0]+xi[1]+xi[2])*(-1-sqrt5+2*sqrt5*xi[0]+(3+sqrt5)*xi[1]+(3+sqrt5)*xi[2]))/2.; + if (i == 2) return (-5*xi[0]*(-1+xi[0]+xi[1]+xi[2])*(1-sqrt5+2*sqrt5*xi[0]+(-3+sqrt5)*xi[1]+(-3+sqrt5)*xi[2]))/2.; + if (i == 3) return xi[0]*(1+5*xi[0]*xi[0]+xi[1]-xi[1]*xi[1]+xi[2]-xi[1]*xi[2]-xi[2]*xi[2]-xi[0]*(5+xi[1]+xi[2])); + if (i == 4) return (5*xi[1]*(-1+xi[0]+xi[1]+xi[2])*(-1-sqrt5+(3+sqrt5)*xi[0]+2*sqrt5*xi[1]+(3+sqrt5)*xi[2]))/2.; + if (i == 5) return -27*xi[0]*xi[1]*(-1+xi[0]+xi[1]+xi[2]); + if (i == 6) return (5*xi[0]*xi[1]*(-2+(3+sqrt5)*xi[0]-(-3+sqrt5)*xi[1]))/2.; + if (i == 7) return (-5*xi[1]*(-1+xi[0]+xi[1]+xi[2])*(1-sqrt5+(-3+sqrt5)*xi[0]+2*sqrt5*xi[1]+(-3+sqrt5)*xi[2]))/2.; + if (i == 8) return (-5*xi[0]*xi[1]*(2+(-3+sqrt5)*xi[0]-(3+sqrt5)*xi[1]))/2.; + if (i == 9) return xi[1]*(1-xi[0]*xi[0]+5*xi[1]*xi[1]+xi[2]-xi[2]*xi[2]-xi[1]*(5+xi[2])-xi[0]*(-1+xi[1]+xi[2])); + if (i == 10) return (5*xi[2]*(-1+xi[0]+xi[1]+xi[2])*(-439204-196418*sqrt5+(710647+317811*sqrt5)*xi[0]+(710647+317811*sqrt5)*xi[1]+606965*xi[2]+271443*sqrt5*xi[2]))/(271443+121393*sqrt5); + if (i == 11) return -27*xi[0]*xi[2]*(-1+xi[0]+xi[1]+xi[2]); + if (i == 12) return (5*xi[0]*xi[2]*(-5-3*sqrt5+(15+7*sqrt5)*xi[0]+2*sqrt5*xi[2]))/(5+3*sqrt5); + if (i == 13) return -27*xi[1]*xi[2]*(-1+xi[0]+xi[1]+xi[2]); + if (i == 14) return 27*xi[0]*xi[1]*xi[2]; + if (i == 15) return (5*xi[1]*xi[2]*(-5-3*sqrt5+(15+7*sqrt5)*xi[1]+2*sqrt5*xi[2]))/(5+3*sqrt5); + if (i == 16) return (5*xi[2]*(-1+xi[0]+xi[1]+xi[2])*(88555+39603*sqrt5+(54730+24476*sqrt5)*xi[0]+(54730+24476*sqrt5)*xi[1]-5*(64079+28657*sqrt5)*xi[2]))/(143285+64079*sqrt5); + if (i == 17) return (-5*xi[0]*xi[2]*(2+(-3+sqrt5)*xi[0]-(3+sqrt5)*xi[2]))/2.; + if (i == 18) return (-5*xi[1]*xi[2]*(2+(-3+sqrt5)*xi[1]-(3+sqrt5)*xi[2]))/2.; + if (i == 19) return -(xi[2]*(-1+xi[0]*xi[0]+xi[1]*xi[1]+xi[1]*(-1+xi[2])-5*(-1+xi[2])*xi[2]+xi[0]*(-1+xi[1]+xi[2]))); + } + + return {}; + } + + vec3 shape_function_gradient(vec3 xi, uint32_t i) const { + // expressions generated symbolically by mathematica + if (p == 1) { + if (i == 0) return {-1, -1, -1}; + if (i == 1) return {1, 0, 0}; + if (i == 2) return {0, 1, 0}; + if (i == 3) return {0, 0, 1}; + } + if (p == 2) { + if (i == 0) return {-3+4*xi[0]+4*xi[1]+4*xi[2], -3+4*xi[0]+4*xi[1]+4*xi[2], -3+4*xi[0]+4*xi[1]+4*xi[2]}; + if (i == 1) return {-4*(-1+2*xi[0]+xi[1]+xi[2]), -4*xi[0], -4*xi[0]}; + if (i == 2) return {-1+4*xi[0], 0, 0}; + if (i == 3) return {-4*xi[1], -4*(-1+xi[0]+2*xi[1]+xi[2]), -4*xi[1]}; + if (i == 4) return {4*xi[1], 4*xi[0], 0}; + if (i == 5) return {0, -1+4*xi[1], 0}; + if (i == 6) return {-4*xi[2], -4*xi[2], -4*(-1+xi[0]+xi[1]+2*xi[2])}; + if (i == 7) return {4*xi[2], 0, 4*xi[0]}; + if (i == 8) return {0, 4*xi[2], 4*xi[1]}; + if (i == 9) return {0, 0, -1+4*xi[2]}; + } + if (p == 3) { + double sqrt5 = 2.23606797749978981; + if (i == 0) return {-6-15*xi[0]*xi[0]-16*xi[1]*xi[1]+xi[1]*(21-33*xi[2])+(21-16*xi[2])*xi[2]-4*xi[0]*(-5+8*xi[1]+8*xi[2]), -6-16*xi[0]*xi[0]+20*xi[1]+xi[0]*(21-32*xi[1]-33*xi[2])+21*xi[2]-(3*xi[1]+4*xi[2])*(5*xi[1]+4*xi[2]), -6-16*xi[0]*xi[0]+21*xi[1]+xi[0]*(21-33*xi[1]-32*xi[2])+20*xi[2]-(4*xi[1]+3*xi[2])*(4*xi[1]+5*xi[2])}; + if (i == 1) return {(5*(6*sqrt5*xi[0]*xi[0]+xi[0]*(-2-6*sqrt5+6*(1+sqrt5)*xi[1]+6*(1+sqrt5)*xi[2])+(-1+xi[1]+xi[2])*(-1-sqrt5+(3+sqrt5)*xi[1]+(3+sqrt5)*xi[2])))/2., (5*xi[0]*(-4-2*sqrt5+3*(1+sqrt5)*xi[0]+2*(3+sqrt5)*xi[1]+2*(3+sqrt5)*xi[2]))/2., (5*xi[0]*(-4-2*sqrt5+3*(1+sqrt5)*xi[0]+2*(3+sqrt5)*xi[1]+2*(3+sqrt5)*xi[2]))/2.}; + if (i == 2) return {-15*sqrt5*xi[0]*xi[0]-(5*(-1+xi[1]+xi[2])*(1-sqrt5+(-3+sqrt5)*xi[1]+(-3+sqrt5)*xi[2]))/2.-5*xi[0]*(1-3*sqrt5+3*(-1+sqrt5)*xi[1]+3*(-1+sqrt5)*xi[2]), (-5*xi[0]*(4-2*sqrt5+3*(-1+sqrt5)*xi[0]+2*(-3+sqrt5)*xi[1]+2*(-3+sqrt5)*xi[2]))/2., (-5*xi[0]*(4-2*sqrt5+3*(-1+sqrt5)*xi[0]+2*(-3+sqrt5)*xi[1]+2*(-3+sqrt5)*xi[2]))/2.}; + if (i == 3) return {1+15*xi[0]*xi[0]+xi[1]-xi[1]*xi[1]+xi[2]-xi[1]*xi[2]-xi[2]*xi[2]-2*xi[0]*(5+xi[1]+xi[2]), -(xi[0]*(-1+xi[0]+2*xi[1]+xi[2])), -(xi[0]*(-1+xi[0]+xi[1]+2*xi[2]))}; + if (i == 4) return {(5*xi[1]*(-2*(2+sqrt5)+2*(3+sqrt5)*xi[0]+3*(1+sqrt5)*xi[1]+2*(3+sqrt5)*xi[2]))/2., 15*sqrt5*xi[1]*xi[1]+5*xi[1]*(-1-3*sqrt5+3*(1+sqrt5)*xi[0]+3*(1+sqrt5)*xi[2])+(5*(-1+xi[0]+xi[2])*(-1-sqrt5+(3+sqrt5)*xi[0]+(3+sqrt5)*xi[2]))/2., (5*xi[1]*(-2*(2+sqrt5)+2*(3+sqrt5)*xi[0]+3*(1+sqrt5)*xi[1]+2*(3+sqrt5)*xi[2]))/2.}; + if (i == 5) return {-27*xi[1]*(-1+2*xi[0]+xi[1]+xi[2]), -27*xi[0]*(-1+xi[0]+2*xi[1]+xi[2]), -27*xi[0]*xi[1]}; + if (i == 6) return {(-5*xi[1]*(2-2*(3+sqrt5)*xi[0]+(-3+sqrt5)*xi[1]))/2., (5*xi[0]*(-2+(3+sqrt5)*xi[0]-2*(-3+sqrt5)*xi[1]))/2., 0}; + if (i == 7) return {(-5*xi[1]*(4-2*sqrt5+2*(-3+sqrt5)*xi[0]+3*(-1+sqrt5)*xi[1]+2*(-3+sqrt5)*xi[2]))/2., -15*sqrt5*xi[1]*xi[1]-(5*(-1+xi[0]+xi[2])*(1-sqrt5+(-3+sqrt5)*xi[0]+(-3+sqrt5)*xi[2]))/2.-5*xi[1]*(1-3*sqrt5+3*(-1+sqrt5)*xi[0]+3*(-1+sqrt5)*xi[2]), (-5*xi[1]*(4-2*sqrt5+2*(-3+sqrt5)*xi[0]+3*(-1+sqrt5)*xi[1]+2*(-3+sqrt5)*xi[2]))/2.}; + if (i == 8) return {(5*xi[1]*(-2-2*(-3+sqrt5)*xi[0]+(3+sqrt5)*xi[1]))/2., (-5*xi[0]*(2+(-3+sqrt5)*xi[0]-2*(3+sqrt5)*xi[1]))/2., 0}; + if (i == 9) return {-(xi[1]*(-1+2*xi[0]+xi[1]+xi[2])), 1-xi[0]*xi[0]+15*xi[1]*xi[1]+xi[2]-xi[2]*xi[2]-2*xi[1]*(5+xi[2])-xi[0]*(-1+2*xi[1]+xi[2]), -(xi[1]*(-1+xi[0]+xi[1]+2*xi[2]))}; + if (i == 10) return {(5*xi[2]*(-2*(2+sqrt5)+2*(3+sqrt5)*xi[0]+2*(3+sqrt5)*xi[1]+3*(1+sqrt5)*xi[2]))/2., (5*xi[2]*(-2*(2+sqrt5)+2*(3+sqrt5)*xi[0]+2*(3+sqrt5)*xi[1]+3*(1+sqrt5)*xi[2]))/2., (5*(1+sqrt5+(3+sqrt5)*xi[0]*xi[0]-2*(2+sqrt5)*xi[1]+(3+sqrt5)*xi[1]*xi[1]+6*(1+sqrt5)*xi[1]*xi[2]+2*xi[2]*(-1-3*sqrt5+3*sqrt5*xi[2])+2*xi[0]*(-2-sqrt5+(3+sqrt5)*xi[1]+3*(1+sqrt5)*xi[2])))/2.}; + if (i == 11) return {-27*xi[2]*(-1+2*xi[0]+xi[1]+xi[2]), -27*xi[0]*xi[2], -27*xi[0]*(-1+xi[0]+xi[1]+2*xi[2])}; + if (i == 12) return {(-5*xi[2]*(2-2*(3+sqrt5)*xi[0]+(-3+sqrt5)*xi[2]))/2., 0, (5*xi[0]*(-2+(3+sqrt5)*xi[0]-2*(-3+sqrt5)*xi[2]))/2.}; + if (i == 13) return {-27*xi[1]*xi[2], -27*xi[2]*(-1+xi[0]+2*xi[1]+xi[2]), -27*xi[1]*(-1+xi[0]+xi[1]+2*xi[2])}; + if (i == 14) return {27*xi[1]*xi[2], 27*xi[0]*xi[2], 27*xi[0]*xi[1]}; + if (i == 15) return {0, (-5*xi[2]*(2-2*(3+sqrt5)*xi[1]+(-3+sqrt5)*xi[2]))/2., (5*xi[1]*(-2+(3+sqrt5)*xi[1]-2*(-3+sqrt5)*xi[2]))/2.}; + if (i == 16) return {(-5*xi[2]*(4-2*sqrt5+2*(-3+sqrt5)*xi[0]+2*(-3+sqrt5)*xi[1]+3*(-1+sqrt5)*xi[2]))/2., (-5*xi[2]*(4-2*sqrt5+2*(-3+sqrt5)*xi[0]+2*(-3+sqrt5)*xi[1]+3*(-1+sqrt5)*xi[2]))/2., (-5*(-3+sqrt5)*xi[0]*xi[0])/2.-5*xi[0]*(2-sqrt5+(-3+sqrt5)*xi[1]+3*(-1+sqrt5)*xi[2])-(5*(-1+sqrt5+(-3+sqrt5)*xi[1]*xi[1]+2*xi[2]*(1-3*sqrt5+3*sqrt5*xi[2])+xi[1]*(4-2*sqrt5+6*(-1+sqrt5)*xi[2])))/2.}; + if (i == 17) return {(5*xi[2]*(-2-2*(-3+sqrt5)*xi[0]+(3+sqrt5)*xi[2]))/2., 0, (-5*xi[0]*(2+(-3+sqrt5)*xi[0]-2*(3+sqrt5)*xi[2]))/2.}; + if (i == 18) return {0, (5*xi[2]*(-2-2*(-3+sqrt5)*xi[1]+(3+sqrt5)*xi[2]))/2., (-5*xi[1]*(2+(-3+sqrt5)*xi[1]-2*(3+sqrt5)*xi[2]))/2.}; + if (i == 19) return {-(xi[2]*(-1+2*xi[0]+xi[1]+xi[2])), -(xi[2]*(-1+xi[0]+2*xi[1]+xi[2])), 1+xi[0]-xi[0]*xi[0]+xi[1]-xi[0]*xi[1]-xi[1]*xi[1]-2*(5+xi[0]+xi[1])*xi[2]+15*xi[2]*xi[2]}; + } + + return {}; + } + + vec3 shape_function_derivative(vec3 xi, uint32_t i) const { + return shape_function_gradient(xi, i); + } + + double interpolate(vec3 xi, double * values) const { + double interpolated_value = 0.0; + for (int i = 0; i < num_nodes(); i++) { + interpolated_value += values[i] * shape_function(xi, i); + } + return interpolated_value; + } + + vec3 gradient(vec3 xi, double * values) const { + vec3 interpolated_gradient{}; + for (int i = 0; i < num_nodes(); i++) { + interpolated_gradient += values[i] * shape_function_gradient(xi, i); + } + return interpolated_gradient; + } + + __host__ __device__ uint32_t batch_interpolation_scratch_space(nd::view xi) const { + return 0; + } + + nd::array< double, 2 > evaluate_shape_functions(nd::view xi) const { + uint32_t q = xi.shape[0]; + nd::array shape_fns({q, num_nodes()}); + for (int i = 0; i < q; i++) { + GaussLobattoInterpolationTetrahedron(&xi(i, 0), p, &shape_fns(i, 0)); + } + return shape_fns; + } + + nd::array< double, 3 > evaluate_shape_function_gradients(nd::view xi) const { + uint32_t q = xi.shape[0]; + nd::array shape_fn_grads({q, num_nodes(), dim}); + for (int i = 0; i < q; i++) { + GaussLobattoInterpolationDerivativeTetrahedron(&xi(i, 0), p, &shape_fn_grads(i, 0, 0)); + } + return shape_fn_grads; + } + + void interpolate(nd::view values_q, nd::view values_e, nd::view shape_fns, double * /*buffer*/) const { + int nnodes = num_nodes(); + int nqpts = values_q.shape[0]; + + for (int q = 0; q < nqpts; q++) { + double sum = 0.0; + for (int i = 0; i < nnodes; i++) { + sum += shape_fns(q, i) * values_e(i); + } + values_q(q) = sum; + } + } + + void gradient(nd::view gradients_q, nd::view values_e, nd::view shape_fn_grads, double * /*buffer*/) const { + int nnodes = num_nodes(); + int nqpts = gradients_q.shape[0]; + + for (int j = 0; j < nqpts; j++) { + grad_type sum{}; + for (int i = 0; i < nnodes; i++) { + sum[0] += values_e(i) * shape_fn_grads(j, i, 0); + sum[1] += values_e(i) * shape_fn_grads(j, i, 1); + sum[2] += values_e(i) * shape_fn_grads(j, i, 2); + } + gradients_q(j) = sum; + } + + } + + nd::array< double, 2 > evaluate_weighted_shape_functions(nd::view xi, + nd::view weights) const { + uint32_t nnodes = num_nodes(); + uint32_t q = xi.shape[0]; + nd::array shape_fns({q, nnodes}); + for (int i = 0; i < q; i++) { + GaussLobattoInterpolationTetrahedron(&xi(i, 0), p, &shape_fns(i, 0)); + for (int j = 0; j < nnodes; j++) { + shape_fns(i, j) = shape_fns(i, j) * weights(i); + } + } + return shape_fns; + } + + __host__ __device__ void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fn, double * /*buffer*/) const { + int nnodes = num_nodes(); + int nqpts = source_q.shape[0]; + + for (int i = 0; i < nnodes; i++) { + double sum = 0.0; + for (int q = 0; q < nqpts; q++) { + sum += shape_fn(q, i) * source_q(q); + } + residual_e(i) = sum; + } + } + + nd::array< double, 3 > evaluate_weighted_shape_function_gradients(nd::view xi, + nd::view weights) const { + uint32_t nnodes = num_nodes(); + uint32_t q = xi.shape[0]; + nd::array shape_fn_grads({q, nnodes, dim}); + for (int i = 0; i < q; i++) { + GaussLobattoInterpolationDerivativeTetrahedron(&xi(i, 0), p, &shape_fn_grads(i, 0, 0)); + for (int j = 0; j < nnodes; j++) { + shape_fn_grads(i, j, 0) = shape_fn_grads(i, j, 0) * weights(i); + shape_fn_grads(i, j, 1) = shape_fn_grads(i, j, 1) * weights(i); + shape_fn_grads(i, j, 2) = shape_fn_grads(i, j, 2) * weights(i); + } + } + + return shape_fn_grads; + } + + void integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fn_grads, double * /* buffer */) const { + int nnodes = num_nodes(); + int nqpts = flux_q.shape[0]; + + for (int i = 0; i < nnodes; i++) { + double sum = 0.0; + for (int q = 0; q < nqpts; q++) { + for (int d = 0; d < dim; d++) { + sum += shape_fn_grads(q, i, d) * flux_q(q)[d]; + } + } + residual_e(i) = sum; + } + } + + #ifdef __CUDACC__ + __device__ void cuda_gradient(nd::view gradients_q, nd::view values_e, nd::view shape_fn_grads, double * /*buffer*/) const { + int nnodes = num_nodes(); + int nqpts = gradients_q.shape[0]; + + for (int j = threadIdx.x; j < nqpts; j += blockDim.x) { + grad_type sum{}; + for (int i = 0; i < nnodes; i++) { + sum[0] += values_e(i) * shape_fn_grads(j, i, 0); + sum[1] += values_e(i) * shape_fn_grads(j, i, 1); + sum[2] += values_e(i) * shape_fn_grads(j, i, 2); + } + gradients_q(j) = sum; + } + } + + __device__ void cuda_integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fn_grads, double * /*buffer*/) const { + int nnodes = num_nodes(); + int nqpts = flux_q.shape[0]; + + for (int i = threadIdx.x; i < nnodes; i += blockDim.x) { + double sum = 0.0; + for (int q = 0; q < nqpts; q++) { + for (int d = 0; d < dim; d++) { + sum += shape_fn_grads(q, i, d) * flux_q(q)[d]; + } + } + residual_e(i) = sum; + } + } + #endif + + uint32_t p; + +}; + +} // namespace refactor diff --git a/src/serac/numerics/refactor/elements/h1_triangle.hpp b/src/serac/numerics/refactor/elements/h1_triangle.hpp new file mode 100644 index 0000000000..0e0a622cd4 --- /dev/null +++ b/src/serac/numerics/refactor/elements/h1_triangle.hpp @@ -0,0 +1,331 @@ +#pragma once + +#include "refactor/connection.hpp" + +namespace refactor { + +// clang-format off +template <> +struct FiniteElement { + + using source_type = vec1; + using flux_type = vec2; + + using value_type = vec1; + using grad_type = vec2; + + static constexpr int dim = 2; + + __host__ __device__ constexpr uint32_t num_nodes() const { return Triangle::number(p + 1); } + + void nodes(nd::view xi) const { + if (p == 1) { + xi(0,0) = 0.0; xi(0,1) = 0.0; + xi(1,0) = 1.0; xi(1,1) = 0.0; + xi(2,0) = 0.0; xi(2,1) = 1.0; + } + if (p == 2) { + xi(0,0) = 0.0; xi(0,1) = 0.0; + xi(1,0) = 0.5; xi(1,1) = 0.0; + xi(2,0) = 1.0; xi(2,1) = 0.0; + xi(3,0) = 0.0; xi(3,1) = 0.5; + xi(4,0) = 0.5; xi(4,1) = 0.5; + xi(5,0) = 0.0; xi(5,1) = 1.0; + } + if (p == 3) { + xi(0,0) = 0.0; xi(0,1) = 0.0; + xi(1,0) = 0.2763932022500210; xi(1,1) = 0.0; + xi(2,0) = 0.7236067977499790; xi(2,1) = 0.0; + xi(3,0) = 1.0; xi(3,1) = 0.0; + xi(4,0) = 0.0; xi(4,1) = 0.2763932022500210; + xi(5,0) = 0.3333333333333333; xi(5,1) = 0.3333333333333333; + xi(6,0) = 0.7236067977499790; xi(6,1) = 0.2763932022500210; + xi(7,0) = 0.0; xi(7,1) = 0.7236067977499790; + xi(8,0) = 0.2763932022500210; xi(8,1) = 0.7236067977499790; + xi(9,0) = 0.0; xi(9,1) = 1.0; + } + } + + __host__ __device__ uint32_t num_interior_nodes() const { return (p > 2) ? Triangle::number(p - 2) : 0; } + + void interior_nodes(nd::view xi) const { + if (p == 3) { + xi(0,0) = 0.3333333333333333; xi(0,1) = 0.3333333333333333; + } + } + + __host__ __device__ void indices(const GeometryInfo & offsets, const Connection * tri, uint32_t * indices) const { + + const Connection * vertex = tri; + const Connection * edge = tri + Triangle::edge_offset; + const Connection cell = *(tri + Triangle::cell_offset); + + if (p == 1) { + // 2 + // 0 1 + indices[0] = offsets.vert + vertex[0].index; + indices[1] = offsets.vert + vertex[1].index; + indices[2] = offsets.vert + vertex[2].index; + return; + } + + if (p == 2) { + // 5 + // 3 4 + // 0 1 2 + indices[0] = offsets.vert + vertex[0].index; + indices[1] = offsets.edge + edge[0].index; + indices[2] = offsets.vert + vertex[1].index; + indices[3] = offsets.edge + edge[2].index; + indices[4] = offsets.edge + edge[1].index; + indices[5] = offsets.vert + vertex[2].index; + } + + if (p == 3) { + // 9 + // 7 8 + // 4 5 6 + // 0 1 2 3 + indices[0] = offsets.vert + vertex[0].index; + indices[1] = offsets.edge + 2 * edge[0].index + 0; + indices[2] = offsets.edge + 2 * edge[0].index + 1; + indices[3] = offsets.vert + vertex[1].index; + indices[4] = offsets.edge + 2 * edge[2].index + 1; + indices[5] = offsets.tri + cell.index; + indices[6] = offsets.edge + 2 * edge[1].index + 0; + indices[7] = offsets.edge + 2 * edge[2].index + 0; + indices[8] = offsets.edge + 2 * edge[1].index + 1; + indices[9] = offsets.vert + vertex[2].index; + + if (flip(edge[0])) { fm::swap(indices[1], indices[2]); } + if (flip(edge[1])) { fm::swap(indices[6], indices[8]); } + if (flip(edge[2])) { fm::swap(indices[7], indices[4]); } + return; + } + } + + constexpr double shape_function(vec2 xi, uint32_t i) const { + if (p == 1) { + if (i == 0) return 1.0 - xi[0] - xi[1]; + if (i == 1) return xi[0]; + if (i == 2) return xi[1]; + } + if (p == 2) { + if (i == 0) return (-1+xi[0]+xi[1])*(-1+2*xi[0]+2*xi[1]); + if (i == 1) return -4*xi[0]*(-1+xi[0]+xi[1]); + if (i == 2) return xi[0]*(-1+2*xi[0]); + if (i == 3) return -4*xi[1]*(-1+xi[0]+xi[1]); + if (i == 4) return 4*xi[0]*xi[1]; + if (i == 5) return xi[1]*(-1+2*xi[1]); + } + if (p == 3) { + double sqrt5 = 2.23606797749978981; + if (i == 0) return -((-1+xi[0]+xi[1])*(1+5*xi[0]*xi[0]+5*(-1+xi[1])*xi[1]+xi[0]*(-5+11*xi[1]))); + if (i == 1) return (5*xi[0]*(-1+xi[0]+xi[1])*(-1-sqrt5+2*sqrt5*xi[0]+(3+sqrt5)*xi[1]))/2.0; + if (i == 2) return (-5*xi[0]*(-1+xi[0]+xi[1])*(1-sqrt5+2*sqrt5*xi[0]+(-3+sqrt5)*xi[1]))/2.0; + if (i == 3) return xi[0]*(1+5*xi[0]*xi[0]+xi[1]-xi[1]*xi[1]-xi[0]*(5+xi[1])); + if (i == 4) return (5*xi[1]*(-1+xi[0]+xi[1])*(-1-sqrt5+(3+sqrt5)*xi[0]+2*sqrt5*xi[1]))/2.0; + if (i == 5) return -27*xi[0]*xi[1]*(-1+xi[0]+xi[1]); + if (i == 6) return (5*xi[0]*xi[1]*(-2+(3+sqrt5)*xi[0]-(-3+sqrt5)*xi[1]))/2.; + if (i == 7) return (5*xi[1]*(-1+xi[0]+xi[1])*(5-3*sqrt5+2*(-5+2*sqrt5)*xi[0]+5*(-1+sqrt5)*xi[1]))/(-5+sqrt5); + if (i == 8) return (-5*xi[0]*xi[1]*(2+(-3+sqrt5)*xi[0]-(3+sqrt5)*xi[1]))/2.; + if (i == 9) return xi[1]*(1+xi[0]-xi[0]*xi[0]-xi[0]*xi[1]+5*(-1+xi[1])*xi[1]); + } + + return -1.0; + } + + vec2 shape_function_gradient(vec2 xi, uint32_t i) const { + // expressions generated symbolically by mathematica + if (p == 1) { + if (i == 0) return {-1.0, -1.0}; + if (i == 1) return { 1.0, 0.0}; + if (i == 2) return { 0.0, 1.0}; + } + if (p == 2) { + if (i == 0) return {-3+4*xi[0]+4*xi[1], -3+4*xi[0]+4*xi[1]}; + if (i == 1) return {-4*(-1+2*xi[0]+xi[1]), -4*xi[0]}; + if (i == 2) return {-1+4*xi[0], 0}; + if (i == 3) return {-4*xi[1], -4*(-1+xi[0]+2*xi[1])}; + if (i == 4) return {4*xi[1], 4*xi[0]}; + if (i == 5) return {0, -1+4*xi[1]}; + } + if (p == 3) { + double sqrt5 = 2.23606797749978981; + if (i == 0) return {-6-15*xi[0]*xi[0]+4*xi[0]*(5-8*xi[1])+(21-16*xi[1])*xi[1], -6-16*xi[0]*xi[0]+xi[0]*(21-32*xi[1])+5*(4-3*xi[1])*xi[1]}; + if (i == 1) return {(5*(6*sqrt5*xi[0]*xi[0]+xi[0]*(-2-6*sqrt5+6*(1+sqrt5)*xi[1])+(-1+xi[1])*(-1-sqrt5+(3+sqrt5)*xi[1])))/2., (5*xi[0]*(-2*(2+sqrt5)+3*(1+sqrt5)*xi[0]+2*(3+sqrt5)*xi[1]))/2.}; + if (i == 2) return {(-5*(6*sqrt5*xi[0]*xi[0]+(-1+xi[1])*(1-sqrt5+(-3+sqrt5)*xi[1])+xi[0]*(2-6*sqrt5+6*(-1+sqrt5)*xi[1])))/2., (-5*xi[0]*(4-2*sqrt5+3*(-1+sqrt5)*xi[0]+2*(-3+sqrt5)*xi[1]))/2.}; + if (i == 3) return {1+15*xi[0]*xi[0]+xi[1]-xi[1]*xi[1]-2*xi[0]*(5+xi[1]), -(xi[0]*(-1+xi[0]+2*xi[1]))}; + if (i == 4) return {(5*xi[1]*(-2*(2+sqrt5)+2*(3+sqrt5)*xi[0]+3*(1+sqrt5)*xi[1]))/2., (5*(1+sqrt5-2*(2+sqrt5)*xi[0]+(3+sqrt5)*xi[0]*xi[0]+6*(1+sqrt5)*xi[0]*xi[1]+2*xi[1]*(-1-3*sqrt5+3*sqrt5*xi[1])))/2.}; + if (i == 5) return {-27*xi[1]*(-1+2*xi[0]+xi[1]), -27*xi[0]*(-1+xi[0]+2*xi[1])}; + if (i == 6) return {(-5*xi[1]*(2-2*(3+sqrt5)*xi[0]+(-3+sqrt5)*xi[1]))/2., (5*xi[0]*(-2+(3+sqrt5)*xi[0]-2*(-3+sqrt5)*xi[1]))/2.}; + if (i == 7) return {(-5*xi[1]*(4-2*sqrt5+2*(-3+sqrt5)*xi[0]+3*(-1+sqrt5)*xi[1]))/2., (-5*(-1+sqrt5+(-3+sqrt5)*xi[0]*xi[0]+2*xi[1]*(1-3*sqrt5+3*sqrt5*xi[1])+xi[0]*(4-2*sqrt5+6*(-1+sqrt5)*xi[1])))/2.}; + if (i == 8) return {(5*xi[1]*(-2-2*(-3+sqrt5)*xi[0]+(3+sqrt5)*xi[1]))/2., (-5*xi[0]*(2+(-3+sqrt5)*xi[0]-2*(3+sqrt5)*xi[1]))/2.}; + if (i == 9) return {-(xi[1]*(-1+2*xi[0]+xi[1])), 1+xi[0]-xi[0]*xi[0]-2*(5+xi[0])*xi[1]+15*xi[1]*xi[1]}; + } + + return {}; + } + + vec2 shape_function_derivative(vec2 xi, uint32_t i) const { + return shape_function_gradient(xi, i); + } + + double interpolate(vec2 xi, const double * values) const { + double interpolated_value = 0.0; + for (int i = 0; i < num_nodes(); i++) { + interpolated_value += values[i] * shape_function(xi, i); + } + return interpolated_value; + } + + vec2 gradient(vec2 xi, const double * values) const { + vec2 interpolated_gradient = {0.0, 0.0}; + for (int i = 0; i < num_nodes(); i++) { + interpolated_gradient += values[i] * shape_function_gradient(xi, i); + } + return interpolated_gradient; + } + + __host__ __device__ uint32_t batch_interpolation_scratch_space(nd::view xi) const { + return 0; + } + + nd::array< double, 2 > evaluate_shape_functions(nd::view xi) const { + uint32_t q = xi.shape[0]; + nd::array shape_fns({q, num_nodes()}); + for (int i = 0; i < q; i++) { + GaussLobattoInterpolationTriangle(&xi(i, 0), p, &shape_fns(i, 0)); + } + return shape_fns; + } + + nd::array< double, 3 > evaluate_shape_function_gradients(nd::view xi) const { + uint32_t q = xi.shape[0]; + nd::array shape_fn_grads({q, num_nodes(), dim}); + for (int i = 0; i < q; i++) { + GaussLobattoInterpolationDerivativeTriangle(&xi(i, 0), p, &shape_fn_grads(i, 0, 0)); + } + return shape_fn_grads; + } + + void interpolate(nd::view values_q, nd::view values_e, nd::view shape_fns, double * /*buffer*/) const { + int nnodes = num_nodes(); + int nqpts = values_q.shape[0]; + + for (int q = 0; q < nqpts; q++) { + double sum = 0.0; + for (int i = 0; i < nnodes; i++) { + sum += shape_fns(q, i) * values_e(i); + } + values_q(q) = sum; + } + } + + void gradient(nd::view gradients_q, nd::view values_e, nd::view shape_fn_grads, double * /*buffer*/) const { + int nnodes = num_nodes(); + int nqpts = gradients_q.shape[0]; + for (int j = 0; j < nqpts; j++) { + grad_type sum{}; + for (int i = 0; i < nnodes; i++) { + sum[0] += values_e(i) * shape_fn_grads(j, i, 0); + sum[1] += values_e(i) * shape_fn_grads(j, i, 1); + } + gradients_q(j) = sum; + } + } + + nd::array< double, 2 > evaluate_weighted_shape_functions(nd::view xi, + nd::view weights) const { + uint32_t nnodes = num_nodes(); + uint32_t q = xi.shape[0]; + nd::array shape_fns({q, nnodes}); + for (uint32_t i = 0; i < q; i++) { + GaussLobattoInterpolationTriangle(&xi(i, 0), p, &shape_fns(i, 0)); + for (uint32_t j = 0; j < nnodes; j++) { + shape_fns(i, j) = shape_fns(i, j) * weights(i); + } + } + return shape_fns; + } + + __host__ __device__ void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fn, double * /*buffer*/) const { + int nnodes = num_nodes(); + int nqpts = source_q.shape[0]; + + for (int i = 0; i < nnodes; i++) { + double sum = 0.0; + for (int q = 0; q < nqpts; q++) { + sum += shape_fn(q, i) * source_q(q); + } + residual_e(i) = sum; + } + } + + nd::array< double, 3 > evaluate_weighted_shape_function_gradients(nd::view xi, + nd::view weights) const { + uint32_t nnodes = num_nodes(); + uint32_t q = xi.shape[0]; + nd::array shape_fn_grads({q, nnodes, dim}); + for (uint32_t i = 0; i < q; i++) { + GaussLobattoInterpolationDerivativeTriangle(&xi(i, 0), p, &shape_fn_grads(i, 0, 0)); + for (uint32_t j = 0; j < nnodes; j++) { + shape_fn_grads(i, j, 0) = shape_fn_grads(i, j, 0) * weights(i); + shape_fn_grads(i, j, 1) = shape_fn_grads(i, j, 1) * weights(i); + } + } + + return shape_fn_grads; + } + + void integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fn_grads, double * /*buffer*/) const { + int nnodes = num_nodes(); + int nqpts = flux_q.shape[0]; + + for (int i = 0; i < nnodes; i++) { + double sum = 0.0; + for (int q = 0; q < nqpts; q++) { + for (int d = 0; d < dim; d++) { + sum += shape_fn_grads(q, i, d) * flux_q(q)[d]; + } + } + residual_e(i) = sum; + } + } + + #ifdef __CUDACC__ + __device__ void cuda_gradient(nd::view gradients_q, nd::view values_e, nd::view shape_fn_grads, double * /*buffer*/) const { + int nnodes = num_nodes(); + int nqpts = gradients_q.shape[0]; + for (int j = threadIdx.x; j < nqpts; j += blockDim.x) { + grad_type sum{}; + for (int i = 0; i < nnodes; i++) { + sum[0] += values_e(i) * shape_fn_grads(j, i, 0); + sum[1] += values_e(i) * shape_fn_grads(j, i, 1); + } + gradients_q(j) = sum; + } + } + + __device__ void cuda_integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fn_grads, double * /*buffer*/) const { + int nnodes = num_nodes(); + int nqpts = flux_q.shape[0]; + + for (int i = threadIdx.x; i < nnodes; i += blockDim.x) { + double sum = 0.0; + for (int q = 0; q < nqpts; q++) { + for (int d = 0; d < dim; d++) { + sum += shape_fn_grads(q, i, d) * flux_q(q)[d]; + } + } + residual_e(i) = sum; + } + } + #endif + + uint32_t p; + +}; +// clang-format on + +} // namespace refactor diff --git a/src/serac/numerics/refactor/elements/h1_vertex.hpp b/src/serac/numerics/refactor/elements/h1_vertex.hpp new file mode 100644 index 0000000000..7dc9655607 --- /dev/null +++ b/src/serac/numerics/refactor/elements/h1_vertex.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include "refactor/connection.hpp" + +namespace refactor { + +template <> +struct FiniteElement { + using source_type = double; + using flux_type = double; + + __host__ __device__ uint32_t num_nodes() const { return 1; } + __host__ __device__ uint32_t num_interior_nodes() const { return 1; } + + uint32_t p; +}; + +} // namespace refactor diff --git a/src/serac/numerics/refactor/elements/hcurl_edge.hpp b/src/serac/numerics/refactor/elements/hcurl_edge.hpp new file mode 100644 index 0000000000..27d5503a23 --- /dev/null +++ b/src/serac/numerics/refactor/elements/hcurl_edge.hpp @@ -0,0 +1,276 @@ +#pragma once + +#include "refactor/interpolation.hpp" + +namespace refactor { + +template <> +struct FiniteElement < Geometry::Edge, Family::Hcurl >{ + + using source_type = vec1; + using flux_type = vec1; + + static constexpr uint32_t dim = 1; + + __host__ __device__ uint32_t num_nodes() const { return p; } + + void nodes(nd::view< double, 2 > xi) const { + if (p == 1) { + xi(0, 0) = GaussLegendreNode01<1, 0>(); + } + + if (p == 2) { + xi(0, 0) = GaussLegendreNode01<2, 0>(); + xi(1, 0) = GaussLegendreNode01<2, 1>(); + } + + if (p == 3) { + xi(0, 0) = GaussLegendreNode01<3, 0>(); + xi(1, 0) = GaussLegendreNode01<3, 1>(); + xi(2, 0) = GaussLegendreNode01<3, 2>(); + } + } + + void directions(nd::view< double, 2 > xi) { + for (int i = 0; i < p; i++) { xi(i, 0) = 1.0; } + } + + __host__ __device__ uint32_t num_interior_nodes() { return p; } + + void interior_nodes(nd::view< double, 2 > xi) { + nodes(xi); // all the nodes in these elements are interior + } + + void interior_directions(nd::view< double, 2 > xi) { + directions(xi); // all the nodes in these elements are interior + } + + __host__ __device__ void indices(const GeometryInfo & offsets, const Connection * edge, uint32_t * ids) { + + uint32_t edge_id = edge[Edge::cell_offset].index; + + if (p == 1) { + ids[0] = offsets.edge + edge_id; + return; + } + + if (p == 2) { + ids[0] = offsets.edge + 2 * edge_id + 0; + ids[1] = offsets.edge + 2 * edge_id + 1; + } + + if (p == 3) { + ids[0] = offsets.edge + 3 * edge_id + 0; + ids[1] = offsets.edge + 3 * edge_id + 1; + ids[2] = offsets.edge + 3 * edge_id + 2; + if (flip(edge[Edge::cell_offset])) { fm::swap(ids[0], ids[2]); } + return; + } + + } + + template < typename T > + __host__ __device__ void reorient(const TransformationType type, const Connection * edge, T * values) { + + // TODO + switch (type) { + case TransformationType::PhysicalToParent: + case TransformationType::TransposePhysicalToParent: + break; + } + + } + + __host__ __device__ void reorient(const TransformationType type, const Connection * edge, int8_t * transformation) { + + for (int i = 0; i < p; i++) { + transformation[i] = 0; + } + + } + + constexpr vec<1> shape_function(vec<1> xi, uint32_t i) const { + if (p == 1 && i == 0) { return GaussLegendreInterpolation01<1, 0>(xi[0]); } + + if (p == 2 && i == 0) { return GaussLegendreInterpolation01<2, 0>(xi[0]); } + if (p == 2 && i == 1) { return GaussLegendreInterpolation01<2, 1>(xi[0]); } + + if (p == 3 && i == 0) { return GaussLegendreInterpolation01<3, 0>(xi[0]); } + if (p == 3 && i == 1) { return GaussLegendreInterpolation01<3, 1>(xi[0]); } + if (p == 3 && i == 2) { return GaussLegendreInterpolation01<3, 2>(xi[0]); } + + return 1000.0f; + } + + constexpr vec1 reoriented_shape_function(vec1 xi, uint32_t i, int8_t transformation) const { + if (transformation == -1) { + return -shape_function(xi, i); + } else { + return shape_function(xi, i); + } + } + + // the other Nedelec elements define this function, + // but what is the appropriate interpretation of "curl" (if any) for 1D? + // + // the implementation below is just the derivative + constexpr vec<1> shape_function_curl(vec<1> xi, uint32_t i) const { + if (p == 1 && i == 0) { return GaussLegendreInterpolationDerivative01<1, 0>(xi); } + + if (p == 2 && i == 0) { return GaussLegendreInterpolationDerivative01<2, 0>(xi); } + if (p == 2 && i == 1) { return GaussLegendreInterpolationDerivative01<2, 1>(xi); } + + if (p == 3 && i == 0) { return GaussLegendreInterpolationDerivative01<3, 0>(xi); } + if (p == 3 && i == 1) { return GaussLegendreInterpolationDerivative01<3, 1>(xi); } + if (p == 3 && i == 2) { return GaussLegendreInterpolationDerivative01<3, 2>(xi); } + + return 1000.0f; + } + + constexpr vec1 reoriented_shape_function_curl(vec1 xi, uint32_t i, int8_t transformation) const { + if (transformation == -1) { + return -shape_function_curl(xi, i); + } else { + return shape_function_curl(xi, i); + } + } + + constexpr vec<1> shape_function_derivative(vec<1> xi, uint32_t i) { + return shape_function_curl(xi, i); + } + + __host__ __device__ uint32_t batch_interpolation_scratch_space(nd::view xi) const { + return 0; + } + + nd::array< double, 2 > evaluate_shape_functions(nd::view xi) { + uint32_t nnodes = num_nodes(); + uint32_t q = xi.shape[0]; + nd::array shape_fns({q, num_nodes()}); + for (uint32_t i = 0; i < q; i++) { + vec1 xi_i = xi(i, 0); + for (uint32_t j = 0; j < nnodes; j++) { + shape_fns(i, j) = shape_function(xi_i, j); + } + } + return shape_fns; + } + + void interpolate(nd::view values_q, nd::view values_e, nd::view shape_fns, double * /*buffer*/) { + int nnodes = num_nodes(); + int nqpts = values_q.shape[0]; + + for (int q = 0; q < nqpts; q++) { + double sum = 0.0; + for (int i = 0; i < nnodes; i++) { + sum += shape_fns(q, i) * values_e(i); + } + values_q(q) = sum; + } + } + + nd::array< double > evaluate_shape_function_curls(nd::view xi) { + uint32_t q = xi.shape[0]; + nd::array buffer({q * p}); + for (int i = 0; i < q; i++) { + GaussLegendreInterpolation(xi(i, 0), p, &buffer(p * i)); + } + return buffer; + } + + void curl(nd::view values_q, nd::view values_e, nd::view buffer, double * /*buffer*/) { + #if 0 + uint32_t n = p + 1; + uint32_t q = sqrt(values_q.shape[0]); + + // 1D shape function evaluations + nd::view B1(buffer.data(), {q, p}); // legendre shape functions + nd::view B2(B1.end(), {q, n}); // lobatto shape functions + nd::view G2(B2.end(), {q, n}); // lobatto shape function derivatives + nd::view A1(G2.end(), {q, n}); // storage for intermediates + + nd::view ue(values_e.data(), {n, p}); + nd::view uq(values_q.data(), {q, q}, {2*q, 2u}); + + _contract(A1, B1, ue); // A1(qx, iy) = sum_{ix} B1(qx, ix) * ue(iy, ix) + _contract(uq, B2, A1); // uq(qy, qx) = sum_{iy} B2(qy, iy) * A1(qx, iy) + + ue = nd::view< const double, 2 >(values_e.data() + (n * p), {n, p}); + + // note: column-major strides here, since quadrature points + // are still enumerated lexicographically as {y, x} but y-component nodes are {x, y} + uq = nd::view(values_q.data() + 1, {q, q}, {2u, 2*q}); + + _contract(A1, B1, ue); // A1(qx, iy) = sum_{ix} B1(qx, ix) * ue(iy, ix) + _contract(uq, B2, A1); // uq(qy, qx) = sum_{iy} B2(qy, iy) * A1(qx, iy) + #endif + } + + nd::array< double, 2 > evaluate_weighted_shape_functions(nd::view xi, nd::view weights) { + uint32_t q = xi.shape[0]; + nd::array shape_fns({q, num_nodes()}); + for (int i = 0; i < q; i++) { + for (int j = 0; j < num_nodes(); j++) { + shape_fns(i, j) = shape_function(xi(i, 0), j) * weights(i); + } + } + return shape_fns; + } + + __host__ __device__ void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fn, double * /*buffer*/) const { + int nnodes = num_nodes(); + int nqpts = source_q.shape[0]; + + for (int i = 0; i < nnodes; i++) { + double sum = 0.0; + for (int q = 0; q < nqpts; q++) { + sum += shape_fn(q, i) * source_q(q); + } + residual_e(i) = sum; + } + } + + nd::array< double, 2 > evaluate_weighted_shape_function_curls(nd::view xi, nd::view weights) { + uint32_t q = xi.shape[0]; + nd::array shape_fns({q, num_nodes()}); + for (int i = 0; i < q; i++) { + for (int j = 0; j < num_nodes(); j++) { + shape_fns(i, j) = shape_function_curl(xi(i, 0), j) * weights(i); + } + } + return shape_fns; + } + + __host__ __device__ void integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fn, double * /*buffer*/) const { + int nnodes = num_nodes(); + int nqpts = flux_q.shape[0]; + + for (int i = 0; i < nnodes; i++) { + double sum = 0.0; + for (int q = 0; q < nqpts; q++) { + sum += shape_fn(q, i) * flux_q(q); + } + residual_e(i) = sum; + } + } + + #ifdef __CUDACC__ + __device__ void cuda_integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fn_curl, double * /*buffer*/) const { + int nnodes = num_nodes(); + int nqpts = flux_q.shape[0]; + + for (int i = threadIdx.x; i < nnodes; i += blockDim.x) { + double sum = 0.0; + for (int q = 0; q < nqpts; q++) { + sum += shape_fn_curl(q, i) * flux_q(q); + } + residual_e(i) = sum; + } + } + #endif + + uint32_t p; + +}; + +} // namespace refactor diff --git a/src/serac/numerics/refactor/elements/hcurl_hexahedron.hpp b/src/serac/numerics/refactor/elements/hcurl_hexahedron.hpp new file mode 100644 index 0000000000..23e78ac2c3 --- /dev/null +++ b/src/serac/numerics/refactor/elements/hcurl_hexahedron.hpp @@ -0,0 +1,1061 @@ +#pragma once + +#include "fm/types/vec.hpp" + +namespace refactor { + +// clang-format off +template <> +struct FiniteElement { + + using value_type = vec3; + using derivative_type = vec3; + + using source_type = vec3; + using flux_type = vec3; + + static constexpr int dim = 3; + + // clang-format off + __host__ __device__ uint8_t const * lexicographic_permutations(int p) { + static constexpr uint8_t linear_lexicographic_permutation[12] = {0,5,1,4,8,9,11,10,2,7,3,6}; + static constexpr uint8_t quadratic_lexicographic_permutation[54] = {0,1,20,23,4,5,18,21,36,45,38,47,44,53,42,51,12,13,32,35,16,17,30,33,3,2,19,22,6,7,37,46,26,29,41,50,11,10,43,52,27,24,39,48,14,15,31,34,8,9,25,28,40,49}; + static constexpr uint8_t cubic_lexicographic_permutation[144] = {0,1,2,51,55,59,9,10,11,48,52,56,96,112,128,99,115,131,111,127,143,108,124,140,36,37,38,87,91,95,45,46,47,84,88,92,5,4,3,8,7,6,50,54,58,49,53,57,12,13,14,24,25,26,97,113,129,98,114,130,63,67,71,75,79,83,103,119,135,107,123,139,23,22,21,35,34,33,110,126,142,109,125,141,68,64,60,80,76,72,104,120,136,100,116,132,39,40,41,42,43,44,85,89,93,86,90,94,15,16,17,18,19,20,27,28,29,30,31,32,61,62,65,66,69,70,73,74,77,78,81,82,101,102,105,106,117,118,121,122,133,134,137,138}; + static constexpr uint8_t const * permutations[4] = {nullptr, linear_lexicographic_permutation, quadratic_lexicographic_permutation, cubic_lexicographic_permutation }; + return permutations[p]; + } + // clang-format on + + __host__ __device__ uint32_t num_nodes() const { return 3 * p * (p + 1) * (p + 1); } + + void nodes(nd::view< double, 2 > xi) const { + + double a[3]; + GaussLegendreNodes(p, a); + + double b[4]; + GaussLobattoNodes(p+1, b); + + int count = 0; + for (int k = 0; k < p+1; k++) { + for (int j = 0; j < p+1; j++) { + for (int i = 0; i < p; i++) { + xi(count, 0) = a[i]; xi(count, 1) = b[j]; xi(count, 2) = b[k]; + count++; + } + } + } + + for (int k = 0; k < p+1; k++) { + for (int j = 0; j < p; j++) { + for (int i = 0; i < p+1; i++) { + xi(count, 0) = b[i]; xi(count, 1) = a[j]; xi(count, 2) = b[k]; + count++; + } + } + } + + for (int k = 0; k < p; k++) { + for (int j = 0; j < p+1; j++) { + for (int i = 0; i < p+1; i++) { + xi(count, 0) = b[i]; xi(count, 1) = b[j]; xi(count, 2) = a[k]; + count++; + } + } + } + + } + + void directions(nd::view d) const { + int i = 0; + for (int k = 0; k < (p * (p + 1) * (p + 1)); k++) { + d(i, 0) = 1.0; d(i, 1) = 0.0; d(i, 2) = 0.0; + i++; + } + for (int k = 0; k < (p * (p + 1) * (p + 1)); k++) { + d(i, 0) = 0.0; d(i, 1) = 1.0; d(i, 2) = 0.0; + i++; + } + for (int k = 0; k < (p * (p + 1) * (p + 1)); k++) { + d(i, 0) = 0.0; d(i, 1) = 0.0; d(i, 2) = 1.0; + i++; + } + } + + __host__ __device__ uint32_t num_interior_nodes() const { return 3 * p * (p - 1) * (p - 1); } + + void interior_nodes(nd::view< double, 2 > xi) const { + + double a[3]; + GaussLegendreNodes(p, a); + + double b[4]; + GaussLobattoNodes(p+1, b); + + int count = 0; + for (int k = 1; k < p; k++) { + for (int j = 1; j < p; j++) { + for (int i = 0; i < p; i++) { + xi(count, 0) = a[i]; xi(count, 1) = b[j]; xi(count, 2) = b[k]; + count++; + } + } + } + + for (int k = 1; k < p; k++) { + for (int j = 0; j < p; j++) { + for (int i = 1; i < p; i++) { + xi(count, 0) = b[i]; xi(count, 1) = a[j]; xi(count, 2) = b[k]; + count++; + } + } + } + + for (int k = 0; k < p; k++) { + for (int j = 1; j < p; j++) { + for (int i = 1; i < p; i++) { + xi(count, 0) = b[i]; xi(count, 1) = b[j]; xi(count, 2) = a[k]; + count++; + } + } + } + + } + + void interior_directions(nd::view d) { + int i = 0; + for (int k = 0; k < (p * (p - 1) * (p - 1)); k++) { + d(i, 0) = 1.0; d(i, 1) = 0.0; d(i, 2) = 0.0; + i++; + } + for (int k = 0; k < (p * (p - 1) * (p - 1)); k++) { + d(i, 0) = 0.0; d(i, 1) = 1.0; d(i, 2) = 0.0; + i++; + } + for (int k = 0; k < (p * (p - 1) * (p - 1)); k++) { + d(i, 0) = 0.0; d(i, 1) = 0.0; d(i, 2) = 1.0; + i++; + } + } + + struct QuadrilateralStrides { + int32_t x_offset; int32_t x_jstride; int32_t x_kstride; + int32_t y_offset; int32_t y_jstride; int32_t y_kstride; + }; + + __host__ __device__ QuadrilateralStrides quad_strides(Connection c, uint32_t offset) { + + uint8_t o = c.orientation(); + int32_t P = p; + int32_t base = offset + c.index * 2 * p * (p - 1); + if (c.sign() == Sign::Positive) { + if (o == 0) return {base + 0, 1, P, base + P*(P-1), 1, P}; + if (o == 1) return {base + P*P-1, -1, P, base + P*(P-2), 1, -P}; + if (o == 2) return {base + P*P-P-1, -1, -P, base + 2*P*(P-1)-1, -1, -P}; + if (o == 3) return {base + P*(2*P-3), 1, -P, base + P-1, -1, P}; + } else { + if (o == 0) return {base + P*(P-1), 1, P, base + 0, 1, P}; + if (o == 1) return {base + P-1, -1, P, base + P*(2*P - 3), 1, -P}; + if (o == 2) return {base + 2*P*(P-1)-1, -1, -P, base + P*P-P-1, -1, -P}; + if (o == 3) return {base + P*(P-2), 1, -P, base + P*P-1, -1, P}; + } + return {}; + + } + + __host__ __device__ void indices(const GeometryInfo & offsets, const Connection * hex, uint32_t * ids) { + + const Connection * edge = hex + Hexahedron::edge_offset; + const Connection * quad = hex + Hexahedron::quad_offset; + const Connection cell = *(hex + Hexahedron::cell_offset); + + uint8_t const * permutation = lexicographic_permutations(p); + + uint32_t count = 0; + + // edge nodes + for (uint32_t i = 0; i < Hexahedron::num_edges; i++) { + bool s = (edge[i].sign() == Sign::Positive); + int32_t stride = s ? 1 : -1; + uint32_t offset = offsets.edge + p * edge[i].index + (s ? 0 : p-1); + for (uint32_t j = 0; j < p; j++) { + ids[permutation[count++]] = offset + j * stride; + } + } + + if (p == 1) return; + + // face nodes + for (uint32_t i = 0; i < Hexahedron::num_quadrilaterals; i++) { + auto [x_offset, x_jstride, x_kstride, y_offset, y_jstride, y_kstride] = quad_strides(quad[i], offsets.quad); + for (uint32_t k = 0; k < p - 1; k++) { + for (uint32_t j = 0; j < p; j++) { + ids[permutation[count++]] = x_offset + j * x_jstride + k * x_kstride; + } + } + + for (uint32_t k = 0; k < p - 1; k++) { + for (uint32_t j = 0; j < p; j++) { + ids[permutation[count++]] = y_offset + j * y_jstride + k * y_kstride; + } + } + } + + // interior nodes + uint32_t num_interior = num_interior_nodes(); + uint32_t offset = offsets.hex + num_interior * cell.index; + for (uint32_t i = 0; i < num_interior; i++) { + ids[permutation[count++]] = offset + i; + } + + } + + template < typename T > + __host__ __device__ void reorient(const TransformationType type, const Connection * hex, T * values) { + + const Connection * edge = hex + Hexahedron::edge_offset; + const Connection * quad = hex + Hexahedron::quad_offset; + + uint8_t const * permutation = lexicographic_permutations(p); + + uint32_t count = 0; + + // edge nodes + for (uint32_t i = 0; i < Hexahedron::num_edges; i++) { + if (edge[i].sign() == Sign::Negative) { + for (uint32_t j = 0; j < p; j++) { + values[permutation[count++]] *= -1; + } + } else { + count += p; + } + } + + if (p == 1) return; + + // face nodes + for (uint32_t i = 0; i < Hexahedron::num_quadrilaterals; i++) { + + uint32_t s = quad[i].sign() == Sign::Positive; + uint32_t o = quad[i].orientation(); + + constexpr bool negate_x[2][4] = {{0, 1, 1, 0}, {0, 0, 0, 0}}; + // note: the canonical face orientations for the hexahedron were + // chosen such that nedelec basis functions on faces 0, 3, 4 + // are flipped in only the local "x" direction + if (negate_x[s][o] ^ (i == 0 || i == 3 || i == 4)) { + for (uint32_t k = 0; k < p * (p - 1); k++) { + values[permutation[count++]] *= -1; + } + } else { + count += p * (p - 1); + } + + constexpr bool negate_y[2][4] = {{0, 0, 1, 1}, {0, 0, 0, 0}}; + if (negate_y[s][o]) { + for (uint32_t k = 0; k < p * (p - 1); k++) { + values[permutation[count++]] *= -1; + } + } else { + count += p * (p - 1); + } + + } + + } + + __host__ __device__ void reorient(const TransformationType type, const Connection * hex, int8_t * transformation) { + + const Connection * edge = hex + Hexahedron::edge_offset; + const Connection * quad = hex + Hexahedron::quad_offset; + + uint8_t const * permutation = lexicographic_permutations(p); + + uint32_t count = 0; + + // edge nodes + for (uint32_t i = 0; i < Hexahedron::num_edges; i++) { + if (edge[i].sign() == Sign::Negative) { + for (uint32_t j = 0; j < p; j++) { + transformation[permutation[count++]] = -1; + } + } else { + for (uint32_t j = 0; j < p; j++) { + transformation[permutation[count++]] = 0; + } + } + } + + if (p == 1) return; + + // face nodes + for (uint32_t i = 0; i < Hexahedron::num_quadrilaterals; i++) { + + uint32_t s = quad[i].sign() == Sign::Positive; + uint32_t o = quad[i].orientation(); + + constexpr bool negate_x[2][4] = {{0, 1, 1, 0}, {0, 0, 0, 0}}; + // note: the canonical face orientations for the hexahedron were + // chosen such that nedelec basis functions on faces 0, 3, 4 + // are flipped in only the local "x" direction + if (negate_x[s][o] ^ (i == 0 || i == 3 || i == 4)) { + for (uint32_t k = 0; k < p * (p - 1); k++) { + transformation[permutation[count++]] = -1; + } + } else { + for (uint32_t k = 0; k < p * (p - 1); k++) { + transformation[permutation[count++]] = 0; + } + } + + constexpr bool negate_y[2][4] = {{0, 0, 1, 1}, {0, 0, 0, 0}}; + if (negate_y[s][o]) { + for (uint32_t k = 0; k < p * (p - 1); k++) { + transformation[permutation[count++]] = -1; + } + } else { + for (uint32_t k = 0; k < p * (p - 1); k++) { + transformation[permutation[count++]] = 0; + } + } + + } + + // all remaining (interior) nodes are always positive + uint32_t nnodes = num_nodes(); + for (uint32_t i = count; i < nnodes; i++) { + transformation[permutation[i]] = 0; + } + + } + + constexpr vec3 shape_function(vec3 xi, uint32_t i) const { + if (p == 1) { + if (i == 0) { return vec3{(-1 + xi[1])*(-1 + xi[2]),0,0}; } + if (i == 1) { return vec3{xi[1] - xi[1]*xi[2],0,0}; } + if (i == 2) { return vec3{xi[2] - xi[1]*xi[2],0,0}; } + if (i == 3) { return vec3{xi[1]*xi[2],0,0}; } + if (i == 4) { return vec3{0,(-1 + xi[0])*(-1 + xi[2]),0}; } + if (i == 5) { return vec3{0,xi[0] - xi[0]*xi[2],0}; } + if (i == 6) { return vec3{0,xi[2] - xi[0]*xi[2],0}; } + if (i == 7) { return vec3{0,xi[0]*xi[2],0}; } + if (i == 8) { return vec3{0,0,(-1 + xi[0])*(-1 + xi[1])}; } + if (i == 9) { return vec3{0,0,xi[0] - xi[0]*xi[1]}; } + if (i == 10) { return vec3{0,0,xi[1] - xi[0]*xi[1]}; } + if (i == 11) { return vec3{0,0,xi[0]*xi[1]}; } + } + if (p == 2) { + if (i == 0) { return vec3{-1.7320508075688772935274463415*(-0.7886751345948128822545743902 + xi[0])*(-1 + xi[1])*(-1 + 2*xi[1])*(-1 + xi[2])*(-1 + 2*xi[2]),0,0}; } + if (i == 1) { return vec3{(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[0])*(-1 + xi[1])*(-1 + 2*xi[1])*(-1 + xi[2])*(-1 + 2*xi[2]),0,0}; } + if (i == 2) { return vec3{6.928203230275509174109785366*(-0.7886751345948128822545743902 + xi[0])*(-1 + xi[1])*xi[1]*(-1 + xi[2])*(-1 + 2*xi[2]),0,0}; } + if (i == 3) { return vec3{-4*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[0])*(-1 + xi[1])*xi[1]*(-1 + xi[2])*(-1 + 2*xi[2]),0,0}; } + if (i == 4) { return vec3{-1.7320508075688772935274463415*(-0.7886751345948128822545743902 + xi[0])*xi[1]*(-1 + 2*xi[1])*(-1 + xi[2])*(-1 + 2*xi[2]),0,0}; } + if (i == 5) { return vec3{(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[0])*xi[1]*(-1 + 2*xi[1])*(-1 + xi[2])*(-1 + 2*xi[2]),0,0}; } + if (i == 6) { return vec3{6.928203230275509174109785366*(-0.7886751345948128822545743902 + xi[0])*(-1 + xi[1])*(-1 + 2*xi[1])*(-1 + xi[2])*xi[2],0,0}; } + if (i == 7) { return vec3{-4*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[0])*(-1 + xi[1])*(-1 + 2*xi[1])*(-1 + xi[2])*xi[2],0,0}; } + if (i == 8) { return vec3{-27.712812921102036696439141464*(-0.7886751345948128822545743902 + xi[0])*(-1. + xi[1])*xi[1]*(-1. + xi[2])*xi[2],0,0}; } + if (i == 9) { return vec3{27.712812921102036696439141*(-0.21132486540518711774542561 + 1.*xi[0])*(-1. + xi[1])*xi[1]*(-1. + xi[2])*xi[2],0,0}; } + if (i == 10) { return vec3{6.928203230275509174109785366*(-0.7886751345948128822545743902 + xi[0])*xi[1]*(-1 + 2*xi[1])*(-1 + xi[2])*xi[2],0,0}; } + if (i == 11) { return vec3{-4*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[0])*xi[1]*(-1 + 2*xi[1])*(-1 + xi[2])*xi[2],0,0}; } + if (i == 12) { return vec3{-1.7320508075688772935274463415*(-0.7886751345948128822545743902 + xi[0])*(-1 + xi[1])*(-1 + 2*xi[1])*xi[2]*(-1 + 2*xi[2]),0,0}; } + if (i == 13) { return vec3{(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[0])*(-1 + xi[1])*(-1 + 2*xi[1])*xi[2]*(-1 + 2*xi[2]),0,0}; } + if (i == 14) { return vec3{6.928203230275509174109785366*(-0.7886751345948128822545743902 + xi[0])*(-1 + xi[1])*xi[1]*xi[2]*(-1 + 2*xi[2]),0,0}; } + if (i == 15) { return vec3{-4*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[0])*(-1 + xi[1])*xi[1]*xi[2]*(-1 + 2*xi[2]),0,0}; } + if (i == 16) { return vec3{-1.7320508075688772935274463415*(-0.7886751345948128822545743902 + xi[0])*xi[1]*(-1 + 2*xi[1])*xi[2]*(-1 + 2*xi[2]),0,0}; } + if (i == 17) { return vec3{(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[0])*xi[1]*(-1 + 2*xi[1])*xi[2]*(-1 + 2*xi[2]),0,0}; } + if (i == 18) { return vec3{0,-1.7320508075688772935274463415*(-1 + xi[0])*(-1 + 2*xi[0])*(-0.7886751345948128822545743902 + xi[1])*(-1 + xi[2])*(-1 + 2*xi[2]),0}; } + if (i == 19) { return vec3{0,6.928203230275509174109785366*(-1 + xi[0])*xi[0]*(-0.7886751345948128822545743902 + xi[1])*(-1 + xi[2])*(-1 + 2*xi[2]),0}; } + if (i == 20) { return vec3{0,-1.7320508075688772935274463415*xi[0]*(-1 + 2*xi[0])*(-0.7886751345948128822545743902 + xi[1])*(-1 + xi[2])*(-1 + 2*xi[2]),0}; } + if (i == 21) { return vec3{0,(-1 + xi[0])*(-1 + 2*xi[0])*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[1])*(-1 + xi[2])*(-1 + 2*xi[2]),0}; } + if (i == 22) { return vec3{0,-4*(-1 + xi[0])*xi[0]*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[1])*(-1 + xi[2])*(-1 + 2*xi[2]),0}; } + if (i == 23) { return vec3{0,xi[0]*(-1 + 2*xi[0])*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[1])*(-1 + xi[2])*(-1 + 2*xi[2]),0}; } + if (i == 24) { return vec3{0,6.928203230275509174109785366*(-1 + xi[0])*(-1 + 2*xi[0])*(-0.7886751345948128822545743902 + xi[1])*(-1 + xi[2])*xi[2],0}; } + if (i == 25) { return vec3{0,-27.712812921102036696439141464*(-1. + xi[0])*xi[0]*(-0.7886751345948128822545743902 + xi[1])*(-1. + xi[2])*xi[2],0}; } + if (i == 26) { return vec3{0,6.928203230275509174109785366*xi[0]*(-1 + 2*xi[0])*(-0.7886751345948128822545743902 + xi[1])*(-1 + xi[2])*xi[2],0}; } + if (i == 27) { return vec3{0,-4*(-1 + xi[0])*(-1 + 2*xi[0])*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[1])*(-1 + xi[2])*xi[2],0}; } + if (i == 28) { return vec3{0,27.7128129211020366964391415*(-1. + xi[0])*xi[0]*(-0.21132486540518711774542561 + 1.*xi[1])*(-1. + xi[2])*xi[2],0}; } + if (i == 29) { return vec3{0,-4*xi[0]*(-1 + 2*xi[0])*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[1])*(-1 + xi[2])*xi[2],0}; } + if (i == 30) { return vec3{0,-1.7320508075688772935274463415*(-1 + xi[0])*(-1 + 2*xi[0])*(-0.7886751345948128822545743902 + xi[1])*xi[2]*(-1 + 2*xi[2]),0}; } + if (i == 31) { return vec3{0,6.928203230275509174109785366*(-1 + xi[0])*xi[0]*(-0.7886751345948128822545743902 + xi[1])*xi[2]*(-1 + 2*xi[2]),0}; } + if (i == 32) { return vec3{0,-1.7320508075688772935274463415*xi[0]*(-1 + 2*xi[0])*(-0.7886751345948128822545743902 + xi[1])*xi[2]*(-1 + 2*xi[2]),0}; } + if (i == 33) { return vec3{0,(-1 + xi[0])*(-1 + 2*xi[0])*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[1])*xi[2]*(-1 + 2*xi[2]),0}; } + if (i == 34) { return vec3{0,-4*(-1 + xi[0])*xi[0]*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[1])*xi[2]*(-1 + 2*xi[2]),0}; } + if (i == 35) { return vec3{0,xi[0]*(-1 + 2*xi[0])*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[1])*xi[2]*(-1 + 2*xi[2]),0}; } + if (i == 36) { return vec3{0,0,-1.7320508075688772935274463415*(-1 + xi[0])*(-1 + 2*xi[0])*(-1 + xi[1])*(-1 + 2*xi[1])*(-0.7886751345948128822545743902 + xi[2])}; } + if (i == 37) { return vec3{0,0,6.928203230275509174109785366*(-1 + xi[0])*xi[0]*(-1 + xi[1])*(-1 + 2*xi[1])*(-0.7886751345948128822545743902 + xi[2])}; } + if (i == 38) { return vec3{0,0,-1.7320508075688772935274463415*xi[0]*(-1 + 2*xi[0])*(-1 + xi[1])*(-1 + 2*xi[1])*(-0.7886751345948128822545743902 + xi[2])}; } + if (i == 39) { return vec3{0,0,6.928203230275509174109785366*(-1 + xi[0])*(-1 + 2*xi[0])*(-1 + xi[1])*xi[1]*(-0.7886751345948128822545743902 + xi[2])}; } + if (i == 40) { return vec3{0,0,-27.712812921102036696439141464*(-1. + xi[0])*xi[0]*(-1. + xi[1])*xi[1]*(-0.7886751345948128822545743902 + xi[2])}; } + if (i == 41) { return vec3{0,0,6.928203230275509174109785366*xi[0]*(-1 + 2*xi[0])*(-1 + xi[1])*xi[1]*(-0.7886751345948128822545743902 + xi[2])}; } + if (i == 42) { return vec3{0,0,-1.7320508075688772935274463415*(-1 + xi[0])*(-1 + 2*xi[0])*xi[1]*(-1 + 2*xi[1])*(-0.7886751345948128822545743902 + xi[2])}; } + if (i == 43) { return vec3{0,0,6.928203230275509174109785366*(-1 + xi[0])*xi[0]*xi[1]*(-1 + 2*xi[1])*(-0.7886751345948128822545743902 + xi[2])}; } + if (i == 44) { return vec3{0,0,-1.7320508075688772935274463415*xi[0]*(-1 + 2*xi[0])*xi[1]*(-1 + 2*xi[1])*(-0.7886751345948128822545743902 + xi[2])}; } + if (i == 45) { return vec3{0,0,(-1 + xi[0])*(-1 + 2*xi[0])*(-1 + xi[1])*(-1 + 2*xi[1])*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[2])}; } + if (i == 46) { return vec3{0,0,-4*(-1 + xi[0])*xi[0]*(-1 + xi[1])*(-1 + 2*xi[1])*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[2])}; } + if (i == 47) { return vec3{0,0,xi[0]*(-1 + 2*xi[0])*(-1 + xi[1])*(-1 + 2*xi[1])*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[2])}; } + if (i == 48) { return vec3{0,0,-4*(-1 + xi[0])*(-1 + 2*xi[0])*(-1 + xi[1])*xi[1]*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[2])}; } + if (i == 49) { return vec3{0,0,27.71281292110203669643914146*(-1. + xi[0])*xi[0]*(-1. + xi[1])*xi[1]*(-0.2113248654051871177454256098 + 1.*xi[2])}; } + if (i == 50) { return vec3{0,0,-4*xi[0]*(-1 + 2*xi[0])*(-1 + xi[1])*xi[1]*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[2])}; } + if (i == 51) { return vec3{0,0,(-1 + xi[0])*(-1 + 2*xi[0])*xi[1]*(-1 + 2*xi[1])*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[2])}; } + if (i == 52) { return vec3{0,0,-4*(-1 + xi[0])*xi[0]*xi[1]*(-1 + 2*xi[1])*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[2])}; } + if (i == 53) { return vec3{0,0,xi[0]*(-1 + 2*xi[0])*xi[1]*(-1 + 2*xi[1])*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[2])}; } + } + if (p == 3) { + if (i == 0) { return vec3{(1.4788305577012361475298776 + xi[0]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[0]))*(1 + xi[1]*(-6. + (10. - 5.*xi[1])*xi[1]))*(1 + xi[2]*(-6. + (10. - 5.*xi[2])*xi[2])),0,0}; } + if (i == 1) { return vec3{-6.66666666666666666666666667*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(1 + xi[1]*(-6. + (10. - 5.*xi[1])*xi[1]))*(1 + xi[2]*(-6. + (10. - 5.*xi[2])*xi[2])),0,0}; } + if (i == 2) { return vec3{(0.1878361089654305191367891 + xi[0]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[0]))*(1 + xi[1]*(-6. + (10. - 5.*xi[1])*xi[1]))*(1 + xi[2]*(-6. + (10. - 5.*xi[2])*xi[2])),0,0}; } + if (i == 3) { return vec3{11.180339887498948*(1.4788305577012361475298776 + xi[0]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[0]))*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(1 + xi[2]*(-6. + (10. - 5.*xi[2])*xi[2])),0,0}; } + if (i == 4) { return vec3{-74.53559924999299*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(1 + xi[2]*(-6. + (10. - 5.*xi[2])*xi[2])),0,0}; } + if (i == 5) { return vec3{11.180339887498948*(0.1878361089654305191367891 + xi[0]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[0]))*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(1 + xi[2]*(-6. + (10. - 5.*xi[2])*xi[2])),0,0}; } + if (i == 6) { return vec3{-11.180339887498948482*(1.4788305577012361475298776 + xi[0]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(1 + xi[2]*(-6. + (10. - 5.*xi[2])*xi[2])),0,0}; } + if (i == 7) { return vec3{74.53559924999298988*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(1 + xi[2]*(-6. + (10. - 5.*xi[2])*xi[2])),0,0}; } + if (i == 8) { return vec3{-11.180339887498948482*(0.1878361089654305191367891 + xi[0]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(1 + xi[2]*(-6. + (10. - 5.*xi[2])*xi[2])),0,0}; } + if (i == 9) { return vec3{(1.4788305577012361475298776 + xi[0]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[0]))*xi[1]*(1. + xi[1]*(-5. + 5.*xi[1]))*(1 + xi[2]*(-6. + (10. - 5.*xi[2])*xi[2])),0,0}; } + if (i == 10) { return vec3{-6.66666666666666666666666667*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*xi[1]*(1. + xi[1]*(-5. + 5.*xi[1]))*(1 + xi[2]*(-6. + (10. - 5.*xi[2])*xi[2])),0,0}; } + if (i == 11) { return vec3{(0.1878361089654305191367891 + xi[0]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[0]))*xi[1]*(1. + xi[1]*(-5. + 5.*xi[1]))*(1 + xi[2]*(-6. + (10. - 5.*xi[2])*xi[2])),0,0}; } + if (i == 12) { return vec3{11.180339887498948*(1.4788305577012361475298776 + xi[0]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[0]))*(1 + xi[1]*(-6. + (10. - 5.*xi[1])*xi[1]))*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2]),0,0}; } + if (i == 13) { return vec3{-74.53559924999299*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(1 + xi[1]*(-6. + (10. - 5.*xi[1])*xi[1]))*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2]),0,0}; } + if (i == 14) { return vec3{11.180339887498948*(0.1878361089654305191367891 + xi[0]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[0]))*(1 + xi[1]*(-6. + (10. - 5.*xi[1])*xi[1]))*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2]),0,0}; } + if (i == 15) { return vec3{125.*(1.4788305577012361475298776 + xi[0]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[0]))*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2]),0,0}; } + if (i == 16) { return vec3{-833.3333333333333*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2]),0,0}; } + if (i == 17) { return vec3{125.*(0.1878361089654305191367891 + xi[0]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[0]))*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2]),0,0}; } + if (i == 18) { return vec3{-125.*(1.4788305577012361475298776 + xi[0]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2]),0,0}; } + if (i == 19) { return vec3{833.3333333333333*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2]),0,0}; } + if (i == 20) { return vec3{-125.*(0.1878361089654305191367891 + xi[0]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2]),0,0}; } + if (i == 21) { return vec3{11.180339887498948*(1.4788305577012361475298776 + xi[0]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[0]))*xi[1]*(1. + xi[1]*(-5. + 5.*xi[1]))*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2]),0,0}; } + if (i == 22) { return vec3{-74.53559924999299*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*xi[1]*(1. + xi[1]*(-5. + 5.*xi[1]))*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2]),0,0}; } + if (i == 23) { return vec3{11.180339887498948*(0.1878361089654305191367891 + xi[0]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[0]))*xi[1]*(1. + xi[1]*(-5. + 5.*xi[1]))*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2]),0,0}; } + if (i == 24) { return vec3{-11.180339887498948482*(1.4788305577012361475298776 + xi[0]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[0]))*(1 + xi[1]*(-6. + (10. - 5.*xi[1])*xi[1]))*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2],0,0}; } + if (i == 25) { return vec3{74.53559924999298988*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(1 + xi[1]*(-6. + (10. - 5.*xi[1])*xi[1]))*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2],0,0}; } + if (i == 26) { return vec3{-11.180339887498948482*(0.1878361089654305191367891 + xi[0]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[0]))*(1 + xi[1]*(-6. + (10. - 5.*xi[1])*xi[1]))*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2],0,0}; } + if (i == 27) { return vec3{-125.*(1.4788305577012361475298776 + xi[0]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[0]))*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2],0,0}; } + if (i == 28) { return vec3{833.3333333333333*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2],0,0}; } + if (i == 29) { return vec3{-125.*(0.1878361089654305191367891 + xi[0]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[0]))*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2],0,0}; } + if (i == 30) { return vec3{125.*(1.4788305577012361475298776 + xi[0]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2],0,0}; } + if (i == 31) { return vec3{-833.3333333333333333*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2],0,0}; } + if (i == 32) { return vec3{125.*(0.1878361089654305191367891 + xi[0]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2],0,0}; } + if (i == 33) { return vec3{-11.180339887498948482*(1.4788305577012361475298776 + xi[0]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[0]))*xi[1]*(1. + xi[1]*(-5. + 5.*xi[1]))*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2],0,0}; } + if (i == 34) { return vec3{74.53559924999298988*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*xi[1]*(1. + xi[1]*(-5. + 5.*xi[1]))*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2],0,0}; } + if (i == 35) { return vec3{-11.180339887498948482*(0.1878361089654305191367891 + xi[0]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[0]))*xi[1]*(1. + xi[1]*(-5. + 5.*xi[1]))*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2],0,0}; } + if (i == 36) { return vec3{(1.4788305577012361475298776 + xi[0]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[0]))*(1 + xi[1]*(-6. + (10. - 5.*xi[1])*xi[1]))*xi[2]*(1. + xi[2]*(-5. + 5.*xi[2])),0,0}; } + if (i == 37) { return vec3{-6.66666666666666666666666667*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(1 + xi[1]*(-6. + (10. - 5.*xi[1])*xi[1]))*xi[2]*(1. + xi[2]*(-5. + 5.*xi[2])),0,0}; } + if (i == 38) { return vec3{(0.1878361089654305191367891 + xi[0]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[0]))*(1 + xi[1]*(-6. + (10. - 5.*xi[1])*xi[1]))*xi[2]*(1. + xi[2]*(-5. + 5.*xi[2])),0,0}; } + if (i == 39) { return vec3{11.180339887498948*(1.4788305577012361475298776 + xi[0]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[0]))*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*xi[2]*(1. + xi[2]*(-5. + 5.*xi[2])),0,0}; } + if (i == 40) { return vec3{-74.53559924999299*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*xi[2]*(1. + xi[2]*(-5. + 5.*xi[2])),0,0}; } + if (i == 41) { return vec3{11.180339887498948*(0.1878361089654305191367891 + xi[0]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[0]))*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*xi[2]*(1. + xi[2]*(-5. + 5.*xi[2])),0,0}; } + if (i == 42) { return vec3{-11.180339887498948482*(1.4788305577012361475298776 + xi[0]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*xi[2]*(1. + xi[2]*(-5. + 5.*xi[2])),0,0}; } + if (i == 43) { return vec3{74.53559924999298988*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*xi[2]*(1. + xi[2]*(-5. + 5.*xi[2])),0,0}; } + if (i == 44) { return vec3{-11.180339887498948482*(0.1878361089654305191367891 + xi[0]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*xi[2]*(1. + xi[2]*(-5. + 5.*xi[2])),0,0}; } + if (i == 45) { return vec3{(1.4788305577012361475298776 + xi[0]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[0]))*xi[1]*(1. + xi[1]*(-5. + 5.*xi[1]))*xi[2]*(1. + xi[2]*(-5. + 5.*xi[2])),0,0}; } + if (i == 46) { return vec3{-6.66666666666666666666666667*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*xi[1]*(1. + xi[1]*(-5. + 5.*xi[1]))*xi[2]*(1. + xi[2]*(-5. + 5.*xi[2])),0,0}; } + if (i == 47) { return vec3{(0.1878361089654305191367891 + xi[0]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[0]))*xi[1]*(1. + xi[1]*(-5. + 5.*xi[1]))*xi[2]*(1. + xi[2]*(-5. + 5.*xi[2])),0,0}; } + if (i == 48) { return vec3{0,(1 + xi[0]*(-6. + (10. - 5.*xi[0])*xi[0]))*(1.4788305577012361475298776 + xi[1]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[1]))*(1 + xi[2]*(-6. + (10. - 5.*xi[2])*xi[2])),0}; } + if (i == 49) { return vec3{0,11.180339887498948*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(1.4788305577012361475298776 + xi[1]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[1]))*(1 + xi[2]*(-6. + (10. - 5.*xi[2])*xi[2])),0}; } + if (i == 50) { return vec3{0,-11.180339887498948482*(-1. + xi[0])*(-0.2763932022500210304 + xi[0])*xi[0]*(1.4788305577012361475298776 + xi[1]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[1]))*(1 + xi[2]*(-6. + (10. - 5.*xi[2])*xi[2])),0}; } + if (i == 51) { return vec3{0,xi[0]*(1. + xi[0]*(-5. + 5.*xi[0]))*(1.4788305577012361475298776 + xi[1]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[1]))*(1 + xi[2]*(-6. + (10. - 5.*xi[2])*xi[2])),0}; } + if (i == 52) { return vec3{0,-6.66666666666666666666666667*(1 + xi[0]*(-6. + (10. - 5.*xi[0])*xi[0]))*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831148207346 + xi[1])*(1 + xi[2]*(-6. + (10. - 5.*xi[2])*xi[2])),0}; } + if (i == 53) { return vec3{0,-74.53559924999299*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831148207346 + xi[1])*(1 + xi[2]*(-6. + (10. - 5.*xi[2])*xi[2])),0}; } + if (i == 54) { return vec3{0,74.53559924999298988*(-1. + xi[0])*(-0.2763932022500210304 + xi[0])*xi[0]*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831148207346 + xi[1])*(1 + xi[2]*(-6. + (10. - 5.*xi[2])*xi[2])),0}; } + if (i == 55) { return vec3{0,-6.66666666666666666666666667*xi[0]*(1. + xi[0]*(-5. + 5.*xi[0]))*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831148207346 + xi[1])*(1 + xi[2]*(-6. + (10. - 5.*xi[2])*xi[2])),0}; } + if (i == 56) { return vec3{0,(1 + xi[0]*(-6. + (10. - 5.*xi[0])*xi[0]))*(0.1878361089654305191367891 + xi[1]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[1]))*(1 + xi[2]*(-6. + (10. - 5.*xi[2])*xi[2])),0}; } + if (i == 57) { return vec3{0,11.180339887498948*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(0.1878361089654305191367891 + xi[1]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[1]))*(1 + xi[2]*(-6. + (10. - 5.*xi[2])*xi[2])),0}; } + if (i == 58) { return vec3{0,-11.180339887498948482*(-1. + xi[0])*(-0.2763932022500210304 + xi[0])*xi[0]*(0.1878361089654305191367891 + xi[1]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[1]))*(1 + xi[2]*(-6. + (10. - 5.*xi[2])*xi[2])),0}; } + if (i == 59) { return vec3{0,xi[0]*(1. + xi[0]*(-5. + 5.*xi[0]))*(0.1878361089654305191367891 + xi[1]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[1]))*(1 + xi[2]*(-6. + (10. - 5.*xi[2])*xi[2])),0}; } + if (i == 60) { return vec3{0,11.180339887498948*(1 + xi[0]*(-6. + (10. - 5.*xi[0])*xi[0]))*(1.4788305577012361475298776 + xi[1]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[1]))*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2]),0}; } + if (i == 61) { return vec3{0,125.*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(1.4788305577012361475298776 + xi[1]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[1]))*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2]),0}; } + if (i == 62) { return vec3{0,-125.*(-1. + xi[0])*(-0.2763932022500210304 + xi[0])*xi[0]*(1.4788305577012361475298776 + xi[1]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[1]))*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2]),0}; } + if (i == 63) { return vec3{0,11.180339887498948*xi[0]*(1. + xi[0]*(-5. + 5.*xi[0]))*(1.4788305577012361475298776 + xi[1]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[1]))*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2]),0}; } + if (i == 64) { return vec3{0,-74.53559924999299*(1 + xi[0]*(-6. + (10. - 5.*xi[0])*xi[0]))*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831148207346 + xi[1])*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2]),0}; } + if (i == 65) { return vec3{0,-833.3333333333333*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831148207346 + xi[1])*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2]),0}; } + if (i == 66) { return vec3{0,833.3333333333333*(-1. + xi[0])*(-0.2763932022500210304 + xi[0])*xi[0]*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831148207346 + xi[1])*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2]),0}; } + if (i == 67) { return vec3{0,-74.53559924999299*xi[0]*(1. + xi[0]*(-5. + 5.*xi[0]))*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831148207346 + xi[1])*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2]),0}; } + if (i == 68) { return vec3{0,11.180339887498948*(1 + xi[0]*(-6. + (10. - 5.*xi[0])*xi[0]))*(0.1878361089654305191367891 + xi[1]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[1]))*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2]),0}; } + if (i == 69) { return vec3{0,125.*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(0.1878361089654305191367891 + xi[1]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[1]))*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2]),0}; } + if (i == 70) { return vec3{0,-125.*(-1. + xi[0])*(-0.2763932022500210304 + xi[0])*xi[0]*(0.1878361089654305191367891 + xi[1]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[1]))*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2]),0}; } + if (i == 71) { return vec3{0,11.180339887498948*xi[0]*(1. + xi[0]*(-5. + 5.*xi[0]))*(0.1878361089654305191367891 + xi[1]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[1]))*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2]),0}; } + if (i == 72) { return vec3{0,-11.180339887498948482*(1 + xi[0]*(-6. + (10. - 5.*xi[0])*xi[0]))*(1.4788305577012361475298776 + xi[1]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[1]))*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2],0}; } + if (i == 73) { return vec3{0,-125.*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(1.4788305577012361475298776 + xi[1]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[1]))*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2],0}; } + if (i == 74) { return vec3{0,125.*(-1. + xi[0])*(-0.2763932022500210304 + xi[0])*xi[0]*(1.4788305577012361475298776 + xi[1]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[1]))*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2],0}; } + if (i == 75) { return vec3{0,-11.180339887498948482*xi[0]*(1. + xi[0]*(-5. + 5.*xi[0]))*(1.4788305577012361475298776 + xi[1]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[1]))*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2],0}; } + if (i == 76) { return vec3{0,74.53559924999298988*(1 + xi[0]*(-6. + (10. - 5.*xi[0])*xi[0]))*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831148207346 + xi[1])*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2],0}; } + if (i == 77) { return vec3{0,833.3333333333333*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831148207346 + xi[1])*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2],0}; } + if (i == 78) { return vec3{0,-833.3333333333333333*(-1. + xi[0])*(-0.2763932022500210304 + xi[0])*xi[0]*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831148207346 + xi[1])*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2],0}; } + if (i == 79) { return vec3{0,74.53559924999298988*xi[0]*(1. + xi[0]*(-5. + 5.*xi[0]))*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831148207346 + xi[1])*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2],0}; } + if (i == 80) { return vec3{0,-11.180339887498948482*(1 + xi[0]*(-6. + (10. - 5.*xi[0])*xi[0]))*(0.1878361089654305191367891 + xi[1]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[1]))*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2],0}; } + if (i == 81) { return vec3{0,-125.*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(0.1878361089654305191367891 + xi[1]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[1]))*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2],0}; } + if (i == 82) { return vec3{0,125.*(-1. + xi[0])*(-0.2763932022500210304 + xi[0])*xi[0]*(0.1878361089654305191367891 + xi[1]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[1]))*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2],0}; } + if (i == 83) { return vec3{0,-11.180339887498948482*xi[0]*(1. + xi[0]*(-5. + 5.*xi[0]))*(0.1878361089654305191367891 + xi[1]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[1]))*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2],0}; } + if (i == 84) { return vec3{0,(1 + xi[0]*(-6. + (10. - 5.*xi[0])*xi[0]))*(1.4788305577012361475298776 + xi[1]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[1]))*xi[2]*(1. + xi[2]*(-5. + 5.*xi[2])),0}; } + if (i == 85) { return vec3{0,11.180339887498948*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(1.4788305577012361475298776 + xi[1]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[1]))*xi[2]*(1. + xi[2]*(-5. + 5.*xi[2])),0}; } + if (i == 86) { return vec3{0,-11.180339887498948482*(-1. + xi[0])*(-0.2763932022500210304 + xi[0])*xi[0]*(1.4788305577012361475298776 + xi[1]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[1]))*xi[2]*(1. + xi[2]*(-5. + 5.*xi[2])),0}; } + if (i == 87) { return vec3{0,xi[0]*(1. + xi[0]*(-5. + 5.*xi[0]))*(1.4788305577012361475298776 + xi[1]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[1]))*xi[2]*(1. + xi[2]*(-5. + 5.*xi[2])),0}; } + if (i == 88) { return vec3{0,-6.66666666666666666666666667*(1 + xi[0]*(-6. + (10. - 5.*xi[0])*xi[0]))*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831148207346 + xi[1])*xi[2]*(1. + xi[2]*(-5. + 5.*xi[2])),0}; } + if (i == 89) { return vec3{0,-74.53559924999299*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831148207346 + xi[1])*xi[2]*(1. + xi[2]*(-5. + 5.*xi[2])),0}; } + if (i == 90) { return vec3{0,74.53559924999298988*(-1. + xi[0])*(-0.2763932022500210304 + xi[0])*xi[0]*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831148207346 + xi[1])*xi[2]*(1. + xi[2]*(-5. + 5.*xi[2])),0}; } + if (i == 91) { return vec3{0,-6.66666666666666666666666667*xi[0]*(1. + xi[0]*(-5. + 5.*xi[0]))*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831148207346 + xi[1])*xi[2]*(1. + xi[2]*(-5. + 5.*xi[2])),0}; } + if (i == 92) { return vec3{0,(1 + xi[0]*(-6. + (10. - 5.*xi[0])*xi[0]))*(0.1878361089654305191367891 + xi[1]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[1]))*xi[2]*(1. + xi[2]*(-5. + 5.*xi[2])),0}; } + if (i == 93) { return vec3{0,11.180339887498948*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(0.1878361089654305191367891 + xi[1]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[1]))*xi[2]*(1. + xi[2]*(-5. + 5.*xi[2])),0}; } + if (i == 94) { return vec3{0,-11.180339887498948482*(-1. + xi[0])*(-0.2763932022500210304 + xi[0])*xi[0]*(0.1878361089654305191367891 + xi[1]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[1]))*xi[2]*(1. + xi[2]*(-5. + 5.*xi[2])),0}; } + if (i == 95) { return vec3{0,xi[0]*(1. + xi[0]*(-5. + 5.*xi[0]))*(0.1878361089654305191367891 + xi[1]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[1]))*xi[2]*(1. + xi[2]*(-5. + 5.*xi[2])),0}; } + if (i == 96) { return vec3{0,0,(1 + xi[0]*(-6. + (10. - 5.*xi[0])*xi[0]))*(1 + xi[1]*(-6. + (10. - 5.*xi[1])*xi[1]))*(1.4788305577012361475298776 + xi[2]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[2]))}; } + if (i == 97) { return vec3{0,0,11.180339887498948*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(1 + xi[1]*(-6. + (10. - 5.*xi[1])*xi[1]))*(1.4788305577012361475298776 + xi[2]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[2]))}; } + if (i == 98) { return vec3{0,0,-11.180339887498948482*(-1. + xi[0])*(-0.2763932022500210304 + xi[0])*xi[0]*(1 + xi[1]*(-6. + (10. - 5.*xi[1])*xi[1]))*(1.4788305577012361475298776 + xi[2]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[2]))}; } + if (i == 99) { return vec3{0,0,xi[0]*(1. + xi[0]*(-5. + 5.*xi[0]))*(1 + xi[1]*(-6. + (10. - 5.*xi[1])*xi[1]))*(1.4788305577012361475298776 + xi[2]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[2]))}; } + if (i == 100) { return vec3{0,0,11.180339887498948*(1 + xi[0]*(-6. + (10. - 5.*xi[0])*xi[0]))*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(1.4788305577012361475298776 + xi[2]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[2]))}; } + if (i == 101) { return vec3{0,0,125.*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(1.4788305577012361475298776 + xi[2]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[2]))}; } + if (i == 102) { return vec3{0,0,-125.*(-1. + xi[0])*(-0.2763932022500210304 + xi[0])*xi[0]*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(1.4788305577012361475298776 + xi[2]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[2]))}; } + if (i == 103) { return vec3{0,0,11.180339887498948*xi[0]*(1. + xi[0]*(-5. + 5.*xi[0]))*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(1.4788305577012361475298776 + xi[2]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[2]))}; } + if (i == 104) { return vec3{0,0,-11.180339887498948482*(1 + xi[0]*(-6. + (10. - 5.*xi[0])*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(1.4788305577012361475298776 + xi[2]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[2]))}; } + if (i == 105) { return vec3{0,0,-125.*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(1.4788305577012361475298776 + xi[2]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[2]))}; } + if (i == 106) { return vec3{0,0,125.*(-1. + xi[0])*(-0.2763932022500210304 + xi[0])*xi[0]*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(1.4788305577012361475298776 + xi[2]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[2]))}; } + if (i == 107) { return vec3{0,0,-11.180339887498948482*xi[0]*(1. + xi[0]*(-5. + 5.*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(1.4788305577012361475298776 + xi[2]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[2]))}; } + if (i == 108) { return vec3{0,0,(1 + xi[0]*(-6. + (10. - 5.*xi[0])*xi[0]))*xi[1]*(1. + xi[1]*(-5. + 5.*xi[1]))*(1.4788305577012361475298776 + xi[2]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[2]))}; } + if (i == 109) { return vec3{0,0,11.180339887498948*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*xi[1]*(1. + xi[1]*(-5. + 5.*xi[1]))*(1.4788305577012361475298776 + xi[2]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[2]))}; } + if (i == 110) { return vec3{0,0,-11.180339887498948482*(-1. + xi[0])*(-0.2763932022500210304 + xi[0])*xi[0]*xi[1]*(1. + xi[1]*(-5. + 5.*xi[1]))*(1.4788305577012361475298776 + xi[2]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[2]))}; } + if (i == 111) { return vec3{0,0,xi[0]*(1. + xi[0]*(-5. + 5.*xi[0]))*xi[1]*(1. + xi[1]*(-5. + 5.*xi[1]))*(1.4788305577012361475298776 + xi[2]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[2]))}; } + if (i == 112) { return vec3{0,0,-6.66666666666666666666666667*(1 + xi[0]*(-6. + (10. - 5.*xi[0])*xi[0]))*(1 + xi[1]*(-6. + (10. - 5.*xi[1])*xi[1]))*(-0.88729833462074168851792654 + xi[2])*(-0.11270166537925831148207346 + xi[2])}; } + if (i == 113) { return vec3{0,0,-74.53559924999299*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(1 + xi[1]*(-6. + (10. - 5.*xi[1])*xi[1]))*(-0.88729833462074168851792654 + xi[2])*(-0.11270166537925831148207346 + xi[2])}; } + if (i == 114) { return vec3{0,0,74.53559924999298988*(-1. + xi[0])*(-0.2763932022500210304 + xi[0])*xi[0]*(1 + xi[1]*(-6. + (10. - 5.*xi[1])*xi[1]))*(-0.88729833462074168851792654 + xi[2])*(-0.11270166537925831148207346 + xi[2])}; } + if (i == 115) { return vec3{0,0,-6.66666666666666666666666667*xi[0]*(1. + xi[0]*(-5. + 5.*xi[0]))*(1 + xi[1]*(-6. + (10. - 5.*xi[1])*xi[1]))*(-0.88729833462074168851792654 + xi[2])*(-0.11270166537925831148207346 + xi[2])}; } + if (i == 116) { return vec3{0,0,-74.53559924999299*(1 + xi[0]*(-6. + (10. - 5.*xi[0])*xi[0]))*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(-0.88729833462074168851792654 + xi[2])*(-0.11270166537925831148207346 + xi[2])}; } + if (i == 117) { return vec3{0,0,-833.3333333333333*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(-0.88729833462074168851792654 + xi[2])*(-0.11270166537925831148207346 + xi[2])}; } + if (i == 118) { return vec3{0,0,833.3333333333333*(-1. + xi[0])*(-0.2763932022500210304 + xi[0])*xi[0]*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(-0.88729833462074168851792654 + xi[2])*(-0.11270166537925831148207346 + xi[2])}; } + if (i == 119) { return vec3{0,0,-74.53559924999299*xi[0]*(1. + xi[0]*(-5. + 5.*xi[0]))*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(-0.88729833462074168851792654 + xi[2])*(-0.11270166537925831148207346 + xi[2])}; } + if (i == 120) { return vec3{0,0,74.53559924999298988*(1 + xi[0]*(-6. + (10. - 5.*xi[0])*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(-0.88729833462074168851792654 + xi[2])*(-0.11270166537925831148207346 + xi[2])}; } + if (i == 121) { return vec3{0,0,833.3333333333333*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(-0.88729833462074168851792654 + xi[2])*(-0.11270166537925831148207346 + xi[2])}; } + if (i == 122) { return vec3{0,0,-833.3333333333333333*(-1. + xi[0])*(-0.2763932022500210304 + xi[0])*xi[0]*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(-0.88729833462074168851792654 + xi[2])*(-0.11270166537925831148207346 + xi[2])}; } + if (i == 123) { return vec3{0,0,74.53559924999298988*xi[0]*(1. + xi[0]*(-5. + 5.*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(-0.88729833462074168851792654 + xi[2])*(-0.11270166537925831148207346 + xi[2])}; } + if (i == 124) { return vec3{0,0,-6.66666666666666666666666667*(1 + xi[0]*(-6. + (10. - 5.*xi[0])*xi[0]))*xi[1]*(1. + xi[1]*(-5. + 5.*xi[1]))*(-0.88729833462074168851792654 + xi[2])*(-0.11270166537925831148207346 + xi[2])}; } + if (i == 125) { return vec3{0,0,-74.53559924999299*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*xi[1]*(1. + xi[1]*(-5. + 5.*xi[1]))*(-0.88729833462074168851792654 + xi[2])*(-0.11270166537925831148207346 + xi[2])}; } + if (i == 126) { return vec3{0,0,74.53559924999298988*(-1. + xi[0])*(-0.2763932022500210304 + xi[0])*xi[0]*xi[1]*(1. + xi[1]*(-5. + 5.*xi[1]))*(-0.88729833462074168851792654 + xi[2])*(-0.11270166537925831148207346 + xi[2])}; } + if (i == 127) { return vec3{0,0,-6.66666666666666666666666667*xi[0]*(1. + xi[0]*(-5. + 5.*xi[0]))*xi[1]*(1. + xi[1]*(-5. + 5.*xi[1]))*(-0.88729833462074168851792654 + xi[2])*(-0.11270166537925831148207346 + xi[2])}; } + if (i == 128) { return vec3{0,0,(1 + xi[0]*(-6. + (10. - 5.*xi[0])*xi[0]))*(1 + xi[1]*(-6. + (10. - 5.*xi[1])*xi[1]))*(0.1878361089654305191367891 + xi[2]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[2]))}; } + if (i == 129) { return vec3{0,0,11.180339887498948*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(1 + xi[1]*(-6. + (10. - 5.*xi[1])*xi[1]))*(0.1878361089654305191367891 + xi[2]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[2]))}; } + if (i == 130) { return vec3{0,0,-11.180339887498948482*(-1. + xi[0])*(-0.2763932022500210304 + xi[0])*xi[0]*(1 + xi[1]*(-6. + (10. - 5.*xi[1])*xi[1]))*(0.1878361089654305191367891 + xi[2]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[2]))}; } + if (i == 131) { return vec3{0,0,xi[0]*(1. + xi[0]*(-5. + 5.*xi[0]))*(1 + xi[1]*(-6. + (10. - 5.*xi[1])*xi[1]))*(0.1878361089654305191367891 + xi[2]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[2]))}; } + if (i == 132) { return vec3{0,0,11.180339887498948*(1 + xi[0]*(-6. + (10. - 5.*xi[0])*xi[0]))*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(0.1878361089654305191367891 + xi[2]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[2]))}; } + if (i == 133) { return vec3{0,0,125.*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(0.1878361089654305191367891 + xi[2]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[2]))}; } + if (i == 134) { return vec3{0,0,-125.*(-1. + xi[0])*(-0.2763932022500210304 + xi[0])*xi[0]*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(0.1878361089654305191367891 + xi[2]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[2]))}; } + if (i == 135) { return vec3{0,0,11.180339887498948*xi[0]*(1. + xi[0]*(-5. + 5.*xi[0]))*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(0.1878361089654305191367891 + xi[2]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[2]))}; } + if (i == 136) { return vec3{0,0,-11.180339887498948482*(1 + xi[0]*(-6. + (10. - 5.*xi[0])*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(0.1878361089654305191367891 + xi[2]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[2]))}; } + if (i == 137) { return vec3{0,0,-125.*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(0.1878361089654305191367891 + xi[2]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[2]))}; } + if (i == 138) { return vec3{0,0,125.*(-1. + xi[0])*(-0.2763932022500210304 + xi[0])*xi[0]*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(0.1878361089654305191367891 + xi[2]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[2]))}; } + if (i == 139) { return vec3{0,0,-11.180339887498948482*xi[0]*(1. + xi[0]*(-5. + 5.*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(0.1878361089654305191367891 + xi[2]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[2]))}; } + if (i == 140) { return vec3{0,0,(1 + xi[0]*(-6. + (10. - 5.*xi[0])*xi[0]))*xi[1]*(1. + xi[1]*(-5. + 5.*xi[1]))*(0.1878361089654305191367891 + xi[2]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[2]))}; } + if (i == 141) { return vec3{0,0,11.180339887498948*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*xi[1]*(1. + xi[1]*(-5. + 5.*xi[1]))*(0.1878361089654305191367891 + xi[2]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[2]))}; } + if (i == 142) { return vec3{0,0,-11.180339887498948482*(-1. + xi[0])*(-0.2763932022500210304 + xi[0])*xi[0]*xi[1]*(1. + xi[1]*(-5. + 5.*xi[1]))*(0.1878361089654305191367891 + xi[2]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[2]))}; } + if (i == 143) { return vec3{0,0,xi[0]*(1. + xi[0]*(-5. + 5.*xi[0]))*xi[1]*(1. + xi[1]*(-5. + 5.*xi[1]))*(0.1878361089654305191367891 + xi[2]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[2]))}; } + } + + return {}; + } + + constexpr vec3 reoriented_shape_function(vec3 xi, uint32_t i, int8_t transformation) const { + if (transformation == -1) { + return -shape_function(xi, i); + } else { + return shape_function(xi, i); + } + } + + constexpr vec3 shape_function_curl(vec3 xi, uint32_t i) const { + // expressions generated symbolically by mathematica + if (p == 1) { + if (i == 0) { return vec3{0,-1 + xi[1],1 - xi[2]}; } + if (i == 1) { return vec3{0,-xi[1],-1 + xi[2]}; } + if (i == 2) { return vec3{0,1 - xi[1],xi[2]}; } + if (i == 3) { return vec3{0,xi[1],-xi[2]}; } + if (i == 4) { return vec3{1 - xi[0],0,-1 + xi[2]}; } + if (i == 5) { return vec3{xi[0],0,1 - xi[2]}; } + if (i == 6) { return vec3{-1 + xi[0],0,-xi[2]}; } + if (i == 7) { return vec3{-xi[0],0,xi[2]}; } + if (i == 8) { return vec3{-1 + xi[0],1 - xi[1],0}; } + if (i == 9) { return vec3{-xi[0],-1 + xi[1],0}; } + if (i == 10) { return vec3{1 - xi[0],xi[1],0}; } + if (i == 11) { return vec3{xi[0],-xi[1],0}; } + } + if (p == 2) { + if (i == 0) { return vec3{0,-13.8564064605510183482195707*(-0.7886751345948128822545743902 + xi[0])*(-1. + xi[1])*(-0.5 + 1.*xi[1])*(-0.75 + 1.*xi[2]),13.856406460551018348219571*(-0.7886751345948128822545743902 + xi[0])*(-0.75 + 1.*xi[1])*(-1. + xi[2])*(-0.5 + 1.*xi[2])}; } + if (i == 1) { return vec3{0,13.85640646055101834821957*(-0.2113248654051871177454256 + 1.*xi[0])*(-1. + xi[1])*(-0.5 + 1.*xi[1])*(-0.75 + 1.*xi[2]),-13.85640646055101834821957*(-0.2113248654051871177454256 + 1.*xi[0])*(-0.75 + 1.*xi[1])*(-1. + xi[2])*(-0.5 + 1.*xi[2])}; } + if (i == 2) { return vec3{0,27.7128129211020366964391415*(-0.7886751345948128822545743902 + xi[0])*(-1. + xi[1])*xi[1]*(-0.75 + 1.*xi[2]),-27.712812921102036696439141*(-0.7886751345948128822545743902 + xi[0])*(-0.5 + 1.*xi[1])*(-1. + xi[2])*(-0.5 + 1.*xi[2])}; } + if (i == 3) { return vec3{0,-27.71281292110203669643914*(-0.2113248654051871177454256 + 1.*xi[0])*(-1. + xi[1])*xi[1]*(-0.75 + 1.*xi[2]),4*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[0])*(-1 + 2*xi[1])*(-1 + xi[2])*(-1 + 2*xi[2])}; } + if (i == 4) { return vec3{0,-13.8564064605510183482195707*(-0.7886751345948128822545743902 + xi[0])*xi[1]*(-0.5 + 1.*xi[1])*(-0.75 + 1.*xi[2]),13.856406460551018348219571*(-0.7886751345948128822545743902 + xi[0])*(-0.25 + 1.*xi[1])*(-1. + xi[2])*(-0.5 + 1.*xi[2])}; } + if (i == 5) { return vec3{0,13.85640646055101834821957*(-0.2113248654051871177454256 + 1.*xi[0])*xi[1]*(-0.5 + 1.*xi[1])*(-0.75 + 1.*xi[2]),(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[0])*(1 - 4*xi[1])*(-1 + xi[2])*(-1 + 2*xi[2])}; } + if (i == 6) { return vec3{0,27.7128129211020366964391415*(-0.7886751345948128822545743902 + xi[0])*(-1. + xi[1])*(-0.5 + 1.*xi[1])*(-0.5 + 1.*xi[2]),-27.712812921102036696439141*(-0.7886751345948128822545743902 + xi[0])*(-0.75 + 1.*xi[1])*(-1. + xi[2])*xi[2]}; } + if (i == 7) { return vec3{0,4*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[0])*(-1 + xi[1])*(-1 + 2*xi[1])*(1 - 2*xi[2]),27.71281292110203669643914*(-0.2113248654051871177454256 + 1.*xi[0])*(-0.75 + 1.*xi[1])*(-1. + xi[2])*xi[2]}; } + if (i == 8) { return vec3{0,-55.42562584220407*(-0.7886751345948128822545743902 + xi[0])*(-1. + xi[1])*xi[1]*(-0.5 + 1.*xi[2]),55.42562584220407*(-0.7886751345948128822545743902 + xi[0])*(-0.5 + 1.*xi[1])*(-1. + xi[2])*xi[2]}; } + if (i == 9) { return vec3{0,55.42562584220407*(-0.2113248654051871177454256 + 1.*xi[0])*(-1. + xi[1])*xi[1]*(-0.5 + 1.*xi[2]),-55.42562584220407*(-0.2113248654051871177454256 + 1.*xi[0])*(-0.5 + 1.*xi[1])*(-1. + xi[2])*xi[2]}; } + if (i == 10) { return vec3{0,27.7128129211020366964391415*(-0.7886751345948128822545743902 + xi[0])*xi[1]*(-0.5 + 1.*xi[1])*(-0.5 + 1.*xi[2]),-27.712812921102036696439141*(-0.7886751345948128822545743902 + xi[0])*(-0.25 + 1.*xi[1])*(-1. + xi[2])*xi[2]}; } + if (i == 11) { return vec3{0,4*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[0])*xi[1]*(-1 + 2*xi[1])*(1 - 2*xi[2]),4*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[0])*(-1 + 4*xi[1])*(-1 + xi[2])*xi[2]}; } + if (i == 12) { return vec3{0,-13.8564064605510183482195707*(-0.7886751345948128822545743902 + xi[0])*(-1. + xi[1])*(-0.5 + 1.*xi[1])*(-0.25 + 1.*xi[2]),13.856406460551018348219571*(-0.7886751345948128822545743902 + xi[0])*(-0.75 + 1.*xi[1])*xi[2]*(-0.5 + 1.*xi[2])}; } + if (i == 13) { return vec3{0,(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[0])*(-1 + xi[1])*(-1 + 2*xi[1])*(-1 + 4*xi[2]),-13.85640646055101834821957*(-0.2113248654051871177454256 + 1.*xi[0])*(-0.75 + 1.*xi[1])*xi[2]*(-0.5 + 1.*xi[2])}; } + if (i == 14) { return vec3{0,27.7128129211020366964391415*(-0.7886751345948128822545743902 + xi[0])*(-1. + xi[1])*xi[1]*(-0.25 + 1.*xi[2]),-27.712812921102036696439141*(-0.7886751345948128822545743902 + xi[0])*(-0.5 + 1.*xi[1])*xi[2]*(-0.5 + 1.*xi[2])}; } + if (i == 15) { return vec3{0,4*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[0])*(-1 + xi[1])*xi[1]*(1 - 4*xi[2]),4*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[0])*(-1 + 2*xi[1])*xi[2]*(-1 + 2*xi[2])}; } + if (i == 16) { return vec3{0,-13.8564064605510183482195707*(-0.7886751345948128822545743902 + xi[0])*xi[1]*(-0.5 + 1.*xi[1])*(-0.25 + 1.*xi[2]),13.856406460551018348219571*(-0.7886751345948128822545743902 + xi[0])*(-0.25 + 1.*xi[1])*xi[2]*(-0.5 + 1.*xi[2])}; } + if (i == 17) { return vec3{0,(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[0])*xi[1]*(-1 + 2*xi[1])*(-1 + 4*xi[2]),(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[0])*(1 - 4*xi[1])*xi[2]*(-1 + 2*xi[2])}; } + if (i == 18) { return vec3{13.8564064605510183482195707*(-1. + xi[0])*(-0.5 + 1.*xi[0])*(-0.7886751345948128822545743902 + xi[1])*(-0.75 + 1.*xi[2]),0,-13.856406460551018348219571*(-0.75 + 1.*xi[0])*(-0.7886751345948128822545743902 + xi[1])*(-1. + xi[2])*(-0.5 + 1.*xi[2])}; } + if (i == 19) { return vec3{-27.7128129211020366964391415*(-1. + xi[0])*xi[0]*(-0.7886751345948128822545743902 + xi[1])*(-0.75 + 1.*xi[2]),0,27.71281292110203669643914*(-0.5 + 1.*xi[0])*(-0.7886751345948128822545743902 + xi[1])*(-1. + xi[2])*(-0.5 + 1.*xi[2])}; } + if (i == 20) { return vec3{13.8564064605510183482195707*xi[0]*(-0.5 + 1.*xi[0])*(-0.7886751345948128822545743902 + xi[1])*(-0.75 + 1.*xi[2]),0,-13.856406460551018348219571*(-0.25 + 1.*xi[0])*(-0.7886751345948128822545743902 + xi[1])*(-1. + xi[2])*(-0.5 + 1.*xi[2])}; } + if (i == 21) { return vec3{-13.856406460551018348219571*(-1. + xi[0])*(-0.5 + 1.*xi[0])*(-0.21132486540518711774542561 + 1.*xi[1])*(-0.75 + 1.*xi[2]),0,13.856406460551018348219571*(-0.75 + 1.*xi[0])*(-0.21132486540518711774542561 + 1.*xi[1])*(-1. + xi[2])*(-0.5 + 1.*xi[2])}; } + if (i == 22) { return vec3{27.712812921102036696439141*(-1. + xi[0])*xi[0]*(-0.21132486540518711774542561 + 1.*xi[1])*(-0.75 + 1.*xi[2]),0,4*(1 - 2*xi[0])*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[1])*(-1 + xi[2])*(-1 + 2*xi[2])}; } + if (i == 23) { return vec3{-13.856406460551018348219571*xi[0]*(-0.5 + 1.*xi[0])*(-0.21132486540518711774542561 + 1.*xi[1])*(-0.75 + 1.*xi[2]),0,(-1 + 4*xi[0])*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[1])*(-1 + xi[2])*(-1 + 2*xi[2])}; } + if (i == 24) { return vec3{-27.7128129211020366964391415*(-1. + xi[0])*(-0.5 + 1.*xi[0])*(-0.7886751345948128822545743902 + xi[1])*(-0.5 + 1.*xi[2]),0,27.71281292110203669643914*(-0.75 + 1.*xi[0])*(-0.7886751345948128822545743902 + xi[1])*(-1. + xi[2])*xi[2]}; } + if (i == 25) { return vec3{55.42562584220407*(-1. + xi[0])*xi[0]*(-0.7886751345948128822545743902 + xi[1])*(-0.5 + 1.*xi[2]),0,-55.42562584220407*(-0.5 + 1.*xi[0])*(-0.7886751345948128822545743902 + xi[1])*(-1. + xi[2])*xi[2]}; } + if (i == 26) { return vec3{-27.7128129211020366964391415*xi[0]*(-0.5 + 1.*xi[0])*(-0.7886751345948128822545743902 + xi[1])*(-0.5 + 1.*xi[2]),0,27.71281292110203669643914*(-0.25 + 1.*xi[0])*(-0.7886751345948128822545743902 + xi[1])*(-1. + xi[2])*xi[2]}; } + if (i == 27) { return vec3{4*(-1 + xi[0])*(-1 + 2*xi[0])*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[1])*(-1 + 2*xi[2]),0,-27.71281292110203669643914*(-0.75 + 1.*xi[0])*(-0.21132486540518711774542561 + 1.*xi[1])*(-1. + xi[2])*xi[2]}; } + if (i == 28) { return vec3{-55.42562584220407*(-1. + xi[0])*xi[0]*(-0.21132486540518711774542561 + 1.*xi[1])*(-0.5 + 1.*xi[2]),0,55.42562584220407*(-0.5 + 1.*xi[0])*(-0.21132486540518711774542561 + 1.*xi[1])*(-1. + xi[2])*xi[2]}; } + if (i == 29) { return vec3{4*xi[0]*(-1 + 2*xi[0])*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[1])*(-1 + 2*xi[2]),0,4*(1 - 4*xi[0])*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[1])*(-1 + xi[2])*xi[2]}; } + if (i == 30) { return vec3{13.8564064605510183482195707*(-1. + xi[0])*(-0.5 + 1.*xi[0])*(-0.7886751345948128822545743902 + xi[1])*(-0.25 + 1.*xi[2]),0,-13.856406460551018348219571*(-0.75 + 1.*xi[0])*(-0.7886751345948128822545743902 + xi[1])*xi[2]*(-0.5 + 1.*xi[2])}; } + if (i == 31) { return vec3{-27.7128129211020366964391415*(-1. + xi[0])*xi[0]*(-0.7886751345948128822545743902 + xi[1])*(-0.25 + 1.*xi[2]),0,27.71281292110203669643914*(-0.5 + 1.*xi[0])*(-0.7886751345948128822545743902 + xi[1])*xi[2]*(-0.5 + 1.*xi[2])}; } + if (i == 32) { return vec3{13.8564064605510183482195707*xi[0]*(-0.5 + 1.*xi[0])*(-0.7886751345948128822545743902 + xi[1])*(-0.25 + 1.*xi[2]),0,-13.856406460551018348219571*(-0.25 + 1.*xi[0])*(-0.7886751345948128822545743902 + xi[1])*xi[2]*(-0.5 + 1.*xi[2])}; } + if (i == 33) { return vec3{(-1 + xi[0])*(-1 + 2*xi[0])*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[1])*(1 - 4*xi[2]),0,13.856406460551018348219571*(-0.75 + 1.*xi[0])*(-0.21132486540518711774542561 + 1.*xi[1])*xi[2]*(-0.5 + 1.*xi[2])}; } + if (i == 34) { return vec3{4*(-1 + xi[0])*xi[0]*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[1])*(-1 + 4*xi[2]),0,4*(1 - 2*xi[0])*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[1])*xi[2]*(-1 + 2*xi[2])}; } + if (i == 35) { return vec3{xi[0]*(-1 + 2*xi[0])*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[1])*(1 - 4*xi[2]),0,(-1 + 4*xi[0])*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[1])*xi[2]*(-1 + 2*xi[2])}; } + if (i == 36) { return vec3{-13.856406460551018348219571*(-1. + xi[0])*(-0.5 + 1.*xi[0])*(-0.75 + 1.*xi[1])*(-0.78867513459481288225457439 + xi[2]),13.856406460551018348219571*(-0.75 + 1.*xi[0])*(-1. + xi[1])*(-0.5 + 1.*xi[1])*(-0.78867513459481288225457439 + xi[2]),0}; } + if (i == 37) { return vec3{27.712812921102036696439141*(-1. + xi[0])*xi[0]*(-0.75 + 1.*xi[1])*(-0.78867513459481288225457439 + xi[2]),-27.71281292110203669643914*(-0.5 + 1.*xi[0])*(-1. + xi[1])*(-0.5 + 1.*xi[1])*(-0.78867513459481288225457439 + xi[2]),0}; } + if (i == 38) { return vec3{-13.856406460551018348219571*xi[0]*(-0.5 + 1.*xi[0])*(-0.75 + 1.*xi[1])*(-0.78867513459481288225457439 + xi[2]),13.856406460551018348219571*(-0.25 + 1.*xi[0])*(-1. + xi[1])*(-0.5 + 1.*xi[1])*(-0.78867513459481288225457439 + xi[2]),0}; } + if (i == 39) { return vec3{27.712812921102036696439141*(-1. + xi[0])*(-0.5 + 1.*xi[0])*(-0.5 + 1.*xi[1])*(-0.78867513459481288225457439 + xi[2]),-27.71281292110203669643914*(-0.75 + 1.*xi[0])*(-1. + xi[1])*xi[1]*(-0.78867513459481288225457439 + xi[2]),0}; } + if (i == 40) { return vec3{-55.42562584220407*(-1. + xi[0])*xi[0]*(-0.5 + 1.*xi[1])*(-0.78867513459481288225457439 + xi[2]),55.42562584220407*(-0.5 + 1.*xi[0])*(-1. + xi[1])*xi[1]*(-0.78867513459481288225457439 + xi[2]),0}; } + if (i == 41) { return vec3{27.712812921102036696439141*xi[0]*(-0.5 + 1.*xi[0])*(-0.5 + 1.*xi[1])*(-0.78867513459481288225457439 + xi[2]),-27.71281292110203669643914*(-0.25 + 1.*xi[0])*(-1. + xi[1])*xi[1]*(-0.78867513459481288225457439 + xi[2]),0}; } + if (i == 42) { return vec3{-13.856406460551018348219571*(-1. + xi[0])*(-0.5 + 1.*xi[0])*(-0.25 + 1.*xi[1])*(-0.78867513459481288225457439 + xi[2]),13.856406460551018348219571*(-0.75 + 1.*xi[0])*xi[1]*(-0.5 + 1.*xi[1])*(-0.78867513459481288225457439 + xi[2]),0}; } + if (i == 43) { return vec3{27.712812921102036696439141*(-1. + xi[0])*xi[0]*(-0.25 + 1.*xi[1])*(-0.78867513459481288225457439 + xi[2]),-27.71281292110203669643914*(-0.5 + 1.*xi[0])*xi[1]*(-0.5 + 1.*xi[1])*(-0.78867513459481288225457439 + xi[2]),0}; } + if (i == 44) { return vec3{-13.856406460551018348219571*xi[0]*(-0.5 + 1.*xi[0])*(-0.25 + 1.*xi[1])*(-0.78867513459481288225457439 + xi[2]),13.856406460551018348219571*(-0.25 + 1.*xi[0])*xi[1]*(-0.5 + 1.*xi[1])*(-0.78867513459481288225457439 + xi[2]),0}; } + if (i == 45) { return vec3{13.856406460551018348219571*(-1. + xi[0])*(-0.5 + 1.*xi[0])*(-0.75 + 1.*xi[1])*(-0.21132486540518711774542561 + 1.*xi[2]),-13.856406460551018348219571*(-0.75 + 1.*xi[0])*(-1. + xi[1])*(-0.5 + 1.*xi[1])*(-0.21132486540518711774542561 + 1.*xi[2]),0}; } + if (i == 46) { return vec3{-27.712812921102036696439141*(-1. + xi[0])*xi[0]*(-0.75 + 1.*xi[1])*(-0.21132486540518711774542561 + 1.*xi[2]),4*(-1 + 2*xi[0])*(-1 + xi[1])*(-1 + 2*xi[1])*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[2]),0}; } + if (i == 47) { return vec3{13.856406460551018348219571*xi[0]*(-0.5 + 1.*xi[0])*(-0.75 + 1.*xi[1])*(-0.21132486540518711774542561 + 1.*xi[2]),(1 - 4*xi[0])*(-1 + xi[1])*(-1 + 2*xi[1])*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[2]),0}; } + if (i == 48) { return vec3{4*(-1 + xi[0])*(-1 + 2*xi[0])*(1 - 2*xi[1])*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[2]),27.712812921102036696439141*(-0.75 + 1.*xi[0])*(-1. + xi[1])*xi[1]*(-0.21132486540518711774542561 + 1.*xi[2]),0}; } + if (i == 49) { return vec3{55.42562584220407*(-1. + xi[0])*xi[0]*(-0.5 + 1.*xi[1])*(-0.21132486540518711774542561 + 1.*xi[2]),-55.42562584220407*(-0.5 + 1.*xi[0])*(-1. + xi[1])*xi[1]*(-0.21132486540518711774542561 + 1.*xi[2]),0}; } + if (i == 50) { return vec3{4*xi[0]*(-1 + 2*xi[0])*(1 - 2*xi[1])*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[2]),4*(-1 + 4*xi[0])*(-1 + xi[1])*xi[1]*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[2]),0}; } + if (i == 51) { return vec3{(-1 + xi[0])*(-1 + 2*xi[0])*(-1 + 4*xi[1])*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[2]),-13.856406460551018348219571*(-0.75 + 1.*xi[0])*xi[1]*(-0.5 + 1.*xi[1])*(-0.21132486540518711774542561 + 1.*xi[2]),0}; } + if (i == 52) { return vec3{4*(-1 + xi[0])*xi[0]*(1 - 4*xi[1])*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[2]),4*(-1 + 2*xi[0])*xi[1]*(-1 + 2*xi[1])*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[2]),0}; } + if (i == 53) { return vec3{xi[0]*(-1 + 2*xi[0])*(-1 + 4*xi[1])*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[2]),(1 - 4*xi[0])*xi[1]*(-1 + 2*xi[1])*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[2]),0}; } + } + if (p == 3) { + if (i == 0) { return vec3{0,250.*(0.4436491673103708 + xi[0]*(-1.387298334620742 + 1.*xi[0]))*(-0.2 + xi[1]*(1.2 + xi[1]*(-2. + 1.*xi[1])))*(0.4 + xi[2]*(-1.333333333333333 + 1.*xi[2])),-250.*(0.4436491673103708 + xi[0]*(-1.387298334620742 + 1.*xi[0]))*(0.4 + xi[1]*(-1.3333333333333333 + 1.*xi[1]))*(-0.2 + xi[2]*(1.2 + xi[2]*(-2. + 1.*xi[2])))}; } + if (i == 1) { return vec3{0,-500.*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(-0.2 + xi[1]*(1.2 + xi[1]*(-2. + 1.*xi[1])))*(0.4 + xi[2]*(-1.333333333333333 + 1.*xi[2])),500.*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(0.4 + xi[1]*(-1.3333333333333333 + 1.*xi[1]))*(-0.2 + xi[2]*(1.2 + xi[2]*(-2. + 1.*xi[2])))}; } + if (i == 2) { return vec3{0,250.*(0.05635083268962916 + xi[0]*(-0.6127016653792583 + 1.*xi[0]))*(-0.2 + xi[1]*(1.2 + xi[1]*(-2. + 1.*xi[1])))*(0.4 + xi[2]*(-1.333333333333333 + 1.*xi[2])),-250.*(0.05635083268962916 + xi[0]*(-0.6127016653792583 + 1.*xi[0]))*(0.4 + xi[1]*(-1.3333333333333333 + 1.*xi[1]))*(-0.2 + xi[2]*(1.2 + xi[2]*(-2. + 1.*xi[2])))}; } + if (i == 3) { return vec3{0,-559.016994374947*(0.4436491673103708 + xi[0]*(-1.387298334620742 + 1.*xi[0]))*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(0.4 + xi[2]*(-1.333333333333333 + 1.*xi[2])),559.016994374947*(0.4436491673103708 + xi[0]*(-1.387298334620742 + 1.*xi[0]))*(0.24120226591666 + xi[1]*(-1.149071198499986 + 1.*xi[1]))*(-0.2 + xi[2]*(1.2 + xi[2]*(-2. + 1.*xi[2])))}; } + if (i == 4) { return vec3{0,1118.033988749895*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(0.4 + xi[2]*(-1.333333333333333 + 1.*xi[2])),-1118.033988749895*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(0.24120226591666 + xi[1]*(-1.149071198499986 + 1.*xi[1]))*(-0.2 + xi[2]*(1.2 + xi[2]*(-2. + 1.*xi[2])))}; } + if (i == 5) { return vec3{0,-559.016994374947*(0.05635083268962916 + xi[0]*(-0.6127016653792583 + 1.*xi[0]))*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(0.4 + xi[2]*(-1.333333333333333 + 1.*xi[2])),559.016994374947*(0.05635083268962916 + xi[0]*(-0.6127016653792583 + 1.*xi[0]))*(0.24120226591666 + xi[1]*(-1.149071198499986 + 1.*xi[1]))*(-0.2 + xi[2]*(1.2 + xi[2]*(-2. + 1.*xi[2])))}; } + if (i == 6) { return vec3{0,559.016994374947*(0.4436491673103708 + xi[0]*(-1.387298334620742 + 1.*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(0.4 + xi[2]*(-1.333333333333333 + 1.*xi[2])),-559.016994374947*(0.4436491673103708 + xi[0]*(-1.387298334620742 + 1.*xi[0]))*(0.0921310674166737 + xi[1]*(-0.850928801500014 + 1.*xi[1]))*(-0.2 + xi[2]*(1.2 + xi[2]*(-2. + 1.*xi[2])))}; } + if (i == 7) { return vec3{0,-1118.0339887498948*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(0.4 + xi[2]*(-1.333333333333333 + 1.*xi[2])),1118.033988749895*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(0.0921310674166737 + xi[1]*(-0.850928801500014 + 1.*xi[1]))*(-0.2 + xi[2]*(1.2 + xi[2]*(-2. + 1.*xi[2])))}; } + if (i == 8) { return vec3{0,559.016994374947*(0.05635083268962916 + xi[0]*(-0.6127016653792583 + 1.*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(0.4 + xi[2]*(-1.333333333333333 + 1.*xi[2])),-559.016994374947*(0.05635083268962916 + xi[0]*(-0.6127016653792583 + 1.*xi[0]))*(0.0921310674166737 + xi[1]*(-0.850928801500014 + 1.*xi[1]))*(-0.2 + xi[2]*(1.2 + xi[2]*(-2. + 1.*xi[2])))}; } + if (i == 9) { return vec3{0,-250.*(0.4436491673103708 + xi[0]*(-1.387298334620742 + 1.*xi[0]))*xi[1]*(0.2 + xi[1]*(-1. + 1.*xi[1]))*(0.4 + xi[2]*(-1.333333333333333 + 1.*xi[2])),250.*(0.4436491673103708 + xi[0]*(-1.387298334620742 + 1.*xi[0]))*(0.0666666666666667 + xi[1]*(-0.6666666666666667 + 1.*xi[1]))*(-0.2 + xi[2]*(1.2 + xi[2]*(-2. + 1.*xi[2])))}; } + if (i == 10) { return vec3{0,500.*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*xi[1]*(0.2 + xi[1]*(-1. + 1.*xi[1]))*(0.4 + xi[2]*(-1.333333333333333 + 1.*xi[2])),-500.*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(0.0666666666666667 + xi[1]*(-0.6666666666666667 + 1.*xi[1]))*(-0.2 + xi[2]*(1.2 + xi[2]*(-2. + 1.*xi[2])))}; } + if (i == 11) { return vec3{0,-250.*(0.05635083268962916 + xi[0]*(-0.6127016653792583 + 1.*xi[0]))*xi[1]*(0.2 + xi[1]*(-1. + 1.*xi[1]))*(0.4 + xi[2]*(-1.333333333333333 + 1.*xi[2])),250.*(0.05635083268962916 + xi[0]*(-0.6127016653792583 + 1.*xi[0]))*(0.0666666666666667 + xi[1]*(-0.6666666666666667 + 1.*xi[1]))*(-0.2 + xi[2]*(1.2 + xi[2]*(-2. + 1.*xi[2])))}; } + if (i == 12) { return vec3{0,-559.016994374947*(0.4436491673103708 + xi[0]*(-1.387298334620742 + 1.*xi[0]))*(-0.2 + xi[1]*(1.2 + xi[1]*(-2. + 1.*xi[1])))*(0.2412022659166597 + xi[2]*(-1.149071198499986 + 1.*xi[2])),559.0169943749474*(0.4436491673103708 + xi[0]*(-1.387298334620742 + 1.*xi[0]))*(0.4 + xi[1]*(-1.3333333333333333 + 1.*xi[1]))*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2])}; } + if (i == 13) { return vec3{0,1118.033988749895*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(-0.2 + xi[1]*(1.2 + xi[1]*(-2. + 1.*xi[1])))*(0.2412022659166597 + xi[2]*(-1.149071198499986 + 1.*xi[2])),-1118.033988749895*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(0.4 + xi[1]*(-1.3333333333333333 + 1.*xi[1]))*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2])}; } + if (i == 14) { return vec3{0,-559.016994374947*(0.05635083268962916 + xi[0]*(-0.6127016653792583 + 1.*xi[0]))*(-0.2 + xi[1]*(1.2 + xi[1]*(-2. + 1.*xi[1])))*(0.2412022659166597 + xi[2]*(-1.149071198499986 + 1.*xi[2])),559.0169943749474*(0.05635083268962916 + xi[0]*(-0.6127016653792583 + 1.*xi[0]))*(0.4 + xi[1]*(-1.3333333333333333 + 1.*xi[1]))*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2])}; } + if (i == 15) { return vec3{0,1250.*(0.4436491673103708 + xi[0]*(-1.387298334620742 + 1.*xi[0]))*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(0.2412022659166597 + xi[2]*(-1.149071198499986 + 1.*xi[2])),-1250.*(0.4436491673103708 + xi[0]*(-1.387298334620742 + 1.*xi[0]))*(0.24120226591666 + xi[1]*(-1.149071198499986 + 1.*xi[1]))*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2])}; } + if (i == 16) { return vec3{0,-2500.*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(0.2412022659166597 + xi[2]*(-1.149071198499986 + 1.*xi[2])),2500.*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(0.24120226591666 + xi[1]*(-1.149071198499986 + 1.*xi[1]))*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2])}; } + if (i == 17) { return vec3{0,1250.*(0.05635083268962916 + xi[0]*(-0.6127016653792583 + 1.*xi[0]))*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(0.2412022659166597 + xi[2]*(-1.149071198499986 + 1.*xi[2])),-1250.*(0.05635083268962916 + xi[0]*(-0.6127016653792583 + 1.*xi[0]))*(0.24120226591666 + xi[1]*(-1.149071198499986 + 1.*xi[1]))*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2])}; } + if (i == 18) { return vec3{0,-1250.*(0.4436491673103708 + xi[0]*(-1.387298334620742 + 1.*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(0.2412022659166597 + xi[2]*(-1.149071198499986 + 1.*xi[2])),1250.*(0.4436491673103708 + xi[0]*(-1.387298334620742 + 1.*xi[0]))*(0.0921310674166737 + xi[1]*(-0.850928801500014 + 1.*xi[1]))*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2])}; } + if (i == 19) { return vec3{0,2500.*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(0.2412022659166597 + xi[2]*(-1.149071198499986 + 1.*xi[2])),-2500.*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(0.0921310674166737 + xi[1]*(-0.850928801500014 + 1.*xi[1]))*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2])}; } + if (i == 20) { return vec3{0,-1250.*(0.05635083268962916 + xi[0]*(-0.6127016653792583 + 1.*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(0.2412022659166597 + xi[2]*(-1.149071198499986 + 1.*xi[2])),1250.*(0.05635083268962916 + xi[0]*(-0.6127016653792583 + 1.*xi[0]))*(0.0921310674166737 + xi[1]*(-0.850928801500014 + 1.*xi[1]))*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2])}; } + if (i == 21) { return vec3{0,559.016994374947*(0.4436491673103708 + xi[0]*(-1.387298334620742 + 1.*xi[0]))*xi[1]*(0.2 + xi[1]*(-1. + 1.*xi[1]))*(0.2412022659166597 + xi[2]*(-1.149071198499986 + 1.*xi[2])),-559.016994374947*(0.4436491673103708 + xi[0]*(-1.387298334620742 + 1.*xi[0]))*(0.0666666666666667 + xi[1]*(-0.6666666666666667 + 1.*xi[1]))*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2])}; } + if (i == 22) { return vec3{0,-1118.033988749895*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*xi[1]*(0.2 + xi[1]*(-1. + 1.*xi[1]))*(0.2412022659166597 + xi[2]*(-1.149071198499986 + 1.*xi[2])),1118.03398874989*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(0.0666666666666667 + xi[1]*(-0.6666666666666667 + 1.*xi[1]))*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2])}; } + if (i == 23) { return vec3{0,559.016994374947*(0.05635083268962916 + xi[0]*(-0.6127016653792583 + 1.*xi[0]))*xi[1]*(0.2 + xi[1]*(-1. + 1.*xi[1]))*(0.2412022659166597 + xi[2]*(-1.149071198499986 + 1.*xi[2])),-559.016994374947*(0.05635083268962916 + xi[0]*(-0.6127016653792583 + 1.*xi[0]))*(0.0666666666666667 + xi[1]*(-0.6666666666666667 + 1.*xi[1]))*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2])}; } + if (i == 24) { return vec3{0,559.016994374947*(0.4436491673103708 + xi[0]*(-1.387298334620742 + 1.*xi[0]))*(-0.2 + xi[1]*(1.2 + xi[1]*(-2. + 1.*xi[1])))*(0.0921310674166737 + xi[2]*(-0.850928801500014 + 1.*xi[2])),-559.016994374947*(0.4436491673103708 + xi[0]*(-1.387298334620742 + 1.*xi[0]))*(0.4 + xi[1]*(-1.3333333333333333 + 1.*xi[1]))*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2]}; } + if (i == 25) { return vec3{0,-1118.033988749895*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(-0.2 + xi[1]*(1.2 + xi[1]*(-2. + 1.*xi[1])))*(0.0921310674166737 + xi[2]*(-0.850928801500014 + 1.*xi[2])),1118.033988749895*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(0.4 + xi[1]*(-1.3333333333333333 + 1.*xi[1]))*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2]}; } + if (i == 26) { return vec3{0,559.016994374947*(0.05635083268962916 + xi[0]*(-0.6127016653792583 + 1.*xi[0]))*(-0.2 + xi[1]*(1.2 + xi[1]*(-2. + 1.*xi[1])))*(0.0921310674166737 + xi[2]*(-0.850928801500014 + 1.*xi[2])),-559.016994374947*(0.05635083268962916 + xi[0]*(-0.6127016653792583 + 1.*xi[0]))*(0.4 + xi[1]*(-1.3333333333333333 + 1.*xi[1]))*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2]}; } + if (i == 27) { return vec3{0,-1250.*(0.4436491673103708 + xi[0]*(-1.387298334620742 + 1.*xi[0]))*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(0.0921310674166737 + xi[2]*(-0.850928801500014 + 1.*xi[2])),1250.*(0.4436491673103708 + xi[0]*(-1.387298334620742 + 1.*xi[0]))*(0.24120226591666 + xi[1]*(-1.149071198499986 + 1.*xi[1]))*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2]}; } + if (i == 28) { return vec3{0,2500.*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(0.0921310674166737 + xi[2]*(-0.850928801500014 + 1.*xi[2])),-2500.*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(0.24120226591666 + xi[1]*(-1.149071198499986 + 1.*xi[1]))*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2]}; } + if (i == 29) { return vec3{0,-1250.*(0.05635083268962916 + xi[0]*(-0.6127016653792583 + 1.*xi[0]))*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(0.0921310674166737 + xi[2]*(-0.850928801500014 + 1.*xi[2])),1250.*(0.05635083268962916 + xi[0]*(-0.6127016653792583 + 1.*xi[0]))*(0.24120226591666 + xi[1]*(-1.149071198499986 + 1.*xi[1]))*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2]}; } + if (i == 30) { return vec3{0,1250.*(0.4436491673103708 + xi[0]*(-1.387298334620742 + 1.*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(0.0921310674166737 + xi[2]*(-0.850928801500014 + 1.*xi[2])),-1250.*(0.4436491673103708 + xi[0]*(-1.387298334620742 + 1.*xi[0]))*(0.0921310674166737 + xi[1]*(-0.850928801500014 + 1.*xi[1]))*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2]}; } + if (i == 31) { return vec3{0,-2500.*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(0.0921310674166737 + xi[2]*(-0.850928801500014 + 1.*xi[2])),2500.*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(0.0921310674166737 + xi[1]*(-0.850928801500014 + 1.*xi[1]))*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2]}; } + if (i == 32) { return vec3{0,1250.*(0.05635083268962916 + xi[0]*(-0.6127016653792583 + 1.*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(0.0921310674166737 + xi[2]*(-0.850928801500014 + 1.*xi[2])),-1250.*(0.05635083268962916 + xi[0]*(-0.6127016653792583 + 1.*xi[0]))*(0.0921310674166737 + xi[1]*(-0.850928801500014 + 1.*xi[1]))*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2]}; } + if (i == 33) { return vec3{0,-559.016994374947*(0.4436491673103708 + xi[0]*(-1.387298334620742 + 1.*xi[0]))*xi[1]*(0.2 + xi[1]*(-1. + 1.*xi[1]))*(0.0921310674166737 + xi[2]*(-0.850928801500014 + 1.*xi[2])),559.016994374947*(0.4436491673103708 + xi[0]*(-1.387298334620742 + 1.*xi[0]))*(0.0666666666666667 + xi[1]*(-0.6666666666666667 + 1.*xi[1]))*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2]}; } + if (i == 34) { return vec3{0,1118.03398874989*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*xi[1]*(0.2 + xi[1]*(-1. + 1.*xi[1]))*(0.0921310674166737 + xi[2]*(-0.850928801500014 + 1.*xi[2])),-1118.03398874989*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(0.0666666666666667 + xi[1]*(-0.6666666666666667 + 1.*xi[1]))*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2]}; } + if (i == 35) { return vec3{0,-559.016994374947*(0.05635083268962916 + xi[0]*(-0.6127016653792583 + 1.*xi[0]))*xi[1]*(0.2 + xi[1]*(-1. + 1.*xi[1]))*(0.0921310674166737 + xi[2]*(-0.850928801500014 + 1.*xi[2])),559.016994374947*(0.05635083268962916 + xi[0]*(-0.6127016653792583 + 1.*xi[0]))*(0.0666666666666667 + xi[1]*(-0.6666666666666667 + 1.*xi[1]))*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2]}; } + if (i == 36) { return vec3{0,-250.*(0.4436491673103708 + xi[0]*(-1.387298334620742 + 1.*xi[0]))*(-0.2 + xi[1]*(1.2 + xi[1]*(-2. + 1.*xi[1])))*(0.06666666666666667 + xi[2]*(-0.6666666666666667 + 1.*xi[2])),250.*(0.4436491673103708 + xi[0]*(-1.387298334620742 + 1.*xi[0]))*(0.4 + xi[1]*(-1.3333333333333333 + 1.*xi[1]))*xi[2]*(0.2 + xi[2]*(-1. + 1.*xi[2]))}; } + if (i == 37) { return vec3{0,500.*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(-0.2 + xi[1]*(1.2 + xi[1]*(-2. + 1.*xi[1])))*(0.06666666666666667 + xi[2]*(-0.6666666666666667 + 1.*xi[2])),-500.*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(0.4 + xi[1]*(-1.3333333333333333 + 1.*xi[1]))*xi[2]*(0.2 + xi[2]*(-1. + 1.*xi[2]))}; } + if (i == 38) { return vec3{0,-250.*(0.05635083268962916 + xi[0]*(-0.6127016653792583 + 1.*xi[0]))*(-0.2 + xi[1]*(1.2 + xi[1]*(-2. + 1.*xi[1])))*(0.06666666666666667 + xi[2]*(-0.6666666666666667 + 1.*xi[2])),250.*(0.05635083268962916 + xi[0]*(-0.6127016653792583 + 1.*xi[0]))*(0.4 + xi[1]*(-1.3333333333333333 + 1.*xi[1]))*xi[2]*(0.2 + xi[2]*(-1. + 1.*xi[2]))}; } + if (i == 39) { return vec3{0,559.016994374947*(0.4436491673103708 + xi[0]*(-1.387298334620742 + 1.*xi[0]))*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(0.06666666666666667 + xi[2]*(-0.6666666666666667 + 1.*xi[2])),-559.016994374947*(0.4436491673103708 + xi[0]*(-1.387298334620742 + 1.*xi[0]))*(0.24120226591666 + xi[1]*(-1.149071198499986 + 1.*xi[1]))*xi[2]*(0.2 + xi[2]*(-1. + 1.*xi[2]))}; } + if (i == 40) { return vec3{0,-1118.033988749895*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(0.06666666666666667 + xi[2]*(-0.6666666666666667 + 1.*xi[2])),1118.03398874989*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(0.24120226591666 + xi[1]*(-1.149071198499986 + 1.*xi[1]))*xi[2]*(0.2 + xi[2]*(-1. + 1.*xi[2]))}; } + if (i == 41) { return vec3{0,559.016994374947*(0.05635083268962916 + xi[0]*(-0.6127016653792583 + 1.*xi[0]))*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(0.06666666666666667 + xi[2]*(-0.6666666666666667 + 1.*xi[2])),-559.016994374947*(0.05635083268962916 + xi[0]*(-0.6127016653792583 + 1.*xi[0]))*(0.24120226591666 + xi[1]*(-1.149071198499986 + 1.*xi[1]))*xi[2]*(0.2 + xi[2]*(-1. + 1.*xi[2]))}; } + if (i == 42) { return vec3{0,-559.016994374947*(0.4436491673103708 + xi[0]*(-1.387298334620742 + 1.*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(0.06666666666666667 + xi[2]*(-0.6666666666666667 + 1.*xi[2])),559.016994374947*(0.4436491673103708 + xi[0]*(-1.387298334620742 + 1.*xi[0]))*(0.0921310674166737 + xi[1]*(-0.850928801500014 + 1.*xi[1]))*xi[2]*(0.2 + xi[2]*(-1. + 1.*xi[2]))}; } + if (i == 43) { return vec3{0,1118.033988749895*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(0.06666666666666667 + xi[2]*(-0.6666666666666667 + 1.*xi[2])),-1118.03398874989*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(0.0921310674166737 + xi[1]*(-0.850928801500014 + 1.*xi[1]))*xi[2]*(0.2 + xi[2]*(-1. + 1.*xi[2]))}; } + if (i == 44) { return vec3{0,-559.016994374947*(0.05635083268962916 + xi[0]*(-0.6127016653792583 + 1.*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(0.06666666666666667 + xi[2]*(-0.6666666666666667 + 1.*xi[2])),559.016994374947*(0.05635083268962916 + xi[0]*(-0.6127016653792583 + 1.*xi[0]))*(0.0921310674166737 + xi[1]*(-0.850928801500014 + 1.*xi[1]))*xi[2]*(0.2 + xi[2]*(-1. + 1.*xi[2]))}; } + if (i == 45) { return vec3{0,250.*(0.4436491673103708 + xi[0]*(-1.387298334620742 + 1.*xi[0]))*xi[1]*(0.2 + xi[1]*(-1. + 1.*xi[1]))*(0.06666666666666667 + xi[2]*(-0.6666666666666667 + 1.*xi[2])),-250.*(0.4436491673103708 + xi[0]*(-1.387298334620742 + 1.*xi[0]))*(0.0666666666666667 + xi[1]*(-0.6666666666666667 + 1.*xi[1]))*xi[2]*(0.2 + xi[2]*(-1. + 1.*xi[2]))}; } + if (i == 46) { return vec3{0,-500.*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*xi[1]*(0.2 + xi[1]*(-1. + 1.*xi[1]))*(0.06666666666666667 + xi[2]*(-0.6666666666666667 + 1.*xi[2])),500.*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(0.0666666666666667 + xi[1]*(-0.6666666666666667 + 1.*xi[1]))*xi[2]*(0.2 + xi[2]*(-1. + 1.*xi[2]))}; } + if (i == 47) { return vec3{0,250.*(0.05635083268962916 + xi[0]*(-0.6127016653792583 + 1.*xi[0]))*xi[1]*(0.2 + xi[1]*(-1. + 1.*xi[1]))*(0.06666666666666667 + xi[2]*(-0.6666666666666667 + 1.*xi[2])),-250.*(0.05635083268962916 + xi[0]*(-0.6127016653792583 + 1.*xi[0]))*(0.0666666666666667 + xi[1]*(-0.6666666666666667 + 1.*xi[1]))*xi[2]*(0.2 + xi[2]*(-1. + 1.*xi[2]))}; } + if (i == 48) { return vec3{-250.*(-0.2 + xi[0]*(1.2 + xi[0]*(-2. + 1.*xi[0])))*(0.44364916731037084 + xi[1]*(-1.3872983346207417 + 1.*xi[1]))*(0.4 + xi[2]*(-1.333333333333333 + 1.*xi[2])),0,250.*(0.4 + xi[0]*(-1.333333333333333 + 1.*xi[0]))*(0.44364916731037084 + xi[1]*(-1.3872983346207417 + 1.*xi[1]))*(-0.2 + xi[2]*(1.2 + xi[2]*(-2. + 1.*xi[2])))}; } + if (i == 49) { return vec3{559.016994374947*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(0.44364916731037084 + xi[1]*(-1.3872983346207417 + 1.*xi[1]))*(0.4 + xi[2]*(-1.333333333333333 + 1.*xi[2])),0,-559.016994374947*(0.24120226591666 + xi[0]*(-1.149071198499986 + 1.*xi[0]))*(0.44364916731037084 + xi[1]*(-1.3872983346207417 + 1.*xi[1]))*(-0.2 + xi[2]*(1.2 + xi[2]*(-2. + 1.*xi[2])))}; } + if (i == 50) { return vec3{-559.016994374947*(-1. + xi[0])*(-0.27639320225002103 + xi[0])*xi[0]*(0.44364916731037084 + xi[1]*(-1.3872983346207417 + 1.*xi[1]))*(0.4 + xi[2]*(-1.333333333333333 + 1.*xi[2])),0,559.01699437495*(0.092131067416674 + xi[0]*(-0.85092880150001 + 1.*xi[0]))*(0.44364916731037084 + xi[1]*(-1.3872983346207417 + 1.*xi[1]))*(-0.2 + xi[2]*(1.2 + xi[2]*(-2. + 1.*xi[2])))}; } + if (i == 51) { return vec3{250.*xi[0]*(0.2 + xi[0]*(-1. + 1.*xi[0]))*(0.44364916731037084 + xi[1]*(-1.3872983346207417 + 1.*xi[1]))*(0.4 + xi[2]*(-1.333333333333333 + 1.*xi[2])),0,-250.*(0.0666666666666667 + xi[0]*(-0.666666666666667 + 1.*xi[0]))*(0.44364916731037084 + xi[1]*(-1.3872983346207417 + 1.*xi[1]))*(-0.2 + xi[2]*(1.2 + xi[2]*(-2. + 1.*xi[2])))}; } + if (i == 52) { return vec3{500.*(-0.2 + xi[0]*(1.2 + xi[0]*(-2. + 1.*xi[0])))*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831 + xi[1])*(0.4 + xi[2]*(-1.333333333333333 + 1.*xi[2])),0,-500.*(0.4 + xi[0]*(-1.333333333333333 + 1.*xi[0]))*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831 + xi[1])*(-0.2 + xi[2]*(1.2 + xi[2]*(-2. + 1.*xi[2])))}; } + if (i == 53) { return vec3{-1118.03398874989*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831 + xi[1])*(0.4 + xi[2]*(-1.333333333333333 + 1.*xi[2])),0,1118.03398874989*(0.24120226591666 + xi[0]*(-1.149071198499986 + 1.*xi[0]))*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831 + xi[1])*(-0.2 + xi[2]*(1.2 + xi[2]*(-2. + 1.*xi[2])))}; } + if (i == 54) { return vec3{1118.0339887498948*(-1. + xi[0])*(-0.27639320225002103 + xi[0])*xi[0]*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831 + xi[1])*(0.4 + xi[2]*(-1.333333333333333 + 1.*xi[2])),0,-1118.033988749895*(0.092131067416674 + xi[0]*(-0.85092880150001 + 1.*xi[0]))*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831 + xi[1])*(-0.2 + xi[2]*(1.2 + xi[2]*(-2. + 1.*xi[2])))}; } + if (i == 55) { return vec3{-500.*xi[0]*(0.2 + xi[0]*(-1. + 1.*xi[0]))*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831 + xi[1])*(0.4 + xi[2]*(-1.333333333333333 + 1.*xi[2])),0,500.*(0.0666666666666667 + xi[0]*(-0.666666666666667 + 1.*xi[0]))*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831 + xi[1])*(-0.2 + xi[2]*(1.2 + xi[2]*(-2. + 1.*xi[2])))}; } + if (i == 56) { return vec3{-250.*(-0.2 + xi[0]*(1.2 + xi[0]*(-2. + 1.*xi[0])))*(0.05635083268962916 + xi[1]*(-0.6127016653792583 + 1.*xi[1]))*(0.4 + xi[2]*(-1.333333333333333 + 1.*xi[2])),0,250.*(0.4 + xi[0]*(-1.333333333333333 + 1.*xi[0]))*(0.05635083268962916 + xi[1]*(-0.6127016653792583 + 1.*xi[1]))*(-0.2 + xi[2]*(1.2 + xi[2]*(-2. + 1.*xi[2])))}; } + if (i == 57) { return vec3{559.016994374947*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(0.05635083268962916 + xi[1]*(-0.6127016653792583 + 1.*xi[1]))*(0.4 + xi[2]*(-1.333333333333333 + 1.*xi[2])),0,-559.016994374947*(0.24120226591666 + xi[0]*(-1.149071198499986 + 1.*xi[0]))*(0.05635083268962916 + xi[1]*(-0.6127016653792583 + 1.*xi[1]))*(-0.2 + xi[2]*(1.2 + xi[2]*(-2. + 1.*xi[2])))}; } + if (i == 58) { return vec3{-559.016994374947*(-1. + xi[0])*(-0.27639320225002103 + xi[0])*xi[0]*(0.05635083268962916 + xi[1]*(-0.6127016653792583 + 1.*xi[1]))*(0.4 + xi[2]*(-1.333333333333333 + 1.*xi[2])),0,559.01699437495*(0.092131067416674 + xi[0]*(-0.85092880150001 + 1.*xi[0]))*(0.05635083268962916 + xi[1]*(-0.6127016653792583 + 1.*xi[1]))*(-0.2 + xi[2]*(1.2 + xi[2]*(-2. + 1.*xi[2])))}; } + if (i == 59) { return vec3{250.*xi[0]*(0.2 + xi[0]*(-1. + 1.*xi[0]))*(0.05635083268962916 + xi[1]*(-0.6127016653792583 + 1.*xi[1]))*(0.4 + xi[2]*(-1.333333333333333 + 1.*xi[2])),0,-250.*(0.0666666666666667 + xi[0]*(-0.666666666666667 + 1.*xi[0]))*(0.05635083268962916 + xi[1]*(-0.6127016653792583 + 1.*xi[1]))*(-0.2 + xi[2]*(1.2 + xi[2]*(-2. + 1.*xi[2])))}; } + if (i == 60) { return vec3{559.016994374947*(-0.2 + xi[0]*(1.2 + xi[0]*(-2. + 1.*xi[0])))*(0.44364916731037084 + xi[1]*(-1.3872983346207417 + 1.*xi[1]))*(0.2412022659166597 + xi[2]*(-1.149071198499986 + 1.*xi[2])),0,-559.016994374947*(0.4 + xi[0]*(-1.333333333333333 + 1.*xi[0]))*(0.44364916731037084 + xi[1]*(-1.3872983346207417 + 1.*xi[1]))*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2])}; } + if (i == 61) { return vec3{-1250.*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(0.44364916731037084 + xi[1]*(-1.3872983346207417 + 1.*xi[1]))*(0.2412022659166597 + xi[2]*(-1.149071198499986 + 1.*xi[2])),0,1250.*(0.24120226591666 + xi[0]*(-1.149071198499986 + 1.*xi[0]))*(0.44364916731037084 + xi[1]*(-1.3872983346207417 + 1.*xi[1]))*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2])}; } + if (i == 62) { return vec3{1250.*(-1. + xi[0])*(-0.27639320225002103 + xi[0])*xi[0]*(0.44364916731037084 + xi[1]*(-1.3872983346207417 + 1.*xi[1]))*(0.2412022659166597 + xi[2]*(-1.149071198499986 + 1.*xi[2])),0,-1250.*(0.092131067416674 + xi[0]*(-0.85092880150001 + 1.*xi[0]))*(0.44364916731037084 + xi[1]*(-1.3872983346207417 + 1.*xi[1]))*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2])}; } + if (i == 63) { return vec3{-559.016994374947*xi[0]*(0.2 + xi[0]*(-1. + 1.*xi[0]))*(0.44364916731037084 + xi[1]*(-1.3872983346207417 + 1.*xi[1]))*(0.2412022659166597 + xi[2]*(-1.149071198499986 + 1.*xi[2])),0,559.016994374947*(0.0666666666666667 + xi[0]*(-0.666666666666667 + 1.*xi[0]))*(0.44364916731037084 + xi[1]*(-1.3872983346207417 + 1.*xi[1]))*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2])}; } + if (i == 64) { return vec3{-1118.033988749895*(-0.2 + xi[0]*(1.2 + xi[0]*(-2. + 1.*xi[0])))*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831 + xi[1])*(0.2412022659166597 + xi[2]*(-1.149071198499986 + 1.*xi[2])),0,1118.033988749895*(0.4 + xi[0]*(-1.333333333333333 + 1.*xi[0]))*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831 + xi[1])*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2])}; } + if (i == 65) { return vec3{2500.*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831 + xi[1])*(0.2412022659166597 + xi[2]*(-1.149071198499986 + 1.*xi[2])),0,-2500.*(0.24120226591666 + xi[0]*(-1.149071198499986 + 1.*xi[0]))*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831 + xi[1])*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2])}; } + if (i == 66) { return vec3{-2500.*(-1. + xi[0])*(-0.27639320225002103 + xi[0])*xi[0]*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831 + xi[1])*(0.2412022659166597 + xi[2]*(-1.149071198499986 + 1.*xi[2])),0,2500.*(0.092131067416674 + xi[0]*(-0.85092880150001 + 1.*xi[0]))*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831 + xi[1])*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2])}; } + if (i == 67) { return vec3{1118.033988749895*xi[0]*(0.2 + xi[0]*(-1. + 1.*xi[0]))*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831 + xi[1])*(0.2412022659166597 + xi[2]*(-1.149071198499986 + 1.*xi[2])),0,-1118.03398874989*(0.0666666666666667 + xi[0]*(-0.666666666666667 + 1.*xi[0]))*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831 + xi[1])*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2])}; } + if (i == 68) { return vec3{559.016994374947*(-0.2 + xi[0]*(1.2 + xi[0]*(-2. + 1.*xi[0])))*(0.05635083268962916 + xi[1]*(-0.6127016653792583 + 1.*xi[1]))*(0.2412022659166597 + xi[2]*(-1.149071198499986 + 1.*xi[2])),0,-559.0169943749474*(0.4 + xi[0]*(-1.333333333333333 + 1.*xi[0]))*(0.05635083268962916 + xi[1]*(-0.6127016653792583 + 1.*xi[1]))*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2])}; } + if (i == 69) { return vec3{-1250.*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(0.05635083268962916 + xi[1]*(-0.6127016653792583 + 1.*xi[1]))*(0.2412022659166597 + xi[2]*(-1.149071198499986 + 1.*xi[2])),0,1250.*(0.24120226591666 + xi[0]*(-1.149071198499986 + 1.*xi[0]))*(0.05635083268962916 + xi[1]*(-0.6127016653792583 + 1.*xi[1]))*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2])}; } + if (i == 70) { return vec3{1250.*(-1. + xi[0])*(-0.27639320225002103 + xi[0])*xi[0]*(0.05635083268962916 + xi[1]*(-0.6127016653792583 + 1.*xi[1]))*(0.2412022659166597 + xi[2]*(-1.149071198499986 + 1.*xi[2])),0,-1250.*(0.092131067416674 + xi[0]*(-0.85092880150001 + 1.*xi[0]))*(0.05635083268962916 + xi[1]*(-0.6127016653792583 + 1.*xi[1]))*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2])}; } + if (i == 71) { return vec3{-559.016994374947*xi[0]*(0.2 + xi[0]*(-1. + 1.*xi[0]))*(0.05635083268962916 + xi[1]*(-0.6127016653792583 + 1.*xi[1]))*(0.2412022659166597 + xi[2]*(-1.149071198499986 + 1.*xi[2])),0,559.016994374947*(0.0666666666666667 + xi[0]*(-0.666666666666667 + 1.*xi[0]))*(0.05635083268962916 + xi[1]*(-0.6127016653792583 + 1.*xi[1]))*(-1. + xi[2])*xi[2]*(-0.723606797749979 + 1.*xi[2])}; } + if (i == 72) { return vec3{-559.0169943749474*(-0.2 + xi[0]*(1.2 + xi[0]*(-2. + 1.*xi[0])))*(0.44364916731037084 + xi[1]*(-1.3872983346207417 + 1.*xi[1]))*(0.0921310674166737 + xi[2]*(-0.850928801500014 + 1.*xi[2])),0,559.01699437495*(0.4 + xi[0]*(-1.333333333333333 + 1.*xi[0]))*(0.44364916731037084 + xi[1]*(-1.3872983346207417 + 1.*xi[1]))*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2]}; } + if (i == 73) { return vec3{1250.*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(0.44364916731037084 + xi[1]*(-1.3872983346207417 + 1.*xi[1]))*(0.0921310674166737 + xi[2]*(-0.850928801500014 + 1.*xi[2])),0,-1250.*(0.24120226591666 + xi[0]*(-1.149071198499986 + 1.*xi[0]))*(0.44364916731037084 + xi[1]*(-1.3872983346207417 + 1.*xi[1]))*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2]}; } + if (i == 74) { return vec3{-1250.*(-1. + xi[0])*(-0.27639320225002103 + xi[0])*xi[0]*(0.44364916731037084 + xi[1]*(-1.3872983346207417 + 1.*xi[1]))*(0.0921310674166737 + xi[2]*(-0.850928801500014 + 1.*xi[2])),0,1250.*(0.092131067416674 + xi[0]*(-0.85092880150001 + 1.*xi[0]))*(0.44364916731037084 + xi[1]*(-1.3872983346207417 + 1.*xi[1]))*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2]}; } + if (i == 75) { return vec3{559.016994374947*xi[0]*(0.2 + xi[0]*(-1. + 1.*xi[0]))*(0.44364916731037084 + xi[1]*(-1.3872983346207417 + 1.*xi[1]))*(0.0921310674166737 + xi[2]*(-0.850928801500014 + 1.*xi[2])),0,-559.01699437495*(0.0666666666666667 + xi[0]*(-0.666666666666667 + 1.*xi[0]))*(0.44364916731037084 + xi[1]*(-1.3872983346207417 + 1.*xi[1]))*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2]}; } + if (i == 76) { return vec3{1118.033988749895*(-0.2 + xi[0]*(1.2 + xi[0]*(-2. + 1.*xi[0])))*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831 + xi[1])*(0.0921310674166737 + xi[2]*(-0.850928801500014 + 1.*xi[2])),0,-1118.0339887499*(0.4 + xi[0]*(-1.333333333333333 + 1.*xi[0]))*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831 + xi[1])*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2]}; } + if (i == 77) { return vec3{-2500.*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831 + xi[1])*(0.0921310674166737 + xi[2]*(-0.850928801500014 + 1.*xi[2])),0,2500.*(0.24120226591666 + xi[0]*(-1.149071198499986 + 1.*xi[0]))*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831 + xi[1])*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2]}; } + if (i == 78) { return vec3{2500.*(-1. + xi[0])*(-0.27639320225002103 + xi[0])*xi[0]*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831 + xi[1])*(0.0921310674166737 + xi[2]*(-0.850928801500014 + 1.*xi[2])),0,-2500.*(0.092131067416674 + xi[0]*(-0.85092880150001 + 1.*xi[0]))*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831 + xi[1])*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2]}; } + if (i == 79) { return vec3{-1118.03398874989*xi[0]*(0.2 + xi[0]*(-1. + 1.*xi[0]))*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831 + xi[1])*(0.0921310674166737 + xi[2]*(-0.850928801500014 + 1.*xi[2])),0,1118.0339887499*(0.0666666666666667 + xi[0]*(-0.666666666666667 + 1.*xi[0]))*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831 + xi[1])*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2]}; } + if (i == 80) { return vec3{-559.0169943749474*(-0.2 + xi[0]*(1.2 + xi[0]*(-2. + 1.*xi[0])))*(0.05635083268962916 + xi[1]*(-0.6127016653792583 + 1.*xi[1]))*(0.0921310674166737 + xi[2]*(-0.850928801500014 + 1.*xi[2])),0,559.01699437495*(0.4 + xi[0]*(-1.333333333333333 + 1.*xi[0]))*(0.05635083268962916 + xi[1]*(-0.6127016653792583 + 1.*xi[1]))*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2]}; } + if (i == 81) { return vec3{1250.*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(0.05635083268962916 + xi[1]*(-0.6127016653792583 + 1.*xi[1]))*(0.0921310674166737 + xi[2]*(-0.850928801500014 + 1.*xi[2])),0,-1250.*(0.24120226591666 + xi[0]*(-1.149071198499986 + 1.*xi[0]))*(0.05635083268962916 + xi[1]*(-0.6127016653792583 + 1.*xi[1]))*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2]}; } + if (i == 82) { return vec3{-1250.*(-1. + xi[0])*(-0.27639320225002103 + xi[0])*xi[0]*(0.05635083268962916 + xi[1]*(-0.6127016653792583 + 1.*xi[1]))*(0.0921310674166737 + xi[2]*(-0.850928801500014 + 1.*xi[2])),0,1250.*(0.092131067416674 + xi[0]*(-0.85092880150001 + 1.*xi[0]))*(0.05635083268962916 + xi[1]*(-0.6127016653792583 + 1.*xi[1]))*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2]}; } + if (i == 83) { return vec3{559.016994374947*xi[0]*(0.2 + xi[0]*(-1. + 1.*xi[0]))*(0.05635083268962916 + xi[1]*(-0.6127016653792583 + 1.*xi[1]))*(0.0921310674166737 + xi[2]*(-0.850928801500014 + 1.*xi[2])),0,-559.01699437495*(0.0666666666666667 + xi[0]*(-0.666666666666667 + 1.*xi[0]))*(0.05635083268962916 + xi[1]*(-0.6127016653792583 + 1.*xi[1]))*(-1. + xi[2])*(-0.2763932022500210304 + xi[2])*xi[2]}; } + if (i == 84) { return vec3{250.*(-0.2 + xi[0]*(1.2 + xi[0]*(-2. + 1.*xi[0])))*(0.44364916731037084 + xi[1]*(-1.3872983346207417 + 1.*xi[1]))*(0.06666666666666667 + xi[2]*(-0.6666666666666667 + 1.*xi[2])),0,-250.*(0.4 + xi[0]*(-1.333333333333333 + 1.*xi[0]))*(0.44364916731037084 + xi[1]*(-1.3872983346207417 + 1.*xi[1]))*xi[2]*(0.2 + xi[2]*(-1. + 1.*xi[2]))}; } + if (i == 85) { return vec3{-559.016994374947*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(0.44364916731037084 + xi[1]*(-1.3872983346207417 + 1.*xi[1]))*(0.06666666666666667 + xi[2]*(-0.6666666666666667 + 1.*xi[2])),0,559.016994374947*(0.24120226591666 + xi[0]*(-1.149071198499986 + 1.*xi[0]))*(0.44364916731037084 + xi[1]*(-1.3872983346207417 + 1.*xi[1]))*xi[2]*(0.2 + xi[2]*(-1. + 1.*xi[2]))}; } + if (i == 86) { return vec3{559.016994374947*(-1. + xi[0])*(-0.27639320225002103 + xi[0])*xi[0]*(0.44364916731037084 + xi[1]*(-1.3872983346207417 + 1.*xi[1]))*(0.06666666666666667 + xi[2]*(-0.6666666666666667 + 1.*xi[2])),0,-559.016994374947*(0.092131067416674 + xi[0]*(-0.85092880150001 + 1.*xi[0]))*(0.44364916731037084 + xi[1]*(-1.3872983346207417 + 1.*xi[1]))*xi[2]*(0.2 + xi[2]*(-1. + 1.*xi[2]))}; } + if (i == 87) { return vec3{-250.*xi[0]*(0.2 + xi[0]*(-1. + 1.*xi[0]))*(0.44364916731037084 + xi[1]*(-1.3872983346207417 + 1.*xi[1]))*(0.06666666666666667 + xi[2]*(-0.6666666666666667 + 1.*xi[2])),0,250.*(0.0666666666666667 + xi[0]*(-0.666666666666667 + 1.*xi[0]))*(0.44364916731037084 + xi[1]*(-1.3872983346207417 + 1.*xi[1]))*xi[2]*(0.2 + xi[2]*(-1. + 1.*xi[2]))}; } + if (i == 88) { return vec3{-500.*(-0.2 + xi[0]*(1.2 + xi[0]*(-2. + 1.*xi[0])))*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831 + xi[1])*(0.06666666666666667 + xi[2]*(-0.6666666666666667 + 1.*xi[2])),0,500.*(0.4 + xi[0]*(-1.333333333333333 + 1.*xi[0]))*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831 + xi[1])*xi[2]*(0.2 + xi[2]*(-1. + 1.*xi[2]))}; } + if (i == 89) { return vec3{1118.03398874989*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831 + xi[1])*(0.06666666666666667 + xi[2]*(-0.6666666666666667 + 1.*xi[2])),0,-1118.03398874989*(0.24120226591666 + xi[0]*(-1.149071198499986 + 1.*xi[0]))*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831 + xi[1])*xi[2]*(0.2 + xi[2]*(-1. + 1.*xi[2]))}; } + if (i == 90) { return vec3{-1118.033988749895*(-1. + xi[0])*(-0.27639320225002103 + xi[0])*xi[0]*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831 + xi[1])*(0.06666666666666667 + xi[2]*(-0.6666666666666667 + 1.*xi[2])),0,1118.033988749895*(0.092131067416674 + xi[0]*(-0.85092880150001 + 1.*xi[0]))*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831 + xi[1])*xi[2]*(0.2 + xi[2]*(-1. + 1.*xi[2]))}; } + if (i == 91) { return vec3{500.*xi[0]*(0.2 + xi[0]*(-1. + 1.*xi[0]))*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831 + xi[1])*(0.06666666666666667 + xi[2]*(-0.6666666666666667 + 1.*xi[2])),0,-500.*(0.0666666666666667 + xi[0]*(-0.666666666666667 + 1.*xi[0]))*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831 + xi[1])*xi[2]*(0.2 + xi[2]*(-1. + 1.*xi[2]))}; } + if (i == 92) { return vec3{250.*(-0.2 + xi[0]*(1.2 + xi[0]*(-2. + 1.*xi[0])))*(0.05635083268962916 + xi[1]*(-0.6127016653792583 + 1.*xi[1]))*(0.06666666666666667 + xi[2]*(-0.6666666666666667 + 1.*xi[2])),0,-250.*(0.4 + xi[0]*(-1.333333333333333 + 1.*xi[0]))*(0.05635083268962916 + xi[1]*(-0.6127016653792583 + 1.*xi[1]))*xi[2]*(0.2 + xi[2]*(-1. + 1.*xi[2]))}; } + if (i == 93) { return vec3{-559.016994374947*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(0.05635083268962916 + xi[1]*(-0.6127016653792583 + 1.*xi[1]))*(0.06666666666666667 + xi[2]*(-0.6666666666666667 + 1.*xi[2])),0,559.016994374947*(0.24120226591666 + xi[0]*(-1.149071198499986 + 1.*xi[0]))*(0.05635083268962916 + xi[1]*(-0.6127016653792583 + 1.*xi[1]))*xi[2]*(0.2 + xi[2]*(-1. + 1.*xi[2]))}; } + if (i == 94) { return vec3{559.016994374947*(-1. + xi[0])*(-0.27639320225002103 + xi[0])*xi[0]*(0.05635083268962916 + xi[1]*(-0.6127016653792583 + 1.*xi[1]))*(0.06666666666666667 + xi[2]*(-0.6666666666666667 + 1.*xi[2])),0,-559.016994374947*(0.092131067416674 + xi[0]*(-0.85092880150001 + 1.*xi[0]))*(0.05635083268962916 + xi[1]*(-0.6127016653792583 + 1.*xi[1]))*xi[2]*(0.2 + xi[2]*(-1. + 1.*xi[2]))}; } + if (i == 95) { return vec3{-250.*xi[0]*(0.2 + xi[0]*(-1. + 1.*xi[0]))*(0.05635083268962916 + xi[1]*(-0.6127016653792583 + 1.*xi[1]))*(0.06666666666666667 + xi[2]*(-0.6666666666666667 + 1.*xi[2])),0,250.*(0.0666666666666667 + xi[0]*(-0.666666666666667 + 1.*xi[0]))*(0.05635083268962916 + xi[1]*(-0.6127016653792583 + 1.*xi[1]))*xi[2]*(0.2 + xi[2]*(-1. + 1.*xi[2]))}; } + if (i == 96) { return vec3{250.*(-0.2 + xi[0]*(1.2 + xi[0]*(-2. + 1.*xi[0])))*(0.4 + xi[1]*(-1.3333333333333333 + 1.*xi[1]))*(0.4436491673103708 + xi[2]*(-1.387298334620742 + 1.*xi[2])),-250.*(0.4 + xi[0]*(-1.333333333333333 + 1.*xi[0]))*(-0.2 + xi[1]*(1.2 + xi[1]*(-2. + 1.*xi[1])))*(0.4436491673103708 + xi[2]*(-1.387298334620742 + 1.*xi[2])),0}; } + if (i == 97) { return vec3{-559.016994374947*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(0.4 + xi[1]*(-1.3333333333333333 + 1.*xi[1]))*(0.443649167310371 + xi[2]*(-1.387298334620742 + 1.*xi[2])),559.016994374947*(0.24120226591666 + xi[0]*(-1.149071198499986 + 1.*xi[0]))*(-0.2 + xi[1]*(1.2 + xi[1]*(-2. + 1.*xi[1])))*(0.443649167310371 + xi[2]*(-1.387298334620742 + 1.*xi[2])),0}; } + if (i == 98) { return vec3{559.016994374947*(-1. + xi[0])*(-0.27639320225002103 + xi[0])*xi[0]*(0.4 + xi[1]*(-1.3333333333333333 + 1.*xi[1]))*(0.4436491673103708 + xi[2]*(-1.387298334620742 + 1.*xi[2])),-559.016994374947*(0.092131067416674 + xi[0]*(-0.85092880150001 + 1.*xi[0]))*(-0.2 + xi[1]*(1.2 + xi[1]*(-2. + 1.*xi[1])))*(0.443649167310371 + xi[2]*(-1.387298334620742 + 1.*xi[2])),0}; } + if (i == 99) { return vec3{-250.*xi[0]*(0.2 + xi[0]*(-1. + 1.*xi[0]))*(0.4 + xi[1]*(-1.3333333333333333 + 1.*xi[1]))*(0.443649167310371 + xi[2]*(-1.387298334620742 + 1.*xi[2])),250.*(0.0666666666666667 + xi[0]*(-0.666666666666667 + 1.*xi[0]))*(-0.2 + xi[1]*(1.2 + xi[1]*(-2. + 1.*xi[1])))*(0.4436491673103708 + xi[2]*(-1.387298334620742 + 1.*xi[2])),0}; } + if (i == 100) { return vec3{-559.016994374947*(-0.2 + xi[0]*(1.2 + xi[0]*(-2. + 1.*xi[0])))*(0.24120226591666 + xi[1]*(-1.149071198499986 + 1.*xi[1]))*(0.4436491673103708 + xi[2]*(-1.387298334620742 + 1.*xi[2])),559.016994374947*(0.4 + xi[0]*(-1.333333333333333 + 1.*xi[0]))*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(0.443649167310371 + xi[2]*(-1.387298334620742 + 1.*xi[2])),0}; } + if (i == 101) { return vec3{1250.*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(0.24120226591666 + xi[1]*(-1.149071198499986 + 1.*xi[1]))*(0.443649167310371 + xi[2]*(-1.387298334620742 + 1.*xi[2])),-1250.*(0.24120226591666 + xi[0]*(-1.149071198499986 + 1.*xi[0]))*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(0.443649167310371 + xi[2]*(-1.387298334620742 + 1.*xi[2])),0}; } + if (i == 102) { return vec3{-1250.*(-1. + xi[0])*(-0.27639320225002103 + xi[0])*xi[0]*(0.24120226591666 + xi[1]*(-1.149071198499986 + 1.*xi[1]))*(0.443649167310371 + xi[2]*(-1.387298334620742 + 1.*xi[2])),1250.*(0.092131067416674 + xi[0]*(-0.85092880150001 + 1.*xi[0]))*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(0.4436491673103708 + xi[2]*(-1.387298334620742 + 1.*xi[2])),0}; } + if (i == 103) { return vec3{559.016994374947*xi[0]*(0.2 + xi[0]*(-1. + 1.*xi[0]))*(0.24120226591666 + xi[1]*(-1.149071198499986 + 1.*xi[1]))*(0.443649167310371 + xi[2]*(-1.387298334620742 + 1.*xi[2])),-559.016994374947*(0.0666666666666667 + xi[0]*(-0.666666666666667 + 1.*xi[0]))*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(0.443649167310371 + xi[2]*(-1.387298334620742 + 1.*xi[2])),0}; } + if (i == 104) { return vec3{559.016994374947*(-0.2 + xi[0]*(1.2 + xi[0]*(-2. + 1.*xi[0])))*(0.0921310674166737 + xi[1]*(-0.850928801500014 + 1.*xi[1]))*(0.443649167310371 + xi[2]*(-1.387298334620742 + 1.*xi[2])),-559.01699437495*(0.4 + xi[0]*(-1.333333333333333 + 1.*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(0.443649167310371 + xi[2]*(-1.387298334620742 + 1.*xi[2])),0}; } + if (i == 105) { return vec3{-1250.*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(0.0921310674166737 + xi[1]*(-0.850928801500014 + 1.*xi[1]))*(0.4436491673103708 + xi[2]*(-1.387298334620742 + 1.*xi[2])),1250.*(0.24120226591666 + xi[0]*(-1.149071198499986 + 1.*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(0.443649167310371 + xi[2]*(-1.387298334620742 + 1.*xi[2])),0}; } + if (i == 106) { return vec3{1250.*(-1. + xi[0])*(-0.27639320225002103 + xi[0])*xi[0]*(0.0921310674166737 + xi[1]*(-0.850928801500014 + 1.*xi[1]))*(0.4436491673103708 + xi[2]*(-1.387298334620742 + 1.*xi[2])),-1250.*(0.092131067416674 + xi[0]*(-0.85092880150001 + 1.*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(0.443649167310371 + xi[2]*(-1.387298334620742 + 1.*xi[2])),0}; } + if (i == 107) { return vec3{-559.016994374947*xi[0]*(0.2 + xi[0]*(-1. + 1.*xi[0]))*(0.0921310674166737 + xi[1]*(-0.850928801500014 + 1.*xi[1]))*(0.443649167310371 + xi[2]*(-1.387298334620742 + 1.*xi[2])),559.01699437495*(0.0666666666666667 + xi[0]*(-0.666666666666667 + 1.*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(0.4436491673103708 + xi[2]*(-1.387298334620742 + 1.*xi[2])),0}; } + if (i == 108) { return vec3{-250.*(-0.2 + xi[0]*(1.2 + xi[0]*(-2. + 1.*xi[0])))*(0.0666666666666667 + xi[1]*(-0.6666666666666667 + 1.*xi[1]))*(0.443649167310371 + xi[2]*(-1.387298334620742 + 1.*xi[2])),250.*(0.4 + xi[0]*(-1.333333333333333 + 1.*xi[0]))*xi[1]*(0.2 + xi[1]*(-1. + 1.*xi[1]))*(0.443649167310371 + xi[2]*(-1.387298334620742 + 1.*xi[2])),0}; } + if (i == 109) { return vec3{559.016994374947*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(0.0666666666666667 + xi[1]*(-0.6666666666666667 + 1.*xi[1]))*(0.443649167310371 + xi[2]*(-1.387298334620742 + 1.*xi[2])),-559.016994374947*(0.24120226591666 + xi[0]*(-1.149071198499986 + 1.*xi[0]))*xi[1]*(0.2 + xi[1]*(-1. + 1.*xi[1]))*(0.4436491673103708 + xi[2]*(-1.387298334620742 + 1.*xi[2])),0}; } + if (i == 110) { return vec3{-559.016994374947*(-1. + xi[0])*(-0.27639320225002103 + xi[0])*xi[0]*(0.0666666666666667 + xi[1]*(-0.6666666666666667 + 1.*xi[1]))*(0.443649167310371 + xi[2]*(-1.387298334620742 + 1.*xi[2])),559.016994374947*(0.092131067416674 + xi[0]*(-0.85092880150001 + 1.*xi[0]))*xi[1]*(0.2 + xi[1]*(-1. + 1.*xi[1]))*(0.443649167310371 + xi[2]*(-1.387298334620742 + 1.*xi[2])),0}; } + if (i == 111) { return vec3{250.*xi[0]*(0.2 + xi[0]*(-1. + 1.*xi[0]))*(0.0666666666666667 + xi[1]*(-0.6666666666666667 + 1.*xi[1]))*(0.4436491673103708 + xi[2]*(-1.387298334620742 + 1.*xi[2])),-250.*(0.0666666666666667 + xi[0]*(-0.666666666666667 + 1.*xi[0]))*xi[1]*(0.2 + xi[1]*(-1. + 1.*xi[1]))*(0.443649167310371 + xi[2]*(-1.387298334620742 + 1.*xi[2])),0}; } + if (i == 112) { return vec3{-500.*(-0.2 + xi[0]*(1.2 + xi[0]*(-2. + 1.*xi[0])))*(0.4 + xi[1]*(-1.3333333333333333 + 1.*xi[1]))*(-0.887298334620742 + xi[2])*(-0.11270166537925831 + xi[2]),500.*(0.4 + xi[0]*(-1.333333333333333 + 1.*xi[0]))*(-0.2 + xi[1]*(1.2 + xi[1]*(-2. + 1.*xi[1])))*(-0.887298334620742 + xi[2])*(-0.11270166537925831 + xi[2]),0}; } + if (i == 113) { return vec3{1118.03398874989*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(0.4 + xi[1]*(-1.3333333333333333 + 1.*xi[1]))*(-0.887298334620742 + xi[2])*(-0.11270166537925831 + xi[2]),-1118.03398874989*(0.24120226591666 + xi[0]*(-1.149071198499986 + 1.*xi[0]))*(-0.2 + xi[1]*(1.2 + xi[1]*(-2. + 1.*xi[1])))*(-0.887298334620742 + xi[2])*(-0.11270166537925831 + xi[2]),0}; } + if (i == 114) { return vec3{-1118.033988749895*(-1. + xi[0])*(-0.27639320225002103 + xi[0])*xi[0]*(0.4 + xi[1]*(-1.3333333333333333 + 1.*xi[1]))*(-0.887298334620742 + xi[2])*(-0.11270166537925831 + xi[2]),1118.033988749895*(0.092131067416674 + xi[0]*(-0.85092880150001 + 1.*xi[0]))*(-0.2 + xi[1]*(1.2 + xi[1]*(-2. + 1.*xi[1])))*(-0.887298334620742 + xi[2])*(-0.11270166537925831 + xi[2]),0}; } + if (i == 115) { return vec3{500.*xi[0]*(0.2 + xi[0]*(-1. + 1.*xi[0]))*(0.4 + xi[1]*(-1.3333333333333333 + 1.*xi[1]))*(-0.887298334620742 + xi[2])*(-0.11270166537925831 + xi[2]),-500.*(0.0666666666666667 + xi[0]*(-0.666666666666667 + 1.*xi[0]))*(-0.2 + xi[1]*(1.2 + xi[1]*(-2. + 1.*xi[1])))*(-0.887298334620742 + xi[2])*(-0.11270166537925831 + xi[2]),0}; } + if (i == 116) { return vec3{1118.03398874989*(-0.2 + xi[0]*(1.2 + xi[0]*(-2. + 1.*xi[0])))*(0.24120226591666 + xi[1]*(-1.149071198499986 + 1.*xi[1]))*(-0.887298334620742 + xi[2])*(-0.11270166537925831 + xi[2]),-1118.033988749895*(0.4 + xi[0]*(-1.333333333333333 + 1.*xi[0]))*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(-0.887298334620742 + xi[2])*(-0.11270166537925831 + xi[2]),0}; } + if (i == 117) { return vec3{-2500.*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(0.24120226591666 + xi[1]*(-1.149071198499986 + 1.*xi[1]))*(-0.887298334620742 + xi[2])*(-0.11270166537925831 + xi[2]),2500.*(0.24120226591666 + xi[0]*(-1.149071198499986 + 1.*xi[0]))*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(-0.887298334620742 + xi[2])*(-0.11270166537925831 + xi[2]),0}; } + if (i == 118) { return vec3{2500.*(-1. + xi[0])*(-0.27639320225002103 + xi[0])*xi[0]*(0.24120226591666 + xi[1]*(-1.149071198499986 + 1.*xi[1]))*(-0.887298334620742 + xi[2])*(-0.11270166537925831 + xi[2]),-2500.*(0.092131067416674 + xi[0]*(-0.85092880150001 + 1.*xi[0]))*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(-0.887298334620742 + xi[2])*(-0.11270166537925831 + xi[2]),0}; } + if (i == 119) { return vec3{-1118.03398874989*xi[0]*(0.2 + xi[0]*(-1. + 1.*xi[0]))*(0.24120226591666 + xi[1]*(-1.149071198499986 + 1.*xi[1]))*(-0.887298334620742 + xi[2])*(-0.11270166537925831 + xi[2]),1118.03398874989*(0.0666666666666667 + xi[0]*(-0.666666666666667 + 1.*xi[0]))*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(-0.887298334620742 + xi[2])*(-0.11270166537925831 + xi[2]),0}; } + if (i == 120) { return vec3{-1118.033988749895*(-0.2 + xi[0]*(1.2 + xi[0]*(-2. + 1.*xi[0])))*(0.0921310674166737 + xi[1]*(-0.850928801500014 + 1.*xi[1]))*(-0.887298334620742 + xi[2])*(-0.11270166537925831 + xi[2]),1118.0339887499*(0.4 + xi[0]*(-1.333333333333333 + 1.*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(-0.88729833462074 + xi[2])*(-0.11270166537925831 + xi[2]),0}; } + if (i == 121) { return vec3{2500.*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(0.0921310674166737 + xi[1]*(-0.850928801500014 + 1.*xi[1]))*(-0.887298334620742 + xi[2])*(-0.11270166537925831 + xi[2]),-2500.*(0.24120226591666 + xi[0]*(-1.149071198499986 + 1.*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(-0.887298334620742 + xi[2])*(-0.11270166537925831 + xi[2]),0}; } + if (i == 122) { return vec3{-2500.*(-1. + xi[0])*(-0.27639320225002103 + xi[0])*xi[0]*(0.0921310674166737 + xi[1]*(-0.850928801500014 + 1.*xi[1]))*(-0.887298334620742 + xi[2])*(-0.11270166537925831 + xi[2]),2500.*(0.092131067416674 + xi[0]*(-0.85092880150001 + 1.*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(-0.88729833462074 + xi[2])*(-0.11270166537925831 + xi[2]),0}; } + if (i == 123) { return vec3{1118.03398874989*xi[0]*(0.2 + xi[0]*(-1. + 1.*xi[0]))*(0.0921310674166737 + xi[1]*(-0.850928801500014 + 1.*xi[1]))*(-0.887298334620742 + xi[2])*(-0.11270166537925831 + xi[2]),-1118.0339887499*(0.0666666666666667 + xi[0]*(-0.666666666666667 + 1.*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(-0.88729833462074 + xi[2])*(-0.11270166537925831 + xi[2]),0}; } + if (i == 124) { return vec3{500.*(-0.2 + xi[0]*(1.2 + xi[0]*(-2. + 1.*xi[0])))*(0.0666666666666667 + xi[1]*(-0.6666666666666667 + 1.*xi[1]))*(-0.887298334620742 + xi[2])*(-0.11270166537925831 + xi[2]),-500.*(0.4 + xi[0]*(-1.333333333333333 + 1.*xi[0]))*xi[1]*(0.2 + xi[1]*(-1. + 1.*xi[1]))*(-0.887298334620742 + xi[2])*(-0.11270166537925831 + xi[2]),0}; } + if (i == 125) { return vec3{-1118.03398874989*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(0.0666666666666667 + xi[1]*(-0.6666666666666667 + 1.*xi[1]))*(-0.887298334620742 + xi[2])*(-0.11270166537925831 + xi[2]),1118.03398874989*(0.24120226591666 + xi[0]*(-1.149071198499986 + 1.*xi[0]))*xi[1]*(0.2 + xi[1]*(-1. + 1.*xi[1]))*(-0.887298334620742 + xi[2])*(-0.11270166537925831 + xi[2]),0}; } + if (i == 126) { return vec3{1118.033988749895*(-1. + xi[0])*(-0.27639320225002103 + xi[0])*xi[0]*(0.0666666666666667 + xi[1]*(-0.6666666666666667 + 1.*xi[1]))*(-0.88729833462074 + xi[2])*(-0.11270166537925831 + xi[2]),-1118.033988749895*(0.092131067416674 + xi[0]*(-0.85092880150001 + 1.*xi[0]))*xi[1]*(0.2 + xi[1]*(-1. + 1.*xi[1]))*(-0.887298334620742 + xi[2])*(-0.11270166537925831 + xi[2]),0}; } + if (i == 127) { return vec3{-500.*xi[0]*(0.2 + xi[0]*(-1. + 1.*xi[0]))*(0.0666666666666667 + xi[1]*(-0.6666666666666667 + 1.*xi[1]))*(-0.887298334620742 + xi[2])*(-0.11270166537925831 + xi[2]),500.*(0.0666666666666667 + xi[0]*(-0.666666666666667 + 1.*xi[0]))*xi[1]*(0.2 + xi[1]*(-1. + 1.*xi[1]))*(-0.887298334620742 + xi[2])*(-0.11270166537925831 + xi[2]),0}; } + if (i == 128) { return vec3{250.*(-0.2 + xi[0]*(1.2 + xi[0]*(-2. + 1.*xi[0])))*(0.4 + xi[1]*(-1.3333333333333333 + 1.*xi[1]))*(0.05635083268962916 + xi[2]*(-0.6127016653792583 + 1.*xi[2])),-250.*(0.4 + xi[0]*(-1.333333333333333 + 1.*xi[0]))*(-0.2 + xi[1]*(1.2 + xi[1]*(-2. + 1.*xi[1])))*(0.05635083268962916 + xi[2]*(-0.6127016653792583 + 1.*xi[2])),0}; } + if (i == 129) { return vec3{-559.016994374947*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(0.4 + xi[1]*(-1.3333333333333333 + 1.*xi[1]))*(0.05635083268962916 + xi[2]*(-0.6127016653792583 + 1.*xi[2])),559.016994374947*(0.24120226591666 + xi[0]*(-1.149071198499986 + 1.*xi[0]))*(-0.2 + xi[1]*(1.2 + xi[1]*(-2. + 1.*xi[1])))*(0.05635083268962916 + xi[2]*(-0.6127016653792583 + 1.*xi[2])),0}; } + if (i == 130) { return vec3{559.016994374947*(-1. + xi[0])*(-0.27639320225002103 + xi[0])*xi[0]*(0.4 + xi[1]*(-1.3333333333333333 + 1.*xi[1]))*(0.05635083268962916 + xi[2]*(-0.6127016653792583 + 1.*xi[2])),-559.01699437495*(0.092131067416674 + xi[0]*(-0.85092880150001 + 1.*xi[0]))*(-0.2 + xi[1]*(1.2 + xi[1]*(-2. + 1.*xi[1])))*(0.05635083268962916 + xi[2]*(-0.6127016653792583 + 1.*xi[2])),0}; } + if (i == 131) { return vec3{-250.*xi[0]*(0.2 + xi[0]*(-1. + 1.*xi[0]))*(0.4 + xi[1]*(-1.3333333333333333 + 1.*xi[1]))*(0.05635083268962916 + xi[2]*(-0.6127016653792583 + 1.*xi[2])),250.*(0.0666666666666667 + xi[0]*(-0.666666666666667 + 1.*xi[0]))*(-0.2 + xi[1]*(1.2 + xi[1]*(-2. + 1.*xi[1])))*(0.05635083268962916 + xi[2]*(-0.6127016653792583 + 1.*xi[2])),0}; } + if (i == 132) { return vec3{-559.016994374947*(-0.2 + xi[0]*(1.2 + xi[0]*(-2. + 1.*xi[0])))*(0.24120226591666 + xi[1]*(-1.149071198499986 + 1.*xi[1]))*(0.05635083268962916 + xi[2]*(-0.6127016653792583 + 1.*xi[2])),559.016994374947*(0.4 + xi[0]*(-1.333333333333333 + 1.*xi[0]))*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(0.05635083268962916 + xi[2]*(-0.6127016653792583 + 1.*xi[2])),0}; } + if (i == 133) { return vec3{1250.*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(0.24120226591666 + xi[1]*(-1.149071198499986 + 1.*xi[1]))*(0.05635083268962916 + xi[2]*(-0.6127016653792583 + 1.*xi[2])),-1250.*(0.24120226591666 + xi[0]*(-1.149071198499986 + 1.*xi[0]))*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(0.05635083268962916 + xi[2]*(-0.6127016653792583 + 1.*xi[2])),0}; } + if (i == 134) { return vec3{-1250.*(-1. + xi[0])*(-0.27639320225002103 + xi[0])*xi[0]*(0.24120226591666 + xi[1]*(-1.149071198499986 + 1.*xi[1]))*(0.05635083268962916 + xi[2]*(-0.6127016653792583 + 1.*xi[2])),1250.*(0.092131067416674 + xi[0]*(-0.85092880150001 + 1.*xi[0]))*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(0.05635083268962916 + xi[2]*(-0.6127016653792583 + 1.*xi[2])),0}; } + if (i == 135) { return vec3{559.016994374947*xi[0]*(0.2 + xi[0]*(-1. + 1.*xi[0]))*(0.24120226591666 + xi[1]*(-1.149071198499986 + 1.*xi[1]))*(0.05635083268962916 + xi[2]*(-0.6127016653792583 + 1.*xi[2])),-559.016994374947*(0.0666666666666667 + xi[0]*(-0.666666666666667 + 1.*xi[0]))*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1])*(0.05635083268962916 + xi[2]*(-0.6127016653792583 + 1.*xi[2])),0}; } + if (i == 136) { return vec3{559.0169943749474*(-0.2 + xi[0]*(1.2 + xi[0]*(-2. + 1.*xi[0])))*(0.0921310674166737 + xi[1]*(-0.850928801500014 + 1.*xi[1]))*(0.05635083268962916 + xi[2]*(-0.6127016653792583 + 1.*xi[2])),-559.01699437495*(0.4 + xi[0]*(-1.333333333333333 + 1.*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(0.05635083268962916 + xi[2]*(-0.6127016653792583 + 1.*xi[2])),0}; } + if (i == 137) { return vec3{-1250.*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(0.0921310674166737 + xi[1]*(-0.850928801500014 + 1.*xi[1]))*(0.05635083268962916 + xi[2]*(-0.6127016653792583 + 1.*xi[2])),1250.*(0.24120226591666 + xi[0]*(-1.149071198499986 + 1.*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(0.05635083268962916 + xi[2]*(-0.6127016653792583 + 1.*xi[2])),0}; } + if (i == 138) { return vec3{1250.*(-1. + xi[0])*(-0.27639320225002103 + xi[0])*xi[0]*(0.0921310674166737 + xi[1]*(-0.850928801500014 + 1.*xi[1]))*(0.05635083268962916 + xi[2]*(-0.6127016653792583 + 1.*xi[2])),-1250.*(0.092131067416674 + xi[0]*(-0.85092880150001 + 1.*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(0.05635083268962916 + xi[2]*(-0.6127016653792583 + 1.*xi[2])),0}; } + if (i == 139) { return vec3{-559.016994374947*xi[0]*(0.2 + xi[0]*(-1. + 1.*xi[0]))*(0.0921310674166737 + xi[1]*(-0.850928801500014 + 1.*xi[1]))*(0.05635083268962916 + xi[2]*(-0.6127016653792583 + 1.*xi[2])),559.01699437495*(0.0666666666666667 + xi[0]*(-0.666666666666667 + 1.*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1]*(0.05635083268962916 + xi[2]*(-0.6127016653792583 + 1.*xi[2])),0}; } + if (i == 140) { return vec3{-250.*(-0.2 + xi[0]*(1.2 + xi[0]*(-2. + 1.*xi[0])))*(0.0666666666666667 + xi[1]*(-0.6666666666666667 + 1.*xi[1]))*(0.05635083268962916 + xi[2]*(-0.6127016653792583 + 1.*xi[2])),250.*(0.4 + xi[0]*(-1.333333333333333 + 1.*xi[0]))*xi[1]*(0.2 + xi[1]*(-1. + 1.*xi[1]))*(0.05635083268962916 + xi[2]*(-0.6127016653792583 + 1.*xi[2])),0}; } + if (i == 141) { return vec3{559.016994374947*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(0.0666666666666667 + xi[1]*(-0.6666666666666667 + 1.*xi[1]))*(0.05635083268962916 + xi[2]*(-0.6127016653792583 + 1.*xi[2])),-559.016994374947*(0.24120226591666 + xi[0]*(-1.149071198499986 + 1.*xi[0]))*xi[1]*(0.2 + xi[1]*(-1. + 1.*xi[1]))*(0.05635083268962916 + xi[2]*(-0.6127016653792583 + 1.*xi[2])),0}; } + if (i == 142) { return vec3{-559.016994374947*(-1. + xi[0])*(-0.27639320225002103 + xi[0])*xi[0]*(0.0666666666666667 + xi[1]*(-0.6666666666666667 + 1.*xi[1]))*(0.05635083268962916 + xi[2]*(-0.6127016653792583 + 1.*xi[2])),559.016994374947*(0.092131067416674 + xi[0]*(-0.85092880150001 + 1.*xi[0]))*xi[1]*(0.2 + xi[1]*(-1. + 1.*xi[1]))*(0.05635083268962916 + xi[2]*(-0.6127016653792583 + 1.*xi[2])),0}; } + if (i == 143) { return vec3{250.*xi[0]*(0.2 + xi[0]*(-1. + 1.*xi[0]))*(0.0666666666666667 + xi[1]*(-0.6666666666666667 + 1.*xi[1]))*(0.05635083268962916 + xi[2]*(-0.6127016653792583 + 1.*xi[2])),-250.*(0.0666666666666667 + xi[0]*(-0.666666666666667 + 1.*xi[0]))*xi[1]*(0.2 + xi[1]*(-1. + 1.*xi[1]))*(0.05635083268962916 + xi[2]*(-0.6127016653792583 + 1.*xi[2])),0}; } + } + + return {}; + } + + constexpr vec3 reoriented_shape_function_curl(vec3 xi, uint32_t i, int8_t transformation) const { + if (transformation == -1) { + return -shape_function_curl(xi, i); + } else { + return shape_function_curl(xi, i); + } + } + + constexpr vec3 shape_function_derivative(vec3 xi, uint32_t i) const { + return shape_function_curl(xi, i); + } + + double shape_function_div(vec3 xi, uint32_t i) { + // expressions generated symbolically by mathematica + if (p == 1) { + return 0.0; + } + + return {}; + } + + vec3 interpolate(vec3 xi, const double * values) { + vec3 interpolated_value{}; + for (int i = 0; i < num_nodes(); i++) { + interpolated_value += values[i] * shape_function(xi, i); + } + return interpolated_value; + } + + vec3 curl(vec3 xi, const double * values) { + vec3 interpolated_curl{}; + for (int i = 0; i < num_nodes(); i++) { + interpolated_curl += values[i] * shape_function_curl(xi, i); + } + return interpolated_curl; + } + + // TODO: set to nonzero when reenabling sum-factorization implementations + __host__ __device__ uint32_t batch_interpolation_scratch_space(nd::view xi) const { + return 0; + } + +#if 0 + + // sum-factorization implementations + + nd::array< double > evaluate_shape_functions(nd::view xi) { + uint32_t q = xi.shape[0]; + nd::array buffer({q * (2 * p + 1)}); + for (int i = 0; i < q; i++) { + GaussLegendreInterpolation(xi(i, 0), p, &buffer(p * i)); + GaussLobattoInterpolation(xi(i, 0), p+1, &buffer(q * p + p * i)); + } + return buffer; + } + + void interpolate(nd::view values_q, nd::view values_e, nd::view buffer) { + uint32_t n = p + 1; + uint32_t q = values_q.shape[0]; + + // 1D shape function evaluations + nd::view B1(buffer.data(), {q, p}); // legendre shape functions + nd::view B2(B1.end(), {q, p+1}); // lobatto shape functions + nd::view A1(B2.end(), {q, p+1, p+1}); // storage for intermediates + nd::view A2(A1.end(), {q, q, p+1}); // storage for intermediates + + for (int d = 0; d < 3; d++) { + nd::view ue(values_e.data() + (n * n * p * d), {n, n, p}); + nd::view uq = nd::reshape<3>(values_q(d), {q, q, q}); + + contract(ue, B1, A1); // A1(qx, iz, iy) = sum_{ix} ue(iz, iy, ix) * B1(qx, ix) + contract(A1, B2, A2); // A2(qy, qx, iz) = sum_{iy} A1(qx, iz, iy) * B2(qy, iy) + contract(A2, B2, uq); // uq(qz, qy, qx) = sum_{iz} A2(qy, qx, iz) * B2(qz, iz) + } + } + + nd::array< double > evaluate_shape_function_curls(nd::view xi) { + uint32_t q = xi.shape[0]; + nd::array buffer({q * (3 * p + 2)}); + for (int i = 0; i < q; i++) { + GaussLegendreInterpolation(xi(i, 0), p, &buffer(p * i)); + GaussLobattoInterpolation(xi(i, 0), p+1, &buffer(q * p + p * i)); + GaussLobattoInterpolationDerivative(xi(i, 0), p+1, &buffer(q * p + p * i)); + } + return buffer; + } + + void curl(nd::view values_q, nd::view values_e, nd::view buffer) { + uint32_t n = p + 1; + uint32_t q = values_q.shape[0]; + + // 1D shape function evaluations + nd::view B1(buffer.data(), {q, p}); // legendre shape functions + nd::view B2(B1.end(), {q, p+1}); // lobatto shape functions + nd::view A1(B2.end(), {q, p+1, p+1}); // storage for intermediates + nd::view A2(A1.end(), {q, q, p+1}); // storage for intermediates + + for (int d = 0; d < 3; d++) { + nd::view ue(values_e.data() + (n * n * p * d), {n, n, p}); + nd::view uq = nd::reshape<3>(values_q(d), {q, q, q}); + + contract(ue, B1, A1); // A1(qx, iz, iy) = sum_{ix} ue(iz, iy, ix) * B1(qx, ix) + contract(A1, B2, A2); // A2(qy, qx, iz) = sum_{iy} A1(qx, iz, iy) * B2(qy, iy) + contract(A2, B2, uq); // uq(qz, qy, qx) = sum_{iz} A2(qy, qx, iz) * B2(qz, iz) + } + } +#else + + // non-sum-factorization implementations + + nd::array< double, 3 > evaluate_shape_functions(nd::view xi) { + uint32_t q = xi.shape[0]; + nd::array shape_fns({q * q * q, num_nodes(), 3}); + uint32_t qcount = 0; + for (int k = 0; k < q; k++) { + for (int j = 0; j < q; j++) { + for (int i = 0; i < q; i++) { + vec3 xi_ijk = vec3{xi(i, 0), xi(j, 0), xi(k, 0)}; + for (int l = 0; l < num_nodes(); l++) { + vec3 phi = shape_function(xi_ijk, l); + shape_fns(qcount, l, 0) = phi[0]; + shape_fns(qcount, l, 1) = phi[1]; + shape_fns(qcount, l, 2) = phi[2]; + } + qcount++; + } + } + } + return shape_fns; + } + + void interpolate(nd::view values_q, nd::view values_e, nd::view shape_fns, double * /*buffer*/) { + int nnodes = num_nodes(); + int nqpts = values_q.shape[0]; + + for (int q = 0; q < nqpts; q++) { + value_type sum{}; + for (int i = 0; i < nnodes; i++) { + for (int c = 0; c < 3; c++) { + sum[c] += shape_fns(q, i, c) * values_e(i); + } + } + values_q(q) = sum; + } + } + + nd::array< double, 3 > evaluate_shape_function_curls(nd::view xi) { + uint32_t q = xi.shape[0]; + nd::array shape_fns({q * q * q, num_nodes(), 3}); + uint32_t qcount = 0; + for (int k = 0; k < q; k++) { + for (int j = 0; j < q; j++) { + for (int i = 0; i < q; i++) { + vec3 xi_ijk = vec3{xi(i, 0), xi(j, 0), xi(k, 0)}; + for (int l = 0; l < num_nodes(); l++) { + vec3 curl_phi = shape_function_curl(xi_ijk, l); + shape_fns(qcount, l, 0) = curl_phi[0]; + shape_fns(qcount, l, 1) = curl_phi[1]; + shape_fns(qcount, l, 2) = curl_phi[2]; + } + qcount++; + } + } + } + return shape_fns; + } + + void curl(nd::view values_q, nd::view values_e, nd::view shape_fn_curls, double * /*buffer*/) { + int nnodes = num_nodes(); + int nqpts = values_q.shape[0]; + + for (int q = 0; q < nqpts; q++) { + derivative_type sum{}; + for (int i = 0; i < nnodes; i++) { + for (int c = 0; c < 3; c++) { + sum[c] += shape_fn_curls(q, i, c) * values_e(i); + } + } + values_q(q) = sum; + } + } + + nd::array< double, 3 > evaluate_weighted_shape_functions(nd::view xi, nd::view weights) { + uint32_t q = xi.shape[0]; + nd::array shape_fns({q * q * q, num_nodes(), dim}); + uint32_t qcount = 0; + for (int k = 0; k < q; k++) { + for (int j = 0; j < q; j++) { + for (int i = 0; i < q; i++) { + vec3 xi_ijk = vec3{xi(i, 0), xi(j, 0), xi(k, 0)}; + for (int l = 0; l < num_nodes(); l++) { + vec3 phi = shape_function(xi_ijk, l); + shape_fns(qcount, l, 0) = phi[0] * weights[i] * weights[j] * weights[k]; + shape_fns(qcount, l, 1) = phi[1] * weights[i] * weights[j] * weights[k]; + shape_fns(qcount, l, 2) = phi[2] * weights[i] * weights[j] * weights[k]; + } + qcount++; + } + } + } + return shape_fns; + } + + __host__ __device__ void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fn, double * /* buffer */) const { + int nnodes = num_nodes(); + int nqpts = source_q.shape[0]; + + for (int i = 0; i < nnodes; i++) { + double sum = 0.0; + for (int q = 0; q < nqpts; q++) { + for (int j = 0; j < dim; j++) { + sum += shape_fn(q, i, j) * source_q(q)[j]; + } + } + residual_e(i) = sum; + } + } + + nd::array< double, 3 > evaluate_weighted_shape_function_curls(nd::view xi, nd::view weights) { + uint32_t q = xi.shape[0]; + nd::array shape_fns({q * q * q, num_nodes(), dim}); + uint32_t qcount = 0; + for (int k = 0; k < q; k++) { + for (int j = 0; j < q; j++) { + for (int i = 0; i < q; i++) { + vec3 xi_ijk = vec3{xi(i, 0), xi(j, 0), xi(k, 0)}; + for (int l = 0; l < num_nodes(); l++) { + vec3 dphi = shape_function_curl(xi_ijk, l); + shape_fns(qcount, l, 0) = dphi[0] * weights[i] * weights[j] * weights[k]; + shape_fns(qcount, l, 1) = dphi[1] * weights[i] * weights[j] * weights[k]; + shape_fns(qcount, l, 2) = dphi[2] * weights[i] * weights[j] * weights[k]; + } + qcount++; + } + } + } + return shape_fns; + } + + void integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fn_curl, double * /*buffer*/) const { + int nnodes = num_nodes(); + int nqpts = flux_q.shape[0]; + + for (int i = 0; i < nnodes; i++) { + double sum = 0.0; + for (int q = 0; q < nqpts; q++) { + for (int j = 0; j < dim; j++) { + sum += shape_fn_curl(q, i, j) * flux_q(q)[j]; + } + } + residual_e(i) = sum; + } + } + + #ifdef __CUDACC__ + __device__ void cuda_integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fn_curl, double * /*buffer*/) const { + int nnodes = num_nodes(); + int nqpts = flux_q.shape[0]; + + for (int i = threadIdx.x; i < nnodes; i += blockDim.x) { + double sum = 0.0; + for (int q = 0; q < nqpts; q++) { + for (int d = 0; d < dim; d++) { + sum += shape_fn_curl(q, i, d) * flux_q(q)[d]; + } + } + residual_e(i) = sum; + } + } + #endif + +#endif + + uint32_t p; + +}; +// clang-format on + +} // namespace refactor diff --git a/src/serac/numerics/refactor/elements/hcurl_quadrilateral.hpp b/src/serac/numerics/refactor/elements/hcurl_quadrilateral.hpp new file mode 100644 index 0000000000..4db3c264ce --- /dev/null +++ b/src/serac/numerics/refactor/elements/hcurl_quadrilateral.hpp @@ -0,0 +1,611 @@ +#pragma once + +#include "fm/types/vec.hpp" + +namespace refactor { + +using namespace fm; + +// clang-format off +template <> +struct FiniteElement { + + using value_type = vec2; + using derivative_type = vec1; + + using source_type = vec2; + using flux_type = vec1; + + static constexpr int dim = 2; + + __host__ __device__ uint32_t num_nodes() const { return 2 * p * (p + 1); } + + void nodes(nd::view xi) const { + if (p == 1) { + xi(0, 0) = 0.5; xi(0, 1) = 0; + xi(1, 0) = 0.5; xi(1, 1) = 1.0; + xi(2, 0) = 0; xi(2, 1) = 0.5; + xi(3, 0) = 1.0; xi(3, 1) = 0.5; + } + if (p == 2) { + xi(0, 0) = 0.21132486540518711775; xi(0, 1) = 0; + xi(1, 0) = 0.78867513459481288225; xi(1, 1) = 0; + xi(2, 0) = 0.21132486540518711775; xi(2, 1) = 0.5; + xi(3, 0) = 0.78867513459481288225; xi(3, 1) = 0.5; + xi(4, 0) = 0.21132486540518711775; xi(4, 1) = 1.0; + xi(5, 0) = 0.78867513459481288225; xi(5, 1) = 1.0; + xi(6, 0) = 0; xi(6, 1) = 0.21132486540518711775; + xi(7, 0) = 0; xi(7, 1) = 0.78867513459481288225; + xi(8, 0) = 0.5; xi(8, 1) = 0.21132486540518711775; + xi(9, 0) = 0.5; xi(9, 1) = 0.78867513459481288225; + xi(10, 0) = 1.0; xi(10, 1) = 0.21132486540518711775; + xi(11, 0) = 1.0; xi(11, 1) = 0.78867513459481288225; + } + if (p == 3) { + xi(0, 0) = 0.11270166537925831148; xi(0, 1) = 0; + xi(1, 0) = 0.5; xi(1, 1) = 0; + xi(2, 0) = 0.88729833462074168852; xi(2, 1) = 0; + xi(3, 0) = 0.11270166537925831148; xi(3, 1) = 0.27639320225002103036; + xi(4, 0) = 0.5; xi(4, 1) = 0.27639320225002103036; + xi(5, 0) = 0.88729833462074168852; xi(5, 1) = 0.27639320225002103036; + xi(6, 0) = 0.11270166537925831148; xi(6, 1) = 0.72360679774997896964; + xi(7, 0) = 0.5; xi(7, 1) = 0.72360679774997896964; + xi(8, 0) = 0.88729833462074168852; xi(8, 1) = 0.72360679774997896964; + xi(9, 0) = 0.11270166537925831148; xi(9, 1) = 1.0; + xi(10, 0) = 0.5; xi(10, 1) = 1.0; + xi(11, 0) = 0.88729833462074168852; xi(11, 1) = 1.0; + xi(12, 0) = 0; xi(12, 1) = 0.11270166537925831148; + xi(13, 0) = 0; xi(13, 1) = 0.5; + xi(14, 0) = 0; xi(14, 1) = 0.88729833462074168852; + xi(15, 0) = 0.27639320225002103036; xi(15, 1) = 0.11270166537925831148; + xi(16, 0) = 0.27639320225002103036; xi(16, 1) = 0.5; + xi(17, 0) = 0.27639320225002103036; xi(17, 1) = 0.88729833462074168852; + xi(18, 0) = 0.72360679774997896964; xi(18, 1) = 0.11270166537925831148; + xi(19, 0) = 0.72360679774997896964; xi(19, 1) = 0.5; + xi(20, 0) = 0.72360679774997896964; xi(20, 1) = 0.88729833462074168852; + xi(21, 0) = 1.0; xi(21, 1) = 0.11270166537925831148; + xi(22, 0) = 1.0; xi(22, 1) = 0.5; + xi(23, 0) = 1.0; xi(23, 1) = 0.88729833462074168852; + } + } + + void directions(nd::view d) const { + int i = 0; + for (int k = 0; k < (p * (p + 1)); k++) { d(i, 0) = 1.0; d(i++, 1) = 0.0; } + for (int k = 0; k < (p * (p + 1)); k++) { d(i, 0) = 0.0; d(i++, 1) = 1.0; } + } + + __host__ __device__ uint32_t num_interior_nodes() const { return (p > 1) ? 2 * p * (p - 1) : 0; } + + void interior_nodes(nd::view xi) const { + if (p == 2) { + xi(0, 0) = 0.21132486540518711775; xi(0, 1) = 0.5; + xi(1, 0) = 0.78867513459481288225; xi(1, 1) = 0.5; + xi(2, 0) = 0.5; xi(2, 1) = 0.21132486540518711775; + xi(3, 0) = 0.5; xi(3, 1) = 0.78867513459481288225; + } + if (p == 3) { + xi(0, 0) = 0.11270166537925831148; xi(0, 1) = 0.27639320225002103036; + xi(1, 0) = 0.5; xi(1, 1) = 0.27639320225002103036; + xi(2, 0) = 0.88729833462074168852; xi(2, 1) = 0.27639320225002103036; + xi(3, 0) = 0.11270166537925831148; xi(3, 1) = 0.72360679774997896964; + xi(4, 0) = 0.5; xi(4, 1) = 0.72360679774997896964; + xi(5, 0) = 0.88729833462074168852; xi(5, 1) = 0.72360679774997896964; + xi(6, 0) = 0.27639320225002103036; xi(6, 1) = 0.11270166537925831148; + xi(7, 0) = 0.27639320225002103036; xi(7, 1) = 0.5; + xi(8, 0) = 0.27639320225002103036; xi(8, 1) = 0.88729833462074168852; + xi(9, 0) = 0.72360679774997896964; xi(9, 1) = 0.11270166537925831148; + xi(10, 0) = 0.72360679774997896964; xi(10, 1) = 0.5; + xi(11, 0) = 0.72360679774997896964; xi(11, 1) = 0.88729833462074168852; + } + } + + void interior_directions(nd::view d) const { + if (p > 1) { + int i = 0; + for (int k = 0; k < (p * (p - 1)); k++) { d(i, 0) = 1.0; d(i++, 1) = 0.0; } + for (int k = 0; k < (p * (p - 1)); k++) { d(i, 0) = 0.0; d(i++, 1) = 1.0; } + } + } + + __host__ __device__ void indices(const GeometryInfo & offsets, const Connection * quad, uint32_t * indices) const { + + const Connection * edge = quad + Quadrilateral::edge_offset; + const Connection cell = *(quad + Quadrilateral::cell_offset); + + if (p == 1) { + + // o-----→-----o o-----1-----o + // | | | | + // | | | | + // ↑ ↑ 2 3 + // | | | | + // | | | | + // o-----→-----o o-----0-----o + indices[0] = offsets.edge + edge[0].index; + indices[1] = offsets.edge + edge[2].index; + indices[2] = offsets.edge + edge[3].index; + indices[3] = offsets.edge + edge[1].index; + return; + + } + + if (p == 2) { + + // o---→---→---o o---4---5---o + // | | | | + // ↑ ↑ ↑ 7 9 11 + // | → → | | 2 3 | + // ↑ ↑ ↑ 6 8 10 + // | | | | + // o---→---→---o o---0---1---o + indices[0] = offsets.edge + 2 * edge[0].index + 0; + indices[1] = offsets.edge + 2 * edge[0].index + 1; + indices[2] = offsets.quad + 4 * cell.index + 0; + indices[3] = offsets.quad + 4 * cell.index + 1; + indices[4] = offsets.edge + 2 * edge[2].index + 1; + indices[5] = offsets.edge + 2 * edge[2].index + 0; + + indices[ 6] = offsets.edge + 2 * edge[3].index + 1; + indices[ 7] = offsets.edge + 2 * edge[3].index + 0; + indices[ 8] = offsets.quad + 4 * cell.index + 2; + indices[ 9] = offsets.quad + 4 * cell.index + 3; + indices[10] = offsets.edge + 2 * edge[1].index + 0; + indices[11] = offsets.edge + 2 * edge[1].index + 1; + + if (flip(edge[0])) { fm::swap(indices[ 0], indices[ 1]); } + if (flip(edge[1])) { fm::swap(indices[10], indices[11]); } + if (flip(edge[2])) { fm::swap(indices[ 4], indices[ 5]); } + if (flip(edge[3])) { fm::swap(indices[ 6], indices[ 7]); } + + } + + if (p == 3) { + + // o--→--→--→--o o--9-10-11--o + // ↑ ↑ ↑ ↑ 14 17 20 23 + // | → → → | | 6 7 8 | + // ↑ ↑ ↑ ↑ 13 16 19 22 + // | → → → | | 3 4 5 | + // ↑ ↑ ↑ ↑ 12 15 18 21 + // o--→--→--→--o o--0--1--2--o + indices[ 0] = offsets.edge + 3 * edge[0].index + 0; + indices[ 1] = offsets.edge + 3 * edge[0].index + 1; + indices[ 2] = offsets.edge + 3 * edge[0].index + 2; + indices[ 3] = offsets.quad + 12 * cell.index + 0; + indices[ 4] = offsets.quad + 12 * cell.index + 1; + indices[ 5] = offsets.quad + 12 * cell.index + 2; + indices[ 6] = offsets.quad + 12 * cell.index + 3; + indices[ 7] = offsets.quad + 12 * cell.index + 4; + indices[ 8] = offsets.quad + 12 * cell.index + 5; + indices[ 9] = offsets.edge + 3 * edge[2].index + 2; + indices[10] = offsets.edge + 3 * edge[2].index + 1; + indices[11] = offsets.edge + 3 * edge[2].index + 0; + + indices[12] = offsets.edge + 3 * edge[3].index + 2; + indices[13] = offsets.edge + 3 * edge[3].index + 1; + indices[14] = offsets.edge + 3 * edge[3].index + 0; + indices[15] = offsets.quad + 12 * cell.index + 6; + indices[16] = offsets.quad + 12 * cell.index + 7; + indices[17] = offsets.quad + 12 * cell.index + 8; + indices[18] = offsets.quad + 12 * cell.index + 9; + indices[19] = offsets.quad + 12 * cell.index + 10; + indices[20] = offsets.quad + 12 * cell.index + 11; + indices[21] = offsets.edge + 3 * edge[1].index + 0; + indices[22] = offsets.edge + 3 * edge[1].index + 1; + indices[23] = offsets.edge + 3 * edge[1].index + 2; + + if (flip(edge[0])) { fm::swap(indices[ 0], indices[ 2]); } + if (flip(edge[1])) { fm::swap(indices[21], indices[23]); } + if (flip(edge[2])) { fm::swap(indices[ 9], indices[11]); } + if (flip(edge[3])) { fm::swap(indices[12], indices[14]); } + + } + + } + + template < typename T > + __host__ __device__ void reorient(const TransformationType type, const Connection * quad, T * values) const { + + const Connection * edge = quad + Quadrilateral::edge_offset; + + if (p == 1) { + if (edge[0].sign() == Sign::Negative) { values[0] *= -1; } + if (edge[1].sign() == Sign::Negative) { values[3] *= -1; } + if (edge[2].sign() == Sign::Positive) { values[1] *= -1; } + if (edge[3].sign() == Sign::Positive) { values[2] *= -1; } + return; + } + + if (p == 2) { + if (edge[0].sign() == Sign::Negative) { values[ 0] *= -1; values[ 1] *= -1; } + if (edge[1].sign() == Sign::Negative) { values[10] *= -1; values[11] *= -1; } + if (edge[2].sign() == Sign::Positive) { values[ 4] *= -1; values[ 5] *= -1; } + if (edge[3].sign() == Sign::Positive) { values[ 6] *= -1; values[ 7] *= -1; } + return; + } + + if (p == 3) { + if (edge[0].sign() == Sign::Negative) { values[ 0] *= -1; values[ 1] *= -1; values[ 2] *= -1;} + if (edge[1].sign() == Sign::Negative) { values[21] *= -1; values[22] *= -1; values[23] *= -1;} + if (edge[2].sign() == Sign::Positive) { values[ 9] *= -1; values[10] *= -1; values[11] *= -1;} + if (edge[3].sign() == Sign::Positive) { values[12] *= -1; values[13] *= -1; values[14] *= -1;} + return; + } + + } + + __host__ __device__ void reorient(const TransformationType type, const Connection * quad, int8_t * transformation) { + + const Connection * edge = quad + Quadrilateral::edge_offset; + + uint32_t nnodes = num_nodes(); + for (int k = 0; k < nnodes; k++) { + transformation[k] = 0; + } + + if (p == 1) { + if (edge[0].sign() == Sign::Negative) { transformation[0] = -1; } + if (edge[1].sign() == Sign::Negative) { transformation[3] = -1; } + if (edge[2].sign() == Sign::Positive) { transformation[1] = -1; } + if (edge[3].sign() == Sign::Positive) { transformation[2] = -1; } + return; + } + + if (p == 2) { + if (edge[0].sign() == Sign::Negative) { transformation[ 0] = -1; transformation[ 1] = -1; } + if (edge[1].sign() == Sign::Negative) { transformation[10] = -1; transformation[11] = -1; } + if (edge[2].sign() == Sign::Positive) { transformation[ 4] = -1; transformation[ 5] = -1; } + if (edge[3].sign() == Sign::Positive) { transformation[ 6] = -1; transformation[ 7] = -1; } + return; + } + + if (p == 3) { + if (edge[0].sign() == Sign::Negative) { transformation[ 0] = -1; transformation[ 1] = -1; transformation[ 2] = -1;} + if (edge[1].sign() == Sign::Negative) { transformation[21] = -1; transformation[22] = -1; transformation[23] = -1;} + if (edge[2].sign() == Sign::Positive) { transformation[ 9] = -1; transformation[10] = -1; transformation[11] = -1;} + if (edge[3].sign() == Sign::Positive) { transformation[12] = -1; transformation[13] = -1; transformation[14] = -1;} + return; + } + + } + + constexpr vec2 shape_function(vec2 xi, uint32_t i) const { + if (p == 1) { + if (i == 0) { return vec2{1 - xi[1],0}; } + if (i == 1) { return vec2{xi[1],0}; } + if (i == 2) { return vec2{0,1 - xi[0]}; } + if (i == 3) { return vec2{0,xi[0]}; } + } + if (p == 2) { + if (i == 0) { return vec2{-1.7320508075688772935274463415*(-0.7886751345948128822545743902 + xi[0])*(-1 + xi[1])*(-1 + 2*xi[1]),0}; } + if (i == 1) { return vec2{(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[0])*(-1 + xi[1])*(-1 + 2*xi[1]),0}; } + if (i == 2) { return vec2{6.928203230275509174109785366*(-0.7886751345948128822545743902 + xi[0])*(-1. + xi[1])*xi[1],0}; } + if (i == 3) { return vec2{-6.92820323027550917410978537*(-0.21132486540518711774542561 + 1.*xi[0])*(-1. + xi[1])*xi[1],0}; } + if (i == 4) { return vec2{-1.7320508075688772935274463415*(-0.7886751345948128822545743902 + xi[0])*xi[1]*(-1 + 2*xi[1]),0}; } + if (i == 5) { return vec2{(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[0])*xi[1]*(-1 + 2*xi[1]),0}; } + if (i == 6) { return vec2{0,-1.7320508075688772935274463415*(-1 + xi[0])*(-1 + 2*xi[0])*(-0.7886751345948128822545743902 + xi[1])}; } + if (i == 7) { return vec2{0,(-1 + xi[0])*(-1 + 2*xi[0])*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[1])}; } + if (i == 8) { return vec2{0,6.928203230275509174109785366*(-1. + xi[0])*xi[0]*(-0.7886751345948128822545743902 + xi[1])}; } + if (i == 9) { return vec2{0,-6.92820323027550917410978537*(-1. + xi[0])*xi[0]*(-0.21132486540518711774542561 + 1.*xi[1])}; } + if (i == 10) { return vec2{0,-1.7320508075688772935274463415*xi[0]*(-1 + 2*xi[0])*(-0.7886751345948128822545743902 + xi[1])}; } + if (i == 11) { return vec2{0,xi[0]*(-1 + 2*xi[0])*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[1])}; } + } + if (p == 3) { + if (i == 0) { return vec2{(1.4788305577012361475298776 + xi[0]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[0]))*(1 + xi[1]*(-6. + (10. - 5.*xi[1])*xi[1])),0}; } + if (i == 1) { return vec2{-6.66666666666666666666666667*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(1 + xi[1]*(-6. + (10. - 5.*xi[1])*xi[1])),0}; } + if (i == 2) { return vec2{(0.1878361089654305191367891 + xi[0]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[0]))*(1 + xi[1]*(-6. + (10. - 5.*xi[1])*xi[1])),0}; } + if (i == 3) { return vec2{11.180339887498948*(1.4788305577012361475298776 + xi[0]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[0]))*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1]),0}; } + if (i == 4) { return vec2{-74.53559924999299*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1]),0}; } + if (i == 5) { return vec2{11.180339887498948*(0.1878361089654305191367891 + xi[0]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[0]))*(-1. + xi[1])*xi[1]*(-0.723606797749979 + 1.*xi[1]),0}; } + if (i == 6) { return vec2{-11.180339887498948482*(1.4788305577012361475298776 + xi[0]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1],0}; } + if (i == 7) { return vec2{74.53559924999298988*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1],0}; } + if (i == 8) { return vec2{-11.180339887498948482*(0.1878361089654305191367891 + xi[0]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1])*xi[1],0}; } + if (i == 9) { return vec2{(1.4788305577012361475298776 + xi[0]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[0]))*xi[1]*(1. + xi[1]*(-5. + 5.*xi[1])),0}; } + if (i == 10) { return vec2{-6.66666666666666666666666667*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*xi[1]*(1. + xi[1]*(-5. + 5.*xi[1])),0}; } + if (i == 11) { return vec2{(0.1878361089654305191367891 + xi[0]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[0]))*xi[1]*(1. + xi[1]*(-5. + 5.*xi[1])),0}; } + if (i == 12) { return vec2{0,(1 + xi[0]*(-6. + (10. - 5.*xi[0])*xi[0]))*(1.4788305577012361475298776 + xi[1]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[1]))}; } + if (i == 13) { return vec2{0,-6.66666666666666666666666667*(1 + xi[0]*(-6. + (10. - 5.*xi[0])*xi[0]))*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831148207346 + xi[1])}; } + if (i == 14) { return vec2{0,(1 + xi[0]*(-6. + (10. - 5.*xi[0])*xi[0]))*(0.1878361089654305191367891 + xi[1]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[1]))}; } + if (i == 15) { return vec2{0,11.180339887498948*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(1.4788305577012361475298776 + xi[1]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[1]))}; } + if (i == 16) { return vec2{0,-74.53559924999299*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831148207346 + xi[1])}; } + if (i == 17) { return vec2{0,11.180339887498948*(-1. + xi[0])*xi[0]*(-0.723606797749979 + 1.*xi[0])*(0.1878361089654305191367891 + xi[1]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[1]))}; } + if (i == 18) { return vec2{0,-11.180339887498948482*(-1. + xi[0])*(-0.2763932022500210304 + xi[0])*xi[0]*(1.4788305577012361475298776 + xi[1]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[1]))}; } + if (i == 19) { return vec2{0,74.53559924999298988*(-1. + xi[0])*(-0.2763932022500210304 + xi[0])*xi[0]*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831148207346 + xi[1])}; } + if (i == 20) { return vec2{0,-11.180339887498948482*(-1. + xi[0])*(-0.2763932022500210304 + xi[0])*xi[0]*(0.1878361089654305191367891 + xi[1]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[1]))}; } + if (i == 21) { return vec2{0,xi[0]*(1. + xi[0]*(-5. + 5.*xi[0]))*(1.4788305577012361475298776 + xi[1]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[1]))}; } + if (i == 22) { return vec2{0,-6.66666666666666666666666667*xi[0]*(1. + xi[0]*(-5. + 5.*xi[0]))*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831148207346 + xi[1])}; } + if (i == 23) { return vec2{0,xi[0]*(1. + xi[0]*(-5. + 5.*xi[0]))*(0.1878361089654305191367891 + xi[1]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[1]))}; } + } + + return {}; + } + + constexpr vec2 reoriented_shape_function(vec2 xi, uint32_t i, int8_t transformation) const { + if (transformation == -1) { + return -shape_function(xi, i); + } else { + return shape_function(xi, i); + } + } + + vec<1> shape_function_curl(vec2 xi, uint32_t i) const { + // expressions generated symbolically by mathematica + if (p == 1) { + if (i == 0) { return 1; } + if (i == 1) { return -1; } + if (i == 2) { return -1; } + if (i == 3) { return 1; } + } + if (p == 2) { + if (i == 0) { return 3.464101615137754587054892683*(-0.7886751345948128822545743902 + xi[0])*(-1 + xi[1]) + 1.7320508075688772935274463415*(-0.7886751345948128822545743902 + xi[0])*(-1 + 2*xi[1]); } + if (i == 1) { return -2*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[0])*(-1 + xi[1]) - (-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[0])*(-1 + 2*xi[1]); } + if (i == 2) { return -6.928203230275509174109785366*(-0.7886751345948128822545743902 + xi[0])*(-1. + xi[1]) - 6.928203230275509174109785366*(-0.7886751345948128822545743902 + xi[0])*xi[1]; } + if (i == 3) { return 6.92820323027550917410978537*(-0.21132486540518711774542561 + 1.*xi[0])*(-1. + xi[1]) + 6.92820323027550917410978537*(-0.21132486540518711774542561 + 1.*xi[0])*xi[1]; } + if (i == 4) { return 3.464101615137754587054892683*(-0.7886751345948128822545743902 + xi[0])*xi[1] + 1.7320508075688772935274463415*(-0.7886751345948128822545743902 + xi[0])*(-1 + 2*xi[1]); } + if (i == 5) { return -2*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[0])*xi[1] - (-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[0])*(-1 + 2*xi[1]); } + if (i == 6) { return -3.464101615137754587054892683*(-1 + xi[0])*(-0.7886751345948128822545743902 + xi[1]) - 1.7320508075688772935274463415*(-1 + 2*xi[0])*(-0.7886751345948128822545743902 + xi[1]); } + if (i == 7) { return 2*(-1 + xi[0])*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[1]) + (-1 + 2*xi[0])*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[1]); } + if (i == 8) { return 6.928203230275509174109785366*(-1. + xi[0])*(-0.7886751345948128822545743902 + xi[1]) + 6.928203230275509174109785366*xi[0]*(-0.7886751345948128822545743902 + xi[1]); } + if (i == 9) { return -6.92820323027550917410978537*(-1. + xi[0])*(-0.21132486540518711774542561 + 1.*xi[1]) - 6.92820323027550917410978537*xi[0]*(-0.21132486540518711774542561 + 1.*xi[1]); } + if (i == 10) { return -3.464101615137754587054892683*xi[0]*(-0.7886751345948128822545743902 + xi[1]) - 1.7320508075688772935274463415*(-1 + 2*xi[0])*(-0.7886751345948128822545743902 + xi[1]); } + if (i == 11) { return 2*xi[0]*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[1]) + (-1 + 2*xi[0])*(-0.3660254037844386467637231708 + 1.7320508075688772935274463415*xi[1]); } + } + if (p == 3) { + if (i == 0) { return -((1.4788305577012361475298776 + xi[0]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[0]))*(-6. + (10. - 10.*xi[1])*xi[1] + (10. - 5.*xi[1])*xi[1])); } + if (i == 1) { return 6.66666666666666666666666667*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(-6. + (10. - 10.*xi[1])*xi[1] + (10. - 5.*xi[1])*xi[1]); } + if (i == 2) { return -((0.1878361089654305191367891 + xi[0]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[0]))*(-6. + (10. - 10.*xi[1])*xi[1] + (10. - 5.*xi[1])*xi[1])); } + if (i == 3) { return -11.180339887498948*(1.4788305577012361475298776 + xi[0]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[0]))*(-1. + xi[1])*xi[1] - 11.180339887498948*(1.4788305577012361475298776 + xi[0]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[0]))*(-1. + xi[1])*(-0.723606797749979 + 1.*xi[1]) - 11.180339887498948*(1.4788305577012361475298776 + xi[0]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[0]))*xi[1]*(-0.723606797749979 + 1.*xi[1]); } + if (i == 4) { return 74.53559924999299*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(-1. + xi[1])*xi[1] + 74.53559924999299*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(-1. + xi[1])*(-0.723606797749979 + 1.*xi[1]) + 74.53559924999299*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*xi[1]*(-0.723606797749979 + 1.*xi[1]); } + if (i == 5) { return -11.180339887498948*(0.1878361089654305191367891 + xi[0]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[0]))*(-1. + xi[1])*xi[1] - 11.180339887498948*(0.1878361089654305191367891 + xi[0]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[0]))*(-1. + xi[1])*(-0.723606797749979 + 1.*xi[1]) - 11.180339887498948*(0.1878361089654305191367891 + xi[0]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[0]))*xi[1]*(-0.723606797749979 + 1.*xi[1]); } + if (i == 6) { return 11.180339887498948482*(1.4788305577012361475298776 + xi[0]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1]) + 11.180339887498948482*(1.4788305577012361475298776 + xi[0]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[0]))*(-1. + xi[1])*xi[1] + 11.180339887498948482*(1.4788305577012361475298776 + xi[0]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[0]))*(-0.2763932022500210304 + xi[1])*xi[1]; } + if (i == 7) { return -74.53559924999298988*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(-1. + xi[1])*(-0.2763932022500210304 + xi[1]) - 74.53559924999298988*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(-1. + xi[1])*xi[1] - 74.53559924999298988*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(-0.2763932022500210304 + xi[1])*xi[1]; } + if (i == 8) { return 11.180339887498948482*(0.1878361089654305191367891 + xi[0]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[0]))*(-1. + xi[1])*(-0.2763932022500210304 + xi[1]) + 11.180339887498948482*(0.1878361089654305191367891 + xi[0]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[0]))*(-1. + xi[1])*xi[1] + 11.180339887498948482*(0.1878361089654305191367891 + xi[0]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[0]))*(-0.2763932022500210304 + xi[1])*xi[1]; } + if (i == 9) { return -((1.4788305577012361475298776 + xi[0]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[0]))*xi[1]*(-5. + 10.*xi[1])) - (1.4788305577012361475298776 + xi[0]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[0]))*(1. + xi[1]*(-5. + 5.*xi[1])); } + if (i == 10) { return 6.66666666666666666666666667*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*xi[1]*(-5. + 10.*xi[1]) + 6.66666666666666666666666667*(-0.88729833462074168851792654 + xi[0])*(-0.11270166537925831148207346 + xi[0])*(1. + xi[1]*(-5. + 5.*xi[1])); } + if (i == 11) { return -((0.1878361089654305191367891 + xi[0]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[0]))*xi[1]*(-5. + 10.*xi[1])) - (0.1878361089654305191367891 + xi[0]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[0]))*(1. + xi[1]*(-5. + 5.*xi[1])); } + if (i == 12) { return (-6. + (10. - 10.*xi[0])*xi[0] + (10. - 5.*xi[0])*xi[0])*(1.4788305577012361475298776 + xi[1]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[1])); } + if (i == 13) { return -6.66666666666666666666666667*(-6. + (10. - 10.*xi[0])*xi[0] + (10. - 5.*xi[0])*xi[0])*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831148207346 + xi[1]); } + if (i == 14) { return (-6. + (10. - 10.*xi[0])*xi[0] + (10. - 5.*xi[0])*xi[0])*(0.1878361089654305191367891 + xi[1]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[1])); } + if (i == 15) { return 11.180339887498948*(-1. + xi[0])*xi[0]*(1.4788305577012361475298776 + xi[1]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[1])) + 11.180339887498948*(-1. + xi[0])*(-0.723606797749979 + 1.*xi[0])*(1.4788305577012361475298776 + xi[1]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[1])) + 11.180339887498948*xi[0]*(-0.723606797749979 + 1.*xi[0])*(1.4788305577012361475298776 + xi[1]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[1])); } + if (i == 16) { return -74.53559924999299*(-1. + xi[0])*xi[0]*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831148207346 + xi[1]) - 74.53559924999299*(-1. + xi[0])*(-0.723606797749979 + 1.*xi[0])*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831148207346 + xi[1]) - 74.53559924999299*xi[0]*(-0.723606797749979 + 1.*xi[0])*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831148207346 + xi[1]); } + if (i == 17) { return 11.180339887498948*(-1. + xi[0])*xi[0]*(0.1878361089654305191367891 + xi[1]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[1])) + 11.180339887498948*(-1. + xi[0])*(-0.723606797749979 + 1.*xi[0])*(0.1878361089654305191367891 + xi[1]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[1])) + 11.180339887498948*xi[0]*(-0.723606797749979 + 1.*xi[0])*(0.1878361089654305191367891 + xi[1]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[1])); } + if (i == 18) { return -11.180339887498948482*(-1. + xi[0])*(-0.2763932022500210304 + xi[0])*(1.4788305577012361475298776 + xi[1]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[1])) - 11.180339887498948482*(-1. + xi[0])*xi[0]*(1.4788305577012361475298776 + xi[1]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[1])) - 11.180339887498948482*(-0.2763932022500210304 + xi[0])*xi[0]*(1.4788305577012361475298776 + xi[1]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[1])); } + if (i == 19) { return 74.53559924999298988*(-1. + xi[0])*(-0.2763932022500210304 + xi[0])*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831148207346 + xi[1]) + 74.53559924999298988*(-1. + xi[0])*xi[0]*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831148207346 + xi[1]) + 74.53559924999298988*(-0.2763932022500210304 + xi[0])*xi[0]*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831148207346 + xi[1]); } + if (i == 20) { return -11.180339887498948482*(-1. + xi[0])*(-0.2763932022500210304 + xi[0])*(0.1878361089654305191367891 + xi[1]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[1])) - 11.180339887498948482*(-1. + xi[0])*xi[0]*(0.1878361089654305191367891 + xi[1]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[1])) - 11.180339887498948482*(-0.2763932022500210304 + xi[0])*xi[0]*(0.1878361089654305191367891 + xi[1]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[1])); } + if (i == 21) { return xi[0]*(-5. + 10.*xi[0])*(1.4788305577012361475298776 + xi[1]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[1])) + (1. + xi[0]*(-5. + 5.*xi[0]))*(1.4788305577012361475298776 + xi[1]*(-4.6243277820691389617264218 + 3.3333333333333333333333333*xi[1])); } + if (i == 22) { return -6.66666666666666666666666667*xi[0]*(-5. + 10.*xi[0])*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831148207346 + xi[1]) - 6.66666666666666666666666667*(1. + xi[0]*(-5. + 5.*xi[0]))*(-0.88729833462074168851792654 + xi[1])*(-0.11270166537925831148207346 + xi[1]); } + if (i == 23) { return xi[0]*(-5. + 10.*xi[0])*(0.1878361089654305191367891 + xi[1]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[1])) + (1. + xi[0]*(-5. + 5.*xi[0]))*(0.1878361089654305191367891 + xi[1]*(-2.0423388845975277049402449 + 3.3333333333333333333333333*xi[1])); } + } + + return {}; + } + + vec1 reoriented_shape_function_curl(vec2 xi, uint32_t i, int8_t transformation) const { + if (transformation == -1) { + return -shape_function_curl(xi, i); + } else { + return shape_function_curl(xi, i); + } + } + + vec<1> shape_function_derivative(vec2 xi, uint32_t i) const { + return shape_function_curl(xi, i); + } + + vec2 interpolate(vec2 xi, const double * values) const { + vec2 interpolated_value{}; + for (int i = 0; i < num_nodes(); i++) { + interpolated_value += values[i] * shape_function(xi, i); + } + return interpolated_value; + } + + vec<1> curl(vec2 xi, const double * values) const { + double interpolated_curl = 0.0; + for (int i = 0; i < num_nodes(); i++) { + interpolated_curl += values[i] * shape_function_curl(xi, i); + } + return interpolated_curl; + } + + // TODO: this is set to nonzero for the batched interpolation, + // even though batched curl doesn't use the buffer + __host__ __device__ uint32_t batch_interpolation_scratch_space(nd::view xi) const { + uint32_t q = xi.shape[0]; + return q * (p + 1); + } + + nd::array< double > evaluate_shape_functions(nd::view xi) const { + uint32_t q = xi.shape[0]; + uint32_t num_entries = 0; + num_entries += q * p; // B1 + num_entries += q * (p + 1); // B2 + nd::array buffer({num_entries}); + for (int i = 0; i < q; i++) { + GaussLegendreInterpolation(xi(i, 0), p, &buffer(p*i)); + GaussLobattoInterpolation(xi(i, 0), p+1, &buffer((p+1)*i + (p*q))); + } + return buffer; + } + + void interpolate(nd::view values_q, nd::view values_e, nd::view shape_fn, double * buffer) const { + uint32_t n = p + 1; + uint32_t q = sqrt(values_q.shape[0]); + + // 1D shape function evaluations + nd::view B1(shape_fn.data(), {q, p}); // legendre shape functions + nd::view B2(B1.end(), {q, n}); // lobatto shape functions + + nd::view A1(buffer, {q, n}); // storage for intermediates + + nd::view ue(values_e.data(), {n, p}); + nd::view uq((double*)values_q.data(), {q, q}, {2*q, 2}); + + _contract(A1, B1, ue); // A1(qx, iy) = sum_{ix} B1(qx, ix) * ue(iy, ix) + _contract(uq, B2, A1); // uq(qy, qx) = sum_{iy} B2(qy, iy) * A1(qx, iy) + + ue = nd::view< const double, 2 >(values_e.data() + (n * p), {n, p}); + + // note: column-major strides here, since quadrature points are still + // enumerated lexicographically as {y, x} but y-component nodes are {x, y} + uq = nd::view(((double*)values_q.data())+1, {q, q}, {2, 2*q}); + + _contract(A1, B1, ue); // A1(qx, iy) = sum_{ix} B1(qx, ix) * ue(iy, ix) + _contract(uq, B2, A1); // uq(qy, qx) = sum_{iy} B2(qy, iy) * A1(qx, iy) + } + +#if 1 + nd::array< double, 2 > evaluate_shape_function_curls(nd::view xi) const { + uint32_t q = xi.shape[0]; + nd::array shape_fns({q * q, num_nodes()}); + for (int i = 0; i < q; i++) { + for (int j = 0; j < q; j++) { + vec2 xi_ij = vec2{xi(j, 0), xi(i, 0)}; + for (int k = 0; k < num_nodes(); k++) { + shape_fns(i * q + j, k) = shape_function_curl(xi_ij, k); + } + } + } + return shape_fns; + } + + void curl(nd::view values_q, nd::view values_e, nd::view shape_fn_curls, double * /*buffer*/) const { + int nnodes = num_nodes(); + int nqpts = values_q.shape[0]; + + for (int q = 0; q < nqpts; q++) { + derivative_type sum = 0.0; + for (int i = 0; i < nnodes; i++) { + sum[0] += shape_fn_curls(q, i) * values_e(i); + } + values_q(q) = sum; + } + } + + nd::array< double, 3 > evaluate_weighted_shape_functions(nd::view xi, nd::view weights) { + uint32_t q = xi.shape[0]; + nd::array shape_fns({q * q, num_nodes(), dim}); + uint32_t qcount = 0; + for (int j = 0; j < q; j++) { + for (int i = 0; i < q; i++) { + vec2 xi_ij = vec2{xi(i, 0), xi(j, 0)}; + for (int l = 0; l < num_nodes(); l++) { + vec2 phi = shape_function(xi_ij, l); + shape_fns(qcount, l, 0) = phi[0] * weights[i] * weights[j]; + shape_fns(qcount, l, 1) = phi[1] * weights[i] * weights[j]; + } + qcount++; + } + } + return shape_fns; + } + + __host__ __device__ void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fn, double * /*buffer*/) const { + int nnodes = num_nodes(); + int nqpts = source_q.shape[0]; + + for (int i = 0; i < nnodes; i++) { + double sum = 0.0; + for (int q = 0; q < nqpts; q++) { + for (int j = 0; j < dim; j++) { + sum += shape_fn(q, i, j) * source_q(q)[j]; + } + } + residual_e(i) = sum; + } + } + + nd::array< double, 2 > evaluate_weighted_shape_function_curls(nd::view xi, nd::view weights) { + uint32_t q = xi.shape[0]; + nd::array shape_fns({q * q, num_nodes()}); + uint32_t qcount = 0; + for (int j = 0; j < q; j++) { + for (int i = 0; i < q; i++) { + vec2 xi_ij = vec2{xi(i, 0), xi(j, 0)}; + for (int l = 0; l < num_nodes(); l++) { + shape_fns(qcount, l) = shape_function_curl(xi_ij, l) * weights[i] * weights[j]; + } + qcount++; + } + } + return shape_fns; + } + + void integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fn_curl, double * /*buffer*/) const { + int nnodes = num_nodes(); + int nqpts = flux_q.shape[0]; + + for (int i = 0; i < nnodes; i++) { + double sum = 0.0; + for (int q = 0; q < nqpts; q++) { + sum += shape_fn_curl(q, i) * flux_q(q); + } + residual_e(i) = sum; + } + } + + #ifdef __CUDACC__ + __device__ void cuda_integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fn_curl, double * /*buffer*/) const { + int nnodes = num_nodes(); + int nqpts = flux_q.shape[0]; + + for (int i = threadIdx.x; i < nnodes; i += blockDim.x) { + double sum = 0.0; + for (int q = 0; q < nqpts; q++) { + sum += shape_fn_curl(q, i) * flux_q(q); + } + residual_e(i) = sum; + } + } + #endif + +#else + // sum factorization + nd::array< double > evaluate_shape_function_curls(nd::view xi) const { + uint32_t q = xi.shape[0]; + + auto [B1, B2, G2, A1, num_entries] = scan({q*p, q*(p+1), q*(p+1), q*(p+1)}); + nd::array buffer({num_entries}); + std::cout << num_entries << std::endl; + for (int i = 0; i < q; i++) { + GaussLegendreInterpolation(xi(i, 0), p, &buffer(B1 + p * i)); + GaussLobattoInterpolation(xi(i, 0), p+1, &buffer(B2 + (p+1)*i)); + GaussLobattoInterpolation(xi(i, 0), p+1, &buffer(G2 + (p+1)*i)); + } + return buffer; + } + + void curl(nd::view values_q, nd::view values_e, nd::view buffer) const { + uint32_t n = p + 1; + uint32_t q = sqrt(values_q.shape[0]); + + // 1D shape function evaluations + nd::view B1(buffer.data(), {q, p}); // legendre shape functions + nd::view B2(B1.end(), {q, n}); // lobatto shape functions + nd::view G2(B2.end(), {q, n}); // lobatto shape function derivatives + nd::view A1(G2.end(), {q, n}); // storage for intermediates + + nd::view ue(values_e.data(), {n, p}); + nd::view uq(values_q.data(), {q, q}, {2*q, 2u}); + + _contract(A1, B1, ue); // A1(qx, iy) = sum_{ix} B1(qx, ix) * ue(iy, ix) + _contract(uq, B2, A1); // uq(qy, qx) = sum_{iy} B2(qy, iy) * A1(qx, iy) + + ue = nd::view< const double, 2 >(values_e.data() + (n * p), {n, p}); + + // note: column-major strides here, since quadrature points + // are still enumerated lexicographically as {y, x} but y-component nodes are {x, y} + uq = nd::view(values_q.data() + 1, {q, q}, {2u, 2*q}); + + _contract(A1, B1, ue); // A1(qx, iy) = sum_{ix} B1(qx, ix) * ue(iy, ix) + _contract(uq, B2, A1); // uq(qy, qx) = sum_{iy} B2(qy, iy) * A1(qx, iy) + } +#endif + + uint32_t p; + +}; +// clang-format on + +} // namespace refactor diff --git a/src/serac/numerics/refactor/elements/hcurl_tetrahedron.hpp b/src/serac/numerics/refactor/elements/hcurl_tetrahedron.hpp new file mode 100644 index 0000000000..214be3f8d4 --- /dev/null +++ b/src/serac/numerics/refactor/elements/hcurl_tetrahedron.hpp @@ -0,0 +1,1686 @@ +#pragma once + +#include "fm/types/vec.hpp" +#include "fm/types/matrix.hpp" + +#include "fm/operations/print.hpp" // REMOVE + +namespace refactor { + +using namespace fm; + +// clang-format off +template <> +struct FiniteElement { + + using value_type = vec3; + using derivative_type = vec3; + + using source_type = vec3; + using flux_type = vec3; + + static constexpr int dim = 3; + + __host__ __device__ constexpr uint32_t num_nodes() const { return (p * (p + 2) * (p + 3)) / 2; } + + constexpr void nodes(nd::view< double, 2 > xi) const { + if (p == 1) { + xi(0, 0) = 0.5; xi(0, 1) = 0; xi(0, 2) = 0; + xi(1, 0) = 0.5; xi(1, 1) = 0.5; xi(1, 2) = 0; + xi(2, 0) = 0; xi(2, 1) = 0.5; xi(2, 2) = 0; + xi(3, 0) = 0; xi(3, 1) = 0; xi(3, 2) = 0.5; + xi(4, 0) = 0.5; xi(4, 1) = 0; xi(4, 2) = 0.5; + xi(5, 0) = 0; xi(5, 1) = 0.5; xi(5, 2) = 0.5; + } + if (p == 2) { + xi(0, 0) = 0.21132486540518711774542560975; xi(0, 1) = 0; xi(0, 2) = 0; + xi(1, 0) = 0.78867513459481288225457439025; xi(1, 1) = 0; xi(1, 2) = 0; + xi(2, 0) = 0.78867513459481288225457439025; xi(2, 1) = 0.21132486540518711774542560975; xi(2, 2) = 0; + xi(3, 0) = 0.21132486540518711774542560975; xi(3, 1) = 0.78867513459481288225457439025; xi(3, 2) = 0; + xi(4, 0) = 0; xi(4, 1) = 0.78867513459481288225457439025; xi(4, 2) = 0; + xi(5, 0) = 0; xi(5, 1) = 0.21132486540518711774542560975; xi(5, 2) = 0; + xi(6, 0) = 0; xi(6, 1) = 0; xi(6, 2) = 0.21132486540518711774542560975; + xi(7, 0) = 0; xi(7, 1) = 0; xi(7, 2) = 0.78867513459481288225457439025; + xi(8, 0) = 0.78867513459481288225457439025; xi(8, 1) = 0; xi(8, 2) = 0.21132486540518711774542560975; + xi(9, 0) = 0.21132486540518711774542560975; xi(9, 1) = 0; xi(9, 2) = 0.78867513459481288225457439025; + xi(10, 0) = 0; xi(10, 1) = 0.78867513459481288225457439025; xi(10, 2) = 0.21132486540518711774542560975; + xi(11, 0) = 0; xi(11, 1) = 0.21132486540518711774542560975; xi(11, 2) = 0.78867513459481288225457439025; + xi(12, 0) = 0.333333333333333333333333333333; xi(12, 1) = 0.333333333333333333333333333333; xi(12, 2) = 0; + xi(13, 0) = 0.333333333333333333333333333333; xi(13, 1) = 0.333333333333333333333333333333; xi(13, 2) = 0; + xi(14, 0) = 0.333333333333333333333333333333; xi(14, 1) = 0; xi(14, 2) = 0.333333333333333333333333333333; + xi(15, 0) = 0.333333333333333333333333333333; xi(15, 1) = 0; xi(15, 2) = 0.333333333333333333333333333333; + xi(16, 0) = 0.333333333333333333333333333333; xi(16, 1) = 0.333333333333333333333333333333; xi(16, 2) = 0.333333333333333333333333333333; + xi(17, 0) = 0.333333333333333333333333333333; xi(17, 1) = 0.333333333333333333333333333333; xi(17, 2) = 0.333333333333333333333333333333; + xi(18, 0) = 0; xi(18, 1) = 0.333333333333333333333333333333; xi(18, 2) = 0.333333333333333333333333333333; + xi(19, 0) = 0; xi(19, 1) = 0.333333333333333333333333333333; xi(19, 2) = 0.333333333333333333333333333333; + } + if (p == 3) { + xi(0, 0) = 0.11270166537925831148207346002; xi(0, 1) = 0; xi(0, 2) = 0; + xi(1, 0) = 0.5; xi(1, 1) = 0; xi(1, 2) = 0; + xi(2, 0) = 0.88729833462074168851792654; xi(2, 1) = 0; xi(2, 2) = 0; + xi(3, 0) = 0.88729833462074168851792653998; xi(3, 1) = 0.11270166537925831148207346002; xi(3, 2) = 0; + xi(4, 0) = 0.5; xi(4, 1) = 0.5; xi(4, 2) = 0; + xi(5, 0) = 0.11270166537925831148207346; xi(5, 1) = 0.88729833462074168851792654; xi(5, 2) = 0; + xi(6, 0) = 0; xi(6, 1) = 0.88729833462074168851792653998; xi(6, 2) = 0; + xi(7, 0) = 0; xi(7, 1) = 0.5; xi(7, 2) = 0; + xi(8, 0) = 0; xi(8, 1) = 0.11270166537925831148207346; xi(8, 2) = 0; + xi(9, 0) = 0; xi(9, 1) = 0; xi(9, 2) = 0.11270166537925831148207346002; + xi(10, 0) = 0; xi(10, 1) = 0; xi(10, 2) = 0.5; + xi(11, 0) = 0; xi(11, 1) = 0; xi(11, 2) = 0.88729833462074168851792654; + xi(12, 0) = 0.88729833462074168851792653998; xi(12, 1) = 0; xi(12, 2) = 0.11270166537925831148207346002; + xi(13, 0) = 0.5; xi(13, 1) = 0; xi(13, 2) = 0.5; + xi(14, 0) = 0.11270166537925831148207346; xi(14, 1) = 0; xi(14, 2) = 0.88729833462074168851792654; + xi(15, 0) = 0; xi(15, 1) = 0.88729833462074168851792653998; xi(15, 2) = 0.11270166537925831148207346002; + xi(16, 0) = 0; xi(16, 1) = 0.5; xi(16, 2) = 0.5; + xi(17, 0) = 0; xi(17, 1) = 0.11270166537925831148207346; xi(17, 2) = 0.88729833462074168851792654; + xi(18, 0) = 0.1744576301870094389594272045; xi(18, 1) = 0.651084739625981122081145591; xi(18, 2) = 0; + xi(19, 0) = 0.1744576301870094389594272045; xi(19, 1) = 0.651084739625981122081145591; xi(19, 2) = 0; + xi(20, 0) = 0.651084739625981122081145591; xi(20, 1) = 0.1744576301870094389594272045; xi(20, 2) = 0; + xi(21, 0) = 0.651084739625981122081145591; xi(21, 1) = 0.1744576301870094389594272045; xi(21, 2) = 0; + xi(22, 0) = 0.1744576301870094389594272045; xi(22, 1) = 0.1744576301870094389594272045; xi(22, 2) = 0; + xi(23, 0) = 0.1744576301870094389594272045; xi(23, 1) = 0.1744576301870094389594272045; xi(23, 2) = 0; + xi(24, 0) = 0.1744576301870094389594272045; xi(24, 1) = 0; xi(24, 2) = 0.1744576301870094389594272045; + xi(25, 0) = 0.1744576301870094389594272045; xi(25, 1) = 0; xi(25, 2) = 0.1744576301870094389594272045; + xi(26, 0) = 0.651084739625981122081145591; xi(26, 1) = 0; xi(26, 2) = 0.1744576301870094389594272045; + xi(27, 0) = 0.651084739625981122081145591; xi(27, 1) = 0; xi(27, 2) = 0.1744576301870094389594272045; + xi(28, 0) = 0.1744576301870094389594272045; xi(28, 1) = 0; xi(28, 2) = 0.651084739625981122081145591; + xi(29, 0) = 0.1744576301870094389594272045; xi(29, 1) = 0; xi(29, 2) = 0.651084739625981122081145591; + xi(30, 0) = 0.651084739625981122081145591; xi(30, 1) = 0.1744576301870094389594272045; xi(30, 2) = 0.1744576301870094389594272045; + xi(31, 0) = 0.651084739625981122081145591; xi(31, 1) = 0.1744576301870094389594272045; xi(31, 2) = 0.1744576301870094389594272045; + xi(32, 0) = 0.1744576301870094389594272045; xi(32, 1) = 0.651084739625981122081145591; xi(32, 2) = 0.1744576301870094389594272045; + xi(33, 0) = 0.1744576301870094389594272045; xi(33, 1) = 0.651084739625981122081145591; xi(33, 2) = 0.1744576301870094389594272045; + xi(34, 0) = 0.1744576301870094389594272045; xi(34, 1) = 0.1744576301870094389594272045; xi(34, 2) = 0.651084739625981122081145591; + xi(35, 0) = 0.1744576301870094389594272045; xi(35, 1) = 0.1744576301870094389594272045; xi(35, 2) = 0.651084739625981122081145591; + xi(36, 0) = 0; xi(36, 1) = 0.651084739625981122081145591; xi(36, 2) = 0.1744576301870094389594272045; + xi(37, 0) = 0; xi(37, 1) = 0.651084739625981122081145591; xi(37, 2) = 0.1744576301870094389594272045; + xi(38, 0) = 0; xi(38, 1) = 0.1744576301870094389594272045; xi(38, 2) = 0.1744576301870094389594272045; + xi(39, 0) = 0; xi(39, 1) = 0.1744576301870094389594272045; xi(39, 2) = 0.1744576301870094389594272045; + xi(40, 0) = 0; xi(40, 1) = 0.1744576301870094389594272045; xi(40, 2) = 0.651084739625981122081145591; + xi(41, 0) = 0; xi(41, 1) = 0.1744576301870094389594272045; xi(41, 2) = 0.651084739625981122081145591; + xi(42, 0) = 0.25; xi(42, 1) = 0.25; xi(42, 2) = 0.25; + xi(43, 0) = 0.25; xi(43, 1) = 0.25; xi(43, 2) = 0.25; + xi(44, 0) = 0.25; xi(44, 1) = 0.25; xi(44, 2) = 0.25; + } + } + + constexpr void directions(nd::view d) const { + if (p == 1) { + d(0, 0) = 1; d(0, 1) = 0; d(0, 2) = 0; + d(1, 0) = -1; d(1, 1) = 1; d(1, 2) = 0; + d(2, 0) = 0; d(2, 1) = -1; d(2, 2) = 0; + d(3, 0) = 0; d(3, 1) = 0; d(3, 2) = 1; + d(4, 0) = -1; d(4, 1) = 0; d(4, 2) = 1; + d(5, 0) = 0; d(5, 1) = -1; d(5, 2) = 1; + } + if (p == 2) { + d(0, 0) = 1; d(0, 1) = 0; d(0, 2) = 0; + d(1, 0) = 1; d(1, 1) = 0; d(1, 2) = 0; + d(2, 0) = -1; d(2, 1) = 1; d(2, 2) = 0; + d(3, 0) = -1; d(3, 1) = 1; d(3, 2) = 0; + d(4, 0) = 0; d(4, 1) = -1; d(4, 2) = 0; + d(5, 0) = 0; d(5, 1) = -1; d(5, 2) = 0; + d(6, 0) = 0; d(6, 1) = 0; d(6, 2) = 1; + d(7, 0) = 0; d(7, 1) = 0; d(7, 2) = 1; + d(8, 0) = -1; d(8, 1) = 0; d(8, 2) = 1; + d(9, 0) = -1; d(9, 1) = 0; d(9, 2) = 1; + d(10, 0) = 0; d(10, 1) = -1; d(10, 2) = 1; + d(11, 0) = 0; d(11, 1) = -1; d(11, 2) = 1; + d(12, 0) = 1; d(12, 1) = -1; d(12, 2) = 0; + d(13, 0) = 0; d(13, 1) = -1; d(13, 2) = 0; + d(14, 0) = 1; d(14, 1) = 0; d(14, 2) = 0; + d(15, 0) = 0; d(15, 1) = 0; d(15, 2) = 1; + d(16, 0) = -1; d(16, 1) = 1; d(16, 2) = 0; + d(17, 0) = -1; d(17, 1) = 0; d(17, 2) = 1; + d(18, 0) = 0; d(18, 1) = -1; d(18, 2) = 0; + d(19, 0) = 0; d(19, 1) = -1; d(19, 2) = 1; + } + if (p == 3) { + d(0, 0) = 1; d(0, 1) = 0; d(0, 2) = 0; + d(1, 0) = 1; d(1, 1) = 0; d(1, 2) = 0; + d(2, 0) = 1; d(2, 1) = 0; d(2, 2) = 0; + d(3, 0) = -1; d(3, 1) = 1; d(3, 2) = 0; + d(4, 0) = -1; d(4, 1) = 1; d(4, 2) = 0; + d(5, 0) = -1; d(5, 1) = 1; d(5, 2) = 0; + d(6, 0) = 0; d(6, 1) = -1; d(6, 2) = 0; + d(7, 0) = 0; d(7, 1) = -1; d(7, 2) = 0; + d(8, 0) = 0; d(8, 1) = -1; d(8, 2) = 0; + d(9, 0) = 0; d(9, 1) = 0; d(9, 2) = 1; + d(10, 0) = 0; d(10, 1) = 0; d(10, 2) = 1; + d(11, 0) = 0; d(11, 1) = 0; d(11, 2) = 1; + d(12, 0) = -1; d(12, 1) = 0; d(12, 2) = 1; + d(13, 0) = -1; d(13, 1) = 0; d(13, 2) = 1; + d(14, 0) = -1; d(14, 1) = 0; d(14, 2) = 1; + d(15, 0) = 0; d(15, 1) = -1; d(15, 2) = 1; + d(16, 0) = 0; d(16, 1) = -1; d(16, 2) = 1; + d(17, 0) = 0; d(17, 1) = -1; d(17, 2) = 1; + d(18, 0) = 1; d(18, 1) = -1; d(18, 2) = 0; + d(19, 0) = 0; d(19, 1) = -1; d(19, 2) = 0; + d(20, 0) = 1; d(20, 1) = -1; d(20, 2) = 0; + d(21, 0) = 0; d(21, 1) = -1; d(21, 2) = 0; + d(22, 0) = 1; d(22, 1) = -1; d(22, 2) = 0; + d(23, 0) = 0; d(23, 1) = -1; d(23, 2) = 0; + d(24, 0) = 1; d(24, 1) = 0; d(24, 2) = 0; + d(25, 0) = 0; d(25, 1) = 0; d(25, 2) = 1; + d(26, 0) = 1; d(26, 1) = 0; d(26, 2) = 0; + d(27, 0) = 0; d(27, 1) = 0; d(27, 2) = 1; + d(28, 0) = 1; d(28, 1) = 0; d(28, 2) = 0; + d(29, 0) = 0; d(29, 1) = 0; d(29, 2) = 1; + d(30, 0) = -1; d(30, 1) = 1; d(30, 2) = 0; + d(31, 0) = -1; d(31, 1) = 0; d(31, 2) = 1; + d(32, 0) = -1; d(32, 1) = 1; d(32, 2) = 0; + d(33, 0) = -1; d(33, 1) = 0; d(33, 2) = 1; + d(34, 0) = -1; d(34, 1) = 1; d(34, 2) = 0; + d(35, 0) = -1; d(35, 1) = 0; d(35, 2) = 1; + d(36, 0) = 0; d(36, 1) = -1; d(36, 2) = 0; + d(37, 0) = 0; d(37, 1) = -1; d(37, 2) = 1; + d(38, 0) = 0; d(38, 1) = -1; d(38, 2) = 0; + d(39, 0) = 0; d(39, 1) = -1; d(39, 2) = 1; + d(40, 0) = 0; d(40, 1) = -1; d(40, 2) = 0; + d(41, 0) = 0; d(41, 1) = -1; d(41, 2) = 1; + d(42, 0) = 1; d(42, 1) = 0; d(42, 2) = 0; + d(43, 0) = 0; d(43, 1) = 1; d(43, 2) = 0; + d(44, 0) = 0; d(44, 1) = 0; d(44, 2) = 1; + } + } + + __host__ __device__ constexpr uint32_t num_interior_nodes() const { return (p == 3) ? 3 : 0; } + + constexpr void interior_nodes(nd::view xi) const { + if (p == 3) { + xi(0, 0) = 0.25; xi(0, 1) = 0.25; xi(0, 2) = 0.25; + xi(1, 0) = 0.25; xi(1, 1) = 0.25; xi(1, 2) = 0.25; + xi(2, 0) = 0.25; xi(2, 1) = 0.25; xi(2, 2) = 0.25; + } + } + + constexpr void interior_directions(nd::view d) const { + if (p == 3) { + d(0, 0) = 1; d(0, 1) = 0; d(0, 2) = 0; + d(1, 0) = 0; d(1, 1) = 1; d(1, 2) = 0; + d(2, 0) = 0; d(2, 1) = 0; d(2, 2) = 1; + } + } + + __host__ __device__ void permute(Connection tri, uint32_t * ids) { + if (tri.sign() == Sign::Negative) { + + //////////////////////////////////////////////////////////////////////////////// + // // + // official | // + // ordering | // + // | | // + // c | c a b | b c a // + // / \ | / \ / \ / \ | / \ / \ / \ // + // / \ | / \ / \ / \ | / \ / \ / \ // + // a-----b | a-----b b-----c c-----a | a-----c b-----a c-----b // + // | | // + // sign | + + + | - - - // + // orientation | 0 1 2 | 0 1 2 // + // // + //////////////////////////////////////////////////////////////////////////////// + uint8_t o = tri.orientation(); + uint32_t tmp; + // swap b<->c + if (o == 0) { + tmp = ids[2]; ids[2] = ids[4]; ids[4] = tmp; + tmp = ids[3]; ids[3] = ids[5]; ids[5] = tmp; + } + + // swap a<->b + if (o == 1) { + tmp = ids[0]; ids[0] = ids[2]; ids[2] = tmp; + tmp = ids[1]; ids[1] = ids[3]; ids[3] = tmp; + } + + // swap a<->c + if (o == 2) { + tmp = ids[0]; ids[0] = ids[4]; ids[4] = tmp; + tmp = ids[1]; ids[1] = ids[5]; ids[5] = tmp; + } + } + } + + __host__ __device__ void indices(const GeometryInfo & offsets, const Connection * tet, uint32_t * ids) { + + const Connection * edge = tet + Tetrahedron::edge_offset; + const Connection * tri = tet + Tetrahedron::tri_offset; + const Connection cell = *(tet + Tetrahedron::cell_offset); + + if (p == 1) { + ids[0] = offsets.edge + edge[0].index; + ids[1] = offsets.edge + edge[1].index; + ids[2] = offsets.edge + edge[2].index; + ids[3] = offsets.edge + edge[3].index; + ids[4] = offsets.edge + edge[4].index; + ids[5] = offsets.edge + edge[5].index; + return; + } + + if (p == 2) { + ids[ 0] = offsets.edge + 2 * edge[0].index + 0; + ids[ 1] = offsets.edge + 2 * edge[0].index + 1; + if (flip(edge[0])) { fm::swap(ids[0], ids[1]); } + + ids[ 2] = offsets.edge + 2 * edge[1].index + 0; + ids[ 3] = offsets.edge + 2 * edge[1].index + 1; + if (flip(edge[1])) { fm::swap(ids[2], ids[3]); } + + ids[ 4] = offsets.edge + 2 * edge[2].index + 0; + ids[ 5] = offsets.edge + 2 * edge[2].index + 1; + if (flip(edge[2])) { fm::swap(ids[4], ids[5]); } + + ids[ 6] = offsets.edge + 2 * edge[3].index + 0; + ids[ 7] = offsets.edge + 2 * edge[3].index + 1; + if (flip(edge[3])) { fm::swap(ids[6], ids[7]); } + + ids[ 8] = offsets.edge + 2 * edge[4].index + 0; + ids[ 9] = offsets.edge + 2 * edge[4].index + 1; + if (flip(edge[4])) { fm::swap(ids[8], ids[9]); } + + ids[10] = offsets.edge + 2 * edge[5].index + 0; + ids[11] = offsets.edge + 2 * edge[5].index + 1; + if (flip(edge[5])) { fm::swap(ids[10], ids[11]); } + + ids[12] = offsets.tri + 2 * tri[0].index + 0; + ids[13] = offsets.tri + 2 * tri[0].index + 1; + + ids[14] = offsets.tri + 2 * tri[1].index + 0; + ids[15] = offsets.tri + 2 * tri[1].index + 1; + + ids[16] = offsets.tri + 2 * tri[2].index + 0; + ids[17] = offsets.tri + 2 * tri[2].index + 1; + + ids[18] = offsets.tri + 2 * tri[3].index + 0; + ids[19] = offsets.tri + 2 * tri[3].index + 1; + return; + } + + if (p == 3) { + + ids[ 0] = offsets.edge + 3 * edge[0].index + 0; + ids[ 1] = offsets.edge + 3 * edge[0].index + 1; + ids[ 2] = offsets.edge + 3 * edge[0].index + 2; + if (flip(edge[0])) { fm::swap(ids[0], ids[2]); } + + ids[ 3] = offsets.edge + 3 * edge[1].index + 0; + ids[ 4] = offsets.edge + 3 * edge[1].index + 1; + ids[ 5] = offsets.edge + 3 * edge[1].index + 2; + if (flip(edge[1])) { fm::swap(ids[3], ids[5]); } + + ids[ 6] = offsets.edge + 3 * edge[2].index + 0; + ids[ 7] = offsets.edge + 3 * edge[2].index + 1; + ids[ 8] = offsets.edge + 3 * edge[2].index + 2; + if (flip(edge[2])) { fm::swap(ids[6], ids[8]); } + + ids[ 9] = offsets.edge + 3 * edge[3].index + 0; + ids[10] = offsets.edge + 3 * edge[3].index + 1; + ids[11] = offsets.edge + 3 * edge[3].index + 2; + if (flip(edge[3])) { fm::swap(ids[9], ids[11]); } + + ids[12] = offsets.edge + 3 * edge[4].index + 0; + ids[13] = offsets.edge + 3 * edge[4].index + 1; + ids[14] = offsets.edge + 3 * edge[4].index + 2; + if (flip(edge[4])) { fm::swap(ids[12], ids[14]); } + + ids[15] = offsets.edge + 3 * edge[5].index + 0; + ids[16] = offsets.edge + 3 * edge[5].index + 1; + ids[17] = offsets.edge + 3 * edge[5].index + 2; + if (flip(edge[5])) { fm::swap(ids[15], ids[17]); } + + ids[18] = offsets.tri + 6 * tri[0].index + 0; + ids[19] = offsets.tri + 6 * tri[0].index + 1; + ids[20] = offsets.tri + 6 * tri[0].index + 2; + ids[21] = offsets.tri + 6 * tri[0].index + 3; + ids[22] = offsets.tri + 6 * tri[0].index + 4; + ids[23] = offsets.tri + 6 * tri[0].index + 5; + permute(tri[0], ids+18); + + ids[24] = offsets.tri + 6 * tri[1].index + 0; + ids[25] = offsets.tri + 6 * tri[1].index + 1; + ids[26] = offsets.tri + 6 * tri[1].index + 2; + ids[27] = offsets.tri + 6 * tri[1].index + 3; + ids[28] = offsets.tri + 6 * tri[1].index + 4; + ids[29] = offsets.tri + 6 * tri[1].index + 5; + permute(tri[1], ids+24); + + ids[30] = offsets.tri + 6 * tri[2].index + 0; + ids[31] = offsets.tri + 6 * tri[2].index + 1; + ids[32] = offsets.tri + 6 * tri[2].index + 2; + ids[33] = offsets.tri + 6 * tri[2].index + 3; + ids[34] = offsets.tri + 6 * tri[2].index + 4; + ids[35] = offsets.tri + 6 * tri[2].index + 5; + permute(tri[2], ids+30); + + ids[36] = offsets.tri + 6 * tri[3].index + 0; + ids[37] = offsets.tri + 6 * tri[3].index + 1; + ids[38] = offsets.tri + 6 * tri[3].index + 2; + ids[39] = offsets.tri + 6 * tri[3].index + 3; + ids[40] = offsets.tri + 6 * tri[3].index + 4; + ids[41] = offsets.tri + 6 * tri[3].index + 5; + permute(tri[3], ids+36); + + ids[42] = offsets.tet + 3 * cell.index + 0; + ids[43] = offsets.tet + 3 * cell.index + 1; + ids[44] = offsets.tet + 3 * cell.index + 2; + return; + } + } + + __host__ __device__ void reorient(const TransformationType type, const Connection * tet, int8_t * transformation) { + + const Connection * edge = tet + Tetrahedron::edge_offset; + const Connection * tri = tet + Tetrahedron::tri_offset; + + uint32_t count = 0; + + // edge nodes + for (uint32_t i = 0; i < Tetrahedron::num_edges; i++) { + if (edge[i].sign() == Sign::Positive) { + for (uint32_t j = 0; j < p; j++) { + transformation[count++] = 0; + } + } else { + for (uint32_t j = 0; j < p; j++) { + transformation[count++] = -1; + } + } + } + + if (p == 1) return; + + // face nodes + for (uint32_t i = 0; i < Tetrahedron::num_triangles; i++) { + if (tri[i].sign() == Sign::Negative) { + for (uint32_t j = 0; j < Triangle::number(p - 1); j++) { + transformation[count++] = face_transformation_id(type, tri[i].orientation()); + transformation[count++] = face_transformation_id(type, tri[i].orientation()); + } + } else { + for (uint32_t j = 0; j < Triangle::number(p - 1); j++) { + transformation[count++] = 0; + transformation[count++] = 0; + } + } + } + + if (p == 2) return; + + // interior nodes + transformation[count++] = 0; + transformation[count++] = 0; + transformation[count++] = 0; + + } + + template < typename T > + __host__ __device__ void reorient(const TransformationType type, const Connection * tet, T * values) { + + const Connection * edge = tet + Tetrahedron::edge_offset; + const Connection * tri = tet + Tetrahedron::tri_offset; + + uint32_t count = 0; + + // edge nodes + if (type == TransformationType::PhysicalToParent || + type == TransformationType::TransposePhysicalToParent) { + for (uint32_t i = 0; i < Tetrahedron::num_edges; i++) { + if (edge[i].sign() == Sign::Negative) { + for (uint32_t j = 0; j < p; j++) { + values[count++] *= -1.0; + } + } else { + count += p; + } + } + } else { + count += p * Tetrahedron::num_edges; + } + + if (p == 1) return; + + constexpr mat2 A[3][3] = { + {{{{0, 1}, {1, 0}}}, {{{-1, 0}, {-1, 1}}}, {{{1, -1}, {0, -1}}}}, // PhysicalToParent + {{{{0, 1}, {1, 0}}}, {{{-1, -1}, {0, 1}}}, {{{1, 0}, {-1, -1}}}}, // TransposePhysicalToParent + }; + + // face nodes + for (uint32_t i = 0; i < Tetrahedron::num_triangles; i++) { + if (tri[i].sign() == Sign::Negative) { + uint32_t o = tri[i].orientation(); + mat2 Ao = A[uint32_t(type)][o]; + for (int j = 0; j < Triangle::number(p - 1); j++) { + T v[2] = {values[count], values[count+1]}; + values[count] = Ao[0][0] * v[0] + Ao[0][1] * v[1]; + values[count+1] = Ao[1][0] * v[0] + Ao[1][1] * v[1]; + count += 2; + } + } else { + count += 2 * Triangle::number(p - 1); + } + } + + } + + constexpr vec3 shape_function(vec3 xi, uint32_t i) const { + // expressions generated symbolically by mathematica + if (p == 1) { + if (i == 0) { return vec3{ 1 - xi[1] - xi[2], xi[0], xi[0] }; } + if (i == 1) { return vec3{ -xi[1], xi[0], 0 }; } + if (i == 2) { return vec3{ -xi[1], -1 + xi[0] + xi[2], -xi[1] }; } + if (i == 3) { return vec3{ xi[2], xi[2], 1 - xi[0] - xi[1] }; } + if (i == 4) { return vec3{ -xi[2], 0, xi[0] }; } + if (i == 5) { return vec3{ 0, -xi[2], xi[1] }; } + } + + if (p == 2) { + if (i == 0) { + return vec3{ + 1.3660254037844386467637231708 - 1.732050807568877293527446342*xi[0] - 3.732050807568877293527446342*xi[1] + 1.732050807568877293527446342*xi[0]*xi[1] + 2.366025403784438646763723171*xi[1]*xi[1] - 3.732050807568877293527446342*xi[2] + 1.732050807568877293527446342*xi[0]*xi[2] + 4.732050807568877293527446342*xi[1]*xi[2] + 2.366025403784438646763723171*xi[2]*xi[2], + 1.3660254037844386467637231708*xi[0] - 1.732050807568877293527446342*xi[0]*xi[0] - 2.366025403784438646763723171*xi[0]*xi[1] - 2.366025403784438646763723171*xi[0]*xi[2], + 1.3660254037844386467637231708*xi[0] - 1.732050807568877293527446342*xi[0]*xi[0] - 2.366025403784438646763723171*xi[0]*xi[1] - 2.366025403784438646763723171*xi[0]*xi[2] + }; + } + if (i == 1) { + return vec3{ + -0.3660254037844386467637231708 + 1.732050807568877293527446342*xi[0] - 0.2679491924311227064725536585*xi[1] - 1.732050807568877293527446342*xi[0]*xi[1] + 0.6339745962155613532362768292*xi[1]*xi[1] - 0.2679491924311227064725536585*xi[2] - 1.732050807568877293527446342*xi[0]*xi[2] + 1.2679491924311227064725536585*xi[1]*xi[2] + 0.6339745962155613532362768292*xi[2]*xi[2], + -0.3660254037844386467637231708*xi[0] + 1.732050807568877293527446342*xi[0]*xi[0] - 0.6339745962155613532362768292*xi[0]*xi[1] - 0.6339745962155613532362768292*xi[0]*xi[2], + -0.3660254037844386467637231708*xi[0] + 1.732050807568877293527446342*xi[0]*xi[0] - 0.633974596215561353236276829*xi[0]*xi[1] - 0.6339745962155613532362768292*xi[0]*xi[2] + }; + } + if (i == 2) { + return vec3{ + xi[1] - 2.366025403784438646763723171*xi[0]*xi[1] - 0.6339745962155613532362768292*xi[1]*xi[1], + -xi[0] + 2.366025403784438646763723171*xi[0]*xi[0] + 0.6339745962155613532362768292*xi[0]*xi[1], + 0 + }; + } + if (i == 3) { + return vec3{ + xi[1] - 0.6339745962155613532362768292*xi[0]*xi[1] - 2.366025403784438646763723171*xi[1]*xi[1], + -xi[0] + 0.6339745962155613532362768292*xi[0]*xi[0] + 2.366025403784438646763723171*xi[0]*xi[1], + 0 + }; + } + if (i == 4) { + return vec3{ + 0.3660254037844386467637231708*xi[1] + 0.6339745962155613532362768292*xi[0]*xi[1] - 1.732050807568877293527446342*xi[1]*xi[1] + 0.6339745962155613532362768292*xi[1]*xi[2], + 0.3660254037844386467637231708 + 0.2679491924311227064725536585*xi[0] - 0.6339745962155613532362768292*xi[0]*xi[0] - 1.732050807568877293527446342*xi[1] + 1.732050807568877293527446342*xi[0]*xi[1] + 0.2679491924311227064725536585*xi[2] - 1.2679491924311227064725536585*xi[0]*xi[2] + 1.732050807568877293527446342*xi[1]*xi[2] - 0.6339745962155613532362768292*xi[2]*xi[2], + 0.3660254037844386467637231708*xi[1] + 0.633974596215561353236276829*xi[0]*xi[1] - 1.732050807568877293527446342*xi[1]*xi[1] + 0.6339745962155613532362768292*xi[1]*xi[2] + }; + } + if (i == 5) { + return vec3{ + -1.3660254037844386467637231708*xi[1] + 2.366025403784438646763723171*xi[0]*xi[1] + 1.732050807568877293527446342*xi[1]*xi[1] + 2.366025403784438646763723171*xi[1]*xi[2], + -1.3660254037844386467637231708 + 3.732050807568877293527446342*xi[0] - 2.366025403784438646763723171*xi[0]*xi[0] + 1.732050807568877293527446342*xi[1] - 1.732050807568877293527446342*xi[0]*xi[1] + 3.732050807568877293527446342*xi[2] - 4.732050807568877293527446342*xi[0]*xi[2] - 1.732050807568877293527446342*xi[1]*xi[2] - 2.366025403784438646763723171*xi[2]*xi[2], + -1.3660254037844386467637231708*xi[1] + 2.366025403784438646763723171*xi[0]*xi[1] + 1.732050807568877293527446342*xi[1]*xi[1] + 2.366025403784438646763723171*xi[1]*xi[2] + }; + } + if (i == 6) { + return vec3{ + 1.3660254037844386467637231708*xi[2] - 2.366025403784438646763723171*xi[0]*xi[2] - 2.366025403784438646763723171*xi[1]*xi[2] - 1.732050807568877293527446342*xi[2]*xi[2], + 1.3660254037844386467637231708*xi[2] - 2.366025403784438646763723171*xi[0]*xi[2] - 2.366025403784438646763723171*xi[1]*xi[2] - 1.732050807568877293527446342*xi[2]*xi[2], + 1.3660254037844386467637231708 - 3.732050807568877293527446342*xi[0] + 2.366025403784438646763723171*xi[0]*xi[0] - 3.732050807568877293527446342*xi[1] + 4.732050807568877293527446342*xi[0]*xi[1] + 2.366025403784438646763723171*xi[1]*xi[1] - 1.732050807568877293527446342*xi[2] + 1.732050807568877293527446342*xi[0]*xi[2] + 1.732050807568877293527446342*xi[1]*xi[2] + }; + } + if (i == 7) { + return vec3{ + -0.3660254037844386467637231708*xi[2] - 0.6339745962155613532362768292*xi[0]*xi[2] - 0.6339745962155613532362768292*xi[1]*xi[2] + 1.732050807568877293527446342*xi[2]*xi[2], + -0.3660254037844386467637231708*xi[2] - 0.6339745962155613532362768292*xi[0]*xi[2] - 0.6339745962155613532362768292*xi[1]*xi[2] + 1.732050807568877293527446342*xi[2]*xi[2], + -0.3660254037844386467637231708 - 0.2679491924311227064725536585*xi[0] + 0.6339745962155613532362768292*xi[0]*xi[0] - 0.2679491924311227064725536585*xi[1] + 1.2679491924311227064725536585*xi[0]*xi[1] + 0.6339745962155613532362768292*xi[1]*xi[1] + 1.732050807568877293527446342*xi[2] - 1.732050807568877293527446342*xi[0]*xi[2] - 1.732050807568877293527446342*xi[1]*xi[2] + }; + } + if (i == 8) { + return vec3{ + xi[2] - 2.366025403784438646763723171*xi[0]*xi[2] - 0.6339745962155613532362768292*xi[2]*xi[2], + 0, + -xi[0] + 2.366025403784438646763723171*xi[0]*xi[0] + 0.6339745962155613532362768292*xi[0]*xi[2] + }; + } + if (i == 9) { + return vec3{ + xi[2] - 0.6339745962155613532362768292*xi[0]*xi[2] - 2.366025403784438646763723171*xi[2]*xi[2], + 0, + -xi[0] + 0.6339745962155613532362768292*xi[0]*xi[0] + 2.366025403784438646763723171*xi[0]*xi[2] + }; + } + if (i == 10) { + return vec3{ + 0, + xi[2] - 2.366025403784438646763723171*xi[1]*xi[2] - 0.6339745962155613532362768292*xi[2]*xi[2], + -xi[1] + 2.366025403784438646763723171*xi[1]*xi[1] + 0.6339745962155613532362768292*xi[1]*xi[2] + }; + } + if (i == 11) { + return vec3{ + 0, + xi[2] - 0.6339745962155613532362768292*xi[1]*xi[2] - 2.366025403784438646763723171*xi[2]*xi[2], + -xi[1] + 0.6339745962155613532362768292*xi[1]*xi[1] + 2.366025403784438646763723171*xi[1]*xi[2] + }; + } + if (i == 12) { + return vec3{ + 6*xi[1] - 3*xi[0]*xi[1] - 6*xi[1]*xi[1] - 6*xi[1]*xi[2], + -3*xi[0] + 3*xi[0]*xi[0] + 6*xi[0]*xi[1] + 3*xi[0]*xi[2], + 3*xi[0]*xi[1] + }; + } + if (i == 13) { + return vec3{ + -3*xi[1] - 3*xi[0]*xi[1] + 3*xi[1]*xi[1] + 3*xi[1]*xi[2], + -3*xi[0] + 3*xi[0]*xi[0] - 3*xi[0]*xi[1] + 3*xi[0]*xi[2], + -6*xi[0]*xi[1] + }; + } + if (i == 14) { + return vec3{ + 6*xi[2] - 3*xi[0]*xi[2] - 6*xi[1]*xi[2] - 6*xi[2]*xi[2], + 3*xi[0]*xi[2], + -3*xi[0] + 3*xi[0]*xi[0] + 3*xi[0]*xi[1] + 6*xi[0]*xi[2] + }; + } + if (i == 15) { + return vec3{ + -3*xi[2] + 6*xi[0]*xi[2] + 3*xi[1]*xi[2] + 3*xi[2]*xi[2], + 3*xi[0]*xi[2], + 6*xi[0] - 6*xi[0]*xi[0] - 6*xi[0]*xi[1] - 3*xi[0]*xi[2] + }; + } + if (i == 16) { + return vec3{ + -3*xi[1]*xi[2], + 6*xi[0]*xi[2], + -3*xi[0]*xi[1] + }; + } + if (i == 17) { + return vec3{ + -3*xi[1]*xi[2], + -3*xi[0]*xi[2], + 6*xi[0]*xi[1] + }; + } + if (i == 18) { + return vec3{ + -6*xi[1]*xi[2], + -3*xi[2] + 3*xi[0]*xi[2] - 3*xi[1]*xi[2] + 3*xi[2]*xi[2], + -3*xi[1] + 3*xi[0]*xi[1] + 3*xi[1]*xi[1] - 3*xi[1]*xi[2] + }; + } + if (i == 19) { + return vec3{ + 3*xi[1]*xi[2], + -3*xi[2] + 3*xi[0]*xi[2] + 6*xi[1]*xi[2] + 3*xi[2]*xi[2], + 6*xi[1] - 6*xi[0]*xi[1] - 6*xi[1]*xi[1] - 3*xi[1]*xi[2] + }; + } + } + + if (p == 3) { + if (i == 0) { + return vec3{ + 1.47883055770123614752987757 - 4.6243277820691389617264218*xi[0] + 10*xi[0]*xi[0]/3. - 8.9733478255330900061205269*xi[1] + 15.3577068878454845050412827*xi[0]*xi[1] - 10*xi[0]*xi[0]*xi[1]/3. + 14.3045824936940910415209517*xi[1]*xi[1] - 10.7333791057763455433148609*xi[0]*xi[1]*xi[1] - 6.8100652258622371829303024*xi[1]*xi[1]*xi[1] - 8.9733478255330900061205269*xi[2] + 15.3577068878454845050412827*xi[0]*xi[2] - 10*xi[0]*xi[0]*xi[2]/3. + 31.3609728867648172865104794*xi[1]*xi[2] - 21.4667582115526910866297217*xi[0]*xi[1]*xi[2] - 23.1820035769633467522594831*xi[1]*xi[1]*xi[2] + 14.3045824936940910415209517*xi[2]*xi[2] - 10.7333791057763455433148609*xi[0]*xi[2]*xi[2] - 23.1820035769633467522594831*xi[1]*xi[2]*xi[2] - 6.8100652258622371829303024*xi[2]*xi[2]*xi[2], + 1.47883055770123614752987757*xi[0] - 4.6243277820691389617264218*xi[0]*xi[0] + 10*xi[0]*xi[0]*xi[0]/3. - 7.4945172678318538585906493*xi[0]*xi[1] + 10.7333791057763455433148609*xi[0]*xi[0]*xi[1] + 6.8100652258622371829303024*xi[0]*xi[1]*xi[1] - 7.4945172678318538585906493*xi[0]*xi[2] + 10.7333791057763455433148609*xi[0]*xi[0]*xi[2] + 16.3719383511011095693291808*xi[0]*xi[1]*xi[2] + 6.8100652258622371829303024*xi[0]*xi[2]*xi[2], + 1.47883055770123614752987757*xi[0] - 4.6243277820691389617264218*xi[0]*xi[0] + 10*xi[0]*xi[0]*xi[0]/3. - 7.4945172678318538585906493*xi[0]*xi[1] + 10.7333791057763455433148609*xi[0]*xi[0]*xi[1] + 6.8100652258622371829303024*xi[0]*xi[1]*xi[1] - 7.4945172678318538585906493*xi[0]*xi[2] + 10.7333791057763455433148609*xi[0]*xi[0]*xi[2] + 16.3719383511011095693291808*xi[0]*xi[1]*xi[2] + 6.8100652258622371829303024*xi[0]*xi[2]*xi[2] + }; + } + if (i == 1) { + return vec3{ + -0.6666666666666666 + 20*xi[0]/3. - 20*xi[0]*xi[0]/3. - 0.303288211279566160999204378*xi[1] - 40*xi[0]*xi[1]/3. + 20*xi[0]*xi[0]*xi[1]/3. + 3.55371777595813879120445478*xi[1]*xi[1] + 20*xi[0]*xi[1]*xi[1]/3. - 2.58376289801190596353858374*xi[1]*xi[1]*xi[1] - 0.303288211279566160999204378*xi[2] - 40*xi[0]*xi[2]/3. + 20*xi[0]*xi[0]*xi[2]/3. + 8.532022983438516349581543*xi[1]*xi[2] + 40*xi[0]*xi[1]*xi[2]/3. - 9.1758761255579566577883846*xi[1]*xi[1]*xi[2] + 3.55371777595813879120445478*xi[2]*xi[2] + 20*xi[0]*xi[2]*xi[2]/3. - 9.1758761255579566577883846*xi[1]*xi[2]*xi[2] - 2.58376289801190596353858374*xi[2]*xi[2]*xi[2], + -2*xi[0]/3. + 20*xi[0]*xi[0]/3. - 20*xi[0]*xi[0]*xi[0]/3. - 0.96995487794623282766587104*xi[0]*xi[1] - 20*xi[0]*xi[0]*xi[1]/3. + 2.58376289801190596353858374*xi[0]*xi[1]*xi[1] - 0.96995487794623282766587104*xi[0]*xi[2] - 20*xi[0]*xi[0]*xi[2]/3. + 6.5921132275460506942498009*xi[0]*xi[1]*xi[2] + 2.58376289801190596353858374*xi[0]*xi[2]*xi[2], + -2*xi[0]/3. + 20*xi[0]*xi[0]/3. - 20*xi[0]*xi[0]*xi[0]/3. - 0.96995487794623282766587104*xi[0]*xi[1] - 20*xi[0]*xi[0]*xi[1]/3. + 2.5837628980119059635385837*xi[0]*xi[1]*xi[1] - 0.96995487794623282766587104*xi[0]*xi[2] - 20*xi[0]*xi[0]*xi[2]/3. + 6.5921132275460506942498009*xi[0]*xi[1]*xi[2] + 2.58376289801190596353858374*xi[0]*xi[2]*xi[2] + }; + } + if (i == 2) { + return vec3{ + 0.1878361089654305191367891 - 2.04233888459752770494024487*xi[0] + 10*xi[0]*xi[0]/3. + 1.00868684438153346064717759*xi[1] - 2.02437355451215117170794933*xi[0]*xi[1] - 10*xi[0]*xi[0]*xi[1]/3. - 1.78650349992773900683519184*xi[1]*xi[1] + 4.0667124391096788766481942*xi[0]*xi[1]*xi[1] + 0.58998054658077502705122515*xi[1]*xi[1]*xi[1] + 1.00868684438153346064717759*xi[2] - 2.02437355451215117170794933*xi[0]*xi[2] - 10*xi[0]*xi[0]*xi[2]/3. - 0.8211991004788428102018077*xi[1]*xi[2] + 8.1334248782193577532963884*xi[0]*xi[1]*xi[2] - 0.98186625963431012231490054*xi[1]*xi[1]*xi[2] - 1.78650349992773900683519184*xi[2]*xi[2] + 4.0667124391096788766481942*xi[0]*xi[2]*xi[2] - 0.98186625963431012231490054*xi[1]*xi[2]*xi[2] + 0.58998054658077502705122515*xi[2]*xi[2]*xi[2], + 0.1878361089654305191367891*xi[0] - 2.04233888459752770494024487*xi[0]*xi[0] + 10*xi[0]*xi[0]*xi[0]/3. + 1.19652295334696397978396669*xi[0]*xi[1] - 4.0667124391096788766481942*xi[0]*xi[0]*xi[1] - 0.58998054658077502705122515*xi[0]*xi[1]*xi[1] + 1.19652295334696397978396669*xi[0]*xi[2] - 4.0667124391096788766481942*xi[0]*xi[0]*xi[2] + 1.57184680621508514936612569*xi[0]*xi[1]*xi[2] - 0.58998054658077502705122515*xi[0]*xi[2]*xi[2], + 0.1878361089654305191367891*xi[0] - 2.04233888459752770494024487*xi[0]*xi[0] + 10*xi[0]*xi[0]*xi[0]/3. + 1.19652295334696397978396669*xi[0]*xi[1] - 4.0667124391096788766481942*xi[0]*xi[0]*xi[1] - 0.58998054658077502705122515*xi[0]*xi[1]*xi[1] + 1.19652295334696397978396669*xi[0]*xi[2] - 4.0667124391096788766481942*xi[0]*xi[0]*xi[2] + 1.57184680621508514936612569*xi[0]*xi[1]*xi[2] - 0.58998054658077502705122515*xi[0]*xi[2]*xi[2] + }; + } + if (i == 3) { + return vec3{ + -0.79437851573161947186953064*xi[1] + 6.1256131838926205072699555*xi[0]*xi[1] - 6.8100652258622371829303024*xi[0]*xi[0]*xi[1] + 0.0165618601854139256815163943*xi[1]*xi[1] - 2.8867513459481288225457439*xi[0]*xi[1]*xi[1] + 0.58998054658077502705122515*xi[1]*xi[1]*xi[1] - 2.75180789937663520346857598*xi[1]*xi[2] + 2.75180789937663520346857598*xi[0]*xi[1]*xi[2] + 2.75180789937663520346857598*xi[1]*xi[1]*xi[2] + 2.75180789937663520346857598*xi[1]*xi[2]*xi[2], + 0.79437851573161947186953064*xi[0] - 6.1256131838926205072699555*xi[0]*xi[0] + 6.8100652258622371829303024*xi[0]*xi[0]*xi[0] - 0.0165618601854139256815163943*xi[0]*xi[1] + 2.8867513459481288225457439*xi[0]*xi[0]*xi[1] - 0.58998054658077502705122515*xi[0]*xi[1]*xi[1] + 2.75180789937663520346857598*xi[0]*xi[2] - 2.75180789937663520346857598*xi[0]*xi[0]*xi[2] - 2.75180789937663520346857598*xi[0]*xi[1]*xi[2] - 2.75180789937663520346857598*xi[0]*xi[2]*xi[2], + 0 + }; + } + if (i == 4) { + return vec3{ + -0.94714135339900646920604603*xi[1] + 4.19757091807757909941129644*xi[0]*xi[1] - 2.58376289801190596353858374*xi[0]*xi[0]*xi[1] + 4.19757091807757909941129644*xi[1]*xi[1] - 11.8341924626904785937438341*xi[0]*xi[1]*xi[1] - 2.58376289801190596353858374*xi[1]*xi[1]*xi[1] - 1.4245874315222387671726334*xi[1]*xi[2] + 1.4245874315222387671726334*xi[0]*xi[1]*xi[2] + 1.4245874315222387671726334*xi[1]*xi[1]*xi[2] + 1.4245874315222387671726334*xi[1]*xi[2]*xi[2], + 0.94714135339900646920604603*xi[0] - 4.19757091807757909941129644*xi[0]*xi[0] + 2.58376289801190596353858374*xi[0]*xi[0]*xi[0] - 4.19757091807757909941129644*xi[0]*xi[1] + 11.8341924626904785937438341*xi[0]*xi[0]*xi[1] + 2.58376289801190596353858374*xi[0]*xi[1]*xi[1] + 1.4245874315222387671726334*xi[0]*xi[2] - 1.4245874315222387671726334*xi[0]*xi[0]*xi[2] - 1.4245874315222387671726334*xi[0]*xi[1]*xi[2] - 1.4245874315222387671726334*xi[0]*xi[2]*xi[2], + 0 + }; + } + if (i == 5) { + return vec3{ + -0.79437851573161947186953064*xi[1] + 0.0165618601854139256815163945*xi[0]*xi[1] + 0.58998054658077502705122515*xi[0]*xi[0]*xi[1] + 6.1256131838926205072699555*xi[1]*xi[1] - 2.8867513459481288225457439*xi[0]*xi[1]*xi[1] - 6.8100652258622371829303024*xi[1]*xi[1]*xi[1] - 2.75180789937663520346857598*xi[1]*xi[2] + 2.75180789937663520346857598*xi[0]*xi[1]*xi[2] + 2.75180789937663520346857598*xi[1]*xi[1]*xi[2] + 2.75180789937663520346857598*xi[1]*xi[2]*xi[2], + 0.79437851573161947186953064*xi[0] - 0.0165618601854139256815163945*xi[0]*xi[0] - 0.58998054658077502705122515*xi[0]*xi[0]*xi[0] - 6.1256131838926205072699555*xi[0]*xi[1] + 2.8867513459481288225457439*xi[0]*xi[0]*xi[1] + 6.8100652258622371829303024*xi[0]*xi[1]*xi[1] + 2.75180789937663520346857598*xi[0]*xi[2] - 2.75180789937663520346857598*xi[0]*xi[0]*xi[2] - 2.75180789937663520346857598*xi[0]*xi[1]*xi[2] - 2.75180789937663520346857598*xi[0]*xi[2]*xi[2], + 0 + }; + } + if (i == 6) { + return vec3{ + -0.1878361089654305191367891*xi[1] - 1.19652295334696397978396669*xi[0]*xi[1] + 0.58998054658077502705122515*xi[0]*xi[0]*xi[1] + 2.04233888459752770494024487*xi[1]*xi[1] + 4.0667124391096788766481942*xi[0]*xi[1]*xi[1] - 10*xi[1]*xi[1]*xi[1]/3. - 1.19652295334696397978396669*xi[1]*xi[2] - 1.57184680621508514936612569*xi[0]*xi[1]*xi[2] + 4.0667124391096788766481942*xi[1]*xi[1]*xi[2] + 0.58998054658077502705122515*xi[1]*xi[2]*xi[2], + -0.1878361089654305191367891 - 1.00868684438153346064717759*xi[0] + 1.78650349992773900683519184*xi[0]*xi[0] - 0.58998054658077502705122515*xi[0]*xi[0]*xi[0] + 2.04233888459752770494024487*xi[1] + 2.02437355451215117170794934*xi[0]*xi[1] - 4.0667124391096788766481942*xi[0]*xi[0]*xi[1] - 10*xi[1]*xi[1]/3. + 10*xi[0]*xi[1]*xi[1]/3. - 1.00868684438153346064717759*xi[2] + 0.8211991004788428102018077*xi[0]*xi[2] + 0.98186625963431012231490054*xi[0]*xi[0]*xi[2] + 2.02437355451215117170794934*xi[1]*xi[2] - 8.1334248782193577532963884*xi[0]*xi[1]*xi[2] + 10*xi[1]*xi[1]*xi[2]/3. + 1.78650349992773900683519184*xi[2]*xi[2] + 0.98186625963431012231490054*xi[0]*xi[2]*xi[2] - 4.0667124391096788766481942*xi[1]*xi[2]*xi[2] - 0.58998054658077502705122515*xi[2]*xi[2]*xi[2], + -0.1878361089654305191367891*xi[1] - 1.19652295334696397978396669*xi[0]*xi[1] + 0.58998054658077502705122515*xi[0]*xi[0]*xi[1] + 2.04233888459752770494024487*xi[1]*xi[1] + 4.0667124391096788766481942*xi[0]*xi[1]*xi[1] - 10*xi[1]*xi[1]*xi[1]/3. - 1.19652295334696397978396669*xi[1]*xi[2] - 1.57184680621508514936612569*xi[0]*xi[1]*xi[2] + 4.0667124391096788766481942*xi[1]*xi[1]*xi[2] + 0.58998054658077502705122515*xi[1]*xi[2]*xi[2] + }; + } + if (i == 7) { + return vec3{ + 2*xi[1]/3. + 0.96995487794623282766587105*xi[0]*xi[1] - 2.58376289801190596353858374*xi[0]*xi[0]*xi[1] - 20*xi[1]*xi[1]/3. + 20*xi[0]*xi[1]*xi[1]/3. + 20*xi[1]*xi[1]*xi[1]/3. + 0.96995487794623282766587105*xi[1]*xi[2] - 6.5921132275460506942498009*xi[0]*xi[1]*xi[2] + 20*xi[1]*xi[1]*xi[2]/3. - 2.58376289801190596353858374*xi[1]*xi[2]*xi[2], + 0.6666666666666666 + 0.303288211279566160999204379*xi[0] - 3.55371777595813879120445479*xi[0]*xi[0] + 2.58376289801190596353858374*xi[0]*xi[0]*xi[0] - 20*xi[1]/3. + 40*xi[0]*xi[1]/3. - 20*xi[0]*xi[0]*xi[1]/3. + 20*xi[1]*xi[1]/3. - 20*xi[0]*xi[1]*xi[1]/3. + 0.303288211279566160999204379*xi[2] - 8.532022983438516349581543*xi[0]*xi[2] + 9.1758761255579566577883846*xi[0]*xi[0]*xi[2] + 40*xi[1]*xi[2]/3. - 40*xi[0]*xi[1]*xi[2]/3. - 20*xi[1]*xi[1]*xi[2]/3. - 3.55371777595813879120445479*xi[2]*xi[2] + 9.1758761255579566577883846*xi[0]*xi[2]*xi[2] - 20*xi[1]*xi[2]*xi[2]/3. + 2.58376289801190596353858374*xi[2]*xi[2]*xi[2], + 2*xi[1]/3. + 0.96995487794623282766587105*xi[0]*xi[1] - 2.5837628980119059635385837*xi[0]*xi[0]*xi[1] - 20*xi[1]*xi[1]/3. + 20*xi[0]*xi[1]*xi[1]/3. + 20*xi[1]*xi[1]*xi[1]/3. + 0.96995487794623282766587105*xi[1]*xi[2] - 6.5921132275460506942498009*xi[0]*xi[1]*xi[2] + 20*xi[1]*xi[1]*xi[2]/3. - 2.58376289801190596353858374*xi[1]*xi[2]*xi[2] + }; + } + if (i == 8) { + return vec3{ + -1.47883055770123614752987757*xi[1] + 7.4945172678318538585906493*xi[0]*xi[1] - 6.8100652258622371829303024*xi[0]*xi[0]*xi[1] + 4.6243277820691389617264218*xi[1]*xi[1] - 10.7333791057763455433148609*xi[0]*xi[1]*xi[1] - 10*xi[1]*xi[1]*xi[1]/3. + 7.4945172678318538585906493*xi[1]*xi[2] - 16.3719383511011095693291808*xi[0]*xi[1]*xi[2] - 10.7333791057763455433148609*xi[1]*xi[1]*xi[2] - 6.8100652258622371829303024*xi[1]*xi[2]*xi[2], + -1.47883055770123614752987757 + 8.9733478255330900061205269*xi[0] - 14.3045824936940910415209517*xi[0]*xi[0] + 6.8100652258622371829303024*xi[0]*xi[0]*xi[0] + 4.6243277820691389617264218*xi[1] - 15.3577068878454845050412827*xi[0]*xi[1] + 10.7333791057763455433148609*xi[0]*xi[0]*xi[1] - 10*xi[1]*xi[1]/3. + 10*xi[0]*xi[1]*xi[1]/3. + 8.9733478255330900061205269*xi[2] - 31.3609728867648172865104794*xi[0]*xi[2] + 23.1820035769633467522594831*xi[0]*xi[0]*xi[2] - 15.3577068878454845050412827*xi[1]*xi[2] + 21.4667582115526910866297217*xi[0]*xi[1]*xi[2] + 10*xi[1]*xi[1]*xi[2]/3. - 14.3045824936940910415209517*xi[2]*xi[2] + 23.1820035769633467522594831*xi[0]*xi[2]*xi[2] + 10.7333791057763455433148609*xi[1]*xi[2]*xi[2] + 6.8100652258622371829303024*xi[2]*xi[2]*xi[2], + -1.47883055770123614752987757*xi[1] + 7.4945172678318538585906493*xi[0]*xi[1] - 6.8100652258622371829303024*xi[0]*xi[0]*xi[1] + 4.6243277820691389617264218*xi[1]*xi[1] - 10.7333791057763455433148609*xi[0]*xi[1]*xi[1] - 10*xi[1]*xi[1]*xi[1]/3. + 7.4945172678318538585906493*xi[1]*xi[2] - 16.3719383511011095693291808*xi[0]*xi[1]*xi[2] - 10.7333791057763455433148609*xi[1]*xi[1]*xi[2] - 6.8100652258622371829303024*xi[1]*xi[2]*xi[2] + }; + } + if (i == 9) { + return vec3{ + 1.47883055770123614752987757*xi[2] - 7.4945172678318538585906493*xi[0]*xi[2] + 6.8100652258622371829303024*xi[0]*xi[0]*xi[2] - 7.4945172678318538585906493*xi[1]*xi[2] + 16.3719383511011095693291808*xi[0]*xi[1]*xi[2] + 6.8100652258622371829303024*xi[1]*xi[1]*xi[2] - 4.6243277820691389617264218*xi[2]*xi[2] + 10.7333791057763455433148609*xi[0]*xi[2]*xi[2] + 10.7333791057763455433148609*xi[1]*xi[2]*xi[2] + 10*xi[2]*xi[2]*xi[2]/3., + 1.47883055770123614752987757*xi[2] - 7.4945172678318538585906493*xi[0]*xi[2] + 6.8100652258622371829303024*xi[0]*xi[0]*xi[2] - 7.4945172678318538585906493*xi[1]*xi[2] + 16.3719383511011095693291808*xi[0]*xi[1]*xi[2] + 6.8100652258622371829303024*xi[1]*xi[1]*xi[2] - 4.6243277820691389617264218*xi[2]*xi[2] + 10.7333791057763455433148609*xi[0]*xi[2]*xi[2] + 10.7333791057763455433148609*xi[1]*xi[2]*xi[2] + 10*xi[2]*xi[2]*xi[2]/3., + 1.47883055770123614752987757 - 8.9733478255330900061205269*xi[0] + 14.3045824936940910415209517*xi[0]*xi[0] - 6.8100652258622371829303024*xi[0]*xi[0]*xi[0] - 8.9733478255330900061205269*xi[1] + 31.3609728867648172865104794*xi[0]*xi[1] - 23.1820035769633467522594831*xi[0]*xi[0]*xi[1] + 14.3045824936940910415209517*xi[1]*xi[1] - 23.1820035769633467522594831*xi[0]*xi[1]*xi[1] - 6.8100652258622371829303024*xi[1]*xi[1]*xi[1] - 4.6243277820691389617264218*xi[2] + 15.3577068878454845050412827*xi[0]*xi[2] - 10.7333791057763455433148609*xi[0]*xi[0]*xi[2] + 15.3577068878454845050412827*xi[1]*xi[2] - 21.4667582115526910866297217*xi[0]*xi[1]*xi[2] - 10.7333791057763455433148609*xi[1]*xi[1]*xi[2] + 10*xi[2]*xi[2]/3. - 10*xi[0]*xi[2]*xi[2]/3. - 10*xi[1]*xi[2]*xi[2]/3. + }; + } + if (i == 10) { + return vec3{ + -2*xi[2]/3. - 0.96995487794623282766587104*xi[0]*xi[2] + 2.58376289801190596353858374*xi[0]*xi[0]*xi[2] - 0.96995487794623282766587104*xi[1]*xi[2] + 6.5921132275460506942498009*xi[0]*xi[1]*xi[2] + 2.58376289801190596353858374*xi[1]*xi[1]*xi[2] + 20*xi[2]*xi[2]/3. - 20*xi[0]*xi[2]*xi[2]/3. - 20*xi[1]*xi[2]*xi[2]/3. - 20*xi[2]*xi[2]*xi[2]/3., + -2*xi[2]/3. - 0.96995487794623282766587104*xi[0]*xi[2] + 2.58376289801190596353858374*xi[0]*xi[0]*xi[2] - 0.96995487794623282766587104*xi[1]*xi[2] + 6.5921132275460506942498009*xi[0]*xi[1]*xi[2] + 2.58376289801190596353858374*xi[1]*xi[1]*xi[2] + 20*xi[2]*xi[2]/3. - 20*xi[0]*xi[2]*xi[2]/3. - 20*xi[1]*xi[2]*xi[2]/3. - 20*xi[2]*xi[2]*xi[2]/3., + -0.6666666666666666 - 0.303288211279566160999204378*xi[0] + 3.55371777595813879120445478*xi[0]*xi[0] - 2.58376289801190596353858374*xi[0]*xi[0]*xi[0] - 0.303288211279566160999204378*xi[1] + 8.532022983438516349581543*xi[0]*xi[1] - 9.1758761255579566577883846*xi[0]*xi[0]*xi[1] + 3.55371777595813879120445478*xi[1]*xi[1] - 9.1758761255579566577883846*xi[0]*xi[1]*xi[1] - 2.58376289801190596353858374*xi[1]*xi[1]*xi[1] + 20*xi[2]/3. - 40*xi[0]*xi[2]/3. + 20*xi[0]*xi[0]*xi[2]/3. - 40*xi[1]*xi[2]/3. + 40*xi[0]*xi[1]*xi[2]/3. + 20*xi[1]*xi[1]*xi[2]/3. - 20*xi[2]*xi[2]/3. + 20*xi[0]*xi[2]*xi[2]/3. + 20*xi[1]*xi[2]*xi[2]/3. + }; + } + if (i == 11) { + return vec3{ + 0.1878361089654305191367891*xi[2] + 1.19652295334696397978396669*xi[0]*xi[2] - 0.58998054658077502705122515*xi[0]*xi[0]*xi[2] + 1.19652295334696397978396669*xi[1]*xi[2] + 1.57184680621508514936612569*xi[0]*xi[1]*xi[2] - 0.58998054658077502705122515*xi[1]*xi[1]*xi[2] - 2.04233888459752770494024487*xi[2]*xi[2] - 4.0667124391096788766481942*xi[0]*xi[2]*xi[2] - 4.0667124391096788766481942*xi[1]*xi[2]*xi[2] + 10*xi[2]*xi[2]*xi[2]/3., + 0.1878361089654305191367891*xi[2] + 1.19652295334696397978396669*xi[0]*xi[2] - 0.58998054658077502705122515*xi[0]*xi[0]*xi[2] + 1.19652295334696397978396669*xi[1]*xi[2] + 1.57184680621508514936612569*xi[0]*xi[1]*xi[2] - 0.58998054658077502705122515*xi[1]*xi[1]*xi[2] - 2.04233888459752770494024487*xi[2]*xi[2] - 4.0667124391096788766481942*xi[0]*xi[2]*xi[2] - 4.0667124391096788766481942*xi[1]*xi[2]*xi[2] + 10*xi[2]*xi[2]*xi[2]/3., + 0.1878361089654305191367891 + 1.00868684438153346064717759*xi[0] - 1.78650349992773900683519184*xi[0]*xi[0] + 0.58998054658077502705122515*xi[0]*xi[0]*xi[0] + 1.00868684438153346064717759*xi[1] - 0.8211991004788428102018077*xi[0]*xi[1] - 0.98186625963431012231490054*xi[0]*xi[0]*xi[1] - 1.78650349992773900683519184*xi[1]*xi[1] - 0.98186625963431012231490054*xi[0]*xi[1]*xi[1] + 0.58998054658077502705122515*xi[1]*xi[1]*xi[1] - 2.04233888459752770494024487*xi[2] - 2.02437355451215117170794933*xi[0]*xi[2] + 4.0667124391096788766481942*xi[0]*xi[0]*xi[2] - 2.02437355451215117170794933*xi[1]*xi[2] + 8.1334248782193577532963884*xi[0]*xi[1]*xi[2] + 4.0667124391096788766481942*xi[1]*xi[1]*xi[2] + 10*xi[2]*xi[2]/3. - 10*xi[0]*xi[2]*xi[2]/3. - 10*xi[1]*xi[2]*xi[2]/3. + }; + } + if (i == 12) { + return vec3{ + -0.79437851573161947186953064*xi[2] + 6.1256131838926205072699555*xi[0]*xi[2] - 6.8100652258622371829303024*xi[0]*xi[0]*xi[2] - 2.75180789937663520346857598*xi[1]*xi[2] + 2.75180789937663520346857598*xi[0]*xi[1]*xi[2] + 2.75180789937663520346857598*xi[1]*xi[1]*xi[2] + 0.0165618601854139256815163943*xi[2]*xi[2] - 2.8867513459481288225457439*xi[0]*xi[2]*xi[2] + 2.75180789937663520346857598*xi[1]*xi[2]*xi[2] + 0.58998054658077502705122515*xi[2]*xi[2]*xi[2], + 0, + 0.79437851573161947186953064*xi[0] - 6.1256131838926205072699555*xi[0]*xi[0] + 6.8100652258622371829303024*xi[0]*xi[0]*xi[0] + 2.75180789937663520346857598*xi[0]*xi[1] - 2.75180789937663520346857598*xi[0]*xi[0]*xi[1] - 2.75180789937663520346857598*xi[0]*xi[1]*xi[1] - 0.0165618601854139256815163943*xi[0]*xi[2] + 2.8867513459481288225457439*xi[0]*xi[0]*xi[2] - 2.75180789937663520346857598*xi[0]*xi[1]*xi[2] - 0.58998054658077502705122515*xi[0]*xi[2]*xi[2] + }; + } + if (i == 13) { + return vec3{ + -0.94714135339900646920604603*xi[2] + 4.19757091807757909941129644*xi[0]*xi[2] - 2.58376289801190596353858374*xi[0]*xi[0]*xi[2] - 1.4245874315222387671726334*xi[1]*xi[2] + 1.4245874315222387671726334*xi[0]*xi[1]*xi[2] + 1.4245874315222387671726334*xi[1]*xi[1]*xi[2] + 4.19757091807757909941129644*xi[2]*xi[2] - 11.8341924626904785937438341*xi[0]*xi[2]*xi[2] + 1.4245874315222387671726334*xi[1]*xi[2]*xi[2] - 2.58376289801190596353858374*xi[2]*xi[2]*xi[2], + 0, + 0.94714135339900646920604603*xi[0] - 4.19757091807757909941129644*xi[0]*xi[0] + 2.58376289801190596353858374*xi[0]*xi[0]*xi[0] + 1.4245874315222387671726334*xi[0]*xi[1] - 1.4245874315222387671726334*xi[0]*xi[0]*xi[1] - 1.4245874315222387671726334*xi[0]*xi[1]*xi[1] - 4.19757091807757909941129644*xi[0]*xi[2] + 11.8341924626904785937438341*xi[0]*xi[0]*xi[2] - 1.4245874315222387671726334*xi[0]*xi[1]*xi[2] + 2.58376289801190596353858374*xi[0]*xi[2]*xi[2] + }; + } + if (i == 14) { + return vec3{ + -0.79437851573161947186953064*xi[2] + 0.0165618601854139256815163945*xi[0]*xi[2] + 0.58998054658077502705122515*xi[0]*xi[0]*xi[2] - 2.75180789937663520346857598*xi[1]*xi[2] + 2.75180789937663520346857598*xi[0]*xi[1]*xi[2] + 2.75180789937663520346857598*xi[1]*xi[1]*xi[2] + 6.1256131838926205072699555*xi[2]*xi[2] - 2.8867513459481288225457439*xi[0]*xi[2]*xi[2] + 2.75180789937663520346857598*xi[1]*xi[2]*xi[2] - 6.8100652258622371829303024*xi[2]*xi[2]*xi[2], + 0, + 0.79437851573161947186953064*xi[0] - 0.0165618601854139256815163945*xi[0]*xi[0] - 0.58998054658077502705122515*xi[0]*xi[0]*xi[0] + 2.75180789937663520346857598*xi[0]*xi[1] - 2.75180789937663520346857598*xi[0]*xi[0]*xi[1] - 2.75180789937663520346857598*xi[0]*xi[1]*xi[1] - 6.1256131838926205072699555*xi[0]*xi[2] + 2.8867513459481288225457439*xi[0]*xi[0]*xi[2] - 2.75180789937663520346857598*xi[0]*xi[1]*xi[2] + 6.8100652258622371829303024*xi[0]*xi[2]*xi[2] + }; + } + if (i == 15) { + return vec3{ + 0, + -0.79437851573161947186953064*xi[2] - 2.75180789937663520346857598*xi[0]*xi[2] + 2.75180789937663520346857598*xi[0]*xi[0]*xi[2] + 6.1256131838926205072699555*xi[1]*xi[2] + 2.75180789937663520346857598*xi[0]*xi[1]*xi[2] - 6.8100652258622371829303024*xi[1]*xi[1]*xi[2] + 0.0165618601854139256815163943*xi[2]*xi[2] + 2.75180789937663520346857598*xi[0]*xi[2]*xi[2] - 2.8867513459481288225457439*xi[1]*xi[2]*xi[2] + 0.58998054658077502705122515*xi[2]*xi[2]*xi[2], + 0.79437851573161947186953064*xi[1] + 2.75180789937663520346857598*xi[0]*xi[1] - 2.75180789937663520346857598*xi[0]*xi[0]*xi[1] - 6.1256131838926205072699555*xi[1]*xi[1] - 2.75180789937663520346857598*xi[0]*xi[1]*xi[1] + 6.8100652258622371829303024*xi[1]*xi[1]*xi[1] - 0.0165618601854139256815163943*xi[1]*xi[2] - 2.75180789937663520346857598*xi[0]*xi[1]*xi[2] + 2.8867513459481288225457439*xi[1]*xi[1]*xi[2] - 0.58998054658077502705122515*xi[1]*xi[2]*xi[2] + }; + } + if (i == 16) { + return vec3{ + 0, + -0.94714135339900646920604603*xi[2] - 1.4245874315222387671726334*xi[0]*xi[2] + 1.4245874315222387671726334*xi[0]*xi[0]*xi[2] + 4.19757091807757909941129644*xi[1]*xi[2] + 1.4245874315222387671726334*xi[0]*xi[1]*xi[2] - 2.58376289801190596353858374*xi[1]*xi[1]*xi[2] + 4.19757091807757909941129644*xi[2]*xi[2] + 1.4245874315222387671726334*xi[0]*xi[2]*xi[2] - 11.8341924626904785937438341*xi[1]*xi[2]*xi[2] - 2.58376289801190596353858374*xi[2]*xi[2]*xi[2], + 0.94714135339900646920604603*xi[1] + 1.4245874315222387671726334*xi[0]*xi[1] - 1.4245874315222387671726334*xi[0]*xi[0]*xi[1] - 4.19757091807757909941129644*xi[1]*xi[1] - 1.4245874315222387671726334*xi[0]*xi[1]*xi[1] + 2.58376289801190596353858374*xi[1]*xi[1]*xi[1] - 4.19757091807757909941129644*xi[1]*xi[2] - 1.4245874315222387671726334*xi[0]*xi[1]*xi[2] + 11.8341924626904785937438341*xi[1]*xi[1]*xi[2] + 2.58376289801190596353858374*xi[1]*xi[2]*xi[2] + }; + } + if (i == 17) { + return vec3{ + 0, + -0.79437851573161947186953064*xi[2] - 2.75180789937663520346857598*xi[0]*xi[2] + 2.75180789937663520346857598*xi[0]*xi[0]*xi[2] + 0.0165618601854139256815163945*xi[1]*xi[2] + 2.75180789937663520346857598*xi[0]*xi[1]*xi[2] + 0.58998054658077502705122515*xi[1]*xi[1]*xi[2] + 6.1256131838926205072699555*xi[2]*xi[2] + 2.75180789937663520346857598*xi[0]*xi[2]*xi[2] - 2.8867513459481288225457439*xi[1]*xi[2]*xi[2] - 6.8100652258622371829303024*xi[2]*xi[2]*xi[2], + 0.79437851573161947186953064*xi[1] + 2.75180789937663520346857598*xi[0]*xi[1] - 2.75180789937663520346857598*xi[0]*xi[0]*xi[1] - 0.0165618601854139256815163945*xi[1]*xi[1] - 2.75180789937663520346857598*xi[0]*xi[1]*xi[1] - 0.58998054658077502705122515*xi[1]*xi[1]*xi[1] - 6.1256131838926205072699555*xi[1]*xi[2] - 2.75180789937663520346857598*xi[0]*xi[1]*xi[2] + 2.8867513459481288225457439*xi[1]*xi[1]*xi[2] + 6.8100652258622371829303024*xi[1]*xi[2]*xi[2] + }; + } + if (i == 18) { + return vec3{ + -2.66025403784438646763723171*xi[1] + 2.09807621135331594029116951*xi[0]*xi[1] + 17.9089653438086685770214805*xi[1]*xi[1] - 12.0262794416288251144009549*xi[0]*xi[1]*xi[1] - 15.2487113059642821093842488*xi[1]*xi[1]*xi[1] - 1.94744111674234977119809024*xi[1]*xi[2] + 3.63397459621556135323627683*xi[0]*xi[1]*xi[2] - 10.6410161513775458705489268*xi[1]*xi[1]*xi[2] + 4.60769515458673623883532195*xi[1]*xi[2]*xi[2], + 2.09807621135331594029116951*xi[0] - 2.09807621135331594029116951*xi[0]*xi[0] - 14.6865334794732115820381866*xi[0]*xi[1] + 12.0262794416288251144009549*xi[0]*xi[0]*xi[1] + 15.2487113059642821093842488*xi[0]*xi[1]*xi[1] + 1.53589838486224541294510732*xi[0]*xi[2] - 3.63397459621556135323627683*xi[0]*xi[0]*xi[2] + 7.4185842870420888755656329*xi[0]*xi[1]*xi[2] - 3.63397459621556135323627683*xi[0]*xi[2]*xi[2], + -0.5621778264910705273460622*xi[0]*xi[1] + 3.2224318643354569949832939*xi[0]*xi[1]*xi[1] - 0.9737205583711748855990451*xi[0]*xi[1]*xi[2] + }; + } + if (i == 19) { + return vec3{ + 0.5621778264910705273460622*xi[1] + 2.09807621135331594029116951*xi[0]*xi[1] - 3.7846096908265275223293561*xi[1]*xi[1] - 12.0262794416288251144009549*xi[0]*xi[1]*xi[1] + 3.2224318643354569949832939*xi[1]*xi[1]*xi[1] + 0.411542731880104358252982926*xi[1]*xi[2] + 3.63397459621556135323627683*xi[0]*xi[1]*xi[2] + 2.24871130596428210938424878*xi[1]*xi[1]*xi[2] - 0.97372055837117488559904512*xi[1]*xi[2]*xi[2], + 2.09807621135331594029116951*xi[0] - 2.09807621135331594029116951*xi[0]*xi[0] - 11.4641016151377545870548927*xi[0]*xi[1] + 12.0262794416288251144009549*xi[0]*xi[0]*xi[1] - 3.2224318643354569949832939*xi[0]*xi[1]*xi[1] + 1.53589838486224541294510732*xi[0]*xi[2] - 3.63397459621556135323627683*xi[0]*xi[0]*xi[2] + 13*xi[0]*xi[1]*xi[2] - 3.63397459621556135323627683*xi[0]*xi[2]*xi[2], + 2.66025403784438646763723171*xi[0]*xi[1] - 15.2487113059642821093842488*xi[0]*xi[1]*xi[1] + 4.60769515458673623883532195*xi[0]*xi[1]*xi[2] + }; + } + if (i == 20) { + return vec3{ + -4.19615242270663188058233902*xi[1] + 26.1506350946109661690930793*xi[0]*xi[1] - 12.0262794416288251144009549*xi[0]*xi[0]*xi[1] + 4.19615242270663188058233902*xi[1]*xi[1] - 24.0525588832576502288019098*xi[0]*xi[1]*xi[1] - 3.07179676972449082589021463*xi[1]*xi[2] - 20.4185842870420888755656329*xi[0]*xi[1]*xi[2] + 7.2679491924311227064725537*xi[1]*xi[1]*xi[2] + 7.2679491924311227064725537*xi[1]*xi[2]*xi[2], + 2.09807621135331594029116951*xi[0] - 14.1243556529821410546921244*xi[0]*xi[0] + 12.0262794416288251144009549*xi[0]*xi[0]*xi[0] - 4.19615242270663188058233902*xi[0]*xi[1] + 24.0525588832576502288019098*xi[0]*xi[0]*xi[1] + 1.53589838486224541294510732*xi[0]*xi[2] + 8.392304845413263761164678*xi[0]*xi[0]*xi[2] - 7.2679491924311227064725537*xi[0]*xi[1]*xi[2] - 3.63397459621556135323627683*xi[0]*xi[2]*xi[2], + -2.09807621135331594029116951*xi[0]*xi[1] + 12.0262794416288251144009549*xi[0]*xi[0]*xi[1] - 3.6339745962155613532362768*xi[0]*xi[1]*xi[2] + }; + } + if (i == 21) { + return vec3{ + 2.09807621135331594029116951*xi[1] - 11.4641016151377545870548927*xi[0]*xi[1] - 3.2224318643354569949832939*xi[0]*xi[0]*xi[1] - 2.09807621135331594029116951*xi[1]*xi[1] + 12.0262794416288251144009549*xi[0]*xi[1]*xi[1] + 1.53589838486224541294510732*xi[1]*xi[2] + 13*xi[0]*xi[1]*xi[2] - 3.63397459621556135323627683*xi[1]*xi[1]*xi[2] - 3.63397459621556135323627683*xi[1]*xi[2]*xi[2], + 0.5621778264910705273460622*xi[0] - 3.7846096908265275223293561*xi[0]*xi[0] + 3.2224318643354569949832939*xi[0]*xi[0]*xi[0] + 2.09807621135331594029116951*xi[0]*xi[1] - 12.0262794416288251144009549*xi[0]*xi[0]*xi[1] + 0.411542731880104358252982926*xi[0]*xi[2] + 2.24871130596428210938424878*xi[0]*xi[0]*xi[2] + 3.63397459621556135323627683*xi[0]*xi[1]*xi[2] - 0.97372055837117488559904512*xi[0]*xi[2]*xi[2], + 2.66025403784438646763723171*xi[0]*xi[1] - 15.2487113059642821093842488*xi[0]*xi[0]*xi[1] + 4.60769515458673623883532195*xi[0]*xi[1]*xi[2] + }; + } + if (i == 22) { + return vec3{ + 12.5884572681198956417470171*xi[1] - 17.9089653438086685770214805*xi[0]*xi[1] + 3.2224318643354569949832939*xi[0]*xi[0]*xi[1] - 27.8371685740841777511312659*xi[1]*xi[1] + 18.4711431702997391043675427*xi[0]*xi[1]*xi[1] + 15.2487113059642821093842488*xi[1]*xi[1]*xi[1] - 32.4448637286709139899665878*xi[1]*xi[2] + 19.4448637286709139899665878*xi[0]*xi[1]*xi[2] + 35.1051177665153004576038195*xi[1]*xi[1]*xi[2] + 19.8564064605510183482195707*xi[1]*xi[2]*xi[2], + -2.66025403784438646763723171*xi[0] + 5.8826859021798434626205256*xi[0]*xi[0] - 3.2224318643354569949832939*xi[0]*xi[0]*xi[0] + 15.810889132455352636730311*xi[0]*xi[1] - 18.4711431702997391043675427*xi[0]*xi[0]*xi[1] - 15.2487113059642821093842488*xi[0]*xi[1]*xi[1] + 6.8564064605510183482195707*xi[0]*xi[2] - 7.4185842870420888755656329*xi[0]*xi[0]*xi[2] - 23.0788383248864753432028646*xi[0]*xi[1]*xi[2] - 4.19615242270663188058233902*xi[0]*xi[2]*xi[2], + 9.9282032302755091741097854*xi[0]*xi[1] - 12.0262794416288251144009549*xi[0]*xi[0]*xi[1] - 12.026279441628825114400955*xi[0]*xi[1]*xi[1] - 15.6602540378443864676372317*xi[0]*xi[1]*xi[2] + }; + } + if (i == 23) { + return vec3{ + -9.9282032302755091741097854*xi[1] + 2.09807621135331594029116951*xi[0]*xi[1] + 12.0262794416288251144009549*xi[0]*xi[0]*xi[1] + 21.9544826719043342885107402*xi[1]*xi[1] - 12.0262794416288251144009549*xi[1]*xi[1]*xi[1] + 25.5884572681198956417470171*xi[1]*xi[2] + 3.63397459621556135323627683*xi[0]*xi[1]*xi[2] - 27.6865334794732115820381866*xi[1]*xi[1]*xi[2] - 15.6602540378443864676372317*xi[1]*xi[2]*xi[2], + -9.9282032302755091741097854*xi[0] + 21.9544826719043342885107402*xi[0]*xi[0] - 12.0262794416288251144009549*xi[0]*xi[0]*xi[0] + 2.09807621135331594029116951*xi[0]*xi[1] + 12.0262794416288251144009549*xi[0]*xi[1]*xi[1] + 25.5884572681198956417470171*xi[0]*xi[2] - 27.6865334794732115820381866*xi[0]*xi[0]*xi[2] + 3.63397459621556135323627683*xi[0]*xi[1]*xi[2] - 15.6602540378443864676372317*xi[0]*xi[2]*xi[2], + -19.8564064605510183482195707*xi[0]*xi[1] + 24.0525588832576502288019098*xi[0]*xi[0]*xi[1] + 24.0525588832576502288019098*xi[0]*xi[1]*xi[1] + 31.3205080756887729352744634*xi[0]*xi[1]*xi[2] + }; + } + if (i == 24) { + return vec3{ + 12.5884572681198956417470171*xi[2] - 17.9089653438086685770214805*xi[0]*xi[2] + 3.2224318643354569949832939*xi[0]*xi[0]*xi[2] - 32.4448637286709139899665878*xi[1]*xi[2] + 19.4448637286709139899665878*xi[0]*xi[1]*xi[2] + 19.8564064605510183482195707*xi[1]*xi[1]*xi[2] - 27.8371685740841777511312659*xi[2]*xi[2] + 18.4711431702997391043675427*xi[0]*xi[2]*xi[2] + 35.1051177665153004576038195*xi[1]*xi[2]*xi[2] + 15.2487113059642821093842488*xi[2]*xi[2]*xi[2], + 9.9282032302755091741097854*xi[0]*xi[2] - 12.0262794416288251144009549*xi[0]*xi[0]*xi[2] - 15.6602540378443864676372317*xi[0]*xi[1]*xi[2] - 12.0262794416288251144009549*xi[0]*xi[2]*xi[2], + -2.66025403784438646763723171*xi[0] + 5.8826859021798434626205256*xi[0]*xi[0] - 3.2224318643354569949832939*xi[0]*xi[0]*xi[0] + 6.8564064605510183482195707*xi[0]*xi[1] - 7.4185842870420888755656329*xi[0]*xi[0]*xi[1] - 4.196152422706631880582339*xi[0]*xi[1]*xi[1] + 15.810889132455352636730311*xi[0]*xi[2] - 18.4711431702997391043675427*xi[0]*xi[0]*xi[2] - 23.0788383248864753432028646*xi[0]*xi[1]*xi[2] - 15.2487113059642821093842488*xi[0]*xi[2]*xi[2] + }; + } + if (i == 25) { + return vec3{ + -2.66025403784438646763723171*xi[2] + 15.810889132455352636730311*xi[0]*xi[2] - 15.2487113059642821093842488*xi[0]*xi[0]*xi[2] + 6.8564064605510183482195707*xi[1]*xi[2] - 23.0788383248864753432028646*xi[0]*xi[1]*xi[2] - 4.19615242270663188058233902*xi[1]*xi[1]*xi[2] + 5.8826859021798434626205256*xi[2]*xi[2] - 18.4711431702997391043675427*xi[0]*xi[2]*xi[2] - 7.4185842870420888755656329*xi[1]*xi[2]*xi[2] - 3.2224318643354569949832939*xi[2]*xi[2]*xi[2], + 9.9282032302755091741097854*xi[0]*xi[2] - 12.0262794416288251144009549*xi[0]*xi[0]*xi[2] - 15.6602540378443864676372317*xi[0]*xi[1]*xi[2] - 12.0262794416288251144009549*xi[0]*xi[2]*xi[2], + 12.5884572681198956417470171*xi[0] - 27.8371685740841777511312659*xi[0]*xi[0] + 15.2487113059642821093842488*xi[0]*xi[0]*xi[0] - 32.4448637286709139899665878*xi[0]*xi[1] + 35.1051177665153004576038195*xi[0]*xi[0]*xi[1] + 19.8564064605510183482195707*xi[0]*xi[1]*xi[1] - 17.9089653438086685770214805*xi[0]*xi[2] + 18.4711431702997391043675427*xi[0]*xi[0]*xi[2] + 19.4448637286709139899665878*xi[0]*xi[1]*xi[2] + 3.2224318643354569949832939*xi[0]*xi[2]*xi[2] + }; + } + if (i == 26) { + return vec3{ + -4.19615242270663188058233902*xi[2] + 26.1506350946109661690930793*xi[0]*xi[2] - 12.0262794416288251144009549*xi[0]*xi[0]*xi[2] - 3.07179676972449082589021463*xi[1]*xi[2] - 20.4185842870420888755656329*xi[0]*xi[1]*xi[2] + 7.2679491924311227064725537*xi[1]*xi[1]*xi[2] + 4.19615242270663188058233902*xi[2]*xi[2] - 24.0525588832576502288019098*xi[0]*xi[2]*xi[2] + 7.2679491924311227064725537*xi[1]*xi[2]*xi[2], + -2.09807621135331594029116951*xi[0]*xi[2] + 12.0262794416288251144009549*xi[0]*xi[0]*xi[2] - 3.63397459621556135323627683*xi[0]*xi[1]*xi[2], + 2.09807621135331594029116951*xi[0] - 14.1243556529821410546921244*xi[0]*xi[0] + 12.0262794416288251144009549*xi[0]*xi[0]*xi[0] + 1.53589838486224541294510732*xi[0]*xi[1] + 8.392304845413263761164678*xi[0]*xi[0]*xi[1] - 3.6339745962155613532362768*xi[0]*xi[1]*xi[1] - 4.19615242270663188058233902*xi[0]*xi[2] + 24.0525588832576502288019098*xi[0]*xi[0]*xi[2] - 7.2679491924311227064725537*xi[0]*xi[1]*xi[2] + }; + } + if (i == 27) { + return vec3{ + 2.09807621135331594029116951*xi[2] - 14.6865334794732115820381866*xi[0]*xi[2] + 15.2487113059642821093842488*xi[0]*xi[0]*xi[2] + 1.53589838486224541294510732*xi[1]*xi[2] + 7.4185842870420888755656329*xi[0]*xi[1]*xi[2] - 3.63397459621556135323627683*xi[1]*xi[1]*xi[2] - 2.09807621135331594029116951*xi[2]*xi[2] + 12.0262794416288251144009549*xi[0]*xi[2]*xi[2] - 3.63397459621556135323627683*xi[1]*xi[2]*xi[2], + -0.5621778264910705273460622*xi[0]*xi[2] + 3.2224318643354569949832939*xi[0]*xi[0]*xi[2] - 0.97372055837117488559904512*xi[0]*xi[1]*xi[2], + -2.66025403784438646763723171*xi[0] + 17.9089653438086685770214805*xi[0]*xi[0] - 15.2487113059642821093842488*xi[0]*xi[0]*xi[0] - 1.94744111674234977119809024*xi[0]*xi[1] - 10.6410161513775458705489268*xi[0]*xi[0]*xi[1] + 4.60769515458673623883532195*xi[0]*xi[1]*xi[1] + 2.09807621135331594029116951*xi[0]*xi[2] - 12.0262794416288251144009549*xi[0]*xi[0]*xi[2] + 3.63397459621556135323627683*xi[0]*xi[1]*xi[2] + }; + } + if (i == 28) { + return vec3{ + -2.66025403784438646763723171*xi[2] + 2.09807621135331594029116951*xi[0]*xi[2] - 1.94744111674234977119809024*xi[1]*xi[2] + 3.63397459621556135323627683*xi[0]*xi[1]*xi[2] + 4.60769515458673623883532195*xi[1]*xi[1]*xi[2] + 17.9089653438086685770214805*xi[2]*xi[2] - 12.0262794416288251144009549*xi[0]*xi[2]*xi[2] - 10.6410161513775458705489268*xi[1]*xi[2]*xi[2] - 15.2487113059642821093842488*xi[2]*xi[2]*xi[2], + -0.5621778264910705273460622*xi[0]*xi[2] - 0.97372055837117488559904512*xi[0]*xi[1]*xi[2] + 3.2224318643354569949832939*xi[0]*xi[2]*xi[2], + 2.09807621135331594029116951*xi[0] - 2.09807621135331594029116951*xi[0]*xi[0] + 1.53589838486224541294510732*xi[0]*xi[1] - 3.63397459621556135323627683*xi[0]*xi[0]*xi[1] - 3.6339745962155613532362768*xi[0]*xi[1]*xi[1] - 14.6865334794732115820381866*xi[0]*xi[2] + 12.0262794416288251144009549*xi[0]*xi[0]*xi[2] + 7.4185842870420888755656329*xi[0]*xi[1]*xi[2] + 15.2487113059642821093842488*xi[0]*xi[2]*xi[2] + }; + } + if (i == 29) { + return vec3{ + 2.09807621135331594029116951*xi[2] - 4.19615242270663188058233902*xi[0]*xi[2] + 1.53589838486224541294510732*xi[1]*xi[2] - 7.2679491924311227064725537*xi[0]*xi[1]*xi[2] - 3.63397459621556135323627683*xi[1]*xi[1]*xi[2] - 14.1243556529821410546921244*xi[2]*xi[2] + 24.0525588832576502288019098*xi[0]*xi[2]*xi[2] + 8.392304845413263761164678*xi[1]*xi[2]*xi[2] + 12.0262794416288251144009549*xi[2]*xi[2]*xi[2], + -2.09807621135331594029116951*xi[0]*xi[2] - 3.63397459621556135323627683*xi[0]*xi[1]*xi[2] + 12.0262794416288251144009549*xi[0]*xi[2]*xi[2], + -4.19615242270663188058233902*xi[0] + 4.19615242270663188058233902*xi[0]*xi[0] - 3.07179676972449082589021463*xi[0]*xi[1] + 7.2679491924311227064725537*xi[0]*xi[0]*xi[1] + 7.2679491924311227064725537*xi[0]*xi[1]*xi[1] + 26.1506350946109661690930793*xi[0]*xi[2] - 24.0525588832576502288019098*xi[0]*xi[0]*xi[2] - 20.4185842870420888755656329*xi[0]*xi[1]*xi[2] - 12.0262794416288251144009549*xi[0]*xi[2]*xi[2] + }; + } + if (i == 30) { + return vec3{ + 5.7320508075688772935274463*xi[1]*xi[2] - 15.6602540378443864676372317*xi[0]*xi[1]*xi[2] - 3.63397459621556135323627683*xi[1]*xi[1]*xi[2] - 3.63397459621556135323627683*xi[1]*xi[2]*xi[2], + -7.2679491924311227064725537*xi[0]*xi[2] + 19.8564064605510183482195707*xi[0]*xi[0]*xi[2] + 4.60769515458673623883532195*xi[0]*xi[1]*xi[2] + 4.60769515458673623883532195*xi[0]*xi[2]*xi[2], + 1.53589838486224541294510732*xi[0]*xi[1] - 4.196152422706631880582339*xi[0]*xi[0]*xi[1] - 0.9737205583711748855990451*xi[0]*xi[1]*xi[1] - 0.9737205583711748855990451*xi[0]*xi[1]*xi[2] + }; + } + if (i == 31) { + return vec3{ + 5.7320508075688772935274463*xi[1]*xi[2] - 15.6602540378443864676372317*xi[0]*xi[1]*xi[2] - 3.63397459621556135323627683*xi[1]*xi[1]*xi[2] - 3.63397459621556135323627683*xi[1]*xi[2]*xi[2], + 1.53589838486224541294510732*xi[0]*xi[2] - 4.19615242270663188058233902*xi[0]*xi[0]*xi[2] - 0.97372055837117488559904512*xi[0]*xi[1]*xi[2] - 0.97372055837117488559904512*xi[0]*xi[2]*xi[2], + -7.2679491924311227064725537*xi[0]*xi[1] + 19.8564064605510183482195707*xi[0]*xi[0]*xi[1] + 4.60769515458673623883532195*xi[0]*xi[1]*xi[1] + 4.60769515458673623883532195*xi[0]*xi[1]*xi[2] + }; + } + if (i == 32) { + return vec3{ + 5.7320508075688772935274463*xi[1]*xi[2] - 3.63397459621556135323627683*xi[0]*xi[1]*xi[2] - 15.6602540378443864676372317*xi[1]*xi[1]*xi[2] - 3.63397459621556135323627683*xi[1]*xi[2]*xi[2], + -11.4641016151377545870548927*xi[0]*xi[2] + 7.2679491924311227064725537*xi[0]*xi[0]*xi[2] + 31.3205080756887729352744634*xi[0]*xi[1]*xi[2] + 7.2679491924311227064725537*xi[0]*xi[2]*xi[2], + 5.7320508075688772935274463*xi[0]*xi[1] - 3.6339745962155613532362768*xi[0]*xi[0]*xi[1] - 15.6602540378443864676372317*xi[0]*xi[1]*xi[1] - 3.6339745962155613532362768*xi[0]*xi[1]*xi[2] + }; + } + if (i == 33) { + return vec3{ + 1.53589838486224541294510732*xi[1]*xi[2] - 0.97372055837117488559904512*xi[0]*xi[1]*xi[2] - 4.19615242270663188058233902*xi[1]*xi[1]*xi[2] - 0.97372055837117488559904512*xi[1]*xi[2]*xi[2], + 5.7320508075688772935274463*xi[0]*xi[2] - 3.63397459621556135323627683*xi[0]*xi[0]*xi[2] - 15.6602540378443864676372317*xi[0]*xi[1]*xi[2] - 3.63397459621556135323627683*xi[0]*xi[2]*xi[2], + -7.2679491924311227064725537*xi[0]*xi[1] + 4.60769515458673623883532195*xi[0]*xi[0]*xi[1] + 19.8564064605510183482195707*xi[0]*xi[1]*xi[1] + 4.60769515458673623883532195*xi[0]*xi[1]*xi[2] + }; + } + if (i == 34) { + return vec3{ + 1.53589838486224541294510732*xi[1]*xi[2] - 0.97372055837117488559904512*xi[0]*xi[1]*xi[2] - 0.97372055837117488559904512*xi[1]*xi[1]*xi[2] - 4.19615242270663188058233902*xi[1]*xi[2]*xi[2], + -7.2679491924311227064725537*xi[0]*xi[2] + 4.60769515458673623883532195*xi[0]*xi[0]*xi[2] + 4.60769515458673623883532195*xi[0]*xi[1]*xi[2] + 19.8564064605510183482195707*xi[0]*xi[2]*xi[2], + 5.7320508075688772935274463*xi[0]*xi[1] - 3.6339745962155613532362768*xi[0]*xi[0]*xi[1] - 3.6339745962155613532362768*xi[0]*xi[1]*xi[1] - 15.6602540378443864676372317*xi[0]*xi[1]*xi[2] + }; + } + if (i == 35) { + return vec3{ + 5.7320508075688772935274463*xi[1]*xi[2] - 3.63397459621556135323627683*xi[0]*xi[1]*xi[2] - 3.63397459621556135323627683*xi[1]*xi[1]*xi[2] - 15.6602540378443864676372317*xi[1]*xi[2]*xi[2], + 5.7320508075688772935274463*xi[0]*xi[2] - 3.63397459621556135323627683*xi[0]*xi[0]*xi[2] - 3.63397459621556135323627683*xi[0]*xi[1]*xi[2] - 15.6602540378443864676372317*xi[0]*xi[2]*xi[2], + -11.4641016151377545870548927*xi[0]*xi[1] + 7.2679491924311227064725537*xi[0]*xi[0]*xi[1] + 7.2679491924311227064725537*xi[0]*xi[1]*xi[1] + 31.3205080756887729352744634*xi[0]*xi[1]*xi[2] + }; + } + if (i == 36) { + return vec3{ + 2.66025403784438646763723171*xi[1]*xi[2] + 4.60769515458673623883532195*xi[0]*xi[1]*xi[2] - 15.2487113059642821093842488*xi[1]*xi[1]*xi[2], + 2.09807621135331594029116951*xi[2] + 1.53589838486224541294510732*xi[0]*xi[2] - 3.63397459621556135323627683*xi[0]*xi[0]*xi[2] - 11.4641016151377545870548927*xi[1]*xi[2] + 13*xi[0]*xi[1]*xi[2] - 3.2224318643354569949832939*xi[1]*xi[1]*xi[2] - 2.09807621135331594029116951*xi[2]*xi[2] - 3.63397459621556135323627683*xi[0]*xi[2]*xi[2] + 12.0262794416288251144009549*xi[1]*xi[2]*xi[2], + 0.5621778264910705273460622*xi[1] + 0.411542731880104358252982926*xi[0]*xi[1] - 0.9737205583711748855990451*xi[0]*xi[0]*xi[1] - 3.7846096908265275223293561*xi[1]*xi[1] + 2.2487113059642821093842488*xi[0]*xi[1]*xi[1] + 3.2224318643354569949832939*xi[1]*xi[1]*xi[1] + 2.09807621135331594029116951*xi[1]*xi[2] + 3.63397459621556135323627683*xi[0]*xi[1]*xi[2] - 12.0262794416288251144009549*xi[1]*xi[1]*xi[2] + }; + } + if (i == 37) { + return vec3{ + -0.5621778264910705273460622*xi[1]*xi[2] - 0.97372055837117488559904512*xi[0]*xi[1]*xi[2] + 3.2224318643354569949832939*xi[1]*xi[1]*xi[2], + 2.09807621135331594029116951*xi[2] + 1.53589838486224541294510732*xi[0]*xi[2] - 3.63397459621556135323627683*xi[0]*xi[0]*xi[2] - 14.6865334794732115820381866*xi[1]*xi[2] + 7.4185842870420888755656329*xi[0]*xi[1]*xi[2] + 15.2487113059642821093842488*xi[1]*xi[1]*xi[2] - 2.09807621135331594029116951*xi[2]*xi[2] - 3.63397459621556135323627683*xi[0]*xi[2]*xi[2] + 12.0262794416288251144009549*xi[1]*xi[2]*xi[2], + -2.66025403784438646763723171*xi[1] - 1.94744111674234977119809024*xi[0]*xi[1] + 4.60769515458673623883532195*xi[0]*xi[0]*xi[1] + 17.9089653438086685770214805*xi[1]*xi[1] - 10.6410161513775458705489268*xi[0]*xi[1]*xi[1] - 15.2487113059642821093842488*xi[1]*xi[1]*xi[1] + 2.09807621135331594029116951*xi[1]*xi[2] + 3.63397459621556135323627683*xi[0]*xi[1]*xi[2] - 12.0262794416288251144009549*xi[1]*xi[1]*xi[2] + }; + } + if (i == 38) { + return vec3{ + -19.8564064605510183482195707*xi[1]*xi[2] + 31.3205080756887729352744634*xi[0]*xi[1]*xi[2] + 24.0525588832576502288019098*xi[1]*xi[1]*xi[2] + 24.0525588832576502288019098*xi[1]*xi[2]*xi[2], + -9.9282032302755091741097854*xi[2] + 25.5884572681198956417470171*xi[0]*xi[2] - 15.6602540378443864676372317*xi[0]*xi[0]*xi[2] + 2.09807621135331594029116951*xi[1]*xi[2] + 3.63397459621556135323627683*xi[0]*xi[1]*xi[2] + 12.0262794416288251144009549*xi[1]*xi[1]*xi[2] + 21.9544826719043342885107402*xi[2]*xi[2] - 27.6865334794732115820381866*xi[0]*xi[2]*xi[2] - 12.0262794416288251144009549*xi[2]*xi[2]*xi[2], + -9.9282032302755091741097854*xi[1] + 25.5884572681198956417470171*xi[0]*xi[1] - 15.6602540378443864676372317*xi[0]*xi[0]*xi[1] + 21.9544826719043342885107402*xi[1]*xi[1] - 27.6865334794732115820381866*xi[0]*xi[1]*xi[1] - 12.0262794416288251144009549*xi[1]*xi[1]*xi[1] + 2.09807621135331594029116951*xi[1]*xi[2] + 3.633974596215561353236277*xi[0]*xi[1]*xi[2] + 12.0262794416288251144009549*xi[1]*xi[2]*xi[2] + }; + } + if (i == 39) { + return vec3{ + 9.9282032302755091741097854*xi[1]*xi[2] - 15.6602540378443864676372317*xi[0]*xi[1]*xi[2] - 12.0262794416288251144009549*xi[1]*xi[1]*xi[2] - 12.0262794416288251144009549*xi[1]*xi[2]*xi[2], + -2.66025403784438646763723171*xi[2] + 6.8564064605510183482195707*xi[0]*xi[2] - 4.19615242270663188058233902*xi[0]*xi[0]*xi[2] + 15.810889132455352636730311*xi[1]*xi[2] - 23.0788383248864753432028646*xi[0]*xi[1]*xi[2] - 15.2487113059642821093842488*xi[1]*xi[1]*xi[2] + 5.8826859021798434626205256*xi[2]*xi[2] - 7.4185842870420888755656329*xi[0]*xi[2]*xi[2] - 18.4711431702997391043675427*xi[1]*xi[2]*xi[2] - 3.2224318643354569949832939*xi[2]*xi[2]*xi[2], + 12.5884572681198956417470171*xi[1] - 32.4448637286709139899665878*xi[0]*xi[1] + 19.8564064605510183482195707*xi[0]*xi[0]*xi[1] - 27.8371685740841777511312659*xi[1]*xi[1] + 35.1051177665153004576038195*xi[0]*xi[1]*xi[1] + 15.2487113059642821093842488*xi[1]*xi[1]*xi[1] - 17.9089653438086685770214805*xi[1]*xi[2] + 19.4448637286709139899665878*xi[0]*xi[1]*xi[2] + 18.4711431702997391043675427*xi[1]*xi[1]*xi[2] + 3.2224318643354569949832939*xi[1]*xi[2]*xi[2] + }; + } + if (i == 40) { + return vec3{ + 2.66025403784438646763723171*xi[1]*xi[2] + 4.60769515458673623883532195*xi[0]*xi[1]*xi[2] - 15.2487113059642821093842488*xi[1]*xi[2]*xi[2], + 0.5621778264910705273460622*xi[2] + 0.411542731880104358252982926*xi[0]*xi[2] - 0.97372055837117488559904512*xi[0]*xi[0]*xi[2] + 2.09807621135331594029116951*xi[1]*xi[2] + 3.63397459621556135323627683*xi[0]*xi[1]*xi[2] - 3.7846096908265275223293561*xi[2]*xi[2] + 2.24871130596428210938424878*xi[0]*xi[2]*xi[2] - 12.0262794416288251144009549*xi[1]*xi[2]*xi[2] + 3.2224318643354569949832939*xi[2]*xi[2]*xi[2], + 2.09807621135331594029116951*xi[1] + 1.53589838486224541294510732*xi[0]*xi[1] - 3.6339745962155613532362768*xi[0]*xi[0]*xi[1] - 2.09807621135331594029116951*xi[1]*xi[1] - 3.63397459621556135323627683*xi[0]*xi[1]*xi[1] - 11.4641016151377545870548927*xi[1]*xi[2] + 13*xi[0]*xi[1]*xi[2] + 12.0262794416288251144009549*xi[1]*xi[1]*xi[2] - 3.2224318643354569949832939*xi[1]*xi[2]*xi[2] + }; + } + if (i == 41) { + return vec3{ + -2.09807621135331594029116951*xi[1]*xi[2] - 3.63397459621556135323627683*xi[0]*xi[1]*xi[2] + 12.0262794416288251144009549*xi[1]*xi[2]*xi[2], + 2.09807621135331594029116951*xi[2] + 1.53589838486224541294510732*xi[0]*xi[2] - 3.63397459621556135323627683*xi[0]*xi[0]*xi[2] - 4.19615242270663188058233902*xi[1]*xi[2] - 7.2679491924311227064725537*xi[0]*xi[1]*xi[2] - 14.1243556529821410546921244*xi[2]*xi[2] + 8.392304845413263761164678*xi[0]*xi[2]*xi[2] + 24.0525588832576502288019098*xi[1]*xi[2]*xi[2] + 12.0262794416288251144009549*xi[2]*xi[2]*xi[2], + -4.19615242270663188058233902*xi[1] - 3.07179676972449082589021463*xi[0]*xi[1] + 7.2679491924311227064725537*xi[0]*xi[0]*xi[1] + 4.19615242270663188058233902*xi[1]*xi[1] + 7.2679491924311227064725537*xi[0]*xi[1]*xi[1] + 26.1506350946109661690930793*xi[1]*xi[2] - 20.4185842870420888755656329*xi[0]*xi[1]*xi[2] - 24.0525588832576502288019098*xi[1]*xi[1]*xi[2] - 12.0262794416288251144009549*xi[1]*xi[2]*xi[2] + }; + } + if (i == 42) { + return vec3{ + 48*xi[1]*xi[2] - 32*xi[0]*xi[1]*xi[2] - 48*xi[1]*xi[1]*xi[2] - 48*xi[1]*xi[2]*xi[2], + -16*xi[0]*xi[2] + 16*xi[0]*xi[0]*xi[2] + 32*xi[0]*xi[1]*xi[2] + 16*xi[0]*xi[2]*xi[2], + -16*xi[0]*xi[1] + 16*xi[0]*xi[0]*xi[1] + 16*xi[0]*xi[1]*xi[1] + 32*xi[0]*xi[1]*xi[2] + }; + } + if (i == 43) { + return vec3{ + -16*xi[1]*xi[2] + 32*xi[0]*xi[1]*xi[2] + 16*xi[1]*xi[1]*xi[2] + 16*xi[1]*xi[2]*xi[2], + 48*xi[0]*xi[2] - 48*xi[0]*xi[0]*xi[2] - 32*xi[0]*xi[1]*xi[2] - 48*xi[0]*xi[2]*xi[2], + -16*xi[0]*xi[1] + 16*xi[0]*xi[0]*xi[1] + 16*xi[0]*xi[1]*xi[1] + 32*xi[0]*xi[1]*xi[2] + }; + } + if (i == 44) { + return vec3{ + -16*xi[1]*xi[2] + 32*xi[0]*xi[1]*xi[2] + 16*xi[1]*xi[1]*xi[2] + 16*xi[1]*xi[2]*xi[2], + -16*xi[0]*xi[2] + 16*xi[0]*xi[0]*xi[2] + 32*xi[0]*xi[1]*xi[2] + 16*xi[0]*xi[2]*xi[2], + 48*xi[0]*xi[1] - 48*xi[0]*xi[0]*xi[1] - 48*xi[0]*xi[1]*xi[1] - 32*xi[0]*xi[1]*xi[2] + }; + } + } + + return {}; + } + + constexpr vec3 reoriented_shape_function(vec3 xi, uint32_t i, int8_t transformation) const { + switch (transformation) { + case -1: return -shape_function(xi, i); + case 0: return shape_function(xi, i); + default: + // the way this element numbers its local dofs + // the first dof in that pair is always even + uint32_t ix = (i & 0xFFFFFFFE) + 0; + uint32_t iy = (i & 0xFFFFFFFE) + 1; + vec2 weights = face_transformation(transformation)[i % 2]; + return shape_function(xi, ix) * weights[0] + shape_function(xi, iy) * weights[1]; + } + } + + constexpr vec3 shape_function_curl(vec3 xi, uint32_t i) const { + // expressions generated symbolically by mathematica + if (p == 1) { + if (i == 0) { return vec3{ 0, -2, 2 }; } + if (i == 1) { return vec3{ 0, 0, 2 }; } + if (i == 2) { return vec3{ -2, 0, 2 }; } + if (i == 3) { return vec3{ -2, 2, 0 }; } + if (i == 4) { return vec3{ 0, -2, 0 }; } + if (i == 5) { return vec3{ 2, 0, 0 }; } + } + + if (p == 2) { + if (i == 0) { + return vec3{ + 0, + -5.098076211353315940291169512 + 5.196152422706631880582339025*xi[0] + 7.098076211353315940291169512*xi[1] + 7.098076211353315940291169512*xi[2], + 5.098076211353315940291169512 - 5.196152422706631880582339025*xi[0] - 7.098076211353315940291169512*xi[1] - 7.098076211353315940291169512*xi[2] + }; + } + if (i == 1) { + return vec3{ + 0, + 0.0980762113533159402911695123 - 5.196152422706631880582339025*xi[0] + 1.901923788646684059708830488*xi[1] + 1.901923788646684059708830488*xi[2], + -0.0980762113533159402911695123 + 5.196152422706631880582339025*xi[0] - 1.901923788646684059708830488*xi[1] - 1.901923788646684059708830488*xi[2] + }; + } + if (i == 2) { + return vec3{ + 0, + 0, + -2 + 7.098076211353315940291169512*xi[0] + 1.901923788646684059708830488*xi[1] + }; + } + if (i == 3) { + return vec3{ + 0, + 0, + -2 + 1.901923788646684059708830488*xi[0] + 7.098076211353315940291169512*xi[1] + }; + } + if (i == 4) { + return vec3{ + 0.0980762113533159402911695123 + 1.901923788646684059708830488*xi[0] - 5.196152422706631880582339025*xi[1] + 1.901923788646684059708830488*xi[2], + 0, + -0.0980762113533159402911695123 - 1.901923788646684059708830488*xi[0] + 5.196152422706631880582339025*xi[1] - 1.901923788646684059708830488*xi[2] + }; + } + if (i == 5) { + return vec3{ + -5.098076211353315940291169512 + 7.098076211353315940291169512*xi[0] + 5.196152422706631880582339025*xi[1] + 7.098076211353315940291169512*xi[2], + 0, + 5.098076211353315940291169512 - 7.098076211353315940291169512*xi[0] - 5.196152422706631880582339025*xi[1] - 7.098076211353315940291169512*xi[2] + }; + } + if (i == 6) { + return vec3{ + -5.098076211353315940291169512 + 7.098076211353315940291169512*xi[0] + 7.098076211353315940291169512*xi[1] + 5.196152422706631880582339025*xi[2], + 5.098076211353315940291169512 - 7.098076211353315940291169512*xi[0] - 7.098076211353315940291169512*xi[1] - 5.196152422706631880582339025*xi[2], + 0 + }; + } + if (i == 7) { + return vec3{ + 0.0980762113533159402911695123 + 1.901923788646684059708830488*xi[0] + 1.901923788646684059708830488*xi[1] - 5.196152422706631880582339025*xi[2], + -0.0980762113533159402911695123 - 1.901923788646684059708830488*xi[0] - 1.901923788646684059708830488*xi[1] + 5.196152422706631880582339025*xi[2], + 0 + }; + } + if (i == 8) { + return vec3{ + 0, + 2 - 7.098076211353315940291169512*xi[0] - 1.901923788646684059708830488*xi[2], + 0 + }; + } + if (i == 9) { + return vec3{ + 0, + 2 - 1.901923788646684059708830488*xi[0] - 7.098076211353315940291169512*xi[2], + 0 + }; + } + if (i == 10) { + return vec3{ + -2 + 7.098076211353315940291169512*xi[1] + 1.901923788646684059708830488*xi[2], + 0, + 0 + }; + } + if (i == 11) { + return vec3{ + -2 + 1.901923788646684059708830488*xi[1] + 7.098076211353315940291169512*xi[2], + 0, + 0 + }; + } + if (i == 12) { + return vec3{ + 0, + -9*xi[1], + -9 + 9*xi[0] + 18*xi[1] + 9*xi[2] + }; + } + if (i == 13) { + return vec3{ + -9*xi[0], + 9*xi[1], + 9*xi[0] - 9*xi[1] + }; + } + if (i == 14) { + return vec3{ + 0, + 9 - 9*xi[0] - 9*xi[1] - 18*xi[2], + 9*xi[2] + }; + } + if (i == 15) { + return vec3{ + -9*xi[0], + -9 + 18*xi[0] + 9*xi[1] + 9*xi[2], + 0 + }; + } + if (i == 16) { + return vec3{ + -9*xi[0], + 0, + 9*xi[2] + }; + } + if (i == 17) { + return vec3{ + 9*xi[0], + -9*xi[1], + 0 + }; + } + if (i == 18) { + return vec3{ + 9*xi[1] - 9*xi[2], + -9*xi[1], + 9*xi[2] + }; + } + if (i == 19) { + return vec3{ + 9 - 9*xi[0] - 18*xi[1] - 9*xi[2], + 9*xi[1], + 0 + }; + } + } + + if (p == 3) { + if (i == 0) { + return vec3{ + -2.751807899376635203468576*xi[0]*xi[1] + 2.751807899376635203468576*xi[0]*xi[2], + -10.4521783832343261536504044 + 24.6063624519837624284941263*xi[0] - 40*xi[0]*xi[0]/3. + 38.8554901545966711451011287*xi[1] - 42.933516423105382173259443*xi[0]*xi[1] - 29.992068802825583935189786*xi[1]*xi[1] + 36.1036822552200359416325527*xi[2] - 42.9335164231053821732594435*xi[0]*xi[2] - 62.735945505027803073848147*xi[1]*xi[2] - 27.2402609034489487317212095*xi[2]*xi[2], + 10.4521783832343261536504044 - 24.6063624519837624284941263*xi[0] + 40*xi[0]*xi[0]/3. - 36.1036822552200359416325527*xi[1] + 42.9335164231053821732594435*xi[0]*xi[1] + 27.2402609034489487317212095*xi[1]*xi[1] - 38.8554901545966711451011287*xi[2] + 42.9335164231053821732594435*xi[0]*xi[2] + 62.735945505027803073848147*xi[1]*xi[2] + 29.9920688028255839351897855*xi[2]*xi[2] + }; + } + if (i == 1) { + return vec3{ + -1.4245874315222387671726334*xi[0]*xi[1] + 1.4245874315222387671726334*xi[0]*xi[2], + 0.36337845538710050566746229 - 80*xi[0]/3. + 80*xi[0]*xi[0]/3. + 9.501977861384749177247414*xi[1] + 80*xi[0]*xi[1]/3. - 11.7596390235698626213269684*xi[1]*xi[1] + 8.0773904298625104100747806*xi[2] + 80*xi[0]*xi[2]/3. - 24.9438654786619640098265701*xi[1]*xi[2] - 10.335051592047623854154335*xi[2]*xi[2], + -0.36337845538710050566746229 + 80*xi[0]/3. - 80*xi[0]*xi[0]/3. - 8.0773904298625104100747806*xi[1] - 80*xi[0]*xi[1]/3. + 10.335051592047623854154335*xi[1]*xi[1] - 9.501977861384749177247414*xi[2] - 80*xi[0]*xi[2]/3. + 24.9438654786619640098265701*xi[1]*xi[2] + 11.7596390235698626213269684*xi[2]*xi[2] + }; + } + if (i == 2) { + return vec3{ + -2.751807899376635203468576*xi[0]*xi[1] + 2.75180789937663520346857598*xi[0]*xi[2], + 0.82085073541610294151038849 + 2.0603042146829042381725404*xi[0] - 40*xi[0]*xi[0]/3. - 2.0177220538258067899857744*xi[1] + 16.2668497564387155065927768*xi[0]*xi[1] - 0.39188571305353509526367539*xi[1]*xi[1] - 4.76952995320244199345435038*xi[2] + 16.2668497564387155065927768*xi[0]*xi[2] - 3.53557932548370539399592676*xi[1]*xi[2] + 2.3599221863231001082049006*xi[2]*xi[2], + -0.82085073541610294151038849 - 2.0603042146829042381725404*xi[0] + 40*xi[0]*xi[0]/3. + 4.76952995320244199345435038*xi[1] - 16.2668497564387155065927768*xi[0]*xi[1] - 2.3599221863231001082049006*xi[1]*xi[1] + 2.0177220538258067899857744*xi[2] - 16.2668497564387155065927768*xi[0]*xi[2] + 3.53557932548370539399592676*xi[1]*xi[2] + 0.39188571305353509526367539*xi[2]*xi[2] + }; + } + if (i == 3) { + return vec3{ + -2.75180789937663520346857598*xi[0] + 2.75180789937663520346857598*xi[0]*xi[0] + 2.75180789937663520346857598*xi[0]*xi[1] + 5.503615798753270406937152*xi[0]*xi[2], + -2.75180789937663520346857598*xi[1] + 2.75180789937663520346857598*xi[0]*xi[1] + 2.75180789937663520346857598*xi[1]*xi[1] + 5.503615798753270406937152*xi[1]*xi[2], + 1.58875703146323894373906129 - 18.3768395516778615218098664*xi[0] + 27.2402609034489487317212095*xi[0]*xi[0] - 0.049685580556241777044549183*xi[1] + 11.5470053837925152901829756*xi[0]*xi[1] - 2.3599221863231001082049006*xi[1]*xi[1] + 5.503615798753270406937152*xi[2] - 8.255423698129905610405728*xi[0]*xi[2] - 8.255423698129905610405728*xi[1]*xi[2] - 5.503615798753270406937152*xi[2]*xi[2] + }; + } + if (i == 4) { + return vec3{ + -1.4245874315222387671726334*xi[0] + 1.4245874315222387671726334*xi[0]*xi[0] + 1.4245874315222387671726334*xi[0]*xi[1] + 2.84917486304447753434526679*xi[0]*xi[2], + -1.4245874315222387671726334*xi[1] + 1.4245874315222387671726334*xi[0]*xi[1] + 1.4245874315222387671726334*xi[1]*xi[1] + 2.84917486304447753434526679*xi[1]*xi[2], + 1.89428270679801293841209206 - 12.5927127542327372982338893*xi[0] + 10.335051592047623854154335*xi[0]*xi[0] - 12.5927127542327372982338893*xi[1] + 47.3367698507619143749753366*xi[0]*xi[1] + 10.335051592047623854154335*xi[1]*xi[1] + 2.84917486304447753434526679*xi[2] - 4.27376229456671630151790019*xi[0]*xi[2] - 4.27376229456671630151790019*xi[1]*xi[2] - 2.84917486304447753434526679*xi[2]*xi[2] + }; + } + if (i == 5) { + return vec3{ + -2.75180789937663520346857598*xi[0] + 2.75180789937663520346857598*xi[0]*xi[0] + 2.75180789937663520346857598*xi[0]*xi[1] + 5.503615798753270406937152*xi[0]*xi[2], + -2.75180789937663520346857598*xi[1] + 2.75180789937663520346857598*xi[0]*xi[1] + 2.75180789937663520346857598*xi[1]*xi[1] + 5.503615798753270406937152*xi[1]*xi[2], + 1.58875703146323894373906129 - 0.0496855805562417770445491834*xi[0] - 2.3599221863231001082049006*xi[0]*xi[0] - 18.3768395516778615218098664*xi[1] + 11.5470053837925152901829756*xi[0]*xi[1] + 27.2402609034489487317212095*xi[1]*xi[1] + 5.503615798753270406937152*xi[2] - 8.255423698129905610405728*xi[0]*xi[2] - 8.255423698129905610405728*xi[1]*xi[2] - 5.503615798753270406937152*xi[2]*xi[2] + }; + } + if (i == 6) { + return vec3{ + 0.82085073541610294151038849 - 2.0177220538258067899857744*xi[0] - 0.39188571305353509526367539*xi[0]*xi[0] + 2.0603042146829042381725404*xi[1] + 16.2668497564387155065927768*xi[0]*xi[1] - 40*xi[1]*xi[1]/3. - 4.76952995320244199345435038*xi[2] - 3.53557932548370539399592676*xi[0]*xi[2] + 16.2668497564387155065927768*xi[1]*xi[2] + 2.3599221863231001082049006*xi[2]*xi[2], + -2.751807899376635203468576*xi[0]*xi[1] + 2.75180789937663520346857598*xi[1]*xi[2], + -0.82085073541610294151038849 + 4.76952995320244199345435038*xi[0] - 2.3599221863231001082049006*xi[0]*xi[0] - 2.0603042146829042381725404*xi[1] - 16.2668497564387155065927768*xi[0]*xi[1] + 40*xi[1]*xi[1]/3. + 2.0177220538258067899857744*xi[2] + 3.53557932548370539399592676*xi[0]*xi[2] - 16.2668497564387155065927768*xi[1]*xi[2] + 0.39188571305353509526367539*xi[2]*xi[2] + }; + } + if (i == 7) { + return vec3{ + 0.36337845538710050566746229 + 9.501977861384749177247414*xi[0] - 11.7596390235698626213269684*xi[0]*xi[0] - 80*xi[1]/3. + 80*xi[0]*xi[1]/3. + 80*xi[1]*xi[1]/3. + 8.0773904298625104100747806*xi[2] - 24.9438654786619640098265701*xi[0]*xi[2] + 80*xi[1]*xi[2]/3. - 10.335051592047623854154335*xi[2]*xi[2], + -1.4245874315222387671726334*xi[0]*xi[1] + 1.4245874315222387671726334*xi[1]*xi[2], + -0.36337845538710050566746229 - 8.0773904298625104100747806*xi[0] + 10.335051592047623854154335*xi[0]*xi[0] + 80*xi[1]/3. - 80*xi[0]*xi[1]/3. - 80*xi[1]*xi[1]/3. - 9.501977861384749177247414*xi[2] + 24.9438654786619640098265701*xi[0]*xi[2] - 80*xi[1]*xi[2]/3. + 11.7596390235698626213269684*xi[2]*xi[2] + }; + } + if (i == 8) { + return vec3{ + -10.4521783832343261536504044 + 38.8554901545966711451011287*xi[0] - 29.992068802825583935189786*xi[0]*xi[0] + 24.6063624519837624284941263*xi[1] - 42.933516423105382173259443*xi[0]*xi[1] - 40*xi[1]*xi[1]/3. + 36.1036822552200359416325527*xi[2] - 62.735945505027803073848147*xi[0]*xi[2] - 42.9335164231053821732594435*xi[1]*xi[2] - 27.2402609034489487317212095*xi[2]*xi[2], + -2.751807899376635203468576*xi[0]*xi[1] + 2.751807899376635203468576*xi[1]*xi[2], + 10.4521783832343261536504044 - 36.1036822552200359416325527*xi[0] + 27.2402609034489487317212095*xi[0]*xi[0] - 24.6063624519837624284941263*xi[1] + 42.9335164231053821732594435*xi[0]*xi[1] + 40*xi[1]*xi[1]/3. - 38.8554901545966711451011287*xi[2] + 62.735945505027803073848147*xi[0]*xi[2] + 42.9335164231053821732594435*xi[1]*xi[2] + 29.9920688028255839351897855*xi[2]*xi[2] + }; + } + if (i == 9) { + return vec3{ + -10.4521783832343261536504044 + 38.8554901545966711451011287*xi[0] - 29.9920688028255839351897855*xi[0]*xi[0] + 36.1036822552200359416325527*xi[1] - 62.735945505027803073848147*xi[0]*xi[1] - 27.2402609034489487317212095*xi[1]*xi[1] + 24.6063624519837624284941263*xi[2] - 42.9335164231053821732594435*xi[0]*xi[2] - 42.9335164231053821732594435*xi[1]*xi[2] - 40*xi[2]*xi[2]/3., + 10.4521783832343261536504044 - 36.1036822552200359416325527*xi[0] + 27.2402609034489487317212095*xi[0]*xi[0] - 38.8554901545966711451011287*xi[1] + 62.735945505027803073848147*xi[0]*xi[1] + 29.9920688028255839351897855*xi[1]*xi[1] - 24.6063624519837624284941263*xi[2] + 42.9335164231053821732594435*xi[0]*xi[2] + 42.9335164231053821732594435*xi[1]*xi[2] + 40*xi[2]*xi[2]/3., + -2.751807899376635203468576*xi[0]*xi[2] + 2.751807899376635203468576*xi[1]*xi[2] + }; + } + if (i == 10) { + return vec3{ + 0.36337845538710050566746229 + 9.501977861384749177247414*xi[0] - 11.7596390235698626213269684*xi[0]*xi[0] + 8.0773904298625104100747806*xi[1] - 24.9438654786619640098265701*xi[0]*xi[1] - 10.335051592047623854154335*xi[1]*xi[1] - 80*xi[2]/3. + 80*xi[0]*xi[2]/3. + 80*xi[1]*xi[2]/3. + 80*xi[2]*xi[2]/3., + -0.36337845538710050566746229 - 8.0773904298625104100747806*xi[0] + 10.335051592047623854154335*xi[0]*xi[0] - 9.501977861384749177247414*xi[1] + 24.9438654786619640098265701*xi[0]*xi[1] + 11.7596390235698626213269684*xi[1]*xi[1] + 80*xi[2]/3. - 80*xi[0]*xi[2]/3. - 80*xi[1]*xi[2]/3. - 80*xi[2]*xi[2]/3., + -1.4245874315222387671726334*xi[0]*xi[2] + 1.4245874315222387671726334*xi[1]*xi[2] + }; + } + if (i == 11) { + return vec3{ + 0.82085073541610294151038849 - 2.0177220538258067899857744*xi[0] - 0.39188571305353509526367539*xi[0]*xi[0] - 4.76952995320244199345435038*xi[1] - 3.5355793254837053939959268*xi[0]*xi[1] + 2.3599221863231001082049006*xi[1]*xi[1] + 2.0603042146829042381725404*xi[2] + 16.2668497564387155065927768*xi[0]*xi[2] + 16.2668497564387155065927768*xi[1]*xi[2] - 40*xi[2]*xi[2]/3., + -0.82085073541610294151038849 + 4.76952995320244199345435038*xi[0] - 2.3599221863231001082049006*xi[0]*xi[0] + 2.0177220538258067899857744*xi[1] + 3.5355793254837053939959268*xi[0]*xi[1] + 0.39188571305353509526367539*xi[1]*xi[1] - 2.0603042146829042381725404*xi[2] - 16.2668497564387155065927768*xi[0]*xi[2] - 16.2668497564387155065927768*xi[1]*xi[2] + 40*xi[2]*xi[2]/3., + -2.75180789937663520346857598*xi[0]*xi[2] + 2.75180789937663520346857598*xi[1]*xi[2] + }; + } + if (i == 12) { + return vec3{ + 2.75180789937663520346857598*xi[0] - 2.75180789937663520346857598*xi[0]*xi[0] - 5.503615798753270406937152*xi[0]*xi[1] - 2.75180789937663520346857598*xi[0]*xi[2], + -1.58875703146323894373906129 + 18.3768395516778615218098664*xi[0] - 27.2402609034489487317212095*xi[0]*xi[0] - 5.503615798753270406937152*xi[1] + 8.255423698129905610405728*xi[0]*xi[1] + 5.503615798753270406937152*xi[1]*xi[1] + 0.049685580556241777044549183*xi[2] - 11.5470053837925152901829756*xi[0]*xi[2] + 8.255423698129905610405728*xi[1]*xi[2] + 2.3599221863231001082049006*xi[2]*xi[2], + 2.75180789937663520346857598*xi[2] - 2.75180789937663520346857598*xi[0]*xi[2] - 5.503615798753270406937152*xi[1]*xi[2] - 2.75180789937663520346857598*xi[2]*xi[2] + }; + } + if (i == 13) { + return vec3{ + 1.4245874315222387671726334*xi[0] - 1.4245874315222387671726334*xi[0]*xi[0] - 2.84917486304447753434526679*xi[0]*xi[1] - 1.4245874315222387671726334*xi[0]*xi[2], + -1.89428270679801293841209206 + 12.5927127542327372982338893*xi[0] - 10.335051592047623854154335*xi[0]*xi[0] - 2.84917486304447753434526679*xi[1] + 4.27376229456671630151790019*xi[0]*xi[1] + 2.84917486304447753434526679*xi[1]*xi[1] + 12.5927127542327372982338893*xi[2] - 47.3367698507619143749753366*xi[0]*xi[2] + 4.27376229456671630151790019*xi[1]*xi[2] - 10.335051592047623854154335*xi[2]*xi[2], + 1.4245874315222387671726334*xi[2] - 1.4245874315222387671726334*xi[0]*xi[2] - 2.84917486304447753434526679*xi[1]*xi[2] - 1.4245874315222387671726334*xi[2]*xi[2] + }; + } + if (i == 14) { + return vec3{ + 2.75180789937663520346857598*xi[0] - 2.75180789937663520346857598*xi[0]*xi[0] - 5.503615798753270406937152*xi[0]*xi[1] - 2.75180789937663520346857598*xi[0]*xi[2], + -1.58875703146323894373906129 + 0.0496855805562417770445491834*xi[0] + 2.3599221863231001082049006*xi[0]*xi[0] - 5.503615798753270406937152*xi[1] + 8.255423698129905610405728*xi[0]*xi[1] + 5.503615798753270406937152*xi[1]*xi[1] + 18.3768395516778615218098664*xi[2] - 11.5470053837925152901829756*xi[0]*xi[2] + 8.255423698129905610405728*xi[1]*xi[2] - 27.2402609034489487317212095*xi[2]*xi[2], + 2.75180789937663520346857598*xi[2] - 2.75180789937663520346857598*xi[0]*xi[2] - 5.503615798753270406937152*xi[1]*xi[2] - 2.75180789937663520346857598*xi[2]*xi[2] + }; + } + if (i == 15) { + return vec3{ + 1.58875703146323894373906129 + 5.503615798753270406937152*xi[0] - 5.503615798753270406937152*xi[0]*xi[0] - 18.3768395516778615218098664*xi[1] - 8.255423698129905610405728*xi[0]*xi[1] + 27.2402609034489487317212095*xi[1]*xi[1] - 0.049685580556241777044549183*xi[2] - 8.255423698129905610405728*xi[0]*xi[2] + 11.5470053837925152901829756*xi[1]*xi[2] - 2.3599221863231001082049006*xi[2]*xi[2], + -2.75180789937663520346857598*xi[1] + 5.503615798753270406937152*xi[0]*xi[1] + 2.75180789937663520346857598*xi[1]*xi[1] + 2.75180789937663520346857598*xi[1]*xi[2], + -2.75180789937663520346857598*xi[2] + 5.503615798753270406937152*xi[0]*xi[2] + 2.75180789937663520346857598*xi[1]*xi[2] + 2.75180789937663520346857598*xi[2]*xi[2] + }; + } + if (i == 16) { + return vec3{ + 1.89428270679801293841209206 + 2.84917486304447753434526679*xi[0] - 2.84917486304447753434526679*xi[0]*xi[0] - 12.5927127542327372982338893*xi[1] - 4.27376229456671630151790019*xi[0]*xi[1] + 10.335051592047623854154335*xi[1]*xi[1] - 12.5927127542327372982338893*xi[2] - 4.27376229456671630151790019*xi[0]*xi[2] + 47.3367698507619143749753366*xi[1]*xi[2] + 10.335051592047623854154335*xi[2]*xi[2], + -1.4245874315222387671726334*xi[1] + 2.84917486304447753434526679*xi[0]*xi[1] + 1.4245874315222387671726334*xi[1]*xi[1] + 1.4245874315222387671726334*xi[1]*xi[2], + -1.4245874315222387671726334*xi[2] + 2.84917486304447753434526679*xi[0]*xi[2] + 1.4245874315222387671726334*xi[1]*xi[2] + 1.4245874315222387671726334*xi[2]*xi[2] + }; + } + if (i == 17) { + return vec3{ + 1.58875703146323894373906129 + 5.503615798753270406937152*xi[0] - 5.503615798753270406937152*xi[0]*xi[0] - 0.0496855805562417770445491834*xi[1] - 8.255423698129905610405728*xi[0]*xi[1] - 2.3599221863231001082049006*xi[1]*xi[1] - 18.3768395516778615218098664*xi[2] - 8.255423698129905610405728*xi[0]*xi[2] + 11.5470053837925152901829756*xi[1]*xi[2] + 27.2402609034489487317212095*xi[2]*xi[2], + -2.75180789937663520346857598*xi[1] + 5.503615798753270406937152*xi[0]*xi[1] + 2.75180789937663520346857598*xi[1]*xi[1] + 2.75180789937663520346857598*xi[1]*xi[2], + -2.75180789937663520346857598*xi[2] + 5.503615798753270406937152*xi[0]*xi[2] + 2.75180789937663520346857598*xi[1]*xi[2] + 2.75180789937663520346857598*xi[2]*xi[2] + }; + } + if (i == 18) { + return vec3{ + -2.09807621135331594029116951*xi[0] + 3.63397459621556135323627683*xi[0]*xi[0] - 0.9737205583711748855990451*xi[0]*xi[1] + 6.2942286340599478208735085*xi[0]*xi[2], + -1.38526329025127924385202805*xi[1] + 3.63397459621556135323627683*xi[0]*xi[1] - 13.8634480157130028655322207*xi[1]*xi[1] + 10.189110867544647363269689*xi[1]*xi[2], + 4.75833024919770240792840122 - 6.2942286340599478208735085*xi[0] - 50.5044641670905487360811476*xi[1] + 48.1051177665153004576038195*xi[0]*xi[1] + 60.994845223857128437536995*xi[1]*xi[1] + 3.48333950160459518414319756*xi[2] - 10.9019237886466840597088305*xi[0]*xi[2] + 28.7006165897971806166634866*xi[1]*xi[2] - 8.2416697508022975920715988*xi[2]*xi[2] + }; + } + if (i == 19) { + return vec3{ + 1.12435565298214105469212439*xi[0] + 3.63397459621556135323627683*xi[0]*xi[0] - 43.4974226119285642187684976*xi[0]*xi[1] + 11.8756443470178589453078756*xi[0]*xi[2], + -2.24871130596428210938424878*xi[1] + 3.63397459621556135323627683*xi[0]*xi[1] + 17.4974226119285642187684976*xi[1]*xi[1] - 6.5551362713290860100334122*xi[1]*xi[2], + 1.53589838486224541294510732 - 6.2942286340599478208735085*xi[0] - 3.8948822334846995423961805*xi[1] + 48.1051177665153004576038195*xi[0]*xi[1] - 12.8897274573418279799331756*xi[1]*xi[1] + 1.12435565298214105469212439*xi[2] - 10.9019237886466840597088305*xi[0]*xi[2] + 8.5025773880714357812315024*xi[1]*xi[2] - 2.66025403784438646763723171*xi[2]*xi[2] + }; + } + if (i == 20) { + return vec3{ + -3.63397459621556135323627683*xi[0] + 3.6339745962155613532362768*xi[0]*xi[0] + 7.2679491924311227064725537*xi[0]*xi[1] + 3.6339745962155613532362768*xi[0]*xi[2], + -0.9737205583711748855990451*xi[1] - 44.471143170299739104367543*xi[0]*xi[1] + 7.2679491924311227064725537*xi[1]*xi[1] + 18.1698729810778067661813841*xi[1]*xi[2], + 6.2942286340599478208735085 - 54.399346400575248278477328*xi[0] + 48.1051177665153004576038195*xi[0]*xi[0] - 12.5884572681198956417470171*xi[1] + 96.210235533030600915207639*xi[0]*xi[1] + 4.60769515458673623883532195*xi[2] + 37.203193977868616397894989*xi[0]*xi[2] - 21.803847577293368119417661*xi[1]*xi[2] - 10.9019237886466840597088305*xi[2]*xi[2] + }; + } + if (i == 21) { + return vec3{ + 2.24871130596428210938424878*xi[0] - 17.4974226119285642187684976*xi[0]*xi[0] - 3.63397459621556135323627683*xi[0]*xi[1] + 6.5551362713290860100334122*xi[0]*xi[2], + -1.12435565298214105469212439*xi[1] + 43.4974226119285642187684976*xi[0]*xi[1] - 3.63397459621556135323627683*xi[1]*xi[1] - 11.8756443470178589453078756*xi[1]*xi[2], + -1.53589838486224541294510732 + 3.8948822334846995423961805*xi[0] + 12.8897274573418279799331756*xi[0]*xi[0] + 6.2942286340599478208735085*xi[1] - 48.1051177665153004576038195*xi[0]*xi[1] - 1.12435565298214105469212439*xi[2] - 8.5025773880714357812315024*xi[0]*xi[2] + 10.9019237886466840597088305*xi[1]*xi[2] + 2.66025403784438646763723171*xi[2]*xi[2] + }; + } + if (i == 22) { + return vec3{ + 3.0717967697244908258902146*xi[0] - 4.607695154586736238835322*xi[0]*xi[0] - 0.973720558371174885599045*xi[0]*xi[1] - 7.2679491924311227064725537*xi[0]*xi[2], + -42.3730669589464231640763732*xi[1] + 43.497422611928564218768498*xi[0]*xi[1] + 47.131397208144125572004774*xi[1]*xi[1] + 55.373066958946423164076373*xi[1]*xi[2], + -15.2487113059642821093842488 + 29.6743371481683555022625317*xi[0] - 12.8897274573418279799331756*xi[0]*xi[0] + 71.485226280623708138992843*xi[1] - 73.884572681198956417470171*xi[0]*xi[1] - 60.994845223857128437536995*xi[1]*xi[1] + 39.3012701892219323381861585*xi[2] - 34.2820323027550917410978537*xi[0]*xi[2] - 93.289073857917076258410504*xi[1]*xi[2] - 24.0525588832576502288019098*xi[2]*xi[2] + }; + } + if (i == 23) { + return vec3{ + -45.4448637286709139899665878*xi[0] + 51.739092362730861810840096*xi[0]*xi[0] + 44.471143170299739104367543*xi[0]*xi[1] + 62.641016151377545870548927*xi[0]*xi[2], + 45.4448637286709139899665878*xi[1] - 44.471143170299739104367543*xi[0]*xi[1] - 51.739092362730861810840096*xi[1]*xi[1] - 62.641016151377545870548927*xi[1]*xi[2], + 41.810889132455352636730311*xi[0] - 48.1051177665153004576038195*xi[0]*xi[0] - 41.810889132455352636730311*xi[1] + 48.1051177665153004576038195*xi[1]*xi[1] - 59.00704155516198451731265*xi[0]*xi[2] + 59.00704155516198451731265*xi[1]*xi[2] + }; + } + if (i == 24) { + return vec3{ + -3.0717967697244908258902146*xi[0] + 4.607695154586736238835322*xi[0]*xi[0] + 7.267949192431122706472554*xi[0]*xi[1] + 0.973720558371174885599045*xi[0]*xi[2], + 15.2487113059642821093842488 - 29.6743371481683555022625317*xi[0] + 12.8897274573418279799331756*xi[0]*xi[0] - 39.3012701892219323381861585*xi[1] + 34.282032302755091741097854*xi[0]*xi[1] + 24.05255888325765022880191*xi[1]*xi[1] - 71.485226280623708138992843*xi[2] + 73.884572681198956417470171*xi[0]*xi[2] + 93.289073857917076258410504*xi[1]*xi[2] + 60.994845223857128437536995*xi[2]*xi[2], + 42.3730669589464231640763732*xi[2] - 43.4974226119285642187684976*xi[0]*xi[2] - 55.373066958946423164076373*xi[1]*xi[2] - 47.1313972081441255720047744*xi[2]*xi[2] + }; + } + if (i == 25) { + return vec3{ + -42.3730669589464231640763732*xi[0] + 47.1313972081441255720047744*xi[0]*xi[0] + 55.373066958946423164076373*xi[0]*xi[1] + 43.4974226119285642187684976*xi[0]*xi[2], + -15.2487113059642821093842488 + 71.485226280623708138992843*xi[0] - 60.994845223857128437536995*xi[0]*xi[0] + 39.3012701892219323381861585*xi[1] - 93.289073857917076258410504*xi[0]*xi[1] - 24.0525588832576502288019098*xi[1]*xi[1] + 29.6743371481683555022625317*xi[2] - 73.884572681198956417470171*xi[0]*xi[2] - 34.2820323027550917410978537*xi[1]*xi[2] - 12.8897274573418279799331756*xi[2]*xi[2], + 3.0717967697244908258902146*xi[2] - 0.9737205583711748855990451*xi[0]*xi[2] - 7.2679491924311227064725537*xi[1]*xi[2] - 4.607695154586736238835322*xi[2]*xi[2] + }; + } + if (i == 26) { + return vec3{ + 3.63397459621556135323627683*xi[0] - 3.6339745962155613532362768*xi[0]*xi[0] - 3.6339745962155613532362768*xi[0]*xi[1] - 7.2679491924311227064725537*xi[0]*xi[2], + -6.2942286340599478208735085 + 54.399346400575248278477328*xi[0] - 48.1051177665153004576038195*xi[0]*xi[0] - 4.60769515458673623883532195*xi[1] - 37.203193977868616397894989*xi[0]*xi[1] + 10.9019237886466840597088305*xi[1]*xi[1] + 12.5884572681198956417470171*xi[2] - 96.210235533030600915207639*xi[0]*xi[2] + 21.803847577293368119417661*xi[1]*xi[2], + 0.9737205583711748855990451*xi[2] + 44.4711431702997391043675427*xi[0]*xi[2] - 18.1698729810778067661813841*xi[1]*xi[2] - 7.2679491924311227064725537*xi[2]*xi[2] + }; + } + if (i == 27) { + return vec3{ + -1.38526329025127924385202805*xi[0] - 13.8634480157130028655322207*xi[0]*xi[0] + 10.189110867544647363269689*xi[0]*xi[1] + 3.63397459621556135323627683*xi[0]*xi[2], + 4.75833024919770240792840122 - 50.5044641670905487360811476*xi[0] + 60.994845223857128437536995*xi[0]*xi[0] + 3.48333950160459518414319756*xi[1] + 28.7006165897971806166634866*xi[0]*xi[1] - 8.2416697508022975920715988*xi[1]*xi[1] - 6.2942286340599478208735085*xi[2] + 48.1051177665153004576038195*xi[0]*xi[2] - 10.9019237886466840597088305*xi[1]*xi[2], + -2.09807621135331594029116951*xi[2] - 0.9737205583711748855990451*xi[0]*xi[2] + 6.2942286340599478208735085*xi[1]*xi[2] + 3.63397459621556135323627683*xi[2]*xi[2] + }; + } + if (i == 28) { + return vec3{ + 2.09807621135331594029116951*xi[0] - 3.63397459621556135323627683*xi[0]*xi[0] - 6.2942286340599478208735085*xi[0]*xi[1] + 0.9737205583711748855990451*xi[0]*xi[2], + -4.75833024919770240792840122 + 6.2942286340599478208735085*xi[0] - 3.48333950160459518414319756*xi[1] + 10.9019237886466840597088305*xi[0]*xi[1] + 8.2416697508022975920715988*xi[1]*xi[1] + 50.5044641670905487360811476*xi[2] - 48.1051177665153004576038195*xi[0]*xi[2] - 28.7006165897971806166634866*xi[1]*xi[2] - 60.994845223857128437536995*xi[2]*xi[2], + 1.38526329025127924385202805*xi[2] - 3.63397459621556135323627683*xi[0]*xi[2] - 10.189110867544647363269689*xi[1]*xi[2] + 13.8634480157130028655322207*xi[2]*xi[2] + }; + } + if (i == 29) { + return vec3{ + -0.9737205583711748855990451*xi[0] + 7.2679491924311227064725537*xi[0]*xi[0] + 18.1698729810778067661813841*xi[0]*xi[1] - 44.4711431702997391043675427*xi[0]*xi[2], + 6.2942286340599478208735085 - 12.5884572681198956417470171*xi[0] + 4.60769515458673623883532195*xi[1] - 21.803847577293368119417661*xi[0]*xi[1] - 10.9019237886466840597088305*xi[1]*xi[1] - 54.399346400575248278477328*xi[2] + 96.210235533030600915207639*xi[0]*xi[2] + 37.203193977868616397894989*xi[1]*xi[2] + 48.1051177665153004576038195*xi[2]*xi[2], + -3.63397459621556135323627683*xi[2] + 7.2679491924311227064725537*xi[0]*xi[2] + 3.6339745962155613532362768*xi[1]*xi[2] + 3.6339745962155613532362768*xi[2]*xi[2] + }; + } + if (i == 30) { + return vec3{ + 8.803847577293368119417661*xi[0] - 24.05255888325765022880191*xi[0]*xi[0] - 6.5551362713290860100334122*xi[0]*xi[1] - 10.189110867544647363269689*xi[0]*xi[2], + 4.196152422706631880582339*xi[1] - 7.267949192431122706472554*xi[0]*xi[1] - 2.6602540378443864676372317*xi[1]*xi[1] - 6.2942286340599478208735085*xi[1]*xi[2], + -13*xi[2] + 55.373066958946423164076373*xi[0]*xi[2] + 11.8756443470178589453078756*xi[1]*xi[2] + 8.2416697508022975920715988*xi[2]*xi[2] + }; + } + if (i == 31) { + return vec3{ + -8.803847577293368119417661*xi[0] + 24.0525588832576502288019098*xi[0]*xi[0] + 10.189110867544647363269689*xi[0]*xi[1] + 6.5551362713290860100334122*xi[0]*xi[2], + 13*xi[1] - 55.373066958946423164076373*xi[0]*xi[1] - 8.2416697508022975920715988*xi[1]*xi[1] - 11.8756443470178589453078756*xi[1]*xi[2], + -4.196152422706631880582339*xi[2] + 7.2679491924311227064725537*xi[0]*xi[2] + 6.2942286340599478208735085*xi[1]*xi[2] + 2.66025403784438646763723171*xi[2]*xi[2] + }; + } + if (i == 32) { + return vec3{ + 17.196152422706631880582339*xi[0] - 10.9019237886466840597088305*xi[0]*xi[0] - 62.641016151377545870548927*xi[0]*xi[1] - 18.1698729810778067661813841*xi[0]*xi[2], + 3.6339745962155613532362768*xi[0]*xi[1] - 3.6339745962155613532362768*xi[1]*xi[2], + -17.196152422706631880582339*xi[2] + 18.1698729810778067661813841*xi[0]*xi[2] + 62.641016151377545870548927*xi[1]*xi[2] + 10.9019237886466840597088305*xi[2]*xi[2] + }; + } + if (i == 33) { + return vec3{ + -13*xi[0] + 8.2416697508022975920715988*xi[0]*xi[0] + 55.373066958946423164076373*xi[0]*xi[1] + 11.8756443470178589453078756*xi[0]*xi[2], + 8.803847577293368119417661*xi[1] - 10.189110867544647363269689*xi[0]*xi[1] - 24.0525588832576502288019098*xi[1]*xi[1] - 6.5551362713290860100334122*xi[1]*xi[2], + 4.196152422706631880582339*xi[2] - 6.2942286340599478208735085*xi[0]*xi[2] - 7.2679491924311227064725537*xi[1]*xi[2] - 2.66025403784438646763723171*xi[2]*xi[2] + }; + } + if (i == 34) { + return vec3{ + 13*xi[0] - 8.2416697508022975920715988*xi[0]*xi[0] - 11.8756443470178589453078756*xi[0]*xi[1] - 55.373066958946423164076373*xi[0]*xi[2], + -4.196152422706631880582339*xi[1] + 6.2942286340599478208735085*xi[0]*xi[1] + 2.6602540378443864676372317*xi[1]*xi[1] + 7.2679491924311227064725537*xi[1]*xi[2], + -8.803847577293368119417661*xi[2] + 10.189110867544647363269689*xi[0]*xi[2] + 6.5551362713290860100334122*xi[1]*xi[2] + 24.0525588832576502288019098*xi[2]*xi[2] + }; + } + if (i == 35) { + return vec3{ + -17.196152422706631880582339*xi[0] + 10.9019237886466840597088305*xi[0]*xi[0] + 18.1698729810778067661813841*xi[0]*xi[1] + 62.641016151377545870548927*xi[0]*xi[2], + 17.196152422706631880582339*xi[1] - 18.1698729810778067661813841*xi[0]*xi[1] - 10.9019237886466840597088305*xi[1]*xi[1] - 62.641016151377545870548927*xi[1]*xi[2], + -3.6339745962155613532362768*xi[0]*xi[2] + 3.6339745962155613532362768*xi[1]*xi[2] + }; + } + if (i == 36) { + return vec3{ + -1.53589838486224541294510732 - 1.12435565298214105469212439*xi[0] + 2.6602540378443864676372317*xi[0]*xi[0] + 3.8948822334846995423961805*xi[1] - 8.502577388071435781231502*xi[0]*xi[1] + 12.8897274573418279799331756*xi[1]*xi[1] + 6.2942286340599478208735085*xi[2] + 10.9019237886466840597088305*xi[0]*xi[2] - 48.1051177665153004576038195*xi[1]*xi[2], + 2.24871130596428210938424878*xi[1] + 6.5551362713290860100334122*xi[0]*xi[1] - 17.4974226119285642187684976*xi[1]*xi[1] - 3.63397459621556135323627683*xi[1]*xi[2], + -1.12435565298214105469212439*xi[2] - 11.8756443470178589453078756*xi[0]*xi[2] + 43.4974226119285642187684976*xi[1]*xi[2] - 3.63397459621556135323627683*xi[2]*xi[2] + }; + } + if (i == 37) { + return vec3{ + -4.75833024919770240792840122 - 3.48333950160459518414319756*xi[0] + 8.2416697508022975920715988*xi[0]*xi[0] + 50.5044641670905487360811476*xi[1] - 28.7006165897971806166634866*xi[0]*xi[1] - 60.994845223857128437536995*xi[1]*xi[1] + 6.2942286340599478208735085*xi[2] + 10.9019237886466840597088305*xi[0]*xi[2] - 48.1051177665153004576038195*xi[1]*xi[2], + 1.38526329025127924385202805*xi[1] - 10.189110867544647363269689*xi[0]*xi[1] + 13.8634480157130028655322207*xi[1]*xi[1] - 3.63397459621556135323627683*xi[1]*xi[2], + 2.09807621135331594029116951*xi[2] - 6.2942286340599478208735085*xi[0]*xi[2] + 0.9737205583711748855990451*xi[1]*xi[2] - 3.63397459621556135323627683*xi[2]*xi[2] + }; + } + if (i == 38) { + return vec3{ + 41.810889132455352636730311*xi[1] - 59.00704155516198451731265*xi[0]*xi[1] - 48.1051177665153004576038195*xi[1]*xi[1] - 41.810889132455352636730311*xi[2] + 59.00704155516198451731265*xi[0]*xi[2] + 48.1051177665153004576038195*xi[2]*xi[2], + -45.4448637286709139899665878*xi[1] + 62.641016151377545870548927*xi[0]*xi[1] + 51.739092362730861810840096*xi[1]*xi[1] + 44.471143170299739104367543*xi[1]*xi[2], + 45.4448637286709139899665878*xi[2] - 62.641016151377545870548927*xi[0]*xi[2] - 44.471143170299739104367543*xi[1]*xi[2] - 51.739092362730861810840096*xi[2]*xi[2] + }; + } + if (i == 39) { + return vec3{ + 15.2487113059642821093842488 - 39.3012701892219323381861585*xi[0] + 24.0525588832576502288019098*xi[0]*xi[0] - 71.485226280623708138992843*xi[1] + 93.289073857917076258410504*xi[0]*xi[1] + 60.994845223857128437536995*xi[1]*xi[1] - 29.6743371481683555022625317*xi[2] + 34.2820323027550917410978537*xi[0]*xi[2] + 73.884572681198956417470171*xi[1]*xi[2] + 12.8897274573418279799331756*xi[2]*xi[2], + 42.3730669589464231640763732*xi[1] - 55.373066958946423164076373*xi[0]*xi[1] - 47.1313972081441255720047744*xi[1]*xi[1] - 43.4974226119285642187684976*xi[1]*xi[2], + -3.0717967697244908258902146*xi[2] + 7.2679491924311227064725537*xi[0]*xi[2] + 0.9737205583711748855990451*xi[1]*xi[2] + 4.607695154586736238835322*xi[2]*xi[2] + }; + } + if (i == 40) { + return vec3{ + 1.53589838486224541294510732 + 1.12435565298214105469212439*xi[0] - 2.6602540378443864676372317*xi[0]*xi[0] - 6.2942286340599478208735085*xi[1] - 10.9019237886466840597088305*xi[0]*xi[1] - 3.8948822334846995423961805*xi[2] + 8.5025773880714357812315024*xi[0]*xi[2] + 48.1051177665153004576038195*xi[1]*xi[2] - 12.8897274573418279799331756*xi[2]*xi[2], + 1.12435565298214105469212439*xi[1] + 11.8756443470178589453078756*xi[0]*xi[1] + 3.63397459621556135323627683*xi[1]*xi[1] - 43.4974226119285642187684976*xi[1]*xi[2], + -2.24871130596428210938424878*xi[2] - 6.5551362713290860100334122*xi[0]*xi[2] + 3.63397459621556135323627683*xi[1]*xi[2] + 17.4974226119285642187684976*xi[2]*xi[2] + }; + } + if (i == 41) { + return vec3{ + -6.2942286340599478208735085 - 4.60769515458673623883532195*xi[0] + 10.9019237886466840597088305*xi[0]*xi[0] + 12.5884572681198956417470171*xi[1] + 21.803847577293368119417661*xi[0]*xi[1] + 54.399346400575248278477328*xi[2] - 37.203193977868616397894989*xi[0]*xi[2] - 96.210235533030600915207639*xi[1]*xi[2] - 48.1051177665153004576038195*xi[2]*xi[2], + 0.9737205583711748855990451*xi[1] - 18.1698729810778067661813841*xi[0]*xi[1] - 7.2679491924311227064725537*xi[1]*xi[1] + 44.4711431702997391043675427*xi[1]*xi[2], + 3.63397459621556135323627683*xi[2] - 3.6339745962155613532362768*xi[0]*xi[2] - 7.2679491924311227064725537*xi[1]*xi[2] - 3.6339745962155613532362768*xi[2]*xi[2] + }; + } + if (i == 42) { + return vec3{ + 0, + 64*xi[1] - 64*xi[0]*xi[1] - 64*xi[1]*xi[1] - 128*xi[1]*xi[2], + -64*xi[2] + 64*xi[0]*xi[2] + 128*xi[1]*xi[2] + 64*xi[2]*xi[2] + }; + } + if (i == 43) { + return vec3{ + -64*xi[0] + 64*xi[0]*xi[0] + 64*xi[0]*xi[1] + 128*xi[0]*xi[2], + 0, + 64*xi[2] - 128*xi[0]*xi[2] - 64*xi[1]*xi[2] - 64*xi[2]*xi[2] + }; + } + if (i == 44) { + return vec3{ + 64*xi[0] - 64*xi[0]*xi[0] - 128*xi[0]*xi[1] - 64*xi[0]*xi[2], + -64*xi[1] + 128*xi[0]*xi[1] + 64*xi[1]*xi[1] + 64*xi[1]*xi[2], + 0 + }; + } + } // if (p == 3) + + return {}; + } + + constexpr vec3 reoriented_shape_function_curl(vec3 xi, uint32_t i, int8_t transformation) const { + switch (transformation) { + case -1: return -shape_function_curl(xi, i); + case 0: return shape_function_curl(xi, i); + default: + // the way this element numbers its local dofs + // the first dof in that pair is always even + uint32_t ix = (i & 0xFFFFFFFE) + 0; + uint32_t iy = (i & 0xFFFFFFFE) + 1; + vec2 weights = face_transformation(transformation)[i % 2]; + return shape_function_curl(xi, ix) * weights[0] + shape_function_curl(xi, iy) * weights[1]; + } + } + + constexpr vec3 shape_function_derivative(vec3 xi, uint32_t i) const { + return shape_function_curl(xi, i); + } + + double shape_function_div(vec3 xi, uint32_t i) const { + // expressions generated symbolically by mathematica + if (p == 1) { + return 0.0; + } + if (p == 2) { + if (i == 0) { return -1.732050807568877293527446342 - 4.732050807568877293527446342*xi[0] + 1.732050807568877293527446342*xi[1] + 1.732050807568877293527446342*xi[2]; } + if (i == 1) { return 1.732050807568877293527446342 - 1.2679491924311227064725536585*xi[0] - 1.732050807568877293527446342*xi[1] - 1.732050807568877293527446342*xi[2]; } + if (i == 2) { return 0.6339745962155613532362768292*xi[0] - 2.366025403784438646763723171*xi[1]; } + if (i == 3) { return 2.366025403784438646763723171*xi[0] - 0.6339745962155613532362768292*xi[1]; } + if (i == 4) { return -1.732050807568877293527446342 + 1.732050807568877293527446342*xi[0] + 1.2679491924311227064725536585*xi[1] + 1.732050807568877293527446342*xi[2]; } + if (i == 5) { return 1.732050807568877293527446342 - 1.732050807568877293527446342*xi[0] + 4.732050807568877293527446342*xi[1] - 1.732050807568877293527446342*xi[2]; } + if (i == 6) { return -1.732050807568877293527446342 + 1.732050807568877293527446342*xi[0] + 1.732050807568877293527446342*xi[1] - 4.732050807568877293527446342*xi[2]; } + if (i == 7) { return 1.732050807568877293527446342 - 1.732050807568877293527446342*xi[0] - 1.732050807568877293527446342*xi[1] - 1.2679491924311227064725536585*xi[2]; } + if (i == 8) { return 0.6339745962155613532362768292*xi[0] - 2.366025403784438646763723171*xi[2]; } + if (i == 9) { return 2.366025403784438646763723171*xi[0] - 0.6339745962155613532362768292*xi[2]; } + if (i == 10) { return 0.6339745962155613532362768292*xi[1] - 2.366025403784438646763723171*xi[2]; } + if (i == 11) { return 2.366025403784438646763723171*xi[1] - 0.6339745962155613532362768292*xi[2]; } + if (i == 12) { return 6*xi[0] - 3*xi[1]; } + if (i == 13) { return -3*xi[0] - 3*xi[1]; } + if (i == 14) { return 6*xi[0] - 3*xi[2]; } + if (i == 15) { return -3*xi[0] + 6*xi[2]; } + if (i == 16) { return 0; } + if (i == 17) { return 0; } + if (i == 18) { return -3*xi[1] - 3*xi[2]; } + if (i == 19) { return -3*xi[1] + 6*xi[2]; } + } // if (p == 2) + if (p == 3) { + if (i == 0) { return -4.6243277820691389617264218 - 8.3223678689970410505146319*xi[0] + 21.4667582115526910866297217*xi[0]*xi[0] + 15.3577068878454845050412827*xi[1] + 23.3254021361589172685231189*xi[0]*xi[1] - 10.7333791057763455433148609*xi[1]*xi[1] + 15.3577068878454845050412827*xi[2] + 23.3254021361589172685231189*xi[0]*xi[2] - 21.4667582115526910866297217*xi[1]*xi[2] - 10.7333791057763455433148609*xi[2]*xi[2]; } + if (i == 1) { return 6.666666666666667 - 15.2732430892257989886650754*xi[0] - 40*xi[0]*xi[0]/3. - 40*xi[1]/3. + 25.0929723569031959546603017*xi[0]*xi[1] + 20*xi[1]*xi[1]/3. - 40*xi[2]/3. + 25.0929723569031959546603017*xi[0]*xi[2] + 40*xi[1]*xi[2]/3. + 20*xi[2]*xi[2]/3.; } + if (i == 2) { return -2.04233888459752770494024487 + 9.0597125733605946262346001*xi[0] - 8.1334248782193577532963884*xi[0]*xi[0] - 2.02437355451215117170794933*xi[1] - 6.2747809536131315714029913*xi[0]*xi[1] + 4.0667124391096788766481942*xi[1]*xi[1] - 2.02437355451215117170794933*xi[2] - 6.2747809536131315714029913*xi[0]*xi[2] + 8.1334248782193577532963884*xi[1]*xi[2] + 4.0667124391096788766481942*xi[2]*xi[2]; } + if (i == 3) { return -0.0165618601854139256815163943*xi[0] + 2.8867513459481288225457439*xi[0]*xi[0] + 6.1256131838926205072699555*xi[1] - 14.8000915448860244199630551*xi[0]*xi[1] - 2.8867513459481288225457439*xi[1]*xi[1] - 2.75180789937663520346857598*xi[0]*xi[2] + 2.75180789937663520346857598*xi[1]*xi[2]; } + if (i == 4) { return -4.19757091807757909941129644*xi[0] + 11.8341924626904785937438341*xi[0]*xi[0] + 4.19757091807757909941129644*xi[1] - 11.8341924626904785937438341*xi[1]*xi[1] - 1.4245874315222387671726334*xi[0]*xi[2] + 1.4245874315222387671726334*xi[1]*xi[2]; } + if (i == 5) { return -6.1256131838926205072699555*xi[0] + 2.8867513459481288225457439*xi[0]*xi[0] + 0.0165618601854139256815163945*xi[1] + 14.8000915448860244199630551*xi[0]*xi[1] - 2.8867513459481288225457439*xi[1]*xi[1] - 2.75180789937663520346857598*xi[0]*xi[2] + 2.75180789937663520346857598*xi[1]*xi[2]; } + if (i == 6) { return 2.04233888459752770494024487 + 2.02437355451215117170794934*xi[0] - 4.0667124391096788766481942*xi[0]*xi[0] - 9.0597125733605946262346001*xi[1] + 6.2747809536131315714029913*xi[0]*xi[1] + 8.1334248782193577532963884*xi[1]*xi[1] + 2.02437355451215117170794934*xi[2] - 8.1334248782193577532963884*xi[0]*xi[2] + 6.2747809536131315714029913*xi[1]*xi[2] - 4.0667124391096788766481942*xi[2]*xi[2]; } + if (i == 7) { return -6.666666666666667 + 40*xi[0]/3. - 20*xi[0]*xi[0]/3. + 15.2732430892257989886650754*xi[1] - 25.0929723569031959546603017*xi[0]*xi[1] + 40*xi[1]*xi[1]/3. + 40*xi[2]/3. - 40*xi[0]*xi[2]/3. - 25.0929723569031959546603017*xi[1]*xi[2] - 20*xi[2]*xi[2]/3.; } + if (i == 8) { return 4.6243277820691389617264218 - 15.3577068878454845050412827*xi[0] + 10.7333791057763455433148609*xi[0]*xi[0] + 8.3223678689970410505146319*xi[1] - 23.3254021361589172685231189*xi[0]*xi[1] - 21.4667582115526910866297217*xi[1]*xi[1] - 15.3577068878454845050412827*xi[2] + 21.4667582115526910866297217*xi[0]*xi[2] - 23.3254021361589172685231189*xi[1]*xi[2] + 10.7333791057763455433148609*xi[2]*xi[2]; } + if (i == 9) { return -4.6243277820691389617264218 + 15.3577068878454845050412827*xi[0] - 10.7333791057763455433148609*xi[0]*xi[0] + 15.3577068878454845050412827*xi[1] - 21.4667582115526910866297217*xi[0]*xi[1] - 10.7333791057763455433148609*xi[1]*xi[1] - 8.3223678689970410505146319*xi[2] + 23.3254021361589172685231189*xi[0]*xi[2] + 23.3254021361589172685231189*xi[1]*xi[2] + 21.4667582115526910866297217*xi[2]*xi[2]; } + if (i == 10) { return 6.666666666666667 - 40*xi[0]/3. + 20*xi[0]*xi[0]/3. - 40*xi[1]/3. + 40*xi[0]*xi[1]/3. + 20*xi[1]*xi[1]/3. - 15.2732430892257989886650754*xi[2] + 25.0929723569031959546603017*xi[0]*xi[2] + 25.0929723569031959546603017*xi[1]*xi[2] - 40*xi[2]*xi[2]/3.; } + if (i == 11) { return -2.04233888459752770494024487 - 2.02437355451215117170794933*xi[0] + 4.0667124391096788766481942*xi[0]*xi[0] - 2.02437355451215117170794933*xi[1] + 8.1334248782193577532963884*xi[0]*xi[1] + 4.0667124391096788766481942*xi[1]*xi[1] + 9.0597125733605946262346001*xi[2] - 6.2747809536131315714029913*xi[0]*xi[2] - 6.2747809536131315714029913*xi[1]*xi[2] - 8.1334248782193577532963884*xi[2]*xi[2]; } + if (i == 12) { return -0.0165618601854139256815163943*xi[0] + 2.8867513459481288225457439*xi[0]*xi[0] - 2.75180789937663520346857598*xi[0]*xi[1] + 6.1256131838926205072699555*xi[2] - 14.8000915448860244199630551*xi[0]*xi[2] + 2.75180789937663520346857598*xi[1]*xi[2] - 2.8867513459481288225457439*xi[2]*xi[2]; } + if (i == 13) { return -4.19757091807757909941129644*xi[0] + 11.8341924626904785937438341*xi[0]*xi[0] - 1.4245874315222387671726334*xi[0]*xi[1] + 4.19757091807757909941129644*xi[2] + 1.4245874315222387671726334*xi[1]*xi[2] - 11.8341924626904785937438341*xi[2]*xi[2]; } + if (i == 14) { return -6.1256131838926205072699555*xi[0] + 2.8867513459481288225457439*xi[0]*xi[0] - 2.75180789937663520346857598*xi[0]*xi[1] + 0.0165618601854139256815163945*xi[2] + 14.8000915448860244199630551*xi[0]*xi[2] + 2.75180789937663520346857598*xi[1]*xi[2] - 2.8867513459481288225457439*xi[2]*xi[2]; } + if (i == 15) { return -0.0165618601854139256815163943*xi[1] - 2.75180789937663520346857598*xi[0]*xi[1] + 2.8867513459481288225457439*xi[1]*xi[1] + 6.1256131838926205072699555*xi[2] + 2.75180789937663520346857598*xi[0]*xi[2] - 14.8000915448860244199630551*xi[1]*xi[2] - 2.8867513459481288225457439*xi[2]*xi[2]; } + if (i == 16) { return -4.19757091807757909941129644*xi[1] - 1.4245874315222387671726334*xi[0]*xi[1] + 11.8341924626904785937438341*xi[1]*xi[1] + 4.19757091807757909941129644*xi[2] + 1.4245874315222387671726334*xi[0]*xi[2] - 11.8341924626904785937438341*xi[2]*xi[2]; } + if (i == 17) { return -6.1256131838926205072699555*xi[1] - 2.75180789937663520346857598*xi[0]*xi[1] + 2.8867513459481288225457439*xi[1]*xi[1] + 0.0165618601854139256815163945*xi[2] + 2.75180789937663520346857598*xi[0]*xi[2] + 14.8000915448860244199630551*xi[1]*xi[2] - 2.8867513459481288225457439*xi[2]*xi[2]; } + if (i == 18) { return -14.6865334794732115820381866*xi[0] + 12.0262794416288251144009549*xi[0]*xi[0] + 2.09807621135331594029116951*xi[1] + 29.5237020535573893331694524*xi[0]*xi[1] - 12.0262794416288251144009549*xi[1]*xi[1] + 7.4185842870420888755656329*xi[0]*xi[2] + 3.63397459621556135323627683*xi[1]*xi[2]; } + if (i == 19) { return -11.4641016151377545870548927*xi[0] + 12.0262794416288251144009549*xi[0]*xi[0] + 2.09807621135331594029116951*xi[1] - 1.8371685740841777511312659*xi[0]*xi[1] - 12.0262794416288251144009549*xi[1]*xi[1] + 13*xi[0]*xi[2] + 3.63397459621556135323627683*xi[1]*xi[2]; } + if (i == 20) { return -4.19615242270663188058233902*xi[0] + 24.0525588832576502288019098*xi[0]*xi[0] + 26.1506350946109661690930793*xi[1] - 27.6865334794732115820381866*xi[0]*xi[1] - 24.0525588832576502288019098*xi[1]*xi[1] - 7.2679491924311227064725537*xi[0]*xi[2] - 20.4185842870420888755656329*xi[1]*xi[2]; } + if (i == 21) { return 2.09807621135331594029116951*xi[0] - 12.0262794416288251144009549*xi[0]*xi[0] - 11.4641016151377545870548927*xi[1] - 1.8371685740841777511312659*xi[0]*xi[1] + 12.0262794416288251144009549*xi[1]*xi[1] + 3.63397459621556135323627683*xi[0]*xi[2] + 13*xi[1]*xi[2]; } + if (i == 22) { return 15.810889132455352636730311*xi[0] - 18.4711431702997391043675427*xi[0]*xi[0] - 17.9089653438086685770214805*xi[1] - 39.712812921102036696439141*xi[0]*xi[1] + 18.4711431702997391043675427*xi[1]*xi[1] - 23.0788383248864753432028646*xi[0]*xi[2] + 19.4448637286709139899665878*xi[1]*xi[2]; } + if (i == 23) { return 2.09807621135331594029116951*xi[0] + 2.09807621135331594029116951*xi[1] + 79.425625842204073392878283*xi[0]*xi[1] + 3.63397459621556135323627683*xi[0]*xi[2] + 3.63397459621556135323627683*xi[1]*xi[2]; } + if (i == 24) { return 15.810889132455352636730311*xi[0] - 18.4711431702997391043675427*xi[0]*xi[0] - 23.0788383248864753432028646*xi[0]*xi[1] - 17.9089653438086685770214805*xi[2] - 39.712812921102036696439141*xi[0]*xi[2] + 19.4448637286709139899665878*xi[1]*xi[2] + 18.4711431702997391043675427*xi[2]*xi[2]; } + if (i == 25) { return -17.9089653438086685770214805*xi[0] + 18.4711431702997391043675427*xi[0]*xi[0] + 19.4448637286709139899665878*xi[0]*xi[1] + 15.810889132455352636730311*xi[2] - 39.712812921102036696439141*xi[0]*xi[2] - 23.0788383248864753432028646*xi[1]*xi[2] - 18.4711431702997391043675427*xi[2]*xi[2]; } + if (i == 26) { return -4.19615242270663188058233902*xi[0] + 24.0525588832576502288019098*xi[0]*xi[0] - 7.2679491924311227064725537*xi[0]*xi[1] + 26.1506350946109661690930793*xi[2] - 27.6865334794732115820381866*xi[0]*xi[2] - 20.4185842870420888755656329*xi[1]*xi[2] - 24.0525588832576502288019098*xi[2]*xi[2]; } + if (i == 27) { return 2.09807621135331594029116951*xi[0] - 12.0262794416288251144009549*xi[0]*xi[0] + 3.63397459621556135323627683*xi[0]*xi[1] - 14.6865334794732115820381866*xi[2] + 29.5237020535573893331694524*xi[0]*xi[2] + 7.4185842870420888755656329*xi[1]*xi[2] + 12.0262794416288251144009549*xi[2]*xi[2]; } + if (i == 28) { return -14.6865334794732115820381866*xi[0] + 12.0262794416288251144009549*xi[0]*xi[0] + 7.4185842870420888755656329*xi[0]*xi[1] + 2.09807621135331594029116951*xi[2] + 29.5237020535573893331694524*xi[0]*xi[2] + 3.63397459621556135323627683*xi[1]*xi[2] - 12.0262794416288251144009549*xi[2]*xi[2]; } + if (i == 29) { return 26.1506350946109661690930793*xi[0] - 24.0525588832576502288019098*xi[0]*xi[0] - 20.4185842870420888755656329*xi[0]*xi[1] - 4.19615242270663188058233902*xi[2] - 27.6865334794732115820381866*xi[0]*xi[2] - 7.2679491924311227064725537*xi[1]*xi[2] + 24.0525588832576502288019098*xi[2]*xi[2]; } + if (i == 30) { return -0.9737205583711748855990451*xi[0]*xi[1] + 4.60769515458673623883532195*xi[0]*xi[2] - 15.6602540378443864676372317*xi[1]*xi[2]; } + if (i == 31) { return 4.60769515458673623883532195*xi[0]*xi[1] - 0.97372055837117488559904512*xi[0]*xi[2] - 15.6602540378443864676372317*xi[1]*xi[2]; } + if (i == 32) { return -3.6339745962155613532362768*xi[0]*xi[1] + 31.3205080756887729352744634*xi[0]*xi[2] - 3.63397459621556135323627683*xi[1]*xi[2]; } + if (i == 33) { return 4.60769515458673623883532195*xi[0]*xi[1] - 15.6602540378443864676372317*xi[0]*xi[2] - 0.97372055837117488559904512*xi[1]*xi[2]; } + if (i == 34) { return -15.6602540378443864676372317*xi[0]*xi[1] + 4.60769515458673623883532195*xi[0]*xi[2] - 0.97372055837117488559904512*xi[1]*xi[2]; } + if (i == 35) { return 31.3205080756887729352744634*xi[0]*xi[1] - 3.63397459621556135323627683*xi[0]*xi[2] - 3.63397459621556135323627683*xi[1]*xi[2]; } + if (i == 36) { return 2.09807621135331594029116951*xi[1] + 3.63397459621556135323627683*xi[0]*xi[1] - 12.0262794416288251144009549*xi[1]*xi[1] - 11.4641016151377545870548927*xi[2] + 13*xi[0]*xi[2] - 1.8371685740841777511312659*xi[1]*xi[2] + 12.0262794416288251144009549*xi[2]*xi[2]; } + if (i == 37) { return 2.09807621135331594029116951*xi[1] + 3.63397459621556135323627683*xi[0]*xi[1] - 12.0262794416288251144009549*xi[1]*xi[1] - 14.6865334794732115820381866*xi[2] + 7.4185842870420888755656329*xi[0]*xi[2] + 29.5237020535573893331694524*xi[1]*xi[2] + 12.0262794416288251144009549*xi[2]*xi[2]; } + if (i == 38) { return 2.09807621135331594029116951*xi[1] + 3.633974596215561353236277*xi[0]*xi[1] + 2.09807621135331594029116951*xi[2] + 3.63397459621556135323627683*xi[0]*xi[2] + 79.425625842204073392878283*xi[1]*xi[2]; } + if (i == 39) { return -17.9089653438086685770214805*xi[1] + 19.4448637286709139899665878*xi[0]*xi[1] + 18.4711431702997391043675427*xi[1]*xi[1] + 15.810889132455352636730311*xi[2] - 23.0788383248864753432028646*xi[0]*xi[2] - 39.712812921102036696439141*xi[1]*xi[2] - 18.4711431702997391043675427*xi[2]*xi[2]; } + if (i == 40) { return -11.4641016151377545870548927*xi[1] + 13*xi[0]*xi[1] + 12.0262794416288251144009549*xi[1]*xi[1] + 2.09807621135331594029116951*xi[2] + 3.63397459621556135323627683*xi[0]*xi[2] - 1.8371685740841777511312659*xi[1]*xi[2] - 12.0262794416288251144009549*xi[2]*xi[2]; } + if (i == 41) { return 26.1506350946109661690930793*xi[1] - 20.4185842870420888755656329*xi[0]*xi[1] - 24.0525588832576502288019098*xi[1]*xi[1] - 4.19615242270663188058233902*xi[2] - 7.2679491924311227064725537*xi[0]*xi[2] - 27.6865334794732115820381866*xi[1]*xi[2] + 24.0525588832576502288019098*xi[2]*xi[2]; } + if (i == 42) { return 32*xi[0]*xi[1] + 32*xi[0]*xi[2] - 32*xi[1]*xi[2]; } + if (i == 43) { return 32*xi[0]*xi[1] - 32*xi[0]*xi[2] + 32*xi[1]*xi[2]; } + if (i == 44) { return -32*xi[0]*xi[1] + 32*xi[0]*xi[2] + 32*xi[1]*xi[2]; } + } // if (p == 3) + + return {}; + } + + constexpr vec3 interpolate(vec3 xi, const double * values) const { + vec3 interpolated_value{}; + for (int i = 0; i < num_nodes(); i++) { + interpolated_value += values[i] * shape_function(xi, i); + } + return interpolated_value; + } + + constexpr vec3 curl(vec3 xi, const double * values) const { + vec3 interpolated_curl{}; + for (int i = 0; i < num_nodes(); i++) { + interpolated_curl += values[i] * shape_function_curl(xi, i); + } + return interpolated_curl; + } + + __host__ __device__ uint32_t batch_interpolation_scratch_space(nd::view xi) const { + return 0; + } + + nd::array< double, 3 > evaluate_shape_functions(nd::view xi) { + uint32_t q = xi.shape[0]; + nd::array shape_fns({q, num_nodes(), dim}); + for (int i = 0; i < q; i++) { + vec3 xi_i = vec3{xi(i, 0), xi(i, 1), xi(i, 2)}; + for (int j = 0; j < num_nodes(); j++) { + vec3 phi_j = shape_function(xi_i, j); + shape_fns(i, j, 0) = phi_j[0]; + shape_fns(i, j, 1) = phi_j[1]; + shape_fns(i, j, 2) = phi_j[2]; + } + } + return shape_fns; + } + + void interpolate(nd::view values_q, nd::view values_e, nd::view shape_fns, double * /*buffer*/) { + int nnodes = num_nodes(); + int nqpts = values_q.shape[0]; + + for (int q = 0; q < nqpts; q++) { + value_type sum{}; + for (int i = 0; i < nnodes; i++) { + for (int j = 0; j < dim; j++) { + sum[j] += shape_fns(q, i, j) * values_e(i); + } + } + values_q(q) = sum; + } + } + + nd::array< double, 3 > evaluate_shape_function_curls(nd::view xi) { + uint32_t q = xi.shape[0]; + nd::array shape_fns({q, num_nodes(), 3}); + for (int i = 0; i < q; i++) { + vec3 xi_i = vec3{xi(i, 0), xi(i, 1), xi(i, 2)}; + for (int j = 0; j < num_nodes(); j++) { + vec3 curl_phi_j = shape_function_curl(xi_i, j); + shape_fns(i, j, 0) = curl_phi_j[0]; + shape_fns(i, j, 1) = curl_phi_j[1]; + shape_fns(i, j, 2) = curl_phi_j[2]; + } + } + return shape_fns; + } + + void curl(nd::view values_q, nd::view values_e, nd::view shape_fn_curls, double * /*buffer*/) { + int nnodes = num_nodes(); + int nqpts = values_q.shape[0]; + + for (int q = 0; q < nqpts; q++) { + derivative_type sum{}; + for (int i = 0; i < nnodes; i++) { + for (int j = 0; j < dim; j++) { + sum[j] += shape_fn_curls(q, i, j) * values_e(i); + } + } + values_q(q) = sum; + } + } + + nd::array< double, 3 > evaluate_weighted_shape_functions(nd::view xi, nd::view weights) const { + uint32_t q = xi.shape[0]; + nd::array shape_fns({q, num_nodes(), dim}); + for (int i = 0; i < q; i++) { + vec3 xi_i = vec3{xi(i, 0), xi(i, 1), xi(i, 2)}; + for (int j = 0; j < num_nodes(); j++) { + vec3 phi_j = shape_function(xi_i, j); + shape_fns(i, j, 0) = phi_j[0] * weights[i]; + shape_fns(i, j, 1) = phi_j[1] * weights[i]; + shape_fns(i, j, 2) = phi_j[2] * weights[i]; + } + } + return shape_fns; + } + + __host__ __device__ void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fn, double * /*buffer*/) const { + int nnodes = num_nodes(); + int nqpts = source_q.shape[0]; + + for (int i = 0; i < nnodes; i++) { + double sum = 0.0; + for (int q = 0; q < nqpts; q++) { + for (int j = 0; j < dim; j++) { + sum += shape_fn(q, i, j) * source_q(q)[j]; + } + } + residual_e(i) = sum; + } + } + + nd::array< double, 3 > evaluate_weighted_shape_function_curls(nd::view xi, nd::view weights) const { + uint32_t q = xi.shape[0]; + nd::array shape_fns({q, num_nodes(), dim}); + for (int i = 0; i < q; i++) { + vec3 xi_i = vec3{xi(i, 0), xi(i, 1), xi(i, 2)}; + for (int j = 0; j < num_nodes(); j++) { + vec3 dphi_j = shape_function_curl(xi_i, j); + shape_fns(i, j, 0) = dphi_j[0] * weights[i]; + shape_fns(i, j, 1) = dphi_j[1] * weights[i]; + shape_fns(i, j, 2) = dphi_j[2] * weights[i]; + } + } + return shape_fns; + } + + __host__ __device__ void integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fn, double * /*buffer*/) const { + int nnodes = num_nodes(); + int nqpts = flux_q.shape[0]; + + for (int i = 0; i < nnodes; i++) { + double sum = 0.0; + for (int q = 0; q < nqpts; q++) { + for (int j = 0; j < dim; j++) { + sum += shape_fn(q, i, j) * flux_q(q)[j]; + } + } + residual_e(i) = sum; + } + } + + #ifdef __CUDACC__ + __device__ void cuda_integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fn_curl, double * /*buffer*/) const { + int nnodes = num_nodes(); + int nqpts = flux_q.shape[0]; + + for (int i = threadIdx.x; i < nnodes; i += blockDim.x) { + double sum = 0.0; + for (int q = 0; q < nqpts; q++) { + for (int d = 0; d < dim; d++) { + sum += shape_fn_curl(q, i, d) * flux_q(q)[d]; + } + } + residual_e(i) = sum; + } + } + #endif + + uint32_t p; + +}; +// clang-format on + +} // namespace refactor diff --git a/src/serac/numerics/refactor/elements/hcurl_triangle.hpp b/src/serac/numerics/refactor/elements/hcurl_triangle.hpp new file mode 100644 index 0000000000..5b62461878 --- /dev/null +++ b/src/serac/numerics/refactor/elements/hcurl_triangle.hpp @@ -0,0 +1,625 @@ +#pragma once + +#include "fm/types/vec.hpp" + +namespace refactor { + +using namespace fm; + +// clang-format off +template <> +struct FiniteElement { + + using value_type = vec2; + using derivative_type = vec1; + + using source_type = vec2; + using flux_type = vec1; + + static constexpr int dim = 2; + + __host__ __device__ uint32_t num_nodes() const { return p * (p + 2); } + + void nodes(nd::view xi) const { + if (p == 1) { + xi(0, 0) = 0.5; xi(0, 1) = 0.0; + xi(1, 0) = 0.5; xi(1, 1) = 0.5; + xi(2, 0) = 0.0; xi(2, 1) = 0.5; + } + if (p == 2) { + constexpr double s = 0.21132486540518711774542560975; + constexpr double t = 0.33333333333333333333333333333; + xi(0, 0) = s; xi(0, 1) = 0.0; + xi(1, 0) = 1-s; xi(1, 1) = 0.0; + xi(2, 0) = 1-s; xi(2, 1) = s; + xi(3, 0) = s; xi(3, 1) = 1-s; + xi(4, 0) = 0; xi(4, 1) = 1-s; + xi(5, 0) = 0; xi(5, 1) = s; + xi(6, 0) = t; xi(6, 1) = t; + xi(7, 0) = t; xi(7, 1) = t; + } + if (p == 3) { + constexpr double s = 0.11270166537925831148207346002; + constexpr double c1 = 0.1744576301870094389594272045; + constexpr double c2 = 0.6510847396259811220811455910; + + xi( 0, 0) = s; xi( 0, 1) = 0.0; + xi( 1, 0) = 0.5; xi( 1, 1) = 0.0; + xi( 2, 0) = 1-s; xi( 2, 1) = 0.0; + + xi( 3, 0) = 1-s; xi( 3, 1) = s; + xi( 4, 0) = 0.5; xi( 4, 1) = 0.5; + xi( 5, 0) = s; xi( 5, 1) = 1-s; + + xi( 6, 0) = 0.0; xi( 6, 1) = 1-s; + xi( 7, 0) = 0.0; xi( 7, 1) = 0.5; + xi( 8, 0) = 0.0; xi( 8, 1) = s; + + xi( 9, 0) = c1; xi( 9, 1) = c1; + xi(10, 0) = c1; xi(10, 1) = c1; + + xi(11, 0) = c2; xi(11, 1) = c1; + xi(12, 0) = c2; xi(12, 1) = c1; + + xi(13, 0) = c1; xi(13, 1) = c2; + xi(14, 0) = c1; xi(14, 1) = c2; + } + } + + void directions(nd::view d) const { + int i = 0; + for (int k = 0; k < p; k++) { d(i, 0) = 1.0; d(i++, 1) = 0.0; } // edge 1 + for (int k = 0; k < p; k++) { d(i, 0) = -1.0; d(i++, 1) = 1.0; } // edge 2 + for (int k = 0; k < p; k++) { d(i, 0) = 0.0; d(i++, 1) = -1.0; } // edge 3 + + // interior nodes + for (int k = 0; k < ((p - 1) * p) / 2; k++) { + d(i, 0) = 1.0; d(i++, 1) = 0.0; + d(i, 0) = 0.0; d(i++, 1) = 1.0; + } + } + + __host__ __device__ uint32_t num_interior_nodes() const { return (p > 1) ? 2 * Triangle::number(p - 1) : 0; } + + void interior_nodes(nd::view xi) const { + if (p == 2) { + xi(0, 0) = 0.3333333333333333333; xi(0, 1) = 0.3333333333333333333; + xi(1, 0) = 0.3333333333333333333; xi(1, 1) = 0.3333333333333333333; + } + if (p == 3) { + constexpr double c1 = 0.1744576301870094389594272045; + constexpr double c2 = 0.6510847396259811220811455910; + xi(0, 0) = c1; xi(0, 1) = c1; + xi(1, 0) = c1; xi(1, 1) = c1; + + xi(2, 0) = c2; xi(2, 1) = c1; + xi(3, 0) = c2; xi(3, 1) = c1; + + xi(4, 0) = c1; xi(4, 1) = c2; + xi(5, 0) = c1; xi(5, 1) = c2; + } + } + + void interior_directions(nd::view d) const { + if (p > 1) { + int i = 0; + for (int k = 0; k < ((p - 1) * p) / 2; k++) { + d(i, 0) = 1.0; d(i++, 1) = 0.0; + d(i, 0) = 0.0; d(i++, 1) = 1.0; + } + } + } + + __host__ __device__ void indices(const GeometryInfo & offsets, const Connection * tri, uint32_t * indices) const { + + const Connection * edge = tri + 3; + const Connection cell = *(tri + 6); + + if (p == 1) { + // * + // | \ + // 2 1 + // | \ + // *--0--* + indices[0] = offsets.edge + edge[0].index; + indices[1] = offsets.edge + edge[1].index; + indices[2] = offsets.edge + edge[2].index; + return; + } + + if (p == 2) { + // * + // | \ + // 4 3 + // | \ + // 5 6/7 2 + // | \ + // *--0--1--* + indices[0] = offsets.edge + 2 * edge[0].index + 0; + indices[1] = offsets.edge + 2 * edge[0].index + 1; + if (flip(edge[0])) { fm::swap(indices[0], indices[1]); } + + indices[2] = offsets.edge + 2 * edge[1].index + 0; + indices[3] = offsets.edge + 2 * edge[1].index + 1; + if (flip(edge[1])) { fm::swap(indices[2], indices[3]); } + + indices[4] = offsets.edge + 2 * edge[2].index + 0; + indices[5] = offsets.edge + 2 * edge[2].index + 1; + if (flip(edge[2])) { fm::swap(indices[4], indices[5]); } + + indices[6] = offsets.tri + 2 * cell.index + 0; + indices[7] = offsets.tri + 2 * cell.index + 1; + } + + if (p == 3) { + // * + // | \ + // 6 5 + // | \ + // 7 13 4 + // | \ + // 8 9 11 3 + // | \ + // *--0--1--2--* + // + // note: nodes for {9/10, 11/12, 13/14} are coincident + indices[0] = offsets.edge + 3 * edge[0].index + 0; + indices[1] = offsets.edge + 3 * edge[0].index + 1; + indices[2] = offsets.edge + 3 * edge[0].index + 2; + if (flip(edge[0])) { fm::swap(indices[0], indices[2]); } + + indices[3] = offsets.edge + 3 * edge[1].index + 0; + indices[4] = offsets.edge + 3 * edge[1].index + 1; + indices[5] = offsets.edge + 3 * edge[1].index + 2; + if (flip(edge[1])) { fm::swap(indices[3], indices[5]); } + + indices[6] = offsets.edge + 3 * edge[2].index + 0; + indices[7] = offsets.edge + 3 * edge[2].index + 1; + indices[8] = offsets.edge + 3 * edge[2].index + 2; + if (flip(edge[2])) { fm::swap(indices[6], indices[8]); } + + indices[ 9] = offsets.tri + 6 * cell.index + 0; + indices[10] = offsets.tri + 6 * cell.index + 1; + + indices[11] = offsets.tri + 6 * cell.index + 2; + indices[12] = offsets.tri + 6 * cell.index + 3; + + indices[13] = offsets.tri + 6 * cell.index + 4; + indices[14] = offsets.tri + 6 * cell.index + 5; + } + } + + template < typename T > + __host__ __device__ void reorient(const TransformationType type, const Connection * tri, T * values) const { + + const Connection * edge = tri + Triangle::edge_offset; + + for (uint32_t e = 0; e < Triangle::num_edges; e++) { + if (edge[e].sign() == Sign::Negative) { + for (uint32_t i = 0; i < p; i++) { + values[p*e + i] *= -1; + } + } + } + + } + + __host__ __device__ void reorient(const TransformationType type, const Connection * tri, int8_t * transformation) { + + const Connection * edge = tri + Triangle::edge_offset; + + uint32_t count = 0; + for (uint32_t e = 0; e < Triangle::num_edges; e++) { + if (edge[e].sign() == Sign::Negative) { + for (uint32_t i = 0; i < p; i++) { + transformation[count++] = -1; + } + } else { + for (uint32_t i = 0; i < p; i++) { + transformation[count++] = 0; + } + } + } + + uint32_t nnodes = num_nodes(); + for (uint32_t k = count; k < nnodes; k++) { + transformation[k] = 0; + } + + } + + constexpr vec2 shape_function(vec2 xi, uint32_t i) const { + if (p == 1) { + if (i == 0) return {1.0 - xi[1], xi[0]}; + if (i == 1) return {-xi[1], xi[0]}; + if (i == 2) return {-xi[1], xi[0] - 1.0}; + } + + if (p == 2) { + if (i == 0) { + return vec2{ + 1.3660254037844386467637231708 - 1.732050807568877293527446342*xi[0] - 3.732050807568877293527446342*xi[1] + 1.732050807568877293527446342*xi[0]*xi[1] + 2.366025403784438646763723171*xi[1]*xi[1], + 1.3660254037844386467637231708*xi[0] - 1.732050807568877293527446342*xi[0]*xi[0] - 2.366025403784438646763723171*xi[0]*xi[1] + }; + } + if (i == 1) { + return vec2{ + -0.3660254037844386467637231708 + 1.732050807568877293527446342*xi[0] - 0.2679491924311227064725536585*xi[1] - 1.732050807568877293527446342*xi[0]*xi[1] + 0.6339745962155613532362768292*xi[1]*xi[1], + -0.3660254037844386467637231708*xi[0] + 1.732050807568877293527446342*xi[0]*xi[0] - 0.6339745962155613532362768292*xi[0]*xi[1] + }; + } + if (i == 2) { + return vec2{ + 1.*xi[1] - 2.366025403784438646763723171*xi[0]*xi[1] - 0.6339745962155613532362768292*xi[1]*xi[1], + -1.*xi[0] + 2.366025403784438646763723171*xi[0]*xi[0] + 0.6339745962155613532362768292*xi[0]*xi[1] + }; + } + if (i == 3) { + return vec2{ + 1.*xi[1] - 0.6339745962155613532362768292*xi[0]*xi[1] - 2.366025403784438646763723171*xi[1]*xi[1], + -1.*xi[0] + 0.6339745962155613532362768292*xi[0]*xi[0] + 2.366025403784438646763723171*xi[0]*xi[1] + }; + } + if (i == 4) { + return vec2{ + 0.3660254037844386467637231708*xi[1] + 0.6339745962155613532362768292*xi[0]*xi[1] - 1.732050807568877293527446342*xi[1]*xi[1], + 0.3660254037844386467637231708 + 0.2679491924311227064725536585*xi[0] - 0.6339745962155613532362768292*xi[0]*xi[0] - 1.732050807568877293527446342*xi[1] + 1.732050807568877293527446342*xi[0]*xi[1] + }; + } + if (i == 5) { + return vec2{ + -1.3660254037844386467637231708*xi[1] + 2.366025403784438646763723171*xi[0]*xi[1] + 1.732050807568877293527446342*xi[1]*xi[1], + -1.3660254037844386467637231708 + 3.732050807568877293527446342*xi[0] - 2.366025403784438646763723171*xi[0]*xi[0] + 1.732050807568877293527446342*xi[1] - 1.732050807568877293527446342*xi[0]*xi[1] + }; + } + if (i == 6) { + return vec2{ + 6.*xi[1] - 3.*xi[0]*xi[1] - 6.*xi[1]*xi[1], + -3.*xi[0] + 3.*xi[0]*xi[0] + 6.*xi[0]*xi[1] + }; + } + if (i == 7) { + return vec2{ + -3.*xi[1] + 6.*xi[0]*xi[1] + 3.*xi[1]*xi[1], + 6.*xi[0] - 6.*xi[0]*xi[0] - 3.*xi[0]*xi[1] + }; + } + } + + if (p == 3) { + if (i == 0) { + return vec2{ + 1.47883055770123614752987757 - 4.6243277820691389617264218*xi[0] + 3.33333333333333333333333333*xi[0]*xi[0] - 8.9733478255330900061205269*xi[1] + 15.3577068878454845050412827*xi[0]*xi[1] - 3.33333333333333333333333333*xi[0]*xi[0]*xi[1] + 14.3045824936940910415209517*xi[1]*xi[1] - 10.7333791057763455433148609*xi[0]*xi[1]*xi[1] - 6.8100652258622371829303024*xi[1]*xi[1]*xi[1], + 1.47883055770123614752987757*xi[0] - 4.6243277820691389617264218*xi[0]*xi[0] + 3.33333333333333333333333333*xi[0]*xi[0]*xi[0] - 7.4945172678318538585906493*xi[0]*xi[1] + 10.7333791057763455433148609*xi[0]*xi[0]*xi[1] + 6.8100652258622371829303024*xi[0]*xi[1]*xi[1] + }; + } + if (i == 1) { + return vec2{ + -0.66666666666666666666666667 + 6.6666666666666666666666667*xi[0] - 6.6666666666666666666666667*xi[0]*xi[0] - 0.303288211279566160999204378*xi[1] - 13.3333333333333333333333333*xi[0]*xi[1] + 6.6666666666666666666666667*xi[0]*xi[0]*xi[1] + 3.55371777595813879120445478*xi[1]*xi[1] + 6.6666666666666666666666667*xi[0]*xi[1]*xi[1] - 2.58376289801190596353858374*xi[1]*xi[1]*xi[1], + -0.66666666666666666666666667*xi[0] + 6.6666666666666666666666667*xi[0]*xi[0] - 6.6666666666666666666666667*xi[0]*xi[0]*xi[0] - 0.96995487794623282766587104*xi[0]*xi[1] - 6.6666666666666666666666667*xi[0]*xi[0]*xi[1] + 2.58376289801190596353858374*xi[0]*xi[1]*xi[1] + }; + } + if (i == 2) { + return vec2{ + 0.1878361089654305191367891 - 2.04233888459752770494024487*xi[0] + 3.33333333333333333333333333*xi[0]*xi[0] + 1.00868684438153346064717759*xi[1] - 2.02437355451215117170794933*xi[0]*xi[1] - 3.33333333333333333333333333*xi[0]*xi[0]*xi[1] - 1.78650349992773900683519184*xi[1]*xi[1] + 4.0667124391096788766481942*xi[0]*xi[1]*xi[1] + 0.58998054658077502705122515*xi[1]*xi[1]*xi[1], + 0.1878361089654305191367891*xi[0] - 2.04233888459752770494024487*xi[0]*xi[0] + 3.33333333333333333333333333*xi[0]*xi[0]*xi[0] + 1.19652295334696397978396669*xi[0]*xi[1] - 4.0667124391096788766481942*xi[0]*xi[0]*xi[1] - 0.58998054658077502705122515*xi[0]*xi[1]*xi[1] + }; + } + if (i == 3) { + return vec2{ + -0.79437851573161947186953064*xi[1] + 6.1256131838926205072699555*xi[0]*xi[1] - 6.8100652258622371829303024*xi[0]*xi[0]*xi[1] + 0.0165618601854139256815163943*xi[1]*xi[1] - 2.8867513459481288225457439*xi[0]*xi[1]*xi[1] + 0.58998054658077502705122515*xi[1]*xi[1]*xi[1], + 0.79437851573161947186953064*xi[0] - 6.1256131838926205072699555*xi[0]*xi[0] + 6.8100652258622371829303024*xi[0]*xi[0]*xi[0] - 0.0165618601854139256815163943*xi[0]*xi[1] + 2.8867513459481288225457439*xi[0]*xi[0]*xi[1] - 0.58998054658077502705122515*xi[0]*xi[1]*xi[1] + }; + } + if (i == 4) { + return vec2{ + -0.94714135339900646920604603*xi[1] + 4.19757091807757909941129644*xi[0]*xi[1] - 2.58376289801190596353858374*xi[0]*xi[0]*xi[1] + 4.19757091807757909941129644*xi[1]*xi[1] - 11.8341924626904785937438341*xi[0]*xi[1]*xi[1] - 2.58376289801190596353858374*xi[1]*xi[1]*xi[1], + 0.94714135339900646920604603*xi[0] - 4.19757091807757909941129644*xi[0]*xi[0] + 2.58376289801190596353858374*xi[0]*xi[0]*xi[0] - 4.19757091807757909941129644*xi[0]*xi[1] + 11.8341924626904785937438341*xi[0]*xi[0]*xi[1] + 2.58376289801190596353858374*xi[0]*xi[1]*xi[1] + }; + } + if (i == 5) { + return vec2{ + -0.79437851573161947186953064*xi[1] + 0.0165618601854139256815163945*xi[0]*xi[1] + 0.58998054658077502705122515*xi[0]*xi[0]*xi[1] + 6.1256131838926205072699555*xi[1]*xi[1] - 2.8867513459481288225457439*xi[0]*xi[1]*xi[1] - 6.8100652258622371829303024*xi[1]*xi[1]*xi[1], + 0.79437851573161947186953064*xi[0] - 0.0165618601854139256815163945*xi[0]*xi[0] - 0.58998054658077502705122515*xi[0]*xi[0]*xi[0] - 6.1256131838926205072699555*xi[0]*xi[1] + 2.8867513459481288225457439*xi[0]*xi[0]*xi[1] + 6.8100652258622371829303024*xi[0]*xi[1]*xi[1] + }; + } + if (i == 6) { + return vec2{ + -0.1878361089654305191367891*xi[1] - 1.19652295334696397978396669*xi[0]*xi[1] + 0.58998054658077502705122515*xi[0]*xi[0]*xi[1] + 2.04233888459752770494024487*xi[1]*xi[1] + 4.0667124391096788766481942*xi[0]*xi[1]*xi[1] - 3.33333333333333333333333333*xi[1]*xi[1]*xi[1], + -0.1878361089654305191367891 - 1.00868684438153346064717759*xi[0] + 1.78650349992773900683519184*xi[0]*xi[0] - 0.58998054658077502705122515*xi[0]*xi[0]*xi[0] + 2.04233888459752770494024487*xi[1] + 2.02437355451215117170794934*xi[0]*xi[1] - 4.0667124391096788766481942*xi[0]*xi[0]*xi[1] - 3.33333333333333333333333333*xi[1]*xi[1] + 3.33333333333333333333333333*xi[0]*xi[1]*xi[1] + }; + } + if (i == 7) { + return vec2{ + 0.66666666666666666666666667*xi[1] + 0.96995487794623282766587105*xi[0]*xi[1] - 2.58376289801190596353858374*xi[0]*xi[0]*xi[1] - 6.6666666666666666666666667*xi[1]*xi[1] + 6.6666666666666666666666667*xi[0]*xi[1]*xi[1] + 6.6666666666666666666666667*xi[1]*xi[1]*xi[1], + 0.66666666666666666666666667 + 0.303288211279566160999204379*xi[0] - 3.55371777595813879120445479*xi[0]*xi[0] + 2.58376289801190596353858374*xi[0]*xi[0]*xi[0] - 6.6666666666666666666666667*xi[1] + 13.3333333333333333333333333*xi[0]*xi[1] - 6.6666666666666666666666667*xi[0]*xi[0]*xi[1] + 6.6666666666666666666666667*xi[1]*xi[1] - 6.6666666666666666666666667*xi[0]*xi[1]*xi[1] + }; + } + if (i == 8) { + return vec2{ + -1.47883055770123614752987757*xi[1] + 7.4945172678318538585906493*xi[0]*xi[1] - 6.8100652258622371829303024*xi[0]*xi[0]*xi[1] + 4.6243277820691389617264218*xi[1]*xi[1] - 10.7333791057763455433148609*xi[0]*xi[1]*xi[1] - 3.33333333333333333333333333*xi[1]*xi[1]*xi[1], + -1.47883055770123614752987757 + 8.9733478255330900061205269*xi[0] - 14.3045824936940910415209517*xi[0]*xi[0] + 6.8100652258622371829303024*xi[0]*xi[0]*xi[0] + 4.6243277820691389617264218*xi[1] - 15.3577068878454845050412827*xi[0]*xi[1] + 10.7333791057763455433148609*xi[0]*xi[0]*xi[1] - 3.33333333333333333333333333*xi[1]*xi[1] + 3.33333333333333333333333333*xi[0]*xi[1]*xi[1] + }; + } + if (i == 9) { + return vec2{ + 12.5884572681198956417470171*xi[1] - 17.9089653438086685770214805*xi[0]*xi[1] + 3.2224318643354569949832939*xi[0]*xi[0]*xi[1] - 27.8371685740841777511312659*xi[1]*xi[1] + 18.4711431702997391043675427*xi[0]*xi[1]*xi[1] + 15.2487113059642821093842488*xi[1]*xi[1]*xi[1], + -2.66025403784438646763723171*xi[0] + 5.8826859021798434626205256*xi[0]*xi[0] - 3.2224318643354569949832939*xi[0]*xi[0]*xi[0] + 15.810889132455352636730311*xi[0]*xi[1] - 18.4711431702997391043675427*xi[0]*xi[0]*xi[1] - 15.2487113059642821093842488*xi[0]*xi[1]*xi[1] + }; + } + if (i == 10) { + return vec2{ + -2.66025403784438646763723171*xi[1] + 15.810889132455352636730311*xi[0]*xi[1] - 15.2487113059642821093842488*xi[0]*xi[0]*xi[1] + 5.8826859021798434626205256*xi[1]*xi[1] - 18.4711431702997391043675427*xi[0]*xi[1]*xi[1] - 3.2224318643354569949832939*xi[1]*xi[1]*xi[1], + 12.5884572681198956417470171*xi[0] - 27.8371685740841777511312659*xi[0]*xi[0] + 15.2487113059642821093842488*xi[0]*xi[0]*xi[0] - 17.9089653438086685770214805*xi[0]*xi[1] + 18.4711431702997391043675427*xi[0]*xi[0]*xi[1] + 3.2224318643354569949832939*xi[0]*xi[1]*xi[1] + }; + } + if (i == 11) { + return vec2{ + -4.19615242270663188058233902*xi[1] + 26.1506350946109661690930793*xi[0]*xi[1] - 12.0262794416288251144009549*xi[0]*xi[0]*xi[1] + 4.19615242270663188058233902*xi[1]*xi[1] - 24.0525588832576502288019098*xi[0]*xi[1]*xi[1], + 2.09807621135331594029116951*xi[0] - 14.1243556529821410546921244*xi[0]*xi[0] + 12.0262794416288251144009549*xi[0]*xi[0]*xi[0] - 4.19615242270663188058233902*xi[0]*xi[1] + 24.0525588832576502288019098*xi[0]*xi[0]*xi[1] + }; + } + if (i == 12) { + return vec2{ + 2.09807621135331594029116951*xi[1] - 14.6865334794732115820381866*xi[0]*xi[1] + 15.2487113059642821093842488*xi[0]*xi[0]*xi[1] - 2.09807621135331594029116951*xi[1]*xi[1] + 12.0262794416288251144009549*xi[0]*xi[1]*xi[1], + -2.66025403784438646763723171*xi[0] + 17.9089653438086685770214805*xi[0]*xi[0] - 15.2487113059642821093842488*xi[0]*xi[0]*xi[0] + 2.09807621135331594029116951*xi[0]*xi[1] - 12.0262794416288251144009549*xi[0]*xi[0]*xi[1] + }; + } + if (i == 13) { + return vec2{ + -2.66025403784438646763723171*xi[1] + 2.09807621135331594029116951*xi[0]*xi[1] + 17.9089653438086685770214805*xi[1]*xi[1] - 12.0262794416288251144009549*xi[0]*xi[1]*xi[1] - 15.2487113059642821093842488*xi[1]*xi[1]*xi[1], + 2.09807621135331594029116951*xi[0] - 2.09807621135331594029116951*xi[0]*xi[0] - 14.6865334794732115820381866*xi[0]*xi[1] + 12.0262794416288251144009549*xi[0]*xi[0]*xi[1] + 15.2487113059642821093842488*xi[0]*xi[1]*xi[1] + }; + } + if (i == 14) { + return vec2{ + 2.09807621135331594029116951*xi[1] - 4.19615242270663188058233902*xi[0]*xi[1] - 14.1243556529821410546921244*xi[1]*xi[1] + 24.0525588832576502288019098*xi[0]*xi[1]*xi[1] + 12.0262794416288251144009549*xi[1]*xi[1]*xi[1], + -4.19615242270663188058233902*xi[0] + 4.19615242270663188058233902*xi[0]*xi[0] + 26.1506350946109661690930793*xi[0]*xi[1] - 24.0525588832576502288019098*xi[0]*xi[0]*xi[1] - 12.0262794416288251144009549*xi[0]*xi[1]*xi[1] + }; + } + } + + return {}; + } + + constexpr vec2 reoriented_shape_function(vec2 xi, uint32_t i, int8_t transformation) const { + if (transformation == -1) { + return -shape_function(xi, i); + } else { + return shape_function(xi, i); + } + } + + vec<1> shape_function_curl(vec2 xi, uint32_t i) const { + // expressions generated symbolically by mathematica + if (p == 1) { + return 2.0; + } + if (p == 2) { + if (i == 0) { return 5.098076211353315940291169512 - 5.196152422706631880582339025*xi[0] - 7.098076211353315940291169512*xi[1]; } + if (i == 1) { return -0.0980762113533159402911695123 + 5.196152422706631880582339025*xi[0] - 1.901923788646684059708830488*xi[1]; } + if (i == 2) { return -2. + 7.098076211353315940291169512*xi[0] + 1.901923788646684059708830488*xi[1]; } + if (i == 3) { return -2. + 1.901923788646684059708830488*xi[0] + 7.098076211353315940291169512*xi[1]; } + if (i == 4) { return -0.0980762113533159402911695123 - 1.901923788646684059708830488*xi[0] + 5.196152422706631880582339025*xi[1]; } + if (i == 5) { return 5.098076211353315940291169512 - 7.098076211353315940291169512*xi[0] - 5.196152422706631880582339025*xi[1]; } + if (i == 6) { return -9. + 9.*xi[0] + 18.*xi[1]; } + if (i == 7) { return 9. - 18.*xi[0] - 9.*xi[1]; } + } + if (p == 3) { + if (i == 0) { return 10.4521783832343261536504044 - 24.6063624519837624284941263*xi[0] + 13.3333333333333333333333333*xi[0]*xi[0] - 36.1036822552200359416325527*xi[1] + 42.9335164231053821732594435*xi[0]*xi[1] + 27.2402609034489487317212095*xi[1]*xi[1]; } + if (i == 1) { return -0.36337845538710050566746229 + 26.6666666666666666666666667*xi[0] - 26.6666666666666666666666667*xi[0]*xi[0] - 8.0773904298625104100747806*xi[1] - 26.6666666666666666666666667*xi[0]*xi[1] + 10.335051592047623854154335*xi[1]*xi[1]; } + if (i == 2) { return -0.82085073541610294151038849 - 2.0603042146829042381725404*xi[0] + 13.3333333333333333333333333*xi[0]*xi[0] + 4.76952995320244199345435038*xi[1] - 16.2668497564387155065927768*xi[0]*xi[1] - 2.3599221863231001082049006*xi[1]*xi[1]; } + if (i == 3) { return 1.58875703146323894373906129 - 18.3768395516778615218098664*xi[0] + 27.2402609034489487317212095*xi[0]*xi[0] - 0.049685580556241777044549183*xi[1] + 11.5470053837925152901829756*xi[0]*xi[1] - 2.3599221863231001082049006*xi[1]*xi[1]; } + if (i == 4) { return 1.89428270679801293841209206 - 12.5927127542327372982338893*xi[0] + 10.335051592047623854154335*xi[0]*xi[0] - 12.5927127542327372982338893*xi[1] + 47.3367698507619143749753366*xi[0]*xi[1] + 10.335051592047623854154335*xi[1]*xi[1]; } + if (i == 5) { return 1.58875703146323894373906129 - 0.0496855805562417770445491834*xi[0] - 2.3599221863231001082049006*xi[0]*xi[0] - 18.3768395516778615218098664*xi[1] + 11.5470053837925152901829756*xi[0]*xi[1] + 27.2402609034489487317212095*xi[1]*xi[1]; } + if (i == 6) { return -0.82085073541610294151038849 + 4.76952995320244199345435038*xi[0] - 2.3599221863231001082049006*xi[0]*xi[0] - 2.0603042146829042381725404*xi[1] - 16.2668497564387155065927768*xi[0]*xi[1] + 13.3333333333333333333333333*xi[1]*xi[1]; } + if (i == 7) { return -0.36337845538710050566746229 - 8.0773904298625104100747806*xi[0] + 10.335051592047623854154335*xi[0]*xi[0] + 26.6666666666666666666666667*xi[1] - 26.6666666666666666666666667*xi[0]*xi[1] - 26.6666666666666666666666667*xi[1]*xi[1]; } + if (i == 8) { return 10.4521783832343261536504044 - 36.1036822552200359416325527*xi[0] + 27.2402609034489487317212095*xi[0]*xi[0] - 24.6063624519837624284941263*xi[1] + 42.9335164231053821732594435*xi[0]*xi[1] + 13.3333333333333333333333333*xi[1]*xi[1]; } + if (i == 9) { return -15.2487113059642821093842488 + 29.6743371481683555022625317*xi[0] - 12.8897274573418279799331756*xi[0]*xi[0] + 71.485226280623708138992843*xi[1] - 73.884572681198956417470171*xi[0]*xi[1] - 60.994845223857128437536995*xi[1]*xi[1]; } + if (i == 10) { return 15.2487113059642821093842488 - 71.485226280623708138992843*xi[0] + 60.994845223857128437536995*xi[0]*xi[0] - 29.6743371481683555022625317*xi[1] + 73.884572681198956417470171*xi[0]*xi[1] + 12.8897274573418279799331756*xi[1]*xi[1]; } + if (i == 11) { return 6.2942286340599478208735085 - 54.399346400575248278477328*xi[0] + 48.1051177665153004576038195*xi[0]*xi[0] - 12.5884572681198956417470171*xi[1] + 96.210235533030600915207639*xi[0]*xi[1]; } + if (i == 12) { return -4.75833024919770240792840122 + 50.5044641670905487360811476*xi[0] - 60.994845223857128437536995*xi[0]*xi[0] + 6.2942286340599478208735085*xi[1] - 48.1051177665153004576038195*xi[0]*xi[1]; } + if (i == 13) { return 4.75833024919770240792840122 - 6.2942286340599478208735085*xi[0] - 50.5044641670905487360811476*xi[1] + 48.1051177665153004576038195*xi[0]*xi[1] + 60.994845223857128437536995*xi[1]*xi[1]; } + if (i == 14) { return -6.2942286340599478208735085 + 12.5884572681198956417470171*xi[0] + 54.399346400575248278477328*xi[1] - 96.210235533030600915207639*xi[0]*xi[1] - 48.1051177665153004576038195*xi[1]*xi[1]; } + } + + return {}; + } + + vec1 reoriented_shape_function_curl(vec2 xi, uint32_t i, int8_t transformation) const { + if (transformation == -1) { + return -shape_function_curl(xi, i); + } else { + return shape_function_curl(xi, i); + } + } + + vec<1> shape_function_derivative(vec2 xi, uint32_t i) const { + return shape_function_curl(xi, i); + } + + vec<1> shape_function_div(const double * xi, uint32_t i) const { + // expressions generated symbolically by mathematica + if (p == 1) { + return 0.0; + } + if (p == 2) { + if (i == 0) { return -1.732050807568877293527446342 - 2.366025403784438646763723171*xi[0] + 1.732050807568877293527446342*xi[1]; } + if (i == 1) { return 1.732050807568877293527446342 - 0.6339745962155613532362768292*xi[0] - 1.732050807568877293527446342*xi[1]; } + if (i == 2) { return 0.6339745962155613532362768292*xi[0] - 2.366025403784438646763723171*xi[1]; } + if (i == 3) { return 2.366025403784438646763723171*xi[0] - 0.6339745962155613532362768292*xi[1]; } + if (i == 4) { return -1.732050807568877293527446342 + 1.732050807568877293527446342*xi[0] + 0.6339745962155613532362768292*xi[1]; } + if (i == 5) { return 1.732050807568877293527446342 - 1.732050807568877293527446342*xi[0] + 2.366025403784438646763723171*xi[1]; } + if (i == 6) { return 6.*xi[0] - 3.*xi[1]; } + if (i == 7) { return -3.*xi[0] + 6.*xi[1]; } + } + if (p == 3) { + if (i == 0) { return -4.6243277820691389617264218 - 0.8278506011651871919239826*xi[0] + 10.7333791057763455433148609*xi[0]*xi[0] + 15.3577068878454845050412827*xi[1] + 6.9534637850578076991939381*xi[0]*xi[1] - 10.7333791057763455433148609*xi[1]*xi[1]; } + if (i == 1) { return 6.6666666666666666666666667 - 14.3032882112795661609992044*xi[0] - 6.6666666666666666666666667*xi[0]*xi[0] - 13.3333333333333333333333333*xi[1] + 18.5008591293571452604105008*xi[0]*xi[1] + 6.6666666666666666666666667*xi[1]*xi[1]; } + if (i == 2) { return -2.04233888459752770494024487 + 7.8631896200136306464506334*xi[0] - 4.0667124391096788766481942*xi[0]*xi[0] - 2.02437355451215117170794933*xi[1] - 7.846627759828216720769117*xi[0]*xi[1] + 4.0667124391096788766481942*xi[1]*xi[1]; } + if (i == 3) { return -0.0165618601854139256815163943*xi[0] + 2.8867513459481288225457439*xi[0]*xi[0] + 6.1256131838926205072699555*xi[1] - 14.8000915448860244199630551*xi[0]*xi[1] - 2.8867513459481288225457439*xi[1]*xi[1]; } + if (i == 4) { return -4.19757091807757909941129644*xi[0] + 11.8341924626904785937438341*xi[0]*xi[0] + 4.19757091807757909941129644*xi[1] + 0.e-25*xi[0]*xi[1] - 11.8341924626904785937438341*xi[1]*xi[1]; } + if (i == 5) { return -6.1256131838926205072699555*xi[0] + 2.8867513459481288225457439*xi[0]*xi[0] + 0.0165618601854139256815163945*xi[1] + 14.8000915448860244199630551*xi[0]*xi[1] - 2.8867513459481288225457439*xi[1]*xi[1]; } + if (i == 6) { return 2.04233888459752770494024487 + 2.02437355451215117170794934*xi[0] - 4.0667124391096788766481942*xi[0]*xi[0] - 7.8631896200136306464506334*xi[1] + 7.846627759828216720769117*xi[0]*xi[1] + 4.0667124391096788766481942*xi[1]*xi[1]; } + if (i == 7) { return -6.6666666666666666666666667 + 13.3333333333333333333333333*xi[0] - 6.6666666666666666666666667*xi[0]*xi[0] + 14.3032882112795661609992044*xi[1] - 18.5008591293571452604105008*xi[0]*xi[1] + 6.6666666666666666666666667*xi[1]*xi[1]; } + if (i == 8) { return 4.6243277820691389617264218 - 15.3577068878454845050412827*xi[0] + 10.7333791057763455433148609*xi[0]*xi[0] + 0.8278506011651871919239826*xi[1] - 6.9534637850578076991939381*xi[0]*xi[1] - 10.7333791057763455433148609*xi[1]*xi[1]; } + if (i == 9) { return 15.810889132455352636730311*xi[0] - 18.4711431702997391043675427*xi[0]*xi[0] - 17.9089653438086685770214805*xi[1] - 24.0525588832576502288019098*xi[0]*xi[1] + 18.4711431702997391043675427*xi[1]*xi[1]; } + if (i == 10) { return -17.9089653438086685770214805*xi[0] + 18.4711431702997391043675427*xi[0]*xi[0] + 15.810889132455352636730311*xi[1] - 24.0525588832576502288019098*xi[0]*xi[1] - 18.4711431702997391043675427*xi[1]*xi[1]; } + if (i == 11) { return -4.19615242270663188058233902*xi[0] + 24.0525588832576502288019098*xi[0]*xi[0] + 26.1506350946109661690930793*xi[1] - 24.0525588832576502288019098*xi[0]*xi[1] - 24.0525588832576502288019098*xi[1]*xi[1]; } + if (i == 12) { return 2.09807621135331594029116951*xi[0] - 12.0262794416288251144009549*xi[0]*xi[0] - 14.6865334794732115820381866*xi[1] + 30.4974226119285642187684976*xi[0]*xi[1] + 12.0262794416288251144009549*xi[1]*xi[1]; } + if (i == 13) { return -14.6865334794732115820381866*xi[0] + 12.0262794416288251144009549*xi[0]*xi[0] + 2.09807621135331594029116951*xi[1] + 30.4974226119285642187684976*xi[0]*xi[1] - 12.0262794416288251144009549*xi[1]*xi[1]; } + if (i == 14) { return 26.1506350946109661690930793*xi[0] - 24.0525588832576502288019098*xi[0]*xi[0] - 4.19615242270663188058233902*xi[1] - 24.0525588832576502288019098*xi[0]*xi[1] + 24.0525588832576502288019098*xi[1]*xi[1]; } + } + + return {}; + } + + vec2 interpolate(vec2 xi, const double * values) const { + vec2 interpolated_value{}; + for (int i = 0; i < num_nodes(); i++) { + interpolated_value += values[i] * shape_function(xi, i); + } + return interpolated_value; + } + + vec1 curl(vec2 xi, const double * values) const { + vec1 interpolated_curl = 0.0; + for (int i = 0; i < num_nodes(); i++) { + interpolated_curl += values[i] * shape_function_curl(xi, i); + } + return interpolated_curl; + } + + __host__ __device__ uint32_t batch_interpolation_scratch_space(nd::view xi) const { + return 0; + } + + nd::array< double, 3 > evaluate_shape_functions(nd::view xi) const { + uint32_t q = xi.shape[0]; + nd::array shape_fns({q, num_nodes(), dim}); + for (int i = 0; i < q; i++) { + vec2 xi_i = vec2{xi(i, 0), xi(i, 1)}; + for (int j = 0; j < num_nodes(); j++) { + vec2 phi_j = shape_function(xi_i, j); + shape_fns(i, j, 0) = phi_j[0]; + shape_fns(i, j, 1) = phi_j[1]; + } + } + return shape_fns; + } + + void interpolate(nd::view values_q, nd::view values_e, nd::view shape_fns, double * /*buffer*/) const { + int nnodes = num_nodes(); + int nqpts = values_q.shape[0]; + + for (int q = 0; q < nqpts; q++) { + value_type sum{}; + for (int i = 0; i < nnodes; i++) { + for (int j = 0; j < dim; j++) { + sum[j] += shape_fns(q, i, j) * values_e(i); + } + } + values_q(q) = sum; + } + } + + nd::array< double, 2 > evaluate_shape_function_curls(nd::view xi) const { + uint32_t q = xi.shape[0]; + nd::array shape_fns({q, num_nodes()}); + for (int i = 0; i < q; i++) { + vec2 xi_i = vec2{xi(i, 0), xi(i, 1)}; + for (int j = 0; j < num_nodes(); j++) { + shape_fns(i, j) = shape_function_curl(xi_i, j); + } + } + return shape_fns; + } + + void curl(nd::view values_q, nd::view values_e, nd::view shape_fn_curls, double * /*buffer*/) const { + int nnodes = num_nodes(); + int nqpts = values_q.shape[0]; + + for (int q = 0; q < nqpts; q++) { + derivative_type sum{}; + for (int i = 0; i < nnodes; i++) { + sum[0] += shape_fn_curls(q, i) * values_e(i); + } + values_q(q) = sum; + } + } + + nd::array< double, 3 > evaluate_weighted_shape_functions(nd::view xi, nd::view weights) const { + uint32_t q = xi.shape[0]; + nd::array shape_fns({q, num_nodes(), dim}); + for (int i = 0; i < q; i++) { + vec2 xi_i = vec2{xi(i, 0), xi(i, 1)}; + for (int j = 0; j < num_nodes(); j++) { + vec2 phi_j = shape_function(xi_i, j); + shape_fns(i, j, 0) = phi_j[0] * weights[i]; + shape_fns(i, j, 1) = phi_j[1] * weights[i]; + } + } + return shape_fns; + } + + __host__ __device__ void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fn, double * /*buffer*/) const { + int nnodes = num_nodes(); + int nqpts = source_q.shape[0]; + + for (int i = 0; i < nnodes; i++) { + double sum = 0.0; + for (int q = 0; q < nqpts; q++) { + for (int j = 0; j < dim; j++) { + sum += shape_fn(q, i, j) * source_q(q)[j]; + } + } + residual_e(i) = sum; + } + } + + nd::array< double, 2 > evaluate_weighted_shape_function_curls(nd::view xi, nd::view weights) const { + uint32_t q = xi.shape[0]; + nd::array shape_fns({q, num_nodes()}); + for (int i = 0; i < q; i++) { + vec2 xi_i = vec2{xi(i, 0), xi(i, 1)}; + for (int j = 0; j < num_nodes(); j++) { + shape_fns(i, j) = shape_function_curl(xi_i, j) * weights[i]; + } + } + return shape_fns; + } + + __host__ __device__ void integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fn, double * /*buffer*/) const { + int nnodes = num_nodes(); + int nqpts = flux_q.shape[0]; + + for (int i = 0; i < nnodes; i++) { + double sum = 0.0; + for (int q = 0; q < nqpts; q++) { + sum += shape_fn(q, i) * flux_q(q); + } + residual_e(i) = sum; + } + } + + #ifdef __CUDACC__ + __device__ void cuda_integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fn_curl, double * /*buffer*/) const { + int nnodes = num_nodes(); + int nqpts = flux_q.shape[0]; + + for (int i = threadIdx.x; i < nnodes; i += blockDim.x) { + double sum = 0.0; + for (int q = 0; q < nqpts; q++) { + sum += shape_fn_curl(q, i) * flux_q(q); + } + residual_e(i) = sum; + } + } + #endif + + uint32_t p; + +}; +// clang-format on + +} // namespace refactor diff --git a/src/serac/numerics/refactor/elements/hcurl_vertex.hpp b/src/serac/numerics/refactor/elements/hcurl_vertex.hpp new file mode 100644 index 0000000000..17e37c7f18 --- /dev/null +++ b/src/serac/numerics/refactor/elements/hcurl_vertex.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include "refactor/interpolation.hpp" + +namespace refactor { + +template <> +struct FiniteElement < Geometry::Vertex, Family::Hcurl >{ + + __host__ __device__ uint32_t num_nodes() const { return 0; } + void nodes(nd::view xi) {} + void directions(nd::view xi) {} + + __host__ __device__ uint32_t num_interior_nodes() { return 0; } + void interior_nodes(nd::view xi) {} + void interior_directions(nd::view xi) {} + + __host__ __device__ void indices(const GeometryInfo & offsets, const Connection * edge, uint32_t * ids) {} + + uint32_t p; + +}; + +} // namespace refactor diff --git a/src/serac/numerics/refactor/finite_element.hpp b/src/serac/numerics/refactor/finite_element.hpp new file mode 100644 index 0000000000..b5a11ad7fa --- /dev/null +++ b/src/serac/numerics/refactor/finite_element.hpp @@ -0,0 +1,119 @@ +#pragma once + +#include "refactor/geometry.hpp" +#include "refactor/quadrature.hpp" + +namespace refactor { + +enum class Family { + H1, + Hcurl, + Hdiv, + DG +}; + +__host__ __device__ constexpr bool is_scalar_valued(Family f) { + return (f == Family::H1); +} + +__host__ __device__ constexpr bool is_vector_valued(Family f) { + return (f == Family::Hcurl); +} + +struct FunctionSpace { + Family family; + uint32_t degree; + uint32_t components; + FunctionSpace() : family{}, degree{}, components{} {} + FunctionSpace(Family f, uint32_t d = 2, uint32_t c = 1) : family{f}, degree{d}, components{c}{} + + bool operator==(const FunctionSpace & other) const { + return (components == other.components) && + (degree == other.degree) && + (family == other.family); + } +}; + +GeometryInfo nodes_per_geom(FunctionSpace space); +GeometryInfo interior_nodes_per_geom(FunctionSpace space); + +GeometryInfo dofs_per_geom(FunctionSpace space); +GeometryInfo interior_dofs_per_geom(FunctionSpace space); + +enum class TransformationType { + PhysicalToParent, + TransposePhysicalToParent, +}; + +template < Geometry g, Family f > +struct FiniteElement; + +template < Geometry geom, Family family > +auto shape_function_derivatives(FiniteElement< geom, family > element, + const nd::view xi) { + if constexpr (family == Family::H1) { + return element.evaluate_shape_function_gradients(xi); + } + + if constexpr (family == Family::Hcurl) { + return element.evaluate_shape_function_curls(xi); + } +} + +template < Geometry geom, Family family > +auto weighted_shape_function_derivatives(FiniteElement< geom, family > element, + const nd::view xi, + const nd::view weights) { + if constexpr (family == Family::H1) { + return element.evaluate_weighted_shape_function_gradients(xi, weights); + } + + if constexpr (family == Family::Hcurl) { + return element.evaluate_weighted_shape_function_curls(xi, weights); + } +} + +__host__ __device__ constexpr fm::mat2 face_transformation(int8_t id) { + constexpr fm::mat2 matrices[5] = { + {{{0, 1}, {1, 0}}}, + {{{-1, 0}, {-1, 1}}}, + {{{1, -1}, {0, -1}}}, + {{{-1, -1}, {0, 1}}}, + {{{1, 0}, {-1, -1}}} + }; + + return matrices[id-1]; +} + +__host__ __device__ constexpr int8_t face_transformation_id(TransformationType type, int orientation) { + if (type == TransformationType::PhysicalToParent) { + constexpr int8_t LUT[3] = {1, 2, 3}; + return LUT[orientation]; + } else { + constexpr int8_t LUT[3] = {1, 4, 5}; + return LUT[orientation]; + } +} + +} + +#include "refactor/elements/h1_vertex.hpp" +#include "refactor/elements/h1_edge.hpp" +#include "refactor/elements/h1_triangle.hpp" +#include "refactor/elements/h1_quadrilateral.hpp" +#include "refactor/elements/h1_tetrahedron.hpp" +#include "refactor/elements/h1_hexahedron.hpp" + +#include "refactor/elements/hcurl_vertex.hpp" +#include "refactor/elements/hcurl_edge.hpp" +#include "refactor/elements/hcurl_triangle.hpp" +#include "refactor/elements/hcurl_quadrilateral.hpp" +#include "refactor/elements/hcurl_tetrahedron.hpp" +#include "refactor/elements/hcurl_hexahedron.hpp" + +#include "refactor/elements/dg_vertex.hpp" +#include "refactor/elements/dg_edge.hpp" +#include "refactor/elements/dg_triangle.hpp" +#include "refactor/elements/dg_quadrilateral.hpp" +#include "refactor/elements/dg_tetrahedron.hpp" +#include "refactor/elements/dg_hexahedron.hpp" diff --git a/src/serac/numerics/refactor/integrate.hpp b/src/serac/numerics/refactor/integrate.hpp new file mode 100644 index 0000000000..eaa9098158 --- /dev/null +++ b/src/serac/numerics/refactor/integrate.hpp @@ -0,0 +1 @@ +#include "serac/physics/state/finite_element_state.hpp" diff --git a/src/serac/numerics/refactor/interpolate.hpp b/src/serac/numerics/refactor/interpolate.hpp new file mode 100644 index 0000000000..e69de29bb2 From 30a8ade4a4a8f3cdc8927078396831e4429fd448 Mon Sep 17 00:00:00 2001 From: Sam Mish Date: Wed, 11 Dec 2024 13:12:10 -0800 Subject: [PATCH 02/15] removing code that won't be needed for serac --- .../refactor/elements/h1_hexahedron.hpp | 161 -------- .../refactor/elements/h1_quadrilateral.hpp | 94 ----- .../refactor/elements/h1_tetrahedron.hpp | 121 ------ .../refactor/elements/h1_triangle.hpp | 86 ----- .../numerics/refactor/elements/h1_vertex.hpp | 1 - .../numerics/refactor/elements/hcurl_edge.hpp | 57 --- .../refactor/elements/hcurl_hexahedron.hpp | 157 -------- .../refactor/elements/hcurl_quadrilateral.hpp | 184 ---------- .../refactor/elements/hcurl_tetrahedron.hpp | 343 ------------------ .../refactor/elements/hcurl_triangle.hpp | 169 --------- .../refactor/elements/hcurl_vertex.hpp | 10 - 11 files changed, 1383 deletions(-) diff --git a/src/serac/numerics/refactor/elements/h1_hexahedron.hpp b/src/serac/numerics/refactor/elements/h1_hexahedron.hpp index 8d11b522f5..520183bf9f 100644 --- a/src/serac/numerics/refactor/elements/h1_hexahedron.hpp +++ b/src/serac/numerics/refactor/elements/h1_hexahedron.hpp @@ -15,167 +15,6 @@ struct FiniteElement { __host__ __device__ constexpr uint32_t num_nodes() const { return (p + 1) * (p + 1) * (p + 1); } - void nodes(nd::view< double, 2 > xi) const { - double lobatto_nodes[4]; - GaussLobattoNodes(p + 1, lobatto_nodes); - - uint32_t count = 0; - for (uint32_t k = 0; k < (p+1); k++) { - for (uint32_t j = 0; j < (p+1); j++) { - for (uint32_t i = 0; i < (p+1); i++) { - xi(count, 0) = lobatto_nodes[i]; - xi(count, 1) = lobatto_nodes[j]; - xi(count, 2) = lobatto_nodes[k]; - count++; - } - } - } - } - - __host__ __device__ uint32_t num_interior_nodes() const { return (p == 1) ? 0 : (p - 1) * (p - 1) * (p - 1); } - - void interior_nodes(nd::view< double, 2 > xi) const { - if (p > 1) { - double lobatto_nodes[4]; - GaussLobattoNodes(p + 1, lobatto_nodes); - - uint32_t count = 0; - for (uint32_t k = 1; k < p; k++) { - for (uint32_t j = 1; j < p; j++) { - for (uint32_t i = 1; i < p; i++) { - xi(count, 0) = lobatto_nodes[i]; - xi(count, 1) = lobatto_nodes[j]; - xi(count, 2) = lobatto_nodes[k]; - count++; - } - } - } - - } - } - - __host__ __device__ inline void reorient(Connection c, uint32_t & i0, uint32_t & i1, uint32_t & i2, uint32_t & i3) const { - - uint8_t o = c.orientation(); - - uint32_t copy[4] = {i0, i1, i2, i3}; - - if (c.sign() == Sign::Negative) { - if (o == 0) { i0 = copy[0]; i1 = copy[2]; i2 = copy[1]; i3 = copy[3]; } // ok - if (o == 1) { i0 = copy[1]; i1 = copy[0]; i2 = copy[3]; i3 = copy[2]; } // ok - if (o == 2) { i0 = copy[3]; i1 = copy[1]; i2 = copy[2]; i3 = copy[0]; } // ok - if (o == 3) { i0 = copy[2]; i1 = copy[3]; i2 = copy[0]; i3 = copy[1]; } // ok - } else { - if (o == 0) { /* nothing to do */ } - if (o == 1) { /* should never occur */ } - if (o == 2) { /* should never occur */ } - if (o == 3) { /* should never occur */ } - } - } - - __host__ __device__ void indices(const GeometryInfo & offsets, - const Connection * connections, - uint32_t * ids) const { - - const Connection * vertex = connections; - const Connection * edge = connections + Hexahedron::edge_offset; - const Connection * quad = connections + Hexahedron::quad_offset; - const Connection * cell = connections + Hexahedron::cell_offset; - - if (p == 1) { - ids[0] = offsets.vert + vertex[0].index; - ids[1] = offsets.vert + vertex[1].index; - ids[2] = offsets.vert + vertex[3].index; - ids[3] = offsets.vert + vertex[2].index; - ids[4] = offsets.vert + vertex[4].index; - ids[5] = offsets.vert + vertex[5].index; - ids[6] = offsets.vert + vertex[7].index; - ids[7] = offsets.vert + vertex[6].index; - return; - } - - if (p == 2) { - #define VERTEX_ID(i) offsets.vert + vertex[i].index - #define EDGE_ID(i) offsets.edge + edge[i].index - #define QUAD_ID(i) offsets.quad + quad[i].index - #define HEX_ID offsets.hex + cell->index - - ids[ 6] = VERTEX_ID(3); ids[ 7] = EDGE_ID(2); ids[ 8] = VERTEX_ID(2); - ids[ 3] = EDGE_ID(3); ids[ 4] = QUAD_ID(0); ids[ 5] = EDGE_ID(1); - ids[ 0] = VERTEX_ID(0); ids[ 1] = EDGE_ID(0); ids[ 2] = VERTEX_ID(1); - - ids[15] = EDGE_ID(7); ids[16] = QUAD_ID(3); ids[17] = EDGE_ID(6); - ids[12] = QUAD_ID(4); ids[13] = HEX_ID; ids[14] = QUAD_ID(2); - ids[ 9] = EDGE_ID(4); ids[10] = QUAD_ID(1); ids[11] = EDGE_ID(5); - - ids[24] = VERTEX_ID(7); ids[25] = EDGE_ID(10); ids[26] = VERTEX_ID(6); - ids[21] = EDGE_ID(11); ids[22] = QUAD_ID(5); ids[23] = EDGE_ID(9); - ids[18] = VERTEX_ID(4); ids[19] = EDGE_ID(8); ids[20] = VERTEX_ID(5); - - #undef VERTEX_ID - #undef EDGE_ID - #undef QUAD_ID - #undef HEX_ID - return; - } - - if (p == 3) { - #define VERTEX_ID(i) offsets.vert + vertex[i].index - #define EDGE_ID(i, j) offsets.edge + 2 * edge[i].index + j - #define QUAD_ID(i, j) offsets.quad + 4 * quad[i].index + j - #define HEX_ID(j) offsets.hex + 8 * cell->index + j - - ids[12] = VERTEX_ID(3); ids[13] = EDGE_ID(2,0); ids[14] = EDGE_ID(2,1); ids[15] = VERTEX_ID(2); - ids[ 8] = EDGE_ID(3,1); ids[ 9] = QUAD_ID(0,3); ids[10] = QUAD_ID(0,2); ids[11] = EDGE_ID(1,1); - ids[ 4] = EDGE_ID(3,0); ids[ 5] = QUAD_ID(0,1); ids[ 6] = QUAD_ID(0,0); ids[ 7] = EDGE_ID(1,0); - ids[ 0] = VERTEX_ID(0); ids[ 1] = EDGE_ID(0,0); ids[ 2] = EDGE_ID(0,1); ids[ 3] = VERTEX_ID(1); - - ids[28] = EDGE_ID(7,0); ids[29] = QUAD_ID(3,1); ids[30] = QUAD_ID(3,0); ids[31] = EDGE_ID(6,0); - ids[24] = QUAD_ID(4,0); ids[25] = HEX_ID(2); ids[26] = HEX_ID(3); ids[27] = QUAD_ID(2,1); - ids[20] = QUAD_ID(4,1); ids[21] = HEX_ID(0); ids[22] = HEX_ID(1); ids[23] = QUAD_ID(2,0); - ids[16] = EDGE_ID(4,0); ids[17] = QUAD_ID(1,0); ids[18] = QUAD_ID(1,1); ids[19] = EDGE_ID(5,0); - - ids[44] = EDGE_ID(7,1); ids[45] = QUAD_ID(3,3); ids[46] = QUAD_ID(3,2); ids[47] = EDGE_ID(6,1); - ids[40] = QUAD_ID(4,2); ids[41] = HEX_ID(6); ids[42] = HEX_ID(7); ids[43] = QUAD_ID(2,3); - ids[36] = QUAD_ID(4,3); ids[37] = HEX_ID(4); ids[38] = HEX_ID(5); ids[39] = QUAD_ID(2,2); - ids[32] = EDGE_ID(4,1); ids[33] = QUAD_ID(1,2); ids[34] = QUAD_ID(1,3); ids[35] = EDGE_ID(5,1); - - ids[60] = VERTEX_ID(7); ids[61] = EDGE_ID(10,0); ids[62] = EDGE_ID(10,1); ids[63] = VERTEX_ID(6); - ids[56] = EDGE_ID(11,1); ids[57] = QUAD_ID(5,2); ids[58] = QUAD_ID(5,3); ids[59] = EDGE_ID(9,1); - ids[52] = EDGE_ID(11,0); ids[53] = QUAD_ID(5,0); ids[54] = QUAD_ID(5,1); ids[55] = EDGE_ID(9,0); - ids[48] = VERTEX_ID(4); ids[49] = EDGE_ID(8,0); ids[50] = EDGE_ID(8,1); ids[51] = VERTEX_ID(5); - - if (edge[ 0].sign() == Sign::Negative) { fm::swap(ids[ 1], ids[ 2]); } - if (edge[ 1].sign() == Sign::Negative) { fm::swap(ids[ 7], ids[11]); } - if (edge[ 2].sign() == Sign::Negative) { fm::swap(ids[14], ids[13]); } - if (edge[ 3].sign() == Sign::Negative) { fm::swap(ids[ 8], ids[ 4]); } - if (edge[ 4].sign() == Sign::Negative) { fm::swap(ids[16], ids[32]); } - if (edge[ 5].sign() == Sign::Negative) { fm::swap(ids[19], ids[35]); } - if (edge[ 6].sign() == Sign::Negative) { fm::swap(ids[31], ids[47]); } - if (edge[ 7].sign() == Sign::Negative) { fm::swap(ids[28], ids[44]); } - if (edge[ 8].sign() == Sign::Negative) { fm::swap(ids[49], ids[50]); } - if (edge[ 9].sign() == Sign::Negative) { fm::swap(ids[55], ids[59]); } - if (edge[10].sign() == Sign::Negative) { fm::swap(ids[62], ids[61]); } - if (edge[11].sign() == Sign::Negative) { fm::swap(ids[56], ids[52]); } - - reorient(quad[0], ids[ 9], ids[10], ids[ 5], ids[ 6]); - reorient(quad[1], ids[17], ids[18], ids[33], ids[34]); - reorient(quad[2], ids[23], ids[27], ids[39], ids[43]); - reorient(quad[3], ids[30], ids[29], ids[46], ids[45]); - reorient(quad[4], ids[24], ids[20], ids[40], ids[36]); - reorient(quad[5], ids[53], ids[54], ids[57], ids[58]); - - #undef VERTEX_ID - #undef EDGE_ID - #undef QUAD_ID - #undef HEX_ID - - return; - - } - - } - constexpr double phi_1D(double xi, uint32_t i) const { return GaussLobattoInterpolation(xi, p + 1, i); } diff --git a/src/serac/numerics/refactor/elements/h1_quadrilateral.hpp b/src/serac/numerics/refactor/elements/h1_quadrilateral.hpp index ba9ce5b724..52085cd618 100644 --- a/src/serac/numerics/refactor/elements/h1_quadrilateral.hpp +++ b/src/serac/numerics/refactor/elements/h1_quadrilateral.hpp @@ -16,100 +16,6 @@ struct FiniteElement { __host__ __device__ constexpr uint32_t num_nodes() const { return (p + 1) * (p + 1); } - void nodes(nd::view< double, 2 > xi) const { - double lobatto_nodes[4]; - GaussLobattoNodes(p + 1, lobatto_nodes); - - uint32_t count = 0; - for (uint32_t i = 0; i < (p+1); i++) { - for (uint32_t j = 0; j < (p+1); j++) { - xi(count, 0) = lobatto_nodes[j]; - xi(count, 1) = lobatto_nodes[i]; - count++; - } - } - } - - __host__ __device__ uint32_t num_interior_nodes() const { return (p < 2) ? 0 : (p - 1) * (p - 1); } - - void interior_nodes(nd::view< double, 2 > xi) const { - if (p > 1) { - double lobatto_nodes[4]; - GaussLobattoNodes(p + 1, lobatto_nodes); - - uint32_t count = 0; - for (uint32_t i = 1; i < p; i++) { - for (uint32_t j = 1; j < p; j++) { - xi(count, 0) = lobatto_nodes[j]; - xi(count, 1) = lobatto_nodes[i]; - count++; - } - } - } - } - - __host__ __device__ void indices(const GeometryInfo & offsets, const Connection * quad, uint32_t * indices) const { - - const Connection * vertex = quad; - const Connection * edge = quad + 4; - const Connection cell = *(quad + 8); - - if (p == 1) { - // 2 3 - // 0 1 - indices[0] = offsets.vert + vertex[0].index; - indices[1] = offsets.vert + vertex[1].index; - indices[2] = offsets.vert + vertex[3].index; - indices[3] = offsets.vert + vertex[2].index; - return; - } - - if (p == 2) { - // 6 7 8 - // 3 4 5 - // 0 1 2 - indices[0] = offsets.vert + quad[0].index; - indices[1] = offsets.edge + quad[4].index; - indices[2] = offsets.vert + quad[1].index; - indices[3] = offsets.edge + quad[7].index; - indices[4] = offsets.quad + quad[8].index; - indices[5] = offsets.edge + quad[5].index; - indices[6] = offsets.vert + quad[3].index; - indices[7] = offsets.edge + quad[6].index; - indices[8] = offsets.vert + quad[2].index; - } - - if (p == 3) { - // 12 13 14 15 - // 8 9 10 11 - // 4 5 6 7 - // 0 1 2 3 - indices[ 0] = offsets.vert + vertex[0].index; - indices[ 1] = offsets.edge + 2 * edge[0].index + 0; - indices[ 2] = offsets.edge + 2 * edge[0].index + 1; - indices[ 3] = offsets.vert + vertex[1].index; - indices[ 4] = offsets.edge + 2 * edge[3].index + 1; - indices[ 5] = offsets.quad + 4 * cell.index + 0; - indices[ 6] = offsets.quad + 4 * cell.index + 1; - indices[ 7] = offsets.edge + 2 * edge[1].index + 0; - indices[ 8] = offsets.edge + 2 * edge[3].index + 0; - indices[ 9] = offsets.quad + 4 * cell .index + 2; - indices[10] = offsets.quad + 4 * cell .index + 3; - indices[11] = offsets.edge + 2 * edge[1].index + 1; - indices[12] = offsets.vert + vertex[3].index; - indices[13] = offsets.edge + 2 * edge[2].index + 1; - indices[14] = offsets.edge + 2 * edge[2].index + 0; - indices[15] = offsets.vert + vertex[2].index; - - if (flip(edge[0])) { fm::swap(indices[ 1], indices[ 2]); } - if (flip(edge[1])) { fm::swap(indices[ 7], indices[11]); } - if (flip(edge[2])) { fm::swap(indices[14], indices[13]); } - if (flip(edge[3])) { fm::swap(indices[ 8], indices[ 4]); } - return; - } - - } - constexpr double phi_1D(double xi, uint32_t i) const { return GaussLobattoInterpolation(xi, p + 1, i); } diff --git a/src/serac/numerics/refactor/elements/h1_tetrahedron.hpp b/src/serac/numerics/refactor/elements/h1_tetrahedron.hpp index 8fef02fb9c..bf1fa66ef4 100644 --- a/src/serac/numerics/refactor/elements/h1_tetrahedron.hpp +++ b/src/serac/numerics/refactor/elements/h1_tetrahedron.hpp @@ -17,127 +17,6 @@ struct FiniteElement { __host__ __device__ constexpr uint32_t num_nodes() const { return Tetrahedron::number(p + 1); } - void nodes(nd::view< double, 2 > xi) const { - if (p == 1) { - xi(0, 0) = 0.0; xi(0, 1) = 0.0; xi(0, 2) = 0.0; - xi(1, 0) = 1.0; xi(1, 1) = 0.0; xi(1, 2) = 0.0; - xi(2, 0) = 0.0; xi(2, 1) = 1.0; xi(2, 2) = 0.0; - - xi(3, 0) = 0.0; xi(3, 1) = 0.0; xi(3, 2) = 1.0; - } - if (p == 2) { - xi(0, 0) = 0.0; xi(0, 1) = 0.0; xi(0, 2) = 0.0; - xi(1, 0) = 0.5; xi(1, 1) = 0.0; xi(1, 2) = 0.0; - xi(2, 0) = 1.0; xi(2, 1) = 0.0; xi(2, 2) = 0.0; - xi(3, 0) = 0.0; xi(3, 1) = 0.5; xi(3, 2) = 0.0; - xi(4, 0) = 0.5; xi(4, 1) = 0.5; xi(4, 2) = 0.0; - xi(5, 0) = 0.0; xi(5, 1) = 1.0; xi(5, 2) = 0.0; - - xi(6, 0) = 0.0; xi(6, 1) = 0.0; xi(6, 2) = 0.5; - xi(7, 0) = 0.5; xi(7, 1) = 0.0; xi(7, 2) = 0.5; - xi(8, 0) = 0.0; xi(8, 1) = 0.5; xi(8, 2) = 0.5; - - xi(9, 0) = 0.0; xi(9, 1) = 0.0; xi(9, 2) = 1.0; - } - if (p == 3) { - constexpr double s1 = 0.2763932022500210; - constexpr double s2 = 0.7236067977499790; - constexpr double s3 = 0.3333333333333333; - - xi( 0, 0) = 0.0; xi( 0, 1) = 0.0; xi( 0, 2) = 0.0; - xi( 1, 0) = s1; xi( 1, 1) = 0.0; xi( 1, 2) = 0.0; - xi( 2, 0) = s2; xi( 2, 1) = 0.0; xi( 2, 2) = 0.0; - xi( 3, 0) = 1.0; xi( 3, 1) = 0.0; xi( 3, 2) = 0.0; - xi( 4, 0) = 0.0; xi( 4, 1) = s1; xi( 4, 2) = 0.0; - xi( 5, 0) = s3; xi( 5, 1) = s3; xi( 5, 2) = 0.0; - xi( 6, 0) = s2; xi( 6, 1) = s1; xi( 6, 2) = 0.0; - xi( 7, 0) = 0.0; xi( 7, 1) = s2; xi( 7, 2) = 0.0; - xi( 8, 0) = s1; xi( 8, 1) = s2; xi( 8, 2) = 0.0; - xi( 9, 0) = 0.0; xi( 9, 1) = 1.0; xi( 9, 2) = 0.0; - - xi(10, 0) = 0.0; xi(10, 1) = 0.0; xi(10, 2) = s1; - xi(11, 0) = s3; xi(11, 1) = 0.0; xi(11, 2) = s3; - xi(12, 0) = s2; xi(12, 1) = 0.0; xi(12, 2) = s1; - xi(13, 0) = 0.0; xi(13, 1) = s3; xi(13, 2) = s3; - xi(14, 0) = s3; xi(14, 1) = s3; xi(14, 2) = s3; - xi(15, 0) = 0.0; xi(15, 1) = s2; xi(15, 2) = s1; - - xi(16, 0) = 0.0; xi(16, 1) = 0.0; xi(16, 2) = s2; - xi(17, 0) = s1; xi(17, 1) = 0.0; xi(17, 2) = s2; - xi(18, 0) = 0.0; xi(18, 1) = s1; xi(18, 2) = s2; - - xi(19, 0) = 0.0; xi(19, 1) = 0.0; xi(19, 2) = 1.0; - } - } - - // interior nodes only show up for tets when p >= 4, but this only supports p <= 3 - __host__ __device__ uint32_t num_interior_nodes() const { return 0; } - - void interior_nodes(nd::view< double, 2 > /* xi */) const {} - - __host__ __device__ void indices(const GeometryInfo & offsets, const Connection * tet, uint32_t * indices) const { - - const Connection * vertex = tet; - const Connection * edge = tet + Tetrahedron::edge_offset; - const Connection * face = tet + Tetrahedron::tri_offset; - - if (p == 1) { - indices[0] = offsets.vert + vertex[0].index; - indices[1] = offsets.vert + vertex[1].index; - indices[2] = offsets.vert + vertex[2].index; - indices[3] = offsets.vert + vertex[3].index; - return; - } - - if (p == 2) { - indices[0] = offsets.vert + vertex[0].index; - indices[1] = offsets.edge + edge[0].index; - indices[2] = offsets.vert + vertex[1].index; - indices[3] = offsets.edge + edge[2].index; - indices[4] = offsets.edge + edge[1].index; - indices[5] = offsets.vert + vertex[2].index; - indices[6] = offsets.edge + edge[3].index; - indices[7] = offsets.edge + edge[4].index; - indices[8] = offsets.edge + edge[5].index; - indices[9] = offsets.vert + vertex[3].index; - } - - if (p == 3) { - indices[ 0] = offsets.vert + vertex[0].index; - indices[ 1] = offsets.edge + 2 * edge[0].index + 0; - indices[ 2] = offsets.edge + 2 * edge[0].index + 1; - indices[ 3] = offsets.vert + vertex[1].index; - indices[ 4] = offsets.edge + 2 * edge[2].index + 1; - indices[ 5] = offsets.tri + face[0].index + 0; - indices[ 6] = offsets.edge + 2 * edge[1].index + 0; - indices[ 7] = offsets.edge + 2 * edge[2].index + 0; - indices[ 8] = offsets.edge + 2 * edge[1].index + 1; - indices[ 9] = offsets.vert + vertex[2].index + 0; - - indices[10] = offsets.edge + 2 * edge[3].index + 0; - indices[11] = offsets.tri + face[1].index; - indices[12] = offsets.edge + 2 * edge[4].index + 0; - indices[13] = offsets.tri + face[3].index; - indices[14] = offsets.tri + face[2].index; - indices[15] = offsets.edge + 2 * edge[5].index + 0; - - indices[16] = offsets.edge + 2 * edge[3].index + 1; - indices[17] = offsets.edge + 2 * edge[4].index + 1; - indices[18] = offsets.edge + 2 * edge[5].index + 1; - - indices[19] = offsets.vert + vertex[3].index; - - if (flip(edge[0])) { fm::swap(indices[ 1], indices[ 2]); } - if (flip(edge[1])) { fm::swap(indices[ 6], indices[ 8]); } - if (flip(edge[2])) { fm::swap(indices[ 7], indices[ 4]); } - if (flip(edge[3])) { fm::swap(indices[10], indices[16]); } - if (flip(edge[4])) { fm::swap(indices[12], indices[17]); } - if (flip(edge[5])) { fm::swap(indices[15], indices[18]); } - return; - } - - } - constexpr double shape_function(vec3 xi, uint32_t i) const { // expressions generated symbolically by mathematica if (p == 1) { diff --git a/src/serac/numerics/refactor/elements/h1_triangle.hpp b/src/serac/numerics/refactor/elements/h1_triangle.hpp index 0e0a622cd4..f230b83702 100644 --- a/src/serac/numerics/refactor/elements/h1_triangle.hpp +++ b/src/serac/numerics/refactor/elements/h1_triangle.hpp @@ -18,92 +18,6 @@ struct FiniteElement { __host__ __device__ constexpr uint32_t num_nodes() const { return Triangle::number(p + 1); } - void nodes(nd::view xi) const { - if (p == 1) { - xi(0,0) = 0.0; xi(0,1) = 0.0; - xi(1,0) = 1.0; xi(1,1) = 0.0; - xi(2,0) = 0.0; xi(2,1) = 1.0; - } - if (p == 2) { - xi(0,0) = 0.0; xi(0,1) = 0.0; - xi(1,0) = 0.5; xi(1,1) = 0.0; - xi(2,0) = 1.0; xi(2,1) = 0.0; - xi(3,0) = 0.0; xi(3,1) = 0.5; - xi(4,0) = 0.5; xi(4,1) = 0.5; - xi(5,0) = 0.0; xi(5,1) = 1.0; - } - if (p == 3) { - xi(0,0) = 0.0; xi(0,1) = 0.0; - xi(1,0) = 0.2763932022500210; xi(1,1) = 0.0; - xi(2,0) = 0.7236067977499790; xi(2,1) = 0.0; - xi(3,0) = 1.0; xi(3,1) = 0.0; - xi(4,0) = 0.0; xi(4,1) = 0.2763932022500210; - xi(5,0) = 0.3333333333333333; xi(5,1) = 0.3333333333333333; - xi(6,0) = 0.7236067977499790; xi(6,1) = 0.2763932022500210; - xi(7,0) = 0.0; xi(7,1) = 0.7236067977499790; - xi(8,0) = 0.2763932022500210; xi(8,1) = 0.7236067977499790; - xi(9,0) = 0.0; xi(9,1) = 1.0; - } - } - - __host__ __device__ uint32_t num_interior_nodes() const { return (p > 2) ? Triangle::number(p - 2) : 0; } - - void interior_nodes(nd::view xi) const { - if (p == 3) { - xi(0,0) = 0.3333333333333333; xi(0,1) = 0.3333333333333333; - } - } - - __host__ __device__ void indices(const GeometryInfo & offsets, const Connection * tri, uint32_t * indices) const { - - const Connection * vertex = tri; - const Connection * edge = tri + Triangle::edge_offset; - const Connection cell = *(tri + Triangle::cell_offset); - - if (p == 1) { - // 2 - // 0 1 - indices[0] = offsets.vert + vertex[0].index; - indices[1] = offsets.vert + vertex[1].index; - indices[2] = offsets.vert + vertex[2].index; - return; - } - - if (p == 2) { - // 5 - // 3 4 - // 0 1 2 - indices[0] = offsets.vert + vertex[0].index; - indices[1] = offsets.edge + edge[0].index; - indices[2] = offsets.vert + vertex[1].index; - indices[3] = offsets.edge + edge[2].index; - indices[4] = offsets.edge + edge[1].index; - indices[5] = offsets.vert + vertex[2].index; - } - - if (p == 3) { - // 9 - // 7 8 - // 4 5 6 - // 0 1 2 3 - indices[0] = offsets.vert + vertex[0].index; - indices[1] = offsets.edge + 2 * edge[0].index + 0; - indices[2] = offsets.edge + 2 * edge[0].index + 1; - indices[3] = offsets.vert + vertex[1].index; - indices[4] = offsets.edge + 2 * edge[2].index + 1; - indices[5] = offsets.tri + cell.index; - indices[6] = offsets.edge + 2 * edge[1].index + 0; - indices[7] = offsets.edge + 2 * edge[2].index + 0; - indices[8] = offsets.edge + 2 * edge[1].index + 1; - indices[9] = offsets.vert + vertex[2].index; - - if (flip(edge[0])) { fm::swap(indices[1], indices[2]); } - if (flip(edge[1])) { fm::swap(indices[6], indices[8]); } - if (flip(edge[2])) { fm::swap(indices[7], indices[4]); } - return; - } - } - constexpr double shape_function(vec2 xi, uint32_t i) const { if (p == 1) { if (i == 0) return 1.0 - xi[0] - xi[1]; diff --git a/src/serac/numerics/refactor/elements/h1_vertex.hpp b/src/serac/numerics/refactor/elements/h1_vertex.hpp index 7dc9655607..24c2103611 100644 --- a/src/serac/numerics/refactor/elements/h1_vertex.hpp +++ b/src/serac/numerics/refactor/elements/h1_vertex.hpp @@ -10,7 +10,6 @@ struct FiniteElement { using flux_type = double; __host__ __device__ uint32_t num_nodes() const { return 1; } - __host__ __device__ uint32_t num_interior_nodes() const { return 1; } uint32_t p; }; diff --git a/src/serac/numerics/refactor/elements/hcurl_edge.hpp b/src/serac/numerics/refactor/elements/hcurl_edge.hpp index 27d5503a23..a8d42f7e1f 100644 --- a/src/serac/numerics/refactor/elements/hcurl_edge.hpp +++ b/src/serac/numerics/refactor/elements/hcurl_edge.hpp @@ -14,61 +14,6 @@ struct FiniteElement < Geometry::Edge, Family::Hcurl >{ __host__ __device__ uint32_t num_nodes() const { return p; } - void nodes(nd::view< double, 2 > xi) const { - if (p == 1) { - xi(0, 0) = GaussLegendreNode01<1, 0>(); - } - - if (p == 2) { - xi(0, 0) = GaussLegendreNode01<2, 0>(); - xi(1, 0) = GaussLegendreNode01<2, 1>(); - } - - if (p == 3) { - xi(0, 0) = GaussLegendreNode01<3, 0>(); - xi(1, 0) = GaussLegendreNode01<3, 1>(); - xi(2, 0) = GaussLegendreNode01<3, 2>(); - } - } - - void directions(nd::view< double, 2 > xi) { - for (int i = 0; i < p; i++) { xi(i, 0) = 1.0; } - } - - __host__ __device__ uint32_t num_interior_nodes() { return p; } - - void interior_nodes(nd::view< double, 2 > xi) { - nodes(xi); // all the nodes in these elements are interior - } - - void interior_directions(nd::view< double, 2 > xi) { - directions(xi); // all the nodes in these elements are interior - } - - __host__ __device__ void indices(const GeometryInfo & offsets, const Connection * edge, uint32_t * ids) { - - uint32_t edge_id = edge[Edge::cell_offset].index; - - if (p == 1) { - ids[0] = offsets.edge + edge_id; - return; - } - - if (p == 2) { - ids[0] = offsets.edge + 2 * edge_id + 0; - ids[1] = offsets.edge + 2 * edge_id + 1; - } - - if (p == 3) { - ids[0] = offsets.edge + 3 * edge_id + 0; - ids[1] = offsets.edge + 3 * edge_id + 1; - ids[2] = offsets.edge + 3 * edge_id + 2; - if (flip(edge[Edge::cell_offset])) { fm::swap(ids[0], ids[2]); } - return; - } - - } - template < typename T > __host__ __device__ void reorient(const TransformationType type, const Connection * edge, T * values) { @@ -82,11 +27,9 @@ struct FiniteElement < Geometry::Edge, Family::Hcurl >{ } __host__ __device__ void reorient(const TransformationType type, const Connection * edge, int8_t * transformation) { - for (int i = 0; i < p; i++) { transformation[i] = 0; } - } constexpr vec<1> shape_function(vec<1> xi, uint32_t i) const { diff --git a/src/serac/numerics/refactor/elements/hcurl_hexahedron.hpp b/src/serac/numerics/refactor/elements/hcurl_hexahedron.hpp index 23e78ac2c3..2a3dd738a2 100644 --- a/src/serac/numerics/refactor/elements/hcurl_hexahedron.hpp +++ b/src/serac/numerics/refactor/elements/hcurl_hexahedron.hpp @@ -28,116 +28,6 @@ struct FiniteElement { __host__ __device__ uint32_t num_nodes() const { return 3 * p * (p + 1) * (p + 1); } - void nodes(nd::view< double, 2 > xi) const { - - double a[3]; - GaussLegendreNodes(p, a); - - double b[4]; - GaussLobattoNodes(p+1, b); - - int count = 0; - for (int k = 0; k < p+1; k++) { - for (int j = 0; j < p+1; j++) { - for (int i = 0; i < p; i++) { - xi(count, 0) = a[i]; xi(count, 1) = b[j]; xi(count, 2) = b[k]; - count++; - } - } - } - - for (int k = 0; k < p+1; k++) { - for (int j = 0; j < p; j++) { - for (int i = 0; i < p+1; i++) { - xi(count, 0) = b[i]; xi(count, 1) = a[j]; xi(count, 2) = b[k]; - count++; - } - } - } - - for (int k = 0; k < p; k++) { - for (int j = 0; j < p+1; j++) { - for (int i = 0; i < p+1; i++) { - xi(count, 0) = b[i]; xi(count, 1) = b[j]; xi(count, 2) = a[k]; - count++; - } - } - } - - } - - void directions(nd::view d) const { - int i = 0; - for (int k = 0; k < (p * (p + 1) * (p + 1)); k++) { - d(i, 0) = 1.0; d(i, 1) = 0.0; d(i, 2) = 0.0; - i++; - } - for (int k = 0; k < (p * (p + 1) * (p + 1)); k++) { - d(i, 0) = 0.0; d(i, 1) = 1.0; d(i, 2) = 0.0; - i++; - } - for (int k = 0; k < (p * (p + 1) * (p + 1)); k++) { - d(i, 0) = 0.0; d(i, 1) = 0.0; d(i, 2) = 1.0; - i++; - } - } - - __host__ __device__ uint32_t num_interior_nodes() const { return 3 * p * (p - 1) * (p - 1); } - - void interior_nodes(nd::view< double, 2 > xi) const { - - double a[3]; - GaussLegendreNodes(p, a); - - double b[4]; - GaussLobattoNodes(p+1, b); - - int count = 0; - for (int k = 1; k < p; k++) { - for (int j = 1; j < p; j++) { - for (int i = 0; i < p; i++) { - xi(count, 0) = a[i]; xi(count, 1) = b[j]; xi(count, 2) = b[k]; - count++; - } - } - } - - for (int k = 1; k < p; k++) { - for (int j = 0; j < p; j++) { - for (int i = 1; i < p; i++) { - xi(count, 0) = b[i]; xi(count, 1) = a[j]; xi(count, 2) = b[k]; - count++; - } - } - } - - for (int k = 0; k < p; k++) { - for (int j = 1; j < p; j++) { - for (int i = 1; i < p; i++) { - xi(count, 0) = b[i]; xi(count, 1) = b[j]; xi(count, 2) = a[k]; - count++; - } - } - } - - } - - void interior_directions(nd::view d) { - int i = 0; - for (int k = 0; k < (p * (p - 1) * (p - 1)); k++) { - d(i, 0) = 1.0; d(i, 1) = 0.0; d(i, 2) = 0.0; - i++; - } - for (int k = 0; k < (p * (p - 1) * (p - 1)); k++) { - d(i, 0) = 0.0; d(i, 1) = 1.0; d(i, 2) = 0.0; - i++; - } - for (int k = 0; k < (p * (p - 1) * (p - 1)); k++) { - d(i, 0) = 0.0; d(i, 1) = 0.0; d(i, 2) = 1.0; - i++; - } - } - struct QuadrilateralStrides { int32_t x_offset; int32_t x_jstride; int32_t x_kstride; int32_t y_offset; int32_t y_jstride; int32_t y_kstride; @@ -163,53 +53,6 @@ struct FiniteElement { } - __host__ __device__ void indices(const GeometryInfo & offsets, const Connection * hex, uint32_t * ids) { - - const Connection * edge = hex + Hexahedron::edge_offset; - const Connection * quad = hex + Hexahedron::quad_offset; - const Connection cell = *(hex + Hexahedron::cell_offset); - - uint8_t const * permutation = lexicographic_permutations(p); - - uint32_t count = 0; - - // edge nodes - for (uint32_t i = 0; i < Hexahedron::num_edges; i++) { - bool s = (edge[i].sign() == Sign::Positive); - int32_t stride = s ? 1 : -1; - uint32_t offset = offsets.edge + p * edge[i].index + (s ? 0 : p-1); - for (uint32_t j = 0; j < p; j++) { - ids[permutation[count++]] = offset + j * stride; - } - } - - if (p == 1) return; - - // face nodes - for (uint32_t i = 0; i < Hexahedron::num_quadrilaterals; i++) { - auto [x_offset, x_jstride, x_kstride, y_offset, y_jstride, y_kstride] = quad_strides(quad[i], offsets.quad); - for (uint32_t k = 0; k < p - 1; k++) { - for (uint32_t j = 0; j < p; j++) { - ids[permutation[count++]] = x_offset + j * x_jstride + k * x_kstride; - } - } - - for (uint32_t k = 0; k < p - 1; k++) { - for (uint32_t j = 0; j < p; j++) { - ids[permutation[count++]] = y_offset + j * y_jstride + k * y_kstride; - } - } - } - - // interior nodes - uint32_t num_interior = num_interior_nodes(); - uint32_t offset = offsets.hex + num_interior * cell.index; - for (uint32_t i = 0; i < num_interior; i++) { - ids[permutation[count++]] = offset + i; - } - - } - template < typename T > __host__ __device__ void reorient(const TransformationType type, const Connection * hex, T * values) { diff --git a/src/serac/numerics/refactor/elements/hcurl_quadrilateral.hpp b/src/serac/numerics/refactor/elements/hcurl_quadrilateral.hpp index 4db3c264ce..e7a4c8ae2e 100644 --- a/src/serac/numerics/refactor/elements/hcurl_quadrilateral.hpp +++ b/src/serac/numerics/refactor/elements/hcurl_quadrilateral.hpp @@ -20,190 +20,6 @@ struct FiniteElement { __host__ __device__ uint32_t num_nodes() const { return 2 * p * (p + 1); } - void nodes(nd::view xi) const { - if (p == 1) { - xi(0, 0) = 0.5; xi(0, 1) = 0; - xi(1, 0) = 0.5; xi(1, 1) = 1.0; - xi(2, 0) = 0; xi(2, 1) = 0.5; - xi(3, 0) = 1.0; xi(3, 1) = 0.5; - } - if (p == 2) { - xi(0, 0) = 0.21132486540518711775; xi(0, 1) = 0; - xi(1, 0) = 0.78867513459481288225; xi(1, 1) = 0; - xi(2, 0) = 0.21132486540518711775; xi(2, 1) = 0.5; - xi(3, 0) = 0.78867513459481288225; xi(3, 1) = 0.5; - xi(4, 0) = 0.21132486540518711775; xi(4, 1) = 1.0; - xi(5, 0) = 0.78867513459481288225; xi(5, 1) = 1.0; - xi(6, 0) = 0; xi(6, 1) = 0.21132486540518711775; - xi(7, 0) = 0; xi(7, 1) = 0.78867513459481288225; - xi(8, 0) = 0.5; xi(8, 1) = 0.21132486540518711775; - xi(9, 0) = 0.5; xi(9, 1) = 0.78867513459481288225; - xi(10, 0) = 1.0; xi(10, 1) = 0.21132486540518711775; - xi(11, 0) = 1.0; xi(11, 1) = 0.78867513459481288225; - } - if (p == 3) { - xi(0, 0) = 0.11270166537925831148; xi(0, 1) = 0; - xi(1, 0) = 0.5; xi(1, 1) = 0; - xi(2, 0) = 0.88729833462074168852; xi(2, 1) = 0; - xi(3, 0) = 0.11270166537925831148; xi(3, 1) = 0.27639320225002103036; - xi(4, 0) = 0.5; xi(4, 1) = 0.27639320225002103036; - xi(5, 0) = 0.88729833462074168852; xi(5, 1) = 0.27639320225002103036; - xi(6, 0) = 0.11270166537925831148; xi(6, 1) = 0.72360679774997896964; - xi(7, 0) = 0.5; xi(7, 1) = 0.72360679774997896964; - xi(8, 0) = 0.88729833462074168852; xi(8, 1) = 0.72360679774997896964; - xi(9, 0) = 0.11270166537925831148; xi(9, 1) = 1.0; - xi(10, 0) = 0.5; xi(10, 1) = 1.0; - xi(11, 0) = 0.88729833462074168852; xi(11, 1) = 1.0; - xi(12, 0) = 0; xi(12, 1) = 0.11270166537925831148; - xi(13, 0) = 0; xi(13, 1) = 0.5; - xi(14, 0) = 0; xi(14, 1) = 0.88729833462074168852; - xi(15, 0) = 0.27639320225002103036; xi(15, 1) = 0.11270166537925831148; - xi(16, 0) = 0.27639320225002103036; xi(16, 1) = 0.5; - xi(17, 0) = 0.27639320225002103036; xi(17, 1) = 0.88729833462074168852; - xi(18, 0) = 0.72360679774997896964; xi(18, 1) = 0.11270166537925831148; - xi(19, 0) = 0.72360679774997896964; xi(19, 1) = 0.5; - xi(20, 0) = 0.72360679774997896964; xi(20, 1) = 0.88729833462074168852; - xi(21, 0) = 1.0; xi(21, 1) = 0.11270166537925831148; - xi(22, 0) = 1.0; xi(22, 1) = 0.5; - xi(23, 0) = 1.0; xi(23, 1) = 0.88729833462074168852; - } - } - - void directions(nd::view d) const { - int i = 0; - for (int k = 0; k < (p * (p + 1)); k++) { d(i, 0) = 1.0; d(i++, 1) = 0.0; } - for (int k = 0; k < (p * (p + 1)); k++) { d(i, 0) = 0.0; d(i++, 1) = 1.0; } - } - - __host__ __device__ uint32_t num_interior_nodes() const { return (p > 1) ? 2 * p * (p - 1) : 0; } - - void interior_nodes(nd::view xi) const { - if (p == 2) { - xi(0, 0) = 0.21132486540518711775; xi(0, 1) = 0.5; - xi(1, 0) = 0.78867513459481288225; xi(1, 1) = 0.5; - xi(2, 0) = 0.5; xi(2, 1) = 0.21132486540518711775; - xi(3, 0) = 0.5; xi(3, 1) = 0.78867513459481288225; - } - if (p == 3) { - xi(0, 0) = 0.11270166537925831148; xi(0, 1) = 0.27639320225002103036; - xi(1, 0) = 0.5; xi(1, 1) = 0.27639320225002103036; - xi(2, 0) = 0.88729833462074168852; xi(2, 1) = 0.27639320225002103036; - xi(3, 0) = 0.11270166537925831148; xi(3, 1) = 0.72360679774997896964; - xi(4, 0) = 0.5; xi(4, 1) = 0.72360679774997896964; - xi(5, 0) = 0.88729833462074168852; xi(5, 1) = 0.72360679774997896964; - xi(6, 0) = 0.27639320225002103036; xi(6, 1) = 0.11270166537925831148; - xi(7, 0) = 0.27639320225002103036; xi(7, 1) = 0.5; - xi(8, 0) = 0.27639320225002103036; xi(8, 1) = 0.88729833462074168852; - xi(9, 0) = 0.72360679774997896964; xi(9, 1) = 0.11270166537925831148; - xi(10, 0) = 0.72360679774997896964; xi(10, 1) = 0.5; - xi(11, 0) = 0.72360679774997896964; xi(11, 1) = 0.88729833462074168852; - } - } - - void interior_directions(nd::view d) const { - if (p > 1) { - int i = 0; - for (int k = 0; k < (p * (p - 1)); k++) { d(i, 0) = 1.0; d(i++, 1) = 0.0; } - for (int k = 0; k < (p * (p - 1)); k++) { d(i, 0) = 0.0; d(i++, 1) = 1.0; } - } - } - - __host__ __device__ void indices(const GeometryInfo & offsets, const Connection * quad, uint32_t * indices) const { - - const Connection * edge = quad + Quadrilateral::edge_offset; - const Connection cell = *(quad + Quadrilateral::cell_offset); - - if (p == 1) { - - // o-----→-----o o-----1-----o - // | | | | - // | | | | - // ↑ ↑ 2 3 - // | | | | - // | | | | - // o-----→-----o o-----0-----o - indices[0] = offsets.edge + edge[0].index; - indices[1] = offsets.edge + edge[2].index; - indices[2] = offsets.edge + edge[3].index; - indices[3] = offsets.edge + edge[1].index; - return; - - } - - if (p == 2) { - - // o---→---→---o o---4---5---o - // | | | | - // ↑ ↑ ↑ 7 9 11 - // | → → | | 2 3 | - // ↑ ↑ ↑ 6 8 10 - // | | | | - // o---→---→---o o---0---1---o - indices[0] = offsets.edge + 2 * edge[0].index + 0; - indices[1] = offsets.edge + 2 * edge[0].index + 1; - indices[2] = offsets.quad + 4 * cell.index + 0; - indices[3] = offsets.quad + 4 * cell.index + 1; - indices[4] = offsets.edge + 2 * edge[2].index + 1; - indices[5] = offsets.edge + 2 * edge[2].index + 0; - - indices[ 6] = offsets.edge + 2 * edge[3].index + 1; - indices[ 7] = offsets.edge + 2 * edge[3].index + 0; - indices[ 8] = offsets.quad + 4 * cell.index + 2; - indices[ 9] = offsets.quad + 4 * cell.index + 3; - indices[10] = offsets.edge + 2 * edge[1].index + 0; - indices[11] = offsets.edge + 2 * edge[1].index + 1; - - if (flip(edge[0])) { fm::swap(indices[ 0], indices[ 1]); } - if (flip(edge[1])) { fm::swap(indices[10], indices[11]); } - if (flip(edge[2])) { fm::swap(indices[ 4], indices[ 5]); } - if (flip(edge[3])) { fm::swap(indices[ 6], indices[ 7]); } - - } - - if (p == 3) { - - // o--→--→--→--o o--9-10-11--o - // ↑ ↑ ↑ ↑ 14 17 20 23 - // | → → → | | 6 7 8 | - // ↑ ↑ ↑ ↑ 13 16 19 22 - // | → → → | | 3 4 5 | - // ↑ ↑ ↑ ↑ 12 15 18 21 - // o--→--→--→--o o--0--1--2--o - indices[ 0] = offsets.edge + 3 * edge[0].index + 0; - indices[ 1] = offsets.edge + 3 * edge[0].index + 1; - indices[ 2] = offsets.edge + 3 * edge[0].index + 2; - indices[ 3] = offsets.quad + 12 * cell.index + 0; - indices[ 4] = offsets.quad + 12 * cell.index + 1; - indices[ 5] = offsets.quad + 12 * cell.index + 2; - indices[ 6] = offsets.quad + 12 * cell.index + 3; - indices[ 7] = offsets.quad + 12 * cell.index + 4; - indices[ 8] = offsets.quad + 12 * cell.index + 5; - indices[ 9] = offsets.edge + 3 * edge[2].index + 2; - indices[10] = offsets.edge + 3 * edge[2].index + 1; - indices[11] = offsets.edge + 3 * edge[2].index + 0; - - indices[12] = offsets.edge + 3 * edge[3].index + 2; - indices[13] = offsets.edge + 3 * edge[3].index + 1; - indices[14] = offsets.edge + 3 * edge[3].index + 0; - indices[15] = offsets.quad + 12 * cell.index + 6; - indices[16] = offsets.quad + 12 * cell.index + 7; - indices[17] = offsets.quad + 12 * cell.index + 8; - indices[18] = offsets.quad + 12 * cell.index + 9; - indices[19] = offsets.quad + 12 * cell.index + 10; - indices[20] = offsets.quad + 12 * cell.index + 11; - indices[21] = offsets.edge + 3 * edge[1].index + 0; - indices[22] = offsets.edge + 3 * edge[1].index + 1; - indices[23] = offsets.edge + 3 * edge[1].index + 2; - - if (flip(edge[0])) { fm::swap(indices[ 0], indices[ 2]); } - if (flip(edge[1])) { fm::swap(indices[21], indices[23]); } - if (flip(edge[2])) { fm::swap(indices[ 9], indices[11]); } - if (flip(edge[3])) { fm::swap(indices[12], indices[14]); } - - } - - } - template < typename T > __host__ __device__ void reorient(const TransformationType type, const Connection * quad, T * values) const { diff --git a/src/serac/numerics/refactor/elements/hcurl_tetrahedron.hpp b/src/serac/numerics/refactor/elements/hcurl_tetrahedron.hpp index 214be3f8d4..b84b80b696 100644 --- a/src/serac/numerics/refactor/elements/hcurl_tetrahedron.hpp +++ b/src/serac/numerics/refactor/elements/hcurl_tetrahedron.hpp @@ -23,349 +23,6 @@ struct FiniteElement { __host__ __device__ constexpr uint32_t num_nodes() const { return (p * (p + 2) * (p + 3)) / 2; } - constexpr void nodes(nd::view< double, 2 > xi) const { - if (p == 1) { - xi(0, 0) = 0.5; xi(0, 1) = 0; xi(0, 2) = 0; - xi(1, 0) = 0.5; xi(1, 1) = 0.5; xi(1, 2) = 0; - xi(2, 0) = 0; xi(2, 1) = 0.5; xi(2, 2) = 0; - xi(3, 0) = 0; xi(3, 1) = 0; xi(3, 2) = 0.5; - xi(4, 0) = 0.5; xi(4, 1) = 0; xi(4, 2) = 0.5; - xi(5, 0) = 0; xi(5, 1) = 0.5; xi(5, 2) = 0.5; - } - if (p == 2) { - xi(0, 0) = 0.21132486540518711774542560975; xi(0, 1) = 0; xi(0, 2) = 0; - xi(1, 0) = 0.78867513459481288225457439025; xi(1, 1) = 0; xi(1, 2) = 0; - xi(2, 0) = 0.78867513459481288225457439025; xi(2, 1) = 0.21132486540518711774542560975; xi(2, 2) = 0; - xi(3, 0) = 0.21132486540518711774542560975; xi(3, 1) = 0.78867513459481288225457439025; xi(3, 2) = 0; - xi(4, 0) = 0; xi(4, 1) = 0.78867513459481288225457439025; xi(4, 2) = 0; - xi(5, 0) = 0; xi(5, 1) = 0.21132486540518711774542560975; xi(5, 2) = 0; - xi(6, 0) = 0; xi(6, 1) = 0; xi(6, 2) = 0.21132486540518711774542560975; - xi(7, 0) = 0; xi(7, 1) = 0; xi(7, 2) = 0.78867513459481288225457439025; - xi(8, 0) = 0.78867513459481288225457439025; xi(8, 1) = 0; xi(8, 2) = 0.21132486540518711774542560975; - xi(9, 0) = 0.21132486540518711774542560975; xi(9, 1) = 0; xi(9, 2) = 0.78867513459481288225457439025; - xi(10, 0) = 0; xi(10, 1) = 0.78867513459481288225457439025; xi(10, 2) = 0.21132486540518711774542560975; - xi(11, 0) = 0; xi(11, 1) = 0.21132486540518711774542560975; xi(11, 2) = 0.78867513459481288225457439025; - xi(12, 0) = 0.333333333333333333333333333333; xi(12, 1) = 0.333333333333333333333333333333; xi(12, 2) = 0; - xi(13, 0) = 0.333333333333333333333333333333; xi(13, 1) = 0.333333333333333333333333333333; xi(13, 2) = 0; - xi(14, 0) = 0.333333333333333333333333333333; xi(14, 1) = 0; xi(14, 2) = 0.333333333333333333333333333333; - xi(15, 0) = 0.333333333333333333333333333333; xi(15, 1) = 0; xi(15, 2) = 0.333333333333333333333333333333; - xi(16, 0) = 0.333333333333333333333333333333; xi(16, 1) = 0.333333333333333333333333333333; xi(16, 2) = 0.333333333333333333333333333333; - xi(17, 0) = 0.333333333333333333333333333333; xi(17, 1) = 0.333333333333333333333333333333; xi(17, 2) = 0.333333333333333333333333333333; - xi(18, 0) = 0; xi(18, 1) = 0.333333333333333333333333333333; xi(18, 2) = 0.333333333333333333333333333333; - xi(19, 0) = 0; xi(19, 1) = 0.333333333333333333333333333333; xi(19, 2) = 0.333333333333333333333333333333; - } - if (p == 3) { - xi(0, 0) = 0.11270166537925831148207346002; xi(0, 1) = 0; xi(0, 2) = 0; - xi(1, 0) = 0.5; xi(1, 1) = 0; xi(1, 2) = 0; - xi(2, 0) = 0.88729833462074168851792654; xi(2, 1) = 0; xi(2, 2) = 0; - xi(3, 0) = 0.88729833462074168851792653998; xi(3, 1) = 0.11270166537925831148207346002; xi(3, 2) = 0; - xi(4, 0) = 0.5; xi(4, 1) = 0.5; xi(4, 2) = 0; - xi(5, 0) = 0.11270166537925831148207346; xi(5, 1) = 0.88729833462074168851792654; xi(5, 2) = 0; - xi(6, 0) = 0; xi(6, 1) = 0.88729833462074168851792653998; xi(6, 2) = 0; - xi(7, 0) = 0; xi(7, 1) = 0.5; xi(7, 2) = 0; - xi(8, 0) = 0; xi(8, 1) = 0.11270166537925831148207346; xi(8, 2) = 0; - xi(9, 0) = 0; xi(9, 1) = 0; xi(9, 2) = 0.11270166537925831148207346002; - xi(10, 0) = 0; xi(10, 1) = 0; xi(10, 2) = 0.5; - xi(11, 0) = 0; xi(11, 1) = 0; xi(11, 2) = 0.88729833462074168851792654; - xi(12, 0) = 0.88729833462074168851792653998; xi(12, 1) = 0; xi(12, 2) = 0.11270166537925831148207346002; - xi(13, 0) = 0.5; xi(13, 1) = 0; xi(13, 2) = 0.5; - xi(14, 0) = 0.11270166537925831148207346; xi(14, 1) = 0; xi(14, 2) = 0.88729833462074168851792654; - xi(15, 0) = 0; xi(15, 1) = 0.88729833462074168851792653998; xi(15, 2) = 0.11270166537925831148207346002; - xi(16, 0) = 0; xi(16, 1) = 0.5; xi(16, 2) = 0.5; - xi(17, 0) = 0; xi(17, 1) = 0.11270166537925831148207346; xi(17, 2) = 0.88729833462074168851792654; - xi(18, 0) = 0.1744576301870094389594272045; xi(18, 1) = 0.651084739625981122081145591; xi(18, 2) = 0; - xi(19, 0) = 0.1744576301870094389594272045; xi(19, 1) = 0.651084739625981122081145591; xi(19, 2) = 0; - xi(20, 0) = 0.651084739625981122081145591; xi(20, 1) = 0.1744576301870094389594272045; xi(20, 2) = 0; - xi(21, 0) = 0.651084739625981122081145591; xi(21, 1) = 0.1744576301870094389594272045; xi(21, 2) = 0; - xi(22, 0) = 0.1744576301870094389594272045; xi(22, 1) = 0.1744576301870094389594272045; xi(22, 2) = 0; - xi(23, 0) = 0.1744576301870094389594272045; xi(23, 1) = 0.1744576301870094389594272045; xi(23, 2) = 0; - xi(24, 0) = 0.1744576301870094389594272045; xi(24, 1) = 0; xi(24, 2) = 0.1744576301870094389594272045; - xi(25, 0) = 0.1744576301870094389594272045; xi(25, 1) = 0; xi(25, 2) = 0.1744576301870094389594272045; - xi(26, 0) = 0.651084739625981122081145591; xi(26, 1) = 0; xi(26, 2) = 0.1744576301870094389594272045; - xi(27, 0) = 0.651084739625981122081145591; xi(27, 1) = 0; xi(27, 2) = 0.1744576301870094389594272045; - xi(28, 0) = 0.1744576301870094389594272045; xi(28, 1) = 0; xi(28, 2) = 0.651084739625981122081145591; - xi(29, 0) = 0.1744576301870094389594272045; xi(29, 1) = 0; xi(29, 2) = 0.651084739625981122081145591; - xi(30, 0) = 0.651084739625981122081145591; xi(30, 1) = 0.1744576301870094389594272045; xi(30, 2) = 0.1744576301870094389594272045; - xi(31, 0) = 0.651084739625981122081145591; xi(31, 1) = 0.1744576301870094389594272045; xi(31, 2) = 0.1744576301870094389594272045; - xi(32, 0) = 0.1744576301870094389594272045; xi(32, 1) = 0.651084739625981122081145591; xi(32, 2) = 0.1744576301870094389594272045; - xi(33, 0) = 0.1744576301870094389594272045; xi(33, 1) = 0.651084739625981122081145591; xi(33, 2) = 0.1744576301870094389594272045; - xi(34, 0) = 0.1744576301870094389594272045; xi(34, 1) = 0.1744576301870094389594272045; xi(34, 2) = 0.651084739625981122081145591; - xi(35, 0) = 0.1744576301870094389594272045; xi(35, 1) = 0.1744576301870094389594272045; xi(35, 2) = 0.651084739625981122081145591; - xi(36, 0) = 0; xi(36, 1) = 0.651084739625981122081145591; xi(36, 2) = 0.1744576301870094389594272045; - xi(37, 0) = 0; xi(37, 1) = 0.651084739625981122081145591; xi(37, 2) = 0.1744576301870094389594272045; - xi(38, 0) = 0; xi(38, 1) = 0.1744576301870094389594272045; xi(38, 2) = 0.1744576301870094389594272045; - xi(39, 0) = 0; xi(39, 1) = 0.1744576301870094389594272045; xi(39, 2) = 0.1744576301870094389594272045; - xi(40, 0) = 0; xi(40, 1) = 0.1744576301870094389594272045; xi(40, 2) = 0.651084739625981122081145591; - xi(41, 0) = 0; xi(41, 1) = 0.1744576301870094389594272045; xi(41, 2) = 0.651084739625981122081145591; - xi(42, 0) = 0.25; xi(42, 1) = 0.25; xi(42, 2) = 0.25; - xi(43, 0) = 0.25; xi(43, 1) = 0.25; xi(43, 2) = 0.25; - xi(44, 0) = 0.25; xi(44, 1) = 0.25; xi(44, 2) = 0.25; - } - } - - constexpr void directions(nd::view d) const { - if (p == 1) { - d(0, 0) = 1; d(0, 1) = 0; d(0, 2) = 0; - d(1, 0) = -1; d(1, 1) = 1; d(1, 2) = 0; - d(2, 0) = 0; d(2, 1) = -1; d(2, 2) = 0; - d(3, 0) = 0; d(3, 1) = 0; d(3, 2) = 1; - d(4, 0) = -1; d(4, 1) = 0; d(4, 2) = 1; - d(5, 0) = 0; d(5, 1) = -1; d(5, 2) = 1; - } - if (p == 2) { - d(0, 0) = 1; d(0, 1) = 0; d(0, 2) = 0; - d(1, 0) = 1; d(1, 1) = 0; d(1, 2) = 0; - d(2, 0) = -1; d(2, 1) = 1; d(2, 2) = 0; - d(3, 0) = -1; d(3, 1) = 1; d(3, 2) = 0; - d(4, 0) = 0; d(4, 1) = -1; d(4, 2) = 0; - d(5, 0) = 0; d(5, 1) = -1; d(5, 2) = 0; - d(6, 0) = 0; d(6, 1) = 0; d(6, 2) = 1; - d(7, 0) = 0; d(7, 1) = 0; d(7, 2) = 1; - d(8, 0) = -1; d(8, 1) = 0; d(8, 2) = 1; - d(9, 0) = -1; d(9, 1) = 0; d(9, 2) = 1; - d(10, 0) = 0; d(10, 1) = -1; d(10, 2) = 1; - d(11, 0) = 0; d(11, 1) = -1; d(11, 2) = 1; - d(12, 0) = 1; d(12, 1) = -1; d(12, 2) = 0; - d(13, 0) = 0; d(13, 1) = -1; d(13, 2) = 0; - d(14, 0) = 1; d(14, 1) = 0; d(14, 2) = 0; - d(15, 0) = 0; d(15, 1) = 0; d(15, 2) = 1; - d(16, 0) = -1; d(16, 1) = 1; d(16, 2) = 0; - d(17, 0) = -1; d(17, 1) = 0; d(17, 2) = 1; - d(18, 0) = 0; d(18, 1) = -1; d(18, 2) = 0; - d(19, 0) = 0; d(19, 1) = -1; d(19, 2) = 1; - } - if (p == 3) { - d(0, 0) = 1; d(0, 1) = 0; d(0, 2) = 0; - d(1, 0) = 1; d(1, 1) = 0; d(1, 2) = 0; - d(2, 0) = 1; d(2, 1) = 0; d(2, 2) = 0; - d(3, 0) = -1; d(3, 1) = 1; d(3, 2) = 0; - d(4, 0) = -1; d(4, 1) = 1; d(4, 2) = 0; - d(5, 0) = -1; d(5, 1) = 1; d(5, 2) = 0; - d(6, 0) = 0; d(6, 1) = -1; d(6, 2) = 0; - d(7, 0) = 0; d(7, 1) = -1; d(7, 2) = 0; - d(8, 0) = 0; d(8, 1) = -1; d(8, 2) = 0; - d(9, 0) = 0; d(9, 1) = 0; d(9, 2) = 1; - d(10, 0) = 0; d(10, 1) = 0; d(10, 2) = 1; - d(11, 0) = 0; d(11, 1) = 0; d(11, 2) = 1; - d(12, 0) = -1; d(12, 1) = 0; d(12, 2) = 1; - d(13, 0) = -1; d(13, 1) = 0; d(13, 2) = 1; - d(14, 0) = -1; d(14, 1) = 0; d(14, 2) = 1; - d(15, 0) = 0; d(15, 1) = -1; d(15, 2) = 1; - d(16, 0) = 0; d(16, 1) = -1; d(16, 2) = 1; - d(17, 0) = 0; d(17, 1) = -1; d(17, 2) = 1; - d(18, 0) = 1; d(18, 1) = -1; d(18, 2) = 0; - d(19, 0) = 0; d(19, 1) = -1; d(19, 2) = 0; - d(20, 0) = 1; d(20, 1) = -1; d(20, 2) = 0; - d(21, 0) = 0; d(21, 1) = -1; d(21, 2) = 0; - d(22, 0) = 1; d(22, 1) = -1; d(22, 2) = 0; - d(23, 0) = 0; d(23, 1) = -1; d(23, 2) = 0; - d(24, 0) = 1; d(24, 1) = 0; d(24, 2) = 0; - d(25, 0) = 0; d(25, 1) = 0; d(25, 2) = 1; - d(26, 0) = 1; d(26, 1) = 0; d(26, 2) = 0; - d(27, 0) = 0; d(27, 1) = 0; d(27, 2) = 1; - d(28, 0) = 1; d(28, 1) = 0; d(28, 2) = 0; - d(29, 0) = 0; d(29, 1) = 0; d(29, 2) = 1; - d(30, 0) = -1; d(30, 1) = 1; d(30, 2) = 0; - d(31, 0) = -1; d(31, 1) = 0; d(31, 2) = 1; - d(32, 0) = -1; d(32, 1) = 1; d(32, 2) = 0; - d(33, 0) = -1; d(33, 1) = 0; d(33, 2) = 1; - d(34, 0) = -1; d(34, 1) = 1; d(34, 2) = 0; - d(35, 0) = -1; d(35, 1) = 0; d(35, 2) = 1; - d(36, 0) = 0; d(36, 1) = -1; d(36, 2) = 0; - d(37, 0) = 0; d(37, 1) = -1; d(37, 2) = 1; - d(38, 0) = 0; d(38, 1) = -1; d(38, 2) = 0; - d(39, 0) = 0; d(39, 1) = -1; d(39, 2) = 1; - d(40, 0) = 0; d(40, 1) = -1; d(40, 2) = 0; - d(41, 0) = 0; d(41, 1) = -1; d(41, 2) = 1; - d(42, 0) = 1; d(42, 1) = 0; d(42, 2) = 0; - d(43, 0) = 0; d(43, 1) = 1; d(43, 2) = 0; - d(44, 0) = 0; d(44, 1) = 0; d(44, 2) = 1; - } - } - - __host__ __device__ constexpr uint32_t num_interior_nodes() const { return (p == 3) ? 3 : 0; } - - constexpr void interior_nodes(nd::view xi) const { - if (p == 3) { - xi(0, 0) = 0.25; xi(0, 1) = 0.25; xi(0, 2) = 0.25; - xi(1, 0) = 0.25; xi(1, 1) = 0.25; xi(1, 2) = 0.25; - xi(2, 0) = 0.25; xi(2, 1) = 0.25; xi(2, 2) = 0.25; - } - } - - constexpr void interior_directions(nd::view d) const { - if (p == 3) { - d(0, 0) = 1; d(0, 1) = 0; d(0, 2) = 0; - d(1, 0) = 0; d(1, 1) = 1; d(1, 2) = 0; - d(2, 0) = 0; d(2, 1) = 0; d(2, 2) = 1; - } - } - - __host__ __device__ void permute(Connection tri, uint32_t * ids) { - if (tri.sign() == Sign::Negative) { - - //////////////////////////////////////////////////////////////////////////////// - // // - // official | // - // ordering | // - // | | // - // c | c a b | b c a // - // / \ | / \ / \ / \ | / \ / \ / \ // - // / \ | / \ / \ / \ | / \ / \ / \ // - // a-----b | a-----b b-----c c-----a | a-----c b-----a c-----b // - // | | // - // sign | + + + | - - - // - // orientation | 0 1 2 | 0 1 2 // - // // - //////////////////////////////////////////////////////////////////////////////// - uint8_t o = tri.orientation(); - uint32_t tmp; - // swap b<->c - if (o == 0) { - tmp = ids[2]; ids[2] = ids[4]; ids[4] = tmp; - tmp = ids[3]; ids[3] = ids[5]; ids[5] = tmp; - } - - // swap a<->b - if (o == 1) { - tmp = ids[0]; ids[0] = ids[2]; ids[2] = tmp; - tmp = ids[1]; ids[1] = ids[3]; ids[3] = tmp; - } - - // swap a<->c - if (o == 2) { - tmp = ids[0]; ids[0] = ids[4]; ids[4] = tmp; - tmp = ids[1]; ids[1] = ids[5]; ids[5] = tmp; - } - } - } - - __host__ __device__ void indices(const GeometryInfo & offsets, const Connection * tet, uint32_t * ids) { - - const Connection * edge = tet + Tetrahedron::edge_offset; - const Connection * tri = tet + Tetrahedron::tri_offset; - const Connection cell = *(tet + Tetrahedron::cell_offset); - - if (p == 1) { - ids[0] = offsets.edge + edge[0].index; - ids[1] = offsets.edge + edge[1].index; - ids[2] = offsets.edge + edge[2].index; - ids[3] = offsets.edge + edge[3].index; - ids[4] = offsets.edge + edge[4].index; - ids[5] = offsets.edge + edge[5].index; - return; - } - - if (p == 2) { - ids[ 0] = offsets.edge + 2 * edge[0].index + 0; - ids[ 1] = offsets.edge + 2 * edge[0].index + 1; - if (flip(edge[0])) { fm::swap(ids[0], ids[1]); } - - ids[ 2] = offsets.edge + 2 * edge[1].index + 0; - ids[ 3] = offsets.edge + 2 * edge[1].index + 1; - if (flip(edge[1])) { fm::swap(ids[2], ids[3]); } - - ids[ 4] = offsets.edge + 2 * edge[2].index + 0; - ids[ 5] = offsets.edge + 2 * edge[2].index + 1; - if (flip(edge[2])) { fm::swap(ids[4], ids[5]); } - - ids[ 6] = offsets.edge + 2 * edge[3].index + 0; - ids[ 7] = offsets.edge + 2 * edge[3].index + 1; - if (flip(edge[3])) { fm::swap(ids[6], ids[7]); } - - ids[ 8] = offsets.edge + 2 * edge[4].index + 0; - ids[ 9] = offsets.edge + 2 * edge[4].index + 1; - if (flip(edge[4])) { fm::swap(ids[8], ids[9]); } - - ids[10] = offsets.edge + 2 * edge[5].index + 0; - ids[11] = offsets.edge + 2 * edge[5].index + 1; - if (flip(edge[5])) { fm::swap(ids[10], ids[11]); } - - ids[12] = offsets.tri + 2 * tri[0].index + 0; - ids[13] = offsets.tri + 2 * tri[0].index + 1; - - ids[14] = offsets.tri + 2 * tri[1].index + 0; - ids[15] = offsets.tri + 2 * tri[1].index + 1; - - ids[16] = offsets.tri + 2 * tri[2].index + 0; - ids[17] = offsets.tri + 2 * tri[2].index + 1; - - ids[18] = offsets.tri + 2 * tri[3].index + 0; - ids[19] = offsets.tri + 2 * tri[3].index + 1; - return; - } - - if (p == 3) { - - ids[ 0] = offsets.edge + 3 * edge[0].index + 0; - ids[ 1] = offsets.edge + 3 * edge[0].index + 1; - ids[ 2] = offsets.edge + 3 * edge[0].index + 2; - if (flip(edge[0])) { fm::swap(ids[0], ids[2]); } - - ids[ 3] = offsets.edge + 3 * edge[1].index + 0; - ids[ 4] = offsets.edge + 3 * edge[1].index + 1; - ids[ 5] = offsets.edge + 3 * edge[1].index + 2; - if (flip(edge[1])) { fm::swap(ids[3], ids[5]); } - - ids[ 6] = offsets.edge + 3 * edge[2].index + 0; - ids[ 7] = offsets.edge + 3 * edge[2].index + 1; - ids[ 8] = offsets.edge + 3 * edge[2].index + 2; - if (flip(edge[2])) { fm::swap(ids[6], ids[8]); } - - ids[ 9] = offsets.edge + 3 * edge[3].index + 0; - ids[10] = offsets.edge + 3 * edge[3].index + 1; - ids[11] = offsets.edge + 3 * edge[3].index + 2; - if (flip(edge[3])) { fm::swap(ids[9], ids[11]); } - - ids[12] = offsets.edge + 3 * edge[4].index + 0; - ids[13] = offsets.edge + 3 * edge[4].index + 1; - ids[14] = offsets.edge + 3 * edge[4].index + 2; - if (flip(edge[4])) { fm::swap(ids[12], ids[14]); } - - ids[15] = offsets.edge + 3 * edge[5].index + 0; - ids[16] = offsets.edge + 3 * edge[5].index + 1; - ids[17] = offsets.edge + 3 * edge[5].index + 2; - if (flip(edge[5])) { fm::swap(ids[15], ids[17]); } - - ids[18] = offsets.tri + 6 * tri[0].index + 0; - ids[19] = offsets.tri + 6 * tri[0].index + 1; - ids[20] = offsets.tri + 6 * tri[0].index + 2; - ids[21] = offsets.tri + 6 * tri[0].index + 3; - ids[22] = offsets.tri + 6 * tri[0].index + 4; - ids[23] = offsets.tri + 6 * tri[0].index + 5; - permute(tri[0], ids+18); - - ids[24] = offsets.tri + 6 * tri[1].index + 0; - ids[25] = offsets.tri + 6 * tri[1].index + 1; - ids[26] = offsets.tri + 6 * tri[1].index + 2; - ids[27] = offsets.tri + 6 * tri[1].index + 3; - ids[28] = offsets.tri + 6 * tri[1].index + 4; - ids[29] = offsets.tri + 6 * tri[1].index + 5; - permute(tri[1], ids+24); - - ids[30] = offsets.tri + 6 * tri[2].index + 0; - ids[31] = offsets.tri + 6 * tri[2].index + 1; - ids[32] = offsets.tri + 6 * tri[2].index + 2; - ids[33] = offsets.tri + 6 * tri[2].index + 3; - ids[34] = offsets.tri + 6 * tri[2].index + 4; - ids[35] = offsets.tri + 6 * tri[2].index + 5; - permute(tri[2], ids+30); - - ids[36] = offsets.tri + 6 * tri[3].index + 0; - ids[37] = offsets.tri + 6 * tri[3].index + 1; - ids[38] = offsets.tri + 6 * tri[3].index + 2; - ids[39] = offsets.tri + 6 * tri[3].index + 3; - ids[40] = offsets.tri + 6 * tri[3].index + 4; - ids[41] = offsets.tri + 6 * tri[3].index + 5; - permute(tri[3], ids+36); - - ids[42] = offsets.tet + 3 * cell.index + 0; - ids[43] = offsets.tet + 3 * cell.index + 1; - ids[44] = offsets.tet + 3 * cell.index + 2; - return; - } - } - __host__ __device__ void reorient(const TransformationType type, const Connection * tet, int8_t * transformation) { const Connection * edge = tet + Tetrahedron::edge_offset; diff --git a/src/serac/numerics/refactor/elements/hcurl_triangle.hpp b/src/serac/numerics/refactor/elements/hcurl_triangle.hpp index 5b62461878..0f16337f4c 100644 --- a/src/serac/numerics/refactor/elements/hcurl_triangle.hpp +++ b/src/serac/numerics/refactor/elements/hcurl_triangle.hpp @@ -20,175 +20,6 @@ struct FiniteElement { __host__ __device__ uint32_t num_nodes() const { return p * (p + 2); } - void nodes(nd::view xi) const { - if (p == 1) { - xi(0, 0) = 0.5; xi(0, 1) = 0.0; - xi(1, 0) = 0.5; xi(1, 1) = 0.5; - xi(2, 0) = 0.0; xi(2, 1) = 0.5; - } - if (p == 2) { - constexpr double s = 0.21132486540518711774542560975; - constexpr double t = 0.33333333333333333333333333333; - xi(0, 0) = s; xi(0, 1) = 0.0; - xi(1, 0) = 1-s; xi(1, 1) = 0.0; - xi(2, 0) = 1-s; xi(2, 1) = s; - xi(3, 0) = s; xi(3, 1) = 1-s; - xi(4, 0) = 0; xi(4, 1) = 1-s; - xi(5, 0) = 0; xi(5, 1) = s; - xi(6, 0) = t; xi(6, 1) = t; - xi(7, 0) = t; xi(7, 1) = t; - } - if (p == 3) { - constexpr double s = 0.11270166537925831148207346002; - constexpr double c1 = 0.1744576301870094389594272045; - constexpr double c2 = 0.6510847396259811220811455910; - - xi( 0, 0) = s; xi( 0, 1) = 0.0; - xi( 1, 0) = 0.5; xi( 1, 1) = 0.0; - xi( 2, 0) = 1-s; xi( 2, 1) = 0.0; - - xi( 3, 0) = 1-s; xi( 3, 1) = s; - xi( 4, 0) = 0.5; xi( 4, 1) = 0.5; - xi( 5, 0) = s; xi( 5, 1) = 1-s; - - xi( 6, 0) = 0.0; xi( 6, 1) = 1-s; - xi( 7, 0) = 0.0; xi( 7, 1) = 0.5; - xi( 8, 0) = 0.0; xi( 8, 1) = s; - - xi( 9, 0) = c1; xi( 9, 1) = c1; - xi(10, 0) = c1; xi(10, 1) = c1; - - xi(11, 0) = c2; xi(11, 1) = c1; - xi(12, 0) = c2; xi(12, 1) = c1; - - xi(13, 0) = c1; xi(13, 1) = c2; - xi(14, 0) = c1; xi(14, 1) = c2; - } - } - - void directions(nd::view d) const { - int i = 0; - for (int k = 0; k < p; k++) { d(i, 0) = 1.0; d(i++, 1) = 0.0; } // edge 1 - for (int k = 0; k < p; k++) { d(i, 0) = -1.0; d(i++, 1) = 1.0; } // edge 2 - for (int k = 0; k < p; k++) { d(i, 0) = 0.0; d(i++, 1) = -1.0; } // edge 3 - - // interior nodes - for (int k = 0; k < ((p - 1) * p) / 2; k++) { - d(i, 0) = 1.0; d(i++, 1) = 0.0; - d(i, 0) = 0.0; d(i++, 1) = 1.0; - } - } - - __host__ __device__ uint32_t num_interior_nodes() const { return (p > 1) ? 2 * Triangle::number(p - 1) : 0; } - - void interior_nodes(nd::view xi) const { - if (p == 2) { - xi(0, 0) = 0.3333333333333333333; xi(0, 1) = 0.3333333333333333333; - xi(1, 0) = 0.3333333333333333333; xi(1, 1) = 0.3333333333333333333; - } - if (p == 3) { - constexpr double c1 = 0.1744576301870094389594272045; - constexpr double c2 = 0.6510847396259811220811455910; - xi(0, 0) = c1; xi(0, 1) = c1; - xi(1, 0) = c1; xi(1, 1) = c1; - - xi(2, 0) = c2; xi(2, 1) = c1; - xi(3, 0) = c2; xi(3, 1) = c1; - - xi(4, 0) = c1; xi(4, 1) = c2; - xi(5, 0) = c1; xi(5, 1) = c2; - } - } - - void interior_directions(nd::view d) const { - if (p > 1) { - int i = 0; - for (int k = 0; k < ((p - 1) * p) / 2; k++) { - d(i, 0) = 1.0; d(i++, 1) = 0.0; - d(i, 0) = 0.0; d(i++, 1) = 1.0; - } - } - } - - __host__ __device__ void indices(const GeometryInfo & offsets, const Connection * tri, uint32_t * indices) const { - - const Connection * edge = tri + 3; - const Connection cell = *(tri + 6); - - if (p == 1) { - // * - // | \ - // 2 1 - // | \ - // *--0--* - indices[0] = offsets.edge + edge[0].index; - indices[1] = offsets.edge + edge[1].index; - indices[2] = offsets.edge + edge[2].index; - return; - } - - if (p == 2) { - // * - // | \ - // 4 3 - // | \ - // 5 6/7 2 - // | \ - // *--0--1--* - indices[0] = offsets.edge + 2 * edge[0].index + 0; - indices[1] = offsets.edge + 2 * edge[0].index + 1; - if (flip(edge[0])) { fm::swap(indices[0], indices[1]); } - - indices[2] = offsets.edge + 2 * edge[1].index + 0; - indices[3] = offsets.edge + 2 * edge[1].index + 1; - if (flip(edge[1])) { fm::swap(indices[2], indices[3]); } - - indices[4] = offsets.edge + 2 * edge[2].index + 0; - indices[5] = offsets.edge + 2 * edge[2].index + 1; - if (flip(edge[2])) { fm::swap(indices[4], indices[5]); } - - indices[6] = offsets.tri + 2 * cell.index + 0; - indices[7] = offsets.tri + 2 * cell.index + 1; - } - - if (p == 3) { - // * - // | \ - // 6 5 - // | \ - // 7 13 4 - // | \ - // 8 9 11 3 - // | \ - // *--0--1--2--* - // - // note: nodes for {9/10, 11/12, 13/14} are coincident - indices[0] = offsets.edge + 3 * edge[0].index + 0; - indices[1] = offsets.edge + 3 * edge[0].index + 1; - indices[2] = offsets.edge + 3 * edge[0].index + 2; - if (flip(edge[0])) { fm::swap(indices[0], indices[2]); } - - indices[3] = offsets.edge + 3 * edge[1].index + 0; - indices[4] = offsets.edge + 3 * edge[1].index + 1; - indices[5] = offsets.edge + 3 * edge[1].index + 2; - if (flip(edge[1])) { fm::swap(indices[3], indices[5]); } - - indices[6] = offsets.edge + 3 * edge[2].index + 0; - indices[7] = offsets.edge + 3 * edge[2].index + 1; - indices[8] = offsets.edge + 3 * edge[2].index + 2; - if (flip(edge[2])) { fm::swap(indices[6], indices[8]); } - - indices[ 9] = offsets.tri + 6 * cell.index + 0; - indices[10] = offsets.tri + 6 * cell.index + 1; - - indices[11] = offsets.tri + 6 * cell.index + 2; - indices[12] = offsets.tri + 6 * cell.index + 3; - - indices[13] = offsets.tri + 6 * cell.index + 4; - indices[14] = offsets.tri + 6 * cell.index + 5; - } - } - template < typename T > __host__ __device__ void reorient(const TransformationType type, const Connection * tri, T * values) const { diff --git a/src/serac/numerics/refactor/elements/hcurl_vertex.hpp b/src/serac/numerics/refactor/elements/hcurl_vertex.hpp index 17e37c7f18..5aeb965def 100644 --- a/src/serac/numerics/refactor/elements/hcurl_vertex.hpp +++ b/src/serac/numerics/refactor/elements/hcurl_vertex.hpp @@ -6,19 +6,9 @@ namespace refactor { template <> struct FiniteElement < Geometry::Vertex, Family::Hcurl >{ - __host__ __device__ uint32_t num_nodes() const { return 0; } - void nodes(nd::view xi) {} - void directions(nd::view xi) {} - - __host__ __device__ uint32_t num_interior_nodes() { return 0; } - void interior_nodes(nd::view xi) {} - void interior_directions(nd::view xi) {} - - __host__ __device__ void indices(const GeometryInfo & offsets, const Connection * edge, uint32_t * ids) {} uint32_t p; - }; } // namespace refactor From 87cd5b9ec63c121a982a44c3b3ee4e396c715e92 Mon Sep 17 00:00:00 2001 From: Sam Mish Date: Thu, 12 Dec 2024 12:55:06 -0800 Subject: [PATCH 03/15] importing more sourcefiles --- .../numerics/refactor/elements/h1_edge.hpp | 1 - src/serac/numerics/refactor/evaluate.hpp | 110 ++++++++++++++ .../numerics/refactor/finite_element.hpp | 15 +- src/serac/numerics/refactor/integrate.hpp | 3 + src/serac/numerics/refactor/interpolate.hpp | 0 .../refactor/tests/h1_evaluation_tests.cpp | 119 +++++++++++++++ .../refactor/tests/hcurl_evaluation_tests.cpp | 125 +++++++++++++++ .../integrate_residual_H1_flux_tests.cpp | 135 +++++++++++++++++ .../integrate_residual_H1_source_tests.cpp | 131 ++++++++++++++++ .../integrate_residual_H1v_flux_tests.cpp | 131 ++++++++++++++++ .../integrate_residual_Hcurl_flux_tests.cpp | 135 +++++++++++++++++ .../integrate_residual_Hcurl_source_tests.cpp | 143 ++++++++++++++++++ 12 files changed, 1045 insertions(+), 3 deletions(-) create mode 100644 src/serac/numerics/refactor/evaluate.hpp delete mode 100644 src/serac/numerics/refactor/interpolate.hpp create mode 100644 src/serac/numerics/refactor/tests/h1_evaluation_tests.cpp create mode 100644 src/serac/numerics/refactor/tests/hcurl_evaluation_tests.cpp create mode 100644 src/serac/numerics/refactor/tests/integrate_residual_H1_flux_tests.cpp create mode 100644 src/serac/numerics/refactor/tests/integrate_residual_H1_source_tests.cpp create mode 100644 src/serac/numerics/refactor/tests/integrate_residual_H1v_flux_tests.cpp create mode 100644 src/serac/numerics/refactor/tests/integrate_residual_Hcurl_flux_tests.cpp create mode 100644 src/serac/numerics/refactor/tests/integrate_residual_Hcurl_source_tests.cpp diff --git a/src/serac/numerics/refactor/elements/h1_edge.hpp b/src/serac/numerics/refactor/elements/h1_edge.hpp index be71fafed9..eef78cf902 100644 --- a/src/serac/numerics/refactor/elements/h1_edge.hpp +++ b/src/serac/numerics/refactor/elements/h1_edge.hpp @@ -1,7 +1,6 @@ #pragma once #include "fm/macros.hpp" -#include "refactor/connection.hpp" #include "refactor/interpolation.hpp" namespace refactor { diff --git a/src/serac/numerics/refactor/evaluate.hpp b/src/serac/numerics/refactor/evaluate.hpp new file mode 100644 index 0000000000..6ece0bbd40 --- /dev/null +++ b/src/serac/numerics/refactor/evaluate.hpp @@ -0,0 +1,110 @@ +#pragma once + +#include "serac/numerics/refactor/finite_element.hpp" +#include "serac/physics/state/finite_element_state.hpp" + +namespace refactor { + +using Field = serac::FiniteElementState; + +enum class Modifier { NONE, DIAGONAL, SYM }; +enum class DerivedQuantity { VALUE, DERIVATIVE }; + +inline bool is_value(DerivedQuantity op) { + return op == DerivedQuantity::VALUE; +} + +inline bool is_derivative(DerivedQuantity op) { + return op == DerivedQuantity::DERIVATIVE; +} + +struct FieldOp { + const DerivedQuantity op; + const Field & field; + + FieldOp(const Field & f) : op(DerivedQuantity::VALUE), field(f){}; + FieldOp(const DerivedQuantity & o, const Field & f) : op(o), field(f){}; +}; + +struct BasisFunctionOp { + const Modifier mod; + const DerivedQuantity op; + const BasisFunction function; + + BasisFunctionOp(const BasisFunction & f) : mod(Modifier::NONE), op(DerivedQuantity::VALUE), function(f){}; + BasisFunctionOp(const DerivedQuantity & o, const BasisFunction & f) : mod(Modifier::NONE), op(o), function(f){}; + BasisFunctionOp(const Modifier & m, const DerivedQuantity & o, const BasisFunction & f) : mod(m), op(o), function(f){}; +}; + + +//////////////////////////////////////////////////////////////////////////////// + +FieldOp grad(const Field & f); +FieldOp curl(const Field & f); +FieldOp div(const Field & f); + +BasisFunctionOp grad(const BasisFunction & phi); +BasisFunctionOp curl(const BasisFunction & phi); +BasisFunctionOp div(const BasisFunction & phi); + +//////////////////////////////////////////////////////////////////////////////// + +// for integrating sparse matrices (e.g. mass, stiffness) +template < typename T1, typename T2, typename T3 > +struct WeightedIntegrand { + const T1 test; + const T2 & qdata; + const T3 trial; +}; + +// for integrating residual vectors +template < typename T1, typename T2 > +struct WeightedIntegrand< T1, T2, void > { + const T1 test; + const T2 & qdata; +}; + +template < typename T > +struct DiagonalOnly : public T {}; + +template < typename T > +DiagonalOnly(T) -> DiagonalOnly; + +template < typename T, uint32_t n > +auto operator*(const nd::array & data, const BasisFunction & phi) { + return WeightedIntegrand< BasisFunctionOp, nd::array, void >{phi, data}; +} + +template < typename T, uint32_t n > +auto operator*(const nd::array & data, const BasisFunctionOp & dphi) { + return WeightedIntegrand< BasisFunctionOp, nd::array, void >{dphi, data}; +} + +template < typename T, uint32_t n > +auto dot(const nd::array & data, const BasisFunctionOp & dphi) { + return WeightedIntegrand< BasisFunctionOp, nd::array, void >{dphi, data}; +} + +template < typename T, uint32_t n > +auto diagonal(WeightedIntegrand< BasisFunctionOp, nd::array, BasisFunctionOp > integrand) { + SERAC_ASSERT( + integrand.test.function == integrand.trial.function, + "diag(...) requires same test and trial space" + ); + + return DiagonalOnly{integrand}; +} + +//////////////////////////////////////////////////////////////////////////////// + +template < typename T, uint32_t n > +auto dot(BasisFunctionOp psi, const nd::array & data, BasisFunctionOp phi) { + return WeightedIntegrand< BasisFunctionOp, nd::array, BasisFunctionOp >{phi, data, psi}; +} + +//////////////////////////////////////////////////////////////////////////////// + +double dot(const Residual & r, const Field & u); +double dot(const Field & u, const Residual & r); + +} diff --git a/src/serac/numerics/refactor/finite_element.hpp b/src/serac/numerics/refactor/finite_element.hpp index b5a11ad7fa..e522c03257 100644 --- a/src/serac/numerics/refactor/finite_element.hpp +++ b/src/serac/numerics/refactor/finite_element.hpp @@ -1,7 +1,7 @@ #pragma once -#include "refactor/geometry.hpp" -#include "refactor/quadrature.hpp" +#include "serac/numerics/refactor/geometry.hpp" +#include "serac/numerics/refactor/quadrature.hpp" namespace refactor { @@ -34,6 +34,17 @@ struct FunctionSpace { } }; +struct BasisFunction { + FunctionSpace space; + BasisFunction(Field f) : space(f.family, f.degree, f.data.shape[1]) {} + BasisFunction(FunctionSpace s) : space(s) {} + bool operator==(const BasisFunction & other) const { + return (space.components == other.space.components) && + (space.degree == other.space.degree) && + (space.family == other.space.family); + } +}; + GeometryInfo nodes_per_geom(FunctionSpace space); GeometryInfo interior_nodes_per_geom(FunctionSpace space); diff --git a/src/serac/numerics/refactor/integrate.hpp b/src/serac/numerics/refactor/integrate.hpp index eaa9098158..c4f598f6c0 100644 --- a/src/serac/numerics/refactor/integrate.hpp +++ b/src/serac/numerics/refactor/integrate.hpp @@ -1 +1,4 @@ +#pragma once + +#include "serac/numerics/refactor/finite_element.hpp" #include "serac/physics/state/finite_element_state.hpp" diff --git a/src/serac/numerics/refactor/interpolate.hpp b/src/serac/numerics/refactor/interpolate.hpp deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/serac/numerics/refactor/tests/h1_evaluation_tests.cpp b/src/serac/numerics/refactor/tests/h1_evaluation_tests.cpp new file mode 100644 index 0000000000..4cf296e619 --- /dev/null +++ b/src/serac/numerics/refactor/tests/h1_evaluation_tests.cpp @@ -0,0 +1,119 @@ +#include + +#include +#include + +#include "refactor/mesh.hpp" +#include "refactor/field.hpp" +#include "refactor/piola_transformations.hpp" + +#include "refactor/domain.hpp" + +#include "misc/for_constexpr.hpp" +#include "forall.hpp" + +#include "fm/types/vec.hpp" +#include "fm/types/matrix.hpp" + +using namespace refactor; + +constexpr int dimension(double) { return 1; } + +template < int dim > +constexpr int dimension(vec < dim >) { return dim; } + +template < typename vec_t > +void evaluation_test(std::string filename, + std::function f, + std::function grad_f, + int p, + double tolerance) { + + constexpr int dim = dimension(vec_t{}); + + using mat_t = mat; + + auto mesh = Mesh::load(SERAC_MESH_DIR + filename); + + Field u = create_field(mesh, Family::H1, p); + nd::array nodes = nodes_for(u, mesh); + + u = forall(f, nodes); + + for (int q = 1; q <= 4; q++) { + + Domain domain(mesh, MeshQuadratureRule(q)); + + auto x_q = evaluate(mesh.X, domain); + auto dX_dxi_q = evaluate(grad(mesh.X), isoparametric(domain)); + + auto u_q = evaluate(u, domain); + auto du_dxi_q = evaluate(grad(u), isoparametric(domain)); + auto du_dX_q_1 = evaluate(grad(u), domain); + auto du_dX_q_2 = forall(contravariant_piola, du_dxi_q, dX_dxi_q); + + // evaluate f, df_dx directly at each quadrature point + auto f_q = forall(f, x_q); + auto df_dX_q = forall(grad_f, x_q); + + EXPECT_LT(relative_error(flatten(u_q), flatten(f_q)), tolerance); + EXPECT_LT(relative_error(flatten(du_dX_q_1), flatten(df_dX_q)), tolerance); + EXPECT_LT(relative_error(du_dX_q_2, df_dX_q), tolerance); + + } + +} + +#define GENERATE_TEST_2D(NAME, mesh, p, tolerance) \ +TEST(InterpolationTest2D, NAME) { \ + evaluation_test( \ + mesh, \ + std::function< double(vec2) >([](vec2 x) { return 3 * pow(x[0], p) + 2 * x[1] - 1; }),\ + std::function< vec2(vec2) >([](vec2 x) { return vec2{3 * p * pow(x[0], p - 1), 2}; }),\ + p, \ + tolerance \ + ); \ +} + +GENERATE_TEST_2D(AffineTestQuadP1, "one_quad_pure_shear.json", 1, 1.0e-15); + +GENERATE_TEST_2D(PatchTestQuadP1, "patch_test_quads.json", 1, 1.0e-15); +GENERATE_TEST_2D(PatchTestQuadP2, "patch_test_quads.json", 2, 1.0e-14); +GENERATE_TEST_2D(PatchTestQuadP3, "patch_test_quads.json", 3, 1.0e-14); + +GENERATE_TEST_2D(PatchTestTriP1, "patch_test_tris.json", 1, 1.0e-15); +GENERATE_TEST_2D(PatchTestTriP2, "patch_test_tris.json", 2, 1.0e-14); +GENERATE_TEST_2D(PatchTestTriP3, "patch_test_tris.json", 3, 1.5e-14); + +GENERATE_TEST_2D(PatchTestTriAndQuadP1, "patch_test_tris_and_quads.json", 1, 1.0e-15); +GENERATE_TEST_2D(PatchTestTriAndQuadP2, "patch_test_tris_and_quads.json", 2, 1.0e-14); +GENERATE_TEST_2D(PatchTestTriAndQuadP3, "patch_test_tris_and_quads.json", 3, 2.0e-14); + +GENERATE_TEST_2D(WrenchTestP1, "wrench.json", 1, 1.0e-12); +GENERATE_TEST_2D(WrenchTestP2, "wrench.json", 2, 1.0e-12); +GENERATE_TEST_2D(WrenchTestP3, "wrench.json", 3, 1.0e-12); + +///////////////////////////////////////////////////////////////////////////////////////////////// + +#define GENERATE_TEST_3D(NAME, mesh, p, tolerance) \ +TEST(InterpolationTest3D, NAME) { \ + evaluation_test( \ + mesh, \ + std::function< double(vec3) >([](vec3 x) { return 3 * pow(x[0], p) + 2 * x[1] + x[2]; }), \ + std::function< vec3(vec3) >([](vec3 x) { return vec3{3 * p * pow(x[0], p - 1), 2, 1}; }), \ + p, \ + tolerance \ + ); \ +} + +GENERATE_TEST_3D(PatchTestHexP1, "patch_test_hexes.json", 1, 2.0e-15); +GENERATE_TEST_3D(PatchTestHexP2, "patch_test_hexes.json", 2, 2.0e-14); +GENERATE_TEST_3D(PatchTestHexP3, "patch_test_hexes.json", 3, 4.5e-13); + +GENERATE_TEST_3D(PatchTestTetP1, "patch_test_tets.json", 1, 5.0e-16); +GENERATE_TEST_3D(PatchTestTetP2, "patch_test_tets.json", 2, 5.0e-15); +GENERATE_TEST_3D(PatchTestTetP3, "patch_test_tets.json", 3, 2.0e-14); + +GENERATE_TEST_3D(PatchTestTetAndHexP1, "patch_test_tets_and_hexes.json", 1, 1.5e-15); +GENERATE_TEST_3D(PatchTestTetAndHexP2, "patch_test_tets_and_hexes.json", 2, 1.5e-14); +GENERATE_TEST_3D(PatchTestTetAndHexP3, "patch_test_tets_and_hexes.json", 3, 3.5e-13); diff --git a/src/serac/numerics/refactor/tests/hcurl_evaluation_tests.cpp b/src/serac/numerics/refactor/tests/hcurl_evaluation_tests.cpp new file mode 100644 index 0000000000..d873ea8615 --- /dev/null +++ b/src/serac/numerics/refactor/tests/hcurl_evaluation_tests.cpp @@ -0,0 +1,125 @@ +#include + +#include +#include + +#include "refactor/mesh.hpp" +#include "refactor/field.hpp" +#include "refactor/piola_transformations.hpp" + +#include "refactor/domain.hpp" + +#include "misc/for_constexpr.hpp" +#include "forall.hpp" + +#include "fm/types/vec.hpp" +#include "fm/types/matrix.hpp" + +using namespace fm; +using namespace refactor; + +template < typename vec_t, typename curl_t> +void evaluation_test(std::string filename, + std::function f, + std::function curl_f, + int p, + double tolerance) { + + constexpr int dim = dimension(vec_t{}); + + using mat_t = mat; + + auto mesh = Mesh::load(SERAC_MESH_DIR + filename); + + Field u = create_field(mesh, Family::Hcurl, p); + nd::array nodes = nodes_for(u, mesh); + nd::array directions = directions_for(u, mesh); + + u = forall(std::function< double(vec_t, vec_t)> ([=](vec_t x, vec_t n){ + return dot(f(x), n); + }), nodes, directions); + + for (int q = 1; q <= 1; q++) { + + Domain domain(mesh, MeshQuadratureRule(q)); + + auto x_q = evaluate(mesh.X, domain); + auto dx_dxi_q = evaluate(grad(mesh.X), isoparametric(domain)); + + auto u_q_1 = evaluate(u, domain); + auto u_xi_q = evaluate(u, isoparametric(domain)); + auto curl_u_q_1 = evaluate(curl(u), domain); + auto curl_u_xi_q = evaluate(curl(u), isoparametric(domain)); + auto u_q_2 = forall(contravariant_piola, u_xi_q, dx_dxi_q); + auto curl_u_q_2 = forall(covariant_piola, curl_u_xi_q, dx_dxi_q); + + // evaluate f, df_dx directly at each quadrature point + auto f_q = forall(f, x_q); + auto curl_f_q = forall(curl_f, x_q); + + EXPECT_LT(relative_error(flatten(u_q_1), flatten(f_q)), tolerance); + EXPECT_LT(relative_error(u_q_2, f_q), tolerance); + EXPECT_LT(relative_error(flatten(curl_u_q_1), flatten(curl_f_q)), tolerance); + EXPECT_LT(relative_error(curl_u_q_2, curl_f_q), tolerance); + + } + +} + +#if 1 +#define GENERATE_TEST_2D(NAME, mesh, p, tolerance) \ +TEST(InterpolationTest2D, NAME) { \ + evaluation_test( \ + mesh, \ + std::function< vec2(vec2) >([](vec2 x) { return vec2{x[1], -x[0]}; }), \ + std::function< double(vec2) >([](vec2 x) { return -2; }), \ + p, \ + tolerance \ + ); \ +} + +GENERATE_TEST_2D(AffineTestQuadP1, "one_quad_pure_shear.json", 1, 1.0e-15); + +//GENERATE_TEST_2D(PatchTestQuadP1, "patch_test_quads.json", 1, 1.0e-15); +GENERATE_TEST_2D(PatchTestQuadP2, "patch_test_quads.json", 2, 1.0e-14); +GENERATE_TEST_2D(PatchTestQuadP3, "patch_test_quads.json", 3, 1.0e-14); + +GENERATE_TEST_2D(HcurlPatchTestTriP1, "patch_test_tris.json", 1, 1.0e-15); +GENERATE_TEST_2D(HcurlPatchTestTriP2, "patch_test_tris.json", 2, 1.0e-14); +GENERATE_TEST_2D(HcurlPatchTestTriP3, "patch_test_tris.json", 3, 1.5e-14); + +//GENERATE_TEST_2D(PatchTestTriAndQuadP1, "patch_test_tris_and_quads.json", 1, 1.0e-15); +GENERATE_TEST_2D(PatchTestTriAndQuadP2, "patch_test_tris_and_quads.json", 2, 1.0e-14); +GENERATE_TEST_2D(PatchTestTriAndQuadP3, "patch_test_tris_and_quads.json", 3, 2.0e-14); + +GENERATE_TEST_2D(WrenchTestP1, "wrench.json", 1, 1.0e-12); +GENERATE_TEST_2D(WrenchTestP2, "wrench.json", 2, 1.0e-12); +GENERATE_TEST_2D(WrenchTestP3, "wrench.json", 3, 1.0e-12); +#endif + +///////////////////////////////////////////////////////////////////////////////////////////////// + +#define GENERATE_TEST_3D(NAME, mesh, p, tolerance) \ +TEST(InterpolationTest3D, NAME) { \ + evaluation_test( \ + mesh, \ + std::function< vec3(vec3) >([](vec3 x) { return vec3{1 + 2*x[1], 3 - 2*x[0], 4}; }), \ + std::function< vec3(vec3) >([](vec3 x) { return vec3{0, 0, -4}; }), \ + p, \ + tolerance \ + ); \ +} + +GENERATE_TEST_3D(PatchTestHexesP1, "one_hex.json", 1, 2.0e-15); + +//GENERATE_TEST_3D(PatchTestHexP1, "patch_test_hexes.json", 1, 2.0e-15); +GENERATE_TEST_3D(PatchTestHexP2, "patch_test_hexes.json", 2, 2.0e-14); +GENERATE_TEST_3D(PatchTestHexP3, "patch_test_hexes.json", 3, 4.5e-13); + +GENERATE_TEST_3D(PatchTestTetP1, "patch_test_tets.json", 1, 3.5e-16); +GENERATE_TEST_3D(PatchTestTetP2, "patch_test_tets.json", 2, 5.0e-15); +GENERATE_TEST_3D(PatchTestTetP3, "patch_test_tets.json", 3, 2.0e-14); + +//GENERATE_TEST_3D(PatchTestTetAndHexP1, "patch_test_tets_and_hexes.json", 1, 1.5e-15); +GENERATE_TEST_3D(PatchTestTetAndHexP2, "patch_test_tets_and_hexes.json", 2, 1.5e-14); +GENERATE_TEST_3D(PatchTestTetAndHexP3, "patch_test_tets_and_hexes.json", 3, 3.5e-13); diff --git a/src/serac/numerics/refactor/tests/integrate_residual_H1_flux_tests.cpp b/src/serac/numerics/refactor/tests/integrate_residual_H1_flux_tests.cpp new file mode 100644 index 0000000000..0be285c718 --- /dev/null +++ b/src/serac/numerics/refactor/tests/integrate_residual_H1_flux_tests.cpp @@ -0,0 +1,135 @@ +#include + +#include +#include +#include + +#include "refactor/mesh.hpp" +#include "refactor/domain.hpp" + +#include "forall.hpp" +#include "fm/types/vec.hpp" +#include "fm/types/matrix.hpp" +#include "containers/ndarray_conversions.hpp" + +using namespace fm; +using namespace refactor; + +// ---------------------------------------------------------------------------- + +template < typename vecd > +void flux_test(std::string filename, + std::function< double(vecd, int) > f, + std::function< vecd(vecd) > g, + std::function< double(int) > answer, + double tolerance) { + + using matd = decltype(outer(vecd{}, vecd{})); + + auto mesh = Mesh::load(SERAC_MESH_DIR + filename); + + // evaluate g at each quadrature point + std::function< vecd(vecd, matd) > g_xi = [g](vecd x, matd J) { + return dot(fm::inv(J), g(x)) * det(J); + }; + + for (int p = 1; p < 4; p++) { + + std::function< double(vecd) > f_p = [f, p](vecd x) { return f(x, p); }; + + Field u = create_field(mesh, Family::H1, p, 1); + nd::array nodes = nodes_for(u, mesh); + u = forall(f_p, nodes); + + BasisFunction phi(u); + + for (int q = p + 1; q < 5; q++) { + + Domain domain(mesh, MeshQuadratureRule(q)); + + auto x_q = evaluate(mesh.X, domain); + auto dx_dxi_q = evaluate(grad(mesh.X), isoparametric(domain)); + + auto g_q = forall(g, x_q); + auto g_xi_q = forall(g_xi, x_q, dx_dxi_q); + + Residual r1 = integrate(dot(g_q, grad(phi)), domain); + Residual r2 = integrate(dot(g_xi_q, grad(phi)), isoparametric(domain)); + + SCOPED_TRACE("p = " + std::to_string(p) + ", q = " + std::to_string(q)); + EXPECT_NEAR(dot(r1, u), answer(p), tolerance); + EXPECT_NEAR(dot(r2, u), answer(p), tolerance); + + } + } + +} + +// ---------------------------------------------------------------------------- + +/* + In[] := + f[x_] := x^p + 3; + gradf[x_] := p x^(p-1); + g[x_] := x; + Integrate[gradf[x] g[x], {x, 0, 1}] + + -------------------- + + Out[] := + 1/2 +*/ + +std::function f3([](double x, int p){ return pow(x, p); }); +std::function g3([](double x){ return x; }); +std::function answer3([](int p){ return double(p) / double(1 + p); }); + +TEST(IntegrateTest, FluxH1Edges) { flux_test("patch_test_edges.json", f3, g3, answer3, 3.0e-15); } + +// ---------------------------------------------------------------------------- + +/* + In[] := + f[{x_, y_}] := x^p - y + 3; + gradf[{x_, y_}] := {p x^(-1 + p), -1}; + g[{x_, y_}] := {y, -x}; + Integrate[gradf[{x, y}] . g[{x, y}], {x, y} \[Element] Rectangle[{0, 0}, {1, 1}]] + + -------------------- + + Out[] := + 1 +*/ + +std::function f4([](vec2 x, int p){ return pow(x[0], p) - x[1] + 3.0; }); +std::function g4([](vec2 x){ return vec2{x[1], -x[0]}; }); +std::function answer4([](int){ return 1.0; }); + +TEST(IntegrateTest, FluxH1Tris) { flux_test("patch_test_tris.json", f4, g4, answer4, 5.0e-15); } +TEST(IntegrateTest, FluxH1Quads) { flux_test("patch_test_quads.json", f4, g4, answer4, 5.0e-15); } +TEST(IntegrateTest, FluxH1Both) { flux_test("patch_test_tris_and_quads.json", f4, g4, answer4, 5.0e-15); } +TEST(IntegrateTest, FluxH1TrisFine) { flux_test("unit_square_of_tris_fine.json", f4, g4, answer4, 8.0e-14); } +TEST(IntegrateTest, FluxH1QuadsFine) { flux_test("unit_square_of_quads_fine.json", f4, g4, answer4, 8.0e-14); } + +// ---------------------------------------------------------------------------- + +/* + In[] := + f[{x_, y_, z_}] := x^p - y - 2 z + 3; + gradf[{x_, y_, z_}] := {p x^(-1 + p), -1, -2}; + g[{x_, y_, z_}] := {z, x, -y}; + Integrate[gradf[{x, y, z}] . g[{x, y, z}], {x, y, z} \[Element] Cuboid[{0, 0, 0}, {1, 1, 1}]] + + -------------------- + + Out[] := + 1 +*/ +std::function f5([](vec3 x, int p){ return pow(x[0], p) - x[1] - 2 * x[2] + 3.0; }); +std::function g5([](vec3 x){ return vec3{x[2], x[0], -x[1]}; }); +std::function answer5([](int){ return 1.0; }); + +TEST(IntegrateTest, FluxH1Tets) { flux_test("patch_test_tets.json", f5, g5, answer5, 5.0e-15); } +TEST(IntegrateTest, FluxH1Hexes) { flux_test("patch_test_hexes.json", f5, g5, answer5, 5.0e-15); } +TEST(IntegrateTest, FluxH1TetsFine) { flux_test("unit_cube_of_tets_fine.json", f5, g5, answer5, 5.0e-14); } +TEST(IntegrateTest, FluxH1HexesFine) { flux_test("unit_cube_of_hexes_fine.json", f5, g5, answer5, 5.0e-15); } diff --git a/src/serac/numerics/refactor/tests/integrate_residual_H1_source_tests.cpp b/src/serac/numerics/refactor/tests/integrate_residual_H1_source_tests.cpp new file mode 100644 index 0000000000..fa2e6ad27e --- /dev/null +++ b/src/serac/numerics/refactor/tests/integrate_residual_H1_source_tests.cpp @@ -0,0 +1,131 @@ +#include + +#include +#include +#include + +#include "refactor/mesh.hpp" +#include "refactor/domain.hpp" + +#include + +#include "forall.hpp" +#include "fm/types/vec.hpp" +#include "fm/types/matrix.hpp" +#include "containers/ndarray_conversions.hpp" + +using namespace refactor; + +// ---------------------------------------------------------------------------- + +template < typename vecd > +void integrate_source_test(std::string filename, + std::function< double(vecd, int) > f, + std::function< double(vecd) > g, + std::function< double(int) > answer, + double tolerance) { + + using matd = decltype(outer(vecd{}, vecd{})); + + auto mesh = Mesh::load(SERAC_MESH_DIR + filename); + + std::cout << std::setprecision(15); + + // evaluate g at each quadrature point + std::function< double(vecd, matd) > g_detJ = [g](vecd x, matd J) { + return g(x) * det(J); + }; + + for (int p = 1; p < 4; p++) { + + std::function< double(vecd) > f_p = [f, p](vecd x) { return f(x,p); }; + + Field u = create_field(mesh, Family::H1, p, 1); + nd::array nodes = nodes_for(u, mesh); + u = forall(f_p, nodes); + + BasisFunction phi(u); + + for (int q = p + 1; q < 5; q++) { + + Domain domain(mesh, MeshQuadratureRule(q)); + + auto x_q = evaluate(mesh.X, domain); + auto dx_dxi_q = evaluate(grad(mesh.X), isoparametric(domain)); + + auto g_q = forall(g, x_q); + auto g_detJ_q = forall(g_detJ, x_q, dx_dxi_q); + + Residual r1 = integrate(g_q * phi, domain); + Residual r2 = integrate(g_detJ_q * phi, isoparametric(domain)); + + SCOPED_TRACE("p = " + std::to_string(p) + ", q = " + std::to_string(q)); + EXPECT_NEAR(dot(r1, u), answer(p), tolerance); + EXPECT_NEAR(dot(r2, u), answer(p), tolerance); + + } + } + +} + +// ---------------------------------------------------------------------------- + +/* + In[] := + f[x_] := x^p + 3; + g[x_] := x; + Integrate[f[x] g[x], {x, 0, 1}] + + -------------------- + + Out[] := + (3.0/2.0) + 1.0 / (2.0 + p) +*/ +std::function f0([](double x, int p){ return pow(x, p) + 3.0; }); +std::function g0([](double x){ return x; }); +std::function answer0([](int p){ return 1.5 + 1.0 / (2 + p); }); + +TEST(IntegrateTest, SourceH1Edge) { integrate_source_test("patch_test_edges.json", f0, g0, answer0, 3.0e-2); } + +// ---------------------------------------------------------------------------- + +/* + In[] := + f[{x_, y_}] := x^p - y + 3; + g[{x_, y_}] := y; + Integrate[f[{x, y}] g[{x, y}], {x, y} \[Element] Rectangle[{0, 0}, {1, 1}]] + + -------------------- + + Out[] := + (7.0/6.0) + 1.0 /(2.0 + 2.0 * p) +*/ +std::function f1([](vec2 x, int p){ return pow(x[0], p) - x[1] + 3.0; }); +std::function g1([](vec2 x){ return x[1]; }); +std::function answer1([](int p){ return (7.0/6.0) + 1.0 /(2.0 + 2.0 * p); }); + +TEST(IntegrateTest, SourceH1Tris) { integrate_source_test("patch_test_tris.json", f1, g1, answer1, 3.0e-15); } +TEST(IntegrateTest, SourceH1Quads) { integrate_source_test("patch_test_quads.json", f1, g1, answer1, 1.0e-15); } +TEST(IntegrateTest, SourceH1Both) { integrate_source_test("patch_test_tris_and_quads.json", f1, g1, answer1, 1.0e-15); } + +// ---------------------------------------------------------------------------- + +/* + In[] := + f[{x_, y_, z_}] := x^p - y - z + 3; + g[{x_, y_, z_}] := 1; + Integrate[f[{x, y, z}] g[{x, y, z}], {x, y, z} \[Element] Cuboid[{0, 0, 0}, {1, 1, 1}]] + + -------------------- + + Out[] := + 2.0 + 1.0 / (1.0 + p) +*/ +std::function f2([](vec3 x, int p){ return pow(x[0], p) - x[1] - x[2] + 3.0; }); +std::function g2([](vec3 x){ return 1.0; }); +std::function answer2([](int p){ return 2.0 + 1.0 / (1.0 + p); }); + +TEST(IntegrateTest, SourceH1Tets) { integrate_source_test("patch_test_tets.json", f2, g2, answer2, 7.0e-15); } +TEST(IntegrateTest, SourceH1Hexes) { integrate_source_test("patch_test_hexes.json", f2, g2, answer2, 1.0e-15); } +TEST(IntegrateTest, SourceH1TetsFine) { integrate_source_test("unit_cube_of_tets_fine.json", f2, g2, answer2, 5.0e-14); } +TEST(IntegrateTest, SourceH1HexesFine) { integrate_source_test("unit_cube_of_hexes_fine.json", f2, g2, answer2, 2.0e-14); } diff --git a/src/serac/numerics/refactor/tests/integrate_residual_H1v_flux_tests.cpp b/src/serac/numerics/refactor/tests/integrate_residual_H1v_flux_tests.cpp new file mode 100644 index 0000000000..fd082514b1 --- /dev/null +++ b/src/serac/numerics/refactor/tests/integrate_residual_H1v_flux_tests.cpp @@ -0,0 +1,131 @@ +#include + +#include +#include +#include + +#include "refactor/mesh.hpp" +#include "refactor/domain.hpp" + +#include + +#include "forall.hpp" +#include "fm/types/vec.hpp" +#include "fm/types/matrix.hpp" +#include "containers/ndarray_conversions.hpp" + +using namespace refactor; + +// ---------------------------------------------------------------------------- + +template < typename vecd > +void flux_test(std::string filename, + std::function< double(vecd, int) > f, + std::function< vecd(vecd) > g, + std::function< double(int) > answer, + double tolerance) { + + constexpr int dim = dimension(vecd{}); + + double scale_factor = (dim == 2) ? 5.0 : 14.0; + + using matd = decltype(outer(vecd{}, vecd{})); + + auto mesh = Mesh::load(SERAC_MESH_DIR + filename); + + // evaluate g at each quadrature point + std::function< matd(vecd, matd) > qf = [g](vecd x, matd J) { + matd output{}; + for (int i = 0; i < dim; i++) { + output[i] = dot(inv(J), g(x)) * det(J) * (i + 1); + } + return output; + }; + + for (int p = 1; p < 4; p++) { + + std::function< vecd(vecd) > f_p = [f, p](vecd x) { + vecd output; + for (int i = 0; i < dim; i++) { + output[i] = f(x, p) * (i + 1); + } + return output; + }; + + Field u = create_field(mesh, Family::H1, p, dim); + nd::array nodes = nodes_for(u, mesh); + u = forall(f_p, nodes); + + BasisFunction phi(u); + + for (int q = p + 1; q < 5; q++) { + + Domain domain(mesh, MeshQuadratureRule(q)); + + auto x_q = evaluate(mesh.X, domain); + auto dx_dxi_q = evaluate(grad(mesh.X), isoparametric(domain)); + + auto g_q = forall(qf, x_q, dx_dxi_q); + + Residual r = integrate(dot(g_q, grad(phi)), isoparametric(domain)); + + SCOPED_TRACE("p = " + std::to_string(p) + ", q = " + std::to_string(q)); + EXPECT_NEAR(dot(r, u), scale_factor * answer(p), tolerance); + + } + } + +} + +// ---------------------------------------------------------------------------- + +// note: edge element tests omitted, since they are 1D elements so this test would +// just duplicate what is already in integrate_H1_flux_tests.cpp + +// ---------------------------------------------------------------------------- + +/* + In[] := + f[{x_, y_}] := x^p - y + 3; + gradf[{x_, y_}] := {p x^(-1 + p), -1}; + g[{x_, y_}] := {y, -x}; + Integrate[gradf[{x, y}] . g[{x, y}], {x, y} \[Element] Rectangle[{0, 0}, {1, 1}]] + + -------------------- + + Out[] := + 1 +*/ + +std::function f4([](vec2 x, int p){ return pow(x[0], p) - x[1] + 3.0; }); +std::function g4([](vec2 x){ return vec2{x[1], -x[0]}; }); +std::function answer4([](int){ return 1.0; }); + +TEST(IntegrateTest, FluxH1Tris) { flux_test("patch_test_tris.json", f4, g4, answer4, 5.0e-14); } +TEST(IntegrateTest, FluxH1Quads) { flux_test("patch_test_quads.json", f4, g4, answer4, 5.0e-14); } +TEST(IntegrateTest, FluxH1Both) { flux_test("patch_test_tris_and_quads.json", f4, g4, answer4, 5.0e-14); } +TEST(IntegrateTest, FluxH1TrisFine) { flux_test("unit_square_of_tris_fine.json", f4, g4, answer4, 8.0e-13); } +TEST(IntegrateTest, FluxH1QuadsFine) { flux_test("unit_square_of_quads_fine.json", f4, g4, answer4, 8.0e-13); } + +// ---------------------------------------------------------------------------- + +/* + In[] := + f[{x_, y_, z_}] := x^p - y - 2 z + 3; + gradf[{x_, y_, z_}] := {p x^(-1 + p), -1, -2}; + g[{x_, y_, z_}] := {z, x, -y}; + Integrate[gradf[{x, y, z}] . g[{x, y, z}], {x, y, z} \[Element] Cuboid[{0, 0, 0}, {1, 1, 1}]] + + -------------------- + + Out[] := + 1 +*/ +std::function f5([](vec3 x, int p){ return pow(x[0], p) - x[1] - 2 * x[2] + 3.0; }); +std::function g5([](vec3 x){ return vec3{x[2], x[0], -x[1]}; }); +std::function answer5([](int){ return 1.0; }); + +TEST(IntegrateTest, FluxH1Tets) { flux_test("patch_test_tets.json", f5, g5, answer5, 1.0e-13); } +TEST(IntegrateTest, FluxH1Hexes) { flux_test("patch_test_hexes.json", f5, g5, answer5, 1.0e-13); } +TEST(IntegrateTest, FluxH1TetsFine) { flux_test("unit_cube_of_tets_fine.json", f5, g5, answer5, 1.0e-13); } +TEST(IntegrateTest, FluxH1HexesFine) { flux_test("unit_cube_of_hexes_fine.json", f5, g5, answer5, 1.0e-13); } diff --git a/src/serac/numerics/refactor/tests/integrate_residual_Hcurl_flux_tests.cpp b/src/serac/numerics/refactor/tests/integrate_residual_Hcurl_flux_tests.cpp new file mode 100644 index 0000000000..ee0ac5c2d4 --- /dev/null +++ b/src/serac/numerics/refactor/tests/integrate_residual_Hcurl_flux_tests.cpp @@ -0,0 +1,135 @@ +#include + +#include +#include +#include + +#include "refactor/mesh.hpp" +#include "refactor/domain.hpp" + +#include + +#include "forall.hpp" +#include "fm/types/vec.hpp" +#include "fm/types/matrix.hpp" +#include "containers/ndarray_conversions.hpp" + +using namespace refactor; + +// ---------------------------------------------------------------------------- + +template < typename vec_t, typename curl_t > +void integrate_flux_test(std::string filename, + std::function< vec_t(vec_t, int) > f, + std::function< curl_t(vec_t) > g, + std::function< double(int) > answer, + double tolerance) { + + using mat_t = decltype(outer(vec_t{}, vec_t{})); + + auto mesh = Mesh::load(SERAC_MESH_DIR + filename); + + std::cout << std::setprecision(15); + + // evaluate g at each quadrature point + std::function< curl_t(vec_t, mat_t) > g_xi = [g](vec_t x, mat_t J) { + // note: detJ cancels out here, since it appears in the numerator from + // the change of coordinates, but also in the denominator from the covariant piola + if constexpr (std::is_same< mat_t, mat2 >::value) { + return g(x); + } else { + return dot(transpose(J), g(x)); + } + }; + + for (int p = 1; p < 4; p++) { + + std::function< double(vec_t, vec_t) > f_p = [f, p](vec_t x, vec_t n) { + return dot(f(x,p), n) ; + }; + + Field u = create_field(mesh, Family::Hcurl, p, 1); + nd::array nodes = nodes_for(u, mesh); + nd::array directions = directions_for(u, mesh); + u = forall(f_p, nodes, directions); + + BasisFunction phi(u); + + for (int q = p + 1; q < 5; q++) { + + Domain domain(mesh, MeshQuadratureRule(q)); + + auto x_q = evaluate(mesh.X, domain); + auto dx_dxi_q = evaluate(grad(mesh.X), isoparametric(domain)); + + nd::array g_q = forall(g, x_q); + nd::array g_xi_q = forall(g_xi, x_q, dx_dxi_q); + + Residual r1 = integrate(dot(g_q, curl(phi)), domain); + Residual r2 = integrate(dot(g_xi_q, curl(phi)), isoparametric(domain)); + + SCOPED_TRACE("p = " + std::to_string(p) + ", q = " + std::to_string(q)); + EXPECT_NEAR(dot(r1, u), answer(p), tolerance); + EXPECT_NEAR(dot(r2, u), answer(p), tolerance); + + } + } + +} + +// ---------------------------------------------------------------------------- + +/* + In[] := + f[{x_, y_}] := {3 + y, 2 - x}; + g[{x_, y_}] := x + y; + Integrate[Curl[f[{x, y}], {x, y}] g[{x, y}], {x, y} \[Element] Rectangle[{0, 0}, {1, 1}]] + + -------------------- + + Out[] := + -2.0 +*/ +std::function f1([](vec2 x, int p){ return vec2{3 + x[1], 2 - x[0]}; }); +std::function g1([](vec2 x){ return x[0] + x[1]; }); +std::function answer1([](int p){ return -2.0; }); + +// note: non affinely-transformed low-order quadrilateral elements can't exactly reproduce the +// functions in this test, so for p=1 those tests have some small finite error +// which decreases with mesh refinement +TEST(IntegrateTest, FluxHcurlTris) { integrate_flux_test("patch_test_tris.json", f1, g1, answer1, 5.0e-14); } +TEST(IntegrateTest, FluxHcurlQuads) { integrate_flux_test("patch_test_quads.json", f1, g1, answer1, 1.0e-2); } +TEST(IntegrateTest, FluxHcurlQuadsFine) { integrate_flux_test("unit_square_of_quads_fine.json", f1, g1, answer1, 1.0e-5); } +TEST(IntegrateTest, FluxHcurlBoth) { integrate_flux_test("patch_test_tris_and_quads.json", f1, g1, answer1, 1.0e-3); } +TEST(IntegrateTest, FluxHcurlTrisFine) { integrate_flux_test("unit_square_of_tris_fine.json", f1, g1, answer1, 1.5e-13); } + +// ---------------------------------------------------------------------------- + +/* + In[] := + f[{x_, y_, z_}] := {y + 3, 2 - x - z, 1 + y}; + g[{x_, y_, z_}] := {y, z, 2 x}; + Integrate[Curl[f[{x, y, z}], {x, y, z}] g[{x, y, z}], {x, y, z} \[Element] Tetrahedron[{{0, 0, 0}, {1, 0, 0}, {0, 1, 0}, {0, 0, 1}}]] + Integrate[Curl[f[{x, y, z}], {x, y, z}] g[{x, y, z}], {x, y, z} \[Element] Cuboid[{0, 0, 0}, {1, 1, 1}]] + Integrate[Curl[f[{x, y, z}], {x, y, z}] g[{x, y, z}], {x, y, z} \[Element] Cuboid[{0, 0, 0}, {2, 1, 1}]] + + -------------------- + + Out[] := + -1.0 / 12.0 + -1.0 + -6.0 +*/ +std::function< vec3(vec3, int) > f2([](vec3 x, int p) { return vec3{3 + x[1], 2 - x[0] - x[2], 1 + x[1]}; }); +std::function< vec3(vec3) > g2([](vec3 x) { return vec3{x[1], x[2], 2 * x[0]}; }); +std::function< double(int)> answer2([](int p){ return -1.0 / 12.0; }); +std::function< double(int)> answer3([](int p){ return -1.0; }); +std::function< double(int)> answer4([](int p){ return -6.0; }); + +TEST(IntegrateTest, FluxHcurlOneTet) { integrate_flux_test("one_tet.json", f2, g2, answer2, 1.0e-13); } +TEST(IntegrateTest, FluxHcurlOneHex) { integrate_flux_test("one_hex.json", f2, g2, answer3, 1.0e-13); } + +TEST(IntegrateTest, FluxHcurlTets) { integrate_flux_test("patch_test_tets.json", f2, g2, answer3, 1.0e-13); } +TEST(IntegrateTest, FluxHcurlHexes) { integrate_flux_test("patch_test_hexes.json", f2, g2, answer3, 1.0e-1); } +TEST(IntegrateTest, FluxHcurlHexesFine) { integrate_flux_test("unit_cube_of_hexes_fine.json", f2, g2, answer3, 5.0e-4); } +TEST(IntegrateTest, FluxHcurlTetsAndHexes) { integrate_flux_test("patch_test_tets_and_hexes.json", f2, g2, answer4, 1.0e-1); } diff --git a/src/serac/numerics/refactor/tests/integrate_residual_Hcurl_source_tests.cpp b/src/serac/numerics/refactor/tests/integrate_residual_Hcurl_source_tests.cpp new file mode 100644 index 0000000000..d961470d50 --- /dev/null +++ b/src/serac/numerics/refactor/tests/integrate_residual_Hcurl_source_tests.cpp @@ -0,0 +1,143 @@ +#include + +#include +#include +#include + +#include "refactor/mesh.hpp" +#include "refactor/domain.hpp" + +#include + +#include "forall.hpp" +#include "fm/types/vec.hpp" +#include "fm/types/matrix.hpp" +#include "containers/ndarray_conversions.hpp" + +using namespace refactor; + +// ---------------------------------------------------------------------------- + +template < typename vecd > +void integrate_source_test(std::string filename, + std::function< vecd(vecd, int) > f, + std::function< vecd(vecd) > g, + std::function< double(int) > answer, + double tolerance) { + + using matd = decltype(outer(vecd{}, vecd{})); + + auto mesh = Mesh::load(SERAC_MESH_DIR + filename); + + std::cout << std::setprecision(15); + + // evaluate g at each quadrature point + std::function< vecd(vecd, matd) > g_xi = [g](vecd x, matd J) { + return dot(inv(J), g(x)) * det(J); + }; + + for (int p = 1; p < 4; p++) { + + std::function< double(vecd, vecd) > f_p = [f, p](vecd x, vecd n) { return dot(f(x,p), n) ; }; + + Field u = create_field(mesh, Family::Hcurl, p, 1); + nd::array nodes = nodes_for(u, mesh); + nd::array directions = directions_for(u, mesh); + u = forall(f_p, nodes, directions); + + BasisFunction phi(u); + + for (int q = p + 1; q < 5; q++) { + + Domain domain(mesh, MeshQuadratureRule(q)); + + auto x_q = evaluate(mesh.X, domain); + auto dx_dxi_q = evaluate(grad(mesh.X), isoparametric(domain)); + + nd::array g_q = forall(g, x_q); + nd::array g_xi_q = forall(g_xi, x_q, dx_dxi_q); + + Residual r1 = integrate(g_q * phi, domain); + Residual r2 = integrate(g_xi_q * phi, isoparametric(domain)); + + SCOPED_TRACE("p = " + std::to_string(p) + ", q = " + std::to_string(q)); + EXPECT_NEAR(dot(r1, u), answer(p), tolerance); + EXPECT_NEAR(dot(r2, u), answer(p), tolerance); + + EXPECT_NEAR(relative_error(r1.data, r2.data), 0.0, 1.0e-14); + + } + } + +} + +// ---------------------------------------------------------------------------- + +/* + In[] := + f[{x_, y_}] := {1, 3}; + g[{x_, y_}] := {1 + y, 2 - x}; + Integrate[f[{x, y}] . g[{x, y}], {x, y} \[Element] Rectangle[{0, 0}, {1, 1}]] + + -------------------- + + Out[] := + 6.0 +*/ +std::function f1([](vec2 x, int p){ return vec2{1, 3}; }); +std::function g1([](vec2 x){ return vec2{1 + x[1], 2 - x[0]}; }); +std::function answer1([](int p){ return 6.0; }); +TEST(IntegrateTest, SourceHcurlTris) { integrate_source_test("patch_test_tris.json", f1, g1, answer1, 1.5e-14); } +TEST(IntegrateTest, SourceHcurlQuads) { integrate_source_test("patch_test_quads.json", f1, g1, answer1, 1.0e-14); } +TEST(IntegrateTest, SourceHcurlBoth) { integrate_source_test("patch_test_tris_and_quads.json", f1, g1, answer1, 1.0e-14); } + +/* + In[] := + f[{x_, y_}] := {1 + 2 y, 3 - 2 x}; + g[{x_, y_}] := {2, 3}; + Integrate[f[{x, y}] . g[{x, y}], {x, y} \[Element] Triangle[{{0, 0}, {1, 0}, {0, 1}}]] + Integrate[f[{x, y}] . g[{x, y}], {x, y} \[Element] Triangle[{{0, 0}, {1, 0}, {1, 1}}]] + + -------------------- + + Out[] := + 31.0 / 6.0 + 25.0 / 6.0 +*/ +std::function f2([](vec2 x, int p){ return vec2{1 + 2 * x[1], 3 - 2 * x[0]}; }); +std::function g2([](vec2 x){ return vec2{2.0, 3.0}; }); +std::function answer2([](int p){ return 31.0 / 6.0; }); +std::function answer3([](int p){ return 25.0 / 6.0; }); +TEST(IntegrateTest, SourceHcurlOneTri) { integrate_source_test("one_tri.json", f2, g2, answer2, 3.0e-14); } +TEST(IntegrateTest, SourceHcurlOneTriRotated) { integrate_source_test("one_tri_rotated.json", f2, g2, answer2, 3.0e-14); } +TEST(IntegrateTest, SourceHcurlOneTriSheared) { integrate_source_test("one_tri_sheared.json", f2, g2, answer3, 3.0e-14); } + +// ---------------------------------------------------------------------------- + +/* + In[] := + f[{x_, y_, z_}] := {1, 2, 3}; + g[{x_, y_, z_}] := {2, 2, 4}; + Integrate[f[{x, y, z}] . g[{x, y, z}], {x, y, z} \[Element] Tetrahedron[{{0, 0, 0}, {1, 0, 0}, {0, 1, 0}, {0, 0, 1}}]] + Integrate[f[{x, y, z}] . g[{x, y, z}], {x, y, z} \[Element] Cuboid[{0, 0, 0}, {1, 1, 1}]] + Integrate[f[{x, y, z}] . g[{x, y, z}], {x, y, z} \[Element] Cuboid[{0, 0, 0}, {2, 1, 1}]] + + -------------------- + + Out[] := + 3 + 18 + 36 +*/ +std::function< vec3(vec3, int) > f3([](vec3 x, int p) { return vec3{1, 2, 3}; }); +std::function< vec3(vec3) > g3([](vec3 x) { return vec3{2, 2, 4}; }); +std::function answer4([](int p){ return 3.0; }); +std::function answer5([](int p){ return 18.0; }); +std::function answer6([](int p){ return 36.0; }); + +TEST(IntegrateTest, SourceHcurlOneTet) { integrate_source_test("one_tet.json", f3, g3, answer4, 1.0e-13); } +TEST(IntegrateTest, SourceHcurlOneHex) { integrate_source_test("one_hex.json", f3, g3, answer5, 1.0e-13); } + +TEST(IntegrateTest, SourceHcurlTets) { integrate_source_test("patch_test_tets.json", f3, g3, answer5, 1.0e-13); } +TEST(IntegrateTest, SourceHcurlHexes) { integrate_source_test("patch_test_hexes.json", f3, g3, answer5, 1.0e-13); } +TEST(IntegrateTest, SourceHcurlTetsAndHexes) { integrate_source_test("patch_test_tets_and_hexes.json", f3, g3, answer6, 1.0e-13); } From 7f3b5487f0a79b7b935cb9fbc310624247792fcf Mon Sep 17 00:00:00 2001 From: Sam Mish Date: Fri, 13 Dec 2024 14:32:52 -0800 Subject: [PATCH 04/15] bring in integrate / evaluate implementations, start migrating some types to MFEM equivalents --- src/serac/numerics/CMakeLists.txt | 2 + .../functional/detail/metaprogramming.hpp | 9 + src/serac/numerics/refactor/CMakeLists.txt | 55 ++ src/serac/numerics/refactor/common.cpp | 171 ++++++ src/serac/numerics/refactor/common.hpp | 294 +++++++++ .../numerics/refactor/containers/memory.cpp | 23 + .../numerics/refactor/containers/memory.cu | 37 ++ .../numerics/refactor/containers/ndarray.cpp | 0 .../numerics/refactor/containers/ndarray.hpp | 578 ++++++++++++++++++ .../refactor/containers/relative_error.cpp | 26 + .../refactor/containers/stack_array.hpp | 42 ++ .../numerics/refactor/elements/h1_edge.hpp | 14 +- .../refactor/elements/h1_hexahedron.hpp | 12 +- .../refactor/elements/h1_quadrilateral.hpp | 8 +- .../refactor/elements/h1_tetrahedron.hpp | 8 +- .../refactor/elements/h1_triangle.hpp | 8 +- .../numerics/refactor/elements/h1_vertex.hpp | 4 +- .../numerics/refactor/elements/hcurl_edge.hpp | 14 +- .../refactor/elements/hcurl_hexahedron.hpp | 16 +- .../refactor/elements/hcurl_quadrilateral.hpp | 12 +- .../refactor/elements/hcurl_tetrahedron.hpp | 14 +- .../refactor/elements/hcurl_triangle.hpp | 14 +- .../refactor/elements/hcurl_vertex.hpp | 4 +- src/serac/numerics/refactor/evaluate.cpp | 248 ++++++++ .../numerics/refactor/finite_element.hpp | 54 +- src/serac/numerics/refactor/geometry.hpp | 290 +++++++++ .../numerics/refactor/integrate_diag.cpp | 311 ++++++++++ .../numerics/refactor/integrate_residual.cpp | 271 ++++++++ .../numerics/refactor/integrate_spmat.cpp | 339 ++++++++++ .../numerics/refactor/tests/CMakeLists.txt | 22 + .../refactor/tests/h1_evaluation_tests.cpp | 12 +- 31 files changed, 2810 insertions(+), 102 deletions(-) create mode 100644 src/serac/numerics/refactor/CMakeLists.txt create mode 100644 src/serac/numerics/refactor/common.cpp create mode 100644 src/serac/numerics/refactor/common.hpp create mode 100644 src/serac/numerics/refactor/containers/memory.cpp create mode 100644 src/serac/numerics/refactor/containers/memory.cu create mode 100644 src/serac/numerics/refactor/containers/ndarray.cpp create mode 100644 src/serac/numerics/refactor/containers/ndarray.hpp create mode 100644 src/serac/numerics/refactor/containers/relative_error.cpp create mode 100644 src/serac/numerics/refactor/containers/stack_array.hpp create mode 100644 src/serac/numerics/refactor/evaluate.cpp create mode 100644 src/serac/numerics/refactor/geometry.hpp create mode 100644 src/serac/numerics/refactor/integrate_diag.cpp create mode 100644 src/serac/numerics/refactor/integrate_residual.cpp create mode 100644 src/serac/numerics/refactor/integrate_spmat.cpp create mode 100644 src/serac/numerics/refactor/tests/CMakeLists.txt diff --git a/src/serac/numerics/CMakeLists.txt b/src/serac/numerics/CMakeLists.txt index 8ea67ec6b8..a0a2ff0e50 100644 --- a/src/serac/numerics/CMakeLists.txt +++ b/src/serac/numerics/CMakeLists.txt @@ -6,6 +6,8 @@ add_subdirectory(functional) +add_subdirectory(refactor) + set(numerics_headers equation_solver.hpp odes.hpp diff --git a/src/serac/numerics/functional/detail/metaprogramming.hpp b/src/serac/numerics/functional/detail/metaprogramming.hpp index 66b7d4be30..45a32230aa 100644 --- a/src/serac/numerics/functional/detail/metaprogramming.hpp +++ b/src/serac/numerics/functional/detail/metaprogramming.hpp @@ -98,3 +98,12 @@ SERAC_HOST_DEVICE constexpr void for_constexpr(const lambda& f) { detail::for_constexpr(f, std::make_integer_sequence{}...); } + + +namespace impl { +} + +template < auto ... args, typename T > +void foreach_constexpr(T && function) { + (function(impl::value{}), ...); +} diff --git a/src/serac/numerics/refactor/CMakeLists.txt b/src/serac/numerics/refactor/CMakeLists.txt new file mode 100644 index 0000000000..0086126b69 --- /dev/null +++ b/src/serac/numerics/refactor/CMakeLists.txt @@ -0,0 +1,55 @@ +# Copyright (c) 2019-2024, Lawrence Livermore National Security, LLC and +# other Serac Project Developers. See the top-level LICENSE file for +# details. +# +# SPDX-License-Identifier: (BSD-3-Clause) + +set(refactor_headers + + elements/h1_edge.hpp + elements/h1_hexahedron.hpp + elements/h1_quadrilateral.hpp + elements/h1_tetrahedron.hpp + elements/h1_triangle.hpp + elements/h1_vertex.hpp + + elements/hcurl_edge.hpp + elements/hcurl_hexahedron.hpp + elements/hcurl_quadrilateral.hpp + elements/hcurl_tetrahedron.hpp + elements/hcurl_triangle.hpp + elements/hcurl_vertex.hpp + + common.hpp + evaluate.hpp + integrate.hpp + +) + +set(refactor_sources + common.cpp + evaluate.cpp + integrate_diag.cpp + integrate_spmat.cpp + integrate_residual.cpp +) + +set(refactor_depends serac_infrastructure serac_functional) + +blt_add_library( + NAME serac_refactor + HEADERS ${refactor_headers} + SOURCES ${refactor_sources} + DEPENDS_ON ${refactor_depends} + ) + +install(FILES ${refactor_headers} DESTINATION include/serac/refactor ) + +install(TARGETS serac_refactor + EXPORT serac-targets + DESTINATION lib + ) + +if(SERAC_ENABLE_TESTS) + add_subdirectory(tests) +endif() diff --git a/src/serac/numerics/refactor/common.cpp b/src/serac/numerics/refactor/common.cpp new file mode 100644 index 0000000000..e5fa640ae9 --- /dev/null +++ b/src/serac/numerics/refactor/common.cpp @@ -0,0 +1,171 @@ +#include "common.hpp" + +#include "refactor/domain.hpp" +#include "refactor/assert.hpp" +#include "refactor/threadpool.hpp" + +#include "misc/timer.hpp" + +#include "parallel_hashmap/phmap.h" + +namespace refactor { + +uint32_t elements_per_block(mfem::Geometry::Type geom, Family family, int p) { + + uint32_t gid = uint32_t(geom); + uint32_t fid = uint32_t(family); + + uint32_t values[6][2][4] = { + + // vertex + {{{}}}, + + // edge + { + {0, 32, 16, 16}, // H1 + {0, 1, 1, 1}, // Hcurl + }, + + // triangle + { + {0, 32, 16, 16}, // H1 + {0, 1, 1, 1}, // Hcurl + }, + + // quadrilateral + { + {0, 32, 14, 8}, // H1 + {0, 1, 1, 1}, // Hcurl + }, + + // tetrahedron + { + {0, 12, 8, 8}, // H1 + {0, 1, 1, 1}, // Hcurl + }, + + // hexahedron + { + {0, 8, 4, 2}, // H1 + {0, 1, 1, 1}, // Hcurl + }, + }; + + return values[gid][fid][p]; + +} + +template < mfem::Geometry::Type geom, Family test_family, Family trial_family > +void sparsity_pattern(std::vector< phmap::flat_hash_set< int > > & column_ids, + FunctionSpace trial_space, + FunctionSpace test_space, + GeometryInfo trial_offsets, + GeometryInfo test_offsets, + nd::view elements, + nd::view connectivity) { + + FiniteElement< geom, test_family > test_el{test_space.degree}; + FiniteElement< geom, trial_family > trial_el{trial_space.degree}; + + // allocate storage for an element's nodal forces + constexpr uint32_t gdim = dimension(geom); + + uint32_t num_elements = elements.shape[0]; + uint32_t test_components = test_space.components; + uint32_t trial_components = trial_space.components; + uint32_t nodes_per_test_element = test_el.num_nodes(); + uint32_t nodes_per_trial_element = trial_el.num_nodes(); + + constexpr int nmutex = 1024; + std::vector< std::mutex > mutexes(nmutex); + + threadpool::parallel_for(num_elements, [&](uint32_t e){ + nd::array test_ids({nodes_per_test_element}); + nd::array trial_ids({nodes_per_trial_element}); + + // get the ids of nodes for that element + test_el.indices(test_offsets, connectivity(elements(e)).data(), test_ids.data()); + trial_el.indices(trial_offsets, connectivity(elements(e)).data(), trial_ids.data()); + + for (int i = 0; i < test_ids.shape[0]; i++) { + for (int ci = 0; ci < test_components; ci++) { + int row_id = test_ids[i] * test_components + ci; + + int which = row_id % nmutex; + mutexes[which].lock(); + auto & row = column_ids[row_id]; + for (int j = 0; j < trial_ids.shape[0]; j++) { + for (int cj = 0; cj < trial_components; cj++) { + row.insert(trial_ids[j] * trial_components + cj); + } + } + mutexes[which].unlock(); + } + } + }); + +} + +refactor::sparse_matrix blank_sparse_matrix(BasisFunctionOp test, BasisFunctionOp trial, const Domain &domain) { + + MTR_SCOPE("integrate_spmat", "blank_sparse_matrix"); + + auto phi = test.function.space; + auto psi = trial.function.space; + + uint32_t test_components = phi.components; + uint32_t trial_components = psi.components; + uint32_t sdim = domain.mesh.spatial_dimension; + uint32_t gdim = domain.mesh.geometry_dimension; + + auto dofs_per_psi = dofs_per_geom(psi); + auto dofs_per_phi = dofs_per_geom(phi); + + GeometryInfo counts = domain.mesh.geometry_counts(); + GeometryInfo test_offsets = scan(interior_nodes_per_geom(phi) * counts); + GeometryInfo trial_offsets = scan(interior_nodes_per_geom(psi) * counts); + auto nrows = total(interior_dofs_per_geom(phi) * counts); + auto ncols = total(interior_dofs_per_geom(psi) * counts); + + std::vector< phmap::flat_hash_set > column_ids(nrows); + foreach_geometry([&](auto geom){ + nd::view elements = domain.active_elements[geom]; + if (gdim == dimension(geom) && elements.size() > 0) { + nd::view connectivity = domain.mesh[geom]; + foreach_constexpr< Family::H1, Family::Hcurl >([&](auto test_family) { + foreach_constexpr< Family::H1, Family::Hcurl >([&](auto trial_family) { + if (test_family == phi.family && trial_family == psi.family) { + sparsity_pattern(column_ids, psi, phi, trial_offsets, test_offsets, elements, connectivity); + } + }); + }); + } + }); + + refactor::sparse_matrix A; + A.nrows = nrows; + A.ncols = ncols; + A.nnz = 0; + A.row_ptr.resize(nrows + 1); + A.row_ptr[0] = 0; + + for (int i = 0; i < nrows; i++) { + int nz_per_row = column_ids[i].size(); + A.nnz += nz_per_row; + A.row_ptr[i+1] = A.row_ptr[i] + nz_per_row; + } + A.col_ind.resize(A.nnz); + A.values.resize(A.nnz); + + threadpool::parallel_for(nrows, [&](int i){ + int offset = A.row_ptr[i]; + for (int col : column_ids[i]) { + A.col_ind[offset++] = col; + } + std::sort(&A.col_ind[A.row_ptr[i]], &A.col_ind[A.row_ptr[i+1]]); + }); + + return A; +} + +} // namespace refactor diff --git a/src/serac/numerics/refactor/common.hpp b/src/serac/numerics/refactor/common.hpp new file mode 100644 index 0000000000..25b74a5992 --- /dev/null +++ b/src/serac/numerics/refactor/common.hpp @@ -0,0 +1,294 @@ +#pragma once + +#include "serac/infrastructure/accelerator.hpp" +#include "serac/numerics/refactor/finite_element.hpp" + +namespace refactor { + +uint32_t elements_per_block(mfem::Geometry::Type geom, Family family, int p); + +template < typename T > +struct array_rank; + +template < typename T, uint32_t n > +struct array_rank< nd::view< T, n > >{ + static constexpr uint32_t value = n; +}; + +template < typename T, uint32_t n > +struct array_rank< nd::array< T, n > >{ + static constexpr uint32_t value = n; +}; + +SERAC_HOST_DEVICE constexpr uint32_t round_up_to_multiple_of_128(uint32_t n) { + return ((n + 127) / 128) * 128; +}; + +constexpr uint32_t source_shape(Family f, uint32_t gdim) { + switch(f) { + case Family::H1: return 1; + case Family::Hcurl: return gdim; + case Family::Hdiv: return gdim; + case Family::DG: return 1; + } + return (1u << 31); +} + +constexpr uint32_t flux_shape(Family f, uint32_t gdim) { + switch(f) { + case Family::H1: return gdim; + case Family::Hcurl: return (gdim == 2) ? 1 : gdim; + case Family::Hdiv: return (gdim == 2) ? 1 : gdim; + case Family::DG: return gdim; + } + + return (1u << 31); +} + +template < Family f, DerivedQuantity op, uint32_t dim > +auto piola_transformation(const mat & dX_dxi) { + if constexpr ((f == Family::H1 && op == DerivedQuantity::DERIVATIVE) || + (f == Family::DG && op == DerivedQuantity::DERIVATIVE) || + (f == Family::Hcurl && op == DerivedQuantity::VALUE)) { + return inv(dX_dxi); + } + + if constexpr ((f == Family::Hcurl && op == DerivedQuantity::DERIVATIVE) || + (f == Family::Hdiv && op == DerivedQuantity::VALUE)) { + if constexpr (dim == 2) { + return mat<1,1>{1.0 / det(dX_dxi)}; + } else { + return transpose(dX_dxi) / det(dX_dxi); + } + } + + if constexpr ((f == Family::H1 && op == DerivedQuantity::VALUE) || + (f == Family::DG && op == DerivedQuantity::VALUE) || + (f == Family::Hdiv && op == DerivedQuantity::DERIVATIVE)) { + // this should never be called, but we implement it here regardless + // to suppress a compiler warning about incompatible return values + return 1.0; + } +} + +template < Family f, DerivedQuantity op, uint32_t dim > +auto weighted_piola_transformation(const mat & dX_dxi) { + if constexpr ((f == Family::H1 && op == DerivedQuantity::DERIVATIVE) || + (f == Family::DG && op == DerivedQuantity::DERIVATIVE) || + (f == Family::Hcurl && op == DerivedQuantity::VALUE)) { + return adj(dX_dxi); + } + + if constexpr ((f == Family::Hcurl && op == DerivedQuantity::DERIVATIVE) || + (f == Family::Hdiv && op == DerivedQuantity::VALUE)) { + if constexpr (dim == 2) { + return mat<1,1>{1.0}; + } else { + return transpose(dX_dxi); + } + } + + if constexpr ((f == Family::H1 && op == DerivedQuantity::VALUE) || + (f == Family::DG && op == DerivedQuantity::VALUE) || + (f == Family::Hdiv && op == DerivedQuantity::DERIVATIVE)) { + return det(dX_dxi); + } +} + +// +------------+------+-------+------+----+ +// | | H1 | Hcurl | Hdiv | DG | +// +------------+------+-------+------+----+ +// | value (1D) | 1 | 1 | 1 | 1 | +// +------------+------+-------+------+----+ +// | deriv (1D) | 1 | 1 | 1 | 1 | +// +------------+------+-------+------+----+ +// | value (2D) | 1 | 2 | 2 | 1 | +// +------------+------+-------+------+----+ +// | deriv (2D) | 2 | 1 | 1 | 2 | +// +------------+------+-------+------+----+ +// | value (3D) | 1 | 3 | 3 | 1 | +// +------------+------+-------+------+----+ +// | deriv (3D) | 3 | 3 | 1 | 3 | +// +------------+------+-------+------+----+ +constexpr uint32_t qshape(Family f, DerivedQuantity op, uint32_t gdim) { + + if (op == DerivedQuantity::VALUE) { + return is_vector_valued(f) ? gdim : 1; + } + + if (op == DerivedQuantity::DERIVATIVE) { + if (f == Family::H1 || f == Family::DG) { return gdim; } + if (f == Family::Hcurl) { return (gdim == 2) ? 1 : gdim; } + if (f == Family::Hdiv) { return 1; } + } + + return (1u<<31); + +} + +template < typename T, uint32_t n > +stack::array remove_ones(const stack::array & x) { + uint32_t rank = 0; + stack::array copy{}; + for (int i = 0; i < n; i++) { + if (x[i] > 1) copy[rank++] = x[i]; + } + return copy; +} + +template < typename T, uint32_t m, uint32_t n > +bool compatible_shapes(const stack::array & x, + const stack::array & y) { + auto x_filtered = remove_ones(x); + auto y_filtered = remove_ones(y); + for (int i = 0; i < std::max(m, n); i++) { + auto xval = (i >= m) ? 0 : x_filtered[i]; + auto yval = (i >= n) ? 0 : y_filtered[i]; + if (xval != yval) { return false; } + } + return true; +} + +template < mfem::Geometry::Type geom, Family test_family, Family trial_family> +void jacobian_rows_and_columns(nd::view rows, + nd::view cols, + FunctionSpace trial_space, + FunctionSpace test_space, + GeometryInfo trial_offsets, + GeometryInfo test_offsets, + nd::view elements, + nd::view connectivity) { + + FiniteElement< geom, test_family > test_el{test_space.degree}; + FiniteElement< geom, trial_family > trial_el{trial_space.degree}; + + // allocate storage for an element's nodal forces + constexpr uint32_t gdim = dimension(geom); + + uint32_t num_elements = rows.shape[0]; + uint32_t test_components = test_space.components; + uint32_t trial_components = trial_space.components; + uint32_t nodes_per_test_element = test_el.num_nodes(); + uint32_t nodes_per_trial_element = trial_el.num_nodes(); + + nd::array test_ids({nodes_per_test_element}); + nd::array trial_ids({nodes_per_trial_element}); + + // for each element of this mfem::Geometry::Type in the domain + for (uint32_t e = 0; e < num_elements; e++) { + + // get the ids of nodes for that element + test_el.indices(test_offsets, connectivity(elements(e)).data(), test_ids.data()); + trial_el.indices(trial_offsets, connectivity(elements(e)).data(), trial_ids.data()); + + // populate the row/column entries for the element jacobian + for (uint32_t J = 0; J < nodes_per_trial_element; J++) { + for (uint32_t j = 0; j < trial_space.components; j++) { + for (uint32_t I = 0; I < nodes_per_test_element; I++) { + for (uint32_t i = 0; i < test_space.components; i++) { + rows(e, J, j, I, i) = int(test_ids(I) * test_space.components + i); + cols(e, J, j, I, i) = int(trial_ids(J) * trial_space.components + j); + } + } + } + } + + } + +} + +template < mfem::Geometry::Type geom > +auto quadrature_point(uint32_t q, const nd::view xi) { + + if constexpr (mfem::Geometry::SQUARE == geom) { + uint32_t q1D = xi.shape[0]; + uint32_t qx = q % q1D; + uint32_t qy = q / q1D; + return vec2{xi(qx, 0), xi(qy, 0)}; + } + + if constexpr (mfem::Geometry::CUBE == geom) { + uint32_t q1D = xi.shape[0]; + uint32_t qx = q % q1D; + uint32_t qy = (q % (q1D * q1D)) / q1D; + uint32_t qz = q / (q1D * q1D); + return vec3{xi(qx, 0), xi(qy, 0), xi(qz, 0)}; + } + + // all other geometries + constexpr int gdim = dimension(geom); + vec< gdim, double > xi_q; + for (uint32_t c = 0; c < gdim; c++) { + xi_q(c) = xi(q, c); + } + return xi_q; + +} + +namespace impl { + +template < Family family, uint32_t n > +auto value_transformation(const mat & A) { + if constexpr (family == Family::H1) { + return mat1{1.0}; + } + if constexpr (family == Family::Hcurl) { + return inv(A); + } +} + +template < Family family, uint32_t n > +auto derivative_transformation(const mat & A) { + if constexpr (family == Family::H1) { + return contravariant_piola(A); + } + if constexpr (family == Family::Hcurl) { + return covariant_piola(A); + } +} + +template < Family family, uint32_t n > +auto source_transformation(const mat & A) { + if constexpr (family == Family::H1) { + return det(A); + } + if constexpr (family == Family::Hcurl) { + return inv(A) * det(A); + } +} + +template < Family family, uint32_t n > +auto flux_transformation(const mat & A) { + if constexpr (family == Family::H1) { + return inv(A) * det(A); + } + if constexpr (family == Family::Hcurl) { + if constexpr (n <= 2) { + return vec<1>(1.0); + } + if constexpr (n == 3) { + return transpose(A); + } + } +} + +} + +} + +namespace nd { + +template < typename T, uint32_t n > +struct printer< fm::vec >{ + static SERAC_HOST_DEVICE void print(const fm::vec & v) { + printf("{"); + printer::print(v(0)); + for (int i = 1; i < n; i++) { + printf(","); + printer::print(v(i)); + } + printf("}"); + } +}; + +} diff --git a/src/serac/numerics/refactor/containers/memory.cpp b/src/serac/numerics/refactor/containers/memory.cpp new file mode 100644 index 0000000000..19ebefba3a --- /dev/null +++ b/src/serac/numerics/refactor/containers/memory.cpp @@ -0,0 +1,23 @@ +#include "nd/array.hpp" + +#ifndef NDARRAY_ENABLE_CUDA +namespace memory { + + void * allocate(uint64_t n) { + return malloc(n); + } + + void deallocate(void * ptr) { + free(ptr); + } + + void memcpy(void * dest, void * src, uint64_t n) { + std::memcpy(dest, src, n); + } + + void zero(void * ptr, uint64_t n) { + std::memset(ptr, 0, n); + } + +} +#endif \ No newline at end of file diff --git a/src/serac/numerics/refactor/containers/memory.cu b/src/serac/numerics/refactor/containers/memory.cu new file mode 100644 index 0000000000..4078b46121 --- /dev/null +++ b/src/serac/numerics/refactor/containers/memory.cu @@ -0,0 +1,37 @@ +#include "nd/array.hpp" + +#include + +#if NDARRAY_ENABLE_CUDA +#define error_check(ans) { gpuAssert((ans), __FILE__, __LINE__); } +inline void gpuAssert(cudaError_t code, const char *file, int line, bool abort=true) +{ + if (code != cudaSuccess) + { + fprintf(stderr,"GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line); + if (abort) exit(code); + } +} + +namespace memory { + + void * allocate(uint64_t n) { + void * ptr; + error_check(cudaMallocManaged(&ptr, n)); + return ptr; + } + + void deallocate(void * ptr) { + error_check(cudaFree(ptr)); + } + + void memcpy(void * dest, void * src, uint64_t n) { + error_check(cudaMemcpy(dest, src, n, cudaMemcpyDefault)); + } + + void zero(void * ptr, uint64_t n) { + error_check(cudaMemset(ptr, 0, n)); + } + +} +#endif \ No newline at end of file diff --git a/src/serac/numerics/refactor/containers/ndarray.cpp b/src/serac/numerics/refactor/containers/ndarray.cpp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/serac/numerics/refactor/containers/ndarray.hpp b/src/serac/numerics/refactor/containers/ndarray.hpp new file mode 100644 index 0000000000..90afecf36b --- /dev/null +++ b/src/serac/numerics/refactor/containers/ndarray.hpp @@ -0,0 +1,578 @@ +#pragma once + +#include // for printf +#include // for std::memcpy +#include // for std::integer_sequence +#include +#include +#include + +#include "serac/infrastructure/accelerator.hpp" +#include "serac/numerics/refactor/containers/stack_array.hpp" + +namespace memory { + enum space {CPU, GPU, UNIFIED}; + + void * allocate(uint64_t n); + void deallocate(void * ptr); + void memcpy(void * dest, void * src, uint64_t n); + void zero(void * ptr, uint64_t n); + + template < typename T > + T * allocate(uint64_t n) { + return static_cast(allocate(n * sizeof(T))); + } + + template < typename T > + void deallocate(T * ptr) { + deallocate(static_cast(ptr)); + } + + template < typename T > + void memcpy(T * dest, T * src, uint64_t n) { + memcpy(static_cast(dest), static_cast(src), n * sizeof(T)); + } + + template < typename T > + void zero(T * ptr, uint64_t n) { + zero(static_cast(ptr), n * sizeof(T)); + } +} + +namespace nd { + + template < uint32_t dim > + SERAC_HOST_DEVICE uint32_t product(stack::array< uint32_t, dim > values) { + uint32_t p = values[0]; + for (int i = 1; i < dim; i++) { p *= values[i]; } + return p; + } + + enum ordering{ row_major, col_major }; + + template < uint32_t dim > + SERAC_HOST_DEVICE stack::array< uint32_t, dim > compute_strides(const stack::array< uint32_t, dim > & shape, ordering o, uint32_t m = 1) { + stack::array< uint32_t, dim > strides{}; + int32_t k = (o == col_major) ? 0 : dim-1; + int32_t s = (o == col_major) ? 1 : -1; + for (uint32_t i = 0; i < dim; i++) { + strides[k] = (i == 0) ? m : strides[k-s] * shape[k-s]; + k += s; + } + return strides; + } + + // used for slicing arrays and views + template < typename T > + struct range { T begin; T end; }; + + template < typename T > + range(T,T) -> range; + + template < typename T > + SERAC_HOST_DEVICE constexpr T begin(const range & r) { return r.begin; } + + template < typename T > + SERAC_HOST_DEVICE constexpr T end(const range & r) { return r.end; } + + template < typename T > + SERAC_HOST_DEVICE constexpr uint32_t is_range(T) { return 0; }; + + template < typename T > + SERAC_HOST_DEVICE constexpr uint32_t is_range(range) { return 1; }; + + SERAC_HOST_DEVICE constexpr int32_t begin(int32_t x) { return x; } + SERAC_HOST_DEVICE constexpr int64_t begin(int64_t x) { return x; } + SERAC_HOST_DEVICE constexpr uint32_t begin(uint32_t x) { return x; } + SERAC_HOST_DEVICE constexpr uint64_t begin(uint64_t x) { return x; } + + SERAC_HOST_DEVICE constexpr int32_t end(int32_t x) { return x; } + SERAC_HOST_DEVICE constexpr int64_t end(int64_t x) { return x; } + SERAC_HOST_DEVICE constexpr uint32_t end(uint32_t x) { return x; } + SERAC_HOST_DEVICE constexpr uint64_t end(uint64_t x) { return x; } + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + + template < typename T, uint32_t dim = 1 > + struct view { + static_assert(dim > 0); + + static constexpr auto iseq = std::make_integer_sequence< uint32_t, dim >(); + + SERAC_HOST_DEVICE constexpr view() { + values = nullptr; + sz = 0; + shape = {}; + stride = {}; + } + + SERAC_HOST_DEVICE constexpr view(T * input, const stack::array< uint32_t, dim > & dimensions) { + values = input; + for (uint32_t i = 0; i < dim; i++) { + uint32_t id = dim - 1 - i; + shape[id] = dimensions[id]; + stride[id] = (id == dim - 1) ? 1 : stride[id+1] * shape[id+1]; + } + sz = product(shape); + } + + SERAC_HOST_DEVICE constexpr view(T * input, const stack::array< uint32_t, dim > & dimensions, const stack::array< uint32_t, dim > & strides) { + values = input; + shape = dimensions; + stride = strides; + sz = product(shape); + } + + template < typename ... index_types > + SERAC_HOST_DEVICE uint32_t index(index_types ... indices) const { + static_assert(sizeof ... (indices) == dim); + return values[index(iseq, indices...)]; + } + + template < uint32_t ... I, typename ... index_types > + SERAC_HOST_DEVICE uint32_t index(std::integer_sequence, index_types ... indices) const { + #ifdef NDARRAY_ENABLE_BOUNDS_CHECKING + // note: the cast to int32_t is a way to avoid warnings + // about pointless comparison between unsigned integer types and 0 + if (((int32_t(indices) < 0 || indices >= shape[I]) || ... )) { + printf("array index out of bounds\n"); + }; + #endif + return ((indices * stride[I]) + ...); + } + + template < typename ... index_types > + SERAC_HOST_DEVICE decltype(auto) operator()(index_types ... indices) const { + constexpr uint32_t num_args = sizeof ... (indices); + static_assert(num_args <= dim); + constexpr uint32_t rank = (is_range(index_types{}) + ... ) + (dim - num_args); + if constexpr (rank == 0) { + return static_cast(values[index(iseq, indices...)]); + } else { + constexpr uint32_t is_a_range[] = {is_range(index_types{}) ... }; + stack::array slice_shape{}; + stack::array slice_stride{}; + + uint32_t beginnings[num_args] = {uint32_t(nd::begin(indices)) ... }; + uint32_t endings[num_args] = {uint32_t(nd::end(indices)) ... }; + int k = 0; + int offset = 0; + for (int i = 0; i < dim; i++) { + if (i >= num_args) { + slice_shape[k] = shape[i]; + slice_stride[k] = stride[i]; + k++; + } else { + offset += stride[i] * beginnings[i]; + if (is_a_range[i]) { + slice_shape[k] = endings[i] - beginnings[i]; + slice_stride[k] = stride[i]; + k++; + } + } + } + return view{&values[offset], slice_shape, slice_stride}; + } + } + + template < typename ... index_types > + SERAC_HOST_DEVICE decltype(auto) operator()(index_types ... indices) { + constexpr uint32_t num_args = sizeof ... (indices); + static_assert(num_args <= dim); + constexpr uint32_t rank = (is_range(index_types{}) + ... ) + (dim - num_args); + if constexpr (rank == 0) { + return static_cast(values[index(iseq, indices...)]); + } else { + constexpr uint32_t is_a_range[] = {is_range(index_types{}) ... }; + stack::array slice_shape{}; + stack::array slice_stride{}; + + uint32_t beginnings[num_args] = {uint32_t(nd::begin(indices)) ... }; + uint32_t endings[num_args] = {uint32_t(nd::end(indices)) ... }; + int k = 0; + int offset = 0; + for (int i = 0; i < dim; i++) { + if (i >= num_args) { + slice_shape[k] = shape[i]; + slice_stride[k] = stride[i]; + k++; + } else { + offset += stride[i] * beginnings[i]; + if (is_a_range[i]) { + slice_shape[k] = endings[i] - beginnings[i]; + slice_stride[k] = stride[i]; + k++; + } + } + } + return view{&values[offset], slice_shape, slice_stride}; + } + } + + template < typename index_type > + SERAC_HOST_DEVICE auto & operator[](index_type i) { return values[i]; } + + template < typename index_type > + SERAC_HOST_DEVICE auto & operator[](index_type i) const { return values[i]; } + + SERAC_HOST_DEVICE operator view() const { + return view{values, shape, stride}; + } + + SERAC_HOST_DEVICE T * data() { return &values[0]; } + SERAC_HOST_DEVICE const T * data() const { return &values[0]; } + + SERAC_HOST_DEVICE uint32_t size() const { return product(shape); } + + SERAC_HOST_DEVICE T * begin() const { return &values[0]; } + SERAC_HOST_DEVICE T * end() const { return &values[size()]; } + + T * values; + uint64_t sz; + stack::array< uint32_t, dim > shape; + stack::array< uint32_t, dim > stride; + + }; + + template < typename T, uint32_t dim > + struct view< const T, dim >{ + static_assert(dim > 0); + + static constexpr auto iseq = std::make_integer_sequence< uint32_t, dim >(); + + SERAC_HOST_DEVICE constexpr view() { + values = nullptr; + sz = 0; + shape = {}; + stride = {}; + } + + SERAC_HOST_DEVICE constexpr view(const T * input, const stack::array< uint32_t, dim > & dimensions) { + values = input; + for (uint32_t i = 0; i < dim; i++) { + uint32_t id = dim - 1 - i; + shape[id] = dimensions[id]; + stride[id] = (id == dim - 1) ? 1 : stride[id+1] * shape[id+1]; + } + sz = product(shape); + } + + SERAC_HOST_DEVICE constexpr view(const T * input, const stack::array< uint32_t, dim > & dimensions, const stack::array< uint32_t, dim > & strides) { + values = input; + shape = dimensions; + stride = strides; + sz = product(shape); + } + + template < typename ... index_types > + SERAC_HOST_DEVICE uint32_t index(index_types ... indices) const { + static_assert(sizeof ... (indices) == dim); + return values[index(iseq, indices...)]; + } + + template < uint32_t ... I, typename ... index_types > + SERAC_HOST_DEVICE uint32_t index(std::integer_sequence, index_types ... indices) const { + #ifdef NDARRAY_ENABLE_BOUNDS_CHECKING + // note: the cast to int32_t is a way to avoid warnings + // about pointless comparison between unsigned integer types and 0 + if (((int32_t(indices) < 0 || indices >= shape[I]) || ... )) { + printf("array index out of bounds\n"); + }; + #endif + return ((indices * stride[I]) + ...); + } + + template < typename ... index_types > + SERAC_HOST_DEVICE decltype(auto) operator()(index_types ... indices) const { + constexpr uint32_t num_args = sizeof ... (indices); + static_assert(num_args <= dim); + constexpr uint32_t rank = (is_range(index_types{}) + ... ) + (dim - num_args); + if constexpr (rank == 0) { + return static_cast(values[index(iseq, indices...)]); + } else { + constexpr uint32_t is_a_range[] = {is_range(index_types{}) ... }; + stack::array slice_shape{}; + stack::array slice_stride{}; + + uint32_t beginnings[num_args] = {uint32_t(nd::begin(indices)) ... }; + uint32_t endings[num_args] = {uint32_t(nd::end(indices)) ... }; + int k = 0; + int offset = 0; + for (int i = 0; i < dim; i++) { + if (i >= num_args) { + slice_shape[k] = shape[i]; + slice_stride[k] = stride[i]; + k++; + } else { + offset += stride[i] * beginnings[i]; + if (is_a_range[i]) { + slice_shape[k] = endings[i] - beginnings[i]; + slice_stride[k] = stride[i]; + k++; + } + } + } + return view{&values[offset], slice_shape, slice_stride}; + } + } + + template < typename index_type > + SERAC_HOST_DEVICE const T & operator[](index_type i) const { return values[i]; } + + SERAC_HOST_DEVICE const T * data() const { return &values[0]; } + + SERAC_HOST_DEVICE uint32_t size() const { return product(shape); } + + SERAC_HOST_DEVICE const T * begin() const { return &values[0]; } + SERAC_HOST_DEVICE const T * end() const { return &values[size()]; } + + const T * values; + uint64_t sz; + stack::array< uint32_t, dim > shape; + stack::array< uint32_t, dim > stride; + + }; + + template < typename T, uint32_t dim > + using const_view = view; + + template < typename T, uint32_t dim = 1 > + struct array : public view< T, dim > { + + using view::iseq; + using view::values; + using view::shape; + using view::stride; + using view::sz; + + array() : view() {} + + array(stack::array< uint32_t, dim > dimensions) : view() { resize(dimensions); } + + array(stack::array< uint32_t, dim > dimensions, + stack::array< uint32_t, dim > strides) : view() { + resize(dimensions, strides); + } + + array(const array & other) { + sz = other.sz; + shape = other.shape; + stride = other.stride; + allocate(sz); + memory::memcpy(values, other.values, other.sz); + } + + void operator=(const array & other) { + shape = other.shape; + stride = other.stride; + _resize(other.sz); + memory::memcpy(values, other.values, sz); + } + + array(array && other) { + sz = other.sz; + shape = other.shape; + values = other.values; + stride = other.stride; + other.values = nullptr; + } + + void operator=(array && other) { + sz = other.sz; + shape = other.shape; + + deallocate(); + values = other.values; + + stride = other.stride; + other.values = nullptr; + } + + ~array() { + deallocate(); + } + + void resize(uint32_t new_size) { + static_assert(dim == 1, "resize(uint32_t) only defined for 1D arrays"); + stride[0] = 1; + shape[0] = new_size; + _resize(new_size); + } + + void resize(const stack::array< uint32_t, dim > & new_shape) { + shape = new_shape; + _resize(product(shape)); + for (uint64_t i = 0; i < dim; i++) { + uint64_t id = dim - 1 - i; + stride[id] = (id == dim - 1) ? 1 : stride[id+1] * shape[id+1]; + } + } + + void resize(const stack::array< uint32_t, dim > & new_shape, + const stack::array< uint32_t, dim > & new_stride) { + shape = new_shape; + stride = new_stride; + _resize(product(shape)); + } + + private: + + void allocate(uint32_t n) { + values = memory::allocate(n); + } + + void deallocate() { + if (values) { + memory::deallocate(values); + values = nullptr; + } + } + + void _resize(uint32_t new_sz) { + if (new_sz != sz) { + deallocate(); + allocate(new_sz); + sz = new_sz; + memory::zero(values, sz); + } + } + + }; + + template < typename T, uint32_t dim > + view(T*, stack::array) -> view; + + template < typename T, uint32_t dim > + view(T*, stack::array, stack::array) -> view; + + ///////////////////////////////////////////////////////////////////////////// + + template < typename T, uint32_t dim > + void zero(array & arr) { + memory::zero(arr.data(), arr.sz); + } + +// template < typename T, uint32_t dim > +// void fill(array & arr, T value) { +// for (uint32_t i = 0; i < arr.size(); i++) { +// arr[i] = value; +// } +// } + + ///////////////////////////////////////////////////////////////////////////// + + template < typename T, uint32_t dim > + SERAC_HOST_DEVICE view flatten(const array & arr) { + return view{&arr.values[0], {product(arr.shape)}}; + } + + template < typename T, uint32_t dim > + SERAC_HOST_DEVICE view flatten(array & arr) { + return view{&arr.values[0], {product(arr.shape)}}; + } + + template < typename T, uint32_t dim > + SERAC_HOST_DEVICE view flatten(view arr) { + return view{arr.values, {product(arr.shape)}}; + } + + ///////////////////////////////////////////////////////////////////////////// + + template < uint32_t dim, typename T > + SERAC_HOST_DEVICE view reshape(view v, stack::array< uint32_t, dim > new_dimensions, ordering o = ordering::row_major) { + #ifdef NDARRAY_ENABLE_BOUNDS_CHECKING + if (product(new_dimensions) != v.shape[0]) { + printf("reshaping view into incompatible shape"); + }; + #endif + + auto strides = nd::compute_strides(new_dimensions, o, v.stride[0]); + + return view{v.data(), new_dimensions, strides}; + } + + ///////////////////////////////////////////////////////////////////////////// + +}; + +double relative_error(nd::view a, nd::view b); +double relative_error(nd::view a, nd::view b); +double relative_error(nd::view a, nd::view b); +double relative_error(nd::view a, nd::view b); + +namespace nd { +template < typename T > +struct printer; + +template <> struct printer{ static SERAC_HOST_DEVICE void print(float x) { printf("%f", static_cast(x)); } }; +template <> struct printer{ static SERAC_HOST_DEVICE void print(double x) { printf("%f", x); } }; +template <> struct printer{ static SERAC_HOST_DEVICE void print(int8_t x) { printf("%d", x); } }; +template <> struct printer{ static SERAC_HOST_DEVICE void print(uint8_t x) { printf("%u", x); } }; +template <> struct printer{ static SERAC_HOST_DEVICE void print(int32_t x) { printf("%d", x); } }; +template <> struct printer{ static SERAC_HOST_DEVICE void print(uint32_t x) { printf("%u", x); } }; +template <> struct printer{ static SERAC_HOST_DEVICE void print(int64_t x) { printf("%ld", x); } }; +template <> struct printer{ static SERAC_HOST_DEVICE void print(uint64_t x) { printf("%lu", x); } }; + +template < typename T, uint32_t dim > +SERAC_HOST_DEVICE void print_recursive(nd::view< T, dim > arr, int depth) { + using S = typename std::remove_const::type; + + if constexpr (dim == 1) { + for (int i = 0; i < depth; i++) printf(" "); + printf("{"); + for (int i = 0; i < arr.shape[0]; i++) { + printer::print(arr(i)); + if (i != arr.shape[0] - 1) { printf(","); } + } + printf("}"); + } else { + const T * ptr = arr.data(); + stack::array< uint32_t, dim - 1 > shape; + stack::array< uint32_t, dim - 1 > stride; + for (int i = 0; i < dim - 1; i++) { + shape[i] = arr.shape[i+1]; + stride[i] = arr.stride[i+1]; + } + nd::view slice{ptr, shape, stride}; + + for (int i = 0; i < depth; i++) printf(" "); + printf("{"); + if (arr.shape[0] == 1) { + print_recursive(slice, 0); + } else { + printf("\n"); + for (int i = 0; i < arr.shape[0]; i++) { + print_recursive(slice, depth+1); + if (i != arr.shape[0] - 1) { printf(","); } + printf("\n"); + slice.values += arr.stride[0]; + } + for (int i = 0; i < depth; i++) printf(" "); + } + printf("}"); + } + if (depth == 0) { printf("\n"); } +} + +} + +template < typename T, uint32_t dim > +SERAC_HOST_DEVICE void print(nd::view< T, dim > arr) { + nd::print_recursive(arr, 0); +} + +template < typename T, uint32_t dim > +std::ostream& operator<<(std::ostream & out, const nd::view< T, dim > & arr) { + print(out, nd::view(arr)); + return out; +} + +template < typename T, uint32_t dim > +std::ostream& operator<<(std::ostream & out, const nd::array< T, dim > & arr) { + print(out, nd::view(arr)); + return out; +} + +#undef SERAC_HOST_DEVICE diff --git a/src/serac/numerics/refactor/containers/relative_error.cpp b/src/serac/numerics/refactor/containers/relative_error.cpp new file mode 100644 index 0000000000..10e18c648f --- /dev/null +++ b/src/serac/numerics/refactor/containers/relative_error.cpp @@ -0,0 +1,26 @@ +#include "nd/array.hpp" + +#include + +template < uint32_t rank > +double relative_error_impl(nd::view x, nd::view y) { + if (x.shape != y.shape) { + std::cout << "shape mismatch" << std::endl; + } + + double norm = 0.0; + double error = 0.0; + uint32_t sz = x.size(); + for (uint32_t i = 0; i < sz; i++) { + double avg = 0.5 * (x.values[i] + y.values[i]); + double diff = x.values[i] - y.values[i]; + error += diff * diff; + norm += avg * avg; + } + return sqrt(error / norm); +} + +double relative_error(nd::view a, nd::view b) { return relative_error_impl(a, b); }; +double relative_error(nd::view a, nd::view b) { return relative_error_impl(a, b); }; +double relative_error(nd::view a, nd::view b) { return relative_error_impl(a, b); }; +double relative_error(nd::view a, nd::view b) { return relative_error_impl(a, b); }; \ No newline at end of file diff --git a/src/serac/numerics/refactor/containers/stack_array.hpp b/src/serac/numerics/refactor/containers/stack_array.hpp new file mode 100644 index 0000000000..e53b1e2442 --- /dev/null +++ b/src/serac/numerics/refactor/containers/stack_array.hpp @@ -0,0 +1,42 @@ +#pragma once + +#include + +namespace stack { + + template < typename T, uint32_t dim > + struct array { + SERAC_HOST_DEVICE constexpr T & operator[](uint32_t i) { return values[i]; } + SERAC_HOST_DEVICE constexpr const T & operator[](uint32_t i) const { return values[i]; } + + SERAC_HOST_DEVICE bool operator==(const array & other) const { + for (uint32_t i = 0; i < dim; i++) { + if (values[i] != other[i]) return false; + } + return true; + } + + SERAC_HOST_DEVICE bool operator!=(const array & other) const { return !(this->operator==(other)); } + + T values[dim]; + }; + + template < typename T, uint32_t dim > + constexpr uint32_t size(array) { return dim; } + + template < typename T > + array(T, T) -> array; + + template < typename T > + array(T, T, T) -> array; + + template < typename T > + array(T, T, T, T) -> array; + + template < typename T > + array(T, T, T, T, T) -> array; + + template < typename T > + array(T, T, T, T, T, T) -> array; + +} diff --git a/src/serac/numerics/refactor/elements/h1_edge.hpp b/src/serac/numerics/refactor/elements/h1_edge.hpp index eef78cf902..0f0f519ff0 100644 --- a/src/serac/numerics/refactor/elements/h1_edge.hpp +++ b/src/serac/numerics/refactor/elements/h1_edge.hpp @@ -8,7 +8,7 @@ namespace refactor { using namespace fm; template <> -struct FiniteElement < Geometry::Edge, Family::H1 >{ +struct FiniteElement < mfem::Geometry::SEGMENT, Family::H1 >{ using source_type = vec1; using flux_type = vec1; @@ -16,7 +16,7 @@ struct FiniteElement < Geometry::Edge, Family::H1 >{ using value_type = vec1; using grad_type = vec1; - __host__ __device__ constexpr uint32_t num_nodes() const { return p + 1; } + SERAC_HOST_DEVICE constexpr uint32_t num_nodes() const { return p + 1; } constexpr double shape_function(vec<1> xi, uint32_t i) const { if (p == 1 && i == 0) { return 1.0 - xi[0]; } @@ -56,7 +56,7 @@ struct FiniteElement < Geometry::Edge, Family::H1 >{ return shape_function_gradient(xi, i); } - __host__ __device__ uint32_t batch_interpolation_scratch_space(nd::view xi) const { + SERAC_HOST_DEVICE uint32_t batch_interpolation_scratch_space(nd::view xi) const { return 0; } @@ -78,7 +78,7 @@ struct FiniteElement < Geometry::Edge, Family::H1 >{ return shape_fn_grads; } - __host__ __device__ void interpolate(nd::view values_q, nd::view values_e, nd::view shape_fns, double * /*buffer*/) const { + SERAC_HOST_DEVICE void interpolate(nd::view values_q, nd::view values_e, nd::view shape_fns, double * /*buffer*/) const { int nnodes = num_nodes(); int nqpts = values_q.shape[0]; @@ -91,7 +91,7 @@ struct FiniteElement < Geometry::Edge, Family::H1 >{ } } - __host__ __device__ void gradient(nd::view gradients_q, nd::view values_e, nd::view shape_fn_grads, double * /*buffer*/) const { + SERAC_HOST_DEVICE void gradient(nd::view gradients_q, nd::view values_e, nd::view shape_fn_grads, double * /*buffer*/) const { int nnodes = num_nodes(); int nqpts = gradients_q.shape[0]; for (int j = 0; j < nqpts; j++) { @@ -117,7 +117,7 @@ struct FiniteElement < Geometry::Edge, Family::H1 >{ return shape_fns; } - __host__ __device__ void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fn, double * /*buffer*/) const { + SERAC_HOST_DEVICE void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fn, double * /*buffer*/) const { int nnodes = num_nodes(); int nqpts = source_q.shape[0]; @@ -144,7 +144,7 @@ struct FiniteElement < Geometry::Edge, Family::H1 >{ return shape_fn_grads; } - __host__ __device__ void integrate_flux(nd::view output_e, nd::view flux_q, nd::view shape_fn_grads, double * /*buffer*/) const { + SERAC_HOST_DEVICE void integrate_flux(nd::view output_e, nd::view flux_q, nd::view shape_fn_grads, double * /*buffer*/) const { int nnodes = num_nodes(); int nqpts = flux_q.shape[0]; for (int i = 0; i < nnodes; i++) { diff --git a/src/serac/numerics/refactor/elements/h1_hexahedron.hpp b/src/serac/numerics/refactor/elements/h1_hexahedron.hpp index 520183bf9f..69a5ad9512 100644 --- a/src/serac/numerics/refactor/elements/h1_hexahedron.hpp +++ b/src/serac/numerics/refactor/elements/h1_hexahedron.hpp @@ -5,7 +5,7 @@ namespace refactor { template <> -struct FiniteElement { +struct FiniteElement { using value_type = vec1; using derivative_type = vec3; @@ -13,7 +13,7 @@ struct FiniteElement { using source_type = vec1; using flux_type = vec3; - __host__ __device__ constexpr uint32_t num_nodes() const { return (p + 1) * (p + 1) * (p + 1); } + SERAC_HOST_DEVICE constexpr uint32_t num_nodes() const { return (p + 1) * (p + 1) * (p + 1); } constexpr double phi_1D(double xi, uint32_t i) const { return GaussLobattoInterpolation(xi, p + 1, i); @@ -84,7 +84,7 @@ struct FiniteElement { return output; } - __host__ __device__ uint32_t batch_interpolation_scratch_space(nd::view xi) const { + SERAC_HOST_DEVICE uint32_t batch_interpolation_scratch_space(nd::view xi) const { uint32_t n = p + 1; uint32_t q = xi.shape[0]; return q * n * (n + q); @@ -101,7 +101,7 @@ struct FiniteElement { return buffer; } - __host__ __device__ void interpolate(nd::view values_q, nd::view values_e, nd::view shape_fns, double * buffer) const { + SERAC_HOST_DEVICE void interpolate(nd::view values_q, nd::view values_e, nd::view shape_fns, double * buffer) const { uint32_t n = p + 1; uint32_t q = shape_fns.shape[1]; @@ -128,7 +128,7 @@ struct FiniteElement { return shape_fn_grads; } - __host__ __device__ void gradient(nd::view gradients_q, nd::view values_e, nd::view shape_fns, double * buffer) const { + SERAC_HOST_DEVICE void gradient(nd::view gradients_q, nd::view values_e, nd::view shape_fns, double * buffer) const { uint32_t n = p + 1; uint32_t q = shape_fns.shape[1]; @@ -177,7 +177,7 @@ struct FiniteElement { return buffer; } - __host__ __device__ void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fn, double * buffer) const { + SERAC_HOST_DEVICE void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fn, double * buffer) const { uint32_t n = p + 1; uint32_t q = shape_fn.shape[1]; diff --git a/src/serac/numerics/refactor/elements/h1_quadrilateral.hpp b/src/serac/numerics/refactor/elements/h1_quadrilateral.hpp index 52085cd618..9d4136c7cc 100644 --- a/src/serac/numerics/refactor/elements/h1_quadrilateral.hpp +++ b/src/serac/numerics/refactor/elements/h1_quadrilateral.hpp @@ -6,7 +6,7 @@ namespace refactor { template <> -struct FiniteElement { +struct FiniteElement { using source_type = vec1; using flux_type = vec2; @@ -14,7 +14,7 @@ struct FiniteElement { using value_type = vec1; using grad_type = vec2; - __host__ __device__ constexpr uint32_t num_nodes() const { return (p + 1) * (p + 1); } + SERAC_HOST_DEVICE constexpr uint32_t num_nodes() const { return (p + 1) * (p + 1); } constexpr double phi_1D(double xi, uint32_t i) const { return GaussLobattoInterpolation(xi, p + 1, i); @@ -97,7 +97,7 @@ struct FiniteElement { return output; } - __host__ __device__ uint32_t batch_interpolation_scratch_space(nd::view xi) const { + SERAC_HOST_DEVICE uint32_t batch_interpolation_scratch_space(nd::view xi) const { uint32_t q = xi.shape[0]; return q * (p + 1); } @@ -176,7 +176,7 @@ struct FiniteElement { return buffer; } - __host__ __device__ void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fns, double * buffer) const { + SERAC_HOST_DEVICE void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fns, double * buffer) const { uint32_t n = p + 1; uint32_t q = shape_fns.shape[1]; diff --git a/src/serac/numerics/refactor/elements/h1_tetrahedron.hpp b/src/serac/numerics/refactor/elements/h1_tetrahedron.hpp index bf1fa66ef4..7656ef6f9c 100644 --- a/src/serac/numerics/refactor/elements/h1_tetrahedron.hpp +++ b/src/serac/numerics/refactor/elements/h1_tetrahedron.hpp @@ -5,7 +5,7 @@ namespace refactor { template <> -struct FiniteElement { +struct FiniteElement { using source_type = vec1; using flux_type = vec3; @@ -15,7 +15,7 @@ struct FiniteElement { static constexpr int dim = 3; - __host__ __device__ constexpr uint32_t num_nodes() const { return Tetrahedron::number(p + 1); } + SERAC_HOST_DEVICE constexpr uint32_t num_nodes() const { return Tetrahedron::number(p + 1); } constexpr double shape_function(vec3 xi, uint32_t i) const { // expressions generated symbolically by mathematica @@ -131,7 +131,7 @@ struct FiniteElement { return interpolated_gradient; } - __host__ __device__ uint32_t batch_interpolation_scratch_space(nd::view xi) const { + SERAC_HOST_DEVICE uint32_t batch_interpolation_scratch_space(nd::view xi) const { return 0; } @@ -196,7 +196,7 @@ struct FiniteElement { return shape_fns; } - __host__ __device__ void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fn, double * /*buffer*/) const { + SERAC_HOST_DEVICE void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fn, double * /*buffer*/) const { int nnodes = num_nodes(); int nqpts = source_q.shape[0]; diff --git a/src/serac/numerics/refactor/elements/h1_triangle.hpp b/src/serac/numerics/refactor/elements/h1_triangle.hpp index f230b83702..1eb767eb39 100644 --- a/src/serac/numerics/refactor/elements/h1_triangle.hpp +++ b/src/serac/numerics/refactor/elements/h1_triangle.hpp @@ -6,7 +6,7 @@ namespace refactor { // clang-format off template <> -struct FiniteElement { +struct FiniteElement { using source_type = vec1; using flux_type = vec2; @@ -16,7 +16,7 @@ struct FiniteElement { static constexpr int dim = 2; - __host__ __device__ constexpr uint32_t num_nodes() const { return Triangle::number(p + 1); } + SERAC_HOST_DEVICE constexpr uint32_t num_nodes() const { return Triangle::number(p + 1); } constexpr double shape_function(vec2 xi, uint32_t i) const { if (p == 1) { @@ -101,7 +101,7 @@ struct FiniteElement { return interpolated_gradient; } - __host__ __device__ uint32_t batch_interpolation_scratch_space(nd::view xi) const { + SERAC_HOST_DEVICE uint32_t batch_interpolation_scratch_space(nd::view xi) const { return 0; } @@ -163,7 +163,7 @@ struct FiniteElement { return shape_fns; } - __host__ __device__ void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fn, double * /*buffer*/) const { + SERAC_HOST_DEVICE void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fn, double * /*buffer*/) const { int nnodes = num_nodes(); int nqpts = source_q.shape[0]; diff --git a/src/serac/numerics/refactor/elements/h1_vertex.hpp b/src/serac/numerics/refactor/elements/h1_vertex.hpp index 24c2103611..cdb4bc977b 100644 --- a/src/serac/numerics/refactor/elements/h1_vertex.hpp +++ b/src/serac/numerics/refactor/elements/h1_vertex.hpp @@ -5,11 +5,11 @@ namespace refactor { template <> -struct FiniteElement { +struct FiniteElement { using source_type = double; using flux_type = double; - __host__ __device__ uint32_t num_nodes() const { return 1; } + SERAC_HOST_DEVICE uint32_t num_nodes() const { return 1; } uint32_t p; }; diff --git a/src/serac/numerics/refactor/elements/hcurl_edge.hpp b/src/serac/numerics/refactor/elements/hcurl_edge.hpp index a8d42f7e1f..51763db5a0 100644 --- a/src/serac/numerics/refactor/elements/hcurl_edge.hpp +++ b/src/serac/numerics/refactor/elements/hcurl_edge.hpp @@ -5,17 +5,17 @@ namespace refactor { template <> -struct FiniteElement < Geometry::Edge, Family::Hcurl >{ +struct FiniteElement < mfem::Geometry::SEGMENT, Family::Hcurl >{ using source_type = vec1; using flux_type = vec1; static constexpr uint32_t dim = 1; - __host__ __device__ uint32_t num_nodes() const { return p; } + SERAC_HOST_DEVICE uint32_t num_nodes() const { return p; } template < typename T > - __host__ __device__ void reorient(const TransformationType type, const Connection * edge, T * values) { + SERAC_HOST_DEVICE void reorient(const TransformationType type, const Connection * edge, T * values) { // TODO switch (type) { @@ -26,7 +26,7 @@ struct FiniteElement < Geometry::Edge, Family::Hcurl >{ } - __host__ __device__ void reorient(const TransformationType type, const Connection * edge, int8_t * transformation) { + SERAC_HOST_DEVICE void reorient(const TransformationType type, const Connection * edge, int8_t * transformation) { for (int i = 0; i < p; i++) { transformation[i] = 0; } @@ -82,7 +82,7 @@ struct FiniteElement < Geometry::Edge, Family::Hcurl >{ return shape_function_curl(xi, i); } - __host__ __device__ uint32_t batch_interpolation_scratch_space(nd::view xi) const { + SERAC_HOST_DEVICE uint32_t batch_interpolation_scratch_space(nd::view xi) const { return 0; } @@ -160,7 +160,7 @@ struct FiniteElement < Geometry::Edge, Family::Hcurl >{ return shape_fns; } - __host__ __device__ void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fn, double * /*buffer*/) const { + SERAC_HOST_DEVICE void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fn, double * /*buffer*/) const { int nnodes = num_nodes(); int nqpts = source_q.shape[0]; @@ -184,7 +184,7 @@ struct FiniteElement < Geometry::Edge, Family::Hcurl >{ return shape_fns; } - __host__ __device__ void integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fn, double * /*buffer*/) const { + SERAC_HOST_DEVICE void integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fn, double * /*buffer*/) const { int nnodes = num_nodes(); int nqpts = flux_q.shape[0]; diff --git a/src/serac/numerics/refactor/elements/hcurl_hexahedron.hpp b/src/serac/numerics/refactor/elements/hcurl_hexahedron.hpp index 2a3dd738a2..599f9f7976 100644 --- a/src/serac/numerics/refactor/elements/hcurl_hexahedron.hpp +++ b/src/serac/numerics/refactor/elements/hcurl_hexahedron.hpp @@ -6,7 +6,7 @@ namespace refactor { // clang-format off template <> -struct FiniteElement { +struct FiniteElement { using value_type = vec3; using derivative_type = vec3; @@ -17,7 +17,7 @@ struct FiniteElement { static constexpr int dim = 3; // clang-format off - __host__ __device__ uint8_t const * lexicographic_permutations(int p) { + SERAC_HOST_DEVICE uint8_t const * lexicographic_permutations(int p) { static constexpr uint8_t linear_lexicographic_permutation[12] = {0,5,1,4,8,9,11,10,2,7,3,6}; static constexpr uint8_t quadratic_lexicographic_permutation[54] = {0,1,20,23,4,5,18,21,36,45,38,47,44,53,42,51,12,13,32,35,16,17,30,33,3,2,19,22,6,7,37,46,26,29,41,50,11,10,43,52,27,24,39,48,14,15,31,34,8,9,25,28,40,49}; static constexpr uint8_t cubic_lexicographic_permutation[144] = {0,1,2,51,55,59,9,10,11,48,52,56,96,112,128,99,115,131,111,127,143,108,124,140,36,37,38,87,91,95,45,46,47,84,88,92,5,4,3,8,7,6,50,54,58,49,53,57,12,13,14,24,25,26,97,113,129,98,114,130,63,67,71,75,79,83,103,119,135,107,123,139,23,22,21,35,34,33,110,126,142,109,125,141,68,64,60,80,76,72,104,120,136,100,116,132,39,40,41,42,43,44,85,89,93,86,90,94,15,16,17,18,19,20,27,28,29,30,31,32,61,62,65,66,69,70,73,74,77,78,81,82,101,102,105,106,117,118,121,122,133,134,137,138}; @@ -26,14 +26,14 @@ struct FiniteElement { } // clang-format on - __host__ __device__ uint32_t num_nodes() const { return 3 * p * (p + 1) * (p + 1); } + SERAC_HOST_DEVICE uint32_t num_nodes() const { return 3 * p * (p + 1) * (p + 1); } struct QuadrilateralStrides { int32_t x_offset; int32_t x_jstride; int32_t x_kstride; int32_t y_offset; int32_t y_jstride; int32_t y_kstride; }; - __host__ __device__ QuadrilateralStrides quad_strides(Connection c, uint32_t offset) { + SERAC_HOST_DEVICE QuadrilateralStrides quad_strides(Connection c, uint32_t offset) { uint8_t o = c.orientation(); int32_t P = p; @@ -54,7 +54,7 @@ struct FiniteElement { } template < typename T > - __host__ __device__ void reorient(const TransformationType type, const Connection * hex, T * values) { + SERAC_HOST_DEVICE void reorient(const TransformationType type, const Connection * hex, T * values) { const Connection * edge = hex + Hexahedron::edge_offset; const Connection * quad = hex + Hexahedron::quad_offset; @@ -107,7 +107,7 @@ struct FiniteElement { } - __host__ __device__ void reorient(const TransformationType type, const Connection * hex, int8_t * transformation) { + SERAC_HOST_DEVICE void reorient(const TransformationType type, const Connection * hex, int8_t * transformation) { const Connection * edge = hex + Hexahedron::edge_offset; const Connection * quad = hex + Hexahedron::quad_offset; @@ -661,7 +661,7 @@ struct FiniteElement { } // TODO: set to nonzero when reenabling sum-factorization implementations - __host__ __device__ uint32_t batch_interpolation_scratch_space(nd::view xi) const { + SERAC_HOST_DEVICE uint32_t batch_interpolation_scratch_space(nd::view xi) const { return 0; } @@ -826,7 +826,7 @@ struct FiniteElement { return shape_fns; } - __host__ __device__ void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fn, double * /* buffer */) const { + SERAC_HOST_DEVICE void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fn, double * /* buffer */) const { int nnodes = num_nodes(); int nqpts = source_q.shape[0]; diff --git a/src/serac/numerics/refactor/elements/hcurl_quadrilateral.hpp b/src/serac/numerics/refactor/elements/hcurl_quadrilateral.hpp index e7a4c8ae2e..af871efb69 100644 --- a/src/serac/numerics/refactor/elements/hcurl_quadrilateral.hpp +++ b/src/serac/numerics/refactor/elements/hcurl_quadrilateral.hpp @@ -8,7 +8,7 @@ using namespace fm; // clang-format off template <> -struct FiniteElement { +struct FiniteElement { using value_type = vec2; using derivative_type = vec1; @@ -18,10 +18,10 @@ struct FiniteElement { static constexpr int dim = 2; - __host__ __device__ uint32_t num_nodes() const { return 2 * p * (p + 1); } + SERAC_HOST_DEVICE uint32_t num_nodes() const { return 2 * p * (p + 1); } template < typename T > - __host__ __device__ void reorient(const TransformationType type, const Connection * quad, T * values) const { + SERAC_HOST_DEVICE void reorient(const TransformationType type, const Connection * quad, T * values) const { const Connection * edge = quad + Quadrilateral::edge_offset; @@ -51,7 +51,7 @@ struct FiniteElement { } - __host__ __device__ void reorient(const TransformationType type, const Connection * quad, int8_t * transformation) { + SERAC_HOST_DEVICE void reorient(const TransformationType type, const Connection * quad, int8_t * transformation) { const Connection * edge = quad + Quadrilateral::edge_offset; @@ -227,7 +227,7 @@ struct FiniteElement { // TODO: this is set to nonzero for the batched interpolation, // even though batched curl doesn't use the buffer - __host__ __device__ uint32_t batch_interpolation_scratch_space(nd::view xi) const { + SERAC_HOST_DEVICE uint32_t batch_interpolation_scratch_space(nd::view xi) const { uint32_t q = xi.shape[0]; return q * (p + 1); } @@ -317,7 +317,7 @@ struct FiniteElement { return shape_fns; } - __host__ __device__ void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fn, double * /*buffer*/) const { + SERAC_HOST_DEVICE void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fn, double * /*buffer*/) const { int nnodes = num_nodes(); int nqpts = source_q.shape[0]; diff --git a/src/serac/numerics/refactor/elements/hcurl_tetrahedron.hpp b/src/serac/numerics/refactor/elements/hcurl_tetrahedron.hpp index b84b80b696..18b7c90063 100644 --- a/src/serac/numerics/refactor/elements/hcurl_tetrahedron.hpp +++ b/src/serac/numerics/refactor/elements/hcurl_tetrahedron.hpp @@ -11,7 +11,7 @@ using namespace fm; // clang-format off template <> -struct FiniteElement { +struct FiniteElement { using value_type = vec3; using derivative_type = vec3; @@ -21,9 +21,9 @@ struct FiniteElement { static constexpr int dim = 3; - __host__ __device__ constexpr uint32_t num_nodes() const { return (p * (p + 2) * (p + 3)) / 2; } + SERAC_HOST_DEVICE constexpr uint32_t num_nodes() const { return (p * (p + 2) * (p + 3)) / 2; } - __host__ __device__ void reorient(const TransformationType type, const Connection * tet, int8_t * transformation) { + SERAC_HOST_DEVICE void reorient(const TransformationType type, const Connection * tet, int8_t * transformation) { const Connection * edge = tet + Tetrahedron::edge_offset; const Connection * tri = tet + Tetrahedron::tri_offset; @@ -70,7 +70,7 @@ struct FiniteElement { } template < typename T > - __host__ __device__ void reorient(const TransformationType type, const Connection * tet, T * values) { + SERAC_HOST_DEVICE void reorient(const TransformationType type, const Connection * tet, T * values) { const Connection * edge = tet + Tetrahedron::edge_offset; const Connection * tri = tet + Tetrahedron::tri_offset; @@ -1194,7 +1194,7 @@ struct FiniteElement { return interpolated_curl; } - __host__ __device__ uint32_t batch_interpolation_scratch_space(nd::view xi) const { + SERAC_HOST_DEVICE uint32_t batch_interpolation_scratch_space(nd::view xi) const { return 0; } @@ -1273,7 +1273,7 @@ struct FiniteElement { return shape_fns; } - __host__ __device__ void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fn, double * /*buffer*/) const { + SERAC_HOST_DEVICE void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fn, double * /*buffer*/) const { int nnodes = num_nodes(); int nqpts = source_q.shape[0]; @@ -1303,7 +1303,7 @@ struct FiniteElement { return shape_fns; } - __host__ __device__ void integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fn, double * /*buffer*/) const { + SERAC_HOST_DEVICE void integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fn, double * /*buffer*/) const { int nnodes = num_nodes(); int nqpts = flux_q.shape[0]; diff --git a/src/serac/numerics/refactor/elements/hcurl_triangle.hpp b/src/serac/numerics/refactor/elements/hcurl_triangle.hpp index 0f16337f4c..989b7896c4 100644 --- a/src/serac/numerics/refactor/elements/hcurl_triangle.hpp +++ b/src/serac/numerics/refactor/elements/hcurl_triangle.hpp @@ -8,7 +8,7 @@ using namespace fm; // clang-format off template <> -struct FiniteElement { +struct FiniteElement { using value_type = vec2; using derivative_type = vec1; @@ -18,10 +18,10 @@ struct FiniteElement { static constexpr int dim = 2; - __host__ __device__ uint32_t num_nodes() const { return p * (p + 2); } + SERAC_HOST_DEVICE uint32_t num_nodes() const { return p * (p + 2); } template < typename T > - __host__ __device__ void reorient(const TransformationType type, const Connection * tri, T * values) const { + SERAC_HOST_DEVICE void reorient(const TransformationType type, const Connection * tri, T * values) const { const Connection * edge = tri + Triangle::edge_offset; @@ -35,7 +35,7 @@ struct FiniteElement { } - __host__ __device__ void reorient(const TransformationType type, const Connection * tri, int8_t * transformation) { + SERAC_HOST_DEVICE void reorient(const TransformationType type, const Connection * tri, int8_t * transformation) { const Connection * edge = tri + Triangle::edge_offset; @@ -321,7 +321,7 @@ struct FiniteElement { return interpolated_curl; } - __host__ __device__ uint32_t batch_interpolation_scratch_space(nd::view xi) const { + SERAC_HOST_DEVICE uint32_t batch_interpolation_scratch_space(nd::view xi) const { return 0; } @@ -393,7 +393,7 @@ struct FiniteElement { return shape_fns; } - __host__ __device__ void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fn, double * /*buffer*/) const { + SERAC_HOST_DEVICE void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fn, double * /*buffer*/) const { int nnodes = num_nodes(); int nqpts = source_q.shape[0]; @@ -420,7 +420,7 @@ struct FiniteElement { return shape_fns; } - __host__ __device__ void integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fn, double * /*buffer*/) const { + SERAC_HOST_DEVICE void integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fn, double * /*buffer*/) const { int nnodes = num_nodes(); int nqpts = flux_q.shape[0]; diff --git a/src/serac/numerics/refactor/elements/hcurl_vertex.hpp b/src/serac/numerics/refactor/elements/hcurl_vertex.hpp index 5aeb965def..a99c538cdc 100644 --- a/src/serac/numerics/refactor/elements/hcurl_vertex.hpp +++ b/src/serac/numerics/refactor/elements/hcurl_vertex.hpp @@ -5,8 +5,8 @@ namespace refactor { template <> -struct FiniteElement < Geometry::Vertex, Family::Hcurl >{ - __host__ __device__ uint32_t num_nodes() const { return 0; } +struct FiniteElement < mfem::Geometry::POINT, Family::Hcurl >{ + SERAC_HOST_DEVICE uint32_t num_nodes() const { return 0; } uint32_t p; }; diff --git a/src/serac/numerics/refactor/evaluate.cpp b/src/serac/numerics/refactor/evaluate.cpp new file mode 100644 index 0000000000..c18821ddec --- /dev/null +++ b/src/serac/numerics/refactor/evaluate.cpp @@ -0,0 +1,248 @@ +#include "common.hpp" + +namespace refactor { + +inline GeometryData< nd::range > ranges(GeometryInfo a) { + GeometryData< nd::range > output; + + uint32_t total = 0; + output.vert = nd::range{total, total + a.vert}; total += a.vert; + output.edge = nd::range{total, total + a.edge}; total += a.edge; + output.tri = nd::range{total, total + a.tri}; total += a.tri; + output.quad = nd::range{total, total + a.quad}; total += a.quad; + output.tet = nd::range{total, total + a.tet}; total += a.tet; + output.hex = nd::range{total, total + a.hex}; total += a.hex; + + return output; +}; + +namespace impl { + +template < mfem::Geometry::Type geom, Family family, DerivedQuantity op > +void batched_interpolate(nd::view u_q, + const Field & u, + const Field & X, + DomainType type, + nd::view connectivity, + const nd::view elements, + const nd::view xi) { + + uint32_t num_elements = elements.size(); + if (num_elements == 0) return; + + FiniteElement< geom, family > u_el{u.degree}; + + using output_t = std::conditional< + op == DerivedQuantity::VALUE, + typename FiniteElement< geom, family >::source_type, + typename FiniteElement< geom, family >::flux_type + >::type; + + nd::view output_q((output_t*)&u_q[0], {u_q.shape[0], u_q.shape[1]}); + + constexpr uint32_t gdim = dimension(geom); + constexpr uint32_t curl_components = source_shape(family, gdim); + uint32_t qpts_per_element = impl::qpe(xi.shape[0]); + + using A_type = decltype(piola_transformation(mat{})); + + uint32_t u_components = u.data.shape[1]; + uint32_t u_nodes_per_element = u_el.num_nodes(); + auto u_shape_fns = [&](){ + if constexpr(op == DerivedQuantity::VALUE) { + return u_el.evaluate_shape_functions(xi); + } + + if constexpr(op == DerivedQuantity::DERIVATIVE && family == Family::Hcurl) { + return u_el.evaluate_shape_function_curls(xi); + } + + if constexpr(op == DerivedQuantity::DERIVATIVE && is_scalar_valued(family)) { + return u_el.evaluate_shape_function_gradients(xi); + } + }(); + + FiniteElement< geom, Family::H1 > X_el{X.degree}; + uint32_t X_components = X.data.shape[1]; + uint32_t X_nodes_per_element = X_el.num_nodes(); + auto X_shape_fn_grads = X_el.evaluate_shape_function_gradients(xi); + + // When do we need to calculate dX/dxi? + // + // ❌ : don't need to ✅ : need to + // +---------------------+------+-------+------+----+ + // | | H1 | Hcurl | Hdiv | DG | + // +---------------------+------+-------+------+----+ + // | isoparametric value | ❌ | ❌ | ❌ | ❌ | + // +---------------------+------+-------+------+----+ + // | isoparametric deriv | ❌ | ❌ | ❌ | ❌ | + // +---------------------+------+-------+------+----+ + // | spatial value | ❌ | ✅ | ✅ | ❌ | + // +---------------------+------+-------+------+----+ + // | spatial deriv | ✅ | ✅ | ✅ | ✅ | + // +---------------------+------+-------+------+----+ + const bool need_to_compute_dX_dxi = + (type == DomainType::SPATIAL && op == DerivedQuantity::DERIVATIVE) || + (type == DomainType::SPATIAL && is_vector_valued(family)); + + // for each element with this geometry + threadpool::block_parallel_for(num_elements, [&](uint32_t istart, uint32_t iend) { + + nd::array< A_type > A_q; + nd::array X_e; + nd::array X_ids; + nd::array< double > X_scratch; + nd::array< vec, 2 > dX_dxi_q; + + if (need_to_compute_dX_dxi) { + A_q.resize({qpts_per_element}); + X_e.resize(X_nodes_per_element); + X_ids.resize(X_nodes_per_element); + X_scratch.resize({X_el.batch_interpolation_scratch_space(xi)}); + dX_dxi_q.resize({X_components, qpts_per_element}); + } + + nd::array u_ids({u_nodes_per_element}); + nd::array u_e({u_nodes_per_element}); + nd::array< double > u_scratch({u_el.batch_interpolation_scratch_space(xi)}); + + for (uint32_t i = istart; i < iend; i++) { + + if (need_to_compute_dX_dxi) { + + // figure out which nodal values belong to this element + X_el.indices(X.offsets, connectivity(elements(i)).data(), X_ids.data()); + + for (int c = 0; c < X_components; c++) { + for (int j = 0; j < X_nodes_per_element; j++) { + X_e(j) = X.data(X_ids(j), c); + } + X_el.gradient(dX_dxi_q(c), X_e, X_shape_fn_grads, X_scratch.data()); + } + + for (int q = 0; q < qpts_per_element; q++) { + mat dX_dxi; + for (int c = 0; c < gdim; c++) { + dX_dxi[c] = dX_dxi_q(c, q); + } + A_q[q] = piola_transformation(dX_dxi); + } + + } + + u_el.indices(u.offsets, connectivity(elements(i)).data(), u_ids.data()); + + nd::array u_xi_q({qpts_per_element}); + for (int c = 0; c < u_components; c++) { + + for (int j = 0; j < u_nodes_per_element; j++) { + u_e(j) = u.data(u_ids(j), c); + } + + if constexpr (is_vector_valued(family)) { + u_el.reorient(TransformationType::PhysicalToParent, &connectivity(elements(i), 0), u_e.data()); + } + + // carry out the appropriate kind of interpolation + // for the requested family and differential operator + if constexpr (op == DerivedQuantity::VALUE) { + u_el.interpolate(u_xi_q, u_e, u_shape_fns, u_scratch.data()); + } + + if constexpr (op == DerivedQuantity::DERIVATIVE && is_scalar_valued(family)) { + u_el.gradient(u_xi_q, u_e, u_shape_fns, u_scratch.data()); + } + + if constexpr (op == DerivedQuantity::DERIVATIVE && family == Family::Hcurl) { + u_el.curl(u_xi_q, u_e, u_shape_fns, u_scratch.data()); + } + + if (need_to_compute_dX_dxi) { + for (int q = 0; q < qpts_per_element; q++) { + output_q(i*qpts_per_element+q, c) = fm::dot(u_xi_q[q], A_q[q]); + } + } else { + for (int q = 0; q < qpts_per_element; q++) { + output_q(i*qpts_per_element+q, c) = u_xi_q[q]; + } + } + + } + + } + + }); + +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +template < Family family, DerivedQuantity op > +void evaluate(nd::array & output, const Field & u, const Domain & domain, const DomainType & type) { + + MTR_SCOPE("evaluate", "field_xi"); + + int gdim = domain.mesh.geometry_dimension; + uint32_t num_components = output.shape[1]; + + auto qranges = ranges(domain.num_qpts); + + uint32_t offset = 0; + foreach_geometry([&](auto geom){ + nd::view elements = domain.active_elements[geom]; + if (gdim == dimension(geom) && elements.size() > 0) { + nd::view xi = domain.rule[geom].points; + nd::view connectivity = domain.mesh[geom]; + nd::range all{0u, num_components}; + impl::batched_interpolate(output(qranges[geom]), u, domain.mesh.X, type, connectivity, elements, xi); + } + }); + +} + +} // namespace impl + +nd::array evaluate(const FieldOp && input, const DomainWithType & d) { + + const Domain & domain = d.domain; + const DomainType & type = d.type; + + Family f = input.field.family; + + int gdim = domain.mesh.geometry_dimension; + uint32_t num_components = input.field.data.shape[1]; + stack::array output_dimensions{ + total(domain.num_qpts), + num_components, + qshape(f, input.op, gdim) + }; + + nd::array u_q(output_dimensions); + + uint32_t offset = 0; + foreach_constexpr< Family::H1, Family::Hcurl >([&](auto family) { + if (family == input.field.family) { + if (input.op == DerivedQuantity::VALUE) { + impl::evaluate(u_q, input.field, domain, type); + } + if (input.op == DerivedQuantity::DERIVATIVE) { + impl::evaluate(u_q, input.field, domain, type); + } + } + }); + + return u_q; + +} + +//void evaluate_vjp(const nd::array & d_du_q, Field & u, const Domain & domain) { +// Family f = u.family; +// // note: H1 only ever interpolates values over the parent element, +// // since its mapping to physical space doesn't require calculating the jacobian +// if (f == Family::H1) { return impl::evaluate_XI(u, domain); } +// if (f == Family::Hcurl) { return impl::evaluate(u, domain); } +//} + +} // namespace refactor diff --git a/src/serac/numerics/refactor/finite_element.hpp b/src/serac/numerics/refactor/finite_element.hpp index e522c03257..35ac355ee8 100644 --- a/src/serac/numerics/refactor/finite_element.hpp +++ b/src/serac/numerics/refactor/finite_element.hpp @@ -12,11 +12,11 @@ enum class Family { DG }; -__host__ __device__ constexpr bool is_scalar_valued(Family f) { +SERAC_HOST_DEVICE constexpr bool is_scalar_valued(Family f) { return (f == Family::H1); } -__host__ __device__ constexpr bool is_vector_valued(Family f) { +SERAC_HOST_DEVICE constexpr bool is_vector_valued(Family f) { return (f == Family::Hcurl); } @@ -56,10 +56,10 @@ enum class TransformationType { TransposePhysicalToParent, }; -template < Geometry g, Family f > +template < mfem::Geometry::Type g, Family f > struct FiniteElement; -template < Geometry geom, Family family > +template < mfem::Geometry::Type geom, Family family > auto shape_function_derivatives(FiniteElement< geom, family > element, const nd::view xi) { if constexpr (family == Family::H1) { @@ -71,7 +71,7 @@ auto shape_function_derivatives(FiniteElement< geom, family > element, } } -template < Geometry geom, Family family > +template < mfem::Geometry::Type geom, Family family > auto weighted_shape_function_derivatives(FiniteElement< geom, family > element, const nd::view xi, const nd::view weights) { @@ -84,7 +84,7 @@ auto weighted_shape_function_derivatives(FiniteElement< geom, family > element, } } -__host__ __device__ constexpr fm::mat2 face_transformation(int8_t id) { +SERAC_HOST_DEVICE constexpr fm::mat2 face_transformation(int8_t id) { constexpr fm::mat2 matrices[5] = { {{{0, 1}, {1, 0}}}, {{{-1, 0}, {-1, 1}}}, @@ -96,7 +96,7 @@ __host__ __device__ constexpr fm::mat2 face_transformation(int8_t id) { return matrices[id-1]; } -__host__ __device__ constexpr int8_t face_transformation_id(TransformationType type, int orientation) { +SERAC_HOST_DEVICE constexpr int8_t face_transformation_id(TransformationType type, int orientation) { if (type == TransformationType::PhysicalToParent) { constexpr int8_t LUT[3] = {1, 2, 3}; return LUT[orientation]; @@ -108,23 +108,23 @@ __host__ __device__ constexpr int8_t face_transformation_id(TransformationType t } -#include "refactor/elements/h1_vertex.hpp" -#include "refactor/elements/h1_edge.hpp" -#include "refactor/elements/h1_triangle.hpp" -#include "refactor/elements/h1_quadrilateral.hpp" -#include "refactor/elements/h1_tetrahedron.hpp" -#include "refactor/elements/h1_hexahedron.hpp" - -#include "refactor/elements/hcurl_vertex.hpp" -#include "refactor/elements/hcurl_edge.hpp" -#include "refactor/elements/hcurl_triangle.hpp" -#include "refactor/elements/hcurl_quadrilateral.hpp" -#include "refactor/elements/hcurl_tetrahedron.hpp" -#include "refactor/elements/hcurl_hexahedron.hpp" - -#include "refactor/elements/dg_vertex.hpp" -#include "refactor/elements/dg_edge.hpp" -#include "refactor/elements/dg_triangle.hpp" -#include "refactor/elements/dg_quadrilateral.hpp" -#include "refactor/elements/dg_tetrahedron.hpp" -#include "refactor/elements/dg_hexahedron.hpp" +#include "serac/numerics/refactor/elements/h1_vertex.hpp" +#include "serac/numerics/refactor/elements/h1_edge.hpp" +#include "serac/numerics/refactor/elements/h1_triangle.hpp" +#include "serac/numerics/refactor/elements/h1_quadrilateral.hpp" +#include "serac/numerics/refactor/elements/h1_tetrahedron.hpp" +#include "serac/numerics/refactor/elements/h1_hexahedron.hpp" + +#include "serac/numerics/refactor/elements/hcurl_vertex.hpp" +#include "serac/numerics/refactor/elements/hcurl_edge.hpp" +#include "serac/numerics/refactor/elements/hcurl_triangle.hpp" +#include "serac/numerics/refactor/elements/hcurl_quadrilateral.hpp" +#include "serac/numerics/refactor/elements/hcurl_tetrahedron.hpp" +#include "serac/numerics/refactor/elements/hcurl_hexahedron.hpp" + +#include "serac/numerics/refactor/elements/dg_vertex.hpp" +#include "serac/numerics/refactor/elements/dg_edge.hpp" +#include "serac/numerics/refactor/elements/dg_triangle.hpp" +#include "serac/numerics/refactor/elements/dg_quadrilateral.hpp" +#include "serac/numerics/refactor/elements/dg_tetrahedron.hpp" +#include "serac/numerics/refactor/elements/dg_hexahedron.hpp" diff --git a/src/serac/numerics/refactor/geometry.hpp b/src/serac/numerics/refactor/geometry.hpp new file mode 100644 index 0000000000..f81fee8f98 --- /dev/null +++ b/src/serac/numerics/refactor/geometry.hpp @@ -0,0 +1,290 @@ +#pragma once + +#include +#include + +#include "serac/infrastructure/accelerator.hpp" +#include "serac/numerics/refactor/containers/ndarray.hpp" + +#include "mfem.hpp" + +namespace refactor { + +namespace impl { + template < mfem::Geometry::Type g > + struct constexpr_geometry{ + constexpr operator mfem::Geometry::Type() { return g; } + }; +} + +template < typename T > +void foreach_geometry(T && function) { + function(impl::constexpr_geometry< mfem::Geometry::SEGMENT >{}); + function(impl::constexpr_geometry< mfem::Geometry::TRIANGLE >{}); + function(impl::constexpr_geometry< mfem::Geometry::SQUARE >{}); + function(impl::constexpr_geometry< mfem::Geometry::TETRAHEDRON >{}); + function(impl::constexpr_geometry< mfem::Geometry::CUBE >{}); +} + +inline const char * to_string(mfem::Geometry::Type g) { + switch (g) { + case mfem::Geometry::POINT: return "Geometry_Vertex"; + case mfem::Geometry::SEGMENT: return "Geometry_Edge"; + case mfem::Geometry::TRIANGLE: return "Geometry_Triangle"; + case mfem::Geometry::SQUARE: return "Geometry_Quadrilateral"; + case mfem::Geometry::TETRAHEDRON: return "Geometry_Tetrahedron"; + case mfem::Geometry::CUBE: return "Geometry_Hexahedron"; + default: return ""; + } + return ""; +} + +constexpr mfem::Geometry::Type all_geometries[6] = { + mfem::Geometry::POINT, + mfem::Geometry::SEGMENT, + mfem::Geometry::TRIANGLE, + mfem::Geometry::SQUARE, + mfem::Geometry::TETRAHEDRON, + mfem::Geometry::CUBE +}; + +constexpr nd::range geometries_by_dim[4] = { + {all_geometries+0, all_geometries+1}, + {all_geometries+1, all_geometries+2}, + {all_geometries+2, all_geometries+4}, + {all_geometries+4, all_geometries+6} +}; + +//constexpr uint32_t dimension(mfem::Geometry::Type g) { +SERAC_HOST_DEVICE constexpr uint32_t dimension(mfem::Geometry::Type g) { + switch (g) { + case mfem::Geometry::POINT: return 0; + case mfem::Geometry::SEGMENT: return 1; + case mfem::Geometry::TRIANGLE: return 2; + case mfem::Geometry::SQUARE: return 2; + case mfem::Geometry::TETRAHEDRON: return 3; + case mfem::Geometry::CUBE: return 3; + default: return 1u<<30; + } +} + +template < typename T > +struct GeometryData { + T vert; + T edge; + T tri; + T quad; + T tet; + T hex; + + T & operator[](mfem::Geometry::Type g) { + switch (g) { + case mfem::Geometry::POINT: return vert; + case mfem::Geometry::SEGMENT: return edge; + case mfem::Geometry::TRIANGLE: return tri; + case mfem::Geometry::SQUARE: return quad; + case mfem::Geometry::TETRAHEDRON: return tet; + case mfem::Geometry::CUBE: return hex; + } + return vert; // unreachable code, to silence compiler warnings + } + + const T & operator[](mfem::Geometry::Type g) const { + switch (g) { + case mfem::Geometry::POINT: return vert; + case mfem::Geometry::SEGMENT: return edge; + case mfem::Geometry::TRIANGLE: return tri; + case mfem::Geometry::SQUARE: return quad; + case mfem::Geometry::TETRAHEDRON: return tet; + case mfem::Geometry::CUBE: return hex; + } + return vert; // unreachable code, to silence compiler warnings + } + +}; + +struct GeometryInfo : public GeometryData { + static GeometryInfo from_array(uint32_t * data) { + return GeometryInfo { data[0], data[1], data[2], data[3], data[4], data[5] }; + } +}; + +inline void operator+=(GeometryInfo & a, const GeometryInfo & b) { + a.vert += b.vert; + a.edge += b.edge; + a.tri += b.tri; + a.quad += b.quad; + a.tet += b.tet; + a.hex += b.hex; +}; + +inline GeometryInfo operator*(GeometryInfo a, GeometryInfo b) { + return GeometryInfo{ + a.vert * b.vert, + a.edge * b.edge, + a.tri * b.tri, + a.quad * b.quad, + a.tet * b.tet, + a.hex * b.hex + }; +}; + +inline GeometryInfo operator*(GeometryInfo a, uint32_t scale) { + return GeometryInfo{ + a.vert * scale, + a.edge * scale, + a.tri * scale, + a.quad * scale, + a.tet * scale, + a.hex * scale + }; +}; + +inline uint32_t total(GeometryInfo input){ + return input.vert + input.edge + input.tri + input.quad + input.tet + input.hex; +}; + +inline GeometryInfo scan(const GeometryInfo & input){ + GeometryInfo output; + output.vert = 0; + output.edge = output.vert + input.vert; + output.tri = output.edge + input.edge; + output.quad = output.tri + input.tri; + output.tet = output.quad + input.quad; + output.hex = output.tet + input.tet; + return output; +}; + +template < uint32_t n > +std::array< uint32_t, n + 1 > scan(const uint32_t (&input)[n]){ + std::array< uint32_t, n + 1 > output{}; + for (uint32_t i = 0; i < n; i++) { + output[i+1] = output[i] + input[i]; + } + return output; +}; + + + +template < mfem::Geometry::Type g > +struct GeometryType; + +template <> +struct GeometryType< mfem::Geometry::POINT > { + static constexpr mfem::Geometry::Type geometry = mfem::Geometry::POINT; + static constexpr int offset = 0; + static constexpr int dim = 0; +}; +using Vertex = GeometryType< mfem::Geometry::POINT >; + +template <> +struct GeometryType< mfem::Geometry::SEGMENT > { + static constexpr mfem::Geometry::Type geometry = mfem::Geometry::SEGMENT; + static constexpr int offset = 1; + + static constexpr int dim = 1; + static constexpr int num_vertices = 2; + + static constexpr int cell_offset = num_vertices; +}; +using Edge = GeometryType< mfem::Geometry::SEGMENT >; + +template <> +struct GeometryType< mfem::Geometry::TRIANGLE > { + static constexpr mfem::Geometry::Type geometry = mfem::Geometry::TRIANGLE; + static constexpr int offset = 2; + + static constexpr int dim = 2; + static constexpr int num_vertices = 3; + static constexpr int num_edges = 3; + + static constexpr int edge_offset = num_vertices; + static constexpr int cell_offset = num_vertices + num_edges; + + static constexpr int local_edge_ids[3][2] = {{0, 1},{1, 2},{2, 0}}; + + SERAC_HOST_DEVICE static constexpr uint32_t number(int n) { return (n * (n + 1)) / 2; }; +}; +using Triangle = GeometryType< mfem::Geometry::TRIANGLE >; + +template <> +struct GeometryType< mfem::Geometry::SQUARE > { + static constexpr mfem::Geometry::Type geometry = mfem::Geometry::SQUARE; + static constexpr int offset = 3; + + static constexpr int dim = 2; + static constexpr int num_vertices = 4; + static constexpr int num_edges = 4; + + static constexpr int edge_offset = num_vertices; + static constexpr int cell_offset = edge_offset + num_edges; + + static constexpr int local_edge_ids[4][4] = {{0, 1},{1, 2},{2, 3},{3,0}}; +}; +using Quadrilateral = GeometryType< mfem::Geometry::SQUARE >; + +template <> +struct GeometryType< mfem::Geometry::TETRAHEDRON > { + static constexpr mfem::Geometry::Type geometry = mfem::Geometry::TETRAHEDRON; + static constexpr int offset = 4; + + static constexpr int dim = 3; + static constexpr int num_vertices = 4; + static constexpr int num_edges = 6; + static constexpr int num_triangles = 4; + static constexpr int num_quadrilaterals = 0; + + static constexpr int edge_offset = num_vertices; + static constexpr int tri_offset = edge_offset + num_edges; + static constexpr int quad_offset = tri_offset + num_triangles; + static constexpr int cell_offset = quad_offset + num_quadrilaterals; + + static constexpr double vertices[4][3] = {{0,0,0}, {1,0,0}, {0,1,0}, {0,0,1}}; + static constexpr int local_edge_ids[6][2] = {{0, 1}, {1, 2}, {2, 0}, {0, 3}, {1, 3}, {2, 3}}; + static constexpr int local_triangle_ids[4][3] = {{2, 1, 0}, {0, 1, 3}, {1, 2, 3}, {2, 0, 3}}; + + SERAC_HOST_DEVICE static constexpr int number(int n) { return (n * (n + 1) * (n + 2)) / 6; } +}; +using Tetrahedron = GeometryType< mfem::Geometry::TETRAHEDRON >; + +template <> +struct GeometryType< mfem::Geometry::CUBE > { + static constexpr mfem::Geometry::Type geometry = mfem::Geometry::CUBE; + static constexpr int offset = 5; + + static constexpr int dim = 3; + static constexpr int num_vertices = 8; + static constexpr int num_edges = 12; + static constexpr int num_triangles = 0; + static constexpr int num_quadrilaterals = 6; + + static constexpr int edge_offset = num_vertices; + static constexpr int tri_offset = edge_offset + num_edges; + static constexpr int quad_offset = tri_offset + num_triangles; + static constexpr int cell_offset = quad_offset + num_quadrilaterals; + + // mathematica code for visualizing these edge/quad numberings + /* + localEdgeIds = 1 + {{0, 1},{1, 2},{3, 2},{0, 3},{0, 4},{1, 5},{2, 6},{3, 7},{4, 5},{5, 6},{7, 6},{4, 7}}; + localQuadIds = 1 + {{1, 0, 3, 2}, {0, 1, 5, 4}, {1, 2, 6, 5}, {2, 3, 7, 6}, {3, 0, 4, 7}, {4, 5, 6, 7}}; + vertices = {{-1, -1, -1}, {1, -1, -1}, {1, 1, -1}, {-1, 1, -1}, {-1, -1, 1}, {1, -1, 1}, {1, 1, 1}, {-1, 1, 1}}; + Graphics3D[{ + Thickness[0.01], JoinForm["Round"], Black, PointSize[0.03], + Point /@ vertices, Table[Text[Style[i - 1, Large], 1.2 vertices[[i]]], {i, 1, 8}], + Red, Arrow[( { {0.9, 0.1}, {0.1, 0.9} } ) . vertices[[#]]] & /@ localEdgeIds, + Table[Text[Style[i - 1, Large], 1.3 Mean[vertices[[localEdgeIds[[i]]]]]], {i, 1, 12}], + Blue, Arrow[( { + {0.7, 0.1, 0.1, 0.1}, + {0.1, 0.7, 0.1, 0.1}, + {0.1, 0.1, 0.7, 0.1}, + {0.1, 0.1, 0.1, 0.7} + } ) . vertices[[#]]] & /@ localQuadIds, + Table[Text[Style[i - 1, Large], Mean[vertices[[localQuadIds[[i]]]]]], {i, 1, 6}] + }, Boxed -> False] + */ + static constexpr int local_edge_ids[12][2] = {{0, 1},{1, 2},{3, 2},{0, 3},{0, 4},{1, 5},{2, 6},{3, 7},{4, 5},{5, 6},{7, 6},{4, 7}}; + static constexpr int local_quadrilateral_ids[6][4] = {{1, 0, 3, 2},{0, 1, 5, 4},{1, 2, 6, 5},{2, 3, 7, 6},{3, 0, 4, 7},{4, 5, 6, 7}}; +}; +using Hexahedron = GeometryType< mfem::Geometry::CUBE >; + +} diff --git a/src/serac/numerics/refactor/integrate_diag.cpp b/src/serac/numerics/refactor/integrate_diag.cpp new file mode 100644 index 0000000000..bc5b318f47 --- /dev/null +++ b/src/serac/numerics/refactor/integrate_diag.cpp @@ -0,0 +1,311 @@ +#include "common.hpp" + +#include "misc/timer.hpp" + +#include "refactor/domain.hpp" +#include "refactor/assert.hpp" +#include "refactor/threadpool.hpp" + +#include "minitrace.h" + +namespace refactor { + +namespace impl { + +template < mfem::Geometry::Type geom, Family family, DerivedQuantity test_op, DerivedQuantity trial_op> +void batched_integrate_diag(nd::view D, + nd::view qdata, + const FunctionSpace space, + const GeometryInfo offsets, + const Field & X, + const DomainType type, + const nd::view connectivity, + const nd::view elements, + const nd::view xi, + const nd::view weights, + const Domain::AssemblyLUT & table, + nd::array & D_e_buffer) { + + MTR_SCOPE("integrate_spmat", "batched_dphi_dpsi_xi"); + + constexpr uint32_t gdim = dimension(geom); + constexpr uint32_t test_qshape = qshape(family, test_op, gdim); + constexpr uint32_t trial_qshape = qshape(family, trial_op, gdim); + + using test_qtype = vec; + using trial_qtype = vec; + using mat_t = mat; + + using test_Atype = decltype(piola_transformation(mat{})); + using trial_Atype = decltype(weighted_piola_transformation(mat{})); + + FiniteElement< geom, Family::H1 > X_el{X.degree}; + FiniteElement< geom, family > el{space.degree}; + + uint32_t num_nodes = D.shape[0]; + uint32_t num_elements = elements.size(); + uint32_t num_components = space.components; + uint32_t nodes_per_element = el.num_nodes(); + uint32_t qpts_per_element = impl::qpe(xi.shape[0]); + + uint32_t X_components = X.data.shape[1]; + uint32_t X_nodes_per_element = X_el.num_nodes(); + + auto X_shape_fn_grads = X_el.evaluate_shape_function_gradients(xi); + + // When do we need to calculate dX/dxi? + // + // ❌ : don't need to ✅ : need to + // +---------------------+------+-------+------+----+ + // | | H1 | Hcurl | Hdiv | DG | + // +---------------------+------+-------+------+----+ + // | isoparametric value | ❌ | ❌ | ❌ | ❌ | + // +---------------------+------+-------+------+----+ + // | isoparametric deriv | ❌ | ❌ | ❌ | ❌ | + // +---------------------+------+-------+------+----+ + // | spatial value | ✅ | ✅ | ✅ | ✅ | + // +---------------------+------+-------+------+----+ + // | spatial deriv | ✅ | ✅ | ✅ | ✅ | + // +---------------------+------+-------+------+----+ + const bool need_to_compute_dX_dxi = (type == DomainType::SPATIAL); + + stack::array D_e_shape = {num_elements * nodes_per_element, num_components}; + + if (D_e_buffer.sz < nd::product(D_e_shape)) { + D_e_buffer.resize(nd::product(D_e_shape)); + } + + nd::view D_e(D_e_buffer.data(), D_e_shape); + + // for each element of this mfem::Geometry::Type in the domain + threadpool::parallel_for(num_elements, [&](uint32_t e) { + + nd::array testA_q; + nd::array trialA_q; + + if (need_to_compute_dX_dxi) { + nd::array, 2> dX_dxi_q({X_components, qpts_per_element}); + nd::array X_ids({X_nodes_per_element}); + nd::array X_e({X_nodes_per_element}); + nd::array X_scratch({X_el.batch_interpolation_scratch_space(xi)}); + + // figure out which nodal values belong to this element + X_el.indices(X.offsets, connectivity(elements(e)).data(), X_ids.data()); + + for (int c = 0; c < X_components; c++) { + for (int j = 0; j < X_nodes_per_element; j++) { + X_e(j) = X.data(X_ids(j), c); + } + X_el.gradient(dX_dxi_q(c), X_e, X_shape_fn_grads, X_scratch.data()); + } + + testA_q.resize({qpts_per_element}); + trialA_q.resize({qpts_per_element}); + for (int q = 0; q < qpts_per_element; q++) { + mat dX_dxi; + for (int c = 0; c < gdim; c++) { + dX_dxi[c] = dX_dxi_q(c, q); + } + testA_q[q] = piola_transformation(dX_dxi); + trialA_q[q] = weighted_piola_transformation(dX_dxi); + } + } + + nd::array< int8_t > transformation({nodes_per_element}); + if constexpr (is_vector_valued(family)) { + el.reorient(TransformationType::TransposePhysicalToParent, &connectivity(elements(e), 0), transformation.data()); + } + + uint32_t qoffset = e * qpts_per_element; + + for (uint32_t i = 0; i < num_components; i++) { + for (uint32_t I = 0; I < nodes_per_element; I++) { + + double sum = 0.0; + + for (uint32_t q = 0; q < qpts_per_element; q++) { + uint32_t qid = qoffset + q; + + auto xi_q = quadrature_point(q, xi); + double wt = integration_weight(q, weights); + + mat_t C{}; + for (uint32_t k = 0; k < test_qshape; k++) { + for (uint32_t m = 0; m < trial_qshape; m++) { + C(k, m) = qdata(qid, i, k, i, m); + } + } + + test_qtype phi_I; + if constexpr (is_scalar_valued(family) && test_op == DerivedQuantity::VALUE) { + phi_I = el.shape_function(xi_q, I); + } + + if constexpr (is_scalar_valued(family) && test_op == DerivedQuantity::DERIVATIVE) { + phi_I = el.shape_function_gradient(xi_q, I); + } + + if constexpr (family == Family::Hcurl && test_op == DerivedQuantity::VALUE) { + phi_I = el.reoriented_shape_function(xi_q, I, transformation[I]); + } + + if constexpr (family == Family::Hcurl && test_op == DerivedQuantity::DERIVATIVE) { + phi_I = el.reoriented_shape_function_curl(xi_q, I, transformation[I]); + } + + trial_qtype psi_I; + if constexpr (is_scalar_valued(family) && trial_op == DerivedQuantity::VALUE) { + psi_I = el.shape_function(xi_q, I); + } + + if constexpr (is_scalar_valued(family) && trial_op == DerivedQuantity::DERIVATIVE) { + psi_I = el.shape_function_gradient(xi_q, I); + } + + if constexpr (family == Family::Hcurl && trial_op == DerivedQuantity::VALUE) { + psi_I = el.reoriented_shape_function(xi_q, I, transformation[I]); + } + + if constexpr (family == Family::Hcurl && trial_op == DerivedQuantity::DERIVATIVE) { + psi_I = el.reoriented_shape_function_curl(xi_q, I, transformation[I]); + } + + if (need_to_compute_dX_dxi) { + phi_I = fm::dot(phi_I, testA_q[q]); + psi_I = fm::dot(psi_I, trialA_q[q]); + } + + sum += fm::dot(fm::dot(phi_I, C), psi_I) * wt; + + } + + D_e(e * nodes_per_element + I, i) = sum; + + } + + } + + }); + + { + MTR_SCOPE("integrate", "(gather)"); + threadpool::block_parallel_for(num_nodes, [&](uint32_t istart, uint32_t iend) { + + std::vector sums(num_components); + + for (uint32_t i = istart; i < iend; i++) { + uint32_t begin = table.offsets[i]; + uint32_t end = table.offsets[i+1]; + + for (uint32_t c = 0; c < num_components; c++) { + sums[c] = 0.0; + } + + for (uint32_t k = begin; k < end; k++) { + uint32_t id = table.ids[k]; + for (uint32_t c = 0; c < num_components; c++) { + sums[c] += D_e(id, c); + } + } + + for (uint32_t c = 0; c < num_components; c++) { + D(i, c) += sums[c]; + } + } + + }); + } + +} + +template +nd::array integrate_sparse_matrix_diagonal(BasisFunction test, const nd::array & qdata, BasisFunction trial, const Domain &domain, const DomainType type) { + + MTR_SCOPE("integrate", "diag"); + + auto phi = test.space; + auto psi = trial.space; + + refactor_ASSERT(phi == psi, "must have matching test and trial spaces for diag(...)"); + + uint32_t test_components = phi.components; + uint32_t trial_components = psi.components; + uint32_t sdim = domain.mesh.spatial_dimension; + uint32_t gdim = domain.mesh.geometry_dimension; + + stack::array shape5D = { + qdata.shape[0], + phi.components, qshape(phi.family, test_op, gdim), + psi.components, qshape(psi.family, trial_op, gdim) + }; + + refactor_ASSERT(compatible_shapes(qdata.shape, shape5D), "incompatible array shapes"); + + nd::view q5D{qdata.data(), shape5D}; + + Residual output(phi, domain.mesh); + + static nd::array< double > D_e_buffer; + + uint32_t qoffset = 0; + foreach_geometry([&](auto geom){ + nd::view elements = domain.active_elements[geom]; + if (gdim == dimension(geom) && elements.size() > 0) { + nd::view connectivity = domain.mesh[geom]; + nd::view xi = domain.rule[geom].points; + nd::view weights = domain.rule[geom].weights; + + stack::array< uint32_t, 5 > qdata_shape{domain.num_qpts[geom], shape5D[1], shape5D[2], shape5D[3], shape5D[4]}; + nd::view geom_qdata{&q5D(qoffset, 0, 0, 0, 0), qdata_shape}; + + const Domain::AssemblyLUT & table = domain.get(geom, phi.family, phi.degree); + + foreach_constexpr< Family::H1, Family::Hcurl >([&](auto family) { + if (family == phi.family) { + batched_integrate_diag( + output.data, + geom_qdata, psi, + output.offsets, domain.mesh.X, type, + connectivity, elements, + xi, weights, + table, D_e_buffer + ); + } + }); + + qoffset += domain.num_qpts[geom]; + } + }); + + return output.data; +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +template nd::array integrate_sparse_matrix_diagonal(BasisFunction, const nd::array &, BasisFunction, const Domain &, const DomainType); +template nd::array integrate_sparse_matrix_diagonal(BasisFunction, const nd::array &, BasisFunction, const Domain &, const DomainType); +template nd::array integrate_sparse_matrix_diagonal(BasisFunction, const nd::array &, BasisFunction, const Domain &, const DomainType); +template nd::array integrate_sparse_matrix_diagonal(BasisFunction, const nd::array &, BasisFunction, const Domain &, const DomainType); + +template nd::array integrate_sparse_matrix_diagonal(BasisFunction, const nd::array &, BasisFunction, const Domain &, const DomainType); +template nd::array integrate_sparse_matrix_diagonal(BasisFunction, const nd::array &, BasisFunction, const Domain &, const DomainType); +template nd::array integrate_sparse_matrix_diagonal(BasisFunction, const nd::array &, BasisFunction, const Domain &, const DomainType); +template nd::array integrate_sparse_matrix_diagonal(BasisFunction, const nd::array &, BasisFunction, const Domain &, const DomainType); + +template nd::array integrate_sparse_matrix_diagonal(BasisFunction, const nd::array &, BasisFunction, const Domain &, const DomainType); +template nd::array integrate_sparse_matrix_diagonal(BasisFunction, const nd::array &, BasisFunction, const Domain &, const DomainType); +template nd::array integrate_sparse_matrix_diagonal(BasisFunction, const nd::array &, BasisFunction, const Domain &, const DomainType); +template nd::array integrate_sparse_matrix_diagonal(BasisFunction, const nd::array &, BasisFunction, const Domain &, const DomainType); + +template nd::array integrate_sparse_matrix_diagonal(BasisFunction, const nd::array &, BasisFunction, const Domain &, const DomainType); +template nd::array integrate_sparse_matrix_diagonal(BasisFunction, const nd::array &, BasisFunction, const Domain &, const DomainType); +template nd::array integrate_sparse_matrix_diagonal(BasisFunction, const nd::array &, BasisFunction, const Domain &, const DomainType); +template nd::array integrate_sparse_matrix_diagonal(BasisFunction, const nd::array &, BasisFunction, const Domain &, const DomainType); + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +} // namespace impl + +} // namespace refactor diff --git a/src/serac/numerics/refactor/integrate_residual.cpp b/src/serac/numerics/refactor/integrate_residual.cpp new file mode 100644 index 0000000000..fd94524bad --- /dev/null +++ b/src/serac/numerics/refactor/integrate_residual.cpp @@ -0,0 +1,271 @@ +#include "common.hpp" + +#include "refactor/domain.hpp" +#include "refactor/assert.hpp" +#include "refactor/threadpool.hpp" + +#include "fm/types/matrix.hpp" +#include "fm/types/vec.hpp" + +#include "common.hpp" + +#include "misc/for_constexpr.hpp" +#include "misc/timer.hpp" + +namespace refactor { + +namespace impl { + +template < mfem::Geometry::Type geom, Family family, DerivedQuantity op > +void batched_integrate_residual(Residual & r, + const Field & X, + const DomainType type, + nd::view f_q, + nd::view connectivity, + const nd::view elements, + const nd::view xi, + const nd::view weights, + const Domain::AssemblyLUT & table, + nd::array & element_residual_buffer) { + + uint32_t num_elements = elements.size(); + if (num_elements == 0) return; + + FiniteElement< geom, family > r_el{r.space.degree}; + + using input_t = std::conditional< + op == DerivedQuantity::VALUE, + typename FiniteElement< geom, family >::source_type, + typename FiniteElement< geom, family >::flux_type + >::type; + + nd::view input_q((input_t*)&f_q[0], {f_q.shape[0], f_q.shape[1]}); + + constexpr uint32_t gdim = dimension(geom); + uint32_t qpts_per_element = impl::qpe(xi.shape[0]); + + using A_type = decltype(weighted_piola_transformation(mat{})); + + uint32_t num_nodes = r.data.shape[0]; + uint32_t r_components = r.data.shape[1]; + uint32_t r_nodes_per_element = r_el.num_nodes(); + auto r_shape_fns = [&](){ + if constexpr(op == DerivedQuantity::VALUE) { + return r_el.evaluate_weighted_shape_functions(xi, weights); + } + + if constexpr(op == DerivedQuantity::DERIVATIVE && family == Family::Hcurl) { + return r_el.evaluate_weighted_shape_function_curls(xi, weights); + } + + if constexpr(op == DerivedQuantity::DERIVATIVE && is_scalar_valued(family)) { + return r_el.evaluate_weighted_shape_function_gradients(xi, weights); + } + }(); + + FiniteElement< geom, Family::H1 > X_el{X.degree}; + uint32_t X_components = X.data.shape[1]; + uint32_t X_nodes_per_element = X_el.num_nodes(); + + auto X_shape_fn_grads = X_el.evaluate_shape_function_gradients(xi); + + // When do we need to calculate dX/dxi? + // + // ❌ : don't need to ✅ : need to + // +---------------------+------+-------+------+----+ + // | | H1 | Hcurl | Hdiv | DG | + // +---------------------+------+-------+------+----+ + // | isoparametric value | ❌ | ❌ | ❌ | ❌ | + // +---------------------+------+-------+------+----+ + // | isoparametric deriv | ❌ | ❌ | ❌ | ❌ | + // +---------------------+------+-------+------+----+ + // | spatial value | ✅ | ✅ | ✅ | ✅ | + // +---------------------+------+-------+------+----+ + // | spatial deriv | ✅ | ✅ | ✅ | ✅ | + // +---------------------+------+-------+------+----+ + const bool need_to_compute_dX_dxi = (type == DomainType::SPATIAL); + + + + stack::array element_residual_shape = {num_elements * r_nodes_per_element, r_components}; + + if (element_residual_buffer.sz < nd::product(element_residual_shape)) { + element_residual_buffer.resize(nd::product(element_residual_shape)); + } + + nd::view element_residuals(element_residual_buffer.data(), element_residual_shape); + + { + MTR_SCOPE("integrate", "(element residuals)"); + + // for each element with this geometry + threadpool::block_parallel_for(num_elements, [&](uint32_t istart, uint32_t iend) { + + nd::array< A_type > A_q; + nd::array< vec, 2 > dX_dxi_q; + nd::array X_ids; + nd::array X_e; + nd::array< double > X_scratch; + + if (need_to_compute_dX_dxi) { + X_ids.resize(X_nodes_per_element); + X_e.resize(X_nodes_per_element); + X_scratch.resize({X_el.batch_interpolation_scratch_space(xi)}); + A_q.resize({qpts_per_element}); + dX_dxi_q.resize({X_components, qpts_per_element}); + } + + nd::array r_ids({r_nodes_per_element}); + nd::array r_e({r_nodes_per_element}); + nd::array< double > r_scratch({r_el.batch_interpolation_scratch_space(xi)}); + + for (uint32_t i = istart; i < iend; i++) { + + if (need_to_compute_dX_dxi) { + + // figure out which nodal values belong to this element + X_el.indices(X.offsets, connectivity(elements(i)).data(), X_ids.data()); + + for (int c = 0; c < X_components; c++) { + for (int j = 0; j < X_nodes_per_element; j++) { + X_e(j) = X.data(X_ids(j), c); + } + X_el.gradient(dX_dxi_q(c), X_e, X_shape_fn_grads, X_scratch.data()); + } + + for (int q = 0; q < qpts_per_element; q++) { + mat dX_dxi; + for (int c = 0; c < gdim; c++) { + dX_dxi[c] = dX_dxi_q(c, q); + } + A_q[q] = weighted_piola_transformation(dX_dxi); + } + + } + + nd::array input_xi_q({qpts_per_element}); + for (int c = 0; c < r_components; c++) { + if (need_to_compute_dX_dxi) { + for (int q = 0; q < qpts_per_element; q++) { + input_xi_q(q) = fm::dot(A_q[q], input_q(i*qpts_per_element+q, c)); + } + } else { + for (int q = 0; q < qpts_per_element; q++) { + input_xi_q(q) = input_q(i*qpts_per_element+q, c); + } + } + + if constexpr (op == DerivedQuantity::VALUE) { + r_el.integrate_source(r_e, input_xi_q, r_shape_fns, r_scratch.data()); + } + + if constexpr (op == DerivedQuantity::DERIVATIVE) { + r_el.integrate_flux(r_e, input_xi_q, r_shape_fns, r_scratch.data()); + } + + if constexpr (is_vector_valued(family)) { + r_el.reorient(TransformationType::TransposePhysicalToParent, &connectivity(elements(i), 0), r_e.data()); + } + + for (int j = 0; j < r_nodes_per_element; j++) { + element_residuals(i * r_nodes_per_element + j, c) = r_e(j); + } + + } + + } + + }); + + } + + { + MTR_SCOPE("integrate", "(gather)"); + threadpool::block_parallel_for(num_nodes, [&](uint32_t istart, uint32_t iend) { + + std::vector sums(r_components); + + for (uint32_t i = istart; i < iend; i++) { + uint32_t begin = table.offsets[i]; + uint32_t end = table.offsets[i+1]; + + for (uint32_t c = 0; c < r_components; c++) { + sums[c] = 0.0; + } + + for (uint32_t k = begin; k < end; k++) { + uint32_t id = table.ids[k]; + for (uint32_t c = 0; c < r_components; c++) { + sums[c] += element_residuals(id, c); + } + } + + for (uint32_t c = 0; c < r_components; c++) { + r.data(i, c) += sums[c]; + } + } + }); + } +} + +template < DerivedQuantity op, uint32_t n > +void integrate_residual(Residual & r, BasisFunction phi, const nd::array & f_q, const Domain & domain, const DomainType type) { + + MTR_SCOPE("integrate", "residual"); + + zero(r.data); + + uint32_t gdim = domain.mesh.geometry_dimension; + + stack::array input_dimensions{ + f_q.shape[0], + phi.space.components, + qshape(r.space.family, op, gdim) + }; + + refactor_ASSERT(compatible_shapes(f_q.shape, input_dimensions), "incompatible array shapes"); + + static nd::array< double > element_residual_buffer; + + nd::view f3D{f_q.data(), input_dimensions}; + uint32_t offset = 0; + foreach_geometry([&](auto geom){ + nd::view elements = domain.active_elements[geom]; + if (gdim == dimension(geom) && elements.shape[0] > 0) { + nd::view xi = domain.rule[geom].points; + nd::view weights = domain.rule[geom].weights; + nd::view connectivity = domain.mesh[geom]; + + nd::view integrand_geom = {&f3D(offset, 0, 0), {domain.num_qpts[geom], f3D.shape[1], f3D.shape[2]}}; + + const Domain::AssemblyLUT & table = domain.get(geom, phi.space.family, phi.space.degree); + + if (phi.space.family == Family::H1) { + batched_integrate_residual(r, domain.mesh.X, type, integrand_geom, connectivity, elements, xi, weights, table, element_residual_buffer); + } + + if (phi.space.family == Family::Hcurl) { + batched_integrate_residual(r, domain.mesh.X, type, integrand_geom, connectivity, elements, xi, weights, table, element_residual_buffer); + } + } + + offset += domain.num_qpts[geom]; + }); + +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +template void integrate_residual(Residual&, BasisFunction, const nd::array &, const Domain &, const DomainType); +template void integrate_residual(Residual&, BasisFunction, const nd::array &, const Domain &, const DomainType); +template void integrate_residual(Residual&, BasisFunction, const nd::array &, const Domain &, const DomainType); + +template void integrate_residual(Residual&, BasisFunction, const nd::array &, const Domain &, const DomainType); +template void integrate_residual(Residual&, BasisFunction, const nd::array &, const Domain &, const DomainType); +template void integrate_residual(Residual&, BasisFunction, const nd::array &, const Domain &, const DomainType); + +} // namespace impl + +} // namespace refactor diff --git a/src/serac/numerics/refactor/integrate_spmat.cpp b/src/serac/numerics/refactor/integrate_spmat.cpp new file mode 100644 index 0000000000..e1a453136b --- /dev/null +++ b/src/serac/numerics/refactor/integrate_spmat.cpp @@ -0,0 +1,339 @@ +#include "common.hpp" + +#include "misc/timer.hpp" + +#include "refactor/domain.hpp" +#include "refactor/assert.hpp" +#include "refactor/threadpool.hpp" + +#include "minitrace.h" + +namespace refactor { + +namespace impl { + +template < mfem::Geometry::Type geom, Family test_family, DerivedQuantity test_op, Family trial_family, DerivedQuantity trial_op> +void batched_integrate_spmat(nd::view values, + nd::view row_ptr, + nd::view col_ind, + nd::view qdata, + FunctionSpace trial_space, + FunctionSpace test_space, + GeometryInfo trial_offsets, + GeometryInfo test_offsets, + const Field & X, + const DomainType type, + nd::view connectivity, + const nd::view elements, + const nd::view xi, + const nd::view weights) { + + MTR_SCOPE("integrate_spmat", "batched_dphi_dpsi_xi"); + + constexpr uint32_t gdim = dimension(geom); + constexpr uint32_t test_qshape = qshape(test_family, test_op, gdim); + constexpr uint32_t trial_qshape = qshape(trial_family, trial_op, gdim); + + using test_qtype = vec; + using trial_qtype = vec; + using mat_t = mat; + + using test_Atype = decltype(piola_transformation(mat{})); + using trial_Atype = decltype(weighted_piola_transformation(mat{})); + + FiniteElement< geom, Family::H1 > X_el{X.degree}; + FiniteElement< geom, test_family > test_el{test_space.degree}; + FiniteElement< geom, trial_family > trial_el{trial_space.degree}; + + uint32_t num_elements = elements.size(); + uint32_t test_components = test_space.components; + uint32_t trial_components = trial_space.components; + uint32_t test_nodes_per_element = test_el.num_nodes(); + uint32_t trial_nodes_per_element = trial_el.num_nodes(); + uint32_t qpts_per_element = impl::qpe(xi.shape[0]); + + constexpr int nmutex = 1024; + std::vector< std::mutex > mutexes(nmutex); + + // precalculate test functions for the provided quadrature rule + auto psi_wt = [&](){ + if constexpr(trial_op == DerivedQuantity::VALUE) { + return trial_el.evaluate_weighted_shape_functions(xi, weights); + } + + if constexpr(trial_op == DerivedQuantity::DERIVATIVE && trial_family == Family::Hcurl) { + return trial_el.evaluate_weighted_shape_function_curls(xi, weights); + } + + if constexpr(trial_op == DerivedQuantity::DERIVATIVE && is_scalar_valued(trial_family)) { + return trial_el.evaluate_weighted_shape_function_gradients(xi, weights); + } + }(); + + uint32_t X_components = X.data.shape[1]; + uint32_t X_nodes_per_element = X_el.num_nodes(); + + auto X_shape_fn_grads = X_el.evaluate_shape_function_gradients(xi); + + // When do we need to calculate dX/dxi? + // + // ❌ : don't need to ✅ : need to + // +---------------------+------+-------+------+----+ + // | | H1 | Hcurl | Hdiv | DG | + // +---------------------+------+-------+------+----+ + // | isoparametric value | ❌ | ❌ | ❌ | ❌ | + // +---------------------+------+-------+------+----+ + // | isoparametric deriv | ❌ | ❌ | ❌ | ❌ | + // +---------------------+------+-------+------+----+ + // | spatial value | ✅ | ✅ | ✅ | ✅ | + // +---------------------+------+-------+------+----+ + // | spatial deriv | ✅ | ✅ | ✅ | ✅ | + // +---------------------+------+-------+------+----+ + const bool need_to_compute_dX_dxi = (type == DomainType::SPATIAL); + + // for each element of this mfem::Geometry::Type in the domain + threadpool::block_parallel_for(num_elements, [&](uint32_t e_start, uint32_t e_end) { + + THREAD_SCOPE_TRACE("integrate_spmat", "element block"); + + nd::array testA_q; + nd::array trialA_q; + nd::array, 2> dX_dxi_q; + nd::array X_ids; + nd::array X_e; + nd::array X_scratch; + + if (need_to_compute_dX_dxi) { + testA_q.resize({qpts_per_element}); + trialA_q.resize({qpts_per_element}); + dX_dxi_q.resize({X_components, qpts_per_element}); + X_ids.resize(X_nodes_per_element); + X_e.resize(X_nodes_per_element); + X_scratch.resize({X_el.batch_interpolation_scratch_space(xi)}); + } + + for (uint32_t e = e_start; e < e_end; e++) { + + if (need_to_compute_dX_dxi) { + // figure out which nodal values belong to this element + X_el.indices(X.offsets, connectivity(elements(e)).data(), X_ids.data()); + + for (int c = 0; c < X_components; c++) { + for (int j = 0; j < X_nodes_per_element; j++) { + X_e(j) = X.data(X_ids(j), c); + } + X_el.gradient(dX_dxi_q(c), X_e, X_shape_fn_grads, X_scratch.data()); + } + + for (int q = 0; q < qpts_per_element; q++) { + mat dX_dxi; + for (int c = 0; c < gdim; c++) { + dX_dxi[c] = dX_dxi_q(c, q); + } + testA_q[q] = piola_transformation(dX_dxi); + trialA_q[q] = weighted_piola_transformation(dX_dxi); + } + } + + nd::array< double > trial_scratch({trial_el.batch_interpolation_scratch_space(xi)}); + + nd::array< trial_qtype > hat_f({qpts_per_element}); + + nd::array test_ids({test_nodes_per_element}); + test_el.indices(test_offsets, connectivity(elements(e)).data(), test_ids.data()); + + nd::array trial_ids({trial_nodes_per_element}); + trial_el.indices(trial_offsets, connectivity(elements(e)).data(), trial_ids.data()); + + nd::array< int8_t > transformation({test_nodes_per_element}); + if constexpr (is_vector_valued(test_family)) { + test_el.reorient(TransformationType::TransposePhysicalToParent, &connectivity(elements(e), 0), transformation.data()); + } + + uint32_t qoffset = e * qpts_per_element; + + for (uint32_t i = 0; i < test_components; i++) { + for (uint32_t j = 0; j < trial_components; j++) { + for (uint32_t I = 0; I < test_nodes_per_element; I++) { + int row_id = test_ids[I] * test_components + i; + + for (uint32_t q = 0; q < qpts_per_element; q++) { + uint32_t qid = qoffset + q; + + auto xi_q = quadrature_point(q, xi); + + mat_t C{}; + for (uint32_t k = 0; k < test_qshape; k++) { + for (uint32_t m = 0; m < trial_qshape; m++) { + C(k, m) = qdata(qid, i, k, j, m); + } + } + + test_qtype phi_I; + + if constexpr (is_scalar_valued(test_family) && test_op == DerivedQuantity::VALUE) { + phi_I = test_el.shape_function(xi_q, I); + } + + if constexpr (is_scalar_valued(test_family) && test_op == DerivedQuantity::DERIVATIVE) { + phi_I = test_el.shape_function_gradient(xi_q, I); + } + + if constexpr (test_family == Family::Hcurl && test_op == DerivedQuantity::VALUE) { + phi_I = test_el.reoriented_shape_function(xi_q, I, transformation[I]); + } + + if constexpr (test_family == Family::Hcurl && test_op == DerivedQuantity::DERIVATIVE) { + phi_I = test_el.reoriented_shape_function_curl(xi_q, I, transformation[I]); + } + + if (need_to_compute_dX_dxi) { + phi_I = fm::dot(phi_I, testA_q[q]); + } + + hat_f[q] = fm::dot(phi_I, C); + + if (need_to_compute_dX_dxi) { + hat_f[q] = fm::dot(trialA_q[q], hat_f[q]); + } + + } + + nd::array r_e({trial_el.num_nodes()}); + + if constexpr (trial_op == DerivedQuantity::VALUE) { + trial_el.integrate_source(r_e, hat_f, psi_wt, trial_scratch.data()); + } + + if constexpr (trial_op == DerivedQuantity::DERIVATIVE) { + trial_el.integrate_flux(r_e, hat_f, psi_wt, trial_scratch.data()); + } + + if constexpr (is_vector_valued(trial_family)) { + trial_el.reorient(TransformationType::TransposePhysicalToParent, &connectivity(elements(e), 0), r_e.data()); + } + + int row_start = row_ptr[row_id]; + int row_end = row_ptr[row_id+1]; + int which = row_id % nmutex; + mutexes[which].lock(); + for (uint32_t J = 0; J < trial_nodes_per_element; J++) { + int col_id = trial_ids[J] * trial_components + j; + + // find the position of the nonzero entry of this row with the right column + int position = std::lower_bound(&col_ind[row_start], &col_ind[row_end], col_id) - &col_ind[0]; + + values[position] += r_e(J); + } + mutexes[which].unlock(); + } + } + } + + } + + }); + +} + +template +std::function< void(refactor::sparse_matrix&) > integrate_sparse_matrix(BasisFunction test, const nd::array & qdata, BasisFunction trial, const Domain &domain, const DomainType type) { + + return [&, type, test, trial](refactor::sparse_matrix & A) { + MTR_SCOPE("integrate_spmat", "dphi_dpsi"); + + auto phi = test.space; + auto psi = trial.space; + + uint32_t test_components = phi.components; + uint32_t trial_components = psi.components; + uint32_t sdim = domain.mesh.spatial_dimension; + uint32_t gdim = domain.mesh.geometry_dimension; + + stack::array shape5D = { + qdata.shape[0], + phi.components, qshape(phi.family, test_op, gdim), + psi.components, qshape(psi.family, trial_op, gdim) + }; + + refactor_ASSERT(compatible_shapes(qdata.shape, shape5D), "incompatible array shapes"); + + nd::view q5D{qdata.data(), shape5D}; + + GeometryInfo counts = domain.mesh.geometry_counts(); + GeometryInfo test_offsets = scan(interior_nodes_per_geom(phi) * counts); + GeometryInfo trial_offsets = scan(interior_nodes_per_geom(psi) * counts); + auto nrows = total(interior_dofs_per_geom(phi) * counts); + auto ncols = total(interior_dofs_per_geom(psi) * counts); + + if (A.nnz == 0) { + A = blank_sparse_matrix(test, trial, domain); + } else { + zero(A.values); + } + + uint32_t qoffset = 0; + foreach_geometry([&](auto geom){ + nd::view elements = domain.active_elements[geom]; + if (gdim == dimension(geom) && elements.size() > 0) { + nd::view connectivity = domain.mesh[geom]; + nd::view xi = domain.rule[geom].points; + nd::view weights = domain.rule[geom].weights; + + if constexpr (geom != mfem::Geometry::POINT) { + stack::array< uint32_t, 5 > qdata_shape{domain.num_qpts[geom], shape5D[1], shape5D[2], shape5D[3], shape5D[4]}; + nd::view geom_qdata{&q5D(qoffset, 0, 0, 0, 0), qdata_shape}; + + foreach_constexpr< Family::H1, Family::Hcurl >([&](auto test_family) { + foreach_constexpr< Family::H1, Family::Hcurl >([&](auto trial_family) { + if (test_family == phi.family && trial_family == psi.family) { + batched_integrate_spmat( + A.values, A.row_ptr, A.col_ind, + geom_qdata, psi, phi, + trial_offsets, test_offsets, domain.mesh.X, type, + connectivity, elements, + xi, weights + ); + } + }); + }); + + qoffset += domain.num_qpts[geom]; + } + } + }); + + return A; + + }; +} + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +template std::function< void(refactor::sparse_matrix&) > integrate_sparse_matrix(BasisFunction, const nd::array &, BasisFunction, const Domain &, const DomainType); +template std::function< void(refactor::sparse_matrix&) > integrate_sparse_matrix(BasisFunction, const nd::array &, BasisFunction, const Domain &, const DomainType); +template std::function< void(refactor::sparse_matrix&) > integrate_sparse_matrix(BasisFunction, const nd::array &, BasisFunction, const Domain &, const DomainType); +template std::function< void(refactor::sparse_matrix&) > integrate_sparse_matrix(BasisFunction, const nd::array &, BasisFunction, const Domain &, const DomainType); + +template std::function< void(refactor::sparse_matrix&) > integrate_sparse_matrix(BasisFunction, const nd::array &, BasisFunction, const Domain &, const DomainType); +template std::function< void(refactor::sparse_matrix&) > integrate_sparse_matrix(BasisFunction, const nd::array &, BasisFunction, const Domain &, const DomainType); +template std::function< void(refactor::sparse_matrix&) > integrate_sparse_matrix(BasisFunction, const nd::array &, BasisFunction, const Domain &, const DomainType); +template std::function< void(refactor::sparse_matrix&) > integrate_sparse_matrix(BasisFunction, const nd::array &, BasisFunction, const Domain &, const DomainType); + +template std::function< void(refactor::sparse_matrix&) > integrate_sparse_matrix(BasisFunction, const nd::array &, BasisFunction, const Domain &, const DomainType); +template std::function< void(refactor::sparse_matrix&) > integrate_sparse_matrix(BasisFunction, const nd::array &, BasisFunction, const Domain &, const DomainType); +template std::function< void(refactor::sparse_matrix&) > integrate_sparse_matrix(BasisFunction, const nd::array &, BasisFunction, const Domain &, const DomainType); +template std::function< void(refactor::sparse_matrix&) > integrate_sparse_matrix(BasisFunction, const nd::array &, BasisFunction, const Domain &, const DomainType); + +template std::function< void(refactor::sparse_matrix&) > integrate_sparse_matrix(BasisFunction, const nd::array &, BasisFunction, const Domain &, const DomainType); +template std::function< void(refactor::sparse_matrix&) > integrate_sparse_matrix(BasisFunction, const nd::array &, BasisFunction, const Domain &, const DomainType); +template std::function< void(refactor::sparse_matrix&) > integrate_sparse_matrix(BasisFunction, const nd::array &, BasisFunction, const Domain &, const DomainType); +template std::function< void(refactor::sparse_matrix&) > integrate_sparse_matrix(BasisFunction, const nd::array &, BasisFunction, const Domain &, const DomainType); + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +} // namespace impl + +} // namespace refactor diff --git a/src/serac/numerics/refactor/tests/CMakeLists.txt b/src/serac/numerics/refactor/tests/CMakeLists.txt new file mode 100644 index 0000000000..e74300d53f --- /dev/null +++ b/src/serac/numerics/refactor/tests/CMakeLists.txt @@ -0,0 +1,22 @@ +# Copyright (c) 2019-2024, Lawrence Livermore National Security, LLC and +# other Serac Project Developers. See the top-level LICENSE file for +# details. +# +# SPDX-License-Identifier: (BSD-3-Clause) + +set(refactor_test_dependencies serac_refactor serac_boundary_conditions gtest) + +set(refactor_serial_test_sources + h1_evaluation_tests.cpp + hcurl_evaluation_tests.cpp + + integrate_residual_H1_flux_tests.cpp + integrate_residual_H1_source_tests.cpp + integrate_residual_H1v_flux_tests.cpp + integrate_residual_Hcurl_flux_tests.cpp + integrate_residual_Hcurl_source_tests.cpp +) + +serac_add_tests( SOURCES ${refactor_serial_test_sources} + DEPENDS_ON ${refactor_test_dependencies} + NUM_MPI_TASKS 1) diff --git a/src/serac/numerics/refactor/tests/h1_evaluation_tests.cpp b/src/serac/numerics/refactor/tests/h1_evaluation_tests.cpp index 4cf296e619..439e854fe0 100644 --- a/src/serac/numerics/refactor/tests/h1_evaluation_tests.cpp +++ b/src/serac/numerics/refactor/tests/h1_evaluation_tests.cpp @@ -3,17 +3,7 @@ #include #include -#include "refactor/mesh.hpp" -#include "refactor/field.hpp" -#include "refactor/piola_transformations.hpp" - -#include "refactor/domain.hpp" - -#include "misc/for_constexpr.hpp" -#include "forall.hpp" - -#include "fm/types/vec.hpp" -#include "fm/types/matrix.hpp" +#include "serac/numerics/refactor/evaluate.hpp" using namespace refactor; From 27c98019ca032191ad8f427abb3818d081d5059d Mon Sep 17 00:00:00 2001 From: Sam Mish Date: Fri, 13 Dec 2024 15:52:03 -0800 Subject: [PATCH 05/15] connecting up more abstractions to serac/mfem equivalents --- .../functional/detail/metaprogramming.hpp | 9 - src/serac/numerics/functional/tensor.hpp | 2 + .../numerics/refactor/containers/ndarray.hpp | 4 +- .../numerics/refactor/elements/h1_edge.hpp | 16 +- .../refactor/elements/h1_hexahedron.hpp | 3 +- .../refactor/elements/h1_quadrilateral.hpp | 5 +- .../refactor/elements/h1_tetrahedron.hpp | 2 +- .../refactor/elements/h1_triangle.hpp | 2 +- .../numerics/refactor/elements/h1_vertex.hpp | 2 - .../numerics/refactor/elements/hcurl_edge.hpp | 2 +- .../refactor/elements/hcurl_vertex.hpp | 2 +- .../refactor/elements/tensor_contractions.hpp | 174 +++++ .../numerics/refactor/finite_element.hpp | 17 +- src/serac/numerics/refactor/geometry.hpp | 30 +- src/serac/numerics/refactor/interpolation.cpp | 599 ++++++++++++++++++ src/serac/numerics/refactor/interpolation.hpp | 180 ++++++ src/serac/numerics/refactor/quadrature.cpp | 368 +++++++++++ src/serac/numerics/refactor/quadrature.hpp | 56 ++ 18 files changed, 1419 insertions(+), 54 deletions(-) create mode 100644 src/serac/numerics/refactor/elements/tensor_contractions.hpp create mode 100644 src/serac/numerics/refactor/interpolation.cpp create mode 100644 src/serac/numerics/refactor/interpolation.hpp create mode 100644 src/serac/numerics/refactor/quadrature.cpp create mode 100644 src/serac/numerics/refactor/quadrature.hpp diff --git a/src/serac/numerics/functional/detail/metaprogramming.hpp b/src/serac/numerics/functional/detail/metaprogramming.hpp index 45a32230aa..66b7d4be30 100644 --- a/src/serac/numerics/functional/detail/metaprogramming.hpp +++ b/src/serac/numerics/functional/detail/metaprogramming.hpp @@ -98,12 +98,3 @@ SERAC_HOST_DEVICE constexpr void for_constexpr(const lambda& f) { detail::for_constexpr(f, std::make_integer_sequence{}...); } - - -namespace impl { -} - -template < auto ... args, typename T > -void foreach_constexpr(T && function) { - (function(impl::value{}), ...); -} diff --git a/src/serac/numerics/functional/tensor.hpp b/src/serac/numerics/functional/tensor.hpp index e215e486ed..356138592e 100644 --- a/src/serac/numerics/functional/tensor.hpp +++ b/src/serac/numerics/functional/tensor.hpp @@ -111,9 +111,11 @@ tensor(const T (&data)[n1]) -> tensor; template tensor(const T (&data)[n1][n2]) -> tensor; +using vec1 = tensor; ///< statically sized "vector" of 1 double using vec2 = tensor; ///< statically sized vector of 2 doubles using vec3 = tensor; ///< statically sized vector of 3 doubles +using mat1 = tensor; ///< statically sized 1x1 "matrix" of doubles using mat2 = tensor; ///< statically sized 2x2 matrix of doubles using mat3 = tensor; ///< statically sized 3x3 matrix of doubles diff --git a/src/serac/numerics/refactor/containers/ndarray.hpp b/src/serac/numerics/refactor/containers/ndarray.hpp index 90afecf36b..6b43781afd 100644 --- a/src/serac/numerics/refactor/containers/ndarray.hpp +++ b/src/serac/numerics/refactor/containers/ndarray.hpp @@ -290,7 +290,7 @@ namespace nd { static_assert(num_args <= dim); constexpr uint32_t rank = (is_range(index_types{}) + ... ) + (dim - num_args); if constexpr (rank == 0) { - return static_cast(values[index(iseq, indices...)]); + return static_cast(values[index(iseq, indices...)]); } else { constexpr uint32_t is_a_range[] = {is_range(index_types{}) ... }; stack::array slice_shape{}; @@ -574,5 +574,3 @@ std::ostream& operator<<(std::ostream & out, const nd::array< T, dim > & arr) { print(out, nd::view(arr)); return out; } - -#undef SERAC_HOST_DEVICE diff --git a/src/serac/numerics/refactor/elements/h1_edge.hpp b/src/serac/numerics/refactor/elements/h1_edge.hpp index 0f0f519ff0..13bb3a336a 100644 --- a/src/serac/numerics/refactor/elements/h1_edge.hpp +++ b/src/serac/numerics/refactor/elements/h1_edge.hpp @@ -1,11 +1,11 @@ #pragma once -#include "fm/macros.hpp" -#include "refactor/interpolation.hpp" +#include "serac/numerics/functional/tensor.hpp" +#include "serac/numerics/refactor/interpolation.hpp" namespace refactor { -using namespace fm; +using namespace serac; template <> struct FiniteElement < mfem::Geometry::SEGMENT, Family::H1 >{ @@ -18,7 +18,7 @@ struct FiniteElement < mfem::Geometry::SEGMENT, Family::H1 >{ SERAC_HOST_DEVICE constexpr uint32_t num_nodes() const { return p + 1; } - constexpr double shape_function(vec<1> xi, uint32_t i) const { + constexpr double shape_function(vec1 xi, uint32_t i) const { if (p == 1 && i == 0) { return 1.0 - xi[0]; } if (p == 1 && i == 1) { return xi[0]; } @@ -35,12 +35,12 @@ struct FiniteElement < mfem::Geometry::SEGMENT, Family::H1 >{ return 7777.77; } - constexpr vec<1> shape_function_gradient(vec<1> xi, uint32_t i) const { + constexpr vec1 shape_function_gradient(vec1 xi, uint32_t i) const { if (p == 1 && i == 0) { return -1.0; } if (p == 1 && i == 1) { return +1.0; } if (p == 2 && i == 0) return -3.0 + 4.0 * xi[0]; - if (p == 2 && i == 1) return 4.0 - 8.0 * xi[0]; + if (p == 2 && i == 1) return 4.0 - 8.0 * xi[0]; if (p == 2 && i == 2) return -1.0 + 4.0 * xi[0]; constexpr double sqrt5 = 2.23606797749978981; @@ -52,7 +52,7 @@ struct FiniteElement < mfem::Geometry::SEGMENT, Family::H1 >{ return 7777.77; } - vec<1> shape_function_derivative(vec<1> xi, uint32_t i) const { + vec1 shape_function_derivative(vec1 xi, uint32_t i) const { return shape_function_gradient(xi, i); } @@ -63,7 +63,7 @@ struct FiniteElement < mfem::Geometry::SEGMENT, Family::H1 >{ nd::array< double, 2 > evaluate_shape_functions(nd::view xi) const { uint32_t q = xi.shape[0]; nd::array shape_fns({q, p+1}); - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { GaussLobattoInterpolation(xi(i, 0), p + 1, &shape_fns(i, 0)); } return shape_fns; diff --git a/src/serac/numerics/refactor/elements/h1_hexahedron.hpp b/src/serac/numerics/refactor/elements/h1_hexahedron.hpp index 69a5ad9512..dde4f5c388 100644 --- a/src/serac/numerics/refactor/elements/h1_hexahedron.hpp +++ b/src/serac/numerics/refactor/elements/h1_hexahedron.hpp @@ -1,6 +1,7 @@ #pragma once -#include "refactor/connection.hpp" +#include "serac/numerics/functional/tensor.hpp" +#include "serac/numerics/refactor/interpolation.hpp" namespace refactor { diff --git a/src/serac/numerics/refactor/elements/h1_quadrilateral.hpp b/src/serac/numerics/refactor/elements/h1_quadrilateral.hpp index 9d4136c7cc..4ef71e7ca1 100644 --- a/src/serac/numerics/refactor/elements/h1_quadrilateral.hpp +++ b/src/serac/numerics/refactor/elements/h1_quadrilateral.hpp @@ -1,12 +1,11 @@ #pragma once -#include "refactor/connection.hpp" -#include "refactor/tensor_contractions.hpp" +#include "serac/numerics/refactor/elements/tensor_contractions.hpp" namespace refactor { template <> -struct FiniteElement { +struct FiniteElement { using source_type = vec1; using flux_type = vec2; diff --git a/src/serac/numerics/refactor/elements/h1_tetrahedron.hpp b/src/serac/numerics/refactor/elements/h1_tetrahedron.hpp index 7656ef6f9c..a96cc3602c 100644 --- a/src/serac/numerics/refactor/elements/h1_tetrahedron.hpp +++ b/src/serac/numerics/refactor/elements/h1_tetrahedron.hpp @@ -1,6 +1,6 @@ #pragma once -#include "refactor/connection.hpp" + namespace refactor { diff --git a/src/serac/numerics/refactor/elements/h1_triangle.hpp b/src/serac/numerics/refactor/elements/h1_triangle.hpp index 1eb767eb39..63b6697e85 100644 --- a/src/serac/numerics/refactor/elements/h1_triangle.hpp +++ b/src/serac/numerics/refactor/elements/h1_triangle.hpp @@ -1,6 +1,6 @@ #pragma once -#include "refactor/connection.hpp" + namespace refactor { diff --git a/src/serac/numerics/refactor/elements/h1_vertex.hpp b/src/serac/numerics/refactor/elements/h1_vertex.hpp index cdb4bc977b..83bd0478d0 100644 --- a/src/serac/numerics/refactor/elements/h1_vertex.hpp +++ b/src/serac/numerics/refactor/elements/h1_vertex.hpp @@ -1,7 +1,5 @@ #pragma once -#include "refactor/connection.hpp" - namespace refactor { template <> diff --git a/src/serac/numerics/refactor/elements/hcurl_edge.hpp b/src/serac/numerics/refactor/elements/hcurl_edge.hpp index 51763db5a0..f351088a19 100644 --- a/src/serac/numerics/refactor/elements/hcurl_edge.hpp +++ b/src/serac/numerics/refactor/elements/hcurl_edge.hpp @@ -1,6 +1,6 @@ #pragma once -#include "refactor/interpolation.hpp" + namespace refactor { diff --git a/src/serac/numerics/refactor/elements/hcurl_vertex.hpp b/src/serac/numerics/refactor/elements/hcurl_vertex.hpp index a99c538cdc..c41524767f 100644 --- a/src/serac/numerics/refactor/elements/hcurl_vertex.hpp +++ b/src/serac/numerics/refactor/elements/hcurl_vertex.hpp @@ -1,6 +1,6 @@ #pragma once -#include "refactor/interpolation.hpp" + namespace refactor { diff --git a/src/serac/numerics/refactor/elements/tensor_contractions.hpp b/src/serac/numerics/refactor/elements/tensor_contractions.hpp new file mode 100644 index 0000000000..378d2d95e4 --- /dev/null +++ b/src/serac/numerics/refactor/elements/tensor_contractions.hpp @@ -0,0 +1,174 @@ +#pragma once + +#include +#include "serac/numerics/refactor/containers/ndarray.hpp" + +inline void contract(const nd::view & A, nd::view & B, nd::view C, bool accumulate = false) { + // A1(qx, iz, iy) = B(qx, ix) * in(iz, iy, ix) + // A2(qy, qx, iz) = B(qy, iy) * A1(qx, iz, iy) + // out(qz, qy, qx) = B(qz, iz) * A2(qy, qx, iz) + uint32_t n0 = C.shape[0]; + uint32_t n1 = C.shape[1]; + uint32_t n2 = C.shape[2]; + uint32_t m = A.shape[2]; + for (uint32_t i0 = 0; i0 < n0; i0++) { + for (uint32_t i1 = 0; i1 < n1; i1++) { + for (uint32_t i2 = 0; i2 < n2; i2++) { + double sum = (accumulate) ? C(i0, i1, i2) : 0.0; + for (int j = 0; j < m; j++) { + sum += B(i0, j) * A(i1, i2, j); + } + C(i0, i1, i2) = sum; + } + } + } +} + +/// C(qx, iy) {=,+=} sum_{ix} A(qx, ix) * B(iy, ix) +inline void _contract(nd::view C, const nd::view & A, const nd::view & B, bool accumulate = false) { + uint32_t n0 = C.shape[0]; + uint32_t n1 = C.shape[1]; + uint32_t m = A.shape[1]; + assert(A.shape[0] == C.shape[0]); + assert(B.shape[0] == C.shape[1]); + assert(A.shape[1] == B.shape[1]); + for (uint32_t i0 = 0; i0 < n0; i0++) { + for (uint32_t i1 = 0; i1 < n1; i1++) { + double sum = (accumulate) ? C(i0, i1) : 0.0; + for (int j = 0; j < m; j++) { + sum += A(i0, j) * B(i1, j); + } + C(i0, i1) = sum; + } + } +} + +template < int i > +void contract(const nd::view & A, nd::view & B, nd::view C, bool accumulate = false) { + uint32_t n0 = C.shape[0]; + uint32_t n1 = C.shape[1]; + uint32_t m = A.shape[i]; + assert(C.shape[1] == B.shape[0]); + assert(A.shape[i] == B.shape[1]); + assert(A.shape[1-i] == C.shape[0]); + for (uint32_t i0 = 0; i0 < n0; i0++) { + for (uint32_t i1 = 0; i1 < n1; i1++) { + double sum = (accumulate) ? C(i0, i1) : 0.0; + for (int j = 0; j < m; j++) { + if constexpr (i == 0) { sum += A(j, i0) * B(i1, j); } + if constexpr (i == 1) { sum += A(i0, j) * B(i1, j); } + } + C(i0, i1) = sum; + } + } +} + +inline void contract(const nd::view & A, nd::view & B, const nd::view C, bool accumulate = false) { + uint32_t n = C.shape[0]; + uint32_t m = A.shape[0]; + for (uint32_t i = 0; i < n; i++) { + double sum = (accumulate) ? C(i) : 0.0; + for (int j = 0; j < m; j++) { + sum += A(j) * B(i, j); + } + C(i) = sum; + } +} + +#ifdef __CUDACC__ +struct threadid { + int x; + int y; + int z; + int stride; +}; + +__device__ __forceinline__ void cuda_contract(threadid tid, const nd::view & A, const nd::view & B, nd::view & C, bool accumulate = false) { + uint32_t n0 = C.shape[0]; + uint32_t n1 = C.shape[1]; + uint32_t n2 = C.shape[2]; + uint32_t m = A.shape[2]; + + for (uint32_t i0 = tid.z; i0 < n0; i0 += tid.stride) { + for (uint32_t i1 = tid.y; i1 < n1; i1 += tid.stride) { + for (uint32_t i2 = tid.x; i2 < n2; i2 += tid.stride) { + double sum = (accumulate) ? C(i0, i1, i2) : 0.0; + for (int j = 0; j < m; j++) { + sum += B(i0, j) * A(i1, i2, j); + } + C(i0, i1, i2) = sum; + } + } + } + __syncthreads(); +} + +template < int i > +__device__ __forceinline__ void cuda_contract(threadid tid, const nd::view & A, const nd::view & B, nd::view C, bool accumulate = false) { + uint32_t n0 = C.shape[0]; + uint32_t n1 = C.shape[1]; + uint32_t m = A.shape[i]; + for (uint32_t i0 = tid.y; i0 < n0; i0 += tid.stride) { + for (uint32_t i1 = tid.x; i1 < n1; i1 += tid.stride) { + double sum = (accumulate) ? C(i0, i1) : 0.0; + for (int j = 0; j < m; j++) { + if constexpr (i == 0) { sum += A(j, i0) * B(i1, j); } + if constexpr (i == 1) { sum += A(i0, j) * B(i1, j); } + } + C(i0, i1) = sum; + } + } + __syncthreads(); +} + +///// C(qx, iy) {=,+=} sum_{ix} A(qx, ix) * B(iy, ix) +//inline void _contract(nd::view C, const nd::view & A, const nd::view & B, bool accumulate = false) { +// uint32_t n0 = C.shape[0]; +// uint32_t n1 = C.shape[1]; +// uint32_t m = A.shape[1]; +// assert(A.shape[0] == C.shape[0]); +// assert(B.shape[0] == C.shape[1]); +// assert(A.shape[1] == B.shape[1]); +// for (uint32_t i0 = 0; i0 < n0; i0++) { +// for (uint32_t i1 = 0; i1 < n1; i1++) { +// double sum = (accumulate) ? C(i0, i1) : 0.0; +// for (int j = 0; j < m; j++) { +// sum += A(i0, j) * B(i1, j); +// } +// C(i0, i1) = sum; +// } +// } +//} +// +//template < int i > +//void contract(const nd::view & A, nd::view & B, nd::view C, bool accumulate = false) { +// uint32_t n0 = C.shape[0]; +// uint32_t n1 = C.shape[1]; +// uint32_t m = A.shape[i]; +// assert(C.shape[1] == B.shape[0]); +// assert(A.shape[i] == B.shape[1]); +// assert(A.shape[1-i] == C.shape[0]); +// for (uint32_t i0 = 0; i0 < n0; i0++) { +// for (uint32_t i1 = 0; i1 < n1; i1++) { +// double sum = (accumulate) ? C(i0, i1) : 0.0; +// for (int j = 0; j < m; j++) { +// if constexpr (i == 0) { sum += A(j, i0) * B(i1, j); } +// if constexpr (i == 1) { sum += A(i0, j) * B(i1, j); } +// } +// C(i0, i1) = sum; +// } +// } +//} +// +//inline void contract(const nd::view & A, nd::view & B, const nd::view C, bool accumulate = false) { +// uint32_t n = C.shape[0]; +// uint32_t m = A.shape[0]; +// for (uint32_t i = 0; i < n; i++) { +// double sum = (accumulate) ? C(i) : 0.0; +// for (int j = 0; j < m; j++) { +// sum += A(j) * B(i, j); +// } +// C(i) = sum; +// } +//} +#endif diff --git a/src/serac/numerics/refactor/finite_element.hpp b/src/serac/numerics/refactor/finite_element.hpp index 35ac355ee8..37cb1adb0c 100644 --- a/src/serac/numerics/refactor/finite_element.hpp +++ b/src/serac/numerics/refactor/finite_element.hpp @@ -1,10 +1,15 @@ #pragma once +#include "serac/numerics/functional/tensor.hpp" #include "serac/numerics/refactor/geometry.hpp" #include "serac/numerics/refactor/quadrature.hpp" +#include "serac/physics/state/finite_element_state.hpp" + namespace refactor { +using Field = serac::FiniteElementState; + enum class Family { H1, Hcurl, @@ -84,8 +89,8 @@ auto weighted_shape_function_derivatives(FiniteElement< geom, family > element, } } -SERAC_HOST_DEVICE constexpr fm::mat2 face_transformation(int8_t id) { - constexpr fm::mat2 matrices[5] = { +SERAC_HOST_DEVICE constexpr serac::mat2 face_transformation(int8_t id) { + constexpr serac::mat2 matrices[5] = { {{{0, 1}, {1, 0}}}, {{{-1, 0}, {-1, 1}}}, {{{1, -1}, {0, -1}}}, @@ -96,6 +101,7 @@ SERAC_HOST_DEVICE constexpr fm::mat2 face_transformation(int8_t id) { return matrices[id-1]; } +// sam: these orientations are for femto's face orientation convention SERAC_HOST_DEVICE constexpr int8_t face_transformation_id(TransformationType type, int orientation) { if (type == TransformationType::PhysicalToParent) { constexpr int8_t LUT[3] = {1, 2, 3}; @@ -121,10 +127,3 @@ SERAC_HOST_DEVICE constexpr int8_t face_transformation_id(TransformationType typ #include "serac/numerics/refactor/elements/hcurl_quadrilateral.hpp" #include "serac/numerics/refactor/elements/hcurl_tetrahedron.hpp" #include "serac/numerics/refactor/elements/hcurl_hexahedron.hpp" - -#include "serac/numerics/refactor/elements/dg_vertex.hpp" -#include "serac/numerics/refactor/elements/dg_edge.hpp" -#include "serac/numerics/refactor/elements/dg_triangle.hpp" -#include "serac/numerics/refactor/elements/dg_quadrilateral.hpp" -#include "serac/numerics/refactor/elements/dg_tetrahedron.hpp" -#include "serac/numerics/refactor/elements/dg_hexahedron.hpp" diff --git a/src/serac/numerics/refactor/geometry.hpp b/src/serac/numerics/refactor/geometry.hpp index f81fee8f98..472125c62d 100644 --- a/src/serac/numerics/refactor/geometry.hpp +++ b/src/serac/numerics/refactor/geometry.hpp @@ -79,26 +79,26 @@ struct GeometryData { T & operator[](mfem::Geometry::Type g) { switch (g) { - case mfem::Geometry::POINT: return vert; - case mfem::Geometry::SEGMENT: return edge; - case mfem::Geometry::TRIANGLE: return tri; - case mfem::Geometry::SQUARE: return quad; - case mfem::Geometry::TETRAHEDRON: return tet; - case mfem::Geometry::CUBE: return hex; + case mfem::Geometry::POINT: return vert; + case mfem::Geometry::SEGMENT: return edge; + case mfem::Geometry::TRIANGLE: return tri; + case mfem::Geometry::SQUARE: return quad; + case mfem::Geometry::TETRAHEDRON: return tet; + case mfem::Geometry::CUBE: return hex; + default: return vert; // (hopefully) unreachable code, to silence compiler warnings } - return vert; // unreachable code, to silence compiler warnings } const T & operator[](mfem::Geometry::Type g) const { switch (g) { - case mfem::Geometry::POINT: return vert; - case mfem::Geometry::SEGMENT: return edge; - case mfem::Geometry::TRIANGLE: return tri; - case mfem::Geometry::SQUARE: return quad; - case mfem::Geometry::TETRAHEDRON: return tet; - case mfem::Geometry::CUBE: return hex; + case mfem::Geometry::POINT: return vert; + case mfem::Geometry::SEGMENT: return edge; + case mfem::Geometry::TRIANGLE: return tri; + case mfem::Geometry::SQUARE: return quad; + case mfem::Geometry::TETRAHEDRON: return tet; + case mfem::Geometry::CUBE: return hex; + default: return vert; // (hopefully) unreachable code, to silence compiler warnings } - return vert; // unreachable code, to silence compiler warnings } }; @@ -203,7 +203,7 @@ struct GeometryType< mfem::Geometry::TRIANGLE > { static constexpr int local_edge_ids[3][2] = {{0, 1},{1, 2},{2, 0}}; - SERAC_HOST_DEVICE static constexpr uint32_t number(int n) { return (n * (n + 1)) / 2; }; + SERAC_HOST_DEVICE static constexpr uint32_t number(int n) { return static_cast< uint32_t >((n * (n + 1)) / 2); }; }; using Triangle = GeometryType< mfem::Geometry::TRIANGLE >; diff --git a/src/serac/numerics/refactor/interpolation.cpp b/src/serac/numerics/refactor/interpolation.cpp new file mode 100644 index 0000000000..83d88141a3 --- /dev/null +++ b/src/serac/numerics/refactor/interpolation.cpp @@ -0,0 +1,599 @@ +#include + +namespace femto { + +void GaussLegendreNodes(int n, double * output) { + + // clang-format off + switch (n) { + case 1: + output[0] = 0.5; + break; + case 2: + output[0] = 0.2113248654051871; + output[1] = 0.7886751345948129; + break; + case 3: + output[0] = 0.1127016653792583; + output[1] = 0.500000000000000; + output[2] = 0.887298334620742; + break; + case 4: + output[0] = 0.0694318442029737; + output[1] = 0.330009478207572 ; + output[2] = 0.669990521792428 ; + output[3] = 0.930568155797026 ; + break; + case 5: + output[0] = 0.04691007703066800; + output[1] = 0.2307653449471585 ; + output[2] = 0.5000000000000000 ; + output[3] = 0.7692346550528415 ; + output[4] = 0.9530899229693320 ; + break; + case 6: + output[0] = 0.03376524289842399; + output[1] = 0.1693953067668677 ; + output[2] = 0.3806904069584015 ; + output[3] = 0.6193095930415985 ; + output[4] = 0.8306046932331323 ; + output[5] = 0.9662347571015760 ; + break; + } + // clang-format on + +} + +void GaussLegendreInterpolation(double x, int n, double * output) { + + if (n == 1) { + output[0] = 1; + } + + if (n == 2) { + output[0] = 1.3660254037844386467637231708 - 1.732050807568877293527446342*x; + output[1] = -0.3660254037844386467637231708 + 1.7320508075688772935274463415*x; + } + + if (n == 3) { + output[0] = 1.4788305577012361475298776 + x*(-4.624327782069138961726422 + 3.3333333333333333333333333*x); + output[1] = -0.666666666666666666666666667 + (6.66666666666666666666666667 - 6.666666666666666666666666667*x)*x; + output[2] = 0.1878361089654305191367891 + x*(-2.0423388845975277049402449 + 3.3333333333333333333333333*x); + } + + if (n == 4) { + output[0] = 1.526788125457266786984328 + x*(-8.54602360787219876597302 + (14.32585835417188815296662 - 7.42054006803894610520064*x)*x); + output[1] = -0.8136324494869272605619 + x*(13.8071669256895770661587 + x*(-31.3882223634460602120582 + 18.7954494075550608112617*x)); + output[2] = 0.400761520311650404800281777 + x*(-7.41707042146263907582738061 + (24.9981258592191222217269164 - 18.79544940755506081126171563*x)*x); + output[3] = -0.11391719628198993122271197 + x*(2.1559271036452607756417044 + x*(-7.935761849944950162635307 + 7.420540068038946105200642*x)); + } + + if (n == 5) { + output[0] = 1.551408049094313012813028 + x*(-13.47028450119487106120462 + x*(38.6444990553441957009803 + x*(-44.9889850558789977671881 + 18.33972111443117301508323*x))); + output[1] = -0.8931583920000717373262 + x*(22.924333555723729737768 + x*(-88.22281082816288605026 + (117.8634151266470135556 - 51.939721114431173015083*x)*x)); + output[2] = 0.5333333333333333333333 + x*(-14.933333333333333333333 + x*(82.13333333333333333333 + x*(-134.4 + 67.2*x))); + output[3] = -0.26794165222338750930410993 + x*(7.6899271783856937562943889 + x*(-46.270892134808883473969833 + (89.895469331077678504736602 - 51.9397211144311730150832251*x)*x)); + output[4] = 0.07635866179581290048392539 + x*(-2.210642899581219099524808 + x*(13.71587057429424048991553 + x*(-28.36989940184569429314485 + 18.33972111443117301508323*x))); + } + + if (n == 6) { + output[0] = 1.565673200151071933093717 + x*(-19.38889969575614186464859 + x*(83.3561716652066047719407 + x*(-161.6334485633571811708389 + (144.8933610434784341266087 - 48.8475703740520537090491*x)*x))); + output[1] = -0.94046284317634892902 + x*(33.94755689005745838881 + x*(-194.5900409203250530156 + x*(431.2442105751191477314 + x*(-416.6718961318097255735 + 147.20243244417318935282*x)))); + output[2] = 0.616930055430488708617 + x*(-24.29050650593736015819 + x*(195.3041651669510511719 + x*(-523.416260790836176187 + (568.4164873451100029584 - 217.0100429728326202484*x)*x))); + output[3] = -0.37922770211461375461734918 + x*(15.315224028266875783526055 + x*(-134.54612286322366212220967 + x*(419.85074113872236683695564 + x*(-516.63372751905309828340431 + 217.010042972832620248366597*x)))); + output[4] = 0.1918000140386679548202 + x*(-7.82468446839184002159 + x*(71.1355384559059302654 + x*(-236.5809504896121389654 + (319.3402660890562211905 - 147.2024324441731893528*x)*x))); + output[5] = -0.05471272432926591289350948 + x*(2.241309751761007872094777 + x*(-20.65971150451487107141517 + x*(70.5357081299639817548955 + x*(-99.344490826781834418637 + 48.84757037405205370904914*x)))); + } + +} + +void GaussLegendreInterpolationDerivative01(double x, int n, double * output) { + + if (n == 1) { + output[0] = 0.0; + } + + if (n == 2) { + output[0] = -1.7320508075688772935274463415; + output[1] = 1.7320508075688772935274463415; + } + + if (n == 3) { + output[0] = -4.6243277820691389617264218 + 6.6666666666666666666666667*x; + output[1] = 6.66666666666666666666666667 - 13.3333333333333333333333333*x; + output[2] = -2.04233888459752770494024487 + 6.6666666666666666666666667*x; + } + + if (n == 4) { + output[0] = -8.546023607872198765973 + (28.6517167083437763059332 - 22.2616202041168383156019*x)*x; + output[1] = 13.80716692568958 + x*(-62.7764447268921 + 56.3863482226652*x); + output[2] = -7.417070421462639075827381 + (49.99625171843824444345383 - 56.38634822266518243378515*x)*x; + output[3] = 2.155927103645260775641704 + x*(-15.87152369988990032527061 + 22.26162020411683831560193*x); + } + + if (n == 5) { + output[0] = -13.4702845011948710612046 + x*(77.288998110688391401961 + x*(-134.966955167636993301564 + 73.358884457724692060333*x)); + output[1] = 22.92433355572373 + x*(-176.4456216563258 + (353.590245379941 - 207.7588844577247*x)*x); + output[2] = -14.93333333333333 + x*(164.2666666666667 + x*(-403.2 + 268.8*x)); + output[3] = 7.689927178385693756294389 + x*(-92.54178426961776694793967 + (269.6864079932330355142098 - 207.7588844577246920603329*x)*x); + output[4] = -2.21064289958121909952481 + x*(27.4317411485884809798311 + x*(-85.1096982055370828794345 + 73.3588844577246920603329*x)); + } + + if (n == 6) { + output[0] = -19.3888996957561418646486 + x*(166.712343330413209543881 + x*(-484.90034569007154351252 + (579.57344417391373650643 - 244.23785187026026854525*x)*x)); + output[1] = 33.94755689005746 + x*(-389.18008184065 + x*(1293.732631725357 + x*(-1666.687584527239 + 736.012162220866*x))); + output[2] = -24.29050650593736 + x*(390.6083303339021 + x*(-1570.248782372509 + (2273.66594938044 - 1085.050214864163*x)*x)); + output[3] = 15.31522402826687578352605 + x*(-269.0922457264473242444193 + x*(1259.552223416167100510867 + x*(-2066.534910076212393133617 + 1085.050214864163101241833*x))); + output[4] = -7.82468446839184 + x*(142.2710769118119 + x*(-709.742851468836 + (1277.361064356225 - 736.012162220866*x)*x)); + output[5] = 2.24130975176100787209478 + x*(-41.3194230090297421428303 + x*(211.607124389891945264686 + x*(-397.377963307127337674548 + 244.237851870260268545246*x))); + } + +} + +void GaussLobattoNodes(int n, double * output) { + if (n == 1) { + output[0] = 0.5; + return; + } + if (n == 2) { + output[0] = 0.0; + output[1] = 1.0; + return; + } + if (n == 3) { + output[0] = 0.0; + output[1] = 0.5; + output[2] = 1.0; + return; + } + if (n == 4) { + output[0] = 0.0; + output[1] = 0.2763932022500210; + output[2] = 0.7236067977499790; + output[3] = 1.0; + return; + } +} + +void GaussLobattoInterpolation(double x, int n, double * output) { + if (n == 1) { + output[0] = 1.0; + return; + } + if (n == 2) { + output[0] = 1.0 - x; + output[1] = x; + return; + } + if (n == 3) { + output[0] = (-1.0 + x) * (-1.0 + 2.0 * x); + output[1] = -4.0 * (-1.0 + x) * x; + output[2] = x * (-1.0 + 2.0 * x); + return; + } + if (n == 4) { + constexpr double sqrt5 = 2.23606797749978981; + output[0] = -(-1.0 + x) * (1.0 + 5.0 * (-1.0 + x) * x); + output[1] = -0.5 * sqrt5 * (5.0 + sqrt5 - 10.0 * x) * (-1.0 + x) * x; + output[2] = -0.5 * sqrt5 * (-1.0 + x) * x * (-5.0 + sqrt5 + 10.0 * x); + output[3] = x * (1.0 + 5.0 * (-1.0 + x) * x); + return; + } + + std::cout << "error: invalid polynomial order in GaussLobattoInterpolation" << std::endl; +} + +void GaussLobattoInterpolationDerivative(double x, int n, double * output) { + if (n == 1) { + output[0] = 0.0; + return; + } + if (n == 2) { + output[0] = -1.0; + output[1] = 1.0; + return; + } + if (n == 3) { + output[0] = -3.0 + 4.0 * x; + output[1] = 4.0 - 8.0 * x; + output[2] = -1.0 + 4.0 * x; + return; + } + if (n == 4) { + constexpr double sqrt5 = 2.23606797749978981; + output[0] = -6.0 + 5.0 * (4.0 - 3.0 * x) * x; + output[1] = 2.5 * (1.0 + sqrt5 + 2.0 * x * (-1.0 - 3.0 * sqrt5 + 3.0 * sqrt5 * x)); + output[2] = -2.5 * (-1.0 + sqrt5 + 2.0 * x * (1.0 - 3.0 * sqrt5 + 3.0 * sqrt5 * x)); + output[3] = 1.0 + 5.0 * x * (-2.0 + 3.0 * x); + return; + } + + std::cout << "error: invalid polynomial order in GaussLobattoInterpolationDerivative" << std::endl; +} + +#if 1 +constexpr double GaussLobattoInterpolation(double x, uint32_t n, uint32_t i) { + if (n == 1) { return 1.0; } + if (n == 2) { return (i == 0) ? 1.0 - x : x; } + if (n == 3) { + if (i == 0) return (-1.0 + x) * (-1.0 + 2.0 * x); + if (i == 1) return -4.0 * (-1.0 + x) * x; + if (i == 2) return x * (-1.0 + 2.0 * x); + } + if (n == 4) { + constexpr double sqrt5 = 2.23606797749978981; + if (i == 0) return -(-1.0 + x) * (1.0 + 5.0 * (-1.0 + x) * x); + if (i == 1) return -0.5 * sqrt5 * (5.0 + sqrt5 - 10.0 * x) * (-1.0 + x) * x; + if (i == 2) return -0.5 * sqrt5 * (-1.0 + x) * x * (-5.0 + sqrt5 + 10.0 * x); + if (i == 3) return x * (1.0 + 5.0 * (-1.0 + x) * x); + } + return -1.0; +} + +constexpr double GaussLobattoInterpolationDerivative(double x, uint32_t n, uint32_t i) { + if (n == 1) { return 0.0; } + if (n == 2) { return (i == 0) ? -1.0 : 1.0; } + if (n == 3) { + if (i == 0) return -3.0 + 4.0 * x; + if (i == 1) return 4.0 - 8.0 * x; + if (i == 2) return -1.0 + 4.0 * x; + } + if (n == 4) { + constexpr double sqrt5 = 2.23606797749978981; + if (i == 0) return -6.0 + 5.0 * (4.0 - 3.0 * x) * x; + if (i == 1) return 2.5 * (1.0 + sqrt5 + 2.0 * x * (-1.0 - 3.0 * sqrt5 + 3.0 * sqrt5 * x)); + if (i == 2) return -2.5 * (-1.0 + sqrt5 + 2.0 * x * (1.0 - 3.0 * sqrt5 + 3.0 * sqrt5 * x)); + if (i == 3) return 1.0 + 5.0 * x * (-2.0 + 3.0 * x); + } + return -1.0; +} +#endif + +void GaussLobattoInterpolationTriangle(const double * xi, int p, double * output) { + if (p == 0) { + output[0] = 1.0; + return; + } + if (p == 1) { + output[0] = 1.0 - xi[0] - xi[1]; + output[1] = xi[0]; + output[2] = xi[1]; + return; + } + if (p == 2) { + output[0] = (-1+xi[0]+xi[1])*(-1+2*xi[0]+2*xi[1]); + output[1] = -4*xi[0]*(-1+xi[0]+xi[1]); + output[2] = xi[0]*(-1+2*xi[0]); + output[3] = -4*xi[1]*(-1+xi[0]+xi[1]); + output[4] = 4*xi[0]*xi[1]; + output[5] = xi[1]*(-1+2*xi[1]); + return; + } + if (p == 3) { + double sqrt5 = 2.23606797749978981; + output[0] = -((-1+xi[0]+xi[1])*(1+5*xi[0]*xi[0]+5*(-1+xi[1])*xi[1]+xi[0]*(-5+11*xi[1]))); + output[1] = (5*xi[0]*(-1+xi[0]+xi[1])*(-1-sqrt5+2*sqrt5*xi[0]+(3+sqrt5)*xi[1]))/2.0; + output[2] = (-5*xi[0]*(-1+xi[0]+xi[1])*(1-sqrt5+2*sqrt5*xi[0]+(-3+sqrt5)*xi[1]))/2.0; + output[3] = xi[0]*(1+5*xi[0]*xi[0]+xi[1]-xi[1]*xi[1]-xi[0]*(5+xi[1])); + output[4] = (5*xi[1]*(-1+xi[0]+xi[1])*(-1-sqrt5+(3+sqrt5)*xi[0]+2*sqrt5*xi[1]))/2.0; + output[5] = -27*xi[0]*xi[1]*(-1+xi[0]+xi[1]); + output[6] = (5*xi[0]*xi[1]*(-2+(3+sqrt5)*xi[0]-(-3+sqrt5)*xi[1]))/2.; + output[7] = (5*xi[1]*(-1+xi[0]+xi[1])*(5-3*sqrt5+2*(-5+2*sqrt5)*xi[0]+5*(-1+sqrt5)*xi[1]))/(-5+sqrt5); + output[8] = (-5*xi[0]*xi[1]*(2+(-3+sqrt5)*xi[0]-(3+sqrt5)*xi[1]))/2.; + output[9] = xi[1]*(1+xi[0]-xi[0]*xi[0]-xi[0]*xi[1]+5*(-1+xi[1])*xi[1]); + return; + } +} + +void GaussLobattoInterpolationDerivativeTriangle(const double * xi, int p, double * output) { + if (p == 0) { + output[0] = 0.0; + output[1] = 0.0; + return; + } + if (p == 1) { + output[0] = -1; + output[1] = -1; + output[2] = 1; + output[3] = 0; + output[4] = 0; + output[5] = 1; + return; + } + if (p == 2) { + output[ 0] = -3+4*xi[0]+4*xi[1]; + output[ 1] = -3+4*xi[0]+4*xi[1]; + output[ 2] = -4*(-1+2*xi[0]+xi[1]); + output[ 3] = -4*xi[0]; + output[ 4] = -1+4*xi[0]; + output[ 5] = 0; + output[ 6] = -4*xi[1]; + output[ 7] = -4*(-1+xi[0]+2*xi[1]); + output[ 8] = 4*xi[1]; + output[ 9] = 4*xi[0]; + output[10] = 0; + output[11] = -1+4*xi[1]; + return; + } + if (p == 3) { + double sqrt5 = 2.23606797749978981; + output[ 0] = -6-15*xi[0]*xi[0]+4*xi[0]*(5-8*xi[1])+(21-16*xi[1])*xi[1]; + output[ 1] = -6-16*xi[0]*xi[0]+xi[0]*(21-32*xi[1])+5*(4-3*xi[1])*xi[1]; + output[ 2] = (5*(6*sqrt5*xi[0]*xi[0]+xi[0]*(-2-6*sqrt5+6*(1+sqrt5)*xi[1])+(-1+xi[1])*(-1-sqrt5+(3+sqrt5)*xi[1])))/2.; + output[ 3] = (5*xi[0]*(-2*(2+sqrt5)+3*(1+sqrt5)*xi[0]+2*(3+sqrt5)*xi[1]))/2.; + output[ 4] = (-5*(6*sqrt5*xi[0]*xi[0]+(-1+xi[1])*(1-sqrt5+(-3+sqrt5)*xi[1])+xi[0]*(2-6*sqrt5+6*(-1+sqrt5)*xi[1])))/2.; + output[ 5] = (-5*xi[0]*(4-2*sqrt5+3*(-1+sqrt5)*xi[0]+2*(-3+sqrt5)*xi[1]))/2.; + output[ 6] = 1+15*xi[0]*xi[0]+xi[1]-xi[1]*xi[1]-2*xi[0]*(5+xi[1]); + output[ 7] = -(xi[0]*(-1+xi[0]+2*xi[1])); + output[ 8] = (5*xi[1]*(-2*(2+sqrt5)+2*(3+sqrt5)*xi[0]+3*(1+sqrt5)*xi[1]))/2.; + output[ 9] = (5*(1+sqrt5-2*(2+sqrt5)*xi[0]+(3+sqrt5)*xi[0]*xi[0]+6*(1+sqrt5)*xi[0]*xi[1]+2*xi[1]*(-1-3*sqrt5+3*sqrt5*xi[1])))/2.; + output[10] = -27*xi[1]*(-1+2*xi[0]+xi[1]); + output[11] = -27*xi[0]*(-1+xi[0]+2*xi[1]); + output[12] = (-5*xi[1]*(2-2*(3+sqrt5)*xi[0]+(-3+sqrt5)*xi[1]))/2.; + output[13] = (5*xi[0]*(-2+(3+sqrt5)*xi[0]-2*(-3+sqrt5)*xi[1]))/2.; + output[14] = (-5*xi[1]*(4-2*sqrt5+2*(-3+sqrt5)*xi[0]+3*(-1+sqrt5)*xi[1]))/2.; + output[15] = (-5*(-1+sqrt5+(-3+sqrt5)*xi[0]*xi[0]+2*xi[1]*(1-3*sqrt5+3*sqrt5*xi[1])+xi[0]*(4-2*sqrt5+6*(-1+sqrt5)*xi[1])))/2.; + output[16] = (5*xi[1]*(-2-2*(-3+sqrt5)*xi[0]+(3+sqrt5)*xi[1]))/2.; + output[17] = (-5*xi[0]*(2+(-3+sqrt5)*xi[0]-2*(3+sqrt5)*xi[1]))/2.; + output[18] = -(xi[1]*(-1+2*xi[0]+xi[1])); + output[19] = 1+xi[0]-xi[0]*xi[0]-2*(5+xi[0])*xi[1]+15*xi[1]*xi[1]; + return; + } +} + +void GaussLobattoInterpolationQuadrilateral(const double * xi, int n, double * output) { + double * N[2] = {new double[n], new double[n]}; + + GaussLobattoInterpolation(xi[0], n, N[0]); + GaussLobattoInterpolation(xi[1], n, N[1]); + + for (int j = 0; j < n; j++) { + for (int i = 0; i < n; i++) { + output[j * n + i] = N[0][i] * N[0][j]; + } + } + + delete N[0]; + delete N[1]; +} + +void GaussLobattoInterpolationDerivativeQuadrilateral(const double * xi, int n, double * output) { + double * N[2] = {new double[n], new double[n]}; + double * dN[2] = {new double[n], new double[n]}; + + GaussLobattoInterpolation(xi[0], n, N[0]); + GaussLobattoInterpolation(xi[1], n, N[1]); + + GaussLobattoInterpolation(xi[0], n, dN[0]); + GaussLobattoInterpolation(xi[1], n, dN[1]); + + for (int j = 0; j < n; j++) { + for (int i = 0; i < n; i++) { + output[2 * (j * n + i) + 0] = dN[0][i] * N[0][j]; + output[2 * (j * n + i) + 1] = N[0][i] * dN[0][j]; + } + } + + delete N[0]; + delete N[1]; + delete dN[0]; + delete dN[1]; +} + +void GaussLobattoInterpolationTetrahedron(const double * xi, int p, double * output) { + if (p == 0) { + output[0] = 1.0; + return; + } + if (p == 1) { + output[0] = 1-xi[0]-xi[1]-xi[2]; + output[1] = xi[0]; + output[2] = xi[1]; + output[3] = xi[2]; + return; + } + if (p == 2) { + output[0] = (-1+xi[0]+xi[1]+xi[2])*(-1+2*xi[0]+2*xi[1]+2*xi[2]); + output[1] = -4*xi[0]*(-1+xi[0]+xi[1]+xi[2]); + output[2] = xi[0]*(-1+2*xi[0]); + output[3] = -4*xi[1]*(-1+xi[0]+xi[1]+xi[2]); + output[4] = 4*xi[0]*xi[1]; + output[5] = xi[1]*(-1+2*xi[1]); + output[6] = -4*xi[2]*(-1+xi[0]+xi[1]+xi[2]); + output[7] = 4*xi[0]*xi[2]; + output[8] = 4*xi[1]*xi[2]; + output[9] = xi[2]*(-1+2*xi[2]); + return; + } + if (p == 3) { + double sqrt5 = 2.23606797749978981; + output[ 0] = -((-1+xi[0]+xi[1]+xi[2])*(1+5*xi[0]*xi[0]+5*xi[1]*xi[1]+5*(-1+xi[2])*xi[2]+xi[1]*(-5+11*xi[2])+xi[0]*(-5+11*xi[1]+11*xi[2]))); + output[ 1] = (5*xi[0]*(-1+xi[0]+xi[1]+xi[2])*(-1-sqrt5+2*sqrt5*xi[0]+(3+sqrt5)*xi[1]+(3+sqrt5)*xi[2]))/2.; + output[ 2] = (-5*xi[0]*(-1+xi[0]+xi[1]+xi[2])*(1-sqrt5+2*sqrt5*xi[0]+(-3+sqrt5)*xi[1]+(-3+sqrt5)*xi[2]))/2.; + output[ 3] = xi[0]*(1+5*xi[0]*xi[0]+xi[1]-xi[1]*xi[1]+xi[2]-xi[1]*xi[2]-xi[2]*xi[2]-xi[0]*(5+xi[1]+xi[2])); + output[ 4] = (5*xi[1]*(-1+xi[0]+xi[1]+xi[2])*(-1-sqrt5+(3+sqrt5)*xi[0]+2*sqrt5*xi[1]+(3+sqrt5)*xi[2]))/2.; + output[ 5] = -27*xi[0]*xi[1]*(-1+xi[0]+xi[1]+xi[2]); + output[ 6] = (5*xi[0]*xi[1]*(-2+(3+sqrt5)*xi[0]-(-3+sqrt5)*xi[1]))/2.; + output[ 7] = (-5*xi[1]*(-1+xi[0]+xi[1]+xi[2])*(1-sqrt5+(-3+sqrt5)*xi[0]+2*sqrt5*xi[1]+(-3+sqrt5)*xi[2]))/2.; + output[ 8] = (-5*xi[0]*xi[1]*(2+(-3+sqrt5)*xi[0]-(3+sqrt5)*xi[1]))/2.; + output[ 9] = xi[1]*(1-xi[0]*xi[0]+5*xi[1]*xi[1]+xi[2]-xi[2]*xi[2]-xi[1]*(5+xi[2])-xi[0]*(-1+xi[1]+xi[2])); + output[10] = (5*xi[2]*(-1+xi[0]+xi[1]+xi[2])*(-439204-196418*sqrt5+(710647+317811*sqrt5)*xi[0]+(710647+317811*sqrt5)*xi[1]+606965*xi[2]+271443*sqrt5*xi[2]))/(271443+121393*sqrt5); + output[11] = -27*xi[0]*xi[2]*(-1+xi[0]+xi[1]+xi[2]); + output[12] = (5*xi[0]*xi[2]*(-5-3*sqrt5+(15+7*sqrt5)*xi[0]+2*sqrt5*xi[2]))/(5+3*sqrt5); + output[13] = -27*xi[1]*xi[2]*(-1+xi[0]+xi[1]+xi[2]); + output[14] = 27*xi[0]*xi[1]*xi[2]; + output[15] = (5*xi[1]*xi[2]*(-5-3*sqrt5+(15+7*sqrt5)*xi[1]+2*sqrt5*xi[2]))/(5+3*sqrt5); + output[16] = (5*xi[2]*(-1+xi[0]+xi[1]+xi[2])*(88555+39603*sqrt5+(54730+24476*sqrt5)*xi[0]+(54730+24476*sqrt5)*xi[1]-5*(64079+28657*sqrt5)*xi[2]))/(143285+64079*sqrt5); + output[17] = (-5*xi[0]*xi[2]*(2+(-3+sqrt5)*xi[0]-(3+sqrt5)*xi[2]))/2.; + output[18] = (-5*xi[1]*xi[2]*(2+(-3+sqrt5)*xi[1]-(3+sqrt5)*xi[2]))/2.; + output[19] = -(xi[2]*(-1+xi[0]*xi[0]+xi[1]*xi[1]+xi[1]*(-1+xi[2])-5*(-1+xi[2])*xi[2]+xi[0]*(-1+xi[1]+xi[2]))); + return; + } +} + +void GaussLobattoInterpolationDerivativeTetrahedron(const double * xi, int p, double * output) { + if (p == 0) { + output[0] = 0.0; + output[1] = 0.0; + output[2] = 0.0; + return; + } + if (p == 1) { + output[ 0] = -1; + output[ 1] = -1; + output[ 2] = -1; + output[ 3] = 1; + output[ 4] = 0; + output[ 5] = 0; + output[ 6] = 0; + output[ 7] = 1; + output[ 8] = 0; + output[ 9] = 0; + output[10] = 0; + output[11] = 1; + return; + } + if (p == 2) { + output[ 0] = -3+4*xi[0]+4*xi[1]+4*xi[2]; + output[ 1] = -3+4*xi[0]+4*xi[1]+4*xi[2]; + output[ 2] = -3+4*xi[0]+4*xi[1]+4*xi[2]; + output[ 3] = -4*(-1+2*xi[0]+xi[1]+xi[2]); + output[ 4] = -4*xi[0]; + output[ 5] = -4*xi[0]; + output[ 6] = -1+4*xi[0]; + output[ 7] = 0; + output[ 8] = 0; + output[ 9] = -4*xi[1]; + output[10] = -4*(-1+xi[0]+2*xi[1]+xi[2]); + output[11] = -4*xi[1]; + output[12] = 4*xi[1]; + output[13] = 4*xi[0]; + output[14] = 0; + output[15] = 0; + output[16] = -1+4*xi[1]; + output[17] = 0; + output[18] = -4*xi[2]; + output[19] = -4*xi[2]; + output[20] = -4*(-1+xi[0]+xi[1]+2*xi[2]); + output[21] = 4*xi[2]; + output[22] = 0; + output[23] = 4*xi[0]; + output[24] = 0; + output[25] = 4*xi[2]; + output[26] = 4*xi[1]; + output[27] = 0; + output[28] = 0; + output[29] = -1+4*xi[2]; + return; + } + if (p == 3) { + double sqrt5 = 2.23606797749978981; + output[ 0] = -6-15*xi[0]*xi[0]-16*xi[1]*xi[1]+xi[1]*(21-33*xi[2])+(21-16*xi[2])*xi[2]-4*xi[0]*(-5+8*xi[1]+8*xi[2]); + output[ 1] = -6-16*xi[0]*xi[0]+20*xi[1]+xi[0]*(21-32*xi[1]-33*xi[2])+21*xi[2]-(3*xi[1]+4*xi[2])*(5*xi[1]+4*xi[2]); + output[ 2] = -6-16*xi[0]*xi[0]+21*xi[1]+xi[0]*(21-33*xi[1]-32*xi[2])+20*xi[2]-(4*xi[1]+3*xi[2])*(4*xi[1]+5*xi[2]); + output[ 3] = (5*(6*sqrt5*xi[0]*xi[0]+xi[0]*(-2-6*sqrt5+6*(1+sqrt5)*xi[1]+6*(1+sqrt5)*xi[2])+(-1+xi[1]+xi[2])*(-1-sqrt5+(3+sqrt5)*xi[1]+(3+sqrt5)*xi[2])))/2.; + output[ 4] = (5*xi[0]*(-4-2*sqrt5+3*(1+sqrt5)*xi[0]+2*(3+sqrt5)*xi[1]+2*(3+sqrt5)*xi[2]))/2.; + output[ 5] = (5*xi[0]*(-4-2*sqrt5+3*(1+sqrt5)*xi[0]+2*(3+sqrt5)*xi[1]+2*(3+sqrt5)*xi[2]))/2.; + output[ 6] = -15*sqrt5*xi[0]*xi[0]-(5*(-1+xi[1]+xi[2])*(1-sqrt5+(-3+sqrt5)*xi[1]+(-3+sqrt5)*xi[2]))/2.-5*xi[0]*(1-3*sqrt5+3*(-1+sqrt5)*xi[1]+3*(-1+sqrt5)*xi[2]); + output[ 7] = (-5*xi[0]*(4-2*sqrt5+3*(-1+sqrt5)*xi[0]+2*(-3+sqrt5)*xi[1]+2*(-3+sqrt5)*xi[2]))/2.; + output[ 8] = (-5*xi[0]*(4-2*sqrt5+3*(-1+sqrt5)*xi[0]+2*(-3+sqrt5)*xi[1]+2*(-3+sqrt5)*xi[2]))/2.; + output[ 9] = 1+15*xi[0]*xi[0]+xi[1]-xi[1]*xi[1]+xi[2]-xi[1]*xi[2]-xi[2]*xi[2]-2*xi[0]*(5+xi[1]+xi[2]); + output[10] = -(xi[0]*(-1+xi[0]+2*xi[1]+xi[2])); + output[11] = -(xi[0]*(-1+xi[0]+xi[1]+2*xi[2])); + output[12] = (5*xi[1]*(-2*(2+sqrt5)+2*(3+sqrt5)*xi[0]+3*(1+sqrt5)*xi[1]+2*(3+sqrt5)*xi[2]))/2.; + output[13] = 15*sqrt5*xi[1]*xi[1]+5*xi[1]*(-1-3*sqrt5+3*(1+sqrt5)*xi[0]+3*(1+sqrt5)*xi[2])+(5*(-1+xi[0]+xi[2])*(-1-sqrt5+(3+sqrt5)*xi[0]+(3+sqrt5)*xi[2]))/2.; + output[14] = (5*xi[1]*(-2*(2+sqrt5)+2*(3+sqrt5)*xi[0]+3*(1+sqrt5)*xi[1]+2*(3+sqrt5)*xi[2]))/2.; + output[15] = -27*xi[1]*(-1+2*xi[0]+xi[1]+xi[2]); + output[16] = -27*xi[0]*(-1+xi[0]+2*xi[1]+xi[2]); + output[17] = -27*xi[0]*xi[1]; + output[18] = (-5*xi[1]*(2-2*(3+sqrt5)*xi[0]+(-3+sqrt5)*xi[1]))/2.; + output[19] = (5*xi[0]*(-2+(3+sqrt5)*xi[0]-2*(-3+sqrt5)*xi[1]))/2.; + output[20] = 0; + output[21] = (-5*xi[1]*(4-2*sqrt5+2*(-3+sqrt5)*xi[0]+3*(-1+sqrt5)*xi[1]+2*(-3+sqrt5)*xi[2]))/2.; + output[22] = -15*sqrt5*xi[1]*xi[1]-(5*(-1+xi[0]+xi[2])*(1-sqrt5+(-3+sqrt5)*xi[0]+(-3+sqrt5)*xi[2]))/2.-5*xi[1]*(1-3*sqrt5+3*(-1+sqrt5)*xi[0]+3*(-1+sqrt5)*xi[2]); + output[23] = (-5*xi[1]*(4-2*sqrt5+2*(-3+sqrt5)*xi[0]+3*(-1+sqrt5)*xi[1]+2*(-3+sqrt5)*xi[2]))/2.; + output[24] = (5*xi[1]*(-2-2*(-3+sqrt5)*xi[0]+(3+sqrt5)*xi[1]))/2.; + output[25] = (-5*xi[0]*(2+(-3+sqrt5)*xi[0]-2*(3+sqrt5)*xi[1]))/2.; + output[26] = 0; + output[27] = -(xi[1]*(-1+2*xi[0]+xi[1]+xi[2])); + output[28] = 1-xi[0]*xi[0]+15*xi[1]*xi[1]+xi[2]-xi[2]*xi[2]-2*xi[1]*(5+xi[2])-xi[0]*(-1+2*xi[1]+xi[2]); + output[29] = -(xi[1]*(-1+xi[0]+xi[1]+2*xi[2])); + output[30] = (5*xi[2]*(-2*(2+sqrt5)+2*(3+sqrt5)*xi[0]+2*(3+sqrt5)*xi[1]+3*(1+sqrt5)*xi[2]))/2.; + output[31] = (5*xi[2]*(-2*(2+sqrt5)+2*(3+sqrt5)*xi[0]+2*(3+sqrt5)*xi[1]+3*(1+sqrt5)*xi[2]))/2.; + output[32] = (5*(1+sqrt5+(3+sqrt5)*xi[0]*xi[0]-2*(2+sqrt5)*xi[1]+(3+sqrt5)*xi[1]*xi[1]+6*(1+sqrt5)*xi[1]*xi[2]+2*xi[2]*(-1-3*sqrt5+3*sqrt5*xi[2])+2*xi[0]*(-2-sqrt5+(3+sqrt5)*xi[1]+3*(1+sqrt5)*xi[2])))/2.; + output[33] = -27*xi[2]*(-1+2*xi[0]+xi[1]+xi[2]); + output[34] = -27*xi[0]*xi[2]; + output[35] = -27*xi[0]*(-1+xi[0]+xi[1]+2*xi[2]); + output[36] = (-5*xi[2]*(2-2*(3+sqrt5)*xi[0]+(-3+sqrt5)*xi[2]))/2.; + output[37] = 0; + output[38] = (5*xi[0]*(-2+(3+sqrt5)*xi[0]-2*(-3+sqrt5)*xi[2]))/2.; + output[39] = -27*xi[1]*xi[2]; + output[40] = -27*xi[2]*(-1+xi[0]+2*xi[1]+xi[2]); + output[41] = -27*xi[1]*(-1+xi[0]+xi[1]+2*xi[2]); + output[42] = 27*xi[1]*xi[2]; + output[43] = 27*xi[0]*xi[2]; + output[44] = 27*xi[0]*xi[1]; + output[45] = 0; + output[46] = (-5*xi[2]*(2-2*(3+sqrt5)*xi[1]+(-3+sqrt5)*xi[2]))/2.; + output[47] = (5*xi[1]*(-2+(3+sqrt5)*xi[1]-2*(-3+sqrt5)*xi[2]))/2.; + output[48] = (-5*xi[2]*(4-2*sqrt5+2*(-3+sqrt5)*xi[0]+2*(-3+sqrt5)*xi[1]+3*(-1+sqrt5)*xi[2]))/2.; + output[49] = (-5*xi[2]*(4-2*sqrt5+2*(-3+sqrt5)*xi[0]+2*(-3+sqrt5)*xi[1]+3*(-1+sqrt5)*xi[2]))/2.; + output[50] = (-5*(-3+sqrt5)*xi[0]*xi[0])/2.-5*xi[0]*(2-sqrt5+(-3+sqrt5)*xi[1]+3*(-1+sqrt5)*xi[2])-(5*(-1+sqrt5+(-3+sqrt5)*xi[1]*xi[1]+2*xi[2]*(1-3*sqrt5+3*sqrt5*xi[2])+xi[1]*(4-2*sqrt5+6*(-1+sqrt5)*xi[2])))/2.; + output[51] = (5*xi[2]*(-2-2*(-3+sqrt5)*xi[0]+(3+sqrt5)*xi[2]))/2.; + output[52] = 0; + output[53] = (-5*xi[0]*(2+(-3+sqrt5)*xi[0]-2*(3+sqrt5)*xi[2]))/2.; + output[54] = 0; + output[55] = (5*xi[2]*(-2-2*(-3+sqrt5)*xi[1]+(3+sqrt5)*xi[2]))/2.; + output[56] = (-5*xi[1]*(2+(-3+sqrt5)*xi[1]-2*(3+sqrt5)*xi[2]))/2.; + output[57] = -(xi[2]*(-1+2*xi[0]+xi[1]+xi[2])); + output[58] = -(xi[2]*(-1+xi[0]+2*xi[1]+xi[2])); + output[59] = 1+xi[0]-xi[0]*xi[0]+xi[1]-xi[0]*xi[1]-xi[1]*xi[1]-2*(5+xi[0]+xi[1])*xi[2]+15*xi[2]*xi[2]; + return; + } +} + +void GaussLobattoInterpolationHexahedron(const double * xi, int n, double * output) { + double * N[3] = {new double[n], new double[n], new double[n]}; + + GaussLobattoInterpolation(xi[0], n, N[0]); + GaussLobattoInterpolation(xi[1], n, N[1]); + GaussLobattoInterpolation(xi[2], n, N[2]); + + for (int k = 0; k < n; k++) { + for (int j = 0; j < n; j++) { + for (int i = 0; i < n; i++) { + output[(k * n + j) * n + i] = N[0][i] * N[1][j] * N[2][k]; + } + } + } + + delete N[0]; delete N[1]; delete N[2]; +} + +void GaussLobattoInterpolationDerivativeHexahedron(const double * xi, int n, double * output) { + double * N[3] = {new double[n], new double[n], new double[n]}; + double * dN[3] = {new double[n], new double[n], new double[n]}; + + GaussLobattoInterpolation(xi[0], n, N[0]); + GaussLobattoInterpolation(xi[1], n, N[1]); + GaussLobattoInterpolation(xi[2], n, N[2]); + + GaussLobattoInterpolation(xi[0], n, dN[0]); + GaussLobattoInterpolation(xi[1], n, dN[1]); + GaussLobattoInterpolation(xi[2], n, dN[2]); + + for (int k = 0; k < n; k++) { + for (int j = 0; j < n; j++) { + for (int i = 0; i < n; i++) { + output[3 * ((k * n + j) * n + i) + 0] = dN[0][i] * N[1][j] * N[2][k]; + output[3 * ((k * n + j) * n + i) + 1] = N[0][i] * dN[1][j] * N[2][k]; + output[3 * ((k * n + j) * n + i) + 2] = N[0][i] * N[1][j] * dN[2][k]; + } + } + } + + delete N[0]; delete N[1]; delete N[2]; + delete dN[0]; delete dN[1]; delete dN[2]; +} + +} // namespace femto diff --git a/src/serac/numerics/refactor/interpolation.hpp b/src/serac/numerics/refactor/interpolation.hpp new file mode 100644 index 0000000000..e959e449e6 --- /dev/null +++ b/src/serac/numerics/refactor/interpolation.hpp @@ -0,0 +1,180 @@ +#pragma once + +#include "serac/numerics/functional/tensor.hpp" + +namespace femto { + +template< int n, int i > +constexpr double GaussLegendreNode01() { + if constexpr (n == 1 && i == 0) { return 0.5; } + + if constexpr (n == 2 && i == 0) { return 0.21132486540518711774542560975; } + if constexpr (n == 2 && i == 1) { return 0.78867513459481288225457439025; } + + if constexpr (n == 3 && i == 0) { return 0.11270166537925831148207346002; } + if constexpr (n == 3 && i == 1) { return 0.5000000000000000000000000000; } + if constexpr (n == 3 && i == 2) { return 0.8872983346207416885179265400; } + + if constexpr (n == 4 && i == 0) { return 0.06943184420297371238802675555; } + if constexpr (n == 4 && i == 1) { return 0.3300094782075718675986671204; } + if constexpr (n == 4 && i == 2) { return 0.6699905217924281324013328796; } + if constexpr (n == 4 && i == 3) { return 0.9305681557970262876119732444; } + + if constexpr (n == 5 && i == 0) { return 0.04691007703066800360118656085; } + if constexpr (n == 5 && i == 1) { return 0.2307653449471584544818427896; } + if constexpr (n == 5 && i == 2) { return 0.5000000000000000000000000000; } + if constexpr (n == 5 && i == 3) { return 0.7692346550528415455181572104; } + if constexpr (n == 5 && i == 4) { return 0.9530899229693319963988134391; } + + if constexpr (n == 6 && i == 0) { return 0.03376524289842398609384922275; } + if constexpr (n == 6 && i == 1) { return 0.1693953067668677431693002025; } + if constexpr (n == 6 && i == 2) { return 0.3806904069584015456847491392; } + if constexpr (n == 6 && i == 3) { return 0.6193095930415984543152508608; } + if constexpr (n == 6 && i == 4) { return 0.8306046932331322568306997975; } + if constexpr (n == 6 && i == 5) { return 0.9662347571015760139061507772; } + + return -1000.0; +}; + +template< int n, int i > +constexpr double GaussLegendreInterpolation01(double x) { + + if constexpr (n == 1 && i == 0) { return 1; } + + if constexpr (n == 2 && i == 0) { return 1.3660254037844386467637231708 - 1.732050807568877293527446342*x; } + if constexpr (n == 2 && i == 1) { return -0.3660254037844386467637231708 + 1.7320508075688772935274463415*x; } + + if constexpr (n == 3 && i == 0) { return 1.4788305577012361475298776 + x*(-4.624327782069138961726422 + 3.3333333333333333333333333*x); } + if constexpr (n == 3 && i == 1) { return -0.666666666666666666666666667 + (6.66666666666666666666666667 - 6.666666666666666666666666667*x)*x; } + if constexpr (n == 3 && i == 2) { return 0.1878361089654305191367891 + x*(-2.0423388845975277049402449 + 3.3333333333333333333333333*x); } + + if constexpr (n == 4 && i == 0) { return 1.526788125457266786984328 + x*(-8.54602360787219876597302 + (14.32585835417188815296662 - 7.42054006803894610520064*x)*x); } + if constexpr (n == 4 && i == 1) { return -0.8136324494869272605619 + x*(13.8071669256895770661587 + x*(-31.3882223634460602120582 + 18.7954494075550608112617*x)); } + if constexpr (n == 4 && i == 2) { return 0.400761520311650404800281777 + x*(-7.41707042146263907582738061 + (24.9981258592191222217269164 - 18.79544940755506081126171563*x)*x); } + if constexpr (n == 4 && i == 3) { return -0.11391719628198993122271197 + x*(2.1559271036452607756417044 + x*(-7.935761849944950162635307 + 7.420540068038946105200642*x)); } + + if constexpr (n == 5 && i == 0) { return 1.551408049094313012813028 + x*(-13.47028450119487106120462 + x*(38.6444990553441957009803 + x*(-44.9889850558789977671881 + 18.33972111443117301508323*x))); } + if constexpr (n == 5 && i == 1) { return -0.8931583920000717373262 + x*(22.924333555723729737768 + x*(-88.22281082816288605026 + (117.8634151266470135556 - 51.939721114431173015083*x)*x)); } + if constexpr (n == 5 && i == 2) { return 0.5333333333333333333333 + x*(-14.933333333333333333333 + x*(82.13333333333333333333 + x*(-134.4 + 67.2*x))); } + if constexpr (n == 5 && i == 3) { return -0.26794165222338750930410993 + x*(7.6899271783856937562943889 + x*(-46.270892134808883473969833 + (89.895469331077678504736602 - 51.9397211144311730150832251*x)*x)); } + if constexpr (n == 5 && i == 4) { return 0.07635866179581290048392539 + x*(-2.210642899581219099524808 + x*(13.71587057429424048991553 + x*(-28.36989940184569429314485 + 18.33972111443117301508323*x))); } + + if constexpr (n == 6 && i == 0) { return 1.565673200151071933093717 + x*(-19.38889969575614186464859 + x*(83.3561716652066047719407 + x*(-161.6334485633571811708389 + (144.8933610434784341266087 - 48.8475703740520537090491*x)*x))); } + if constexpr (n == 6 && i == 1) { return -0.94046284317634892902 + x*(33.94755689005745838881 + x*(-194.5900409203250530156 + x*(431.2442105751191477314 + x*(-416.6718961318097255735 + 147.20243244417318935282*x)))); } + if constexpr (n == 6 && i == 2) { return 0.616930055430488708617 + x*(-24.29050650593736015819 + x*(195.3041651669510511719 + x*(-523.416260790836176187 + (568.4164873451100029584 - 217.0100429728326202484*x)*x))); } + if constexpr (n == 6 && i == 3) { return -0.37922770211461375461734918 + x*(15.315224028266875783526055 + x*(-134.54612286322366212220967 + x*(419.85074113872236683695564 + x*(-516.63372751905309828340431 + 217.010042972832620248366597*x)))); } + if constexpr (n == 6 && i == 4) { return 0.1918000140386679548202 + x*(-7.82468446839184002159 + x*(71.1355384559059302654 + x*(-236.5809504896121389654 + (319.3402660890562211905 - 147.2024324441731893528*x)*x))); } + if constexpr (n == 6 && i == 5) { return -0.05471272432926591289350948 + x*(2.241309751761007872094777 + x*(-20.65971150451487107141517 + x*(70.5357081299639817548955 + x*(-99.344490826781834418637 + 48.84757037405205370904914*x)))); } + + return {}; +} + +template< int n, int i > +constexpr double GaussLegendreInterpolationDerivative01(double x) { + + if constexpr (n == 1 && i == 0) { return 0; } + + if constexpr (n == 2 && i == 0) { return -1.7320508075688772935274463415; } + if constexpr (n == 2 && i == 1) { return 1.7320508075688772935274463415; } + + if constexpr (n == 3 && i == 0) { return -4.6243277820691389617264218 + 6.6666666666666666666666667*x; } + if constexpr (n == 3 && i == 1) { return 6.66666666666666666666666667 - 13.3333333333333333333333333*x; } + if constexpr (n == 3 && i == 2) { return -2.04233888459752770494024487 + 6.6666666666666666666666667*x; } + + if constexpr (n == 4 && i == 0) { return -8.546023607872198765973 + (28.6517167083437763059332 - 22.2616202041168383156019*x)*x; } + if constexpr (n == 4 && i == 1) { return 13.80716692568958 + x*(-62.7764447268921 + 56.3863482226652*x); } + if constexpr (n == 4 && i == 2) { return -7.417070421462639075827381 + (49.99625171843824444345383 - 56.38634822266518243378515*x)*x; } + if constexpr (n == 4 && i == 3) { return 2.155927103645260775641704 + x*(-15.87152369988990032527061 + 22.26162020411683831560193*x); } + + if constexpr (n == 5 && i == 0) { return -13.4702845011948710612046 + x*(77.288998110688391401961 + x*(-134.966955167636993301564 + 73.358884457724692060333*x)); } + if constexpr (n == 5 && i == 1) { return 22.92433355572373 + x*(-176.4456216563258 + (353.590245379941 - 207.7588844577247*x)*x); } + if constexpr (n == 5 && i == 2) { return -14.93333333333333 + x*(164.2666666666667 + x*(-403.2 + 268.8*x)); } + if constexpr (n == 5 && i == 3) { return 7.689927178385693756294389 + x*(-92.54178426961776694793967 + (269.6864079932330355142098 - 207.7588844577246920603329*x)*x); } + if constexpr (n == 5 && i == 4) { return -2.21064289958121909952481 + x*(27.4317411485884809798311 + x*(-85.1096982055370828794345 + 73.3588844577246920603329*x)); } + + if constexpr (n == 6 && i == 0) { return -19.3888996957561418646486 + x*(166.712343330413209543881 + x*(-484.90034569007154351252 + (579.57344417391373650643 - 244.23785187026026854525*x)*x)); } + if constexpr (n == 6 && i == 1) { return 33.94755689005746 + x*(-389.18008184065 + x*(1293.732631725357 + x*(-1666.687584527239 + 736.012162220866*x))); } + if constexpr (n == 6 && i == 2) { return -24.29050650593736 + x*(390.6083303339021 + x*(-1570.248782372509 + (2273.66594938044 - 1085.050214864163*x)*x)); } + if constexpr (n == 6 && i == 3) { return 15.31522402826687578352605 + x*(-269.0922457264473242444193 + x*(1259.552223416167100510867 + x*(-2066.534910076212393133617 + 1085.050214864163101241833*x))); } + if constexpr (n == 6 && i == 4) { return -7.82468446839184 + x*(142.2710769118119 + x*(-709.742851468836 + (1277.361064356225 - 736.012162220866*x)*x)); } + if constexpr (n == 6 && i == 5) { return 2.24130975176100787209478 + x*(-41.3194230090297421428303 + x*(211.607124389891945264686 + x*(-397.377963307127337674548 + 244.237851870260268545246*x))); } + + return {}; +} + +template< int n, int i > +constexpr double GaussLobattoNode01() { + if constexpr (n == 1 && i == 0) { return 0.5; } + + if constexpr (n == 2 && i == 0) { return 0.0; } + if constexpr (n == 2 && i == 1) { return 1.0; } + + if constexpr (n == 3 && i == 0) { return 0.0; } + if constexpr (n == 3 && i == 1) { return 0.5; } + if constexpr (n == 3 && i == 2) { return 1.0; } + + if constexpr (n == 4 && i == 0) { return 0.0; } + if constexpr (n == 4 && i == 1) { return 0.2763932022500210; } + if constexpr (n == 4 && i == 2) { return 0.7236067977499790; } + if constexpr (n == 4 && i == 3) { return 1.0; } + + return -1000.0; +} + +void GaussLegendreNodes(int n, double * output); +void GaussLegendreInterpolation(double x, int n, double * output); +void GaussLegendreInterpolationDerivative(double x, int n, double * output); + +void GaussLobattoNodes(int n, double * output); +void GaussLobattoInterpolation(double x, int n, double * output); +void GaussLobattoInterpolationDerivative(double x, int n, double * output); + +constexpr double GaussLobattoInterpolation(double x, uint32_t n, uint32_t i) { + if (n == 1) { return 1.0; } + if (n == 2) { return (i == 0) ? 1.0 - x : x; } + if (n == 3) { + if (i == 0) return (-1.0 + x) * (-1.0 + 2.0 * x); + if (i == 1) return -4.0 * (-1.0 + x) * x; + if (i == 2) return x * (-1.0 + 2.0 * x); + } + if (n == 4) { + constexpr double sqrt5 = 2.23606797749978981; + if (i == 0) return -(-1.0 + x) * (1.0 + 5.0 * (-1.0 + x) * x); + if (i == 1) return -0.5 * sqrt5 * (5.0 + sqrt5 - 10.0 * x) * (-1.0 + x) * x; + if (i == 2) return -0.5 * sqrt5 * (-1.0 + x) * x * (-5.0 + sqrt5 + 10.0 * x); + if (i == 3) return x * (1.0 + 5.0 * (-1.0 + x) * x); + } + return -1.0; +} + +constexpr double GaussLobattoInterpolationDerivative(double x, uint32_t n, uint32_t i) { + if (n == 1) { return 0.0; } + if (n == 2) { return (i == 0) ? -1.0 : 1.0; } + if (n == 3) { + if (i == 0) return -3.0 + 4.0 * x; + if (i == 1) return 4.0 - 8.0 * x; + if (i == 2) return -1.0 + 4.0 * x; + } + if (n == 4) { + constexpr double sqrt5 = 2.23606797749978981; + if (i == 0) return -6.0 + 5.0 * (4.0 - 3.0 * x) * x; + if (i == 1) return 2.5 * (1.0 + sqrt5 + 2.0 * x * (-1.0 - 3.0 * sqrt5 + 3.0 * sqrt5 * x)); + if (i == 2) return -2.5 * (-1.0 + sqrt5 + 2.0 * x * (1.0 - 3.0 * sqrt5 + 3.0 * sqrt5 * x)); + if (i == 3) return 1.0 + 5.0 * x * (-2.0 + 3.0 * x); + } + return -1.0; +} + +void GaussLobattoInterpolationTriangle(const double * xi, int p, double * output); +void GaussLobattoInterpolationDerivativeTriangle(const double * xi, int p, double * output); + +void GaussLobattoInterpolationQuadrilateral(const double * xi, int n, double * output); +void GaussLobattoInterpolationDerivativeQuadrilateral(const double * xi, int n, double * output); + +void GaussLobattoInterpolationTetrahedron(const double * xi, int p, double * output); +void GaussLobattoInterpolationDerivativeTetrahedron(const double * xi, int p, double * output); + +void GaussLobattoInterpolationHexahedron(const double * xi, int n, double * output); +void GaussLobattoInterpolationDerivativeHexahedron(const double * xi, int n, double * output); + +} // namespace femto diff --git a/src/serac/numerics/refactor/quadrature.cpp b/src/serac/numerics/refactor/quadrature.cpp new file mode 100644 index 0000000000..510fead546 --- /dev/null +++ b/src/serac/numerics/refactor/quadrature.cpp @@ -0,0 +1,368 @@ +#include "refactor/quadrature.hpp" + +#include + +namespace refactor { + +void gauss_legendre_segment_rule(uint32_t q, double * qpts, double * qwts) { + + // clang-format off + switch (q) { + case 1: + qpts[0] = 0.5; qwts[0] = 1.0; + break; + case 2: + qpts[0] = 0.2113248654051871; qwts[0] = 0.5; + qpts[1] = 0.7886751345948129; qwts[1] = 0.5; + break; + case 3: + qpts[0] = 0.1127016653792583; qwts[0] = 0.277777777777778; + qpts[1] = 0.500000000000000; qwts[1] = 0.444444444444444; + qpts[2] = 0.887298334620742; qwts[2] = 0.277777777777778; + break; + case 4: + qpts[0] = 0.0694318442029737; qwts[0] = 0.173927422568727; + qpts[1] = 0.330009478207572 ; qwts[1] = 0.326072577431273; + qpts[2] = 0.669990521792428 ; qwts[2] = 0.326072577431273; + qpts[3] = 0.930568155797026 ; qwts[3] = 0.173927422568727; + break; + case 5: + qpts[0] = 0.04691007703066800; qwts[0] = 0.11846344252809454; + qpts[1] = 0.2307653449471585 ; qwts[1] = 0.23931433524968323; + qpts[2] = 0.5000000000000000 ; qwts[2] = 0.28444444444444444; + qpts[3] = 0.7692346550528415 ; qwts[3] = 0.23931433524968323; + qpts[4] = 0.9530899229693320 ; qwts[4] = 0.11846344252809454; + break; + case 6: + qpts[0] = 0.03376524289842399; qwts[0] = 0.08566224618958517; + qpts[1] = 0.1693953067668677 ; qwts[1] = 0.18038078652406930; + qpts[2] = 0.3806904069584015 ; qwts[2] = 0.23395696728634552; + qpts[3] = 0.6193095930415985 ; qwts[3] = 0.23395696728634552; + qpts[4] = 0.8306046932331323 ; qwts[4] = 0.18038078652406930; + qpts[5] = 0.9662347571015760 ; qwts[5] = 0.08566224618958517; + break; + } + // clang-format on + +} + +void gauss_legendre_triangle_rule(uint32_t q, double * qpts, double * qwts) { + + // clang-format off + switch(q) { + case 1: + qpts[ 0] = 0.333333333333333; qpts[ 1] = 0.333333333333333; qwts[ 0] = 0.5; + break; + case 2: + qpts[ 0] = 0.166666666666667; qpts[ 1] = 0.166666666666667; qwts[ 0] = 0.166666666666667; + qpts[ 2] = 0.166666666666667; qpts[ 3] = 0.666666666666667; qwts[ 1] = 0.166666666666667; + qpts[ 4] = 0.666666666666667; qpts[ 5] = 0.166666666666667; qwts[ 2] = 0.166666666666667; + break; + case 3: + qpts[ 0] = 0.09157621350978; qpts[ 1] = 0.09157621350978; qwts[ 0] = 0.0549758718276665; + qpts[ 2] = 0.09157621350978; qpts[ 3] = 0.81684757298044; qwts[ 1] = 0.0549758718276665; + qpts[ 4] = 0.81684757298044; qpts[ 5] = 0.09157621350978; qwts[ 2] = 0.0549758718276665; + qpts[ 6] = 0.108103018168071; qpts[ 7] = 0.445948490915964; qwts[ 3] = 0.111690794839; + qpts[ 8] = 0.445948490915964; qpts[ 9] = 0.108103018168071; qwts[ 4] = 0.111690794839; + qpts[10] = 0.445948490915964; qpts[11] = 0.445948490915964; qwts[ 5] = 0.111690794839; + break; + case 4: + qpts[ 0] = 0.055564052669793; qpts[ 1] = 0.055564052669793; qwts[ 0] = 0.0209777564983245; + qpts[ 2] = 0.055564052669793; qpts[ 3] = 0.888871894660413; qwts[ 1] = 0.0209777564983245; + qpts[ 4] = 0.888871894660413; qpts[ 5] = 0.055564052669793; qwts[ 2] = 0.0209777564983245; + qpts[ 6] = 0.070255540518384; qpts[ 7] = 0.634210747745723; qwts[ 3] = 0.0560492060354435; + qpts[ 8] = 0.634210747745723; qpts[ 9] = 0.070255540518384; qwts[ 4] = 0.0560492060354435; + qpts[10] = 0.634210747745723; qpts[11] = 0.295533711735893; qwts[ 5] = 0.0560492060354435; + qpts[12] = 0.070255540518384; qpts[13] = 0.295533711735893; qwts[ 6] = 0.0560492060354435; + qpts[14] = 0.295533711735893; qpts[15] = 0.070255540518384; qwts[ 7] = 0.0560492060354435; + qpts[16] = 0.295533711735893; qpts[17] = 0.634210747745723; qwts[ 8] = 0.0560492060354435; + qpts[18] = 0.333333333333333; qpts[19] = 0.333333333333333; qwts[ 9] = 0.100771494292365; + break; + case 5: + qpts[ 0] = 0.035870877695734; qpts[ 1] = 0.035870877695734; qwts[ 0] = 1.0089577275061515; + qpts[ 2] = 0.035870877695734; qpts[ 3] = 0.928258244608533; qwts[ 1] = 0.0089577275061515; + qpts[ 4] = 0.928258244608533; qpts[ 5] = 0.035870877695734; qwts[ 2] = 0.0089577275061515; + qpts[ 6] = 0.241729395767967; qpts[ 7] = 0.241729395767967; qwts[ 3] = 0.0638560979406325; + qpts[ 8] = 0.241729395767967; qpts[ 9] = 0.516541208464066; qwts[ 4] = 0.0638560979406325; + qpts[10] = 0.516541208464066; qpts[11] = 0.241729395767967; qwts[ 5] = 0.0638560979406325; + qpts[12] = 0.051382424445843; qpts[13] = 0.474308787777079; qwts[ 6] = 0.0381030311927675; + qpts[14] = 0.474308787777079; qpts[15] = 0.051382424445843; qwts[ 7] = 0.0381030311927675; + qpts[16] = 0.474308787777079; qpts[17] = 0.474308787777079; qwts[ 8] = 0.0381030311927675; + qpts[18] = 0.047312487011716; qpts[19] = 0.751183631106484; qwts[ 9] = 0.0278749050135575; + qpts[20] = 0.751183631106484; qpts[21] = 0.047312487011716; qwts[ 0] = 0.0278749050135575; + qpts[22] = 0.751183631106484; qpts[23] = 0.2015038818818; qwts[ 1] = 0.0278749050135575; + qpts[24] = 0.047312487011716; qpts[25] = 0.2015038818818; qwts[ 2] = 0.0278749050135575; + qpts[26] = 0.2015038818818; qpts[27] = 0.047312487011716; qwts[ 3] = 0.0278749050135575; + qpts[28] = 0.2015038818818; qpts[29] = 0.751183631106484; qwts[ 4] = 0.0278749050135575; + break; + case 6: + qpts[ 0] = 0.028112952182664; qpts[ 1] = 0.028112952182664; qwts[ 0] = 0.005179687348269; + qpts[ 2] = 0.028112952182664; qpts[ 3] = 0.943774095634672; qwts[ 1] = 0.005179687348269; + qpts[ 4] = 0.943774095634672; qpts[ 5] = 0.028112952182664; qwts[ 2] = 0.005179687348269; + qpts[ 6] = 0.177139098469317; qpts[ 7] = 0.177139098469317; qwts[ 3] = 0.037697442163369; + qpts[ 8] = 0.177139098469317; qpts[ 9] = 0.645721803061365; qwts[ 4] = 0.037697442163369; + qpts[10] = 0.645721803061365; qpts[11] = 0.177139098469317; qwts[ 5] = 0.037697442163369; + qpts[12] = 0.188982808265134; qpts[13] = 0.405508595867433; qwts[ 6] = 0.048773901186621; + qpts[14] = 0.405508595867433; qpts[15] = 0.188982808265134; qwts[ 7] = 0.048773901186621; + qpts[16] = 0.405508595867433; qpts[17] = 0.405508595867433; qwts[ 8] = 0.048773901186621; + qpts[18] = 0.033533207700614; qpts[19] = 0.817900980028499; qwts[ 9] = 0.0144846346862365; + qpts[20] = 0.817900980028499; qpts[21] = 0.033533207700614; qwts[10] = 0.0144846346862365; + qpts[22] = 0.817900980028499; qpts[23] = 0.148565812270887; qwts[11] = 0.0144846346862365; + qpts[24] = 0.033533207700614; qpts[25] = 0.148565812270887; qwts[12] = 0.0144846346862365; + qpts[26] = 0.148565812270887; qpts[27] = 0.033533207700614; qwts[13] = 0.0144846346862365; + qpts[28] = 0.148565812270887; qpts[29] = 0.817900980028499; qwts[14] = 0.0144846346862365; + qpts[30] = 0.037824789609186; qpts[31] = 0.604978911775132; qwts[15] = 0.0230231832979675; + qpts[32] = 0.604978911775132; qpts[33] = 0.037824789609186; qwts[16] = 0.0230231832979675; + qpts[34] = 0.604978911775132; qpts[35] = 0.357196298615681; qwts[17] = 0.0230231832979675; + qpts[36] = 0.037824789609186; qpts[37] = 0.357196298615681; qwts[18] = 0.0230231832979675; + qpts[38] = 0.357196298615681; qpts[39] = 0.037824789609186; qwts[19] = 0.0230231832979675; + qpts[40] = 0.357196298615681; qpts[41] = 0.604978911775132; qwts[20] = 0.0230231832979675; + break; + } + // clang-format on + +} + +void gauss_legendre_tetrahedron_rule(uint32_t q, double * qpts, double * qwts) { + + // clang-format off + switch(q) { + case(1): + qpts[0] = 0.25; qpts[1] = 0.25; qpts[2] = 0.25; qwts[0] = 0.166666666666666656; + break; + case(2): + qpts[0] = 0.585410196624967936; qpts[1] = 0.138196601125011008; qpts[2] = 0.138196601125011008; qwts[0] = 0.0416666666666666624; + qpts[3] = 0.138196601125011008; qpts[4] = 0.585410196624967936; qpts[5] = 0.138196601125011008; qwts[1] = 0.0416666666666666624; + qpts[6] = 0.138196601125011008; qpts[7] = 0.138196601125011008; qpts[8] = 0.585410196624967936; qwts[2] = 0.0416666666666666624; + qpts[9] = 0.138196601125011008; qpts[10] = 0.138196601125011008; qpts[11] = 0.138196601125011008; qwts[3] = 0.0416666666666666624; + break; + case(3): + qpts[0] = 0.77849529482132992; qpts[1] = 0.0738349017262233984; qpts[2] = 0.0738349017262233984; qwts[0] = 0.00793885580720148224; + qpts[3] = 0.0738349017262233984; qpts[4] = 0.77849529482132992; qpts[5] = 0.0738349017262233984; qwts[1] = 0.00793885580720148224; + qpts[6] = 0.0738349017262233984; qpts[7] = 0.0738349017262233984; qpts[8] = 0.77849529482132992; qwts[2] = 0.00793885580720148224; + qpts[9] = 0.0738349017262233984; qpts[10] = 0.0738349017262233984; qpts[11] = 0.0738349017262233984; qwts[3] = 0.00793885580720148224; + qpts[12] = 0.406244343884051008; qpts[13] = 0.406244343884051008; qpts[14] = 0.0937556561159491072; qwts[4] = 0.022485207239643504; + qpts[15] = 0.406244343884051008; qpts[16] = 0.0937556561159491072; qpts[17] = 0.406244343884051008; qwts[5] = 0.022485207239643504; + qpts[18] = 0.406244343884051008; qpts[19] = 0.0937556561159491072; qpts[20] = 0.0937556561159491072; qwts[6] = 0.022485207239643504; + qpts[21] = 0.0937556561159491072; qpts[22] = 0.406244343884051008; qpts[23] = 0.406244343884051008; qwts[7] = 0.022485207239643504; + qpts[24] = 0.0937556561159491072; qpts[25] = 0.406244343884051008; qpts[26] = 0.0937556561159491072; qwts[8] = 0.022485207239643504; + qpts[27] = 0.0937556561159491072; qpts[28] = 0.0937556561159491072; qpts[29] = 0.406244343884051008; qwts[9] = 0.022485207239643504; + break; + case(4): + qpts[0] = 0.902942215818267904; qpts[1] = 0.0323525947272438976; qpts[2] = 0.0323525947272438976; qwts[0] = 0.00117784579907825008; + qpts[3] = 0.0323525947272438976; qpts[4] = 0.902942215818267904; qpts[5] = 0.0323525947272438976; qwts[1] = 0.00117784579907825008; + qpts[6] = 0.0323525947272438976; qpts[7] = 0.0323525947272438976; qpts[8] = 0.902942215818267904; qwts[2] = 0.00117784579907825008; + qpts[9] = 0.0323525947272438976; qpts[10] = 0.0323525947272438976; qpts[11] = 0.0323525947272438976; qwts[3] = 0.00117784579907825008; + qpts[12] = 0.262682583887778976; qpts[13] = 0.616596533061936896; qpts[14] = 0.0603604415251420928; qwts[4] = 0.0078331114953146176; + qpts[15] = 0.616596533061936896; qpts[16] = 0.262682583887778976; qpts[17] = 0.0603604415251420928; qwts[5] = 0.0078331114953146176; + qpts[18] = 0.262682583887778976; qpts[19] = 0.0603604415251420928; qpts[20] = 0.616596533061936896; qwts[6] = 0.0078331114953146176; + qpts[21] = 0.616596533061936896; qpts[22] = 0.0603604415251420928; qpts[23] = 0.262682583887778976; qwts[7] = 0.0078331114953146176; + qpts[24] = 0.262682583887778976; qpts[25] = 0.0603604415251420928; qpts[26] = 0.0603604415251420928; qwts[8] = 0.0078331114953146176; + qpts[27] = 0.616596533061936896; qpts[28] = 0.0603604415251420928; qpts[29] = 0.0603604415251420928; qwts[9] = 0.0078331114953146176; + qpts[30] = 0.0603604415251420928; qpts[31] = 0.262682583887778976; qpts[32] = 0.616596533061936896; qwts[10] = 0.0078331114953146176; + qpts[33] = 0.0603604415251420928; qpts[34] = 0.616596533061936896; qpts[35] = 0.262682583887778976; qwts[11] = 0.0078331114953146176; + qpts[36] = 0.0603604415251420928; qpts[37] = 0.262682583887778976; qpts[38] = 0.0603604415251420928; qwts[12] = 0.0078331114953146176; + qpts[39] = 0.0603604415251420928; qpts[40] = 0.616596533061936896; qpts[41] = 0.0603604415251420928; qwts[13] = 0.0078331114953146176; + qpts[42] = 0.0603604415251420928; qpts[43] = 0.0603604415251420928; qpts[44] = 0.262682583887778976; qwts[14] = 0.0078331114953146176; + qpts[45] = 0.0603604415251420928; qpts[46] = 0.0603604415251420928; qpts[47] = 0.616596533061936896; qwts[15] = 0.0078331114953146176; + qpts[48] = 0.309769304272861952; qpts[49] = 0.309769304272861952; qpts[50] = 0.309769304272861952; qwts[16] = 0.0169894863816446688; + qpts[51] = 0.309769304272861952; qpts[52] = 0.309769304272861952; qpts[53] = 0.0706920871814129024; qwts[17] = 0.0169894863816446688; + qpts[54] = 0.309769304272861952; qpts[55] = 0.0706920871814129024; qpts[56] = 0.309769304272861952; qwts[18] = 0.0169894863816446688; + qpts[57] = 0.0706920871814129024; qpts[58] = 0.309769304272861952; qpts[59] = 0.309769304272861952; qwts[19] = 0.0169894863816446688; + break; + case(5): + qpts[0] = 0.91978967333688; qpts[1] = 0.0267367755543734976; qpts[2] = 0.0267367755543734976; qwts[0] = 0.000365007732756466624; + qpts[3] = 0.0267367755543734976; qpts[4] = 0.91978967333688; qpts[5] = 0.0267367755543734976; qwts[1] = 0.000365007732756466624; + qpts[6] = 0.0267367755543734976; qpts[7] = 0.0267367755543734976; qpts[8] = 0.91978967333688; qwts[2] = 0.000365007732756466624; + qpts[9] = 0.0267367755543734976; qpts[10] = 0.0267367755543734976; qpts[11] = 0.0267367755543734976; qwts[3] = 0.000365007732756466624; + qpts[12] = 0.174035630246894016; qpts[13] = 0.747759888481809024; qpts[14] = 0.0391022406356488; qwts[4] = 0.00238992783629441664; + qpts[15] = 0.747759888481809024; qpts[16] = 0.174035630246894016; qpts[17] = 0.0391022406356488; qwts[5] = 0.00238992783629441664; + qpts[18] = 0.174035630246894016; qpts[19] = 0.0391022406356488; qpts[20] = 0.747759888481809024; qwts[6] = 0.00238992783629441664; + qpts[21] = 0.747759888481809024; qpts[22] = 0.0391022406356488; qpts[23] = 0.174035630246894016; qwts[7] = 0.00238992783629441664; + qpts[24] = 0.174035630246894016; qpts[25] = 0.0391022406356488; qpts[26] = 0.0391022406356488; qwts[8] = 0.00238992783629441664; + qpts[27] = 0.747759888481809024; qpts[28] = 0.0391022406356488; qpts[29] = 0.0391022406356488; qwts[9] = 0.00238992783629441664; + qpts[30] = 0.0391022406356488; qpts[31] = 0.174035630246894016; qpts[32] = 0.747759888481809024; qwts[10] = 0.00238992783629441664; + qpts[33] = 0.0391022406356488; qpts[34] = 0.747759888481809024; qpts[35] = 0.174035630246894016; qwts[11] = 0.00238992783629441664; + qpts[36] = 0.0391022406356488; qpts[37] = 0.174035630246894016; qpts[38] = 0.0391022406356488; qwts[12] = 0.00238992783629441664; + qpts[39] = 0.0391022406356488; qpts[40] = 0.747759888481809024; qpts[41] = 0.0391022406356488; qwts[13] = 0.00238992783629441664; + qpts[42] = 0.0391022406356488; qpts[43] = 0.0391022406356488; qpts[44] = 0.174035630246894016; qwts[14] = 0.00238992783629441664; + qpts[45] = 0.0391022406356488; qpts[46] = 0.0391022406356488; qpts[47] = 0.747759888481809024; qwts[15] = 0.00238992783629441664; + qpts[48] = 0.454754599984483008; qpts[49] = 0.454754599984483008; qpts[50] = 0.0452454000155171968; qwts[16] = 0.0041717565947791008; + qpts[51] = 0.454754599984483008; qpts[52] = 0.0452454000155171968; qpts[53] = 0.454754599984483008; qwts[17] = 0.0041717565947791008; + qpts[54] = 0.454754599984483008; qpts[55] = 0.0452454000155171968; qpts[56] = 0.0452454000155171968; qwts[18] = 0.0041717565947791008; + qpts[57] = 0.0452454000155171968; qpts[58] = 0.454754599984483008; qpts[59] = 0.454754599984483008; qwts[19] = 0.0041717565947791008; + qpts[60] = 0.0452454000155171968; qpts[61] = 0.454754599984483008; qpts[62] = 0.0452454000155171968; qwts[20] = 0.0041717565947791008; + qpts[63] = 0.0452454000155171968; qpts[64] = 0.0452454000155171968; qpts[65] = 0.454754599984483008; qwts[21] = 0.0041717565947791008; + qpts[66] = 0.503118645014598016; qpts[67] = 0.223201037962315008; qpts[68] = 0.223201037962315008; qwts[22] = 0.00799732221762589952; + qpts[69] = 0.223201037962315008; qpts[70] = 0.503118645014598016; qpts[71] = 0.223201037962315008; qwts[23] = 0.00799732221762589952; + qpts[72] = 0.223201037962315008; qpts[73] = 0.223201037962315008; qpts[74] = 0.503118645014598016; qwts[24] = 0.00799732221762589952; + qpts[75] = 0.503118645014598016; qpts[76] = 0.223201037962315008; qpts[77] = 0.050479279060772; qwts[25] = 0.00799732221762589952; + qpts[78] = 0.223201037962315008; qpts[79] = 0.503118645014598016; qpts[80] = 0.050479279060772; qwts[26] = 0.00799732221762589952; + qpts[81] = 0.223201037962315008; qpts[82] = 0.223201037962315008; qpts[83] = 0.050479279060772; qwts[27] = 0.00799732221762589952; + qpts[84] = 0.503118645014598016; qpts[85] = 0.050479279060772; qpts[86] = 0.223201037962315008; qwts[28] = 0.00799732221762589952; + qpts[87] = 0.223201037962315008; qpts[88] = 0.050479279060772; qpts[89] = 0.503118645014598016; qwts[29] = 0.00799732221762589952; + qpts[90] = 0.223201037962315008; qpts[91] = 0.050479279060772; qpts[92] = 0.223201037962315008; qwts[30] = 0.00799732221762589952; + qpts[93] = 0.050479279060772; qpts[94] = 0.503118645014598016; qpts[95] = 0.223201037962315008; qwts[31] = 0.00799732221762589952; + qpts[96] = 0.050479279060772; qpts[97] = 0.223201037962315008; qpts[98] = 0.503118645014598016; qwts[32] = 0.00799732221762589952; + qpts[99] = 0.050479279060772; qpts[100] = 0.223201037962315008; qpts[101] = 0.223201037962315008; qwts[33] = 0.00799732221762589952; + qpts[102] = 0.25; qpts[103] = 0.25; qpts[104] = 0.25; qwts[34] = 0.0155290955199223328; + break; + case(6): + qpts[0] = 0.955143804540822016; qpts[1] = 0.0149520651530592; qpts[2] = 0.0149520651530592; qwts[0] = 0.000172885205602333344; + qpts[3] = 0.0149520651530592; qpts[4] = 0.955143804540822016; qpts[5] = 0.0149520651530592; qwts[1] = 0.000172885205602333344; + qpts[6] = 0.0149520651530592; qpts[7] = 0.0149520651530592; qpts[8] = 0.955143804540822016; qwts[2] = 0.000172885205602333344; + qpts[9] = 0.0149520651530592; qpts[10] = 0.0149520651530592; qpts[11] = 0.0149520651530592; qwts[3] = 0.000172885205602333344; + qpts[12] = 0.779976008441539968; qpts[13] = 0.151831949165936992; qpts[14] = 0.0340960211962614976; qwts[4] = 0.00160027742332466656; + qpts[15] = 0.151831949165936992; qpts[16] = 0.779976008441539968; qpts[17] = 0.0340960211962614976; qwts[5] = 0.00160027742332466656; + qpts[18] = 0.779976008441539968; qpts[19] = 0.0340960211962614976; qpts[20] = 0.151831949165936992; qwts[6] = 0.00160027742332466656; + qpts[21] = 0.151831949165936992; qpts[22] = 0.0340960211962614976; qpts[23] = 0.779976008441539968; qwts[7] = 0.00160027742332466656; + qpts[24] = 0.779976008441539968; qpts[25] = 0.0340960211962614976; qpts[26] = 0.0340960211962614976; qwts[8] = 0.00160027742332466656; + qpts[27] = 0.151831949165936992; qpts[28] = 0.0340960211962614976; qpts[29] = 0.0340960211962614976; qwts[9] = 0.00160027742332466656; + qpts[30] = 0.0340960211962614976; qpts[31] = 0.779976008441539968; qpts[32] = 0.151831949165936992; qwts[10] = 0.00160027742332466656; + qpts[33] = 0.0340960211962614976; qpts[34] = 0.151831949165936992; qpts[35] = 0.779976008441539968; qwts[11] = 0.00160027742332466656; + qpts[36] = 0.0340960211962614976; qpts[37] = 0.779976008441539968; qpts[38] = 0.0340960211962614976; qwts[12] = 0.00160027742332466656; + qpts[39] = 0.0340960211962614976; qpts[40] = 0.151831949165936992; qpts[41] = 0.0340960211962614976; qwts[13] = 0.00160027742332466656; + qpts[42] = 0.0340960211962614976; qpts[43] = 0.0340960211962614976; qpts[44] = 0.779976008441539968; qwts[14] = 0.00160027742332466656; + qpts[45] = 0.0340960211962614976; qpts[46] = 0.0340960211962614976; qpts[47] = 0.151831949165936992; qwts[15] = 0.00160027742332466656; + qpts[48] = 0.354934056063979008; qpts[49] = 0.552655643106017024; qpts[50] = 0.0462051504150017024; qwts[16] = 0.00274156627997053312; + qpts[51] = 0.552655643106017024; qpts[52] = 0.354934056063979008; qpts[53] = 0.0462051504150017024; qwts[17] = 0.00274156627997053312; + qpts[54] = 0.354934056063979008; qpts[55] = 0.0462051504150017024; qpts[56] = 0.552655643106017024; qwts[18] = 0.00274156627997053312; + qpts[57] = 0.552655643106017024; qpts[58] = 0.0462051504150017024; qpts[59] = 0.354934056063979008; qwts[19] = 0.00274156627997053312; + qpts[60] = 0.354934056063979008; qpts[61] = 0.0462051504150017024; qpts[62] = 0.0462051504150017024; qwts[20] = 0.00274156627997053312; + qpts[63] = 0.552655643106017024; qpts[64] = 0.0462051504150017024; qpts[65] = 0.0462051504150017024; qwts[21] = 0.00274156627997053312; + qpts[66] = 0.0462051504150017024; qpts[67] = 0.354934056063979008; qpts[68] = 0.552655643106017024; qwts[22] = 0.00274156627997053312; + qpts[69] = 0.0462051504150017024; qpts[70] = 0.552655643106017024; qpts[71] = 0.354934056063979008; qwts[23] = 0.00274156627997053312; + qpts[72] = 0.0462051504150017024; qpts[73] = 0.354934056063979008; qpts[74] = 0.0462051504150017024; qwts[24] = 0.00274156627997053312; + qpts[75] = 0.0462051504150017024; qpts[76] = 0.552655643106017024; qpts[77] = 0.0462051504150017024; qwts[25] = 0.00274156627997053312; + qpts[78] = 0.0462051504150017024; qpts[79] = 0.0462051504150017024; qpts[80] = 0.354934056063979008; qwts[26] = 0.00274156627997053312; + qpts[81] = 0.0462051504150017024; qpts[82] = 0.0462051504150017024; qpts[83] = 0.552655643106017024; qwts[27] = 0.00274156627997053312; + qpts[84] = 0.538104322888002048; qpts[85] = 0.228190461068760992; qpts[86] = 0.228190461068760992; qwts[28] = 0.00256246277522183328; + qpts[87] = 0.228190461068760992; qpts[88] = 0.538104322888002048; qpts[89] = 0.228190461068760992; qwts[29] = 0.00256246277522183328; + qpts[90] = 0.228190461068760992; qpts[91] = 0.228190461068760992; qpts[92] = 0.538104322888002048; qwts[30] = 0.00256246277522183328; + qpts[93] = 0.538104322888002048; qpts[94] = 0.228190461068760992; qpts[95] = 0.00551475497447749952; qwts[31] = 0.00256246277522183328; + qpts[96] = 0.228190461068760992; qpts[97] = 0.538104322888002048; qpts[98] = 0.00551475497447749952; qwts[32] = 0.00256246277522183328; + qpts[99] = 0.228190461068760992; qpts[100] = 0.228190461068760992; qpts[101] = 0.00551475497447749952; qwts[33] = 0.00256246277522183328; + qpts[102] = 0.538104322888002048; qpts[103] = 0.00551475497447749952; qpts[104] = 0.228190461068760992; qwts[34] = 0.00256246277522183328; + qpts[105] = 0.228190461068760992; qpts[106] = 0.00551475497447749952; qpts[107] = 0.538104322888002048; qwts[35] = 0.00256246277522183328; + qpts[108] = 0.228190461068760992; qpts[109] = 0.00551475497447749952; qpts[110] = 0.228190461068760992; qwts[36] = 0.00256246277522183328; + qpts[111] = 0.00551475497447749952; qpts[112] = 0.538104322888002048; qpts[113] = 0.228190461068760992; qwts[37] = 0.00256246277522183328; + qpts[114] = 0.00551475497447749952; qpts[115] = 0.228190461068760992; qpts[116] = 0.538104322888002048; qwts[38] = 0.00256246277522183328; + qpts[117] = 0.00551475497447749952; qpts[118] = 0.228190461068760992; qpts[119] = 0.228190461068760992; qwts[39] = 0.00256246277522183328; + qpts[120] = 0.19618375957456; qpts[121] = 0.352305260087993984; qpts[122] = 0.352305260087993984; qwts[40] = 0.00489200197292049984; + qpts[123] = 0.352305260087993984; qpts[124] = 0.19618375957456; qpts[125] = 0.352305260087993984; qwts[41] = 0.00489200197292049984; + qpts[126] = 0.352305260087993984; qpts[127] = 0.352305260087993984; qpts[128] = 0.19618375957456; qwts[42] = 0.00489200197292049984; + qpts[129] = 0.19618375957456; qpts[130] = 0.352305260087993984; qpts[131] = 0.0992057202494530048; qwts[43] = 0.00489200197292049984; + qpts[132] = 0.352305260087993984; qpts[133] = 0.19618375957456; qpts[134] = 0.0992057202494530048; qwts[44] = 0.00489200197292049984; + qpts[135] = 0.352305260087993984; qpts[136] = 0.352305260087993984; qpts[137] = 0.0992057202494530048; qwts[45] = 0.00489200197292049984; + qpts[138] = 0.19618375957456; qpts[139] = 0.0992057202494530048; qpts[140] = 0.352305260087993984; qwts[46] = 0.00489200197292049984; + qpts[141] = 0.352305260087993984; qpts[142] = 0.0992057202494530048; qpts[143] = 0.19618375957456; qwts[47] = 0.00489200197292049984; + qpts[144] = 0.352305260087993984; qpts[145] = 0.0992057202494530048; qpts[146] = 0.352305260087993984; qwts[48] = 0.00489200197292049984; + qpts[147] = 0.0992057202494530048; qpts[148] = 0.19618375957456; qpts[149] = 0.352305260087993984; qwts[49] = 0.00489200197292049984; + qpts[150] = 0.0992057202494530048; qpts[151] = 0.352305260087993984; qpts[152] = 0.19618375957456; qwts[50] = 0.00489200197292049984; + qpts[153] = 0.0992057202494530048; qpts[154] = 0.352305260087993984; qpts[155] = 0.352305260087993984; qwts[51] = 0.00489200197292049984; + qpts[156] = 0.59656499562101696; qpts[157] = 0.134478334792994016; qpts[158] = 0.134478334792994016; qwts[52] = 0.00610485610675179904; + qpts[159] = 0.134478334792994016; qpts[160] = 0.59656499562101696; qpts[161] = 0.134478334792994016; qwts[53] = 0.00610485610675179904; + qpts[162] = 0.134478334792994016; qpts[163] = 0.134478334792994016; qpts[164] = 0.59656499562101696; qwts[54] = 0.00610485610675179904; + qpts[165] = 0.134478334792994016; qpts[166] = 0.134478334792994016; qpts[167] = 0.134478334792994016; qwts[55] = 0.00610485610675179904; + break; + } + // clang-format on + +} + +MeshQuadratureRule::MeshQuadratureRule(uint32_t q, bool compact) { + + if (q > 6) { + std::cout << "error: gauss_legendre_rule only supports up to q=6" << std::endl; + exit(1); + } + + type = QuadratureRuleType::UniformStructured; + + edge.compact = false; + edge.points = nd::array({q, 1}); + edge.weights = nd::array({q}); + gauss_legendre_segment_rule(q, edge.points.data(), edge.weights.data()); + + tri.compact = false; + tri.points = nd::array({(q * (q + 1)) / 2, 2}); + tri.weights = nd::array({(q * (q + 1)) / 2}); + gauss_legendre_triangle_rule(q, tri.points.data(), tri.weights.data()); + + tet.compact = false; + tet.points = nd::array({(q * (q + 1) * (q + 2)) / 6, 3}); + tet.weights = nd::array({(q * (q + 1) * (q + 2)) / 6}); + gauss_legendre_tetrahedron_rule(q, tet.points.data(), tet.weights.data()); + +//////////////////////////////////////////////////////////////////////////////////// + + if (compact) { + // note: quadrilaterals and hexahedra are treated differently here, + // they only store a 1D quadrature rule, and the + // cartesian-product structure is implied + quad.compact = true; + quad.points = nd::array({q, 1}); + quad.weights = nd::array({q}); + gauss_legendre_segment_rule(q, quad.points.data(), quad.weights.data()); + + hex.compact = true; + hex.points = nd::array({q, 1}); + hex.weights = nd::array({q}); + gauss_legendre_segment_rule(q, hex.points.data(), hex.weights.data()); + } else { + quad.compact = false; + quad.points = nd::array({q * q, 2}); + quad.weights = nd::array({q * q}); + uint32_t count = 0; + for (uint32_t j = 0; j < q; j++) { + for (uint32_t i = 0; i < q; i++) { + quad.points(count, 0) = edge.points(i, 0); + quad.points(count, 1) = edge.points(j, 0); + quad.weights(count) = edge.weights(i) * edge.weights(j); + } + } + + hex.compact = false; + hex.points = nd::array({q * q * q, 3}); + hex.weights = nd::array({q * q * q}); + count = 0; + for (uint32_t k = 0; k < q; k++) { + for (uint32_t j = 0; j < q; j++) { + for (uint32_t i = 0; i < q; i++) { + hex.points(count, 0) = edge.points(i, 0); + hex.points(count, 1) = edge.points(j, 0); + hex.points(count, 2) = edge.points(k, 0); + hex.weights(count) = edge.weights(i) * edge.weights(j) * edge.weights(k); + } + } + } + + } + +//////////////////////////////////////////////////////////////////////////////////// + +} + +GeometryInfo qpts_per_geom(const MeshQuadratureRule & qrule) { + return GeometryInfo { + 0, + qrule.edge.points.shape[0], + qrule.tri.points.shape[0], + qrule.quad.points.shape[0] * qrule.quad.points.shape[0], + qrule.tet.points.shape[0], + qrule.hex.points.shape[0] * qrule.hex.points.shape[0] * qrule.hex.points.shape[0] + }; +} + +GeometryInfo qpts_per_geom(const MeshQuadratureRule & qrule, int dim) { + return GeometryInfo { + 0, + (dim == 1) * qrule.edge.points.shape[0], + (dim == 2) * qrule.tri.points.shape[0], + (dim == 2) * qrule.quad.points.shape[0] * qrule.quad.points.shape[0], + (dim == 3) * qrule.tet.points.shape[0], + (dim == 3) * qrule.hex.points.shape[0] * qrule.hex.points.shape[0] * qrule.hex.points.shape[0] + }; +} + +} // namespace refactor diff --git a/src/serac/numerics/refactor/quadrature.hpp b/src/serac/numerics/refactor/quadrature.hpp new file mode 100644 index 0000000000..517d2f6e72 --- /dev/null +++ b/src/serac/numerics/refactor/quadrature.hpp @@ -0,0 +1,56 @@ +#pragma once + +#include "serac/numerics/refactor/geometry.hpp" +#include "serac/numerics/refactor/containers/ndarray.hpp" + +namespace refactor { + +struct ElementQuadratureRule { + bool compact; + nd::array points; + nd::array weights; +}; + +enum class QuadratureRuleType { UniformStructured, UniformUnstructured, Nonuniform }; + +struct MeshQuadratureRule : public GeometryData< ElementQuadratureRule >{ + MeshQuadratureRule(uint32_t q, bool compact = true); + QuadratureRuleType type; +}; + +void gauss_legendre_segment_rule(uint32_t q, double * qpts, double * qwts); +void gauss_legendre_triangle_rule(uint32_t q, double * qpts, double * qwts); +void gauss_legendre_tetrahedron_rule(uint32_t q, double * qpts, double * qwts); + +GeometryInfo qpts_per_geom(const MeshQuadratureRule & qrule); +GeometryInfo qpts_per_geom(const MeshQuadratureRule & qrule, int dim); + +namespace impl { + +template < mfem::Geometry::Type geom > +uint32_t qpe(uint32_t q) { + if (geom == mfem::Geometry::SQUARE) { return q * q; } + if (geom == mfem::Geometry::CUBE) { return q * q * q; } + return q; +} + +template < mfem::Geometry::Type geom > +double integration_weight(uint32_t i, const nd::view w) { + uint32_t Q = w.shape[0]; + if constexpr (geom == mfem::Geometry::SQUARE) { + uint32_t ix = i % Q; + uint32_t iy = i / Q; + return w(ix) * w(iy); + } + if constexpr (geom == mfem::Geometry::CUBE) { + uint32_t ix = i % Q; + uint32_t iy = (i % (Q * Q)) / Q; + uint32_t iz = i / (Q * Q); + return w(ix) * w(iy) * w(iz); + } + return w(i); +} + +} + +} From 22b7f602f9be15de5e74ff78d6f7151079d9200d Mon Sep 17 00:00:00 2001 From: Sam Mish Date: Mon, 16 Dec 2024 11:31:19 -0800 Subject: [PATCH 06/15] fix mislabeled namespaces, make integer types more consistent (favoring uint32_t) --- src/serac/numerics/functional/tensor.hpp | 30 ++++++++-- .../numerics/refactor/elements/h1_edge.hpp | 48 +++++++-------- .../refactor/elements/h1_hexahedron.hpp | 8 +-- .../refactor/elements/h1_quadrilateral.hpp | 8 +-- .../refactor/elements/h1_tetrahedron.hpp | 56 ++++++++--------- .../refactor/elements/h1_triangle.hpp | 60 +++++++++---------- .../numerics/refactor/elements/hcurl_edge.hpp | 36 +++++------ .../refactor/elements/hcurl_hexahedron.hpp | 54 ++++++++--------- .../refactor/elements/hcurl_quadrilateral.hpp | 44 +++++++------- .../refactor/elements/hcurl_tetrahedron.hpp | 50 ++++++++-------- .../refactor/elements/hcurl_triangle.hpp | 50 ++++++++-------- .../refactor/elements/tensor_contractions.hpp | 8 +-- .../numerics/refactor/finite_element.hpp | 27 ++++++++- src/serac/numerics/refactor/geometry.hpp | 2 +- src/serac/numerics/refactor/interpolation.cpp | 32 +++++----- src/serac/numerics/refactor/interpolation.hpp | 32 +++++----- 16 files changed, 294 insertions(+), 251 deletions(-) diff --git a/src/serac/numerics/functional/tensor.hpp b/src/serac/numerics/functional/tensor.hpp index 356138592e..f21f13c865 100644 --- a/src/serac/numerics/functional/tensor.hpp +++ b/src/serac/numerics/functional/tensor.hpp @@ -73,19 +73,39 @@ struct tensor { SERAC_HOST_DEVICE constexpr auto& operator[](int i) { return data[i]; } SERAC_HOST_DEVICE constexpr const auto& operator[](int i) const { return data[i]; } - template ::type> + T data[m]; +}; + +template +struct tensor { + + SERAC_HOST_DEVICE constexpr tensor() : data{} {} + SERAC_HOST_DEVICE constexpr tensor(T value) : data(value) {} + + template + SERAC_HOST_DEVICE constexpr auto& operator()(i_type) + { + return data; + } + template + SERAC_HOST_DEVICE constexpr auto& operator()(i_type) const + { + return data; + } + SERAC_HOST_DEVICE constexpr auto& operator[](int) { return data; } + SERAC_HOST_DEVICE constexpr const auto& operator[](int) const { return data; } + SERAC_HOST_DEVICE constexpr operator T() { - return data[0]; + return data; } - template ::type> SERAC_HOST_DEVICE constexpr operator T() const { - return data[0]; + return data; } - T data[m]; + T data; }; /// @endcond diff --git a/src/serac/numerics/refactor/elements/h1_edge.hpp b/src/serac/numerics/refactor/elements/h1_edge.hpp index 13bb3a336a..685756dd83 100644 --- a/src/serac/numerics/refactor/elements/h1_edge.hpp +++ b/src/serac/numerics/refactor/elements/h1_edge.hpp @@ -56,7 +56,7 @@ struct FiniteElement < mfem::Geometry::SEGMENT, Family::H1 >{ return shape_function_gradient(xi, i); } - SERAC_HOST_DEVICE uint32_t batch_interpolation_scratch_space(nd::view xi) const { + SERAC_HOST_DEVICE uint32_t batch_interpolation_scratch_space([[maybe_unused]] nd::view xi) const { return 0; } @@ -72,19 +72,19 @@ struct FiniteElement < mfem::Geometry::SEGMENT, Family::H1 >{ nd::array< double, 2 > evaluate_shape_function_gradients(nd::view xi) const { uint32_t q = xi.shape[0]; nd::array shape_fn_grads({q, num_nodes()}); - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { GaussLobattoInterpolationDerivative(xi(i, 0), p + 1, &shape_fn_grads(i, 0)); } return shape_fn_grads; } SERAC_HOST_DEVICE void interpolate(nd::view values_q, nd::view values_e, nd::view shape_fns, double * /*buffer*/) const { - int nnodes = num_nodes(); - int nqpts = values_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = values_q.shape[0]; - for (int q = 0; q < nqpts; q++) { + for (uint32_t q = 0; q < nqpts; q++) { double sum = 0.0; - for (int i = 0; i < nnodes; i++) { + for (uint32_t i = 0; i < nnodes; i++) { sum += shape_fns(q, i) * values_e(i); } values_q(q) = sum; @@ -92,11 +92,11 @@ struct FiniteElement < mfem::Geometry::SEGMENT, Family::H1 >{ } SERAC_HOST_DEVICE void gradient(nd::view gradients_q, nd::view values_e, nd::view shape_fn_grads, double * /*buffer*/) const { - int nnodes = num_nodes(); - int nqpts = gradients_q.shape[0]; - for (int j = 0; j < nqpts; j++) { + uint32_t nnodes = num_nodes(); + uint32_t nqpts = gradients_q.shape[0]; + for (uint32_t j = 0; j < nqpts; j++) { double sum = 0.0; - for (int i = 0; i < nnodes; i++) { + for (uint32_t i = 0; i < nnodes; i++) { sum += values_e(i) * shape_fn_grads(j, i); } gradients_q(j) = sum; @@ -118,12 +118,12 @@ struct FiniteElement < mfem::Geometry::SEGMENT, Family::H1 >{ } SERAC_HOST_DEVICE void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fn, double * /*buffer*/) const { - int nnodes = num_nodes(); - int nqpts = source_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = source_q.shape[0]; - for (int i = 0; i < nnodes; i++) { + for (uint32_t i = 0; i < nnodes; i++) { double sum = 0.0; - for (int q = 0; q < nqpts; q++) { + for (uint32_t q = 0; q < nqpts; q++) { sum += shape_fn(q, i) * source_q(q); } residual_e(i) = sum; @@ -145,11 +145,11 @@ struct FiniteElement < mfem::Geometry::SEGMENT, Family::H1 >{ } SERAC_HOST_DEVICE void integrate_flux(nd::view output_e, nd::view flux_q, nd::view shape_fn_grads, double * /*buffer*/) const { - int nnodes = num_nodes(); - int nqpts = flux_q.shape[0]; - for (int i = 0; i < nnodes; i++) { + uint32_t nnodes = num_nodes(); + uint32_t nqpts = flux_q.shape[0]; + for (uint32_t i = 0; i < nnodes; i++) { double sum = 0.0; - for (int q = 0; q < nqpts; q++) { + for (uint32_t q = 0; q < nqpts; q++) { sum += shape_fn_grads(q, i) * flux_q(q); } output_e(i) = sum; @@ -158,11 +158,11 @@ struct FiniteElement < mfem::Geometry::SEGMENT, Family::H1 >{ #ifdef __CUDACC__ __device__ void cuda_gradient(nd::view gradients_q, nd::view values_e, nd::view shape_fn_grads, double * /*buffer*/) const { - int nnodes = num_nodes(); - int nqpts = gradients_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = gradients_q.shape[0]; for (int j = threadIdx.x; j < nqpts; j += blockDim.x) { double sum = 0.0; - for (int i = 0; i < nnodes; i++) { + for (uint32_t i = 0; i < nnodes; i++) { sum += values_e(i) * shape_fn_grads(j, i); } gradients_q(j) = sum; @@ -170,12 +170,12 @@ struct FiniteElement < mfem::Geometry::SEGMENT, Family::H1 >{ } __device__ void cuda_integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fn_grads, double * /*buffer*/) const { - int nnodes = num_nodes(); - int nqpts = flux_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = flux_q.shape[0]; for (int i = threadIdx.x; i < nnodes; i += blockDim.x) { double sum = 0.0; - for (int q = 0; q < nqpts; q++) { + for (uint32_t q = 0; q < nqpts; q++) { sum += shape_fn_grads(q, i) * flux_q(q); } residual_e(i) = sum; diff --git a/src/serac/numerics/refactor/elements/h1_hexahedron.hpp b/src/serac/numerics/refactor/elements/h1_hexahedron.hpp index dde4f5c388..ff386c3782 100644 --- a/src/serac/numerics/refactor/elements/h1_hexahedron.hpp +++ b/src/serac/numerics/refactor/elements/h1_hexahedron.hpp @@ -96,7 +96,7 @@ struct FiniteElement { nd::array< double, 3 > evaluate_shape_functions(nd::view xi) const { uint32_t q = xi.shape[0]; nd::array buffer({1, q, p+1}); - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { GaussLobattoInterpolation(xi(i, 0), p+1, &buffer(0, i, 0)); } return buffer; @@ -122,7 +122,7 @@ struct FiniteElement { nd::array< double, 3 > evaluate_shape_function_gradients(nd::view xi) const { uint32_t q = xi.shape[0]; nd::array shape_fn_grads({2, q, p+1}); - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { GaussLobattoInterpolation(xi(i, 0), p+1, &shape_fn_grads(0, i, 0)); GaussLobattoInterpolationDerivative(xi(i, 0), p+1, &shape_fn_grads(1, i, 0)); } @@ -169,7 +169,7 @@ struct FiniteElement { uint32_t q = xi.shape[0]; nd::array buffer({p+1, q}); nd::array tmp({p+1}); - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { GaussLobattoInterpolation(xi(i, 0), p+1, &tmp(0)); for (int j = 0; j < p+1; j++) { buffer(j, i) = tmp(j) * weights(i); @@ -206,7 +206,7 @@ struct FiniteElement { uint32_t q = xi.shape[0]; nd::array buffer({2, p+1, q}); nd::array tmp({p+1}); - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { GaussLobattoInterpolation(xi(i, 0), p+1, &tmp(0)); for (int j = 0; j < p+1; j++) { buffer(0, j, i) = tmp(j) * weights(i); diff --git a/src/serac/numerics/refactor/elements/h1_quadrilateral.hpp b/src/serac/numerics/refactor/elements/h1_quadrilateral.hpp index 4ef71e7ca1..f35b0b5935 100644 --- a/src/serac/numerics/refactor/elements/h1_quadrilateral.hpp +++ b/src/serac/numerics/refactor/elements/h1_quadrilateral.hpp @@ -106,7 +106,7 @@ struct FiniteElement { nd::array< double, 2 > evaluate_shape_functions(nd::view xi) const { uint32_t q = xi.shape[0]; nd::array shape_fns({q, p+1}); - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { GaussLobattoInterpolation(xi(i, 0), p + 1, &shape_fns(i, 0)); } return shape_fns; @@ -129,7 +129,7 @@ struct FiniteElement { nd::array< double, 3 > evaluate_shape_function_gradients(nd::view xi) const { uint32_t q = xi.shape[0]; nd::array shape_fn_grads({2, q, p+1}); - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { GaussLobattoInterpolation(xi(i,0), p+1, &shape_fn_grads(0, i, 0)); GaussLobattoInterpolationDerivative(xi(i,0), p+1, &shape_fn_grads(1, i, 0)); } @@ -166,7 +166,7 @@ struct FiniteElement { uint32_t q = xi.shape[0]; nd::array buffer({p+1, q}); nd::array tmp({p+1}); - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { GaussLobattoInterpolation(xi(i, 0), p+1, &tmp(0)); for (int j = 0; j < p+1; j++) { buffer(j, i) = tmp(j) * weights(i); @@ -196,7 +196,7 @@ struct FiniteElement { uint32_t q = xi.shape[0]; nd::array buffer({2, p+1, q}); nd::array tmp({p+1}); - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { GaussLobattoInterpolation(xi(i, 0), p+1, &tmp(0)); for (int j = 0; j < p+1; j++) { buffer(0, j, i) = tmp(j) * weights(i); diff --git a/src/serac/numerics/refactor/elements/h1_tetrahedron.hpp b/src/serac/numerics/refactor/elements/h1_tetrahedron.hpp index a96cc3602c..9a40768380 100644 --- a/src/serac/numerics/refactor/elements/h1_tetrahedron.hpp +++ b/src/serac/numerics/refactor/elements/h1_tetrahedron.hpp @@ -117,7 +117,7 @@ struct FiniteElement { double interpolate(vec3 xi, double * values) const { double interpolated_value = 0.0; - for (int i = 0; i < num_nodes(); i++) { + for (uint32_t i = 0; i < num_nodes(); i++) { interpolated_value += values[i] * shape_function(xi, i); } return interpolated_value; @@ -125,7 +125,7 @@ struct FiniteElement { vec3 gradient(vec3 xi, double * values) const { vec3 interpolated_gradient{}; - for (int i = 0; i < num_nodes(); i++) { + for (uint32_t i = 0; i < num_nodes(); i++) { interpolated_gradient += values[i] * shape_function_gradient(xi, i); } return interpolated_gradient; @@ -138,7 +138,7 @@ struct FiniteElement { nd::array< double, 2 > evaluate_shape_functions(nd::view xi) const { uint32_t q = xi.shape[0]; nd::array shape_fns({q, num_nodes()}); - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { GaussLobattoInterpolationTetrahedron(&xi(i, 0), p, &shape_fns(i, 0)); } return shape_fns; @@ -147,19 +147,19 @@ struct FiniteElement { nd::array< double, 3 > evaluate_shape_function_gradients(nd::view xi) const { uint32_t q = xi.shape[0]; nd::array shape_fn_grads({q, num_nodes(), dim}); - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { GaussLobattoInterpolationDerivativeTetrahedron(&xi(i, 0), p, &shape_fn_grads(i, 0, 0)); } return shape_fn_grads; } void interpolate(nd::view values_q, nd::view values_e, nd::view shape_fns, double * /*buffer*/) const { - int nnodes = num_nodes(); - int nqpts = values_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = values_q.shape[0]; - for (int q = 0; q < nqpts; q++) { + for (uint32_t q = 0; q < nqpts; q++) { double sum = 0.0; - for (int i = 0; i < nnodes; i++) { + for (uint32_t i = 0; i < nnodes; i++) { sum += shape_fns(q, i) * values_e(i); } values_q(q) = sum; @@ -167,12 +167,12 @@ struct FiniteElement { } void gradient(nd::view gradients_q, nd::view values_e, nd::view shape_fn_grads, double * /*buffer*/) const { - int nnodes = num_nodes(); - int nqpts = gradients_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = gradients_q.shape[0]; - for (int j = 0; j < nqpts; j++) { + for (uint32_t j = 0; j < nqpts; j++) { grad_type sum{}; - for (int i = 0; i < nnodes; i++) { + for (uint32_t i = 0; i < nnodes; i++) { sum[0] += values_e(i) * shape_fn_grads(j, i, 0); sum[1] += values_e(i) * shape_fn_grads(j, i, 1); sum[2] += values_e(i) * shape_fn_grads(j, i, 2); @@ -187,7 +187,7 @@ struct FiniteElement { uint32_t nnodes = num_nodes(); uint32_t q = xi.shape[0]; nd::array shape_fns({q, nnodes}); - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { GaussLobattoInterpolationTetrahedron(&xi(i, 0), p, &shape_fns(i, 0)); for (int j = 0; j < nnodes; j++) { shape_fns(i, j) = shape_fns(i, j) * weights(i); @@ -197,12 +197,12 @@ struct FiniteElement { } SERAC_HOST_DEVICE void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fn, double * /*buffer*/) const { - int nnodes = num_nodes(); - int nqpts = source_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = source_q.shape[0]; - for (int i = 0; i < nnodes; i++) { + for (uint32_t i = 0; i < nnodes; i++) { double sum = 0.0; - for (int q = 0; q < nqpts; q++) { + for (uint32_t q = 0; q < nqpts; q++) { sum += shape_fn(q, i) * source_q(q); } residual_e(i) = sum; @@ -214,7 +214,7 @@ struct FiniteElement { uint32_t nnodes = num_nodes(); uint32_t q = xi.shape[0]; nd::array shape_fn_grads({q, nnodes, dim}); - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { GaussLobattoInterpolationDerivativeTetrahedron(&xi(i, 0), p, &shape_fn_grads(i, 0, 0)); for (int j = 0; j < nnodes; j++) { shape_fn_grads(i, j, 0) = shape_fn_grads(i, j, 0) * weights(i); @@ -227,12 +227,12 @@ struct FiniteElement { } void integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fn_grads, double * /* buffer */) const { - int nnodes = num_nodes(); - int nqpts = flux_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = flux_q.shape[0]; - for (int i = 0; i < nnodes; i++) { + for (uint32_t i = 0; i < nnodes; i++) { double sum = 0.0; - for (int q = 0; q < nqpts; q++) { + for (uint32_t q = 0; q < nqpts; q++) { for (int d = 0; d < dim; d++) { sum += shape_fn_grads(q, i, d) * flux_q(q)[d]; } @@ -243,12 +243,12 @@ struct FiniteElement { #ifdef __CUDACC__ __device__ void cuda_gradient(nd::view gradients_q, nd::view values_e, nd::view shape_fn_grads, double * /*buffer*/) const { - int nnodes = num_nodes(); - int nqpts = gradients_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = gradients_q.shape[0]; for (int j = threadIdx.x; j < nqpts; j += blockDim.x) { grad_type sum{}; - for (int i = 0; i < nnodes; i++) { + for (uint32_t i = 0; i < nnodes; i++) { sum[0] += values_e(i) * shape_fn_grads(j, i, 0); sum[1] += values_e(i) * shape_fn_grads(j, i, 1); sum[2] += values_e(i) * shape_fn_grads(j, i, 2); @@ -258,12 +258,12 @@ struct FiniteElement { } __device__ void cuda_integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fn_grads, double * /*buffer*/) const { - int nnodes = num_nodes(); - int nqpts = flux_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = flux_q.shape[0]; for (int i = threadIdx.x; i < nnodes; i += blockDim.x) { double sum = 0.0; - for (int q = 0; q < nqpts; q++) { + for (uint32_t q = 0; q < nqpts; q++) { for (int d = 0; d < dim; d++) { sum += shape_fn_grads(q, i, d) * flux_q(q)[d]; } diff --git a/src/serac/numerics/refactor/elements/h1_triangle.hpp b/src/serac/numerics/refactor/elements/h1_triangle.hpp index 63b6697e85..70b6809541 100644 --- a/src/serac/numerics/refactor/elements/h1_triangle.hpp +++ b/src/serac/numerics/refactor/elements/h1_triangle.hpp @@ -87,7 +87,7 @@ struct FiniteElement { double interpolate(vec2 xi, const double * values) const { double interpolated_value = 0.0; - for (int i = 0; i < num_nodes(); i++) { + for (uint32_t i = 0; i < num_nodes(); i++) { interpolated_value += values[i] * shape_function(xi, i); } return interpolated_value; @@ -95,20 +95,20 @@ struct FiniteElement { vec2 gradient(vec2 xi, const double * values) const { vec2 interpolated_gradient = {0.0, 0.0}; - for (int i = 0; i < num_nodes(); i++) { + for (uint32_t i = 0; i < num_nodes(); i++) { interpolated_gradient += values[i] * shape_function_gradient(xi, i); } return interpolated_gradient; } - SERAC_HOST_DEVICE uint32_t batch_interpolation_scratch_space(nd::view xi) const { + SERAC_HOST_DEVICE uint32_t batch_interpolation_scratch_space(nd::view) const { return 0; } nd::array< double, 2 > evaluate_shape_functions(nd::view xi) const { uint32_t q = xi.shape[0]; nd::array shape_fns({q, num_nodes()}); - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { GaussLobattoInterpolationTriangle(&xi(i, 0), p, &shape_fns(i, 0)); } return shape_fns; @@ -117,19 +117,19 @@ struct FiniteElement { nd::array< double, 3 > evaluate_shape_function_gradients(nd::view xi) const { uint32_t q = xi.shape[0]; nd::array shape_fn_grads({q, num_nodes(), dim}); - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { GaussLobattoInterpolationDerivativeTriangle(&xi(i, 0), p, &shape_fn_grads(i, 0, 0)); } return shape_fn_grads; } void interpolate(nd::view values_q, nd::view values_e, nd::view shape_fns, double * /*buffer*/) const { - int nnodes = num_nodes(); - int nqpts = values_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = values_q.shape[0]; - for (int q = 0; q < nqpts; q++) { + for (uint32_t q = 0; q < nqpts; q++) { double sum = 0.0; - for (int i = 0; i < nnodes; i++) { + for (uint32_t i = 0; i < nnodes; i++) { sum += shape_fns(q, i) * values_e(i); } values_q(q) = sum; @@ -137,15 +137,15 @@ struct FiniteElement { } void gradient(nd::view gradients_q, nd::view values_e, nd::view shape_fn_grads, double * /*buffer*/) const { - int nnodes = num_nodes(); - int nqpts = gradients_q.shape[0]; - for (int j = 0; j < nqpts; j++) { + uint32_t nnodes = num_nodes(); + uint32_t nqpts = gradients_q.shape[0]; + for (uint32_t q = 0; q < nqpts; q++) { grad_type sum{}; - for (int i = 0; i < nnodes; i++) { - sum[0] += values_e(i) * shape_fn_grads(j, i, 0); - sum[1] += values_e(i) * shape_fn_grads(j, i, 1); + for (uint32_t i = 0; i < nnodes; i++) { + sum[0] += values_e(i) * shape_fn_grads(q, i, 0); + sum[1] += values_e(i) * shape_fn_grads(q, i, 1); } - gradients_q(j) = sum; + gradients_q(q) = sum; } } @@ -164,12 +164,12 @@ struct FiniteElement { } SERAC_HOST_DEVICE void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fn, double * /*buffer*/) const { - int nnodes = num_nodes(); - int nqpts = source_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = source_q.shape[0]; - for (int i = 0; i < nnodes; i++) { + for (uint32_t i = 0; i < nnodes; i++) { double sum = 0.0; - for (int q = 0; q < nqpts; q++) { + for (uint32_t q = 0; q < nqpts; q++) { sum += shape_fn(q, i) * source_q(q); } residual_e(i) = sum; @@ -193,12 +193,12 @@ struct FiniteElement { } void integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fn_grads, double * /*buffer*/) const { - int nnodes = num_nodes(); - int nqpts = flux_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = flux_q.shape[0]; - for (int i = 0; i < nnodes; i++) { + for (uint32_t i = 0; i < nnodes; i++) { double sum = 0.0; - for (int q = 0; q < nqpts; q++) { + for (uint32_t q = 0; q < nqpts; q++) { for (int d = 0; d < dim; d++) { sum += shape_fn_grads(q, i, d) * flux_q(q)[d]; } @@ -209,11 +209,11 @@ struct FiniteElement { #ifdef __CUDACC__ __device__ void cuda_gradient(nd::view gradients_q, nd::view values_e, nd::view shape_fn_grads, double * /*buffer*/) const { - int nnodes = num_nodes(); - int nqpts = gradients_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = gradients_q.shape[0]; for (int j = threadIdx.x; j < nqpts; j += blockDim.x) { grad_type sum{}; - for (int i = 0; i < nnodes; i++) { + for (uint32_t i = 0; i < nnodes; i++) { sum[0] += values_e(i) * shape_fn_grads(j, i, 0); sum[1] += values_e(i) * shape_fn_grads(j, i, 1); } @@ -222,12 +222,12 @@ struct FiniteElement { } __device__ void cuda_integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fn_grads, double * /*buffer*/) const { - int nnodes = num_nodes(); - int nqpts = flux_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = flux_q.shape[0]; for (int i = threadIdx.x; i < nnodes; i += blockDim.x) { double sum = 0.0; - for (int q = 0; q < nqpts; q++) { + for (uint32_t q = 0; q < nqpts; q++) { for (int d = 0; d < dim; d++) { sum += shape_fn_grads(q, i, d) * flux_q(q)[d]; } diff --git a/src/serac/numerics/refactor/elements/hcurl_edge.hpp b/src/serac/numerics/refactor/elements/hcurl_edge.hpp index f351088a19..9cfd7c2561 100644 --- a/src/serac/numerics/refactor/elements/hcurl_edge.hpp +++ b/src/serac/numerics/refactor/elements/hcurl_edge.hpp @@ -100,12 +100,12 @@ struct FiniteElement < mfem::Geometry::SEGMENT, Family::Hcurl >{ } void interpolate(nd::view values_q, nd::view values_e, nd::view shape_fns, double * /*buffer*/) { - int nnodes = num_nodes(); - int nqpts = values_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = values_q.shape[0]; - for (int q = 0; q < nqpts; q++) { + for (uint32_t q = 0; q < nqpts; q++) { double sum = 0.0; - for (int i = 0; i < nnodes; i++) { + for (uint32_t i = 0; i < nnodes; i++) { sum += shape_fns(q, i) * values_e(i); } values_q(q) = sum; @@ -115,7 +115,7 @@ struct FiniteElement < mfem::Geometry::SEGMENT, Family::Hcurl >{ nd::array< double > evaluate_shape_function_curls(nd::view xi) { uint32_t q = xi.shape[0]; nd::array buffer({q * p}); - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { GaussLegendreInterpolation(xi(i, 0), p, &buffer(p * i)); } return buffer; @@ -152,7 +152,7 @@ struct FiniteElement < mfem::Geometry::SEGMENT, Family::Hcurl >{ nd::array< double, 2 > evaluate_weighted_shape_functions(nd::view xi, nd::view weights) { uint32_t q = xi.shape[0]; nd::array shape_fns({q, num_nodes()}); - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { for (int j = 0; j < num_nodes(); j++) { shape_fns(i, j) = shape_function(xi(i, 0), j) * weights(i); } @@ -161,12 +161,12 @@ struct FiniteElement < mfem::Geometry::SEGMENT, Family::Hcurl >{ } SERAC_HOST_DEVICE void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fn, double * /*buffer*/) const { - int nnodes = num_nodes(); - int nqpts = source_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = source_q.shape[0]; - for (int i = 0; i < nnodes; i++) { + for (uint32_t i = 0; i < nnodes; i++) { double sum = 0.0; - for (int q = 0; q < nqpts; q++) { + for (uint32_t q = 0; q < nqpts; q++) { sum += shape_fn(q, i) * source_q(q); } residual_e(i) = sum; @@ -176,7 +176,7 @@ struct FiniteElement < mfem::Geometry::SEGMENT, Family::Hcurl >{ nd::array< double, 2 > evaluate_weighted_shape_function_curls(nd::view xi, nd::view weights) { uint32_t q = xi.shape[0]; nd::array shape_fns({q, num_nodes()}); - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { for (int j = 0; j < num_nodes(); j++) { shape_fns(i, j) = shape_function_curl(xi(i, 0), j) * weights(i); } @@ -185,12 +185,12 @@ struct FiniteElement < mfem::Geometry::SEGMENT, Family::Hcurl >{ } SERAC_HOST_DEVICE void integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fn, double * /*buffer*/) const { - int nnodes = num_nodes(); - int nqpts = flux_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = flux_q.shape[0]; - for (int i = 0; i < nnodes; i++) { + for (uint32_t i = 0; i < nnodes; i++) { double sum = 0.0; - for (int q = 0; q < nqpts; q++) { + for (uint32_t q = 0; q < nqpts; q++) { sum += shape_fn(q, i) * flux_q(q); } residual_e(i) = sum; @@ -199,12 +199,12 @@ struct FiniteElement < mfem::Geometry::SEGMENT, Family::Hcurl >{ #ifdef __CUDACC__ __device__ void cuda_integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fn_curl, double * /*buffer*/) const { - int nnodes = num_nodes(); - int nqpts = flux_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = flux_q.shape[0]; for (int i = threadIdx.x; i < nnodes; i += blockDim.x) { double sum = 0.0; - for (int q = 0; q < nqpts; q++) { + for (uint32_t q = 0; q < nqpts; q++) { sum += shape_fn_curl(q, i) * flux_q(q); } residual_e(i) = sum; diff --git a/src/serac/numerics/refactor/elements/hcurl_hexahedron.hpp b/src/serac/numerics/refactor/elements/hcurl_hexahedron.hpp index 599f9f7976..fe7d9dc666 100644 --- a/src/serac/numerics/refactor/elements/hcurl_hexahedron.hpp +++ b/src/serac/numerics/refactor/elements/hcurl_hexahedron.hpp @@ -646,7 +646,7 @@ struct FiniteElement { vec3 interpolate(vec3 xi, const double * values) { vec3 interpolated_value{}; - for (int i = 0; i < num_nodes(); i++) { + for (uint32_t i = 0; i < num_nodes(); i++) { interpolated_value += values[i] * shape_function(xi, i); } return interpolated_value; @@ -654,7 +654,7 @@ struct FiniteElement { vec3 curl(vec3 xi, const double * values) { vec3 interpolated_curl{}; - for (int i = 0; i < num_nodes(); i++) { + for (uint32_t i = 0; i < num_nodes(); i++) { interpolated_curl += values[i] * shape_function_curl(xi, i); } return interpolated_curl; @@ -672,7 +672,7 @@ struct FiniteElement { nd::array< double > evaluate_shape_functions(nd::view xi) { uint32_t q = xi.shape[0]; nd::array buffer({q * (2 * p + 1)}); - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { GaussLegendreInterpolation(xi(i, 0), p, &buffer(p * i)); GaussLobattoInterpolation(xi(i, 0), p+1, &buffer(q * p + p * i)); } @@ -702,7 +702,7 @@ struct FiniteElement { nd::array< double > evaluate_shape_function_curls(nd::view xi) { uint32_t q = xi.shape[0]; nd::array buffer({q * (3 * p + 2)}); - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { GaussLegendreInterpolation(xi(i, 0), p, &buffer(p * i)); GaussLobattoInterpolation(xi(i, 0), p+1, &buffer(q * p + p * i)); GaussLobattoInterpolationDerivative(xi(i, 0), p+1, &buffer(q * p + p * i)); @@ -739,7 +739,7 @@ struct FiniteElement { uint32_t qcount = 0; for (int k = 0; k < q; k++) { for (int j = 0; j < q; j++) { - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { vec3 xi_ijk = vec3{xi(i, 0), xi(j, 0), xi(k, 0)}; for (int l = 0; l < num_nodes(); l++) { vec3 phi = shape_function(xi_ijk, l); @@ -755,12 +755,12 @@ struct FiniteElement { } void interpolate(nd::view values_q, nd::view values_e, nd::view shape_fns, double * /*buffer*/) { - int nnodes = num_nodes(); - int nqpts = values_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = values_q.shape[0]; - for (int q = 0; q < nqpts; q++) { + for (uint32_t q = 0; q < nqpts; q++) { value_type sum{}; - for (int i = 0; i < nnodes; i++) { + for (uint32_t i = 0; i < nnodes; i++) { for (int c = 0; c < 3; c++) { sum[c] += shape_fns(q, i, c) * values_e(i); } @@ -775,7 +775,7 @@ struct FiniteElement { uint32_t qcount = 0; for (int k = 0; k < q; k++) { for (int j = 0; j < q; j++) { - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { vec3 xi_ijk = vec3{xi(i, 0), xi(j, 0), xi(k, 0)}; for (int l = 0; l < num_nodes(); l++) { vec3 curl_phi = shape_function_curl(xi_ijk, l); @@ -791,12 +791,12 @@ struct FiniteElement { } void curl(nd::view values_q, nd::view values_e, nd::view shape_fn_curls, double * /*buffer*/) { - int nnodes = num_nodes(); - int nqpts = values_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = values_q.shape[0]; - for (int q = 0; q < nqpts; q++) { + for (uint32_t q = 0; q < nqpts; q++) { derivative_type sum{}; - for (int i = 0; i < nnodes; i++) { + for (uint32_t i = 0; i < nnodes; i++) { for (int c = 0; c < 3; c++) { sum[c] += shape_fn_curls(q, i, c) * values_e(i); } @@ -811,7 +811,7 @@ struct FiniteElement { uint32_t qcount = 0; for (int k = 0; k < q; k++) { for (int j = 0; j < q; j++) { - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { vec3 xi_ijk = vec3{xi(i, 0), xi(j, 0), xi(k, 0)}; for (int l = 0; l < num_nodes(); l++) { vec3 phi = shape_function(xi_ijk, l); @@ -827,12 +827,12 @@ struct FiniteElement { } SERAC_HOST_DEVICE void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fn, double * /* buffer */) const { - int nnodes = num_nodes(); - int nqpts = source_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = source_q.shape[0]; - for (int i = 0; i < nnodes; i++) { + for (uint32_t i = 0; i < nnodes; i++) { double sum = 0.0; - for (int q = 0; q < nqpts; q++) { + for (uint32_t q = 0; q < nqpts; q++) { for (int j = 0; j < dim; j++) { sum += shape_fn(q, i, j) * source_q(q)[j]; } @@ -847,7 +847,7 @@ struct FiniteElement { uint32_t qcount = 0; for (int k = 0; k < q; k++) { for (int j = 0; j < q; j++) { - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { vec3 xi_ijk = vec3{xi(i, 0), xi(j, 0), xi(k, 0)}; for (int l = 0; l < num_nodes(); l++) { vec3 dphi = shape_function_curl(xi_ijk, l); @@ -863,12 +863,12 @@ struct FiniteElement { } void integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fn_curl, double * /*buffer*/) const { - int nnodes = num_nodes(); - int nqpts = flux_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = flux_q.shape[0]; - for (int i = 0; i < nnodes; i++) { + for (uint32_t i = 0; i < nnodes; i++) { double sum = 0.0; - for (int q = 0; q < nqpts; q++) { + for (uint32_t q = 0; q < nqpts; q++) { for (int j = 0; j < dim; j++) { sum += shape_fn_curl(q, i, j) * flux_q(q)[j]; } @@ -879,12 +879,12 @@ struct FiniteElement { #ifdef __CUDACC__ __device__ void cuda_integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fn_curl, double * /*buffer*/) const { - int nnodes = num_nodes(); - int nqpts = flux_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = flux_q.shape[0]; for (int i = threadIdx.x; i < nnodes; i += blockDim.x) { double sum = 0.0; - for (int q = 0; q < nqpts; q++) { + for (uint32_t q = 0; q < nqpts; q++) { for (int d = 0; d < dim; d++) { sum += shape_fn_curl(q, i, d) * flux_q(q)[d]; } diff --git a/src/serac/numerics/refactor/elements/hcurl_quadrilateral.hpp b/src/serac/numerics/refactor/elements/hcurl_quadrilateral.hpp index af871efb69..fb58b543cd 100644 --- a/src/serac/numerics/refactor/elements/hcurl_quadrilateral.hpp +++ b/src/serac/numerics/refactor/elements/hcurl_quadrilateral.hpp @@ -211,7 +211,7 @@ struct FiniteElement { vec2 interpolate(vec2 xi, const double * values) const { vec2 interpolated_value{}; - for (int i = 0; i < num_nodes(); i++) { + for (uint32_t i = 0; i < num_nodes(); i++) { interpolated_value += values[i] * shape_function(xi, i); } return interpolated_value; @@ -219,7 +219,7 @@ struct FiniteElement { vec<1> curl(vec2 xi, const double * values) const { double interpolated_curl = 0.0; - for (int i = 0; i < num_nodes(); i++) { + for (uint32_t i = 0; i < num_nodes(); i++) { interpolated_curl += values[i] * shape_function_curl(xi, i); } return interpolated_curl; @@ -238,7 +238,7 @@ struct FiniteElement { num_entries += q * p; // B1 num_entries += q * (p + 1); // B2 nd::array buffer({num_entries}); - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { GaussLegendreInterpolation(xi(i, 0), p, &buffer(p*i)); GaussLobattoInterpolation(xi(i, 0), p+1, &buffer((p+1)*i + (p*q))); } @@ -275,7 +275,7 @@ struct FiniteElement { nd::array< double, 2 > evaluate_shape_function_curls(nd::view xi) const { uint32_t q = xi.shape[0]; nd::array shape_fns({q * q, num_nodes()}); - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { for (int j = 0; j < q; j++) { vec2 xi_ij = vec2{xi(j, 0), xi(i, 0)}; for (int k = 0; k < num_nodes(); k++) { @@ -287,12 +287,12 @@ struct FiniteElement { } void curl(nd::view values_q, nd::view values_e, nd::view shape_fn_curls, double * /*buffer*/) const { - int nnodes = num_nodes(); - int nqpts = values_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = values_q.shape[0]; - for (int q = 0; q < nqpts; q++) { + for (uint32_t q = 0; q < nqpts; q++) { derivative_type sum = 0.0; - for (int i = 0; i < nnodes; i++) { + for (uint32_t i = 0; i < nnodes; i++) { sum[0] += shape_fn_curls(q, i) * values_e(i); } values_q(q) = sum; @@ -304,7 +304,7 @@ struct FiniteElement { nd::array shape_fns({q * q, num_nodes(), dim}); uint32_t qcount = 0; for (int j = 0; j < q; j++) { - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { vec2 xi_ij = vec2{xi(i, 0), xi(j, 0)}; for (int l = 0; l < num_nodes(); l++) { vec2 phi = shape_function(xi_ij, l); @@ -318,12 +318,12 @@ struct FiniteElement { } SERAC_HOST_DEVICE void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fn, double * /*buffer*/) const { - int nnodes = num_nodes(); - int nqpts = source_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = source_q.shape[0]; - for (int i = 0; i < nnodes; i++) { + for (uint32_t i = 0; i < nnodes; i++) { double sum = 0.0; - for (int q = 0; q < nqpts; q++) { + for (uint32_t q = 0; q < nqpts; q++) { for (int j = 0; j < dim; j++) { sum += shape_fn(q, i, j) * source_q(q)[j]; } @@ -337,7 +337,7 @@ struct FiniteElement { nd::array shape_fns({q * q, num_nodes()}); uint32_t qcount = 0; for (int j = 0; j < q; j++) { - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { vec2 xi_ij = vec2{xi(i, 0), xi(j, 0)}; for (int l = 0; l < num_nodes(); l++) { shape_fns(qcount, l) = shape_function_curl(xi_ij, l) * weights[i] * weights[j]; @@ -349,12 +349,12 @@ struct FiniteElement { } void integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fn_curl, double * /*buffer*/) const { - int nnodes = num_nodes(); - int nqpts = flux_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = flux_q.shape[0]; - for (int i = 0; i < nnodes; i++) { + for (uint32_t i = 0; i < nnodes; i++) { double sum = 0.0; - for (int q = 0; q < nqpts; q++) { + for (uint32_t q = 0; q < nqpts; q++) { sum += shape_fn_curl(q, i) * flux_q(q); } residual_e(i) = sum; @@ -363,12 +363,12 @@ struct FiniteElement { #ifdef __CUDACC__ __device__ void cuda_integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fn_curl, double * /*buffer*/) const { - int nnodes = num_nodes(); - int nqpts = flux_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = flux_q.shape[0]; for (int i = threadIdx.x; i < nnodes; i += blockDim.x) { double sum = 0.0; - for (int q = 0; q < nqpts; q++) { + for (uint32_t q = 0; q < nqpts; q++) { sum += shape_fn_curl(q, i) * flux_q(q); } residual_e(i) = sum; @@ -384,7 +384,7 @@ struct FiniteElement { auto [B1, B2, G2, A1, num_entries] = scan({q*p, q*(p+1), q*(p+1), q*(p+1)}); nd::array buffer({num_entries}); std::cout << num_entries << std::endl; - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { GaussLegendreInterpolation(xi(i, 0), p, &buffer(B1 + p * i)); GaussLobattoInterpolation(xi(i, 0), p+1, &buffer(B2 + (p+1)*i)); GaussLobattoInterpolation(xi(i, 0), p+1, &buffer(G2 + (p+1)*i)); diff --git a/src/serac/numerics/refactor/elements/hcurl_tetrahedron.hpp b/src/serac/numerics/refactor/elements/hcurl_tetrahedron.hpp index 18b7c90063..b351b7bb25 100644 --- a/src/serac/numerics/refactor/elements/hcurl_tetrahedron.hpp +++ b/src/serac/numerics/refactor/elements/hcurl_tetrahedron.hpp @@ -1180,7 +1180,7 @@ struct FiniteElement { constexpr vec3 interpolate(vec3 xi, const double * values) const { vec3 interpolated_value{}; - for (int i = 0; i < num_nodes(); i++) { + for (uint32_t i = 0; i < num_nodes(); i++) { interpolated_value += values[i] * shape_function(xi, i); } return interpolated_value; @@ -1188,7 +1188,7 @@ struct FiniteElement { constexpr vec3 curl(vec3 xi, const double * values) const { vec3 interpolated_curl{}; - for (int i = 0; i < num_nodes(); i++) { + for (uint32_t i = 0; i < num_nodes(); i++) { interpolated_curl += values[i] * shape_function_curl(xi, i); } return interpolated_curl; @@ -1201,7 +1201,7 @@ struct FiniteElement { nd::array< double, 3 > evaluate_shape_functions(nd::view xi) { uint32_t q = xi.shape[0]; nd::array shape_fns({q, num_nodes(), dim}); - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { vec3 xi_i = vec3{xi(i, 0), xi(i, 1), xi(i, 2)}; for (int j = 0; j < num_nodes(); j++) { vec3 phi_j = shape_function(xi_i, j); @@ -1214,12 +1214,12 @@ struct FiniteElement { } void interpolate(nd::view values_q, nd::view values_e, nd::view shape_fns, double * /*buffer*/) { - int nnodes = num_nodes(); - int nqpts = values_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = values_q.shape[0]; - for (int q = 0; q < nqpts; q++) { + for (uint32_t q = 0; q < nqpts; q++) { value_type sum{}; - for (int i = 0; i < nnodes; i++) { + for (uint32_t i = 0; i < nnodes; i++) { for (int j = 0; j < dim; j++) { sum[j] += shape_fns(q, i, j) * values_e(i); } @@ -1231,7 +1231,7 @@ struct FiniteElement { nd::array< double, 3 > evaluate_shape_function_curls(nd::view xi) { uint32_t q = xi.shape[0]; nd::array shape_fns({q, num_nodes(), 3}); - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { vec3 xi_i = vec3{xi(i, 0), xi(i, 1), xi(i, 2)}; for (int j = 0; j < num_nodes(); j++) { vec3 curl_phi_j = shape_function_curl(xi_i, j); @@ -1244,12 +1244,12 @@ struct FiniteElement { } void curl(nd::view values_q, nd::view values_e, nd::view shape_fn_curls, double * /*buffer*/) { - int nnodes = num_nodes(); - int nqpts = values_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = values_q.shape[0]; - for (int q = 0; q < nqpts; q++) { + for (uint32_t q = 0; q < nqpts; q++) { derivative_type sum{}; - for (int i = 0; i < nnodes; i++) { + for (uint32_t i = 0; i < nnodes; i++) { for (int j = 0; j < dim; j++) { sum[j] += shape_fn_curls(q, i, j) * values_e(i); } @@ -1261,7 +1261,7 @@ struct FiniteElement { nd::array< double, 3 > evaluate_weighted_shape_functions(nd::view xi, nd::view weights) const { uint32_t q = xi.shape[0]; nd::array shape_fns({q, num_nodes(), dim}); - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { vec3 xi_i = vec3{xi(i, 0), xi(i, 1), xi(i, 2)}; for (int j = 0; j < num_nodes(); j++) { vec3 phi_j = shape_function(xi_i, j); @@ -1274,12 +1274,12 @@ struct FiniteElement { } SERAC_HOST_DEVICE void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fn, double * /*buffer*/) const { - int nnodes = num_nodes(); - int nqpts = source_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = source_q.shape[0]; - for (int i = 0; i < nnodes; i++) { + for (uint32_t i = 0; i < nnodes; i++) { double sum = 0.0; - for (int q = 0; q < nqpts; q++) { + for (uint32_t q = 0; q < nqpts; q++) { for (int j = 0; j < dim; j++) { sum += shape_fn(q, i, j) * source_q(q)[j]; } @@ -1291,7 +1291,7 @@ struct FiniteElement { nd::array< double, 3 > evaluate_weighted_shape_function_curls(nd::view xi, nd::view weights) const { uint32_t q = xi.shape[0]; nd::array shape_fns({q, num_nodes(), dim}); - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { vec3 xi_i = vec3{xi(i, 0), xi(i, 1), xi(i, 2)}; for (int j = 0; j < num_nodes(); j++) { vec3 dphi_j = shape_function_curl(xi_i, j); @@ -1304,12 +1304,12 @@ struct FiniteElement { } SERAC_HOST_DEVICE void integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fn, double * /*buffer*/) const { - int nnodes = num_nodes(); - int nqpts = flux_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = flux_q.shape[0]; - for (int i = 0; i < nnodes; i++) { + for (uint32_t i = 0; i < nnodes; i++) { double sum = 0.0; - for (int q = 0; q < nqpts; q++) { + for (uint32_t q = 0; q < nqpts; q++) { for (int j = 0; j < dim; j++) { sum += shape_fn(q, i, j) * flux_q(q)[j]; } @@ -1320,12 +1320,12 @@ struct FiniteElement { #ifdef __CUDACC__ __device__ void cuda_integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fn_curl, double * /*buffer*/) const { - int nnodes = num_nodes(); - int nqpts = flux_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = flux_q.shape[0]; for (int i = threadIdx.x; i < nnodes; i += blockDim.x) { double sum = 0.0; - for (int q = 0; q < nqpts; q++) { + for (uint32_t q = 0; q < nqpts; q++) { for (int d = 0; d < dim; d++) { sum += shape_fn_curl(q, i, d) * flux_q(q)[d]; } diff --git a/src/serac/numerics/refactor/elements/hcurl_triangle.hpp b/src/serac/numerics/refactor/elements/hcurl_triangle.hpp index 989b7896c4..b7fadd4892 100644 --- a/src/serac/numerics/refactor/elements/hcurl_triangle.hpp +++ b/src/serac/numerics/refactor/elements/hcurl_triangle.hpp @@ -307,7 +307,7 @@ struct FiniteElement { vec2 interpolate(vec2 xi, const double * values) const { vec2 interpolated_value{}; - for (int i = 0; i < num_nodes(); i++) { + for (uint32_t i = 0; i < num_nodes(); i++) { interpolated_value += values[i] * shape_function(xi, i); } return interpolated_value; @@ -315,7 +315,7 @@ struct FiniteElement { vec1 curl(vec2 xi, const double * values) const { vec1 interpolated_curl = 0.0; - for (int i = 0; i < num_nodes(); i++) { + for (uint32_t i = 0; i < num_nodes(); i++) { interpolated_curl += values[i] * shape_function_curl(xi, i); } return interpolated_curl; @@ -328,7 +328,7 @@ struct FiniteElement { nd::array< double, 3 > evaluate_shape_functions(nd::view xi) const { uint32_t q = xi.shape[0]; nd::array shape_fns({q, num_nodes(), dim}); - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { vec2 xi_i = vec2{xi(i, 0), xi(i, 1)}; for (int j = 0; j < num_nodes(); j++) { vec2 phi_j = shape_function(xi_i, j); @@ -340,12 +340,12 @@ struct FiniteElement { } void interpolate(nd::view values_q, nd::view values_e, nd::view shape_fns, double * /*buffer*/) const { - int nnodes = num_nodes(); - int nqpts = values_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = values_q.shape[0]; - for (int q = 0; q < nqpts; q++) { + for (uint32_t q = 0; q < nqpts; q++) { value_type sum{}; - for (int i = 0; i < nnodes; i++) { + for (uint32_t i = 0; i < nnodes; i++) { for (int j = 0; j < dim; j++) { sum[j] += shape_fns(q, i, j) * values_e(i); } @@ -357,7 +357,7 @@ struct FiniteElement { nd::array< double, 2 > evaluate_shape_function_curls(nd::view xi) const { uint32_t q = xi.shape[0]; nd::array shape_fns({q, num_nodes()}); - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { vec2 xi_i = vec2{xi(i, 0), xi(i, 1)}; for (int j = 0; j < num_nodes(); j++) { shape_fns(i, j) = shape_function_curl(xi_i, j); @@ -367,12 +367,12 @@ struct FiniteElement { } void curl(nd::view values_q, nd::view values_e, nd::view shape_fn_curls, double * /*buffer*/) const { - int nnodes = num_nodes(); - int nqpts = values_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = values_q.shape[0]; - for (int q = 0; q < nqpts; q++) { + for (uint32_t q = 0; q < nqpts; q++) { derivative_type sum{}; - for (int i = 0; i < nnodes; i++) { + for (uint32_t i = 0; i < nnodes; i++) { sum[0] += shape_fn_curls(q, i) * values_e(i); } values_q(q) = sum; @@ -382,7 +382,7 @@ struct FiniteElement { nd::array< double, 3 > evaluate_weighted_shape_functions(nd::view xi, nd::view weights) const { uint32_t q = xi.shape[0]; nd::array shape_fns({q, num_nodes(), dim}); - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { vec2 xi_i = vec2{xi(i, 0), xi(i, 1)}; for (int j = 0; j < num_nodes(); j++) { vec2 phi_j = shape_function(xi_i, j); @@ -394,12 +394,12 @@ struct FiniteElement { } SERAC_HOST_DEVICE void integrate_source(nd::view residual_e, nd::view source_q, nd::view shape_fn, double * /*buffer*/) const { - int nnodes = num_nodes(); - int nqpts = source_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = source_q.shape[0]; - for (int i = 0; i < nnodes; i++) { + for (uint32_t i = 0; i < nnodes; i++) { double sum = 0.0; - for (int q = 0; q < nqpts; q++) { + for (uint32_t q = 0; q < nqpts; q++) { for (int j = 0; j < dim; j++) { sum += shape_fn(q, i, j) * source_q(q)[j]; } @@ -411,7 +411,7 @@ struct FiniteElement { nd::array< double, 2 > evaluate_weighted_shape_function_curls(nd::view xi, nd::view weights) const { uint32_t q = xi.shape[0]; nd::array shape_fns({q, num_nodes()}); - for (int i = 0; i < q; i++) { + for (uint32_t i = 0; i < q; i++) { vec2 xi_i = vec2{xi(i, 0), xi(i, 1)}; for (int j = 0; j < num_nodes(); j++) { shape_fns(i, j) = shape_function_curl(xi_i, j) * weights[i]; @@ -421,12 +421,12 @@ struct FiniteElement { } SERAC_HOST_DEVICE void integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fn, double * /*buffer*/) const { - int nnodes = num_nodes(); - int nqpts = flux_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = flux_q.shape[0]; - for (int i = 0; i < nnodes; i++) { + for (uint32_t i = 0; i < nnodes; i++) { double sum = 0.0; - for (int q = 0; q < nqpts; q++) { + for (uint32_t q = 0; q < nqpts; q++) { sum += shape_fn(q, i) * flux_q(q); } residual_e(i) = sum; @@ -435,12 +435,12 @@ struct FiniteElement { #ifdef __CUDACC__ __device__ void cuda_integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fn_curl, double * /*buffer*/) const { - int nnodes = num_nodes(); - int nqpts = flux_q.shape[0]; + uint32_t nnodes = num_nodes(); + uint32_t nqpts = flux_q.shape[0]; for (int i = threadIdx.x; i < nnodes; i += blockDim.x) { double sum = 0.0; - for (int q = 0; q < nqpts; q++) { + for (uint32_t q = 0; q < nqpts; q++) { sum += shape_fn_curl(q, i) * flux_q(q); } residual_e(i) = sum; diff --git a/src/serac/numerics/refactor/elements/tensor_contractions.hpp b/src/serac/numerics/refactor/elements/tensor_contractions.hpp index 378d2d95e4..5edcd8f5fa 100644 --- a/src/serac/numerics/refactor/elements/tensor_contractions.hpp +++ b/src/serac/numerics/refactor/elements/tensor_contractions.hpp @@ -15,7 +15,7 @@ inline void contract(const nd::view & A, nd::view & B, for (uint32_t i1 = 0; i1 < n1; i1++) { for (uint32_t i2 = 0; i2 < n2; i2++) { double sum = (accumulate) ? C(i0, i1, i2) : 0.0; - for (int j = 0; j < m; j++) { + for (uint32_t j = 0; j < m; j++) { sum += B(i0, j) * A(i1, i2, j); } C(i0, i1, i2) = sum; @@ -35,7 +35,7 @@ inline void _contract(nd::view C, const nd::view & A, for (uint32_t i0 = 0; i0 < n0; i0++) { for (uint32_t i1 = 0; i1 < n1; i1++) { double sum = (accumulate) ? C(i0, i1) : 0.0; - for (int j = 0; j < m; j++) { + for (uint32_t j = 0; j < m; j++) { sum += A(i0, j) * B(i1, j); } C(i0, i1) = sum; @@ -54,7 +54,7 @@ void contract(const nd::view & A, nd::view & B, nd::vi for (uint32_t i0 = 0; i0 < n0; i0++) { for (uint32_t i1 = 0; i1 < n1; i1++) { double sum = (accumulate) ? C(i0, i1) : 0.0; - for (int j = 0; j < m; j++) { + for (uint32_t j = 0; j < m; j++) { if constexpr (i == 0) { sum += A(j, i0) * B(i1, j); } if constexpr (i == 1) { sum += A(i0, j) * B(i1, j); } } @@ -68,7 +68,7 @@ inline void contract(const nd::view & A, nd::view & B, c uint32_t m = A.shape[0]; for (uint32_t i = 0; i < n; i++) { double sum = (accumulate) ? C(i) : 0.0; - for (int j = 0; j < m; j++) { + for (uint32_t j = 0; j < m; j++) { sum += A(j) * B(i, j); } C(i) = sum; diff --git a/src/serac/numerics/refactor/finite_element.hpp b/src/serac/numerics/refactor/finite_element.hpp index 37cb1adb0c..ee8d18cdd7 100644 --- a/src/serac/numerics/refactor/finite_element.hpp +++ b/src/serac/numerics/refactor/finite_element.hpp @@ -31,6 +31,29 @@ struct FunctionSpace { uint32_t components; FunctionSpace() : family{}, degree{}, components{} {} FunctionSpace(Family f, uint32_t d = 2, uint32_t c = 1) : family{f}, degree{d}, components{c}{} + FunctionSpace(Field f) { + + const auto & pgf = f.gridFunction(); + switch(pgf.FESpace()->FEColl()->GetContType()) { + case mfem::FiniteElementCollection::CONTINUOUS: + family = Family::H1; + break; + case mfem::FiniteElementCollection::TANGENTIAL: + family = Family::Hcurl; + break; + case mfem::FiniteElementCollection::NORMAL: + family = Family::Hdiv; + break; + case mfem::FiniteElementCollection::DISCONTINUOUS: + family = Family::DG; + break; + } + + degree = uint32_t(pgf.FESpace()->FEColl()->GetOrder()); + + components = uint32_t(pgf.VectorDim()); + + } bool operator==(const FunctionSpace & other) const { return (components == other.components) && @@ -41,7 +64,7 @@ struct FunctionSpace { struct BasisFunction { FunctionSpace space; - BasisFunction(Field f) : space(f.family, f.degree, f.data.shape[1]) {} + BasisFunction(Field f) : space(f) {} BasisFunction(FunctionSpace s) : space(s) {} bool operator==(const BasisFunction & other) const { return (space.components == other.space.components) && @@ -101,7 +124,7 @@ SERAC_HOST_DEVICE constexpr serac::mat2 face_transformation(int8_t id) { return matrices[id-1]; } -// sam: these orientations are for femto's face orientation convention +// sam: these orientations are for refactor's face orientation convention SERAC_HOST_DEVICE constexpr int8_t face_transformation_id(TransformationType type, int orientation) { if (type == TransformationType::PhysicalToParent) { constexpr int8_t LUT[3] = {1, 2, 3}; diff --git a/src/serac/numerics/refactor/geometry.hpp b/src/serac/numerics/refactor/geometry.hpp index 472125c62d..38b109fd3a 100644 --- a/src/serac/numerics/refactor/geometry.hpp +++ b/src/serac/numerics/refactor/geometry.hpp @@ -203,7 +203,7 @@ struct GeometryType< mfem::Geometry::TRIANGLE > { static constexpr int local_edge_ids[3][2] = {{0, 1},{1, 2},{2, 0}}; - SERAC_HOST_DEVICE static constexpr uint32_t number(int n) { return static_cast< uint32_t >((n * (n + 1)) / 2); }; + SERAC_HOST_DEVICE static constexpr uint32_t number(uint32_t n) { return (n * (n + 1)) / 2; }; }; using Triangle = GeometryType< mfem::Geometry::TRIANGLE >; diff --git a/src/serac/numerics/refactor/interpolation.cpp b/src/serac/numerics/refactor/interpolation.cpp index 83d88141a3..ea093e1140 100644 --- a/src/serac/numerics/refactor/interpolation.cpp +++ b/src/serac/numerics/refactor/interpolation.cpp @@ -1,8 +1,8 @@ #include -namespace femto { +namespace refactor { -void GaussLegendreNodes(int n, double * output) { +void GaussLegendreNodes(uint32_t n, double * output) { // clang-format off switch (n) { @@ -44,7 +44,7 @@ void GaussLegendreNodes(int n, double * output) { } -void GaussLegendreInterpolation(double x, int n, double * output) { +void GaussLegendreInterpolation(double x, uint32_t n, double * output) { if (n == 1) { output[0] = 1; @@ -87,7 +87,7 @@ void GaussLegendreInterpolation(double x, int n, double * output) { } -void GaussLegendreInterpolationDerivative01(double x, int n, double * output) { +void GaussLegendreInterpolationDerivative01(double x, uint32_t n, double * output) { if (n == 1) { output[0] = 0.0; @@ -130,7 +130,7 @@ void GaussLegendreInterpolationDerivative01(double x, int n, double * output) { } -void GaussLobattoNodes(int n, double * output) { +void GaussLobattoNodes(uint32_t n, double * output) { if (n == 1) { output[0] = 0.5; return; @@ -155,7 +155,7 @@ void GaussLobattoNodes(int n, double * output) { } } -void GaussLobattoInterpolation(double x, int n, double * output) { +void GaussLobattoInterpolation(double x, uint32_t n, double * output) { if (n == 1) { output[0] = 1.0; return; @@ -183,7 +183,7 @@ void GaussLobattoInterpolation(double x, int n, double * output) { std::cout << "error: invalid polynomial order in GaussLobattoInterpolation" << std::endl; } -void GaussLobattoInterpolationDerivative(double x, int n, double * output) { +void GaussLobattoInterpolationDerivative(double x, uint32_t n, double * output) { if (n == 1) { output[0] = 0.0; return; @@ -249,7 +249,7 @@ constexpr double GaussLobattoInterpolationDerivative(double x, uint32_t n, uint3 } #endif -void GaussLobattoInterpolationTriangle(const double * xi, int p, double * output) { +void GaussLobattoInterpolationTriangle(const double * xi, uint32_t p, double * output) { if (p == 0) { output[0] = 1.0; return; @@ -285,7 +285,7 @@ void GaussLobattoInterpolationTriangle(const double * xi, int p, double * output } } -void GaussLobattoInterpolationDerivativeTriangle(const double * xi, int p, double * output) { +void GaussLobattoInterpolationDerivativeTriangle(const double * xi, uint32_t p, double * output) { if (p == 0) { output[0] = 0.0; output[1] = 0.0; @@ -341,7 +341,7 @@ void GaussLobattoInterpolationDerivativeTriangle(const double * xi, int p, doubl } } -void GaussLobattoInterpolationQuadrilateral(const double * xi, int n, double * output) { +void GaussLobattoInterpolationQuadrilateral(const double * xi, uint32_t n, double * output) { double * N[2] = {new double[n], new double[n]}; GaussLobattoInterpolation(xi[0], n, N[0]); @@ -357,7 +357,7 @@ void GaussLobattoInterpolationQuadrilateral(const double * xi, int n, double * o delete N[1]; } -void GaussLobattoInterpolationDerivativeQuadrilateral(const double * xi, int n, double * output) { +void GaussLobattoInterpolationDerivativeQuadrilateral(const double * xi, uint32_t n, double * output) { double * N[2] = {new double[n], new double[n]}; double * dN[2] = {new double[n], new double[n]}; @@ -380,7 +380,7 @@ void GaussLobattoInterpolationDerivativeQuadrilateral(const double * xi, int n, delete dN[1]; } -void GaussLobattoInterpolationTetrahedron(const double * xi, int p, double * output) { +void GaussLobattoInterpolationTetrahedron(const double * xi, uint32_t p, double * output) { if (p == 0) { output[0] = 1.0; return; @@ -431,7 +431,7 @@ void GaussLobattoInterpolationTetrahedron(const double * xi, int p, double * out } } -void GaussLobattoInterpolationDerivativeTetrahedron(const double * xi, int p, double * output) { +void GaussLobattoInterpolationDerivativeTetrahedron(const double * xi, uint32_t p, double * output) { if (p == 0) { output[0] = 0.0; output[1] = 0.0; @@ -552,7 +552,7 @@ void GaussLobattoInterpolationDerivativeTetrahedron(const double * xi, int p, do } } -void GaussLobattoInterpolationHexahedron(const double * xi, int n, double * output) { +void GaussLobattoInterpolationHexahedron(const double * xi, uint32_t n, double * output) { double * N[3] = {new double[n], new double[n], new double[n]}; GaussLobattoInterpolation(xi[0], n, N[0]); @@ -570,7 +570,7 @@ void GaussLobattoInterpolationHexahedron(const double * xi, int n, double * outp delete N[0]; delete N[1]; delete N[2]; } -void GaussLobattoInterpolationDerivativeHexahedron(const double * xi, int n, double * output) { +void GaussLobattoInterpolationDerivativeHexahedron(const double * xi, uint32_t n, double * output) { double * N[3] = {new double[n], new double[n], new double[n]}; double * dN[3] = {new double[n], new double[n], new double[n]}; @@ -596,4 +596,4 @@ void GaussLobattoInterpolationDerivativeHexahedron(const double * xi, int n, dou delete dN[0]; delete dN[1]; delete dN[2]; } -} // namespace femto +} // namespace refactor diff --git a/src/serac/numerics/refactor/interpolation.hpp b/src/serac/numerics/refactor/interpolation.hpp index e959e449e6..eb5e911a50 100644 --- a/src/serac/numerics/refactor/interpolation.hpp +++ b/src/serac/numerics/refactor/interpolation.hpp @@ -2,7 +2,7 @@ #include "serac/numerics/functional/tensor.hpp" -namespace femto { +namespace refactor { template< int n, int i > constexpr double GaussLegendreNode01() { @@ -121,13 +121,13 @@ constexpr double GaussLobattoNode01() { return -1000.0; } -void GaussLegendreNodes(int n, double * output); -void GaussLegendreInterpolation(double x, int n, double * output); -void GaussLegendreInterpolationDerivative(double x, int n, double * output); +void GaussLegendreNodes(uint32_t n, double * output); +void GaussLegendreInterpolation(double x, uint32_t n, double * output); +void GaussLegendreInterpolationDerivative(double x, uint32_t n, double * output); -void GaussLobattoNodes(int n, double * output); -void GaussLobattoInterpolation(double x, int n, double * output); -void GaussLobattoInterpolationDerivative(double x, int n, double * output); +void GaussLobattoNodes(uint32_t n, double * output); +void GaussLobattoInterpolation(double x, uint32_t n, double * output); +void GaussLobattoInterpolationDerivative(double x, uint32_t n, double * output); constexpr double GaussLobattoInterpolation(double x, uint32_t n, uint32_t i) { if (n == 1) { return 1.0; } @@ -165,16 +165,16 @@ constexpr double GaussLobattoInterpolationDerivative(double x, uint32_t n, uint3 return -1.0; } -void GaussLobattoInterpolationTriangle(const double * xi, int p, double * output); -void GaussLobattoInterpolationDerivativeTriangle(const double * xi, int p, double * output); +void GaussLobattoInterpolationTriangle(const double * xi, uint32_t p, double * output); +void GaussLobattoInterpolationDerivativeTriangle(const double * xi, uint32_t p, double * output); -void GaussLobattoInterpolationQuadrilateral(const double * xi, int n, double * output); -void GaussLobattoInterpolationDerivativeQuadrilateral(const double * xi, int n, double * output); +void GaussLobattoInterpolationQuadrilateral(const double * xi, uint32_t n, double * output); +void GaussLobattoInterpolationDerivativeQuadrilateral(const double * xi, uint32_t n, double * output); -void GaussLobattoInterpolationTetrahedron(const double * xi, int p, double * output); -void GaussLobattoInterpolationDerivativeTetrahedron(const double * xi, int p, double * output); +void GaussLobattoInterpolationTetrahedron(const double * xi, uint32_t p, double * output); +void GaussLobattoInterpolationDerivativeTetrahedron(const double * xi, uint32_t p, double * output); -void GaussLobattoInterpolationHexahedron(const double * xi, int n, double * output); -void GaussLobattoInterpolationDerivativeHexahedron(const double * xi, int n, double * output); +void GaussLobattoInterpolationHexahedron(const double * xi, uint32_t n, double * output); +void GaussLobattoInterpolationDerivativeHexahedron(const double * xi, uint32_t n, double * output); -} // namespace femto +} // namespace refactor From aa7c0759a68f993dc2864111011ba0c554e461b0 Mon Sep 17 00:00:00 2001 From: Sam Mish Date: Mon, 16 Dec 2024 14:12:45 -0800 Subject: [PATCH 07/15] a million more int signedness changes, fix many broken #includes --- src/serac/numerics/functional/tensor.hpp | 13 ++ src/serac/numerics/refactor/common.hpp | 55 +---- .../numerics/refactor/containers/ndarray.hpp | 6 +- .../refactor/elements/h1_hexahedron.hpp | 28 +-- .../refactor/elements/h1_quadrilateral.hpp | 35 ++- .../refactor/elements/h1_tetrahedron.hpp | 8 +- .../refactor/elements/h1_triangle.hpp | 2 +- .../numerics/refactor/elements/hcurl_edge.hpp | 40 +--- .../refactor/elements/hcurl_hexahedron.hpp | 219 ++---------------- .../refactor/elements/hcurl_quadrilateral.hpp | 96 ++------ .../refactor/elements/hcurl_tetrahedron.hpp | 119 +--------- .../refactor/elements/hcurl_triangle.hpp | 29 ++- src/serac/numerics/refactor/evaluate.hpp | 2 - .../numerics/refactor/finite_element.hpp | 3 + src/serac/numerics/refactor/geometry.hpp | 2 +- .../numerics/refactor/integrate_residual.cpp | 4 +- .../refactor/tests/hcurl_evaluation_tests.cpp | 6 +- .../integrate_residual_H1_flux_tests.cpp | 6 +- .../integrate_residual_H1_source_tests.cpp | 4 +- .../integrate_residual_H1v_flux_tests.cpp | 4 +- .../integrate_residual_Hcurl_flux_tests.cpp | 4 +- .../integrate_residual_Hcurl_source_tests.cpp | 4 +- 22 files changed, 153 insertions(+), 536 deletions(-) diff --git a/src/serac/numerics/functional/tensor.hpp b/src/serac/numerics/functional/tensor.hpp index f21f13c865..0b9eac3996 100644 --- a/src/serac/numerics/functional/tensor.hpp +++ b/src/serac/numerics/functional/tensor.hpp @@ -73,6 +73,9 @@ struct tensor { SERAC_HOST_DEVICE constexpr auto& operator[](int i) { return data[i]; } SERAC_HOST_DEVICE constexpr const auto& operator[](int i) const { return data[i]; } + SERAC_HOST_DEVICE constexpr auto& operator[](uint32_t i) { return data[i]; } + SERAC_HOST_DEVICE constexpr const auto& operator[](uint32_t i) const { return data[i]; } + T data[m]; }; @@ -92,9 +95,13 @@ struct tensor { { return data; } + SERAC_HOST_DEVICE constexpr auto& operator[](int) { return data; } SERAC_HOST_DEVICE constexpr const auto& operator[](int) const { return data; } + SERAC_HOST_DEVICE constexpr auto& operator[](uint32_t) { return data; } + SERAC_HOST_DEVICE constexpr const auto& operator[](uint32_t) const { return data; } + SERAC_HOST_DEVICE constexpr operator T() { return data; @@ -135,10 +142,16 @@ using vec1 = tensor; ///< statically sized "vector" of 1 double using vec2 = tensor; ///< statically sized vector of 2 doubles using vec3 = tensor; ///< statically sized vector of 3 doubles +template < int n, typename T = double > +using vec = tensor; ///< statically sized vector with n components + using mat1 = tensor; ///< statically sized 1x1 "matrix" of doubles using mat2 = tensor; ///< statically sized 2x2 matrix of doubles using mat3 = tensor; ///< statically sized 3x3 matrix of doubles +template < int m, int n, typename T = double > +using mat = tensor; ///< statically sized mxn matrix + /** * @brief A sentinel struct for eliding no-op tensor operations */ diff --git a/src/serac/numerics/refactor/common.hpp b/src/serac/numerics/refactor/common.hpp index 25b74a5992..0806cd62a5 100644 --- a/src/serac/numerics/refactor/common.hpp +++ b/src/serac/numerics/refactor/common.hpp @@ -1,6 +1,7 @@ #pragma once #include "serac/infrastructure/accelerator.hpp" +#include "serac/numerics/functional/tensor.hpp" #include "serac/numerics/refactor/finite_element.hpp" namespace refactor { @@ -149,54 +150,6 @@ bool compatible_shapes(const stack::array & x, return true; } -template < mfem::Geometry::Type geom, Family test_family, Family trial_family> -void jacobian_rows_and_columns(nd::view rows, - nd::view cols, - FunctionSpace trial_space, - FunctionSpace test_space, - GeometryInfo trial_offsets, - GeometryInfo test_offsets, - nd::view elements, - nd::view connectivity) { - - FiniteElement< geom, test_family > test_el{test_space.degree}; - FiniteElement< geom, trial_family > trial_el{trial_space.degree}; - - // allocate storage for an element's nodal forces - constexpr uint32_t gdim = dimension(geom); - - uint32_t num_elements = rows.shape[0]; - uint32_t test_components = test_space.components; - uint32_t trial_components = trial_space.components; - uint32_t nodes_per_test_element = test_el.num_nodes(); - uint32_t nodes_per_trial_element = trial_el.num_nodes(); - - nd::array test_ids({nodes_per_test_element}); - nd::array trial_ids({nodes_per_trial_element}); - - // for each element of this mfem::Geometry::Type in the domain - for (uint32_t e = 0; e < num_elements; e++) { - - // get the ids of nodes for that element - test_el.indices(test_offsets, connectivity(elements(e)).data(), test_ids.data()); - trial_el.indices(trial_offsets, connectivity(elements(e)).data(), trial_ids.data()); - - // populate the row/column entries for the element jacobian - for (uint32_t J = 0; J < nodes_per_trial_element; J++) { - for (uint32_t j = 0; j < trial_space.components; j++) { - for (uint32_t I = 0; I < nodes_per_test_element; I++) { - for (uint32_t i = 0; i < test_space.components; i++) { - rows(e, J, j, I, i) = int(test_ids(I) * test_space.components + i); - cols(e, J, j, I, i) = int(trial_ids(J) * trial_space.components + j); - } - } - } - } - - } - -} - template < mfem::Geometry::Type geom > auto quadrature_point(uint32_t q, const nd::view xi) { @@ -264,7 +217,7 @@ auto flux_transformation(const mat & A) { } if constexpr (family == Family::Hcurl) { if constexpr (n <= 2) { - return vec<1>(1.0); + return vec1(1.0); } if constexpr (n == 3) { return transpose(A); @@ -279,8 +232,8 @@ auto flux_transformation(const mat & A) { namespace nd { template < typename T, uint32_t n > -struct printer< fm::vec >{ - static SERAC_HOST_DEVICE void print(const fm::vec & v) { +struct printer< serac::vec >{ + static SERAC_HOST_DEVICE void print(const serac::vec & v) { printf("{"); printer::print(v(0)); for (int i = 1; i < n; i++) { diff --git a/src/serac/numerics/refactor/containers/ndarray.hpp b/src/serac/numerics/refactor/containers/ndarray.hpp index 6b43781afd..e57d22df98 100644 --- a/src/serac/numerics/refactor/containers/ndarray.hpp +++ b/src/serac/numerics/refactor/containers/ndarray.hpp @@ -191,9 +191,9 @@ namespace nd { uint32_t beginnings[num_args] = {uint32_t(nd::begin(indices)) ... }; uint32_t endings[num_args] = {uint32_t(nd::end(indices)) ... }; - int k = 0; - int offset = 0; - for (int i = 0; i < dim; i++) { + uint32_t k = 0; + uint32_t offset = 0; + for (uint32_t i = 0; i < dim; i++) { if (i >= num_args) { slice_shape[k] = shape[i]; slice_stride[k] = stride[i]; diff --git a/src/serac/numerics/refactor/elements/h1_hexahedron.hpp b/src/serac/numerics/refactor/elements/h1_hexahedron.hpp index ff386c3782..217b93985d 100644 --- a/src/serac/numerics/refactor/elements/h1_hexahedron.hpp +++ b/src/serac/numerics/refactor/elements/h1_hexahedron.hpp @@ -49,11 +49,11 @@ struct FiniteElement { double interpolate(vec3 xi, double * values) const { uint32_t count = 0; double output = 0.0; - for (int iz = 0; iz < (p+1); iz++) { + for (uint32_t iz = 0; iz < (p+1); iz++) { double phi_z = phi_1D(xi[2], iz); - for (int iy = 0; iy < (p+1); iy++) { + for (uint32_t iy = 0; iy < (p+1); iy++) { double phi_y = phi_1D(xi[1], iy); - for (int ix = 0; ix < (p+1); ix++) { + for (uint32_t ix = 0; ix < (p+1); ix++) { double phi_x = phi_1D(xi[0], ix); output += phi_x * phi_y * phi_z * values[count]; count++; @@ -66,13 +66,13 @@ struct FiniteElement { vec3 gradient(vec3 xi, double * values) const { vec3 output{}; uint32_t count = 0; - for (int iz = 0; iz < (p+1); iz++) { + for (uint32_t iz = 0; iz < (p+1); iz++) { double phi_z = phi_1D(xi[2], iz); double dphi_z = dphi_1D(xi[2], iz); - for (int iy = 0; iy < (p+1); iy++) { + for (uint32_t iy = 0; iy < (p+1); iy++) { double phi_y = phi_1D(xi[1], iy); double dphi_y = dphi_1D(xi[1], iy); - for (int ix = 0; ix < (p+1); ix++) { + for (uint32_t ix = 0; ix < (p+1); ix++) { double phi_x = phi_1D(xi[0], ix); double dphi_x = dphi_1D(xi[0], ix); output[0] += dphi_x * phi_y * phi_z * values[count]; @@ -111,7 +111,7 @@ struct FiniteElement { nd::view A2(buffer + q * n * n, {q, q, n}); nd::view values_e_3D = nd::reshape<3>(values_e, {n, n, n}); - nd::view values_q_3D((double*)&values_q[0], {q, q, q}); + nd::view values_q_3D(static_cast(&values_q[0][0]), {q, q, q}); contract(values_e_3D, phi, A1); contract( A1, phi, A2); contract( A2, phi, values_q_3D); @@ -138,10 +138,8 @@ struct FiniteElement { nd::view A1(buffer, {q, n, n}); nd::view A2(buffer + q * n * n, {q, q, n}); - nd::range All{0u, gradients_q.shape[0]}; - nd::view values_e_3D = nd::reshape<3>(values_e, {n, n, n}); - nd::view gradients_q_3D((double*)&gradients_q[0], {q, q, q}, {3*q*q, 3*q, 3}); + nd::view gradients_q_3D(static_cast(&gradients_q[0][0]), {q, q, q}, {3*q*q, 3*q, 3}); // du_dxi contract(values_e_3D, G, A1); @@ -171,7 +169,7 @@ struct FiniteElement { nd::array tmp({p+1}); for (uint32_t i = 0; i < q; i++) { GaussLobattoInterpolation(xi(i, 0), p+1, &tmp(0)); - for (int j = 0; j < p+1; j++) { + for (uint32_t j = 0; j < p+1; j++) { buffer(j, i) = tmp(j) * weights(i); } } @@ -186,7 +184,7 @@ struct FiniteElement { nd::view A1(buffer, {n, q, q}); nd::view A2(buffer + n*q*q, {n, n, q}); - nd::view s3D((double*)&source_q[0], {q, q, q}); + nd::view s3D(static_cast(&source_q[0][0]), {q, q, q}); nd::view r3D = nd::reshape<3>(residual_e, {n, n, n}); // r(iz, iy, ix) = s(qz, qy, qx) * BT(ix, qx) * BT(iy, qy) * BT(iz, qz) @@ -208,12 +206,12 @@ struct FiniteElement { nd::array tmp({p+1}); for (uint32_t i = 0; i < q; i++) { GaussLobattoInterpolation(xi(i, 0), p+1, &tmp(0)); - for (int j = 0; j < p+1; j++) { + for (uint32_t j = 0; j < p+1; j++) { buffer(0, j, i) = tmp(j) * weights(i); } GaussLobattoInterpolationDerivative(xi(i, 0), p+1, &tmp(0)); - for (int j = 0; j < p+1; j++) { + for (uint32_t j = 0; j < p+1; j++) { buffer(1, j, i) = tmp(j) * weights(i); } } @@ -229,8 +227,6 @@ struct FiniteElement { nd::view A1(buffer, {n, q, q}); nd::view A2(buffer+n*q*q, {n, n, q}); - nd::range All{0u, flux_q.shape[0]}; - uint32_t s = flux_q.stride[0] * 3; nd::view f3D(nullptr, {q, q, q}, {s*q*q, s*q, s}); nd::view r3D = nd::reshape<3>(residual_e, {n, n, n}); diff --git a/src/serac/numerics/refactor/elements/h1_quadrilateral.hpp b/src/serac/numerics/refactor/elements/h1_quadrilateral.hpp index f35b0b5935..2f26c27494 100644 --- a/src/serac/numerics/refactor/elements/h1_quadrilateral.hpp +++ b/src/serac/numerics/refactor/elements/h1_quadrilateral.hpp @@ -1,11 +1,12 @@ #pragma once +#include "serac/numerics/functional/tensor.hpp" #include "serac/numerics/refactor/elements/tensor_contractions.hpp" namespace refactor { template <> -struct FiniteElement { +struct FiniteElement< mfem::Geometry::SQUARE, Family::H1 > { using source_type = vec1; using flux_type = vec2; @@ -47,15 +48,15 @@ struct FiniteElement { GaussLobattoInterpolation(xi[0], p+1, phi); double interpolated_in_xi[4]{}; - for (int i = 0; i < (p+1); i++) { - for (int j = 0; j < (p+1); j++) { + for (uint32_t i = 0; i < (p+1); i++) { + for (uint32_t j = 0; j < (p+1); j++) { interpolated_in_xi[i] += phi[j] * values[i*(p+1)+j]; } } GaussLobattoInterpolation(xi[1], p+1, phi); double result{}; - for (int i = 0; i < (p+1); i++) { + for (uint32_t i = 0; i < (p+1); i++) { result += phi[i] * interpolated_in_xi[i]; } return result; @@ -68,28 +69,28 @@ struct FiniteElement { double partially_interpolated[4]{}; GaussLobattoInterpolationDerivative(xi[0], p+1, phi); - for (int i = 0; i < (p+1); i++) { - for (int j = 0; j < (p+1); j++) { + for (uint32_t i = 0; i < (p+1); i++) { + for (uint32_t j = 0; j < (p+1); j++) { partially_interpolated[i] += phi[j] * values[i*(p+1)+j]; } } GaussLobattoInterpolation(xi[1], p+1, phi); - for (int i = 0; i < (p+1); i++) { + for (uint32_t i = 0; i < (p+1); i++) { output[0] += phi[i] * partially_interpolated[i]; } //-------------------------------------------------- GaussLobattoInterpolation(xi[0], p+1, phi); - for (int i = 0; i < (p+1); i++) { - for (int j = 0; j < (p+1); j++) { + for (uint32_t i = 0; i < (p+1); i++) { + for (uint32_t j = 0; j < (p+1); j++) { partially_interpolated[i] += phi[j] * values[i*(p+1)+j]; } } GaussLobattoInterpolationDerivative(xi[1], p+1, phi); - for (int i = 0; i < (p+1); i++) { + for (uint32_t i = 0; i < (p+1); i++) { output[1] += phi[i] * partially_interpolated[i]; } @@ -119,7 +120,7 @@ struct FiniteElement { nd::view A(buffer, {n, q}); nd::view values_e_2D = nd::reshape<2>(values_e, {n, n}); - nd::view values_q_2D((double*)&values_q[0], {q, q}, {1, q}); + nd::view values_q_2D(static_cast(&values_q[0].data), {q, q}, {1, q}); contract<1>(values_e_2D, shape_fns, A); contract<0>(A, shape_fns, values_q_2D); } @@ -144,9 +145,8 @@ struct FiniteElement { nd::view G = shape_fns(1); nd::view A(buffer, {n, q}); - nd::range All{0u, gradients_q.shape[0]}; nd::view values_e_2D = nd::reshape<2>(values_e, {n, n}); - nd::view gradients_q_2D((double*)&gradients_q[0], {q, q}, {2, 2*q}); + nd::view gradients_q_2D(static_cast(&gradients_q[0][0]), {q, q}, {2, 2*q}); // du_dxi contract<1>(values_e_2D, G, A); @@ -168,7 +168,7 @@ struct FiniteElement { nd::array tmp({p+1}); for (uint32_t i = 0; i < q; i++) { GaussLobattoInterpolation(xi(i, 0), p+1, &tmp(0)); - for (int j = 0; j < p+1; j++) { + for (uint32_t j = 0; j < p+1; j++) { buffer(j, i) = tmp(j) * weights(i); } } @@ -182,7 +182,7 @@ struct FiniteElement { nd::view BT = shape_fns; nd::view A(buffer, {q, n}); - nd::view s2D((double*)&source_q[0], {q, q}, {1, q}); + nd::view s2D(static_cast(&source_q[0][0]), {q, q}, {1, q}); nd::view r2D = nd::reshape<2>(residual_e, {n, n}); contract<1>(s2D, BT, A); @@ -198,12 +198,12 @@ struct FiniteElement { nd::array tmp({p+1}); for (uint32_t i = 0; i < q; i++) { GaussLobattoInterpolation(xi(i, 0), p+1, &tmp(0)); - for (int j = 0; j < p+1; j++) { + for (uint32_t j = 0; j < p+1; j++) { buffer(0, j, i) = tmp(j) * weights(i); } GaussLobattoInterpolationDerivative(xi(i, 0), p+1, &tmp(0)); - for (int j = 0; j < p+1; j++) { + for (uint32_t j = 0; j < p+1; j++) { buffer(1, j, i) = tmp(j) * weights(i); } } @@ -219,7 +219,6 @@ struct FiniteElement { nd::view A(buffer, {q, n}); uint32_t s = 2 * flux_q.stride[0]; - nd::range All{0u, flux_q.shape[0]}; nd::view f2D(&flux_q(0)[0], {q, q}, {s, s*q}); // ? nd::view r2D = nd::reshape<2>(residual_e, {n, n}); diff --git a/src/serac/numerics/refactor/elements/h1_tetrahedron.hpp b/src/serac/numerics/refactor/elements/h1_tetrahedron.hpp index 9a40768380..b5fe246e7d 100644 --- a/src/serac/numerics/refactor/elements/h1_tetrahedron.hpp +++ b/src/serac/numerics/refactor/elements/h1_tetrahedron.hpp @@ -1,6 +1,6 @@ #pragma once - +#include "serac/numerics/functional/tensor.hpp" namespace refactor { @@ -131,7 +131,7 @@ struct FiniteElement { return interpolated_gradient; } - SERAC_HOST_DEVICE uint32_t batch_interpolation_scratch_space(nd::view xi) const { + SERAC_HOST_DEVICE uint32_t batch_interpolation_scratch_space(nd::view) const { return 0; } @@ -189,7 +189,7 @@ struct FiniteElement { nd::array shape_fns({q, nnodes}); for (uint32_t i = 0; i < q; i++) { GaussLobattoInterpolationTetrahedron(&xi(i, 0), p, &shape_fns(i, 0)); - for (int j = 0; j < nnodes; j++) { + for (uint32_t j = 0; j < nnodes; j++) { shape_fns(i, j) = shape_fns(i, j) * weights(i); } } @@ -216,7 +216,7 @@ struct FiniteElement { nd::array shape_fn_grads({q, nnodes, dim}); for (uint32_t i = 0; i < q; i++) { GaussLobattoInterpolationDerivativeTetrahedron(&xi(i, 0), p, &shape_fn_grads(i, 0, 0)); - for (int j = 0; j < nnodes; j++) { + for (uint32_t j = 0; j < nnodes; j++) { shape_fn_grads(i, j, 0) = shape_fn_grads(i, j, 0) * weights(i); shape_fn_grads(i, j, 1) = shape_fn_grads(i, j, 1) * weights(i); shape_fn_grads(i, j, 2) = shape_fn_grads(i, j, 2) * weights(i); diff --git a/src/serac/numerics/refactor/elements/h1_triangle.hpp b/src/serac/numerics/refactor/elements/h1_triangle.hpp index 70b6809541..ab577f9d31 100644 --- a/src/serac/numerics/refactor/elements/h1_triangle.hpp +++ b/src/serac/numerics/refactor/elements/h1_triangle.hpp @@ -1,6 +1,6 @@ #pragma once - +#include "serac/numerics/functional/tensor.hpp" namespace refactor { diff --git a/src/serac/numerics/refactor/elements/hcurl_edge.hpp b/src/serac/numerics/refactor/elements/hcurl_edge.hpp index 9cfd7c2561..4019251648 100644 --- a/src/serac/numerics/refactor/elements/hcurl_edge.hpp +++ b/src/serac/numerics/refactor/elements/hcurl_edge.hpp @@ -1,6 +1,6 @@ #pragma once - +#include "serac/numerics/functional/tensor.hpp" namespace refactor { @@ -14,25 +14,7 @@ struct FiniteElement < mfem::Geometry::SEGMENT, Family::Hcurl >{ SERAC_HOST_DEVICE uint32_t num_nodes() const { return p; } - template < typename T > - SERAC_HOST_DEVICE void reorient(const TransformationType type, const Connection * edge, T * values) { - - // TODO - switch (type) { - case TransformationType::PhysicalToParent: - case TransformationType::TransposePhysicalToParent: - break; - } - - } - - SERAC_HOST_DEVICE void reorient(const TransformationType type, const Connection * edge, int8_t * transformation) { - for (int i = 0; i < p; i++) { - transformation[i] = 0; - } - } - - constexpr vec<1> shape_function(vec<1> xi, uint32_t i) const { + constexpr vec1 shape_function(vec1 xi, uint32_t i) const { if (p == 1 && i == 0) { return GaussLegendreInterpolation01<1, 0>(xi[0]); } if (p == 2 && i == 0) { return GaussLegendreInterpolation01<2, 0>(xi[0]); } @@ -42,7 +24,7 @@ struct FiniteElement < mfem::Geometry::SEGMENT, Family::Hcurl >{ if (p == 3 && i == 1) { return GaussLegendreInterpolation01<3, 1>(xi[0]); } if (p == 3 && i == 2) { return GaussLegendreInterpolation01<3, 2>(xi[0]); } - return 1000.0f; + return 1000.0; } constexpr vec1 reoriented_shape_function(vec1 xi, uint32_t i, int8_t transformation) const { @@ -57,7 +39,7 @@ struct FiniteElement < mfem::Geometry::SEGMENT, Family::Hcurl >{ // but what is the appropriate interpretation of "curl" (if any) for 1D? // // the implementation below is just the derivative - constexpr vec<1> shape_function_curl(vec<1> xi, uint32_t i) const { + constexpr vec1 shape_function_curl(vec1 xi, uint32_t i) const { if (p == 1 && i == 0) { return GaussLegendreInterpolationDerivative01<1, 0>(xi); } if (p == 2 && i == 0) { return GaussLegendreInterpolationDerivative01<2, 0>(xi); } @@ -67,7 +49,7 @@ struct FiniteElement < mfem::Geometry::SEGMENT, Family::Hcurl >{ if (p == 3 && i == 1) { return GaussLegendreInterpolationDerivative01<3, 1>(xi); } if (p == 3 && i == 2) { return GaussLegendreInterpolationDerivative01<3, 2>(xi); } - return 1000.0f; + return 1000.0; } constexpr vec1 reoriented_shape_function_curl(vec1 xi, uint32_t i, int8_t transformation) const { @@ -78,11 +60,11 @@ struct FiniteElement < mfem::Geometry::SEGMENT, Family::Hcurl >{ } } - constexpr vec<1> shape_function_derivative(vec<1> xi, uint32_t i) { + constexpr vec1 shape_function_derivative(vec1 xi, uint32_t i) { return shape_function_curl(xi, i); } - SERAC_HOST_DEVICE uint32_t batch_interpolation_scratch_space(nd::view xi) const { + SERAC_HOST_DEVICE uint32_t batch_interpolation_scratch_space(nd::view) const { return 0; } @@ -121,8 +103,8 @@ struct FiniteElement < mfem::Geometry::SEGMENT, Family::Hcurl >{ return buffer; } - void curl(nd::view values_q, nd::view values_e, nd::view buffer, double * /*buffer*/) { #if 0 + void curl(nd::view values_q, nd::view values_e, nd::view buffer, double * /*buffer*/) { uint32_t n = p + 1; uint32_t q = sqrt(values_q.shape[0]); @@ -146,14 +128,14 @@ struct FiniteElement < mfem::Geometry::SEGMENT, Family::Hcurl >{ _contract(A1, B1, ue); // A1(qx, iy) = sum_{ix} B1(qx, ix) * ue(iy, ix) _contract(uq, B2, A1); // uq(qy, qx) = sum_{iy} B2(qy, iy) * A1(qx, iy) - #endif } + #endif nd::array< double, 2 > evaluate_weighted_shape_functions(nd::view xi, nd::view weights) { uint32_t q = xi.shape[0]; nd::array shape_fns({q, num_nodes()}); for (uint32_t i = 0; i < q; i++) { - for (int j = 0; j < num_nodes(); j++) { + for (uint32_t j = 0; j < num_nodes(); j++) { shape_fns(i, j) = shape_function(xi(i, 0), j) * weights(i); } } @@ -177,7 +159,7 @@ struct FiniteElement < mfem::Geometry::SEGMENT, Family::Hcurl >{ uint32_t q = xi.shape[0]; nd::array shape_fns({q, num_nodes()}); for (uint32_t i = 0; i < q; i++) { - for (int j = 0; j < num_nodes(); j++) { + for (uint32_t j = 0; j < num_nodes(); j++) { shape_fns(i, j) = shape_function_curl(xi(i, 0), j) * weights(i); } } diff --git a/src/serac/numerics/refactor/elements/hcurl_hexahedron.hpp b/src/serac/numerics/refactor/elements/hcurl_hexahedron.hpp index fe7d9dc666..3efb391df9 100644 --- a/src/serac/numerics/refactor/elements/hcurl_hexahedron.hpp +++ b/src/serac/numerics/refactor/elements/hcurl_hexahedron.hpp @@ -1,6 +1,6 @@ #pragma once -#include "fm/types/vec.hpp" +#include "serac/numerics/functional/tensor.hpp" namespace refactor { @@ -17,161 +17,17 @@ struct FiniteElement { static constexpr int dim = 3; // clang-format off - SERAC_HOST_DEVICE uint8_t const * lexicographic_permutations(int p) { + SERAC_HOST_DEVICE uint8_t const * lexicographic_permutations(uint32_t p_) { static constexpr uint8_t linear_lexicographic_permutation[12] = {0,5,1,4,8,9,11,10,2,7,3,6}; static constexpr uint8_t quadratic_lexicographic_permutation[54] = {0,1,20,23,4,5,18,21,36,45,38,47,44,53,42,51,12,13,32,35,16,17,30,33,3,2,19,22,6,7,37,46,26,29,41,50,11,10,43,52,27,24,39,48,14,15,31,34,8,9,25,28,40,49}; static constexpr uint8_t cubic_lexicographic_permutation[144] = {0,1,2,51,55,59,9,10,11,48,52,56,96,112,128,99,115,131,111,127,143,108,124,140,36,37,38,87,91,95,45,46,47,84,88,92,5,4,3,8,7,6,50,54,58,49,53,57,12,13,14,24,25,26,97,113,129,98,114,130,63,67,71,75,79,83,103,119,135,107,123,139,23,22,21,35,34,33,110,126,142,109,125,141,68,64,60,80,76,72,104,120,136,100,116,132,39,40,41,42,43,44,85,89,93,86,90,94,15,16,17,18,19,20,27,28,29,30,31,32,61,62,65,66,69,70,73,74,77,78,81,82,101,102,105,106,117,118,121,122,133,134,137,138}; static constexpr uint8_t const * permutations[4] = {nullptr, linear_lexicographic_permutation, quadratic_lexicographic_permutation, cubic_lexicographic_permutation }; - return permutations[p]; + return permutations[p_]; } // clang-format on SERAC_HOST_DEVICE uint32_t num_nodes() const { return 3 * p * (p + 1) * (p + 1); } - struct QuadrilateralStrides { - int32_t x_offset; int32_t x_jstride; int32_t x_kstride; - int32_t y_offset; int32_t y_jstride; int32_t y_kstride; - }; - - SERAC_HOST_DEVICE QuadrilateralStrides quad_strides(Connection c, uint32_t offset) { - - uint8_t o = c.orientation(); - int32_t P = p; - int32_t base = offset + c.index * 2 * p * (p - 1); - if (c.sign() == Sign::Positive) { - if (o == 0) return {base + 0, 1, P, base + P*(P-1), 1, P}; - if (o == 1) return {base + P*P-1, -1, P, base + P*(P-2), 1, -P}; - if (o == 2) return {base + P*P-P-1, -1, -P, base + 2*P*(P-1)-1, -1, -P}; - if (o == 3) return {base + P*(2*P-3), 1, -P, base + P-1, -1, P}; - } else { - if (o == 0) return {base + P*(P-1), 1, P, base + 0, 1, P}; - if (o == 1) return {base + P-1, -1, P, base + P*(2*P - 3), 1, -P}; - if (o == 2) return {base + 2*P*(P-1)-1, -1, -P, base + P*P-P-1, -1, -P}; - if (o == 3) return {base + P*(P-2), 1, -P, base + P*P-1, -1, P}; - } - return {}; - - } - - template < typename T > - SERAC_HOST_DEVICE void reorient(const TransformationType type, const Connection * hex, T * values) { - - const Connection * edge = hex + Hexahedron::edge_offset; - const Connection * quad = hex + Hexahedron::quad_offset; - - uint8_t const * permutation = lexicographic_permutations(p); - - uint32_t count = 0; - - // edge nodes - for (uint32_t i = 0; i < Hexahedron::num_edges; i++) { - if (edge[i].sign() == Sign::Negative) { - for (uint32_t j = 0; j < p; j++) { - values[permutation[count++]] *= -1; - } - } else { - count += p; - } - } - - if (p == 1) return; - - // face nodes - for (uint32_t i = 0; i < Hexahedron::num_quadrilaterals; i++) { - - uint32_t s = quad[i].sign() == Sign::Positive; - uint32_t o = quad[i].orientation(); - - constexpr bool negate_x[2][4] = {{0, 1, 1, 0}, {0, 0, 0, 0}}; - // note: the canonical face orientations for the hexahedron were - // chosen such that nedelec basis functions on faces 0, 3, 4 - // are flipped in only the local "x" direction - if (negate_x[s][o] ^ (i == 0 || i == 3 || i == 4)) { - for (uint32_t k = 0; k < p * (p - 1); k++) { - values[permutation[count++]] *= -1; - } - } else { - count += p * (p - 1); - } - - constexpr bool negate_y[2][4] = {{0, 0, 1, 1}, {0, 0, 0, 0}}; - if (negate_y[s][o]) { - for (uint32_t k = 0; k < p * (p - 1); k++) { - values[permutation[count++]] *= -1; - } - } else { - count += p * (p - 1); - } - - } - - } - - SERAC_HOST_DEVICE void reorient(const TransformationType type, const Connection * hex, int8_t * transformation) { - - const Connection * edge = hex + Hexahedron::edge_offset; - const Connection * quad = hex + Hexahedron::quad_offset; - - uint8_t const * permutation = lexicographic_permutations(p); - - uint32_t count = 0; - - // edge nodes - for (uint32_t i = 0; i < Hexahedron::num_edges; i++) { - if (edge[i].sign() == Sign::Negative) { - for (uint32_t j = 0; j < p; j++) { - transformation[permutation[count++]] = -1; - } - } else { - for (uint32_t j = 0; j < p; j++) { - transformation[permutation[count++]] = 0; - } - } - } - - if (p == 1) return; - - // face nodes - for (uint32_t i = 0; i < Hexahedron::num_quadrilaterals; i++) { - - uint32_t s = quad[i].sign() == Sign::Positive; - uint32_t o = quad[i].orientation(); - - constexpr bool negate_x[2][4] = {{0, 1, 1, 0}, {0, 0, 0, 0}}; - // note: the canonical face orientations for the hexahedron were - // chosen such that nedelec basis functions on faces 0, 3, 4 - // are flipped in only the local "x" direction - if (negate_x[s][o] ^ (i == 0 || i == 3 || i == 4)) { - for (uint32_t k = 0; k < p * (p - 1); k++) { - transformation[permutation[count++]] = -1; - } - } else { - for (uint32_t k = 0; k < p * (p - 1); k++) { - transformation[permutation[count++]] = 0; - } - } - - constexpr bool negate_y[2][4] = {{0, 0, 1, 1}, {0, 0, 0, 0}}; - if (negate_y[s][o]) { - for (uint32_t k = 0; k < p * (p - 1); k++) { - transformation[permutation[count++]] = -1; - } - } else { - for (uint32_t k = 0; k < p * (p - 1); k++) { - transformation[permutation[count++]] = 0; - } - } - - } - - // all remaining (interior) nodes are always positive - uint32_t nnodes = num_nodes(); - for (uint32_t i = count; i < nnodes; i++) { - transformation[permutation[i]] = 0; - } - - } - constexpr vec3 shape_function(vec3 xi, uint32_t i) const { if (p == 1) { if (i == 0) { return vec3{(-1 + xi[1])*(-1 + xi[2]),0,0}; } @@ -393,14 +249,6 @@ struct FiniteElement { return {}; } - constexpr vec3 reoriented_shape_function(vec3 xi, uint32_t i, int8_t transformation) const { - if (transformation == -1) { - return -shape_function(xi, i); - } else { - return shape_function(xi, i); - } - } - constexpr vec3 shape_function_curl(vec3 xi, uint32_t i) const { // expressions generated symbolically by mathematica if (p == 1) { @@ -623,27 +471,10 @@ struct FiniteElement { return {}; } - constexpr vec3 reoriented_shape_function_curl(vec3 xi, uint32_t i, int8_t transformation) const { - if (transformation == -1) { - return -shape_function_curl(xi, i); - } else { - return shape_function_curl(xi, i); - } - } - constexpr vec3 shape_function_derivative(vec3 xi, uint32_t i) const { return shape_function_curl(xi, i); } - double shape_function_div(vec3 xi, uint32_t i) { - // expressions generated symbolically by mathematica - if (p == 1) { - return 0.0; - } - - return {}; - } - vec3 interpolate(vec3 xi, const double * values) { vec3 interpolated_value{}; for (uint32_t i = 0; i < num_nodes(); i++) { @@ -661,7 +492,7 @@ struct FiniteElement { } // TODO: set to nonzero when reenabling sum-factorization implementations - SERAC_HOST_DEVICE uint32_t batch_interpolation_scratch_space(nd::view xi) const { + SERAC_HOST_DEVICE uint32_t batch_interpolation_scratch_space(nd::view) const { return 0; } @@ -672,7 +503,7 @@ struct FiniteElement { nd::array< double > evaluate_shape_functions(nd::view xi) { uint32_t q = xi.shape[0]; nd::array buffer({q * (2 * p + 1)}); - for (uint32_t i = 0; i < q; i++) { + for (int i = 0; i < q; i++) { GaussLegendreInterpolation(xi(i, 0), p, &buffer(p * i)); GaussLobattoInterpolation(xi(i, 0), p+1, &buffer(q * p + p * i)); } @@ -702,7 +533,7 @@ struct FiniteElement { nd::array< double > evaluate_shape_function_curls(nd::view xi) { uint32_t q = xi.shape[0]; nd::array buffer({q * (3 * p + 2)}); - for (uint32_t i = 0; i < q; i++) { + for (int i = 0; i < q; i++) { GaussLegendreInterpolation(xi(i, 0), p, &buffer(p * i)); GaussLobattoInterpolation(xi(i, 0), p+1, &buffer(q * p + p * i)); GaussLobattoInterpolationDerivative(xi(i, 0), p+1, &buffer(q * p + p * i)); @@ -737,11 +568,11 @@ struct FiniteElement { uint32_t q = xi.shape[0]; nd::array shape_fns({q * q * q, num_nodes(), 3}); uint32_t qcount = 0; - for (int k = 0; k < q; k++) { - for (int j = 0; j < q; j++) { + for (uint32_t k = 0; k < q; k++) { + for (uint32_t j = 0; j < q; j++) { for (uint32_t i = 0; i < q; i++) { vec3 xi_ijk = vec3{xi(i, 0), xi(j, 0), xi(k, 0)}; - for (int l = 0; l < num_nodes(); l++) { + for (uint32_t l = 0; l < num_nodes(); l++) { vec3 phi = shape_function(xi_ijk, l); shape_fns(qcount, l, 0) = phi[0]; shape_fns(qcount, l, 1) = phi[1]; @@ -761,7 +592,7 @@ struct FiniteElement { for (uint32_t q = 0; q < nqpts; q++) { value_type sum{}; for (uint32_t i = 0; i < nnodes; i++) { - for (int c = 0; c < 3; c++) { + for (uint32_t c = 0; c < 3; c++) { sum[c] += shape_fns(q, i, c) * values_e(i); } } @@ -773,11 +604,11 @@ struct FiniteElement { uint32_t q = xi.shape[0]; nd::array shape_fns({q * q * q, num_nodes(), 3}); uint32_t qcount = 0; - for (int k = 0; k < q; k++) { - for (int j = 0; j < q; j++) { + for (uint32_t k = 0; k < q; k++) { + for (uint32_t j = 0; j < q; j++) { for (uint32_t i = 0; i < q; i++) { vec3 xi_ijk = vec3{xi(i, 0), xi(j, 0), xi(k, 0)}; - for (int l = 0; l < num_nodes(); l++) { + for (uint32_t l = 0; l < num_nodes(); l++) { vec3 curl_phi = shape_function_curl(xi_ijk, l); shape_fns(qcount, l, 0) = curl_phi[0]; shape_fns(qcount, l, 1) = curl_phi[1]; @@ -797,7 +628,7 @@ struct FiniteElement { for (uint32_t q = 0; q < nqpts; q++) { derivative_type sum{}; for (uint32_t i = 0; i < nnodes; i++) { - for (int c = 0; c < 3; c++) { + for (uint32_t c = 0; c < 3; c++) { sum[c] += shape_fn_curls(q, i, c) * values_e(i); } } @@ -809,11 +640,11 @@ struct FiniteElement { uint32_t q = xi.shape[0]; nd::array shape_fns({q * q * q, num_nodes(), dim}); uint32_t qcount = 0; - for (int k = 0; k < q; k++) { - for (int j = 0; j < q; j++) { + for (uint32_t k = 0; k < q; k++) { + for (uint32_t j = 0; j < q; j++) { for (uint32_t i = 0; i < q; i++) { vec3 xi_ijk = vec3{xi(i, 0), xi(j, 0), xi(k, 0)}; - for (int l = 0; l < num_nodes(); l++) { + for (uint32_t l = 0; l < num_nodes(); l++) { vec3 phi = shape_function(xi_ijk, l); shape_fns(qcount, l, 0) = phi[0] * weights[i] * weights[j] * weights[k]; shape_fns(qcount, l, 1) = phi[1] * weights[i] * weights[j] * weights[k]; @@ -833,7 +664,7 @@ struct FiniteElement { for (uint32_t i = 0; i < nnodes; i++) { double sum = 0.0; for (uint32_t q = 0; q < nqpts; q++) { - for (int j = 0; j < dim; j++) { + for (uint32_t j = 0; j < dim; j++) { sum += shape_fn(q, i, j) * source_q(q)[j]; } } @@ -845,11 +676,11 @@ struct FiniteElement { uint32_t q = xi.shape[0]; nd::array shape_fns({q * q * q, num_nodes(), dim}); uint32_t qcount = 0; - for (int k = 0; k < q; k++) { - for (int j = 0; j < q; j++) { + for (uint32_t k = 0; k < q; k++) { + for (uint32_t j = 0; j < q; j++) { for (uint32_t i = 0; i < q; i++) { vec3 xi_ijk = vec3{xi(i, 0), xi(j, 0), xi(k, 0)}; - for (int l = 0; l < num_nodes(); l++) { + for (uint32_t l = 0; l < num_nodes(); l++) { vec3 dphi = shape_function_curl(xi_ijk, l); shape_fns(qcount, l, 0) = dphi[0] * weights[i] * weights[j] * weights[k]; shape_fns(qcount, l, 1) = dphi[1] * weights[i] * weights[j] * weights[k]; @@ -869,7 +700,7 @@ struct FiniteElement { for (uint32_t i = 0; i < nnodes; i++) { double sum = 0.0; for (uint32_t q = 0; q < nqpts; q++) { - for (int j = 0; j < dim; j++) { + for (uint32_t j = 0; j < dim; j++) { sum += shape_fn_curl(q, i, j) * flux_q(q)[j]; } } @@ -879,12 +710,12 @@ struct FiniteElement { #ifdef __CUDACC__ __device__ void cuda_integrate_flux(nd::view residual_e, nd::view flux_q, nd::view shape_fn_curl, double * /*buffer*/) const { - uint32_t nnodes = num_nodes(); - uint32_t nqpts = flux_q.shape[0]; + int nnodes = num_nodes(); + int nqpts = flux_q.shape[0]; for (int i = threadIdx.x; i < nnodes; i += blockDim.x) { double sum = 0.0; - for (uint32_t q = 0; q < nqpts; q++) { + for (int q = 0; q < nqpts; q++) { for (int d = 0; d < dim; d++) { sum += shape_fn_curl(q, i, d) * flux_q(q)[d]; } diff --git a/src/serac/numerics/refactor/elements/hcurl_quadrilateral.hpp b/src/serac/numerics/refactor/elements/hcurl_quadrilateral.hpp index fb58b543cd..1df2144378 100644 --- a/src/serac/numerics/refactor/elements/hcurl_quadrilateral.hpp +++ b/src/serac/numerics/refactor/elements/hcurl_quadrilateral.hpp @@ -1,10 +1,10 @@ #pragma once -#include "fm/types/vec.hpp" +#include "serac/numerics/functional/tensor.hpp" namespace refactor { -using namespace fm; +using namespace serac; // clang-format off template <> @@ -20,72 +20,6 @@ struct FiniteElement { SERAC_HOST_DEVICE uint32_t num_nodes() const { return 2 * p * (p + 1); } - template < typename T > - SERAC_HOST_DEVICE void reorient(const TransformationType type, const Connection * quad, T * values) const { - - const Connection * edge = quad + Quadrilateral::edge_offset; - - if (p == 1) { - if (edge[0].sign() == Sign::Negative) { values[0] *= -1; } - if (edge[1].sign() == Sign::Negative) { values[3] *= -1; } - if (edge[2].sign() == Sign::Positive) { values[1] *= -1; } - if (edge[3].sign() == Sign::Positive) { values[2] *= -1; } - return; - } - - if (p == 2) { - if (edge[0].sign() == Sign::Negative) { values[ 0] *= -1; values[ 1] *= -1; } - if (edge[1].sign() == Sign::Negative) { values[10] *= -1; values[11] *= -1; } - if (edge[2].sign() == Sign::Positive) { values[ 4] *= -1; values[ 5] *= -1; } - if (edge[3].sign() == Sign::Positive) { values[ 6] *= -1; values[ 7] *= -1; } - return; - } - - if (p == 3) { - if (edge[0].sign() == Sign::Negative) { values[ 0] *= -1; values[ 1] *= -1; values[ 2] *= -1;} - if (edge[1].sign() == Sign::Negative) { values[21] *= -1; values[22] *= -1; values[23] *= -1;} - if (edge[2].sign() == Sign::Positive) { values[ 9] *= -1; values[10] *= -1; values[11] *= -1;} - if (edge[3].sign() == Sign::Positive) { values[12] *= -1; values[13] *= -1; values[14] *= -1;} - return; - } - - } - - SERAC_HOST_DEVICE void reorient(const TransformationType type, const Connection * quad, int8_t * transformation) { - - const Connection * edge = quad + Quadrilateral::edge_offset; - - uint32_t nnodes = num_nodes(); - for (int k = 0; k < nnodes; k++) { - transformation[k] = 0; - } - - if (p == 1) { - if (edge[0].sign() == Sign::Negative) { transformation[0] = -1; } - if (edge[1].sign() == Sign::Negative) { transformation[3] = -1; } - if (edge[2].sign() == Sign::Positive) { transformation[1] = -1; } - if (edge[3].sign() == Sign::Positive) { transformation[2] = -1; } - return; - } - - if (p == 2) { - if (edge[0].sign() == Sign::Negative) { transformation[ 0] = -1; transformation[ 1] = -1; } - if (edge[1].sign() == Sign::Negative) { transformation[10] = -1; transformation[11] = -1; } - if (edge[2].sign() == Sign::Positive) { transformation[ 4] = -1; transformation[ 5] = -1; } - if (edge[3].sign() == Sign::Positive) { transformation[ 6] = -1; transformation[ 7] = -1; } - return; - } - - if (p == 3) { - if (edge[0].sign() == Sign::Negative) { transformation[ 0] = -1; transformation[ 1] = -1; transformation[ 2] = -1;} - if (edge[1].sign() == Sign::Negative) { transformation[21] = -1; transformation[22] = -1; transformation[23] = -1;} - if (edge[2].sign() == Sign::Positive) { transformation[ 9] = -1; transformation[10] = -1; transformation[11] = -1;} - if (edge[3].sign() == Sign::Positive) { transformation[12] = -1; transformation[13] = -1; transformation[14] = -1;} - return; - } - - } - constexpr vec2 shape_function(vec2 xi, uint32_t i) const { if (p == 1) { if (i == 0) { return vec2{1 - xi[1],0}; } @@ -145,7 +79,7 @@ struct FiniteElement { } } - vec<1> shape_function_curl(vec2 xi, uint32_t i) const { + vec1 shape_function_curl(vec2 xi, uint32_t i) const { // expressions generated symbolically by mathematica if (p == 1) { if (i == 0) { return 1; } @@ -205,7 +139,7 @@ struct FiniteElement { } } - vec<1> shape_function_derivative(vec2 xi, uint32_t i) const { + vec1 shape_function_derivative(vec2 xi, uint32_t i) const { return shape_function_curl(xi, i); } @@ -217,7 +151,7 @@ struct FiniteElement { return interpolated_value; } - vec<1> curl(vec2 xi, const double * values) const { + vec1 curl(vec2 xi, const double * values) const { double interpolated_curl = 0.0; for (uint32_t i = 0; i < num_nodes(); i++) { interpolated_curl += values[i] * shape_function_curl(xi, i); @@ -247,7 +181,7 @@ struct FiniteElement { void interpolate(nd::view values_q, nd::view values_e, nd::view shape_fn, double * buffer) const { uint32_t n = p + 1; - uint32_t q = sqrt(values_q.shape[0]); + uint32_t q = uint32_t(sqrt(values_q.shape[0])); // 1D shape function evaluations nd::view B1(shape_fn.data(), {q, p}); // legendre shape functions @@ -256,7 +190,7 @@ struct FiniteElement { nd::view A1(buffer, {q, n}); // storage for intermediates nd::view ue(values_e.data(), {n, p}); - nd::view uq((double*)values_q.data(), {q, q}, {2*q, 2}); + nd::view uq(static_cast(&values_q[0][0]), {q, q}, {2*q, 2}); _contract(A1, B1, ue); // A1(qx, iy) = sum_{ix} B1(qx, ix) * ue(iy, ix) _contract(uq, B2, A1); // uq(qy, qx) = sum_{iy} B2(qy, iy) * A1(qx, iy) @@ -265,7 +199,7 @@ struct FiniteElement { // note: column-major strides here, since quadrature points are still // enumerated lexicographically as {y, x} but y-component nodes are {x, y} - uq = nd::view(((double*)values_q.data())+1, {q, q}, {2, 2*q}); + uq = nd::view(static_cast(&values_q[0][0])+1, {q, q}, {2, 2*q}); _contract(A1, B1, ue); // A1(qx, iy) = sum_{ix} B1(qx, ix) * ue(iy, ix) _contract(uq, B2, A1); // uq(qy, qx) = sum_{iy} B2(qy, iy) * A1(qx, iy) @@ -276,9 +210,9 @@ struct FiniteElement { uint32_t q = xi.shape[0]; nd::array shape_fns({q * q, num_nodes()}); for (uint32_t i = 0; i < q; i++) { - for (int j = 0; j < q; j++) { + for (uint32_t j = 0; j < q; j++) { vec2 xi_ij = vec2{xi(j, 0), xi(i, 0)}; - for (int k = 0; k < num_nodes(); k++) { + for (uint32_t k = 0; k < num_nodes(); k++) { shape_fns(i * q + j, k) = shape_function_curl(xi_ij, k); } } @@ -303,10 +237,10 @@ struct FiniteElement { uint32_t q = xi.shape[0]; nd::array shape_fns({q * q, num_nodes(), dim}); uint32_t qcount = 0; - for (int j = 0; j < q; j++) { + for (uint32_t j = 0; j < q; j++) { for (uint32_t i = 0; i < q; i++) { vec2 xi_ij = vec2{xi(i, 0), xi(j, 0)}; - for (int l = 0; l < num_nodes(); l++) { + for (uint32_t l = 0; l < num_nodes(); l++) { vec2 phi = shape_function(xi_ij, l); shape_fns(qcount, l, 0) = phi[0] * weights[i] * weights[j]; shape_fns(qcount, l, 1) = phi[1] * weights[i] * weights[j]; @@ -324,7 +258,7 @@ struct FiniteElement { for (uint32_t i = 0; i < nnodes; i++) { double sum = 0.0; for (uint32_t q = 0; q < nqpts; q++) { - for (int j = 0; j < dim; j++) { + for (uint32_t j = 0; j < dim; j++) { sum += shape_fn(q, i, j) * source_q(q)[j]; } } @@ -336,10 +270,10 @@ struct FiniteElement { uint32_t q = xi.shape[0]; nd::array shape_fns({q * q, num_nodes()}); uint32_t qcount = 0; - for (int j = 0; j < q; j++) { + for (uint32_t j = 0; j < q; j++) { for (uint32_t i = 0; i < q; i++) { vec2 xi_ij = vec2{xi(i, 0), xi(j, 0)}; - for (int l = 0; l < num_nodes(); l++) { + for (uint32_t l = 0; l < num_nodes(); l++) { shape_fns(qcount, l) = shape_function_curl(xi_ij, l) * weights[i] * weights[j]; } qcount++; diff --git a/src/serac/numerics/refactor/elements/hcurl_tetrahedron.hpp b/src/serac/numerics/refactor/elements/hcurl_tetrahedron.hpp index b351b7bb25..5f3dcf7eae 100644 --- a/src/serac/numerics/refactor/elements/hcurl_tetrahedron.hpp +++ b/src/serac/numerics/refactor/elements/hcurl_tetrahedron.hpp @@ -1,13 +1,11 @@ #pragma once -#include "fm/types/vec.hpp" -#include "fm/types/matrix.hpp" +#include "serac/numerics/functional/tensor.hpp" -#include "fm/operations/print.hpp" // REMOVE namespace refactor { -using namespace fm; +using namespace serac; // clang-format off template <> @@ -23,101 +21,6 @@ struct FiniteElement { SERAC_HOST_DEVICE constexpr uint32_t num_nodes() const { return (p * (p + 2) * (p + 3)) / 2; } - SERAC_HOST_DEVICE void reorient(const TransformationType type, const Connection * tet, int8_t * transformation) { - - const Connection * edge = tet + Tetrahedron::edge_offset; - const Connection * tri = tet + Tetrahedron::tri_offset; - - uint32_t count = 0; - - // edge nodes - for (uint32_t i = 0; i < Tetrahedron::num_edges; i++) { - if (edge[i].sign() == Sign::Positive) { - for (uint32_t j = 0; j < p; j++) { - transformation[count++] = 0; - } - } else { - for (uint32_t j = 0; j < p; j++) { - transformation[count++] = -1; - } - } - } - - if (p == 1) return; - - // face nodes - for (uint32_t i = 0; i < Tetrahedron::num_triangles; i++) { - if (tri[i].sign() == Sign::Negative) { - for (uint32_t j = 0; j < Triangle::number(p - 1); j++) { - transformation[count++] = face_transformation_id(type, tri[i].orientation()); - transformation[count++] = face_transformation_id(type, tri[i].orientation()); - } - } else { - for (uint32_t j = 0; j < Triangle::number(p - 1); j++) { - transformation[count++] = 0; - transformation[count++] = 0; - } - } - } - - if (p == 2) return; - - // interior nodes - transformation[count++] = 0; - transformation[count++] = 0; - transformation[count++] = 0; - - } - - template < typename T > - SERAC_HOST_DEVICE void reorient(const TransformationType type, const Connection * tet, T * values) { - - const Connection * edge = tet + Tetrahedron::edge_offset; - const Connection * tri = tet + Tetrahedron::tri_offset; - - uint32_t count = 0; - - // edge nodes - if (type == TransformationType::PhysicalToParent || - type == TransformationType::TransposePhysicalToParent) { - for (uint32_t i = 0; i < Tetrahedron::num_edges; i++) { - if (edge[i].sign() == Sign::Negative) { - for (uint32_t j = 0; j < p; j++) { - values[count++] *= -1.0; - } - } else { - count += p; - } - } - } else { - count += p * Tetrahedron::num_edges; - } - - if (p == 1) return; - - constexpr mat2 A[3][3] = { - {{{{0, 1}, {1, 0}}}, {{{-1, 0}, {-1, 1}}}, {{{1, -1}, {0, -1}}}}, // PhysicalToParent - {{{{0, 1}, {1, 0}}}, {{{-1, -1}, {0, 1}}}, {{{1, 0}, {-1, -1}}}}, // TransposePhysicalToParent - }; - - // face nodes - for (uint32_t i = 0; i < Tetrahedron::num_triangles; i++) { - if (tri[i].sign() == Sign::Negative) { - uint32_t o = tri[i].orientation(); - mat2 Ao = A[uint32_t(type)][o]; - for (int j = 0; j < Triangle::number(p - 1); j++) { - T v[2] = {values[count], values[count+1]}; - values[count] = Ao[0][0] * v[0] + Ao[0][1] * v[1]; - values[count+1] = Ao[1][0] * v[0] + Ao[1][1] * v[1]; - count += 2; - } - } else { - count += 2 * Triangle::number(p - 1); - } - } - - } - constexpr vec3 shape_function(vec3 xi, uint32_t i) const { // expressions generated symbolically by mathematica if (p == 1) { @@ -1194,7 +1097,7 @@ struct FiniteElement { return interpolated_curl; } - SERAC_HOST_DEVICE uint32_t batch_interpolation_scratch_space(nd::view xi) const { + SERAC_HOST_DEVICE uint32_t batch_interpolation_scratch_space(nd::view) const { return 0; } @@ -1203,7 +1106,7 @@ struct FiniteElement { nd::array shape_fns({q, num_nodes(), dim}); for (uint32_t i = 0; i < q; i++) { vec3 xi_i = vec3{xi(i, 0), xi(i, 1), xi(i, 2)}; - for (int j = 0; j < num_nodes(); j++) { + for (uint32_t j = 0; j < num_nodes(); j++) { vec3 phi_j = shape_function(xi_i, j); shape_fns(i, j, 0) = phi_j[0]; shape_fns(i, j, 1) = phi_j[1]; @@ -1220,7 +1123,7 @@ struct FiniteElement { for (uint32_t q = 0; q < nqpts; q++) { value_type sum{}; for (uint32_t i = 0; i < nnodes; i++) { - for (int j = 0; j < dim; j++) { + for (uint32_t j = 0; j < dim; j++) { sum[j] += shape_fns(q, i, j) * values_e(i); } } @@ -1233,7 +1136,7 @@ struct FiniteElement { nd::array shape_fns({q, num_nodes(), 3}); for (uint32_t i = 0; i < q; i++) { vec3 xi_i = vec3{xi(i, 0), xi(i, 1), xi(i, 2)}; - for (int j = 0; j < num_nodes(); j++) { + for (uint32_t j = 0; j < num_nodes(); j++) { vec3 curl_phi_j = shape_function_curl(xi_i, j); shape_fns(i, j, 0) = curl_phi_j[0]; shape_fns(i, j, 1) = curl_phi_j[1]; @@ -1250,7 +1153,7 @@ struct FiniteElement { for (uint32_t q = 0; q < nqpts; q++) { derivative_type sum{}; for (uint32_t i = 0; i < nnodes; i++) { - for (int j = 0; j < dim; j++) { + for (uint32_t j = 0; j < dim; j++) { sum[j] += shape_fn_curls(q, i, j) * values_e(i); } } @@ -1263,7 +1166,7 @@ struct FiniteElement { nd::array shape_fns({q, num_nodes(), dim}); for (uint32_t i = 0; i < q; i++) { vec3 xi_i = vec3{xi(i, 0), xi(i, 1), xi(i, 2)}; - for (int j = 0; j < num_nodes(); j++) { + for (uint32_t j = 0; j < num_nodes(); j++) { vec3 phi_j = shape_function(xi_i, j); shape_fns(i, j, 0) = phi_j[0] * weights[i]; shape_fns(i, j, 1) = phi_j[1] * weights[i]; @@ -1280,7 +1183,7 @@ struct FiniteElement { for (uint32_t i = 0; i < nnodes; i++) { double sum = 0.0; for (uint32_t q = 0; q < nqpts; q++) { - for (int j = 0; j < dim; j++) { + for (uint32_t j = 0; j < dim; j++) { sum += shape_fn(q, i, j) * source_q(q)[j]; } } @@ -1293,7 +1196,7 @@ struct FiniteElement { nd::array shape_fns({q, num_nodes(), dim}); for (uint32_t i = 0; i < q; i++) { vec3 xi_i = vec3{xi(i, 0), xi(i, 1), xi(i, 2)}; - for (int j = 0; j < num_nodes(); j++) { + for (uint32_t j = 0; j < num_nodes(); j++) { vec3 dphi_j = shape_function_curl(xi_i, j); shape_fns(i, j, 0) = dphi_j[0] * weights[i]; shape_fns(i, j, 1) = dphi_j[1] * weights[i]; @@ -1310,7 +1213,7 @@ struct FiniteElement { for (uint32_t i = 0; i < nnodes; i++) { double sum = 0.0; for (uint32_t q = 0; q < nqpts; q++) { - for (int j = 0; j < dim; j++) { + for (uint32_t j = 0; j < dim; j++) { sum += shape_fn(q, i, j) * flux_q(q)[j]; } } diff --git a/src/serac/numerics/refactor/elements/hcurl_triangle.hpp b/src/serac/numerics/refactor/elements/hcurl_triangle.hpp index b7fadd4892..f5a542ce26 100644 --- a/src/serac/numerics/refactor/elements/hcurl_triangle.hpp +++ b/src/serac/numerics/refactor/elements/hcurl_triangle.hpp @@ -1,10 +1,10 @@ #pragma once -#include "fm/types/vec.hpp" +#include "serac/numerics/functional/tensor.hpp" namespace refactor { -using namespace fm; +using namespace serac; // clang-format off template <> @@ -20,6 +20,10 @@ struct FiniteElement { SERAC_HOST_DEVICE uint32_t num_nodes() const { return p * (p + 2); } + #if 0 + // sam: we don't have a good way to get the orientation info from mfem into the cuda kernel + // so hcurl elements need to be handled slightly differently (e.g. the reorientation could happen in the + // "ElementRestriction" operators instead) template < typename T > SERAC_HOST_DEVICE void reorient(const TransformationType type, const Connection * tri, T * values) const { @@ -58,6 +62,7 @@ struct FiniteElement { } } + #endif constexpr vec2 shape_function(vec2 xi, uint32_t i) const { if (p == 1) { @@ -221,7 +226,7 @@ struct FiniteElement { } } - vec<1> shape_function_curl(vec2 xi, uint32_t i) const { + vec1 shape_function_curl(vec2 xi, uint32_t i) const { // expressions generated symbolically by mathematica if (p == 1) { return 2.0; @@ -265,11 +270,11 @@ struct FiniteElement { } } - vec<1> shape_function_derivative(vec2 xi, uint32_t i) const { + vec1 shape_function_derivative(vec2 xi, uint32_t i) const { return shape_function_curl(xi, i); } - vec<1> shape_function_div(const double * xi, uint32_t i) const { + vec1 shape_function_div(const double * xi, uint32_t i) const { // expressions generated symbolically by mathematica if (p == 1) { return 0.0; @@ -321,7 +326,7 @@ struct FiniteElement { return interpolated_curl; } - SERAC_HOST_DEVICE uint32_t batch_interpolation_scratch_space(nd::view xi) const { + SERAC_HOST_DEVICE uint32_t batch_interpolation_scratch_space(nd::view) const { return 0; } @@ -330,7 +335,7 @@ struct FiniteElement { nd::array shape_fns({q, num_nodes(), dim}); for (uint32_t i = 0; i < q; i++) { vec2 xi_i = vec2{xi(i, 0), xi(i, 1)}; - for (int j = 0; j < num_nodes(); j++) { + for (uint32_t j = 0; j < num_nodes(); j++) { vec2 phi_j = shape_function(xi_i, j); shape_fns(i, j, 0) = phi_j[0]; shape_fns(i, j, 1) = phi_j[1]; @@ -346,7 +351,7 @@ struct FiniteElement { for (uint32_t q = 0; q < nqpts; q++) { value_type sum{}; for (uint32_t i = 0; i < nnodes; i++) { - for (int j = 0; j < dim; j++) { + for (uint32_t j = 0; j < dim; j++) { sum[j] += shape_fns(q, i, j) * values_e(i); } } @@ -359,7 +364,7 @@ struct FiniteElement { nd::array shape_fns({q, num_nodes()}); for (uint32_t i = 0; i < q; i++) { vec2 xi_i = vec2{xi(i, 0), xi(i, 1)}; - for (int j = 0; j < num_nodes(); j++) { + for (uint32_t j = 0; j < num_nodes(); j++) { shape_fns(i, j) = shape_function_curl(xi_i, j); } } @@ -384,7 +389,7 @@ struct FiniteElement { nd::array shape_fns({q, num_nodes(), dim}); for (uint32_t i = 0; i < q; i++) { vec2 xi_i = vec2{xi(i, 0), xi(i, 1)}; - for (int j = 0; j < num_nodes(); j++) { + for (uint32_t j = 0; j < num_nodes(); j++) { vec2 phi_j = shape_function(xi_i, j); shape_fns(i, j, 0) = phi_j[0] * weights[i]; shape_fns(i, j, 1) = phi_j[1] * weights[i]; @@ -400,7 +405,7 @@ struct FiniteElement { for (uint32_t i = 0; i < nnodes; i++) { double sum = 0.0; for (uint32_t q = 0; q < nqpts; q++) { - for (int j = 0; j < dim; j++) { + for (uint32_t j = 0; j < dim; j++) { sum += shape_fn(q, i, j) * source_q(q)[j]; } } @@ -413,7 +418,7 @@ struct FiniteElement { nd::array shape_fns({q, num_nodes()}); for (uint32_t i = 0; i < q; i++) { vec2 xi_i = vec2{xi(i, 0), xi(i, 1)}; - for (int j = 0; j < num_nodes(); j++) { + for (uint32_t j = 0; j < num_nodes(); j++) { shape_fns(i, j) = shape_function_curl(xi_i, j) * weights[i]; } } diff --git a/src/serac/numerics/refactor/evaluate.hpp b/src/serac/numerics/refactor/evaluate.hpp index 6ece0bbd40..5f0f5c3e45 100644 --- a/src/serac/numerics/refactor/evaluate.hpp +++ b/src/serac/numerics/refactor/evaluate.hpp @@ -7,8 +7,6 @@ namespace refactor { using Field = serac::FiniteElementState; -enum class Modifier { NONE, DIAGONAL, SYM }; -enum class DerivedQuantity { VALUE, DERIVATIVE }; inline bool is_value(DerivedQuantity op) { return op == DerivedQuantity::VALUE; diff --git a/src/serac/numerics/refactor/finite_element.hpp b/src/serac/numerics/refactor/finite_element.hpp index ee8d18cdd7..773bdda66d 100644 --- a/src/serac/numerics/refactor/finite_element.hpp +++ b/src/serac/numerics/refactor/finite_element.hpp @@ -17,6 +17,9 @@ enum class Family { DG }; +enum class Modifier { NONE, DIAGONAL, SYM }; +enum class DerivedQuantity { VALUE, DERIVATIVE }; + SERAC_HOST_DEVICE constexpr bool is_scalar_valued(Family f) { return (f == Family::H1); } diff --git a/src/serac/numerics/refactor/geometry.hpp b/src/serac/numerics/refactor/geometry.hpp index 38b109fd3a..d6cfb7ea72 100644 --- a/src/serac/numerics/refactor/geometry.hpp +++ b/src/serac/numerics/refactor/geometry.hpp @@ -243,7 +243,7 @@ struct GeometryType< mfem::Geometry::TETRAHEDRON > { static constexpr int local_edge_ids[6][2] = {{0, 1}, {1, 2}, {2, 0}, {0, 3}, {1, 3}, {2, 3}}; static constexpr int local_triangle_ids[4][3] = {{2, 1, 0}, {0, 1, 3}, {1, 2, 3}, {2, 0, 3}}; - SERAC_HOST_DEVICE static constexpr int number(int n) { return (n * (n + 1) * (n + 2)) / 6; } + SERAC_HOST_DEVICE static constexpr uint32_t number(uint32_t n) { return (n * (n + 1) * (n + 2)) / 6; } }; using Tetrahedron = GeometryType< mfem::Geometry::TETRAHEDRON >; diff --git a/src/serac/numerics/refactor/integrate_residual.cpp b/src/serac/numerics/refactor/integrate_residual.cpp index fd94524bad..dfa16a4bac 100644 --- a/src/serac/numerics/refactor/integrate_residual.cpp +++ b/src/serac/numerics/refactor/integrate_residual.cpp @@ -4,8 +4,8 @@ #include "refactor/assert.hpp" #include "refactor/threadpool.hpp" -#include "fm/types/matrix.hpp" -#include "fm/types/vec.hpp" + +#include "serac/numerics/functional/tensor.hpp" #include "common.hpp" diff --git a/src/serac/numerics/refactor/tests/hcurl_evaluation_tests.cpp b/src/serac/numerics/refactor/tests/hcurl_evaluation_tests.cpp index d873ea8615..56227c1273 100644 --- a/src/serac/numerics/refactor/tests/hcurl_evaluation_tests.cpp +++ b/src/serac/numerics/refactor/tests/hcurl_evaluation_tests.cpp @@ -12,10 +12,10 @@ #include "misc/for_constexpr.hpp" #include "forall.hpp" -#include "fm/types/vec.hpp" -#include "fm/types/matrix.hpp" +#include "serac/numerics/functional/tensor.hpp" -using namespace fm; + +using namespace serac; using namespace refactor; template < typename vec_t, typename curl_t> diff --git a/src/serac/numerics/refactor/tests/integrate_residual_H1_flux_tests.cpp b/src/serac/numerics/refactor/tests/integrate_residual_H1_flux_tests.cpp index 0be285c718..00d28f67ad 100644 --- a/src/serac/numerics/refactor/tests/integrate_residual_H1_flux_tests.cpp +++ b/src/serac/numerics/refactor/tests/integrate_residual_H1_flux_tests.cpp @@ -8,11 +8,11 @@ #include "refactor/domain.hpp" #include "forall.hpp" -#include "fm/types/vec.hpp" -#include "fm/types/matrix.hpp" +#include "serac/numerics/functional/tensor.hpp" + #include "containers/ndarray_conversions.hpp" -using namespace fm; +using namespace serac; using namespace refactor; // ---------------------------------------------------------------------------- diff --git a/src/serac/numerics/refactor/tests/integrate_residual_H1_source_tests.cpp b/src/serac/numerics/refactor/tests/integrate_residual_H1_source_tests.cpp index fa2e6ad27e..0c32287ee9 100644 --- a/src/serac/numerics/refactor/tests/integrate_residual_H1_source_tests.cpp +++ b/src/serac/numerics/refactor/tests/integrate_residual_H1_source_tests.cpp @@ -10,8 +10,8 @@ #include #include "forall.hpp" -#include "fm/types/vec.hpp" -#include "fm/types/matrix.hpp" +#include "serac/numerics/functional/tensor.hpp" + #include "containers/ndarray_conversions.hpp" using namespace refactor; diff --git a/src/serac/numerics/refactor/tests/integrate_residual_H1v_flux_tests.cpp b/src/serac/numerics/refactor/tests/integrate_residual_H1v_flux_tests.cpp index fd082514b1..052cff750f 100644 --- a/src/serac/numerics/refactor/tests/integrate_residual_H1v_flux_tests.cpp +++ b/src/serac/numerics/refactor/tests/integrate_residual_H1v_flux_tests.cpp @@ -10,8 +10,8 @@ #include #include "forall.hpp" -#include "fm/types/vec.hpp" -#include "fm/types/matrix.hpp" +#include "serac/numerics/functional/tensor.hpp" + #include "containers/ndarray_conversions.hpp" using namespace refactor; diff --git a/src/serac/numerics/refactor/tests/integrate_residual_Hcurl_flux_tests.cpp b/src/serac/numerics/refactor/tests/integrate_residual_Hcurl_flux_tests.cpp index ee0ac5c2d4..b6dfb6da62 100644 --- a/src/serac/numerics/refactor/tests/integrate_residual_Hcurl_flux_tests.cpp +++ b/src/serac/numerics/refactor/tests/integrate_residual_Hcurl_flux_tests.cpp @@ -10,8 +10,8 @@ #include #include "forall.hpp" -#include "fm/types/vec.hpp" -#include "fm/types/matrix.hpp" +#include "serac/numerics/functional/tensor.hpp" + #include "containers/ndarray_conversions.hpp" using namespace refactor; diff --git a/src/serac/numerics/refactor/tests/integrate_residual_Hcurl_source_tests.cpp b/src/serac/numerics/refactor/tests/integrate_residual_Hcurl_source_tests.cpp index d961470d50..a3a9db01ed 100644 --- a/src/serac/numerics/refactor/tests/integrate_residual_Hcurl_source_tests.cpp +++ b/src/serac/numerics/refactor/tests/integrate_residual_Hcurl_source_tests.cpp @@ -10,8 +10,8 @@ #include #include "forall.hpp" -#include "fm/types/vec.hpp" -#include "fm/types/matrix.hpp" +#include "serac/numerics/functional/tensor.hpp" + #include "containers/ndarray_conversions.hpp" using namespace refactor; From 9643679b0be8a896f9f01bf829c119da033f9121 Mon Sep 17 00:00:00 2001 From: Sam Mish Date: Tue, 17 Dec 2024 11:25:02 -0800 Subject: [PATCH 08/15] add ndarray tests, fixing more includes/compilation errors --- src/serac/numerics/refactor/CMakeLists.txt | 4 +- src/serac/numerics/refactor/common.cpp | 121 ---------- .../refactor/containers/CMakeLists.txt | 35 +++ .../numerics/refactor/containers/ndarray.hpp | 29 +-- .../refactor/containers/tests/CMakeLists.txt | 21 ++ .../containers/tests/accessor_tests.cpp | 213 ++++++++++++++++++ .../containers/tests/accessor_tests.cu | 158 +++++++++++++ .../refactor/containers/tests/common.hpp | 69 ++++++ .../refactor/containers/tests/ctor_tests.cpp | 59 +++++ .../containers/tests/reshape_tests.cpp | 53 +++++ .../containers/tests/stride_tests.cpp | 51 +++++ .../refactor/containers/tests/usage_tests.cpp | 54 +++++ .../numerics/refactor/integrate_diag.cpp | 8 - .../numerics/refactor/integrate_residual.cpp | 174 ++++++-------- .../numerics/refactor/integrate_spmat.cpp | 210 ++++++++--------- 15 files changed, 900 insertions(+), 359 deletions(-) create mode 100644 src/serac/numerics/refactor/containers/CMakeLists.txt create mode 100644 src/serac/numerics/refactor/containers/tests/CMakeLists.txt create mode 100644 src/serac/numerics/refactor/containers/tests/accessor_tests.cpp create mode 100644 src/serac/numerics/refactor/containers/tests/accessor_tests.cu create mode 100644 src/serac/numerics/refactor/containers/tests/common.hpp create mode 100644 src/serac/numerics/refactor/containers/tests/ctor_tests.cpp create mode 100644 src/serac/numerics/refactor/containers/tests/reshape_tests.cpp create mode 100644 src/serac/numerics/refactor/containers/tests/stride_tests.cpp create mode 100644 src/serac/numerics/refactor/containers/tests/usage_tests.cpp diff --git a/src/serac/numerics/refactor/CMakeLists.txt b/src/serac/numerics/refactor/CMakeLists.txt index 0086126b69..05871ee6ce 100644 --- a/src/serac/numerics/refactor/CMakeLists.txt +++ b/src/serac/numerics/refactor/CMakeLists.txt @@ -4,6 +4,8 @@ # # SPDX-License-Identifier: (BSD-3-Clause) +add_subdirectory(containers) + set(refactor_headers elements/h1_edge.hpp @@ -34,7 +36,7 @@ set(refactor_sources integrate_residual.cpp ) -set(refactor_depends serac_infrastructure serac_functional) +set(refactor_depends serac_infrastructure serac_functional serac_refactor_containers) blt_add_library( NAME serac_refactor diff --git a/src/serac/numerics/refactor/common.cpp b/src/serac/numerics/refactor/common.cpp index e5fa640ae9..562ddb5509 100644 --- a/src/serac/numerics/refactor/common.cpp +++ b/src/serac/numerics/refactor/common.cpp @@ -1,13 +1,5 @@ #include "common.hpp" -#include "refactor/domain.hpp" -#include "refactor/assert.hpp" -#include "refactor/threadpool.hpp" - -#include "misc/timer.hpp" - -#include "parallel_hashmap/phmap.h" - namespace refactor { uint32_t elements_per_block(mfem::Geometry::Type geom, Family family, int p) { @@ -55,117 +47,4 @@ uint32_t elements_per_block(mfem::Geometry::Type geom, Family family, int p) { } -template < mfem::Geometry::Type geom, Family test_family, Family trial_family > -void sparsity_pattern(std::vector< phmap::flat_hash_set< int > > & column_ids, - FunctionSpace trial_space, - FunctionSpace test_space, - GeometryInfo trial_offsets, - GeometryInfo test_offsets, - nd::view elements, - nd::view connectivity) { - - FiniteElement< geom, test_family > test_el{test_space.degree}; - FiniteElement< geom, trial_family > trial_el{trial_space.degree}; - - // allocate storage for an element's nodal forces - constexpr uint32_t gdim = dimension(geom); - - uint32_t num_elements = elements.shape[0]; - uint32_t test_components = test_space.components; - uint32_t trial_components = trial_space.components; - uint32_t nodes_per_test_element = test_el.num_nodes(); - uint32_t nodes_per_trial_element = trial_el.num_nodes(); - - constexpr int nmutex = 1024; - std::vector< std::mutex > mutexes(nmutex); - - threadpool::parallel_for(num_elements, [&](uint32_t e){ - nd::array test_ids({nodes_per_test_element}); - nd::array trial_ids({nodes_per_trial_element}); - - // get the ids of nodes for that element - test_el.indices(test_offsets, connectivity(elements(e)).data(), test_ids.data()); - trial_el.indices(trial_offsets, connectivity(elements(e)).data(), trial_ids.data()); - - for (int i = 0; i < test_ids.shape[0]; i++) { - for (int ci = 0; ci < test_components; ci++) { - int row_id = test_ids[i] * test_components + ci; - - int which = row_id % nmutex; - mutexes[which].lock(); - auto & row = column_ids[row_id]; - for (int j = 0; j < trial_ids.shape[0]; j++) { - for (int cj = 0; cj < trial_components; cj++) { - row.insert(trial_ids[j] * trial_components + cj); - } - } - mutexes[which].unlock(); - } - } - }); - -} - -refactor::sparse_matrix blank_sparse_matrix(BasisFunctionOp test, BasisFunctionOp trial, const Domain &domain) { - - MTR_SCOPE("integrate_spmat", "blank_sparse_matrix"); - - auto phi = test.function.space; - auto psi = trial.function.space; - - uint32_t test_components = phi.components; - uint32_t trial_components = psi.components; - uint32_t sdim = domain.mesh.spatial_dimension; - uint32_t gdim = domain.mesh.geometry_dimension; - - auto dofs_per_psi = dofs_per_geom(psi); - auto dofs_per_phi = dofs_per_geom(phi); - - GeometryInfo counts = domain.mesh.geometry_counts(); - GeometryInfo test_offsets = scan(interior_nodes_per_geom(phi) * counts); - GeometryInfo trial_offsets = scan(interior_nodes_per_geom(psi) * counts); - auto nrows = total(interior_dofs_per_geom(phi) * counts); - auto ncols = total(interior_dofs_per_geom(psi) * counts); - - std::vector< phmap::flat_hash_set > column_ids(nrows); - foreach_geometry([&](auto geom){ - nd::view elements = domain.active_elements[geom]; - if (gdim == dimension(geom) && elements.size() > 0) { - nd::view connectivity = domain.mesh[geom]; - foreach_constexpr< Family::H1, Family::Hcurl >([&](auto test_family) { - foreach_constexpr< Family::H1, Family::Hcurl >([&](auto trial_family) { - if (test_family == phi.family && trial_family == psi.family) { - sparsity_pattern(column_ids, psi, phi, trial_offsets, test_offsets, elements, connectivity); - } - }); - }); - } - }); - - refactor::sparse_matrix A; - A.nrows = nrows; - A.ncols = ncols; - A.nnz = 0; - A.row_ptr.resize(nrows + 1); - A.row_ptr[0] = 0; - - for (int i = 0; i < nrows; i++) { - int nz_per_row = column_ids[i].size(); - A.nnz += nz_per_row; - A.row_ptr[i+1] = A.row_ptr[i] + nz_per_row; - } - A.col_ind.resize(A.nnz); - A.values.resize(A.nnz); - - threadpool::parallel_for(nrows, [&](int i){ - int offset = A.row_ptr[i]; - for (int col : column_ids[i]) { - A.col_ind[offset++] = col; - } - std::sort(&A.col_ind[A.row_ptr[i]], &A.col_ind[A.row_ptr[i+1]]); - }); - - return A; -} - } // namespace refactor diff --git a/src/serac/numerics/refactor/containers/CMakeLists.txt b/src/serac/numerics/refactor/containers/CMakeLists.txt new file mode 100644 index 0000000000..f517f97683 --- /dev/null +++ b/src/serac/numerics/refactor/containers/CMakeLists.txt @@ -0,0 +1,35 @@ +# Copyright (c) 2019-2024, Lawrence Livermore National Security, LLC and +# other Serac Project Developers. See the top-level LICENSE file for +# details. +# +# SPDX-License-Identifier: (BSD-3-Clause) + +set(refactor_containers_headers + ndarray.hpp + stack_array.hpp +) + +set(refactor_containers_sources + memory.cpp + relative_error.cpp +) + +set(refactor_containers_depends serac_infrastructure) + +blt_add_library( + NAME serac_refactor_containers + HEADERS ${refactor_containers_headers} + SOURCES ${refactor_containers_sources} + DEPENDS_ON ${refactor_containers_depends} + ) + +install(FILES ${refactor_containers_headers} DESTINATION include/serac/refactor/containers ) + +install(TARGETS serac_refactor_containers + EXPORT serac-targets + DESTINATION lib + ) + +if(SERAC_ENABLE_TESTS) + add_subdirectory(tests) +endif() diff --git a/src/serac/numerics/refactor/containers/ndarray.hpp b/src/serac/numerics/refactor/containers/ndarray.hpp index e57d22df98..c0bca4dbb7 100644 --- a/src/serac/numerics/refactor/containers/ndarray.hpp +++ b/src/serac/numerics/refactor/containers/ndarray.hpp @@ -44,7 +44,7 @@ namespace nd { template < uint32_t dim > SERAC_HOST_DEVICE uint32_t product(stack::array< uint32_t, dim > values) { uint32_t p = values[0]; - for (int i = 1; i < dim; i++) { p *= values[i]; } + for (uint32_t i = 1; i < dim; i++) { p *= values[i]; } return p; } @@ -53,11 +53,14 @@ namespace nd { template < uint32_t dim > SERAC_HOST_DEVICE stack::array< uint32_t, dim > compute_strides(const stack::array< uint32_t, dim > & shape, ordering o, uint32_t m = 1) { stack::array< uint32_t, dim > strides{}; - int32_t k = (o == col_major) ? 0 : dim-1; - int32_t s = (o == col_major) ? 1 : -1; - for (uint32_t i = 0; i < dim; i++) { - strides[k] = (i == 0) ? m : strides[k-s] * shape[k-s]; - k += s; + if (o == col_major) { + for (uint32_t i = 0; i < dim; i++) { + strides[i] = (i == 0) ? m : strides[i-1] * shape[i-1]; + } + } else { // row major + for (uint32_t i = 0; i < dim; i++) { + strides[dim-i-1] = (i == 0) ? m : strides[dim-i] * shape[dim-i]; + } } return strides; } @@ -140,7 +143,7 @@ namespace nd { printf("array index out of bounds\n"); }; #endif - return ((indices * stride[I]) + ...); + return ((static_cast(indices) * stride[I]) + ...); } template < typename ... index_types > @@ -281,7 +284,7 @@ namespace nd { printf("array index out of bounds\n"); }; #endif - return ((indices * stride[I]) + ...); + return ((static_cast(indices) * stride[I]) + ...); } template < typename ... index_types > @@ -298,9 +301,9 @@ namespace nd { uint32_t beginnings[num_args] = {uint32_t(nd::begin(indices)) ... }; uint32_t endings[num_args] = {uint32_t(nd::end(indices)) ... }; - int k = 0; - int offset = 0; - for (int i = 0; i < dim; i++) { + uint32_t k = 0; + uint32_t offset = 0; + for (uint32_t i = 0; i < dim; i++) { if (i >= num_args) { slice_shape[k] = shape[i]; slice_stride[k] = stride[i]; @@ -404,8 +407,8 @@ namespace nd { void resize(const stack::array< uint32_t, dim > & new_shape) { shape = new_shape; _resize(product(shape)); - for (uint64_t i = 0; i < dim; i++) { - uint64_t id = dim - 1 - i; + for (uint32_t i = 0; i < dim; i++) { + uint32_t id = dim - 1 - i; stride[id] = (id == dim - 1) ? 1 : stride[id+1] * shape[id+1]; } } diff --git a/src/serac/numerics/refactor/containers/tests/CMakeLists.txt b/src/serac/numerics/refactor/containers/tests/CMakeLists.txt new file mode 100644 index 0000000000..18db9725ce --- /dev/null +++ b/src/serac/numerics/refactor/containers/tests/CMakeLists.txt @@ -0,0 +1,21 @@ +# Copyright (c) 2019-2024, Lawrence Livermore National Security, LLC and +# other Serac Project Developers. See the top-level LICENSE file for +# details. +# +# SPDX-License-Identifier: (BSD-3-Clause) + +set(refactor_container_test_dependencies serac_refactor gtest) + +set(refactor_container_test_sources + accessor_tests.cpp + ctor_tests.cpp + reshape_tests.cpp + stride_tests.cpp + usage_tests.cpp +) + +# TODO register CUDA tests + +serac_add_tests( SOURCES ${refactor_container_test_sources} + DEPENDS_ON ${refactor_container_test_dependencies} + NUM_MPI_TASKS 1) diff --git a/src/serac/numerics/refactor/containers/tests/accessor_tests.cpp b/src/serac/numerics/refactor/containers/tests/accessor_tests.cpp new file mode 100644 index 0000000000..16546c51fa --- /dev/null +++ b/src/serac/numerics/refactor/containers/tests/accessor_tests.cpp @@ -0,0 +1,213 @@ +#include + +#include "common.hpp" + +TEST(UnitTest, BasicAccess) { + + nd::array< double, 2 > arr2D = make_patterned_ndarray(stack::array{7u, 8u}); + EXPECT_EQ(arr2D(0, 0), 00); + EXPECT_EQ(arr2D(1, 0), 10); + EXPECT_EQ(arr2D(2, 1), 21); + EXPECT_EQ(arr2D(4, 2), 42); + EXPECT_EQ(arr2D(6, 7), 67); + + nd::view< double, 2 > view2D = arr2D; + EXPECT_EQ(view2D(0, 0), 00); + EXPECT_EQ(view2D(1, 0), 10); + EXPECT_EQ(view2D(2, 1), 21); + EXPECT_EQ(view2D(4, 2), 42); + EXPECT_EQ(view2D(6, 7), 67); + + nd::array< double, 3 > arr3D = make_patterned_ndarray(stack::array{6u, 7u, 8u}); + EXPECT_EQ(arr3D(0, 0, 0), 000); + EXPECT_EQ(arr3D(1, 3, 0), 130); + EXPECT_EQ(arr3D(2, 0, 2), 202); + EXPECT_EQ(arr3D(3, 1, 7), 317); + EXPECT_EQ(arr3D(5, 6, 7), 567); + + //#ifdef NDARRAY_ENABLE_BOUNDS_CHECKING + // EXPECT_EQ(arr3D(10, 10, 10), 1000); + //#endif + + nd::view< double, 3 > view3D = arr3D; + EXPECT_EQ(view3D(0, 0, 0), 000); + EXPECT_EQ(view3D(1, 3, 0), 130); + EXPECT_EQ(view3D(2, 0, 2), 202); + EXPECT_EQ(view3D(3, 1, 7), 317); + EXPECT_EQ(view3D(5, 6, 7), 567); + +} + + +TEST(UnitTest, ArraySlicing) { + + nd::array< double, 3 > arr3D = make_patterned_ndarray(stack::array{6u, 7u, 8u}); + + double value = arr3D(1, 2, 3); + arr3D(1,2,3) = value; + + nd::view< double, 2 > slice1 = arr3D(nd::range{2,5}, 4); + EXPECT_EQ(slice1.stride[0], arr3D.stride[0]); + EXPECT_EQ(slice1.stride[1], arr3D.stride[2]); + EXPECT_EQ(slice1.shape[0], 3); + EXPECT_EQ(slice1.shape[1], 8); + EXPECT_EQ(slice1(0,0), arr3D(2,4,0)); + EXPECT_EQ(slice1(1,1), arr3D(3,4,1)); + EXPECT_EQ(slice1(2,2), arr3D(4,4,2)); + + nd::view< double, 1 > slice2 = arr3D(1, 2, nd::range{2,5}); + EXPECT_EQ(slice2.stride[0], arr3D.stride[2]); + EXPECT_EQ(slice2.shape[0], 3); + EXPECT_EQ(slice2(0), arr3D(1,2,2)); + EXPECT_EQ(slice2(1), arr3D(1,2,3)); + EXPECT_EQ(slice2(2), arr3D(1,2,4)); + + nd::view< double, 2 > slice3 = arr3D(nd::range{2,5}, nd::range{1,2}, 4); + EXPECT_EQ(slice3.stride[0], arr3D.stride[0]); + EXPECT_EQ(slice3.stride[1], arr3D.stride[1]); + EXPECT_EQ(slice3.shape[0], 3); + EXPECT_EQ(slice3.shape[1], 1); + EXPECT_EQ(slice3(0,0), arr3D(2,1,4)); + EXPECT_EQ(slice3(1,0), arr3D(3,1,4)); + EXPECT_EQ(slice3(2,0), arr3D(4,1,4)); + + nd::view< double, 3 > slice4 = arr3D(nd::range{1, 2}, nd::range{2, 5}, nd::range{1,2}); + EXPECT_EQ(slice4.stride[0], arr3D.stride[0]); + EXPECT_EQ(slice4.stride[1], arr3D.stride[1]); + EXPECT_EQ(slice4.stride[2], arr3D.stride[2]); + EXPECT_EQ(slice4.shape[0], 1); + EXPECT_EQ(slice4.shape[1], 3); + EXPECT_EQ(slice4.shape[2], 1); + EXPECT_EQ(slice4(0,0,0), arr3D(1, 2, 1)); + EXPECT_EQ(slice4(0,1,0), arr3D(1, 3, 1)); + EXPECT_EQ(slice4(0,2,0), arr3D(1, 4, 1)); + +} + +TEST(UnitTest, ConstArraySlicing) { + + const nd::array< double, 3 > arr3D = make_patterned_ndarray(stack::array{6u, 7u, 8u}); + + nd::view< const double, 2 > slice1 = arr3D(nd::range{2,5}, 4); + EXPECT_EQ(slice1.stride[0], arr3D.stride[0]); + EXPECT_EQ(slice1.stride[1], arr3D.stride[2]); + EXPECT_EQ(slice1.shape[0], 3); + EXPECT_EQ(slice1.shape[1], 8); + EXPECT_EQ(slice1(0,0), arr3D(2,4,0)); + EXPECT_EQ(slice1(1,1), arr3D(3,4,1)); + EXPECT_EQ(slice1(2,2), arr3D(4,4,2)); + + nd::view< const double, 1 > slice2 = arr3D(1, 2, nd::range{2,5}); + EXPECT_EQ(slice2.stride[0], arr3D.stride[2]); + EXPECT_EQ(slice2.shape[0], 3); + EXPECT_EQ(slice2(0), arr3D(1,2,2)); + EXPECT_EQ(slice2(1), arr3D(1,2,3)); + EXPECT_EQ(slice2(2), arr3D(1,2,4)); + + nd::view< const double, 2 > slice3 = arr3D(nd::range{2,5}, nd::range{1,2}, 4); + EXPECT_EQ(slice3.stride[0], arr3D.stride[0]); + EXPECT_EQ(slice3.stride[1], arr3D.stride[1]); + EXPECT_EQ(slice3.shape[0], 3); + EXPECT_EQ(slice3.shape[1], 1); + EXPECT_EQ(slice3(0,0), arr3D(2,1,4)); + EXPECT_EQ(slice3(1,0), arr3D(3,1,4)); + EXPECT_EQ(slice3(2,0), arr3D(4,1,4)); + + nd::view< const double, 3 > slice4 = arr3D(nd::range{1, 2}, nd::range{2, 5}, nd::range{1,2}); + EXPECT_EQ(slice4.stride[0], arr3D.stride[0]); + EXPECT_EQ(slice4.stride[1], arr3D.stride[1]); + EXPECT_EQ(slice4.stride[2], arr3D.stride[2]); + EXPECT_EQ(slice4.shape[0], 1); + EXPECT_EQ(slice4.shape[1], 3); + EXPECT_EQ(slice4.shape[2], 1); + EXPECT_EQ(slice4(0,0,0), arr3D(1, 2, 1)); + EXPECT_EQ(slice4(0,1,0), arr3D(1, 3, 1)); + EXPECT_EQ(slice4(0,2,0), arr3D(1, 4, 1)); + +} + +TEST(UnitTest, ViewConstSlicing) { + + const nd::array< double, 3 > arr3D = make_patterned_ndarray(stack::array{6u, 7u, 8u}); + nd::view< const double, 3 > view3D = arr3D; + + nd::view< const double, 2 > slice1 = view3D(nd::range{2,5}, 4); + EXPECT_EQ(slice1.stride[0], arr3D.stride[0]); + EXPECT_EQ(slice1.stride[1], arr3D.stride[2]); + EXPECT_EQ(slice1.shape[0], 3); + EXPECT_EQ(slice1.shape[1], 8); + EXPECT_EQ(slice1(0,0), arr3D(2,4,0)); + EXPECT_EQ(slice1(1,1), arr3D(3,4,1)); + EXPECT_EQ(slice1(2,2), arr3D(4,4,2)); + + nd::view< const double, 1 > slice2 = view3D(1, 2, nd::range{2,5}); + EXPECT_EQ(slice2.stride[0], arr3D.stride[2]); + EXPECT_EQ(slice2.shape[0], 3); + EXPECT_EQ(slice2(0), arr3D(1,2,2)); + EXPECT_EQ(slice2(1), arr3D(1,2,3)); + EXPECT_EQ(slice2(2), arr3D(1,2,4)); + + nd::view< const double, 2 > slice3 = view3D(nd::range{2,5}, nd::range{1,2}, 4); + EXPECT_EQ(slice3.stride[0], arr3D.stride[0]); + EXPECT_EQ(slice3.stride[1], arr3D.stride[1]); + EXPECT_EQ(slice3.shape[0], 3); + EXPECT_EQ(slice3.shape[1], 1); + EXPECT_EQ(slice3(0,0), arr3D(2,1,4)); + EXPECT_EQ(slice3(1,0), arr3D(3,1,4)); + EXPECT_EQ(slice3(2,0), arr3D(4,1,4)); + + nd::view< const double, 3 > slice4 = view3D(nd::range{1, 2}, nd::range{2, 5}, nd::range{1,2}); + EXPECT_EQ(slice4.stride[0], arr3D.stride[0]); + EXPECT_EQ(slice4.stride[1], arr3D.stride[1]); + EXPECT_EQ(slice4.stride[2], arr3D.stride[2]); + EXPECT_EQ(slice4.shape[0], 1); + EXPECT_EQ(slice4.shape[1], 3); + EXPECT_EQ(slice4.shape[2], 1); + EXPECT_EQ(slice4(0,0,0), arr3D(1, 2, 1)); + EXPECT_EQ(slice4(0,1,0), arr3D(1, 3, 1)); + EXPECT_EQ(slice4(0,2,0), arr3D(1, 4, 1)); + +} + +TEST(UnitTest, ConstViewSlicing) { + + nd::array< double, 3 > arr3D = make_patterned_ndarray(stack::array{6u, 7u, 8u}); + const nd::view< double, 3 > view3D = arr3D; + + nd::view< double, 2 > slice1 = view3D(nd::range{2,5}, 4); + EXPECT_EQ(slice1.stride[0], arr3D.stride[0]); + EXPECT_EQ(slice1.stride[1], arr3D.stride[2]); + EXPECT_EQ(slice1.shape[0], 3); + EXPECT_EQ(slice1.shape[1], 8); + EXPECT_EQ(slice1(0,0), arr3D(2,4,0)); + EXPECT_EQ(slice1(1,1), arr3D(3,4,1)); + EXPECT_EQ(slice1(2,2), arr3D(4,4,2)); + + nd::view< double, 1 > slice2 = view3D(1, 2, nd::range{2,5}); + EXPECT_EQ(slice2.stride[0], arr3D.stride[2]); + EXPECT_EQ(slice2.shape[0], 3); + EXPECT_EQ(slice2(0), arr3D(1,2,2)); + EXPECT_EQ(slice2(1), arr3D(1,2,3)); + EXPECT_EQ(slice2(2), arr3D(1,2,4)); + + nd::view< double, 2 > slice3 = view3D(nd::range{2,5}, nd::range{1,2}, 4); + EXPECT_EQ(slice3.stride[0], arr3D.stride[0]); + EXPECT_EQ(slice3.stride[1], arr3D.stride[1]); + EXPECT_EQ(slice3.shape[0], 3); + EXPECT_EQ(slice3.shape[1], 1); + EXPECT_EQ(slice3(0,0), arr3D(2,1,4)); + EXPECT_EQ(slice3(1,0), arr3D(3,1,4)); + EXPECT_EQ(slice3(2,0), arr3D(4,1,4)); + + nd::view< double, 3 > slice4 = view3D(nd::range{1, 2}, nd::range{2, 5}, nd::range{1,2}); + EXPECT_EQ(slice4.stride[0], arr3D.stride[0]); + EXPECT_EQ(slice4.stride[1], arr3D.stride[1]); + EXPECT_EQ(slice4.stride[2], arr3D.stride[2]); + EXPECT_EQ(slice4.shape[0], 1); + EXPECT_EQ(slice4.shape[1], 3); + EXPECT_EQ(slice4.shape[2], 1); + EXPECT_EQ(slice4(0,0,0), arr3D(1, 2, 1)); + EXPECT_EQ(slice4(0,1,0), arr3D(1, 3, 1)); + EXPECT_EQ(slice4(0,2,0), arr3D(1, 4, 1)); + +} \ No newline at end of file diff --git a/src/serac/numerics/refactor/containers/tests/accessor_tests.cu b/src/serac/numerics/refactor/containers/tests/accessor_tests.cu new file mode 100644 index 0000000000..acc08d2f5a --- /dev/null +++ b/src/serac/numerics/refactor/containers/tests/accessor_tests.cu @@ -0,0 +1,158 @@ +#include + +#include "common.hpp" + +TEST(UnitTest, BasicAccessOnCPU) { + + nd::array< double, 2 > arr2D = make_patterned_ndarray_on_GPU(stack::array{7u, 8u}); + EXPECT_EQ(arr2D(0, 0), 00); + EXPECT_EQ(arr2D(1, 0), 10); + EXPECT_EQ(arr2D(2, 1), 21); + EXPECT_EQ(arr2D(4, 2), 42); + EXPECT_EQ(arr2D(6, 7), 67); + + nd::view< double, 2 > view2D = arr2D; + EXPECT_EQ(view2D(0, 0), 00); + EXPECT_EQ(view2D(1, 0), 10); + EXPECT_EQ(view2D(2, 1), 21); + EXPECT_EQ(view2D(4, 2), 42); + EXPECT_EQ(view2D(6, 7), 67); + + nd::array< double, 3 > arr3D = make_patterned_ndarray_on_GPU(stack::array{6u, 7u, 8u}); + EXPECT_EQ(arr3D(0, 0, 0), 000); + EXPECT_EQ(arr3D(1, 3, 0), 130); + EXPECT_EQ(arr3D(2, 0, 2), 202); + EXPECT_EQ(arr3D(3, 1, 7), 317); + EXPECT_EQ(arr3D(5, 6, 7), 567); + + //#ifdef NDARRAY_ENABLE_BOUNDS_CHECKING + // EXPECT_EQ(arr3D(10, 10, 10), 1000); + //#endif + + nd::view< double, 3 > view3D = arr3D; + EXPECT_EQ(view3D(0, 0, 0), 000); + EXPECT_EQ(view3D(1, 3, 0), 130); + EXPECT_EQ(view3D(2, 0, 2), 202); + EXPECT_EQ(view3D(3, 1, 7), 317); + EXPECT_EQ(view3D(5, 6, 7), 567); + +} + +__global__ void accessor_kernel(int * num_errors, nd::view v) { + *num_errors += (v(0, 0) != 00); + *num_errors += (v(1, 0) != 10); + *num_errors += (v(2, 1) != 21); + *num_errors += (v(4, 2) != 42); + *num_errors += (v(6, 7) != 67); +} + +__global__ void accessor_kernel(int * num_errors, nd::view v) { + *num_errors += (v(0, 0, 0) != 000); + *num_errors += (v(1, 3, 0) != 130); + *num_errors += (v(2, 0, 2) != 202); + *num_errors += (v(3, 1, 7) != 317); + *num_errors += (v(5, 6, 7) != 567); +} + +TEST(UnitTest, BasicAccessOnGPU) { + int * errors; + cudaMallocManaged(&errors, sizeof(int)); + +//////////////////////////////////////////////////////////////////////////////// + + nd::array< double, 2 > arr2D = make_patterned_ndarray_on_GPU(stack::array{7u, 8u}); + + *errors = 0; + accessor_kernel<<<1,1>>>(errors, arr2D); + cudaDeviceSynchronize(); + EXPECT_EQ(*errors, 0); + +//////////////////////////////////////////////////////////////////////////////// + + nd::array< double, 3 > arr3D = make_patterned_ndarray_on_GPU(stack::array{6u, 7u, 8u}); + + *errors = 0; + accessor_kernel<<<1,1>>>(errors, arr3D); + cudaDeviceSynchronize(); + EXPECT_EQ(*errors, 0); + +//////////////////////////////////////////////////////////////////////////////// + + cudaFree(errors); +} + +template < typename S, typename T > +__global__ void slicing_kernel(int * num_errors, nd::view arr3D) { + + nd::view< S, 2 > slice1 = arr3D(nd::range{2,5}, 4); + *num_errors += (slice1.stride[0] != arr3D.stride[0]); + *num_errors += (slice1.stride[1] != arr3D.stride[2]); + *num_errors += (slice1.shape[0] != 3); + *num_errors += (slice1.shape[1] != 8); + *num_errors += (slice1(0,0) != arr3D(2,4,0)); + *num_errors += (slice1(1,1) != arr3D(3,4,1)); + *num_errors += (slice1(2,2) != arr3D(4,4,2)); + + nd::view< S, 1 > slice2 = arr3D(1, 2, nd::range{2,5}); + *num_errors += (slice2.stride[0] != arr3D.stride[2]); + *num_errors += (slice2.shape[0] != 3); + *num_errors += (slice2(0) != arr3D(1,2,2)); + *num_errors += (slice2(1) != arr3D(1,2,3)); + *num_errors += (slice2(2) != arr3D(1,2,4)); + + nd::view< S, 2 > slice3 = arr3D(nd::range{2,5}, nd::range{1,2}, 4); + *num_errors += (slice3.stride[0] != arr3D.stride[0]); + *num_errors += (slice3.stride[1] != arr3D.stride[1]); + *num_errors += (slice3.shape[0] != 3); + *num_errors += (slice3.shape[1] != 1); + *num_errors += (slice3(0,0) != arr3D(2,1,4)); + *num_errors += (slice3(1,0) != arr3D(3,1,4)); + *num_errors += (slice3(2,0) != arr3D(4,1,4)); + + nd::view< S, 3 > slice4 = arr3D(nd::range{1, 2}, nd::range{2, 5}, nd::range{1,2}); + *num_errors += (slice4.stride[0] != arr3D.stride[0]); + *num_errors += (slice4.stride[1] != arr3D.stride[1]); + *num_errors += (slice4.stride[2] != arr3D.stride[2]); + *num_errors += (slice4.shape[0] != 1); + *num_errors += (slice4.shape[1] != 3); + *num_errors += (slice4.shape[2] != 1); + *num_errors += (slice4(0,0,0) != arr3D(1, 2, 1)); + *num_errors += (slice4(0,1,0) != arr3D(1, 3, 1)); + *num_errors += (slice4(0,2,0) != arr3D(1, 4, 1)); +} + +TEST(UnitTest, ArraySlicingOnGPU) { + int * errors; + cudaMallocManaged(&errors, sizeof(int)); + +//////////////////////////////////////////////////////////////////////////////// + + nd::array< double, 3 > arr3D = make_patterned_ndarray_on_GPU(stack::array{6u, 7u, 8u}); + + *errors = 0; + slicing_kernel<<<1,1>>>(errors, arr3D); + cudaDeviceSynchronize(); + EXPECT_EQ(*errors, 0); + +//////////////////////////////////////////////////////////////////////////////// + + cudaFree(errors); +} + +TEST(UnitTest, ConstArraySlicingOnGPU) { + int * errors; + cudaMallocManaged(&errors, sizeof(int)); + +//////////////////////////////////////////////////////////////////////////////// + + nd::array< double, 3 > arr3D = make_patterned_ndarray_on_GPU(stack::array{6u, 7u, 8u}); + + *errors = 0; + slicing_kernel<<<1,1>>>(errors, arr3D); + cudaDeviceSynchronize(); + EXPECT_EQ(*errors, 0); + +//////////////////////////////////////////////////////////////////////////////// + + cudaFree(errors); +} diff --git a/src/serac/numerics/refactor/containers/tests/common.hpp b/src/serac/numerics/refactor/containers/tests/common.hpp new file mode 100644 index 0000000000..7f85c4dcf5 --- /dev/null +++ b/src/serac/numerics/refactor/containers/tests/common.hpp @@ -0,0 +1,69 @@ +#pragma once + +#include "serac/numerics/refactor/containers/ndarray.hpp" + +#if __CUDACC__ +// dimension should each be less than 10 +template < uint32_t rank > +__global__ void patterned_ndarray_kernel(nd::view output, stack::array dimensions) { + uint32_t i = threadIdx.x + blockIdx.x * blockDim.x; + if (i < dimensions[0]) { + if constexpr (rank > 1) { + for (int j = 0; j < dimensions[1]; j++) { + if constexpr (rank > 2) { + for (int k = 0; k < dimensions[2]; k++) { + output(i, j, k) = 100 * i + 10 * j + k; + } + } else { + output(i, j) = 10 * i + j; + } + } + } else { + output(i) = i; + } + } +} + +template < uint32_t rank > +nd::array make_patterned_ndarray_on_GPU(stack::array dimensions) { + static_assert(rank <= 3); + + nd::array output({dimensions}); + nd::view v = output; + + uint32_t blocksize = 64; + uint32_t gridsize = (dimensions[0] + blocksize - 1) / blocksize; + patterned_ndarray_kernel<<>>(v, dimensions); + cudaDeviceSynchronize(); + + return output; +} +#endif + +// dimension should each be less than 10 +template < uint32_t rank > +nd::array make_patterned_ndarray(stack::array dimensions) { + + static_assert(rank <= 3); + + nd::array output({dimensions}); + + for (int i = 0; i < dimensions[0]; i++) { + if constexpr (rank > 1) { + for (int j = 0; j < dimensions[1]; j++) { + if constexpr (rank > 2) { + for (int k = 0; k < dimensions[2]; k++) { + output(i, j, k) = 100 * i + 10 * j + k; + } + } else { + output(i, j) = 10 * i + j; + } + } + } else { + output(i) = i; + } + } + + return output; + +} diff --git a/src/serac/numerics/refactor/containers/tests/ctor_tests.cpp b/src/serac/numerics/refactor/containers/tests/ctor_tests.cpp new file mode 100644 index 0000000000..6197b4e1fe --- /dev/null +++ b/src/serac/numerics/refactor/containers/tests/ctor_tests.cpp @@ -0,0 +1,59 @@ +#include + +#include "common.hpp" + +TEST(UnitTest, DefaultCtor2D) { + nd::array< double, 2 > arr2D; +} + +TEST(UnitTest, DefaultCtor3D) { + nd::array< double, 3 > arr3D; +} + +TEST(UnitTest, CopyCtor2D) { + nd::array< double, 2 > arr2D({3, 4}); + nd::array< double, 2 > copy2D = arr2D; +} + +TEST(UnitTest, CopyCtor3D) { + nd::array< double, 3 > arr3D({2, 3, 4}); + nd::array< double, 3 > copy3D = arr3D; +} + +TEST(UnitTest, MoveCtor2D) { + nd::array< double, 2 > arr2D({3, 4}); + nd::array< double, 2 > copy2D = std::move(arr2D); + EXPECT_EQ(arr2D.data(), nullptr); +} + +TEST(UnitTest, MoveCtor3D) { + nd::array< double, 3 > arr3D({2, 3, 4}); + nd::array< double, 3 > copy3D = std::move(arr3D); + EXPECT_EQ(arr3D.data(), nullptr); +} + +TEST(UnitTest, CopyAssignmentCtor2D) { + nd::array< double, 2 > arr2D({3, 4}); + nd::array< double, 2 > copy2D; + copy2D = arr2D; +} + +TEST(UnitTest, CopyAssignmentCtor3D) { + nd::array< double, 3 > arr3D({2, 3, 4}); + nd::array< double, 3 > copy3D; + copy3D = arr3D; +} + +TEST(UnitTest, MoveAssignmentCtor2D) { + nd::array< double, 2 > arr2D({3, 4}); + nd::array< double, 2 > copy2D; + copy2D = std::move(arr2D); + EXPECT_EQ(arr2D.data(), nullptr); +} + +TEST(UnitTest, MoveAssignmentCtor3D) { + nd::array< double, 3 > arr3D({2, 3, 4}); + nd::array< double, 3 > copy3D; + copy3D = std::move(arr3D); + EXPECT_EQ(arr3D.data(), nullptr); +} diff --git a/src/serac/numerics/refactor/containers/tests/reshape_tests.cpp b/src/serac/numerics/refactor/containers/tests/reshape_tests.cpp new file mode 100644 index 0000000000..482fbee040 --- /dev/null +++ b/src/serac/numerics/refactor/containers/tests/reshape_tests.cpp @@ -0,0 +1,53 @@ +#include + +#include "common.hpp" + +TEST(UnitTest, Flattening2D) { + nd::array< double, 2 > arr2D = make_patterned_ndarray(stack::array{7u, 8u}); + nd::view< double > view1D = flatten(arr2D); + EXPECT_EQ(view1D(0), 0); + EXPECT_EQ(view1D(10), 12); + EXPECT_EQ(view1D(24), 30); +} + +TEST(UnitTest, Flattening3D) { + nd::array< double, 3 > arr3D = make_patterned_ndarray(stack::array{6u, 7u, 8u}); + nd::view< double > view1D = flatten(arr3D); + EXPECT_EQ(view1D(0), 0); + EXPECT_EQ(view1D(10), 12); + EXPECT_EQ(view1D(24), 30); + EXPECT_EQ(view1D(57), 101); +} + +TEST(UnitTest, Reshape) { + + nd::array< double, 2 > arr2D = make_patterned_ndarray(stack::array{8u, 3u}); + + // select column 1 from 2D array + // { + // { 0, ( 1), 2}, + // {10, (11), 12}, + // {20, (21), 22}, + // {30, (31), 32}, + // {40, (41), 42}, + // {50, (51), 52}, + // {60, (61), 62}, + // {70, (71), 72} + // } + nd::view< double > view1D = arr2D(nd::range{0,8}, 1); + EXPECT_EQ(view1D(0), 1); + EXPECT_EQ(view1D(1), 11); + EXPECT_EQ(view1D(2), 21); + + nd::view< double, 3 > view3D = nd::reshape<3>(view1D, {2,2,2}); + EXPECT_EQ(view3D(0, 0, 0), 1); + EXPECT_EQ(view3D(1, 1, 0), 61); + EXPECT_EQ(view3D(1, 0, 1), 51); + EXPECT_EQ(view3D(0, 1, 0), 21); + + view3D = nd::reshape<3>(view1D, {2,2,2}, nd::ordering::col_major); + EXPECT_EQ(view3D(0, 0, 0), 1); + EXPECT_EQ(view3D(0, 1, 1), 61); + EXPECT_EQ(view3D(1, 0, 1), 51); + EXPECT_EQ(view3D(0, 1, 0), 21); +} \ No newline at end of file diff --git a/src/serac/numerics/refactor/containers/tests/stride_tests.cpp b/src/serac/numerics/refactor/containers/tests/stride_tests.cpp new file mode 100644 index 0000000000..b11f5ed00c --- /dev/null +++ b/src/serac/numerics/refactor/containers/tests/stride_tests.cpp @@ -0,0 +1,51 @@ +#include + +#include "common.hpp" + +TEST(UnitTest, StridesColumnMajor2D) { + stack::array< uint32_t, 2 > shape = {4, 6}; + stack::array< uint32_t, 2 > strides = nd::compute_strides(shape, nd::ordering::col_major); + EXPECT_EQ(strides[0], 1); + EXPECT_EQ(strides[1], 4); + + strides = nd::compute_strides(shape, nd::ordering::col_major, 4); + EXPECT_EQ(strides[0], 4); + EXPECT_EQ(strides[1], 16); +} + +TEST(UnitTest, StridesColumnMajor3D) { + stack::array< uint32_t, 3 > shape = {4, 6, 7}; + stack::array< uint32_t, 3 > strides = nd::compute_strides(shape, nd::ordering::col_major); + EXPECT_EQ(strides[0], 1); + EXPECT_EQ(strides[1], 4); + EXPECT_EQ(strides[2], 24); + + strides = nd::compute_strides(shape, nd::ordering::col_major, 4); + EXPECT_EQ(strides[0], 4); + EXPECT_EQ(strides[1], 16); + EXPECT_EQ(strides[2], 96); +} + +TEST(UnitTest, StridesRowMajor2D) { + stack::array< uint32_t, 2 > shape = {4, 6}; + stack::array< uint32_t, 2 > strides = nd::compute_strides(shape, nd::ordering::row_major); + EXPECT_EQ(strides[0], 6); + EXPECT_EQ(strides[1], 1); + + strides = nd::compute_strides(shape, nd::ordering::row_major, 4); + EXPECT_EQ(strides[0], 24); + EXPECT_EQ(strides[1], 4); +} + +TEST(UnitTest, StridesRowMajor3D) { + stack::array< uint32_t, 3 > shape = {4, 6, 7}; + stack::array< uint32_t, 3 > strides = nd::compute_strides(shape, nd::ordering::row_major); + EXPECT_EQ(strides[0], 42); + EXPECT_EQ(strides[1], 7); + EXPECT_EQ(strides[2], 1); + + strides = nd::compute_strides(shape, nd::ordering::row_major, 4); + EXPECT_EQ(strides[0], 168); + EXPECT_EQ(strides[1], 28); + EXPECT_EQ(strides[2], 4); +} \ No newline at end of file diff --git a/src/serac/numerics/refactor/containers/tests/usage_tests.cpp b/src/serac/numerics/refactor/containers/tests/usage_tests.cpp new file mode 100644 index 0000000000..6cb9a2bdb3 --- /dev/null +++ b/src/serac/numerics/refactor/containers/tests/usage_tests.cpp @@ -0,0 +1,54 @@ +#include + +#include "common.hpp" + +void accepts_const_ndarray(const nd::array< double, 2 > & arr) {} + +void accepts_ndarray(nd::array< double, 2 > & arr) { + accepts_const_ndarray(arr); +} + +void accepts_ndview(nd::view< double, 2 > arr) {} + +void accepts_const_ndview(nd::view< const double, 2 > arr) {} + +void accepts_1dview(nd::view< double, 1 > arr) {} + +void operator*(nd::view arr, double scale) {} + +nd::array returns_ndarray() { + return nd::array{{1, 2}}; +} + +TEST(UnitTest, foo) { + + nd::array arr = returns_ndarray(); + nd::view arr_view = arr; + + accepts_ndarray(arr); + + // nd::array can implicitly convert to nd::view, but not vice versa + // accepts_ndarray(arr_view); + + accepts_ndview(arr); + accepts_ndview(arr_view); + + // implicit conversion of `nd::array &&` to `nd::view` + // is disallowed, since it would create a dangling reference + #if 0 + accepts_ndview(returns_ndarray()); + #endif + + // nd::array and nd::view can both + // implicitly convert to nd::view + accepts_const_ndview(arr); + accepts_const_ndview(arr_view); + + // nd::view conversions and transformations can be concatenated + accepts_1dview(flatten(arr)); + accepts_1dview(flatten(arr_view)); + + // implicit conversion on operator overloads + arr * 3.0; + +} diff --git a/src/serac/numerics/refactor/integrate_diag.cpp b/src/serac/numerics/refactor/integrate_diag.cpp index bc5b318f47..1f8212b64c 100644 --- a/src/serac/numerics/refactor/integrate_diag.cpp +++ b/src/serac/numerics/refactor/integrate_diag.cpp @@ -1,13 +1,5 @@ #include "common.hpp" -#include "misc/timer.hpp" - -#include "refactor/domain.hpp" -#include "refactor/assert.hpp" -#include "refactor/threadpool.hpp" - -#include "minitrace.h" - namespace refactor { namespace impl { diff --git a/src/serac/numerics/refactor/integrate_residual.cpp b/src/serac/numerics/refactor/integrate_residual.cpp index dfa16a4bac..8d0b80e31a 100644 --- a/src/serac/numerics/refactor/integrate_residual.cpp +++ b/src/serac/numerics/refactor/integrate_residual.cpp @@ -1,17 +1,7 @@ #include "common.hpp" -#include "refactor/domain.hpp" -#include "refactor/assert.hpp" -#include "refactor/threadpool.hpp" - - #include "serac/numerics/functional/tensor.hpp" -#include "common.hpp" - -#include "misc/for_constexpr.hpp" -#include "misc/timer.hpp" - namespace refactor { namespace impl { @@ -95,124 +85,108 @@ void batched_integrate_residual(Residual & r, nd::view element_residuals(element_residual_buffer.data(), element_residual_shape); - { - MTR_SCOPE("integrate", "(element residuals)"); - - // for each element with this geometry - threadpool::block_parallel_for(num_elements, [&](uint32_t istart, uint32_t iend) { - - nd::array< A_type > A_q; - nd::array< vec, 2 > dX_dxi_q; - nd::array X_ids; - nd::array X_e; - nd::array< double > X_scratch; + nd::array< A_type > A_q; + nd::array< vec, 2 > dX_dxi_q; + nd::array X_ids; + nd::array X_e; + nd::array< double > X_scratch; + + if (need_to_compute_dX_dxi) { + X_ids.resize(X_nodes_per_element); + X_e.resize(X_nodes_per_element); + X_scratch.resize({X_el.batch_interpolation_scratch_space(xi)}); + A_q.resize({qpts_per_element}); + dX_dxi_q.resize({X_components, qpts_per_element}); + } - if (need_to_compute_dX_dxi) { - X_ids.resize(X_nodes_per_element); - X_e.resize(X_nodes_per_element); - X_scratch.resize({X_el.batch_interpolation_scratch_space(xi)}); - A_q.resize({qpts_per_element}); - dX_dxi_q.resize({X_components, qpts_per_element}); - } + // for each element with this geometry + for (uint32_t i = 0; i < num_elements; i++) { - nd::array r_ids({r_nodes_per_element}); - nd::array r_e({r_nodes_per_element}); - nd::array< double > r_scratch({r_el.batch_interpolation_scratch_space(xi)}); + nd::array r_ids({r_nodes_per_element}); + nd::array r_e({r_nodes_per_element}); + nd::array< double > r_scratch({r_el.batch_interpolation_scratch_space(xi)}); - for (uint32_t i = istart; i < iend; i++) { + if (need_to_compute_dX_dxi) { - if (need_to_compute_dX_dxi) { + // figure out which nodal values belong to this element + X_el.indices(X.offsets, connectivity(elements(i)).data(), X_ids.data()); - // figure out which nodal values belong to this element - X_el.indices(X.offsets, connectivity(elements(i)).data(), X_ids.data()); + for (uint32_t c = 0; c < X_components; c++) { + for (uint32_t j = 0; j < X_nodes_per_element; j++) { + X_e(j) = X.data(X_ids(j), c); + } + X_el.gradient(dX_dxi_q(c), X_e, X_shape_fn_grads, X_scratch.data()); + } - for (int c = 0; c < X_components; c++) { - for (int j = 0; j < X_nodes_per_element; j++) { - X_e(j) = X.data(X_ids(j), c); - } - X_el.gradient(dX_dxi_q(c), X_e, X_shape_fn_grads, X_scratch.data()); - } + for (uint32_t q = 0; q < qpts_per_element; q++) { + mat dX_dxi; + for (uint32_t c = 0; c < gdim; c++) { + dX_dxi[c] = dX_dxi_q(c, q); + } + A_q[q] = weighted_piola_transformation(dX_dxi); + } - for (int q = 0; q < qpts_per_element; q++) { - mat dX_dxi; - for (int c = 0; c < gdim; c++) { - dX_dxi[c] = dX_dxi_q(c, q); - } - A_q[q] = weighted_piola_transformation(dX_dxi); - } + } + nd::array input_xi_q({qpts_per_element}); + for (uint32_t c = 0; c < r_components; c++) { + if (need_to_compute_dX_dxi) { + for (uint32_t q = 0; q < qpts_per_element; q++) { + input_xi_q(q) = serac::dot(A_q[q], input_q(i*qpts_per_element+q, c)); + } + } else { + for (uint32_t q = 0; q < qpts_per_element; q++) { + input_xi_q(q) = input_q(i*qpts_per_element+q, c); } + } - nd::array input_xi_q({qpts_per_element}); - for (int c = 0; c < r_components; c++) { - if (need_to_compute_dX_dxi) { - for (int q = 0; q < qpts_per_element; q++) { - input_xi_q(q) = fm::dot(A_q[q], input_q(i*qpts_per_element+q, c)); - } - } else { - for (int q = 0; q < qpts_per_element; q++) { - input_xi_q(q) = input_q(i*qpts_per_element+q, c); - } - } - - if constexpr (op == DerivedQuantity::VALUE) { - r_el.integrate_source(r_e, input_xi_q, r_shape_fns, r_scratch.data()); - } - - if constexpr (op == DerivedQuantity::DERIVATIVE) { - r_el.integrate_flux(r_e, input_xi_q, r_shape_fns, r_scratch.data()); - } - - if constexpr (is_vector_valued(family)) { - r_el.reorient(TransformationType::TransposePhysicalToParent, &connectivity(elements(i), 0), r_e.data()); - } - - for (int j = 0; j < r_nodes_per_element; j++) { - element_residuals(i * r_nodes_per_element + j, c) = r_e(j); - } + if constexpr (op == DerivedQuantity::VALUE) { + r_el.integrate_source(r_e, input_xi_q, r_shape_fns, r_scratch.data()); + } - } + if constexpr (op == DerivedQuantity::DERIVATIVE) { + r_el.integrate_flux(r_e, input_xi_q, r_shape_fns, r_scratch.data()); + } + + if constexpr (is_vector_valued(family)) { + r_el.reorient(TransformationType::TransposePhysicalToParent, &connectivity(elements(i), 0), r_e.data()); + } + for (uint32_t j = 0; j < r_nodes_per_element; j++) { + element_residuals(i * r_nodes_per_element + j, c) = r_e(j); } - }); + } } - { - MTR_SCOPE("integrate", "(gather)"); - threadpool::block_parallel_for(num_nodes, [&](uint32_t istart, uint32_t iend) { + std::vector sums(r_components); - std::vector sums(r_components); + for (uint32_t i = 0; i < num_nodes; i++) { + uint32_t begin = table.offsets[i]; + uint32_t end = table.offsets[i+1]; - for (uint32_t i = istart; i < iend; i++) { - uint32_t begin = table.offsets[i]; - uint32_t end = table.offsets[i+1]; + for (uint32_t c = 0; c < r_components; c++) { + sums[c] = 0.0; + } - for (uint32_t c = 0; c < r_components; c++) { - sums[c] = 0.0; - } + for (uint32_t k = begin; k < end; k++) { + uint32_t id = table.ids[k]; + for (uint32_t c = 0; c < r_components; c++) { + sums[c] += element_residuals(id, c); + } + } - for (uint32_t k = begin; k < end; k++) { - uint32_t id = table.ids[k]; - for (uint32_t c = 0; c < r_components; c++) { - sums[c] += element_residuals(id, c); - } - } + for (uint32_t c = 0; c < r_components; c++) { + r.data(i, c) += sums[c]; + } - for (uint32_t c = 0; c < r_components; c++) { - r.data(i, c) += sums[c]; - } - } - }); } } template < DerivedQuantity op, uint32_t n > void integrate_residual(Residual & r, BasisFunction phi, const nd::array & f_q, const Domain & domain, const DomainType type) { - MTR_SCOPE("integrate", "residual"); - zero(r.data); uint32_t gdim = domain.mesh.geometry_dimension; diff --git a/src/serac/numerics/refactor/integrate_spmat.cpp b/src/serac/numerics/refactor/integrate_spmat.cpp index e1a453136b..12091bf617 100644 --- a/src/serac/numerics/refactor/integrate_spmat.cpp +++ b/src/serac/numerics/refactor/integrate_spmat.cpp @@ -1,13 +1,5 @@ #include "common.hpp" -#include "misc/timer.hpp" - -#include "refactor/domain.hpp" -#include "refactor/assert.hpp" -#include "refactor/threadpool.hpp" - -#include "minitrace.h" - namespace refactor { namespace impl { @@ -28,8 +20,6 @@ void batched_integrate_spmat(nd::view values, const nd::view xi, const nd::view weights) { - MTR_SCOPE("integrate_spmat", "batched_dphi_dpsi_xi"); - constexpr uint32_t gdim = dimension(geom); constexpr uint32_t test_qshape = qshape(test_family, test_op, gdim); constexpr uint32_t trial_qshape = qshape(trial_family, trial_op, gdim); @@ -52,9 +42,6 @@ void batched_integrate_spmat(nd::view values, uint32_t trial_nodes_per_element = trial_el.num_nodes(); uint32_t qpts_per_element = impl::qpe(xi.shape[0]); - constexpr int nmutex = 1024; - std::vector< std::mutex > mutexes(nmutex); - // precalculate test functions for the provided quadrature rule auto psi_wt = [&](){ if constexpr(trial_op == DerivedQuantity::VALUE) { @@ -75,6 +62,13 @@ void batched_integrate_spmat(nd::view values, auto X_shape_fn_grads = X_el.evaluate_shape_function_gradients(xi); + nd::array testA_q; + nd::array trialA_q; + nd::array, 2> dX_dxi_q; + nd::array X_ids; + nd::array X_e; + nd::array X_scratch; + // When do we need to calculate dX/dxi? // // ❌ : don't need to ✅ : need to @@ -91,149 +85,133 @@ void batched_integrate_spmat(nd::view values, // +---------------------+------+-------+------+----+ const bool need_to_compute_dX_dxi = (type == DomainType::SPATIAL); - // for each element of this mfem::Geometry::Type in the domain - threadpool::block_parallel_for(num_elements, [&](uint32_t e_start, uint32_t e_end) { - - THREAD_SCOPE_TRACE("integrate_spmat", "element block"); + if (need_to_compute_dX_dxi) { + testA_q.resize({qpts_per_element}); + trialA_q.resize({qpts_per_element}); + dX_dxi_q.resize({X_components, qpts_per_element}); + X_ids.resize(X_nodes_per_element); + X_e.resize(X_nodes_per_element); + X_scratch.resize({X_el.batch_interpolation_scratch_space(xi)}); + } - nd::array testA_q; - nd::array trialA_q; - nd::array, 2> dX_dxi_q; - nd::array X_ids; - nd::array X_e; - nd::array X_scratch; + // for each element of this mfem::Geometry::Type in the domain + for (uint32_t e = 0; e < num_elements; e++) { if (need_to_compute_dX_dxi) { - testA_q.resize({qpts_per_element}); - trialA_q.resize({qpts_per_element}); - dX_dxi_q.resize({X_components, qpts_per_element}); - X_ids.resize(X_nodes_per_element); - X_e.resize(X_nodes_per_element); - X_scratch.resize({X_el.batch_interpolation_scratch_space(xi)}); - } + // figure out which nodal values belong to this element + X_el.indices(X.offsets, connectivity(elements(e)).data(), X_ids.data()); - for (uint32_t e = e_start; e < e_end; e++) { - - if (need_to_compute_dX_dxi) { - // figure out which nodal values belong to this element - X_el.indices(X.offsets, connectivity(elements(e)).data(), X_ids.data()); - - for (int c = 0; c < X_components; c++) { - for (int j = 0; j < X_nodes_per_element; j++) { - X_e(j) = X.data(X_ids(j), c); - } - X_el.gradient(dX_dxi_q(c), X_e, X_shape_fn_grads, X_scratch.data()); + for (uint32_t c = 0; c < X_components; c++) { + for (uint32_t j = 0; j < X_nodes_per_element; j++) { + X_e(j) = X.data(X_ids(j), c); } + X_el.gradient(dX_dxi_q(c), X_e, X_shape_fn_grads, X_scratch.data()); + } - for (int q = 0; q < qpts_per_element; q++) { - mat dX_dxi; - for (int c = 0; c < gdim; c++) { - dX_dxi[c] = dX_dxi_q(c, q); - } - testA_q[q] = piola_transformation(dX_dxi); - trialA_q[q] = weighted_piola_transformation(dX_dxi); - } + for (uint32_t q = 0; q < qpts_per_element; q++) { + mat dX_dxi; + for (uint32_t c = 0; c < gdim; c++) { + dX_dxi[c] = dX_dxi_q(c, q); + } + testA_q[q] = piola_transformation(dX_dxi); + trialA_q[q] = weighted_piola_transformation(dX_dxi); } + } - nd::array< double > trial_scratch({trial_el.batch_interpolation_scratch_space(xi)}); + nd::array< double > trial_scratch({trial_el.batch_interpolation_scratch_space(xi)}); - nd::array< trial_qtype > hat_f({qpts_per_element}); + nd::array< trial_qtype > hat_f({qpts_per_element}); - nd::array test_ids({test_nodes_per_element}); - test_el.indices(test_offsets, connectivity(elements(e)).data(), test_ids.data()); + nd::array test_ids({test_nodes_per_element}); + test_el.indices(test_offsets, connectivity(elements(e)).data(), test_ids.data()); - nd::array trial_ids({trial_nodes_per_element}); - trial_el.indices(trial_offsets, connectivity(elements(e)).data(), trial_ids.data()); + nd::array trial_ids({trial_nodes_per_element}); + trial_el.indices(trial_offsets, connectivity(elements(e)).data(), trial_ids.data()); - nd::array< int8_t > transformation({test_nodes_per_element}); - if constexpr (is_vector_valued(test_family)) { - test_el.reorient(TransformationType::TransposePhysicalToParent, &connectivity(elements(e), 0), transformation.data()); - } + nd::array< int8_t > transformation({test_nodes_per_element}); + if constexpr (is_vector_valued(test_family)) { + test_el.reorient(TransformationType::TransposePhysicalToParent, &connectivity(elements(e), 0), transformation.data()); + } - uint32_t qoffset = e * qpts_per_element; + uint32_t qoffset = e * qpts_per_element; - for (uint32_t i = 0; i < test_components; i++) { - for (uint32_t j = 0; j < trial_components; j++) { - for (uint32_t I = 0; I < test_nodes_per_element; I++) { - int row_id = test_ids[I] * test_components + i; + for (uint32_t i = 0; i < test_components; i++) { + for (uint32_t j = 0; j < trial_components; j++) { + for (uint32_t I = 0; I < test_nodes_per_element; I++) { + int row_id = test_ids[I] * test_components + i; - for (uint32_t q = 0; q < qpts_per_element; q++) { - uint32_t qid = qoffset + q; + for (uint32_t q = 0; q < qpts_per_element; q++) { + uint32_t qid = qoffset + q; - auto xi_q = quadrature_point(q, xi); + auto xi_q = quadrature_point(q, xi); - mat_t C{}; - for (uint32_t k = 0; k < test_qshape; k++) { - for (uint32_t m = 0; m < trial_qshape; m++) { - C(k, m) = qdata(qid, i, k, j, m); - } + mat_t C{}; + for (uint32_t k = 0; k < test_qshape; k++) { + for (uint32_t m = 0; m < trial_qshape; m++) { + C(k, m) = qdata(qid, i, k, j, m); } + } - test_qtype phi_I; + test_qtype phi_I; - if constexpr (is_scalar_valued(test_family) && test_op == DerivedQuantity::VALUE) { - phi_I = test_el.shape_function(xi_q, I); - } - - if constexpr (is_scalar_valued(test_family) && test_op == DerivedQuantity::DERIVATIVE) { - phi_I = test_el.shape_function_gradient(xi_q, I); - } + if constexpr (is_scalar_valued(test_family) && test_op == DerivedQuantity::VALUE) { + phi_I = test_el.shape_function(xi_q, I); + } - if constexpr (test_family == Family::Hcurl && test_op == DerivedQuantity::VALUE) { - phi_I = test_el.reoriented_shape_function(xi_q, I, transformation[I]); - } + if constexpr (is_scalar_valued(test_family) && test_op == DerivedQuantity::DERIVATIVE) { + phi_I = test_el.shape_function_gradient(xi_q, I); + } - if constexpr (test_family == Family::Hcurl && test_op == DerivedQuantity::DERIVATIVE) { - phi_I = test_el.reoriented_shape_function_curl(xi_q, I, transformation[I]); - } + if constexpr (test_family == Family::Hcurl && test_op == DerivedQuantity::VALUE) { + phi_I = test_el.reoriented_shape_function(xi_q, I, transformation[I]); + } - if (need_to_compute_dX_dxi) { - phi_I = fm::dot(phi_I, testA_q[q]); - } + if constexpr (test_family == Family::Hcurl && test_op == DerivedQuantity::DERIVATIVE) { + phi_I = test_el.reoriented_shape_function_curl(xi_q, I, transformation[I]); + } - hat_f[q] = fm::dot(phi_I, C); + if (need_to_compute_dX_dxi) { + phi_I = fm::dot(phi_I, testA_q[q]); + } - if (need_to_compute_dX_dxi) { - hat_f[q] = fm::dot(trialA_q[q], hat_f[q]); - } + hat_f[q] = fm::dot(phi_I, C); + if (need_to_compute_dX_dxi) { + hat_f[q] = fm::dot(trialA_q[q], hat_f[q]); } - nd::array r_e({trial_el.num_nodes()}); + } - if constexpr (trial_op == DerivedQuantity::VALUE) { - trial_el.integrate_source(r_e, hat_f, psi_wt, trial_scratch.data()); - } + nd::array r_e({trial_el.num_nodes()}); - if constexpr (trial_op == DerivedQuantity::DERIVATIVE) { - trial_el.integrate_flux(r_e, hat_f, psi_wt, trial_scratch.data()); - } + if constexpr (trial_op == DerivedQuantity::VALUE) { + trial_el.integrate_source(r_e, hat_f, psi_wt, trial_scratch.data()); + } - if constexpr (is_vector_valued(trial_family)) { - trial_el.reorient(TransformationType::TransposePhysicalToParent, &connectivity(elements(e), 0), r_e.data()); - } + if constexpr (trial_op == DerivedQuantity::DERIVATIVE) { + trial_el.integrate_flux(r_e, hat_f, psi_wt, trial_scratch.data()); + } - int row_start = row_ptr[row_id]; - int row_end = row_ptr[row_id+1]; - int which = row_id % nmutex; - mutexes[which].lock(); - for (uint32_t J = 0; J < trial_nodes_per_element; J++) { - int col_id = trial_ids[J] * trial_components + j; + if constexpr (is_vector_valued(trial_family)) { + trial_el.reorient(TransformationType::TransposePhysicalToParent, &connectivity(elements(e), 0), r_e.data()); + } - // find the position of the nonzero entry of this row with the right column - int position = std::lower_bound(&col_ind[row_start], &col_ind[row_end], col_id) - &col_ind[0]; + int row_start = row_ptr[row_id]; + int row_end = row_ptr[row_id+1]; + for (uint32_t J = 0; J < trial_nodes_per_element; J++) { + int col_id = static_cast(trial_ids[J] * trial_components + j); - values[position] += r_e(J); - } - mutexes[which].unlock(); + // find the position of the nonzero entry of this row with the right column + int position = std::lower_bound(&col_ind[row_start], &col_ind[row_end], col_id) - &col_ind[0]; + + values[position] += r_e(J); } } } + } } - }); - } template From ae518bd0d6829c659d8b63a81806642322ba54f0 Mon Sep 17 00:00:00 2001 From: Sam Mish Date: Tue, 17 Dec 2024 11:25:44 -0800 Subject: [PATCH 09/15] fix some includes in container sources --- src/serac/numerics/refactor/containers/memory.cpp | 4 ++-- src/serac/numerics/refactor/containers/memory.cu | 4 ++-- src/serac/numerics/refactor/containers/ndarray.cpp | 0 src/serac/numerics/refactor/containers/relative_error.cpp | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) delete mode 100644 src/serac/numerics/refactor/containers/ndarray.cpp diff --git a/src/serac/numerics/refactor/containers/memory.cpp b/src/serac/numerics/refactor/containers/memory.cpp index 19ebefba3a..bf42b5f2a1 100644 --- a/src/serac/numerics/refactor/containers/memory.cpp +++ b/src/serac/numerics/refactor/containers/memory.cpp @@ -1,4 +1,4 @@ -#include "nd/array.hpp" +#include "serac/numerics/refactor/containers/ndarray.hpp" #ifndef NDARRAY_ENABLE_CUDA namespace memory { @@ -20,4 +20,4 @@ namespace memory { } } -#endif \ No newline at end of file +#endif diff --git a/src/serac/numerics/refactor/containers/memory.cu b/src/serac/numerics/refactor/containers/memory.cu index 4078b46121..827062ab43 100644 --- a/src/serac/numerics/refactor/containers/memory.cu +++ b/src/serac/numerics/refactor/containers/memory.cu @@ -1,4 +1,4 @@ -#include "nd/array.hpp" +#include "serac/numerics/refactor/containers/ndarray.hpp" #include @@ -34,4 +34,4 @@ namespace memory { } } -#endif \ No newline at end of file +#endif diff --git a/src/serac/numerics/refactor/containers/ndarray.cpp b/src/serac/numerics/refactor/containers/ndarray.cpp deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/serac/numerics/refactor/containers/relative_error.cpp b/src/serac/numerics/refactor/containers/relative_error.cpp index 10e18c648f..3063c9c251 100644 --- a/src/serac/numerics/refactor/containers/relative_error.cpp +++ b/src/serac/numerics/refactor/containers/relative_error.cpp @@ -1,7 +1,7 @@ -#include "nd/array.hpp" - #include +#include "serac/numerics/refactor/containers/ndarray.hpp" + template < uint32_t rank > double relative_error_impl(nd::view x, nd::view y) { if (x.shape != y.shape) { @@ -23,4 +23,4 @@ double relative_error_impl(nd::view x, nd::view a, nd::view b) { return relative_error_impl(a, b); }; double relative_error(nd::view a, nd::view b) { return relative_error_impl(a, b); }; double relative_error(nd::view a, nd::view b) { return relative_error_impl(a, b); }; -double relative_error(nd::view a, nd::view b) { return relative_error_impl(a, b); }; \ No newline at end of file +double relative_error(nd::view a, nd::view b) { return relative_error_impl(a, b); }; From ac67b780a0551578d37f815c8a743ecba9b7514f Mon Sep 17 00:00:00 2001 From: Sam Mish Date: Tue, 17 Dec 2024 11:55:35 -0800 Subject: [PATCH 10/15] fixing namespaces, deleting unnecessary code, add DomainType enum --- src/serac/numerics/functional/domain.hpp | 14 +++++ src/serac/numerics/refactor/evaluate.cpp | 2 +- .../numerics/refactor/finite_element.hpp | 2 + .../numerics/refactor/integrate_diag.cpp | 55 ++++--------------- .../numerics/refactor/integrate_residual.cpp | 36 +----------- .../numerics/refactor/integrate_spmat.cpp | 8 +-- .../integrate_residual_H1_flux_tests.cpp | 2 +- 7 files changed, 35 insertions(+), 84 deletions(-) diff --git a/src/serac/numerics/functional/domain.hpp b/src/serac/numerics/functional/domain.hpp index 97f5ebeb92..f14caa72a5 100644 --- a/src/serac/numerics/functional/domain.hpp +++ b/src/serac/numerics/functional/domain.hpp @@ -246,6 +246,20 @@ struct Domain { mfem::Geometry::Type element_geometry); }; +enum class DomainType { ISOPARAMETRIC, SPATIAL }; + +struct DomainWithType { + const Domain & domain; + const DomainType type; + + DomainWithType(const Domain & d) : domain(d), type(DomainType::SPATIAL) {}; + DomainWithType(DomainType t, const Domain & d) : domain(d), type(t) {}; +}; + +inline DomainWithType isoparametric(const Domain & domain) { + return DomainWithType(DomainType::ISOPARAMETRIC, domain); +} + /// @brief constructs a domain from all the elements in a mesh Domain EntireDomain(const mesh_t& mesh); diff --git a/src/serac/numerics/refactor/evaluate.cpp b/src/serac/numerics/refactor/evaluate.cpp index c18821ddec..175149d989 100644 --- a/src/serac/numerics/refactor/evaluate.cpp +++ b/src/serac/numerics/refactor/evaluate.cpp @@ -159,7 +159,7 @@ void batched_interpolate(nd::view u_q, if (need_to_compute_dX_dxi) { for (int q = 0; q < qpts_per_element; q++) { - output_q(i*qpts_per_element+q, c) = fm::dot(u_xi_q[q], A_q[q]); + output_q(i*qpts_per_element+q, c) = serac::dot(u_xi_q[q], A_q[q]); } } else { for (int q = 0; q < qpts_per_element; q++) { diff --git a/src/serac/numerics/refactor/finite_element.hpp b/src/serac/numerics/refactor/finite_element.hpp index 773bdda66d..1740013cb0 100644 --- a/src/serac/numerics/refactor/finite_element.hpp +++ b/src/serac/numerics/refactor/finite_element.hpp @@ -5,10 +5,12 @@ #include "serac/numerics/refactor/quadrature.hpp" #include "serac/physics/state/finite_element_state.hpp" +#include "serac/physics/state/finite_element_dual.hpp" namespace refactor { using Field = serac::FiniteElementState; +using Residual = serac::FiniteElementDual; enum class Family { H1, diff --git a/src/serac/numerics/refactor/integrate_diag.cpp b/src/serac/numerics/refactor/integrate_diag.cpp index 1f8212b64c..48bfd6be3a 100644 --- a/src/serac/numerics/refactor/integrate_diag.cpp +++ b/src/serac/numerics/refactor/integrate_diag.cpp @@ -11,15 +11,11 @@ void batched_integrate_diag(nd::view D, const GeometryInfo offsets, const Field & X, const DomainType type, - const nd::view connectivity, const nd::view elements, const nd::view xi, const nd::view weights, - const Domain::AssemblyLUT & table, nd::array & D_e_buffer) { - MTR_SCOPE("integrate_spmat", "batched_dphi_dpsi_xi"); - constexpr uint32_t gdim = dimension(geom); constexpr uint32_t test_qshape = qshape(family, test_op, gdim); constexpr uint32_t trial_qshape = qshape(family, trial_op, gdim); @@ -70,7 +66,7 @@ void batched_integrate_diag(nd::view D, nd::view D_e(D_e_buffer.data(), D_e_shape); // for each element of this mfem::Geometry::Type in the domain - threadpool::parallel_for(num_elements, [&](uint32_t e) { + for (uint32_t e = 0; e < num_elements; e++) { nd::array testA_q; nd::array trialA_q; @@ -84,8 +80,8 @@ void batched_integrate_diag(nd::view D, // figure out which nodal values belong to this element X_el.indices(X.offsets, connectivity(elements(e)).data(), X_ids.data()); - for (int c = 0; c < X_components; c++) { - for (int j = 0; j < X_nodes_per_element; j++) { + for (uint32_t c = 0; c < X_components; c++) { + for (uint32_t j = 0; j < X_nodes_per_element; j++) { X_e(j) = X.data(X_ids(j), c); } X_el.gradient(dX_dxi_q(c), X_e, X_shape_fn_grads, X_scratch.data()); @@ -93,9 +89,9 @@ void batched_integrate_diag(nd::view D, testA_q.resize({qpts_per_element}); trialA_q.resize({qpts_per_element}); - for (int q = 0; q < qpts_per_element; q++) { + for (uint32_t q = 0; q < qpts_per_element; q++) { mat dX_dxi; - for (int c = 0; c < gdim; c++) { + for (uint32_t c = 0; c < gdim; c++) { dX_dxi[c] = dX_dxi_q(c, q); } testA_q[q] = piola_transformation(dX_dxi); @@ -163,11 +159,11 @@ void batched_integrate_diag(nd::view D, } if (need_to_compute_dX_dxi) { - phi_I = fm::dot(phi_I, testA_q[q]); - psi_I = fm::dot(psi_I, trialA_q[q]); + phi_I = serac::dot(phi_I, testA_q[q]); + psi_I = serac::dot(psi_I, trialA_q[q]); } - sum += fm::dot(fm::dot(phi_I, C), psi_I) * wt; + sum += serac::dot(serac::dot(phi_I, C), psi_I) * wt; } @@ -177,35 +173,6 @@ void batched_integrate_diag(nd::view D, } - }); - - { - MTR_SCOPE("integrate", "(gather)"); - threadpool::block_parallel_for(num_nodes, [&](uint32_t istart, uint32_t iend) { - - std::vector sums(num_components); - - for (uint32_t i = istart; i < iend; i++) { - uint32_t begin = table.offsets[i]; - uint32_t end = table.offsets[i+1]; - - for (uint32_t c = 0; c < num_components; c++) { - sums[c] = 0.0; - } - - for (uint32_t k = begin; k < end; k++) { - uint32_t id = table.ids[k]; - for (uint32_t c = 0; c < num_components; c++) { - sums[c] += D_e(id, c); - } - } - - for (uint32_t c = 0; c < num_components; c++) { - D(i, c) += sums[c]; - } - } - - }); } } @@ -213,12 +180,10 @@ void batched_integrate_diag(nd::view D, template nd::array integrate_sparse_matrix_diagonal(BasisFunction test, const nd::array & qdata, BasisFunction trial, const Domain &domain, const DomainType type) { - MTR_SCOPE("integrate", "diag"); - auto phi = test.space; auto psi = trial.space; - refactor_ASSERT(phi == psi, "must have matching test and trial spaces for diag(...)"); + SLIC_ASSERT_MSG(phi == psi, "must have matching test and trial spaces for diag(...)"); uint32_t test_components = phi.components; uint32_t trial_components = psi.components; @@ -231,7 +196,7 @@ nd::array integrate_sparse_matrix_diagonal(BasisFunction test, const n psi.components, qshape(psi.family, trial_op, gdim) }; - refactor_ASSERT(compatible_shapes(qdata.shape, shape5D), "incompatible array shapes"); + SLIC_ASSERT_MSG(compatible_shapes(qdata.shape, shape5D), "incompatible array shapes"); nd::view q5D{qdata.data(), shape5D}; diff --git a/src/serac/numerics/refactor/integrate_residual.cpp b/src/serac/numerics/refactor/integrate_residual.cpp index 8d0b80e31a..8e9c1f4bb5 100644 --- a/src/serac/numerics/refactor/integrate_residual.cpp +++ b/src/serac/numerics/refactor/integrate_residual.cpp @@ -11,11 +11,9 @@ void batched_integrate_residual(Residual & r, const Field & X, const DomainType type, nd::view f_q, - nd::view connectivity, const nd::view elements, const nd::view xi, const nd::view weights, - const Domain::AssemblyLUT & table, nd::array & element_residual_buffer) { uint32_t num_elements = elements.size(); @@ -23,13 +21,13 @@ void batched_integrate_residual(Residual & r, FiniteElement< geom, family > r_el{r.space.degree}; - using input_t = std::conditional< + using input_t = typename std::conditional< op == DerivedQuantity::VALUE, typename FiniteElement< geom, family >::source_type, typename FiniteElement< geom, family >::flux_type >::type; - nd::view input_q((input_t*)&f_q[0], {f_q.shape[0], f_q.shape[1]}); + nd::view input_q(reinterpret_cast(&f_q[0]), {f_q.shape[0], f_q.shape[1]}); constexpr uint32_t gdim = dimension(geom); uint32_t qpts_per_element = impl::qpe(xi.shape[0]); @@ -75,8 +73,6 @@ void batched_integrate_residual(Residual & r, // +---------------------+------+-------+------+----+ const bool need_to_compute_dX_dxi = (type == DomainType::SPATIAL); - - stack::array element_residual_shape = {num_elements * r_nodes_per_element, r_components}; if (element_residual_buffer.sz < nd::product(element_residual_shape)) { @@ -92,7 +88,6 @@ void batched_integrate_residual(Residual & r, nd::array< double > X_scratch; if (need_to_compute_dX_dxi) { - X_ids.resize(X_nodes_per_element); X_e.resize(X_nodes_per_element); X_scratch.resize({X_el.batch_interpolation_scratch_space(xi)}); A_q.resize({qpts_per_element}); @@ -108,9 +103,6 @@ void batched_integrate_residual(Residual & r, if (need_to_compute_dX_dxi) { - // figure out which nodal values belong to this element - X_el.indices(X.offsets, connectivity(elements(i)).data(), X_ids.data()); - for (uint32_t c = 0; c < X_components; c++) { for (uint32_t j = 0; j < X_nodes_per_element; j++) { X_e(j) = X.data(X_ids(j), c); @@ -160,28 +152,6 @@ void batched_integrate_residual(Residual & r, } - std::vector sums(r_components); - - for (uint32_t i = 0; i < num_nodes; i++) { - uint32_t begin = table.offsets[i]; - uint32_t end = table.offsets[i+1]; - - for (uint32_t c = 0; c < r_components; c++) { - sums[c] = 0.0; - } - - for (uint32_t k = begin; k < end; k++) { - uint32_t id = table.ids[k]; - for (uint32_t c = 0; c < r_components; c++) { - sums[c] += element_residuals(id, c); - } - } - - for (uint32_t c = 0; c < r_components; c++) { - r.data(i, c) += sums[c]; - } - - } } template < DerivedQuantity op, uint32_t n > @@ -197,7 +167,7 @@ void integrate_residual(Residual & r, BasisFunction phi, const nd::array element_residual_buffer; diff --git a/src/serac/numerics/refactor/integrate_spmat.cpp b/src/serac/numerics/refactor/integrate_spmat.cpp index 12091bf617..1b53f7ece5 100644 --- a/src/serac/numerics/refactor/integrate_spmat.cpp +++ b/src/serac/numerics/refactor/integrate_spmat.cpp @@ -171,13 +171,13 @@ void batched_integrate_spmat(nd::view values, } if (need_to_compute_dX_dxi) { - phi_I = fm::dot(phi_I, testA_q[q]); + phi_I = serac::dot(phi_I, testA_q[q]); } - hat_f[q] = fm::dot(phi_I, C); + hat_f[q] = serac::dot(phi_I, C); if (need_to_compute_dX_dxi) { - hat_f[q] = fm::dot(trialA_q[q], hat_f[q]); + hat_f[q] = serac::dot(trialA_q[q], hat_f[q]); } } @@ -234,7 +234,7 @@ std::function< void(refactor::sparse_matrix&) > integrate_sparse_matrix(BasisFun psi.components, qshape(psi.family, trial_op, gdim) }; - refactor_ASSERT(compatible_shapes(qdata.shape, shape5D), "incompatible array shapes"); + SLIC_ASSERT_MSG(compatible_shapes(qdata.shape, shape5D), "incompatible array shapes"); nd::view q5D{qdata.data(), shape5D}; diff --git a/src/serac/numerics/refactor/tests/integrate_residual_H1_flux_tests.cpp b/src/serac/numerics/refactor/tests/integrate_residual_H1_flux_tests.cpp index 00d28f67ad..4bca91ca46 100644 --- a/src/serac/numerics/refactor/tests/integrate_residual_H1_flux_tests.cpp +++ b/src/serac/numerics/refactor/tests/integrate_residual_H1_flux_tests.cpp @@ -30,7 +30,7 @@ void flux_test(std::string filename, // evaluate g at each quadrature point std::function< vecd(vecd, matd) > g_xi = [g](vecd x, matd J) { - return dot(fm::inv(J), g(x)) * det(J); + return dot(serac::inv(J), g(x)) * det(J); }; for (int p = 1; p < 4; p++) { From e34cb2e3edcc2207368e249e4890aa3d5bb3deec Mon Sep 17 00:00:00 2001 From: Sam Mish Date: Tue, 17 Dec 2024 15:47:37 -0800 Subject: [PATCH 11/15] add some free functions to access relevant info from serac::FiniteElement{State/Dual} classes --- src/serac/numerics/functional/domain.hpp | 8 + src/serac/numerics/refactor/common.hpp | 4 +- .../refactor/containers/tests/common.hpp | 2 +- src/serac/numerics/refactor/evaluate.cpp | 163 ++++++++---------- src/serac/numerics/refactor/evaluate.hpp | 1 - .../numerics/refactor/finite_element.hpp | 70 +++++--- .../numerics/refactor/integrate_diag.cpp | 11 +- .../numerics/refactor/integrate_residual.cpp | 22 ++- .../numerics/refactor/integrate_spmat.cpp | 12 +- .../integrate_residual_H1_flux_tests.cpp | 6 - 10 files changed, 151 insertions(+), 148 deletions(-) diff --git a/src/serac/numerics/functional/domain.hpp b/src/serac/numerics/functional/domain.hpp index f14caa72a5..cc17d1b7ba 100644 --- a/src/serac/numerics/functional/domain.hpp +++ b/src/serac/numerics/functional/domain.hpp @@ -246,6 +246,14 @@ struct Domain { mfem::Geometry::Type element_geometry); }; +inline uint32_t spatial_dimension(const Domain & domain) { + return static_cast(domain.mesh_.SpaceDimension()); +} + +inline uint32_t geometry_dimension(const Domain & domain) { + return static_cast(domain.dim_); +} + enum class DomainType { ISOPARAMETRIC, SPATIAL }; struct DomainWithType { diff --git a/src/serac/numerics/refactor/common.hpp b/src/serac/numerics/refactor/common.hpp index 0806cd62a5..7ea3fe8bdb 100644 --- a/src/serac/numerics/refactor/common.hpp +++ b/src/serac/numerics/refactor/common.hpp @@ -131,7 +131,7 @@ template < typename T, uint32_t n > stack::array remove_ones(const stack::array & x) { uint32_t rank = 0; stack::array copy{}; - for (int i = 0; i < n; i++) { + for (uint32_t i = 0; i < n; i++) { if (x[i] > 1) copy[rank++] = x[i]; } return copy; @@ -142,7 +142,7 @@ bool compatible_shapes(const stack::array & x, const stack::array & y) { auto x_filtered = remove_ones(x); auto y_filtered = remove_ones(y); - for (int i = 0; i < std::max(m, n); i++) { + for (uint32_t i = 0; i < std::max(m, n); i++) { auto xval = (i >= m) ? 0 : x_filtered[i]; auto yval = (i >= n) ? 0 : y_filtered[i]; if (xval != yval) { return false; } diff --git a/src/serac/numerics/refactor/containers/tests/common.hpp b/src/serac/numerics/refactor/containers/tests/common.hpp index 7f85c4dcf5..9697763921 100644 --- a/src/serac/numerics/refactor/containers/tests/common.hpp +++ b/src/serac/numerics/refactor/containers/tests/common.hpp @@ -2,7 +2,7 @@ #include "serac/numerics/refactor/containers/ndarray.hpp" -#if __CUDACC__ +#ifdef __CUDACC__ // dimension should each be less than 10 template < uint32_t rank > __global__ void patterned_ndarray_kernel(nd::view output, stack::array dimensions) { diff --git a/src/serac/numerics/refactor/evaluate.cpp b/src/serac/numerics/refactor/evaluate.cpp index 175149d989..2d5ebbe369 100644 --- a/src/serac/numerics/refactor/evaluate.cpp +++ b/src/serac/numerics/refactor/evaluate.cpp @@ -1,3 +1,5 @@ +#include "evaluate.hpp" + #include "common.hpp" namespace refactor { @@ -23,22 +25,21 @@ void batched_interpolate(nd::view u_q, const Field & u, const Field & X, DomainType type, - nd::view connectivity, const nd::view elements, const nd::view xi) { uint32_t num_elements = elements.size(); if (num_elements == 0) return; - FiniteElement< geom, family > u_el{u.degree}; + FiniteElement< geom, family > u_el{get_degree(u)}; - using output_t = std::conditional< + using output_t = typename std::conditional< op == DerivedQuantity::VALUE, typename FiniteElement< geom, family >::source_type, typename FiniteElement< geom, family >::flux_type >::type; - nd::view output_q((output_t*)&u_q[0], {u_q.shape[0], u_q.shape[1]}); + nd::view output_q(reinterpret_cast(&u_q[0]), {u_q.shape[0], u_q.shape[1]}); constexpr uint32_t gdim = dimension(geom); constexpr uint32_t curl_components = source_shape(family, gdim); @@ -46,7 +47,7 @@ void batched_interpolate(nd::view u_q, using A_type = decltype(piola_transformation(mat{})); - uint32_t u_components = u.data.shape[1]; + uint32_t u_components = get_num_components(u); uint32_t u_nodes_per_element = u_el.num_nodes(); auto u_shape_fns = [&](){ if constexpr(op == DerivedQuantity::VALUE) { @@ -62,8 +63,8 @@ void batched_interpolate(nd::view u_q, } }(); - FiniteElement< geom, Family::H1 > X_el{X.degree}; - uint32_t X_components = X.data.shape[1]; + FiniteElement< geom, Family::H1 > X_el{get_degree(X)}; + uint32_t X_components = get_num_components(X); uint32_t X_nodes_per_element = X_el.num_nodes(); auto X_shape_fn_grads = X_el.evaluate_shape_function_gradients(xi); @@ -85,93 +86,84 @@ void batched_interpolate(nd::view u_q, (type == DomainType::SPATIAL && op == DerivedQuantity::DERIVATIVE) || (type == DomainType::SPATIAL && is_vector_valued(family)); - // for each element with this geometry - threadpool::block_parallel_for(num_elements, [&](uint32_t istart, uint32_t iend) { - - nd::array< A_type > A_q; - nd::array X_e; - nd::array X_ids; - nd::array< double > X_scratch; - nd::array< vec, 2 > dX_dxi_q; - - if (need_to_compute_dX_dxi) { - A_q.resize({qpts_per_element}); - X_e.resize(X_nodes_per_element); - X_ids.resize(X_nodes_per_element); - X_scratch.resize({X_el.batch_interpolation_scratch_space(xi)}); - dX_dxi_q.resize({X_components, qpts_per_element}); - } - - nd::array u_ids({u_nodes_per_element}); - nd::array u_e({u_nodes_per_element}); - nd::array< double > u_scratch({u_el.batch_interpolation_scratch_space(xi)}); + nd::array< A_type > A_q; + nd::array X_e; + nd::array X_ids; + nd::array< double > X_scratch; + nd::array< vec, 2 > dX_dxi_q; - for (uint32_t i = istart; i < iend; i++) { + if (need_to_compute_dX_dxi) { + A_q.resize({qpts_per_element}); + X_e.resize(X_nodes_per_element); + X_ids.resize(X_nodes_per_element); + X_scratch.resize({X_el.batch_interpolation_scratch_space(xi)}); + dX_dxi_q.resize({X_components, qpts_per_element}); + } - if (need_to_compute_dX_dxi) { + // for each element with this geometry + nd::array u_ids({u_nodes_per_element}); + nd::array u_e({u_nodes_per_element}); + nd::array< double > u_scratch({u_el.batch_interpolation_scratch_space(xi)}); - // figure out which nodal values belong to this element - X_el.indices(X.offsets, connectivity(elements(i)).data(), X_ids.data()); + for (uint32_t i = 0; i < num_elements; i++) { - for (int c = 0; c < X_components; c++) { - for (int j = 0; j < X_nodes_per_element; j++) { - X_e(j) = X.data(X_ids(j), c); - } - X_el.gradient(dX_dxi_q(c), X_e, X_shape_fn_grads, X_scratch.data()); - } + if (need_to_compute_dX_dxi) { - for (int q = 0; q < qpts_per_element; q++) { - mat dX_dxi; - for (int c = 0; c < gdim; c++) { - dX_dxi[c] = dX_dxi_q(c, q); - } - A_q[q] = piola_transformation(dX_dxi); + for (uint32_t c = 0; c < X_components; c++) { + for (uint32_t j = 0; j < X_nodes_per_element; j++) { + X_e(j) = X.data(X_ids(j), c); } + X_el.gradient(dX_dxi_q(c), X_e, X_shape_fn_grads, X_scratch.data()); + } + for (uint32_t q = 0; q < qpts_per_element; q++) { + mat dX_dxi; + for (uint32_t c = 0; c < gdim; c++) { + dX_dxi[c] = dX_dxi_q(c, q); + } + A_q[q] = piola_transformation(dX_dxi); } - u_el.indices(u.offsets, connectivity(elements(i)).data(), u_ids.data()); + } - nd::array u_xi_q({qpts_per_element}); - for (int c = 0; c < u_components; c++) { + nd::array u_xi_q({qpts_per_element}); + for (uint32_t c = 0; c < u_components; c++) { - for (int j = 0; j < u_nodes_per_element; j++) { - u_e(j) = u.data(u_ids(j), c); - } + for (uint32_t j = 0; j < u_nodes_per_element; j++) { + u_e(j) = u.data(u_ids(j), c); + } - if constexpr (is_vector_valued(family)) { - u_el.reorient(TransformationType::PhysicalToParent, &connectivity(elements(i), 0), u_e.data()); - } + if constexpr (is_vector_valued(family)) { + u_el.reorient(TransformationType::PhysicalToParent, &connectivity(elements(i), 0), u_e.data()); + } - // carry out the appropriate kind of interpolation - // for the requested family and differential operator - if constexpr (op == DerivedQuantity::VALUE) { - u_el.interpolate(u_xi_q, u_e, u_shape_fns, u_scratch.data()); - } + // carry out the appropriate kind of interpolation + // for the requested family and differential operator + if constexpr (op == DerivedQuantity::VALUE) { + u_el.interpolate(u_xi_q, u_e, u_shape_fns, u_scratch.data()); + } - if constexpr (op == DerivedQuantity::DERIVATIVE && is_scalar_valued(family)) { - u_el.gradient(u_xi_q, u_e, u_shape_fns, u_scratch.data()); - } + if constexpr (op == DerivedQuantity::DERIVATIVE && is_scalar_valued(family)) { + u_el.gradient(u_xi_q, u_e, u_shape_fns, u_scratch.data()); + } - if constexpr (op == DerivedQuantity::DERIVATIVE && family == Family::Hcurl) { - u_el.curl(u_xi_q, u_e, u_shape_fns, u_scratch.data()); - } + if constexpr (op == DerivedQuantity::DERIVATIVE && family == Family::Hcurl) { + u_el.curl(u_xi_q, u_e, u_shape_fns, u_scratch.data()); + } - if (need_to_compute_dX_dxi) { - for (int q = 0; q < qpts_per_element; q++) { - output_q(i*qpts_per_element+q, c) = serac::dot(u_xi_q[q], A_q[q]); - } - } else { - for (int q = 0; q < qpts_per_element; q++) { - output_q(i*qpts_per_element+q, c) = u_xi_q[q]; - } + if (need_to_compute_dX_dxi) { + for (uint32_t q = 0; q < qpts_per_element; q++) { + output_q(i*qpts_per_element+q, c) = serac::dot(u_xi_q[q], A_q[q]); + } + } else { + for (uint32_t q = 0; q < qpts_per_element; q++) { + output_q(i*qpts_per_element+q, c) = u_xi_q[q]; } - } } - }); + } } @@ -182,9 +174,7 @@ void batched_interpolate(nd::view u_q, template < Family family, DerivedQuantity op > void evaluate(nd::array & output, const Field & u, const Domain & domain, const DomainType & type) { - MTR_SCOPE("evaluate", "field_xi"); - - int gdim = domain.mesh.geometry_dimension; + uint32_t gdim = static_cast(domain.dim_); uint32_t num_components = output.shape[1]; auto qranges = ranges(domain.num_qpts); @@ -194,9 +184,8 @@ void evaluate(nd::array & output, const Field & u, const Domain & doma nd::view elements = domain.active_elements[geom]; if (gdim == dimension(geom) && elements.size() > 0) { nd::view xi = domain.rule[geom].points; - nd::view connectivity = domain.mesh[geom]; nd::range all{0u, num_components}; - impl::batched_interpolate(output(qranges[geom]), u, domain.mesh.X, type, connectivity, elements, xi); + impl::batched_interpolate(output(qranges[geom]), u, domain.mesh.X, type, elements, xi); } }); @@ -209,10 +198,10 @@ nd::array evaluate(const FieldOp && input, const DomainWithType & d) { const Domain & domain = d.domain; const DomainType & type = d.type; - Family f = input.field.family; + Family f = get_family(input.field); - int gdim = domain.mesh.geometry_dimension; - uint32_t num_components = input.field.data.shape[1]; + uint32_t gdim = geometry_dimension(domain); + uint32_t num_components = get_num_components(input.field); stack::array output_dimensions{ total(domain.num_qpts), num_components, @@ -222,8 +211,8 @@ nd::array evaluate(const FieldOp && input, const DomainWithType & d) { nd::array u_q(output_dimensions); uint32_t offset = 0; - foreach_constexpr< Family::H1, Family::Hcurl >([&](auto family) { - if (family == input.field.family) { + for_constexpr< Family::H1, Family::Hcurl >([&](auto family) { + if (family == f) { if (input.op == DerivedQuantity::VALUE) { impl::evaluate(u_q, input.field, domain, type); } @@ -237,12 +226,4 @@ nd::array evaluate(const FieldOp && input, const DomainWithType & d) { } -//void evaluate_vjp(const nd::array & d_du_q, Field & u, const Domain & domain) { -// Family f = u.family; -// // note: H1 only ever interpolates values over the parent element, -// // since its mapping to physical space doesn't require calculating the jacobian -// if (f == Family::H1) { return impl::evaluate_XI(u, domain); } -// if (f == Family::Hcurl) { return impl::evaluate(u, domain); } -//} - } // namespace refactor diff --git a/src/serac/numerics/refactor/evaluate.hpp b/src/serac/numerics/refactor/evaluate.hpp index 5f0f5c3e45..1038094ecc 100644 --- a/src/serac/numerics/refactor/evaluate.hpp +++ b/src/serac/numerics/refactor/evaluate.hpp @@ -7,7 +7,6 @@ namespace refactor { using Field = serac::FiniteElementState; - inline bool is_value(DerivedQuantity op) { return op == DerivedQuantity::VALUE; } diff --git a/src/serac/numerics/refactor/finite_element.hpp b/src/serac/numerics/refactor/finite_element.hpp index 1740013cb0..80e97c580c 100644 --- a/src/serac/numerics/refactor/finite_element.hpp +++ b/src/serac/numerics/refactor/finite_element.hpp @@ -4,8 +4,8 @@ #include "serac/numerics/refactor/geometry.hpp" #include "serac/numerics/refactor/quadrature.hpp" -#include "serac/physics/state/finite_element_state.hpp" #include "serac/physics/state/finite_element_dual.hpp" +#include "serac/physics/state/finite_element_state.hpp" namespace refactor { @@ -19,6 +19,50 @@ enum class Family { DG }; +Family get_family(const Field & f) { + switch(f.gridFunction().FESpace()->FEColl()->GetContType()) { + case mfem::FiniteElementCollection::CONTINUOUS: return Family::H1; + case mfem::FiniteElementCollection::TANGENTIAL: return Family::Hcurl; + case mfem::FiniteElementCollection::NORMAL: return Family::Hdiv; + case mfem::FiniteElementCollection::DISCONTINUOUS: return Family::DG; + } + return Family::H1; // unreachable +} + +Family get_family(const Residual & r) { + switch(r.linearForm().FESpace()->FEColl()->GetContType()) { + case mfem::FiniteElementCollection::CONTINUOUS: return Family::H1; + case mfem::FiniteElementCollection::TANGENTIAL: return Family::Hcurl; + case mfem::FiniteElementCollection::NORMAL: return Family::Hdiv; + case mfem::FiniteElementCollection::DISCONTINUOUS: return Family::DG; + } + return Family::H1; // unreachable +} + +uint32_t get_degree(const Field & f) { + return uint32_t(f.gridFunction().FESpace()->FEColl()->GetOrder()); +} + +uint32_t get_degree(const Residual & r) { + return uint32_t(r.linearForm().FESpace()->FEColl()->GetOrder()); +} + +uint32_t get_num_components(const Field & f) { + return uint32_t(f.gridFunction().VectorDim()); +} + +uint32_t get_num_components(const Residual & r) { + return uint32_t(r.linearForm().ParFESpace()->GetVDim()); +} + +uint32_t get_num_nodes(const Field & f) { + return uint32_t(f.gridFunction().FESpace()->GetNDofs()); +} + +uint32_t get_num_nodes(const Residual & r) { + return uint32_t(r.linearForm().FESpace()->GetNDofs()); +} + enum class Modifier { NONE, DIAGONAL, SYM }; enum class DerivedQuantity { VALUE, DERIVATIVE }; @@ -37,27 +81,9 @@ struct FunctionSpace { FunctionSpace() : family{}, degree{}, components{} {} FunctionSpace(Family f, uint32_t d = 2, uint32_t c = 1) : family{f}, degree{d}, components{c}{} FunctionSpace(Field f) { - - const auto & pgf = f.gridFunction(); - switch(pgf.FESpace()->FEColl()->GetContType()) { - case mfem::FiniteElementCollection::CONTINUOUS: - family = Family::H1; - break; - case mfem::FiniteElementCollection::TANGENTIAL: - family = Family::Hcurl; - break; - case mfem::FiniteElementCollection::NORMAL: - family = Family::Hdiv; - break; - case mfem::FiniteElementCollection::DISCONTINUOUS: - family = Family::DG; - break; - } - - degree = uint32_t(pgf.FESpace()->FEColl()->GetOrder()); - - components = uint32_t(pgf.VectorDim()); - + family = get_family(f); + degree = get_degree(f); + components = get_num_components(f); } bool operator==(const FunctionSpace & other) const { diff --git a/src/serac/numerics/refactor/integrate_diag.cpp b/src/serac/numerics/refactor/integrate_diag.cpp index 48bfd6be3a..8833a267ad 100644 --- a/src/serac/numerics/refactor/integrate_diag.cpp +++ b/src/serac/numerics/refactor/integrate_diag.cpp @@ -8,7 +8,6 @@ template < mfem::Geometry::Type geom, Family family, DerivedQuantity test_op, De void batched_integrate_diag(nd::view D, nd::view qdata, const FunctionSpace space, - const GeometryInfo offsets, const Field & X, const DomainType type, const nd::view elements, @@ -27,7 +26,7 @@ void batched_integrate_diag(nd::view D, using test_Atype = decltype(piola_transformation(mat{})); using trial_Atype = decltype(weighted_piola_transformation(mat{})); - FiniteElement< geom, Family::H1 > X_el{X.degree}; + FiniteElement< geom, Family::H1 > X_el{get_degree(X)}; FiniteElement< geom, family > el{space.degree}; uint32_t num_nodes = D.shape[0]; @@ -36,7 +35,7 @@ void batched_integrate_diag(nd::view D, uint32_t nodes_per_element = el.num_nodes(); uint32_t qpts_per_element = impl::qpe(xi.shape[0]); - uint32_t X_components = X.data.shape[1]; + uint32_t X_components = get_num_components(X); uint32_t X_nodes_per_element = X_el.num_nodes(); auto X_shape_fn_grads = X_el.evaluate_shape_function_gradients(xi); @@ -77,8 +76,6 @@ void batched_integrate_diag(nd::view D, nd::array X_e({X_nodes_per_element}); nd::array X_scratch({X_el.batch_interpolation_scratch_space(xi)}); - // figure out which nodal values belong to this element - X_el.indices(X.offsets, connectivity(elements(e)).data(), X_ids.data()); for (uint32_t c = 0; c < X_components; c++) { for (uint32_t j = 0; j < X_nodes_per_element; j++) { @@ -187,8 +184,8 @@ nd::array integrate_sparse_matrix_diagonal(BasisFunction test, const n uint32_t test_components = phi.components; uint32_t trial_components = psi.components; - uint32_t sdim = domain.mesh.spatial_dimension; - uint32_t gdim = domain.mesh.geometry_dimension; + uint32_t sdim = spatial_dimension(domain); + uint32_t gdim = geometry_dimension(domain); stack::array shape5D = { qdata.shape[0], diff --git a/src/serac/numerics/refactor/integrate_residual.cpp b/src/serac/numerics/refactor/integrate_residual.cpp index 8e9c1f4bb5..d8c0dab6c4 100644 --- a/src/serac/numerics/refactor/integrate_residual.cpp +++ b/src/serac/numerics/refactor/integrate_residual.cpp @@ -19,7 +19,7 @@ void batched_integrate_residual(Residual & r, uint32_t num_elements = elements.size(); if (num_elements == 0) return; - FiniteElement< geom, family > r_el{r.space.degree}; + FiniteElement< geom, family > r_el{get_degree(r)}; using input_t = typename std::conditional< op == DerivedQuantity::VALUE, @@ -34,8 +34,8 @@ void batched_integrate_residual(Residual & r, using A_type = decltype(weighted_piola_transformation(mat{})); - uint32_t num_nodes = r.data.shape[0]; - uint32_t r_components = r.data.shape[1]; + uint32_t num_nodes = get_num_nodes(r); + uint32_t r_components = get_num_components(r); uint32_t r_nodes_per_element = r_el.num_nodes(); auto r_shape_fns = [&](){ if constexpr(op == DerivedQuantity::VALUE) { @@ -51,8 +51,8 @@ void batched_integrate_residual(Residual & r, } }(); - FiniteElement< geom, Family::H1 > X_el{X.degree}; - uint32_t X_components = X.data.shape[1]; + FiniteElement< geom, Family::H1 > X_el{get_degree(X)}; + uint32_t X_components = get_num_components(X); uint32_t X_nodes_per_element = X_el.num_nodes(); auto X_shape_fn_grads = X_el.evaluate_shape_function_gradients(xi); @@ -157,14 +157,14 @@ void batched_integrate_residual(Residual & r, template < DerivedQuantity op, uint32_t n > void integrate_residual(Residual & r, BasisFunction phi, const nd::array & f_q, const Domain & domain, const DomainType type) { - zero(r.data); + r = 0.0; - uint32_t gdim = domain.mesh.geometry_dimension; + uint32_t gdim = geometry_dimension(domain); stack::array input_dimensions{ f_q.shape[0], phi.space.components, - qshape(r.space.family, op, gdim) + qshape(get_family(r), op, gdim) }; SLIC_ASSERT_MSG(compatible_shapes(f_q.shape, input_dimensions), "incompatible array shapes"); @@ -182,14 +182,12 @@ void integrate_residual(Residual & r, BasisFunction phi, const nd::array integrand_geom = {&f3D(offset, 0, 0), {domain.num_qpts[geom], f3D.shape[1], f3D.shape[2]}}; - const Domain::AssemblyLUT & table = domain.get(geom, phi.space.family, phi.space.degree); - if (phi.space.family == Family::H1) { - batched_integrate_residual(r, domain.mesh.X, type, integrand_geom, connectivity, elements, xi, weights, table, element_residual_buffer); + batched_integrate_residual(r, domain.mesh.X, type, integrand_geom, elements, xi, weights, element_residual_buffer); } if (phi.space.family == Family::Hcurl) { - batched_integrate_residual(r, domain.mesh.X, type, integrand_geom, connectivity, elements, xi, weights, table, element_residual_buffer); + batched_integrate_residual(r, domain.mesh.X, type, integrand_geom, elements, xi, weights, element_residual_buffer); } } diff --git a/src/serac/numerics/refactor/integrate_spmat.cpp b/src/serac/numerics/refactor/integrate_spmat.cpp index 1b53f7ece5..52b6a724e6 100644 --- a/src/serac/numerics/refactor/integrate_spmat.cpp +++ b/src/serac/numerics/refactor/integrate_spmat.cpp @@ -31,7 +31,7 @@ void batched_integrate_spmat(nd::view values, using test_Atype = decltype(piola_transformation(mat{})); using trial_Atype = decltype(weighted_piola_transformation(mat{})); - FiniteElement< geom, Family::H1 > X_el{X.degree}; + FiniteElement< geom, Family::H1 > X_el{get_degree(X)}; FiniteElement< geom, test_family > test_el{test_space.degree}; FiniteElement< geom, trial_family > trial_el{trial_space.degree}; @@ -57,7 +57,7 @@ void batched_integrate_spmat(nd::view values, } }(); - uint32_t X_components = X.data.shape[1]; + uint32_t X_components = get_num_components(X); uint32_t X_nodes_per_element = X_el.num_nodes(); auto X_shape_fn_grads = X_el.evaluate_shape_function_gradients(xi); @@ -98,6 +98,7 @@ void batched_integrate_spmat(nd::view values, for (uint32_t e = 0; e < num_elements; e++) { if (need_to_compute_dX_dxi) { + // figure out which nodal values belong to this element X_el.indices(X.offsets, connectivity(elements(e)).data(), X_ids.data()); @@ -138,7 +139,7 @@ void batched_integrate_spmat(nd::view values, for (uint32_t i = 0; i < test_components; i++) { for (uint32_t j = 0; j < trial_components; j++) { for (uint32_t I = 0; I < test_nodes_per_element; I++) { - int row_id = test_ids[I] * test_components + i; + uint32_t row_id = test_ids[I] * test_components + i; for (uint32_t q = 0; q < qpts_per_element; q++) { uint32_t qid = qoffset + q; @@ -218,15 +219,14 @@ template std::function< void(refactor::sparse_matrix&) > integrate_sparse_matrix(BasisFunction test, const nd::array & qdata, BasisFunction trial, const Domain &domain, const DomainType type) { return [&, type, test, trial](refactor::sparse_matrix & A) { - MTR_SCOPE("integrate_spmat", "dphi_dpsi"); auto phi = test.space; auto psi = trial.space; uint32_t test_components = phi.components; uint32_t trial_components = psi.components; - uint32_t sdim = domain.mesh.spatial_dimension; - uint32_t gdim = domain.mesh.geometry_dimension; + uint32_t sdim = spatial_dimension(domain); + uint32_t gdim = geometry_dimension(domain); stack::array shape5D = { qdata.shape[0], diff --git a/src/serac/numerics/refactor/tests/integrate_residual_H1_flux_tests.cpp b/src/serac/numerics/refactor/tests/integrate_residual_H1_flux_tests.cpp index 4bca91ca46..9a77960eca 100644 --- a/src/serac/numerics/refactor/tests/integrate_residual_H1_flux_tests.cpp +++ b/src/serac/numerics/refactor/tests/integrate_residual_H1_flux_tests.cpp @@ -4,14 +4,8 @@ #include #include -#include "refactor/mesh.hpp" -#include "refactor/domain.hpp" - -#include "forall.hpp" #include "serac/numerics/functional/tensor.hpp" -#include "containers/ndarray_conversions.hpp" - using namespace serac; using namespace refactor; From a8f1ce2c736a135a8d56277020393dbea05f30a7 Mon Sep 17 00:00:00 2001 From: Sam Mish Date: Mon, 23 Dec 2024 08:02:32 -0800 Subject: [PATCH 12/15] working on functions to return nodal coords/directions --- .../functional/detail/hexahedron_H1.inl | 2 +- .../functional/detail/quadrilateral_H1.inl | 2 +- src/serac/numerics/refactor/CMakeLists.txt | 3 + src/serac/numerics/refactor/evaluate.cpp | 13 +-- src/serac/numerics/refactor/evaluate.hpp | 5 ++ .../numerics/refactor/finite_element.hpp | 24 +++--- .../refactor/get_nodal_coordinates.cpp | 84 +++++++++++++++++++ .../refactor/get_nodal_directions.cpp | 41 +++++++++ .../numerics/refactor/integrate_diag.cpp | 2 + .../numerics/refactor/integrate_residual.cpp | 2 + .../numerics/refactor/integrate_spmat.cpp | 2 + .../numerics/refactor/tests/CMakeLists.txt | 2 + src/serac/numerics/refactor/tests/common.hpp | 13 +++ .../refactor/tests/h1_evaluation_tests.cpp | 14 ++-- ...nodal_coordinates_and_directions_tests.cpp | 34 ++++++++ 15 files changed, 219 insertions(+), 24 deletions(-) create mode 100644 src/serac/numerics/refactor/get_nodal_coordinates.cpp create mode 100644 src/serac/numerics/refactor/get_nodal_directions.cpp create mode 100644 src/serac/numerics/refactor/tests/common.hpp create mode 100644 src/serac/numerics/refactor/tests/nodal_coordinates_and_directions_tests.cpp diff --git a/src/serac/numerics/functional/detail/hexahedron_H1.inl b/src/serac/numerics/functional/detail/hexahedron_H1.inl index 1e8d0a02b2..1e1be13ac9 100644 --- a/src/serac/numerics/functional/detail/hexahedron_H1.inl +++ b/src/serac/numerics/functional/detail/hexahedron_H1.inl @@ -209,7 +209,7 @@ struct finite_element > { union { tensor one_dimensional; tensor, tensor >, q, q, q> three_dimensional; - } output; + } output{}; for (int qz = 0; qz < q; qz++) { for (int qy = 0; qy < q; qy++) { diff --git a/src/serac/numerics/functional/detail/quadrilateral_H1.inl b/src/serac/numerics/functional/detail/quadrilateral_H1.inl index b0ef136ce9..c6a544ec3e 100644 --- a/src/serac/numerics/functional/detail/quadrilateral_H1.inl +++ b/src/serac/numerics/functional/detail/quadrilateral_H1.inl @@ -226,7 +226,7 @@ struct finite_element > { union { tensor one_dimensional; tensor, tensor >, q, q> two_dimensional; - } output; + } output{}; for (int qy = 0; qy < q; qy++) { for (int qx = 0; qx < q; qx++) { diff --git a/src/serac/numerics/refactor/CMakeLists.txt b/src/serac/numerics/refactor/CMakeLists.txt index 05871ee6ce..17a3c9731d 100644 --- a/src/serac/numerics/refactor/CMakeLists.txt +++ b/src/serac/numerics/refactor/CMakeLists.txt @@ -34,6 +34,9 @@ set(refactor_sources integrate_diag.cpp integrate_spmat.cpp integrate_residual.cpp + + get_nodal_coordinates.cpp + get_nodal_directions.cpp ) set(refactor_depends serac_infrastructure serac_functional serac_refactor_containers) diff --git a/src/serac/numerics/refactor/evaluate.cpp b/src/serac/numerics/refactor/evaluate.cpp index 2d5ebbe369..2a2b9f2081 100644 --- a/src/serac/numerics/refactor/evaluate.cpp +++ b/src/serac/numerics/refactor/evaluate.cpp @@ -1,3 +1,4 @@ +#if 0 #include "evaluate.hpp" #include "common.hpp" @@ -172,19 +173,18 @@ void batched_interpolate(nd::view u_q, //////////////////////////////////////////////////////////////////////////////// template < Family family, DerivedQuantity op > -void evaluate(nd::array & output, const Field & u, const Domain & domain, const DomainType & type) { +void evaluate(nd::array & output, const Field & u, const Domain & domain, const DomainType & type, const MeshQuadratureRule & qrule) { uint32_t gdim = static_cast(domain.dim_); uint32_t num_components = output.shape[1]; - auto qranges = ranges(domain.num_qpts); + auto qranges = ranges(qrule.num_qpts); uint32_t offset = 0; foreach_geometry([&](auto geom){ nd::view elements = domain.active_elements[geom]; if (gdim == dimension(geom) && elements.size() > 0) { - nd::view xi = domain.rule[geom].points; - nd::range all{0u, num_components}; + nd::view xi = qrule[geom].points; impl::batched_interpolate(output(qranges[geom]), u, domain.mesh.X, type, elements, xi); } }); @@ -193,7 +193,7 @@ void evaluate(nd::array & output, const Field & u, const Domain & doma } // namespace impl -nd::array evaluate(const FieldOp && input, const DomainWithType & d) { +nd::array evaluate(const FieldOp && input, const DomainWithType & d, const MeshQuadratureRule & qrule) { const Domain & domain = d.domain; const DomainType & type = d.type; @@ -203,7 +203,7 @@ nd::array evaluate(const FieldOp && input, const DomainWithType & d) { uint32_t gdim = geometry_dimension(domain); uint32_t num_components = get_num_components(input.field); stack::array output_dimensions{ - total(domain.num_qpts), + total(qrule.num_qpts), num_components, qshape(f, input.op, gdim) }; @@ -227,3 +227,4 @@ nd::array evaluate(const FieldOp && input, const DomainWithType & d) { } } // namespace refactor +#endif diff --git a/src/serac/numerics/refactor/evaluate.hpp b/src/serac/numerics/refactor/evaluate.hpp index 1038094ecc..1adc447126 100644 --- a/src/serac/numerics/refactor/evaluate.hpp +++ b/src/serac/numerics/refactor/evaluate.hpp @@ -1,5 +1,6 @@ #pragma once +#include "serac/numerics/refactor/containers/ndarray.hpp" #include "serac/numerics/refactor/finite_element.hpp" #include "serac/physics/state/finite_element_state.hpp" @@ -104,4 +105,8 @@ auto dot(BasisFunctionOp psi, const nd::array & data, BasisFunctionOp phi) double dot(const Residual & r, const Field & u); double dot(const Field & u, const Residual & r); +//////////////////////////////////////////////////////////////////////////////// + +nd::array evaluate(const FieldOp && input, const DomainWithType & d, const MeshQuadratureRule &); + } diff --git a/src/serac/numerics/refactor/finite_element.hpp b/src/serac/numerics/refactor/finite_element.hpp index 80e97c580c..f85a7653c9 100644 --- a/src/serac/numerics/refactor/finite_element.hpp +++ b/src/serac/numerics/refactor/finite_element.hpp @@ -3,6 +3,7 @@ #include "serac/numerics/functional/tensor.hpp" #include "serac/numerics/refactor/geometry.hpp" #include "serac/numerics/refactor/quadrature.hpp" +#include "serac/numerics/refactor/containers/ndarray.hpp" #include "serac/physics/state/finite_element_dual.hpp" #include "serac/physics/state/finite_element_state.hpp" @@ -19,7 +20,7 @@ enum class Family { DG }; -Family get_family(const Field & f) { +inline Family get_family(const Field & f) { switch(f.gridFunction().FESpace()->FEColl()->GetContType()) { case mfem::FiniteElementCollection::CONTINUOUS: return Family::H1; case mfem::FiniteElementCollection::TANGENTIAL: return Family::Hcurl; @@ -29,7 +30,7 @@ Family get_family(const Field & f) { return Family::H1; // unreachable } -Family get_family(const Residual & r) { +inline Family get_family(const Residual & r) { switch(r.linearForm().FESpace()->FEColl()->GetContType()) { case mfem::FiniteElementCollection::CONTINUOUS: return Family::H1; case mfem::FiniteElementCollection::TANGENTIAL: return Family::Hcurl; @@ -39,39 +40,42 @@ Family get_family(const Residual & r) { return Family::H1; // unreachable } -uint32_t get_degree(const Field & f) { +inline uint32_t get_degree(const Field & f) { return uint32_t(f.gridFunction().FESpace()->FEColl()->GetOrder()); } -uint32_t get_degree(const Residual & r) { +inline uint32_t get_degree(const Residual & r) { return uint32_t(r.linearForm().FESpace()->FEColl()->GetOrder()); } -uint32_t get_num_components(const Field & f) { +inline uint32_t get_num_components(const Field & f) { return uint32_t(f.gridFunction().VectorDim()); } -uint32_t get_num_components(const Residual & r) { +inline uint32_t get_num_components(const Residual & r) { return uint32_t(r.linearForm().ParFESpace()->GetVDim()); } -uint32_t get_num_nodes(const Field & f) { +inline uint32_t get_num_nodes(const Field & f) { return uint32_t(f.gridFunction().FESpace()->GetNDofs()); } -uint32_t get_num_nodes(const Residual & r) { +inline uint32_t get_num_nodes(const Residual & r) { return uint32_t(r.linearForm().FESpace()->GetNDofs()); } +nd::array< double, 2 > get_nodal_coordinates(const Field & f); +nd::array< double, 2 > get_nodal_directions(const Field & f); + enum class Modifier { NONE, DIAGONAL, SYM }; enum class DerivedQuantity { VALUE, DERIVATIVE }; SERAC_HOST_DEVICE constexpr bool is_scalar_valued(Family f) { - return (f == Family::H1); + return (f == Family::H1) || (f == Family::DG); } SERAC_HOST_DEVICE constexpr bool is_vector_valued(Family f) { - return (f == Family::Hcurl); + return (f == Family::Hcurl) || (f == Family::Hdiv); } struct FunctionSpace { diff --git a/src/serac/numerics/refactor/get_nodal_coordinates.cpp b/src/serac/numerics/refactor/get_nodal_coordinates.cpp new file mode 100644 index 0000000000..d7027837a4 --- /dev/null +++ b/src/serac/numerics/refactor/get_nodal_coordinates.cpp @@ -0,0 +1,84 @@ +#include "serac/numerics/refactor/finite_element.hpp" + +namespace refactor { + +nd::array< double, 2 > get_nodal_coordinates(const Field & f) { + + uint32_t num_nodes = get_num_nodes(f); + uint32_t spatial_dimension = static_cast(f.mesh().SpaceDimension()); + + mfem::ParGridFunction pgf = f.gridFunction(); + + if (refactor::is_scalar_valued(get_family(f))) { + + // it seems there is no direct way to get the nodal coordinates + // for an mfem::GridFunction, so instead we proceed by asking pgf + // to evaluate the identity function at each of its nodes + mfem::VectorFunctionCoefficient identity_function( + static_cast(spatial_dimension), + [&](const mfem::Vector& x, mfem::Vector & output) { + output = x; + } + ); + + pgf.ProjectCoefficient(identity_function); + + // then, we extract the nodal coordinates from the gridfunction + nd::array nodal_coords({num_nodes, spatial_dimension}); + + for (uint32_t i = 0; i < num_nodes; i++) { + for (uint32_t j = 0; j < spatial_dimension; j++) { + nodal_coords(i, j) = pgf[static_cast(i * spatial_dimension + j)]; + } + } + + return nodal_coords; + + } else { + + // with vector-valued fields, the workaround is weirder: + // if we evaluate the function f(x, y, z) = {x, 0, 0}, that will + // reveal the x-coordinate of the node times the length of the nodal direction + // + // so, to get just the coordinates, we need to compute the directions + // as well, so we can later divide through by their magnitudes. + + nd::array nodal_directions = get_nodal_directions(f); + + nd::array magnitudes({num_nodes}); + for (uint32_t i = 0; i < num_nodes; i++) { + double sum = 0.0; + for (uint32_t d = 0; d < spatial_dimension; d++) { + sum += nodal_directions(i, d) * nodal_directions(i, d); + } + magnitudes[i] = sqrt(sum); + } + + nd::array nodal_coords({num_nodes, spatial_dimension}); + + for (uint32_t d = 0; d < spatial_dimension; d++) { + + mfem::VectorFunctionCoefficient directional_identity_function( + static_cast(spatial_dimension), + [&](const mfem::Vector& x, mfem::Vector & output) { + output = 0.0; + output[static_cast(d)] = x[static_cast(d)]; + } + ); + + pgf.ProjectCoefficient(directional_identity_function); + + for (uint32_t i = 0; i < num_nodes; i++) { + nodal_coords(i, d) = pgf[static_cast(i * spatial_dimension + d)]; + } + + } + + return nodal_coords; + + + } + +} + +} diff --git a/src/serac/numerics/refactor/get_nodal_directions.cpp b/src/serac/numerics/refactor/get_nodal_directions.cpp new file mode 100644 index 0000000000..5478d52d95 --- /dev/null +++ b/src/serac/numerics/refactor/get_nodal_directions.cpp @@ -0,0 +1,41 @@ +#include "serac/numerics/refactor/finite_element.hpp" + +namespace refactor { + +nd::array< double, 2 > get_nodal_directions(const Field & f) { + + if (refactor::is_scalar_valued(get_family(f))) { + SLIC_ERROR("invalid function space for get_nodal_directions"); + } + + uint32_t num_nodes = get_num_nodes(f); + uint32_t spatial_dimension = static_cast(f.mesh().SpaceDimension()); + + mfem::ParGridFunction pgf = f.gridFunction(); + + // it seems there is no direct way to get the nodal directions + // for a mfem::GridFunction, so instead we proceed by asking pgf + // to evaluate the identity function at each of its nodes + mfem::VectorFunctionCoefficient identity_function( + static_cast(spatial_dimension), + [&](const mfem::Vector& x, mfem::Vector & output) { + output = x; + } + ); + + pgf.ProjectCoefficient(identity_function); + + // then, we extract the nodal coordinates from the gridfunction + nd::array nodal_coords({num_nodes, spatial_dimension}); + + for (uint32_t i = 0; i < num_nodes; i++) { + for (uint32_t j = 0; j < spatial_dimension; j++) { + nodal_coords(i, j) = pgf[static_cast(i * spatial_dimension + j)]; + } + } + + return nodal_coords; + +} + +} diff --git a/src/serac/numerics/refactor/integrate_diag.cpp b/src/serac/numerics/refactor/integrate_diag.cpp index 8833a267ad..56748408ae 100644 --- a/src/serac/numerics/refactor/integrate_diag.cpp +++ b/src/serac/numerics/refactor/integrate_diag.cpp @@ -1,3 +1,4 @@ +#if 0 #include "common.hpp" namespace refactor { @@ -263,3 +264,4 @@ template nd::array integrate_sparse_matrix_diagonal(Residual&, Basi } // namespace impl } // namespace refactor +#endif diff --git a/src/serac/numerics/refactor/integrate_spmat.cpp b/src/serac/numerics/refactor/integrate_spmat.cpp index 52b6a724e6..e33f96617d 100644 --- a/src/serac/numerics/refactor/integrate_spmat.cpp +++ b/src/serac/numerics/refactor/integrate_spmat.cpp @@ -1,3 +1,4 @@ +#if 0 #include "common.hpp" namespace refactor { @@ -315,3 +316,4 @@ template std::function< void(refactor::sparse_matrix&) > integrate_sparse_matrix } // namespace impl } // namespace refactor +#endif diff --git a/src/serac/numerics/refactor/tests/CMakeLists.txt b/src/serac/numerics/refactor/tests/CMakeLists.txt index e74300d53f..c5bf6536a2 100644 --- a/src/serac/numerics/refactor/tests/CMakeLists.txt +++ b/src/serac/numerics/refactor/tests/CMakeLists.txt @@ -15,6 +15,8 @@ set(refactor_serial_test_sources integrate_residual_H1v_flux_tests.cpp integrate_residual_Hcurl_flux_tests.cpp integrate_residual_Hcurl_source_tests.cpp + + nodal_coordinates_and_directions_tests.cpp ) serac_add_tests( SOURCES ${refactor_serial_test_sources} diff --git a/src/serac/numerics/refactor/tests/common.hpp b/src/serac/numerics/refactor/tests/common.hpp new file mode 100644 index 0000000000..f69e983f14 --- /dev/null +++ b/src/serac/numerics/refactor/tests/common.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "serac/mesh/mesh_utils.hpp" +#include "serac/serac_config.hpp" +#include "serac/infrastructure/initialize.hpp" +#include "serac/infrastructure/terminator.hpp" + +#define SERAC_MESH_DIR SERAC_REPO_DIR "/data/meshes/" + +mfem::ParMesh load_parmesh(std::string filename) { + mfem::Mesh mesh(filename); + return mfem::ParMesh(*serac::mesh::refineAndDistribute(std::move(mesh), 0, 0)); +} diff --git a/src/serac/numerics/refactor/tests/h1_evaluation_tests.cpp b/src/serac/numerics/refactor/tests/h1_evaluation_tests.cpp index 439e854fe0..f49909997e 100644 --- a/src/serac/numerics/refactor/tests/h1_evaluation_tests.cpp +++ b/src/serac/numerics/refactor/tests/h1_evaluation_tests.cpp @@ -4,6 +4,7 @@ #include #include "serac/numerics/refactor/evaluate.hpp" +#include "serac/numerics/refactor/tests/common.hpp" using namespace refactor; @@ -25,21 +26,22 @@ void evaluation_test(std::string filename, auto mesh = Mesh::load(SERAC_MESH_DIR + filename); - Field u = create_field(mesh, Family::H1, p); + Field u = create_field(mesh, refactor::Family::H1, p); nd::array nodes = nodes_for(u, mesh); u = forall(f, nodes); - for (int q = 1; q <= 4; q++) { + for (uint32_t q = 1; q <= 4; q++) { - Domain domain(mesh, MeshQuadratureRule(q)); + MeshQuadratureRule qrule(q); + Domain domain(mesh); auto x_q = evaluate(mesh.X, domain); auto dX_dxi_q = evaluate(grad(mesh.X), isoparametric(domain)); - auto u_q = evaluate(u, domain); - auto du_dxi_q = evaluate(grad(u), isoparametric(domain)); - auto du_dX_q_1 = evaluate(grad(u), domain); + auto u_q = evaluate(u, domain, qrule); + auto du_dxi_q = evaluate(grad(u), isoparametric(domain), qrule); + auto du_dX_q_1 = evaluate(grad(u), domain, qrule); auto du_dX_q_2 = forall(contravariant_piola, du_dxi_q, dX_dxi_q); // evaluate f, df_dx directly at each quadrature point diff --git a/src/serac/numerics/refactor/tests/nodal_coordinates_and_directions_tests.cpp b/src/serac/numerics/refactor/tests/nodal_coordinates_and_directions_tests.cpp new file mode 100644 index 0000000000..6f4eaed26b --- /dev/null +++ b/src/serac/numerics/refactor/tests/nodal_coordinates_and_directions_tests.cpp @@ -0,0 +1,34 @@ +#include + +#include +#include + +#include "serac/numerics/refactor/evaluate.hpp" +#include "serac/numerics/refactor/tests/common.hpp" + +using namespace refactor; + +template< int p > +void nodal_coordinates_test(std::string mesh_filename) { + + mfem::ParMesh pmesh = load_parmesh(SERAC_MESH_DIR + mesh_filename); + + serac::FiniteElementState u(pmesh, H1