diff --git a/.github/workflows/unittests.yml b/.github/workflows/unittests.yml index 57c8b9de..8ca31dc8 100644 --- a/.github/workflows/unittests.yml +++ b/.github/workflows/unittests.yml @@ -14,7 +14,7 @@ jobs: run: git submodule init && git submodule update - name: Configure - run: cmake -S . -B build + run: cmake -S . -B build -DBUILD_TESTS=ON - name: Build run: cmake --build build - name: Run all tests diff --git a/.gitignore b/.gitignore index 5e35c563..0d722e24 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,12 @@ examples/*/*_config.yaml tests/regression-tests/*.yaml tests/regression-tests/*/cpu/*.yaml tests/regression-tests/*/gpu/*.yaml +*.mod +*.o +*/OUTPUT_FILES/* +*.gnu +examples/*/Par_File +*OUTPUT_FILES* +*.sqlite +*.nsys-rep +*.ncu-rep diff --git a/.jenkins/compiler_checks.gvy b/.jenkins/compiler_checks.gvy index 865c8784..2f0f6cbb 100644 --- a/.jenkins/compiler_checks.gvy +++ b/.jenkins/compiler_checks.gvy @@ -51,18 +51,19 @@ pipeline{ steps { echo "Building ${CMAKE_HOST_FLAGS} ${CMAKE_DEVICE_FLAGS}" sh """ + module load boost/1.73.0 module load ${CUDA_MODULE} - cmake3 -S . -B build_GNU_${CMAKE_HOST_NAME}_${CMAKE_DEVICE_NAME} -DCMAKE_BUILD_TYPE=Release ${CMAKE_HOST_FLAGS} ${CMAKE_DEVICE_FLAGS} - cmake3 --build build_GNU_${CMAKE_HOST_NAME}_${CMAKE_DEVICE_NAME} + cmake3 -S . -B build_GNU_${CMAKE_HOST_NAME}_${CMAKE_DEVICE_NAME}_${env.GIT_COMMIT} -DCMAKE_BUILD_TYPE=Release ${CMAKE_HOST_FLAGS} ${CMAKE_DEVICE_FLAGS} + cmake3 --build build_GNU_${CMAKE_HOST_NAME}_${CMAKE_DEVICE_NAME}_${env.GIT_COMMIT} """ echo ' Build completed ' } } - stage (' Clean '){ - steps { - echo ' Cleaning ' - sh "rm -rf build_GNU_${CMAKE_HOST_NAME}_${CMAKE_DEVICE_NAME}" - } + } + post { + always { + echo ' Cleaning ' + sh "rm -rf build_GNU_${CMAKE_HOST_NAME}_${CMAKE_DEVICE_NAME}_${env.GIT_COMMIT}" } } } @@ -107,20 +108,21 @@ pipeline{ steps { echo "Building ${CMAKE_HOST_FLAGS} ${CMAKE_DEVICE_FLAGS}" sh """ + module load boost/1.73.0 module load intel/2022.2.0 export CC=icx export CXX=icpx - cmake3 -S . -B build_INTEL_${CMAKE_HOST_NAME}_${CMAKE_DEVICE_NAME} -DCMAKE_BUILD_TYPE=Release ${CMAKE_HOST_FLAGS} ${CMAKE_DEVICE_FLAGS} - cmake3 --build build_INTEL_${CMAKE_HOST_NAME}_${CMAKE_DEVICE_NAME} + cmake3 -S . -B build_INTEL_${CMAKE_HOST_NAME}_${CMAKE_DEVICE_NAME}_${env.GIT_COMMIT} -DCMAKE_BUILD_TYPE=Release ${CMAKE_HOST_FLAGS} ${CMAKE_DEVICE_FLAGS} + cmake3 --build build_INTEL_${CMAKE_HOST_NAME}_${CMAKE_DEVICE_NAME}_${env.GIT_COMMIT} """ echo ' Build completed ' } } - stage (' Clean '){ - steps { - echo ' Cleaning ' - sh "rm -rf build_INTEL_${CMAKE_HOST_NAME}_${CMAKE_DEVICE_NAME}" - } + } + post { + always { + echo ' Cleaning ' + sh "rm -rf build_INTEL_${CMAKE_HOST_NAME}_${CMAKE_DEVICE_NAME}_${env.GIT_COMMIT}" } } } diff --git a/.jenkins/regression_tests.gvy b/.jenkins/regression_tests.gvy index 1b553b3a..5725e1ac 100644 --- a/.jenkins/regression_tests.gvy +++ b/.jenkins/regression_tests.gvy @@ -13,7 +13,7 @@ pipeline { // Screen is needed since the sessions need to remain active even when this stage exits sh """ screen -dm salloc -J jenkins_cpu -N 1 -n 1 -t 00:30:00 --constraint=broadwell - screen -dm salloc -J jenkins_gpu -N 1 -c 10 -t 00:30:00 --gres=gpu:1 --constraint=a100 & + screen -dm salloc -J jenkins_gpu -N 1 -c 10 -t 00:30:00 --gres=gpu:1 --constraint=a100 """ } } @@ -145,9 +145,9 @@ pipeline { stage (' Checkout main branch '){ steps { checkout([$class: 'GitSCM', - branches: [[name: 'devel']], + branches: [[name: 'code-along']], extensions: [lfs()], - userRemoteConfigs: [[url: 'https://github.com/PrincetonUniversity/specfem2d_kokkos']]]) + userRemoteConfigs: [[url: 'https://github.com/PrincetonUniversity/specfempp']]]) } } diff --git a/.jenkins/unittests.gvy b/.jenkins/unittests.gvy index 6623dd51..b8cd25b6 100644 --- a/.jenkins/unittests.gvy +++ b/.jenkins/unittests.gvy @@ -61,9 +61,10 @@ pipeline { steps { echo "Building ${CMAKE_HOST_FLAGS} ${CMAKE_DEVICE_FLAGS}" sh """ + module load boost/1.73.0 module load ${CUDA_MODULE} - cmake3 -S . -B build_GNU_${CMAKE_HOST_NAME}_${CMAKE_DEVICE_NAME} -DCMAKE_BUILD_TYPE=Release ${CMAKE_HOST_FLAGS} ${CMAKE_DEVICE_FLAGS} - cmake3 --build build_GNU_${CMAKE_HOST_NAME}_${CMAKE_DEVICE_NAME} + cmake3 -S . -B build_GNU_${CMAKE_HOST_NAME}_${CMAKE_DEVICE_NAME}_${env.GIT_COMMIT} -DCMAKE_BUILD_TYPE=Release ${CMAKE_HOST_FLAGS} ${CMAKE_DEVICE_FLAGS} -DBUILD_TESTS=ON + cmake3 --build build_GNU_${CMAKE_HOST_NAME}_${CMAKE_DEVICE_NAME}_${env.GIT_COMMIT} """ echo ' Build completed ' } @@ -72,16 +73,17 @@ pipeline { steps { echo " Running Unittests " sh """ - cd build_GNU_${CMAKE_HOST_NAME}_${CMAKE_DEVICE_NAME}/tests/unit-tests - srun -N 1 -t 00:10:00 ${HOST_RUN_FLAGS} ${DEVICE_RUN_FLAGS} bash -c 'export OMP_PROC_BIND=spread; export OMP_THREADS=places; ctest' + module load boost/1.73.0 + cd build_GNU_${CMAKE_HOST_NAME}_${CMAKE_DEVICE_NAME}_${env.GIT_COMMIT}/tests/unit-tests + srun -N 1 -t 00:10:00 ${HOST_RUN_FLAGS} ${DEVICE_RUN_FLAGS} bash -c 'export OMP_PROC_BIND=spread; export OMP_THREADS=places; ctest; ctest --rerun-failed --output-on-failure;' """ } } - stage (' Clean '){ - steps { - echo ' Cleaning ' - sh "rm -rf build_GNU_${CMAKE_HOST_NAME}_${CMAKE_DEVICE_NAME}" - } + } + post { + always { + echo ' Cleaning ' + sh "rm -rf build_GNU_${CMAKE_HOST_NAME}_${CMAKE_DEVICE_NAME}_${env.GIT_COMMIT}" } } } @@ -138,8 +140,8 @@ pipeline { module load intel/2022.2.0 export CC=icx export CXX=icpx - cmake3 -S . -B build_INTEL_${CMAKE_HOST_NAME}_${CMAKE_DEVICE_NAME} -DCMAKE_BUILD_TYPE=Release ${CMAKE_HOST_FLAGS} ${CMAKE_DEVICE_FLAGS} - cmake3 --build build_INTEL_${CMAKE_HOST_NAME}_${CMAKE_DEVICE_NAME} + cmake3 -S . -B build_INTEL_${CMAKE_HOST_NAME}_${CMAKE_DEVICE_NAME}_${env.GIT_COMMIT} -DCMAKE_BUILD_TYPE=Release ${CMAKE_HOST_FLAGS} ${CMAKE_DEVICE_FLAGS} -DBUILD_TESTS=ON + cmake3 --build build_INTEL_${CMAKE_HOST_NAME}_${CMAKE_DEVICE_NAME}_${env.GIT_COMMIT} """ echo ' Build completed ' } @@ -148,17 +150,18 @@ pipeline { steps { echo " Running Unittests " sh """ + module load boost/1.73.0 module load intel/2022.2.0 - cd build_INTEL_${CMAKE_HOST_NAME}_${CMAKE_DEVICE_NAME}/tests/unit-tests - srun -N 1 -t 00:10:00 ${HOST_RUN_FLAGS} ${DEVICE_RUN_FLAGS} bash -c 'export OMP_PROC_BIND=spread; export OMP_THREADS=places; ctest' + cd build_INTEL_${CMAKE_HOST_NAME}_${CMAKE_DEVICE_NAME}_${env.GIT_COMMIT}/tests/unit-tests + srun -N 1 -t 00:10:00 ${HOST_RUN_FLAGS} ${DEVICE_RUN_FLAGS} bash -c 'export OMP_PROC_BIND=spread; export OMP_THREADS=places; ctest; ctest --rerun-failed --output-on-failure;' """ } } - stage (' Clean '){ - steps { - echo ' Cleaning ' - sh "rm -rf build_INTEL_${CMAKE_HOST_NAME}_${CMAKE_DEVICE_NAME}" - } + } + post { + always { + echo ' Cleaning ' + sh "rm -rf build_INTEL_${CMAKE_HOST_NAME}_${CMAKE_DEVICE_NAME}_${env.GIT_COMMIT}" } } } diff --git a/CMakeLists.txt b/CMakeLists.txt index e28c2bb9..c1e44cdf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,8 @@ project(specfem2d_kokkos VERSION 0.1.0) set(CMAKE_CXX_STANDARD 17) option(MPI_PARALLEL "MPI enabled" OFF) +option(BUILD_TESTS "Tests included" OFF) +option(BUILD_EXAMPLES "Examples included" OFF) if(CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM") set(CMAKE_CXX_FLAGS "-fp-model=precise") @@ -25,25 +27,37 @@ endif() ## TODO: Add options for on utilizing in house builds include(FetchContent) FetchContent_Declare( - kokkos - URL https://github.com/kokkos/kokkos/archive/refs/tags/4.0.00.zip +kokkos +URL https://github.com/kokkos/kokkos/archive/refs/tags/4.0.00.zip ) FetchContent_MakeAvailable(kokkos) FetchContent_Declare( yaml - URL https://github.com/jbeder/yaml-cpp/archive/refs/tags/yaml-cpp-0.7.0.zip + URL https://github.com/jbeder/yaml-cpp/archive/refs/tags/0.8.0.tar.gz ) FetchContent_MakeAvailable(yaml) -include_directories(BEFORE SYSTEM ${yaml_SOURCE_DIR} ${yaml_BINARY_DIR}/include) -add_subdirectory(boost-cmake) +include_directories(BEFORE SYSTEM ${yaml_BINARY_DIR} ${yaml_SOURCE_DIR}/include) + +# Try finding boost and if not found install. +find_package(Boost 1.73.0 COMPONENTS program_options filesystem system) + +if (NOT ${Boost_FOUND}) + add_subdirectory(boost-cmake) +else () + message(STATUS " LIB: ${Boost_LIBRARY_DIRS}") + message(STATUS " INC: ${Boost_INCLUDE_DIRS}") + message(STATUS " LIBSO: ${Boost_LIBRARIES}") +endif() configure_file(constants.hpp.in constants.hpp) include_directories(include) include_directories(${CMAKE_BINARY_DIR}) +add_subdirectory(meshfem2d) + # Build specfem2d libraries add_library( quadrature @@ -85,16 +99,6 @@ else() message("-- Compiling SPECFEM without MPI") endif(MPI_PARALLEL) -add_library( - operators - src/mathematical_operators/mathematical_operators.cpp -) - -target_link_libraries( - operators - Kokkos::kokkos -) - add_library( material_class src/material/elastic_material.cpp @@ -113,12 +117,15 @@ add_library( src/mesh/IO/fortran/read_material_properties.cpp src/mesh/boundaries/forcing_boundaries.cpp src/mesh/boundaries/absorbing_boundaries.cpp + src/mesh/boundaries/acoustic_free_surface.cpp src/mesh/elements/tangential_elements.cpp src/mesh/elements/axial_elements.cpp src/mesh/properties/properties.cpp src/mesh/mpi_interfaces/mpi_interfaces.cpp src/mesh/material_indic/material_indic.cpp - src/mesh/surfaces/acoustic_free_surface.cpp + src/mesh/coupled_interfaces/elastic_acoustic.cpp + src/mesh/coupled_interfaces/elastic_poroelastic.cpp + src/mesh/coupled_interfaces/acoustic_poroelastic.cpp src/mesh/mesh.cpp ) @@ -157,6 +164,7 @@ target_link_libraries( add_library( source_time_function src/source_time_function/dirac.cpp + src/source_time_function/ricker.cpp ) target_link_libraries( @@ -206,6 +214,8 @@ add_library( src/compute/compute_properties.cpp src/compute/compute_sources.cpp src/compute/compute_receivers.cpp + src/compute/coupled_interfaces.cpp + src/compute/compute_boundaries.cpp ) target_link_libraries( @@ -218,22 +228,6 @@ target_link_libraries( Kokkos::kokkos ) -# there seems to be a bug when compiling compute with -O3 mode using the icpx compiler. -# set_target_properties(compute PROPERTIES COMPILE_OPTIONS "$<$:-fp-model=precise>") - -add_library( - domain - src/domain/elastic_domain.cpp -) - -target_link_libraries( - domain - compute - quadrature - operators - Kokkos::kokkos -) - add_library( timescheme src/timescheme/timescheme.cpp @@ -242,7 +236,9 @@ add_library( target_link_libraries( timescheme - domain + Kokkos::kokkos + yaml-cpp + compute ) add_library( @@ -256,18 +252,6 @@ target_link_libraries( receiver_class ) -add_library( - solver - src/solver/time_marching.cpp -) - -target_link_libraries( - solver - domain - timescheme - writer -) - add_library( parameter_reader src/parameter_parser/run_setup.cpp @@ -288,6 +272,7 @@ target_link_libraries( timescheme receiver_class yaml-cpp + writer Boost::filesystem ) @@ -306,17 +291,22 @@ target_link_libraries( compute source_class parameter_reader - domain - solver receiver_class writer Boost::program_options ) # Include tests -add_subdirectory(tests/unit-tests) -add_subdirectory(tests/regression-tests) -add_subdirectory(examples) +if (BUILD_TESTS) + message("-- Including tests.") + add_subdirectory(tests/unit-tests) + add_subdirectory(tests/regression-tests) +endif() + +if (BUILD_EXAMPLES) + message("-- Including examples.") + add_subdirectory(examples) +endif() # Doxygen diff --git a/README.md b/README.md index 804c2c11..2f91e309 100644 --- a/README.md +++ b/README.md @@ -1,53 +1,35 @@ -# SPECFEM2D Kokkos implementation +# SPECFEM++ -[![Unittests](https://github.com/PrincetonUniversity/specfem2d_kokkos/actions/workflows/unittests.yml/badge.svg)](https://github.com/PrincetonUniversity/specfem2d_kokkos/actions/workflows/unittests.yml) +[![Tests](https://github.com/PrincetonUniversity/specfem2d_kokkos/actions/workflows/unittests.yml/badge.svg)](https://github.com/PrincetonUniversity/specfem2d_kokkos/actions/workflows/unittests.yml) [![Build](https://github.com/PrincetonUniversity/specfem2d_kokkos/actions/workflows/compilation.yml/badge.svg)](https://github.com/PrincetonUniversity/specfem2d_kokkos/actions/workflows/compilation.yml) [![Documentation Status](https://readthedocs.org/projects/specfem2d-kokkos/badge/?version=latest)](https://specfem2d-kokkos.readthedocs.io/en/latest/?badge=latest) ## About +SPECFEM++ is a complete re-write of SPECFEM suite of packages (SPECFEM2D, SPECFEM3D, SPECFEM3D_GLOBE) using C++. Compared to the earlier version, SPECFEM++ code base provides: -SPECFEM kokkos is C++ implementation of SPECFEM suite of software using the [Kokkos]() programming model. Kokkos is a is a production level solution for writing modern C++ applications in a hardware agnostic way, this allows us to write a single source code which can run across all modern architectures. The goal of this project is to provide the same level of functionality as provided by SPECFEM2D, SPECFEM3D and SPECFEM3d_GLOBE in a singular package that runs across all architectures. + 1. a robust and flexible code structure, + 2. modularity that allows for easy addition of new features, + 3. portability that allows the code to run on a variety of architectures (CPU, NVIDIA GPUs, Intel GPUs, AMD GPUs etc.), and + 4. a user-friendly build infrastructure that allows the code to be easily compiled and run on a variety of platforms. ## Documentation -The online documentation for SPECFEM2D Kokkos is located [here](https://specfem2d-kokkos.readthedocs.io/en/latest/index.html#) +The online documentation for SPECFEM++ is located [here](https://specfem2d-kokkos.readthedocs.io/en/latest/index.html#) ## Installation Completer installation instructions are located in the [online documentation](https://specfem2d-kokkos.readthedocs.io/en/latest/user_documentation/index.html) -## Code feature matrix +## Running SPECFEM++ - -Table below shows various features available and tested in this package on various architectures: - -| | CPU(serial) | CPU(OpenMP) | CUDA | HIP -----------------------|------------:|-----------:|------:|-----| -| **Physics** | -| P-SV waves | X | X | X | | -| Elastic Domains | X | X | X | | -| **Simulation Setup** | -| Forward Simulations | X | X | X | | -| **Time Schemes** | -| Newmark | X | X | X | | -| **Seismograms** | -| Displacement | X | X | X | | -| Velocity | X | X | X | | -| Acceleration | X | X | X | | -| **Seismogram format** | -| ASCII | X | X | X | | - -## Running SPECFEM2D Kokkos - -Intructions on how to run SPECFEM2D Kokkos can be found [here](https://specfem2d-kokkos.readthedocs.io/en/latest/user_documentation/index.html). +Intructions on how to run SPECFEM++ can be found [here](https://specfem2d-kokkos.readthedocs.io/en/latest/user_documentation/index.html). For use case examples of running the software please see [cookbooks](https://specfem2d-kokkos.readthedocs.io/en/latest/cookbooks/index.html) -## Contributing to SPECFEM2D Kokkos - +## Contributing to SPECFEM++ SPECFEM is a community project that lives by the participation of its members — i.e., including you! It is our goal to build an inclusive and participatory community so we are happy that you are interested in participating! Please see [this page](https://specfem2d-kokkos.readthedocs.io/en/latest/developer_documentation/index.html) for developer documentation. @@ -55,7 +37,6 @@ In particular you should follow the git development workflow and pre-commit styl ## License - [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](LICENSE) -SPECFEM2D Kokkos is distributed under the [GPL v3 license](LICENSE) +SPECFEM++ is distributed under the [GPL v3 license](LICENSE) diff --git a/constants.hpp.in b/constants.hpp.in index cb0e4ac6..37e3ba69 100644 --- a/constants.hpp.in +++ b/constants.hpp.in @@ -10,14 +10,6 @@ const std::string __default_file__ = "@CMAKE_SOURCE_DIR@/parameter_files/default namespace specfem { -namespace elements { -enum type { - elastic, ///< elastic element - acoustic, ///< acoustic element - poroelastic ///< poroelastic element -}; -} // namespace elements - namespace wave { enum type { p_sv, ///< P-SV wave @@ -25,21 +17,6 @@ enum type { }; } // namespace wave -namespace seismogram { -enum type { - displacement, ///< Displacement seismogram - velocity, ///< Velocity Seismogram - acceleration ///< Acceleration seismogram -}; - -namespace format { -enum type { - seismic_unix, ///< Seismic unix output format - ascii ///< ASCII output format -}; -} -} // namespace seismogram - } // namespace specfem #endif diff --git a/docs/Doxyfile.in b/docs/Doxyfile.in index 9a768aa4..2e925d3e 100644 --- a/docs/Doxyfile.in +++ b/docs/Doxyfile.in @@ -283,6 +283,10 @@ TAB_SIZE = 4 # @} or use a double escape (\\{ and \\}) ALIASES = +ALIASES += xix="\f$\partial \xi / \partial x\f$" +ALIASES += xiz="\f$\partial \xi / \partial z\f$" +ALIASES += gammax="\f$\partial \gamma / \partial x\f$" +ALIASES += gammaz="\f$\partial \gamma / \partial z\f$" # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For diff --git a/docs/_static/css/center_align_table.css b/docs/_static/css/center_align_table.css new file mode 100644 index 00000000..56e2e717 --- /dev/null +++ b/docs/_static/css/center_align_table.css @@ -0,0 +1,4 @@ +.center-table { + margin: auto; + text-align: center; +} diff --git a/docs/api/IO.rst b/docs/api/IO.rst deleted file mode 100644 index 3092e66a..00000000 --- a/docs/api/IO.rst +++ /dev/null @@ -1,14 +0,0 @@ -.. _IO:: - -Input/Output module -==================== - -This section contains IO modules used to read/write databases - -FortranIO ----------- - -This module contains routines used to read unformatted fortran binary files - -.. doxygenfile:: fortranio/interface.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION diff --git a/docs/api/IO/fortran_io.rst b/docs/api/IO/fortran_io.rst new file mode 100644 index 00000000..86982c3b --- /dev/null +++ b/docs/api/IO/fortran_io.rst @@ -0,0 +1,8 @@ +.. _IO:: + +Fortran IO +========== + +Fortran IO namespace provides a functions to read data stored in unformatted fortran binary files. + +.. doxygenfunction:: specfem::fortran_IO::fortran_read_line diff --git a/docs/api/IO/index.rst b/docs/api/IO/index.rst new file mode 100644 index 00000000..f3475239 --- /dev/null +++ b/docs/api/IO/index.rst @@ -0,0 +1,10 @@ + +Input/Output modules +==================== + +.. toctree:: + :maxdepth: 2 + + fortran_io + mesh/index + writer/index diff --git a/docs/api/IO/mesh/boundaries/absorbing_boundaries.rst b/docs/api/IO/mesh/boundaries/absorbing_boundaries.rst new file mode 100644 index 00000000..a6951e1a --- /dev/null +++ b/docs/api/IO/mesh/boundaries/absorbing_boundaries.rst @@ -0,0 +1,9 @@ + +Absorbing Boundary Conditions +============================= + +The ``absorbing_boundary`` struct provides information about elements that lie on absorbing boundaries. + +.. doxygenstruct:: specfem::mesh::boundaries::absorbing_boundary + :members: + :undoc-members: diff --git a/docs/api/IO/mesh/boundaries/acoustic_forcing.rst b/docs/api/IO/mesh/boundaries/acoustic_forcing.rst new file mode 100644 index 00000000..1c8eb5c5 --- /dev/null +++ b/docs/api/IO/mesh/boundaries/acoustic_forcing.rst @@ -0,0 +1,9 @@ + +Acoustic Forcing Boundaries +============================ + +The ``forcing_boundary`` struct is used to store element information for elments on the acoustic forcing boundary. + +.. doxygenstruct:: specfem::mesh::boundaries::forcing_boundary + :members: + :undoc-members: diff --git a/docs/api/IO/mesh/boundaries/acoustic_free_surface.rst b/docs/api/IO/mesh/boundaries/acoustic_free_surface.rst new file mode 100644 index 00000000..73446b62 --- /dev/null +++ b/docs/api/IO/mesh/boundaries/acoustic_free_surface.rst @@ -0,0 +1,9 @@ + +Acoustic Free Surface +===================== + +The ``acoustic_free_surface`` struct give information about acoustic elements on the free surface. These elements need to be treated differently to account for the free surface boundary condition. + +.. doxygenstruct:: specfem::mesh::boundaries::acoustic_free_surface + :members: + :undoc-members: diff --git a/docs/api/IO/mesh/boundaries/index.rst b/docs/api/IO/mesh/boundaries/index.rst new file mode 100644 index 00000000..d1c5f7d5 --- /dev/null +++ b/docs/api/IO/mesh/boundaries/index.rst @@ -0,0 +1,12 @@ + +Boundaries +========== + +Structs provided here are used to store information about the boundary conditions on the mesh. + +.. toctree:: + :maxdepth: 1 + + forcing_boundaries + absorbing_boundaries + acoustic_free_surface diff --git a/docs/api/IO/mesh/elements/axial_elements.rst b/docs/api/IO/mesh/elements/axial_elements.rst new file mode 100644 index 00000000..5c301652 --- /dev/null +++ b/docs/api/IO/mesh/elements/axial_elements.rst @@ -0,0 +1,9 @@ + +Axial Elements +============== + +The ``axial_elements`` struct contains information about elements that lie on a axis in 2.5D simulations. + +.. doxygenstruct:: specfem::mesh::elements::axial_elements + :members: + :undoc-members: diff --git a/docs/api/IO/mesh/elements/index.rst b/docs/api/IO/mesh/elements/index.rst new file mode 100644 index 00000000..9dc23c6d --- /dev/null +++ b/docs/api/IO/mesh/elements/index.rst @@ -0,0 +1,12 @@ +.. _elements_index:: + +Special Elements +================ + +Structs in this section provide information about special elements that need to treated differently. + +.. toctree:: + :maxdepth: 1 + + axial_elements + tangential_elements diff --git a/docs/api/IO/mesh/elements/tangential_elements.rst b/docs/api/IO/mesh/elements/tangential_elements.rst new file mode 100644 index 00000000..8e06ef23 --- /dev/null +++ b/docs/api/IO/mesh/elements/tangential_elements.rst @@ -0,0 +1,10 @@ + +Tangential Elements +=================== + +The ``tangential_elements`` provides information about elements that are tangential to simulation surface. + +.. warning:: + This information is not used in the current release of the package. + +.. doxygenstruct:: specfem::mesh::elements::tangential_elements diff --git a/docs/api/IO/mesh/index.rst b/docs/api/IO/mesh/index.rst new file mode 100644 index 00000000..0cfdaf76 --- /dev/null +++ b/docs/api/IO/mesh/index.rst @@ -0,0 +1,32 @@ +.. mesh_io:: + +Mesh Input Module +================== + +The mesh module provides set of structs and functions to read and store mesh database files generated by ``MESHFEM2D``. The mesh database files need to be stored in fortran binary format. + +Mesh Struct API +---------------- + +.. doxygenstruct:: specfem::mesh::mesh + :members: + :undoc-members: + +Supporting Struct API +--------------------- + +.. toctree:: + :maxdepth: 1 + + mesh_properties + material_information + boundaries/index + elements/index + coupling/index + +Supporting functions +-------------------- + +.. doxygenfunction:: specfem::mesh::IO::fortran::read_mesh_database_header + +.. doxygenfunction:: specfem::mesh::IO::fortran::read_material_properties diff --git a/docs/api/IO/mesh/material_information.rst b/docs/api/IO/mesh/material_information.rst new file mode 100644 index 00000000..66821f73 --- /dev/null +++ b/docs/api/IO/mesh/material_information.rst @@ -0,0 +1,9 @@ + +Mesh Material Information +========================== + +The ``material_ind`` struct is used to store material information for every spectral element in the mesh. + +.. doxygenstruct:: specfem::mesh::material_ind + :members: + :undoc-members: diff --git a/docs/api/IO/mesh/mesh_properties.rst b/docs/api/IO/mesh/mesh_properties.rst new file mode 100644 index 00000000..b33e1aaf --- /dev/null +++ b/docs/api/IO/mesh/mesh_properties.rst @@ -0,0 +1,9 @@ + +Mesh properties struct +====================== + +The ``properties`` struct contains properties that are used to describe the mesh. + +.. doxygenstruct:: specfem::mesh::properties + :members: + :undoc-members: diff --git a/docs/api/IO/writer/index.rst b/docs/api/IO/writer/index.rst new file mode 100644 index 00000000..c1906e59 --- /dev/null +++ b/docs/api/IO/writer/index.rst @@ -0,0 +1,18 @@ + +Writer API +========== + +The ``writer`` class provides interfaces to write simulation data as output files. + +.. doxygenclass:: specfem::writer::writer + :members: + :undoc-members: + :private-members: + +Types of writers +---------------- + +.. toctree:: + :maxdepth: 1 + + seismogram_writer diff --git a/docs/api/IO/writer/seismogram_writer.rst b/docs/api/IO/writer/seismogram_writer.rst new file mode 100644 index 00000000..452dbb91 --- /dev/null +++ b/docs/api/IO/writer/seismogram_writer.rst @@ -0,0 +1,10 @@ + +Seismogram Writer +================= + +The ``seismogram`` provides methods to write seismograms to a file. + +.. doxygenclass:: specfem::writer::seismogram + :members: + :undoc-members: + :private-members: diff --git a/docs/api/boundary_conditions/composite_boundaries.rst b/docs/api/boundary_conditions/composite_boundaries.rst new file mode 100644 index 00000000..6abd7bf2 --- /dev/null +++ b/docs/api/boundary_conditions/composite_boundaries.rst @@ -0,0 +1,55 @@ +.. _composite_boundaries: + +Composite Boundaries +==================== + +Composite boundaries are a special type of boundary that is used to enforce a combination of multiple boundary conditions. For example, a composite boundary can be used to enforce a Dirichlet boundary condition on the top boundary of an element and a stacey ABC on the right/left boundaries of the element. + +Definition +---------- + +.. doxygenclass:: specfem::enums::boundary_conditions::composite_boundary + +Interface +--------- + +.. codeblock:: + + template + class composite_boundary; + +Parameters +---------- + +.. _stacey: stacey.html + +.. |stacey| replace:: stacey() + +.. _dirichlet: dirichlet.html + +.. |dirichlet| replace:: dirichlet() + +.. _none: none.html + +.. |none| replace:: none() + +* ``BC...``: A variadic list of 2 or more boundary conditions. The boundary conditions must be one of the following: + + - |stacey|_ : Stacey absorbing boundary condition + - |dirichlet|_ : Dirichlet boundary condition + - |none|_ : No boundary condition + +.. note:: + + Template specializations are provided for the combination of boundary conditions listed below. + +Template Specializations +------------------------ + +.. _stacey_dirichlet: stacey_dirichlet_implementation.html + +.. |stacey_dirichlet| replace:: composite_boundary< |stacey|_ , |dirichlet|_ > + +* Composite boundary condition enforcing a stacey ABC on one edge and a Dirichlet boundary condition on another edge. + + - |stacey_dirichlet|_ diff --git a/docs/api/boundary_conditions/dirichlet.rst b/docs/api/boundary_conditions/dirichlet.rst new file mode 100644 index 00000000..3811290a --- /dev/null +++ b/docs/api/boundary_conditions/dirichlet.rst @@ -0,0 +1,83 @@ +.. _dirichlet_bc: + +Dirichlet boundary conditions +============================== + +Definition +---------- + +.. doxygenclass:: specfem::enums::boundary_conditions::dirichlet + +Interface +--------- + +.. codeblock:: + + template + class dirichlet + +Parameters +---------- + +.. _dim2: ../enumerations/element/dim2.html + +.. |dim2| replace:: dim2() + +.. _dim3: ../enumerations/element/dim3.html + +.. |dim3| replace:: dim3() + +.. _elastic: ../enumerations/element/elastic.html + +.. |elastic| replace:: elastic() + +.. _acoustic: ../enumerations/element/acoustic.html + +.. |acoustic| replace:: acoustic() + +.. _static_quadrature_points: ../enumerations/element/static_quadrature_points.html + +.. |static_quadrature_points| replace:: static_quadrature_points< NGLL >() + +.. _isotropic: ../enumerations/element/isotropic.html + +.. |isotropic| replace:: isotropic() + +* ``dimension``: + + The dimension of the element. + + - |dim2|_: A two dimensional element. + - |dim3|_: A three dimensional element. + +* ``medium``: + + The medium of the element. + + - |elastic|_: An elastic element. + - |acoustic|_: An acoustic element. + +* ``quadrature_points_type``: + + The quadrature points of the element. + + - |static_quadrature_points|_: A static quadrature point set. + +* ``properties``: + + The properties of the element. The properties describe any specializations made the implementation. + + - Type of element: + + - |isotropic|_: An isotropic element. + +Template Implementation +----------------------- + +.. _dirichlet_implementation: dirichlet_implementation.html + +.. |dirichlet_implementation| replace:: dirichlet< typename dimension , typename medium , typename property , typename quadrature_points >() + +* Dirichlet implementation of various elements + + - |dirichlet_implementation|_ diff --git a/docs/api/boundary_conditions/dirichlet_implementation.rst b/docs/api/boundary_conditions/dirichlet_implementation.rst new file mode 100644 index 00000000..fe1f20db --- /dev/null +++ b/docs/api/boundary_conditions/dirichlet_implementation.rst @@ -0,0 +1,4 @@ + +.. doxygenclass:: specfem::enums::boundary_conditions::dirichlet + :members: + :private-members: diff --git a/docs/api/boundary_conditions/index.rst b/docs/api/boundary_conditions/index.rst new file mode 100644 index 00000000..1bdd56c6 --- /dev/null +++ b/docs/api/boundary_conditions/index.rst @@ -0,0 +1,29 @@ +.. _boundary_conditions: + +Boundary conditions +------------------- + +Boundary conditions class is used as a template parameter of :doxygenclass:`specfem::domain::impl::elements::element` class. The approach for applying boundary conditions is defined more in detail in the :ref:`boundary_conditions` section. + +Interface +~~~~~~~~~ + +Interface for various types of boundary conditions + +.. codeblock:: + + template + class (boundary_condition_type) + +Types of boundary conditions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following boundary conditions are implemented: + +.. toctree:: + :maxdepth: 1 + + stacey + dirichlet + none + composite_boundaries diff --git a/docs/api/boundary_conditions/none.rst b/docs/api/boundary_conditions/none.rst new file mode 100644 index 00000000..0544081f --- /dev/null +++ b/docs/api/boundary_conditions/none.rst @@ -0,0 +1,83 @@ +.. _none_bc: + +None boundary conditions +======================== + +Definition +---------- + +.. doxygenclass:: specfem::enums::boundary_conditions::stacey + +Interface +--------- + +.. codeblock:: + + template + class none + +Parameters +---------- + +.. _dim2: ../enumerations/element/dim2.html + +.. |dim2| replace:: dim2() + +.. _dim3: ../enumerations/element/dim3.html + +.. |dim3| replace:: dim3() + +.. _elastic: ../enumerations/element/elastic.html + +.. |elastic| replace:: elastic() + +.. _acoustic: ../enumerations/element/acoustic.html + +.. |acoustic| replace:: acoustic() + +.. _static_quadrature_points: ../enumerations/element/static_quadrature_points.html + +.. |static_quadrature_points| replace:: static_quadrature_points< NGLL >() + +.. _isotropic: ../enumerations/element/isotropic.html + +.. |isotropic| replace:: isotropic() + +* ``dimension``: + + The dimension of the element. + + - |dim2|_: A two dimensional element. + - |dim3|_: A three dimensional element. + +* ``medium``: + + The medium of the element. + + - |elastic|_: An elastic element. + - |acoustic|_: An acoustic element. + +* ``quadrature_points_type``: + + The quadrature points of the element. + + - |static_quadrature_points|_: A static quadrature point set. + +* ``properties``: + + The properties of the element. The properties describe any specializations made the implementation. + + - Type of element: + + - |isotropic|_: An isotropic element. + +Template Implementation +----------------------- + +.. _dirichlet_implementation: none_implementation.html + +.. |dirichlet_implementation| replace:: none< typename dimension , typename medium , typename property , typename quadrature_points >() + +* None implementation of various elements. + + - |dirichlet_implementation|_ diff --git a/docs/api/boundary_conditions/none_implementation.rst b/docs/api/boundary_conditions/none_implementation.rst new file mode 100644 index 00000000..8b29af05 --- /dev/null +++ b/docs/api/boundary_conditions/none_implementation.rst @@ -0,0 +1,4 @@ + +.. doxygenclass:: specfem::enums::boundary_conditions::none + :members: + :private-members: diff --git a/docs/api/boundary_conditions/stacey.rst b/docs/api/boundary_conditions/stacey.rst new file mode 100644 index 00000000..d385c6f2 --- /dev/null +++ b/docs/api/boundary_conditions/stacey.rst @@ -0,0 +1,95 @@ +.. _stacey_ABCs:: + +Stacey ABCs +============ + +Definition +---------- + +.. doxygenclass:: specfem::enums::boundary_conditions::stacey + +Interface +--------- + +.. codeblock:: + + template + class stacey + +Parameters +---------- + +.. _dim2: ../enumerations/element/dim2.html + +.. |dim2| replace:: dim2() + +.. _dim3: ../enumerations/element/dim3.html + +.. |dim3| replace:: dim3() + +.. _elastic: ../enumerations/element/elastic.html + +.. |elastic| replace:: elastic() + +.. _acoustic: ../enumerations/element/acoustic.html + +.. |acoustic| replace:: acoustic() + +.. _static_quadrature_points: ../enumerations/element/static_quadrature_points.html + +.. |static_quadrature_points| replace:: static_quadrature_points< NGLL >() + +.. _isotropic: ../enumerations/element/isotropic.html + +.. |isotropic| replace:: isotropic() + +* ``dimension``: + + The dimension of the element. + + - |dim2|_: A two dimensional element. + - |dim3|_: A three dimensional element. + +* ``medium``: + + The medium of the element. + + - |elastic|_: An elastic element. + - |acoustic|_: An acoustic element. + +* ``quadrature_points_type``: + + The quadrature points of the element. + + - |static_quadrature_points|_: A static quadrature point set. + +* ``properties``: + + The properties of the element. The properties describe any specializations made the implementation. + + - Type of element: + + - |isotropic|_: An isotropic element. + +.. warning:: + + The Stacey ABCs are only implemented for the combination of parameters listed below. + +Template Specializations +------------------------ + +.. _stacey_dim2_elastic: stacey_dim2_elastic_implementation.html + +.. |stacey_dim2_elastic| replace:: stacey< |dim2|_, |elastic|_, typename property , typename quadrature_points >() + +.. _stacey_dim2_acoustic: stacey_dim2_acoustic_implementation.html + +.. |stacey_dim2_acoustic| replace:: stacey< |dim2|_, |acoustic|_, typename property , typename quadrature_points >() + +* Stacey ABCs for a two dimensional elements. + + - |stacey_dim2_elastic|_ + +* Stacey ABCs for a two dimensional isotropic acoustic element with a static quadrature point set. + + - |stacey_dim2_acoustic|_ diff --git a/docs/api/boundary_conditions/stacey_dim2_acoustic_implementation.rst b/docs/api/boundary_conditions/stacey_dim2_acoustic_implementation.rst new file mode 100644 index 00000000..33ec36bf --- /dev/null +++ b/docs/api/boundary_conditions/stacey_dim2_acoustic_implementation.rst @@ -0,0 +1,4 @@ + +.. doxygenclass:: specfem::enums::boundary_conditions::stacey< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::acoustic, property, qp_type > + :members: + :private-members: diff --git a/docs/api/boundary_conditions/stacey_dim2_elastic_implementation.rst b/docs/api/boundary_conditions/stacey_dim2_elastic_implementation.rst new file mode 100644 index 00000000..383088db --- /dev/null +++ b/docs/api/boundary_conditions/stacey_dim2_elastic_implementation.rst @@ -0,0 +1,4 @@ + +.. doxygenclass:: specfem::enums::boundary_conditions::stacey< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::elastic, property, qp_type > + :members: + :private-members: diff --git a/docs/api/boundary_conditions/stacey_dirichlet_implementation.rst b/docs/api/boundary_conditions/stacey_dirichlet_implementation.rst new file mode 100644 index 00000000..a8c33281 --- /dev/null +++ b/docs/api/boundary_conditions/stacey_dirichlet_implementation.rst @@ -0,0 +1,4 @@ + +.. doxygenclass:: specfem::enums::boundary_conditions::composite_boundary< specfem::enums::boundary_conditions::stacey< properties... >, specfem::enums::boundary_conditions::dirichlet< properties... > > + :members: + :private-members: diff --git a/docs/api/compute.rst b/docs/api/compute.rst deleted file mode 100644 index 57e0c2be..00000000 --- a/docs/api/compute.rst +++ /dev/null @@ -1,21 +0,0 @@ -.. _compute:: - -Data interface to compute forces -================================= - -The interfaces provided here stores data required to compute mass and stiffness terms at elemental level. - -.. doxygenfile:: compute.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -.. doxygenfile:: compute_partial_derivatives.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -.. doxygenfile:: compute_properties.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -.. doxygenfile:: compute_sources.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -.. doxygenfile:: compute_receivers.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION diff --git a/docs/api/compute/compute.rst b/docs/api/compute/compute.rst new file mode 100644 index 00000000..d7dd1a47 --- /dev/null +++ b/docs/api/compute/compute.rst @@ -0,0 +1,14 @@ +.. _compute:: + +Compute Struct +=============== + +The ``compute`` struct is used to compute and store mesh assembly information. + +.. doxygenstruct:: specfem::compute::compute + :members: + :undoc-members: + +.. doxygenstruct:: specfem::compute::coordinates + :members: + :undoc-members: diff --git a/docs/api/compute/compute_coupled_interfaces.rst b/docs/api/compute/compute_coupled_interfaces.rst new file mode 100644 index 00000000..3246df24 --- /dev/null +++ b/docs/api/compute/compute_coupled_interfaces.rst @@ -0,0 +1,22 @@ +.. _compute_coupled_interfaces:: + +Coupled Interfaces Struct +========================= + +The ``coupled_interfaces`` struct is used to read and store coupling information for every coupled interface within the domain. + +.. doxygenstruct:: specfem::compute::coupled_interfaces::coupled_interfaces + :members: + :undoc-members: + +.. doxygenstruct:: specfem::compute::coupled_interfaces::elastic_acoustic + :members: + :undoc-members: + +.. doxygenstruct:: specfem::compute::coupled_interfaces::elastic_poroelastic + :members: + :undoc-members: + +.. doxygenstruct:: specfem::compute::coupled_interfaces::acoustic_poroelastic + :members: + :undoc-members: diff --git a/docs/api/compute/compute_partial_derivatives.rst b/docs/api/compute/compute_partial_derivatives.rst new file mode 100644 index 00000000..15fc8775 --- /dev/null +++ b/docs/api/compute/compute_partial_derivatives.rst @@ -0,0 +1,10 @@ +.. _compute_partial_derivatives:: + +Partial Derivatives Struct +========================== + +The ``partial_derivatives`` struct is used to store partial derivatives for all GLL points in the mesh. + +.. doxygenstruct:: specfem::compute::partial_derivatives + :members: + :undoc-members: diff --git a/docs/api/compute/compute_properties.rst b/docs/api/compute/compute_properties.rst new file mode 100644 index 00000000..2223b404 --- /dev/null +++ b/docs/api/compute/compute_properties.rst @@ -0,0 +1,10 @@ +.. _compute_properties:: + +Properties Struct +================= + +The ``properties`` struct is used to store material properties for quadrature point within the mesh. + +.. doxygenstruct:: specfem::compute::properties + :members: + :undoc-members: diff --git a/docs/api/compute/compute_receivers.rst b/docs/api/compute/compute_receivers.rst new file mode 100644 index 00000000..81f9ea83 --- /dev/null +++ b/docs/api/compute/compute_receivers.rst @@ -0,0 +1,10 @@ +.. _compute_receivers:: + +Receivers Struct +================ + +The ``receivers`` struct is used to store receiver information, computed receiver seismograms, and receiver elemental properties (lagrange interpolants) within the mesh. + +.. doxygenstruct:: specfem::compute::receivers + :members: + :undoc-members: diff --git a/docs/api/compute/compute_sources.rst b/docs/api/compute/compute_sources.rst new file mode 100644 index 00000000..9e49d390 --- /dev/null +++ b/docs/api/compute/compute_sources.rst @@ -0,0 +1,10 @@ +.. _compute_sources:: + +Sources Struct +=============== + +The ``sources`` struct is used to store source information and its elemental contribution properties (lagrange interpolants) within the mesh. + +.. doxygenstruct:: specfem::compute::sources + :members: + :undoc-members: diff --git a/docs/api/compute/index.rst b/docs/api/compute/index.rst new file mode 100644 index 00000000..537e864f --- /dev/null +++ b/docs/api/compute/index.rst @@ -0,0 +1,16 @@ +.. _compute_index:: + +Compute Data Interface +********************** + +The interfaces provided here stores data required to compute mass and stiffness terms at elemental level. Compute struct enables easy transfer of data between host and device. Organizing compute struct into smaller structs allows us to a pass these structs to host and device functions and eliminate the need for global arrays. This improves readability and maintainability. + +.. toctree:: + :maxdepth: 1 + + compute + compute_partial_derivatives + compute_properties + compute_sources + compute_receivers + compute_coupled_interfaces diff --git a/docs/api/coupling_physics/coupled_interface.rst b/docs/api/coupling_physics/coupled_interface.rst new file mode 100644 index 00000000..5d644d09 --- /dev/null +++ b/docs/api/coupling_physics/coupled_interface.rst @@ -0,0 +1,52 @@ + +Coupled Interface API +===================== + +Definition +---------- + +.. doxygenclass:: specfem::coupled_interface::coupled_interface + +Interface +~~~~~~~~~ + +.. code-block:: + + template + class coupled_interface + +Parameters +~~~~~~~~~~ + +.. note:: + + Coupled interface template parameters are deduced from the constructor arguments. + +.. _domain: ../domain/domain.html + +.. |domain| replace:: domain() + +* ``self_domain``: + + Primary domain of the edge. This is the domain whose wavefield is updated by methods within this class. + + - |domain|_: An instantiation of a domain class + +* ``coupled_domain``: + + Secondary domain of the edge. This is the domain whose wavefield is used to compute coupling interaction. + + - |domain|_: An instantiation of a domain class + +Class methods +------------- + +.. doxygenclass:: specfem::coupled_interface::coupled_interface + :members: + :private-members: + +Iterators +--------- + +.. doxygennamespace:: specfem::compute::coupled_interfaces::iterator + :members: diff --git a/docs/api/coupling_physics/edge/edge.rst b/docs/api/coupling_physics/edge/edge.rst new file mode 100644 index 00000000..ba8d85bf --- /dev/null +++ b/docs/api/coupling_physics/edge/edge.rst @@ -0,0 +1,89 @@ + +Edge API +======== + +Edges are used as building blocks for any coupled interface. The methods presented within edge class evaluate the coupling physics at a single GLL point within the edge + +Definition +---------- + +.. doxygenclass:: specfem::coupled_interface::impl::edges::edge + +Interface +~~~~~~~~~ + +.. code-block:: + + template + class edge + +Parameters +~~~~~~~~~~ + +.. note:: + + template parameters are deduced from the constructor arguments by the compiler + +.. _domain: ../../domain/domain.html + +.. |domain| replace:: domain() + +* ``self_domain``: + + Primary domain of the edge. This is the domain whose wavefield is updated by methods within this class. + + - |domain|_: An instantiation of a domain class + +* ``coupled_domain``: + + Secondary domain of the edge. This is the domain whose wavefield is used to compute coupling interaction. + + - |domain|_: An instantiation of a domain class + +.. warning:: + + Implemetations exists for only for the specializations defined below. + +Template Specializations +------------------------ + +.. _dim2: ../../enumerations/element/dim2.html + +.. |dim2| replace:: dim2() + +.. _dim3: ../../enumerations/element/dim3.html + +.. |dim3| replace:: dim3() + +.. _elastic: ../../enumerations/element/elastic.html + +.. |elastic| replace:: elastic() + +.. _acoustic: ../../enumerations/element/acoustic.html + +.. |acoustic| replace:: acoustic() + +.. _static_quadrature_points: ../../enumerations/element/static_quadrature_points.html + +.. |static_quadrature_points| replace:: static_quadrature_points< NGLL >() + +.. _isotropic: ../../enumerations/element/isotropic.html + +.. |isotropic| replace:: isotropic() + +.. |static_elastic_domain| replace:: domain< |elastic|_, |static_quadrature_points|_ >() + +.. |static_acoustic_domain| replace:: domain< |acoustic|_, |static_quadrature_points|_ >() + +.. _elastic_acoustic_edge: elastic_acoustic/elastic_acoustic_edge.html + +.. |elastic_acoustic_edge| replace:: edge< |static_elastic_domain|, |static_acoustic_domain| >() + +.. _acoustic_elastic_edge: elastic_acoustic/acoustic_elastic_edge.html + +.. |acoustic_elastic_edge| replace:: edge< |static_acoustic_domain|, |static_elastic_domain| >() + +* Elastic-Acoustic Edges + + - |elastic_acoustic_edge|_: Elastic acoustic edge with elastic domain as primary domain and acoustic domain as secondary domain + - |acoustic_elastic_edge|_: Acoustic elastic edge with acoustic domain as primary domain and elastic domain as secondary domain diff --git a/docs/api/coupling_physics/edge/elastic_acoustic/acoustic_elastic_edge.rst b/docs/api/coupling_physics/edge/elastic_acoustic/acoustic_elastic_edge.rst new file mode 100644 index 00000000..d894138a --- /dev/null +++ b/docs/api/coupling_physics/edge/elastic_acoustic/acoustic_elastic_edge.rst @@ -0,0 +1,5 @@ +.. _specfem_coupling_physics_edge_acoustic_elastic: + +.. doxygenclass:: specfem::coupled_interface::impl::edges::edge< specfem::domain::domain< specfem::enums::element::medium::acoustic, qp_type >, specfem::domain::domain< specfem::enums::element::medium::elastic, qp_type > > + :members: + :private-members: diff --git a/docs/api/coupling_physics/edge/elastic_acoustic/elastic_acoustic_edge.rst b/docs/api/coupling_physics/edge/elastic_acoustic/elastic_acoustic_edge.rst new file mode 100644 index 00000000..73e1098e --- /dev/null +++ b/docs/api/coupling_physics/edge/elastic_acoustic/elastic_acoustic_edge.rst @@ -0,0 +1,5 @@ +.. _specfem_coupling_physics_edge_elastic_acoustic: + +.. doxygenclass:: specfem::coupled_interface::impl::edges::edge< specfem::domain::domain< specfem::enums::element::medium::elastic, qp_type >, specfem::domain::domain< specfem::enums::element::medium::acoustic, qp_type > > + :members: + :private-members: diff --git a/docs/api/coupling_physics/index.rst b/docs/api/coupling_physics/index.rst new file mode 100644 index 00000000..07291425 --- /dev/null +++ b/docs/api/coupling_physics/index.rst @@ -0,0 +1,11 @@ + +Coupled Interface +***************** + +Coupled Interface is used to define coupling physics at domain interfaces. + +.. toctree:: + :maxdepth: 1 + + coupled_interface + edge/edge diff --git a/docs/api/domain.rst b/docs/api/domain.rst deleted file mode 100644 index a324f188..00000000 --- a/docs/api/domain.rst +++ /dev/null @@ -1,18 +0,0 @@ -.. _domain:: - -Domain interface -================= - -Domain class is used to implement physics related to specific types of domain. - -.. doxygenfile:: domain.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -.. doxygenfile:: elastic_domain.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -Helper routines to compute stresses ------------------------------------ - -.. doxygenfile:: mathematical_operators.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION diff --git a/docs/api/domain/Domain_Namespace.svg b/docs/api/domain/Domain_Namespace.svg new file mode 100644 index 00000000..cae4c035 --- /dev/null +++ b/docs/api/domain/Domain_Namespace.svg @@ -0,0 +1 @@ + diff --git a/docs/api/domain/domain.rst b/docs/api/domain/domain.rst new file mode 100644 index 00000000..e36fa5c8 --- /dev/null +++ b/docs/api/domain/domain.rst @@ -0,0 +1,64 @@ +.. _domain: + +Domain API +---------- + +Definition +========== + +.. doxygenclass:: specfem::domain::domain + +Interface +~~~~~~~~~ + +.. code-block:: + + template + class specfem::domain::domain + +Parameters +~~~~~~~~~~ + +.. _dim2: ../enumerations/element/dim2.html + +.. |dim2| replace:: dim2() + +.. _dim3: ../enumerations/element/dim3.html + +.. |dim3| replace:: dim3() + +.. _elastic: ../enumerations/element/elastic.html + +.. |elastic| replace:: elastic() + +.. _acoustic: ../enumerations/element/acoustic.html + +.. |acoustic| replace:: acoustic() + +.. _static_quadrature_points: ../enumerations/element/static_quadrature_points.html + +.. |static_quadrature_points| replace:: static_quadrature_points< NGLL >() + +.. _isotropic: ../enumerations/element/isotropic.html + +.. |isotropic| replace:: isotropic() + +* ``medium``: + + The medium of the element. + + - |elastic|_: An elastic element. + - |acoustic|_: An acoustic element. + +* ``quadrature_points_type``: + + The quadrature points of the element. + + - |static_quadrature_points|_: A static quadrature point set. + +Class members +============= + +.. doxygenclass:: specfem::domain::domain + :members: + :private-members: diff --git a/docs/api/domain/element/elements.rst b/docs/api/domain/element/elements.rst new file mode 100644 index 00000000..579384c0 --- /dev/null +++ b/docs/api/domain/element/elements.rst @@ -0,0 +1,128 @@ +.. _element_api_documentation:: + +Element API +=========== + +Elements are the building blocks of the compute infratructure within a domain. Each instance of an element class respresents a single spectral element within the domain. The methods within this class compute elemental contributions at a single quadrature within the element. + +Definition +---------- + +.. doxygenclass:: specfem::domain::impl::elements::element + +Interface +~~~~~~~~~ + +.. code-block:: + + template + class specfem::domain::impl::elements::element + +Parameters +~~~~~~~~~~ + +.. _dim2: ../../enumerations/element/dim2.html + +.. |dim2| replace:: dim2() + +.. _dim3: ../../enumerations/element/dim3.html + +.. |dim3| replace:: dim3() + +.. _elastic: ../../enumerations/element/elastic.html + +.. |elastic| replace:: elastic() + +.. _acoustic: ../../enumerations/element/acoustic.html + +.. |acoustic| replace:: acoustic() + +.. _static_quadrature_points: ../../enumerations/element/static_quadrature_points.html + +.. |static_quadrature_points| replace:: static_quadrature_points< NGLL >() + +.. _isotropic: ../../enumerations/element/isotropic.html + +.. |isotropic| replace:: isotropic() + +.. _boundary_conditions: ../boundary_conditions/boundary_conditions.html + +.. _dirichlet: ../boundary_conditions/dirichlet.html + +.. |dirichlet| replace:: dirichlet() + +.. _stacey: ../boundary_conditions/stacey.html + +.. |stacey| replace:: stacey() + +.. _none: ../boundary_conditions/none.html + +.. |none| replace:: none() + +.. _composite: ../boundary_conditions/composite.html + +.. |composite| replace:: composite() + +* ``dimension``: + + The dimension of the element. + + - |dim2|_: A two dimensional element. + - |dim3|_: A three dimensional element. + +* ``medium``: + + The medium of the element. + + - |elastic|_: An elastic element. + - |acoustic|_: An acoustic element. + +* ``quadrature_points_type``: + + The quadrature points of the element. + + - |static_quadrature_points|_: A static quadrature point set. + +* ``properties``: + + The properties of the element. The properties describe any specializations made the implementation. + + - Type of element: + + - |isotropic|_: An isotropic element. + +* ``boundary_conditions``: + + The boundary conditions to be applied to the element. The boundary conditions modify the contribution of element's force vector to the global force vector. + +.. note:: + An element on the boundary is not Boundary conditions are not specified, the element will be assumed to have neumann boundary condition. + + - |dirichlet|_: A Dirichlet boundary condition. + - |stacey|_: A Stacey boundary condition. + - |none|_ (default): No boundary condition. + - |composite|_: A composite boundary condition. + + +.. warning:: + + Implemetations exists for only for the specializations defined below. + +Template specializations +------------------------- + +.. _dim2_elastic_static_quadrature_points_isotropic: elements_dim2_elastic_static_quadrature_points_isotropic.html + +.. |dim2_elastic_static_quadrature_points_isotropic| replace:: element< |dim2|_, |elastic|_, |static_quadrature_points|_, |isotropic|_, typename |boundary_conditions|_ >() + +.. _dim2_acoustic_static_quadrature_points_isotropic: elements_dim2_acoustic_static_quadrature_points_isotropic.html + +.. |dim2_acoustic_static_quadrature_points_isotropic| replace:: element< |dim2|_, |acoustic|_, |static_quadrature_points|_, |isotropic|_, typename |boundary_conditions|_ >() + +* 2D elastic isotropic elements: + + - |dim2_elastic_static_quadrature_points_isotropic|_: A two dimensional elastic element with static quadrature points and isotropic material properties. + +* 2D acoustic isotropic elements: + + - |dim2_acoustic_static_quadrature_points_isotropic|_: A two dimensional acoustic element with static quadrature points and isotropic material properties. diff --git a/docs/api/domain/element/elements_dim2_acoustic_static_quadrature_points_isotropic.rst b/docs/api/domain/element/elements_dim2_acoustic_static_quadrature_points_isotropic.rst new file mode 100644 index 00000000..bafd49ed --- /dev/null +++ b/docs/api/domain/element/elements_dim2_acoustic_static_quadrature_points_isotropic.rst @@ -0,0 +1,4 @@ + +.. doxygenclass:: specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::elastic, specfem::enums::element::quadrature::static_quadrature_points< NGLL >, specfem::enums::element::property::isotropic > + :members: + :private-members: diff --git a/docs/api/domain/element/elements_dim2_elastic_static_quadrature_points_isotropic.rst b/docs/api/domain/element/elements_dim2_elastic_static_quadrature_points_isotropic.rst new file mode 100644 index 00000000..bafd49ed --- /dev/null +++ b/docs/api/domain/element/elements_dim2_elastic_static_quadrature_points_isotropic.rst @@ -0,0 +1,4 @@ + +.. doxygenclass:: specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::elastic, specfem::enums::element::quadrature::static_quadrature_points< NGLL >, specfem::enums::element::property::isotropic > + :members: + :private-members: diff --git a/docs/api/domain/index.rst b/docs/api/domain/index.rst new file mode 100644 index 00000000..fd861c33 --- /dev/null +++ b/docs/api/domain/index.rst @@ -0,0 +1,22 @@ +.. _domain_index_api_guide:: + +Domain +====== + +The domain is a templated class used to store wavefields and methods used to compute evolution of the wavefield in time. From a architectural standpoint, a domain consists of a set of elements, elemental sources and elemental receivers. + +.. figure:: Domain_Namespace.svg + :alt: Domain Namespace + :width: 800 + :align: center + + Domain Namespace + +.. toctree:: + :maxdepth: 1 + + domain + kernels/index + element/elements + receivers/receivers + sources/sources diff --git a/docs/api/domain/kernels/elemental_kernels.rst b/docs/api/domain/kernels/elemental_kernels.rst new file mode 100644 index 00000000..90212537 --- /dev/null +++ b/docs/api/domain/kernels/elemental_kernels.rst @@ -0,0 +1,5 @@ + +.. doxygenclass:: specfem::domain::impl::kernels::element_kernel + :members: + :undoc-members: + :private-members: diff --git a/docs/api/domain/kernels/index.rst b/docs/api/domain/kernels/index.rst new file mode 100644 index 00000000..84ae95d4 --- /dev/null +++ b/docs/api/domain/kernels/index.rst @@ -0,0 +1,84 @@ + +Kernels +======= + +The ``kernels`` namespace is used to store Kokkos kernel implementations. The kernel implemetation describes the parallelism required to execute the computations within elements, elemental sources and elemental receivers. + +Kernels storage class +--------------------- + +Interface +~~~~~~~~~ + +.. code-block:: + + template + class specfem::domain::impl::kernels::kernels + +Parameters +~~~~~~~~~~ + +.. _dim2: ../enumerations/element/dim2.html + +.. |dim2| replace:: dim2() + +.. _dim3: ../enumerations/element/dim3.html + +.. |dim3| replace:: dim3() + +.. _elastic: ../enumerations/element/elastic.html + +.. |elastic| replace:: elastic() + +.. _acoustic: ../enumerations/element/acoustic.html + +.. |acoustic| replace:: acoustic() + +.. _static_quadrature_points: ../enumerations/element/static_quadrature_points.html + +.. |static_quadrature_points| replace:: static_quadrature_points< NGLL >() + +.. _isotropic: ../enumerations/element/isotropic.html + +.. |isotropic| replace:: isotropic() + +* ``medium``: + + The medium of the element. + + - |elastic|_: An elastic element. + - |acoustic|_: An acoustic element. + +* ``quadrature_points_type``: + + The quadrature points of the element. + + - |static_quadrature_points|_: A static quadrature point set. + +Class Description +~~~~~~~~~~~~~~~~~ + +.. _kernels: kernels.html + +.. |kernels| replace:: kernels() + +- |kernels|_ + +Kernel implementations +---------------------- + +.. _elemental_kernels: elemental_kernels.html + +.. |elemental_kernels| replace:: elemental_kernels() + +.. _source_kernels: source_kernel.html + +.. |source_kernels| replace:: source_kernels() + +.. _receiver_kernels: receiver_kernels.html + +.. |receiver_kernels| replace:: receiver_kernels() + +- |elemental_kernels|_ +- |source_kernels|_ +- |receiver_kernels|_ diff --git a/docs/api/domain/kernels/kernels.rst b/docs/api/domain/kernels/kernels.rst new file mode 100644 index 00000000..b25c27e4 --- /dev/null +++ b/docs/api/domain/kernels/kernels.rst @@ -0,0 +1,5 @@ + +.. doxygenclass:: specfem::domain::impl::kernels::kernels + :members: + :private-members: + :undoc-members: diff --git a/docs/api/domain/kernels/receiver_kernels.rst b/docs/api/domain/kernels/receiver_kernels.rst new file mode 100644 index 00000000..bb9e04a4 --- /dev/null +++ b/docs/api/domain/kernels/receiver_kernels.rst @@ -0,0 +1,5 @@ + +.. doxygenclass:: specfem::domain::impl::kernels::receiver_kernel + :members: + :undoc-members: + :private-members: diff --git a/docs/api/domain/kernels/source_kernel.rst b/docs/api/domain/kernels/source_kernel.rst new file mode 100644 index 00000000..581a0d25 --- /dev/null +++ b/docs/api/domain/kernels/source_kernel.rst @@ -0,0 +1,5 @@ + +.. doxygenclass:: specfem::domain::impl::kernels::source_kernel + :members: + :undoc-members: + :private-members: diff --git a/docs/api/domain/receivers/receivers.rst b/docs/api/domain/receivers/receivers.rst new file mode 100644 index 00000000..6f64630c --- /dev/null +++ b/docs/api/domain/receivers/receivers.rst @@ -0,0 +1,97 @@ +.. elemental_receivers_api_doc:: + +Elemental Receivers API +======================= + +Elemental receivers class defines the methods required to compute siesmograms at the receivers for a given siesmogram step. The methods in this class only compute contribution to the seismogram for a single receiver at a single GLL point inside the element where the receiver is located. + +Definition +---------- + +.. doxygenclass:: specfem::domain::impl::receivers::receiver + +Interface +~~~~~~~~~ + +.. code-block:: + + template + class specfem::domain::impl::receivers::receiver + +Parameters +~~~~~~~~~~ + +.. _dim2: ../../enumerations/element/dim2.html + +.. |dim2| replace:: dim2() + +.. _dim3: ../../enumerations/element/dim3.html + +.. |dim3| replace:: dim3() + +.. _elastic: ../../enumerations/element/elastic.html + +.. |elastic| replace:: elastic() + +.. _acoustic: ../../enumerations/element/acoustic.html + +.. |acoustic| replace:: acoustic() + +.. _static_quadrature_points: ../../enumerations/element/static_quadrature_points.html + +.. |static_quadrature_points| replace:: static_quadrature_points< NGLL >() + +.. _isotropic: ../../enumerations/element/isotropic.html + +.. |isotropic| replace:: isotropic() + +* ``dimension``: + + The dimension of the element. + + - |dim2|_: A two dimensional element. + - |dim3|_: A three dimensional element. + +* ``medium``: + + The medium of the element. + + - |elastic|_: An elastic element. + - |acoustic|_: An acoustic element. + +* ``quadrature_points_type``: + + The quadrature points of the element. + + - |static_quadrature_points|_: A static quadrature point set. + +* ``Properties``: + + The properties of the element. The properties describe any specializations made the implementation. + + - Type of element: + + - |isotropic|_: An isotropic element. + +.. warning:: + + Implemetations exists for only for the specializations defined below. + +Template specializations +------------------------- + +.. _dim2_elastic_static_quadrature_points_isotropic: receivers_dim2_elastic_static_quadrature_points_isotropic.html + +.. |dim2_elastic_static_quadrature_points_isotropic| replace:: receiver< |dim2|_, |elastic|_, |static_quadrature_points|_, |isotropic|_ >() + +.. _dim2_acoustic_static_quadrature_points_isotropic: receivers_dim2_acoustic_static_quadrature_points_isotropic.html + +.. |dim2_acoustic_static_quadrature_points_isotropic| replace:: receiver< |dim2|_, |acoustic|_, |static_quadrature_points|_, |isotropic|_ >() + +* 2D elastic isotropic elements: + + - |dim2_elastic_static_quadrature_points_isotropic|_: Receiver located in a two dimensional elastic element with static quadrature points and isotropic material properties. + +* 2D acoustic isotropic elements: + + - |dim2_acoustic_static_quadrature_points_isotropic|_: Receiver located in a two dimensional acoustic element with static quadrature points and isotropic material properties. diff --git a/docs/api/domain/receivers/receivers_dim2_acoustic_static_quadrature_points_isotropic.rst b/docs/api/domain/receivers/receivers_dim2_acoustic_static_quadrature_points_isotropic.rst new file mode 100644 index 00000000..1b70eddf --- /dev/null +++ b/docs/api/domain/receivers/receivers_dim2_acoustic_static_quadrature_points_isotropic.rst @@ -0,0 +1,4 @@ + +.. doxygenclass:: specfem::domain::impl::receivers::receiver< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::acoustic, specfem::enums::element::quadrature::static_quadrature_points< NGLL >, specfem::enums::element::property::isotropic > + :members: + :private-members: diff --git a/docs/api/domain/receivers/receivers_dim2_elastic_static_quadrature_points_isotropic.rst b/docs/api/domain/receivers/receivers_dim2_elastic_static_quadrature_points_isotropic.rst new file mode 100644 index 00000000..ef72f8b3 --- /dev/null +++ b/docs/api/domain/receivers/receivers_dim2_elastic_static_quadrature_points_isotropic.rst @@ -0,0 +1,4 @@ + +.. doxygenclass:: specfem::domain::impl::receivers::receiver< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::elastic, specfem::enums::element::quadrature::static_quadrature_points< NGLL >, specfem::enums::element::property::isotropic > + :members: + :private-members: diff --git a/docs/api/domain/sources/sources.rst b/docs/api/domain/sources/sources.rst new file mode 100644 index 00000000..38db93d8 --- /dev/null +++ b/docs/api/domain/sources/sources.rst @@ -0,0 +1,97 @@ +.. elemental_sources_api_documentation + +Elemental Sources API +===================== + +Elemental sources class defines the methods required to compute the contribution of a source to the global acceleration at a given timestep. The methods in this class only compute the contributions of a single source for a single GLL point in the element where the source is located. + +Definition +---------- + +.. doxygenclass:: specfem::domain::impl::sources::source + +Interface +~~~~~~~~~ + +.. code-block:: + + template + class specfem::domain::impl::sources::source + +Parameters +~~~~~~~~~~ + +.. _dim2: ../../enumerations/element/dim2.html + +.. |dim2| replace:: dim2() + +.. _dim3: ../../enumerations/element/dim3.html + +.. |dim3| replace:: dim3() + +.. _elastic: ../../enumerations/element/elastic.html + +.. |elastic| replace:: elastic() + +.. _acoustic: ../../enumerations/element/acoustic.html + +.. |acoustic| replace:: acoustic() + +.. _static_quadrature_points: ../../enumerations/element/static_quadrature_points.html + +.. |static_quadrature_points| replace:: static_quadrature_points< NGLL >() + +.. _isotropic: ../../enumerations/element/isotropic.html + +.. |isotropic| replace:: isotropic() + +* ``dimension``: + + The dimension of the element. + + - |dim2|_: A two dimensional element. + - |dim3|_: A three dimensional element. + +* ``medium``: + + The medium of the element. + + - |elastic|_: An elastic element. + - |acoustic|_: An acoustic element. + +* ``quadrature_points_type``: + + The quadrature points of the element. + + - |static_quadrature_points|_: A static quadrature point set. + +* ``Properties``: + + The properties of the element. The properties describe any specializations made the implementation. + + - Type of element: + + - |isotropic|_: An isotropic element. + +.. warning:: + + Implemetations exists for only for the specializations defined below. + +Template specializations +------------------------- + +.. _dim2_elastic_static_quadrature_points_isotropic: sources_dim2_elastic_static_quadrature_points_isotropic.html + +.. |dim2_elastic_static_quadrature_points_isotropic| replace:: source< |dim2|_, |elastic|_, |static_quadrature_points|_, |isotropic|_ >() + +.. _dim2_acoustic_static_quadrature_points_isotropic: sources_dim2_acoustic_static_quadrature_points_isotropic.html + +.. |dim2_acoustic_static_quadrature_points_isotropic| replace:: source< |dim2|_, |acoustic|_, |static_quadrature_points|_, |isotropic|_ >() + +* 2D elastic isotropic elements: + + - |dim2_elastic_static_quadrature_points_isotropic|_: Source located in a two dimensional elastic element with static quadrature points and isotropic material properties. + +* 2D acoustic isotropic elements: + + - |dim2_acoustic_static_quadrature_points_isotropic|_: Source located in a two dimensional acoustic element with static quadrature points and isotropic material properties. diff --git a/docs/api/domain/sources/sources_dim2_acoustic_static_quadrature_points_isotropic.rst b/docs/api/domain/sources/sources_dim2_acoustic_static_quadrature_points_isotropic.rst new file mode 100644 index 00000000..a673791c --- /dev/null +++ b/docs/api/domain/sources/sources_dim2_acoustic_static_quadrature_points_isotropic.rst @@ -0,0 +1,4 @@ + +.. doxygenclass:: specfem::domain::impl::sources::source< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::acoustic, specfem::enums::element::quadrature::static_quadrature_points< NGLL >, specfem::enums::element::property::isotropic > + :members: + :private-members: diff --git a/docs/api/domain/sources/sources_dim2_elastic_static_quadrature_points_isotropic.rst b/docs/api/domain/sources/sources_dim2_elastic_static_quadrature_points_isotropic.rst new file mode 100644 index 00000000..a0d5ed24 --- /dev/null +++ b/docs/api/domain/sources/sources_dim2_elastic_static_quadrature_points_isotropic.rst @@ -0,0 +1,4 @@ + +.. doxygenclass:: specfem::domain::impl::sources::source< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::elastic, specfem::enums::element::quadrature::static_quadrature_points< NGLL >, specfem::enums::element::property::isotropic > + :members: + :private-members: diff --git a/docs/api/enumerations/axes/axes_enumeration.rst b/docs/api/enumerations/axes/axes_enumeration.rst new file mode 100644 index 00000000..14195e6b --- /dev/null +++ b/docs/api/enumerations/axes/axes_enumeration.rst @@ -0,0 +1,7 @@ + +Axes Enumeration +~~~~~~~~~~~~~~~~ + +Define cartesian axes. + +.. doxygenenum:: specfem::enums::axes diff --git a/docs/api/enumerations/coupling/coupling_enumerations.rst b/docs/api/enumerations/coupling/coupling_enumerations.rst new file mode 100644 index 00000000..94d0ee48 --- /dev/null +++ b/docs/api/enumerations/coupling/coupling_enumerations.rst @@ -0,0 +1,8 @@ + +Coupling Enumerations +~~~~~~~~~~~~~~~~~~~~~ + +Coulping enumerations are used to specify coupling edges. + +.. doxygennamespace:: specfem::enums::coupling + :members: diff --git a/docs/api/enumerations/element/acoustic.rst b/docs/api/enumerations/element/acoustic.rst new file mode 100644 index 00000000..4dc6f9b8 --- /dev/null +++ b/docs/api/enumerations/element/acoustic.rst @@ -0,0 +1,5 @@ +.. _specfem_enums_element_medium_acoustic: + +.. doxygenclass:: specfem::enums::element::medium::acoustic + :members: + :private-members: diff --git a/docs/api/enumerations/element/dim2.rst b/docs/api/enumerations/element/dim2.rst new file mode 100644 index 00000000..542adb13 --- /dev/null +++ b/docs/api/enumerations/element/dim2.rst @@ -0,0 +1,5 @@ +.. _specfem_enums_element_dimension_dim2: + +.. doxygenclass:: specfem::enums::element::dimension::dim2 + :members: + :private-members: diff --git a/docs/api/enumerations/element/dim3.rst b/docs/api/enumerations/element/dim3.rst new file mode 100644 index 00000000..3b38cb03 --- /dev/null +++ b/docs/api/enumerations/element/dim3.rst @@ -0,0 +1,5 @@ +.. _specfem_enums_element_dimension_dim2: + +.. doxygenclass:: specfem::enums::element::dimension::dim3 + :members: + :private-members: diff --git a/docs/api/enumerations/element/elastic.rst b/docs/api/enumerations/element/elastic.rst new file mode 100644 index 00000000..3ba24aee --- /dev/null +++ b/docs/api/enumerations/element/elastic.rst @@ -0,0 +1,5 @@ +.. _specfem_enums_element_medium_elastic: + +.. doxygenclass:: specfem::enums::element::medium::elastic + :members: + :private-members: diff --git a/docs/api/enumerations/element/element_enumeration.rst b/docs/api/enumerations/element/element_enumeration.rst new file mode 100644 index 00000000..a494566f --- /dev/null +++ b/docs/api/enumerations/element/element_enumeration.rst @@ -0,0 +1,84 @@ + +Element +~~~~~~~ + +Enumerations that define a type of element. + +.. _dim2: dim2.html + +.. |dim2| replace:: dim2() + +.. _dim3: dim3.html + +.. |dim3| replace:: dim3() + +.. _elastic: elastic.html + +.. |elastic| replace:: elastic() + +.. _acoustic: acoustic.html + +.. |acoustic| replace:: acoustic() + +.. _static_quadrature_points: static_quadrature_points.html + +.. |static_quadrature_points| replace:: static_quadrature_points< NGLL >() + +.. _isotropic: isotropic.html + +.. |isotropic| replace:: isotropic() + +.. _boundary_conditions: ../../boundary_conditions/index.html + +.. |boundary_conditions| replace:: boundary_conditions + +Dimension +_________ + +The dimension of the element. + +- |dim2|_: A two dimensional element. +- |dim3|_: A three dimensional element. + +Medium +______ + +The medium of the element. + +- |elastic|_: An elastic element. +- |acoustic|_: An acoustic element. + +Medium enumerations to tag the element with a medium. + +.. doxygenenum:: specfem::enums::element::type + +Quadrature Points +_________________ + +The quadrature points of the element. + +- |static_quadrature_points|_: A static quadrature point set. + +Elemental Properties +____________________ + +The properties of the element. The properties describe any specializations made the implementation. + +- Type of element: + + - |isotropic|_: An isotropic element. + +Property enumerations to tag the element with a property. + +.. doxygenenum:: specfem::enums::element::property_tag + +Boundary Conditions +___________________ + +Defines the boundary conditions on the element. The boundary conditions are used to modify the element's force contribution to the global force vector. + +- |boundary_conditions|_: The boundary conditions of the element. + +Boundary condition enumerations to tag the element with a boundary condition. + +.. doxygenenum:: specfem::enums::element::boundary_tag diff --git a/docs/api/enumerations/element/isotropic.rst b/docs/api/enumerations/element/isotropic.rst new file mode 100644 index 00000000..f2facc74 --- /dev/null +++ b/docs/api/enumerations/element/isotropic.rst @@ -0,0 +1,5 @@ +.. _specfem_enums_element_property_isotropic: + +.. doxygenclass:: specfem::enums::element::property::isotropic + :members: + :private-members: diff --git a/docs/api/enumerations/element/static_quadrature_points.rst b/docs/api/enumerations/element/static_quadrature_points.rst new file mode 100644 index 00000000..b015d449 --- /dev/null +++ b/docs/api/enumerations/element/static_quadrature_points.rst @@ -0,0 +1,5 @@ +.. _specfem_enums_element_quadrature_static_quadrature_points: + +.. doxygenclass:: specfem::enums::element::quadrature::static_quadrature_points + :members: + :private-members: diff --git a/docs/api/enumerations/index.rst b/docs/api/enumerations/index.rst new file mode 100644 index 00000000..a3aa584e --- /dev/null +++ b/docs/api/enumerations/index.rst @@ -0,0 +1,14 @@ +.. _specfem_enumerations:: + +Enumerations +************ + +Enumerations are used to define template parameters for different objects. + +.. toctree:: + :maxdepth: 1 + + element/element_enumeration + axes/axes_enumeration + coupling/coupling_enumerations + seismogram/seismogram_enumeration diff --git a/docs/api/enumerations/seismogram/seismogram_enumeration.rst b/docs/api/enumerations/seismogram/seismogram_enumeration.rst new file mode 100644 index 00000000..6dc813b7 --- /dev/null +++ b/docs/api/enumerations/seismogram/seismogram_enumeration.rst @@ -0,0 +1,7 @@ + +Seismogram Enumerations +~~~~~~~~~~~~~~~~~~~~~~~ + +Enumerations used to describe the type of seismogram data. + +.. doxygenenum:: specfem::enum::seismogram::type diff --git a/docs/api/index.rst b/docs/api/index.rst index 20bf89f5..120c90fc 100644 --- a/docs/api/index.rst +++ b/docs/api/index.rst @@ -7,4 +7,18 @@ API documentation :maxdepth: 2 :glob: - * + kokkos_abstractions + namespace/index + quadrature/index + material/index + IO/index + sources/index + receivers/index + compute/index + enumerations/index + domain/index + boundary_conditions/index + coupling_physics/index + timescheme/index + solver/index + setup_parameters/index diff --git a/docs/api/jacobian.rst b/docs/api/jacobian.rst deleted file mode 100644 index 920def9f..00000000 --- a/docs/api/jacobian.rst +++ /dev/null @@ -1,14 +0,0 @@ -.. _jacobian:: - -Utilities to compute elemental Jacobian and shape functions -============================================================ - -Shape Functions ----------------- -.. doxygenfile:: shape_functions.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -Jacobian ---------- -.. doxygenfile:: jacobian.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION diff --git a/docs/api/kokkos_abstractions.rst b/docs/api/kokkos_abstractions.rst index bc9e6ca2..5299f530 100644 --- a/docs/api/kokkos_abstractions.rst +++ b/docs/api/kokkos_abstractions.rst @@ -1,11 +1,12 @@ .. _kokkos_abstractions: -SPECFEM abstractions for Kokkos interfaces -=========================================== +Views and Execution Policies +============================ Specfem abstractions for Kokkos interfaces. The goal is never to use Kokkos views or execution policies directly. Ideally we would want to define them in kokkos_abstractions.h file under the specfem namespace. This keeps definition of datatypes/execution-policies consistent throughout the whole project. -.. doxygenfile:: kokkos_abstractions.h - :project: SPECFEM KOKKOS IMPLEMENTATION +.. doxygennamespace:: specfem::kokkos + :members: + :undoc-members: diff --git a/docs/api/material.rst b/docs/api/material.rst deleted file mode 100644 index 9de0c120..00000000 --- a/docs/api/material.rst +++ /dev/null @@ -1,15 +0,0 @@ -.. _material_interface: - -Material properties and helper routines -======================================== - -This section contains classes and functions required to read and store material properties to be assigned to various spectral elements. - -Material Class ---------------- - -.. doxygenfile:: material.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -.. doxygenfile:: elastic_material.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION diff --git a/docs/api/material/acoustic_material.rst b/docs/api/material/acoustic_material.rst new file mode 100644 index 00000000..e455b8c3 --- /dev/null +++ b/docs/api/material/acoustic_material.rst @@ -0,0 +1,10 @@ + +Acoustic Material +================= + +Acoustic material class + +.. doxygenclass:: specfem::material::acoustic_material + :members: + :undoc-members: + :private-members: diff --git a/docs/api/material/elastic_material.rst b/docs/api/material/elastic_material.rst new file mode 100644 index 00000000..30a8eb3d --- /dev/null +++ b/docs/api/material/elastic_material.rst @@ -0,0 +1,10 @@ + +Elastic Material +================= + +Elastic material class + +.. doxygenclass:: specfem::material::elastic_material + :members: + :undoc-members: + :private-members: diff --git a/docs/api/material/index.rst b/docs/api/material/index.rst new file mode 100644 index 00000000..9dd6b4c8 --- /dev/null +++ b/docs/api/material/index.rst @@ -0,0 +1,21 @@ +Materials Class API +=================== + +Materials Class is used to store material information for every material in the mesh. + +.. toctree:: + :maxdepth: 1 + +.. doxygenclass:: specfem::material::material + :members: + :undoc-members: + :private-members: + +Types of Materials Implemented +----------------------------- + +.. toctree:: + :maxdepth: 1 + + acoustic_material + elastic_material diff --git a/docs/api/mesh.rst b/docs/api/mesh.rst deleted file mode 100644 index 55575608..00000000 --- a/docs/api/mesh.rst +++ /dev/null @@ -1,61 +0,0 @@ -.. _mesh_interface: - -Mesh interface -============== - -Mesh interface ---------------- -.. doxygenfile:: mesh.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -Mesh properties ----------------- -.. doxygenfile:: mesh_properties.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -Material Definition --------------------- -.. doxygenfile:: material_indic.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -Boundaries Interface --------------------- - -.. doxygenfile:: boundaries/boundaries.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -.. doxygenfile:: boundaries/absorbing_boundaries.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -.. doxygenfile:: boundaries/forcing_boundaries.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -Elements Interface -------------------- - -.. doxygenfile:: elements/elements.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -.. doxygenfile:: elements/axial_elements.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -.. doxygenfile:: elements/tangential_elements.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -Surface Interface ------------------- - -.. doxygenfile:: surfaces.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -.. doxygenfile:: acoustic_free_surface.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -Routines to read fortran binary mesh files ------------------------------------------- - -.. doxygenfile:: read_mesh_database.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -.. doxygenfile:: read_material_properties.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION diff --git a/docs/api/namespaces/index.rst b/docs/api/namespaces/index.rst new file mode 100644 index 00000000..61fd498d --- /dev/null +++ b/docs/api/namespaces/index.rst @@ -0,0 +1,81 @@ + +Namespace Discription +===================== + +.. note:: + Still in progress. + +.. doxygennamespace:: specfem + :desc-only: + +.. doxygennamespace:: specfem::kokkos + :desc-only: + +.. doxygennamespace:: specfem::mesh + :desc-only: + +.. doxygennamespace:: specfem::mesh::boundaries + :desc-only: + +.. doxygennamespace:: specfem::mesh::elements + :desc-only: + +.. doxygennamespace:: specfem::mesh::coupled_interfaces + :desc-only: + +.. doxygennamespace:: specfem::mesh::IO + :desc-only: + +.. doxygennamespace:: specfem::mesh::IO::fortran + :desc-only: + +.. doxygennamespace:: specfem::compute + :desc-only: + +.. doxygennamespace:: specfem::domain + :desc-only: + +.. doxygennamespace:: specfem::domain::impl + :desc-only: + +.. doxygennamespace:: specfem::domain::impl::elements + :desc-only: + +.. doxygennamespace:: specfem::domain::impl::sources + :desc-only: + +.. doxygennamespace:: specfem::domain::impl::receivers + :desc-only: + +.. doxygennamespace:: specfem::coupled_interface + :desc-only: + +.. doxygennamespace:: specfem::coupled_interface::impl + :desc-only: + +.. doxygennamespace:: specfem::coupled_interface::impl::edges + :desc-only: + +.. doxygennamespace:: specfem::quadrature + :desc-only: + +.. doxygennamespace:: specfem::quadrature::gll + :desc-only: + +.. doxygennamespace:: specfem::material + :desc-only: + +.. doxygennamespace:: specfem::sources + :desc-only: + +.. doxygennamespace:: specfem::receivers + :desc-only: + +.. doxygennamespace:: specfem::TimeScheme + :desc-only: + +.. doxygennamespace:: specfem::writer + :desc-only: + +.. doxygennamespace:: specfem::runtime_configuration + :desc-only: diff --git a/docs/api/parameter.rst b/docs/api/parameter.rst deleted file mode 100644 index 8249cc67..00000000 --- a/docs/api/parameter.rst +++ /dev/null @@ -1,36 +0,0 @@ -.. _parameter: - -Simulation setup -================ - -Specfem setup object is used to parse specfem configuration file and instantiate simulation. - -Setup object used to instantiate a simulation ---------------------------------------------- - -.. doxygenfile:: parameter_parser/solver/solver.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -.. doxygenfile:: parameter_parser/solver/time_marching.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -.. doxygenfile:: parameter_parser/database_configuration.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -.. doxygenfile:: parameter_parser/header.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -.. doxygenfile:: parameter_parser/quadrature.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -.. doxygenfile:: parameter_parser/run_setup.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -.. doxygenfile:: parameter_parser/receivers.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -.. doxygenfile:: parameter_parser/seismogram.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -.. doxygenfile:: parameter_parser/setup.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION diff --git a/docs/api/quadrature.rst b/docs/api/quadrature.rst deleted file mode 100644 index c38c4eaa..00000000 --- a/docs/api/quadrature.rst +++ /dev/null @@ -1,30 +0,0 @@ -.. _quadrature: - -Quadrature object and helper routines -======================================= - -This section contains implementation details for the quadrature class and helper routines used to populate a quadrature object - -Quadrature Class ------------------ - -.. doxygenfile:: quadrature/quadrature.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -.. doxygenfile:: quadrature/gll/gll.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -GLL/GLJ helper routines ------------------------ - -.. doxygenfile:: quadrature/gll/gll_library.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -.. doxygenfile:: quadrature/gll/gll_utils.pp - :project: SPECFEM KOKKOS IMPLEMENTATION - -Lagrange polynomial helper routines ------------------------------------- - -.. doxygenfile:: quadrature/gll/lagrange_poly.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION diff --git a/docs/api/quadrature/gll.rst b/docs/api/quadrature/gll.rst new file mode 100644 index 00000000..f793a428 --- /dev/null +++ b/docs/api/quadrature/gll.rst @@ -0,0 +1,10 @@ + +GLL quadrature +==================== + +Gauss-Legendre-Lobatto quadrature rule. + +.. doxygenclass:: specfem::quadrature::gll::gll + :members: + :undoc-members: + :private-members: diff --git a/docs/api/quadrature/index.rst b/docs/api/quadrature/index.rst new file mode 100644 index 00000000..993471f7 --- /dev/null +++ b/docs/api/quadrature/index.rst @@ -0,0 +1,18 @@ + +Quadrature API +=================== + +The ``quadrature`` class provides methods to compute the quadrature points and weights required to compute integrals and derivatives of functions within a spectral element. + +.. doxygenclass:: specfem::quadrature::quadrature + :members: + :undoc-members: + :private-members: + +Types of quadratures implemented +-------------------------------- + +.. toctree:: + :maxdepth: 1 + + gll diff --git a/docs/api/receivers/index.rst b/docs/api/receivers/index.rst new file mode 100644 index 00000000..29360852 --- /dev/null +++ b/docs/api/receivers/index.rst @@ -0,0 +1,15 @@ + +Receiver API +================= + +The ``receiver`` class provides methods to read, store and process seismogram station data. + +.. doxygenclass:: specfem::receivers::receiver + :members: + :undoc-members: + :private-members: + +Auxiliary functions +------------------- + +.. doxygenfunction:: specfem::receivers::read_receivers diff --git a/docs/api/setup_parameters/database_configuration.rst b/docs/api/setup_parameters/database_configuration.rst new file mode 100644 index 00000000..eeaeed91 --- /dev/null +++ b/docs/api/setup_parameters/database_configuration.rst @@ -0,0 +1,10 @@ + +Database information +===================== + +Methods to parse database information from configuration file. + +.. doxygenclass:: specfem::runtime_configuration::database_configuration + :members: + :undoc-members: + :private-members: diff --git a/docs/api/setup_parameters/header.rst b/docs/api/setup_parameters/header.rst new file mode 100644 index 00000000..7d9e5ce3 --- /dev/null +++ b/docs/api/setup_parameters/header.rst @@ -0,0 +1,10 @@ + +Header +======= + +Methods to read header information from configuration file. + +.. doxygenclass:: specfem::runtime_configuration::header + :members: + :undoc-members: + :private-members: diff --git a/docs/api/setup_parameters/index.rst b/docs/api/setup_parameters/index.rst new file mode 100644 index 00000000..73e6ae70 --- /dev/null +++ b/docs/api/setup_parameters/index.rst @@ -0,0 +1,17 @@ + +Setup Parameters +================= + +Methods used to read the runtime configuration file and set up the simulation. Each class in this module implement methods required to parse a single node in the ``specfem_config.yaml`` YAML file. + +.. toctree:: + :maxdepth: 1 + + header + quadrature + solver/index + receivers + run_setup + database_configuration + seismogram + setup diff --git a/docs/api/setup_parameters/quadrature.rst b/docs/api/setup_parameters/quadrature.rst new file mode 100644 index 00000000..4d10c4f0 --- /dev/null +++ b/docs/api/setup_parameters/quadrature.rst @@ -0,0 +1,10 @@ + +Quadrature +================== + +Methods to read quadrature information from configuration file and instantiate quadrature objects. + +.. doxygenclass:: specfem::runtime_configuration::quadrature + :members: + :undoc-members: + :private-members: diff --git a/docs/api/setup_parameters/receivers.rst b/docs/api/setup_parameters/receivers.rst new file mode 100644 index 00000000..f35cecd0 --- /dev/null +++ b/docs/api/setup_parameters/receivers.rst @@ -0,0 +1,10 @@ + +Receiver information +===================== + +Methods to parse receiver information from the configuration file. + +.. doxygenclass:: specfem::runtime_configuration::receivers + :members: + :undoc-members: + :private-members: diff --git a/docs/api/setup_parameters/run_setup.rst b/docs/api/setup_parameters/run_setup.rst new file mode 100644 index 00000000..491d30a9 --- /dev/null +++ b/docs/api/setup_parameters/run_setup.rst @@ -0,0 +1,10 @@ + +Runtime Setup +================= + +Methods to parse runtime setup node from configuration file. + +.. doxygenclass:: specfem::runtime_configuration::run_setup + :members: + :undoc-members: + :private-members: diff --git a/docs/api/setup_parameters/seismogram.rst b/docs/api/setup_parameters/seismogram.rst new file mode 100644 index 00000000..c19524a4 --- /dev/null +++ b/docs/api/setup_parameters/seismogram.rst @@ -0,0 +1,10 @@ + +Seismogram information +======================= + +Methods to parse seismogram information from runtime configuration. + +.. doxygenclass:: specfem::runtime_configuration::seismogram + :members: + :undoc-members: + :private-members: diff --git a/docs/api/setup_parameters/setup.rst b/docs/api/setup_parameters/setup.rst new file mode 100644 index 00000000..317f4272 --- /dev/null +++ b/docs/api/setup_parameters/setup.rst @@ -0,0 +1,10 @@ + +Setup class +================= + +The ``setup`` class serves as the primary driver to parse the configuration file and instantiate the simulation. + +.. doxygenclass:: specfem::runtime_configuration::setup + :members: + :undoc-members: + :private-members: diff --git a/docs/api/setup_parameters/solver/index.rst b/docs/api/setup_parameters/solver/index.rst new file mode 100644 index 00000000..3a6ae1e1 --- /dev/null +++ b/docs/api/setup_parameters/solver/index.rst @@ -0,0 +1,18 @@ + +Solver API +=========== + +Methods to read solver information from the configuration file and instantiate a solver. + +.. doxygenclass:: specfem::runtime_configuration::solver:solver + :members: + :undoc-members: + :private-members: + +Types of solvers +---------------- + +.. toctree:: + :maxdepth: 1 + + time_marching diff --git a/docs/api/setup_parameters/solver/time_marching.rst b/docs/api/setup_parameters/solver/time_marching.rst new file mode 100644 index 00000000..dcb0a7e2 --- /dev/null +++ b/docs/api/setup_parameters/solver/time_marching.rst @@ -0,0 +1,8 @@ + +Time Marching Solver +===================== + +.. doxygenclass:: specfem::runtime_configuration::solver::time_marching + :members: + :undoc-members: + :private-members: diff --git a/docs/api/solver.rst b/docs/api/solver.rst deleted file mode 100644 index c4511c17..00000000 --- a/docs/api/solver.rst +++ /dev/null @@ -1,10 +0,0 @@ -.. _solver: - -Solver interface -================ - -.. doxygenfile:: include/solver/solver.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -.. doxygenfile:: include/solver/time_marching.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION diff --git a/docs/api/solver/index.rst b/docs/api/solver/index.rst new file mode 100644 index 00000000..915e1183 --- /dev/null +++ b/docs/api/solver/index.rst @@ -0,0 +1,18 @@ + +Solver API +================= + +The ``solver`` class provides interfaces to describe the solver algorithm. + +.. doxygenclass:: specfem::solver::solver + :members: + :undoc-members: + :private-members: + +Types of solvers +---------------- + +.. toctree:: + :maxdepth: 1 + + time_marching diff --git a/docs/api/solver/time_marching.rst b/docs/api/solver/time_marching.rst new file mode 100644 index 00000000..eba6f55b --- /dev/null +++ b/docs/api/solver/time_marching.rst @@ -0,0 +1,10 @@ + +Time Marching Solver +==================== + +Time marching explicit solver + +.. doxygenclass:: specfem::solver::time_marching + :members: + :undoc-members: + :private-members: diff --git a/docs/api/sources/force_source.rst b/docs/api/sources/force_source.rst new file mode 100644 index 00000000..04faae28 --- /dev/null +++ b/docs/api/sources/force_source.rst @@ -0,0 +1,10 @@ + +Force Source +================= + +Force source implementation + +.. doxygenclass:: specfem::sources::force + :members: + :undoc-members: + :private-members: diff --git a/docs/api/sources/index.rst b/docs/api/sources/index.rst new file mode 100644 index 00000000..afbcdf9d --- /dev/null +++ b/docs/api/sources/index.rst @@ -0,0 +1,24 @@ + +Sources API +================= + +Sources module provides methods and classes used to read, store and process data for various sources. + +.. doxygenclass:: specfem::sources::source + :members: + :undoc-members: + :private-members: + +Types of sources +---------------- + +.. toctree:: + :maxdepth: 1 + + force_source + moment_tensor_source + +Auxiliary functions +------------------- + +.. doxygenfunction:: specfem::sources::read_sources diff --git a/docs/api/sources/moment_tensor_source.rst b/docs/api/sources/moment_tensor_source.rst new file mode 100644 index 00000000..305de20f --- /dev/null +++ b/docs/api/sources/moment_tensor_source.rst @@ -0,0 +1,10 @@ + +Moment-Tensor Source +==================== + +Moment-Tensor implementation + +.. doxygenclass:: specfem::sources::moment_tensor + :members: + :undoc-members: + :private-members: diff --git a/docs/api/sources_recievers.rst b/docs/api/sources_recievers.rst deleted file mode 100644 index e18d428c..00000000 --- a/docs/api/sources_recievers.rst +++ /dev/null @@ -1,39 +0,0 @@ -.. _sources_and_recievers: - -Sources and Recievers Interface -================================ - -This section contains the implementation details of source and reciever classes. - -Source Interface ------------------ - -.. doxygenfile:: source.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -.. doxygenfile:: force_source.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -.. doxygenfile:: moment_tensor_source.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -Reciever Interface -------------------- - -.. doxygenfile:: receiver.hpp - :projet: SPECFEM KOKKOS IMPLEMENTATION - -Helper Routines ----------------- - -.. doxygenfile:: read_sources.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -.. doxygenfile:: read_receiver.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -Source Time Function ---------------------- - -.. doxygenfile:: source_time_function.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION diff --git a/docs/api/specfem_mpi.rst b/docs/api/specfem_mpi.rst deleted file mode 100644 index 1484708e..00000000 --- a/docs/api/specfem_mpi.rst +++ /dev/null @@ -1,9 +0,0 @@ -.. _specfem_mpi:: - -SPECFEM abstractions for MPI interface -======================================= - -Always manage MPI communication using a global instantiation of MPI class. Never call MPI routines directly. - -.. doxygenfile:: specfem_mpi.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION diff --git a/docs/api/timescheme.rst b/docs/api/timescheme.rst deleted file mode 100644 index aa336bcf..00000000 --- a/docs/api/timescheme.rst +++ /dev/null @@ -1,12 +0,0 @@ -.. _timescheme: - -Time marching schemes -===================== - -Time scheme class defines routines used to manage time evolution of the spectral element method. - -.. doxygenfile:: timescheme/timescheme.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -.. doxygenfile:: timescheme/newmark.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION diff --git a/docs/api/timescheme/index.rst b/docs/api/timescheme/index.rst new file mode 100644 index 00000000..8b8a2138 --- /dev/null +++ b/docs/api/timescheme/index.rst @@ -0,0 +1,18 @@ + +Time Scheme API +================ + +The ``TimeScheme`` class provides methods to compute the time evolution of a wavefield. + +.. doxygenclass:: specfem::TimeScheme::TimeScheme + :members: + :undoc-members: + :private-members: + +Types of Time Schemes +--------------------- + +.. toctree:: + :maxdepth: 1 + + newmark diff --git a/docs/api/timescheme/newmark.rst b/docs/api/timescheme/newmark.rst new file mode 100644 index 00000000..2d6e4e26 --- /dev/null +++ b/docs/api/timescheme/newmark.rst @@ -0,0 +1,8 @@ + +Newmark Time Scheme +==================== + +.. doxygenclass:: specfem::TimeScheme::Newmark + :members: + :undoc-members: + :private-members: diff --git a/docs/api/writer.rst b/docs/api/writer.rst deleted file mode 100644 index 69cf8b65..00000000 --- a/docs/api/writer.rst +++ /dev/null @@ -1,12 +0,0 @@ -.. writer:: - -Writer interface -================= - -Writer class to store required outputs (seismograms, wavefields, etc.) to disk. - -.. doxygenfile:: writer/writer.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION - -.. doxygenfile:: writer/seismogram.hpp - :project: SPECFEM KOKKOS IMPLEMENTATION diff --git a/docs/benchmarks/benchmarks.rst b/docs/benchmarks/benchmarks.rst new file mode 100644 index 00000000..5de66e3a --- /dev/null +++ b/docs/benchmarks/benchmarks.rst @@ -0,0 +1,12 @@ +.. benchmarks:: + +Performance Benchmarks +---------------------- + +.. note:: + + We are working towards providing set of scripts for generating reproducible benchmarks. + +1. Coupled elastic-acoustic domain + +.. figure:: elastic_acoustic.svg diff --git a/docs/benchmarks/elastic_acoustic.svg b/docs/benchmarks/elastic_acoustic.svg new file mode 100644 index 00000000..6bb6766f --- /dev/null +++ b/docs/benchmarks/elastic_acoustic.svg @@ -0,0 +1,2546 @@ + + + + + + + + 2023-12-18T15:32:27.037627 + image/svg+xml + + + Matplotlib v3.6.2, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/conf.py b/docs/conf.py index eb7ea22c..ca6e63ce 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -21,8 +21,8 @@ # -- Project information ----------------------------------------------------- -project = 'SPECFEM KOKKOS IMPLEMENTATION' -copyright = '2020, Rohit Kakodkar' +project = 'SPECFEM++' +copyright = '2023, Rohit Kakodkar' author = 'Rohit Kakodkar' @@ -33,6 +33,7 @@ # ones. extensions = [ 'sphinx.ext.autodoc', + 'sphinx.ext.doctest', 'sphinx.ext.intersphinx', 'sphinx.ext.autosectionlabel', 'sphinx.ext.todo', @@ -91,6 +92,7 @@ # or fully qualified paths (eg. https://...) html_css_files = [ 'css/scrollable_code_blocks.css', + 'css/center_align_table.css', ] @@ -100,4 +102,4 @@ "SPECFEM KOKKOS IMPLEMENTATION": "_build/xml" } breathe_default_project = "SPECFEM KOKKOS IMPLEMENTATION" -breathe_default_members = ('members', 'undoc-members') +breathe_default_members = () diff --git a/docs/cookbooks/example_01.rst b/docs/cookbooks/example_01.rst index 931ecb00..6dadcfd7 100644 --- a/docs/cookbooks/example_01.rst +++ b/docs/cookbooks/example_01.rst @@ -1,3 +1,5 @@ +.. homogeneous_example:: + Wave propagration through homogeneous media =========================================== @@ -6,11 +8,12 @@ In this example we simulate wave propagation through a 2-dimensional homogeneous Generating a mesh ----------------- -To generate a mesh for homogeneous media we utilize `SPECFEM2D mesh generator -`_ (xmeshfem2d). To run xmeshfem2d we need to define 2 -files: The ``Par_file``, which defines the parameters used by ``xmeshfem2D``, and ``topography_file.dat``, which defines -the topography of the domain. More information on generating the mesh can be found `here -`_. +To generate the mesh for the homogeneous media we need a parameter file, ``Par_File``, a topography file, `topography_file.dat`, and the mesher executible, ``xmeshfem2D``, which should have been compiled during the installation process. + +.. note:: + Currently, we still use a mesher that was developed for the original `SPECFEM2D `_ code. More details on the meshing process can be found `here `_. + +We first define the meshing parameters in a Parameter file. Parameter File ~~~~~~~~~~~~~~~~ @@ -27,34 +30,12 @@ Parameter File # title of job title = Elastic Simulation with point source - # forward or adjoint simulation - # 1 = forward, 2 = adjoint, 3 = both simultaneously - # note: 2 is purposely UNUSED (for compatibility with the numbering of our 3D codes) - SIMULATION_TYPE = 1 - # 0 = regular wave propagation simulation, 1/2/3 = noise simulation - NOISE_TOMOGRAPHY = 0 - # save the last frame, needed for adjoint simulation - SAVE_FORWARD = .false. - # parameters concerning partitioning NPROC = 1 # number of processes - # time step parameters - # total number of time steps - NSTEP = 100 - - # duration of a time step (see section "How to choose the time step" of the manual for how to do this) - DT = 1.1d-5 - - # time stepping - # 1 = Newmark (2nd order), 2 = LDDRK4-6 (4th-order 6-stage low storage Runge-Kutta), 3 = classical RK4 4th-order 4-stage Runge-Kutta - time_stepping_scheme = 1 + # Output folder to store mesh related files + OUTPUT_FILES = - # set the type of calculation (P-SV or SH/membrane waves) - P_SV = .true. - - # axisymmetric (2.5D) or Cartesian planar (2D) simulation - AXISYM = .false. #----------------------------------------------------------- # @@ -68,91 +49,8 @@ Parameter File # number of control nodes per element (4 or 9) NGNOD = 9 - # creates/reads a binary database that allows to skip all time consuming setup steps in initialization - # 0 = does not read/create database - # 1 = creates database - # 2 = reads database - setup_with_binary_database = 0 - - # available models - # default - define model using nbmodels below - # ascii - read model from ascii database file - # binary - read model from binary databse file - # binary_voigt - read Voigt model from binary database file - # external - define model using define_external_model subroutine - # gll - read GLL model from binary database file - # legacy - read model from model_velocity.dat_input - MODEL = default - - # Output the model with the requested type, does not save if turn to default or .false. - # (available output formats: ascii,binary,gll,legacy) - SAVE_MODEL = default - - - #----------------------------------------------------------- - # - # Attenuation - # - #----------------------------------------------------------- - - # attenuation parameters - ATTENUATION_VISCOELASTIC = .false. # turn attenuation (viscoelasticity) on or off for non-poroelastic solid parts of the model - ATTENUATION_VISCOACOUSTIC = .false. # turn attenuation (viscoacousticity) on or off for non-poroelastic fluid parts of the model - - # for viscoelastic or viscoacoustic attenuation - N_SLS = 3 # number of standard linear solids for attenuation (3 is usually the minimum) - ATTENUATION_f0_REFERENCE = 5.196 # in case of attenuation, reference frequency in Hz at which the velocity values in the velocity model are given (unused otherwise); relevant only if source is a Dirac or a Heaviside, otherwise it is automatically set to f0 the dominant frequency of the source in the DATA/SOURCE file - READ_VELOCITIES_AT_f0 = .false. # read seismic velocities at ATTENUATION_f0_REFERENCE instead of at infinite frequency (see user manual for more information) - USE_SOLVOPT = .false. # use more precise but much more expensive way of determining the Q factor relaxation times, as in https://doi.org/10.1093/gji/ggw024 - - # for poroelastic attenuation - ATTENUATION_PORO_FLUID_PART = .false. # turn viscous attenuation on or off for the fluid part of poroelastic parts of the model - Q0_poroelastic = 1 # quality factor for viscous attenuation (ignore it if you are not using a poroelastic material) - freq0_poroelastic = 10 # frequency for viscous attenuation (ignore it if you are not using a poroelastic material) - - # to undo attenuation and/or PMLs for sensitivity kernel calculations or forward runs with SAVE_FORWARD - # use the flag below. It performs undoing of attenuation and/or of PMLs in an exact way for sensitivity kernel calculations - # but requires disk space for temporary storage, and uses a significant amount of memory used as buffers for temporary storage. - # When that option is on the second parameter indicates how often the code dumps restart files to disk (if in doubt, use something between 100 and 1000). - UNDO_ATTENUATION_AND_OR_PML = .false. - NT_DUMP_ATTENUATION = 500 - - # Instead of reconstructing the forward wavefield, this option reads it from the disk using asynchronous I/O. - # Outperforms conventional mode using a value of NTSTEP_BETWEEN_COMPUTE_KERNELS high enough. - NO_BACKWARD_RECONSTRUCTION = .false. - - #----------------------------------------------------------- - # - # Sources - # - #----------------------------------------------------------- - - # source parameters - NSOURCES = 1 # number of sources (source information is then read from the DATA/SOURCE file) - force_normal_to_surface = .false. # angleforce normal to surface (external mesh and curve file needed) - - # use an existing initial wave field as source or start from zero (medium initially at rest) - initialfield = .false. - add_Bielak_conditions_bottom = .false. # add Bielak conditions or not if initial plane wave - add_Bielak_conditions_right = .false. - add_Bielak_conditions_top = .false. - add_Bielak_conditions_left = .false. - - # acoustic forcing - ACOUSTIC_FORCING = .false. # acoustic forcing of an acoustic medium with a rigid interface - - # noise simulations - type of noise source time function: - # 0=external (S_squared), 1=Ricker(second derivative), 2=Ricker(first derivative), 3=Gaussian, 4=Figure 2a of Tromp et al. 2010 - # (default value 4 is chosen to reproduce the time function from Fig 2a of "Tromp et al., 2010, Noise Cross-Correlation Sensitivity Kernels") - noise_source_time_function_type = 4 - - # moving sources - # Set write_moving_sources_database to .true. if the generation of moving source databases takes - # a long time. Then the simulation is done in two steps: first you run the code and it writes the databases to file - # (in DATA folder by default). Then you rerun the code and it will read the databases in there directly possibly - # saving a lot of time. - # This is only useful for GPU version (for now) - write_moving_sources_database = .false. + # location to store the mesh + database_filename = #----------------------------------------------------------- # @@ -160,32 +58,6 @@ Parameter File # #----------------------------------------------------------- - # receiver set parameters for recording stations (i.e. recording points) - # seismotype : record 1=displ 2=veloc 3=accel 4=pressure 5=curl of displ 6=the fluid potential - seismotype = 1 # several values can be chosen. For example : 1,2,4 - - # interval in time steps for writing of seismograms - # every how many time steps we save the seismograms - # (costly, do not use a very small value; if you use a very large value that is larger than the total number - # of time steps of the run, the seismograms will automatically be saved once at the end of the run anyway) - NTSTEP_BETWEEN_OUTPUT_SEISMOS = 10000 - - # set to n to reduce the sampling rate of output seismograms by a factor of n - # defaults to 1, which means no down-sampling - NTSTEP_BETWEEN_OUTPUT_SAMPLE = 1 - - # so far, this option can only be used if all the receivers are in acoustic elements - USE_TRICK_FOR_BETTER_PRESSURE = .false. - - # use this t0 as earliest starting time rather than the automatically calculated one - USER_T0 = 0.0d0 - - # seismogram formats - save_ASCII_seismograms = .true. # save seismograms in ASCII format or not - save_binary_seismograms_single = .true. # save seismograms in single precision binary format or not (can be used jointly with ASCII above to save both) - save_binary_seismograms_double = .false. # save seismograms in double precision binary format or not (can be used jointly with both flags above to save all) - SU_FORMAT = .false. # output single precision binary seismograms in Seismic Unix format (adjoint traces will be read in the same format) - # use an existing STATION file found in ./DATA or create a new one from the receiver positions below in this Par_file use_existing_STATIONS = .false. @@ -197,65 +69,24 @@ Parameter File rec_normal_to_surface = .false. # base anglerec normal to surface (external mesh and curve file needed) # first receiver set (repeat these 6 lines and adjust nreceiversets accordingly) - nrec = 11 # number of receivers - xdeb = 300. # first receiver x in meters + nrec = 3 # number of receivers + xdeb = 2200. # first receiver x in meters zdeb = 2200. # first receiver z in meters - xfin = 3700. # last receiver x in meters (ignored if only one receiver) + xfin = 2800. # last receiver x in meters (ignored if only one receiver) zfin = 2200. # last receiver z in meters (ignored if only one receiver) record_at_surface_same_vertical = .true. # receivers inside the medium or at the surface (z values are ignored if this is set to true, they are replaced with the topography height) # second receiver set - nrec = 11 # number of receivers + nrec = 3 # number of receivers xdeb = 2500. # first receiver x in meters zdeb = 2500. # first receiver z in meters xfin = 2500. # last receiver x in meters (ignored if only one receiver) - zfin = 0. # last receiver z in meters (ignored if only one receiver) + zfin = 1900. # last receiver z in meters (ignored if only one receiver) record_at_surface_same_vertical = .false. # receivers inside the medium or at the surface (z values are ignored if this is set to true, they are replaced with the topography height) - #----------------------------------------------------------- - # - # adjoint kernel outputs - # - #----------------------------------------------------------- - - # save sensitivity kernels in ASCII format (much bigger files, but compatible with current GMT scripts) or in binary format - save_ASCII_kernels = .true. - - # since the accuracy of kernel integration may not need to respect the CFL, this option permits to save computing time, and memory with UNDO_ATTENUATION_AND_OR_PML mode - NTSTEP_BETWEEN_COMPUTE_KERNELS = 1 - - # outputs approximate Hessian for preconditioning - APPROXIMATE_HESS_KL = .false. - - #----------------------------------------------------------- - # - # Boundary conditions - # - #----------------------------------------------------------- - - # Perfectly Matched Layer (PML) boundaries - # absorbing boundary active or not - PML_BOUNDARY_CONDITIONS = .false. - NELEM_PML_THICKNESS = 3 - ROTATE_PML_ACTIVATE = .false. - ROTATE_PML_ANGLE = 30. - # change the four parameters below only if you know what you are doing; they change the damping profiles inside the PMLs - K_MIN_PML = 1.0d0 # from Gedney page 8.11 - K_MAX_PML = 1.0d0 - damping_change_factor_acoustic = 0.5d0 - damping_change_factor_elastic = 1.0d0 - # set the parameter below to .false. unless you know what you are doing; this implements automatic adjustment of the PML parameters for elongated models. - # The goal is to improve the absorbing efficiency of PML for waves with large incidence angles, but this can lead to artefacts. - # In particular, this option is efficient only when the number of sources NSOURCES is equal to one. - PML_PARAMETER_ADJUSTMENT = .false. - - # Stacey ABC - STACEY_ABSORBING_CONDITIONS = .false. - - # periodic boundaries - ADD_PERIODIC_CONDITIONS = .false. - PERIODIC_HORIZ_DIST = 4000.d0 + # filename to store stations file + stations_filename = #----------------------------------------------------------- # @@ -281,9 +112,6 @@ Parameter File # To convert one to the other see doc/Qkappa_Qmu_versus_Qp_Qs_relationship_in_2D_plane_strain.pdf and # utils/attenuation/conversion_from_Qkappa_Qmu_to_Qp_Qs_from_Dahlen_Tromp_959_960.f90. 1 1 2700.d0 3000.d0 1732.051d0 0 0 9999 9999 0 0 0 0 0 0 - # 2 1 2500.d0 2700.d0 1443.375d0 0 0 9999 9999 0 0 0 0 0 0 - # 3 1 2200.d0 2500.d0 1443.375d0 0 0 9999 9999 0 0 0 0 0 0 - # 4 1 2200.d0 2200.d0 1343.375d0 0 0 9999 9999 0 0 0 0 0 0 # external tomography file TOMOGRAPHY_FILE = ./DATA/tomo_file.xyz @@ -316,7 +144,7 @@ Parameter File #----------------------------------------------------------- # file containing interfaces for internal mesh - interfacesfile = ../EXAMPLES/simple_topography_and_also_a_simple_fluid_layer/DATA/interfaces_simple_topo_flat.dat + interfacesfile = # geometry of the model (origin lower-left corner = 0,0) and mesh description xmin = 0.d0 # abscissa of left side of the model @@ -333,158 +161,26 @@ Parameter File nbregions = 1 # then set below the different regions and model number for each region # format of each line: nxmin nxmax nzmin nzmax material_number 1 80 1 60 1 - # 1 59 21 40 2 - # 71 80 21 40 2 - # 1 80 41 60 3 - # 60 70 21 40 4 #----------------------------------------------------------- # - # Display parameters + # DISPLAY PARAMETERS # #----------------------------------------------------------- - # interval at which we output time step info and max of norm of displacement - # (every how many time steps we display information about the simulation. costly, do not use a very small value) - NTSTEP_BETWEEN_OUTPUT_INFO = 100 - # meshing output output_grid_Gnuplot = .false. # generate a GNUPLOT file containing the grid, and a script to plot it output_grid_ASCII = .false. # dump the grid in an ASCII text file consisting of a set of X,Y,Z points or not - # to plot total energy curves, for instance to monitor how CPML absorbing layers behave; - # should be turned OFF in most cases because a bit expensive - OUTPUT_ENERGY = .false. - - # every how many time steps we compute energy (which is a bit expensive to compute) - NTSTEP_BETWEEN_OUTPUT_ENERGY = 10 - - # Compute the field int_0^t v^2 dt for a set of GLL points and write it to file. Use - # the script utils/visualisation/plotIntegratedEnergyFile.py to watch. It is refreshed at the same time than the seismograms - COMPUTE_INTEGRATED_ENERGY_FIELD = .false. - - #----------------------------------------------------------- - # - # Movies/images/snaphots visualizations - # - #----------------------------------------------------------- - - # every how many time steps we draw JPEG or PostScript pictures of the simulation - # and/or we dump results of the simulation as ASCII or binary files (costly, do not use a very small value) - NTSTEP_BETWEEN_OUTPUT_IMAGES = 100 - - # minimum amplitude kept in % for the JPEG and PostScript snapshots; amplitudes below that are muted - cutsnaps = 1. - - #### for JPEG color images #### - output_color_image = .false. # output JPEG color image of the results every NTSTEP_BETWEEN_OUTPUT_IMAGES time steps or not - imagetype_JPEG = 3 # display 1=displ_Ux 2=displ_Uz 3=displ_norm 4=veloc_Vx 5=veloc_Vz 6=veloc_norm 7=accel_Ax 8=accel_Az 9=accel_norm 10=pressure - factor_subsample_image = 1.0d0 # (double precision) factor to subsample or oversample (if set to e.g. 0.5) color images output by the code (useful for very large models, or to get nicer looking denser pictures) - USE_CONSTANT_MAX_AMPLITUDE = .true. # by default the code normalizes each image independently to its maximum; use this option to use the global maximum below instead - CONSTANT_MAX_AMPLITUDE_TO_USE = 1.17d-7 # constant maximum amplitude to use for all color images if the above USE_CONSTANT_MAX_AMPLITUDE option is true - POWER_DISPLAY_COLOR = 0.30d0 # non linear display to enhance small amplitudes in JPEG color images - DRAW_SOURCES_AND_RECEIVERS = .true. # display sources as orange crosses and receivers as green squares in JPEG images or not - DRAW_WATER_IN_BLUE = .true. # display acoustic layers as constant blue in JPEG images, because they likely correspond to water in the case of ocean acoustics or in the case of offshore oil industry experiments (if off, display them as greyscale, as for elastic or poroelastic elements, for instance for acoustic-only oil industry models of solid media) - USE_SNAPSHOT_NUMBER_IN_FILENAME = .false. # use snapshot number in the file name of JPEG color snapshots instead of the time step (for instance to create movies in an easier way later) - - #### for PostScript snapshots #### - output_postscript_snapshot = .false. # output Postscript snapshot of the results every NTSTEP_BETWEEN_OUTPUT_IMAGES time steps or not - imagetype_postscript = 1 # display 1=displ vector 2=veloc vector 3=accel vector; small arrows are displayed for the vectors - meshvect = .true. # display mesh on PostScript plots or not - modelvect = .false. # display velocity model on PostScript plots or not - boundvect = .true. # display boundary conditions on PostScript plots or not - interpol = .true. # interpolation of the PostScript display on a regular grid inside each spectral element, or use the non-evenly spaced GLL points - pointsdisp = 6 # number of points in each direction for interpolation of PostScript snapshots (set to 1 for lower-left corner only) - subsamp_postscript = 1 # subsampling of background velocity model in PostScript snapshots - sizemax_arrows = 1.d0 # maximum size of arrows on PostScript plots in centimeters - US_LETTER = .false. # use US letter or European A4 paper for PostScript plots - - #### for wavefield dumps #### - output_wavefield_dumps = .false. # output wave field to a text file (creates very big files) - imagetype_wavefield_dumps = 1 # display 1=displ vector 2=veloc vector 3=accel vector 4=pressure - use_binary_for_wavefield_dumps = .false. # use ASCII or single-precision binary format for the wave field dumps - - #----------------------------------------------------------- - - # Ability to run several calculations (several earthquakes) - # in an embarrassingly-parallel fashion from within the same run; - # this can be useful when using a very large supercomputer to compute - # many earthquakes in a catalog, in which case it can be better from - # a batch job submission point of view to start fewer and much larger jobs, - # each of them computing several earthquakes in parallel. - # To turn that option on, set parameter NUMBER_OF_SIMULTANEOUS_RUNS to a value greater than 1. - # To implement that, we create NUMBER_OF_SIMULTANEOUS_RUNS MPI sub-communicators, - # each of them being labeled "my_local_mpi_comm_world", and we use them - # in all the routines in "src/shared/parallel.f90", except in MPI_ABORT() because in that case - # we need to kill the entire run. - # When that option is on, of course the number of processor cores used to start - # the code in the batch system must be a multiple of NUMBER_OF_SIMULTANEOUS_RUNS, - # all the individual runs must use the same number of processor cores, - # which as usual is NPROC in the Par_file, - # and thus the total number of processor cores to request from the batch system - # should be NUMBER_OF_SIMULTANEOUS_RUNS * NPROC. - # All the runs to perform must be placed in directories called run0001, run0002, run0003 and so on - # (with exactly four digits). - # - # Imagine you have 10 independent calculations to do, each of them on 100 cores; you have three options: - # - # 1/ submit 10 jobs to the batch system - # - # 2/ submit a single job on 1000 cores to the batch, and in that script create a sub-array of jobs to start 10 jobs, - # each running on 100 cores (see e.g. http://www.schedmd.com/slurmdocs/job_array.html ) - # - # 3/ submit a single job on 1000 cores to the batch, start SPECFEM2D on 1000 cores, create 10 sub-communicators, - # cd into one of 10 subdirectories (called e.g. run0001, run0002,... run0010) depending on the sub-communicator - # your MPI rank belongs to, and run normally on 100 cores using that sub-communicator. - # - # The option below implements 3/. - # - NUMBER_OF_SIMULTANEOUS_RUNS = 1 - - # if we perform simultaneous runs in parallel, if only the source and receivers vary between these runs - # but not the mesh nor the model (velocity and density) then we can also read the mesh and model files - # from a single run in the beginning and broadcast them to all the others; for a large number of simultaneous - # runs for instance when solving inverse problems iteratively this can DRASTICALLY reduce I/Os to disk in the solver - # (by a factor equal to NUMBER_OF_SIMULTANEOUS_RUNS), and reducing I/Os is crucial in the case of huge runs. - # Thus, always set this option to .true. if the mesh and the model are the same for all simultaneous runs. - # In that case there is no need to duplicate the mesh and model file database (the content of the DATABASES_MPI - # directories) in each of the run0001, run0002,... directories, it is sufficient to have one in run0001 - # and the code will broadcast it to the others) - BROADCAST_SAME_MESH_AND_MODEL = .true. - - #----------------------------------------------------------- - - # set to true to use GPUs - GPU_MODE = .true. -At this point, it is worthwhile to note few key parameters within the ``PAR_FILE`` as it pertains to the ``Kokkos`` -version of the solver. +At this point, it is worthwhile to note few key parameters within the ``PAR_FILE`` as it pertains to SPECFEM++. -- This version of SPECFEM2D Kokkos does not support simulations running across multiple nodes, i.e., we have not enabled - MPI. Relevant parameter value: +- This version of SPECFEM++ does not support simulations running across multiple nodes, i.e., we have not enabled MPI. Relevant parameter value: .. code:: bash NPROC = 1 -- This version of the software can only simulate meshes generated by the internal mesher included in meshfem2d. Relevant - parameter values: - -.. code:: bash - - MODEL = default - - SAVE_MODEL = default - -- While defining the velocity models for different materials we need to make sure that all materials describe elastic - materials. Other material systems are not implemented in this version of the package. - -.. note:: - - The ``PAR_FILE`` shown above contains many values which define the runtime behaviour of `xmeshfem2D - `_ . These values will be omitted by the - ``Kokkos`` solver. We define some of these values below in ``specfem_config.yaml`` - - The path to the topography file is provided using the ``interfacesfile`` parameter. Relevant values: .. code:: bash @@ -528,19 +224,22 @@ Topography file Running ``xmeshfem2D`` ~~~~~~~~~~~~~~~~~~~~~~ -Copy the parameters file and topography file to the ``DATA`` folder within ``SPECFEM2D`` root directory. To execute the -mesher from the root of ``specfem2d`` run +To execute the mesher run .. code:: bash - ./bin/xmeshfem2D + ./xmeshfem2D -p + +.. note:: + + Make sure either your are in the build directory of SPECFEM++ or the build directory is added to your ``PATH``. -Note the path of the database file and :ref:`stations_file` generated after successfully running the mesher. Generally, the database will be located within ``OUTPUT_FILES`` directory within root of SPECFEM2D and the :ref:`stations_file` should be located in ``DATA`` folder of SPECFEM2D root. +Note the path of the database file and :ref:`stations_file` generated after successfully running the mesher. Defining sources ---------------- -Next we define the sources using a YAML file. For full description on parameters used to define sources refer :ref:`source_description`. Here we define 2 sources file pertaining to a single single source and 2 sources inside the simulation box. +Next we define the sources using a YAML file. For full description on parameters used to define sources refer :ref:`source_description`. .. code:: yaml :linenos: @@ -555,36 +254,10 @@ Next we define the sources using a YAML file. For full description on parameters angle : 0.0 vx : 0.0 vz : 0.0 - Dirac: - factor: 1.0 - tshift: 0.0 - -.. code:: yaml - :linenos: - :caption: two_sources.yaml - - number-of-sources: 2 - sources: - - force: - x : 2500.0 - z : 2500.0 - source_surf: false - angle : 0.0 - vx : 0.0 - vz : 0.0 - Dirac: - factor: 1.0 - tshift: 0.0 - - force: - x : 2500.0 - z : 500.0 - source_surf: false - angle : 0.0 - vx : 0.0 - vz : 0.0 - Dirac: - factor: 1.0 + Ricker: + factor: 1e10 tshift: 0.0 + f0: 10.0 Configuring the solver ----------------------- @@ -618,8 +291,8 @@ Now that we have generated a mesh and defined the sources, we need to set up the type-of-simulation: forward time-scheme: type: Newmark - dt: 1.1e-5 - nstep: 100 + dt: 1.1e-3 + nstep: 1600 receivers: stations-file: @@ -678,7 +351,7 @@ At this point lets focus on a few sections in this file: Running the solver ------------------- -Finally, to run the SPECFEM2D kokkos solver +Finally, to run the SPECFEM++ solver .. code:: bash @@ -686,13 +359,41 @@ Finally, to run the SPECFEM2D kokkos solver .. note:: - Make sure either your are in the build directory of SPECFEM2D kokkos or the build directory is added to your ``PATH``. + Make sure either your are in the build directory of SPECFEM++ or the build directory is added to your ``PATH``. Visualizing seimograms ---------------------- -On successful completion of the simulation the seismograms are stored within the output folder. Which can be visualized using standard plotting tools. +Let us now plot the traces generated by the solver using ``obspy``. This version of the code only supports ASCII output format for seismograms. To plot the seismograms we need to read the ASCII files as ``numpy`` arrays and them convert them to ``obspy`` streams. The following code snippet shows how to do this. -.. note:: +.. code-block:: python + + import os + import numpy as np + import obspy + + def get_traces(directory): + traces = [] + ## iterate over all seismograms + for filename in os.listdir(directory): + f = os.path.join(directory, filename) + station_name = os.path.splitext(filename)[0] + trace = np.loadtxt(f, delimiter=' ') + starttime = trace[0,0] + dt = trace[1,0] - trace[0,0] + traces.append(obspy.Trace(trace[:,1], {'network': station_name, 'starttime': starttime, 'delta': dt})) + + stream = obspy.Stream(traces) + + return stream + + directory = ## PATH TO DIRECTORY WHERE SEISMOGRAMS ARE STORED + stream = get_traces(directory) + stream.plot(size=(800, 1000)) + +.. figure:: ../../examples/homogeneous-medium-flat-topography/traces.svg + :alt: Traces + :width: 800 + :align: center - As we move forward, we plan to add modules for visualizing seismograms and integrating with common siesmic postprocessing tools like obspy. + Traces. diff --git a/docs/cookbooks/example_02.rst b/docs/cookbooks/example_02.rst new file mode 100644 index 00000000..11cfcfec --- /dev/null +++ b/docs/cookbooks/example_02.rst @@ -0,0 +1,296 @@ +Wave propagration through fluid-solid interface +=============================================== + +This example simulates the fluid-solid example with flat ocean bottom from `Komatitsch et. al. `_. This example demonstrates the use of the ``xmeshfem2D`` mesher to generate interface between 2 conforming material systems and the setting up absorbing boundary conditions. + +Meshing the domain +------------------ + +We first start by generating a mesh for our simulation domain using ``xmeshfem2D``. To do this, we first define our simulation domain and the meshing parmeters in a parameter file. + +Parameter file +~~~~~~~~~~~~~ + +.. code-block:: bash + + #----------------------------------------------------------- + # + # Simulation input parameters + # + #----------------------------------------------------------- + + # title of job + title = Flat fluid/solid interface + + # parameters concerning partitioning + NPROC = 1 # number of processes + + # Output folder to store mesh related files + OUTPUT_FILES = + + #----------------------------------------------------------- + # + # Mesh + # + #----------------------------------------------------------- + + # Partitioning algorithm for decompose_mesh + PARTITIONING_TYPE = 3 # SCOTCH = 3, ascending order (very bad idea) = 1 + + # number of control nodes per element (4 or 9) + NGNOD = 4 + + # location to store the mesh + database_filename = + + #----------------------------------------------------------- + # + # Receivers + # + #----------------------------------------------------------- + + # use an existing STATION file found in ./DATA or create a new one from the receiver positions below in this Par_file + use_existing_STATIONS = .false. + + # number of receiver sets (i.e. number of receiver lines to create below) + nreceiversets = 1 + + # orientation + anglerec = 0.d0 # angle to rotate components at receivers + rec_normal_to_surface = .false. # base anglerec normal to surface (external mesh and curve file needed) + + # first receiver set (repeat these 6 lines and adjust nreceiversets accordingly) + nrec = 110 # number of receivers + xdeb = 2500.d0 # first receiver x in meters + zdeb = 2933.33333d0 # first receiver z in meters + xfin = 6000.d0 # last receiver x in meters (ignored if only one receiver) + zfin = 2933.33333d0 # last receiver z in meters (ignored if only one receiver) + record_at_surface_same_vertical = .false. # receivers inside the medium or at the surface + + # filename to store stations file + stations_filename = + + #----------------------------------------------------------- + # + # Velocity and density models + # + #----------------------------------------------------------- + + # number of model materials + nbmodels = 2 + # available material types (see user manual for more information) + # acoustic: model_number 1 rho Vp 0 0 0 QKappa Qmu 0 0 0 0 0 0 + # elastic: model_number 1 rho Vp Vs 0 0 QKappa Qmu 0 0 0 0 0 0 + # anistoropic: model_number 2 rho c11 c13 c15 c33 c35 c55 c12 c23 c25 0 0 0 + # poroelastic: model_number 3 rhos rhof phi c kxx kxz kzz Ks Kf Kfr etaf mufr Qmu + # tomo: model_number -1 0 9999 9999 A 0 0 9999 9999 0 0 0 0 0 + 1 1 2500.d0 3400.d0 1963.d0 0 0 9999 9999 0 0 0 0 0 0 + 2 1 1020.d0 1500.d0 0.d0 0 0 9999 9999 0 0 0 0 0 0 + + # external tomography file + TOMOGRAPHY_FILE = ./DATA/tomo_file.xyz + + # use an external mesh created by an external meshing tool or use the internal mesher + read_external_mesh = .false. + + #----------------------------------------------------------- + # + # PARAMETERS FOR EXTERNAL MESHING + # + #----------------------------------------------------------- + + # data concerning mesh, when generated using third-party app (more info in README) + # (see also absorbing_conditions above) + mesh_file = ./DATA/Mesh_canyon/canyon_mesh_file # file containing the mesh + nodes_coords_file = ./DATA/Mesh_canyon/canyon_nodes_coords_file # file containing the nodes coordinates + materials_file = ./DATA/Mesh_canyon/canyon_materials_file # file containing the material number for each element + free_surface_file = ./DATA/Mesh_canyon/canyon_free_surface_file # file containing the free surface + axial_elements_file = ./DATA/axial_elements_file # file containing the axial elements if AXISYM is true + absorbing_surface_file = ./DATA/Mesh_canyon/canyon_absorbing_surface_file # file containing the absorbing surface + acoustic_forcing_surface_file = ./DATA/MSH/Surf_acforcing_Bottom_enforcing_mesh # file containing the acoustic forcing surface + absorbing_cpml_file = ./DATA/absorbing_cpml_file # file containing the CPML element numbers + tangential_detection_curve_file = ./DATA/courbe_eros_nodes # file containing the curve delimiting the velocity model + + #----------------------------------------------------------- + # + # PARAMETERS FOR INTERNAL MESHING + # + #----------------------------------------------------------- + + # file containing interfaces for internal mesh + interfacesfile = + + # geometry of the model (origin lower-left corner = 0,0) and mesh description + xmin = 0.d0 # abscissa of left side of the model + xmax = 6400.d0 # abscissa of right side of the model + nx = 144 # number of elements along X + + # absorbing boundary parameters (see absorbing_conditions above) + absorbbottom = .true. + absorbright = .true. + absorbtop = .true. + absorbleft = .true. + + # define the different regions of the model in the (nx,nz) spectral-element mesh + nbregions = 2 # then set below the different regions and model number for each region + 1 144 1 54 1 + 1 144 55 108 2 + + #----------------------------------------------------------- + # + # DISPLAY PARAMETERS + # + #----------------------------------------------------------- + + # meshing output + output_grid_Gnuplot = .false. # generate a GNUPLOT file containing the grid, and a script to plot it + output_grid_ASCII = .false. # dump the grid in an ASCII text file consisting of a set of X,Y,Z points or not + +- We define the acoustic and elastic velocity models in the `Velocity and density models` section of the parameter file. + - Firstly, ``nbmodels`` defines the number of material systems in the simulation domain. + - We then define the velocity model for each material system using the following format: ``model_number rho Vp Vs 0 0 QKappa Qmu 0 0 0 0 0 0``. + +- We define stacey absorbing boundary conditions on all the edges of the domain using the ``absorbbottom``, ``absorbright``, ``absorbtop`` and ``absorbleft`` parameters. + +Defining the topography of the domain +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +We define the topography of the domain using the following topography file + +.. code:: bash + + # + # number of interfaces + # + 3 + # + # for each interface below, we give the number of points and then x,z for each point + # + # + # interface number 1 (bottom of the mesh) + # + 2 + 0 0 + 6400 0 + # + # interface number 2 (ocean bottom) + # + 2 + 0 2400 + 6400 2400 + # + # interface number 3 (topography, top of the mesh) + # + 2 + 0 4800 + 6400 4800 + # + # for each layer, we give the number of spectral elements in the vertical direction + # + # + # layer number 1 (bottom layer) + # + ## The original 2000 Geophysics paper used nz = 90 but NGLLZ = 6 + ## here I rescale it to nz = 108 and NGLLZ = 5 because nowadays we almost always use NGLLZ = 5 + 54 + # + # layer number 2 (top layer) + # + 54 + +Running ``xmeshfem2D`` +~~~~~~~~~~~~~~~~~~~~~~ + +To execute the mesher run + +.. code:: bash + + ./xmeshfem2D -p + +.. note:: + + Make sure either your are in the build directory of SPECFEM2D kokkos or the build directory is added to your ``PATH``. + +Note the path of the database file and :ref:`stations_file` generated after successfully running the mesher. + +Defining the source +~~~~~~~~~~~~~~~~~~~ + +We define the source location and the source time function in the source file. + +.. code:: yaml + :linenos: + + number-of-sources: 1 + sources: + - force: + x : 1575.0 + z : 2900.0 + source_surf: false + angle : 0.0 + vx : 0.0 + vz : 0.0 + Ricker: + factor: 1e9 + tshift: 0.0 + f0: 10.0 + +Running the simulation +---------------------- + +To run the solver, we first need to define a configuration file ``specfem_config.yaml``. + +.. code-block:: yaml + :linenos: + :caption: specfem_config.yaml + + parameters: + + header: + ## Header information is used for logging. It is good practice to give your simulations explicit names + title: Heterogeneous acoustic-elastic medium with 1 acoustic-elastic interface # name for your simulation + # A detailed description for your simulation + description: | + Material systems : Elastic domain (1), Acoustic domain (1) + Interfaces : Acoustic-elastic interface (1) + Sources : Force source (1) + Boundary conditions : Neumann BCs on all edges + + simulation-setup: + ## quadrature setup + quadrature: + alpha: 0.0 + beta: 0.0 + ngllx: 5 + ngllz: 5 + + ## Solver setup + solver: + time-marching: + type-of-simulation: forward + time-scheme: + type: Newmark + dt: 0.85e-3 + nstep: 800 + + receivers: + stations-file: + angle: 0.0 + seismogram-type: + - displacement + - velocity + nstep_between_samples: 1 + + ## Runtime setup + run-setup: + number-of-processors: 1 + number-of-runs: 1 + + ## databases + databases: + mesh-database: + source-file: + + seismogram: + seismogram-format: ascii + output-folder: "." diff --git a/docs/cookbooks/index.rst b/docs/cookbooks/index.rst index cdb263e5..1d897415 100644 --- a/docs/cookbooks/index.rst +++ b/docs/cookbooks/index.rst @@ -3,13 +3,10 @@ Cookbooks ######### -In this section, let us define a number "cookbooks" - examples / case studies showing how to use SPECFEM. For this version of the package we assume that you have a compiled version of `SPECFEM2D mesh generator `_. - -.. note:: - - Please note, in this cookbooks we refer to this package as ``SPECFEM2D - Kokkos`` and the `fortran version - `_ as ``SPECFEM2D``. +In this section, let us define a number "cookbooks" - examples / case studies showing how to use SPECFEM++. .. toctree:: + :maxdepth: 1 + example_01 + example_02 diff --git a/docs/developer_documentation/SPECFEM_architecture/SPECFEM_Architecture.svg b/docs/developer_documentation/SPECFEM_architecture/SPECFEM_Architecture.svg new file mode 100644 index 00000000..e53d24cf --- /dev/null +++ b/docs/developer_documentation/SPECFEM_architecture/SPECFEM_Architecture.svg @@ -0,0 +1 @@ + diff --git a/docs/developer_documentation/SPECFEM_architecture/architecture.rst b/docs/developer_documentation/SPECFEM_architecture/architecture.rst new file mode 100644 index 00000000..834d1321 --- /dev/null +++ b/docs/developer_documentation/SPECFEM_architecture/architecture.rst @@ -0,0 +1,31 @@ +.. _architecture: + +SPECFEM++ Architecture +==================== + +SPECFEM++ is designed with portability and modularity as primary goals. The goal is develop a code that is easy to maintain and extend, while maintaining performance characteristics of original `SPECFEM2D solver `_. This is achieved using C++ templatized classes. + +The code is divided into set of modules (classes and structs), the major of which to understand code architecture are: + +1. Quadrature : This module defines the quadrature rules used to compute differentials and integrals. +2. Mesh : Mesh struct defines the IO routines and data structures used to read and store mesh generated by internal meshing tools or external meshing tools such as CUBIT. +3. Compute : Compute struct defines data structures used to compute and store velocity models, spatial derivatives, source and receiver properties, coupled interface location and properties, and other data structures required to compute the evolution of the wavefield at each time step. The compute struct provides an interface layer where the developer can access simulation data at any timestep. +4. Domain : Domain is a templated class which defines methods required to compute the evolution of the wavefield at each time step. The class is templated on type of domain (acoustic, elastic, poroelastic, etc.), where we define specialized template implementations for each domain type. + The domain class in itself defines (Kokkos) parallelism used to compute the evolution of the wavefield. The physics of the domain is defined by specialized templated element, source and receiver classes. This lets us separate the physics of the domain from the parallelism, which should make it easier to extend the code to different physics. +5. Coupling Interfaces : ``coupled_interfaces`` class defines the methods used to compute coupling between different domains. The class is templated on the two domains that are coupled (``self_domain_type``, ``coupled_domain_type``), where we define specialized template implementations for different domain combinations. + Similar to the domain class, the coupling interface class in itself defines (Kokkos) parallelism used to compute the coupling between the two domains. The physics of the coupling is defined by specialized templated edge class. + +.. figure:: SPECFEM_Architecture.svg + :alt: SPECFEM Architecture + :width: 800 + :align: center + + SPECFEM Architecture. + +.. toctree:: + :maxdepth: 1 + + quadrature + mesh + compute + domain diff --git a/docs/developer_documentation/SPECFEM_architecture/compute.rst b/docs/developer_documentation/SPECFEM_architecture/compute.rst new file mode 100644 index 00000000..c3cdda61 --- /dev/null +++ b/docs/developer_documentation/SPECFEM_architecture/compute.rst @@ -0,0 +1,47 @@ +.. compute_dev_guide: + +Compute namespace developer guide +================================== + +The ``compute`` namespace in SPECFEM++ is designed to separate simulation data from the C++ methods and objects used to compute the evolution of the wavefield. This separation allows for a more modular and flexible approach to implementing post-processing and ad-hoc analysis capabilities without modifying the core routines used to compute the wavefield. + +By separating the simulation data from the computation methods, it becomes easier to view and manipulate the data without affecting the underlying computation. This can be especially useful for debugging and testing purposes, as well as for implementing new features and capabilities. + +The ``compute`` struct is key part of the SPECFEM++ codebase, and understanding its interaction with the rest of the code is essential for developing new features and capabilities. This developer guide is intended to provide a high-level overview of the ``compute`` struct and its interaction with the core SPECFEM++ computational routines. + +Understanding Kokkos Views +-------------------------- + +Before we explain how the data stored in compute struct is accessed by various SPECFEM++ computational routines. We need to understand a few key concepts of Kokkos views. Kokkos views are multi-dimensional arrays which are used to store/sync data across a host and device. The views are templated C++ classes where the template parameters define, at runtime, the dimension, data type, memory space, and layout of the view. The size of the array can be defined either at compile time or at runtime. For e.g. : + +.. code-block:: C++ + + // alias for 1D device view of doubles + using DeviceView1d = Kokkos::View; + + // alias for 2D host view of doubles + using HostView2d = Kokkos::View; + + // 1D view of size 10 + DeviceView1d view_1d("view_1d", 10); + + // 2D view of size 10x10 + HostView2d h_view_2d("view_2d", 10, 10); + +Anatomically the view contains 2 elements: +1. The metadata describing the view (e.g. size, layout, memory space, etc.). +2. An allocation (pointer) to the data stored in the view. + +.. note:: + The default copy constructor and assignment operator for Kokkos views perform a shallow copy of the view. This means that the metadata is copied, but the data is not. Instead, the data is shared between the original view and the copy. This is important to keep in mind when passing views to functions, as the function may modify the data in the view. This is fundamentally how we pass data stored in ``compute`` namespace between methods/objects in SPECFEM++. + + +Adding new data to ``compute`` namespace +--------------------------------------- +ß +Idea behind ``compute`` namespace is to provide a data layer to access simulation data during or at the end of simulation. Thus it makes sense to extend the namespace with new data when implemeting new features. A few things to keep in mind while adding new data to ``compute`` namespace: + +1. Create a logical heirarchical structure for the data. For e.g. ``specfem::compute::receivers`` struct which contains all the data related to receivers. This grouping allows us to pass only the receiver data to a methods/objects which needs it. +2. Think about when to initialize the data and where it will be accessed. Create device views are host mirrors when required and ``deep_copy`` the data to the device views when initialized. +3. GPU memory is precious, do not allocate more memory then required on the device. Do any pre-processing on the host and only copy the data required for computation to the device to reduce memory footprint. +4. Make sure any data that could be accessed in the future is available from within the ``compute`` namespace. diff --git a/docs/developer_documentation/SPECFEM_architecture/domain.rst b/docs/developer_documentation/SPECFEM_architecture/domain.rst new file mode 100644 index 00000000..35207507 --- /dev/null +++ b/docs/developer_documentation/SPECFEM_architecture/domain.rst @@ -0,0 +1,483 @@ +.. domain_coupled_interface_dev_guide:: + +Domain and Coupled Interface Developer Guide +=========================================== + +``specfem::domain::domain`` is a templated C++ class. A templated domain class allows us to provide cookie-cutter parallelism frameworks while allowing developers to describe the physics at elemental level ``specfem::domain::impl::elements``. This developer guide provides an in-depth methodology for understanding and extending the domain class to implement new physics. + +Brief introduction to C++ templates +----------------------------------- + +C++ templates are a powerful tool for generic programming. They allow us to write code that is independent of the type of data it operates on. + +.. code-block:: C++ + + template + T add(T a, T b) { + return a + b; + } + +For example the function above, adds two numbers without knowing whether they are integers, floating point numbers, or complex numbers. The compiler will generate a different version of the function for each type of data. Thus the compiler needs to know the type of data at compile time. In modern compilers (C++17 and above) the compiler can utilize type deduction to infer the type of data from the function arguments. + +The power of templates for writing portable code becomes obvious when using user defined types. For example, consider the following function which allows us to calculate L2 norm of a vector in dimension independent manner. + +.. code-block:: C++ + + class dim2{ + public: + constexpr int dim = 2; + }; + + class dim3{ + public: + constexpr int dim = 3; + }; + + template + double l2_norm(const std::vector vec) { + double norm = 0.0; + assert(vec.size() == T::dim; + for (int i = 0; i < T::dim; i++) { + norm += vec[i] * vec[i]; + } + return std::sqrt(norm); + } + +There are a couple of key points to note here from a performance standpoint: + +1. The compiler will generate a different version of the function for each dimension. +2. Since ``T::dim`` is a ``constexpr`` the compiler will unroll the loop - which on modern CPUs and GPUs can lead to significant performance gains. + +Apart from performance, templates also provide us a way to define a generic interface for different types of data i.e. in the above code we didn't need to write two different functions for `dim2` and `dim3` vectors. The importance of this in SPECFEM++ context will become clear in the following sections. + +Anatomy of a SPECFEM++ Domain and Coupled Interface +--------------------------------------------------- + +The following figure shows the different components of a SPECFEM++ domain and coupled interface. + +.. figure:: domain_coupled_interface_definition.svg + :alt: Domain definition + :width: 800 + :align: center + + Schematic of elements of domain and coupled interface. Each of the elements are implemented as C++ objects within SPECFEM++. + + +As the name suggests ``specfem::domain::domain`` is closely related to a spectral element domain. The domain is comprised of set of finite elements. The finite element method provide us a way to descritize the domain into small elements where we can approximate the solution using a polynomial basis. The approach is then to compute the coefficients of the polynomial basis at elemental levels which greatly reduces the computational cost. + +Similaly, coupled interface is a set of finite element edges which are used to describe coupling physics between different domains. Each edge contains a mapping between coupled GLL points between the 2 domains. + +.. note:: + + While the above figure depicts the finite elements are conforming between the 2 domains, this is not a nacessity. For example, non-conforming elements are used to describe the coupling physics at a fault. + +Let us look at computing the contribution of acoustic domain to global :math:`\frac {\partial \chi}{\partial t^2}`. The mathematical formulation to which is given by `Komatitsch and Tromp, 2002 `_: + +.. math:: + + \int \kappa^{-1} w \partial_t^2 \chi dV = - \int \rho^{-1} \nabla w \cdot \nabla \chi dV + \int w \hat{n} \cdot \partial_t s dS + +Where the first term on the right hand side is the contribution from the acoustic domain and the second term is the contribution from the coupled interface. The above equation is evaluated at each GLL point in the domain. Thus the contribution from the acoustic domain at elemental level is given by: + +.. math:: + + \int_{\Omega_e} \rho^{-1} \nabla w \cdot \nabla \chi dV \approx \sum_{\alpha, \beta, \gamma = 0}^{n_{\alpha}, n_{\beta}, n_{\gamma}} w^{\alpha \beta \gamma} \left[ \omega_{\beta} \omega_{\gamma} \sigma_{\xi} + \omega_{\alpha} \omega_{\gamma} \sigma_{\eta} + \omega_{\alpha} \omega_{\beta} \sigma_{\zeta} \right] + +where: + +.. math:: + + \sigma_{\xi} = \sum_{\alpha' = 0}^{n_{\alpha}} \omega_{\alpha'} J^{\alpha' \beta \gamma} \left( \rho^{\alpha' \beta \gamma} \right)^{-1} \left( \partial_1 \chi \right)^{\alpha' \beta \gamma} l'_{\alpha} \left( \xi_{\alpha'} \right) + + \sigma_{\eta} = \sum_{\beta' = 0}^{n_{\beta}} \omega_{\beta'} J^{\alpha \beta' \gamma} \left( \rho^{\alpha \beta' \gamma} \right)^{-1} \left( \partial_2 \chi \right)^{\alpha \beta' \gamma} l'_{\beta} \left( \eta_{\beta'} \right) + + \sigma_{\zeta} = \sum_{\gamma' = 0}^{n_{\gamma}} \omega_{\gamma'} J^{\alpha \beta \gamma'} \left( \rho^{\alpha \beta \gamma'} \right)^{-1} \left( \partial_3 \chi \right)^{\alpha \beta \gamma'} l'_{\gamma} \left( \zeta_{\gamma'} \right) + +The terms :math:`J^{\alpha' \beta \gamma} \left( \rho^{\alpha' \beta \gamma} \right)^{-1} \left( \partial_1 \chi \right)^{\alpha' \beta \gamma}` is what we call stress integrand in SPECFEM++. Finally, the gradient of the potential (i.e. :math:`\partial_i \chi`) is given by: + +.. math:: + + \left( \partial_i \chi \right)^{\alpha \beta \gamma} = \sum_{\alpha = 0}^{n_{\alpha}} \chi^{\alpha \beta' \gamma'} l'_{\alpha} \left( \xi_{\alpha'} \right) \partial_i \xi + \sum_{\beta = 0}^{n_{\beta}} \chi^{\alpha' \beta \gamma'} l'_{\beta} \left( \eta_{\beta'} \right) \partial_i \eta + \sum_{\gamma = 0}^{n_{\gamma}} \chi^{\alpha' \beta' \gamma} l'_{\gamma} \left( \zeta_{\gamma'} \right) \partial_i \zeta + +There are several key features of this equation that can be exploited when designing the domain class: + +1. As with any finite element code, the integration over a whole domain involves computing the elemental contribution at all GLL points within that domain. +2. The elemental contribution at each GLL point is independent of the other GLL points and is independent of other elements in the domain. + +Thus we can design the domain class in an element agnostic way. The domain class provides a generic interface to compute the elemental contribution of a given physics - separating the physics from the parallelism. + +.. note:: + + Later we will see a similar analogy of separating the physics from parallelism can be drawn between coupled interface and finite element edges. + +Understanding the parallelism +------------------------------ + +Let us now look at a naive serial implementation for the above formulation in 3D. + +.. code:: C++ + + void compute_acoustic_stiffness_interaction() { + for (int ispec = 0; ispec < nspec; i++) { + for (int iz = 0; iz < ngllz; iz++) { + for (int iy = 0; iy < ngllz; iy++) { + for (int ix = 0; ix < ngllx; ix++) { + // compute the global index of the GLL point + iglob = ibool(ispec, iz, iy, ix); // ibool is the mapping vector from GLL point to global index + // compute gradient at GLL point ix, iy, iz + acoustic_element.compute_gradient(ix, iy, iz); + // compute stresses at GLL point ix, iy, iz + acoustic_element.compute_stresses(ix, iy, iz); + // compute the md2chidt2 at GLL point ix, iy, iz + type_real md2chidt2 = acoustic_element.compute_acceleration(ix, iy, iz); + // add the contribution to the global vector + potential_dot_dot[iglob] += md2chidt2; + } + } + } + } + } + +Since the computations in each dimension are independent of each other we can simplify the above code even further. + +.. code:: C++ + + void compute_acoustic_stiffness_interaction() { + for (int ispec = 0; ispec < nspec; i++) { + for (int xyz = 0; xyx < ngllxyz; xyx++) { + auto [ix, iy, iz] = sub2ind(xyz); + // compute the global index of the GLL point + iglob = ibool(ispec, iz, iy, ix); // ibool is the mapping vector from GLL point to global index + // compute gradient at GLL point ix, iy, iz + acoustic_element.compute_gradient(ix, iy, iz, ); + // compute stresses at GLL point ix, iy, iz + acoustic_element.compute_stresses(ix, iy, iz, ); + // compute the md2chidt2 at GLL point ix, iy, iz + type_real md2chidt2 = acoustic_element.compute_acceleration(ix, iy, iz, ); + // add the contribution to the global vector + potential_dot_dot[iglob] += md2chidt2; + } + } + } + +Now let us template the above code to make it dimension independent using a bit of macro magic. + +.. code:: C++ + + #ifdef DIM2 + #define INDEX iz,ix + #endif + + #ifdef DIM3 + #define INDEX iz,iy, ix + #endif + + template + void compute_acoustic_stiffness_interaction() { + for (int ispec = 0; ispec < nspec; i++) { + for (int qp = 0; qp < dimension::get_num_qp(); qp++) { + auto [INDEX] = sub2ind(qp); + // rest of the code + ... + } + } + } + +Kokkos parallelism +................... + +The above code is a good starting point for parallelizing the code. A naive method of parallelizing the above section would be to distribute the 2 for loops among the available threads for example using OpenMP `collapse(2)` clause. However, since different elements could have different implementation (physics) for calculating the gradient, stresses, and acceleration contribution such a parallelization would result in poor performance on GPUs cause of warp divergence. Even on CPUs the performance would be poor since compiler could miss vectorization opportunities. + +Kokkos provides a natural formalism to exploit this type of parallelism using `heirarchical parallelism `_ . The idea is to parallelize the outer loop over elements using Kokkos teams and then parallelize the inner loop over quadrature points using Kokkos thread teams. This guarantees that all the threads in a team (which is mapped to CUDA blocks on NVIDIA GPUs) execute the same code path - thus avoiding warp divergence. + +.. code:: C++ + + template + void compute_acoustic_stiffness_interaction() { + Kokkos::parallel_for("compute_acoustic_stiffness_interaction", Kokkos::TeamPolicy(nspec, Kokkos::AUTO), KOKKOS_LAMBDA(const Kokkos::TeamPolicy::member_type& team) { + int ispec = team.league_rank(); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, dimension::get_num_qp()), [=] (const int& qp) { + auto [INDEX] = sub2ind(qp); + // rest of the code + ... + }); + }); + } + +Optimizing using shared/cache memory +.................................... + +At this point, it would be good to look at elmental implementations to understand the performance bottlenecks. Let us start by looking at function to compute the gradient of the potential inside a 2D acoustic element. + +.. code:: C++ + + class acoustic_element { + void compute_gradient( + const int &ispec, const int &xz, const View2d hprime_xx, + const View2d hprime_zz, const View1d field_chi, + type_real *dchidxl, type_real *dchidzl){ + + + int ix, iz, iglob; + sub2ind(xz, NGLL, iz, ix); + + const type_real xixl = this->xix(ispec, iz, ix); + const type_real gammaxl = this->gammax(ispec, iz, ix); + const type_real xizl = this->xiz(ispec, iz, ix); + const type_real gammazl = this->gammaz(ispec, iz, ix); + + type_real dchi_dxi = 0.0; + type_real dchi_dgamma = 0.0; + + for (int l = 0; l < ngllx; l++) { + iglob = ibool(ispec, iz, l) + dchi_dxi += hprime_xx(ix, l) * field_chi(iglob, 0); + } + + for (int l = 0; l < ngllz; l++) { + iglob = ibool(ispec, l, ix) + dchi_dgamma += hprime_zz(iz, l) * field_chi(iglob, 0); + } + + // dchidx + dchidxl[0] = dchi_dxi * xixl + dchi_dgamma * gammaxl; + + // dchidz + dchidzl[0] = dchi_dxi * xizl + dchi_dgamma * gammazl; + + return; + } + }; + +This implementation is not very efficient since it requires a lot of global memory accesses. In particular, if we look at the inner loop the accesses to `hprime_xx`, `hprime_zz` and `field_chi` are not coalesced. To improve the performance we can use shared memory to cache the values of `hprime_xx`, `hprime_zz` and `field_chi` for each element. + +.. code:: C++ + + template + void compute_acoustic_stiffness_interaction() { + + // allocate shared memory + typedef Kokkos::DefaultExecutionSpace::scratch_memory_space ScratchSpace; + // Define a view type in ScratchSpace + typedef Kokkos::View> scratch_view; + + // allocate shared memory for hprime_xx, hprime_zz, and field_chi + size_t scratch_size = + scratch_view::shmem_size(ngllx, ngllx) + + scratch_view::shmem_size(ngllx, ngllx) + + scratch_view::shmem_size(ngllz, ngllx); + + int scratch_size = + Kokkos::parallel_for("compute_acoustic_stiffness_interaction", Kokkos::TeamPolicy(nspec, Kokkos::AUTO), KOKKOS_LAMBDA(const Kokkos::TeamPolicy::member_type& team) { + int ispec = team.league_rank(); + // allocate shared memory + scratch_view s_hprime_xx(team.team_scratch(0), ngllx, ngllx); + scratch_view s_hprime_zz(team.team_scratch(0), ngllz, ngllz); + scratch_view s_field_chi(team.team_scratch(0), ngllz, ngllx); + + // copy data to shared memory + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, ngllxx), [=] (const int &xx) { + i = xx % ngllx; + j = xx / ngllx; + s_hprime_xx(i, j) = hprime_xx(i, j); + }); + + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, ngllzz), [=] (const int &xx) { + i = zz % ngllz; + j = zz / ngllz; + s_hprime_zz(i, j) = hprime_zz(i, j); + }); + + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, ngllxz) [=] (const int &xz) { + int ix, iz; + sub2ind(xz, ngllxz, iz, ix); + s_field_chi(iz, ix) = field_chi(ibool(ispec, iz, ix), 0); + }); + + team.team_barrier(); + + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, dimension::get_num_qp()), [=] (const int& qp) { + auto ix, iz = sub2ind(qp); + + acoustic_element.compute_gradient(ispec, qp, s_hprime_xx, s_hprime_zz, s_field_chi, dchidxl, dchidzl); + // rest of the code + ... + }); + }); + } + +.. note:: + + The description provided here serves as a good starting point for understanding the domain class. The actual implementation, while based on ideas presented here, is more complex and optimized for performance. + +Specializing elemental implementations +-------------------------------------- + +Let us next consider the elemental implementation for computing stresses in 2D isotropic elastic element and 2D anisotropic elastic element. + +.. math:: + + \bf{T(\bf{x} (\xi_{\alpha}, \eta_{beta}, \zeta_{\gamma}), t)} = \bf{c}(\bf{x} (\xi_{\alpha}, \eta_{\beta}, \zeta_{\gamma}), t) : \bf{e}(\bf{x} (\xi_{\alpha}, \eta_{\beta}, \zeta_{\gamma}), t) + +The elasticity tensor :math:`C^{ijkl}` for anisotropic elements is a 4th order tensor with 21 independent components. However, for isotropic elements the tensor :math:`\bf{c(x)}` is a diagonal with only 2 independent components given by: + +.. math:: + + C^{ijkl} = \lambda \delta^{ij} \delta^{kl} + \mu \left( \delta^{ik} \delta^{jl} + \delta^{il} \delta^{jk} \right) + +Computationally, the number of accesses from global memory when computing the stresses for isotropic elements is an order or magnitude less than that for anisotropic elements (2 accesses vs 21 accesses). Thus it makes sense to specialize the elemental implementation for isotropic and anisotropic elements. + +.. code:: C++ + + // definition of element class + template + class element{} + + // specialization for acoustic isotropic elements + template <> + class element{ + // implementation specific details + } + + // specialization for elastic isotropic elements + template <> + class element{ + // implementation specific details + } + + // specialization for elastic anisotropic elements + template <> + class element{ + // implementation specific details + } + +Using the above specialization we've provided a unified interface for acoustic and elastic elements where we can further specialize those elements based on domain/spectral element properties. + +.. note:: + + Specializing the elemental implementation for different types of elements is a powerful tool for performance optimization. However, it requires us to launch a different kernel for each type of element. This creates a bookkeeping overhead - where we need to make sure every element is accounted for exactly once. This bookkeeping and launch of the kernels is done by ``specfem::domain::impl::kernels`` + +.. note:: + + The other solution to the above problem is to use a single kernel and use class inheritance and polymorphism to deduce elemental specialization at runtime. However, this approach is not very efficient since GPUs are very inefficient at resolving virtual function calls. + +Optimization using loop unrolling +--------------------------------- + +From some profiling experiments we found that the most computationally intensive loop is the one used to compute gradients and evaluate integrals. The loops is shown below: + +.. code-block:: C++ + + // compute gradients + for (int l = 0; l < ngllx; l++) { + dchi_dxi += s_hprime_xx(ix, l) * s_field_chi(l, ix); + } + + for (int l = 0; l < ngllz; l++) { + dchi_dgamma += s_hprime_zz(iz, l) * s_field_chi(iz, l); + } + +.. code-block:: C++ + + // evaluate integrals + for (int l = 0; l < ngllx; l++) { + temp1 += s_hprimewgll_xx(ix, l) * stress_integrand_xx(l, iz); + } + + for (int l = 0; l < ngllz; l++) { + temp2 += s_hprimewgll_zz(iz, l) * stress_integrand_zz(l, ix); + } + +The above loops are not very efficient, especially on the GPU, since there are large number of memory accesses for each iteration. In many applications where SPECFEM++ is used, the number of GLL points is fixed - in most cases 4th order GLL quadrature (NGLL = 5) or 7th order GLL quadrature (NGLL = 8). Thus we can specialize the above methods for those NGLL values and unroll the loops. + +.. code:: C++ + + template + class element< + dim2, acoustic, + static_quadrature_points, + isotropic > { + void compute_gradient( + const int &ispec, const int &xz, const ScratchView2d hprime_xx, + const ScratchView2d hprime_zz, const ScratchView2d field_chi, + type_real *dchidxl, type_real *dchidzl){ + + + int ix, iz, iglob; + sub2ind(xz, NGLL, iz, ix); + + const type_real xixl = this->xix(ispec, iz, ix); + const type_real gammaxl = this->gammax(ispec, iz, ix); + const type_real xizl = this->xiz(ispec, iz, ix); + const type_real gammazl = this->gammaz(ispec, iz, ix); + + type_real dchi_dxi = 0.0; + type_real dchi_dgamma = 0.0; + + #ifdef KOKKOS_ENABLE_CUDA + #pragma unroll + #endif + for (int l = 0; l < NGLL; l++) { + dchi_dxi += s_hprime_xx(ix, l, 0) * field_chi(iz, l, 0); + dchi_dgamma += s_hprime_zz(iz, l, 0) * field_chi(l, ix, 0); + } + + // dchidx + dchidxl[0] = dchi_dxi * xixl + dchi_dgamma * gammaxl; + + // dchidz + dchidzl[0] = dchi_dxi * xizl + dchi_dgamma * gammazl; + + return; + } + }; + +The speedup from the above optimization is significant. For example, for 4th order GLL quadrature the speedup is ~ 4x on NVIDIA A100 GPU. + +.. note:: + + The key thing to note here is we need to define NGLL at compile time. As stated earlier, in many applications the NGLL = 5 or 8 so we can specialize the above method for those values in our implementation of the solver. However, to support cases when NGLL is not either of those values we have a general, *much slower*, implementation of the above method. So the performance of SPECFEM++, by design, is dependent on the NGLL value. + +.. warning:: + + The generalized implementation is not included in this release. It will be added soon as a patch release. + +Understanding the coupled interface +----------------------------------- + +``specfem::coupled_interfaces::coupled_interface`` is a templated C++ class that lets us define coupling physics between two types of domains. Similar to ``specfem::domain::domain`` class the ``specfem::coupled_interfaces::coupled_interface`` class serves as parallelism framework to implement the coupling physics defined inside ``specfem::coupled_interface::impl::edge`` class. + +Let us now look at the mathematical formulation for the coupling physics on the coupling interface (:math:`\Gamma`) between elastic and acoustic domains as described on the elastic side by `Komatitsch and Tromp, 2002 `_: + +.. math:: + + \int_{\Gamma} p \hat{n} \cdot w d\Gamma = \sum_b \int_{\Gamma_b} p \hat{n} \cdot w d\Gamma_b \approx \sum_b \sum_{\alpha, \beta = 0}^{n_{\alpha}, n_{\beta}} \omega_{\alpha} \omega_{\beta} J_b^{\alpha \beta} \dot{\chi}(t) \sum_{i = 1}^{3} w_i^{\alpha \beta} \hat{n}_i^{\alpha \beta} + +Again, similar to a methodology described in section `Understanding the parallelism`_ we can describe the the outer summation over all edges using Kokkos teams and the inner summation over all quadrature points using Kokkos thread teams. This ensures that we avoid warp divergence on GPUs and potentially benefit from vectorization on CPUs. + +.. code-block:: C++ + + void compute_coupling(){ + Kokkos::parallel_for( + "specfem::coupled_interfaces::coupled_interfaces::compute_coupling", + specfem::kokkos::DeviceTeam(this->nedges, Kokkos::AUTO, 1), + KOKKOS_CLASS_LAMBDA( + const specfem::kokkos::DeviceTeam::member_type &team_member) { + // Get number of quadrature points + int ngllx, ngllz; + quadrature_points.get_ngll(&ngllx, &ngllz); + int iedge_l = team_member.league_rank(); + // Get the edge + const auto self_edge_l = this->self_edge(iedge_l); + const auto coupled_edge_l = this->coupled_edge(iedge_l); + + auto npoints = specfem::compute::coupled_interfaces::iterator::npoints( + self_edge_l, ngllx, ngllz); + + // Iterate over the edges using TeamThreadRange + Kokkos::parallel_for( + Kokkos::TeamThreadRange(team_member, npoints), + [=](const int ipoint) { edge.compute_coupling(iedge_l, ipoint); }); + }); + } diff --git a/docs/developer_documentation/SPECFEM_architecture/domain_coupled_interface_definition.svg b/docs/developer_documentation/SPECFEM_architecture/domain_coupled_interface_definition.svg new file mode 100644 index 00000000..b30bb566 --- /dev/null +++ b/docs/developer_documentation/SPECFEM_architecture/domain_coupled_interface_definition.svg @@ -0,0 +1 @@ +AAAsZ2p1bWIAAAAeanVtZGMycGEAEQAQgAAAqgA4m3EDYzJwYQAAACxBanVtYgAAAEdqdW1kYzJtYQARABCAAACqADibcQN1cm46dXVpZDphY2VkNmZlMy0yYThiLTQ0MWEtYjkxZC0zODZiY2E5MjEyZmYAAAABp2p1bWIAAAApanVtZGMyYXMAEQAQgAAAqgA4m3EDYzJwYS5hc3NlcnRpb25zAAAAAMpqdW1iAAAAJmp1bWRjYm9yABEAEIAAAKoAOJtxA2MycGEuYWN0aW9ucwAAAACcY2JvcqFnYWN0aW9uc4GjZmFjdGlvbmtjMnBhLmVkaXRlZG1zb2Z0d2FyZUFnZW50bUFkb2JlIEZpcmVmbHlxZGlnaXRhbFNvdXJjZVR5cGV4Rmh0dHA6Ly9jdi5pcHRjLm9yZy9uZXdzY29kZXMvZGlnaXRhbHNvdXJjZXR5cGUvdHJhaW5lZEFsZ29yaXRobWljTWVkaWEAAACsanVtYgAAAChqdW1kY2JvcgARABCAAACqADibcQNjMnBhLmhhc2guZGF0YQAAAAB8Y2JvcqVqZXhjbHVzaW9uc4GiZXN0YXJ0GNRmbGVuZ3RoGTs0ZG5hbWVuanVtYmYgbWFuaWZlc3RjYWxnZnNoYTI1NmRoYXNoWCCgqkzRqkND1wwY8hgCNfIANrR/nwP327AnFd4bUmRQhWNwYWRJAAAAAAAAAAAAAAACC2p1bWIAAAAkanVtZGMyY2wAEQAQgAAAqgA4m3EDYzJwYS5jbGFpbQAAAAHfY2JvcqhoZGM6dGl0bGVvR2VuZXJhdGVkIEltYWdlaWRjOmZvcm1hdG1pbWFnZS9zdmcreG1samluc3RhbmNlSUR4LHhtcDppaWQ6YWFhOGM3YTQtMDQ0NS00MWFkLWE3YzItNWNkNWU2YmVjYWFkb2NsYWltX2dlbmVyYXRvcng2QWRvYmVfSWxsdXN0cmF0b3IvMjguMCBhZG9iZV9jMnBhLzAuNy42IGMycGEtcnMvMC4yNS4ydGNsYWltX2dlbmVyYXRvcl9pbmZvgb9kbmFtZXFBZG9iZSBJbGx1c3RyYXRvcmd2ZXJzaW9uZDI4LjD/aXNpZ25hdHVyZXgZc2VsZiNqdW1iZj1jMnBhLnNpZ25hdHVyZWphc3NlcnRpb25zgqJjdXJseCdzZWxmI2p1bWJmPWMycGEuYXNzZXJ0aW9ucy9jMnBhLmFjdGlvbnNkaGFzaFgg66xm4WqDn3xgnOk59f7WI0GCp10rxJISEEb0ImTQK8GiY3VybHgpc2VsZiNqdW1iZj1jMnBhLmFzc2VydGlvbnMvYzJwYS5oYXNoLmRhdGFkaGFzaFgggfYHN1K75qGRb9biBP4pNx/T9QiAUk6FwWzCnOwgfDtjYWxnZnNoYTI1NgAAKEBqdW1iAAAAKGp1bWRjMmNzABEAEIAAAKoAOJtxA2MycGEuc2lnbmF0dXJlAAAAKBBjYm9y0oREoQE4JKNneDVjaGFpboJZBjMwggYvMIIEF6ADAgECAhAbWws72rDkXfLzDZ5U0drSMA0GCSqGSIb3DQEBCwUAMHUxCzAJBgNVBAYTAlVTMSMwIQYDVQQKExpBZG9iZSBTeXN0ZW1zIEluY29ycG9yYXRlZDEdMBsGA1UECxMUQWRvYmUgVHJ1c3QgU2VydmljZXMxIjAgBgNVBAMTGUFkb2JlIFByb2R1Y3QgU2VydmljZXMgRzMwHhcNMjMwMjAxMDAwMDAwWhcNMjQwMjAxMjM1OTU5WjCBoTERMA8GA1UEAwwIY2FpLXByb2QxHDAaBgNVBAsME0NvbnRlbnQgQ3JlZGVudGlhbHMxEzARBgNVBAoMCkFkb2JlIEluYy4xETAPBgNVBAcMCFNhbiBKb3NlMRMwEQYDVQQIDApDYWxpZm9ybmlhMQswCQYDVQQGEwJVUzEkMCIGCSqGSIb3DQEJARYVZ3JwLWNhaS1vcHNAYWRvYmUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA79MAp32GPZZBw7MpK0xuxWJZ2BwXMrmpbg+bvVC487/hbE1ji4PDYa8/UU8SPRHgW7t1pu3+L6j7EGH8ZBKdMCGug1ZhDmYWwHkX24cm1kPw+Fr73JOJhGUfkGZk6SJ+x1+tYG7TBR5SVMZGAXLSKALfUwQBW8/XeSINlhtG7B9/W+v/FEl5yCJOBQenbQUU9cXhMEg7cDndWAaV1zQSZkVh1zSWWfOaH9rQU3rIP5DL06ziScWA2fe1ONesHL21aJpXnrPjV1GN/2QeMR/jbGYpbO5tWy9r9oUpx4i6KmXlCpJWx1Jk+GaY62QnbbiLFpuY9jz1yq+xylLgm2UlwQIDAQAFo4IBjDCCAYgwDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCB4AwHgYDVR0lBBcwFQYJKoZIhvcvAQEMBggrBgEFBQcDBDCBjgYDVR0gBIGGMIGDMIGABgkqhkiG9y8BAgMwczBxBggrBgEFBQcCAjBlDGNZb3UgYXJlIG5vdCBwZXJtaXR0ZWQgdG8gdXNlIHRoaXMgTGljZW5zZSBDZXJ0aWZpY2F0ZSBleGNlcHQgYXMgcGVybWl0dGVkIGJ5IHRoZSBsaWNlbnNlIGFncmVlbWVudC4wXQYDVR0fBFYwVDBSoFCgToZMaHR0cDovL3BraS1jcmwuc3ltYXV0aC5jb20vY2FfN2E1YzNhMGM3MzExNzQwNmFkZDE5MzEyYmMxYmMyM2YvTGF0ZXN0Q1JMLmNybDA3BggrBgEFBQcBAQQrMCkwJwYIKwYBBQUHMAGGG2h0dHA6Ly9wa2ktb2NzcC5zeW1hdXRoLmNvbTAfBgNVHSMEGDAWgBRXKXoyTcz+5DVOwB8kc85zU6vfajANBgkqhkiG9w0BAQsFAAOCAgEAV45Rmt8gCvxoo5+p/yTVPRWZu9jD+r3OXM61nvctE/hGsLkb4aQ+RHYtU515K6XvLDJIEo0xnW2PshoavM5QlkHlzdf2lqNy/V69bjcWP6FaS59Llln53ye8kfYCpf8qDH4Y8nU+LdX1x4vzIX4a1klUR6l9lN9VBRs/3tvfD9pL/r6oc6SFKNW4/o4m7aDyzDEHAjk7SoiTk4eKN1UmacEAxEQs6PdTZBfi52Y8GJenxOVEiJIP6AqKJl8Uj6aMMmw63ESfYpW7SXBEePPyxoMM7/3OzmHa6J+D5xF5tRZDmlY/kEX+zsIjU4s6J4SMy0eVX6dEBzlr/2z87woz0Hfl69EONN9lpUsUMKLLTUwD7aFQFODgsFR9xHId/HpidNP+n5Awna+zDfP+J9i0jazFL2gRGXZi6gwgZztNnWxa5qYN6U3NBakUOBi//PKY0TUjMubVPUqEJ0ghmKiLI3y/AM4DxBol10YAAWHNbl3nH+P3msm9ytjD7O4Z1k21CqRxySMMaXTd70xnWTVqc/TsX7qN3hC0JZE7wAh4KpGl4vxQGpx3uTwoZ+n69f+HDRfIKA9G7jwKYEt888Ko0Ycax/CEsD3yZ/Cas7qzGiwzJ53NfLR81IjLV+943+qF4e76AsV/0+A95xT5cVN6JtnKXC0NVneNNusdfK5UhkdZBqUwggahMIIEiaADAgECAhAMqLZUe4nm0gaJdc2Lm4niMA0GCSqGSIb3DQEBCwUAMGwxCzAJBgNVBAYTAlVTMSMwIQYDVQQKExpBZG9iZSBTeXN0ZW1zIEluY29ycG9yYXRlZDEdMBsGA1UECxMUQWRvYmUgVHJ1c3QgU2VydmljZXMxGTAXBgNVBAMTEEFkb2JlIFJvb3QgQ0EgRzIwHhcNMTYxMTI5MDAwMDAwWhcNNDExMTI4MjM1OTU5WjB1MQswCQYDVQQGEwJVUzEjMCEGA1UEChMaQWRvYmUgU3lzdGVtcyBJbmNvcnBvcmF0ZWQxHTAbBgNVBAsTFEFkb2JlIFRydXN0IFNlcnZpY2VzMSIwIAYDVQQDExlBZG9iZSBQcm9kdWN0IFNlcnZpY2VzIEczMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtx8uvb0Js1xIbP4Mg65sAepReCWkgD6Jp7GyiGTa9ol2gfn5HfOV/HiYjZiOz+TuHFU+DXNad86xEqgVeGVMlvIHGe/EHcKBxvEDXdlTXB5zIEkfl0/SGn7J6vTX8MNybfSi95eQDUOZ9fjCaq+PBFjS5ZfeNmzi/yR+MsA0jKKoWarSRCFFFBpUFQWfAgLyXOyxOnXQOQudjxNj6Wu0X0IB13+IH11WcKcWEWXM4j4jh6hLy29Cd3EoVG3oxcVenMF/EMgD2tXjx4NUbTNB1/g9+MR6Nw5Mhp5k/g3atNExAxhtugC+T3SDShSEJfs2quiiRUHtX3RhOcK1s1OJgT5s2s9xGy5/uxVpcAIaK2KiDJXW3xxN8nXPmk1NSVu/mxtfapr4TvSJbhrU7UA3qhQY9n4On2sbH1X1Tw+7LTek8KCA5ZDghOERPiIp/Jt893qov1bE5rJkagcVg0Wqjh89NhCaBA8VyRt3ovlGyCKdNV2UL3bn5vdFsTk7qqmp9makz1/SuVXYxIf6L6+8RXOatXWaPkmucuLE1TPOeP7S1N5JToFCs80l2D2EtxoQXGCR48K/cTUR5zV/fQ+hdIOzoo0nFn77Y8Ydd2k7/x9BE78pmoeMnw6VXYfXCuWEgj6p7jpbLoxQMoWMCVzlg72WVNhJFlSw4aD8fc6ezeECAwEAAaOCATQwggEwMBIGA1UdEwEB/wQIMAYBAf8CAQAwNQYDVR0fBC4wLDAqoCigJoYkaHR0cDovL2NybC5hZG9iZS5jb20vYWRvYmVyb290ZzIuY3JsMA4GA1UdDwEB/wQEAwIBBjAUBgNVHSUEDTALBgkqhkiG9y8BAQcwVwYDVR0gBFAwTjBMBgkqhkiG9y8BAgMwPzA9BggrBgEFBQcCARYxaHR0cHM6Ly93d3cuYWRvYmUuY29tL21pc2MvcGtpL3Byb2Rfc3ZjZV9jcHMuaHRtbDAkBgNVHREEHTAbpBkwFzEVMBMGA1UEAxMMU1lNQy00MDk2LTMzMB0GA1UdDgQWBBRXKXoyTcz+5DVOwB8kc85zU6vfajAfBgNVHSMEGDAWgBSmHOFtVCRMqI9Icr9uqYzV5Owx1DANBgkqhkiG9w0BAQsFAAOCAgEAcc7lB4ym3C3cyOA7ZV4AkoGV65UgJK+faThdyXzxuNqlTQBlOyXBGFyevlm33BsGO1mDJfozuyLyT2+7IVxWFvW5yYMV+5S1NeChMXIZnCzWNXnuiIQSdmPD82TEVCkneQpFET4NDwSxo8/ykfw6Hx8fhuKz0wjhjkWMXmK3dNZXIuYVcbynHLyJOzA+vWU3sH2T0jPtFp7FN39GZne4YG0aVMlnHhtHhxaXVCiv2RVoR4w1QtvKHQpzfPObR53Cl74iLStGVFKPwCLYRSpYRF7J6vVS/XxW4LzvN2b6VEKOcvJmN3LhpxFRl3YYzW+dwnwtbuHW6WJlmjffbLm1MxLFGlG95aCz31X8wzqYNsvb9+5AXcv8Ll69tLXmO1OtsY/3wILNUEp4VLZTE3wqm3n8hMnClZiiKyZCS7L4E0mClbx+BRSMH3eVo6jgve41/fK3FQM4QCNIkpGs7FjjLy+ptC+JyyWqcfvORrFV/GOgB5hD+G5ghJcIpeigD/lHsCRYsOa5sFdqREhwIWLmSWtNwfLZdJ3dkCc7yRpm3gal6qRfTkYpxTNxxKyvKbkaJDoxR9vtWrC3iNrQd9VvxC3TXtuzoHbqumeqgcAqefWF9u6snQ4Q9FkXzeuJArNuSvPIhgBjVtggH0w0vm/lmCQYiC/Y12GeCxfgYlL33btmc2lnVHN0oWl0c3RUb2tlbnOBoWN2YWxZF0Ewghc9MAMCAQAwghc0BgkqhkiG9w0BBwKgghclMIIXIQIBAzEPMA0GCWCGSAFlAwQCAQUAMIGDBgsqhkiG9w0BCRABBKB0BHIwcAIBAQYJYIZIAYb9bAcBMDEwDQYJYIZIAWUDBAIBBQAEIB49dHFM605+jGuWaSvYdawSHXXCBNhjpV+Y+xwKzSywAhEA2Q3QRMYqJrqd6k5uIkaduhgPMjAyMzEwMjAxNTE5MDNaAgkAoS23UzloL22gghMJMIIGwjCCBKqgAwIBAgIQBUSv85SdCDmmv9s/X+VhFjANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xOzA5BgNVBAMTMkRpZ2lDZXJ0IFRydXN0ZWQgRzQgUlNBNDA5NiBTSEEyNTYgVGltZVN0YW1waW5nIENBMB4XDTIzMDcxNDAwMDAwMFoXDTM0MTAxMzIzNTk1OVowSDELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMSAwHgYDVQQDExdEaWdpQ2VydCBUaW1lc3RhbXAgMjAyMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKNTRYcdg45brD5UsyPgz5/X5dLnXaEOCdwvSKOXejsqnGfcYhVYwamTEafNqrJq3RApih5iY2nTWJw1cb86l+uUUI8cIOrHmjsvlmbjaedp/lvD1isgHMGXlLSlUIHyz8sHpjBoyoNC2vx/CSSUpIIa2mq62DvKXd4ZGIX7ReoNYWyd/nFexAaaPPDFLnkPG2ZS48jWPl/aQ9OE9dDH9kgtXkV1lnX+3RChG4PBuOZSlbVH13gpOWvgeFmX40QrStWVzu8IF+qCZE3/I+PKhu60pCFkcOvV5aDaY7Mu6QXuqvYk9R28mxyyt1/f8O52fTGZZUdVnUokL6wrl76f5P17cz4y7lI0+9S769SgLDSb495uZBkHNwGRDxy1Uc2qTGaDiGhiu7xBG3gZbeTZD+BYQfvYsSzhUa+0rRUGFOpiCBPTaR58ZE2dD9/O0V6MqqtQFcmzyrzXxDtoRKOlO0L9c33u3Qr/eTQQfqZcClhMAD6FaXXHg2TWdc2PEnZWpST618RrIbroHzSYLzrqawGw9/sqhux7UjipmAmhcbJsca8+uG+W1eEQE/5hRwqM/vC2x9XH3mwk8L9CgsqgcT2ckpMEtGlwJw1Pt7U20clfCKRwo+wK8REuZODLIivK8SgTIUlRfgZm0zu++uuRONhRB8qUt+JQofM604qDy0B7AgMBAAGjggGLMIIBhzAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDAgBgNVHSAEGTAXMAgGBmeBDAEEAjALBglghkgBhv1sBwEwHwYDVR0jBBgwFoAUuhbZbU2FL3MpdpovdYxqII+eyG8wHQYDVR0OBBYEFKW27xPn783QZKHVVqllMaPe1eNJMFoGA1UdHwRTMFEwT6BNoEuGSWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFJTQTQwOTZTSEEyNTZUaW1lU3RhbXBpbmdDQS5jcmwwgZAGCCsGAQUFBwEBBIGDMIGAMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wWAYIKwYBBQUHMAKGTGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFJTQTQwOTZTSEEyNTZUaW1lU3RhbXBpbmdDQS5jcnQwDQYJKoZIhvcNAQELBQADggIBAIEa1t6gqbWYF7xwjU+KPGic2CX/yyzkzepdIpLsjCICqbjPgKjZ5+PF7SaCinEvGN1Ott5s1+FgnCvt7T1IjrhrunxdvcJhN2hJd6PrkKoS1yeF844ektrCQDifXcigLiV4JZ0qBXqEKZi2V3mP2yZWK7Dzp703DNiYdk9WuVLCtp04qYHnbUFcjGnRuSvExnvPnPp44pMadqJpddNQ5EQSviANnqlE0PjlSXcIWiHFtM+YlRpUurm8wWkZus8W8oM3NG6wQSbd3lqXTzON1I13fXVFoaVYJmoDRd7ZULVQjK9WvUzF4UbFKNOt50MAcN7MmJ4ZiQPq1JE3701S88lgIcRWR+3aEUuMMsOI5ljitts++V+wQtaP4xeR0arAVeOGv6wnLEHQmjNKqDbUuXKWfpd5OEhfysLcPTLfddY2Z1qJ+Panx+VPNTwAvb6cKmx5AdzaROY63jg7B145WPR8czFVoIARyxQMfq68/qTreWWqaNYiyjvrmoI1VygWy2nyMpqy0tg6uLFGhmu6F/3Ed2wVbK6rr3M66ElGt9V/zLY4wNjsHPW2obhDLN9OTH0eaHDAdwrUAuBcYLso/zjlUlrWrBciI0707NMX+1Br/wd3H3GXREHJuEbTbDJ8WC9nR2XlG3O2mflrLAZG70Ee8PBf4NvZrZCARK+AEEGKMIIGrjCCBJagAwIBAgIQBzY3tyRUfNhHrP0oZipeWzANBgkqhkiG9w0BAQsFADBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMjIwMzIzMDAwMDAwWhcNMzcwMzIyMjM1OTU5WjBjMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xOzA5BgNVBAMTMkRpZ2lDZXJ0IFRydXN0ZWQgRzQgUlNBNDA5NiBTSEEyNTYgVGltZVN0YW1waW5nIENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxoY1BkmzwT1ySVFVxyUDxPKRN6mXUaHW0oPRnkyibaCwzIP5WvYRoUQVQl+kiPNo+n3znIkLf50fng8zH1ATCyZzlm34V6gCff1DtITaEfFzsbPuK4CEiiIY3+vaPcQXf6sZKz5C3GeO6lE98NZW1OcoLevTsbV15x8GZY2UKdPZ7Gnf2ZCHRgB720RBidx8ald68Dd5n12sy+iEZLRS8nZH92GDGd1ftFQLIWhuNyG7QKxfst5Kfc71ORJn7w6lY2zkpsUdzTYNXNXmG6jBZHRAp8ByxbpOH7G1WE15/tePc5OsLDnipUjW8LAxE6lXKZYnLvWHpo9OdhVVJnCYJn+gGkcgQ+NDY4B7dW4nJZCYOjgRs/b2nuY7W+yB3iIU2YIqx5K/oN7jPqJz+ucfWmyU8lKVEStYdEAoq3NDzt9KoRxrOMUp88qqlnNCaJ+2RrOdOqPVA+C/8KI8ykLcGEh/FDTP0kyr75s9/g64ZCr6dSgkQe1CvwWcZklSUPRR8zZJTYsg0ixXNXkrqPNFYLwjjVj33GHek/45wPmyMKVM1+mYSlg+0wOI/rOP015LdhJRk8mMDDtbiiKowSYI+RQQEgN9XyO7ZONj4KbhPvbCdLI/Hgl27KtdRnXiYKNYCQEoAA6EVO7O6V3IXjASvUaetdN2udIOa5kM0jO0zbECAwEAAaOCAV0wggFZMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFLoW2W1NhS9zKXaaL3WMaiCPnshvMB8GA1UdIwQYMBaAFOzX44LScV1kTN8uZz/nupiuHA9PMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEFBQcDCDB3BggrBgEFBQcBAQRrMGkwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBBBggrBgEFBQcwAoY1aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcnQwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcmwwIAYDVR0gBBkwFzAIBgZngQwBBAIwCwYJYIZIAYb9bAcBMA0GCSqGSIb3DQEBCwUAA4ICAQB9WY7Ak7ZvmKlEIgF+ZtbYIULhsBguEE0TzzBTzr8Y+8dQXeJLKftwig2qKWn8acHPHQfpPmDI2AvlXFvXbYf6hCAlNDFnzbYSlm/EUExiHQwIgqgWvalWzxVzjQEiJc6VaT9Hd/tydBTX/6tPiix6q4XNQ1/tYLaqT5Fmniye4Iqs5f2MvGQmh2ySvZ180HAKfO+ovHVPulr3qRCyXen/KFSJ8NWKcXZl2szwcqMj+sAngkSumScbqyQeJsG33irr9p6xeZmBo1aGqwpFyd/EjaDnmPv7pp1yr8THwcFqcdnGE4AJxLafzYeHJLtPo0m5d2aR8XKc6UsCUqc3fpNTrDsdCEkPlM05et3/JWOZJyw9P2un8WbDQc1PtkCbISFA0LcTJM3cHXg65J6t5TRxktcma+Q4c6umAU+9Pzt4rUyt+8SVe+0KXzM5h0F4ejjpnOHdI/0dKNPH+ejxmF/7K9h+8kaddSweJywm228Vex4Ziza4k9Tm8heZWcpw8De/mADfIBZPJ/tgZxahZrrdVcA6KYawmKAr7ZVBtzrVFZgxtGIJDwq9gdkT/r+k0fNX2bwE+oLeMt8EifAAzV3C+dAjfwAL5HYCJtnwZXZCpimHCUcr5n8apIUP/JiW9lVUKx+A+sDyDivl1vupL0QVSucTDh3bNzgaoSv27dZ8/DCCBY0wggR1oAMCAQICEA6bGI750C3n79tQ4ghAGFowDQYJKoZIhvcNAQEMBQAwZTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEkMCIGA1UEAxMbRGlnaUNlcnQgQXNzdXJlZCBJRCBSb290IENBMB4XDTIyMDgwMTAwMDAwMFoXDTMxMTEwOTIzNTk1OVowYjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNlcnQgVHJ1c3RlZCBSb290IEc0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAv+aQc2jeu+RdSjwwIjBpM+zCpyUuySE98orYWcLhKac9WKt2ms2uexuEDcQwH/MbpDgW61bGl20dq7J58soR0uRf1gU8Ug9SH8aeFaV+vp+pVxZZVXKvaJNwwrK6dZlqczKU0RBEEC7fgvMHhOZ0O21x4i0MG+4g1ckgHWMpLc7sXk7Ik/ghYZs06wXGXuxbGrzryc/NrDRAX7F6Zu53yEioZldXn1RYjgwrt0+nMNlW7sp7XeOtyU9e5TXnMcvak17cjo+A2raRmECQecN4x7axxLVqGDgDEI3Y1DekLgV9iPWCPhCRcKtVgkEy19sEcypukQF8IUzUvK4bA3VdeGbZOjFEmjNAvwjXWkmkwuapoGfdpCe8oU85tRFYF/ckXEaPZPfBaYh2mHY9WV1CdoeJl2l6SPDgohIbZpp0yt5LHucOY67m1O+SkjqePdwA5EUlibaaRBkrfsCUtNJhbesz2cXfSwQAzH0clcOP9yGyshG3u3/y1YxwLEFgqrFjGESVGnZifvaAsPvoZKYz0YkH4b235kOkGLimdwHhD5QMIR2yVCkliWzlDlJRR3S+Jqy2QXXeeqxfjT/JvNNBERJb5RBQ6zHFynIWIgnffEx1P2PsIV/EIFFrb7GrhotPwtZFX50g/KEexcCPorF+CiaZ9eRpL5gdLfXZqbId5RsCAwEAAaOCATowggE2MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFOzX44LScV1kTN8uZz/nupiuHA9PMB8GA1UdIwQYMBaAFEXroq/0ksuCMS1Ri6enIZ3zbcgPMA4GA1UdDwEB/wQEAwIBhjB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDBFBgNVHR8EPjA8MDqgOKA2hjRodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3JsMBEGA1UdIAQKMAgwBgYEVR0gADANBgkqhkiG9w0BAQwFAAOCAQEAcKC/Q1xV5zhfoKN0Gz22Ftf3v1cHvZqsoYcs7IVeqRq7IviHGmlUIu2kiHdtvRoU9BNKei8ttzjv9P+Aufih9/Jy3iS8UgPITtAq3votVs/59PesMHqai7Je1M/RQ0SbQyHrlnKhSLSZy51PpwYDE3cnRNTnf+hZqPC/Lwum6fI0POz3A8eHqNJMQBk1RmppVLC4oVaO7KTVPeix3P0c2PR3WlxUjG/voVA9/HYJaISfb8rbII01YBwCA8sgsKxYoA5AY8WYIsGyWfVVa88nq2x2zm8jLfR+cWojayL/ErhULSd+2DrZ8LaHlv1b0VysGMNNn3O3AamfV6peKOK5lDGCA3YwggNyAgEBMHcwYzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMTswOQYDVQQDEzJEaWdpQ2VydCBUcnVzdGVkIEc0IFJTQTQwOTYgU0hBMjU2IFRpbWVTdGFtcGluZyBDQQIQBUSv85SdCDmmv9s/X+VhFjANBglghkgBZQMEAgEFAKCB0TAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwHAYJKoZIhvcNAQkFMQ8XDTIzMTAyMDE1MTkwM1owKwYLKoZIhvcNAQkQAgwxHDAaMBgwFgQUZvArMsLCyQ+CXc6qisnGTxmcz0AwLwYJKoZIhvcNAQkEMSIEIEm/+ayNaE49xeQHPLMZYKHZafGwb1hEh5//MupKEYBPMDcGCyqGSIb3DQEJEAIvMSgwJjAkMCIEINL25G3tdCLM0dRAV2hBNm+CitpVmq4zFq9NGprUDHgoMA0GCSqGSIb3DQEBAQUABIICADYIIcWoSFBWOCN508mOoouujOGwI+79pwiA5WoF0soYw/V8Wknx92uCMv7qs4PVDVKDCoTbN3X6Y5pkUKTGoN9KslfVL9t9k4BuZEQHGdhEE20Tvyuem1/nVDombhTXl4UvSCRcNPfyxftZj8JJzfxPU3VbRhAcMpsQKHJRlKCoSWiuJmEw5Hs4GGn+VjJ9Ie6X5eaeRgGmR2+2M0pQTQktrHfnH2Q7Yfp2sFYpxrvqM3aSPZyMg8W2HOwpFFeF3YQ1EbIcEYOi2xWNxDxnXVZ9LAJnCO4W7lSIjBnVjOt14Vvzk8FTjS8Yc63gQRp268/LNOywRgzWe85mYb3NBdbVX276FTjiNgqyrUaQGVtPo06ZBzb8B4DriUQR7Ei+vofc1XK38fevDgaP0Uy43s3qS+xA8G5V0rpqDLePv9Pkea7A/5y0SCjPxPyOT6oxgmb7TP6nye7SrSXGINn5ZQvpNW8JdOGSqYAw/zx7BRXr4oTNqUBgxwyqLfnZ815+6PTwLv+IM2R3KrqSeJ3kUab8Rnq/ckmokKbGJ/w4q3vsr4pVmnGrqdZ5G6tDhUevyn20YWLz+9CCGNlLST6wg3k1lb2/0KrdIi9oDxV4KBMN4sXsyZbXuDaMdwU5yb9j4bRMt0v9dZV/4RZPSxrmom4T7Xcq6jOwHFQMvXbIErVDY3BhZFkCsgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPZZAQCGU5tNEtB/VZvqMOKPx+MhDvXo6jD59NqqefP7Kl/C43BemmLRh/6vgiijKINIvJcHtCYYqLkGsqJMBwGvzYg+wEBFhaKxRgzIQcMEstsXg8YbqTOLqx7jQd2lGp8ndm4IFPt8ARf/ETbe4JoES3SJhNQjqHO1b3/5lnJxz2d3axlhAZBcmppsGd4jGYk7XU477a2bwZhNDiIiK/VnQ3YA1wWmkxdrs3NHsAb6wuoyYhaa1fjR8a9UlhYlEVCnyzq2w2WRBE4oBuIuFqsR40xKHzI2pmfgw8Tfq3GCjUEfCsoAy6lScO+aAcKpIJuBTlHbmXesO6V8yIJ+cKFvdBHn diff --git a/docs/developer_documentation/SPECFEM_architecture/mesh.rst b/docs/developer_documentation/SPECFEM_architecture/mesh.rst new file mode 100644 index 00000000..7cc3fc77 --- /dev/null +++ b/docs/developer_documentation/SPECFEM_architecture/mesh.rst @@ -0,0 +1,9 @@ +.. _mesh_dev_guide: + +Mesh developer guide +===================== + +``mesh`` struct defines IO routines and data structures to store data related to spectral element mesh. The mesh itself is generated using either the internal mesher or an external mesher. The current implementation only supports meshes generated using `MESHFEM2D `_. This guide describes the data structures and IO routines required to incorporate a new mesher. + +.. note:: + A few changes need to made to the code before I can write this guide. These changes would be incorporated in the next release. diff --git a/docs/developer_documentation/SPECFEM_architecture/quadrature.rst b/docs/developer_documentation/SPECFEM_architecture/quadrature.rst new file mode 100644 index 00000000..4ce41b6d --- /dev/null +++ b/docs/developer_documentation/SPECFEM_architecture/quadrature.rst @@ -0,0 +1,19 @@ +.. _quadrature_dev_guide: + +Quadrature developer guide: +=========================== + +Quadrature class defines quadrature rules for numerical integration. Defining new quadrature rules requires building a parent class that inherits from the Quadrature class and implements the following methods: + +1. Constructor: + - A constructor must: + b. Compute the quadrature points ``specfem::kokkos::DeviceView1d xi`` and weights ``specfem::kokkos::DeviceView1d w`` and store them within the class as Kokkos views. Where ``xi(p)`` defines the p`th quadrature point and ``w(p)`` defines the weight of the `p`th quadrature point. + c. Compute derivatives of polynomial ``specfem::kokkos::DeviceView2d hprime`` at quadrature points and store them within Kokkos View. Where ``hprime(p, q)`` defines the derivative of the ``q``th polynomial at the ``p``th quadrature point. + d. Define host mirrors of the above Kokkos views. i.e ``specfem::kokkos::HostMirror1d h_xi``, ``specfem::kokkos::HostMirror1d h_w`` and ``specfem::kokkos::HostMirror2d h_hprime``. + - A typical implementation computes these values on the host and them deep copies them to the device using ``Kokkos::deep_copy``. + +2. ``int get_N() const override`` : Returns the number of quadrature points. +3. ``specfem::kokkos::DeviceView1d get_xi() const override`` and ``specfem::kokkos::HostMirror1d get_hxi() const override`` : Returns the quadrature points on the device and host respectively. +4. ``specfem::kokkos::DeviceView1d get_w() const override`` and ``specfem::kokkos::HostMirror1d get_hw() const override`` : Returns the quadrature weights on the device and host respectively. +5. ``specfem::kokkos::DeviceView2d get_hprime() const override`` and ``specfem::kokkos::HostMirror2d get_hhprime() const override`` : Returns the derivatives of the polynomials at the quadrature points on the device and host respectively. +6. ``void print(const std::ostream& os) const override`` : Prints the quadrature information to the output stream `os`. diff --git a/docs/developer_documentation/build_requirements.rst b/docs/developer_documentation/build_requirements.rst index f04b5a48..c83c24e5 100644 --- a/docs/developer_documentation/build_requirements.rst +++ b/docs/developer_documentation/build_requirements.rst @@ -1,7 +1,7 @@ Build system requirements ========================== -This section covers compilation checks required so that SPECFEM is able to run across all architectures. +This section covers compilation checks required so that SPECFEM++ is able to run across all architectures. .. note:: diff --git a/docs/developer_documentation/cmake_primer.rst b/docs/developer_documentation/cmake_primer.rst index d5b23056..04056fad 100644 --- a/docs/developer_documentation/cmake_primer.rst +++ b/docs/developer_documentation/cmake_primer.rst @@ -1,5 +1,5 @@ CMake -======= +===== .. note:: diff --git a/docs/developer_documentation/git_workflow.rst b/docs/developer_documentation/git_workflow.rst index d7013c44..9dab12b9 100644 --- a/docs/developer_documentation/git_workflow.rst +++ b/docs/developer_documentation/git_workflow.rst @@ -1,11 +1,11 @@ Git development workflow ========================= -At SPECFEM we follow master-develop workflow. The master (main) branch is always a stable working code and is generally synced with the latest release of SPECFEM. The develop branch is a stable code with potentially new features which haven't been released in the latest version of SPECFEM yet. If you are contributing to SPECFEM then issue your `pull request `_ against the develop branch. +At SPECFEM++ we follow master-develop workflow. The master (main) branch is always a stable working code and is generally synced with the latest release of SPECFEM++. The develop branch is a stable code with potentially new features which haven't been released in the latest version of SPECFEM++ yet. If you are contributing to SPECFEM++ then issue your `pull request `_ against the develop branch. -To make a change to SPECFEM2D (This development workflow is similar to the one suggested by `github `_) +To make a change to SPECFEM++ (This development workflow is similar to the one suggested by `github `_) -- Create a `fork `_ of the SPECFEM2D repository. This will be your version of the package where you'd make changes which will stay local to your version until you make a pull request against original repository. +- Create a `fork `_ of the SPECFEM++ repository. This will be your version of the package where you'd make changes which will stay local to your version until you make a pull request against original repository. - Clone your fork locally and checkout to develop .. code-block:: bash @@ -33,4 +33,4 @@ To make a change to SPECFEM2D (This development workflow is similar to the one s git push origin -- Finally, head over to the main `SPECFEM2D repo `_ and issue a pull request against the develop branch. Once you've issued a pull request one of the maintainers will have a look at the changes, before approving a merge. +- Finally, head over to the main `SPECFEM++ repo `_ and issue a pull request against the develop branch. Once you've issued a pull request one of the maintainers will have a look at the changes, before approving a merge. diff --git a/docs/developer_documentation/index.rst b/docs/developer_documentation/index.rst index 62275640..9c990cc0 100644 --- a/docs/developer_documentation/index.rst +++ b/docs/developer_documentation/index.rst @@ -3,9 +3,13 @@ Developer documentation ============================ -SPECFEM tries to follow best practices to keep the code readable, maintainable and reproducable. This section outlines several best practices we follow in the development process. If you contribute to this project we expect you to follow these practices. +SPECFEM++ tries to follow best practices to keep the code readable, maintainable and reproducable. This section outlines several best practices we follow in the development process. If you contribute to this project we expect you to follow these practices. .. toctree:: + :maxdepth: 2 + git_workflow build_requirements style + tests + SPECFEM_architecture/architecture diff --git a/docs/developer_documentation/style.rst b/docs/developer_documentation/style.rst index 58136b0f..0a4af4fe 100644 --- a/docs/developer_documentation/style.rst +++ b/docs/developer_documentation/style.rst @@ -4,7 +4,7 @@ Style Pre-commit =========== -SPECFEM uses pre-commit to check style. Pre-commit can be installed inside python virtual environments. There are several methods for creating virtual environments, but I've found poetry tool is great at managing python environments. Especailly in collaborative environments poetry gives easy method for managing consistency of environments between all contributors via :code:`pyproject.toml` and :code:`poetry.lock` files. But more on this later. +SPECFEM++ uses pre-commit to check style. Pre-commit can be installed inside python virtual environments. There are several methods for creating virtual environments, but I've found poetry tool is great at managing python environments. Especailly in collaborative environments poetry gives easy method for managing consistency of environments between all contributors via :code:`pyproject.toml` and :code:`poetry.lock` files. But more on this later. Here we give a short tutorial for using poetry specifically with intention of using pre-commit hooks, but the information provided here can be translated for managing any python environment. The official poetry documentation can be found at `poetry docs `_ @@ -34,14 +34,14 @@ Adding python packages .. note:: - This section is only for educational purposes since SPECFEM comes with a :code:`pyproject.toml` + This section is only for educational purposes since SPECFEM++ comes with a :code:`pyproject.toml` We define all the packages required within our environment using the `pyproject.toml` file. For example, if we needed to add pre-commit to our environment we would define it within :code:`pyproject.toml` as .. code-block:: toml [tool.poetry] - name = "specfem2d_kokkos" + name = "specfempp" version = "0.1.0" description = "Kokkos implementation of SpecFEM2D code" authors = ["Your Name "] @@ -69,7 +69,7 @@ To install python packages run When you run this command one of two things happen, -1. If a correct version of a package already exists within :code:`poetry.lock` file then poetry installs that version. Here the assumption is that a `poetry.lock` already exists, if not then one is created for you (within SPECFEM `poetry.lock` should already exist). `poetry.lock` ensures that all developers have consistent environments. +1. If a correct version of a package already exists within :code:`poetry.lock` file then poetry installs that version. Here the assumption is that a `poetry.lock` already exists, if not then one is created for you (within SPECFEM++ `poetry.lock` should already exist). `poetry.lock` ensures that all developers have consistent environments. 2. If a correct version of a package doesn't exist within :code:`poetry.lock` then poetry will install a correct version and update `poetry.lock` file. @@ -84,7 +84,7 @@ When you run this command one of two things happen, Using your python/poetry environment ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -If you're in the SPECFEM root directory you should have access to the poetry environment. To run a command within the environment either +If you're in the SPECFEM++ root directory you should have access to the poetry environment. To run a command within the environment either 1. Explicitly activate the environment using :code:`poetry shell` as shown below @@ -104,7 +104,7 @@ Or Pre-commit hooks ~~~~~~~~~~~~~~~~~ -Next, we install pre-commit hooks to check style. Pre-commit hooks are defined in :code:`.pre-commit-config.yaml` within SPECFEM root directory. More documentation on pre-commit hooks can be found `here `_. +Next, we install pre-commit hooks to check style. Pre-commit hooks are defined in :code:`.pre-commit-config.yaml` within SPECFEM++ root directory. More documentation on pre-commit hooks can be found `here `_. To enable the hooks (This only needs to be done when you clone the repo or there is an update to :code:`.pre-commit-config.yaml`) diff --git a/docs/developer_documentation/tests.rst b/docs/developer_documentation/tests.rst index ca3cd5bc..62c91ed2 100644 --- a/docs/developer_documentation/tests.rst +++ b/docs/developer_documentation/tests.rst @@ -1,7 +1,68 @@ +.. _tests: + Tests ====== -.. note:: +The following tests are enabled within SPECFEM++ project: + +1. **Partial compilation checks (github actions)**: These tests are run on every push to the repository. This check tests if the code can be copiled using GNU compilers in serial mode. The goal is to ensure current push doesn't break the compilation. These tests would run on forks of this repository. Ulitmately, the hope is that end developer commits their changes to local fork at regualar intervals which would reduce compilation errors during development process. + +2. **Partial unit tests (github actions)**: These tests are run on every push to the repository. The tests are run in a serial mode using GNU compilers. The goal is to ensure current push doesn't break the unit tests. These tests would run on forks of this repository. Ulitmately, the hope is that end developer commits their changes to local fork at regualar intervals which would reduce unit test errors during development process. + +3. **Complete compilation checks (Jenkins)**: These tests are run on every pull request to the repository. The tests ensure the code can be compiled on various supported platforms. If you're are first time contributor, then an admin would have to approve your request to run these tests. The pull request would be merged only if these tests pass. + + list of tested compilers: + + - CPU: GNU 8.5.0, Intel 2020.2.0 + - CUDA: cudatoolkit/11.7 + + list of tested GPU architectures: + + - NVIDIA Ampere: A100 + - NVIDIA Volta: V100 + - NVIDIA Pascal: P100 + + Currently, GPU compilation is only checked using GNU compilers. The following matrix shows the list of compilers and GPU architectures that are tested: + + .. rst-class:: center-table + + +------------------------------+--------------------+---------------------+--------------------+---------------------+ + | | NONE | NVIDIA Ampere: A100 | NVIDIA Volta: V100 | NVIDIA Pascal: P100 | + +==============================+====================+=====================+====================+=====================+ + | GNU 8.5.0 (serial mode) | ✓ | ✓ | ✓ | ✓ | + +------------------------------+--------------------+---------------------+--------------------+---------------------+ + | Intel 2020.2.0 (serial mode) | ✓ | ✘ | ✘ | ✘ | + +------------------------------+--------------------+---------------------+--------------------+---------------------+ + | GNU 8.5.0 (OpenMP) | ✓ | ✓ | ✓ | ✓ | + +------------------------------+--------------------+---------------------+--------------------+---------------------+ + | Intel 2020.2.0 (OpenMP) | ✓ | ✘ | ✘ | ✘ | + +------------------------------+--------------------+---------------------+--------------------+---------------------+ + +4. **Complete unit tests (Jenkins)**: These tests are run on every pull request to the repository. The tests ensure the code runs accurately on various supported platforms. If you're are first time contributor, then an admin would have to approve your request to run these tests. The pull request would be merged only if these tests pass. + + list of tested compilers: + + - CPU: GNU 8.5.0, Intel 2020.2.0 + - CUDA: cudatoolkit/11.7 + + list of tested GPU architectures: + + - NVIDIA Ampere: A100 + + Currently, GPU compilation is only checked using GNU compilers. The following matrix shows the list of compilers and GPU architectures that are tested: + + .. rst-class:: center-table + + +------------------------------+--------------------+---------------------+ + | | NONE | NVIDIA Ampere: A100 | + +==============================+====================+=====================+ + | GNU 8.5.0 (serial mode) | ✓ | ✓ | + +------------------------------+--------------------+---------------------+ + | Intel 2020.2.0 (serial mode) | ✓ | ✘ | + +------------------------------+--------------------+---------------------+ + | GNU 8.5.0 (OpenMP) | ✓ | ✓ | + +------------------------------+--------------------+---------------------+ + | Intel 2020.2.0 (OpenMP) | ✓ | ✘ | + +------------------------------+--------------------+---------------------+ - This section is still under development. - Right now I am testing a pull request +5. **Regression tests (Jenkins)**: These tests are run on every pull request to the repository. The tests ensure that the current pull request doesn't degrade the performance of the code. If you're are first time contributor, then an admin would have to approve your request to run these tests. The pull request would be merged only if these tests pass. diff --git a/docs/examples/CMakeLists.txt b/docs/examples/CMakeLists.txt new file mode 100644 index 00000000..30614bc7 --- /dev/null +++ b/docs/examples/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 3.17.5) + +add_subdirectory(homogeneous-medium-flat-topography) +add_subdirectory(fluid-solid-interface) diff --git a/docs/examples/fluid-solid-interface/CMakeLists.txt b/docs/examples/fluid-solid-interface/CMakeLists.txt new file mode 100644 index 00000000..5235ddfa --- /dev/null +++ b/docs/examples/fluid-solid-interface/CMakeLists.txt @@ -0,0 +1,5 @@ + +CMAKE_MINIMUM_REQUIRED(VERSION 3.17.5) + +configure_file(specfem_config.yaml.in ${CMAKE_SOURCE_DIR}/examples/fluid-solid-interface/specfem_config.yaml) +configure_file(Par_File.in ${CMAKE_SOURCE_DIR}/examples/fluid-solid-interface/Par_File) diff --git a/docs/examples/fluid-solid-interface/Par_File b/docs/examples/fluid-solid-interface/Par_File new file mode 100644 index 00000000..f9c2a691 --- /dev/null +++ b/docs/examples/fluid-solid-interface/Par_File @@ -0,0 +1,132 @@ +#----------------------------------------------------------- +# +# Simulation input parameters +# +#----------------------------------------------------------- + +# title of job +title = Flat fluid/solid interface + +# parameters concerning partitioning +NPROC = 1 # number of processes + +# Output folder to store mesh related files +OUTPUT_FILES = /scratch/gpfs/rk9481/specfem2d_kokkos/examples/fluid-solid-interface/OUTPUT_FILES + +#----------------------------------------------------------- +# +# Mesh +# +#----------------------------------------------------------- + +# Partitioning algorithm for decompose_mesh +PARTITIONING_TYPE = 3 # SCOTCH = 3, ascending order (very bad idea) = 1 + +# number of control nodes per element (4 or 9) +NGNOD = 4 + +# location to store the mesh +database_filename = /scratch/gpfs/rk9481/specfem2d_kokkos/examples/fluid-solid-interface/OUTPUT_FILES/database.bin + +#----------------------------------------------------------- +# +# Receivers +# +#----------------------------------------------------------- + +# use an existing STATION file found in ./DATA or create a new one from the receiver positions below in this Par_file +use_existing_STATIONS = .false. + +# number of receiver sets (i.e. number of receiver lines to create below) +nreceiversets = 1 + +# orientation +anglerec = 0.d0 # angle to rotate components at receivers +rec_normal_to_surface = .false. # base anglerec normal to surface (external mesh and curve file needed) + +# first receiver set (repeat these 6 lines and adjust nreceiversets accordingly) +nrec = 110 # number of receivers +xdeb = 2500.d0 # first receiver x in meters +zdeb = 2933.33333d0 # first receiver z in meters +xfin = 6000.d0 # last receiver x in meters (ignored if only one receiver) +zfin = 2933.33333d0 # last receiver z in meters (ignored if only one receiver) +record_at_surface_same_vertical = .false. # receivers inside the medium or at the surface + +# filename to store stations file +stations_filename = /scratch/gpfs/rk9481/specfem2d_kokkos/examples/fluid-solid-interface/OUTPUT_FILES/STATIONS + +#----------------------------------------------------------- +# +# Velocity and density models +# +#----------------------------------------------------------- + +# number of model materials +nbmodels = 2 +# available material types (see user manual for more information) +# acoustic: model_number 1 rho Vp 0 0 0 QKappa Qmu 0 0 0 0 0 0 +# elastic: model_number 1 rho Vp Vs 0 0 QKappa Qmu 0 0 0 0 0 0 +# anistoropic: model_number 2 rho c11 c13 c15 c33 c35 c55 c12 c23 c25 0 0 0 +# poroelastic: model_number 3 rhos rhof phi c kxx kxz kzz Ks Kf Kfr etaf mufr Qmu +# tomo: model_number -1 0 9999 9999 A 0 0 9999 9999 0 0 0 0 0 +1 1 2500.d0 3400.d0 1963.d0 0 0 9999 9999 0 0 0 0 0 0 +2 1 1020.d0 1500.d0 0.d0 0 0 9999 9999 0 0 0 0 0 0 + +# external tomography file +TOMOGRAPHY_FILE = ./DATA/tomo_file.xyz + +# use an external mesh created by an external meshing tool or use the internal mesher +read_external_mesh = .false. + +#----------------------------------------------------------- +# +# PARAMETERS FOR EXTERNAL MESHING +# +#----------------------------------------------------------- + +# data concerning mesh, when generated using third-party app (more info in README) +# (see also absorbing_conditions above) +mesh_file = ./DATA/Mesh_canyon/canyon_mesh_file # file containing the mesh +nodes_coords_file = ./DATA/Mesh_canyon/canyon_nodes_coords_file # file containing the nodes coordinates +materials_file = ./DATA/Mesh_canyon/canyon_materials_file # file containing the material number for each element +free_surface_file = ./DATA/Mesh_canyon/canyon_free_surface_file # file containing the free surface +axial_elements_file = ./DATA/axial_elements_file # file containing the axial elements if AXISYM is true +absorbing_surface_file = ./DATA/Mesh_canyon/canyon_absorbing_surface_file # file containing the absorbing surface +acoustic_forcing_surface_file = ./DATA/MSH/Surf_acforcing_Bottom_enforcing_mesh # file containing the acoustic forcing surface +absorbing_cpml_file = ./DATA/absorbing_cpml_file # file containing the CPML element numbers +tangential_detection_curve_file = ./DATA/courbe_eros_nodes # file containing the curve delimiting the velocity model + +#----------------------------------------------------------- +# +# PARAMETERS FOR INTERNAL MESHING +# +#----------------------------------------------------------- + +# file containing interfaces for internal mesh +interfacesfile = /scratch/gpfs/rk9481/specfem2d_kokkos/examples/fluid-solid-interface/interfaces_fluid_flat.dat + +# geometry of the model (origin lower-left corner = 0,0) and mesh description +xmin = 0.d0 # abscissa of left side of the model +xmax = 6400.d0 # abscissa of right side of the model +nx = 144 # number of elements along X + +# absorbing boundary parameters (see absorbing_conditions above) +absorbbottom = .true. +absorbright = .true. +absorbtop = .true. +absorbleft = .true. + +# define the different regions of the model in the (nx,nz) spectral-element mesh +nbregions = 2 # then set below the different regions and model number for each region +1 144 1 54 1 +1 144 55 108 2 + +#----------------------------------------------------------- +# +# DISPLAY PARAMETERS +# +#----------------------------------------------------------- + +# meshing output +output_grid_Gnuplot = .false. # generate a GNUPLOT file containing the grid, and a script to plot it +output_grid_ASCII = .false. # dump the grid in an ASCII text file consisting of a set of X,Y,Z points or not diff --git a/docs/examples/fluid-solid-interface/Par_File.in b/docs/examples/fluid-solid-interface/Par_File.in new file mode 100644 index 00000000..a577d9ee --- /dev/null +++ b/docs/examples/fluid-solid-interface/Par_File.in @@ -0,0 +1,132 @@ +#----------------------------------------------------------- +# +# Simulation input parameters +# +#----------------------------------------------------------- + +# title of job +title = Flat fluid/solid interface + +# parameters concerning partitioning +NPROC = 1 # number of processes + +# Output folder to store mesh related files +OUTPUT_FILES = @CMAKE_SOURCE_DIR@/examples/fluid-solid-interface/OUTPUT_FILES + +#----------------------------------------------------------- +# +# Mesh +# +#----------------------------------------------------------- + +# Partitioning algorithm for decompose_mesh +PARTITIONING_TYPE = 3 # SCOTCH = 3, ascending order (very bad idea) = 1 + +# number of control nodes per element (4 or 9) +NGNOD = 4 + +# location to store the mesh +database_filename = @CMAKE_SOURCE_DIR@/examples/fluid-solid-interface/OUTPUT_FILES/database.bin + +#----------------------------------------------------------- +# +# Receivers +# +#----------------------------------------------------------- + +# use an existing STATION file found in ./DATA or create a new one from the receiver positions below in this Par_file +use_existing_STATIONS = .false. + +# number of receiver sets (i.e. number of receiver lines to create below) +nreceiversets = 1 + +# orientation +anglerec = 0.d0 # angle to rotate components at receivers +rec_normal_to_surface = .false. # base anglerec normal to surface (external mesh and curve file needed) + +# first receiver set (repeat these 6 lines and adjust nreceiversets accordingly) +nrec = 110 # number of receivers +xdeb = 2500.d0 # first receiver x in meters +zdeb = 2933.33333d0 # first receiver z in meters +xfin = 6000.d0 # last receiver x in meters (ignored if only one receiver) +zfin = 2933.33333d0 # last receiver z in meters (ignored if only one receiver) +record_at_surface_same_vertical = .false. # receivers inside the medium or at the surface + +# filename to store stations file +stations_filename = @CMAKE_SOURCE_DIR@/examples/fluid-solid-interface/OUTPUT_FILES/STATIONS + +#----------------------------------------------------------- +# +# Velocity and density models +# +#----------------------------------------------------------- + +# number of model materials +nbmodels = 2 +# available material types (see user manual for more information) +# acoustic: model_number 1 rho Vp 0 0 0 QKappa Qmu 0 0 0 0 0 0 +# elastic: model_number 1 rho Vp Vs 0 0 QKappa Qmu 0 0 0 0 0 0 +# anistoropic: model_number 2 rho c11 c13 c15 c33 c35 c55 c12 c23 c25 0 0 0 +# poroelastic: model_number 3 rhos rhof phi c kxx kxz kzz Ks Kf Kfr etaf mufr Qmu +# tomo: model_number -1 0 9999 9999 A 0 0 9999 9999 0 0 0 0 0 +1 1 2500.d0 3400.d0 1963.d0 0 0 9999 9999 0 0 0 0 0 0 +2 1 1020.d0 1500.d0 0.d0 0 0 9999 9999 0 0 0 0 0 0 + +# external tomography file +TOMOGRAPHY_FILE = ./DATA/tomo_file.xyz + +# use an external mesh created by an external meshing tool or use the internal mesher +read_external_mesh = .false. + +#----------------------------------------------------------- +# +# PARAMETERS FOR EXTERNAL MESHING +# +#----------------------------------------------------------- + +# data concerning mesh, when generated using third-party app (more info in README) +# (see also absorbing_conditions above) +mesh_file = ./DATA/Mesh_canyon/canyon_mesh_file # file containing the mesh +nodes_coords_file = ./DATA/Mesh_canyon/canyon_nodes_coords_file # file containing the nodes coordinates +materials_file = ./DATA/Mesh_canyon/canyon_materials_file # file containing the material number for each element +free_surface_file = ./DATA/Mesh_canyon/canyon_free_surface_file # file containing the free surface +axial_elements_file = ./DATA/axial_elements_file # file containing the axial elements if AXISYM is true +absorbing_surface_file = ./DATA/Mesh_canyon/canyon_absorbing_surface_file # file containing the absorbing surface +acoustic_forcing_surface_file = ./DATA/MSH/Surf_acforcing_Bottom_enforcing_mesh # file containing the acoustic forcing surface +absorbing_cpml_file = ./DATA/absorbing_cpml_file # file containing the CPML element numbers +tangential_detection_curve_file = ./DATA/courbe_eros_nodes # file containing the curve delimiting the velocity model + +#----------------------------------------------------------- +# +# PARAMETERS FOR INTERNAL MESHING +# +#----------------------------------------------------------- + +# file containing interfaces for internal mesh +interfacesfile = @CMAKE_SOURCE_DIR@/examples/fluid-solid-interface/interfaces_fluid_flat.dat + +# geometry of the model (origin lower-left corner = 0,0) and mesh description +xmin = 0.d0 # abscissa of left side of the model +xmax = 6400.d0 # abscissa of right side of the model +nx = 144 # number of elements along X + +# absorbing boundary parameters (see absorbing_conditions above) +absorbbottom = .true. +absorbright = .true. +absorbtop = .true. +absorbleft = .true. + +# define the different regions of the model in the (nx,nz) spectral-element mesh +nbregions = 2 # then set below the different regions and model number for each region +1 144 1 54 1 +1 144 55 108 2 + +#----------------------------------------------------------- +# +# DISPLAY PARAMETERS +# +#----------------------------------------------------------- + +# meshing output +output_grid_Gnuplot = .false. # generate a GNUPLOT file containing the grid, and a script to plot it +output_grid_ASCII = .false. # dump the grid in an ASCII text file consisting of a set of X,Y,Z points or not diff --git a/docs/examples/fluid-solid-interface/README.md b/docs/examples/fluid-solid-interface/README.md new file mode 100644 index 00000000..fbfac340 --- /dev/null +++ b/docs/examples/fluid-solid-interface/README.md @@ -0,0 +1,29 @@ +# Wave propagration through fluid-solid interface + +This example creates the fluid-solid example with flat ocean bottom from [Komatitsch et. al.](https://doi.org/10.1190/1.1444758). + +## Generating the mesh + +To generate the mesh for the homogeneous media we need a parameter file, `Par_File`, a topography file, `topography_file.dat`, and the mesher executible, `xmeshfem2D`, which should have been compiled during the installation process. + +> Currently, we still use a mesher that was developed for the original [SPECFEM2D](https://specfem2d.readthedocs.io/en/latest/03_mesh_generation/) code. More details on the meshing process can be found [here](https://specfem2d.readthedocs.io/en/latest/03_mesh_generation/). + +## Running the mesher + +To execute the mesher run + +``` + ./xmeshfem2D -p +``` + +> Make sure either your are in the build directory of SPECFEM2D kokkos or the build directory is added to your ``PATH``. + +Note the path of the database file and :ref:`stations_file` generated after successfully running the mesher. + +## Running the solver + +Finally, to run the SPECFEM2D kokkos solver + +``` + ./specfem2d -p +``` diff --git a/docs/examples/fluid-solid-interface/sources.yaml b/docs/examples/fluid-solid-interface/sources.yaml new file mode 100644 index 00000000..804bce48 --- /dev/null +++ b/docs/examples/fluid-solid-interface/sources.yaml @@ -0,0 +1,13 @@ +number-of-sources: 1 +sources: + - force: + x : 1575.0 + z : 2900.0 + source_surf: false + angle : 0.0 + vx : 0.0 + vz : 0.0 + Ricker: + factor: 1e9 + tshift: 0.0 + f0: 10.0 diff --git a/docs/examples/fluid-solid-interface/specfem_config.yaml b/docs/examples/fluid-solid-interface/specfem_config.yaml new file mode 100644 index 00000000..5e561e30 --- /dev/null +++ b/docs/examples/fluid-solid-interface/specfem_config.yaml @@ -0,0 +1,50 @@ +parameters: + + header: + ## Header information is used for logging. It is good practice to give your simulations explicit names + title: Heterogeneous acoustic-elastic medium with 1 acoustic-elastic interface # name for your simulation + # A detailed description for your simulation + description: | + Material systems : Elastic domain (1), Acoustic domain (1) + Interfaces : Acoustic-elastic interface (1) + Sources : Force source (1) + Boundary conditions : Neumann BCs on all edges + + simulation-setup: + ## quadrature setup + quadrature: + alpha: 0.0 + beta: 0.0 + ngllx: 5 + ngllz: 5 + + ## Solver setup + solver: + time-marching: + type-of-simulation: forward + time-scheme: + type: Newmark + dt: 0.85e-3 + nstep: 800 + + receivers: + stations-file: "/scratch/gpfs/rk9481/specfem2d_kokkos/examples/fluid_solid_interface/OUTPUT_FILES/STATIONS" + angle: 0.0 + seismogram-type: + - displacement + - velocity + nstep_between_samples: 1 + + ## Runtime setup + run-setup: + number-of-processors: 1 + number-of-runs: 1 + + ## databases + databases: + mesh-database: "/scratch/gpfs/rk9481/specfem2d_kokkos/examples/fluid-solid-interface/OUTPUT_FILES/database.bin" + source-file: "/scratch/gpfs/rk9481/specfem2d_kokkos/examples/fluid-solid-interface/sources.yaml" + + seismogram: + seismogram-format: ascii + output-folder: "." diff --git a/docs/examples/fluid-solid-interface/specfem_config.yaml.in b/docs/examples/fluid-solid-interface/specfem_config.yaml.in new file mode 100644 index 00000000..bcbf42ca --- /dev/null +++ b/docs/examples/fluid-solid-interface/specfem_config.yaml.in @@ -0,0 +1,50 @@ +parameters: + + header: + ## Header information is used for logging. It is good practice to give your simulations explicit names + title: Heterogeneous acoustic-elastic medium with 1 acoustic-elastic interface # name for your simulation + # A detailed description for your simulation + description: | + Material systems : Elastic domain (1), Acoustic domain (1) + Interfaces : Acoustic-elastic interface (1) + Sources : Force source (1) + Boundary conditions : Neumann BCs on all edges + + simulation-setup: + ## quadrature setup + quadrature: + alpha: 0.0 + beta: 0.0 + ngllx: 5 + ngllz: 5 + + ## Solver setup + solver: + time-marching: + type-of-simulation: forward + time-scheme: + type: Newmark + dt: 0.85e-3 + nstep: 800 + + receivers: + stations-file: "@CMAKE_SOURCE_DIR@/examples/fluid_solid_interface/OUTPUT_FILES/STATIONS" + angle: 0.0 + seismogram-type: + - displacement + - velocity + nstep_between_samples: 1 + + ## Runtime setup + run-setup: + number-of-processors: 1 + number-of-runs: 1 + + ## databases + databases: + mesh-database: "@CMAKE_SOURCE_DIR@/examples/fluid-solid-interface/OUTPUT_FILES/database.bin" + source-file: "@CMAKE_SOURCE_DIR@/examples/fluid-solid-interface/sources.yaml" + + seismogram: + seismogram-format: ascii + output-folder: "." diff --git a/docs/examples/homogeneous-medium-flat-topography/CMakeLists.txt b/docs/examples/homogeneous-medium-flat-topography/CMakeLists.txt new file mode 100644 index 00000000..98b29e65 --- /dev/null +++ b/docs/examples/homogeneous-medium-flat-topography/CMakeLists.txt @@ -0,0 +1,5 @@ + +CMAKE_MINIMUM_REQUIRED(VERSION 3.17.5) + +configure_file(Par_File.in ${CMAKE_SOURCE_DIR}/examples/homogeneous-medium-flat-topography/Par_File) +configure_file(specfem_config.yaml.in ${CMAKE_SOURCE_DIR}/examples/homogeneous-medium-flat-topography/specfem_config.yaml) diff --git a/docs/examples/homogeneous-medium-flat-topography/Par_File b/docs/examples/homogeneous-medium-flat-topography/Par_File new file mode 100644 index 00000000..c802f743 --- /dev/null +++ b/docs/examples/homogeneous-medium-flat-topography/Par_File @@ -0,0 +1,152 @@ +#----------------------------------------------------------- +# +# Simulation input parameters +# +#----------------------------------------------------------- + +# title of job +title = Elastic Simulation with point source + +# parameters concerning partitioning +NPROC = 1 # number of processes + +# Output folder to store mesh related files +OUTPUT_FILES = /scratch/gpfs/rk9481/specfem2d_kokkos/examples/homogeneous-medium-flat-topography/OUTPUT_FILES + + +#----------------------------------------------------------- +# +# Mesh +# +#----------------------------------------------------------- + +# Partitioning algorithm for decompose_mesh +PARTITIONING_TYPE = 3 # SCOTCH = 3, ascending order (very bad idea) = 1 + +# number of control nodes per element (4 or 9) +NGNOD = 9 + +# location to store the mesh +database_filename = /scratch/gpfs/rk9481/specfem2d_kokkos/examples/homogeneous-medium-flat-topography/OUTPUT_FILES/database.bin + +#----------------------------------------------------------- +# +# Receivers +# +#----------------------------------------------------------- + +# use an existing STATION file found in ./DATA or create a new one from the receiver positions below in this Par_file +use_existing_STATIONS = .false. + +# number of receiver sets (i.e. number of receiver lines to create below) +nreceiversets = 2 + +# orientation +anglerec = 0.d0 # angle to rotate components at receivers +rec_normal_to_surface = .false. # base anglerec normal to surface (external mesh and curve file needed) + +# first receiver set (repeat these 6 lines and adjust nreceiversets accordingly) +nrec = 3 # number of receivers +xdeb = 2200. # first receiver x in meters +zdeb = 2200. # first receiver z in meters +xfin = 2800. # last receiver x in meters (ignored if only one receiver) +zfin = 2200. # last receiver z in meters (ignored if only one receiver) +record_at_surface_same_vertical = .true. # receivers inside the medium or at the surface (z values are ignored if this is set to true, they are replaced with the topography height) + +# second receiver set +nrec = 3 # number of receivers +xdeb = 2500. # first receiver x in meters +zdeb = 2500. # first receiver z in meters +xfin = 2500. # last receiver x in meters (ignored if only one receiver) +zfin = 1900. # last receiver z in meters (ignored if only one receiver) +record_at_surface_same_vertical = .false. # receivers inside the medium or at the surface (z values are ignored if this is set to true, they are replaced with the topography height) + +# filename to store stations file +stations_filename = /scratch/gpfs/rk9481/specfem2d_kokkos/examples/homogeneous-medium-flat-topography/OUTPUT_FILES/STATIONS + +#----------------------------------------------------------- +# +# Velocity and density models +# +#----------------------------------------------------------- + +# number of model materials +nbmodels = 1 +# available material types (see user manual for more information) +# acoustic: model_number 1 rho Vp 0 0 0 QKappa 9999 0 0 0 0 0 0 (for QKappa use 9999 to ignore it) +# elastic: model_number 1 rho Vp Vs 0 0 QKappa Qmu 0 0 0 0 0 0 (for QKappa and Qmu use 9999 to ignore them) +# anisotropic: model_number 2 rho c11 c13 c15 c33 c35 c55 c12 c23 c25 0 QKappa Qmu +# anisotropic in AXISYM: model_number 2 rho c11 c13 c15 c33 c35 c55 c12 c23 c25 c22 QKappa Qmu +# poroelastic: model_number 3 rhos rhof phi c kxx kxz kzz Ks Kf Kfr etaf mufr Qmu +# tomo: model_number -1 0 0 A 0 0 0 0 0 0 0 0 0 0 +# +# note: When viscoelasticity or viscoacousticity is turned on, +# the Vp and Vs values that are read here are the UNRELAXED ones i.e. the values at infinite frequency +# unless the READ_VELOCITIES_AT_f0 parameter above is set to true, in which case they are the values at frequency f0. +# +# Please also note that Qmu is always equal to Qs, but Qkappa is in general not equal to Qp. +# To convert one to the other see doc/Qkappa_Qmu_versus_Qp_Qs_relationship_in_2D_plane_strain.pdf and +# utils/attenuation/conversion_from_Qkappa_Qmu_to_Qp_Qs_from_Dahlen_Tromp_959_960.f90. +1 1 2700.d0 3000.d0 1732.051d0 0 0 9999 9999 0 0 0 0 0 0 +# 2 1 2500.d0 2700.d0 1443.375d0 0 0 9999 9999 0 0 0 0 0 0 +# 3 1 2200.d0 2500.d0 1443.375d0 0 0 9999 9999 0 0 0 0 0 0 +# 4 1 2200.d0 2200.d0 1343.375d0 0 0 9999 9999 0 0 0 0 0 0 + +# external tomography file +TOMOGRAPHY_FILE = ./DATA/tomo_file.xyz + +# use an external mesh created by an external meshing tool or use the internal mesher +read_external_mesh = .false. + +#----------------------------------------------------------- +# +# PARAMETERS FOR EXTERNAL MESHING +# +#----------------------------------------------------------- + +# data concerning mesh, when generated using third-party app (more info in README) +# (see also absorbing_conditions above) +mesh_file = ./DATA/mesh_file # file containing the mesh +nodes_coords_file = ./DATA/nodes_coords_file # file containing the nodes coordinates +materials_file = ./DATA/materials_file # file containing the material number for each element +free_surface_file = ./DATA/free_surface_file # file containing the free surface +axial_elements_file = ./DATA/axial_elements_file # file containing the axial elements if AXISYM is true +absorbing_surface_file = ./DATA/absorbing_surface_file # file containing the absorbing surface +acoustic_forcing_surface_file = ./DATA/MSH/Surf_acforcing_Bottom_enforcing_mesh # file containing the acoustic forcing surface +absorbing_cpml_file = ./DATA/absorbing_cpml_file # file containing the CPML element numbers +tangential_detection_curve_file = ./DATA/courbe_eros_nodes # file containing the curve delimiting the velocity model + +#----------------------------------------------------------- +# +# PARAMETERS FOR INTERNAL MESHING +# +#----------------------------------------------------------- + +# file containing interfaces for internal mesh +interfacesfile = /scratch/gpfs/rk9481/specfem2d_kokkos/examples/homogeneous-medium-flat-topography/topography.dat + +# geometry of the model (origin lower-left corner = 0,0) and mesh description +xmin = 0.d0 # abscissa of left side of the model +xmax = 4000.d0 # abscissa of right side of the model +nx = 80 # number of elements along X + +# absorbing boundary parameters (see absorbing_conditions above) +absorbbottom = .false. +absorbright = .false. +absorbtop = .false. +absorbleft = .false. + +# define the different regions of the model in the (nx,nz) spectral-element mesh +nbregions = 1 # then set below the different regions and model number for each region +# format of each line: nxmin nxmax nzmin nzmax material_number +1 80 1 60 1 + +#----------------------------------------------------------- +# +# DISPLAY PARAMETERS +# +#----------------------------------------------------------- + +# meshing output +output_grid_Gnuplot = .false. # generate a GNUPLOT file containing the grid, and a script to plot it +output_grid_ASCII = .false. # dump the grid in an ASCII text file consisting of a set of X,Y,Z points or not diff --git a/docs/examples/homogeneous-medium-flat-topography/Par_File.in b/docs/examples/homogeneous-medium-flat-topography/Par_File.in new file mode 100644 index 00000000..d1319caf --- /dev/null +++ b/docs/examples/homogeneous-medium-flat-topography/Par_File.in @@ -0,0 +1,152 @@ +#----------------------------------------------------------- +# +# Simulation input parameters +# +#----------------------------------------------------------- + +# title of job +title = Elastic Simulation with point source + +# parameters concerning partitioning +NPROC = 1 # number of processes + +# Output folder to store mesh related files +OUTPUT_FILES = @CMAKE_SOURCE_DIR@/examples/homogeneous-medium-flat-topography/OUTPUT_FILES + + +#----------------------------------------------------------- +# +# Mesh +# +#----------------------------------------------------------- + +# Partitioning algorithm for decompose_mesh +PARTITIONING_TYPE = 3 # SCOTCH = 3, ascending order (very bad idea) = 1 + +# number of control nodes per element (4 or 9) +NGNOD = 9 + +# location to store the mesh +database_filename = @CMAKE_SOURCE_DIR@/examples/homogeneous-medium-flat-topography/OUTPUT_FILES/database.bin + +#----------------------------------------------------------- +# +# Receivers +# +#----------------------------------------------------------- + +# use an existing STATION file found in ./DATA or create a new one from the receiver positions below in this Par_file +use_existing_STATIONS = .false. + +# number of receiver sets (i.e. number of receiver lines to create below) +nreceiversets = 2 + +# orientation +anglerec = 0.d0 # angle to rotate components at receivers +rec_normal_to_surface = .false. # base anglerec normal to surface (external mesh and curve file needed) + +# first receiver set (repeat these 6 lines and adjust nreceiversets accordingly) +nrec = 3 # number of receivers +xdeb = 2200. # first receiver x in meters +zdeb = 2200. # first receiver z in meters +xfin = 2800. # last receiver x in meters (ignored if only one receiver) +zfin = 2200. # last receiver z in meters (ignored if only one receiver) +record_at_surface_same_vertical = .true. # receivers inside the medium or at the surface (z values are ignored if this is set to true, they are replaced with the topography height) + +# second receiver set +nrec = 3 # number of receivers +xdeb = 2500. # first receiver x in meters +zdeb = 2500. # first receiver z in meters +xfin = 2500. # last receiver x in meters (ignored if only one receiver) +zfin = 1900. # last receiver z in meters (ignored if only one receiver) +record_at_surface_same_vertical = .false. # receivers inside the medium or at the surface (z values are ignored if this is set to true, they are replaced with the topography height) + +# filename to store stations file +stations_filename = @CMAKE_SOURCE_DIR@/examples/homogeneous-medium-flat-topography/OUTPUT_FILES/STATIONS + +#----------------------------------------------------------- +# +# Velocity and density models +# +#----------------------------------------------------------- + +# number of model materials +nbmodels = 1 +# available material types (see user manual for more information) +# acoustic: model_number 1 rho Vp 0 0 0 QKappa 9999 0 0 0 0 0 0 (for QKappa use 9999 to ignore it) +# elastic: model_number 1 rho Vp Vs 0 0 QKappa Qmu 0 0 0 0 0 0 (for QKappa and Qmu use 9999 to ignore them) +# anisotropic: model_number 2 rho c11 c13 c15 c33 c35 c55 c12 c23 c25 0 QKappa Qmu +# anisotropic in AXISYM: model_number 2 rho c11 c13 c15 c33 c35 c55 c12 c23 c25 c22 QKappa Qmu +# poroelastic: model_number 3 rhos rhof phi c kxx kxz kzz Ks Kf Kfr etaf mufr Qmu +# tomo: model_number -1 0 0 A 0 0 0 0 0 0 0 0 0 0 +# +# note: When viscoelasticity or viscoacousticity is turned on, +# the Vp and Vs values that are read here are the UNRELAXED ones i.e. the values at infinite frequency +# unless the READ_VELOCITIES_AT_f0 parameter above is set to true, in which case they are the values at frequency f0. +# +# Please also note that Qmu is always equal to Qs, but Qkappa is in general not equal to Qp. +# To convert one to the other see doc/Qkappa_Qmu_versus_Qp_Qs_relationship_in_2D_plane_strain.pdf and +# utils/attenuation/conversion_from_Qkappa_Qmu_to_Qp_Qs_from_Dahlen_Tromp_959_960.f90. +1 1 2700.d0 3000.d0 1732.051d0 0 0 9999 9999 0 0 0 0 0 0 +# 2 1 2500.d0 2700.d0 1443.375d0 0 0 9999 9999 0 0 0 0 0 0 +# 3 1 2200.d0 2500.d0 1443.375d0 0 0 9999 9999 0 0 0 0 0 0 +# 4 1 2200.d0 2200.d0 1343.375d0 0 0 9999 9999 0 0 0 0 0 0 + +# external tomography file +TOMOGRAPHY_FILE = ./DATA/tomo_file.xyz + +# use an external mesh created by an external meshing tool or use the internal mesher +read_external_mesh = .false. + +#----------------------------------------------------------- +# +# PARAMETERS FOR EXTERNAL MESHING +# +#----------------------------------------------------------- + +# data concerning mesh, when generated using third-party app (more info in README) +# (see also absorbing_conditions above) +mesh_file = ./DATA/mesh_file # file containing the mesh +nodes_coords_file = ./DATA/nodes_coords_file # file containing the nodes coordinates +materials_file = ./DATA/materials_file # file containing the material number for each element +free_surface_file = ./DATA/free_surface_file # file containing the free surface +axial_elements_file = ./DATA/axial_elements_file # file containing the axial elements if AXISYM is true +absorbing_surface_file = ./DATA/absorbing_surface_file # file containing the absorbing surface +acoustic_forcing_surface_file = ./DATA/MSH/Surf_acforcing_Bottom_enforcing_mesh # file containing the acoustic forcing surface +absorbing_cpml_file = ./DATA/absorbing_cpml_file # file containing the CPML element numbers +tangential_detection_curve_file = ./DATA/courbe_eros_nodes # file containing the curve delimiting the velocity model + +#----------------------------------------------------------- +# +# PARAMETERS FOR INTERNAL MESHING +# +#----------------------------------------------------------- + +# file containing interfaces for internal mesh +interfacesfile = @CMAKE_SOURCE_DIR@/examples/homogeneous-medium-flat-topography/topography.dat + +# geometry of the model (origin lower-left corner = 0,0) and mesh description +xmin = 0.d0 # abscissa of left side of the model +xmax = 4000.d0 # abscissa of right side of the model +nx = 80 # number of elements along X + +# absorbing boundary parameters (see absorbing_conditions above) +absorbbottom = .false. +absorbright = .false. +absorbtop = .false. +absorbleft = .false. + +# define the different regions of the model in the (nx,nz) spectral-element mesh +nbregions = 1 # then set below the different regions and model number for each region +# format of each line: nxmin nxmax nzmin nzmax material_number +1 80 1 60 1 + +#----------------------------------------------------------- +# +# DISPLAY PARAMETERS +# +#----------------------------------------------------------- + +# meshing output +output_grid_Gnuplot = .false. # generate a GNUPLOT file containing the grid, and a script to plot it +output_grid_ASCII = .false. # dump the grid in an ASCII text file consisting of a set of X,Y,Z points or not diff --git a/docs/examples/homogeneous-medium-flat-topography/README.md b/docs/examples/homogeneous-medium-flat-topography/README.md new file mode 100644 index 00000000..d068c21a --- /dev/null +++ b/docs/examples/homogeneous-medium-flat-topography/README.md @@ -0,0 +1,29 @@ +# Wave propagation through homogeneous medium with no interfaces + +In this example we simulate wave propagation through a 2-dimensional homogeneous medium. + +## Generating the mesh + +To generate the mesh for the homogeneous media we need a parameter file, `Par_File`, a topography file, `topography_file.dat`, and the mesher executible, `xmeshfem2D`, which should have been compiled during the installation process. + +> Currently, we still use a mesher that was developed for the original [SPECFEM2D](https://specfem2d.readthedocs.io/en/latest/03_mesh_generation/) code. More details on the meshing process can be found [here](https://specfem2d.readthedocs.io/en/latest/03_mesh_generation/). + +## Running the mesher + +To execute the mesher run + +``` + ./xmeshfem2D -p +``` + +> Make sure either your are in the build directory of SPECFEM2D kokkos or the build directory is added to your ``PATH``. + +Note the path of the database file and :ref:`stations_file` generated after successfully running the mesher. + +## Running the solver + +Finally, to run the SPECFEM2D kokkos solver + +``` + ./specfem2d -p +``` diff --git a/docs/examples/homogeneous-medium-flat-topography/STATIONS b/docs/examples/homogeneous-medium-flat-topography/STATIONS new file mode 100644 index 00000000..21c6a206 --- /dev/null +++ b/docs/examples/homogeneous-medium-flat-topography/STATIONS @@ -0,0 +1,22 @@ +S0001 AA 300.0000000 3000.0000000 0.0 0.0 +S0002 AA 640.0000000 3000.0000000 0.0 0.0 +S0003 AA 980.0000000 3000.0000000 0.0 0.0 +S0004 AA 1320.0000000 3000.0000000 0.0 0.0 +S0005 AA 1660.0000000 3000.0000000 0.0 0.0 +S0006 AA 2000.0000000 3000.0000000 0.0 0.0 +S0007 AA 2340.0000000 3000.0000000 0.0 0.0 +S0008 AA 2680.0000000 3000.0000000 0.0 0.0 +S0009 AA 3020.0000000 3000.0000000 0.0 0.0 +S0010 AA 3360.0000000 3000.0000000 0.0 0.0 +S0011 AA 3700.0000000 3000.0000000 0.0 0.0 +S0012 AA 2500.0000000 2500.0000000 0.0 0.0 +S0013 AA 2500.0000000 2250.0000000 0.0 0.0 +S0014 AA 2500.0000000 2000.0000000 0.0 0.0 +S0015 AA 2500.0000000 1750.0000000 0.0 0.0 +S0016 AA 2500.0000000 1500.0000000 0.0 0.0 +S0017 AA 2500.0000000 1250.0000000 0.0 0.0 +S0018 AA 2500.0000000 1000.0000000 0.0 0.0 +S0019 AA 2500.0000000 750.0000000 0.0 0.0 +S0020 AA 2500.0000000 500.0000000 0.0 0.0 +S0021 AA 2500.0000000 250.0000000 0.0 0.0 +S0022 AA 2500.0000000 0.0000000 0.0 0.0 diff --git a/docs/examples/homogeneous-medium-flat-topography/source.yaml b/docs/examples/homogeneous-medium-flat-topography/source.yaml new file mode 100644 index 00000000..2a674e3d --- /dev/null +++ b/docs/examples/homogeneous-medium-flat-topography/source.yaml @@ -0,0 +1,13 @@ +number-of-sources: 1 +sources: + - force: + x : 2500.0 + z : 2500.0 + source_surf: false + angle : 0.0 + vx : 0.0 + vz : 0.0 + Ricker: + factor: 1e10 + tshift: 0.0 + f0: 10.0 diff --git a/docs/examples/homogeneous-medium-flat-topography/specfem_config.yaml b/docs/examples/homogeneous-medium-flat-topography/specfem_config.yaml new file mode 100644 index 00000000..975b1765 --- /dev/null +++ b/docs/examples/homogeneous-medium-flat-topography/specfem_config.yaml @@ -0,0 +1,46 @@ +parameters: + + header: + ## Header information is used for logging. It is good practice to give your simulations explicit names + title: Isotropic Elastic simulation # name for your simulation + # A detailed description for your simulation + description: | + Material systems : Elastic domain (1) + Interfaces : None + Sources : Force source (1) + Boundary conditions : Neumann BCs on all edges + + simulation-setup: + ## quadrature setup + quadrature: + quadrature-type: GLL4 + + ## Solver setup + solver: + time-marching: + type-of-simulation: forward + time-scheme: + type: Newmark + dt: 1.1e-3 + nstep: 1600 + + receivers: + stations-file: "/scratch/gpfs/rk9481/specfem2d_kokkos/examples/homogeneous-medium-flat-topography/OUTPUT_FILES/STATIONS" + angle: 0.0 + seismogram-type: + - velocity + nstep_between_samples: 1 + + seismogram: + seismogram-format: ascii + output-folder: "/scratch/gpfs/rk9481/specfem2d_kokkos/results" + + ## Runtime setup + run-setup: + number-of-processors: 1 + number-of-runs: 1 + + ## databases + databases: + mesh-database: "/scratch/gpfs/rk9481/specfem2d_kokkos/examples/homogeneous-medium-flat-topography/OUTPUT_FILES/database.bin" + source-file: "/scratch/gpfs/rk9481/specfem2d_kokkos/examples/homogeneous-medium-flat-topography/source.yaml" diff --git a/docs/examples/homogeneous-medium-flat-topography/specfem_config.yaml.in b/docs/examples/homogeneous-medium-flat-topography/specfem_config.yaml.in new file mode 100644 index 00000000..86ed576f --- /dev/null +++ b/docs/examples/homogeneous-medium-flat-topography/specfem_config.yaml.in @@ -0,0 +1,46 @@ +parameters: + + header: + ## Header information is used for logging. It is good practice to give your simulations explicit names + title: Isotropic Elastic simulation # name for your simulation + # A detailed description for your simulation + description: | + Material systems : Elastic domain (1) + Interfaces : None + Sources : Force source (1) + Boundary conditions : Neumann BCs on all edges + + simulation-setup: + ## quadrature setup + quadrature: + quadrature-type: GLL4 + + ## Solver setup + solver: + time-marching: + type-of-simulation: forward + time-scheme: + type: Newmark + dt: 1.1e-3 + nstep: 1600 + + receivers: + stations-file: "@CMAKE_SOURCE_DIR@/examples/homogeneous-medium-flat-topography/OUTPUT_FILES/STATIONS" + angle: 0.0 + seismogram-type: + - velocity + nstep_between_samples: 1 + + # seismogram: + # seismogram-format: ascii + # output-folder: "/scratch/gpfs/rk9481/specfem2d_kokkos/results" + + ## Runtime setup + run-setup: + number-of-processors: 1 + number-of-runs: 1 + + ## databases + databases: + mesh-database: "@CMAKE_SOURCE_DIR@/examples/homogeneous-medium-flat-topography/OUTPUT_FILES/database.bin" + source-file: "@CMAKE_SOURCE_DIR@/examples/homogeneous-medium-flat-topography/source.yaml" diff --git a/docs/examples/homogeneous-medium-flat-topography/traces.svg b/docs/examples/homogeneous-medium-flat-topography/traces.svg new file mode 100644 index 00000000..54d7fa47 --- /dev/null +++ b/docs/examples/homogeneous-medium-flat-topography/traces.svg @@ -0,0 +1,3456 @@ + + + + + + + + 2023-10-31T13:57:13.974044 + image/svg+xml + + + Matplotlib v3.7.0, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/feature_request/index.rst b/docs/feature_request/index.rst new file mode 100644 index 00000000..69b7c0c7 --- /dev/null +++ b/docs/feature_request/index.rst @@ -0,0 +1,3 @@ + +`Request a new feature `_ +============================================================================================= diff --git a/docs/index.rst b/docs/index.rst index 71b2fced..3238e3e2 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,79 +1,232 @@ -.. C++ Sphinx Doxygen Breathe documentation master file, created by - sphinx-quickstart on Wed Jun 24 11:46:27 2020. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. +SPECFEM++ - A modular and portable spectral-element code for seismic wave propagation +===================================================================================== -SPECFEM Kokkos documentation -============================= +.. admonition:: Community Project -.. toctree:: - :maxdepth: 2 - :caption: Contents: + SPECFEM++ is a community project. We welcome contributions from everyone. Please see :ref:`developer documentation` sections for more details. + +.. admonition:: Under Development + + The package is currently under development and is not yet ready for production use. We are working towards making the package more complete. Please `report any bugs `_ you find or `request features `_ that you would like to see in the package. + +.. admonition:: Monthly Developer Meetings -About SPECFEM2D Kokkos -^^^^^^^^^^^^^^^^^^^^^^ + We host a monthly developer meeting on the first Wednesday of every month at 12:00 PM Eastern Time. Please join us if you are interested in contributing to the project or would like to learn more about the project. Please see `this page `_ for more details. -Introduction -------------- +SPECFEM++ is a complete re-write of SPECFEM suite of packages (SPECFEM2D, SPECFEM3D, SPECFEM3D_GLOBE) using C++. Compared to the earlier version, SPECFEM++ code base provides: -SPECFEM kokkos is C++ implementation of SPECFEM suite of software using the `Kokkos `_ programming model. Kokkos is a is a production level solution for writing modern C++ applications in a hardware agnostic way, this allows us to write a single source code which can run across all modern architectures. The goal of this project is to provide the same level of functionality as provided by SPECFEM2D, SPECFEM3D and SPECFEM3d_GLOBE in a singular package that runs across all architectures. + 1. a robust and flexible code structure, + 2. modularity that allows for easy addition of new features, + 3. portability that allows the code to run on a variety of architectures (CPU, NVIDIA GPUs, Intel GPUs, AMD GPUs etc.), and + 4. a user-friendly build infrastructure that allows the code to be easily compiled and run on a variety of platforms. -Code feature matrix +.. admonition:: Download the code + + The code is available on `GitHub `_. + +Current capabilities -------------------- Table below shows various features available and tested in this package on various architectures: -+---------------------+-------------+-------------+------+-----+ -| | CPU(serial) | CPU(OpenMP) | CUDA | HIP | -+=====================+=============+=============+======+=====+ -| Physics | -+---------------------+-------------+-------------+------+-----+ -| P-SV waves | X | X | X | | -+---------------------+-------------+-------------+------+-----+ -| Elastic Domains | X | X | X | | -+---------------------+-------------+-------------+------+-----+ -| Simulation Setup | -+---------------------+-------------+-------------+------+-----+ -| Forward Simulations | X | X | X | | -+---------------------+-------------+-------------+------+-----+ -| Time Schemes | -+---------------------+-------------+-------------+------+-----+ -| Newmark | X | X | X | | -+---------------------+-------------+-------------+------+-----+ -| Seismograms | -+---------------------+-------------+-------------+------+-----+ -| displacement | X | X | X | | -+---------------------+-------------+-------------+------+-----+ -| velocity | X | X | X | | -+---------------------+-------------+-------------+------+-----+ -| Seimogram Formats | -+---------------------+-------------+-------------+------+-----+ -| ASCII | X | X | X | | -+---------------------+-------------+-------------+------+-----+ +.. list-table:: + :widths: 36 16 16 16 16 + :header-rows: 1 + + * - **Feature** + - **CPU (serial)** + - **CPU (OpenMP)** + - **CUDA** + - **HIP** + + * - **Physics** + - + - + - + - + + * - P-SV waves + - ✔ + - ✔ + - ✔ + - + + * - Elastic Domains + - ✔ + - ✔ + - ✔ + - + + * - Acoustic Domains + - ✔ + - ✔ + - ✔ + - + + * - Acoustic-Elastic coupling + - ✔ + - ✔ + - ✔ + - + + * - **Boundary Conditions** + - + - + - + - + + * - Absorbing Boundary Conditions (Stacey) + - ✔ + - ✔ + - ✔ + - + + * - Free Surface Boundary Conditions + - ✔ + - ✔ + - ✔ + - + + * - **Simulation Setup** + - + - + - + - + + * - Forward Simulations + - ✔ + - ✔ + - ✔ + - + + * - **Time Schemes** + - + - + - + - + + * - Newmark + - ✔ + - ✔ + - ✔ + - + + * - **Seismograms** + - + - + - + - + + * - displacement + - ✔ + - ✔ + - ✔ + - + + * - velocity + - ✔ + - ✔ + - ✔ + - + + * - acceleration + - ✔ + - ✔ + - ✔ + - + + * - **Seimogram Formats** + - + - + - + - + + * - ASCII + - ✔ + - ✔ + - ✔ + - .. note:: While we work towards building this package and making the code/documentation more complete, please refer relevant SPECFEM package documentations for technical details on SPECFEM theory. -Any contributions to this documentation and package are always welcome. Please see :ref:`developer documentation` sections for more details. - - - -Table of Contents -^^^^^^^^^^^^^^^^^ +.. raw:: html + + + +User Documentation +------------------ .. toctree:: - :maxdepth: 2 + :caption: USER DOCUMENTATION + :maxdepth: 1 + :hidden: user_documentation/index + meshfem2d/index parameter_documentation/index source_description/index + +Cookbooks +--------- + +.. toctree:: + :caption: COOKBOOKS + :maxdepth: 1 + :hidden: + cookbooks/index + +Contribution Guidelines +----------------------- + +.. toctree:: + :caption: CONTRIBUTION GUIDELINES + :maxdepth: 1 + :hidden: + developer_documentation/index - api/index -Indices and tables -^^^^^^^^^^^^^^^^^^ +Community +--------- + +.. toctree:: + :caption: COMMUNITY + :maxdepth: 1 + :hidden: + + Report bugs + Request a new feature + Join the discussion + +Benchmarks +---------- -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` +.. toctree:: + :caption: BENCHMARKS + :maxdepth: 1 + :hidden: + + benchmarks/benchmarks.rst + +API Documentation +----------------- + +.. toctree:: + :caption: API DOCUMENTATION + :maxdepth: 1 + :hidden: + + api/index diff --git a/docs/join_the_community/index.rst b/docs/join_the_community/index.rst new file mode 100644 index 00000000..fa548361 --- /dev/null +++ b/docs/join_the_community/index.rst @@ -0,0 +1,3 @@ + +`Join the discussion `_ +==================================================================== diff --git a/docs/meshfem2d/display_parameter.rst b/docs/meshfem2d/display_parameter.rst new file mode 100644 index 00000000..1caee845 --- /dev/null +++ b/docs/meshfem2d/display_parameter.rst @@ -0,0 +1,17 @@ + +Display parameters +================== + +**Parameter Name**: ``output_grid_Gnuplot`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Description**: Output grid as a Gnuplot file + +**Type**: ``logical`` + +**Parameter Name**: ``output_grid_ASCII`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Description**: Output grid as an ASCII file + +**Type**: ``logical`` diff --git a/docs/meshfem2d/external_mesher.rst b/docs/meshfem2d/external_mesher.rst new file mode 100644 index 00000000..f43393e6 --- /dev/null +++ b/docs/meshfem2d/external_mesher.rst @@ -0,0 +1,83 @@ + +External Meshing +================ + +Parameters here describe the paths to different files generated when using an external mesher. + +**Parameter Name**: ``mesh_file`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Description**: Path to the mesh file. + +**Type**: ``path`` + +**Parameter Name**: ``nodes_coords_file`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Description**: Path to the file containing the coordinates of the nodes. + +**Type**: ``path`` + +**Parameter Name**: ``materials_file`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Description**: Path to the file containing the materials number for each element. + +**Type**: ``path`` + +**Parameter Name**: ``free_surface_file`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Description**: Path to the file containing the element number describing the free surface. + +**Type**: ``path`` + +**Parameter Name**: ``axial_elements_file`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + This parameter is not supported in the solver. + +**Description**: Path to the file containing the element number for elements on the axis. + +**Type**: ``path`` + +**Parameter Name**: ``absorbing_surface_file`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + This parameter is not supported in the solver. + +**Description**: Path to the file containing the element number for elements on the absorbing surface. + +**Type**: ``path`` + +**Parameter Name**: ``acoustic_forcing_surface_file`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + This parameter is not supported in the solver. + +**Description**: Path to the file containing the element number for elements on the acoustic forcing surface. + +**Type**: ``path`` + +**Parameter Name**: ``absorbing_cpml_file`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + This parameter is not supported in the solver. + +**Description**: Path to the file containing the element number for elements on the absorbing PML surface. + +**Type**: ``path`` + +**Parameter Name**: ``tangential_detection_curve_file`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + This parameter is not supported in the solver. + +**Description**: Path to the file containing the element number for elements on the tangential curve. + +**Type**: ``path`` diff --git a/docs/meshfem2d/header.rst b/docs/meshfem2d/header.rst new file mode 100644 index 00000000..5664c17a --- /dev/null +++ b/docs/meshfem2d/header.rst @@ -0,0 +1,27 @@ + +Simulation input parameters +=========================== + +**Parameter name**: ``title`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Description**: Title of the simulation + +**Type**: ``string`` + +**Parameter name**: ``NPROC`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + SPECFEM++ currently only supports a single MPI processor. Please set this value to 1. + +**Description**: Number of MPI processors + +**Type**: ``integer`` + +**Parameter name**: ``OUTPUT_FILES`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Description**: Location to store artifacts generated by the mesher + +**Type**: ``Path`` diff --git a/docs/meshfem2d/index.rst b/docs/meshfem2d/index.rst new file mode 100644 index 00000000..338e7321 --- /dev/null +++ b/docs/meshfem2d/index.rst @@ -0,0 +1,71 @@ +.. _MESHFEM_Parameter_documentation: + +MESHFEM Parameter Documentation +=============================== + +SPECFEM++ uses a modified version of the mesher provided by the original `SPECFEM2D `_ code. The modifications isolate only the nacessary parameters for the meshing process and remove those needed by the solver from the original ``Par_File``. Here I will document the parameters that are used by the meshing process. However you should also refer to the `SPECFEM2D documentation `_ for a more in-depth description of the mesher. + +To define the meshing parameters, you will need to create a ``Par_File``. This is a simple text file that contains the parameters you wish to use. The parameters are defined in the following format: + +.. code-block:: bash + + parameter_name = parameter_value + +Parameter Description +--------------------- + +.. toctree:: + + header + meshing_parameters + receivers + velocity_models + internal_mesher + external_mesher + display_parameter + +.. _topography_file: + +Topography File +--------------- + +Topography files are used to define the surface topography of the mesh. The topography file is a simple text file that describes the topography of every interface in the simulation domain. For example the following topography file describes a simple 2 layer model with a flat surface and a flat interface between the two layers: + +.. code-block:: bash + + # + # number of interfaces + # + 3 + # + # for each interface below, we give the number of points and then x,z for each point + # + # + # interface number 1 (bottom of the mesh) + # + 2 + 0 0 + 6400 0 + # + # interface number 2 (ocean bottom) + # + 2 + 0 2400 + 6400 2400 + # + # interface number 3 (topography, top of the mesh) + # + 2 + 0 4800 + 6400 4800 + # + # for each layer, we give the number of spectral elements in the vertical direction + # + # + # layer number 1 (bottom layer) + # + 54 + # + # layer number 2 (top layer) + # + 54 diff --git a/docs/meshfem2d/internal_mesher.rst b/docs/meshfem2d/internal_mesher.rst new file mode 100644 index 00000000..aaa6ad35 --- /dev/null +++ b/docs/meshfem2d/internal_mesher.rst @@ -0,0 +1,92 @@ + +Internal Meshing +================ + +**Parameter Name**: ``interfacesfile`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Description**: The file describing the topography of the simulation domain. For more information, see the :ref:`topography_file` section. + +**Type**: ``path`` + +**Parameter Name**: ``xmin`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Description**: The minimum x-coordinate of the simulation domain. + +**Type**: ``real`` + +**Parameter Name**: ``xmax`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Description**: The maximum x-coordinate of the simulation domain. + +**Type**: ``real`` + +**Parameter Name**: ``nx`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Description**: The number of elements in the x-direction. + +**Type**: ``int`` + +**Parameter Name**: ``absorbbottom`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + Only free surface boundary conditions are currently supported. + +**Description**: If ``True``, the bottom boundary is an absorbing boundary. + +**Type**: ``logical`` + +**Parameter Name**: ``absorbtop`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + Only free surface boundary conditions are currently supported. + +**Description**: If ``True``, the top boundary is an absorbing boundary. + +**Type**: ``logical`` + +**Parameter Name**: ``absorbleft`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + Only free surface boundary conditions are currently supported. + +**Description**: If ``True``, the left boundary is an absorbing boundary. + +**Type**: ``logical`` + +**Parameter Name**: ``absorbright`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + Only free surface boundary conditions are currently supported. + +**Description**: If ``True``, the right boundary is an absorbing boundary. + +**Type**: ``logical`` + +**Parameter Name**: ``nbregions`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Description**: The number of regions in the simulation domain. + +**Type**: ``int`` + +Describing a region +------------------- + +The region is described using a string. + +**string value**: ``nxmin nxmax nzmin nzmax material_number`` + +**Description**: + - ``nxmin``: Integer value describing the x-coordinate of the spectral element at the bottom left corner of the region. + - ``nxmax``: Integer value describing the x-coordinate of the spectral element at the top right corner of the region. + - ``nzmin``: Integer value describing the z-coordinate of the spectral element at the bottom left corner of the region. + - ``nzmax``: Integer value describing the z-coordinate of the spectral element at the top right corner of the region. + - ``material_number``: Integer value describing the type of material in the region. This value references the material number in the :ref:`velocity_model` section. diff --git a/docs/meshfem2d/meshing_parameters.rst b/docs/meshfem2d/meshing_parameters.rst new file mode 100644 index 00000000..cd169bdd --- /dev/null +++ b/docs/meshfem2d/meshing_parameters.rst @@ -0,0 +1,35 @@ + +Meshing Parameters +================== + +**Parameter Name**: ``PARTITIONING_TYPE`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + + This parameter is only used for MPI simulations and is ignored for serial simulations. + +**Description**: The type of mesh partitioning to use for MPI simulations. + - SCOTCH: ``3`` + - METIS: ``2`` + - INTERNAL (Ascending): ``1`` + +**Type**: ``int`` + +**Parameter Name**: ``NGNOD`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Description**: Number of control nodes per element. + +**Type**: ``int`` + - Supported values: `4` or `9` + +**Parameter Name**: ``database_filename`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Description**: Name of the database file to store the generated mesh. + +**Type**: ``string`` + +.. note:: + The database filename needs to be same in meshing and solver parameter files. diff --git a/docs/meshfem2d/receiver_documentation.rst b/docs/meshfem2d/receiver_documentation.rst new file mode 100644 index 00000000..c5dccf99 --- /dev/null +++ b/docs/meshfem2d/receiver_documentation.rst @@ -0,0 +1,88 @@ + +Receiver Parameters +==================== + +**Parameter Name**: ``use_existing_STATIONS`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Description**: If set to ``.true.``, the receivers will be places based on an existing STATIONS file. + +**Type**: ``logical`` + +**Paramter Name**: ``nreceiversets`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Description**: Number of receiver sets. + +**Type**: ``int`` + +**Parameter Name**: ``anglerec`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Description**: Angle to rotate components at receivers + +**Type**: ``real`` + +**Parameter Name**: ``rec_normal_to_surface`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Description**: If set to ``.true.``, the receiver base angle will be set normal to the surface. Requires external mesh and tangential curve file. + +**Type**: ``logical`` + +.. note:: + This paramter is not supported yet in the solver. + +Define receiver sets: +--------------------- + +Next we define each receiver sets using the following parameters: + +**Parameter Name**: ``nrec`` +***************************** + +**Description**: Number of receivers in this set. The receivers will be placed at equal distances. + +**Type**: ``int`` + +**Parameter Name**: ``xdeb`` +***************************** + +**Description**: X coordinate of the first receiver in this set. + +**Type**: ``real`` + +**Parameter Name**: ``zdeb`` +***************************** + +**Description**: Y coordinate of the first receiver in this set. + +**Type**: ``real`` + +**Parameter Name**: ``xfin`` +***************************** + +**Description**: X coordinate of the last receiver in this set. + +**Type**: ``real`` + +**Parameter Name**: ``zfin`` +***************************** + +**Description**: Y coordinate of the last receiver in this set. + +**Type**: ``real`` + +**Parameter Name**: ``record_at_surface_same_vertical`` +****************************************************** + +**Description**: If set to ``.true.``, the receivers will be placed at the surface of the medium. The vertical position of the receivers will be replaces with topography height. + +**Type**: ``logical`` + +**Parameter Name**: ``stations_filename`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Description**: Name of the STATIONS file to use. if ``use_existing_STATIONS`` is set to ``.true.``, this defines a file to read receiver locations from. If ``use_existing_STATIONS`` is set to ``.false.``, this defines a file to write receiver locations to. + +**Type**: ``string`` diff --git a/docs/meshfem2d/velocity_models.rst b/docs/meshfem2d/velocity_models.rst new file mode 100644 index 00000000..534e9921 --- /dev/null +++ b/docs/meshfem2d/velocity_models.rst @@ -0,0 +1,62 @@ + +Velocity Models +================ + +**Parameter Name**: ``nbmodels`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Description**: Number of material systems in the model. + +**Type**: ``int`` + +**Paramter Name**: ``TOPOGRAPHY_FILE`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Description**: Path to an external topography file. + +**Type**: ``string`` + +**Parameter Name**: ``read_external_mesh`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Description**: If ``True`` the mesh is read from an external file. + +**Type**: ``logical`` + +Description of material system +------------------------------ + +Each material system in the model is described by a string. + +.. note:: + Only elastic and acoustic material systems are supported. + +Elastic material system +************************ + +**string value**: ``model_number 1 rho Vp 0 0 0 QKappa 9999 0 0 0 0 0 0`` + +**Description**: + - ``model_number``: integer number to refence the material system + - ``rho``: density + - ``Vp``: P-wave velocity + - ``QKappa``: Attenuation parameter (set to ``9999`` for no attenuation) + +**Example**: + ``1 1 2700.d0 3000.d0 1732.051d0 0 0 9999 9999 0 0 0 0 0 0`` + +Acoustic material system +************************* + +**string value**: ``model_number 1 rho Vp Vs 0 0 QKappa QMu 0 0 0 0 0 0`` + +**Description**: + - ``model_number``: integer number to refence the material system + - ``rho``: density + - ``Vp``: P-wave velocity + - ``Vs``: S-wave velocity + - ``QKappa``: Attenuation parameter (set to ``9999`` for no attenuation) + - ``QMu``: Attenuation parameter (set to ``9999`` for no attenuation) + +**Example**: + ``1 1 2700.d0 3000.d0 1732.051d0 0 0 9999 9999 0 0 0 0 0 0`` diff --git a/docs/output.txt b/docs/output.txt new file mode 100644 index 00000000..a373dc1b --- /dev/null +++ b/docs/output.txt @@ -0,0 +1,2163 @@ +warning: ignoring unsupported tag `CREATE_SUBDIRS_LEVEL =' at line 92, file Doxyfile.in +warning: ignoring unsupported tag `JAVADOC_BANNER =' at line 221, file Doxyfile.in +warning: ignoring unsupported tag `PYTHON_DOCSTRING =' at line 249, file Doxyfile.in +warning: ignoring unsupported tag `OPTIMIZE_OUTPUT_SLICE =' at line 325, file Doxyfile.in +warning: ignoring unsupported tag `NUM_PROC_THREADS =' at line 491, file Doxyfile.in +warning: ignoring unsupported tag `EXTRACT_PRIV_VIRTUAL =' at line 517, file Doxyfile.in +warning: ignoring unsupported tag `RESOLVE_UNNAMED_PARAMS =' at line 561, file Doxyfile.in +warning: ignoring unsupported tag `SHOW_HEADERFILE =' at line 634, file Doxyfile.in +warning: ignoring unsupported tag `WARN_IF_INCOMPLETE_DOC =' at line 852, file Doxyfile.in +warning: ignoring unsupported tag `WARN_LINE_FORMAT =' at line 892, file Doxyfile.in +warning: ignoring unsupported tag `DOCSET_FEEDURL =' at line 1406, file Doxyfile.in +warning: ignoring unsupported tag `FULL_SIDEBAR =' at line 1617, file Doxyfile.in +warning: ignoring unsupported tag `OBFUSCATE_EMAILS =' at line 1648, file Doxyfile.in +warning: ignoring unsupported tag `HTML_FORMULA_FORMAT =' at line 1659, file Doxyfile.in +warning: ignoring unsupported tag `FORMULA_MACROFILE =' at line 1685, file Doxyfile.in +warning: ignoring unsupported tag `MATHJAX_VERSION =' at line 1707, file Doxyfile.in +warning: ignoring unsupported tag `LATEX_MAKEINDEX_CMD =' at line 1896, file Doxyfile.in +warning: ignoring unsupported tag `LATEX_EMOJI_DIRECTORY =' at line 2031, file Doxyfile.in +warning: ignoring unsupported tag `XML_NS_MEMB_FILE_SCOPE =' at line 2165, file Doxyfile.in +warning: ignoring unsupported tag `DOT_UML_DETAILS =' at line 2480, file Doxyfile.in +warning: ignoring unsupported tag `DOT_WRAP_THRESHOLD =' at line 2489, file Doxyfile.in +warning: ignoring unsupported tag `DIR_GRAPH_MAX_DEPTH =' at line 2562, file Doxyfile.in +/scratch/gpfs/rk9481/specfem2d_kokkos/include/compute/compute_receivers.hpp:102: warning: The following parameters of specfem::compute::receivers::receivers(const std::vector< specfem::receivers::receiver * > &receivers, const std::vector< specfem::enums::seismogram::type > &stypes, const specfem::quadrature::quadrature *quadx, const specfem::quadrature::quadrature *quadz, const type_real xmax, const type_real xmin, const type_real zmax, const type_real zmin, const int max_sig_step, specfem::MPI::MPI *mpi) are not documented: + parameter 'xmax' + parameter 'xmin' + parameter 'zmax' + parameter 'zmin' + parameter 'max_sig_step' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/compute/compute_sources.hpp:56: warning: The following parameters of specfem::compute::sources::sources(const std::vector< specfem::sources::source * > &sources, const specfem::quadrature::quadrature *quadx, const specfem::quadrature::quadrature *quadz, const type_real xmax, const type_real xmin, const type_real zmax, const type_real zmin, specfem::MPI::MPI *mpi) are not documented: + parameter 'xmax' + parameter 'xmin' + parameter 'zmax' + parameter 'zmin' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/domain.hpp:143: warning: argument 'seismogram_types' of command @param is not found in the argument list of specfem::domain::domain< medium, qp_type >::compute_seismogram(const int isig_step) +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:51: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:51: warning: Found unknown command `\beta' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:75: warning: The following parameters of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::acoustic, quadrature_points >::compute_gradient(const int &ispec, const int &xz, const ScratchViewType< type_real, 1 > s_hprime_xx, const ScratchViewType< type_real, 1 > s_hprime_zz, const ScratchViewType< type_real, medium::components > field_chi, type_real *dchidxl, type_real *dchidzl) const=0 are not documented: + parameter 'ispec' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:51: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:51: warning: Found unknown command `\beta' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:51: warning: Found unknown command `\sum_' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:51: warning: Found unknown command `\Omega_e' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:51: warning: Found unknown command `\sum_' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:51: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:51: warning: Found unknown command `\beta' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:52: warning: Found unknown command `\omega_' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:52: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:52: warning: Found unknown command `\omega_' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:52: warning: Found unknown command `\beta' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:52: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:52: warning: Found unknown command `\beta' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:61: warning: The following parameters of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::acoustic, quadrature_points >::compute_mass_matrix_component(const int &ispec, const int &xz, type_real *mass_matrix) const=0 are not documented: + parameter 'ispec' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:83: warning: argument 'dchipdzl' of command @param is not found in the argument list of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::acoustic, quadrature_points >::compute_stress(const int &ispec, const int &xz, const type_real *dchidxl, const type_real *dchidzl, type_real *stress_integrand_xi, type_real *stress_integrand_gamma) const=0 +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:104: warning: The following parameters of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::acoustic, quadrature_points >::compute_stress(const int &ispec, const int &xz, const type_real *dchidxl, const type_real *dchidzl, type_real *stress_integrand_xi, type_real *stress_integrand_gamma) const=0 are not documented: + parameter 'ispec' + parameter 'dchidzl' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:115: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:115: warning: Found unknown command `\gamma' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:115: warning: Found unknown command `\rho' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:115: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:115: warning: Found unknown command `\gamma' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:115: warning: Found unknown command `\partial_x' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:115: warning: Found unknown command `\chi' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:115: warning: Found unknown command `\partial_x' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:116: warning: Found unknown command `\xi' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:116: warning: Found unknown command `\partial_z' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:116: warning: Found unknown command `\chi' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:116: warning: Found unknown command `\partial_z' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:116: warning: Found unknown command `\xi' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:109: warning: argument 'field_dot_dot' of command @param is not found in the argument list of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::acoustic, quadrature_points >::update_acceleration(const int &xz, const type_real &wxglll, const type_real &wzglll, const ScratchViewType< type_real, medium::components > stress_integrand_xi, const ScratchViewType< type_real, medium::components > stress_integrand_gamma, const ScratchViewType< type_real, 1 > s_hprimewgll_xx, const ScratchViewType< type_real, 1 > s_hprimewgll_zz, type_real *acceleration) const=0 +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:127: warning: The following parameters of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::acoustic, quadrature_points >::update_acceleration(const int &xz, const type_real &wxglll, const type_real &wzglll, const ScratchViewType< type_real, medium::components > stress_integrand_xi, const ScratchViewType< type_real, medium::components > stress_integrand_gamma, const ScratchViewType< type_real, 1 > s_hprimewgll_xx, const ScratchViewType< type_real, 1 > s_hprimewgll_zz, type_real *acceleration) const=0 are not documented: + parameter 'acceleration' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:80: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:80: warning: Found unknown command `\beta' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:69: warning: argument 'ispec' of command @param is not found in the argument list of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::acoustic, specfem::enums::element::quadrature::static_quadrature_points< NGLL >, specfem::enums::element::property::isotropic >::element(const specfem::compute::partial_derivatives partial_derivatives, const specfem::compute::properties properties) +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:140: warning: argument 'field_dot_dot' of command @param is not found in the argument list of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::acoustic, specfem::enums::element::quadrature::static_quadrature_points< NGLL >, specfem::enums::element::property::isotropic >::compute_acceleration(const int &xz, const type_real &wxglll, const type_real &wzglll, const ScratchViewType< type_real, medium_type::components > stress_integrand_xi, const ScratchViewType< type_real, medium_type::components > stress_integrand_gamma, const ScratchViewType< type_real, 1 > s_hprimewgll_xx, const ScratchViewType< type_real, 1 > s_hprimewgll_zz, type_real *acceleration) const +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:161: warning: The following parameters of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::acoustic, specfem::enums::element::quadrature::static_quadrature_points< NGLL >, specfem::enums::element::property::isotropic >::compute_acceleration(const int &xz, const type_real &wxglll, const type_real &wzglll, const ScratchViewType< type_real, medium_type::components > stress_integrand_xi, const ScratchViewType< type_real, medium_type::components > stress_integrand_gamma, const ScratchViewType< type_real, 1 > s_hprimewgll_xx, const ScratchViewType< type_real, 1 > s_hprimewgll_zz, type_real *acceleration) const are not documented: + parameter 'acceleration' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:106: warning: The following parameters of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::acoustic, specfem::enums::element::quadrature::static_quadrature_points< NGLL >, specfem::enums::element::property::isotropic >::compute_gradient(const int &ispec, const int &xz, const ScratchViewType< type_real, 1 > s_hprime_xx, const ScratchViewType< type_real, 1 > s_hprime_zz, const ScratchViewType< type_real, medium_type::components > field_chi, type_real *dchidxl, type_real *dchidzl) const are not documented: + parameter 'ispec' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:80: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:80: warning: Found unknown command `\beta' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:80: warning: Found unknown command `\sum_' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:80: warning: Found unknown command `\Omega_e' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:80: warning: Found unknown command `\sum_' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:80: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:80: warning: Found unknown command `\beta' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:81: warning: Found unknown command `\omega_' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:81: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:81: warning: Found unknown command `\omega_' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:81: warning: Found unknown command `\beta' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:81: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:81: warning: Found unknown command `\beta' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:90: warning: The following parameters of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::acoustic, specfem::enums::element::quadrature::static_quadrature_points< NGLL >, specfem::enums::element::property::isotropic >::compute_mass_matrix_component(const int &ispec, const int &xz, type_real *mass_matrix) const are not documented: + parameter 'ispec' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:114: warning: argument 'dchipdzl' of command @param is not found in the argument list of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::acoustic, specfem::enums::element::quadrature::static_quadrature_points< NGLL >, specfem::enums::element::property::isotropic >::compute_stress(const int &ispec, const int &xz, const type_real *dchidxl, const type_real *dchidzl, type_real *stress_integrand_xi, type_real *stress_integrand_gamma) const +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:135: warning: The following parameters of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::acoustic, specfem::enums::element::quadrature::static_quadrature_points< NGLL >, specfem::enums::element::property::isotropic >::compute_stress(const int &ispec, const int &xz, const type_real *dchidxl, const type_real *dchidzl, type_real *stress_integrand_xi, type_real *stress_integrand_gamma) const are not documented: + parameter 'ispec' + parameter 'dchidzl' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:53: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:53: warning: Found unknown command `\beta' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:80: warning: The following parameters of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::elastic, qp_type >::compute_gradient(const int &ispec, const int &xz, const ScratchViewType< type_real, 1 > s_hprime_xx, const ScratchViewType< type_real, 1 > s_hprime_zz, const ScratchViewType< type_real, medium_type::components > u, type_real *dudxl, type_real *dudzl) const=0 are not documented: + parameter 'ispec' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:53: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:53: warning: Found unknown command `\beta' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:53: warning: Found unknown command `\sum_' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:53: warning: Found unknown command `\Omega_e' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:53: warning: Found unknown command `\sum_' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:53: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:53: warning: Found unknown command `\beta' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:54: warning: Found unknown command `\omega_' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:54: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:54: warning: Found unknown command `\omega_' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:54: warning: Found unknown command `\beta' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:54: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:54: warning: Found unknown command `\beta' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:63: warning: The following parameters of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::elastic, qp_type >::compute_mass_matrix_component(const int &ispec, const int &xz, type_real *mass_matrix) const=0 are not documented: + parameter 'ispec' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:104: warning: The following parameters of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::elastic, qp_type >::compute_stress(const int &ispec, const int &xz, const type_real *dudxl, const type_real *dudzl, type_real *stress_integrand_xi, type_real *stress_integrand_gamma) const=0 are not documented: + parameter 'ispec' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:109: warning: argument 'stress_integrand_1' of command @param is not found in the argument list of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::elastic, qp_type >::update_acceleration(const int &xz, const type_real &wxglll, const type_real &wzglll, const ScratchViewType< type_real, medium_type::components > stress_integrand_xi, const ScratchViewType< type_real, medium_type::components > stress_integrand_gamma, const ScratchViewType< type_real, 1 > s_hprimewgll_xx, const ScratchViewType< type_real, 1 > s_hprimewgll_zz, type_real *acceleration) const=0 +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:109: warning: argument 'stress_integrand_2' of command @param is not found in the argument list of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::elastic, qp_type >::update_acceleration(const int &xz, const type_real &wxglll, const type_real &wzglll, const ScratchViewType< type_real, medium_type::components > stress_integrand_xi, const ScratchViewType< type_real, medium_type::components > stress_integrand_gamma, const ScratchViewType< type_real, 1 > s_hprimewgll_xx, const ScratchViewType< type_real, 1 > s_hprimewgll_zz, type_real *acceleration) const=0 +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:109: warning: argument 'field_dot_dot' of command @param is not found in the argument list of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::elastic, qp_type >::update_acceleration(const int &xz, const type_real &wxglll, const type_real &wzglll, const ScratchViewType< type_real, medium_type::components > stress_integrand_xi, const ScratchViewType< type_real, medium_type::components > stress_integrand_gamma, const ScratchViewType< type_real, 1 > s_hprimewgll_xx, const ScratchViewType< type_real, 1 > s_hprimewgll_zz, type_real *acceleration) const=0 +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:127: warning: The following parameters of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::elastic, qp_type >::update_acceleration(const int &xz, const type_real &wxglll, const type_real &wzglll, const ScratchViewType< type_real, medium_type::components > stress_integrand_xi, const ScratchViewType< type_real, medium_type::components > stress_integrand_gamma, const ScratchViewType< type_real, 1 > s_hprimewgll_xx, const ScratchViewType< type_real, 1 > s_hprimewgll_zz, type_real *acceleration) const=0 are not documented: + parameter 'stress_integrand_xi' + parameter 'stress_integrand_gamma' + parameter 'acceleration' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d_isotropic.hpp:84: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d_isotropic.hpp:84: warning: Found unknown command `\beta' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d_isotropic.hpp:145: warning: argument 'field_dot_dot' of command @param is not found in the argument list of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::elastic, specfem::enums::element::quadrature::static_quadrature_points< NGLL >, specfem::enums::element::property::isotropic >::compute_acceleration(const int &xz, const type_real &wxglll, const type_real &wzglll, const ScratchViewType< type_real, medium_type::components > stress_integrand_xi, const ScratchViewType< type_real, medium_type::components > stress_integrand_gamma, const ScratchViewType< type_real, 1 > s_hprimewgll_xx, const ScratchViewType< type_real, 1 > s_hprimewgll_zz, type_real *acceleration) const +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d_isotropic.hpp:163: warning: The following parameters of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::elastic, specfem::enums::element::quadrature::static_quadrature_points< NGLL >, specfem::enums::element::property::isotropic >::compute_acceleration(const int &xz, const type_real &wxglll, const type_real &wzglll, const ScratchViewType< type_real, medium_type::components > stress_integrand_xi, const ScratchViewType< type_real, medium_type::components > stress_integrand_gamma, const ScratchViewType< type_real, 1 > s_hprimewgll_xx, const ScratchViewType< type_real, 1 > s_hprimewgll_zz, type_real *acceleration) const are not documented: + parameter 'acceleration' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d_isotropic.hpp:84: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d_isotropic.hpp:84: warning: Found unknown command `\beta' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d_isotropic.hpp:84: warning: Found unknown command `\sum_' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d_isotropic.hpp:84: warning: Found unknown command `\Omega_e' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d_isotropic.hpp:84: warning: Found unknown command `\sum_' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d_isotropic.hpp:84: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d_isotropic.hpp:84: warning: Found unknown command `\beta' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d_isotropic.hpp:85: warning: Found unknown command `\omega_' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d_isotropic.hpp:85: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d_isotropic.hpp:85: warning: Found unknown command `\omega_' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d_isotropic.hpp:85: warning: Found unknown command `\beta' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d_isotropic.hpp:85: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d_isotropic.hpp:85: warning: Found unknown command `\beta' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/receivers/elastic/elastic2d_isotropic.hpp:85: warning: argument 'siesmogram_type' of command @param is not found in the argument list of specfem::domain::impl::receivers::receiver< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::elastic, specfem::enums::element::quadrature::static_quadrature_points< NGLL >, specfem::enums::element::property::isotropic >::get_field(const int &ireceiver, const int &iseis, const int &ispec, const specfem::enums::seismogram::type &seismogram_type, const int &xz, const int &isig_step, const ScratchViewType< type_real, medium_type::components > field, const ScratchViewType< type_real, medium_type::components > field_dot, const ScratchViewType< type_real, medium_type::components > field_dot_dot, const ScratchViewType< type_real, 1 > s_hprime_xx, const ScratchViewType< type_real, 1 > s_hprime_zz) const +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/receivers/elastic/elastic2d_isotropic.hpp:85: warning: argument 'hprime_xx' of command @param is not found in the argument list of specfem::domain::impl::receivers::receiver< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::elastic, specfem::enums::element::quadrature::static_quadrature_points< NGLL >, specfem::enums::element::property::isotropic >::get_field(const int &ireceiver, const int &iseis, const int &ispec, const specfem::enums::seismogram::type &seismogram_type, const int &xz, const int &isig_step, const ScratchViewType< type_real, medium_type::components > field, const ScratchViewType< type_real, medium_type::components > field_dot, const ScratchViewType< type_real, medium_type::components > field_dot_dot, const ScratchViewType< type_real, 1 > s_hprime_xx, const ScratchViewType< type_real, 1 > s_hprime_zz) const +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/receivers/elastic/elastic2d_isotropic.hpp:85: warning: argument 'hprime_zz' of command @param is not found in the argument list of specfem::domain::impl::receivers::receiver< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::elastic, specfem::enums::element::quadrature::static_quadrature_points< NGLL >, specfem::enums::element::property::isotropic >::get_field(const int &ireceiver, const int &iseis, const int &ispec, const specfem::enums::seismogram::type &seismogram_type, const int &xz, const int &isig_step, const ScratchViewType< type_real, medium_type::components > field, const ScratchViewType< type_real, medium_type::components > field_dot, const ScratchViewType< type_real, medium_type::components > field_dot_dot, const ScratchViewType< type_real, 1 > s_hprime_xx, const ScratchViewType< type_real, 1 > s_hprime_zz) const +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/receivers/elastic/elastic2d_isotropic.hpp:101: warning: The following parameters of specfem::domain::impl::receivers::receiver< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::elastic, specfem::enums::element::quadrature::static_quadrature_points< NGLL >, specfem::enums::element::property::isotropic >::get_field(const int &ireceiver, const int &iseis, const int &ispec, const specfem::enums::seismogram::type &seismogram_type, const int &xz, const int &isig_step, const ScratchViewType< type_real, medium_type::components > field, const ScratchViewType< type_real, medium_type::components > field_dot, const ScratchViewType< type_real, medium_type::components > field_dot_dot, const ScratchViewType< type_real, 1 > s_hprime_xx, const ScratchViewType< type_real, 1 > s_hprime_zz) const are not documented: + parameter 'seismogram_type' + parameter 's_hprime_xx' + parameter 's_hprime_zz' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/sources/elastic/elastic2d_isotropic.hpp:70: warning: The following parameters of specfem::domain::impl::sources::source< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::elastic, specfem::enums::element::quadrature::static_quadrature_points< NGLL >, specfem::enums::element::property::isotropic >::source(const specfem::compute::properties &properties, specfem::kokkos::DeviceView4d< type_real > source_array) are not documented: + parameter 'properties' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/jacobian/jacobian.hpp:220: warning: argument 'teamMember' of command @param is not found in the argument list of specfem::jacobian::compute_inverted_derivatives(const specfem::kokkos::HostView2d< type_real > s_coorg, const int ngnod, const type_real xi, const type_real gamma) +/scratch/gpfs/rk9481/specfem2d_kokkos/include/jacobian/jacobian.hpp:159: warning: The following parameters of specfem::jacobian::compute_jacobian(const specfem::kokkos::HostTeam::member_type &teamMember, const specfem::kokkos::HostScratchView2d< type_real > s_coorg, const int ngnod, const type_real xi, const type_real gamma) are not documented: + parameter 'teamMember' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/jacobian/jacobian.hpp:174: warning: The following parameters of specfem::jacobian::compute_jacobian(const specfem::kokkos::HostTeam::member_type &teamMember, const specfem::kokkos::HostScratchView2d< type_real > s_coorg, const int ngnod, const specfem::kokkos::HostView2d< type_real > dershape2D) are not documented: + parameter 'teamMember' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/jacobian/jacobian.hpp:65: warning: argument 'coorg' of command @param is not found in the argument list of specfem::jacobian::compute_locations(const specfem::kokkos::HostView2d< type_real > s_coorg, const int ngnod, const specfem::kokkos::HostView1d< type_real > shape2D) +/scratch/gpfs/rk9481/specfem2d_kokkos/include/jacobian/jacobian.hpp:74: warning: The following parameters of specfem::jacobian::compute_locations(const specfem::kokkos::HostView2d< type_real > s_coorg, const int ngnod, const specfem::kokkos::HostView1d< type_real > shape2D) are not documented: + parameter 's_coorg' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/jacobian/jacobian.hpp:119: warning: argument 'teamMember' of command @param is not found in the argument list of specfem::jacobian::compute_partial_derivatives(const specfem::kokkos::HostView2d< type_real > s_coorg, const int ngnod, const type_real xi, const type_real gamma) +/scratch/gpfs/rk9481/specfem2d_kokkos/include/kokkos_abstractions.h:574: warning: Unsupported xml/html tag found +/scratch/gpfs/rk9481/specfem2d_kokkos/include/kokkos_abstractions.h:574: warning: Unsupported xml/html tag found +/scratch/gpfs/rk9481/specfem2d_kokkos/include/mesh/mesh.hpp:82: warning: The following parameters of specfem::mesh::mesh::mesh(const std::string filename, std::vector< specfem::material::material * > &materials, const specfem::MPI::MPI *mpi) are not documented: + parameter 'materials' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/specfem_mpi/specfem_mpi.hpp:212: warning: The following parameters of specfem::MPI::MPI::bcast(int &val, int root) const are not documented: + parameter 'root' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/specfem_mpi/specfem_mpi.hpp:218: warning: The following parameters of specfem::MPI::MPI::bcast(float &val, int root) const are not documented: + parameter 'root' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/specfem_mpi/specfem_mpi.hpp:224: warning: The following parameters of specfem::MPI::MPI::bcast(double &val, int root) const are not documented: + parameter 'root' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/quadrature/quadrature.hpp:23: warning: argument 'alpha' of command @param is not found in the argument list of specfem::quadrature::quadrature::get_xi() const +/scratch/gpfs/rk9481/specfem2d_kokkos/include/quadrature/quadrature.hpp:23: warning: argument 'beta' of command @param is not found in the argument list of specfem::quadrature::quadrature::get_xi() const +/scratch/gpfs/rk9481/specfem2d_kokkos/include/parameter_parser/seismogram.hpp:48: warning: The following parameters of specfem::runtime_configuration::seismogram::instantiate_seismogram_writer(std::vector< specfem::receivers::receiver * > &receivers, specfem::compute::receivers *compute_receivers, const type_real dt, const type_real t0, const int nsteps_between_samples) const are not documented: + parameter 'nsteps_between_samples' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/solver/time_marching.hpp:33: warning: The following parameters of specfem::solver::time_marching::time_marching(specfem::domain::domain< specfem::enums::element::medium::acoustic, qp_type > &acoustic_domain, specfem::domain::domain< specfem::enums::element::medium::elastic, qp_type > &elastic_domain, specfem::coupled_interface::coupled_interface< specfem::domain::domain< specfem::enums::element::medium::acoustic, qp_type >, specfem::domain::domain< specfem::enums::element::medium::elastic, qp_type > > &acoustic_elastic_interface, specfem::coupled_interface::coupled_interface< specfem::domain::domain< specfem::enums::element::medium::elastic, qp_type >, specfem::domain::domain< specfem::enums::element::medium::acoustic, qp_type > > &elastic_acoustic_interface, specfem::TimeScheme::TimeScheme *it) are not documented: + parameter 'acoustic_elastic_interface' + parameter 'elastic_acoustic_interface' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/source/force_source.hpp:25: warning: argument 'force_source' of command @param is not found in the argument list of specfem::sources::force::force(YAML::Node &Node, const type_real dt) +/scratch/gpfs/rk9481/specfem2d_kokkos/include/source/force_source.hpp:31: warning: The following parameters of specfem::sources::force::force(YAML::Node &Node, const type_real dt) are not documented: + parameter 'Node' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/source/moment_tensor_source.hpp:26: warning: argument 'moment_tensor' of command @param is not found in the argument list of specfem::sources::moment_tensor::moment_tensor(YAML::Node &Node, const type_real dt) +/scratch/gpfs/rk9481/specfem2d_kokkos/include/source/moment_tensor_source.hpp:31: warning: The following parameters of specfem::sources::moment_tensor::moment_tensor(YAML::Node &Node, const type_real dt) are not documented: + parameter 'Node' + parameter 'dt' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/timescheme/newmark.hpp:25: warning: The following parameters of specfem::TimeScheme::Newmark::Newmark(const int nstep, const type_real t0, const type_real dt, const int nstep_between_samples) are not documented: + parameter 'nstep_between_samples' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/timescheme/newmark.hpp:74: warning: argument 'domain_class' of command @param is not found in the argument list of specfem::TimeScheme::Newmark::apply_corrector_phase(specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot_dot) +/scratch/gpfs/rk9481/specfem2d_kokkos/include/timescheme/newmark.hpp:78: warning: The following parameters of specfem::TimeScheme::Newmark::apply_corrector_phase(specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot_dot) are not documented: + parameter 'field' + parameter 'field_dot' + parameter 'field_dot_dot' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/timescheme/newmark.hpp:64: warning: argument 'domain_class' of command @param is not found in the argument list of specfem::TimeScheme::Newmark::apply_predictor_phase(specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot_dot) +/scratch/gpfs/rk9481/specfem2d_kokkos/include/timescheme/newmark.hpp:68: warning: The following parameters of specfem::TimeScheme::Newmark::apply_predictor_phase(specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot_dot) are not documented: + parameter 'field' + parameter 'field_dot' + parameter 'field_dot_dot' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/timescheme/timescheme.hpp:63: warning: argument 'domain_class' of command @param is not found in the argument list of specfem::TimeScheme::TimeScheme::apply_corrector_phase(specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot_dot) +/scratch/gpfs/rk9481/specfem2d_kokkos/include/timescheme/timescheme.hpp:67: warning: The following parameters of specfem::TimeScheme::TimeScheme::apply_corrector_phase(specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot_dot) are not documented: + parameter 'field' + parameter 'field_dot' + parameter 'field_dot_dot' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/timescheme/timescheme.hpp:53: warning: argument 'domain_class' of command @param is not found in the argument list of specfem::TimeScheme::TimeScheme::apply_predictor_phase(specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot_dot) +/scratch/gpfs/rk9481/specfem2d_kokkos/include/timescheme/timescheme.hpp:57: warning: The following parameters of specfem::TimeScheme::TimeScheme::apply_predictor_phase(specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot_dot) are not documented: + parameter 'field' + parameter 'field_dot' + parameter 'field_dot_dot' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/domain.hpp:143: warning: argument 'seismogram_types' of command @param is not found in the argument list of specfem::domain::domain< medium, qp_type >::compute_seismogram(const int isig_step) +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:51: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:51: warning: Found unknown command `\beta' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:51: warning: Found unknown command `\sum_' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:51: warning: Found unknown command `\Omega_e' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:51: warning: Found unknown command `\sum_' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:51: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:51: warning: Found unknown command `\beta' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:52: warning: Found unknown command `\omega_' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:52: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:52: warning: Found unknown command `\omega_' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:52: warning: Found unknown command `\beta' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:52: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:52: warning: Found unknown command `\beta' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:61: warning: The following parameters of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::acoustic, quadrature_points >::compute_mass_matrix_component(const int &ispec, const int &xz, type_real *mass_matrix) const=0 are not documented: + parameter 'ispec' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:75: warning: The following parameters of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::acoustic, quadrature_points >::compute_gradient(const int &ispec, const int &xz, const ScratchViewType< type_real, 1 > s_hprime_xx, const ScratchViewType< type_real, 1 > s_hprime_zz, const ScratchViewType< type_real, medium::components > field_chi, type_real *dchidxl, type_real *dchidzl) const=0 are not documented: + parameter 'ispec' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:83: warning: argument 'dchipdzl' of command @param is not found in the argument list of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::acoustic, quadrature_points >::compute_stress(const int &ispec, const int &xz, const type_real *dchidxl, const type_real *dchidzl, type_real *stress_integrand_xi, type_real *stress_integrand_gamma) const=0 +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:104: warning: The following parameters of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::acoustic, quadrature_points >::compute_stress(const int &ispec, const int &xz, const type_real *dchidxl, const type_real *dchidzl, type_real *stress_integrand_xi, type_real *stress_integrand_gamma) const=0 are not documented: + parameter 'ispec' + parameter 'dchidzl' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:115: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:115: warning: Found unknown command `\gamma' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:115: warning: Found unknown command `\rho' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:115: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:115: warning: Found unknown command `\gamma' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:115: warning: Found unknown command `\partial_x' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:115: warning: Found unknown command `\chi' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:115: warning: Found unknown command `\partial_x' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:116: warning: Found unknown command `\xi' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:116: warning: Found unknown command `\partial_z' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:116: warning: Found unknown command `\chi' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:116: warning: Found unknown command `\partial_z' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:116: warning: Found unknown command `\xi' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:109: warning: argument 'field_dot_dot' of command @param is not found in the argument list of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::acoustic, quadrature_points >::update_acceleration(const int &xz, const type_real &wxglll, const type_real &wzglll, const ScratchViewType< type_real, medium::components > stress_integrand_xi, const ScratchViewType< type_real, medium::components > stress_integrand_gamma, const ScratchViewType< type_real, 1 > s_hprimewgll_xx, const ScratchViewType< type_real, 1 > s_hprimewgll_zz, type_real *acceleration) const=0 +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d.hpp:127: warning: The following parameters of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::acoustic, quadrature_points >::update_acceleration(const int &xz, const type_real &wxglll, const type_real &wzglll, const ScratchViewType< type_real, medium::components > stress_integrand_xi, const ScratchViewType< type_real, medium::components > stress_integrand_gamma, const ScratchViewType< type_real, 1 > s_hprimewgll_xx, const ScratchViewType< type_real, 1 > s_hprimewgll_zz, type_real *acceleration) const=0 are not documented: + parameter 'acceleration' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:69: warning: argument 'ispec' of command @param is not found in the argument list of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::acoustic, specfem::enums::element::quadrature::static_quadrature_points< NGLL >, specfem::enums::element::property::isotropic >::element(const specfem::compute::partial_derivatives partial_derivatives, const specfem::compute::properties properties) +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:80: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:80: warning: Found unknown command `\beta' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:80: warning: Found unknown command `\sum_' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:80: warning: Found unknown command `\Omega_e' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:80: warning: Found unknown command `\sum_' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:80: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:80: warning: Found unknown command `\beta' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:81: warning: Found unknown command `\omega_' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:81: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:81: warning: Found unknown command `\omega_' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:81: warning: Found unknown command `\beta' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:81: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:81: warning: Found unknown command `\beta' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:90: warning: The following parameters of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::acoustic, specfem::enums::element::quadrature::static_quadrature_points< NGLL >, specfem::enums::element::property::isotropic >::compute_mass_matrix_component(const int &ispec, const int &xz, type_real *mass_matrix) const are not documented: + parameter 'ispec' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:106: warning: The following parameters of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::acoustic, specfem::enums::element::quadrature::static_quadrature_points< NGLL >, specfem::enums::element::property::isotropic >::compute_gradient(const int &ispec, const int &xz, const ScratchViewType< type_real, 1 > s_hprime_xx, const ScratchViewType< type_real, 1 > s_hprime_zz, const ScratchViewType< type_real, medium_type::components > field_chi, type_real *dchidxl, type_real *dchidzl) const are not documented: + parameter 'ispec' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:114: warning: argument 'dchipdzl' of command @param is not found in the argument list of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::acoustic, specfem::enums::element::quadrature::static_quadrature_points< NGLL >, specfem::enums::element::property::isotropic >::compute_stress(const int &ispec, const int &xz, const type_real *dchidxl, const type_real *dchidzl, type_real *stress_integrand_xi, type_real *stress_integrand_gamma) const +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:135: warning: The following parameters of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::acoustic, specfem::enums::element::quadrature::static_quadrature_points< NGLL >, specfem::enums::element::property::isotropic >::compute_stress(const int &ispec, const int &xz, const type_real *dchidxl, const type_real *dchidzl, type_real *stress_integrand_xi, type_real *stress_integrand_gamma) const are not documented: + parameter 'ispec' + parameter 'dchidzl' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:140: warning: argument 'field_dot_dot' of command @param is not found in the argument list of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::acoustic, specfem::enums::element::quadrature::static_quadrature_points< NGLL >, specfem::enums::element::property::isotropic >::compute_acceleration(const int &xz, const type_real &wxglll, const type_real &wzglll, const ScratchViewType< type_real, medium_type::components > stress_integrand_xi, const ScratchViewType< type_real, medium_type::components > stress_integrand_gamma, const ScratchViewType< type_real, 1 > s_hprimewgll_xx, const ScratchViewType< type_real, 1 > s_hprimewgll_zz, type_real *acceleration) const +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp:161: warning: The following parameters of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::acoustic, specfem::enums::element::quadrature::static_quadrature_points< NGLL >, specfem::enums::element::property::isotropic >::compute_acceleration(const int &xz, const type_real &wxglll, const type_real &wzglll, const ScratchViewType< type_real, medium_type::components > stress_integrand_xi, const ScratchViewType< type_real, medium_type::components > stress_integrand_gamma, const ScratchViewType< type_real, 1 > s_hprimewgll_xx, const ScratchViewType< type_real, 1 > s_hprimewgll_zz, type_real *acceleration) const are not documented: + parameter 'acceleration' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:53: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:53: warning: Found unknown command `\beta' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:53: warning: Found unknown command `\sum_' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:53: warning: Found unknown command `\Omega_e' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:53: warning: Found unknown command `\sum_' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:53: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:53: warning: Found unknown command `\beta' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:54: warning: Found unknown command `\omega_' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:54: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:54: warning: Found unknown command `\omega_' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:54: warning: Found unknown command `\beta' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:54: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:54: warning: Found unknown command `\beta' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:63: warning: The following parameters of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::elastic, qp_type >::compute_mass_matrix_component(const int &ispec, const int &xz, type_real *mass_matrix) const=0 are not documented: + parameter 'ispec' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:80: warning: The following parameters of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::elastic, qp_type >::compute_gradient(const int &ispec, const int &xz, const ScratchViewType< type_real, 1 > s_hprime_xx, const ScratchViewType< type_real, 1 > s_hprime_zz, const ScratchViewType< type_real, medium_type::components > u, type_real *dudxl, type_real *dudzl) const=0 are not documented: + parameter 'ispec' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:104: warning: The following parameters of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::elastic, qp_type >::compute_stress(const int &ispec, const int &xz, const type_real *dudxl, const type_real *dudzl, type_real *stress_integrand_xi, type_real *stress_integrand_gamma) const=0 are not documented: + parameter 'ispec' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:109: warning: argument 'stress_integrand_1' of command @param is not found in the argument list of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::elastic, qp_type >::update_acceleration(const int &xz, const type_real &wxglll, const type_real &wzglll, const ScratchViewType< type_real, medium_type::components > stress_integrand_xi, const ScratchViewType< type_real, medium_type::components > stress_integrand_gamma, const ScratchViewType< type_real, 1 > s_hprimewgll_xx, const ScratchViewType< type_real, 1 > s_hprimewgll_zz, type_real *acceleration) const=0 +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:109: warning: argument 'stress_integrand_2' of command @param is not found in the argument list of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::elastic, qp_type >::update_acceleration(const int &xz, const type_real &wxglll, const type_real &wzglll, const ScratchViewType< type_real, medium_type::components > stress_integrand_xi, const ScratchViewType< type_real, medium_type::components > stress_integrand_gamma, const ScratchViewType< type_real, 1 > s_hprimewgll_xx, const ScratchViewType< type_real, 1 > s_hprimewgll_zz, type_real *acceleration) const=0 +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:109: warning: argument 'field_dot_dot' of command @param is not found in the argument list of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::elastic, qp_type >::update_acceleration(const int &xz, const type_real &wxglll, const type_real &wzglll, const ScratchViewType< type_real, medium_type::components > stress_integrand_xi, const ScratchViewType< type_real, medium_type::components > stress_integrand_gamma, const ScratchViewType< type_real, 1 > s_hprimewgll_xx, const ScratchViewType< type_real, 1 > s_hprimewgll_zz, type_real *acceleration) const=0 +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d.hpp:127: warning: The following parameters of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::elastic, qp_type >::update_acceleration(const int &xz, const type_real &wxglll, const type_real &wzglll, const ScratchViewType< type_real, medium_type::components > stress_integrand_xi, const ScratchViewType< type_real, medium_type::components > stress_integrand_gamma, const ScratchViewType< type_real, 1 > s_hprimewgll_xx, const ScratchViewType< type_real, 1 > s_hprimewgll_zz, type_real *acceleration) const=0 are not documented: + parameter 'stress_integrand_xi' + parameter 'stress_integrand_gamma' + parameter 'acceleration' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d_isotropic.hpp:84: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d_isotropic.hpp:84: warning: Found unknown command `\beta' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d_isotropic.hpp:84: warning: Found unknown command `\sum_' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d_isotropic.hpp:84: warning: Found unknown command `\Omega_e' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d_isotropic.hpp:84: warning: Found unknown command `\sum_' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d_isotropic.hpp:84: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d_isotropic.hpp:84: warning: Found unknown command `\beta' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d_isotropic.hpp:85: warning: Found unknown command `\omega_' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d_isotropic.hpp:85: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d_isotropic.hpp:85: warning: Found unknown command `\omega_' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d_isotropic.hpp:85: warning: Found unknown command `\beta' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d_isotropic.hpp:85: warning: Found unknown command `\alpha' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d_isotropic.hpp:85: warning: Found unknown command `\beta' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d_isotropic.hpp:145: warning: argument 'field_dot_dot' of command @param is not found in the argument list of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::elastic, specfem::enums::element::quadrature::static_quadrature_points< NGLL >, specfem::enums::element::property::isotropic >::compute_acceleration(const int &xz, const type_real &wxglll, const type_real &wzglll, const ScratchViewType< type_real, medium_type::components > stress_integrand_xi, const ScratchViewType< type_real, medium_type::components > stress_integrand_gamma, const ScratchViewType< type_real, 1 > s_hprimewgll_xx, const ScratchViewType< type_real, 1 > s_hprimewgll_zz, type_real *acceleration) const +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/elements/elastic/elastic2d_isotropic.hpp:163: warning: The following parameters of specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::elastic, specfem::enums::element::quadrature::static_quadrature_points< NGLL >, specfem::enums::element::property::isotropic >::compute_acceleration(const int &xz, const type_real &wxglll, const type_real &wzglll, const ScratchViewType< type_real, medium_type::components > stress_integrand_xi, const ScratchViewType< type_real, medium_type::components > stress_integrand_gamma, const ScratchViewType< type_real, 1 > s_hprimewgll_xx, const ScratchViewType< type_real, 1 > s_hprimewgll_zz, type_real *acceleration) const are not documented: + parameter 'acceleration' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/source/force_source.hpp:25: warning: argument 'force_source' of command @param is not found in the argument list of specfem::sources::force::force(YAML::Node &Node, const type_real dt) +/scratch/gpfs/rk9481/specfem2d_kokkos/include/source/force_source.hpp:31: warning: The following parameters of specfem::sources::force::force(YAML::Node &Node, const type_real dt) are not documented: + parameter 'Node' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/mesh/mesh.hpp:82: warning: The following parameters of specfem::mesh::mesh::mesh(const std::string filename, std::vector< specfem::material::material * > &materials, const specfem::MPI::MPI *mpi) are not documented: + parameter 'materials' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/source/moment_tensor_source.hpp:26: warning: argument 'moment_tensor' of command @param is not found in the argument list of specfem::sources::moment_tensor::moment_tensor(YAML::Node &Node, const type_real dt) +/scratch/gpfs/rk9481/specfem2d_kokkos/include/source/moment_tensor_source.hpp:31: warning: The following parameters of specfem::sources::moment_tensor::moment_tensor(YAML::Node &Node, const type_real dt) are not documented: + parameter 'Node' + parameter 'dt' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/specfem_mpi/specfem_mpi.hpp:212: warning: The following parameters of specfem::MPI::MPI::bcast(int &val, int root) const are not documented: + parameter 'root' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/specfem_mpi/specfem_mpi.hpp:218: warning: The following parameters of specfem::MPI::MPI::bcast(float &val, int root) const are not documented: + parameter 'root' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/specfem_mpi/specfem_mpi.hpp:224: warning: The following parameters of specfem::MPI::MPI::bcast(double &val, int root) const are not documented: + parameter 'root' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/timescheme/newmark.hpp:25: warning: The following parameters of specfem::TimeScheme::Newmark::Newmark(const int nstep, const type_real t0, const type_real dt, const int nstep_between_samples) are not documented: + parameter 'nstep_between_samples' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/timescheme/newmark.hpp:64: warning: argument 'domain_class' of command @param is not found in the argument list of specfem::TimeScheme::Newmark::apply_predictor_phase(specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot_dot) +/scratch/gpfs/rk9481/specfem2d_kokkos/include/timescheme/newmark.hpp:68: warning: The following parameters of specfem::TimeScheme::Newmark::apply_predictor_phase(specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot_dot) are not documented: + parameter 'field' + parameter 'field_dot' + parameter 'field_dot_dot' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/timescheme/newmark.hpp:74: warning: argument 'domain_class' of command @param is not found in the argument list of specfem::TimeScheme::Newmark::apply_corrector_phase(specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot_dot) +/scratch/gpfs/rk9481/specfem2d_kokkos/include/timescheme/newmark.hpp:78: warning: The following parameters of specfem::TimeScheme::Newmark::apply_corrector_phase(specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot_dot) are not documented: + parameter 'field' + parameter 'field_dot' + parameter 'field_dot_dot' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/quadrature/quadrature.hpp:23: warning: argument 'alpha' of command @param is not found in the argument list of specfem::quadrature::quadrature::get_xi() const +/scratch/gpfs/rk9481/specfem2d_kokkos/include/quadrature/quadrature.hpp:23: warning: argument 'beta' of command @param is not found in the argument list of specfem::quadrature::quadrature::get_xi() const +/scratch/gpfs/rk9481/specfem2d_kokkos/include/receiver/receiver.hpp:133: warning: Found unknown command `\xi' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/receiver/receiver.hpp:134: warning: Found unknown command `\gamma' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/receivers/elastic/elastic2d_isotropic.hpp:85: warning: argument 'siesmogram_type' of command @param is not found in the argument list of specfem::domain::impl::receivers::receiver< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::elastic, specfem::enums::element::quadrature::static_quadrature_points< NGLL >, specfem::enums::element::property::isotropic >::get_field(const int &ireceiver, const int &iseis, const int &ispec, const specfem::enums::seismogram::type &seismogram_type, const int &xz, const int &isig_step, const ScratchViewType< type_real, medium_type::components > field, const ScratchViewType< type_real, medium_type::components > field_dot, const ScratchViewType< type_real, medium_type::components > field_dot_dot, const ScratchViewType< type_real, 1 > s_hprime_xx, const ScratchViewType< type_real, 1 > s_hprime_zz) const +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/receivers/elastic/elastic2d_isotropic.hpp:85: warning: argument 'hprime_xx' of command @param is not found in the argument list of specfem::domain::impl::receivers::receiver< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::elastic, specfem::enums::element::quadrature::static_quadrature_points< NGLL >, specfem::enums::element::property::isotropic >::get_field(const int &ireceiver, const int &iseis, const int &ispec, const specfem::enums::seismogram::type &seismogram_type, const int &xz, const int &isig_step, const ScratchViewType< type_real, medium_type::components > field, const ScratchViewType< type_real, medium_type::components > field_dot, const ScratchViewType< type_real, medium_type::components > field_dot_dot, const ScratchViewType< type_real, 1 > s_hprime_xx, const ScratchViewType< type_real, 1 > s_hprime_zz) const +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/receivers/elastic/elastic2d_isotropic.hpp:85: warning: argument 'hprime_zz' of command @param is not found in the argument list of specfem::domain::impl::receivers::receiver< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::elastic, specfem::enums::element::quadrature::static_quadrature_points< NGLL >, specfem::enums::element::property::isotropic >::get_field(const int &ireceiver, const int &iseis, const int &ispec, const specfem::enums::seismogram::type &seismogram_type, const int &xz, const int &isig_step, const ScratchViewType< type_real, medium_type::components > field, const ScratchViewType< type_real, medium_type::components > field_dot, const ScratchViewType< type_real, medium_type::components > field_dot_dot, const ScratchViewType< type_real, 1 > s_hprime_xx, const ScratchViewType< type_real, 1 > s_hprime_zz) const +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/receivers/elastic/elastic2d_isotropic.hpp:101: warning: The following parameters of specfem::domain::impl::receivers::receiver< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::elastic, specfem::enums::element::quadrature::static_quadrature_points< NGLL >, specfem::enums::element::property::isotropic >::get_field(const int &ireceiver, const int &iseis, const int &ispec, const specfem::enums::seismogram::type &seismogram_type, const int &xz, const int &isig_step, const ScratchViewType< type_real, medium_type::components > field, const ScratchViewType< type_real, medium_type::components > field_dot, const ScratchViewType< type_real, medium_type::components > field_dot_dot, const ScratchViewType< type_real, 1 > s_hprime_xx, const ScratchViewType< type_real, 1 > s_hprime_zz) const are not documented: + parameter 'seismogram_type' + parameter 's_hprime_xx' + parameter 's_hprime_zz' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/compute/compute_receivers.hpp:102: warning: The following parameters of specfem::compute::receivers::receivers(const std::vector< specfem::receivers::receiver * > &receivers, const std::vector< specfem::enums::seismogram::type > &stypes, const specfem::quadrature::quadrature *quadx, const specfem::quadrature::quadrature *quadz, const type_real xmax, const type_real xmin, const type_real zmax, const type_real zmin, const int max_sig_step, specfem::MPI::MPI *mpi) are not documented: + parameter 'xmax' + parameter 'xmin' + parameter 'zmax' + parameter 'zmin' + parameter 'max_sig_step' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/parameter_parser/seismogram.hpp:48: warning: The following parameters of specfem::runtime_configuration::seismogram::instantiate_seismogram_writer(std::vector< specfem::receivers::receiver * > &receivers, specfem::compute::receivers *compute_receivers, const type_real dt, const type_real t0, const int nsteps_between_samples) const are not documented: + parameter 'nsteps_between_samples' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/domain/impl/sources/elastic/elastic2d_isotropic.hpp:70: warning: The following parameters of specfem::domain::impl::sources::source< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::elastic, specfem::enums::element::quadrature::static_quadrature_points< NGLL >, specfem::enums::element::property::isotropic >::source(const specfem::compute::properties &properties, specfem::kokkos::DeviceView4d< type_real > source_array) are not documented: + parameter 'properties' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/compute/compute_sources.hpp:56: warning: The following parameters of specfem::compute::sources::sources(const std::vector< specfem::sources::source * > &sources, const specfem::quadrature::quadrature *quadx, const specfem::quadrature::quadrature *quadz, const type_real xmax, const type_real xmin, const type_real zmax, const type_real zmin, specfem::MPI::MPI *mpi) are not documented: + parameter 'xmax' + parameter 'xmin' + parameter 'zmax' + parameter 'zmin' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/kokkos_abstractions.h:574: warning: Unsupported xml/html tag found +/scratch/gpfs/rk9481/specfem2d_kokkos/include/kokkos_abstractions.h:574: warning: Unsupported xml/html tag found +/scratch/gpfs/rk9481/specfem2d_kokkos/include/solver/time_marching.hpp:33: warning: The following parameters of specfem::solver::time_marching::time_marching(specfem::domain::domain< specfem::enums::element::medium::acoustic, qp_type > &acoustic_domain, specfem::domain::domain< specfem::enums::element::medium::elastic, qp_type > &elastic_domain, specfem::coupled_interface::coupled_interface< specfem::domain::domain< specfem::enums::element::medium::acoustic, qp_type >, specfem::domain::domain< specfem::enums::element::medium::elastic, qp_type > > &acoustic_elastic_interface, specfem::coupled_interface::coupled_interface< specfem::domain::domain< specfem::enums::element::medium::elastic, qp_type >, specfem::domain::domain< specfem::enums::element::medium::acoustic, qp_type > > &elastic_acoustic_interface, specfem::TimeScheme::TimeScheme *it) are not documented: + parameter 'acoustic_elastic_interface' + parameter 'elastic_acoustic_interface' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/timescheme/timescheme.hpp:53: warning: argument 'domain_class' of command @param is not found in the argument list of specfem::TimeScheme::TimeScheme::apply_predictor_phase(specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot_dot) +/scratch/gpfs/rk9481/specfem2d_kokkos/include/timescheme/timescheme.hpp:57: warning: The following parameters of specfem::TimeScheme::TimeScheme::apply_predictor_phase(specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot_dot) are not documented: + parameter 'field' + parameter 'field_dot' + parameter 'field_dot_dot' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/timescheme/timescheme.hpp:63: warning: argument 'domain_class' of command @param is not found in the argument list of specfem::TimeScheme::TimeScheme::apply_corrector_phase(specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot_dot) +/scratch/gpfs/rk9481/specfem2d_kokkos/include/timescheme/timescheme.hpp:67: warning: The following parameters of specfem::TimeScheme::TimeScheme::apply_corrector_phase(specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot_dot) are not documented: + parameter 'field' + parameter 'field_dot' + parameter 'field_dot_dot' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/enumerations/specfem_enums.hpp:19: warning: Internal inconsistency: member x does not belong to any container! +/scratch/gpfs/rk9481/specfem2d_kokkos/include/enumerations/specfem_enums.hpp:19: warning: Internal inconsistency: member x does not belong to any container! +/scratch/gpfs/rk9481/specfem2d_kokkos/include/enumerations/specfem_enums.hpp:20: warning: Internal inconsistency: member y does not belong to any container! +/scratch/gpfs/rk9481/specfem2d_kokkos/include/enumerations/specfem_enums.hpp:20: warning: Internal inconsistency: member y does not belong to any container! +/scratch/gpfs/rk9481/specfem2d_kokkos/include/enumerations/specfem_enums.hpp:22: warning: Internal inconsistency: member z does not belong to any container! +/scratch/gpfs/rk9481/specfem2d_kokkos/include/enumerations/specfem_enums.hpp:22: warning: Internal inconsistency: member z does not belong to any container! +/scratch/gpfs/rk9481/specfem2d_kokkos/include/enumerations/specfem_enums.hpp:30: warning: Internal inconsistency: member displacement does not belong to any container! +/scratch/gpfs/rk9481/specfem2d_kokkos/include/enumerations/specfem_enums.hpp:30: warning: Internal inconsistency: member displacement does not belong to any container! +/scratch/gpfs/rk9481/specfem2d_kokkos/include/enumerations/specfem_enums.hpp:31: warning: Internal inconsistency: member velocity does not belong to any container! +/scratch/gpfs/rk9481/specfem2d_kokkos/include/enumerations/specfem_enums.hpp:31: warning: Internal inconsistency: member velocity does not belong to any container! +/scratch/gpfs/rk9481/specfem2d_kokkos/include/enumerations/specfem_enums.hpp:33: warning: Internal inconsistency: member acceleration does not belong to any container! +/scratch/gpfs/rk9481/specfem2d_kokkos/include/enumerations/specfem_enums.hpp:33: warning: Internal inconsistency: member acceleration does not belong to any container! +/scratch/gpfs/rk9481/specfem2d_kokkos/include/jacobian/jacobian.hpp:65: warning: argument 'coorg' of command @param is not found in the argument list of specfem::jacobian::compute_locations(const specfem::kokkos::HostView2d< type_real > s_coorg, const int ngnod, const specfem::kokkos::HostView1d< type_real > shape2D) +/scratch/gpfs/rk9481/specfem2d_kokkos/include/jacobian/jacobian.hpp:74: warning: The following parameters of specfem::jacobian::compute_locations(const specfem::kokkos::HostView2d< type_real > s_coorg, const int ngnod, const specfem::kokkos::HostView1d< type_real > shape2D) are not documented: + parameter 's_coorg' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/jacobian/jacobian.hpp:119: warning: argument 'teamMember' of command @param is not found in the argument list of specfem::jacobian::compute_partial_derivatives(const specfem::kokkos::HostView2d< type_real > s_coorg, const int ngnod, const type_real xi, const type_real gamma) +/scratch/gpfs/rk9481/specfem2d_kokkos/include/jacobian/jacobian.hpp:159: warning: The following parameters of specfem::jacobian::compute_jacobian(const specfem::kokkos::HostTeam::member_type &teamMember, const specfem::kokkos::HostScratchView2d< type_real > s_coorg, const int ngnod, const type_real xi, const type_real gamma) are not documented: + parameter 'teamMember' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/jacobian/jacobian.hpp:174: warning: The following parameters of specfem::jacobian::compute_jacobian(const specfem::kokkos::HostTeam::member_type &teamMember, const specfem::kokkos::HostScratchView2d< type_real > s_coorg, const int ngnod, const specfem::kokkos::HostView2d< type_real > dershape2D) are not documented: + parameter 'teamMember' +/scratch/gpfs/rk9481/specfem2d_kokkos/include/jacobian/jacobian.hpp:220: warning: argument 'teamMember' of command @param is not found in the argument list of specfem::jacobian::compute_inverted_derivatives(const specfem::kokkos::HostView2d< type_real > s_coorg, const int ngnod, const type_real xi, const type_real gamma) +/scratch/gpfs/rk9481/specfem2d_kokkos/include/source/read_sources.hpp:20: warning: The following parameters of specfem::sources::read_sources(const std::string sources_file, const type_real dt, const specfem::MPI::MPI *mpi) are not documented: + parameter 'dt' +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/IO/fortran_io.rst:1: WARNING: malformed hyperlink target. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/IO/mesh/boundaries/index.rst:7: WARNING: toctree contains reference to nonexisting document 'api/IO/mesh/boundaries/forcing_boundaries' +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/IO/mesh/elements/index.rst:1: WARNING: malformed hyperlink target. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/IO/mesh/index.rst:1: ERROR: Unknown directive type "mesh_io". + +.. mesh_io:: +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/IO/mesh/index.rst:18: WARNING: toctree contains reference to nonexisting document 'api/IO/mesh/coupling/index' +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/compute/compute.rst:1: WARNING: malformed hyperlink target. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/compute/compute_coupled_interfaces.rst:1: WARNING: malformed hyperlink target. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/compute/compute_partial_derivatives.rst:1: WARNING: malformed hyperlink target. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/compute/compute_properties.rst:1: WARNING: malformed hyperlink target. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/compute/compute_receivers.rst:1: WARNING: malformed hyperlink target. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/compute/compute_sources.rst:1: WARNING: malformed hyperlink target. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/compute/index.rst:1: WARNING: malformed hyperlink target. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/compute/index.rst:8: ERROR: Error in "toctree" directive: +invalid option block. + +.. toctree:: + :maxdepth: 1 + compute + compute_partial_derivatives + compute_properties + compute_sources + compute_receivers + compute_coupled_interfaces +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/coupling_physics/coupled_interface.rst:44: WARNING: Duplicate C++ declaration, also defined at api/coupling_physics/coupled_interface:8. +Declaration is '.. cpp:class:: template specfem::coupled_interface::coupled_interface'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/coupling_physics/coupled_interface.rst:3: CRITICAL: Duplicate ID: "classspecfem_1_1coupled__interface_1_1coupled__interface". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/coupling_physics/coupled_interface.rst:3: WARNING: Duplicate explicit target name: "classspecfem_1_1coupled__interface_1_1coupled__interface". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/coupling_physics/coupled_interface.rst:51: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 16] + KOKKOS_FUNCTION int npoints (const specfem::enums::coupling::edge::type &edge, const int ngllx, const int ngllz) + ----------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected identifier in nested name, got keyword: int [error at 19] + KOKKOS_FUNCTION int npoints (const specfem::enums::coupling::edge::type &edge, const int ngllx, const int ngllz) + -------------------^ + If declarator-id: + Invalid C++ declaration: Expected identifier in nested name, got keyword: int [error at 19] + KOKKOS_FUNCTION int npoints (const specfem::enums::coupling::edge::type &edge, const int ngllx, const int ngllz) + -------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/coupling_physics/coupled_interface.rst:51: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 16] + KOKKOS_FUNCTION void self_iterator (const int &ipoint, const specfem::enums::coupling::edge::type &edge, const int ngllx, const int ngllz, int &i, int &j) + ----------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 20] + KOKKOS_FUNCTION void self_iterator (const int &ipoint, const specfem::enums::coupling::edge::type &edge, const int ngllx, const int ngllz, int &i, int &j) + --------------------^ + If declarator-id: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 20] + KOKKOS_FUNCTION void self_iterator (const int &ipoint, const specfem::enums::coupling::edge::type &edge, const int ngllx, const int ngllz, int &i, int &j) + --------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/coupling_physics/coupled_interface.rst:51: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 16] + KOKKOS_FUNCTION void coupled_iterator (const int &ipoint, const specfem::enums::coupling::edge::type &edge, const int ngllx, const int ngllz, int &i, int &j) + ----------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 20] + KOKKOS_FUNCTION void coupled_iterator (const int &ipoint, const specfem::enums::coupling::edge::type &edge, const int ngllx, const int ngllz, int &i, int &j) + --------------------^ + If declarator-id: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 20] + KOKKOS_FUNCTION void coupled_iterator (const int &ipoint, const specfem::enums::coupling::edge::type &edge, const int ngllx, const int ngllz, int &i, int &j) + --------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/coupling_physics/edge/edge.rst:8: WARNING: duplicate label definition, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/coupling_physics/coupled_interface.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/coupling_physics/edge/edge.rst:13: WARNING: duplicate label interface, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/coupling_physics/coupled_interface.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/coupling_physics/edge/edge.rst:21: WARNING: duplicate label parameters, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/coupling_physics/coupled_interface.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/coupling_physics/edge/elastic_acoustic/acoustic_elastic_edge.rst:2: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 16] + KOKKOS_FUNCTION void compute_coupling (const int &iedge, const int &ipoint) const + ----------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 20] + KOKKOS_FUNCTION void compute_coupling (const int &iedge, const int &ipoint) const + --------------------^ + If declarator-id: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 20] + KOKKOS_FUNCTION void compute_coupling (const int &iedge, const int &ipoint) const + --------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/coupling_physics/edge/elastic_acoustic/acoustic_elastic_edge.rst:2: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 23] + inline KOKKOS_FUNCTION void get_edges (const int &iedge, specfem::enums::coupling::edge::type &self_edge_type, specfem::enums::coupling::edge::type &coupled_edge_type) const + -----------------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 27] + inline KOKKOS_FUNCTION void get_edges (const int &iedge, specfem::enums::coupling::edge::type &self_edge_type, specfem::enums::coupling::edge::type &coupled_edge_type) const + ---------------------------^ + If declarator-id: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 27] + inline KOKKOS_FUNCTION void get_edges (const int &iedge, specfem::enums::coupling::edge::type &self_edge_type, specfem::enums::coupling::edge::type &coupled_edge_type) const + ---------------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/coupling_physics/edge/elastic_acoustic/elastic_acoustic_edge.rst:2: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 16] + KOKKOS_FUNCTION void compute_coupling (const int &iedge, const int &ipoint) const + ----------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 20] + KOKKOS_FUNCTION void compute_coupling (const int &iedge, const int &ipoint) const + --------------------^ + If declarator-id: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 20] + KOKKOS_FUNCTION void compute_coupling (const int &iedge, const int &ipoint) const + --------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/coupling_physics/edge/elastic_acoustic/elastic_acoustic_edge.rst:2: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 23] + inline KOKKOS_FUNCTION void get_edges (const int &iedge, specfem::enums::coupling::edge::type &self_edge_type, specfem::enums::coupling::edge::type &coupled_edge_type) const + -----------------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 27] + inline KOKKOS_FUNCTION void get_edges (const int &iedge, specfem::enums::coupling::edge::type &self_edge_type, specfem::enums::coupling::edge::type &coupled_edge_type) const + ---------------------------^ + If declarator-id: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 27] + inline KOKKOS_FUNCTION void get_edges (const int &iedge, specfem::enums::coupling::edge::type &self_edge_type, specfem::enums::coupling::edge::type &coupled_edge_type) const + ---------------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/domain.rst:1: WARNING: malformed hyperlink target. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/domain.rst:22: WARNING: malformed hyperlink target. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/domain.rst:26: WARNING: malformed hyperlink target. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/domain.rst:30: WARNING: malformed hyperlink target. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/domain.rst:50: WARNING: Duplicate C++ declaration, also defined at api/domain/domain:9. +Declaration is '.. cpp:class:: template specfem::domain::domain'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/domain.rst:4: CRITICAL: Duplicate ID: "classspecfem_1_1domain_1_1domain". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/domain.rst:4: WARNING: Duplicate explicit target name: "classspecfem_1_1domain_1_1domain". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/domain.rst:7: WARNING: duplicate label definition, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/coupling_physics/edge/edge.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/domain.rst:12: WARNING: duplicate label interface, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/coupling_physics/edge/edge.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/domain.rst:20: WARNING: duplicate label parameters, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/coupling_physics/edge/edge.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/element/elements.rst:1: WARNING: malformed hyperlink target. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/element/elements.rst:9: WARNING: duplicate label definition, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/domain.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/element/elements.rst:14: WARNING: duplicate label interface, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/domain.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/element/elements.rst:22: WARNING: duplicate label parameters, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/domain.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/element/elements.rst:82: WARNING: duplicate label template specializations, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/coupling_physics/edge/edge.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/element/elements_dim2_acoustic_static_quadrature_points_isotropic.rst:2: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 23] + KOKKOS_INLINE_FUNCTION void compute_mass_matrix_component (const int &ispec, const int &xz, type_real *mass_matrix) const + -----------------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 27] + KOKKOS_INLINE_FUNCTION void compute_mass_matrix_component (const int &ispec, const int &xz, type_real *mass_matrix) const + ---------------------------^ + If declarator-id: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 27] + KOKKOS_INLINE_FUNCTION void compute_mass_matrix_component (const int &ispec, const int &xz, type_real *mass_matrix) const + ---------------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/element/elements_dim2_acoustic_static_quadrature_points_isotropic.rst:2: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 23] + KOKKOS_INLINE_FUNCTION void compute_gradient (const int &ispec, const int &xz, const ScratchViewType< type_real, 1 > s_hprime_xx, const ScratchViewType< type_real, 1 > s_hprime_zz, const ScratchViewType< type_real, medium_type::components > u, type_real *dudxl, type_real *dudzl) const + -----------------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 27] + KOKKOS_INLINE_FUNCTION void compute_gradient (const int &ispec, const int &xz, const ScratchViewType< type_real, 1 > s_hprime_xx, const ScratchViewType< type_real, 1 > s_hprime_zz, const ScratchViewType< type_real, medium_type::components > u, type_real *dudxl, type_real *dudzl) const + ---------------------------^ + If declarator-id: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 27] + KOKKOS_INLINE_FUNCTION void compute_gradient (const int &ispec, const int &xz, const ScratchViewType< type_real, 1 > s_hprime_xx, const ScratchViewType< type_real, 1 > s_hprime_zz, const ScratchViewType< type_real, medium_type::components > u, type_real *dudxl, type_real *dudzl) const + ---------------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/element/elements_dim2_acoustic_static_quadrature_points_isotropic.rst:2: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 23] + KOKKOS_INLINE_FUNCTION void compute_stress (const int &ispec, const int &xz, const type_real *dudxl, const type_real *dudzl, type_real *stress_integrand_xi, type_real *stress_integrand_gamma) const + -----------------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 27] + KOKKOS_INLINE_FUNCTION void compute_stress (const int &ispec, const int &xz, const type_real *dudxl, const type_real *dudzl, type_real *stress_integrand_xi, type_real *stress_integrand_gamma) const + ---------------------------^ + If declarator-id: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 27] + KOKKOS_INLINE_FUNCTION void compute_stress (const int &ispec, const int &xz, const type_real *dudxl, const type_real *dudzl, type_real *stress_integrand_xi, type_real *stress_integrand_gamma) const + ---------------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/element/elements_dim2_acoustic_static_quadrature_points_isotropic.rst:2: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 23] + KOKKOS_INLINE_FUNCTION void compute_acceleration (const int &xz, const type_real &wxglll, const type_real &wzglll, const ScratchViewType< type_real, medium_type::components > stress_integrand_xi, const ScratchViewType< type_real, medium_type::components > stress_integrand_gamma, const ScratchViewType< type_real, 1 > s_hprimewgll_xx, const ScratchViewType< type_real, 1 > s_hprimewgll_zz, type_real *acceleration) const + -----------------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 27] + KOKKOS_INLINE_FUNCTION void compute_acceleration (const int &xz, const type_real &wxglll, const type_real &wzglll, const ScratchViewType< type_real, medium_type::components > stress_integrand_xi, const ScratchViewType< type_real, medium_type::components > stress_integrand_gamma, const ScratchViewType< type_real, 1 > s_hprimewgll_xx, const ScratchViewType< type_real, 1 > s_hprimewgll_zz, type_real *acceleration) const + ---------------------------^ + If declarator-id: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 27] + KOKKOS_INLINE_FUNCTION void compute_acceleration (const int &xz, const type_real &wxglll, const type_real &wzglll, const ScratchViewType< type_real, medium_type::components > stress_integrand_xi, const ScratchViewType< type_real, medium_type::components > stress_integrand_gamma, const ScratchViewType< type_real, 1 > s_hprimewgll_xx, const ScratchViewType< type_real, 1 > s_hprimewgll_zz, type_real *acceleration) const + ---------------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/element/elements_dim2_elastic_static_quadrature_points_isotropic.rst:2: WARNING: Duplicate C++ declaration, also defined at api/domain/element/elements_dim2_acoustic_static_quadrature_points_isotropic:2. +Declaration is '.. cpp:class:: template specfem::domain::impl::elements::element< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::elastic, specfem::enums::element::quadrature::static_quadrature_points< NGLL >, specfem::enums::element::property::isotropic >'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/element/elements_dim2_elastic_static_quadrature_points_isotropic.rst:2: WARNING: Duplicate C++ declaration, also defined at api/domain/element/elements_dim2_acoustic_static_quadrature_points_isotropic:2. +Declaration is '.. cpp:type:: dimension = specfem::enums::element::dimension::dim2'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/element/elements_dim2_elastic_static_quadrature_points_isotropic.rst:2: WARNING: Duplicate C++ declaration, also defined at api/domain/element/elements_dim2_acoustic_static_quadrature_points_isotropic:2. +Declaration is '.. cpp:type:: medium_type = specfem::enums::element::medium::elastic'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/element/elements_dim2_elastic_static_quadrature_points_isotropic.rst:2: WARNING: Duplicate C++ declaration, also defined at api/domain/element/elements_dim2_acoustic_static_quadrature_points_isotropic:2. +Declaration is '.. cpp:type:: quadrature_points_type = specfem::enums::element::quadrature::static_quadrature_points< NGLL >'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/element/elements_dim2_elastic_static_quadrature_points_isotropic.rst:2: WARNING: Duplicate C++ declaration, also defined at api/domain/element/elements_dim2_acoustic_static_quadrature_points_isotropic:2. +Declaration is '.. cpp:type:: template ScratchViewType = typename quadrature_points_type::template ScratchViewType< T, N >'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/element/elements_dim2_elastic_static_quadrature_points_isotropic.rst:2: WARNING: Duplicate C++ declaration, also defined at api/domain/element/elements_dim2_acoustic_static_quadrature_points_isotropic:2. +Declaration is '.. cpp:member:: specfem::kokkos::DeviceView3d< type_real > xix'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/element/elements_dim2_elastic_static_quadrature_points_isotropic.rst:2: WARNING: Duplicate C++ declaration, also defined at api/domain/element/elements_dim2_acoustic_static_quadrature_points_isotropic:2. +Declaration is '.. cpp:member:: specfem::kokkos::DeviceView3d< type_real > xiz'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/element/elements_dim2_elastic_static_quadrature_points_isotropic.rst:2: WARNING: Duplicate C++ declaration, also defined at api/domain/element/elements_dim2_acoustic_static_quadrature_points_isotropic:2. +Declaration is '.. cpp:member:: specfem::kokkos::DeviceView3d< type_real > gammax'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/element/elements_dim2_elastic_static_quadrature_points_isotropic.rst:2: WARNING: Duplicate C++ declaration, also defined at api/domain/element/elements_dim2_acoustic_static_quadrature_points_isotropic:2. +Declaration is '.. cpp:member:: specfem::kokkos::DeviceView3d< type_real > gammaz'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/element/elements_dim2_elastic_static_quadrature_points_isotropic.rst:2: WARNING: Duplicate C++ declaration, also defined at api/domain/element/elements_dim2_acoustic_static_quadrature_points_isotropic:2. +Declaration is '.. cpp:member:: specfem::kokkos::DeviceView3d< type_real > jacobian'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/element/elements_dim2_elastic_static_quadrature_points_isotropic.rst:2: WARNING: Duplicate C++ declaration, also defined at api/domain/element/elements_dim2_acoustic_static_quadrature_points_isotropic:2. +Declaration is '.. cpp:member:: specfem::kokkos::DeviceView3d< type_real > lambdaplus2mu'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/element/elements_dim2_elastic_static_quadrature_points_isotropic.rst:2: WARNING: Duplicate C++ declaration, also defined at api/domain/element/elements_dim2_acoustic_static_quadrature_points_isotropic:2. +Declaration is '.. cpp:member:: specfem::kokkos::DeviceView3d< type_real > mu'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/element/elements_dim2_elastic_static_quadrature_points_isotropic.rst:2: WARNING: Duplicate C++ declaration, also defined at api/domain/element/elements_dim2_acoustic_static_quadrature_points_isotropic:2. +Declaration is '.. cpp:member:: specfem::kokkos::DeviceView3d< type_real > rho'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/element/elements_dim2_elastic_static_quadrature_points_isotropic.rst:2: WARNING: Duplicate C++ declaration, also defined at api/domain/element/elements_dim2_acoustic_static_quadrature_points_isotropic:2. +Declaration is '.. cpp:function:: KOKKOS_FUNCTION element ()=default'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/element/elements_dim2_elastic_static_quadrature_points_isotropic.rst:2: WARNING: Duplicate C++ declaration, also defined at api/domain/element/elements_dim2_acoustic_static_quadrature_points_isotropic:2. +Declaration is '.. cpp:function:: KOKKOS_FUNCTION element (const specfem::compute::partial_derivatives partial_derivatives, const specfem::compute::properties properties)'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/element/elements_dim2_elastic_static_quadrature_points_isotropic.rst:2: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 23] + KOKKOS_INLINE_FUNCTION void compute_mass_matrix_component (const int &ispec, const int &xz, type_real *mass_matrix) const + -----------------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 27] + KOKKOS_INLINE_FUNCTION void compute_mass_matrix_component (const int &ispec, const int &xz, type_real *mass_matrix) const + ---------------------------^ + If declarator-id: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 27] + KOKKOS_INLINE_FUNCTION void compute_mass_matrix_component (const int &ispec, const int &xz, type_real *mass_matrix) const + ---------------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/element/elements_dim2_elastic_static_quadrature_points_isotropic.rst:2: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 23] + KOKKOS_INLINE_FUNCTION void compute_gradient (const int &ispec, const int &xz, const ScratchViewType< type_real, 1 > s_hprime_xx, const ScratchViewType< type_real, 1 > s_hprime_zz, const ScratchViewType< type_real, medium_type::components > u, type_real *dudxl, type_real *dudzl) const + -----------------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 27] + KOKKOS_INLINE_FUNCTION void compute_gradient (const int &ispec, const int &xz, const ScratchViewType< type_real, 1 > s_hprime_xx, const ScratchViewType< type_real, 1 > s_hprime_zz, const ScratchViewType< type_real, medium_type::components > u, type_real *dudxl, type_real *dudzl) const + ---------------------------^ + If declarator-id: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 27] + KOKKOS_INLINE_FUNCTION void compute_gradient (const int &ispec, const int &xz, const ScratchViewType< type_real, 1 > s_hprime_xx, const ScratchViewType< type_real, 1 > s_hprime_zz, const ScratchViewType< type_real, medium_type::components > u, type_real *dudxl, type_real *dudzl) const + ---------------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/element/elements_dim2_elastic_static_quadrature_points_isotropic.rst:2: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 23] + KOKKOS_INLINE_FUNCTION void compute_stress (const int &ispec, const int &xz, const type_real *dudxl, const type_real *dudzl, type_real *stress_integrand_xi, type_real *stress_integrand_gamma) const + -----------------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 27] + KOKKOS_INLINE_FUNCTION void compute_stress (const int &ispec, const int &xz, const type_real *dudxl, const type_real *dudzl, type_real *stress_integrand_xi, type_real *stress_integrand_gamma) const + ---------------------------^ + If declarator-id: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 27] + KOKKOS_INLINE_FUNCTION void compute_stress (const int &ispec, const int &xz, const type_real *dudxl, const type_real *dudzl, type_real *stress_integrand_xi, type_real *stress_integrand_gamma) const + ---------------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/element/elements_dim2_elastic_static_quadrature_points_isotropic.rst:2: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 23] + KOKKOS_INLINE_FUNCTION void compute_acceleration (const int &xz, const type_real &wxglll, const type_real &wzglll, const ScratchViewType< type_real, medium_type::components > stress_integrand_xi, const ScratchViewType< type_real, medium_type::components > stress_integrand_gamma, const ScratchViewType< type_real, 1 > s_hprimewgll_xx, const ScratchViewType< type_real, 1 > s_hprimewgll_zz, type_real *acceleration) const + -----------------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 27] + KOKKOS_INLINE_FUNCTION void compute_acceleration (const int &xz, const type_real &wxglll, const type_real &wzglll, const ScratchViewType< type_real, medium_type::components > stress_integrand_xi, const ScratchViewType< type_real, medium_type::components > stress_integrand_gamma, const ScratchViewType< type_real, 1 > s_hprimewgll_xx, const ScratchViewType< type_real, 1 > s_hprimewgll_zz, type_real *acceleration) const + ---------------------------^ + If declarator-id: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 27] + KOKKOS_INLINE_FUNCTION void compute_acceleration (const int &xz, const type_real &wxglll, const type_real &wzglll, const ScratchViewType< type_real, medium_type::components > stress_integrand_xi, const ScratchViewType< type_real, medium_type::components > stress_integrand_gamma, const ScratchViewType< type_real, 1 > s_hprimewgll_xx, const ScratchViewType< type_real, 1 > s_hprimewgll_zz, type_real *acceleration) const + ---------------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/index.rst:1: WARNING: malformed hyperlink target. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/receivers/receivers.rst:1: ERROR: Unknown directive type "elemental_receivers_api_doc". + +.. elemental_receivers_api_doc:: +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/receivers/receivers.rst:9: WARNING: duplicate label definition, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/element/elements.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/receivers/receivers.rst:14: WARNING: duplicate label interface, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/element/elements.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/receivers/receivers.rst:22: WARNING: duplicate label parameters, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/element/elements.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/receivers/receivers.rst:81: WARNING: duplicate label template specializations, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/element/elements.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/receivers/receivers_dim2_acoustic_static_quadrature_points_isotropic.rst:2: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 16] + KOKKOS_FUNCTION void get_field (const int &ireceiver, const int &iseis, const int &ispec, const specfem::enums::seismogram::type &siesmogram_type, const int &xz, const int &isig_step, const ScratchViewType< type_real, medium_type::components > field, const ScratchViewType< type_real, medium_type::components > field_dot, const ScratchViewType< type_real, medium_type::components > field_dot_dot, const ScratchViewType< type_real, 1 > hprime_xx, const ScratchViewType< type_real, 1 > hprime_zz) const + ----------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 20] + KOKKOS_FUNCTION void get_field (const int &ireceiver, const int &iseis, const int &ispec, const specfem::enums::seismogram::type &siesmogram_type, const int &xz, const int &isig_step, const ScratchViewType< type_real, medium_type::components > field, const ScratchViewType< type_real, medium_type::components > field_dot, const ScratchViewType< type_real, medium_type::components > field_dot_dot, const ScratchViewType< type_real, 1 > hprime_xx, const ScratchViewType< type_real, 1 > hprime_zz) const + --------------------^ + If declarator-id: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 20] + KOKKOS_FUNCTION void get_field (const int &ireceiver, const int &iseis, const int &ispec, const specfem::enums::seismogram::type &siesmogram_type, const int &xz, const int &isig_step, const ScratchViewType< type_real, medium_type::components > field, const ScratchViewType< type_real, medium_type::components > field_dot, const ScratchViewType< type_real, medium_type::components > field_dot_dot, const ScratchViewType< type_real, 1 > hprime_xx, const ScratchViewType< type_real, 1 > hprime_zz) const + --------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/receivers/receivers_dim2_acoustic_static_quadrature_points_isotropic.rst:2: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 16] + KOKKOS_FUNCTION void compute_seismogram_components (const int &ireceiver, const int &iseis, const specfem::enums::seismogram::type &seismogram_type, const int &xz, const int &isig_step, dimension::array_type< type_real > &l_seismogram_components) const + ----------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 20] + KOKKOS_FUNCTION void compute_seismogram_components (const int &ireceiver, const int &iseis, const specfem::enums::seismogram::type &seismogram_type, const int &xz, const int &isig_step, dimension::array_type< type_real > &l_seismogram_components) const + --------------------^ + If declarator-id: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 20] + KOKKOS_FUNCTION void compute_seismogram_components (const int &ireceiver, const int &iseis, const specfem::enums::seismogram::type &seismogram_type, const int &xz, const int &isig_step, dimension::array_type< type_real > &l_seismogram_components) const + --------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/receivers/receivers_dim2_acoustic_static_quadrature_points_isotropic.rst:2: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 16] + KOKKOS_FUNCTION void compute_seismogram (const int &ireceiver, const dimension::array_type< type_real > &seismogram_components, specfem::kokkos::DeviceView1d< type_real > receiver_seismogram) const + ----------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 20] + KOKKOS_FUNCTION void compute_seismogram (const int &ireceiver, const dimension::array_type< type_real > &seismogram_components, specfem::kokkos::DeviceView1d< type_real > receiver_seismogram) const + --------------------^ + If declarator-id: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 20] + KOKKOS_FUNCTION void compute_seismogram (const int &ireceiver, const dimension::array_type< type_real > &seismogram_components, specfem::kokkos::DeviceView1d< type_real > receiver_seismogram) const + --------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/receivers/receivers_dim2_elastic_static_quadrature_points_isotropic.rst:2: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 16] + KOKKOS_FUNCTION void get_field (const int &ireceiver, const int &iseis, const int &ispec, const specfem::enums::seismogram::type &seismogram_type, const int &xz, const int &isig_step, const ScratchViewType< type_real, medium_type::components > field, const ScratchViewType< type_real, medium_type::components > field_dot, const ScratchViewType< type_real, medium_type::components > field_dot_dot, const ScratchViewType< type_real, 1 > s_hprime_xx, const ScratchViewType< type_real, 1 > s_hprime_zz) const + ----------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 20] + KOKKOS_FUNCTION void get_field (const int &ireceiver, const int &iseis, const int &ispec, const specfem::enums::seismogram::type &seismogram_type, const int &xz, const int &isig_step, const ScratchViewType< type_real, medium_type::components > field, const ScratchViewType< type_real, medium_type::components > field_dot, const ScratchViewType< type_real, medium_type::components > field_dot_dot, const ScratchViewType< type_real, 1 > s_hprime_xx, const ScratchViewType< type_real, 1 > s_hprime_zz) const + --------------------^ + If declarator-id: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 20] + KOKKOS_FUNCTION void get_field (const int &ireceiver, const int &iseis, const int &ispec, const specfem::enums::seismogram::type &seismogram_type, const int &xz, const int &isig_step, const ScratchViewType< type_real, medium_type::components > field, const ScratchViewType< type_real, medium_type::components > field_dot, const ScratchViewType< type_real, medium_type::components > field_dot_dot, const ScratchViewType< type_real, 1 > s_hprime_xx, const ScratchViewType< type_real, 1 > s_hprime_zz) const + --------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/receivers/receivers_dim2_elastic_static_quadrature_points_isotropic.rst:2: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 16] + KOKKOS_FUNCTION void compute_seismogram_components (const int &ireceiver, const int &iseis, const specfem::enums::seismogram::type &seismogram_type, const int &xz, const int &isig_step, dimension::array_type< type_real > &l_seismogram_components) const + ----------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 20] + KOKKOS_FUNCTION void compute_seismogram_components (const int &ireceiver, const int &iseis, const specfem::enums::seismogram::type &seismogram_type, const int &xz, const int &isig_step, dimension::array_type< type_real > &l_seismogram_components) const + --------------------^ + If declarator-id: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 20] + KOKKOS_FUNCTION void compute_seismogram_components (const int &ireceiver, const int &iseis, const specfem::enums::seismogram::type &seismogram_type, const int &xz, const int &isig_step, dimension::array_type< type_real > &l_seismogram_components) const + --------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/receivers/receivers_dim2_elastic_static_quadrature_points_isotropic.rst:2: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 16] + KOKKOS_FUNCTION void compute_seismogram (const int &ireceiver, const dimension::array_type< type_real > &seismogram_components, specfem::kokkos::DeviceView1d< type_real > receiver_seismogram) const + ----------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 20] + KOKKOS_FUNCTION void compute_seismogram (const int &ireceiver, const dimension::array_type< type_real > &seismogram_components, specfem::kokkos::DeviceView1d< type_real > receiver_seismogram) const + --------------------^ + If declarator-id: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 20] + KOKKOS_FUNCTION void compute_seismogram (const int &ireceiver, const dimension::array_type< type_real > &seismogram_components, specfem::kokkos::DeviceView1d< type_real > receiver_seismogram) const + --------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/sources/sources.rst:9: WARNING: duplicate label definition, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/receivers/receivers.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/sources/sources.rst:14: WARNING: duplicate label interface, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/receivers/receivers.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/sources/sources.rst:22: WARNING: duplicate label parameters, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/receivers/receivers.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/sources/sources.rst:81: WARNING: duplicate label template specializations, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/receivers/receivers.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/sources/sources_dim2_acoustic_static_quadrature_points_isotrpoic.rst:2: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 23] + KOKKOS_INLINE_FUNCTION void compute_interaction (const int &isource, const int &ispec, const int &xz, const type_real &stf_value, type_real *acceleration) const + -----------------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 27] + KOKKOS_INLINE_FUNCTION void compute_interaction (const int &isource, const int &ispec, const int &xz, const type_real &stf_value, type_real *acceleration) const + ---------------------------^ + If declarator-id: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 27] + KOKKOS_INLINE_FUNCTION void compute_interaction (const int &isource, const int &ispec, const int &xz, const type_real &stf_value, type_real *acceleration) const + ---------------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/sources/sources_dim2_elastic_static_quadrature_points_isotropic.rst:2: WARNING: doxygenclass: Cannot find class "specfem::domain::impl::sources::elemental_sources_api_documentation< specfem::enums::element::dimension::dim2, specfem::enums::element::medium::elastic, specfem::enums::element::quadrature::static_quadrature_points< NGLL >, specfem::enums::element::property::isotropic >" in doxygen xml output for project "SPECFEM KOKKOS IMPLEMENTATION" from directory: _build/xml +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/enumerations/element/acoustic.rst:2: WARNING: doxygenclass: Cannot find class "specfem::enums::element::medium::acosutic" in doxygen xml output for project "SPECFEM KOKKOS IMPLEMENTATION" from directory: _build/xml +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/enumerations/element/dim2.rst:2: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 30] + inline KOKKOS_INLINE_FUNCTION T & operator[] (const int &i) + ------------------------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected '::' in pointer to member (function). [error at 32] + inline KOKKOS_INLINE_FUNCTION T & operator[] (const int &i) + --------------------------------^ + If declarator-id: + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 32] + inline KOKKOS_INLINE_FUNCTION T & operator[] (const int &i) + --------------------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/enumerations/element/dim2.rst:2: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 30] + inline KOKKOS_INLINE_FUNCTION const T & operator[] (const int &i) const + ------------------------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected '::' in pointer to member (function). [error at 38] + inline KOKKOS_INLINE_FUNCTION const T & operator[] (const int &i) const + --------------------------------------^ + If declarator-id: + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 38] + inline KOKKOS_INLINE_FUNCTION const T & operator[] (const int &i) const + --------------------------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/enumerations/element/dim2.rst:2: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 30] + inline KOKKOS_INLINE_FUNCTION array_type< T > & operator+= (const array_type< T > &rhs) + ------------------------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected '::' in pointer to member (function). [error at 46] + inline KOKKOS_INLINE_FUNCTION array_type< T > & operator+= (const array_type< T > &rhs) + ----------------------------------------------^ + If declarator-id: + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 46] + inline KOKKOS_INLINE_FUNCTION array_type< T > & operator+= (const array_type< T > &rhs) + ----------------------------------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/enumerations/element/dim2.rst:2: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 30] + inline KOKKOS_INLINE_FUNCTION void init () + ------------------------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 34] + inline KOKKOS_INLINE_FUNCTION void init () + ----------------------------------^ + If declarator-id: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 34] + inline KOKKOS_INLINE_FUNCTION void init () + ----------------------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/enumerations/element/dim3.rst:2: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 30] + inline KOKKOS_INLINE_FUNCTION T & operator[] (const int &i) + ------------------------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected '::' in pointer to member (function). [error at 32] + inline KOKKOS_INLINE_FUNCTION T & operator[] (const int &i) + --------------------------------^ + If declarator-id: + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 32] + inline KOKKOS_INLINE_FUNCTION T & operator[] (const int &i) + --------------------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/enumerations/element/dim3.rst:2: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 30] + inline KOKKOS_INLINE_FUNCTION const T & operator[] (const int &i) const + ------------------------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected '::' in pointer to member (function). [error at 38] + inline KOKKOS_INLINE_FUNCTION const T & operator[] (const int &i) const + --------------------------------------^ + If declarator-id: + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 38] + inline KOKKOS_INLINE_FUNCTION const T & operator[] (const int &i) const + --------------------------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/enumerations/element/dim3.rst:2: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 30] + inline KOKKOS_INLINE_FUNCTION array_type< T > & operator+= (const array_type< T > &rhs) + ------------------------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected '::' in pointer to member (function). [error at 46] + inline KOKKOS_INLINE_FUNCTION array_type< T > & operator+= (const array_type< T > &rhs) + ----------------------------------------------^ + If declarator-id: + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 46] + inline KOKKOS_INLINE_FUNCTION array_type< T > & operator+= (const array_type< T > &rhs) + ----------------------------------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/enumerations/element/dim3.rst:2: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 30] + inline KOKKOS_INLINE_FUNCTION void init () + ------------------------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 34] + inline KOKKOS_INLINE_FUNCTION void init () + ----------------------------------^ + If declarator-id: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 34] + inline KOKKOS_INLINE_FUNCTION void init () + ----------------------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/enumerations/element/static_quadrature_points.rst:2: WARNING: doxygenclass: Cannot find class "specfem::enums::element::quadrature::static_quadrature_points< NGLL >" in doxygen xml output for project "SPECFEM KOKKOS IMPLEMENTATION" from directory: _build/xml +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/enumerations/index.rst:1: WARNING: malformed hyperlink target. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/enumerations/seismogram/seismogram_enumeration.rst:7: WARNING: doxygenenum: Cannot find enum "specfem::enum::seismogram::type" in doxygen xml output for project "SPECFEM KOKKOS IMPLEMENTATION" from directory: _build/xml +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/index.rst:6: WARNING: toctree contains reference to nonexisting document 'api/namespace/index' +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/jacobian.rst:1: WARNING: malformed hyperlink target. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/jacobian.rst:13: WARNING: Duplicate C++ declaration, also defined at api/jacobian:8. +Declaration is '.. cpp:type:: specfem'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/jacobian.rst:13: WARNING: Duplicate C++ declaration, also defined at api/jacobian:8. +Declaration is '.. cpp:type:: jacobian'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/jacobian.rst:4: CRITICAL: Duplicate ID: "namespacespecfem_1_1jacobian". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/jacobian.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem_1_1jacobian". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/jacobian.rst:4: CRITICAL: Duplicate ID: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/jacobian.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/kokkos_abstractions.rst:10: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 30] + inline KOKKOS_INLINE_FUNCTION void init (value_type &update) const + ------------------------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 34] + inline KOKKOS_INLINE_FUNCTION void init (value_type &update) const + ----------------------------------^ + If declarator-id: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 34] + inline KOKKOS_INLINE_FUNCTION void init (value_type &update) const + ----------------------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/kokkos_abstractions.rst:10: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 30] + inline KOKKOS_INLINE_FUNCTION void join (value_type &update, const value_type &source) const + ------------------------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 34] + inline KOKKOS_INLINE_FUNCTION void join (value_type &update, const value_type &source) const + ----------------------------------^ + If declarator-id: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 34] + inline KOKKOS_INLINE_FUNCTION void join (value_type &update, const value_type &source) const + ----------------------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/kokkos_abstractions.rst:10: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 30] + inline KOKKOS_INLINE_FUNCTION value_type & reference () const + ------------------------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected '::' in pointer to member (function). [error at 41] + inline KOKKOS_INLINE_FUNCTION value_type & reference () const + -----------------------------------------^ + If declarator-id: + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 41] + inline KOKKOS_INLINE_FUNCTION value_type & reference () const + -----------------------------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/kokkos_abstractions.rst:10: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 30] + inline KOKKOS_INLINE_FUNCTION result_view_type view () const + ------------------------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected '::' in pointer to member (function). [error at 47] + inline KOKKOS_INLINE_FUNCTION result_view_type view () const + -----------------------------------------------^ + If declarator-id: + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 47] + inline KOKKOS_INLINE_FUNCTION result_view_type view () const + -----------------------------------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/kokkos_abstractions.rst:10: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 30] + inline KOKKOS_INLINE_FUNCTION bool references_scalar () const + ------------------------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected identifier in nested name, got keyword: bool [error at 34] + inline KOKKOS_INLINE_FUNCTION bool references_scalar () const + ----------------------------------^ + If declarator-id: + Invalid C++ declaration: Expected identifier in nested name, got keyword: bool [error at 34] + inline KOKKOS_INLINE_FUNCTION bool references_scalar () const + ----------------------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/material.rst:11: WARNING: Duplicate C++ declaration, also defined at api/jacobian:8. +Declaration is '.. cpp:type:: specfem'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/material.rst:14: WARNING: Duplicate C++ declaration, also defined at api/jacobian:8. +Declaration is '.. cpp:type:: specfem'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/material.rst:14: WARNING: Duplicate C++ declaration, also defined at api/material:11. +Declaration is '.. cpp:type:: material'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/material.rst:4: CRITICAL: Duplicate ID: "namespacespecfem_1_1material". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/material.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem_1_1material". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/material.rst:4: CRITICAL: Duplicate ID: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/material.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/material/elastic_material.rst:7: WARNING: Duplicate C++ declaration, also defined at api/material:14. +Declaration is '.. cpp:class:: specfem::material::elastic_material : public specfem::material::material'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/material/elastic_material.rst:7: WARNING: Duplicate C++ declaration, also defined at api/material:14. +Declaration is '.. cpp:member:: type_real density'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/material/elastic_material.rst:7: WARNING: Duplicate C++ declaration, also defined at api/material:14. +Declaration is '.. cpp:member:: type_real cs'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/material/elastic_material.rst:7: WARNING: Duplicate C++ declaration, also defined at api/material:14. +Declaration is '.. cpp:member:: type_real cp'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/material/elastic_material.rst:7: WARNING: Duplicate C++ declaration, also defined at api/material:14. +Declaration is '.. cpp:member:: type_real Qkappa'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/material/elastic_material.rst:7: WARNING: Duplicate C++ declaration, also defined at api/material:14. +Declaration is '.. cpp:member:: type_real Qmu'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/material/elastic_material.rst:7: WARNING: Duplicate C++ declaration, also defined at api/material:14. +Declaration is '.. cpp:member:: type_real compaction_grad'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/material/elastic_material.rst:7: WARNING: Duplicate C++ declaration, also defined at api/material:14. +Declaration is '.. cpp:member:: type_real lambdaplus2mu'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/material/elastic_material.rst:7: WARNING: Duplicate C++ declaration, also defined at api/material:14. +Declaration is '.. cpp:member:: type_real mu'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/material/elastic_material.rst:7: WARNING: Duplicate C++ declaration, also defined at api/material:14. +Declaration is '.. cpp:member:: type_real lambda'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/material/elastic_material.rst:7: WARNING: Duplicate C++ declaration, also defined at api/material:14. +Declaration is '.. cpp:member:: type_real kappa'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/material/elastic_material.rst:7: WARNING: Duplicate C++ declaration, also defined at api/material:14. +Declaration is '.. cpp:member:: type_real young'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/material/elastic_material.rst:7: WARNING: Duplicate C++ declaration, also defined at api/material:14. +Declaration is '.. cpp:member:: type_real poisson'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/material/elastic_material.rst:7: WARNING: Duplicate C++ declaration, also defined at api/material:14. +Declaration is '.. cpp:member:: specfem::enums::element::type ispec_type =specfem::enums::element::elastic'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/material/elastic_material.rst:7: WARNING: Duplicate C++ declaration, also defined at api/material:14. +Declaration is '.. cpp:function:: elastic_material ()'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/material/elastic_material.rst:7: WARNING: Duplicate C++ declaration, also defined at api/material:14. +Declaration is '.. cpp:function:: elastic_material (const type_real &density, const type_real &cs, const type_real &cp, const type_real &Qkappa, const type_real &Qmu, const type_real &compaction_grad)'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/material/elastic_material.rst:7: WARNING: Duplicate C++ declaration, also defined at api/material:14. +Declaration is '.. cpp:function:: virtual utilities::return_holder get_properties () override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/material/elastic_material.rst:7: WARNING: Duplicate C++ declaration, also defined at api/material:14. +Declaration is '.. cpp:function:: inline virtual specfem::enums::element::type get_ispec_type () override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/material/elastic_material.rst:7: WARNING: Duplicate C++ declaration, also defined at api/material:14. +Declaration is '.. cpp:function:: virtual std::string print () const override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/material/elastic_material.rst:7: WARNING: Duplicate C++ declaration, also defined at api/material:14. +Declaration is '.. cpp:function:: friend std::ostream & operator<< (std::ostream &out, const elastic_material &h)'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/material/index.rst:9: WARNING: Duplicate C++ declaration, also defined at api/material:11. +Declaration is '.. cpp:class:: specfem::material::material'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/material/index.rst:9: WARNING: Duplicate C++ declaration, also defined at api/material:11. +Declaration is '.. cpp:function:: inline material ()'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/material/index.rst:9: WARNING: Duplicate C++ declaration, also defined at api/material:11. +Declaration is '.. cpp:function:: inline virtual utilities::return_holder get_properties ()'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/material/index.rst:9: WARNING: Duplicate C++ declaration, also defined at api/material:11. +Declaration is '.. cpp:function:: inline virtual specfem::enums::element::type get_ispec_type ()'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/material/index.rst:9: WARNING: Duplicate C++ declaration, also defined at api/material:11. +Declaration is '.. cpp:function:: inline virtual std::string print () const'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/material/index.rst:15: WARNING: Title underline too short. + +Types of Materials Implemented +----------------------------- +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/namespaces/index.rst:8: WARNING: Duplicate C++ declaration, also defined at api/jacobian:8. +Declaration is '.. cpp:type:: specfem'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/namespaces/index.rst:11: WARNING: Duplicate C++ declaration, also defined at api/kokkos_abstractions:10. +Declaration is '.. cpp:type:: specfem::kokkos'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/namespaces/index.rst:26: WARNING: doxygennamespace: Cannot find namespace "specfem::mesh::io" in doxygen xml output for project "SPECFEM KOKKOS IMPLEMENTATION" from directory: _build/xml +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/namespaces/index.rst:29: WARNING: doxygennamespace: Cannot find namespace "specfem::mesh::io::fortran" in doxygen xml output for project "SPECFEM KOKKOS IMPLEMENTATION" from directory: _build/xml +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/namespaces/index.rst:50: WARNING: doxygennamespace: Cannot find namespace "specfem::coupled_interfaces" in doxygen xml output for project "SPECFEM KOKKOS IMPLEMENTATION" from directory: _build/xml +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/namespaces/index.rst:53: WARNING: doxygennamespace: Cannot find namespace "specfem::coupled_interfaces::impl" in doxygen xml output for project "SPECFEM KOKKOS IMPLEMENTATION" from directory: _build/xml +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/namespaces/index.rst:56: WARNING: doxygennamespace: Cannot find namespace "specfem::coupled_interfaces::impl::edge" in doxygen xml output for project "SPECFEM KOKKOS IMPLEMENTATION" from directory: _build/xml +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/namespaces/index.rst:65: WARNING: doxygennamespace: Cannot find namespace "specfem::materials" in doxygen xml output for project "SPECFEM KOKKOS IMPLEMENTATION" from directory: _build/xml +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:11: WARNING: Duplicate C++ declaration, also defined at api/jacobian:8. +Declaration is '.. cpp:type:: specfem'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:11: WARNING: Duplicate C++ declaration, also defined at api/namespaces/index:80. +Declaration is '.. cpp:type:: runtime_configuration'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:14: WARNING: Duplicate C++ declaration, also defined at api/jacobian:8. +Declaration is '.. cpp:type:: specfem'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:14: WARNING: Duplicate C++ declaration, also defined at api/namespaces/index:80. +Declaration is '.. cpp:type:: runtime_configuration'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:14: WARNING: Duplicate C++ declaration, also defined at api/parameter:11. +Declaration is '.. cpp:type:: solver'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:4: CRITICAL: Duplicate ID: "namespacespecfem_1_1runtime__configuration_1_1solver". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem_1_1runtime__configuration_1_1solver". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:4: CRITICAL: Duplicate ID: "namespacespecfem_1_1runtime__configuration". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem_1_1runtime__configuration". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:4: CRITICAL: Duplicate ID: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:17: WARNING: Duplicate C++ declaration, also defined at api/jacobian:8. +Declaration is '.. cpp:type:: specfem'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:17: WARNING: Duplicate C++ declaration, also defined at api/namespaces/index:80. +Declaration is '.. cpp:type:: runtime_configuration'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:4: CRITICAL: Duplicate ID: "namespacespecfem_1_1runtime__configuration". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem_1_1runtime__configuration". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:4: CRITICAL: Duplicate ID: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:20: WARNING: Duplicate C++ declaration, also defined at api/jacobian:8. +Declaration is '.. cpp:type:: specfem'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:20: WARNING: Duplicate C++ declaration, also defined at api/namespaces/index:80. +Declaration is '.. cpp:type:: runtime_configuration'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:4: CRITICAL: Duplicate ID: "namespacespecfem_1_1runtime__configuration". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem_1_1runtime__configuration". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:4: CRITICAL: Duplicate ID: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:23: WARNING: Duplicate C++ declaration, also defined at api/jacobian:8. +Declaration is '.. cpp:type:: specfem'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:23: WARNING: Duplicate C++ declaration, also defined at api/namespaces/index:80. +Declaration is '.. cpp:type:: runtime_configuration'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:4: CRITICAL: Duplicate ID: "namespacespecfem_1_1runtime__configuration". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem_1_1runtime__configuration". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:4: CRITICAL: Duplicate ID: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:26: WARNING: Duplicate C++ declaration, also defined at api/jacobian:8. +Declaration is '.. cpp:type:: specfem'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:26: WARNING: Duplicate C++ declaration, also defined at api/namespaces/index:80. +Declaration is '.. cpp:type:: runtime_configuration'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:4: CRITICAL: Duplicate ID: "namespacespecfem_1_1runtime__configuration". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem_1_1runtime__configuration". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:4: CRITICAL: Duplicate ID: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:29: WARNING: Duplicate C++ declaration, also defined at api/jacobian:8. +Declaration is '.. cpp:type:: specfem'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:29: WARNING: Duplicate C++ declaration, also defined at api/namespaces/index:80. +Declaration is '.. cpp:type:: runtime_configuration'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:4: CRITICAL: Duplicate ID: "namespacespecfem_1_1runtime__configuration". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem_1_1runtime__configuration". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:4: CRITICAL: Duplicate ID: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:32: WARNING: Duplicate C++ declaration, also defined at api/jacobian:8. +Declaration is '.. cpp:type:: specfem'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:32: WARNING: Duplicate C++ declaration, also defined at api/namespaces/index:80. +Declaration is '.. cpp:type:: runtime_configuration'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:4: CRITICAL: Duplicate ID: "namespacespecfem_1_1runtime__configuration". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem_1_1runtime__configuration". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:4: CRITICAL: Duplicate ID: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:35: WARNING: Duplicate C++ declaration, also defined at api/jacobian:8. +Declaration is '.. cpp:type:: specfem'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:35: WARNING: Duplicate C++ declaration, also defined at api/namespaces/index:80. +Declaration is '.. cpp:type:: runtime_configuration'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:4: CRITICAL: Duplicate ID: "namespacespecfem_1_1runtime__configuration". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem_1_1runtime__configuration". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:4: CRITICAL: Duplicate ID: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature.rst:11: WARNING: Duplicate C++ declaration, also defined at api/jacobian:8. +Declaration is '.. cpp:type:: specfem'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature.rst:11: WARNING: Duplicate C++ declaration, also defined at api/namespaces/index:59. +Declaration is '.. cpp:type:: quadrature'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature.rst:14: WARNING: Duplicate C++ declaration, also defined at api/jacobian:8. +Declaration is '.. cpp:type:: specfem'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature.rst:14: WARNING: Duplicate C++ declaration, also defined at api/namespaces/index:59. +Declaration is '.. cpp:type:: quadrature'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature.rst:14: WARNING: Duplicate C++ declaration, also defined at api/namespaces/index:62. +Declaration is '.. cpp:type:: gll'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature.rst:4: CRITICAL: Duplicate ID: "namespacespecfem_1_1quadrature". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem_1_1quadrature". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature.rst:4: CRITICAL: Duplicate ID: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature.rst:20: WARNING: Duplicate C++ declaration, also defined at api/jacobian:8. +Declaration is '.. cpp:type:: specfem'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature.rst:20: WARNING: Duplicate C++ declaration, also defined at api/namespaces/index:59. +Declaration is '.. cpp:type:: quadrature'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature.rst:20: WARNING: Duplicate C++ declaration, also defined at api/namespaces/index:62. +Declaration is '.. cpp:type:: gll'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature.rst:4: CRITICAL: Duplicate ID: "namespacespecfem_1_1quadrature_1_1gll". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem_1_1quadrature_1_1gll". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature.rst:4: CRITICAL: Duplicate ID: "namespacespecfem_1_1quadrature". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem_1_1quadrature". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature.rst:4: CRITICAL: Duplicate ID: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature.rst:23: WARNING: doxygenfile: Cannot find file "quadrature/gll/gll_utils.pp +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature.rst:29: WARNING: Duplicate C++ declaration, also defined at api/jacobian:8. +Declaration is '.. cpp:type:: specfem'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature.rst:29: WARNING: Duplicate C++ declaration, also defined at api/namespaces/index:59. +Declaration is '.. cpp:type:: quadrature'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature.rst:29: WARNING: Duplicate C++ declaration, also defined at api/namespaces/index:62. +Declaration is '.. cpp:type:: gll'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature.rst:4: CRITICAL: Duplicate ID: "namespacespecfem_1_1quadrature_1_1gll". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem_1_1quadrature_1_1gll". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature.rst:4: CRITICAL: Duplicate ID: "namespacespecfem_1_1quadrature". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem_1_1quadrature". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature.rst:4: CRITICAL: Duplicate ID: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/gll.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:14. +Declaration is '.. cpp:class:: specfem::quadrature::gll::gll : public specfem::quadrature::quadrature'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/gll.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:14. +Declaration is '.. cpp:member:: type_real alpha'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/gll.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:14. +Declaration is '.. cpp:member:: type_real beta'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/gll.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:14. +Declaration is '.. cpp:member:: int N'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/gll.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:14. +Declaration is '.. cpp:member:: specfem::kokkos::DeviceView1d< type_real > xi'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/gll.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:14. +Declaration is '.. cpp:member:: specfem::kokkos::HostMirror1d< type_real > h_xi'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/gll.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:14. +Declaration is '.. cpp:member:: specfem::kokkos::DeviceView1d< type_real > w'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/gll.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:14. +Declaration is '.. cpp:member:: specfem::kokkos::HostView1d< type_real > h_w'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/gll.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:14. +Declaration is '.. cpp:member:: specfem::kokkos::DeviceView2d< type_real > hprime'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/gll.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:14. +Declaration is '.. cpp:member:: specfem::kokkos::HostView2d< type_real > h_hprime'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/gll.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:14. +Declaration is '.. cpp:function:: gll ()'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/gll.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:14. +Declaration is '.. cpp:function:: gll (const type_real alpha, const type_real beta)'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/gll.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:14. +Declaration is '.. cpp:function:: gll (const type_real alpha, const type_real beta, const int N)'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/gll.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:14. +Declaration is '.. cpp:function:: void set_derivation_matrices ()'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/gll.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:14. +Declaration is '.. cpp:function:: inline specfem::kokkos::DeviceView1d< type_real > get_xi () const override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/gll.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:14. +Declaration is '.. cpp:function:: inline specfem::kokkos::DeviceView1d< type_real > get_w () const override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/gll.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:14. +Declaration is '.. cpp:function:: inline specfem::kokkos::DeviceView2d< type_real > get_hprime () const override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/gll.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:14. +Declaration is '.. cpp:function:: inline specfem::kokkos::HostMirror1d< type_real > get_hxi () const override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/gll.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:14. +Declaration is '.. cpp:function:: inline specfem::kokkos::HostMirror1d< type_real > get_hw () const override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/gll.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:14. +Declaration is '.. cpp:function:: inline specfem::kokkos::HostMirror2d< type_real > get_hhprime () const override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/gll.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:14. +Declaration is '.. cpp:function:: inline int get_N () const override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/gll.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:14. +Declaration is '.. cpp:function:: void print (std::ostream &out) const override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/gll.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:14. +Declaration is '.. cpp:function:: void set_allocations ()'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/gll.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:14. +Declaration is '.. cpp:function:: void sync_views ()'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/index.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:11. +Declaration is '.. cpp:class:: specfem::quadrature::quadrature'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/index.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:11. +Declaration is '.. cpp:member:: type_real alpha'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/index.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:11. +Declaration is '.. cpp:member:: type_real beta'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/index.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:11. +Declaration is '.. cpp:member:: int N'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/index.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:11. +Declaration is '.. cpp:member:: specfem::kokkos::DeviceView1d< type_real > xi'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/index.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:11. +Declaration is '.. cpp:member:: specfem::kokkos::HostMirror1d< type_real > h_xi'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/index.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:11. +Declaration is '.. cpp:member:: specfem::kokkos::DeviceView1d< type_real > w'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/index.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:11. +Declaration is '.. cpp:member:: specfem::kokkos::HostView1d< type_real > h_w'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/index.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:11. +Declaration is '.. cpp:member:: specfem::kokkos::DeviceView2d< type_real > hprime'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/index.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:11. +Declaration is '.. cpp:member:: specfem::kokkos::HostView2d< type_real > h_hprime'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/index.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:11. +Declaration is '.. cpp:function:: inline quadrature ()'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/index.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:11. +Declaration is '.. cpp:function:: inline virtual specfem::kokkos::DeviceView1d< type_real > get_xi () const'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/index.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:11. +Declaration is '.. cpp:function:: inline virtual specfem::kokkos::DeviceView1d< type_real > get_w () const'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/index.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:11. +Declaration is '.. cpp:function:: inline virtual specfem::kokkos::DeviceView2d< type_real > get_hprime () const'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/index.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:11. +Declaration is '.. cpp:function:: inline virtual specfem::kokkos::HostMirror1d< type_real > get_hxi () const'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/index.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:11. +Declaration is '.. cpp:function:: inline virtual specfem::kokkos::HostMirror1d< type_real > get_hw () const'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/index.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:11. +Declaration is '.. cpp:function:: inline virtual specfem::kokkos::HostMirror2d< type_real > get_hhprime () const'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/index.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:11. +Declaration is '.. cpp:function:: inline virtual int get_N () const'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature/index.rst:7: WARNING: Duplicate C++ declaration, also defined at api/quadrature:11. +Declaration is '.. cpp:function:: virtual void print (std::ostream &out) const'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/database_configuration.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:17. +Declaration is '.. cpp:class:: specfem::runtime_configuration::database_configuration'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/database_configuration.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:17. +Declaration is '.. cpp:member:: std::string fortran_database'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/database_configuration.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:17. +Declaration is '.. cpp:member:: std::string source_database'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/database_configuration.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:17. +Declaration is '.. cpp:function:: inline database_configuration (std::string fortran_database, std::string source_database)'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/database_configuration.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:17. +Declaration is '.. cpp:function:: database_configuration (const YAML::Node &Node)'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/database_configuration.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:17. +Declaration is '.. cpp:function:: inline std::tuple< std::string, std::string > get_databases () const'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/header.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:20. +Declaration is '.. cpp:class:: specfem::runtime_configuration::header'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/header.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:20. +Declaration is '.. cpp:member:: std::string title'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/header.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:20. +Declaration is '.. cpp:member:: std::string description'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/header.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:20. +Declaration is '.. cpp:function:: inline header (std::string title, std::string description)'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/header.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:20. +Declaration is '.. cpp:function:: header (const YAML::Node &Node)'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/header.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:20. +Declaration is '.. cpp:function:: inline std::string get_title ()'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/header.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:20. +Declaration is '.. cpp:function:: inline std::string get_description ()'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/header.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:20. +Declaration is '.. cpp:function:: friend std::ostream & operator<< (std::ostream &out, header &header)'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/quadrature.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:23. +Declaration is '.. cpp:class:: specfem::runtime_configuration::quadrature'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/quadrature.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:23. +Declaration is '.. cpp:member:: type_real alpha'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/quadrature.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:23. +Declaration is '.. cpp:member:: type_real beta'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/quadrature.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:23. +Declaration is '.. cpp:member:: int ngllx'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/quadrature.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:23. +Declaration is '.. cpp:member:: int ngllz'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/quadrature.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:23. +Declaration is '.. cpp:function:: inline quadrature (type_real alpha, type_real beta, int ngllx, int ngllz)'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/quadrature.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:23. +Declaration is '.. cpp:function:: quadrature (const YAML::Node &Node)'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/quadrature.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:23. +Declaration is '.. cpp:function:: quadrature (const std::string quadrature)'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/quadrature.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:23. +Declaration is '.. cpp:function:: std::tuple< specfem::quadrature::quadrature *, specfem::quadrature::quadrature * > instantiate ()'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/quadrature.rst:3: WARNING: duplicate label quadrature, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/receivers.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:29. +Declaration is '.. cpp:class:: specfem::runtime_configuration::receivers'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/receivers.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:29. +Declaration is '.. cpp:member:: std::string stations_file'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/receivers.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:29. +Declaration is '.. cpp:member:: type_real angle'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/receivers.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:29. +Declaration is '.. cpp:member:: int nstep_between_samples'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/receivers.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:29. +Declaration is '.. cpp:member:: std::vector< specfem::enums::seismogram::type > stypes'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/receivers.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:29. +Declaration is '.. cpp:function:: inline receivers (const std::string stations_file, const int angle, const int nstep_between_samples)'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/receivers.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:29. +Declaration is '.. cpp:function:: receivers (const YAML::Node &Node)'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/receivers.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:29. +Declaration is '.. cpp:function:: inline std::string get_stations_file () const'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/receivers.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:29. +Declaration is '.. cpp:function:: inline type_real get_angle () const'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/receivers.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:29. +Declaration is '.. cpp:function:: inline int get_nstep_between_samples () const'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/receivers.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:29. +Declaration is '.. cpp:function:: inline std::vector< specfem::enums::seismogram::type > get_seismogram_types () const'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/run_setup.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:26. +Declaration is '.. cpp:class:: specfem::runtime_configuration::run_setup'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/run_setup.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:26. +Declaration is '.. cpp:member:: int nproc'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/run_setup.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:26. +Declaration is '.. cpp:member:: int nruns'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/run_setup.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:26. +Declaration is '.. cpp:function:: inline run_setup (int nproc, int nruns)'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/run_setup.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:26. +Declaration is '.. cpp:function:: run_setup (const YAML::Node &Node)'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/seismogram.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:32. +Declaration is '.. cpp:class:: specfem::runtime_configuration::seismogram'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/seismogram.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:32. +Declaration is '.. cpp:member:: std::string seismogram_format'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/seismogram.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:32. +Declaration is '.. cpp:member:: std::string output_folder'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/seismogram.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:32. +Declaration is '.. cpp:function:: inline seismogram (const std::string seismogram_format, const std::string output_folder)'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/seismogram.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:32. +Declaration is '.. cpp:function:: seismogram (const YAML::Node &Node)'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/seismogram.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:32. +Declaration is '.. cpp:function:: specfem::writer::writer * instantiate_seismogram_writer (std::vector< specfem::receivers::receiver *> &receivers, specfem::compute::receivers *compute_receivers, const type_real dt, const type_real t0, const int nsteps_between_samples) const'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/setup.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:35. +Declaration is '.. cpp:class:: specfem::runtime_configuration::setup'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/setup.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:35. +Declaration is '.. cpp:member:: std::unique_ptr< specfem::runtime_configuration::header > header'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/setup.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:35. +Declaration is '.. cpp:member:: std::unique_ptr< specfem::runtime_configuration::solver::solver > solver'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/setup.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:35. +Declaration is '.. cpp:member:: std::unique_ptr< specfem::runtime_configuration::run_setup > run_setup'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/setup.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:35. +Declaration is '.. cpp:member:: std::unique_ptr< specfem::runtime_configuration::quadrature > quadrature'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/setup.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:35. +Declaration is '.. cpp:member:: std::unique_ptr< specfem::runtime_configuration::receivers > receivers'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/setup.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:35. +Declaration is '.. cpp:member:: std::unique_ptr< specfem::runtime_configuration::seismogram > seismogram'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/setup.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:35. +Declaration is '.. cpp:member:: std::unique_ptr< specfem::runtime_configuration::database_configuration > databases'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/setup.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:35. +Declaration is '.. cpp:function:: setup (const std::string ¶meter_file, const std::string &default_file)'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/setup.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:35. +Declaration is '.. cpp:function:: inline std::tuple< specfem::quadrature::quadrature *, specfem::quadrature::quadrature * > instantiate_quadrature ()'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/setup.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:35. +Declaration is '.. cpp:function:: inline specfem::TimeScheme::TimeScheme * instantiate_solver ()'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/setup.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:35. +Declaration is '.. cpp:function:: inline void update_t0 (type_real t0)'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/setup.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:35. +Declaration is '.. cpp:function:: std::string print_header (std::chrono::time_point< std::chrono::high_resolution_clock > now)'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/setup.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:35. +Declaration is '.. cpp:function:: inline type_real get_dt () const'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/setup.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:35. +Declaration is '.. cpp:function:: inline std::tuple< std::string, std::string > get_databases () const'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/setup.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:35. +Declaration is '.. cpp:function:: inline std::string get_stations_file () const'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/setup.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:35. +Declaration is '.. cpp:function:: inline type_real get_receiver_angle () const'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/setup.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:35. +Declaration is '.. cpp:function:: inline std::vector< specfem::enums::seismogram::type > get_seismogram_types () const'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/setup.rst:7: WARNING: Duplicate C++ declaration, also defined at api/parameter:35. +Declaration is '.. cpp:function:: inline specfem::writer::writer * instantiate_seismogram_writer (std::vector< specfem::receivers::receiver *> &receivers, specfem::compute::receivers *compute_receivers) const'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/solver/index.rst:7: WARNING: doxygenclass: Cannot find class "specfem::runtime_configuration::solver:solver" in doxygen xml output for project "SPECFEM KOKKOS IMPLEMENTATION" from directory: _build/xml +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/solver/time_marching.rst:5: WARNING: Duplicate C++ declaration, also defined at api/parameter:14. +Declaration is '.. cpp:class:: specfem::runtime_configuration::solver::time_marching : public specfem::runtime_configuration::solver::solver'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/solver/time_marching.rst:5: WARNING: Duplicate C++ declaration, also defined at api/parameter:14. +Declaration is '.. cpp:member:: int nstep'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/solver/time_marching.rst:5: WARNING: Duplicate C++ declaration, also defined at api/parameter:14. +Declaration is '.. cpp:member:: type_real dt'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/solver/time_marching.rst:5: WARNING: Duplicate C++ declaration, also defined at api/parameter:14. +Declaration is '.. cpp:member:: type_real t0'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/solver/time_marching.rst:5: WARNING: Duplicate C++ declaration, also defined at api/parameter:14. +Declaration is '.. cpp:member:: std::string timescheme'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/solver/time_marching.rst:5: WARNING: Duplicate C++ declaration, also defined at api/parameter:14. +Declaration is '.. cpp:function:: inline time_marching (std::string timescheme, type_real dt, type_real nstep)'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/solver/time_marching.rst:5: WARNING: Duplicate C++ declaration, also defined at api/parameter:14. +Declaration is '.. cpp:function:: time_marching (const YAML::Node &Node)'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/solver/time_marching.rst:5: WARNING: Duplicate C++ declaration, also defined at api/parameter:14. +Declaration is '.. cpp:function:: inline virtual void update_t0 (type_real t0) override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/solver/time_marching.rst:5: WARNING: Duplicate C++ declaration, also defined at api/parameter:14. +Declaration is '.. cpp:function:: virtual specfem::TimeScheme::TimeScheme * instantiate (const int nstep_between_samples) override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/solver/time_marching.rst:5: WARNING: Duplicate C++ declaration, also defined at api/parameter:14. +Declaration is '.. cpp:function:: inline virtual type_real get_dt () const override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/solver/time_marching.rst:5: WARNING: Duplicate C++ declaration, also defined at api/parameter:14. +Declaration is '.. cpp:function:: inline virtual type_real get_t0 () const override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/solver.rst:6: WARNING: Duplicate C++ declaration, also defined at api/jacobian:8. +Declaration is '.. cpp:type:: specfem'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/solver.rst:9: WARNING: Duplicate C++ declaration, also defined at api/jacobian:8. +Declaration is '.. cpp:type:: specfem'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/solver.rst:9: WARNING: Duplicate C++ declaration, also defined at api/solver:6. +Declaration is '.. cpp:type:: solver'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/solver.rst:4: CRITICAL: Duplicate ID: "namespacespecfem_1_1solver". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/solver.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem_1_1solver". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/solver.rst:4: CRITICAL: Duplicate ID: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/solver.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/solver/index.rst:7: WARNING: Duplicate C++ declaration, also defined at api/solver:6. +Declaration is '.. cpp:class:: specfem::solver::solver'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/solver/index.rst:7: WARNING: Duplicate C++ declaration, also defined at api/solver:6. +Declaration is '.. cpp:function:: virtual void run ()=0'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/solver/index.rst:3: WARNING: duplicate label solver api, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/solver/index.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/solver/index.rst:13: WARNING: duplicate label types of solvers, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/solver/index.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/solver/time_marching.rst:7: WARNING: Duplicate C++ declaration, also defined at api/solver:9. +Declaration is '.. cpp:class:: template specfem::solver::time_marching : public specfem::solver::solver'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/solver/time_marching.rst:7: WARNING: Duplicate C++ declaration, also defined at api/solver:9. +Declaration is '.. cpp:member:: specfem::domain::domain< specfem::enums::element::medium::acoustic, qp_type > acoustic_domain'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/solver/time_marching.rst:7: WARNING: Duplicate C++ declaration, also defined at api/solver:9. +Declaration is '.. cpp:member:: specfem::domain::domain< specfem::enums::element::medium::elastic, qp_type > elastic_domain'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/solver/time_marching.rst:7: WARNING: Duplicate C++ declaration, also defined at api/solver:9. +Declaration is '.. cpp:member:: specfem::coupled_interface::coupled_interface< specfem::domain::domain< specfem::enums::element::medium::acoustic, qp_type >, specfem::domain::domain< specfem::enums::element::medium::elastic, qp_type > > acoustic_elastic_interface'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/solver/time_marching.rst:7: WARNING: Duplicate C++ declaration, also defined at api/solver:9. +Declaration is '.. cpp:member:: specfem::coupled_interface::coupled_interface< specfem::domain::domain< specfem::enums::element::medium::elastic, qp_type >, specfem::domain::domain< specfem::enums::element::medium::acoustic, qp_type > > elastic_acoustic_interface'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/solver/time_marching.rst:7: WARNING: Duplicate C++ declaration, also defined at api/solver:9. +Declaration is '.. cpp:member:: specfem::TimeScheme::TimeScheme * it'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/solver/time_marching.rst:7: WARNING: Duplicate C++ declaration, also defined at api/solver:9. +Declaration is '.. cpp:function:: inline time_marching (specfem::domain::domain< specfem::enums::element::medium::acoustic, qp_type > &acoustic_domain, specfem::domain::domain< specfem::enums::element::medium::elastic, qp_type > &elastic_domain, specfem::coupled_interface::coupled_interface< specfem::domain::domain< specfem::enums::element::medium::acoustic, qp_type >, specfem::domain::domain< specfem::enums::element::medium::elastic, qp_type > > &acoustic_elastic_interface, specfem::coupled_interface::coupled_interface< specfem::domain::domain< specfem::enums::element::medium::elastic, qp_type >, specfem::domain::domain< specfem::enums::element::medium::acoustic, qp_type > > &elastic_acoustic_interface, specfem::TimeScheme::TimeScheme *it)'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/solver/time_marching.rst:7: WARNING: Duplicate C++ declaration, also defined at api/solver:9. +Declaration is '.. cpp:function:: virtual void run () override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/solver/time_marching.rst:3: WARNING: duplicate label time marching solver, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/solver/time_marching.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources/force_source.rst:7: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 34] + virtual KOKKOS_IMPL_HOST_FUNCTION type_real get_t0 () const override + ----------------------------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected '::' in pointer to member (function). [error at 44] + virtual KOKKOS_IMPL_HOST_FUNCTION type_real get_t0 () const override + --------------------------------------------^ + If declarator-id: + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 44] + virtual KOKKOS_IMPL_HOST_FUNCTION type_real get_t0 () const override + --------------------------------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources/index.rst:7: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 41] + inline virtual KOKKOS_IMPL_HOST_FUNCTION type_real get_t0 () const + -----------------------------------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected '::' in pointer to member (function). [error at 51] + inline virtual KOKKOS_IMPL_HOST_FUNCTION type_real get_t0 () const + ---------------------------------------------------^ + If declarator-id: + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 51] + inline virtual KOKKOS_IMPL_HOST_FUNCTION type_real get_t0 () const + ---------------------------------------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources/index.rst:22: WARNING: duplicate label auxiliary functions, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/receivers/index.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources/moment_tensor_source.rst:7: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 34] + virtual KOKKOS_IMPL_HOST_FUNCTION type_real get_t0 () const override + ----------------------------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected '::' in pointer to member (function). [error at 44] + virtual KOKKOS_IMPL_HOST_FUNCTION type_real get_t0 () const override + --------------------------------------------^ + If declarator-id: + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 44] + virtual KOKKOS_IMPL_HOST_FUNCTION type_real get_t0 () const override + --------------------------------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:11: WARNING: doxygenfile: Found multiple matches for file "source.hpp +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:14: WARNING: Duplicate C++ declaration, also defined at api/jacobian:8. +Declaration is '.. cpp:type:: specfem'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:14: WARNING: Duplicate C++ declaration, also defined at api/namespaces/index:68. +Declaration is '.. cpp:type:: sources'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:14: WARNING: Duplicate C++ declaration, also defined at api/sources/force_source:7. +Declaration is '.. cpp:class:: force : public specfem::sources::source'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:14: WARNING: Duplicate C++ declaration, also defined at api/sources/force_source:7. +Declaration is '.. cpp:member:: type_real xi'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:14: WARNING: Duplicate C++ declaration, also defined at api/sources/force_source:7. +Declaration is '.. cpp:member:: type_real gamma'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:14: WARNING: Duplicate C++ declaration, also defined at api/sources/force_source:7. +Declaration is '.. cpp:member:: type_real x'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:14: WARNING: Duplicate C++ declaration, also defined at api/sources/force_source:7. +Declaration is '.. cpp:member:: type_real z'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:14: WARNING: Duplicate C++ declaration, also defined at api/sources/force_source:7. +Declaration is '.. cpp:member:: type_real angle'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:14: WARNING: Duplicate C++ declaration, also defined at api/sources/force_source:7. +Declaration is '.. cpp:member:: int ispec'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:14: WARNING: Duplicate C++ declaration, also defined at api/sources/force_source:7. +Declaration is '.. cpp:member:: int islice'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:14: WARNING: Duplicate C++ declaration, also defined at api/sources/force_source:7. +Declaration is '.. cpp:member:: specfem::enums::element::type el_type'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:14: WARNING: Duplicate C++ declaration, also defined at api/sources/force_source:7. +Declaration is '.. cpp:member:: specfem::forcing_function::stf * forcing_function =NULL'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:14: WARNING: Duplicate C++ declaration, also defined at api/sources/force_source:7. +Declaration is '.. cpp:function:: force (YAML::Node &Node, const type_real dt)'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:14: WARNING: Duplicate C++ declaration, also defined at api/sources/force_source:7. +Declaration is '.. cpp:function:: virtual void locate (const specfem::kokkos::HostView2d< type_real > coord, const specfem::kokkos::HostMirror3d< int > h_ibool, const specfem::kokkos::HostMirror1d< type_real > xigll, const specfem::kokkos::HostMirror1d< type_real > zigll, const int nproc, const specfem::kokkos::HostView2d< type_real > coorg, const specfem::kokkos::HostView2d< int > knods, const int npgeo, const specfem::kokkos::HostMirror1d< specfem::enums::element::type > ispec_type, const specfem::MPI::MPI *mpi) override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:14: WARNING: Duplicate C++ declaration, also defined at api/sources/force_source:7. +Declaration is '.. cpp:function:: virtual void compute_source_array (const specfem::quadrature::quadrature *quadx, const specfem::quadrature::quadrature *quadz, specfem::kokkos::HostView3d< type_real > source_array) override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:14: WARNING: Duplicate C++ declaration, also defined at api/sources/force_source:7. +Declaration is '.. cpp:function:: virtual void check_locations (const type_real xmin, const type_real xmax, const type_real zmin, const type_real zmax, const specfem::MPI::MPI *mpi) override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:14: WARNING: Duplicate C++ declaration, also defined at api/sources/force_source:7. +Declaration is '.. cpp:function:: inline virtual int get_islice () const override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:14: WARNING: Duplicate C++ declaration, also defined at api/sources/force_source:7. +Declaration is '.. cpp:function:: inline virtual int get_ispec () const override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:14: WARNING: Duplicate C++ declaration, also defined at api/sources/force_source:7. +Declaration is '.. cpp:function:: inline virtual type_real get_x () const override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:14: WARNING: Duplicate C++ declaration, also defined at api/sources/force_source:7. +Declaration is '.. cpp:function:: inline virtual type_real get_z () const override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:14: WARNING: Duplicate C++ declaration, also defined at api/sources/force_source:7. +Declaration is '.. cpp:function:: inline virtual type_real get_xi () const override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:14: WARNING: Duplicate C++ declaration, also defined at api/sources/force_source:7. +Declaration is '.. cpp:function:: inline virtual type_real get_gamma () const override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:14: WARNING: Duplicate C++ declaration, also defined at api/sources/force_source:7. +Declaration is '.. cpp:function:: inline ~force ()'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:14: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 34] + virtual KOKKOS_IMPL_HOST_FUNCTION type_real get_t0 () const override + ----------------------------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected '::' in pointer to member (function). [error at 44] + virtual KOKKOS_IMPL_HOST_FUNCTION type_real get_t0 () const override + --------------------------------------------^ + If declarator-id: + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 44] + virtual KOKKOS_IMPL_HOST_FUNCTION type_real get_t0 () const override + --------------------------------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:14: WARNING: Duplicate C++ declaration, also defined at api/sources/force_source:7. +Declaration is '.. cpp:function:: virtual void update_tshift (type_real tshift) override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:14: WARNING: Duplicate C++ declaration, also defined at api/sources/force_source:7. +Declaration is '.. cpp:function:: virtual void print (std::ostream &out) const override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:14: WARNING: Duplicate C++ declaration, also defined at api/sources/force_source:7. +Declaration is '.. cpp:function:: virtual std::string print () const override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:14: WARNING: Duplicate C++ declaration, also defined at api/sources/force_source:7. +Declaration is '.. cpp:function:: inline virtual specfem::forcing_function::stf * get_stf () const override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:17: WARNING: Duplicate C++ declaration, also defined at api/jacobian:8. +Declaration is '.. cpp:type:: specfem'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:17: WARNING: Duplicate C++ declaration, also defined at api/namespaces/index:68. +Declaration is '.. cpp:type:: sources'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:17: WARNING: Duplicate C++ declaration, also defined at api/sources/moment_tensor_source:7. +Declaration is '.. cpp:class:: moment_tensor : public specfem::sources::source'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:17: WARNING: Duplicate C++ declaration, also defined at api/sources/moment_tensor_source:7. +Declaration is '.. cpp:member:: type_real xi'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:17: WARNING: Duplicate C++ declaration, also defined at api/sources/moment_tensor_source:7. +Declaration is '.. cpp:member:: type_real gamma'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:17: WARNING: Duplicate C++ declaration, also defined at api/sources/moment_tensor_source:7. +Declaration is '.. cpp:member:: type_real x'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:17: WARNING: Duplicate C++ declaration, also defined at api/sources/moment_tensor_source:7. +Declaration is '.. cpp:member:: type_real z'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:17: WARNING: Duplicate C++ declaration, also defined at api/sources/moment_tensor_source:7. +Declaration is '.. cpp:member:: type_real Mxx'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:17: WARNING: Duplicate C++ declaration, also defined at api/sources/moment_tensor_source:7. +Declaration is '.. cpp:member:: type_real Mxz'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:17: WARNING: Duplicate C++ declaration, also defined at api/sources/moment_tensor_source:7. +Declaration is '.. cpp:member:: type_real Mzz'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:17: WARNING: Duplicate C++ declaration, also defined at api/sources/moment_tensor_source:7. +Declaration is '.. cpp:member:: int ispec'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:17: WARNING: Duplicate C++ declaration, also defined at api/sources/moment_tensor_source:7. +Declaration is '.. cpp:member:: int islice'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:17: WARNING: Duplicate C++ declaration, also defined at api/sources/moment_tensor_source:7. +Declaration is '.. cpp:member:: specfem::kokkos::HostView2d< type_real > s_coorg'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:17: WARNING: Duplicate C++ declaration, also defined at api/sources/moment_tensor_source:7. +Declaration is '.. cpp:member:: specfem::forcing_function::stf * forcing_function =NULL'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:17: WARNING: Duplicate C++ declaration, also defined at api/sources/moment_tensor_source:7. +Declaration is '.. cpp:member:: specfem::enums::element::type el_type'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:17: WARNING: Duplicate C++ declaration, also defined at api/sources/moment_tensor_source:7. +Declaration is '.. cpp:function:: moment_tensor (YAML::Node &Node, const type_real dt)'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:17: WARNING: Duplicate C++ declaration, also defined at api/sources/moment_tensor_source:7. +Declaration is '.. cpp:function:: virtual void locate (const specfem::kokkos::HostView2d< type_real > coord, const specfem::kokkos::HostMirror3d< int > h_ibool, const specfem::kokkos::HostMirror1d< type_real > xigll, const specfem::kokkos::HostMirror1d< type_real > zigll, const int nproc, const specfem::kokkos::HostView2d< type_real > coorg, const specfem::kokkos::HostView2d< int > knods, const int npgeo, const specfem::kokkos::HostMirror1d< specfem::enums::element::type > ispec_type, const specfem::MPI::MPI *mpi) override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:17: WARNING: Duplicate C++ declaration, also defined at api/sources/moment_tensor_source:7. +Declaration is '.. cpp:function:: virtual void compute_source_array (const specfem::quadrature::quadrature *quadx, const specfem::quadrature::quadrature *quadz, specfem::kokkos::HostView3d< type_real > source_array) override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:17: WARNING: Duplicate C++ declaration, also defined at api/sources/moment_tensor_source:7. +Declaration is '.. cpp:function:: inline virtual int get_islice () const override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:17: WARNING: Duplicate C++ declaration, also defined at api/sources/moment_tensor_source:7. +Declaration is '.. cpp:function:: inline virtual int get_ispec () const override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:17: WARNING: Duplicate C++ declaration, also defined at api/sources/moment_tensor_source:7. +Declaration is '.. cpp:function:: inline virtual type_real get_x () const override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:17: WARNING: Duplicate C++ declaration, also defined at api/sources/moment_tensor_source:7. +Declaration is '.. cpp:function:: inline virtual type_real get_z () const override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:17: WARNING: Duplicate C++ declaration, also defined at api/sources/moment_tensor_source:7. +Declaration is '.. cpp:function:: inline virtual type_real get_xi () const override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:17: WARNING: Duplicate C++ declaration, also defined at api/sources/moment_tensor_source:7. +Declaration is '.. cpp:function:: inline virtual type_real get_gamma () const override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:17: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 34] + virtual KOKKOS_IMPL_HOST_FUNCTION type_real get_t0 () const override + ----------------------------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected '::' in pointer to member (function). [error at 44] + virtual KOKKOS_IMPL_HOST_FUNCTION type_real get_t0 () const override + --------------------------------------------^ + If declarator-id: + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 44] + virtual KOKKOS_IMPL_HOST_FUNCTION type_real get_t0 () const override + --------------------------------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:17: WARNING: Duplicate C++ declaration, also defined at api/sources/moment_tensor_source:7. +Declaration is '.. cpp:function:: virtual void update_tshift (type_real tshift) override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:17: WARNING: Duplicate C++ declaration, also defined at api/sources/moment_tensor_source:7. +Declaration is '.. cpp:function:: virtual void print (std::ostream &out) const override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:17: WARNING: Duplicate C++ declaration, also defined at api/sources/moment_tensor_source:7. +Declaration is '.. cpp:function:: virtual std::string print () const override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:17: WARNING: Duplicate C++ declaration, also defined at api/sources/moment_tensor_source:7. +Declaration is '.. cpp:function:: inline virtual specfem::forcing_function::stf * get_stf () const override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:17: WARNING: Duplicate C++ declaration, also defined at api/sources/moment_tensor_source:7. +Declaration is '.. cpp:function:: virtual void check_locations (const type_real xmin, const type_real xmax, const type_real zmin, const type_real zmax, const specfem::MPI::MPI *mpi) override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:17: WARNING: Duplicate C++ declaration, also defined at api/sources/moment_tensor_source:7. +Declaration is '.. cpp:function:: inline ~moment_tensor ()'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:4: CRITICAL: Duplicate ID: "namespacespecfem_1_1sources". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem_1_1sources". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:4: CRITICAL: Duplicate ID: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:23: ERROR: Error in "doxygenfile" directive: +unknown option: "projet". + +.. doxygenfile:: receiver.hpp + :projet: SPECFEM KOKKOS IMPLEMENTATION +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:29: WARNING: Duplicate C++ declaration, also defined at api/jacobian:8. +Declaration is '.. cpp:type:: specfem'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:29: WARNING: Duplicate C++ declaration, also defined at api/namespaces/index:68. +Declaration is '.. cpp:type:: sources'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:29: WARNING: Duplicate C++ declaration, also defined at api/sources/index:24. +Declaration is '.. cpp:function:: std::tuple< std::vector< specfem::sources::source * >, type_real > read_sources (const std::string sources_file, const type_real dt, const specfem::MPI::MPI *mpi)'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:4: CRITICAL: Duplicate ID: "namespacespecfem_1_1sources". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem_1_1sources". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:4: CRITICAL: Duplicate ID: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:32: WARNING: Duplicate C++ declaration, also defined at api/jacobian:8. +Declaration is '.. cpp:type:: specfem'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:32: WARNING: Duplicate C++ declaration, also defined at api/namespaces/index:71. +Declaration is '.. cpp:type:: receivers'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:32: WARNING: Duplicate C++ declaration, also defined at api/receivers/index:15. +Declaration is '.. cpp:function:: std::vector< specfem::receivers::receiver * > read_receivers (const std::string stations_file, const type_real angle)'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:4: CRITICAL: Duplicate ID: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:38: WARNING: Duplicate C++ declaration, also defined at api/jacobian:8. +Declaration is '.. cpp:type:: specfem'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:38: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 31] + inline virtual KOKKOS_FUNCTION type_real compute (type_real t) + -------------------------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected '::' in pointer to member (function). [error at 41] + inline virtual KOKKOS_FUNCTION type_real compute (type_real t) + -----------------------------------------^ + If declarator-id: + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 41] + inline virtual KOKKOS_FUNCTION type_real compute (type_real t) + -----------------------------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:38: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 31] + inline virtual KOKKOS_FUNCTION void update_tshift (type_real tshift) + -------------------------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 35] + inline virtual KOKKOS_FUNCTION void update_tshift (type_real tshift) + -----------------------------------^ + If declarator-id: + Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 35] + inline virtual KOKKOS_FUNCTION void update_tshift (type_real tshift) + -----------------------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:38: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 31] + inline virtual KOKKOS_FUNCTION type_real get_t0 () const + -------------------------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected '::' in pointer to member (function). [error at 41] + inline virtual KOKKOS_FUNCTION type_real get_t0 () const + -----------------------------------------^ + If declarator-id: + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 41] + inline virtual KOKKOS_FUNCTION type_real get_t0 () const + -----------------------------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:38: WARNING: Error when parsing function declaration. +If the function has no return type: + Error in declarator or parameters-and-qualifiers + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 23] + inline KOKKOS_FUNCTION type_real compute (const type_real t) + -----------------------^ +If the function has a return type: + Error in declarator or parameters-and-qualifiers + If pointer to member declarator: + Invalid C++ declaration: Expected '::' in pointer to member (function). [error at 33] + inline KOKKOS_FUNCTION type_real compute (const type_real t) + ---------------------------------^ + If declarator-id: + Invalid C++ declaration: Expecting "(" in parameters-and-qualifiers. [error at 33] + inline KOKKOS_FUNCTION type_real compute (const type_real t) + ---------------------------------^ + +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:4: CRITICAL: Duplicate ID: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/specfem_enums.rst:8: WARNING: doxygenfile: Cannot find file "include/specfem_enums.hpp +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/specfem_enums.rst:4: WARNING: duplicate label enumerations, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/enumerations/index.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/specfem_mpi.rst:1: WARNING: malformed hyperlink target. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/specfem_mpi.rst:8: WARNING: Duplicate C++ declaration, also defined at api/jacobian:8. +Declaration is '.. cpp:type:: specfem'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme.rst:8: WARNING: Duplicate C++ declaration, also defined at api/jacobian:8. +Declaration is '.. cpp:type:: specfem'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme.rst:8: WARNING: Duplicate C++ declaration, also defined at api/namespaces/index:74. +Declaration is '.. cpp:type:: TimeScheme'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme.rst:11: WARNING: Duplicate C++ declaration, also defined at api/jacobian:8. +Declaration is '.. cpp:type:: specfem'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme.rst:11: WARNING: Duplicate C++ declaration, also defined at api/namespaces/index:74. +Declaration is '.. cpp:type:: TimeScheme'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme.rst:4: CRITICAL: Duplicate ID: "namespacespecfem_1_1_time_scheme". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem_1_1_time_scheme". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme.rst:4: CRITICAL: Duplicate ID: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/index.rst:7: WARNING: Duplicate C++ declaration, also defined at api/timescheme:8. +Declaration is '.. cpp:class:: specfem::TimeScheme::TimeScheme'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/index.rst:7: WARNING: Duplicate C++ declaration, also defined at api/timescheme:8. +Declaration is '.. cpp:function:: inline virtual bool status () const'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/index.rst:7: WARNING: Duplicate C++ declaration, also defined at api/timescheme:8. +Declaration is '.. cpp:function:: inline virtual void increment_time ()'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/index.rst:7: WARNING: Duplicate C++ declaration, also defined at api/timescheme:8. +Declaration is '.. cpp:function:: inline virtual type_real get_time () const'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/index.rst:7: WARNING: Duplicate C++ declaration, also defined at api/timescheme:8. +Declaration is '.. cpp:function:: inline virtual int get_timestep () const'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/index.rst:7: WARNING: Duplicate C++ declaration, also defined at api/timescheme:8. +Declaration is '.. cpp:function:: inline virtual void reset_time ()'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/index.rst:7: WARNING: Duplicate C++ declaration, also defined at api/timescheme:8. +Declaration is '.. cpp:function:: inline virtual int get_max_timestep ()'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/index.rst:7: WARNING: Duplicate C++ declaration, also defined at api/timescheme:8. +Declaration is '.. cpp:function:: inline virtual void apply_predictor_phase (specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot_dot)'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/index.rst:7: WARNING: Duplicate C++ declaration, also defined at api/timescheme:8. +Declaration is '.. cpp:function:: inline virtual void apply_corrector_phase (specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot_dot)'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/index.rst:7: WARNING: Duplicate C++ declaration, also defined at api/timescheme:8. +Declaration is '.. cpp:function:: virtual void print (std::ostream &out) const'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/index.rst:7: WARNING: Duplicate C++ declaration, also defined at api/timescheme:8. +Declaration is '.. cpp:function:: inline virtual bool compute_seismogram () const'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/index.rst:7: WARNING: Duplicate C++ declaration, also defined at api/timescheme:8. +Declaration is '.. cpp:function:: inline virtual int get_seismogram_step () const'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/index.rst:7: WARNING: Duplicate C++ declaration, also defined at api/timescheme:8. +Declaration is '.. cpp:function:: inline virtual int get_max_seismogram_step () const'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/index.rst:7: WARNING: Duplicate C++ declaration, also defined at api/timescheme:8. +Declaration is '.. cpp:function:: inline virtual void increment_seismogram_step ()'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/index.rst:7: WARNING: Duplicate C++ declaration, also defined at api/timescheme:8. +Declaration is '.. cpp:function:: friend std::ostream & operator<< (std::ostream &out, TimeScheme &ts)'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/newmark.rst:5: WARNING: Duplicate C++ declaration, also defined at api/timescheme:11. +Declaration is '.. cpp:class:: specfem::TimeScheme::Newmark : public specfem::TimeScheme::TimeScheme'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/newmark.rst:5: WARNING: Duplicate C++ declaration, also defined at api/timescheme:11. +Declaration is '.. cpp:member:: type_real current_time'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/newmark.rst:5: WARNING: Duplicate C++ declaration, also defined at api/timescheme:11. +Declaration is '.. cpp:member:: int istep = 0'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/newmark.rst:5: WARNING: Duplicate C++ declaration, also defined at api/timescheme:11. +Declaration is '.. cpp:member:: type_real deltat'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/newmark.rst:5: WARNING: Duplicate C++ declaration, also defined at api/timescheme:11. +Declaration is '.. cpp:member:: type_real deltatover2'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/newmark.rst:5: WARNING: Duplicate C++ declaration, also defined at api/timescheme:11. +Declaration is '.. cpp:member:: type_real deltatsquareover2'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/newmark.rst:5: WARNING: Duplicate C++ declaration, also defined at api/timescheme:11. +Declaration is '.. cpp:member:: int nstep'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/newmark.rst:5: WARNING: Duplicate C++ declaration, also defined at api/timescheme:11. +Declaration is '.. cpp:member:: type_real t0'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/newmark.rst:5: WARNING: Duplicate C++ declaration, also defined at api/timescheme:11. +Declaration is '.. cpp:member:: int nstep_between_samples'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/newmark.rst:5: WARNING: Duplicate C++ declaration, also defined at api/timescheme:11. +Declaration is '.. cpp:member:: int isig_step = 0'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/newmark.rst:5: WARNING: Duplicate C++ declaration, also defined at api/timescheme:11. +Declaration is '.. cpp:function:: Newmark (const int nstep, const type_real t0, const type_real dt, const int nstep_between_samples)'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/newmark.rst:5: WARNING: Duplicate C++ declaration, also defined at api/timescheme:11. +Declaration is '.. cpp:function:: inline virtual bool status () const override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/newmark.rst:5: WARNING: Duplicate C++ declaration, also defined at api/timescheme:11. +Declaration is '.. cpp:function:: virtual void increment_time () override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/newmark.rst:5: WARNING: Duplicate C++ declaration, also defined at api/timescheme:11. +Declaration is '.. cpp:function:: inline virtual type_real get_time () const override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/newmark.rst:5: WARNING: Duplicate C++ declaration, also defined at api/timescheme:11. +Declaration is '.. cpp:function:: inline virtual int get_timestep () const override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/newmark.rst:5: WARNING: Duplicate C++ declaration, also defined at api/timescheme:11. +Declaration is '.. cpp:function:: virtual void reset_time () override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/newmark.rst:5: WARNING: Duplicate C++ declaration, also defined at api/timescheme:11. +Declaration is '.. cpp:function:: inline virtual int get_max_timestep () override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/newmark.rst:5: WARNING: Duplicate C++ declaration, also defined at api/timescheme:11. +Declaration is '.. cpp:function:: virtual void apply_predictor_phase (specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot_dot) override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/newmark.rst:5: WARNING: Duplicate C++ declaration, also defined at api/timescheme:11. +Declaration is '.. cpp:function:: virtual void apply_corrector_phase (specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot, specfem::kokkos::DeviceView2d< type_real, Kokkos::LayoutLeft > field_dot_dot) override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/newmark.rst:5: WARNING: Duplicate C++ declaration, also defined at api/timescheme:11. +Declaration is '.. cpp:function:: inline virtual bool compute_seismogram () const override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/newmark.rst:5: WARNING: Duplicate C++ declaration, also defined at api/timescheme:11. +Declaration is '.. cpp:function:: inline virtual int get_seismogram_step () const override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/newmark.rst:5: WARNING: Duplicate C++ declaration, also defined at api/timescheme:11. +Declaration is '.. cpp:function:: inline virtual int get_max_seismogram_step () const override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/newmark.rst:5: WARNING: Duplicate C++ declaration, also defined at api/timescheme:11. +Declaration is '.. cpp:function:: inline virtual void increment_seismogram_step () override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme/newmark.rst:5: WARNING: Duplicate C++ declaration, also defined at api/timescheme:11. +Declaration is '.. cpp:function:: virtual void print (std::ostream &out) const override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/writer.rst:1: ERROR: Unknown directive type "writer". + +.. writer:: +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/writer.rst:8: WARNING: Duplicate C++ declaration, also defined at api/jacobian:8. +Declaration is '.. cpp:type:: specfem'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/writer.rst:8: WARNING: Duplicate C++ declaration, also defined at api/namespaces/index:77. +Declaration is '.. cpp:type:: writer'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/writer.rst:8: WARNING: Duplicate C++ declaration, also defined at api/IO/writer/index:7. +Declaration is '.. cpp:class:: writer'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/writer.rst:8: WARNING: Duplicate C++ declaration, also defined at api/IO/writer/index:7. +Declaration is '.. cpp:function:: inline virtual void write ()'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/writer.rst:11: WARNING: Duplicate C++ declaration, also defined at api/jacobian:8. +Declaration is '.. cpp:type:: specfem'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/writer.rst:11: WARNING: Duplicate C++ declaration, also defined at api/namespaces/index:77. +Declaration is '.. cpp:type:: writer'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/writer.rst:11: WARNING: Duplicate C++ declaration, also defined at api/IO/writer/seismogram_writer:7. +Declaration is '.. cpp:class:: seismogram : public specfem::writer::writer'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/writer.rst:11: WARNING: Duplicate C++ declaration, also defined at api/IO/writer/seismogram_writer:7. +Declaration is '.. cpp:member:: specfem::enums::seismogram::format type'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/writer.rst:11: WARNING: Duplicate C++ declaration, also defined at api/IO/writer/seismogram_writer:7. +Declaration is '.. cpp:member:: std::string output_folder'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/writer.rst:11: WARNING: Duplicate C++ declaration, also defined at api/IO/writer/seismogram_writer:7. +Declaration is '.. cpp:member:: specfem::compute::receivers * compute_receivers'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/writer.rst:11: WARNING: Duplicate C++ declaration, also defined at api/IO/writer/seismogram_writer:7. +Declaration is '.. cpp:member:: std::vector< specfem::receivers::receiver * > receivers'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/writer.rst:11: WARNING: Duplicate C++ declaration, also defined at api/IO/writer/seismogram_writer:7. +Declaration is '.. cpp:member:: type_real dt'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/writer.rst:11: WARNING: Duplicate C++ declaration, also defined at api/IO/writer/seismogram_writer:7. +Declaration is '.. cpp:member:: type_real t0'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/writer.rst:11: WARNING: Duplicate C++ declaration, also defined at api/IO/writer/seismogram_writer:7. +Declaration is '.. cpp:member:: int nstep_between_samples'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/writer.rst:11: WARNING: Duplicate C++ declaration, also defined at api/IO/writer/seismogram_writer:7. +Declaration is '.. cpp:function:: inline seismogram (std ::vector< specfem::receivers::receiver *> &receivers, specfem::compute::receivers *compute_receivers, const specfem::enums::seismogram::format type, const std::string output_folder, const type_real dt, const type_real t0, const int nstep_between_samples)'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/writer.rst:11: WARNING: Duplicate C++ declaration, also defined at api/IO/writer/seismogram_writer:7. +Declaration is '.. cpp:function:: virtual void write () override'. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/writer.rst:4: CRITICAL: Duplicate ID: "namespacespecfem_1_1writer". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/writer.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem_1_1writer". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/writer.rst:4: CRITICAL: Duplicate ID: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/writer.rst:4: WARNING: Duplicate explicit target name: "namespacespecfem". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/cookbooks/example_01.rst:545: ERROR: Error in "code" directive: +unknown option: "linenos". + +.. code:: yaml + :linenos: + :caption: single_source.yaml + + number-of-sources: 1 + sources: + - force: + x : 2500.0 + z : 2500.0 + source_surf: false + angle : 0.0 + vx : 0.0 + vz : 0.0 + Dirac: + factor: 1.0 + tshift: 0.0 +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/cookbooks/example_01.rst:562: ERROR: Error in "code" directive: +unknown option: "linenos". + +.. code:: yaml + :linenos: + :caption: two_sources.yaml + + number-of-sources: 2 + sources: + - force: + x : 2500.0 + z : 2500.0 + source_surf: false + angle : 0.0 + vx : 0.0 + vz : 0.0 + Dirac: + factor: 1.0 + tshift: 0.0 + - force: + x : 2500.0 + z : 500.0 + source_surf: false + angle : 0.0 + vx : 0.0 + vz : 0.0 + Dirac: + factor: 1.0 + tshift: 0.0 +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/cookbooks/index.rst:4: WARNING: duplicate label cookbooks, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/cookbooks/index.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/developer_documentation/SPECFEM_architecture/domain.rst:1: ERROR: Unknown directive type "domain_coupled_interface_dev_guide". + +.. domain_coupled_interface_dev_guide:: +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/developer_documentation/SPECFEM_architecture/domain.rst:4: WARNING: Title underline too short. + +Domain and Coupled Interface Developer Guide +=========================================== +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/developer_documentation/SPECFEM_architecture/domain.rst:71: ERROR: Unknown interpreted text role "cite". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/developer_documentation/SPECFEM_architecture/domain.rst:161: WARNING: Mismatch: both interpreted text role prefix and reference suffix. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/developer_documentation/SPECFEM_architecture/domain.rst:421: ERROR: Unknown interpreted text role "cite". +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/developer_documentation/SPECFEM_architecture/quadrature.rst:10: ERROR: Unexpected indentation. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/developer_documentation/SPECFEM_architecture/quadrature.rst:10: WARNING: Inline interpreted text or phrase reference start-string without end-string. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/developer_documentation/SPECFEM_architecture/quadrature.rst:11: WARNING: Inline interpreted text or phrase reference start-string without end-string. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/developer_documentation/SPECFEM_architecture/quadrature.rst:11: WARNING: Inline interpreted text or phrase reference start-string without end-string. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/developer_documentation/SPECFEM_architecture/quadrature.rst:13: WARNING: Block quote ends without a blank line; unexpected unindent. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/developer_documentation/git_workflow.rst:11: WARNING: Bullet list ends without a blank line; unexpected unindent. +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/developer_documentation/index.rst:4: WARNING: duplicate label developer documentation, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/developer_documentation/index.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/developer_documentation/tests.rst:4: WARNING: duplicate label tests, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/developer_documentation/tests.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/parameter_documentation/databases.rst:10: WARNING: Title underline too short. + +**Parameter name** : ``databases`` +------------------------------- +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/parameter_documentation/header.rst:2: WARNING: duplicate label header, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/header.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/parameter_documentation/header.rst:7: WARNING: duplicate label parameter definitions, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/parameter_documentation/databases.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/parameter_documentation/run_setup.rst:2: WARNING: duplicate label runtime setup, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/run_setup.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/parameter_documentation/run_setup.rst:7: WARNING: duplicate label parameter definitions, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/parameter_documentation/header.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/parameter_documentation/seismogram_setup.rst:8: WARNING: duplicate label parameter definitions, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/parameter_documentation/run_setup.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/parameter_documentation/simulation_setup.rst:2: WARNING: duplicate label simulation setup, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/parameter_documentation/simulation_setup.rst:7: WARNING: duplicate label parameter definitions, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/parameter_documentation/seismogram_setup.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/source_description/index.rst:75: WARNING: Title underline too short. + +**Parameter Name** : ``sources..source_surf`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/source_description/index.rst:75: WARNING: Title underline too short. + +**Parameter Name** : ``sources..source_surf`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/source_description/index.rst:111: WARNING: Title underline too short. + +**Parameter Name** : ``sources.moment_tensor.Mxx`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/source_description/index.rst:111: WARNING: Title underline too short. + +**Parameter Name** : ``sources.moment_tensor.Mxx`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/source_description/index.rst:120: WARNING: Title underline too short. + +**Parameter Name** : ``sources.moment_tensor.Mxz`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/source_description/index.rst:120: WARNING: Title underline too short. + +**Parameter Name** : ``sources.moment_tensor.Mxz`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/source_description/index.rst:129: WARNING: Title underline too short. + +**Parameter Name** : ``sources.moment_tensor.Mzz`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/source_description/index.rst:129: WARNING: Title underline too short. + +**Parameter Name** : ``sources.moment_tensor.Mzz`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/source_description/index.rst:138: WARNING: Title underline too short. + +**Parameter Name** : ``sources..Dirac`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/source_description/index.rst:138: WARNING: Title underline too short. + +**Parameter Name** : ``sources..Dirac`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/source_description/index.rst:30: WARNING: duplicate label **parameter name** : ``sources``, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/source_description/index.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/source_description/index.rst:156: WARNING: duplicate label **parameter name** : ``sources..dirac.factor``, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/source_description/index.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/user_documentation/introduction.rst:2: WARNING: duplicate label introduction, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/index.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/user_documentation/introduction.rst:7: WARNING: duplicate label code feature matrix, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/index.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/user_documentation/running_the_solver.rst:2: WARNING: duplicate label running the solver, other instance in /scratch/gpfs/rk9481/specfem2d_kokkos/docs/cookbooks/example_01.rst +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/IO/mesh/boundaries/acoustic_forcing.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/compute/compute.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/compute/compute_coupled_interfaces.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/compute/compute_partial_derivatives.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/compute/compute_properties.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/compute/compute_receivers.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/compute/compute_sources.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/coupling_physics/edge/elastic_acoustic/acoustic_elastic_edge.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/coupling_physics/edge/elastic_acoustic/elastic_acoustic_edge.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/element/elements_dim2_acoustic_static_quadrature_points_isotropic.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/element/elements_dim2_elastic_static_quadrature_points_isotropic.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/receivers/receivers_dim2_acoustic_static_quadrature_points_isotropic.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/receivers/receivers_dim2_elastic_static_quadrature_points_isotropic.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/sources/sources_dim2_acoustic_static_quadrature_points_isotrpoic.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/domain/sources/sources_dim2_elastic_static_quadrature_points_isotropic.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/enumerations/element/acoustic.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/enumerations/element/dim2.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/enumerations/element/dim3.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/enumerations/element/elastic.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/enumerations/element/isotropic.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/enumerations/element/static_quadrature_points.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/jacobian.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/kokkos_abstractions.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/material.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/namespaces/index.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/parameter.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/quadrature.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/setup_parameters/setup.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/solver.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/sources_recievers.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/specfem_enums.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/specfem_mpi.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/timescheme.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/api/writer.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/developer_documentation/SPECFEM_architecture/architecture.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/developer_documentation/SPECFEM_architecture/compute.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/developer_documentation/SPECFEM_architecture/domain.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/developer_documentation/SPECFEM_architecture/mesh.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/developer_documentation/SPECFEM_architecture/quadrature.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/developer_documentation/cmake_primer.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/developer_documentation/doxygen_primer.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/developer_documentation/kokkos_primer.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/user_documentation/introduction.rst: WARNING: document isn't included in any toctree +/scratch/gpfs/rk9481/specfem2d_kokkos/docs/developer_documentation/SPECFEM_architecture/domain.rst:427: WARNING: undefined label: parallelism diff --git a/docs/parameter_documentation/index.rst b/docs/parameter_documentation/index.rst index e8079719..9053b82a 100644 --- a/docs/parameter_documentation/index.rst +++ b/docs/parameter_documentation/index.rst @@ -1,7 +1,7 @@ .. _parameter_documentation: -Parameter documentation -======================= +SPECFEM++ Parameter Documentation +================================= Overall run-time behaviour of simulation can be configured using a configuration file defined as YAML. The configuration file is splint into 3 separate `YAML nodes `_ within a ``parameters`` YAML node: diff --git a/docs/parameter_documentation/receivers.rst b/docs/parameter_documentation/receivers.rst index ccecadbb..0f8121fc 100644 --- a/docs/parameter_documentation/receivers.rst +++ b/docs/parameter_documentation/receivers.rst @@ -5,7 +5,7 @@ Receivers section defines receiver information required to calculate seismograms .. note:: - Please note that the :ref:`stations_file` is generated using SPECFEM meshgenerator i.e. xmeshfem2d + Please note that the :ref:`stations_file` is generated using SPECFEM2D mesh generator i.e. xmeshfem2d **Parameter Name** : ``receivers`` ----------------------------------- diff --git a/docs/report_bugs/index.rst b/docs/report_bugs/index.rst new file mode 100644 index 00000000..9a79010c --- /dev/null +++ b/docs/report_bugs/index.rst @@ -0,0 +1,3 @@ + +`Report bugs `_ +=================================================================================== diff --git a/docs/user_documentation/installation.rst b/docs/user_documentation/installation.rst index 9099ae42..6a6e7af3 100644 --- a/docs/user_documentation/installation.rst +++ b/docs/user_documentation/installation.rst @@ -1,21 +1,21 @@ Installation ############### -Downloading SPECFEM -=================== +Downloading SPECFEM++ +===================== Get the latest version of the package: .. code-block:: bash - + git clone git@github.com:PrincetonUniversity/SPECFEMPP.git git submodule init git submodule update Compilation ============ -Configure the package using Cmake configuration keywords before building using cmake. SPECFEM inherits several architecure specific keywords from `Kokkos `_ Cmakelists. Several examples for compiling for different architectures are shown below +Configure the package using Cmake configuration keywords before building using cmake. SPECFEM++ inherits several architecure specific keywords from `Kokkos `_ Cmakelists. Several examples for compiling for different architectures are shown below * CPU Serial version @@ -36,14 +36,19 @@ Configure the package using Cmake configuration keywords before building using c .. code-block:: bash - cmake3 -S . -B build -DKokkos_ENABLE_OPENMP=ON -DKokkos_ENABLE_CUDA=ON -DKokkos_ARCH_AMPERE80=ON -DKokkos_ENABLE_CUDA_LAMBDA=ON -DKokkos_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE=ON + cmake3 -S . -B build -DKokkos_ENABLE_OPENMP=ON -DKokkos_ENABLE_CUDA=ON -DKokkos_ARCH_AMPERE80=ON cmake3 --build build Adding SPECFEM to PATH ====================== -Finally, once compiled you could run specfem from inside the build directory, by running the executible ``./specfem``. However, we recommend you add SPECFEM build directory to your ``PATH`` using +Finally, once compiled you could run SPECFEM++ from inside the build directory, by running the executible ``./specfem``. However, we recommend you add SPECFEM++ build directory to your ``PATH`` using .. code-block:: bash export PATH=${PATH}: + +Testing Installation +===================== + +To check if the compilation is successful, compile and run the tests, then build the code with ``-DBUILD_TESTS=ON``. Then, run the test by ``cd build/tests/unit-tests && ctest``. diff --git a/docs/user_documentation/introduction.rst b/docs/user_documentation/introduction.rst index 6fb119a5..7a18c4de 100644 --- a/docs/user_documentation/introduction.rst +++ b/docs/user_documentation/introduction.rst @@ -1,3 +1,5 @@ +.. This file is not part of the SPECFEM++ documentation. + Introduction ============ @@ -13,23 +15,27 @@ Table below shows various features available and tested in this package on vario +=====================+=============+=============+======+=====+ | Physics | +---------------------+-------------+-------------+------+-----+ -| P-SV waves | X | X | X | | -+---------------------+-------------+-------------+------+-----+ -| SH waves | | | | | +| P-SV waves | ✔ | ✔ | ✔ | | +---------------------+-------------+-------------+------+-----+ -| Elastic Domains | X | X | X | | +| Elastic Domains | ✔ | ✔ | ✔ | | +---------------------+-------------+-------------+------+-----+ | Simulation Setup | +---------------------+-------------+-------------+------+-----+ -| Forward Simulations | X | X | X | | +| Forward Simulations | ✔ | ✔ | ✔ | | +---------------------+-------------+-------------+------+-----+ | Time Schemes | +---------------------+-------------+-------------+------+-----+ -| Newmark | X | X | X | | +| Newmark | ✔ | ✔ | ✔ | | +---------------------+-------------+-------------+------+-----+ | Seismograms | +---------------------+-------------+-------------+------+-----+ -| | | | | | +| displacement | ✔ | ✔ | ✔ | | ++---------------------+-------------+-------------+------+-----+ +| velocity | ✔ | ✔ | ✔ | | ++---------------------+-------------+-------------+------+-----+ +| Seimogram Formats | ++---------------------+-------------+-------------+------+-----+ +| ASCII | ✔ | ✔ | ✔ | | +---------------------+-------------+-------------+------+-----+ .. note:: diff --git a/docs/user_documentation/mesh_generation.rst b/docs/user_documentation/mesh_generation.rst index 525efed0..63f55e80 100644 --- a/docs/user_documentation/mesh_generation.rst +++ b/docs/user_documentation/mesh_generation.rst @@ -1,8 +1,13 @@ Mesh Generation =============== -In this version of the package meshfem has not been implemented. However, the package can read internal meshes generated via `SPECFEM2D mesh generator `_ . Please refer to the documentation there to generate meshes. Thus for now, we require a *Par_file* for generation of mesh and a *configuration file* for setting up and running the solver. +Mesh generation requires use of a meshing software. We provide an internal mesher to generate meshes for simple domain geometries i.e. layer cake model (rectangular domains with interfaces between different material systems). However, for more complex geometries, we recommend using external meshing software such as Gmsh (http://gmsh.info/) or CUBIT (https://cubit.sandia.gov/). -The recommended workflow for running the code would be to generate an internal mesh using ``xmeshfem2D``. Make sure the domain is entirely elastic, this version does not support acoustic domains. Then define the path to the generated database file using :ref:`database-file-parameter`. +.. note:: + The internal mesher is a slightly modified version of the mesher provided with the original `SPECFEM2D `_ package. -Please have a look at the :ref:`cookbooks` for examples on generating a mesh. +We configure the mesher using a :ref:`Parameter_File` to define the meshing specifications and a :ref:`Topography_File` to define the topography of the domain. The meshing software is called using the following command: + +.. code-block:: bash + + $ ./xmeshfem2d -p diff --git a/docs/user_documentation/requirements.rst b/docs/user_documentation/requirements.rst index d644468b..27544471 100644 --- a/docs/user_documentation/requirements.rst +++ b/docs/user_documentation/requirements.rst @@ -4,6 +4,9 @@ Requirements Compiler Versions ----------------- +.. note:: + The following compilers are supported and tested by Kokkos. In theory, SPECFEM++ should work with any of these compiler versions. However we have not tested all of them and cannot guarantee the same. If you have issues compiling with a compiler versions listed below, please create an issue on GitHub. For a list of tested compilers and platforms, see :ref:`tests` section. + .. list-table:: :widths: 30 35 35 :header-rows: 1 @@ -41,8 +44,33 @@ Compiler Versions * 20.1 * 20.1 +.. warning:: + + We support cudatoolkit versions ``>=11.7``. For a list of tested compilers and platforms, see :ref:`tests` section. + Build system ------------ * CMake >= 3.16: required * CMake >= 3.21.1 for NVC++ + + +Dependencies +------------ + +None of the dependencies need to be installed prior to the installation of +the package. Having installed some packages does however reduce build time +because the dependencies do not have to be fetched. + +Boost ++++++ + +Current requirements of the ``Boost`` library are a version that is ``>=1.66.0``. +If you have ``Boost`` installed on your system, set the environment variable +``BOOST_ROOT`` containing the absolute path to your ``Boost`` installation. +For example, on machines (clusters) with ``lmod`` package manager this can be +done by loading the boost module + +.. code:: bash + + module load boost/?.??.? # Eg. boost/1.73.0 diff --git a/docs/user_documentation/seismogram.rst b/docs/user_documentation/seismogram.rst index e675e574..af5bf21e 100644 --- a/docs/user_documentation/seismogram.rst +++ b/docs/user_documentation/seismogram.rst @@ -1,7 +1,7 @@ Seismogram output ================== -On successful completion of the SPECFEM2D run a seismogram will be written to the output directory. Below are definitions output formats as defined in SPECFEM. +On successful completion of the SPECFEM++ run a seismogram will be written to the output directory. Below are definitions output formats as defined in SPECFEM2D. .. _stations_file: diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 200432cf..30614bc7 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,3 +1,4 @@ cmake_minimum_required(VERSION 3.17.5) -configure_file(homogeneous-medium-flat-topography/specfem_config.yaml.in ${CMAKE_SOURCE_DIR}/examples/homogeneous-medium-flat-topography/specfem_config.yaml) +add_subdirectory(homogeneous-medium-flat-topography) +add_subdirectory(fluid-solid-interface) diff --git a/examples/fluid-solid-interface/CMakeLists.txt b/examples/fluid-solid-interface/CMakeLists.txt new file mode 100644 index 00000000..5235ddfa --- /dev/null +++ b/examples/fluid-solid-interface/CMakeLists.txt @@ -0,0 +1,5 @@ + +CMAKE_MINIMUM_REQUIRED(VERSION 3.17.5) + +configure_file(specfem_config.yaml.in ${CMAKE_SOURCE_DIR}/examples/fluid-solid-interface/specfem_config.yaml) +configure_file(Par_File.in ${CMAKE_SOURCE_DIR}/examples/fluid-solid-interface/Par_File) diff --git a/examples/fluid-solid-interface/Par_File.in b/examples/fluid-solid-interface/Par_File.in new file mode 100644 index 00000000..a577d9ee --- /dev/null +++ b/examples/fluid-solid-interface/Par_File.in @@ -0,0 +1,132 @@ +#----------------------------------------------------------- +# +# Simulation input parameters +# +#----------------------------------------------------------- + +# title of job +title = Flat fluid/solid interface + +# parameters concerning partitioning +NPROC = 1 # number of processes + +# Output folder to store mesh related files +OUTPUT_FILES = @CMAKE_SOURCE_DIR@/examples/fluid-solid-interface/OUTPUT_FILES + +#----------------------------------------------------------- +# +# Mesh +# +#----------------------------------------------------------- + +# Partitioning algorithm for decompose_mesh +PARTITIONING_TYPE = 3 # SCOTCH = 3, ascending order (very bad idea) = 1 + +# number of control nodes per element (4 or 9) +NGNOD = 4 + +# location to store the mesh +database_filename = @CMAKE_SOURCE_DIR@/examples/fluid-solid-interface/OUTPUT_FILES/database.bin + +#----------------------------------------------------------- +# +# Receivers +# +#----------------------------------------------------------- + +# use an existing STATION file found in ./DATA or create a new one from the receiver positions below in this Par_file +use_existing_STATIONS = .false. + +# number of receiver sets (i.e. number of receiver lines to create below) +nreceiversets = 1 + +# orientation +anglerec = 0.d0 # angle to rotate components at receivers +rec_normal_to_surface = .false. # base anglerec normal to surface (external mesh and curve file needed) + +# first receiver set (repeat these 6 lines and adjust nreceiversets accordingly) +nrec = 110 # number of receivers +xdeb = 2500.d0 # first receiver x in meters +zdeb = 2933.33333d0 # first receiver z in meters +xfin = 6000.d0 # last receiver x in meters (ignored if only one receiver) +zfin = 2933.33333d0 # last receiver z in meters (ignored if only one receiver) +record_at_surface_same_vertical = .false. # receivers inside the medium or at the surface + +# filename to store stations file +stations_filename = @CMAKE_SOURCE_DIR@/examples/fluid-solid-interface/OUTPUT_FILES/STATIONS + +#----------------------------------------------------------- +# +# Velocity and density models +# +#----------------------------------------------------------- + +# number of model materials +nbmodels = 2 +# available material types (see user manual for more information) +# acoustic: model_number 1 rho Vp 0 0 0 QKappa Qmu 0 0 0 0 0 0 +# elastic: model_number 1 rho Vp Vs 0 0 QKappa Qmu 0 0 0 0 0 0 +# anistoropic: model_number 2 rho c11 c13 c15 c33 c35 c55 c12 c23 c25 0 0 0 +# poroelastic: model_number 3 rhos rhof phi c kxx kxz kzz Ks Kf Kfr etaf mufr Qmu +# tomo: model_number -1 0 9999 9999 A 0 0 9999 9999 0 0 0 0 0 +1 1 2500.d0 3400.d0 1963.d0 0 0 9999 9999 0 0 0 0 0 0 +2 1 1020.d0 1500.d0 0.d0 0 0 9999 9999 0 0 0 0 0 0 + +# external tomography file +TOMOGRAPHY_FILE = ./DATA/tomo_file.xyz + +# use an external mesh created by an external meshing tool or use the internal mesher +read_external_mesh = .false. + +#----------------------------------------------------------- +# +# PARAMETERS FOR EXTERNAL MESHING +# +#----------------------------------------------------------- + +# data concerning mesh, when generated using third-party app (more info in README) +# (see also absorbing_conditions above) +mesh_file = ./DATA/Mesh_canyon/canyon_mesh_file # file containing the mesh +nodes_coords_file = ./DATA/Mesh_canyon/canyon_nodes_coords_file # file containing the nodes coordinates +materials_file = ./DATA/Mesh_canyon/canyon_materials_file # file containing the material number for each element +free_surface_file = ./DATA/Mesh_canyon/canyon_free_surface_file # file containing the free surface +axial_elements_file = ./DATA/axial_elements_file # file containing the axial elements if AXISYM is true +absorbing_surface_file = ./DATA/Mesh_canyon/canyon_absorbing_surface_file # file containing the absorbing surface +acoustic_forcing_surface_file = ./DATA/MSH/Surf_acforcing_Bottom_enforcing_mesh # file containing the acoustic forcing surface +absorbing_cpml_file = ./DATA/absorbing_cpml_file # file containing the CPML element numbers +tangential_detection_curve_file = ./DATA/courbe_eros_nodes # file containing the curve delimiting the velocity model + +#----------------------------------------------------------- +# +# PARAMETERS FOR INTERNAL MESHING +# +#----------------------------------------------------------- + +# file containing interfaces for internal mesh +interfacesfile = @CMAKE_SOURCE_DIR@/examples/fluid-solid-interface/interfaces_fluid_flat.dat + +# geometry of the model (origin lower-left corner = 0,0) and mesh description +xmin = 0.d0 # abscissa of left side of the model +xmax = 6400.d0 # abscissa of right side of the model +nx = 144 # number of elements along X + +# absorbing boundary parameters (see absorbing_conditions above) +absorbbottom = .true. +absorbright = .true. +absorbtop = .true. +absorbleft = .true. + +# define the different regions of the model in the (nx,nz) spectral-element mesh +nbregions = 2 # then set below the different regions and model number for each region +1 144 1 54 1 +1 144 55 108 2 + +#----------------------------------------------------------- +# +# DISPLAY PARAMETERS +# +#----------------------------------------------------------- + +# meshing output +output_grid_Gnuplot = .false. # generate a GNUPLOT file containing the grid, and a script to plot it +output_grid_ASCII = .false. # dump the grid in an ASCII text file consisting of a set of X,Y,Z points or not diff --git a/examples/fluid-solid-interface/README.md b/examples/fluid-solid-interface/README.md new file mode 100644 index 00000000..fbfac340 --- /dev/null +++ b/examples/fluid-solid-interface/README.md @@ -0,0 +1,29 @@ +# Wave propagration through fluid-solid interface + +This example creates the fluid-solid example with flat ocean bottom from [Komatitsch et. al.](https://doi.org/10.1190/1.1444758). + +## Generating the mesh + +To generate the mesh for the homogeneous media we need a parameter file, `Par_File`, a topography file, `topography_file.dat`, and the mesher executible, `xmeshfem2D`, which should have been compiled during the installation process. + +> Currently, we still use a mesher that was developed for the original [SPECFEM2D](https://specfem2d.readthedocs.io/en/latest/03_mesh_generation/) code. More details on the meshing process can be found [here](https://specfem2d.readthedocs.io/en/latest/03_mesh_generation/). + +## Running the mesher + +To execute the mesher run + +``` + ./xmeshfem2D -p +``` + +> Make sure either your are in the build directory of SPECFEM2D kokkos or the build directory is added to your ``PATH``. + +Note the path of the database file and :ref:`stations_file` generated after successfully running the mesher. + +## Running the solver + +Finally, to run the SPECFEM2D kokkos solver + +``` + ./specfem2d -p +``` diff --git a/examples/fluid-solid-interface/sources.yaml b/examples/fluid-solid-interface/sources.yaml new file mode 100644 index 00000000..804bce48 --- /dev/null +++ b/examples/fluid-solid-interface/sources.yaml @@ -0,0 +1,13 @@ +number-of-sources: 1 +sources: + - force: + x : 1575.0 + z : 2900.0 + source_surf: false + angle : 0.0 + vx : 0.0 + vz : 0.0 + Ricker: + factor: 1e9 + tshift: 0.0 + f0: 10.0 diff --git a/examples/fluid-solid-interface/specfem_config.yaml.in b/examples/fluid-solid-interface/specfem_config.yaml.in new file mode 100644 index 00000000..bcbf42ca --- /dev/null +++ b/examples/fluid-solid-interface/specfem_config.yaml.in @@ -0,0 +1,50 @@ +parameters: + + header: + ## Header information is used for logging. It is good practice to give your simulations explicit names + title: Heterogeneous acoustic-elastic medium with 1 acoustic-elastic interface # name for your simulation + # A detailed description for your simulation + description: | + Material systems : Elastic domain (1), Acoustic domain (1) + Interfaces : Acoustic-elastic interface (1) + Sources : Force source (1) + Boundary conditions : Neumann BCs on all edges + + simulation-setup: + ## quadrature setup + quadrature: + alpha: 0.0 + beta: 0.0 + ngllx: 5 + ngllz: 5 + + ## Solver setup + solver: + time-marching: + type-of-simulation: forward + time-scheme: + type: Newmark + dt: 0.85e-3 + nstep: 800 + + receivers: + stations-file: "@CMAKE_SOURCE_DIR@/examples/fluid_solid_interface/OUTPUT_FILES/STATIONS" + angle: 0.0 + seismogram-type: + - displacement + - velocity + nstep_between_samples: 1 + + ## Runtime setup + run-setup: + number-of-processors: 1 + number-of-runs: 1 + + ## databases + databases: + mesh-database: "@CMAKE_SOURCE_DIR@/examples/fluid-solid-interface/OUTPUT_FILES/database.bin" + source-file: "@CMAKE_SOURCE_DIR@/examples/fluid-solid-interface/sources.yaml" + + seismogram: + seismogram-format: ascii + output-folder: "." diff --git a/examples/homogeneous-medium-flat-topography/CMakeLists.txt b/examples/homogeneous-medium-flat-topography/CMakeLists.txt new file mode 100644 index 00000000..98b29e65 --- /dev/null +++ b/examples/homogeneous-medium-flat-topography/CMakeLists.txt @@ -0,0 +1,5 @@ + +CMAKE_MINIMUM_REQUIRED(VERSION 3.17.5) + +configure_file(Par_File.in ${CMAKE_SOURCE_DIR}/examples/homogeneous-medium-flat-topography/Par_File) +configure_file(specfem_config.yaml.in ${CMAKE_SOURCE_DIR}/examples/homogeneous-medium-flat-topography/specfem_config.yaml) diff --git a/examples/homogeneous-medium-flat-topography/Par_File.in b/examples/homogeneous-medium-flat-topography/Par_File.in new file mode 100644 index 00000000..d1319caf --- /dev/null +++ b/examples/homogeneous-medium-flat-topography/Par_File.in @@ -0,0 +1,152 @@ +#----------------------------------------------------------- +# +# Simulation input parameters +# +#----------------------------------------------------------- + +# title of job +title = Elastic Simulation with point source + +# parameters concerning partitioning +NPROC = 1 # number of processes + +# Output folder to store mesh related files +OUTPUT_FILES = @CMAKE_SOURCE_DIR@/examples/homogeneous-medium-flat-topography/OUTPUT_FILES + + +#----------------------------------------------------------- +# +# Mesh +# +#----------------------------------------------------------- + +# Partitioning algorithm for decompose_mesh +PARTITIONING_TYPE = 3 # SCOTCH = 3, ascending order (very bad idea) = 1 + +# number of control nodes per element (4 or 9) +NGNOD = 9 + +# location to store the mesh +database_filename = @CMAKE_SOURCE_DIR@/examples/homogeneous-medium-flat-topography/OUTPUT_FILES/database.bin + +#----------------------------------------------------------- +# +# Receivers +# +#----------------------------------------------------------- + +# use an existing STATION file found in ./DATA or create a new one from the receiver positions below in this Par_file +use_existing_STATIONS = .false. + +# number of receiver sets (i.e. number of receiver lines to create below) +nreceiversets = 2 + +# orientation +anglerec = 0.d0 # angle to rotate components at receivers +rec_normal_to_surface = .false. # base anglerec normal to surface (external mesh and curve file needed) + +# first receiver set (repeat these 6 lines and adjust nreceiversets accordingly) +nrec = 3 # number of receivers +xdeb = 2200. # first receiver x in meters +zdeb = 2200. # first receiver z in meters +xfin = 2800. # last receiver x in meters (ignored if only one receiver) +zfin = 2200. # last receiver z in meters (ignored if only one receiver) +record_at_surface_same_vertical = .true. # receivers inside the medium or at the surface (z values are ignored if this is set to true, they are replaced with the topography height) + +# second receiver set +nrec = 3 # number of receivers +xdeb = 2500. # first receiver x in meters +zdeb = 2500. # first receiver z in meters +xfin = 2500. # last receiver x in meters (ignored if only one receiver) +zfin = 1900. # last receiver z in meters (ignored if only one receiver) +record_at_surface_same_vertical = .false. # receivers inside the medium or at the surface (z values are ignored if this is set to true, they are replaced with the topography height) + +# filename to store stations file +stations_filename = @CMAKE_SOURCE_DIR@/examples/homogeneous-medium-flat-topography/OUTPUT_FILES/STATIONS + +#----------------------------------------------------------- +# +# Velocity and density models +# +#----------------------------------------------------------- + +# number of model materials +nbmodels = 1 +# available material types (see user manual for more information) +# acoustic: model_number 1 rho Vp 0 0 0 QKappa 9999 0 0 0 0 0 0 (for QKappa use 9999 to ignore it) +# elastic: model_number 1 rho Vp Vs 0 0 QKappa Qmu 0 0 0 0 0 0 (for QKappa and Qmu use 9999 to ignore them) +# anisotropic: model_number 2 rho c11 c13 c15 c33 c35 c55 c12 c23 c25 0 QKappa Qmu +# anisotropic in AXISYM: model_number 2 rho c11 c13 c15 c33 c35 c55 c12 c23 c25 c22 QKappa Qmu +# poroelastic: model_number 3 rhos rhof phi c kxx kxz kzz Ks Kf Kfr etaf mufr Qmu +# tomo: model_number -1 0 0 A 0 0 0 0 0 0 0 0 0 0 +# +# note: When viscoelasticity or viscoacousticity is turned on, +# the Vp and Vs values that are read here are the UNRELAXED ones i.e. the values at infinite frequency +# unless the READ_VELOCITIES_AT_f0 parameter above is set to true, in which case they are the values at frequency f0. +# +# Please also note that Qmu is always equal to Qs, but Qkappa is in general not equal to Qp. +# To convert one to the other see doc/Qkappa_Qmu_versus_Qp_Qs_relationship_in_2D_plane_strain.pdf and +# utils/attenuation/conversion_from_Qkappa_Qmu_to_Qp_Qs_from_Dahlen_Tromp_959_960.f90. +1 1 2700.d0 3000.d0 1732.051d0 0 0 9999 9999 0 0 0 0 0 0 +# 2 1 2500.d0 2700.d0 1443.375d0 0 0 9999 9999 0 0 0 0 0 0 +# 3 1 2200.d0 2500.d0 1443.375d0 0 0 9999 9999 0 0 0 0 0 0 +# 4 1 2200.d0 2200.d0 1343.375d0 0 0 9999 9999 0 0 0 0 0 0 + +# external tomography file +TOMOGRAPHY_FILE = ./DATA/tomo_file.xyz + +# use an external mesh created by an external meshing tool or use the internal mesher +read_external_mesh = .false. + +#----------------------------------------------------------- +# +# PARAMETERS FOR EXTERNAL MESHING +# +#----------------------------------------------------------- + +# data concerning mesh, when generated using third-party app (more info in README) +# (see also absorbing_conditions above) +mesh_file = ./DATA/mesh_file # file containing the mesh +nodes_coords_file = ./DATA/nodes_coords_file # file containing the nodes coordinates +materials_file = ./DATA/materials_file # file containing the material number for each element +free_surface_file = ./DATA/free_surface_file # file containing the free surface +axial_elements_file = ./DATA/axial_elements_file # file containing the axial elements if AXISYM is true +absorbing_surface_file = ./DATA/absorbing_surface_file # file containing the absorbing surface +acoustic_forcing_surface_file = ./DATA/MSH/Surf_acforcing_Bottom_enforcing_mesh # file containing the acoustic forcing surface +absorbing_cpml_file = ./DATA/absorbing_cpml_file # file containing the CPML element numbers +tangential_detection_curve_file = ./DATA/courbe_eros_nodes # file containing the curve delimiting the velocity model + +#----------------------------------------------------------- +# +# PARAMETERS FOR INTERNAL MESHING +# +#----------------------------------------------------------- + +# file containing interfaces for internal mesh +interfacesfile = @CMAKE_SOURCE_DIR@/examples/homogeneous-medium-flat-topography/topography.dat + +# geometry of the model (origin lower-left corner = 0,0) and mesh description +xmin = 0.d0 # abscissa of left side of the model +xmax = 4000.d0 # abscissa of right side of the model +nx = 80 # number of elements along X + +# absorbing boundary parameters (see absorbing_conditions above) +absorbbottom = .false. +absorbright = .false. +absorbtop = .false. +absorbleft = .false. + +# define the different regions of the model in the (nx,nz) spectral-element mesh +nbregions = 1 # then set below the different regions and model number for each region +# format of each line: nxmin nxmax nzmin nzmax material_number +1 80 1 60 1 + +#----------------------------------------------------------- +# +# DISPLAY PARAMETERS +# +#----------------------------------------------------------- + +# meshing output +output_grid_Gnuplot = .false. # generate a GNUPLOT file containing the grid, and a script to plot it +output_grid_ASCII = .false. # dump the grid in an ASCII text file consisting of a set of X,Y,Z points or not diff --git a/examples/homogeneous-medium-flat-topography/README.md b/examples/homogeneous-medium-flat-topography/README.md index 9f322790..d068c21a 100644 --- a/examples/homogeneous-medium-flat-topography/README.md +++ b/examples/homogeneous-medium-flat-topography/README.md @@ -1 +1,29 @@ # Wave propagation through homogeneous medium with no interfaces + +In this example we simulate wave propagation through a 2-dimensional homogeneous medium. + +## Generating the mesh + +To generate the mesh for the homogeneous media we need a parameter file, `Par_File`, a topography file, `topography_file.dat`, and the mesher executible, `xmeshfem2D`, which should have been compiled during the installation process. + +> Currently, we still use a mesher that was developed for the original [SPECFEM2D](https://specfem2d.readthedocs.io/en/latest/03_mesh_generation/) code. More details on the meshing process can be found [here](https://specfem2d.readthedocs.io/en/latest/03_mesh_generation/). + +## Running the mesher + +To execute the mesher run + +``` + ./xmeshfem2D -p +``` + +> Make sure either your are in the build directory of SPECFEM2D kokkos or the build directory is added to your ``PATH``. + +Note the path of the database file and :ref:`stations_file` generated after successfully running the mesher. + +## Running the solver + +Finally, to run the SPECFEM2D kokkos solver + +``` + ./specfem2d -p +``` diff --git a/examples/homogeneous-medium-flat-topography/databases/database.bin b/examples/homogeneous-medium-flat-topography/databases/database.bin deleted file mode 100644 index cab102f0..00000000 --- a/examples/homogeneous-medium-flat-topography/databases/database.bin +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:09eacdd4f6fbebea21e1b20005441d97446d4aaa64c156df637b619f8b29502c -size 3245020 diff --git a/examples/homogeneous-medium-flat-topography/source.yaml b/examples/homogeneous-medium-flat-topography/source.yaml index ed49a37f..2a674e3d 100644 --- a/examples/homogeneous-medium-flat-topography/source.yaml +++ b/examples/homogeneous-medium-flat-topography/source.yaml @@ -7,6 +7,7 @@ sources: angle : 0.0 vx : 0.0 vz : 0.0 - Dirac: + Ricker: factor: 1e10 tshift: 0.0 + f0: 10.0 diff --git a/examples/homogeneous-medium-flat-topography/specfem_config.yaml.in b/examples/homogeneous-medium-flat-topography/specfem_config.yaml.in index 144b3cb1..86ed576f 100644 --- a/examples/homogeneous-medium-flat-topography/specfem_config.yaml.in +++ b/examples/homogeneous-medium-flat-topography/specfem_config.yaml.in @@ -21,11 +21,11 @@ parameters: type-of-simulation: forward time-scheme: type: Newmark - dt: 1.1e-5 - nstep: 100 + dt: 1.1e-3 + nstep: 1600 receivers: - stations-file: "@CMAKE_SOURCE_DIR@/examples/homogeneous-medium-flat-topography/STATIONS" + stations-file: "@CMAKE_SOURCE_DIR@/examples/homogeneous-medium-flat-topography/OUTPUT_FILES/STATIONS" angle: 0.0 seismogram-type: - velocity @@ -42,5 +42,5 @@ parameters: ## databases databases: - mesh-database: "@CMAKE_SOURCE_DIR@/examples/homogeneous-medium-flat-topography/databases/database.bin" + mesh-database: "@CMAKE_SOURCE_DIR@/examples/homogeneous-medium-flat-topography/OUTPUT_FILES/database.bin" source-file: "@CMAKE_SOURCE_DIR@/examples/homogeneous-medium-flat-topography/source.yaml" diff --git a/examples/homogeneous-medium-flat-topography/traces.svg b/examples/homogeneous-medium-flat-topography/traces.svg new file mode 100644 index 00000000..54d7fa47 --- /dev/null +++ b/examples/homogeneous-medium-flat-topography/traces.svg @@ -0,0 +1,3456 @@ + + + + + + + + 2023-10-31T13:57:13.974044 + image/svg+xml + + + Matplotlib v3.7.0, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/include/compute/compute.hpp b/include/compute/compute.hpp index ed5de2e9..59764e5b 100644 --- a/include/compute/compute.hpp +++ b/include/compute/compute.hpp @@ -9,6 +9,10 @@ namespace specfem { namespace compute { +/** + * @brief Compute and store global coordinates for the mesh during assembly + * + */ struct coordinates { specfem::kokkos::HostView2d coord; ///< (x, z) for every distinct @@ -17,17 +21,17 @@ struct coordinates { * @name Coodindates meta data **/ ///@{ - type_real xmax; ///< maximum x-coorinate of the quadrature point within this - ///< MPI slice - type_real xmin; ///< minimum x-coorinate of the quadrature point within this - ///< MPI slice - type_real zmax; ///< maximum z-coorinate of the quadrature point within this - ///< MPI slice - type_real zmin; ///< minimum z-coorinate of the quadrature point within this - ///< MPI slice + type_real xmax; ///< maximum x-coorinate of the quadrature point + type_real xmin; ///< minimum x-coorinate of the quadrature point + type_real zmax; ///< maximum z-coorinate of the quadrature point + type_real zmin; ///< minimum z-coorinate of the quadrature point ///@} }; +/** + * @brief Compute and store mesh assembly information + * + */ struct compute { specfem::kokkos::DeviceView3d ibool; ///< Global number for every ///< quadrature point stored on diff --git a/include/compute/compute_boundaries.hpp b/include/compute/compute_boundaries.hpp new file mode 100644 index 00000000..d7178a3c --- /dev/null +++ b/include/compute/compute_boundaries.hpp @@ -0,0 +1,248 @@ +#ifndef _COMPUTE_BOUNDARIES_HPP +#define _COMPUTE_BOUNDARIES_HPP + +#include "enumerations/specfem_enums.hpp" +#include "kokkos_abstractions.h" +#include "material/interface.hpp" +#include "mesh/mesh.hpp" +#include + +namespace specfem { +namespace compute { + +/** + * @namespace Defines special functions used to access structs defined in + * compute module. + * + */ +namespace access { + +/** + * @brief Struct to save boundary types for each element + * + * We store the boundary tag for every edge/node on the element + * + */ +struct boundary_types { + + specfem::enums::element::boundary_tag top = + specfem::enums::element::boundary_tag::none; ///< top boundary tag + specfem::enums::element::boundary_tag bottom = + specfem::enums::element::boundary_tag::none; ///< bottom boundary tag + specfem::enums::element::boundary_tag left = + specfem::enums::element::boundary_tag::none; ///< left boundary tag + specfem::enums::element::boundary_tag right = + specfem::enums::element::boundary_tag::none; ///< right boundary tag + specfem::enums::element::boundary_tag bottom_right = + specfem::enums::element::boundary_tag::none; ///< bottom right boundary + ///< tag + specfem::enums::element::boundary_tag bottom_left = + specfem::enums::element::boundary_tag::none; ///< bottom left boundary tag + specfem::enums::element::boundary_tag top_right = + specfem::enums::element::boundary_tag::none; ///< top right boundary tag + specfem::enums::element::boundary_tag top_left = + specfem::enums::element::boundary_tag::none; ///< top left boundary tag + + /** + * @brief Construct a new boundary types object + * + */ + KOKKOS_FUNCTION boundary_types() = default; + + /** + * @brief Update the tag for a given boundary type + * + * @param type Type of the boundary to update - defines an edge or node + * @param tag Tag to update the boundary with + */ + void update_boundary_type(const specfem::enums::boundaries::type &type, + const specfem::enums::element::boundary_tag &tag); +}; + +/** + * @brief Evaluate if a GLL point is on a boundary of type tag + * + * @param tag Boundary tag to check + * @param type Boundary type to check + * @param iz z-index of GLL point + * @param ix x-index of GLL point + * @param ngllz Number of GLL points in z-direction + * @param ngllx Number of GLL points in x-direction + * @return bool True if the GLL point is on the boundary, false otherwise + */ +KOKKOS_FUNCTION bool +is_on_boundary(const specfem::enums::element::boundary_tag &tag, + const specfem::compute::access::boundary_types &type, + const int &iz, const int &ix, const int &ngllz, + const int &ngllx); +} // namespace access + +/** + * @brief Struct to store the acoustic free surface boundary + * + */ +struct acoustic_free_surface { + + /** + * @brief Construct a new acoustic free surface object + * + * @param kmato Element to material mapping + * @param materials Vector of materials + * @param absorbing_boundaries Absorbing boundary object defined in mesh + * module + * @param acoustic_free_surface Acoustic free surface boundary object defined + * in mesh module + */ + acoustic_free_surface( + const specfem::kokkos::HostView1d kmato, + const std::vector materials, + const specfem::mesh::boundaries::absorbing_boundary &absorbing_boundaries, + const specfem::mesh::boundaries::acoustic_free_surface + &acoustic_free_surface); + + int nelements; ///< Number of elements with acoustic free surface boundary + specfem::kokkos::DeviceView1d ispec; ///< Element indices with acoustic + ///< free surface boundary + specfem::kokkos::HostMirror1d h_ispec; ///< Host mirror of ispec + specfem::kokkos::DeviceView1d + type; ///< Boundary information for each element + specfem::kokkos::HostMirror1d + h_type; ///< Host mirror of type +}; + +/** + * @brief Struct to store the Stacey boundary for a given medium + * + */ +struct stacey_medium { + + /** + * @brief Construct a new stacey medium object + * + */ + stacey_medium() = default; + + /** + * @brief Construct a new stacey medium object + * + * @param medium Type of medium to construct + * @param kmato Element to material mapping + * @param materials Vector of materials + * @param absorbing_boundaries Absorbing boundary object defined in mesh + * module + * @param acoustic_free_surface Acoustic free surface boundary object defined + * in mesh module + */ + stacey_medium( + const specfem::enums::element::type medium, + const specfem::kokkos::HostView1d kmato, + const std::vector materials, + const specfem::mesh::boundaries::absorbing_boundary &absorbing_boundaries, + const specfem::mesh::boundaries::acoustic_free_surface + &acoustic_free_surface); + + int nelements; ///< Number of elements with Stacey boundary + specfem::kokkos::DeviceView1d ispec; ///< Element indices with Stacey + ///< boundary + specfem::kokkos::HostMirror1d h_ispec; ///< Host mirror of ispec + specfem::kokkos::DeviceView1d + type; ///< Boundary information for each element + specfem::kokkos::HostMirror1d + h_type; ///< Host mirror of type +}; + +/** + * @brief Struct to store stacey boundaries on the simulation domain + * + */ +struct stacey { + /** + * @brief Construct a new stacey object + * + * @param kmato Element to material mapping + * @param materials Vector of materials + * @param absorbing_boundaries Absorbing boundary object defined in mesh + * module + * @param acoustic_free_surface Acoustic free surface boundary object defined + * in mesh module + */ + stacey( + const specfem::kokkos::HostView1d kmato, + const std::vector materials, + const specfem::mesh::boundaries::absorbing_boundary &absorbing_boundaries, + const specfem::mesh::boundaries::acoustic_free_surface + &acoustic_free_surface); + + int nelements; ///< Number of elements with Stacey boundary + specfem::compute::stacey_medium elastic; ///< Elastic Stacey boundary + specfem::compute::stacey_medium acoustic; ///< Acoustic Stacey boundary +}; + +/** + * @brief Struct to store Stacey and Dirichlet composite boundaries + * + */ +struct composite_stacey_dirichlet { + /** + * @brief Construct a new composite stacey dirichlet object + * + * @param kmato Element to material mapping + * @param materials Vector of materials + * @param absorbing_boundaries Absorbing boundary object defined in mesh + * module + * @param acoustic_free_surface Acoustic free surface boundary object defined + * in mesh module + */ + composite_stacey_dirichlet( + const specfem::kokkos::HostView1d kmato, + const std::vector materials, + const specfem::mesh::boundaries::absorbing_boundary &absorbing_boundaries, + const specfem::mesh::boundaries::acoustic_free_surface + &acoustic_free_surface); + + int nelements; ///< Number of elements with composite boundary + specfem::kokkos::DeviceView1d ispec; ///< Element indices with composite + ///< boundary + specfem::kokkos::HostMirror1d h_ispec; ///< Host mirror of ispec + specfem::kokkos::DeviceView1d + type; ///< Boundary information for each element + specfem::kokkos::HostMirror1d + h_type; ///< Host mirror of type +}; + +/** + * @brief Struct to store all boundary types + * + */ +struct boundaries { + /** + * @brief Construct a new boundaries object + * + * @param boundaries mesh boundaries object providing the necessary + * information about boundaries within the mesh + */ + boundaries( + const specfem::kokkos::HostView1d kmato, + const std::vector materials, + const specfem::mesh::boundaries::acoustic_free_surface + &acoustic_free_surface, + const specfem::mesh::boundaries::absorbing_boundary &absorbing_boundaries) + : acoustic_free_surface(kmato, materials, absorbing_boundaries, + acoustic_free_surface), + stacey(kmato, materials, absorbing_boundaries, acoustic_free_surface), + composite_stacey_dirichlet(kmato, materials, absorbing_boundaries, + acoustic_free_surface) {} + + specfem::compute::acoustic_free_surface acoustic_free_surface; ///< acoustic + ///< free + ///< surface + ///< boundary + + specfem::compute::stacey stacey; ///< Stacey boundary + specfem::compute::composite_stacey_dirichlet + composite_stacey_dirichlet; ///< Composite Stacey-Dirichlet boundary +}; +} // namespace compute +} // namespace specfem + +#endif diff --git a/include/compute/compute_partial_derivatives.hpp b/include/compute/compute_partial_derivatives.hpp index ca15e99b..ba7d5370 100644 --- a/include/compute/compute_partial_derivatives.hpp +++ b/include/compute/compute_partial_derivatives.hpp @@ -1,7 +1,9 @@ #ifndef _COMPUTE_PARTIAL_DERIVATIVES_HPP #define _COMPUTE_PARTIAL_DERIVATIVES_HPP +#include "enumerations/specfem_enums.hpp" #include "kokkos_abstractions.h" +#include "macros.hpp" #include "quadrature/interface.hpp" #include "specfem_setup.hpp" #include @@ -17,34 +19,26 @@ namespace compute { */ struct partial_derivatives { specfem::kokkos::DeviceView3d xix; ///< inverted partial derivates - ///< \f$\partial \xi / \partial - ///< x\f$ stored on the device + ///< @xix stored on the device specfem::kokkos::HostMirror3d h_xix; ///< inverted partial - ///< derivates \f$\partial \xi - ///< / \partial x\f$ stored on + ///< derivates @xix stored on ///< the host specfem::kokkos::DeviceView3d xiz; ///< inverted partial derivates - ///< \f$\partial \xi / \partial - ///< z\f$ stored on the device - specfem::kokkos::HostMirror3d h_xiz; ///< inverted partial - ///< derivates \f$\partial \xi - ///< / \partial z\f$ stored on - ///< the host - specfem::kokkos::DeviceView3d gammax; ///< inverted partial - ///< derivates \f$\partial - ///< \gamma / \partial x\f$ - ///< stored on device + ///< @xiz stored on the device + specfem::kokkos::HostMirror3d h_xiz; ///< inverted partial + ///< derivates @xiz stored on + ///< the host + specfem::kokkos::DeviceView3d gammax; ///< inverted partial + ///< derivates @gammax + ///< stored on device specfem::kokkos::HostMirror3d h_gammax; ///< inverted partial - ///< derivates \f$\partial - ///< \gamma / \partial x\f$ + ///< derivates @gammax ///< stored on host specfem::kokkos::DeviceView3d gammaz; ///< inverted partial - ///< derivates \f$\partial - ///< \gamma / \partial z\f$ + ///< derivates @gammaz ///< stored on device specfem::kokkos::HostMirror3d h_gammaz; ///< inverted partial - ///< derivates \f$\partial - ///< \gamma / \partial z\f$ + ///< derivates @gammaz ///< stored on host specfem::kokkos::DeviceView3d jacobian; ///< Jacobian values stored ///< on device @@ -75,14 +69,92 @@ struct partial_derivatives { const specfem::kokkos::HostView2d knods, const specfem::quadrature::quadrature *quadx, const specfem::quadrature::quadrature *quadz); - /** * @brief Helper routine to sync views within this struct * */ void sync_views(); }; + +/** + * @brief Struct to store the partial derivatives of the element at a given + * quadrature point + * + */ +struct element_partial_derivatives { + type_real xix; + type_real gammax; + type_real xiz; + type_real gammaz; + type_real jacobian; + + KOKKOS_FUNCTION + element_partial_derivatives() = default; + + KOKKOS_FUNCTION + element_partial_derivatives(const type_real &xix, const type_real &gammax, + const type_real &xiz, const type_real &gammaz) + : xix(xix), gammax(gammax), xiz(xiz), gammaz(gammaz) {} + + KOKKOS_FUNCTION + element_partial_derivatives(const type_real &xix, const type_real &gammax, + const type_real &xiz, const type_real &gammaz, + const type_real &jacobian) + : xix(xix), gammax(gammax), xiz(xiz), gammaz(gammaz), jacobian(jacobian) { + } + + // KOKKOS_FUNCTION specfem::kokkos::array_type + // specfem::compute::element_partial_derivatives::compute_normal( + // const specfem::enums::boundaries::type type) const; + + template + KOKKOS_INLINE_FUNCTION specfem::kokkos::array_type + compute_normal() const { + ASSERT(false, "Invalid boundary type"); + return specfem::kokkos::array_type(); + }; +}; } // namespace compute } // namespace specfem +template <> +KOKKOS_INLINE_FUNCTION specfem::kokkos::array_type +specfem::compute::element_partial_derivatives::compute_normal< + specfem::enums::boundaries::type::BOTTOM>() const { + specfem::kokkos::array_type dn; + dn[0] = -1.0 * this->gammax * this->jacobian; + dn[1] = -1.0 * this->gammaz * this->jacobian; + return dn; +}; + +template <> +KOKKOS_INLINE_FUNCTION specfem::kokkos::array_type +specfem::compute::element_partial_derivatives::compute_normal< + specfem::enums::boundaries::type::TOP>() const { + specfem::kokkos::array_type dn; + dn[0] = this->gammax * this->jacobian; + dn[1] = this->gammaz * this->jacobian; + return dn; +}; + +template <> +KOKKOS_INLINE_FUNCTION specfem::kokkos::array_type +specfem::compute::element_partial_derivatives::compute_normal< + specfem::enums::boundaries::type::LEFT>() const { + specfem::kokkos::array_type dn; + dn[0] = -1.0 * this->xix * this->jacobian; + dn[1] = -1.0 * this->xiz * this->jacobian; + return dn; +}; + +template <> +KOKKOS_INLINE_FUNCTION specfem::kokkos::array_type +specfem::compute::element_partial_derivatives::compute_normal< + specfem::enums::boundaries::type::RIGHT>() const { + specfem::kokkos::array_type dn; + dn[0] = this->xix * this->jacobian; + dn[1] = this->xiz * this->jacobian; + return dn; +}; + #endif diff --git a/include/compute/compute_properties.hpp b/include/compute/compute_properties.hpp index f8cf3449..f7922919 100644 --- a/include/compute/compute_properties.hpp +++ b/include/compute/compute_properties.hpp @@ -1,6 +1,7 @@ #ifndef _COMPUTE_PROPERTIES_HPP #define _COMPUTE_PROPERTIES_HPP +#include "enumerations/specfem_enums.hpp" #include "kokkos_abstractions.h" #include "material/interface.hpp" #include "specfem_setup.hpp" @@ -27,7 +28,8 @@ struct properties { specfem::kokkos::DeviceView3d mu; specfem::kokkos::HostMirror3d h_mu; - specfem::kokkos::HostView3d kappa; + specfem::kokkos::DeviceView3d kappa; + specfem::kokkos::HostMirror3d h_kappa; specfem::kokkos::HostView3d qmu; @@ -37,14 +39,21 @@ struct properties { specfem::kokkos::HostView3d rho_vs; + specfem::kokkos::DeviceView3d rho_inverse; + specfem::kokkos::HostMirror3d h_rho_inverse; + specfem::kokkos::DeviceView3d lambdaplus2mu; specfem::kokkos::HostMirror3d h_lambdaplus2mu; + + specfem::kokkos::DeviceView3d lambdaplus2mu_inverse; + specfem::kokkos::HostMirror3d h_lambdaplus2mu_inverse; + ///@} // element type is defined in specfem_setup.hpp - specfem::kokkos::DeviceView1d + specfem::kokkos::DeviceView1d ispec_type; ///< type of element ///< stored on device - specfem::kokkos::HostMirror1d + specfem::kokkos::HostMirror1d h_ispec_type; ///< type of element ///< stored on host @@ -81,6 +90,50 @@ struct properties { void sync_views(); }; +template +struct element_properties {}; + +template <> +struct element_properties { + type_real lambdaplus2mu; + type_real mu; + type_real rho; + type_real lambda; + + type_real rho_vp; + type_real rho_vs; + + KOKKOS_FUNCTION + element_properties() = default; + + KOKKOS_FUNCTION + element_properties(const type_real &lambdaplus2mu, const type_real &mu, + const type_real &rho) + : lambdaplus2mu(lambdaplus2mu), mu(mu), rho(rho), + lambda(lambdaplus2mu - 2 * mu), rho_vp(sqrt(rho * lambdaplus2mu)), + rho_vs(sqrt(rho * mu)) {} +}; + +template <> +struct element_properties { + type_real lambdaplus2mu_inverse; + type_real rho_inverse; + + type_real rho_vpinverse; + + KOKKOS_FUNCTION + element_properties() = default; + + KOKKOS_FUNCTION + element_properties(const type_real &lambdaplus2mu_inverse, + const type_real &rho_inverse) + : lambdaplus2mu_inverse(lambdaplus2mu_inverse), rho_inverse(rho_inverse), + rho_vpinverse(sqrt(rho_inverse * lambdaplus2mu_inverse)) {} +}; + } // namespace compute } // namespace specfem diff --git a/include/compute/compute_receivers.hpp b/include/compute/compute_receivers.hpp index 0121625f..a82baebf 100644 --- a/include/compute/compute_receivers.hpp +++ b/include/compute/compute_receivers.hpp @@ -66,12 +66,24 @@ struct receivers { ///< seismograms ///< stored on the ///< device - specfem::kokkos::DeviceView1d + specfem::kokkos::DeviceView1d seismogram_types; ///< Types of seismograms to be calculated stored on ///< the device - specfem::kokkos::HostMirror1d + specfem::kokkos::HostMirror1d h_seismogram_types; ///< Types of seismograms to be calculated stored on ///< the host + specfem::kokkos::DeviceView6d receiver_field; ///< Receiver field + ///< inside the + ///< element where + ///< receiver is + ///< located stored + ///< on the device + specfem::kokkos::HostMirror6d h_receiver_field; ///< Receiver field + ///< inside the + ///< element where + ///< receiver is + ///< located stored + ///< on the host /** * @brief Default constructor @@ -88,7 +100,7 @@ struct receivers { * @param mpi Pointer to the MPI object */ receivers(const std::vector &receivers, - const std::vector &stypes, + const std::vector &stypes, const specfem::quadrature::quadrature *quadx, const specfem::quadrature::quadrature *quadz, const type_real xmax, const type_real xmin, const type_real zmax, const type_real zmin, diff --git a/include/compute/coupled_interfaces.hpp b/include/compute/coupled_interfaces.hpp new file mode 100644 index 00000000..55313ee4 --- /dev/null +++ b/include/compute/coupled_interfaces.hpp @@ -0,0 +1,264 @@ +#ifndef _COMPUTE_COUPLED_INTERFACES_HPP +#define _COMPUTE_COUPLED_INTERFACES_HPP + +#include "enumerations/specfem_enums.hpp" +#include "kokkos_abstractions.h" +#include "macros.hpp" +#include "mesh/coupled_interfaces/coupled_interfaces.hpp" + +namespace specfem { +namespace compute { +namespace coupled_interfaces { +/** + * @brief Elastic-Acoustic interface information + * + */ +struct elastic_acoustic { + specfem::kokkos::HostMirror1d h_elastic_ispec; ///< Index of the spectal + ///< element on the + ///< elastic side of the + ///< interface (host + ///< mirror) + specfem::kokkos::HostMirror1d h_acoustic_ispec; ///< Index of the spectal + ///< element on the + ///< acoustic side of the + ///< interface (host + ///< mirror) + specfem::kokkos::DeviceView1d elastic_ispec; ///< Index of the spectal + ///< element on the elastic + ///< side of the interface + specfem::kokkos::DeviceView1d acoustic_ispec; ///< Index of the spectal + ///< element on the + ///< acoustic side of the + ///< interface + specfem::kokkos::DeviceView1d + elastic_edge; ///< Which edge of the element is coupled to the acoustic + ///< element + specfem::kokkos::DeviceView1d + acoustic_edge; ///< Which edge of the element is coupled to the elastic + ///< element + specfem::kokkos::HostMirror1d + h_elastic_edge; ///< Which edge of the element is coupled to the acoustic + ///< element (host mirror) + specfem::kokkos::HostMirror1d + h_acoustic_edge; ///< Which edge of the element is coupled to the elastic + ///< element (host mirror) + int num_interfaces; ///< Total number of edges coupled between elastic and + ///< acoustic elements + + /** + * @brief Construct a new elastic acoustic interface + * + * @param h_ibool Global Index for every quadrature point in the mesh + * @param coord coordinates of every quadrature point in the mesh + * @param h_ispec_type Element type (acoustic/elastic) for every element in + * the mesh + * @param elastic_acoustic Interface information for every elastic-acoustic + * interface read from mesher + */ + elastic_acoustic( + const specfem::kokkos::HostMirror3d h_ibool, + const specfem::kokkos::HostView2d coord, + const specfem::kokkos::HostView1d + h_ispec_type, + const specfem::mesh::coupled_interfaces::elastic_acoustic + &elastic_acoustic); +}; +/** + * @brief Elastic-Poroelastic interface information + * + */ +struct elastic_poroelastic { + specfem::kokkos::HostMirror1d h_elastic_ispec; ///< Index of the spectal + ///< element on the + ///< elastic side of the + ///< interface (host + ///< mirror) + specfem::kokkos::HostMirror1d + h_poroelastic_ispec; ///< Index of the spectal element on the poroelastic + ///< side of the interface (host mirror) + specfem::kokkos::DeviceView1d elastic_ispec; ///< Index of the spectal + ///< element on the elastic + ///< side of the interface + specfem::kokkos::DeviceView1d poroelastic_ispec; ///< Index of the + ///< spectal element on + ///< the poroelastic + ///< side of the + ///< interface + specfem::kokkos::DeviceView1d + elastic_edge; ///< Which edge of the element is coupled to the poroelastic + ///< element + specfem::kokkos::DeviceView1d + poroelastic_edge; ///< Which edge of the element is coupled to the elastic + ///< element + specfem::kokkos::HostMirror1d + h_elastic_edge; ///< Which edge of the element is coupled to the + ///< poroelastic element (host mirror) + specfem::kokkos::HostMirror1d + h_poroelastic_edge; ///< Which edge of the element is coupled to the + ///< elastic element (host mirror) + int num_interfaces; ///< Total number of edges coupled between elastic and + ///< poroelastic elements + + /** + * @brief Contruct a new elastic poroelastic interface + * + * @param h_ibool Index for every quadrature point in the mesh + * @param coord Coordinates of every quadrature point in the mesh + * @param h_ispec_type Element type (elastic/poroelastic) for every element in + * the mesh + * @param elastic_poroelastic Interface information for every + * elastic-poroelastic interface read from mesher + */ + elastic_poroelastic( + const specfem::kokkos::HostMirror3d h_ibool, + const specfem::kokkos::HostView2d coord, + const specfem::kokkos::HostView1d + h_ispec_type, + const specfem::mesh::coupled_interfaces::elastic_poroelastic + &elastic_poroelastic); +}; +/** + * @brief Acoustic-Poroelastic interface information + * + */ +struct acoustic_poroelastic { + specfem::kokkos::HostMirror1d h_acoustic_ispec; ///< Index of the spectal + ///< element on the + ///< acoustic side of the + ///< interface (host + ///< mirror) + specfem::kokkos::HostMirror1d + h_poroelastic_ispec; ///< Index of the spectal element on the poroelastic + ///< side of the interface (host mirror) + specfem::kokkos::DeviceView1d acoustic_ispec; ///< Index of the spectal + ///< element on the + ///< acoustic side of the + ///< interface + specfem::kokkos::DeviceView1d poroelastic_ispec; ///< Index of the + ///< spectal element on + ///< the poroelastic + ///< side of the + ///< interface + specfem::kokkos::DeviceView1d + acoustic_edge; ///< Which edge of the element is coupled to the + ///< poroelastic element + specfem::kokkos::DeviceView1d + poroelastic_edge; ///< Which edge of the element is coupled to the + ///< acoustic element + specfem::kokkos::HostMirror1d + h_acoustic_edge; ///< Which edge of the element is coupled to the + ///< poroelastic element (host mirror) + specfem::kokkos::HostMirror1d + h_poroelastic_edge; ///< Which edge of the element is coupled to the + ///< acoustic element (host mirror) + int num_interfaces; ///< Total number of edges coupled between acoustic and + ///< poroelastic elements + + /** + * @brief Construct a new acoustic poroelastic interface + * + * @param h_ibool Index for every quadrature point in the mesh + * @param coord Coordinates of every quadrature point in the mesh + * @param h_ispec_type Element type (acoustic/poroelastic) for every element + * in the mesh + * @param acoustic_poroelastic Interface information for every + * acoustic-poroelastic interface read from mesher + */ + acoustic_poroelastic( + const specfem::kokkos::HostMirror3d h_ibool, + const specfem::kokkos::HostView2d coord, + const specfem::kokkos::HostView1d + h_ispec_type, + const specfem::mesh::coupled_interfaces::acoustic_poroelastic + &acoustic_poroelastic); +}; + +/** + * @brief Struct used to store all interface information at every interfacial + * quadrature point within the mesh + * + */ +struct coupled_interfaces { +public: + specfem::compute::coupled_interfaces::elastic_acoustic + elastic_acoustic; ///< Elastic-Acoustic interface information + specfem::compute::coupled_interfaces::elastic_poroelastic + elastic_poroelastic; ///< Elastic-Poroelastic interface information + specfem::compute::coupled_interfaces::acoustic_poroelastic + acoustic_poroelastic; ///< Acoustic-Poroelastic interface information + + /** + * @brief Construct a new coupled interfaces object + * + * @param h_ibool Index for every quadrature point in the mesh + * @param coord Coordinates of every quadrature point in the mesh + * @param h_ispec_type Element type (acoustic/elastic/poroelastic) for every + * element in the mesh + * @param coupled_interfaces Interface information for every interface read + * from mesher + */ + coupled_interfaces( + const specfem::kokkos::HostMirror3d h_ibool, + const specfem::kokkos::HostView2d coord, + const specfem::kokkos::HostView1d + h_ispec_type, + const specfem::mesh::coupled_interfaces::coupled_interfaces + &coupled_interfaces); +}; + +/** + * @namespace Helper functions to access the edges at an interface + * + */ +namespace access { + +/** + * @brief Compute the number of points at an edge of an element + * + * @param edge Orientation of the edge + * @param ngllx Number of GLL points in the x-direction + * @param ngllz Number of GLL points in the z-direction + */ +KOKKOS_FUNCTION +int npoints(const specfem::enums::edge::type &edge, const int ngllx, + const int ngllz); + +/** + * @brief Get the index of quadrature point of self domain (ix, iz) at an edge + * of an element given the edge orientation and index of the quadrature point on + * that edge + * + * @param ipoint Index of the quadrature point on the edge + * @param edge Orientation of the edge + * @param ngllx Number of GLL points in the x-direction + * @param ngllz Number of GLL points in the z-direction + * @param i ix index of the quadrature point + * @param j iz index of the quadrature point + */ +KOKKOS_FUNCTION +void self_iterator(const int &ipoint, const specfem::enums::edge::type &edge, + const int ngllx, const int ngllz, int &i, int &j); + +/** + * @brief Get the index of quadrature point of coupled domain (ix, iz) at an + * edge of an element given the edge orientation and index of the quadrature + * point on that edge + * + * @param ipoint Index of the quadrature point on the edge + * @param edge Orientation of the edge + * @param ngllx Number of GLL points in the x-direction + * @param ngllz Number of GLL points in the z-direction + * @param i ix index of the quadrature point + * @param j iz index of the quadrature point + */ +KOKKOS_FUNCTION +void coupled_iterator(const int &ipoint, const specfem::enums::edge::type &edge, + const int ngllx, const int ngllz, int &i, int &j); + +} // namespace access +} // namespace coupled_interfaces +} // namespace compute +} // namespace specfem + +#endif diff --git a/include/compute/interface.hpp b/include/compute/interface.hpp index 98b568ea..fb291282 100644 --- a/include/compute/interface.hpp +++ b/include/compute/interface.hpp @@ -2,9 +2,11 @@ #define _COMPUTE_INTERFACE_HPP #include "compute.hpp" +#include "compute_boundaries.hpp" #include "compute_partial_derivatives.hpp" #include "compute_properties.hpp" #include "compute_receivers.hpp" #include "compute_sources.hpp" +#include "coupled_interfaces.hpp" #endif diff --git a/include/coupled_interface/coupled_interface.hpp b/include/coupled_interface/coupled_interface.hpp new file mode 100644 index 00000000..ac984684 --- /dev/null +++ b/include/coupled_interface/coupled_interface.hpp @@ -0,0 +1,92 @@ +#ifndef _COUPLED_INTERFACE_HPP_ +#define _COUPLED_INTERFACE_HPP_ + +#include "compute/interface.hpp" +#include "enumerations/interface.hpp" +#include "impl/edge/interface.hpp" +#include "kokkos_abstractions.h" +#include "specfem_setup.hpp" + +namespace specfem { +namespace coupled_interface { +/** + * @brief Class to compute the coupling between two domains. + * + * @tparam self_domain_type Primary domain of the interface. + * @tparam coupled_domain_type Coupled domain of the interface. + */ +template +class coupled_interface { +public: + /** + * @brief Typedefs + * + */ + ///@{ + /** + * @brief Self medium type. + * + */ + using self_medium = typename self_domain_type::medium_type; + /** + * @brief Coupled medium type. + * + */ + using coupled_medium = typename coupled_domain_type::medium_type; + /** + * @brief Quadrature points object to define the quadrature points either at + * compile time or run time. + * + */ + using quadrature_points_type = + typename self_domain_type::quadrature_points_type; + ///@} + + /** + * @brief Construct a new coupled interface object + * + * @param self_domain Primary domain of the interface. + * @param coupled_domain Coupled domain of the interface. + * @param coupled_interfaces struct containing the coupling information. + * @param quadrature_points A quadrature points object defining the quadrature + * points either at compile time or run time. + * @param partial_derivatives struct containing the partial derivatives. + * @param ibool Global index of the GLL points. + * @param wxgll weights for the GLL quadrature points in the x direction. + * @param wzgll weights for the GLL quadrature points in the z direction. + */ + coupled_interface( + self_domain_type &self_domain, coupled_domain_type &coupled_domain, + const specfem::compute::coupled_interfaces::coupled_interfaces + &coupled_interfaces, + const quadrature_points_type &quadrature_points, + const specfem::compute::partial_derivatives &partial_derivatives, + const specfem::kokkos::DeviceView3d ibool, + const specfem::kokkos::DeviceView1d wxgll, + const specfem::kokkos::DeviceView1d wzgll); + + /** + * @brief Compute the coupling between the primary and coupled domains. + * + */ + void compute_coupling(); + +private: + int nedges; ///< Number of edges in the interface. + specfem::kokkos::DeviceView1d + self_edge; ///< Orientation of the edge of the primary domain. + specfem::kokkos::DeviceView1d + coupled_edge; ///< Orientation of the edge of the coupled domain. + self_domain_type self_domain; ///< Primary domain of the interface. + coupled_domain_type coupled_domain; ///< Coupled domain of the interface. + quadrature_points_type quadrature_points; ///< Quadrature points object to + ///< define the quadrature points + ///< either at compile time or run + ///< time. + specfem::coupled_interface::impl::edges::edge + edge; ///< Edge class to implement coupling physics +}; +} // namespace coupled_interface +} // namespace specfem +#endif // _COUPLED_INTERFACES_HPP_ diff --git a/include/coupled_interface/coupled_interface.tpp b/include/coupled_interface/coupled_interface.tpp new file mode 100644 index 00000000..87672786 --- /dev/null +++ b/include/coupled_interface/coupled_interface.tpp @@ -0,0 +1,89 @@ +#ifndef _COUPLED_INTERFACE_TPP +#define _COUPLED_INTERFACE_TPP + +#include "compute/interface.hpp" +#include "coupled_interface.hpp" +#include "impl/edge/interface.hpp" +#include "kokkos_abstractions.h" +#include "macros.hpp" +#include "enumerations/interface.hpp" +#include + +template +specfem::coupled_interface:: + coupled_interface::coupled_interface( + self_domain_type &self_domain, coupled_domain_type &coupled_domain, + const specfem::compute::coupled_interfaces::coupled_interfaces + &coupled_interfaces, + const quadrature_points_type &quadrature_points, + const specfem::compute::partial_derivatives &partial_derivatives, + const specfem::kokkos::DeviceView3d ibool, + const specfem::kokkos::DeviceView1d wxgll, + const specfem::kokkos::DeviceView1d wzgll) + : nedges(coupled_interfaces.elastic_acoustic.num_interfaces), + self_domain(self_domain), coupled_domain(coupled_domain), + quadrature_points(quadrature_points), + edge(self_domain, coupled_domain, quadrature_points, coupled_interfaces, + partial_derivatives, wxgll, wzgll, ibool) { + + static_assert(std::is_same_v == false, + "Error: self_medium cannot be equal to coupled_medium"); + + bool constexpr elastic_acoustic_condition = + (std::is_same_v && + std::is_same_v) || + (std::is_same_v && + std::is_same_v); + + static_assert(elastic_acoustic_condition, + "Only acoustic-elastic coupling is supported at the moment."); + + if constexpr (std::is_same_v) { + this->self_edge = coupled_interfaces.elastic_acoustic.elastic_edge; + this->coupled_edge = coupled_interfaces.elastic_acoustic.acoustic_edge; + } else { + this->self_edge = coupled_interfaces.elastic_acoustic.acoustic_edge; + this->coupled_edge = coupled_interfaces.elastic_acoustic.elastic_edge; + } + + return; +} + +template +void specfem::coupled_interface::coupled_interface< + self_domain_type, coupled_domain_type>::compute_coupling() { + + if (this->nedges == 0) + return; + + Kokkos::parallel_for( + "specfem::coupled_interfaces::coupled_interfaces::compute_coupling", + specfem::kokkos::DeviceTeam(this->nedges, Kokkos::AUTO, 1), + KOKKOS_CLASS_LAMBDA( + const specfem::kokkos::DeviceTeam::member_type &team_member) { + // Get number of quadrature points + int ngllx, ngllz; + quadrature_points.get_ngll(&ngllx, &ngllz); + int iedge_l = team_member.league_rank(); + // Get the edge + const auto self_edge_l = this->self_edge(iedge_l); + const auto coupled_edge_l = this->coupled_edge(iedge_l); + + auto npoints = specfem::compute::coupled_interfaces::access::npoints( + self_edge_l, ngllx, ngllz); + + // Iterate over the edges using TeamThreadRange + Kokkos::parallel_for( + Kokkos::TeamThreadRange(team_member, npoints), + [=](const int ipoint) { edge.compute_coupling(iedge_l, ipoint); }); + }); + + Kokkos::fence(); + + return; +} + +#endif // _COUPLED_INTERFACE_TPP diff --git a/include/coupled_interface/impl/edge/edge.hpp b/include/coupled_interface/impl/edge/edge.hpp new file mode 100644 index 00000000..06641d88 --- /dev/null +++ b/include/coupled_interface/impl/edge/edge.hpp @@ -0,0 +1,107 @@ +#ifndef _COUPLED_INTERFACE_IMPL_EDGE_HPP +#define _COUPLED_INTERFACE_IMPL_EDGE_HPP + +#include "compute/coupled_interfaces.hpp" +#include "enumerations/interface.hpp" +#include + +namespace specfem { +namespace coupled_interface { +namespace impl { +namespace edges { + +/** + * @brief Wrapper for iterator class to iterate through points on the primary + * domain of a coupled interface. + * + */ +struct self_iterator { + int ngllx; ///< Number of GLL points in the x direction. + int ngllz; ///< Number of GLL points in the z direction. + + self_iterator() = default; + + /** + * @brief Construct a new self iterator object + * + * @param ngllx ///< Number of GLL points in the x direction. + * @param ngllz ///< Number of GLL points in the z direction. + */ + self_iterator(const int &ngllx, const int &ngllz) + : ngllx(ngllx), ngllz(ngllz){}; + + /** + * @brief Operator to iterate through points on the primary domain of a + * coupled interface. + * + * @param ipoint Index of the point on the edge of the primary domain. + * @param iedge_type Type of the edge of the primary domain. + * @param i X index of the quadrature point inside the element of the primary + * domain which forms the edge. + * @param j Z index of the quadrature point inside the element of the coupled + * domain which forms the edge. + */ + KOKKOS_FUNCTION + void operator()(const int &ipoint, + const specfem::enums::edge::type &iedge_type, int &i, + int &j) const { + specfem::compute::coupled_interfaces::access::self_iterator( + ipoint, iedge_type, this->ngllx, this->ngllz, i, j); + return; + } +}; + +/** + * @brief Wrapper for iterator class to iterate through points on the coupled + * domain of a coupled interface. + * + */ +struct coupled_iterator { + int ngllx; ///< Number of GLL points in the x direction. + int ngllz; ///< Number of GLL points in the z direction. + + coupled_iterator() = default; + + /** + * @brief Construct a new coupled iterator object + * + * @param ngllx Number of GLL points in the x direction. + * @param ngllz Number of GLL points in the z direction. + */ + coupled_iterator(const int &ngllx, const int &ngllz) + : ngllx(ngllx), ngllz(ngllz){}; + + /** + * @brief Operator to iterate through points on the coupled domain of a + * coupled interface. + * + * @param ipoint Index of the point on the edge of the coupled domain. + * @param iedge_type Type of the edge of the coupled domain. + * @param i X index of the quadrature point inside the element of the coupled + * domain which forms the edge. + * @param j Z index of the quadrature point inside the element of the coupled + * domain which forms the edge. + */ + KOKKOS_FUNCTION + void operator()(const int &ipoint, + const specfem::enums::edge::type &iedge_type, int &i, + int &j) const { + specfem::compute::coupled_interfaces::access::coupled_iterator( + ipoint, iedge_type, this->ngllx, this->ngllz, i, j); + return; + } +}; + +/** + * @brief Coupling edge class to define coupling physics between 2 domains. + * + * @tparam self_domain Primary domain of the interface. + * @tparam coupled_domain Coupled domain of the interface. + */ +template class edge {}; +} // namespace edges +} // namespace impl +} // namespace coupled_interface +} // namespace specfem + +#endif // _COUPLED_INTERFACE_IMPL_EDGE_HPP diff --git a/include/coupled_interface/impl/edge/elastic_acoustic/acoustic_elastic.hpp b/include/coupled_interface/impl/edge/elastic_acoustic/acoustic_elastic.hpp new file mode 100644 index 00000000..8c0acc7d --- /dev/null +++ b/include/coupled_interface/impl/edge/elastic_acoustic/acoustic_elastic.hpp @@ -0,0 +1,144 @@ +#ifndef _COUPLED_INTERFACE_IMPL_ACOUSTIC_ELASTIC_EDGE_HPP +#define _COUPLED_INTERFACE_IMPL_ACOUSTIC_ELASTIC_EDGE_HPP + +#include "coupled_interface/impl/edge/edge.hpp" +#include "domain/interface.hpp" +#include "enumerations/interface.hpp" +#include "kokkos_abstractions.h" +#include "specfem_setup.hpp" +#include + +namespace specfem { +namespace coupled_interface { +namespace impl { +namespace edges { +/** + * @brief Template specialization for the edge between an acoustic and an + * elastic domain. + * + * @tparam qp_type Quadrature points type. + */ +template +class edge< + specfem::domain::domain, + specfem::domain::domain > { +public: + /** + * @name Typedefs + * + */ + ///@{ + /** + * @brief Self medium type. + */ + using self_medium = typename specfem::domain::domain< + specfem::enums::element::medium::acoustic, qp_type>::medium_type; + /** + * @brief Coupled medium type. + * + */ + using coupled_medium = + typename specfem::domain::domain::medium_type; + /** + * @brief Quadrature points type. + * + */ + using quadrature_points_type = qp_type; + ///@} + + edge(){}; + + /** + * @brief Construct a new coupling edge object + * + * @param self_domain Primary domain of the interface (acoustic). + * @param coupled_domain Coupled domain of the interface (elastic). + * @param quadrature_points A quadrature points object defining the quadrature + * points either at compile time or run time. + * @param coupled_interfaces struct containing the coupling information. + * @param partial_derivatives struct containing the partial derivatives. + * @param wxgll weights for the GLL quadrature points in the x direction. + * @param wzgll weights for the GLL quadrature points in the z direction. + * @param ibool Global indexing for all GLL points + */ + edge(const specfem::domain::domain &self_domain, + const specfem::domain::domain &coupled_domain, + const qp_type &quadrature_points, + const specfem::compute::coupled_interfaces::coupled_interfaces + &coupled_interfaces, + const specfem::compute::partial_derivatives &partial_derivatives, + const specfem::kokkos::DeviceView1d wxgll, + const specfem::kokkos::DeviceView1d wzgll, + const specfem::kokkos::DeviceView3d ibool); + + /** + * @brief Compute the coupling between the acoustic and elastic domains. + * + * @param iedge Index of the edge. + * @param ipoint Index of the quadrature point on the edge. + */ + KOKKOS_FUNCTION + void compute_coupling(const int &iedge, const int &ipoint) const; + + /** + * @brief Get the orientation of edges on the coupled interface. + * + * @param iedge Index of the edge. + * @param self_edge_type Orientation of the edge on the self domain. + * @param coupled_edge_type Orientation of the edge on the coupled domain. + */ + KOKKOS_FUNCTION void + get_edges(const int &iedge, specfem::enums::edge::type &self_edge_type, + specfem::enums::edge::type &coupled_edge_type) const { + self_edge_type = this->acoustic_edge(iedge); + coupled_edge_type = this->elastic_edge(iedge); + return; + } + +private: + specfem::kokkos::DeviceView1d acoustic_ispec; ///< Index of acoustic + ///< elements on the edge + specfem::kokkos::DeviceView1d elastic_ispec; ///< Index of elastic + ///< elements on the edge + specfem::kokkos::DeviceView3d ibool; ///< Global indexing for all GLL + ///< points + specfem::kokkos::DeviceView3d xix; ///< xix + specfem::kokkos::DeviceView3d xiz; ///< xiz + specfem::kokkos::DeviceView3d gammax; ///< gammax + specfem::kokkos::DeviceView3d gammaz; ///< gammaz + specfem::kokkos::DeviceView3d jacobian; ///< Jacobian + specfem::kokkos::DeviceView1d + acoustic_edge; ///< Orientation of edges on the acoustic domain + specfem::kokkos::DeviceView1d + elastic_edge; ///< Orientation of edges on the elastic domain + specfem::kokkos::DeviceView2d + self_field_dot_dot; ///< Second derivative of potential field on the + ///< acoustic domain + specfem::kokkos::DeviceView2d + coupled_field; ///< Displacement on the elastic domain + qp_type quadrature_points; ///< Quadrature points object defining the + ///< quadrature points either at compile time or + ///< run time. + specfem::kokkos::DeviceView1d wxgll; ///< Weights for the GLL + ///< quadrature points in the + ///< x direction + specfem::kokkos::DeviceView1d wzgll; ///< Weights for the GLL + ///< quadrature points in the + ///< z direction + + specfem::coupled_interface::impl::edges::self_iterator + self_iterator; ///< Iterator for points on the edge in the primary domain + specfem::coupled_interface::impl::edges::coupled_iterator + coupled_iterator; ///< Iterator for points on the edge in the coupled + ///< domain +}; +} // namespace edges +} // namespace impl +} // namespace coupled_interface +} // namespace specfem + +#endif // _COUPLED_INTERFACE_IMPL_ACOUSTIC_ELASTIC_EDGE_HPP diff --git a/include/coupled_interface/impl/edge/elastic_acoustic/acoustic_elastic.tpp b/include/coupled_interface/impl/edge/elastic_acoustic/acoustic_elastic.tpp new file mode 100644 index 00000000..2918e648 --- /dev/null +++ b/include/coupled_interface/impl/edge/elastic_acoustic/acoustic_elastic.tpp @@ -0,0 +1,147 @@ +#ifndef _COUPLED_INTERFACE_IMPL_ACOUSTIC_ELASTIC_TPP +#define _COUPLED_INTERFACE_IMPL_ACOUSTIC_ELASTIC_TPP + +#include "compute/interface.hpp" +#include "coupled_interface/impl/edge/edge.hpp" +#include "coupled_interface/impl/edge/elastic_acoustic/acoustic_elastic.hpp" +#include "domain/interface.hpp" +#include "kokkos_abstractions.h" +#include "macros.hpp" +#include "enumerations/interface.hpp" +#include "specfem_setup.hpp" +#include + +template +specfem::coupled_interface::impl::edges::edge< + specfem::domain::domain, + specfem::domain::domain >:: + edge(const specfem::domain::domain< + specfem::enums::element::medium::acoustic, qp_type> &self_domain, + const specfem::domain::domain &coupled_domain, + const qp_type &quadrature_points, + const specfem::compute::coupled_interfaces::coupled_interfaces + &coupled_interfaces, + const specfem::compute::partial_derivatives &partial_derivatives, + const specfem::kokkos::DeviceView1d wxgll, + const specfem::kokkos::DeviceView1d wzgll, + const specfem::kokkos::DeviceView3d ibool) + : acoustic_ispec(coupled_interfaces.elastic_acoustic.acoustic_ispec), + elastic_ispec(coupled_interfaces.elastic_acoustic.elastic_ispec), + acoustic_edge(coupled_interfaces.elastic_acoustic.acoustic_edge), + elastic_edge(coupled_interfaces.elastic_acoustic.elastic_edge), + ibool(ibool), xix(partial_derivatives.xix), xiz(partial_derivatives.xiz), + gammax(partial_derivatives.gammax), gammaz(partial_derivatives.gammaz), + jacobian(partial_derivatives.jacobian), + self_field_dot_dot(self_domain.get_field_dot_dot()), + coupled_field(coupled_domain.get_field()), + quadrature_points(quadrature_points), wxgll(wxgll), wzgll(wzgll) { + + int ngllx, ngllz; + quadrature_points.get_ngll(&ngllx, &ngllz); + +#ifndef NDEBUG + assert(ibool.extent(1) == ngllz); + assert(ibool.extent(2) == ngllx); + assert(partial_derivatives.xix.extent(1) == ngllz); + assert(partial_derivatives.xix.extent(2) == ngllx); + assert(partial_derivatives.xiz.extent(1) == ngllz); + assert(partial_derivatives.xiz.extent(2) == ngllx); + assert(partial_derivatives.gammax.extent(1) == ngllz); + assert(partial_derivatives.gammax.extent(2) == ngllx); + assert(partial_derivatives.gammaz.extent(1) == ngllz); + assert(partial_derivatives.gammaz.extent(2) == ngllx); + assert(partial_derivatives.jacobian.extent(1) == ngllz); + assert(partial_derivatives.jacobian.extent(2) == ngllx); + assert(wxgll.extent(0) == ngllx); + assert(wzgll.extent(0) == ngllz); +#endif + + self_iterator = + specfem::coupled_interface::impl::edges::self_iterator(ngllx, ngllz); + + coupled_iterator = + specfem::coupled_interface::impl::edges::coupled_iterator(ngllx, ngllz); + +#ifndef NDEBUG + assert(self_field_dot_dot.extent(1) == self_medium::components); + assert(coupled_field.extent(1) == coupled_medium::components); +#endif + + return; +} + +template +KOKKOS_FUNCTION void specfem::coupled_interface::impl::edges::edge< + specfem::domain::domain, + specfem::domain::domain >::compute_coupling(const int &iedge, + const int &ipoint) + const { + + int ngllx, ngllz; + quadrature_points.get_ngll(&ngllx, &ngllz); + + const auto acoustic_edge_type = this->acoustic_edge(iedge); + const auto elastic_edge_type = this->elastic_edge(iedge); + + const int acoustic_ispec_l = this->acoustic_ispec(iedge); + const int elastic_ispec_l = this->elastic_ispec(iedge); + + int ix, iz; + coupled_iterator(ipoint, elastic_edge_type, ix, iz); + + int iglob = ibool(elastic_ispec_l, iz, ix); + const type_real displ_x = coupled_field(iglob, 0); + const type_real displ_z = coupled_field(iglob, 1); + + type_real val; + + switch (acoustic_edge_type) { + case specfem::enums::edge::type::LEFT: + self_iterator(ipoint, acoustic_edge_type, ix, iz); + iglob = ibool(acoustic_ispec_l, iz, ix); + val = -1.0 * wzgll(iz) * + (xix(acoustic_ispec_l, iz, ix) * jacobian(acoustic_ispec_l, iz, ix) * + displ_x + + xiz(acoustic_ispec_l, iz, ix) * jacobian(acoustic_ispec_l, iz, ix) * + displ_z); + Kokkos::atomic_add(&self_field_dot_dot(iglob, 0), val); + break; + case specfem::enums::edge::type::RIGHT: + self_iterator(ipoint, acoustic_edge_type, ix, iz); + iglob = ibool(acoustic_ispec_l, iz, ix); + val = wzgll(iz) * (xix(acoustic_ispec_l, iz, ix) * + jacobian(acoustic_ispec_l, iz, ix) * displ_x + + xiz(acoustic_ispec_l, iz, ix) * + jacobian(acoustic_ispec_l, iz, ix) * displ_z); + Kokkos::atomic_add(&self_field_dot_dot(iglob, 0), val); + break; + case specfem::enums::edge::type::BOTTOM: + self_iterator(ipoint, acoustic_edge_type, ix, iz); + iglob = ibool(acoustic_ispec_l, iz, ix); + val = -1.0 * wxgll(ix) * + (gammax(acoustic_ispec_l, iz, ix) * + jacobian(acoustic_ispec_l, iz, ix) * displ_x + + gammaz(acoustic_ispec_l, iz, ix) * + jacobian(acoustic_ispec_l, iz, ix) * displ_z); + Kokkos::atomic_add(&self_field_dot_dot(iglob, 0), val); + break; + case specfem::enums::edge::type::TOP: + self_iterator(ipoint, acoustic_edge_type, ix, iz); + iglob = ibool(acoustic_ispec_l, iz, ix); + val = wxgll(ix) * (gammax(acoustic_ispec_l, iz, ix) * + jacobian(acoustic_ispec_l, iz, ix) * displ_x + + gammaz(acoustic_ispec_l, iz, ix) * + jacobian(acoustic_ispec_l, iz, ix) * displ_z); + Kokkos::atomic_add(&self_field_dot_dot(iglob, 0), val); + break; + default: + break; + } + + return; +} + +#endif // _COUPLED_INTERFACE_IMPL_ACOUSTIC_ELASTIC_TPP diff --git a/include/coupled_interface/impl/edge/elastic_acoustic/elastic_acoustic.hpp b/include/coupled_interface/impl/edge/elastic_acoustic/elastic_acoustic.hpp new file mode 100644 index 00000000..645c7c87 --- /dev/null +++ b/include/coupled_interface/impl/edge/elastic_acoustic/elastic_acoustic.hpp @@ -0,0 +1,144 @@ +#ifndef _COUPLED_INTERFACE_IMPL_ELASTIC_ACOUSTIC_EDGE_HPP +#define _COUPLED_INTERFACE_IMPL_ELASTIC_ACOUSTIC_EDGE_HPP + +#include "coupled_interface/impl/edge/edge.hpp" +#include "domain/interface.hpp" +#include "enumerations/interface.hpp" +#include "kokkos_abstractions.h" +#include "specfem_setup.hpp" +#include + +namespace specfem { +namespace coupled_interface { +namespace impl { +namespace edges { +/** + * @brief Template specialization for the edge between an acoustic and an + * elastic domain. + * + * @tparam qp_type Quadrature points type. + */ +template +class edge< + specfem::domain::domain, + specfem::domain::domain > { + +public: + /** + * @name Typedefs + * + */ + ///@{ + /** + * @brief Self medium type. + */ + using self_medium = + typename specfem::domain::domain::medium_type; + /** + * @brief Coupled medium type. + * + */ + using coupled_medium = typename specfem::domain::domain< + specfem::enums::element::medium::acoustic, qp_type>::medium_type; + /** + * @brief Quadrature points type. + * + */ + using quadrature_points_type = qp_type; + ///@} + + edge(){}; + + /** + * @brief Construct a new coupling edge object + * + * @param self_domain Primary domain of the interface (elastic). + * @param coupled_domain Coupled domain of the interface (acoustic). + * @param quadrature_points A quadrature points object defining the quadrature + * points either at compile time or run time. + * @param coupled_interfaces struct used to store coupling information. + * @param partial_derivatives struct used to store partial derivatives. + * @param wxgll weights for the GLL quadrature points in the x direction. + * @param wzgll weights for the GLL quadrature points in the z direction. + * @param ibool Global indexing for all GLL points + */ + edge(const specfem::domain::domain &self_domain, + const specfem::domain::domain &coupled_domain, + const qp_type &quadrature_points, + const specfem::compute::coupled_interfaces::coupled_interfaces + &coupled_interfaces, + const specfem::compute::partial_derivatives &partial_derivatives, + const specfem::kokkos::DeviceView1d wxgll, + const specfem::kokkos::DeviceView1d wzgll, + const specfem::kokkos::DeviceView3d ibool); + + /** + * @brief Compute coupling interaction between domains + * + * @param iedge Index of the edge. + * @param ipoint Index of the quadrature point on the edge. + */ + KOKKOS_FUNCTION + void compute_coupling(const int &iedge, const int &ipoint) const; + + /** + * @brief Get the orientation of coupling edges + * + * @param iedge Index of the edge. + * @param self_edge_type Orientation of edge in primary domain. + * @param coupled_edge_type Orientation of edge in coupled domain. + */ + KOKKOS_FUNCTION void + get_edges(const int &iedge, specfem::enums::edge::type &self_edge_type, + specfem::enums::edge::type &coupled_edge_type) const { + self_edge_type = this->elastic_edge(iedge); + coupled_edge_type = this->acoustic_edge(iedge); + return; + } + +private: + specfem::kokkos::DeviceView1d acoustic_ispec; ///< Index of acoustic + ///< elements on the edge + specfem::kokkos::DeviceView1d elastic_ispec; ///< Index of elastic + ///< elements on the edge + specfem::kokkos::DeviceView3d ibool; ///< Global indexing for all GLL + ///< points + specfem::kokkos::DeviceView3d xix; ///< xix + specfem::kokkos::DeviceView3d xiz; ///< xiz + specfem::kokkos::DeviceView3d gammax; ///< gammax + specfem::kokkos::DeviceView3d gammaz; ///< gammaz + specfem::kokkos::DeviceView3d jacobian; ///< Jacobian + specfem::kokkos::DeviceView1d + acoustic_edge; ///< Orientation of edge in acoustic domain + specfem::kokkos::DeviceView1d + elastic_edge; ///< Orientation of edge in elastic domain + specfem::kokkos::DeviceView2d + self_field_dot_dot; ///< Acceleration in elastic domain + specfem::kokkos::DeviceView2d + coupled_field_dot_dot; ///< Second derivative of potential in acoustic + ///< domain + qp_type quadrature_points; ///< Quadrature points object to define quadrature + ///< points at compile time or run time + specfem::kokkos::DeviceView1d wxgll; ///< Weights for the GLL + ///< quadrature points in the + ///< x direction + specfem::kokkos::DeviceView1d wzgll; ///< Weights for the GLL + ///< quadrature points in the + ///< z direction + + specfem::coupled_interface::impl::edges::self_iterator + self_iterator; ///< Iterator for points on the edge in the primary domain + specfem::coupled_interface::impl::edges::coupled_iterator + coupled_iterator; ///< Iterator for points on the edge in the coupled + ///< domain +}; +} // namespace edges +} // namespace impl +} // namespace coupled_interface +} // namespace specfem + +#endif /* _COUPLED_INTERFACE_IMPL_ELASTIC_ACOUSTIC_EDGE_HPP */ diff --git a/include/coupled_interface/impl/edge/elastic_acoustic/elastic_acoustic.tpp b/include/coupled_interface/impl/edge/elastic_acoustic/elastic_acoustic.tpp new file mode 100644 index 00000000..2d3383f6 --- /dev/null +++ b/include/coupled_interface/impl/edge/elastic_acoustic/elastic_acoustic.tpp @@ -0,0 +1,150 @@ +#ifndef _COUPLED_INTERFACE_IMPL_ELASTIC_ACOUSTIC_EDGE_TPP +#define _COUPLED_INTERFACE_IMPL_ELASTIC_ACOUSTIC_EDGE_TPP + +#include "compute/interface.hpp" +#include "coupled_interface/impl/edge/edge.hpp" +#include "coupled_interface/impl/edge/elastic_acoustic/elastic_acoustic.hpp" +#include "domain/interface.hpp" +#include "kokkos_abstractions.h" +#include "macros.hpp" +#include "enumerations/interface.hpp" +#include "specfem_setup.hpp" +#include + +template +specfem::coupled_interface::impl::edges::edge< + specfem::domain::domain, + specfem::domain::domain >:: + edge(const specfem::domain::domain &self_domain, + const specfem::domain::domain &coupled_domain, + const qp_type &quadrature_points, + const specfem::compute::coupled_interfaces::coupled_interfaces + &coupled_interfaces, + const specfem::compute::partial_derivatives &partial_derivatives, + const specfem::kokkos::DeviceView1d wxgll, + const specfem::kokkos::DeviceView1d wzgll, + const specfem::kokkos::DeviceView3d ibool) + : acoustic_ispec(coupled_interfaces.elastic_acoustic.acoustic_ispec), + elastic_ispec(coupled_interfaces.elastic_acoustic.elastic_ispec), + acoustic_edge(coupled_interfaces.elastic_acoustic.acoustic_edge), + elastic_edge(coupled_interfaces.elastic_acoustic.elastic_edge), + ibool(ibool), xix(partial_derivatives.xix), xiz(partial_derivatives.xiz), + gammax(partial_derivatives.gammax), gammaz(partial_derivatives.gammaz), + jacobian(partial_derivatives.jacobian), + self_field_dot_dot(self_domain.get_field_dot_dot()), + coupled_field_dot_dot(coupled_domain.get_field_dot_dot()), + quadrature_points(quadrature_points), wxgll(wxgll), wzgll(wzgll) { + + int ngllx, ngllz; + quadrature_points.get_ngll(&ngllx, &ngllz); + +#ifndef NDEBUG + assert(ibool.extent(1) == ngllz); + assert(ibool.extent(2) == ngllx); + assert(partial_derivatives.xix.extent(1) == ngllz); + assert(partial_derivatives.xix.extent(2) == ngllx); + assert(partial_derivatives.xiz.extent(1) == ngllz); + assert(partial_derivatives.xiz.extent(2) == ngllx); + assert(partial_derivatives.gammax.extent(1) == ngllz); + assert(partial_derivatives.gammax.extent(2) == ngllx); + assert(partial_derivatives.gammaz.extent(1) == ngllz); + assert(partial_derivatives.gammaz.extent(2) == ngllx); + assert(partial_derivatives.jacobian.extent(1) == ngllz); + assert(partial_derivatives.jacobian.extent(2) == ngllx); + assert(wxgll.extent(0) == ngllx); + assert(wzgll.extent(0) == ngllz); +#endif + + self_iterator = + specfem::coupled_interface::impl::edges::self_iterator(ngllx, ngllz); + coupled_iterator = + specfem::coupled_interface::impl::edges::coupled_iterator(ngllx, ngllz); + +#ifndef NDEBUG + assert(self_field_dot_dot.extent(1) == self_medium::components); + assert(coupled_field_dot_dot.extent(1) == coupled_medium::components); +#endif + + return; +} + +template +KOKKOS_FUNCTION void specfem::coupled_interface::impl::edges::edge< + specfem::domain::domain, + specfem::domain::domain >::compute_coupling(const int &iedge, + const int &ipoint) + const { + int ngllx, ngllz; + + quadrature_points.get_ngll(&ngllx, &ngllz); + + const auto acoustic_edge_type = this->acoustic_edge(iedge); + const auto elastic_edge_type = this->elastic_edge(iedge); + + const int acoustic_ispec_l = this->acoustic_ispec(iedge); + const int elastic_ispec_l = this->elastic_ispec(iedge); + + int ix, iz; + coupled_iterator(ipoint, acoustic_edge_type, ix, iz); + + int iglob = ibool(acoustic_ispec_l, iz, ix); + type_real pressure = -1.0 * coupled_field_dot_dot(iglob, 0); + + type_real valx, valz; + + switch (acoustic_edge_type) { + case specfem::enums::edge::type::LEFT: + valx = -1.0 * wzgll(iz) * + (xix(acoustic_ispec_l, iz, ix) * jacobian(acoustic_ispec_l, iz, ix) * + pressure); + valz = -1.0 * wzgll(iz) * + (xiz(acoustic_ispec_l, iz, ix) * jacobian(acoustic_ispec_l, iz, ix) * + pressure); + self_iterator(ipoint, elastic_edge_type, ix, iz); + iglob = ibool(elastic_ispec_l, iz, ix); + Kokkos::atomic_add(&self_field_dot_dot(iglob, 0), valx); + Kokkos::atomic_add(&self_field_dot_dot(iglob, 1), valz); + break; + case specfem::enums::edge::type::RIGHT: + valx = wzgll(iz) * (xix(acoustic_ispec_l, iz, ix) * + jacobian(acoustic_ispec_l, iz, ix) * pressure); + valz = wzgll(iz) * (xiz(acoustic_ispec_l, iz, ix) * + jacobian(acoustic_ispec_l, iz, ix) * pressure); + self_iterator(ipoint, elastic_edge_type, ix, iz); + iglob = ibool(elastic_ispec_l, iz, ix); + Kokkos::atomic_add(&self_field_dot_dot(iglob, 0), valx); + Kokkos::atomic_add(&self_field_dot_dot(iglob, 1), valz); + break; + case specfem::enums::edge::type::BOTTOM: + valx = -1.0 * wxgll(ix) * + (gammax(acoustic_ispec_l, iz, ix) * + jacobian(acoustic_ispec_l, iz, ix) * pressure); + valz = -1.0 * wxgll(ix) * + (gammaz(acoustic_ispec_l, iz, ix) * + jacobian(acoustic_ispec_l, iz, ix) * pressure); + self_iterator(ipoint, elastic_edge_type, ix, iz); + iglob = ibool(elastic_ispec_l, iz, ix); + Kokkos::atomic_add(&self_field_dot_dot(iglob, 0), valx); + Kokkos::atomic_add(&self_field_dot_dot(iglob, 1), valz); + break; + case specfem::enums::edge::type::TOP: + valx = wxgll(ix) * (gammax(acoustic_ispec_l, iz, ix) * + jacobian(acoustic_ispec_l, iz, ix) * pressure); + valz = wxgll(ix) * (gammaz(acoustic_ispec_l, iz, ix) * + jacobian(acoustic_ispec_l, iz, ix) * pressure); + self_iterator(ipoint, elastic_edge_type, ix, iz); + iglob = ibool(elastic_ispec_l, iz, ix); + Kokkos::atomic_add(&self_field_dot_dot(iglob, 0), valx); + Kokkos::atomic_add(&self_field_dot_dot(iglob, 1), valz); + break; + default: + assert(false); + break; + } +} + +#endif // _COUPLED_INTERFACE_IMPL_ELASTIC_ACOUSTIC_EDGE_TPP diff --git a/include/coupled_interface/impl/edge/interface.hpp b/include/coupled_interface/impl/edge/interface.hpp new file mode 100644 index 00000000..d0bcdd09 --- /dev/null +++ b/include/coupled_interface/impl/edge/interface.hpp @@ -0,0 +1,10 @@ +#ifndef _COUPLED_INTERFACE_IMPL_EDGE_INTERFACE_HPP +#define _COUPLED_INTERFACE_IMPL_EDGE_INTERFACE_HPP + +#include "edge.hpp" +#include "elastic_acoustic/acoustic_elastic.hpp" +#include "elastic_acoustic/acoustic_elastic.tpp" +#include "elastic_acoustic/elastic_acoustic.hpp" +#include "elastic_acoustic/elastic_acoustic.tpp" + +#endif // _COUPLED_INTERFACE_IMPL_EDGE_INTERFACE_HPP diff --git a/include/coupled_interface/interface.hpp b/include/coupled_interface/interface.hpp new file mode 100644 index 00000000..fdc62188 --- /dev/null +++ b/include/coupled_interface/interface.hpp @@ -0,0 +1,8 @@ +#ifndef _COUPLED_INTERFACE_INTERFACE_HPP +#define _COUPLED_INTERFACE_INTERFACE_HPP + +#include "coupled_interface.hpp" +#include "coupled_interface.tpp" +#include "impl/edge/interface.hpp" + +#endif // _COUPLED_INTERFACE_INTERFACE_HPP diff --git a/include/domain/domain.hpp b/include/domain/domain.hpp index 011c4348..c103d2f1 100644 --- a/include/domain/domain.hpp +++ b/include/domain/domain.hpp @@ -2,149 +2,249 @@ #define _DOMAIN_HPP #include "compute/interface.hpp" +#include "impl/interface.hpp" +#include "impl/receivers/interface.hpp" +#include "impl/sources/interface.hpp" #include "quadrature/interface.hpp" #include "specfem_setup.hpp" #include -// using simd_type = Kokkos::Experimental::native_simd; - namespace specfem { -namespace Domain { +namespace domain { /** - * @brief Base Domain class + * @brief domain class + * + * Domain class serves as the driver used to compute the elemental kernels. It + * describes the parallelism and updates the wavefield at each time step. * + * @tparam medium class defining the domain medium. Separate implementations + * exist for elastic, acoustic or poroelastic media + * @tparam quadrature_points class used to define the quadrature points either + * at compile time or run time + * + * Domain implementation details: + * - field -> stores a 2 dimensional field along different components. The + * components may vary based of medium type. For example Acoustic domain have + * only 1 component i.e. potential, Elastic domain have 2 components i.e. X,Z */ -class Domain { - +template class domain { public: + using dimension = specfem::enums::element::dimension::dim2; ///< Dimension of + ///< the domain + using medium_type = medium; ///< Type of medium i.e. acoustic, elastic or + ///< poroelastic + using quadrature_points_type = qp_type; ///< Type of quadrature points i.e. + ///< static or dynamic + + /** + * @brief Alias for scratch view type + * + * @code + * template + * using ScratchViewType = Kokkos::View>; + * @endcode + * + * @tparam T type of scratch view + * @tparam N Extent of scratch view in 3rd dimension + */ + template + using ScratchViewType = + typename quadrature_points_type::template ScratchViewType; + + /** + * @brief Construct a new domain object + * + * @param nglob Total number of distinct quadrature points + * @param quadrature_points Type of quadrature points - either static (number + * of quadrature points defined at compile time) or dynamic (number of + * quadrature points defined at runtime) + * @param compute Pointer to compute struct used to store spectral element + * numbering mapping (ibool) + * @param material_properties properties struct used to store material + * properties at each quadrature point + * @param partial_derivatives partial derivatives struct used to store partial + * derivatives of basis functions at each quadrature point + * @param compute_sources sources struct used to store source information + * @param compute_receivers receivers struct used to store receiver + * information + * @param quadx Quadrature object in x-dimension + * @param quadz Quadrature object in z-dimension + */ + domain(const int nglob, const qp_type &quadrature_points, + specfem::compute::compute *compute, + specfem::compute::properties material_properties, + specfem::compute::partial_derivatives partial_derivatives, + specfem::compute::boundaries boundary_conditions, + specfem::compute::sources compute_sources, + specfem::compute::receivers compute_receivers, + specfem::quadrature::quadrature *quadx, + specfem::quadrature::quadrature *quadz); + + /** + * @brief Default destructor + * + */ + ~domain() = default; + + /** + * @brief Initialize the domain + * + */ + template + void mass_time_contribution(const type_real dt) { + kernels.template mass_time_contribution(dt); + }; + + /** + * @brief Compute interaction of stiffness matrix on acceleration + * + */ + void compute_stiffness_interaction() { + kernels.compute_stiffness_interaction(); + }; + + /** + * @brief Invert the mass matrix + * + */ + void invert_mass_matrix(); + /** - * @brief Get a view of the field stored on the device + * @brief Divide the acceleration by the mass matrix + * + */ + void divide_mass_matrix(); + + /** + * @brief Compute interaction of sources on acceleration + * + * @param timeval + */ + void compute_source_interaction(const type_real timeval) { + kernels.compute_source_interaction(timeval); + }; + + /** + * @brief Sync displacements views between host and device + * + * @param kind defines sync direction i.e. DeviceToHost or HostToDevice + */ + void sync_field(specfem::sync::kind kind); + + /** + * @brief Sync velocity views between host and device + * + * @param kind defines sync direction i.e. DeviceToHost or HostToDevice + */ + void sync_field_dot(specfem::sync::kind kind); + + /** + * @brief Sync acceleration views between host and device + * + * @param kind defines sync direction i.e. DeviceToHost or HostToDevice + */ + void sync_field_dot_dot(specfem::sync::kind kind); + + /** + * @brief Sync inverse of mass matrix views between host and device + * + * @param kind defines sync direction i.e. DeviceToHost or HostToDevice + */ + void sync_rmass_inverse(specfem::sync::kind kind); + + /** + * @brief Compute seismograms at for all receivers at isig_step + * + * @param seismogram_types DeviceView of types of seismograms to be + * calculated + * @param isig_step timestep for seismogram calculation + */ + void compute_seismogram(const int isig_step) { + kernels.compute_seismograms(isig_step); + }; + + /** + * @brief Get a view of field stored on the device * * @return specfem::kokkos::DeviceView2d */ - virtual specfem::kokkos::DeviceView2d + specfem::kokkos::DeviceView2d get_field() const { return this->field; } + /** - * @brief Get a view of the field stored on the host + * @brief Get a view of field stored on the host * - * @return specfem::kokkos::HostMirror2d + * @return specfem::kokkos::DeviceView2d */ - virtual specfem::kokkos::HostMirror2d + specfem::kokkos::HostMirror2d get_host_field() const { return this->h_field; } + /** - * @brief Get a view of the derivative of field stored on the device + * @brief Get a view of derivate of field stored on device * * @return specfem::kokkos::DeviceView2d */ - virtual specfem::kokkos::DeviceView2d + specfem::kokkos::DeviceView2d get_field_dot() const { return this->field_dot; } + /** - * @brief Get a view of the derivative of field stored on the host + * @brief Get a view of derivative of field stored on host * - * @return specfem::kokkos::HostMirror2d + * @return specfem::kokkos::DeviceView2d */ - virtual specfem::kokkos::HostMirror2d + specfem::kokkos::HostMirror2d get_host_field_dot() const { return this->h_field_dot; } + /** - * @brief Get a view of the second derivative of field stored on the Device + * @brief Get a view of double derivative of field stored on device * * @return specfem::kokkos::DeviceView2d */ - virtual specfem::kokkos::DeviceView2d + specfem::kokkos::DeviceView2d get_field_dot_dot() const { return this->field_dot_dot; } + /** - * @brief Get a view of the second derivative of field stored on the host + * @brief Get a view of double derivative of field stored on host * - * @return specfem::kokkos::HostMirror2d + * @return specfem::kokkos::DeviceView2d */ - virtual specfem::kokkos::HostMirror2d + specfem::kokkos::HostMirror2d get_host_field_dot_dot() const { return this->h_field_dot_dot; } + /** - * @brief Get a view of rmass_inverse stored on the device + * @brief Get a view of inverse of mass matrix stored on device * * @return specfem::kokkos::DeviceView2d */ - virtual specfem::kokkos::DeviceView2d + specfem::kokkos::DeviceView2d get_rmass_inverse() const { return this->rmass_inverse; } + /** - * @brief Get a view of rmass_inverse stored on the host + * @brief Get a view of inverse of mass matrix stored on host * - * @return specfem::kokkos::HostMirror2d + * @return specfem::kokkos::DeviceView2d */ - virtual specfem::kokkos::HostMirror2d + specfem::kokkos::HostMirror2d get_host_rmass_inverse() const { return this->h_rmass_inverse; } - /** - * @brief Compute interaction of stiffness matrix on second derivative of - * field - * - */ - virtual void compute_stiffness_interaction_calling_routine(){}; - /** - * @brief Divide the second derivative of field by the mass matrix - * - */ - virtual void divide_mass_matrix(){}; - /** - * @brief Compute interaction of sources on second derivative of field - * - * @param timeval - */ - virtual void compute_source_interaction(const type_real timeval){}; - - /** - * @brief Sync field views between host and device - * - * @param kind defines sync direction i.e. DeviceToHost or HostToDevice - */ - virtual void sync_field(specfem::sync::kind kind){}; - /** - * @brief Sync derivative of field views between host and device - * - * @param kind defines sync direction i.e. DeviceToHost or HostToDevice - */ - virtual void sync_field_dot(specfem::sync::kind kind){}; - /** - * @brief Sync second derivative of field views between host and device - * - * @param kind defines sync direction i.e. DeviceToHost or HostToDevice - */ - virtual void sync_field_dot_dot(specfem::sync::kind kind){}; - /** - * @brief Sync inverse of mass matrix views between host and device - * - * @param kind defines sync direction i.e. DeviceToHost or HostToDevice - */ - virtual void sync_rmass_inverse(specfem::sync::kind kind){}; - /** - * @brief Compute seismograms at for all receivers at isig_step - * - * @param seismogram_types DeviceView of types of seismograms to be calculated - * @param isig_step timestep for seismogram calculation - */ - virtual void compute_seismogram(const int isig_step){}; - // /** - // * @brief Load arrays required for compute forces into simd_arrays when - // * compiled with explicit SIMD types, or else reference original arrays. - // * - // */ - // virtual void simd_configure_arrays(); private: specfem::kokkos::DeviceView2d @@ -173,9 +273,13 @@ class Domain { h_rmass_inverse; ///< View of inverse ///< of mass matrix ///< on host + int nelem_domain; ///< Total number of elements in this domain + + specfem::domain::impl::kernels::kernels + kernels; ///< Kernels object used to compute elemental kernels }; +} // namespace domain -} // namespace Domain } // namespace specfem #endif diff --git a/include/domain/domain.tpp b/include/domain/domain.tpp new file mode 100644 index 00000000..d340b614 --- /dev/null +++ b/include/domain/domain.tpp @@ -0,0 +1,229 @@ +#ifndef _DOMAIN_TPP +#define _DOMAIN_TPP + +#include "compute/interface.hpp" +#include "domain.hpp" +#include "enumerations/interface.hpp" +#include "impl/interface.hpp" +#include "impl/receivers/interface.hpp" +#include "impl/sources/interface.hpp" +#include "kokkos_abstractions.h" +#include "quadrature/interface.hpp" +#include "specfem_setup.hpp" +#include +#include + +namespace { +template +void initialize_views( + const int &nglob, + specfem::kokkos::DeviceView2d field, + specfem::kokkos::DeviceView2d field_dot, + specfem::kokkos::DeviceView2d field_dot_dot, + specfem::kokkos::DeviceView2d + rmass_inverse) { + + constexpr int components = medium::components; + + Kokkos::parallel_for( + "specfem::domain::domain::initiaze_views", + specfem::kokkos::DeviceMDrange<2, Kokkos::Iterate::Left>( + { 0, 0 }, { nglob, components }), + KOKKOS_LAMBDA(const int iglob, const int idim) { + field(iglob, idim) = 0; + field_dot(iglob, idim) = 0; + field_dot_dot(iglob, idim) = 0; + rmass_inverse(iglob, idim) = 0; + }); +} + +template +void initialize_rmass_inverse( + const specfem::domain::impl::kernels::kernels &kernels, + specfem::kokkos::DeviceView2d + &rmass_inverse) { + // Compute the mass matrix + + const int nglob = rmass_inverse.extent(0); + const int components = rmass_inverse.extent(1); + + kernels.compute_mass_matrix(); + + // Kokkos::fence(); + + // // Invert the mass matrix + // Kokkos::parallel_for( + // "specfem::domain::domain::invert_rmass_matrix", + // specfem::kokkos::DeviceMDrange<2, Kokkos::Iterate::Left>( + // { 0, 0 }, { nglob, components }), + // KOKKOS_LAMBDA(const int iglob, const int idim) { + // if (rmass_inverse(iglob, idim) == 0) { + // rmass_inverse(iglob, idim) = 1.0; + // } else { + // rmass_inverse(iglob, idim) = 1.0 / rmass_inverse(iglob, idim); + // } + // }); + + // Kokkos::fence(); + + return; +} +} // namespace + +template +specfem::domain::domain::domain( + const int nglob, const qp_type &quadrature_points, + specfem::compute::compute *compute, + specfem::compute::properties material_properties, + specfem::compute::partial_derivatives partial_derivatives, + specfem::compute::boundaries boundary_conditions, + specfem::compute::sources compute_sources, + specfem::compute::receivers compute_receivers, + specfem::quadrature::quadrature *quadx, + specfem::quadrature::quadrature *quadz) + : field(specfem::kokkos::DeviceView2d( + "specfem::domain::domain::field", nglob, medium::components)), + field_dot(specfem::kokkos::DeviceView2d( + "specfem::domain::domain::field_dot", nglob, medium::components)), + field_dot_dot( + specfem::kokkos::DeviceView2d( + "specfem::domain::domain::field_dot_dot", nglob, + medium::components)), + rmass_inverse( + specfem::kokkos::DeviceView2d( + "specfem::domain::domain::rmass_inverse", nglob, + medium::components)) { + + this->h_field = Kokkos::create_mirror_view(this->field); + this->h_field_dot = Kokkos::create_mirror_view(this->field_dot); + this->h_field_dot_dot = Kokkos::create_mirror_view(this->field_dot_dot); + this->h_rmass_inverse = Kokkos::create_mirror_view(this->rmass_inverse); + + //---------------------------------------------------------------------------- + // Initialize views + + // In CUDA you can't call class lambdas inside the constructors + // Hence I need to use this function to initialize views + initialize_views(nglob, this->field, this->field_dot, + this->field_dot_dot, this->rmass_inverse); + + this->kernels = specfem::domain::impl::kernels::kernels( + compute->ibool, partial_derivatives, material_properties, + boundary_conditions, compute_sources, compute_receivers, quadx, quadz, + quadrature_points, this->field, this->field_dot, this->field_dot_dot, this->rmass_inverse); + + //---------------------------------------------------------------------------- + // Inverse of mass matrix + + initialize_rmass_inverse(this->kernels, this->rmass_inverse); + + return; +}; + +template +void specfem::domain::domain::sync_field( + specfem::sync::kind kind) { + + if (kind == specfem::sync::DeviceToHost) { + Kokkos::deep_copy(h_field, field); + } else if (kind == specfem::sync::HostToDevice) { + Kokkos::deep_copy(field, h_field); + } else { + throw std::runtime_error("Could not recognize the kind argument"); + } + + return; +} + +template +void specfem::domain::domain::sync_field_dot( + specfem::sync::kind kind) { + + if (kind == specfem::sync::DeviceToHost) { + Kokkos::deep_copy(h_field_dot, field_dot); + } else if (kind == specfem::sync::HostToDevice) { + Kokkos::deep_copy(field_dot, h_field_dot); + } else { + throw std::runtime_error("Could not recognize the kind argument"); + } + + return; +} + +template +void specfem::domain::domain::sync_field_dot_dot( + specfem::sync::kind kind) { + + if (kind == specfem::sync::DeviceToHost) { + Kokkos::deep_copy(h_field_dot_dot, field_dot_dot); + } else if (kind == specfem::sync::HostToDevice) { + Kokkos::deep_copy(field_dot_dot, h_field_dot_dot); + } else { + throw std::runtime_error("Could not recognize the kind argument"); + } + + return; +} + +template +void specfem::domain::domain::sync_rmass_inverse( + specfem::sync::kind kind) { + + if (kind == specfem::sync::DeviceToHost) { + Kokkos::deep_copy(h_rmass_inverse, rmass_inverse); + } else if (kind == specfem::sync::HostToDevice) { + Kokkos::deep_copy(rmass_inverse, h_rmass_inverse); + } else { + throw std::runtime_error("Could not recognize the kind argument"); + } + + return; +} + +template +void specfem::domain::domain::divide_mass_matrix() { + + constexpr int components = medium::components; + const int nglob = this->rmass_inverse.extent(0); + + Kokkos::parallel_for( + "specfem::domain::domain::divide_mass_matrix", + specfem::kokkos::DeviceRange(0, components * nglob), + KOKKOS_CLASS_LAMBDA(const int in) { + const int iglob = in % nglob; + const int idim = in / nglob; + const type_real acceleration = this->field_dot_dot(iglob, idim); + const type_real rmass_inverse = this->rmass_inverse(iglob, idim); + this->field_dot_dot(iglob, idim) = + this->field_dot_dot(iglob, idim) * this->rmass_inverse(iglob, idim); + }); + + Kokkos::fence(); + + return; +} + +template +void specfem::domain::domain::invert_mass_matrix() { + + constexpr int components = medium::components; + const int nglob = this->rmass_inverse.extent(0); + + Kokkos::parallel_for( + "specfem::domain::domain::invert_mass_matrix", + specfem::kokkos::DeviceRange(0, components * nglob), + KOKKOS_CLASS_LAMBDA(const int in) { + const int iglob = in % nglob; + const int idim = in / nglob; + if (this->rmass_inverse(iglob, idim) == 0) { + this->rmass_inverse(iglob, idim) = 1.0; + } else { + this->rmass_inverse(iglob, idim) = + 1.0 / this->rmass_inverse(iglob, idim); + } + }); + + Kokkos::fence(); +} + +#endif /* DOMAIN_HPP_ */ diff --git a/include/domain/elastic_domain.hpp b/include/domain/elastic_domain.hpp deleted file mode 100644 index a7f41d6e..00000000 --- a/include/domain/elastic_domain.hpp +++ /dev/null @@ -1,267 +0,0 @@ -#ifndef _ELASTIC_DOMAIN_HPP -#define _ELASTIC_DOMAIN_HPP - -#include "compute/interface.hpp" -#include "quadrature/interface.hpp" -#include "specfem_setup.hpp" -#include - -namespace specfem { -namespace Domain { -/** - * @brief Elastic domain class - * - * Elastic domains implementation details: - * - field -> Displacements along the 2 dimensions (idim) for every global - * point (iglob) stored as a 2D View field(iglob, idim) - * - field_dot -> Velocity along the 2 dimensions (idim) for every global point - * (iglob) stored as a 2D View field(iglob, idim) - * - field_dot_dot -> Acceleration along the 2 dimensions (idim) for every - * global point (iglob) stored as a 2D View field(iglob, idim) - */ -class Elastic : public specfem::Domain::Domain { -public: - /** - * @brief Get a view of displacement stored on the device - * - * @return specfem::kokkos::DeviceView2d - */ - specfem::kokkos::DeviceView2d - get_field() const override { - return this->field; - } - /** - * @brief Get a view of displacement stored on the hsot - * - * @return specfem::kokkos::DeviceView2d - */ - specfem::kokkos::HostMirror2d - get_host_field() const override { - return this->h_field; - } - /** - * @brief Get a view of velocity stored on device - * - * @return specfem::kokkos::DeviceView2d - */ - specfem::kokkos::DeviceView2d - get_field_dot() const override { - return this->field_dot; - } - /** - * @brief Get a view of velocity stored on host - * - * @return specfem::kokkos::DeviceView2d - */ - specfem::kokkos::HostMirror2d - get_host_field_dot() const override { - return this->h_field_dot; - } - /** - * @brief Get a view of acceleration stored on device - * - * @return specfem::kokkos::DeviceView2d - */ - specfem::kokkos::DeviceView2d - get_field_dot_dot() const override { - return this->field_dot_dot; - } - /** - * @brief Get a view of acceleration stored on host - * - * @return specfem::kokkos::DeviceView2d - */ - specfem::kokkos::HostMirror2d - get_host_field_dot_dot() const override { - return this->h_field_dot_dot; - } - /** - * @brief Get a view of inverse of mass matrix stored on device - * - * @return specfem::kokkos::DeviceView2d - */ - specfem::kokkos::DeviceView2d - get_rmass_inverse() const override { - return this->rmass_inverse; - } - /** - * @brief Get a view of inverse of mass matrix stored on host - * - * @return specfem::kokkos::DeviceView2d - */ - specfem::kokkos::HostMirror2d - get_host_rmass_inverse() const override { - return this->h_rmass_inverse; - } - - /** - * @brief Construct a new Elastic domain object - * - * This contructor helps in instantiating fields. Without instantiating any - * material or mesh related private fields - * - * @param ndim Number of dimensions - * @param nglob Total number of distinct quadrature points - */ - Elastic(const int ndim, const int nglob); - - /** - * @brief Construct a new Elastic domain object - * - * @param ndim Number of dimensions - * @param nglob Total number of distinct quadrature points inside the - * domain - * @param compute Pointer to specfem::compute::compute struct - * @param material_properties Pointer to specfem::compute::properties - * struct - * @param partial_derivatives Pointer to - * specfem::compute::partial_derivatives struct - * @param sources Pointer to specfem::compute::sources struct - * @param quadx Pointer to quadrature object in x-dimension - * @param quadx Pointer to quadrature object in z-dimension - */ - Elastic(const int ndim, const int nglob, specfem::compute::compute *compute, - specfem::compute::properties *material_properties, - specfem::compute::partial_derivatives *partial_derivatives, - specfem::compute::sources *sources, - specfem::compute::receivers *receivers, - specfem::quadrature::quadrature *quadx, - specfem::quadrature::quadrature *quadz); - /** - * @brief Compute interaction of stiffness matrix on acceleration - * - */ - void compute_stiffness_interaction_calling_routine() override; - /** - * @brief Specialized kernel to compute the interaction of stiffness matrix on - * acceleration. - * - * Use this kernel when NGLL is known at compile time and NGLLX == NGLLZ. - * - * @tparam NGLL number of quadrature points - */ - template void compute_stiffness_interaction(); - /** - * @brief Compute interaction of stiffness matrix on acceleration - generic - * implementation - * - */ - void compute_stiffness_interaction(); - - /** - * @brief Divide the acceleration by the mass matrix - * - */ - void divide_mass_matrix() override; - /** - * @brief Compute interaction of sources on acceleration - * - * @param timeval - */ - void compute_source_interaction(const type_real timeval) override; - /** - * @brief Sync displacements views between host and device - * - * @param kind defines sync direction i.e. DeviceToHost or HostToDevice - */ - void sync_field(specfem::sync::kind kind) override; - /** - * @brief Sync velocity views between host and device - * - * @param kind defines sync direction i.e. DeviceToHost or HostToDevice - */ - void sync_field_dot(specfem::sync::kind kind) override; - /** - * @brief Sync acceleration views between host and device - * - * @param kind defines sync direction i.e. DeviceToHost or HostToDevice - */ - void sync_field_dot_dot(specfem::sync::kind kind) override; - /** - * @brief Sync inverse of mass matrix views between host and device - * - * @param kind defines sync direction i.e. DeviceToHost or HostToDevice - */ - void sync_rmass_inverse(specfem::sync::kind kind) override; - /** - * @brief function used to assign host and device views used in elastic domain - * class - * - */ - KOKKOS_IMPL_HOST_FUNCTION - void assign_views(); - /** - * @brief Compute seismograms at for all receivers at isig_step - * - * @param seismogram_types DeviceView of types of seismograms to be calculated - * @param isig_step timestep for seismogram calculation - */ - void compute_seismogram(const int isig_step) override; - // /** - // * @brief Load arrays required for compute forces into simd_arrays when - // * compiled with explicit SIMD types, or else reference original arrays. - // * - // */ - // void simd_configure_arrays() override; - -private: - specfem::kokkos::DeviceView2d - field; ///< View of field on Device - specfem::kokkos::HostMirror2d - h_field; ///< View of field on host - specfem::kokkos::DeviceView2d - field_dot; ///< View of derivative of - ///< field on Device - specfem::kokkos::HostMirror2d - h_field_dot; ///< View of derivative - ///< of field on host - specfem::kokkos::DeviceView2d - field_dot_dot; ///< View of second - ///< derivative of - ///< field on Device - specfem::kokkos::HostMirror2d - h_field_dot_dot; ///< View of second - ///< derivative of - ///< field on host - specfem::kokkos::DeviceView2d - rmass_inverse; ///< View of inverse - ///< of mass matrix on - ///< device - specfem::kokkos::HostMirror2d - h_rmass_inverse; ///< View of inverse - ///< of mass matrix - ///< on host - specfem::compute::compute *compute; ///< Pointer to compute struct used to - ///< store spectral element numbering - ///< mapping (ibool) - specfem::compute::properties *material_properties; ///< Pointer to struct used - ///< to store material - ///< properties - specfem::compute::partial_derivatives *partial_derivatives; ///< Pointer to - ///< struct used - ///< to store - ///< partial - ///< derivates - specfem::compute::sources *sources; ///< Pointer to struct used to store - ///< sources - specfem::compute::receivers *receivers; ///< Pointer to struct used to store - ///< receivers - quadrature::quadrature *quadx; ///< Pointer to quadrature object in - ///< x-dimension - quadrature::quadrature *quadz; ///< Pointer to quadrature object in - ///< z-dimension - int nelem_domain; ///< Total number of elements in this domain - specfem::kokkos::DeviceView1d ispec_domain; ///< Array containing global - ///< indices(ispec) of all - ///< elements in this domain - ///< on the device - specfem::kokkos::HostMirror1d h_ispec_domain; ///< Array containing - ///< global indices(ispec) - ///< of all elements in - ///< this domain on the - ///< host -}; -} // namespace Domain -} // namespace specfem - -#endif diff --git a/include/domain/impl/elements/acoustic/acoustic2d.hpp b/include/domain/impl/elements/acoustic/acoustic2d.hpp new file mode 100644 index 00000000..50529d3f --- /dev/null +++ b/include/domain/impl/elements/acoustic/acoustic2d.hpp @@ -0,0 +1,148 @@ +#ifndef _DOMAIN_ACOUSTIC_ELEMENTS2D_HPP +#define _DOMAIN_ACOUSTIC_ELEMENTS2D_HPP + +#include "domain/impl/elements/element.hpp" +#include "enumerations/interface.hpp" +#include "kokkos_abstractions.h" +#include "specfem_setup.hpp" + +/** + * @brief Decltype for the field subviewed at particular global index + * + */ +using field_type = Kokkos::Subview< + specfem::kokkos::DeviceView2d, int, + std::remove_const_t >; + +namespace specfem { +namespace domain { +namespace impl { +namespace elements { + +/** + * @brief Acoustic element in 2D + * + * Base class to define specialized acoustic elements in 2D. This class defines + * pure virtual methods to compute the gradient and stress at the quadrature + * points of the element. The specific implementaions are left to the derived + * classes, e.g. + * + * @tparam quadrature_points Type for number of quadrature points defined either + * at compile time or run time + */ +template +class element { + +public: + using dimension = specfem::enums::element::dimension::dim2; + using medium = specfem::enums::element::medium::acoustic; + /** + * @brief Scratch view type as defined by the quadrature points (either at + * compile time or run time) + * + * @tparam T Type of the scratch view + */ + template + using ScratchViewType = + typename quadrature_points::template ScratchViewType; + + /** + * @brief Compute the mass matrix component ($ m_{\alpha, \beta} $) for a + * given quadrature point + * + * Mass matrix is given by \\f$ M = \sum_{\Omega_e} \sum_{\alpha, \beta} + * \omega_{\alpha} \omega_{\beta} m_{\alpha, \beta} \\f$ + * + * @param xz index of the quadrature point + * @param mass_matrix mass matrix component + */ + KOKKOS_INLINE_FUNCTION virtual void + compute_mass_matrix_component(const int &ispec, const int &xz, + type_real *mass_matrix) const = 0; + + /** + * @brief Compute the gradient of the field at the quadrature point xz + * (Komatisch & Tromp, 2002-I., eq. 22(theory, OC),44,45) + * + * @param xz Index of the quadrature point + * @param s_hprime_xx lagrange polynomial derivative in x direction + * @param s_hprime_zz lagraange polynomial derivative in z direction + * @param field_chi potential field + * @param dchidxl \f$ \frac{\partial \chi}{\partial x} \f$ + * @param dchidzl \f$ \frac{\partial \chi}{\partial z} \f$ + */ + KOKKOS_INLINE_FUNCTION virtual void compute_gradient( + const int &ispec, const int &xz, + const ScratchViewType s_hprime_xx, + const ScratchViewType s_hprime_zz, + const ScratchViewType field_chi, + type_real *dchidxl, type_real *dchidzl) const = 0; + + /** + * @brief Compute the stress integrand at a particular Gauss-Lobatto-Legendre + * quadrature point. Note the collapse of jacobian elements into the + * integrands for the gradient of \f$ w \f$ + * (Komatisch & Tromp, 2002-I., eq. 44,45) + * + * @param xz Index of Gauss-Lobatto-Legendre quadrature point + * @param dchidxl Partial derivative of field \f$ \frac{\partial + * \chi}{\partial x} \f$ + * @param dchipdzl Partial derivative of field \f$ \frac{\partial + * \chi}{\partial z} \f$ + * @param stress_integrand_xi Stress integrand wrt. \f$ \xi \f$ + * \f$ J^{\alpha\gamma} * {\rho^{\alpha\gamma}}^{-1} + * \partial_x \chi \partial_x \xi + * + \partial_z \chi * \partial_z \xi \f$ + * @param stress_integrand_gamma Stress integrand wrt. \f$\gamma\f$ + * \f$ J^{\alpha\gamma} * {\rho^{\alpha\gamma}}^{-1} + * \partial_x \chi \partial_x \gamma + * + \partial_z \chi * \partial_z \gamma \f$ + * @return KOKKOS_FUNCTION + */ + KOKKOS_INLINE_FUNCTION virtual void + compute_stress(const int &ispec, const int &xz, const type_real *dchidxl, + const type_real *dchidzl, type_real *stress_integrand_xi, + type_real *stress_integrand_gamma) const = 0; + + /** + * @brief Update the acceleration at the quadrature point xz + * + * @param xz Index of the quadrature point + * @param wxglll Weight of the Gauss-Lobatto-Legendre quadrature point in x + * direction + * @param wzglll Weight of the Gauss-Lobatto-Legendre quadrature point in z + * direction + * @param stress_integrand_xi Stress integrand wrt. \f$ \xi \f$ + * J^{\alpha\gamma} * {\rho^{\alpha\gamma}}^{-1} \partial_x \chi \partial_x + * \xi + \partial_z \chi * \partial_z \xi as computed by compute_stress + * @param stress_integrand_gamma Stress integrand wrt. \f$\gamma\f$ + * \f$ J^{\alpha\gamma} * {\rho^{\alpha\gamma}}^{-1} + * \partial_x \chi \partial_x \gamma + \partial_z \chi * \partial_z \gamma \f$ + * as computed by compute_stress + * @param s_hprimewgll_xx Scratch view hprime_xx * wxgll + * @param s_hprimewgll_zz Scratch view hprime_zz * wzgll + * @param field_dot_dot Acceleration of the field subviewed at global index xz + */ + KOKKOS_INLINE_FUNCTION virtual void update_acceleration( + const int &xz, const type_real &wxglll, const type_real &wzglll, + const ScratchViewType stress_integrand_xi, + const ScratchViewType + stress_integrand_gamma, + const ScratchViewType s_hprimewgll_xx, + const ScratchViewType s_hprimewgll_zz, + type_real *acceleration) const = 0; + + /** + * @brief Get the global index of the element + * + */ + KOKKOS_INLINE_FUNCTION virtual int get_ispec() const = 0; +}; // namespace element + +} // namespace elements +} // namespace impl +} // namespace domain +} // namespace specfem + +#endif diff --git a/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp b/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp new file mode 100644 index 00000000..50052975 --- /dev/null +++ b/include/domain/impl/elements/acoustic/acoustic2d_isotropic.hpp @@ -0,0 +1,219 @@ +#ifndef _DOMAIN_ACOUSTIC_ELEMENTS2D_IMPLEMENTATION_HPP +#define _DOMAIN_ACOUSTIC_ELEMENTS2D_IMPLEMENTATION_HPP + +#include "compute/interface.hpp" +#include "domain/impl/elements/acoustic/acoustic2d.hpp" +#include "domain/impl/elements/element.hpp" +#include "enumerations/interface.hpp" +#include "kokkos_abstractions.h" +#include "specfem_setup.hpp" +#include + +namespace specfem { +namespace domain { +namespace impl { +namespace elements { +/** + * @brief Element specialization for 2D elastic isotropic spectral elements with + * static quadrature points + * + * @tparam NGLL Number of Gauss-Lobatto-Legendre quadrature points defined at + * compile time + * + * @tparam BC Boundary conditions if void then neumann boundary conditions are + * assumed + */ +template +class element< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::acoustic, + specfem::enums::element::quadrature::static_quadrature_points, + specfem::enums::element::property::isotropic, BC> { +public: + /** @name Typedefs + * + */ + ///@{ + /** + * @brief dimension of the element + * + */ + using dimension = specfem::enums::element::dimension::dim2; + /** + * @brief Medium of the element + * + */ + using medium_type = specfem::enums::element::medium::acoustic; + /** + * @brief Property of the element + * + */ + using property_type = specfem::enums::element::property::isotropic; + + /** + * @brief Number of Gauss-Lobatto-Legendre quadrature points + */ + using quadrature_points_type = + specfem::enums::element::quadrature::static_quadrature_points; + /** + * @brief Boundary conditions of the element + * + * if BC == none then neumann boundary conditions are assumed + * + */ + using boundary_conditions_type = BC; + /** + * @brief Use the scratch view type from the quadrature points + * + * @tparam T Type of the scratch view + * @tparam N Number of components + */ + template + using ScratchViewType = + typename quadrature_points_type::template ScratchViewType; + ///@} + + /** + * @brief Construct a new element object + * + */ + KOKKOS_FUNCTION + element() = default; + + /** + * @brief Construct a new element object + * + * @param ispec Index of the element + * @param partial_derivatives partial derivatives + * @param properties Properties of the element + */ + KOKKOS_FUNCTION + element(const specfem::compute::partial_derivatives &partial_derivatives, + const specfem::compute::properties &properties, + const specfem::compute::boundaries &boundary_conditions, + const quadrature_points_type &quadrature_points); + + /** + * @brief Compute the mass matrix component ($ m_{\alpha, \beta} $) for a + * given quadrature point + * + * Mass matrix is given by \\f$ M = \sum_{\Omega_e} \sum_{\alpha, \beta} + * \omega_{\alpha} \omega_{\beta} m_{\alpha, \beta} \\f$ + * + * @param xz index of the quadrature point + * @param mass_matrix mass matrix component + */ + KOKKOS_INLINE_FUNCTION + void compute_mass_matrix_component( + const int &ispec, const int &xz, + specfem::kokkos::array_type &mass_matrix) const; + + template + KOKKOS_INLINE_FUNCTION void mass_time_contribution( + const int &ispec, const int &ielement, const int &xz, const type_real &dt, + const specfem::kokkos::array_type &weight, + specfem::kokkos::array_type + &rmass_inverse) const; + + /** + * @brief Compute the gradient of the field at the quadrature point xz + * (Komatisch & Tromp, 2002-I., eq. 22(theory, OC),44,45) + * + * @param xz Index of the quadrature point + * @param s_hprime_xx lagrange polynomial derivative in x direction + * @param s_hprime_zz lagraange polynomial derivative in z direction + * @param field_chi potential field + * @param dchidxl Computed partial derivative of field \f$ \frac{\partial + * \chi}{\partial x} \f$ + * @param dchidzl Computed partial derivative of field \f$ \frac{\partial + * \chi}{\partial z} \f$ + */ + KOKKOS_INLINE_FUNCTION void compute_gradient( + const int &ispec, const int &ielement, const int &xz, + const ScratchViewType s_hprime_xx, + const ScratchViewType s_hprime_zz, + const ScratchViewType field_chi, + specfem::kokkos::array_type &dchidxl, + specfem::kokkos::array_type &dchidzl) const; + + /** + * @brief Compute the stress integrand at a particular Gauss-Lobatto-Legendre + * quadrature point. Note the collapse of jacobian elements into the + * integrands for the gradient of \f$ w \f$ + * (Komatisch & Tromp, 2002-I., eq. 44,45) + * + * @param xz Index of Gauss-Lobatto-Legendre quadrature point + * @param dchidxl Partial derivative of field \f$ \frac{\partial + * \chi}{\partial x} \f$ + * @param dchipdzl Partial derivative of field \f$ \frac{\partial + * \chi}{\partial z} \f$ + * @param stress_integrand_xi Stress integrand wrt. \f$ \xi \f$ + * \f$ J^{\alpha\gamma} * {\rho^{\alpha\gamma}}^{-1} + * \partial_x \chi \partial_x \xi + * + \partial_z \chi * \partial_z \xi \f$ + * @param stress_integrand_gamma Stress integrand wrt. \f$\gamma\f$ + * \f$ J^{\alpha\gamma} * {\rho^{\alpha\gamma}}^{-1} + * \partial_x \chi \partial_x \gamma + * + \partial_z \chi * \partial_z \gamma \f$ + * @return KOKKOS_FUNCTION + */ + KOKKOS_INLINE_FUNCTION void compute_stress( + const int &ispec, const int &ielement, const int &xz, + const specfem::kokkos::array_type &dchidxl, + const specfem::kokkos::array_type &dchidzl, + specfem::kokkos::array_type &stress_integrand_xi, + specfem::kokkos::array_type &stress_integrand_gamma) const; + + /** + * @brief Update the acceleration at a particular Gauss-Lobatto-Legendre + * quadrature point + * + * @param xz Index of Gauss-Lobatto-Legendre quadrature point + * @param wxglll Weight of the Gauss-Lobatto-Legendre quadrature point in x + * direction + * @param wzglll Weight of the Gauss-Lobatto-Legendre quadrature point in z + * direction + * @param stress_integrand_xi Stress integrand wrt. \f$ \xi \f$ + * \f$ J^{\alpha\gamma} * {\rho^{\alpha\gamma}}^{-1} + * \partial_x \chi \partial_x \xi + \partial_z \chi * \partial_z \xi \f$ as + * computed by compute_stress + * @param stress_integrand_gamma Stress integrand wrt. \f$\gamma\f$ + * \f$ J^{\alpha\gamma} * {\rho^{\alpha\gamma}}^{-1} + * \partial_x \chi \partial_x \gamma + \partial_z \chi * \partial_z \gamma \f$ + * as computed by compute_stress + * @param s_hprimewgll_xx Scratch view hprime_xx * wxgll + * @param s_hprimewgll_zz Scratch view hprime_zz * wzgll + * @param field_dot_dot Acceleration of the field subviewed at global index xz + */ + KOKKOS_INLINE_FUNCTION void compute_acceleration( + const int &ispec, const int &ielement, const int &xz, + const specfem::kokkos::array_type &weight, + const ScratchViewType + stress_integrand_xi, + const ScratchViewType + stress_integrand_gamma, + const ScratchViewType s_hprimewgll_xx, + const ScratchViewType s_hprimewgll_zz, + const specfem::kokkos::array_type + &velocity, + specfem::kokkos::array_type &acceleration) const; + +private: + specfem::kokkos::DeviceView3d xix; ///< xix + specfem::kokkos::DeviceView3d xiz; ///< xiz + specfem::kokkos::DeviceView3d gammax; ///< gammax + specfem::kokkos::DeviceView3d gammaz; ///< gammaz + specfem::kokkos::DeviceView3d jacobian; ///< jacobian + specfem::kokkos::DeviceView3d rho_inverse; ///< rho inverse + specfem::kokkos::DeviceView3d lambdaplus2mu_inverse; ///< lambda + + ///< 2 mu + ///< inverse + specfem::kokkos::DeviceView3d kappa; ///< kappa + boundary_conditions_type boundary_conditions; ///< boundary conditions +}; +} // namespace elements +} // namespace impl +} // namespace domain +} // namespace specfem + +#endif diff --git a/include/domain/impl/elements/acoustic/acoustic2d_isotropic.tpp b/include/domain/impl/elements/acoustic/acoustic2d_isotropic.tpp new file mode 100644 index 00000000..89426794 --- /dev/null +++ b/include/domain/impl/elements/acoustic/acoustic2d_isotropic.tpp @@ -0,0 +1,293 @@ +#ifndef _DOMAIN_ACOUSTIC_ELEMENTS2D_ISOTROPIC_TPP +#define _DOMAIN_ACOUSTIC_ELEMENTS2D_ISOTROPIC_TPP + +#include "compute/interface.hpp" +#include "domain/impl/elements/acoustic/acoustic2d_isotropic.hpp" +#include "domain/impl/elements/element.hpp" +#include "enumerations/interface.hpp" +#include "globals.h" +#include "kokkos_abstractions.h" +#include "specfem_setup.hpp" +#include + +template +using StaticScratchViewType = + typename specfem::enums::element::quadrature::static_quadrature_points< + N>::template ScratchViewType; + +// using field_type = Kokkos::Subview< +// specfem::kokkos::DeviceView2d, int, +// std::remove_const_t >; + +// ----------------------------------------------------------------------------- +// SPECIALIZED ELEMENT +// ----------------------------------------------------------------------------- +template +KOKKOS_FUNCTION specfem::domain::impl::elements::element< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::acoustic, + specfem::enums::element::quadrature::static_quadrature_points, + specfem::enums::element::property::isotropic, + BC>::element(const specfem::compute::partial_derivatives + &partial_derivatives, + const specfem::compute::properties &properties, + const specfem::compute::boundaries &boundary_conditions, + const quadrature_points_type &quadrature_points) { + +#ifndef NDEBUG + assert(partial_derivatives.xix.extent(1) == NGLL); + assert(partial_derivatives.xix.extent(2) == NGLL); + assert(partial_derivatives.gammax.extent(1) == NGLL); + assert(partial_derivatives.gammax.extent(2) == NGLL); + assert(partial_derivatives.xiz.extent(1) == NGLL); + assert(partial_derivatives.xiz.extent(2) == NGLL); + assert(partial_derivatives.gammaz.extent(1) == NGLL); + assert(partial_derivatives.gammaz.extent(2) == NGLL); + assert(partial_derivatives.jacobian.extent(1) == NGLL); + assert(partial_derivatives.jacobian.extent(2) == NGLL); + + // Properties + assert(properties.rho_inverse.extent(1) == NGLL); + assert(properties.rho_inverse.extent(2) == NGLL); + assert(properties.lambdaplus2mu_inverse.extent(1) == NGLL); + assert(properties.lambdaplus2mu_inverse.extent(2) == NGLL); + assert(properties.kappa.extent(1) == NGLL); + assert(properties.kappa.extent(2) == NGLL); +#endif + + this->xix = partial_derivatives.xix; + this->gammax = partial_derivatives.gammax; + this->xiz = partial_derivatives.xiz; + this->gammaz = partial_derivatives.gammaz; + this->jacobian = partial_derivatives.jacobian; + this->rho_inverse = properties.rho_inverse; + this->lambdaplus2mu_inverse = properties.lambdaplus2mu_inverse; + this->kappa = properties.kappa; + + this->boundary_conditions = + boundary_conditions_type(boundary_conditions, quadrature_points); + + return; +} + +template +KOKKOS_INLINE_FUNCTION void specfem::domain::impl::elements::element< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::acoustic, + specfem::enums::element::quadrature::static_quadrature_points, + specfem::enums::element::property::isotropic, + BC>::compute_mass_matrix_component(const int &ispec, const int &xz, + specfem::kokkos::array_type + &mass_matrix) const { + int ix, iz; + sub2ind(xz, NGLL, iz, ix); + + constexpr int components = medium_type::components; + + static_assert(components == 1, "Acoustic medium has only one component"); + + mass_matrix[0] = this->jacobian(ispec, iz, ix) / this->kappa(ispec, iz, ix); + + return; +} + +template +template +KOKKOS_INLINE_FUNCTION void specfem::domain::impl::elements::element< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::acoustic, + specfem::enums::element::quadrature::static_quadrature_points, + specfem::enums::element::property::isotropic, BC>:: + mass_time_contribution( + const int &ispec, const int &ielement, const int &xz, + const type_real &dt, + const specfem::kokkos::array_type &weight, + specfem::kokkos::array_type + &rmass_inverse) const { + + int ix, iz; + sub2ind(xz, NGLL, iz, ix); + + const specfem::compute::element_partial_derivatives partial_derivatives( + this->xix(ispec, iz, ix), this->gammax(ispec, iz, ix), + this->xiz(ispec, iz, ix), this->gammaz(ispec, iz, ix), + this->jacobian(ispec, iz, ix)); + + const specfem::compute::element_properties + properties(this->lambdaplus2mu_inverse(ispec, iz, ix), + this->rho_inverse(ispec, iz, ix)); + + rmass_inverse[0] = 0.0; + + // comppute mass matrix component + boundary_conditions.template mass_time_contribution( + ielement, xz, dt, weight, partial_derivatives, properties, rmass_inverse); + + return; +} + +template +KOKKOS_INLINE_FUNCTION void specfem::domain::impl::elements::element< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::acoustic, + specfem::enums::element::quadrature::static_quadrature_points, + specfem::enums::element::property::isotropic, BC>:: + compute_gradient( + const int &ispec, const int &ielement, const int &xz, + const ScratchViewType s_hprime_xx, + const ScratchViewType s_hprime_zz, + const ScratchViewType field_chi, + specfem::kokkos::array_type &dchidxl, + specfem::kokkos::array_type &dchidzl) const { + + int ix, iz; + sub2ind(xz, NGLL, iz, ix); + + const specfem::compute::element_partial_derivatives partial_derivatives = + specfem::compute::element_partial_derivatives( + this->xix(ispec, iz, ix), this->gammax(ispec, iz, ix), + this->xiz(ispec, iz, ix), this->gammaz(ispec, iz, ix)); + + type_real dchi_dxi = 0.0; + type_real dchi_dgamma = 0.0; + +#ifdef KOKKOS_ENABLE_CUDA +#pragma unroll +#endif + for (int l = 0; l < NGLL; l++) { + dchi_dxi += s_hprime_xx(ix, l, 0) * field_chi(iz, l, 0); + dchi_dgamma += s_hprime_zz(iz, l, 0) * field_chi(l, ix, 0); + } + + // dchidx + dchidxl[0] = dchi_dxi * partial_derivatives.xix + + dchi_dgamma * partial_derivatives.gammax; + + // dchidz + dchidzl[0] = dchi_dxi * partial_derivatives.xiz + + dchi_dgamma * partial_derivatives.gammaz; + + boundary_conditions.enforce_gradient(ielement, xz, partial_derivatives, + dchidxl, dchidzl); + + return; +} + +template +KOKKOS_INLINE_FUNCTION void specfem::domain::impl::elements::element< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::acoustic, + specfem::enums::element::quadrature::static_quadrature_points, + specfem::enums::element::property::isotropic, BC>:: + compute_stress( + const int &ispec, const int &ielement, const int &xz, + const specfem::kokkos::array_type &dchidxl, + const specfem::kokkos::array_type &dchidzl, + specfem::kokkos::array_type &stress_integrand_xi, + specfem::kokkos::array_type &stress_integrand_gamma) + const { + + int ix, iz; + sub2ind(xz, NGLL, iz, ix); + + const specfem::compute::element_partial_derivatives partial_derivatives( + this->xix(ispec, iz, ix), this->gammax(ispec, iz, ix), + this->xiz(ispec, iz, ix), this->gammaz(ispec, iz, ix), + this->jacobian(ispec, iz, ix)); + + const specfem::compute::element_properties + properties(this->lambdaplus2mu_inverse(ispec, iz, ix), + this->rho_inverse(ispec, iz, ix)); + + // Precompute the factor + type_real fac = partial_derivatives.jacobian * properties.rho_inverse; + + // Compute stress integrands 1 and 2 + // Here it is extremely important that this seems at odds with + // equations (44) & (45) from Komatitsch and Tromp 2002 I. - Validation + // The equations are however missing dxi/dx, dxi/dz, dzeta/dx, dzeta/dz + // for the gradient of w^{\alpha\gamma}. In this->update_acceleration + // the weights for the integration and the interpolated values for the + // first derivatives of the lagrange polynomials are then collapsed + stress_integrand_xi[0] = fac * (partial_derivatives.xix * dchidxl[0] + + partial_derivatives.xiz * dchidzl[0]); + stress_integrand_gamma[0] = fac * (partial_derivatives.gammax * dchidxl[0] + + partial_derivatives.gammaz * dchidzl[0]); + + boundary_conditions.enforce_stress(ielement, xz, partial_derivatives, + properties, stress_integrand_xi, + stress_integrand_gamma); + + return; +} + +template +KOKKOS_INLINE_FUNCTION void specfem::domain::impl::elements::element< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::acoustic, + specfem::enums::element::quadrature::static_quadrature_points, + specfem::enums::element::property::isotropic, BC>:: + compute_acceleration( + const int &ispec, const int &ielement, const int &xz, + const specfem::kokkos::array_type &weight, + const ScratchViewType + stress_integrand_xi, + const ScratchViewType + stress_integrand_gamma, + const ScratchViewType + s_hprimewgll_xx, + const ScratchViewType + s_hprimewgll_zz, + const specfem::kokkos::array_type + &velocity, + specfem::kokkos::array_type + &acceleration) const { + + int ix, iz; + sub2ind(xz, NGLL, iz, ix); + type_real temp1l = 0.0; + type_real temp2l = 0.0; + + constexpr int components = medium_type::components; + + static_assert(components == 1, "Acoustic medium has only one component"); + + specfem::compute::element_partial_derivatives partial_derivatives; + + specfem::compute::element_properties + properties; + + // populate partial derivatives only if the boundary is stacey + if constexpr (boundary_conditions_type::value == + specfem::enums::element::boundary_tag::stacey) { + partial_derivatives = specfem::compute::element_partial_derivatives( + this->xix(ispec, iz, ix), this->gammax(ispec, iz, ix), + this->xiz(ispec, iz, ix), this->gammaz(ispec, iz, ix), + this->jacobian(ispec, iz, ix)); + + properties = specfem::compute::element_properties( + this->lambdaplus2mu_inverse(ispec, iz, ix), + this->rho_inverse(ispec, iz, ix)); + } + +#ifdef KOKKOS_ENABLE_CUDA +#pragma unroll +#endif + for (int l = 0; l < NGLL; l++) { + temp1l += s_hprimewgll_xx(ix, l, 0) * stress_integrand_xi(iz, l, 0); + temp2l += s_hprimewgll_zz(iz, l, 0) * stress_integrand_gamma(l, ix, 0); + } + + acceleration[0] = -1.0 * ((weight[1] * temp1l) + (weight[0] * temp2l)); + + boundary_conditions.enforce_traction(ielement, xz, weight, + partial_derivatives, properties, + velocity, acceleration); + + return; +} + +#endif diff --git a/include/domain/impl/elements/acoustic/interface.hpp b/include/domain/impl/elements/acoustic/interface.hpp new file mode 100644 index 00000000..47182c56 --- /dev/null +++ b/include/domain/impl/elements/acoustic/interface.hpp @@ -0,0 +1,8 @@ +#ifndef _DOMAIN_IMPL_ELEMENTS_ACOUSTIC_INTERFACE_HPP +#define _DOMAIN_IMPL_ELEMENTS_ACOUSTIC_INTERFACE_HPP + +#include "acoustic2d.hpp" +#include "acoustic2d_isotropic.hpp" +#include "acoustic2d_isotropic.tpp" + +#endif // _DOMAIN_IMPL_ELEMENTS_ACOUTIC_INTERFACE_HPP diff --git a/include/domain/impl/elements/container.hpp b/include/domain/impl/elements/container.hpp new file mode 100644 index 00000000..d332323b --- /dev/null +++ b/include/domain/impl/elements/container.hpp @@ -0,0 +1,103 @@ +#ifndef _ELEMENT_CONTAINER_HPP +#define _ELEMENT_CONTAINER_HPP + +namespace specfem { +namespace domain { +namespace impl { +namespace elements { +/** + * @brief Struct to hold a pointer to an element + * + * Kokkos views have a syntantic problem when creating a view of pointers. For + * example, let's say we have want to create a view of pointers to int. The + * syntax would be: View, this is ambigous since the compiler doesn't + * know if the * is part of 2-dimensional view type or a pointer to int type. To + * avoid this problem, we create a struct which holds a pointer to an element. + * This struct is then used to create a view of structs. This allows us to + * create a view of pointers to elements. + * + * @tparam base_element Base element class i.e. elastic, acoustic or poroelastic + */ +template struct container { + base_element *element; ///< Pointer to an element + + /** + * @brief Default constructor + * + */ + KOKKOS_FUNCTION + container() = default; + + /** + * @brief Construct a new container object + * + * @param element Pointer to an element + */ + KOKKOS_FUNCTION + container(base_element *element) { + this->element = element; + return; + } + + template + KOKKOS_INLINE_FUNCTION void + compute_mass_matrix_component(Args... values) const { + return this->element->compute_mass_matrix_component(values...); + } + + /** + * @brief Wrapper to compute gradients method of the element + * + * @tparam Args Arguments to the compute_gradient method of the element + * @param values Arguments to the compute_gradient method of the element + */ + template + KOKKOS_INLINE_FUNCTION void compute_gradient(Args... values) const { + this->element->compute_gradient(values...); + return; + } + + /** + * @brief Wrapper to compute stresses method of the element + * + * @tparam Args Arguments to the compute_stress method of the element + * @param values Arguments to the compute_stress method of the element + */ + template + KOKKOS_INLINE_FUNCTION void compute_stress(Args... values) const { + this->element->compute_stress(values...); + return; + } + + /** + * @brief Wrapper to update acceleration method of the element + * + * @tparam Args Arguments to the update_acceleration method of the element + * @param values Arguments to the update_acceleration method of the element + */ + template + KOKKOS_INLINE_FUNCTION void update_acceleration(Args... values) const { + this->element->update_acceleration(values...); + return; + } + + /** + * @brief Wrapper to get_ispec method of the element + * + */ + KOKKOS_INLINE_FUNCTION + int get_ispec() const { return this->element->get_ispec(); } + + /** + * @brief Default destructor + * + */ + KOKKOS_FUNCTION + ~container() = default; +}; +} // namespace elements +} // namespace impl +} // namespace domain +} // namespace specfem + +#endif diff --git a/include/domain/impl/elements/elastic/elastic2d.hpp b/include/domain/impl/elements/elastic/elastic2d.hpp new file mode 100644 index 00000000..640af03a --- /dev/null +++ b/include/domain/impl/elements/elastic/elastic2d.hpp @@ -0,0 +1,149 @@ +#ifndef _DOMAIN_ELASTIC_ELEMENTS2D_HPP +#define _DOMAIN_ELASTIC_ELEMENTS2D_HPP + +#include "domain/impl/elements/element.hpp" +#include "enumerations/interface.hpp" +#include "kokkos_abstractions.h" +#include "specfem_setup.hpp" + +/** + * @brief Decltype for the field subviewed at particular global index + * + */ +using field_type = Kokkos::Subview< + specfem::kokkos::DeviceView2d, int, + std::remove_const_t >; + +namespace specfem { +namespace domain { +namespace impl { +namespace elements { + +/** + * @brief Elastic element in 2D + * + * Base class to define specialized elastic elements in 2D. This class defines + * pure virtual methods to compute the gradient and stress at the quadrature + * points of the element. The specific implementaions are left to the derived + * classes. + * + * @tparam quadrature_points Type for number of quadrature points defined either + * at compile time or run time + */ +template +class element { + +public: + using dimension = specfem::enums::element::dimension::dim2; + using medium_type = specfem::enums::element::medium::elastic; + using quadrature_points_type = qp_type; + + /** + * @brief Scratch view type as defined by the quadrature points (either at + * compile time or run time) + * + * @tparam T Type of the scratch view + */ + template + using ScratchViewType = + typename quadrature_points_type::template ScratchViewType; + + /** + * @brief Compute the mass matrix component ($ m_{\alpha, \beta} $) for a + * given quadrature point + * + * Mass matrix is given by \\f$ M = \sum_{\Omega_e} \sum_{\alpha, \beta} + * \omega_{\alpha} \omega_{\beta} m_{\alpha, \beta} \\f$ + * + * @param xz index of the quadrature point + * @param mass_matrix mass matrix component + */ + KOKKOS_INLINE_FUNCTION virtual void + compute_mass_matrix_component(const int &ispec, const int &xz, + type_real *mass_matrix) const = 0; + + /** + * @brief Compute the gradient of the field at the quadrature point xz + * + * @param xz Index of the quadrature point + * @param s_hprime_xx lagrange polynomial derivative in x direction + * @param s_hprime_zz lagraange polynomial derivative in z direction + * @param u Scratch view of field. In elastic domains the field has 2 + * components + * @param dudxl Partial derivative of field \f$ \frac{\partial + * \tilde{u}}{\partial x} \f$ + * @param dudzl Partial derivative of field \f$ \frac{\partial + * \tilde{u}}{\partial z} \f$ + */ + KOKKOS_INLINE_FUNCTION virtual void + compute_gradient(const int &ispec, const int &xz, + const ScratchViewType s_hprime_xx, + const ScratchViewType s_hprime_zz, + const ScratchViewType u, + type_real *dudxl, type_real *dudzl) const = 0; + + /** + * @brief Compute the stress integrand at a particular Gauss-Lobatto-Legendre + * quadrature point. + * + * @param xz Index of Gauss-Lobatto-Legendre quadrature point + * @param dudxl Partial derivative of field \f$ \frac{\partial + * \tilde{u}}{\partial x} \f$ + * @param dudzl Partial derivative of field \f$ \frac{\partial + * \tilde{u}}{\partial z} \f$ + * @param stress_integrand_xi Stress integrand wrt. \f$ \xi \f$ \f$ + * J^{\alpha, \gamma} \partial_x u \partial_x \xi + \partial_z u * \partial_z + * \xi \f$ + * @param stress_integrand_gamma Stress integrand wrt. \f$\gamma\f$ \f$ + * J^{\alpha, \gamma} \partial_x u \partial_x \gamma + \partial_z u * + * \partial_z \gamma \f$ + * @return KOKKOS_FUNCTION + */ + KOKKOS_INLINE_FUNCTION virtual void + compute_stress(const int &ispec, const int &xz, const type_real *dudxl, + const type_real *dudzl, type_real *stress_integrand_xi, + type_real *stress_integrand_gamma) const = 0; + + /** + * @brief Update the acceleration at the quadrature point xz + * + * @param xz Index of the quadrature point + * @param wxglll Weight of the Gauss-Lobatto-Legendre quadrature point in x + * direction + * @param wzglll Weight of the Gauss-Lobatto-Legendre quadrature point in z + * direction + * @param stress_integrand_1 Stress integrand wrt. \f$ \xi \f$ \f$ J^{\alpha, + * \gamma} \partial_x u \partial_x \xi + \partial_z u * \partial_z \xi \f$ as + * computed by compute_stress + * @param stress_integrand_2 Stress integrand wrt. \f$\gamma\f$ \f$ J^{\alpha, + * \gamma} \partial_x u \partial_x \gamma + \partial_z u * \partial_z \gamma + * \f$ as computed by compute_stress + * @param s_hprimewgll_xx Scratch view hprime_xx * wxgll + * @param s_hprimewgll_zz Scratch view hprime_zz * wzgll + * @param field_dot_dot Acceleration of the field subviewed at global index xz + */ + KOKKOS_INLINE_FUNCTION virtual void + update_acceleration(const int &xz, const type_real &wxglll, + const type_real &wzglll, + const ScratchViewType + stress_integrand_xi, + const ScratchViewType + stress_integrand_gamma, + const ScratchViewType s_hprimewgll_xx, + const ScratchViewType s_hprimewgll_zz, + type_real *acceleration) const = 0; + + /** + * @brief Get the global index of the element + * + */ + KOKKOS_INLINE_FUNCTION virtual int get_ispec() const = 0; +}; // namespace element + +} // namespace elements +} // namespace impl +} // namespace domain +} // namespace specfem + +#endif diff --git a/include/domain/impl/elements/elastic/elastic2d_isotropic.hpp b/include/domain/impl/elements/elastic/elastic2d_isotropic.hpp new file mode 100644 index 00000000..79367b49 --- /dev/null +++ b/include/domain/impl/elements/elastic/elastic2d_isotropic.hpp @@ -0,0 +1,222 @@ +#ifndef _DOMAIN_ELASTIC_ELEMENTS2D_ISOTROPIC_HPP +#define _DOMAIN_ELASTIC_ELEMENTS2D_ISOTROPIC_HPP + +#include "compute/interface.hpp" +#include "domain/impl/elements/elastic/elastic2d.hpp" +#include "domain/impl/elements/element.hpp" +#include "enumerations/interface.hpp" +#include "kokkos_abstractions.h" +#include "specfem_setup.hpp" +#include + +namespace specfem { +namespace domain { +namespace impl { +namespace elements { +/** + * @brief Element specialization for 2D elastic isotropic spectral elements with + * static quadrature points + * + * @tparam NGLL Number of Gauss-Lobatto-Legendre quadrature points defined at + * compile time + * + * @tparam BC Boundary conditions if void then neumann boundary conditions are + * assumed + */ +template +class element< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::elastic, + specfem::enums::element::quadrature::static_quadrature_points, + specfem::enums::element::property::isotropic, BC> { +public: + /** @name Typedefs + * + */ + ///@{ + /** + * @brief dimension of the element + * + */ + using dimension = specfem::enums::element::dimension::dim2; + + /** + * @brief Medium of the element + * + */ + using medium_type = specfem::enums::element::medium::elastic; + + /** + * @brief Property of the element + * + */ + using property_type = specfem::enums::element::property::isotropic; + + /** + * @brief Number of Gauss-Lobatto-Legendre quadrature points defined at + * compile time + */ + using quadrature_points_type = + specfem::enums::element::quadrature::static_quadrature_points; + + /** + * @brief Boundary conditions of the element + * + * if BC == none then neumann boundary conditions are assumed + * + */ + using boundary_conditions_type = BC; + + /** + * @brief Use the scratch view type from the quadrature points + * + * @tparam T Type of the scratch view + * @tparam N Number of components + */ + template + using ScratchViewType = + typename quadrature_points_type::template ScratchViewType; + ///@} + + /** + * @brief Default constructor + * + */ + KOKKOS_FUNCTION + element() = default; + + /** + * @brief Construct a new element object + * + * @param partial_derivatives struct used to store partial derivatives at + * every GLL point + * @param properties struct used to store material properties at every GLL + * point + */ + KOKKOS_FUNCTION + element(const specfem::compute::partial_derivatives &partial_derivatives, + const specfem::compute::properties &properties, + const specfem::compute::boundaries &boundary_conditions, + const quadrature_points_type &quadrature_points); + + /** + * @brief Compute the mass matrix component ($ m_{\alpha, \beta} $) for a + * given quadrature point + * + * Mass matrix is given by \\f$ M = \sum_{\Omega_e} \sum_{\alpha, \beta} + * \omega_{\alpha} \omega_{\beta} m_{\alpha, \beta} \\f$ + * + * @param ispec Index of the spectral element + * @param xz index of the quadrature point within the spectral element + * @param mass_matrix mass matrix component + */ + KOKKOS_INLINE_FUNCTION + void compute_mass_matrix_component( + const int &ispec, const int &xz, + specfem::kokkos::array_type &mass_matrix) const; + + template + KOKKOS_INLINE_FUNCTION void mass_time_contribution( + const int &ispec, const int &ielement, const int &xz, const type_real &dt, + const specfem::kokkos::array_type &weight, + specfem::kokkos::array_type + &rmass_inverse) const; + + /** + * @brief Compute the gradient of the field at a particular + * Gauss-Lobatto-Legendre quadrature point + * + * @param ispec Index of the spectral element + * @param xz Index of Gauss-Lobatto-Legendre quadrature point + * @param s_hprime_xx Scratch view of derivative of Lagrange polynomial in x + * direction + * @param s_hprime_zz Scratch view of derivative of Lagrange polynomial in z + * direction + * @param u Scrath view of field. For elastic domains the field has 2 + * components + * @param dudxl Computed partial derivative of field \f$ \frac{\partial + * \tilde{u}}{\partial x} \f$ + * @param dudzl Computed partial derivative of field \f$ \frac{\partial + * \tilde{u}}{\partial z} \f$ + */ + KOKKOS_INLINE_FUNCTION void + compute_gradient(const int &ispec, const int &ielement, const int &xz, + const ScratchViewType s_hprime_xx, + const ScratchViewType s_hprime_zz, + const ScratchViewType u, + specfem::kokkos::array_type &dudxl, + specfem::kokkos::array_type &dudzl) const; + + /** + * @brief Compute the stress integrand at a particular Gauss-Lobatto-Legendre + * quadrature point. + * + * @param ispec Index of the spectral element + * @param xz Index of Gauss-Lobatto-Legendre quadrature point + * @param dudxl Partial derivative of field \f$ \frac{\partial + * \tilde{u}}{\partial x} \f$ + * @param dudzl Partial derivative of field \f$ \frac{\partial + * \tilde{u}}{\partial z} \f$ + * @param stress_integrand_xi Stress integrand wrt. \f$ \xi \f$ \f$ + * J^{\alpha, \gamma} \partial_x u \partial_x \xi + \partial_z u * \partial_z + * \xi \f$ + * @param stress_integrand_gamma Stress integrand wrt. \f$\gamma\f$ \f$ + * J^{\alpha, \gamma} \partial_x u \partial_x \gamma + \partial_z u * + * \partial_z \gamma \f$ + */ + KOKKOS_INLINE_FUNCTION void compute_stress( + const int &ispec, const int &ielement, const int &xz, + const specfem::kokkos::array_type &dudxl, + const specfem::kokkos::array_type &dudzl, + specfem::kokkos::array_type &stress_integrand_xi, + specfem::kokkos::array_type &stress_integrand_gamma) const; + + /** + * @brief Update the acceleration at the quadrature point xz + * + * @param xz Index of the quadrature point + * @param wxglll Weight of the Gauss-Lobatto-Legendre quadrature point in x + * direction + * @param wzglll Weight of the Gauss-Lobatto-Legendre quadrature point in z + * direction + * @param stress_integrand_xi Stress integrand wrt. \f$ \xi \f$ \f$ J^{\alpha, + * \gamma} \partial_x u \partial_x \xi + \partial_z u * \partial_z \xi \f$ as + * computed by compute_stress + * @param stress_integrand_gamma Stress integrand wrt. \f$\gamma\f$ \f$ + * J^{\alpha, \gamma} \partial_x u \partial_x \gamma + \partial_z u * + * \partial_z \gamma \f$ as computed by compute_stress + * @param s_hprimewgll_xx Scratch view hprime_xx * wxgll + * @param s_hprimewgll_zz Scratch view hprime_zz * wzgll + * @param field_dot_dot Acceleration of the field subviewed at global index xz + */ + KOKKOS_INLINE_FUNCTION void compute_acceleration( + const int &ispec, const int &ielement, const int &xz, + const specfem::kokkos::array_type &weight, + const ScratchViewType + stress_integrand_xi, + const ScratchViewType + stress_integrand_gamma, + const ScratchViewType s_hprimewgll_xx, + const ScratchViewType s_hprimewgll_zz, + const specfem::kokkos::array_type + &velocity, + specfem::kokkos::array_type &acceleration) const; + +private: + specfem::kokkos::DeviceView3d xix; ///< xix + specfem::kokkos::DeviceView3d xiz; ///< xiz + specfem::kokkos::DeviceView3d gammax; ///< gammax + specfem::kokkos::DeviceView3d gammaz; ///< gammaz + specfem::kokkos::DeviceView3d jacobian; ///< jacobian + specfem::kokkos::DeviceView3d lambdaplus2mu; ///< lambda + + ///< 2 * mu + specfem::kokkos::DeviceView3d mu; ///< mu + specfem::kokkos::DeviceView3d rho; ///< rho + boundary_conditions_type boundary_conditions; ///< Boundary conditions +}; +} // namespace elements +} // namespace impl +} // namespace domain +} // namespace specfem + +#endif diff --git a/include/domain/impl/elements/elastic/elastic2d_isotropic.tpp b/include/domain/impl/elements/elastic/elastic2d_isotropic.tpp new file mode 100644 index 00000000..8d7fa0ac --- /dev/null +++ b/include/domain/impl/elements/elastic/elastic2d_isotropic.tpp @@ -0,0 +1,332 @@ +#ifndef _DOMAIN_ELASTIC_ELEMENTS2D_ISOTROPIC_TPP +#define _DOMAIN_ELASTIC_ELEMENTS2D_ISOTROPIC_TPP + +#include "compute/interface.hpp" +#include "domain/impl/elements/elastic/elastic2d_isotropic.hpp" +#include "domain/impl/elements/element.hpp" +#include "enumerations/interface.hpp" +#include "globals.h" +#include "kokkos_abstractions.h" +#include "specfem_setup.hpp" +#include + +template +using StaticScratchViewType = + typename specfem::enums::element::quadrature::static_quadrature_points< + N>::template ScratchViewType; + +// using field_type = Kokkos::Subview< +// specfem::kokkos::DeviceView2d, int, +// std::remove_const_t >; + +// ----------------------------------------------------------------------------- +// SPECIALIZED ELEMENT +// ----------------------------------------------------------------------------- +template +KOKKOS_FUNCTION specfem::domain::impl::elements::element< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::elastic, + specfem::enums::element::quadrature::static_quadrature_points, + specfem::enums::element::property::isotropic, + BC>::element(const specfem::compute::partial_derivatives + &partial_derivatives, + const specfem::compute::properties &properties, + const specfem::compute::boundaries &boundary_conditions, + const quadrature_points_type &quadrature_points) { + +#ifndef NDEBUG + assert(partial_derivatives.xix.extent(1) == NGLL); + assert(partial_derivatives.xix.extent(2) == NGLL); + assert(partial_derivatives.gammax.extent(1) == NGLL); + assert(partial_derivatives.gammax.extent(2) == NGLL); + assert(partial_derivatives.xiz.extent(1) == NGLL); + assert(partial_derivatives.xiz.extent(2) == NGLL); + assert(partial_derivatives.gammaz.extent(1) == NGLL); + assert(partial_derivatives.gammaz.extent(2) == NGLL); + assert(partial_derivatives.jacobian.extent(1) == NGLL); + assert(partial_derivatives.jacobian.extent(2) == NGLL); + + // Properties + assert(properties.rho.extent(1) == NGLL); + assert(properties.rho.extent(2) == NGLL); + assert(properties.lambdaplus2mu.extent(1) == NGLL); + assert(properties.lambdaplus2mu.extent(2) == NGLL); + assert(properties.mu.extent(1) == NGLL); + assert(properties.mu.extent(2) == NGLL); +#endif + + this->xix = partial_derivatives.xix; + this->gammax = partial_derivatives.gammax; + this->xiz = partial_derivatives.xiz; + this->gammaz = partial_derivatives.gammaz; + this->jacobian = partial_derivatives.jacobian; + this->rho = properties.rho; + this->lambdaplus2mu = properties.lambdaplus2mu; + this->mu = properties.mu; + + this->boundary_conditions = + boundary_conditions_type(boundary_conditions, quadrature_points); + + return; +} + +template +KOKKOS_INLINE_FUNCTION void specfem::domain::impl::elements::element< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::elastic, + specfem::enums::element::quadrature::static_quadrature_points, + specfem::enums::element::property::isotropic, + BC>::compute_mass_matrix_component(const int &ispec, const int &xz, + specfem::kokkos::array_type + &mass_matrix) const { + int ix, iz; + sub2ind(xz, NGLL, iz, ix); + + constexpr int components = medium_type::components; + + static_assert(components == 2, + "Number of components must be 2 for 2D isotropic elastic " + "medium"); + + mass_matrix[0] = this->rho(ispec, iz, ix) * this->jacobian(ispec, iz, ix); + mass_matrix[1] = this->rho(ispec, iz, ix) * this->jacobian(ispec, iz, ix); + + return; +} + +template +template +KOKKOS_INLINE_FUNCTION void specfem::domain::impl::elements::element< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::elastic, + specfem::enums::element::quadrature::static_quadrature_points, + specfem::enums::element::property::isotropic, BC>:: + mass_time_contribution( + const int &ispec, const int &ielement, const int &xz, + const type_real &dt, + const specfem::kokkos::array_type &weight, + specfem::kokkos::array_type &rmass_inverse) const { + + int ix, iz; + sub2ind(xz, NGLL, iz, ix); + + constexpr int components = medium_type::components; + + const specfem::compute::element_partial_derivatives partial_derivatives = + specfem::compute::element_partial_derivatives( + this->xix(ispec, iz, ix), this->gammax(ispec, iz, ix), + this->xiz(ispec, iz, ix), this->gammaz(ispec, iz, ix), + this->jacobian(ispec, iz, ix)); + + const specfem::compute::element_properties + properties(this->lambdaplus2mu(ispec, iz, ix), this->mu(ispec, iz, ix), + this->rho(ispec, iz, ix)); + + rmass_inverse[0] = 0.0; + rmass_inverse[1] = 0.0; + + boundary_conditions.template mass_time_contribution( + ielement, xz, dt, weight, partial_derivatives, properties, rmass_inverse); + + return; +} + +template +KOKKOS_INLINE_FUNCTION void specfem::domain::impl::elements::element< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::elastic, + specfem::enums::element::quadrature::static_quadrature_points, + specfem::enums::element::property::isotropic, BC>:: + compute_gradient( + const int &ispec, const int &ielement, const int &xz, + const ScratchViewType s_hprime_xx, + const ScratchViewType s_hprime_zz, + const ScratchViewType u, + specfem::kokkos::array_type &dudxl, + specfem::kokkos::array_type &dudzl) const { + + int ix, iz; + sub2ind(xz, NGLL, iz, ix); + + const specfem::compute::element_partial_derivatives partial_derivatives = + specfem::compute::element_partial_derivatives( + this->xix(ispec, iz, ix), this->gammax(ispec, iz, ix), + this->xiz(ispec, iz, ix), this->gammaz(ispec, iz, ix)); + + type_real du_dxi[medium_type::components] = { 0.0, 0.0 }; + type_real du_dgamma[medium_type::components] = { 0.0, 0.0 }; + +#ifdef KOKKOS_ENABLE_CUDA +#pragma unroll +#endif + for (int l = 0; l < NGLL; l++) { + du_dxi[0] += s_hprime_xx(ix, l, 0) * u(iz, l, 0); + du_dxi[1] += s_hprime_xx(ix, l, 0) * u(iz, l, 1); + du_dgamma[0] += s_hprime_zz(iz, l, 0) * u(l, ix, 0); + du_dgamma[1] += s_hprime_zz(iz, l, 0) * u(l, ix, 1); + } + // duxdx + dudxl[0] = partial_derivatives.xix * du_dxi[0] + + partial_derivatives.gammax * du_dgamma[0]; + + // duxdz + dudzl[0] = partial_derivatives.xiz * du_dxi[0] + + partial_derivatives.gammaz * du_dgamma[0]; + + // duzdx + dudxl[1] = partial_derivatives.xix * du_dxi[1] + + partial_derivatives.gammax * du_dgamma[1]; + + // duzdz + dudzl[1] = partial_derivatives.gammax * du_dxi[1] + + partial_derivatives.gammaz * du_dgamma[1]; + + boundary_conditions.enforce_gradient(ielement, xz, partial_derivatives, dudxl, + dudzl); + + return; +} + +template +KOKKOS_INLINE_FUNCTION void specfem::domain::impl::elements::element< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::elastic, + specfem::enums::element::quadrature::static_quadrature_points, + specfem::enums::element::property::isotropic, + BC>::compute_stress(const int &ispec, const int &ielement, const int &xz, + const specfem::kokkos::array_type &dudxl, + const specfem::kokkos::array_type &dudzl, + specfem::kokkos::array_type + &stress_integrand_xi, + specfem::kokkos::array_type + &stress_integrand_gamma) const { + + int ix, iz; + sub2ind(xz, NGLL, iz, ix); + + const specfem::compute::element_partial_derivatives partial_derivatives = + specfem::compute::element_partial_derivatives( + this->xix(ispec, iz, ix), this->gammax(ispec, iz, ix), + this->xiz(ispec, iz, ix), this->gammaz(ispec, iz, ix), + this->jacobian(ispec, iz, ix)); + + const specfem::compute::element_properties + properties(this->lambdaplus2mu(ispec, iz, ix), this->mu(ispec, iz, ix), + this->rho(ispec, iz, ix)); + + type_real sigma_xx, sigma_zz, sigma_xz; + + if (specfem::globals::simulation_wave == specfem::wave::p_sv) { + // P_SV case + // sigma_xx + sigma_xx = + properties.lambdaplus2mu * dudxl[0] + properties.lambda * dudzl[1]; + + // sigma_zz + sigma_zz = + properties.lambdaplus2mu * dudzl[1] + properties.lambda * dudxl[0]; + + // sigma_xz + sigma_xz = properties.mu * (dudxl[1] + dudzl[0]); + } else if (specfem::globals::simulation_wave == specfem::wave::sh) { + // SH-case + // sigma_xx + sigma_xx = properties.mu * dudxl[0]; // would be sigma_xy in + // CPU-version + + // sigma_xz + sigma_xz = properties.mu * dudzl[0]; // sigma_zy + } + + stress_integrand_xi[0] = + partial_derivatives.jacobian * + (sigma_xx * partial_derivatives.xix + sigma_xz * partial_derivatives.xiz); + stress_integrand_xi[1] = + partial_derivatives.jacobian * + (sigma_xz * partial_derivatives.xix + sigma_zz * partial_derivatives.xiz); + stress_integrand_gamma[0] = + partial_derivatives.jacobian * (sigma_xx * partial_derivatives.gammax + + sigma_xz * partial_derivatives.gammaz); + stress_integrand_gamma[1] = + partial_derivatives.jacobian * (sigma_xz * partial_derivatives.gammax + + sigma_zz * partial_derivatives.gammaz); + + boundary_conditions.enforce_stress(ielement, xz, partial_derivatives, + properties, stress_integrand_xi, + stress_integrand_gamma); + + return; +} + +template +KOKKOS_INLINE_FUNCTION void specfem::domain::impl::elements::element< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::elastic, + specfem::enums::element::quadrature::static_quadrature_points, + specfem::enums::element::property::isotropic, BC>:: + compute_acceleration( + const int &ispec, const int &ielement, const int &xz, + const specfem::kokkos::array_type &weight, + const ScratchViewType + stress_integrand_xi, + const ScratchViewType + stress_integrand_gamma, + const ScratchViewType s_hprimewgll_xx, + const ScratchViewType s_hprimewgll_zz, + const specfem::kokkos::array_type + &velocity, + specfem::kokkos::array_type &acceleration) const { + + int ix, iz; + sub2ind(xz, NGLL, iz, ix); + type_real tempx1 = 0.0; + type_real tempz1 = 0.0; + type_real tempx3 = 0.0; + type_real tempz3 = 0.0; + + constexpr int components = medium_type::components; + + static_assert(components == 2, + "Number of components must be 2 for 2D isotropic elastic " + "medium"); + + specfem::compute::element_partial_derivatives partial_derivatives; + + specfem::compute::element_properties + properties; + + // populate partial derivatives only if the boundary is stacey + if constexpr (boundary_conditions_type::value == + specfem::enums::element::boundary_tag::stacey) { + partial_derivatives = specfem::compute::element_partial_derivatives( + this->xix(ispec, iz, ix), this->gammax(ispec, iz, ix), + this->xiz(ispec, iz, ix), this->gammaz(ispec, iz, ix), + this->jacobian(ispec, iz, ix)); + + properties = specfem::compute::element_properties( + this->lambdaplus2mu(ispec, iz, ix), this->mu(ispec, iz, ix), + this->rho(ispec, iz, ix)); + } + +#ifdef KOKKOS_ENABLE_CUDA +#pragma unroll +#endif + for (int l = 0; l < NGLL; l++) { + tempx1 += s_hprimewgll_xx(ix, l, 0) * stress_integrand_xi(iz, l, 0); + tempz1 += s_hprimewgll_xx(ix, l, 0) * stress_integrand_xi(iz, l, 1); + tempx3 += s_hprimewgll_zz(iz, l, 0) * stress_integrand_gamma(l, ix, 0); + tempz3 += s_hprimewgll_zz(iz, l, 0) * stress_integrand_gamma(l, ix, 1); + } + + acceleration[0] = -1.0 * (weight[1] * tempx1) - (weight[0] * tempx3); + acceleration[1] = -1.0 * (weight[1] * tempz1) - (weight[0] * tempz3); + + boundary_conditions.enforce_traction(ielement, xz, weight, + partial_derivatives, properties, + velocity, acceleration); +} + +#endif diff --git a/include/domain/impl/elements/elastic/interface.hpp b/include/domain/impl/elements/elastic/interface.hpp new file mode 100644 index 00000000..8f07017a --- /dev/null +++ b/include/domain/impl/elements/elastic/interface.hpp @@ -0,0 +1,8 @@ +#ifndef _DOMAIN_IMPL_ELEMENTS_ELASTIC_INTERFACE_HPP +#define _DOMAIN_IMPL_ELEMENTS_ELASTIC_INTERFACE_HPP + +#include "elastic2d.hpp" +#include "elastic2d_isotropic.hpp" +#include "elastic2d_isotropic.tpp" + +#endif // _DOMAIN_IMPL_ELEMENTS_ELASTIC_INTERFACE_HPP diff --git a/include/domain/impl/elements/element.hpp b/include/domain/impl/elements/element.hpp new file mode 100644 index 00000000..13360cf4 --- /dev/null +++ b/include/domain/impl/elements/element.hpp @@ -0,0 +1,23 @@ +#ifndef DOMAIN_ELEMENTS_HPP +#define DOMAIN_ELEMENTS_HPP + +#include "enumerations/interface.hpp" + +namespace specfem { +namespace domain { +namespace impl { +namespace elements { +/** + * @brief Element class to describe the physics of a spectral element + * + * @tparam properties of the element used to specialize elemental + * implementation + */ +template class element {}; + +} // namespace elements +} // namespace impl +} // namespace domain +} // namespace specfem + +#endif diff --git a/include/domain/impl/elements/interface.hpp b/include/domain/impl/elements/interface.hpp new file mode 100644 index 00000000..3222e448 --- /dev/null +++ b/include/domain/impl/elements/interface.hpp @@ -0,0 +1,15 @@ +#ifndef _DOMAIN_ELEMENT_INTERFACE_HPP +#define _DOMAIN_ELEMENT_INTERFACE_HPP + +#include "acoustic/acoustic2d.hpp" +#include "acoustic/acoustic2d_isotropic.hpp" +#include "acoustic/acoustic2d_isotropic.tpp" +#include "container.hpp" +#include "elastic/elastic2d.hpp" +#include "elastic/elastic2d_isotropic.hpp" +#include "elastic/elastic2d_isotropic.tpp" +#include "element.hpp" +#include "kernel.hpp" +#include "kernel.tpp" + +#endif diff --git a/include/domain/impl/elements/kernel.hpp b/include/domain/impl/elements/kernel.hpp new file mode 100644 index 00000000..83b92c6d --- /dev/null +++ b/include/domain/impl/elements/kernel.hpp @@ -0,0 +1,71 @@ +#ifndef DOMAIN_IMPL_ELEMENTS_KERNEL_HPP +#define DOMAIN_IMPL_ELEMENTS_KERNEL_HPP + +#include "compute/interface.hpp" +#include "domain/impl/elements/acoustic/interface.hpp" +#include "domain/impl/elements/elastic/interface.hpp" +#include "enumerations/interface.hpp" +#include "kokkos_abstractions.h" +#include "quadrature/interface.hpp" +#include "specfem_setup.hpp" + +namespace specfem { +namespace domain { +namespace impl { +namespace kernels { + +template +class element_kernel { + +public: + using dimension = specfem::enums::element::dimension::dim2; + using medium_type = medium; + using quadrature_point_type = qp_type; + using property_type = property; + using boundary_conditions_type = BC; + + element_kernel() = default; + element_kernel( + const specfem::kokkos::DeviceView3d ibool, + const specfem::kokkos::DeviceView1d ispec, + const specfem::compute::partial_derivatives &partial_derivatives, + const specfem::compute::properties &properties, + const specfem::compute::boundaries &boundary_conditions, + specfem::quadrature::quadrature *quadx, + specfem::quadrature::quadrature *quadz, qp_type quadrature_points, + specfem::kokkos::DeviceView2d field, + specfem::kokkos::DeviceView2d field_dot, + specfem::kokkos::DeviceView2d + field_dot_dot, + specfem::kokkos::DeviceView2d mass_matrix); + + void compute_mass_matrix() const; + + void compute_stiffness_interaction() const; + + template + void mass_time_contribution(const type_real dt) const; + + __inline__ int total_elements() const { return ispec.extent(0); } + +private: + specfem::kokkos::DeviceView1d ispec; + specfem::kokkos::DeviceView3d ibool; + specfem::kokkos::DeviceView2d field; + specfem::kokkos::DeviceView2d field_dot; + specfem::kokkos::DeviceView2d field_dot_dot; + specfem::kokkos::DeviceView2d mass_matrix; + qp_type quadrature_points; + specfem::quadrature::quadrature *quadx; + specfem::quadrature::quadrature *quadz; + specfem::domain::impl::elements::element< + dimension, medium, qp_type, property_type, boundary_conditions_type> + element; +}; + +} // namespace kernels +} // namespace impl +} // namespace domain +} // namespace specfem + +#endif // DOMAIN_IMPL_ELEMENTS_KERNEL_HPP diff --git a/include/domain/impl/elements/kernel.tpp b/include/domain/impl/elements/kernel.tpp new file mode 100644 index 00000000..36ba9b2f --- /dev/null +++ b/include/domain/impl/elements/kernel.tpp @@ -0,0 +1,413 @@ +#ifndef _DOMAIN_IMPL_ELEMENTS_KERNEL_TPP +#define _DOMAIN_IMPL_ELEMENTS_KERNEL_TPP + +#include "compute/interface.hpp" +#include "domain/impl/elements/acoustic/interface.hpp" +#include "domain/impl/elements/elastic/interface.hpp" +#include "enumerations/interface.hpp" +#include "kernel.hpp" +#include "kokkos_abstractions.h" +#include "quadrature/interface.hpp" +#include "specfem_setup.hpp" +#include + +namespace { +// Do not pull velocity from global memory +template +KOKKOS_INLINE_FUNCTION specfem::kokkos::array_type +get_velocity( + const int &iglob, + specfem::kokkos::DeviceView2d field_dot) { + + specfem::kokkos::array_type velocity; + + // check if we need the velocity for computing the acceleration + constexpr bool flag = + ((tag == specfem::enums::element::boundary_tag::stacey) || + (tag == + specfem::enums::element::boundary_tag::composite_stacey_dirichlet)); + + // Only get velocity from global memory for stacey boundary + if constexpr (flag) { + for (int icomponent = 0; icomponent < components; ++icomponent) + velocity[icomponent] = field_dot(iglob, icomponent); + } else { + for (int icomponent = 0; icomponent < components; ++icomponent) + velocity[icomponent] = 0.0; + } + + return velocity; +}; +} // namespace + +template +specfem::domain::impl::kernels::element_kernel:: + element_kernel( + const specfem::kokkos::DeviceView3d ibool, + const specfem::kokkos::DeviceView1d ispec, + const specfem::compute::partial_derivatives &partial_derivatives, + const specfem::compute::properties &properties, + const specfem::compute::boundaries &boundary_conditions, + specfem::quadrature::quadrature *quadx, + specfem::quadrature::quadrature *quadz, qp_type quadrature_points, + specfem::kokkos::DeviceView2d field, + specfem::kokkos::DeviceView2d field_dot, + specfem::kokkos::DeviceView2d + field_dot_dot, + specfem::kokkos::DeviceView2d + mass_matrix) + : ibool(ibool), ispec(ispec), quadx(quadx), quadz(quadz), + quadrature_points(quadrature_points), field(field), field_dot(field_dot), + field_dot_dot(field_dot_dot), mass_matrix(mass_matrix) { + +#ifndef NDEBUG + assert(field.extent(1) == medium::components); + assert(field_dot_dot.extent(1) == medium::components); + assert(mass_matrix.extent(1) == medium::components); +#endif + + static_assert(std::is_same_v, + "Boundary conditions should have the same medium type as the " + "element kernel"); + static_assert(std::is_same_v, + "Boundary conditions should have the same dimension as the " + "element kernel"); + static_assert(std::is_same_v, + "Boundary conditions should have the same quadrature point " + "type as the element kernel"); + static_assert(std::is_same_v, + "Boundary conditions should have the same property as the " + "element kernel"); + + element = specfem::domain::impl::elements::element< + dimension, medium_type, quadrature_point_type, property, BC>( + partial_derivatives, properties, boundary_conditions, quadrature_points); + return; +} + +template +void specfem::domain::impl::kernels::element_kernel< + medium, qp_type, property, BC>::compute_mass_matrix() const { + + constexpr int components = medium::components; + const int nelements = ispec.extent(0); + + if (nelements == 0) + return; + + const auto wxgll = this->quadx->get_w(); + const auto wzgll = this->quadz->get_w(); + + Kokkos::parallel_for( + "specfem::domain::kernes::elements::compute_mass_matrix", + specfem::kokkos::DeviceTeam(ispec.extent(0), Kokkos::AUTO, 1), + KOKKOS_CLASS_LAMBDA( + const specfem::kokkos::DeviceTeam::member_type &team_member) { + int ngllx, ngllz; + quadrature_points.get_ngll(&ngllx, &ngllz); + const auto ispec_l = ispec(team_member.league_rank()); + + Kokkos::parallel_for( + quadrature_points.template TeamThreadRange( + team_member), + [&](const int xz) { + int ix, iz; + sub2ind(xz, ngllx, iz, ix); + int iglob = ibool(ispec_l, iz, ix); + + specfem::kokkos::array_type + mass_matrix_element; + + element.compute_mass_matrix_component(ispec_l, xz, + mass_matrix_element); + +#ifdef KOKKOS_ENABLE_CUDA +#pragma unroll +#endif + for (int icomponent = 0; icomponent < components; icomponent++) { + Kokkos::single(Kokkos::PerThread(team_member), [&]() { + Kokkos::atomic_add(&mass_matrix(iglob, icomponent), + wxgll(ix) * wzgll(iz) * + mass_matrix_element[icomponent]); + }); + } + }); + }); + + Kokkos::fence(); + + return; +} + +template +template +void specfem::domain::impl::kernels::element_kernel< + medium, qp_type, property, BC>::mass_time_contribution(const type_real dt) + const { + + constexpr int components = medium::components; + const int nelements = ispec.extent(0); + + if (nelements == 0) + return; + + const auto wxgll = this->quadx->get_w(); + const auto wzgll = this->quadz->get_w(); + + Kokkos::parallel_for( + "specfem::domain::kernes::elements::add_mass_matrix_contribution", + specfem::kokkos::DeviceTeam(ispec.extent(0), Kokkos::AUTO, 1), + KOKKOS_CLASS_LAMBDA( + const specfem::kokkos::DeviceTeam::member_type &team_member) { + int ngllx, ngllz; + quadrature_points.get_ngll(&ngllx, &ngllz); + const auto ielement = team_member.league_rank(); + const auto ispec_l = ispec(ielement); + + Kokkos::parallel_for( + quadrature_points.template TeamThreadRange( + team_member), + [&](const int xz) { + int ix, iz; + sub2ind(xz, ngllx, iz, ix); + int iglob = ibool(ispec_l, iz, ix); + + specfem::kokkos::array_type + mass_matrix_element; + + specfem::kokkos::array_type weight; + + weight[0] = wxgll(ix); + weight[1] = wzgll(iz); + + element.template mass_time_contribution( + ispec_l, ielement, xz, dt, weight, mass_matrix_element); + +#ifdef KOKKOS_ENABLE_CUDA +#pragma unroll +#endif + for (int icomponent = 0; icomponent < components; ++icomponent) { + const type_real __mass_matrix = mass_matrix(iglob, icomponent); + Kokkos::single(Kokkos::PerThread(team_member), [&]() { + Kokkos::atomic_add(&mass_matrix(iglob, icomponent), + mass_matrix_element[icomponent]); + }); + } + }); + }); + + Kokkos::fence(); + return; +} + +template +void specfem::domain::impl::kernels::element_kernel< + medium, qp_type, property, BC>::compute_stiffness_interaction() const { + + constexpr int components = medium::components; + const int nelements = ispec.extent(0); + + if (nelements == 0) + return; + + const auto hprime_xx = this->quadx->get_hprime(); + const auto hprime_zz = this->quadz->get_hprime(); + const auto wxgll = this->quadx->get_w(); + const auto wzgll = this->quadz->get_w(); + + // s_hprime_xx, s_hprimewgll_xx + int scratch_size = + 2 * quadrature_points.template shmem_size< + type_real, 1, specfem::enums::axes::x, specfem::enums::axes::x>(); + + // s_hprime_zz, s_hprimewgll_zz + scratch_size += + 2 * quadrature_points.template shmem_size< + type_real, 1, specfem::enums::axes::z, specfem::enums::axes::z>(); + + // s_field, s_stress_integrand_xi, s_stress_integrand_gamma + scratch_size += + 3 * + quadrature_points + .template shmem_size(); + + // s_iglob + scratch_size += + quadrature_points.template shmem_size(); + + Kokkos::parallel_for( + "specfem::domain::impl::kernels::elements::compute_stiffness_interaction", + specfem::kokkos::DeviceTeam(nelements, NTHREADS, NLANES) + .set_scratch_size(0, Kokkos::PerTeam(scratch_size)), + KOKKOS_CLASS_LAMBDA( + const specfem::kokkos::DeviceTeam::member_type &team_member) { + int ngllx, ngllz; + quadrature_points.get_ngll(&ngllx, &ngllz); + const auto ielement = team_member.league_rank(); + const auto ispec_l = ispec(ielement); + + // Instantiate shared views + // --------------------------------------------------------------- + auto s_hprime_xx = quadrature_points.template ScratchView< + type_real, 1, specfem::enums::axes::x, specfem::enums::axes::x>( + team_member.team_scratch(0)); + auto s_hprime_zz = quadrature_points.template ScratchView< + type_real, 1, specfem::enums::axes::z, specfem::enums::axes::z>( + team_member.team_scratch(0)); + auto s_hprimewgll_xx = quadrature_points.template ScratchView< + type_real, 1, specfem::enums::axes::x, specfem::enums::axes::x>( + team_member.team_scratch(0)); + auto s_hprimewgll_zz = quadrature_points.template ScratchView< + type_real, 1, specfem::enums::axes::z, specfem::enums::axes::z>( + team_member.team_scratch(0)); + + auto s_field = + quadrature_points.template ScratchView( + team_member.team_scratch(0)); + auto s_stress_integrand_xi = + quadrature_points.template ScratchView( + team_member.team_scratch(0)); + auto s_stress_integrand_gamma = + quadrature_points.template ScratchView( + team_member.team_scratch(0)); + auto s_iglob = quadrature_points.template ScratchView< + int, 1, specfem::enums::axes::z, specfem::enums::axes::x>( + team_member.team_scratch(0)); + + // ---------- Allocate shared views ------------------------------- + Kokkos::parallel_for( + quadrature_points.template TeamThreadRange( + team_member), + [&](const int xz) { + int iz, ix; + sub2ind(xz, ngllx, iz, ix); + s_hprime_xx(iz, ix, 0) = hprime_xx(iz, ix); + s_hprimewgll_xx(ix, iz, 0) = wxgll(iz) * hprime_xx(iz, ix); + }); + + Kokkos::parallel_for( + quadrature_points.template TeamThreadRange( + team_member), + [&](const int xz) { + int iz, ix; + sub2ind(xz, ngllz, iz, ix); + s_hprime_zz(iz, ix, 0) = hprime_zz(iz, ix); + s_hprimewgll_zz(ix, iz, 0) = wzgll(iz) * hprime_zz(iz, ix); + }); + + Kokkos::parallel_for( + quadrature_points.template TeamThreadRange( + team_member), + [&](const int xz) { + int iz, ix; + sub2ind(xz, ngllx, iz, ix); + const int iglob = ibool(ispec_l, iz, ix); + s_iglob(iz, ix, 0) = iglob; +#ifdef KOKKOS_ENABLE_CUDA +#pragma unroll +#endif + for (int icomponent = 0; icomponent < components; ++icomponent) { + s_field(iz, ix, icomponent) = field(iglob, icomponent); + s_stress_integrand_xi(iz, ix, icomponent) = 0.0; + s_stress_integrand_gamma(iz, ix, icomponent) = 0.0; + } + }); + + // ------------------------------------------------------------------ + + team_member.team_barrier(); + + Kokkos::parallel_for( + quadrature_points.template TeamThreadRange( + team_member), + [&](const int xz) { + int ix, iz; + sub2ind(xz, ngllx, iz, ix); + + specfem::kokkos::array_type + dudxl; + specfem::kokkos::array_type + dudzl; + + element.compute_gradient(ispec_l, ielement, xz, s_hprime_xx, + s_hprime_zz, s_field, dudxl, dudzl); + + specfem::kokkos::array_type + stress_integrand_xi; + specfem::kokkos::array_type + stress_integrand_gamma; + + element.compute_stress(ispec_l, ielement, xz, dudxl, dudzl, + stress_integrand_xi, + stress_integrand_gamma); +#ifdef KOKKOS_ENABLE_CUDA +#pragma unroll +#endif + for (int icomponent = 0; icomponent < components; ++icomponent) { + s_stress_integrand_xi(iz, ix, icomponent) = + stress_integrand_xi[icomponent]; + s_stress_integrand_gamma(iz, ix, icomponent) = + stress_integrand_gamma[icomponent]; + } + }); + + team_member.team_barrier(); + + Kokkos::parallel_for( + quadrature_points.template TeamThreadRange( + team_member), + [&](const int xz) { + int iz, ix; + sub2ind(xz, ngllx, iz, ix); + + const int iglob = s_iglob(iz, ix, 0); + specfem::kokkos::array_type weight; + + weight[0] = wxgll(ix); + weight[1] = wzgll(iz); + + specfem::kokkos::array_type + acceleration; + + // only get velocity from global memory for stacey boundary + auto velocity = + get_velocity(iglob, field_dot); + + element.compute_acceleration( + ispec_l, ielement, xz, weight, s_stress_integrand_xi, + s_stress_integrand_gamma, s_hprimewgll_xx, s_hprimewgll_zz, + velocity, acceleration); + +#ifdef KOKKOS_ENABLE_CUDA +#pragma unroll +#endif + for (int icomponent = 0; icomponent < components; ++icomponent) { + Kokkos::single(Kokkos::PerThread(team_member), [&]() { + Kokkos::atomic_add(&field_dot_dot(iglob, icomponent), + acceleration[icomponent]); + }); + } + }); + }); + + Kokkos::fence(); + + return; +} + +#endif // _DOMAIN_IMPL_ELEMENTS_KERNEL_TPP diff --git a/include/domain/impl/interface.hpp b/include/domain/impl/interface.hpp new file mode 100644 index 00000000..e22ed794 --- /dev/null +++ b/include/domain/impl/interface.hpp @@ -0,0 +1,8 @@ +#ifndef _DOMAIN_IMPL_KERNELS_INTERFACE_HPP +#define _DOMAIN_IMPL_KERNELS_INTERFACE_HPP + +#include "domain/impl/elements/interface.hpp" +#include "kernels.hpp" +#include "kernels.tpp" + +#endif // _DOMAIN_IMPL_KERNELS_INTERFACE_HPP diff --git a/include/domain/impl/kernels.hpp b/include/domain/impl/kernels.hpp new file mode 100644 index 00000000..f1b1c3fc --- /dev/null +++ b/include/domain/impl/kernels.hpp @@ -0,0 +1,234 @@ +#ifndef _DOMAIN_KERNELS_HPP +#define _DOMAIN_KERNELS_HPP + +#include "compute/interface.hpp" +#include "domain/impl/elements/interface.hpp" +#include "domain/impl/receivers/interface.hpp" +#include "domain/impl/sources/interface.hpp" +#include "enumerations/interface.hpp" + +namespace specfem { +namespace domain { +namespace impl { +namespace kernels { + +/** + * @brief Kernels object used to compute elemental kernels + * + * This object consists of various Kokkos kernels used to compute elemental + * contributions from different types of element, sources, and receivers. + * + * The template parameters are inherited from the domain class. + * + * @tparam medium class defining the domain medium. Separate implementations + * exist for elastic, acoustic or poroelastic media + * @tparam qp_type class used to define the quadrature points either + * at compile time or run time + */ +template class kernels { + +public: + using dimension = specfem::enums::element::dimension::dim2; // Dimension of + // the domain + using medium_type = medium; // Type of medium i.e. acoustic, elastic or + // poroelastic + using quadrature_point_type = qp_type; // Type of quadrature points i.e. + // static or dynamic + + /** + * @brief Default constructor + * + */ + kernels() = default; + + /** + * @brief Construct a new kernels object + * + * @param ibool Global index for every GLL point in the SPECFEM simulation + * @param partial_derivatives struct used to store partial derivatives at + * every GLL point + * @param properties struct used to store material properties at every GLL + * point + * @param sources struct used to store information about sources + * @param receives struct used to store information about receivers + * @param quadx Pointer to quadrature points in X direction + * @param quadz Pointer to quadrature points in Z direction + * @param quadrature_points quadrature points object to define number of + * quadrature points either at compile time or run time + * @param field wavefield inside the domain + * @param field_dot derivative of wavefield inside the domain + * @param field_dot_dot double derivative of wavefield inside the domain + * @param mass_matrix mass matrix for every GLL point inside the domain + */ + kernels( + const specfem::kokkos::DeviceView3d ibool, + const specfem::compute::partial_derivatives &partial_derivatives, + const specfem::compute::properties &properties, + const specfem::compute::boundaries &boundaries, + const specfem::compute::sources &sources, + const specfem::compute::receivers &receives, + specfem::quadrature::quadrature *quadx, + specfem::quadrature::quadrature *quadz, qp_type quadrature_points, + specfem::kokkos::DeviceView2d field, + specfem::kokkos::DeviceView2d field_dot, + specfem::kokkos::DeviceView2d + field_dot_dot, + specfem::kokkos::DeviceView2d mass_matrix); + + /** + * @brief + * + */ + template + inline void mass_time_contribution(const type_real &dt) const { + isotropic_elements.template mass_time_contribution(dt); + isotropic_elements_dirichlet.template mass_time_contribution( + dt); + isotropic_elements_stacey.template mass_time_contribution(dt); + isotropic_elements_stacey_dirichlet + .template mass_time_contribution(dt); + return; + } + + /** + * @brief execute Kokkos kernel to compute contribution of stiffness matrix to + * the global acceleration + * + */ + inline void compute_stiffness_interaction() const { + isotropic_elements.compute_stiffness_interaction(); + isotropic_elements_dirichlet.compute_stiffness_interaction(); + isotropic_elements_stacey.compute_stiffness_interaction(); + isotropic_elements_stacey_dirichlet.compute_stiffness_interaction(); + return; + } + + /** + * @brief execute Kokkos kernel to compute the mass matrix for every GLL point + * + */ + inline void compute_mass_matrix() const { + isotropic_elements.compute_mass_matrix(); + isotropic_elements_dirichlet.compute_mass_matrix(); + isotropic_elements_stacey.compute_mass_matrix(); + isotropic_elements_stacey_dirichlet.compute_mass_matrix(); + return; + } + + /** + * @brief execute Kokkos kernel compute the contribution of sources to the + * global acceleration + * + * @param timeval time value at the current time step + */ + inline void compute_source_interaction(const type_real timeval) const { + isotropic_sources.compute_source_interaction(timeval); + return; + } + + /** + * @brief execute Kokkos kernel to compute seismogram values at every receiver + * for the current seismogram step + * + * A seismogram step is defined as the current time step divided by the + * seismogram sampling rate + * + * @param isig_step current seismogram step. + */ + inline void compute_seismograms(const int &isig_step) const { + isotropic_receivers.compute_seismograms(isig_step); + return; + } + +private: + template + using dirichlet = specfem::enums::boundary_conditions::template dirichlet< + dimension, medium_type, property, quadrature_point_type>; // Dirichlet + // boundary + // conditions + + template + using stacey = specfem::enums::boundary_conditions::template stacey< + dimension, medium_type, property, quadrature_point_type>; // Stacey + // boundary + // conditions + + template + using none = specfem::enums::boundary_conditions::template none< + dimension, medium_type, property, quadrature_point_type>; // No boundary + // conditions + + template + using composite_boundary = + specfem::enums::boundary_conditions::composite_boundary< + BC1, BC2>; // Composite boundary conditions + + /** + * @brief Elemental kernels for isotropic elements + * + */ + specfem::domain::impl::kernels::element_kernel< + medium_type, quadrature_point_type, + specfem::enums::element::property::isotropic, + none > + isotropic_elements; + + /** + * @brief Elemental kernels for isotropic elements with dirichlet boundary + * conditions + * + */ + specfem::domain::impl::kernels::element_kernel< + medium_type, quadrature_point_type, + specfem::enums::element::property::isotropic, + dirichlet > + isotropic_elements_dirichlet; + + /** + * @brief Elemental kernels for isotropic elements with stacey boundary + * + */ + specfem::domain::impl::kernels::element_kernel< + medium_type, quadrature_point_type, + specfem::enums::element::property::isotropic, + stacey > + isotropic_elements_stacey; + + /** + * @brief Elemental kernels for isotropic elements with composite stacey and + * dirichlet boundary + * + */ + specfem::domain::impl::kernels::element_kernel< + medium_type, quadrature_point_type, + specfem::enums::element::property::isotropic, + composite_boundary< + stacey, + dirichlet > > + isotropic_elements_stacey_dirichlet; + + /** + * @brief Elemental source kernels for isotropic elements + * + */ + specfem::domain::impl::kernels::source_kernel< + medium_type, quadrature_point_type, + specfem::enums::element::property::isotropic> + isotropic_sources; + + /** + * @brief Elemental receiver kernels for isotropic elements + * + */ + specfem::domain::impl::kernels::receiver_kernel< + medium_type, quadrature_point_type, + specfem::enums::element::property::isotropic> + isotropic_receivers; ///< Elemental receiver kernels for isotropic + ///< elements +}; +} // namespace kernels +} // namespace impl +} // namespace domain +} // namespace specfem + +#endif // _DOMAIN_KERNELS_HPP diff --git a/include/domain/impl/kernels.tpp b/include/domain/impl/kernels.tpp new file mode 100644 index 00000000..ba773055 --- /dev/null +++ b/include/domain/impl/kernels.tpp @@ -0,0 +1,423 @@ +#ifndef _DOMAIN_KERNELS_TPP +#define _DOMAIN_KERNELS_TPP + +#include "compute/interface.hpp" +#include "domain/impl/elements/interface.hpp" +#include "domain/impl/receivers/interface.hpp" +#include "domain/impl/sources/interface.hpp" +#include "enumerations/interface.hpp" +#include "kernels.hpp" +#include "kokkos_abstractions.h" +#include "macros.hpp" +#include "quadrature/interface.hpp" + +namespace { +/// Struct to tag each element +struct element_tag { + + element_tag( + const specfem::enums::element::type &medium_tag, + const specfem::enums::element::property_tag &property_tag, + const specfem::enums::element::boundary_tag_container &boundary_tag) + : medium_tag(medium_tag), property_tag(property_tag), + boundary_tag(boundary_tag) {} + + element_tag() = default; + + specfem::enums::element::property_tag property_tag; + specfem::enums::element::boundary_tag_container boundary_tag; + specfem::enums::element::type medium_tag; +}; + +template +void allocate_elements( + const specfem::kokkos::DeviceView3d ibool, + const specfem::kokkos::HostView1d element_tags, + const specfem::compute::partial_derivatives &partial_derivatives, + const specfem::compute::properties &properties, + const specfem::compute::boundaries &boundary_conditions, + specfem::quadrature::quadrature *quadx, + specfem::quadrature::quadrature *quadz, qp_type quadrature_points, + specfem::kokkos::DeviceView2d field, + specfem::kokkos::DeviceView2d field_dot, + specfem::kokkos::DeviceView2d field_dot_dot, + specfem::kokkos::DeviceView2d mass_matrix, + specfem::domain::impl::kernels::element_kernel &elements) { + + constexpr auto boundary_tag = BC::value; + constexpr auto medium_tag = medium::value; + constexpr auto property_tag = property::value; + + const int nspec = partial_derivatives.xix.extent(0); + + // count number of elements in this domain + int nelements = 0; + for (int ispec = 0; ispec < nspec; ispec++) { + if (element_tags(ispec).medium_tag == medium_tag && + element_tags(ispec).property_tag == property_tag && + element_tags(ispec).boundary_tag == boundary_tag) { + + // make sure acoustic free surface elements are acoustic + if (element_tags(ispec).boundary_tag == + specfem::enums::element::boundary_tag::acoustic_free_surface) { + if (element_tags(ispec).medium_tag != + specfem::enums::element::type::acoustic) { + throw std::runtime_error("Error: acoustic free surface boundary " + "condition found non acoustic element"); + } + } + nelements++; + } + } + + specfem::kokkos::DeviceView1d ispec_domain( + "specfem::domain::domain::h_ispec_domain", nelements); + specfem::kokkos::HostMirror1d h_ispec_domain = + Kokkos::create_mirror_view(ispec_domain); + + // Get ispec for each element in this domain + int index = 0; + for (int ispec = 0; ispec < nspec; ispec++) { + if (element_tags(ispec).medium_tag == medium_tag && + element_tags(ispec).property_tag == property_tag && + element_tags(ispec).boundary_tag == boundary_tag) { + h_ispec_domain(index) = ispec; + index++; + } + } + + // assert that boundary_conditions ispec matches with calculated ispec + if constexpr (((boundary_tag == specfem::enums::element::boundary_tag:: + acoustic_free_surface) && + (medium_tag == specfem::enums::element::type::acoustic))) { + ASSERT( + nelements == boundary_conditions.acoustic_free_surface.nelements, + "nelements = " << nelements << " nelem_acoustic_surface = " + << boundary_conditions.acoustic_free_surface.nelements); + for (int i = 0; i < nelements; i++) { + ASSERT(h_ispec_domain(i) == + boundary_conditions.acoustic_free_surface.h_ispec(i), + "Error: computing ispec for acoustic free surface elements"); + } + } + + // assert that boundary_conditions ispec matches with calculated ispec + if constexpr ((boundary_tag == + specfem::enums::element::boundary_tag::stacey) && + (medium_tag == specfem::enums::element::type::acoustic)) { + ASSERT(nelements == boundary_conditions.stacey.acoustic.nelements, + "nelements = " << nelements << " nelements = " + << boundary_conditions.stacey.acoustic.nelements); + for (int i = 0; i < nelements; i++) { + ASSERT(h_ispec_domain(i) == + boundary_conditions.stacey.acoustic.h_ispec(i), + "Error: computing ispec for stacey elements"); + } + } else if constexpr ((boundary_tag == + specfem::enums::element::boundary_tag::stacey) && + (medium_tag == specfem::enums::element::type::elastic)) { + ASSERT(nelements == boundary_conditions.stacey.elastic.nelements, + "nelements = " << nelements << " nelements = " + << boundary_conditions.stacey.elastic.nelements); + for (int i = 0; i < nelements; i++) { + ASSERT(h_ispec_domain(i) == boundary_conditions.stacey.elastic.h_ispec(i), + "Error: computing ispec for stacey elements"); + } + } + + // assert that boundary_conditions ispec matches with calculated ispec + if constexpr ((boundary_tag == specfem::enums::element::boundary_tag:: + composite_stacey_dirichlet) && + (medium_tag == specfem::enums::element::type::acoustic)) { + ASSERT(nelements == + boundary_conditions.composite_stacey_dirichlet.nelements, + "nelements = " + << nelements << " nelements = " + << boundary_conditions.composite_stacey_dirichlet.nelements); + for (int i = 0; i < nelements; i++) { + ASSERT(h_ispec_domain(i) == + boundary_conditions.composite_stacey_dirichlet.h_ispec(i), + "Error: computing ispec for stacey dirichlet elements"); + } + } + + // Copy ispec_domain to device + Kokkos::deep_copy(ispec_domain, h_ispec_domain); + + std::cout << " - Element type: \n" + << " - dimension : " + << specfem::enums::element::dimension::dim2::to_string() << "\n" + << " - property : " << property::to_string() << "\n" + << " - Boundary Conditions : " << BC::to_string() << "\n" + << " - Number of elements : " << nelements << "\n\n"; + + // Create isotropic acoustic surface elements + elements = specfem::domain::impl::kernels::element_kernel( + ibool, ispec_domain, partial_derivatives, properties, boundary_conditions, + quadx, quadz, quadrature_points, field, field_dot, field_dot_dot, + mass_matrix); +} + +template +void allocate_isotropic_sources( + const specfem::kokkos::DeviceView3d ibool, + const specfem::compute::properties &properties, + const specfem::compute::sources &sources, qp_type quadrature_points, + specfem::kokkos::DeviceView2d field_dot_dot, + specfem::domain::impl::kernels::source_kernel< + medium, qp_type, specfem::enums::element::property::isotropic> + &isotropic_sources) { + + const auto value = medium::value; + + // Create isotropic sources + + const auto ispec_array = sources.h_ispec_array; + int nsources = 0; + for (int isource = 0; isource < ispec_array.extent(0); isource++) { + if (properties.h_ispec_type(ispec_array(isource)) == value) { + nsources++; + } + } + + specfem::kokkos::DeviceView1d ispec_sources( + "specfem::domain::domain::ispec_sources", nsources); + + specfem::kokkos::HostMirror1d h_ispec_sources = + Kokkos::create_mirror_view(ispec_sources); + + specfem::kokkos::DeviceView1d isource_array( + "specfem::domain::domain::isource_array", nsources); + + specfem::kokkos::HostMirror1d h_isource_array = + Kokkos::create_mirror_view(isource_array); + + int index = 0; + for (int isource = 0; isource < ispec_array.extent(0); isource++) { + if (properties.h_ispec_type(ispec_array(isource)) == value) { + h_ispec_sources(index) = ispec_array(isource); + h_isource_array(index) = isource; + index++; + } + } + + Kokkos::deep_copy(ispec_sources, h_ispec_sources); + Kokkos::deep_copy(isource_array, h_isource_array); + + isotropic_sources = specfem::domain::impl::kernels::source_kernel< + medium, qp_type, specfem::enums::element::property::isotropic>( + ibool, ispec_sources, isource_array, properties, sources, + quadrature_points, field_dot_dot); + + return; +} + +template +void allocate_isotropic_receivers( + const specfem::kokkos::DeviceView3d ibool, + const specfem::compute::partial_derivatives &partial_derivatives, + const specfem::compute::properties &properties, + const specfem::compute::receivers &receivers, + specfem::kokkos::DeviceView2d field, + specfem::kokkos::DeviceView2d field_dot, + specfem::kokkos::DeviceView2d field_dot_dot, + specfem::quadrature::quadrature *quadx, + specfem::quadrature::quadrature *quadz, qp_type quadrature_points, + specfem::domain::impl::kernels::receiver_kernel< + medium, qp_type, specfem::enums::element::property::isotropic> + &isotropic_receivers) { + + const auto value = medium::value; + + // Create isotropic receivers + + const auto ispec_array = receivers.h_ispec_array; + int nreceivers = 0; + for (int ireceiver = 0; ireceiver < ispec_array.extent(0); ireceiver++) { + if (properties.h_ispec_type(ispec_array(ireceiver)) == value) { + nreceivers++; + } + } + + specfem::kokkos::DeviceView1d ispec_receivers( + "specfem::domain::domain::ispec_receivers", nreceivers); + + specfem::kokkos::HostMirror1d h_ispec_receivers = + Kokkos::create_mirror_view(ispec_receivers); + + specfem::kokkos::DeviceView1d ireceiver_array( + "specfem::domain::domain::ireceiver_array", nreceivers); + + specfem::kokkos::HostMirror1d h_ireceiver_array = + Kokkos::create_mirror_view(ireceiver_array); + + int index = 0; + for (int ireceiver = 0; ireceiver < ispec_array.extent(0); ireceiver++) { + if (properties.h_ispec_type(ispec_array(ireceiver)) == value) { + h_ispec_receivers(index) = ispec_array(ireceiver); + h_ireceiver_array(index) = ireceiver; + index++; + } + } + + Kokkos::deep_copy(ispec_receivers, h_ispec_receivers); + Kokkos::deep_copy(ireceiver_array, h_ireceiver_array); + + isotropic_receivers = specfem::domain::impl::kernels::receiver_kernel< + medium, qp_type, specfem::enums::element::property::isotropic>( + ibool, ispec_receivers, ireceiver_array, partial_derivatives, properties, + receivers, field, field_dot, field_dot_dot, quadx, quadz, + quadrature_points); + + return; +} +} // namespace + +template +specfem::domain::impl::kernels::kernels::kernels( + const specfem::kokkos::DeviceView3d ibool, + const specfem::compute::partial_derivatives &partial_derivatives, + const specfem::compute::properties &properties, + const specfem::compute::boundaries &boundary_conditions, + const specfem::compute::sources &sources, + const specfem::compute::receivers &receivers, + specfem::quadrature::quadrature *quadx, + specfem::quadrature::quadrature *quadz, qp_type quadrature_points, + specfem::kokkos::DeviceView2d field, + specfem::kokkos::DeviceView2d field_dot, + specfem::kokkos::DeviceView2d field_dot_dot, + specfem::kokkos::DeviceView2d mass_matrix) { + + const int nspec = ibool.extent(0); + specfem::kokkos::HostView1d element_tags( + "specfem::domain::domain::element_tag", nspec); + // ----------------------------------------------------------- + // Start by tagging different elements + // ----------------------------------------------------------- + // creating a context here for memory management + { + // find medium type for every element + specfem::kokkos::HostView1d ielement_type( + "specfem::domain::impl::kernels::kernels::ielement_type", nspec); + + for (int ispec = 0; ispec < nspec; ispec++) { + ielement_type(ispec) = properties.h_ispec_type(ispec); + } + + // at start we consider every element is isotropic + specfem::kokkos::HostView1d + ielement_property( + "specfem::domain::impl::kernels::kernels::ielement_property", + nspec); + + for (int ispec = 0; ispec < nspec; ispec++) { + ielement_property(ispec) = + specfem::enums::element::property_tag::isotropic; + } + + // at start we consider every element is not on the boundary + specfem::kokkos::HostView1d + ielement_boundary( + "specfem::domain::impl::kernels::kernels::ielement_boundary", + nspec); + + const auto &stacey = boundary_conditions.stacey; + // mark stacey elements + if (stacey.nelements > 0) { + if (stacey.acoustic.nelements > 0) { + for (int i = 0; i < stacey.acoustic.nelements; i++) { + const int ispec = stacey.acoustic.h_ispec(i); + ielement_boundary(ispec) += + specfem::enums::element::boundary_tag::stacey; + } + } + + if (stacey.elastic.nelements > 0) { + for (int i = 0; i < stacey.elastic.nelements; i++) { + const int ispec = stacey.elastic.h_ispec(i); + ielement_boundary(ispec) += + specfem::enums::element::boundary_tag::stacey; + } + } + } + + const auto &acoustic_free_surface = + boundary_conditions.acoustic_free_surface; + + // mark acoustic free surface elements + if (acoustic_free_surface.nelements > 0) { + for (int i = 0; i < acoustic_free_surface.nelements; i++) { + const int ispec = acoustic_free_surface.h_ispec(i); + ielement_boundary(ispec) += + specfem::enums::element::boundary_tag::acoustic_free_surface; + } + } + + const auto &composite_stacey_dirichlet = + boundary_conditions.composite_stacey_dirichlet; + + // mark composite stacey dirichlet elements + if (composite_stacey_dirichlet.nelements > 0) { + for (int i = 0; i < composite_stacey_dirichlet.nelements; i++) { + const int ispec = composite_stacey_dirichlet.h_ispec(i); + ielement_boundary(ispec) += + specfem::enums::element::boundary_tag::composite_stacey_dirichlet; + } + } + + // mark every element type + for (int ispec = 0; ispec < nspec; ispec++) { + element_tags(ispec) = + element_tag(ielement_type(ispec), ielement_property(ispec), + ielement_boundary(ispec)); + } + } + + std::cout << " Element Statistics \n" + << "------------------------------\n" + << "- Types of elements in " << medium::to_string() + << " medium :\n\n"; + + // ----------------------------------------------------------- + + // Allocate isotropic elements with dirichlet boundary conditions + allocate_elements(ibool, element_tags, partial_derivatives, properties, + boundary_conditions, quadx, quadz, quadrature_points, field, + field_dot, field_dot_dot, mass_matrix, + isotropic_elements_dirichlet); + + // Allocate isotropic elements with stacey boundary conditions + allocate_elements(ibool, element_tags, partial_derivatives, properties, + boundary_conditions, quadx, quadz, quadrature_points, field, + field_dot, field_dot_dot, mass_matrix, + isotropic_elements_stacey); + + // Allocate isotropic elements with stacey dirichlet boundary conditions + allocate_elements(ibool, element_tags, partial_derivatives, properties, + boundary_conditions, quadx, quadz, quadrature_points, field, + field_dot, field_dot_dot, mass_matrix, + isotropic_elements_stacey_dirichlet); + + // Allocate isotropic elements + + allocate_elements(ibool, element_tags, partial_derivatives, properties, + boundary_conditions, quadx, quadz, quadrature_points, field, + field_dot, field_dot_dot, mass_matrix, isotropic_elements); + + // Allocate isotropic sources + + allocate_isotropic_sources(ibool, properties, sources, quadrature_points, + field_dot_dot, isotropic_sources); + + // Allocate isotropic receivers + + allocate_isotropic_receivers( + ibool, partial_derivatives, properties, receivers, field, field_dot, + field_dot_dot, quadx, quadz, quadrature_points, isotropic_receivers); + + return; +} + +#endif // _DOMAIN_KERNELS_TPP diff --git a/include/domain/impl/receivers/acoustic/acoustic2d.hpp b/include/domain/impl/receivers/acoustic/acoustic2d.hpp new file mode 100644 index 00000000..25101b00 --- /dev/null +++ b/include/domain/impl/receivers/acoustic/acoustic2d.hpp @@ -0,0 +1,50 @@ +#ifndef _DOMIAN_IMPL_RECEIVERS_ACOUSTIC2D_HPP_ +#define _DOMIAN_IMPL_RECEIVERS_ACOUSTIC2D_HPP_ + +#include "constants.hpp" +#include "domain/impl/receivers/receiver.hpp" +#include "enumerations/interface.hpp" +#include + +namespace specfem { +namespace domain { +namespace impl { +namespace receivers { + +template +class receiver { +public: + using dimension = specfem::enums::element::dimension::dim2; + using medium_type = specfem::enums::element::medium::acoustic; + using quadrature_points_type = qp_type; + + template + using ScratchViewType = + typename quadrature_points_type::template ScratchViewType; + + KOKKOS_INLINE_FUNCTION virtual void get_field( + const int xz, const int isig_step, + const ScratchViewType field, + const ScratchViewType field_dot, + const ScratchViewType field_dot_dot, + const ScratchViewType hprime_xx, + const ScratchViewType hprime_zz) const {}; + KOKKOS_INLINE_FUNCTION virtual void + compute_seismogram_components(const int xz, const int isig_step, + specfem::kokkos::array_type + &l_seismogram_components) const {}; + KOKKOS_INLINE_FUNCTION virtual void compute_seismogram( + const int isig_step, + const specfem::kokkos::array_type &seismogram_components){}; + KOKKOS_INLINE_FUNCTION virtual specfem::enums::seismogram::type + get_seismogram_type() const = 0; + KOKKOS_INLINE_FUNCTION virtual int get_ispec() const = 0; +}; + +} // namespace receivers +} // namespace impl +} // namespace domain +} // namespace specfem + +#endif /* _DOMIAN_IMPL_RECEIVERS_ACOUSTIC2D_HPP_ */ diff --git a/include/domain/impl/receivers/acoustic/acoustic2d_isotropic.hpp b/include/domain/impl/receivers/acoustic/acoustic2d_isotropic.hpp new file mode 100644 index 00000000..8587c7d0 --- /dev/null +++ b/include/domain/impl/receivers/acoustic/acoustic2d_isotropic.hpp @@ -0,0 +1,170 @@ +#ifndef DOMAIN_IMPL_RECEIVERS_ACOUSTIC2D_ISOTRPOIC_HPP_ +#define DOMAIN_IMPL_RECEIVERS_ACOUSTIC2D_ISOTRPOIC_HPP_ + +#include "constants.hpp" +#include "domain/impl/receivers/acoustic/acoustic2d.hpp" +#include "domain/impl/receivers/receiver.hpp" +#include "enumerations/interface.hpp" +#include + +namespace specfem { +namespace domain { +namespace impl { +namespace receivers { +/** + * @brief Template specialization for receiver located inside 2D isotropic + * acoustic element with static quadrature points + * + * @tparam NGLL Number of Gauss-Lobatto-Legendre quadrature points defined at + * compile time + */ +template +class receiver< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::acoustic, + specfem::enums::element::quadrature::static_quadrature_points, + specfem::enums::element::property::isotropic> { + +public: + /** + * @name Typedefs + */ + ///@{ + /** + * @brief Dimension of the element + * + */ + using dimension = specfem::enums::element::dimension::dim2; + /** + * @brief Medium of the element + * + */ + using medium_type = specfem::enums::element::medium::acoustic; + /** + * @brief Number of Gauss-Lobatto-Legendre quadrature points + */ + using quadrature_points_type = + specfem::enums::element::quadrature::static_quadrature_points; + /** + * @brief Use the scratch view type from the quadrature points + * + * @tparam T Type of the scratch view + * @tparam N Number of components + */ + template + using ScratchViewType = + typename quadrature_points_type::template ScratchViewType; + ///@} + + KOKKOS_FUNCTION + receiver() = default; + + /** + * @brief Construct a new elemental receiver object + * + * @param sin_rec sin of the receiver angle + * @param cos_rec cosine of the receiver angle + * @param receiver_array receiver array containing pre-computed lagrange + * interpolants + * @param partial_derivatives struct used to store partial derivatives at + * quadrature points + * @param properties struct used to store material properties at quadrature + * points + * @param receiver_field view to store compute receiver field at all GLL + * points where the receiver is located + */ + KOKKOS_FUNCTION + receiver(const specfem::kokkos::DeviceView1d sin_rec, + const specfem::kokkos::DeviceView1d cos_rec, + const specfem::kokkos::DeviceView4d receiver_array, + const specfem::compute::partial_derivatives &partial_derivatives, + const specfem::compute::properties &properties, + specfem::kokkos::DeviceView6d receiver_field); + + /** + * @brief Compute and populate the receiver field at all GLL points where the + * receiver is located for a given time step + * + * @param ireceiver Index of the receiver + * @param iseis Index of the seismogram + * @param ispec Index of the element + * @param siesmogram_type Type of the seismogram + * @param xz Index of the quadrature point + * @param isig_step Seismogram step. Seismograms step = current time step / + * seismogram sampling rate + * @param field Global wavefield + * @param field_dot Global wavefield time derivative + * @param field_dot_dot Global wavefield second time derivative + * @param hprime_xx Derivates of Lagrange interpolants in the x direction + * @param hprime_zz Derivates of Lagrange interpolants in the z direction + */ + KOKKOS_FUNCTION + void get_field( + const int &ireceiver, const int &iseis, const int &ispec, + const specfem::enums::seismogram::type &siesmogram_type, const int &xz, + const int &isig_step, + const ScratchViewType field, + const ScratchViewType field_dot, + const ScratchViewType field_dot_dot, + const ScratchViewType hprime_xx, + const ScratchViewType hprime_zz) const; + + /** + * @brief Compute the seismogram components for a given receiver and + * seismogram + * + * @param ireceiver Index of the receiver + * @param iseis Index of the seismogram + * @param seismogram_type Type of the seismogram + * @param xz Index of the quadrature point + * @param isig_step Seismogram step. Seismograms step = current time step / + * seismogram sampling rate + * @param l_seismogram_components Local seismogram components + */ + KOKKOS_FUNCTION + void compute_seismogram_components( + const int &ireceiver, const int &iseis, + const specfem::enums::seismogram::type &seismogram_type, const int &xz, + const int &isig_step, + specfem::kokkos::array_type &l_seismogram_components) const; + + /** + * @brief Store the computed seismogram components in the global seismogram + * view + * + * @param ireceiver Index of the receiver + * @param seismogram_components Local seismogram components + * @param receiver_seismogram Gloabl seismogram view + */ + KOKKOS_FUNCTION + void compute_seismogram( + const int &ireceiver, + const specfem::kokkos::array_type &seismogram_components, + specfem::kokkos::DeviceView1d receiver_seismogram) const; + +private: + specfem::kokkos::DeviceView1d sin_rec; ///< sin of the receiver + ///< angle + specfem::kokkos::DeviceView1d cos_rec; ///< cosine of the receiver + ///< angle + specfem::kokkos::DeviceView4d receiver_array; ///< receiver array + ///< containing + ///< pre-computed + ///< lagrange + ///< interpolants + specfem::kokkos::DeviceView3d xix; ///< xix + specfem::kokkos::DeviceView3d gammax; ///< gammax + specfem::kokkos::DeviceView3d xiz; ///< xiz + specfem::kokkos::DeviceView3d gammaz; ///< gammaz + specfem::kokkos::DeviceView3d rho_inverse; ///< rho inverse + specfem::kokkos::DeviceView6d + receiver_field; ///< view to store compute receiver field at all GLL + ///< points where the receiver is located +}; + +} // namespace receivers +} // namespace impl +} // namespace domain +} // namespace specfem + +#endif /* DOMAIN_IMPL_RECEIVERS_ACOUSTIC2D_ISOTRPOIC_HPP_ */ diff --git a/include/domain/impl/receivers/acoustic/acoustic2d_isotropic.tpp b/include/domain/impl/receivers/acoustic/acoustic2d_isotropic.tpp new file mode 100644 index 00000000..c30a8bef --- /dev/null +++ b/include/domain/impl/receivers/acoustic/acoustic2d_isotropic.tpp @@ -0,0 +1,204 @@ +#ifndef DOMAIN_IMPL_RECEIVERS_ACOUSTIC2D_ISOTROPIC_TPP_ +#define DOMAIN_IMPL_RECEIVERS_ACOUSTIC2D_ISOTROPIC_TPP_ + +#include "constants.hpp" +#include "domain/impl/receivers/acoustic/acoustic2d.hpp" +#include "domain/impl/receivers/receiver.hpp" +#include "globals.h" +#include "kokkos_abstractions.h" +#include "enumerations/interface.hpp" +#include + +template +KOKKOS_FUNCTION specfem::domain::impl::receivers::receiver< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::acoustic, + specfem::enums::element::quadrature::static_quadrature_points, + specfem::enums::element::property::isotropic>:: + receiver(const specfem::kokkos::DeviceView1d sin_rec, + const specfem::kokkos::DeviceView1d cos_rec, + const specfem::kokkos::DeviceView4d receiver_array, + const specfem::compute::partial_derivatives &partial_derivatives, + const specfem::compute::properties &properties, + specfem::kokkos::DeviceView6d receiver_field) + : sin_rec(sin_rec), cos_rec(cos_rec), receiver_array(receiver_array), + receiver_field(receiver_field) { + +#ifndef NDEBUG + assert(partial_derivatives.xix.extent(1) == NGLL); + assert(partial_derivatives.xix.extent(2) == NGLL); + assert(partial_derivatives.gammax.extent(1) == NGLL); + assert(partial_derivatives.gammax.extent(2) == NGLL); + assert(partial_derivatives.xiz.extent(1) == NGLL); + assert(partial_derivatives.xiz.extent(2) == NGLL); + assert(partial_derivatives.gammaz.extent(1) == NGLL); + assert(partial_derivatives.gammaz.extent(2) == NGLL); + + // Properties + assert(properties.rho_inverse.extent(1) == NGLL); + assert(properties.rho_inverse.extent(2) == NGLL); +#endif + + this->xix = partial_derivatives.xix; + this->gammax = partial_derivatives.gammax; + this->xiz = partial_derivatives.xiz; + this->gammaz = partial_derivatives.gammaz; + this->rho_inverse = properties.rho_inverse; + return; +} + +template +KOKKOS_INLINE_FUNCTION void specfem::domain::impl::receivers::receiver< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::acoustic, + specfem::enums::element::quadrature::static_quadrature_points, + specfem::enums::element::property::isotropic>:: + get_field( + const int &ireceiver, const int &iseis, const int &ispec, + const specfem::enums::seismogram::type &seismogram_type, const int &xz, + const int &isig_step, + const ScratchViewType field, + const ScratchViewType field_dot, + const ScratchViewType field_dot_dot, + const ScratchViewType hprime_xx, + const ScratchViewType hprime_zz) const { + +#ifndef NDEBUG + assert(field.extent(0) == NGLL); + assert(field.extent(1) == NGLL); + assert(field_dot.extent(0) == NGLL); + assert(field_dot.extent(1) == NGLL); + assert(field_dot_dot.extent(0) == NGLL); + assert(field_dot_dot.extent(1) == NGLL); + assert(hprime_xx.extent(0) == NGLL); + assert(hprime_xx.extent(1) == NGLL); + assert(hprime_zz.extent(0) == NGLL); + assert(hprime_zz.extent(1) == NGLL); +#endif + + int ix, iz; + sub2ind(xz, NGLL, iz, ix); + + const type_real xixl = this->xix(ispec, iz, ix); + const type_real gammaxl = this->gammax(ispec, iz, ix); + const type_real xizl = this->xiz(ispec, iz, ix); + const type_real gammazl = this->gammaz(ispec, iz, ix); + const type_real rho_inversel = this->rho_inverse(ispec, iz, ix); + + using sv_ScratchViewType = + Kokkos::Subview, + std::remove_const_t, + std::remove_const_t, int>; + + sv_ScratchViewType active_field; + + switch (seismogram_type) { + case specfem::enums::seismogram::type::displacement: + active_field = Kokkos::subview(field, Kokkos::ALL, Kokkos::ALL, 0); + break; + case specfem::enums::seismogram::type::velocity: + active_field = Kokkos::subview(field_dot, Kokkos::ALL, Kokkos::ALL, 0); + break; + case specfem::enums::seismogram::type::acceleration: + active_field = Kokkos::subview(field_dot_dot, Kokkos::ALL, Kokkos::ALL, 0); + break; + } + + type_real dchi_dxi = 0.0; + type_real dchi_dgamma = 0.0; + +#ifndef KOKKOS_ENABLE_CUDA +#pragma unroll +#endif + for (int l = 0; l < NGLL; l++) { + dchi_dxi += hprime_xx(ix, l, 0) * active_field(iz, l); + dchi_dgamma += hprime_zz(iz, l, 0) * active_field(l, ix); + } + + // dchidx + type_real fieldx = (dchi_dxi * xixl + dchi_dgamma * gammaxl) * rho_inversel; + + // dchidz + type_real fieldz = (dchi_dxi * xizl + dchi_dgamma * gammazl) * rho_inversel; + + // Receiver field is probably not the best way of storing this, since this + // would require global memory accesses. A better way for doing this would be + // create register array and the store the values there. However, post + // simulation people might require the field stored inside an element where a + // receiver is located. If the number of receivers << nspec - hopefully this + // shouldn't be a bottleneck. + this->receiver_field(isig_step, ireceiver, iseis, 0, iz, ix) = fieldx; + this->receiver_field(isig_step, ireceiver, iseis, 1, iz, ix) = fieldz; + + return; +} + +template +KOKKOS_INLINE_FUNCTION void specfem::domain::impl::receivers::receiver< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::acoustic, + specfem::enums::element::quadrature::static_quadrature_points, + specfem::enums::element::property::isotropic>:: + compute_seismogram_components( + const int &ireceiver, const int &iseis, + const specfem::enums::seismogram::type &seismogram_type, const int &xz, + const int &isig_step, + specfem::kokkos::array_type &l_seismogram_components) const { + int ix, iz; + sub2ind(xz, NGLL, iz, ix); + + switch (seismogram_type) { + case specfem::enums::seismogram::type::displacement: + case specfem::enums::seismogram::type::velocity: + case specfem::enums::seismogram::type::acceleration: + if (specfem::globals::simulation_wave == specfem::wave::p_sv) { + l_seismogram_components[0] += + this->receiver_array(ireceiver, iz, ix, 0) * + this->receiver_field(isig_step, ireceiver, iseis, 0, iz, ix); + l_seismogram_components[1] += + this->receiver_array(ireceiver, iz, ix, 1) * + this->receiver_field(isig_step, ireceiver, iseis, 1, iz, ix); + } else if (specfem::globals::simulation_wave == specfem::wave::sh) { + l_seismogram_components[0] += + this->receiver_array(ireceiver, iz, ix, 0) * + this->receiver_field(isig_step, ireceiver, iseis, 0, iz, ix); + l_seismogram_components[1] += 0; + } + break; + + default: + // seismogram not supported + assert(false); + break; + } +} + +template +KOKKOS_INLINE_FUNCTION void specfem::domain::impl::receivers::receiver< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::acoustic, + specfem::enums::element::quadrature::static_quadrature_points, + specfem::enums::element::property::isotropic>:: + compute_seismogram( + const int &ireceiver, + const specfem::kokkos::array_type &seismogram_components, + specfem::kokkos::DeviceView1d receiver_seismogram) const { + + if (specfem::globals::simulation_wave == specfem::wave::p_sv) { + receiver_seismogram(0) = + this->cos_rec(ireceiver) * seismogram_components[0] + + this->sin_rec(ireceiver) * seismogram_components[1]; + receiver_seismogram(1) = + this->sin_rec(ireceiver) * seismogram_components[0] + + this->cos_rec(ireceiver) * seismogram_components[1]; + } else if (specfem::globals::simulation_wave == specfem::wave::sh) { + receiver_seismogram(0) = + this->cos_rec(ireceiver) * seismogram_components[0] + + this->sin_rec(ireceiver) * seismogram_components[1]; + receiver_seismogram(1) = 0; + } + + return; +} + +#endif /* DOMAIN_IMPL_RECEIVERS_ACOUSTIC2D_ISOTROPIC_TPP_ */ diff --git a/include/domain/impl/receivers/acoustic/interface.hpp b/include/domain/impl/receivers/acoustic/interface.hpp new file mode 100644 index 00000000..dcb0e966 --- /dev/null +++ b/include/domain/impl/receivers/acoustic/interface.hpp @@ -0,0 +1,8 @@ +#ifndef _DOMAIN_RECEIVERS_ACOUSTIC_INTERFACE_HPP_ +#define _DOMAIN_RECEIVERS_ACOUSTIC_INTERFACE_HPP_ + +#include "acoustic2d.hpp" +#include "acoustic2d_isotropic.hpp" +#include "acoustic2d_isotropic.tpp" + +#endif /* _DOMAIN_RECEIVERS_ACOUSTIC_INTERFACE_HPP_ */ diff --git a/include/domain/impl/receivers/container.hpp b/include/domain/impl/receivers/container.hpp new file mode 100644 index 00000000..0a34b068 --- /dev/null +++ b/include/domain/impl/receivers/container.hpp @@ -0,0 +1,62 @@ +#ifndef _RECEIVER_CONTAINER_HPP +#define _RECEIVER_CONTAINER_HPP + +#include "enumerations/interface.hpp" + +namespace specfem { +namespace domain { +namespace impl { +namespace receivers { + +template struct container { +public: + base_elemental_receiver *receiver; + + KOKKOS_FUNCTION + container() = default; + + KOKKOS_FUNCTION + container(base_elemental_receiver *receiver) { + this->receiver = receiver; + return; + } + + template + KOKKOS_INLINE_FUNCTION void get_field(Args... values) const { + this->receiver->get_field(values...); + return; + } + + KOKKOS_INLINE_FUNCTION specfem::enums::seismogram::type + get_seismogram_type() const { + return this->receiver->get_seismogram_type(); + } + + template + KOKKOS_INLINE_FUNCTION void compute_seismogram(Args... values) const { + this->receiver->compute_seismogram(values...); + return; + } + + template + KOKKOS_INLINE_FUNCTION void + compute_seismogram_components(Args &&...values) const { + this->receiver->compute_seismogram_components( + std::forward(values)...); + return; + } + + KOKKOS_INLINE_FUNCTION int get_ispec() const { + return this->receiver->get_ispec(); + } + + KOKKOS_FUNCTION + ~container() = default; +}; + +} // namespace receivers +} // namespace impl +} // namespace domain +} // namespace specfem + +#endif diff --git a/include/domain/impl/receivers/elastic/elastic2d.hpp b/include/domain/impl/receivers/elastic/elastic2d.hpp new file mode 100644 index 00000000..c637c51e --- /dev/null +++ b/include/domain/impl/receivers/elastic/elastic2d.hpp @@ -0,0 +1,49 @@ +#ifndef _DOMAIN_IMPL_RECEIVERS_ELASTIC2D_HPP_ +#define _DOMAIN_IMPL_RECEIVERS_ELASTIC2D_HPP_ + +#include "domain/impl/receivers/receiver.hpp" +#include "enumerations/interface.hpp" +#include + +namespace specfem { +namespace domain { +namespace impl { +namespace receivers { + +template +class receiver { +public: + using dimension = specfem::enums::element::dimension::dim2; + using medium_type = specfem::enums::element::medium::elastic; + using quadrature_points_type = qp_type; + + template + using ScratchViewType = + typename quadrature_points_type::template ScratchViewType; + + KOKKOS_INLINE_FUNCTION virtual void get_field( + const int xz, const int isig_step, + const ScratchViewType fieldx, + const ScratchViewType field_dot, + const ScratchViewType fieldx_dot_dot, + const ScratchViewType s_hprime_xx, + const ScratchViewType s_hprime_zz) const {}; + KOKKOS_INLINE_FUNCTION virtual void + compute_seismogram_components(const int xz, const int isig_step, + specfem::kokkos::array_type + &l_seismogram_components) const {}; + KOKKOS_INLINE_FUNCTION virtual void compute_seismogram( + const int isig_step, + const specfem::kokkos::array_type &seismogram_components){}; + KOKKOS_INLINE_FUNCTION virtual specfem::enums::seismogram::type + get_seismogram_type() const = 0; + KOKKOS_INLINE_FUNCTION virtual int get_ispec() const = 0; +}; + +} // namespace receivers +} // namespace impl +} // namespace domain +} // namespace specfem + +#endif /* _DOMAIN_IMPL_RECEIVERS_ELASTIC2D_HPP_ */ diff --git a/include/domain/impl/receivers/elastic/elastic2d_isotropic.hpp b/include/domain/impl/receivers/elastic/elastic2d_isotropic.hpp new file mode 100644 index 00000000..41e75551 --- /dev/null +++ b/include/domain/impl/receivers/elastic/elastic2d_isotropic.hpp @@ -0,0 +1,162 @@ +#ifndef _DOMAIN_IMPL_RECEIVERS_ELASTIC2D_ISOTROPIC_HPP_ +#define _DOMAIN_IMPL_RECEIVERS_ELASTIC2D_ISOTROPIC_HPP_ + +#include "constants.hpp" +#include "domain/impl/receivers/elastic/elastic2d.hpp" +#include "domain/impl/receivers/receiver.hpp" +#include "enumerations/interface.hpp" +#include "kokkos_abstractions.h" +#include "quadrature/interface.hpp" +#include + +namespace specfem { +namespace domain { +namespace impl { +namespace receivers { +/** + * @brief Elemental receiver specialization for 2D elastic isotropic spectral + * elements with static quadrature points + * + * @tparam NGLL Number of Gauss-Lobatto-Legendre quadrature points defined at + * compile time + */ +template +class receiver< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::elastic, + specfem::enums::element::quadrature::static_quadrature_points, + specfem::enums::element::property::isotropic> { +public: + /** + * @name Typedefs + */ + ///@{ + /** + * @brief Dimension of the element + * + */ + using dimension = specfem::enums::element::dimension::dim2; + /** + * @brief Medium of the element + * + */ + using medium_type = specfem::enums::element::medium::elastic; + /** + * @brief Number of Gauss-Lobatto-Legendre quadrature points + */ + using quadrature_points_type = + specfem::enums::element::quadrature::static_quadrature_points; + + /** + * @brief Use the scratch view type from the quadrature points + * + * @tparam T Type of the scratch view + * @tparam N Number of components + */ + template + using ScratchViewType = + typename quadrature_points_type::template ScratchViewType; + + KOKKOS_FUNCTION receiver() = default; + + /** + * @brief Construct a new elemental receiver object + * + * @param sin_rec sin of the receiver angle + * @param cos_rec cosine of the receiver angle + * @param receiver_array receiver array containing pre-computed lagrange + * interpolants + * @param partial_derivatives struct used to store partial derivatives at + * quadrature points + * @param properties struct used to store material properties at quadrature + * points + * @param receiver_field view to store compute receiver field at all GLL + * points where the receiver is located + */ + KOKKOS_FUNCTION + receiver(const specfem::kokkos::DeviceView1d sin_rec, + const specfem::kokkos::DeviceView1d cos_rec, + const specfem::kokkos::DeviceView4d receiver_array, + const specfem::compute::partial_derivatives &partial_derivatives, + const specfem::compute::properties &properties, + specfem::kokkos::DeviceView6d receiver_field); + + /** + * @brief Compute and populate the receiver field at all GLL points where the + * receiver is located for a given time step + * + * @param ireceiver Index of the receiver + * @param iseis Index of the seismogram + * @param ispec Index of the element + * @param siesmogram_type Type of the seismogram + * @param xz Index of the quadrature point + * @param isig_step Seismogram step. Seismograms step = current time step / + * seismogram sampling rate + * @param field Global wavefield + * @param field_dot Global wavefield time derivative + * @param field_dot_dot Global wavefield second time derivative + * @param hprime_xx Derivates of Lagrange interpolants in the x direction + * @param hprime_zz Derivates of Lagrange interpolants in the z direction + */ + KOKKOS_FUNCTION void get_field( + const int &ireceiver, const int &iseis, const int &ispec, + const specfem::enums::seismogram::type &seismogram_type, const int &xz, + const int &isig_step, + const ScratchViewType field, + const ScratchViewType field_dot, + const ScratchViewType field_dot_dot, + const ScratchViewType s_hprime_xx, + const ScratchViewType s_hprime_zz) const; + + /** + * @brief Compute the seismogram components for a given receiver and + * seismogram + * + * @param ireceiver Index of the receiver + * @param iseis Index of the seismogram + * @param seismogram_type Type of the seismogram + * @param xz Index of the quadrature point + * @param isig_step Seismogram step. Seismograms step = current time step / + * seismogram sampling rate + * @param l_seismogram_components Local seismogram components + */ + KOKKOS_FUNCTION void compute_seismogram_components( + const int &ireceiver, const int &iseis, + const specfem::enums::seismogram::type &seismogram_type, const int &xz, + const int &isig_step, + specfem::kokkos::array_type &l_seismogram_components) const; + + /** + * @brief Store the computed seismogram components in the global seismogram + * view + * + * @param ireceiver Index of the receiver + * @param seismogram_components Local seismogram components + * @param receiver_seismogram Gloabl seismogram view + */ + KOKKOS_FUNCTION void compute_seismogram( + const int &ireceiver, + const specfem::kokkos::array_type &seismogram_components, + specfem::kokkos::DeviceView1d receiver_seismogram) const; + +private: + specfem::kokkos::DeviceView1d sin_rec; ///< sin of the receiver + ///< angle + specfem::kokkos::DeviceView1d cos_rec; ///< cosine of the receiver + ///< angle + specfem::kokkos::DeviceView4d receiver_array; ///< receiver array + ///< containing + ///< pre-computed + ///< lagrange + ///< interpolants + specfem::kokkos::DeviceView6d + receiver_field; ///< view to store compute receiver field at all GLL + ///< points where the receiver is located +}; + +} // namespace receivers +} // namespace impl +} // namespace domain +} // namespace specfem + +#endif /* _DOMAIN_IMPL_RECEIVERS_ELASTIC2D_ISOTROPIC_HPP_ */ diff --git a/include/domain/impl/receivers/elastic/elastic2d_isotropic.tpp b/include/domain/impl/receivers/elastic/elastic2d_isotropic.tpp new file mode 100644 index 00000000..8341f48f --- /dev/null +++ b/include/domain/impl/receivers/elastic/elastic2d_isotropic.tpp @@ -0,0 +1,178 @@ +#ifndef _DOMAIN_IMPL_RECEIVERS_ELASTIC2D_ISOTROPIC_TPP_ +#define _DOMAIN_IMPL_RECEIVERS_ELASTIC2D_ISOTROPIC_TPP_ + +#include "compute/interface.hpp" +#include "domain/impl/receivers/elastic/elastic2d.hpp" +#include "domain/impl/receivers/elastic/elastic2d_isotropic.hpp" +#include "domain/impl/receivers/receiver.hpp" +#include "enumerations/interface.hpp" +#include "globals.h" +#include "kokkos_abstractions.h" +#include "quadrature/interface.hpp" +#include "specfem_setup.hpp" +#include + +template +KOKKOS_FUNCTION specfem::domain::impl::receivers::receiver< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::elastic, + specfem::enums::element::quadrature::static_quadrature_points, + specfem::enums::element::property::isotropic>:: + receiver(const specfem::kokkos::DeviceView1d sin_rec, + const specfem::kokkos::DeviceView1d cos_rec, + const specfem::kokkos::DeviceView4d receiver_array, + const specfem::compute::partial_derivatives &partial_derivatives, + const specfem::compute::properties &properties, + specfem::kokkos::DeviceView6d receiver_field) + : sin_rec(sin_rec), cos_rec(cos_rec), receiver_array(receiver_array), + receiver_field(receiver_field) {} + +template +KOKKOS_FUNCTION void specfem::domain::impl::receivers::receiver< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::elastic, + specfem::enums::element::quadrature::static_quadrature_points, + specfem::enums::element::property::isotropic>:: + get_field( + const int &ireceiver, const int &iseis, const int &ispec, + const specfem::enums::seismogram::type &seismogram_type, const int &xz, + const int &isig_step, + const ScratchViewType field, + const ScratchViewType field_dot, + const ScratchViewType field_dot_dot, + const ScratchViewType s_hprime_xx, + const ScratchViewType s_hprime_zz) const { + +#ifndef NDEBUG + // check that the dimensions of the fields are correct + assert(field.extent(0) == NGLL); + assert(field.extent(1) == NGLL); + assert(field_dot.extent(0) == NGLL); + assert(field_dot.extent(1) == NGLL); + assert(field_dot_dot.extent(0) == NGLL); + assert(field_dot_dot.extent(1) == NGLL); + assert(s_hprime_xx.extent(0) == NGLL); + assert(s_hprime_xx.extent(1) == NGLL); + assert(s_hprime_zz.extent(0) == NGLL); + assert(s_hprime_zz.extent(1) == NGLL); +#endif /* NDEBUG */ + + int ix, iz; + sub2ind(xz, NGLL, iz, ix); + + using sv_ScratchViewType = + Kokkos::Subview, + std::remove_const_t, + std::remove_const_t, int>; + + sv_ScratchViewType active_fieldx; + sv_ScratchViewType active_fieldz; + + switch (seismogram_type) { + case specfem::enums::seismogram::type::displacement: + active_fieldx = Kokkos::subview(field, Kokkos::ALL, Kokkos::ALL, 0); + active_fieldz = Kokkos::subview(field, Kokkos::ALL, Kokkos::ALL, 1); + break; + case specfem::enums::seismogram::type::velocity: + active_fieldx = Kokkos::subview(field_dot, Kokkos::ALL, Kokkos::ALL, 0); + active_fieldz = Kokkos::subview(field_dot, Kokkos::ALL, Kokkos::ALL, 1); + break; + case specfem::enums::seismogram::type::acceleration: + active_fieldx = Kokkos::subview(field_dot_dot, Kokkos::ALL, Kokkos::ALL, 0); + active_fieldz = Kokkos::subview(field_dot_dot, Kokkos::ALL, Kokkos::ALL, 1); + break; + default: + // seismogram not supported + assert(false && "seismogram not supported"); + break; + } + + // Receiver field is probably not the best way of storing this, since this + // would require global memory accesses. A better way for doing this would be + // create register array and the store the values there. However, post + // simulation people might require the field stored inside an element where a + // receiver is located. If the number of receivers << nspec - hopefully this + // shouldn't be a bottleneck. + if (specfem::globals::simulation_wave == specfem::wave::p_sv) { + this->receiver_field(isig_step, ireceiver, iseis, 0, iz, ix) = + active_fieldx(iz, ix); + this->receiver_field(isig_step, ireceiver, iseis, 1, iz, ix) = + active_fieldz(iz, ix); + } else if (specfem::globals::simulation_wave == specfem::wave::sh) { + this->receiver_field(isig_step, ireceiver, iseis, 0, iz, ix) = + active_fieldx(iz, ix); + } + + return; +} + +template +KOKKOS_FUNCTION void specfem::domain::impl::receivers::receiver< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::elastic, + specfem::enums::element::quadrature::static_quadrature_points, + specfem::enums::element::property::isotropic>:: + compute_seismogram_components( + const int &ireceiver, const int &iseis, + const specfem::enums::seismogram::type &seismogram_type, const int &xz, + const int &isig_step, + specfem::kokkos::array_type &l_seismogram_components) + const { + int ix, iz; + sub2ind(xz, NGLL, iz, ix); + + switch (seismogram_type) { + case specfem::enums::seismogram::type::displacement: + case specfem::enums::seismogram::type::velocity: + case specfem::enums::seismogram::type::acceleration: + if (specfem::globals::simulation_wave == specfem::wave::p_sv) { + l_seismogram_components[0] += + this->receiver_array(ireceiver, iz, ix, 0) * + this->receiver_field(isig_step, ireceiver, iseis, 0, iz, ix); + l_seismogram_components[1] += + this->receiver_array(ireceiver, iz, ix, 1) * + this->receiver_field(isig_step, ireceiver, iseis, 1, iz, ix); + } else if (specfem::globals::simulation_wave == specfem::wave::sh) { + l_seismogram_components[0] += + this->receiver_array(ireceiver, iz, ix, 0) * + this->receiver_field(isig_step, ireceiver, iseis, 0, iz, ix); + l_seismogram_components[1] += 0; + } + break; + + default: + // seismogram not supported + assert(false && "seismogram not supported"); + break; + } +} + +template +KOKKOS_FUNCTION void specfem::domain::impl::receivers::receiver< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::elastic, + specfem::enums::element::quadrature::static_quadrature_points, + specfem::enums::element::property::isotropic>:: + compute_seismogram( + const int &ireceiver, + const specfem::kokkos::array_type &seismogram_components, + specfem::kokkos::DeviceView1d receiver_seismogram) const { + + if (specfem::globals::simulation_wave == specfem::wave::p_sv) { + receiver_seismogram(0) = + this->cos_rec(ireceiver) * seismogram_components[0] + + this->sin_rec(ireceiver) * seismogram_components[1]; + receiver_seismogram(1) = + this->sin_rec(ireceiver) * seismogram_components[0] + + this->cos_rec(ireceiver) * seismogram_components[1]; + } else if (specfem::globals::simulation_wave == specfem::wave::sh) { + receiver_seismogram(0) = + this->cos_rec(ireceiver) * seismogram_components[0] + + this->sin_rec(ireceiver) * seismogram_components[1]; + receiver_seismogram(1) = 0; + } + + return; +} + +#endif /* _DOMAIN_IMPL_RECEIVERS_ELASTIC2D_ISOTROPIC_TPP_ */ diff --git a/include/domain/impl/receivers/elastic/interface.hpp b/include/domain/impl/receivers/elastic/interface.hpp new file mode 100644 index 00000000..5e90d198 --- /dev/null +++ b/include/domain/impl/receivers/elastic/interface.hpp @@ -0,0 +1,8 @@ +#ifndef _DOMAIN_RECEIVERS_ELASTIC_INTERFACE_HPP_ +#define _DOMAIN_RECEIVERS_ELASTIC_INTERFACE_HPP_ + +#include "elastic2d.hpp" +#include "elastic2d_isotropic.hpp" +#include "elastic2d_isotropic.tpp" + +#endif /* _DOMAIN_RECEIVERS_ELASTIC_INTERFACE_HPP_ */ diff --git a/include/domain/impl/receivers/interface.hpp b/include/domain/impl/receivers/interface.hpp new file mode 100644 index 00000000..3400f081 --- /dev/null +++ b/include/domain/impl/receivers/interface.hpp @@ -0,0 +1,15 @@ +#ifndef _DOMAIN_RECEIVERS_INTERFACE_HPP +#define _DOMAIN_RECEIVERS_INTERFACE_HPP + +#include "acoustic/acoustic2d.hpp" +#include "acoustic/acoustic2d_isotropic.hpp" +#include "acoustic/acoustic2d_isotropic.tpp" +#include "container.hpp" +#include "elastic/elastic2d.hpp" +#include "elastic/elastic2d_isotropic.hpp" +#include "elastic/elastic2d_isotropic.tpp" +#include "kernel.hpp" +#include "kernel.tpp" +#include "receiver.hpp" + +#endif /* _DOMAIN_RECEIVERS_INTERFACE_HPP */ diff --git a/include/domain/impl/receivers/kernel.hpp b/include/domain/impl/receivers/kernel.hpp new file mode 100644 index 00000000..9523bbf2 --- /dev/null +++ b/include/domain/impl/receivers/kernel.hpp @@ -0,0 +1,66 @@ +#ifndef _DOMAIN_IMPL_RECEIVERS_KERNEL_HPP +#define _DOMAIN_IMPL_RECEIVERS_KERNEL_HPP + +#include "domain/impl/receivers/acoustic/interface.hpp" +#include "domain/impl/receivers/elastic/interface.hpp" +#include "enumerations/interface.hpp" +#include "kokkos_abstractions.h" +#include "quadrature/interface.hpp" +#include "specfem_setup.hpp" + +namespace specfem { +namespace domain { +namespace impl { +namespace kernels { + +template +class receiver_kernel { +public: + using dimension = specfem::enums::element::dimension::dim2; + using medium_type = medium; + using quadrature_points_type = qp_type; + + receiver_kernel() = default; + + receiver_kernel( + const specfem::kokkos::DeviceView3d ibool, + const specfem::kokkos::DeviceView1d ispec, + const specfem::kokkos::DeviceView1d ireceiver, + const specfem::compute::partial_derivatives &partial_derivatives, + const specfem::compute::properties &properties, + const specfem::compute::receivers &receivers, + const specfem::kokkos::DeviceView2d field, + const specfem::kokkos::DeviceView2d + field_dot, + const specfem::kokkos::DeviceView2d + field_dot_dot, + specfem::quadrature::quadrature *quadx, + specfem::quadrature::quadrature *quadz, + quadrature_points_type quadrature_points); + + void compute_seismograms(const int &isig_step) const; + +private: + specfem::kokkos::DeviceView3d ibool; + specfem::kokkos::DeviceView1d ispec; + specfem::kokkos::DeviceView1d ireceiver; + specfem::kokkos::DeviceView1d iseis; + specfem::kokkos::DeviceView1d + seismogram_types; + specfem::kokkos::DeviceView4d receiver_seismogram; + quadrature_points_type quadrature_points; + specfem::quadrature::quadrature *quadx; + specfem::quadrature::quadrature *quadz; + specfem::kokkos::DeviceView2d field; + specfem::kokkos::DeviceView2d field_dot; + specfem::kokkos::DeviceView2d field_dot_dot; + specfem::domain::impl::receivers::receiver< + dimension, medium_type, quadrature_points_type, elemental_properties...> + receiver; +}; +} // namespace kernels +} // namespace impl +} // namespace domain +} // namespace specfem + +#endif // _DOMAIN_IMPL_RECEIVERS_KERNEL_HPP diff --git a/include/domain/impl/receivers/kernel.tpp b/include/domain/impl/receivers/kernel.tpp new file mode 100644 index 00000000..195a9189 --- /dev/null +++ b/include/domain/impl/receivers/kernel.tpp @@ -0,0 +1,222 @@ +#ifndef _DOMAIN_IMPL_RECEIVERS_KERNEL_TPP +#define _DOMAIN_IMPL_RECEIVERS_KERNEL_TPP + +#include "domain/impl/receivers/acoustic/interface.hpp" +#include "domain/impl/receivers/elastic/interface.hpp" +#include "enumerations/interface.hpp" +#include "kernel.hpp" +#include "kokkos_abstractions.h" +#include "quadrature/interface.hpp" +#include "specfem_setup.hpp" + +template +specfem::domain::impl::kernels:: + receiver_kernel::receiver_kernel( + const specfem::kokkos::DeviceView3d ibool, + const specfem::kokkos::DeviceView1d ispec, + const specfem::kokkos::DeviceView1d ireceiver, + const specfem::compute::partial_derivatives &partial_derivatives, + const specfem::compute::properties &properties, + const specfem::compute::receivers &receivers, + const specfem::kokkos::DeviceView2d + field, + const specfem::kokkos::DeviceView2d + field_dot, + const specfem::kokkos::DeviceView2d + field_dot_dot, + specfem::quadrature::quadrature *quadx, + specfem::quadrature::quadrature *quadz, + quadrature_points_type quadrature_points) + : ibool(ibool), ispec(ispec), ireceiver(ireceiver), + quadrature_points(quadrature_points), field(field), field_dot(field_dot), + field_dot_dot(field_dot_dot), + seismogram_types(receivers.seismogram_types), quadx(quadx), quadz(quadz), + receiver_seismogram(receivers.seismogram) { + +#ifndef NDEBUG + assert(field.extent(1) == medium::components); + assert(field_dot.extent(1) == medium::components); + assert(field_dot_dot.extent(1) == medium::components); +#endif + + const auto sin_rec = receivers.sin_recs; + const auto cos_rec = receivers.cos_recs; + const auto receiver_array = receivers.receiver_array; + const auto receiver_field = receivers.receiver_field; + + // Allocate receivers + this->receiver = specfem::domain::impl::receivers::receiver< + dimension, medium_type, quadrature_points_type, elemental_properties...>( + sin_rec, cos_rec, receiver_array, partial_derivatives, properties, + receiver_field); + + return; +} + +template +void specfem::domain::impl::kernels::receiver_kernel< + medium, qp_type, + elemental_properties...>::compute_seismograms(const int &isig_step) const { + + // Allocate scratch views for field, field_dot & field_dot_dot. Incase of + // acostic domains when calculating displacement, velocity and acceleration + // seismograms we need to compute the derivatives of the field variables. This + // requires summing over all lagrange derivatives at all quadrature points + // within the element. Scratch views speed up this computation by limiting + // global memory accesses. + + constexpr int components = medium::components; + const int nreceivers = ispec.extent(0); + + if (nreceivers == 0) + return; + + const int nseismograms = seismogram_types.extent(0); + const auto ibool = this->ibool; + const auto hprime_xx = this->quadx->get_hprime(); + const auto hprime_zz = this->quadz->get_hprime(); + // hprime_xx + int scratch_size = quadrature_points.template shmem_size< + type_real, 1, specfem::enums::axes::x, specfem::enums::axes::x>(); + + // hprime_zz + scratch_size += quadrature_points.template shmem_size< + type_real, 1, specfem::enums::axes::z, specfem::enums::axes::z>(); + + // field, field_dot, field_dot_dot + scratch_size += + 3 * + quadrature_points + .template shmem_size(); + + Kokkos::parallel_for( + "specfem::domain::domain::compute_seismogram", + specfem::kokkos::DeviceTeam(nreceivers * nseismograms, Kokkos::AUTO, 1) + .set_scratch_size(0, Kokkos::PerTeam(scratch_size)), + KOKKOS_CLASS_LAMBDA( + const specfem::kokkos::DeviceTeam::member_type &team_member) { + int ngllx, ngllz; + quadrature_points.get_ngll(&ngllx, &ngllz); + const int ireceiver_l = + this->ireceiver(team_member.league_rank() / nseismograms); + const int ispec_l = + this->ispec(team_member.league_rank() / nseismograms); + const int iseis_l = team_member.league_rank() % nseismograms; + const auto seismogram_type_l = this->seismogram_types(iseis_l); + + // Instantiate shared views + // ---------------------------------------------------------------- + auto s_hprime_xx = quadrature_points.template ScratchView< + type_real, 1, specfem::enums::axes::x, specfem::enums::axes::x>( + team_member.team_scratch(0)); + + auto s_hprime_zz = quadrature_points.template ScratchView< + type_real, 1, specfem::enums::axes::z, specfem::enums::axes::z>( + team_member.team_scratch(0)); + + auto s_field = + quadrature_points.template ScratchView( + team_member.team_scratch(0)); + + auto s_field_dot = + quadrature_points.template ScratchView( + team_member.team_scratch(0)); + + auto s_field_dot_dot = + quadrature_points.template ScratchView( + team_member.team_scratch(0)); + + // Allocate shared views + // ---------------------------------------------------------------- + Kokkos::parallel_for( + quadrature_points.template TeamThreadRange( + team_member), + [=](const int xz) { + int iz, ix; + sub2ind(xz, ngllx, iz, ix); + s_hprime_xx(iz, ix, 0) = hprime_xx(iz, ix); + }); + + Kokkos::parallel_for( + quadrature_points.template TeamThreadRange( + team_member), + [=](const int xz) { + int iz, ix; + sub2ind(xz, ngllz, iz, ix); + s_hprime_zz(iz, ix, 0) = hprime_zz(iz, ix); + }); + + Kokkos::parallel_for( + quadrature_points.template TeamThreadRange( + team_member), + [=](const int xz) { + int iz, ix; + sub2ind(xz, ngllx, iz, ix); + int iglob = ibool(ispec_l, iz, ix); +#ifdef KOKKOS_ENABLE_CUDA +#pragma unroll +#endif + for (int icomponent = 0; icomponent < components; icomponent++) { + s_field(iz, ix, icomponent) = field(iglob, icomponent); + s_field_dot(iz, ix, icomponent) = field_dot(iglob, icomponent); + s_field_dot_dot(iz, ix, icomponent) = + field_dot_dot(iglob, icomponent); + } + }); + + // Get seismogram field + // ---------------------------------------------------------------- + + Kokkos::parallel_for( + quadrature_points.template TeamThreadRange( + team_member), + [=](const int xz) { + receiver.get_field(ireceiver_l, iseis_l, ispec_l, + seismogram_type_l, xz, isig_step, s_field, + s_field_dot, s_field_dot_dot, s_hprime_xx, + s_hprime_zz); + }); + + // compute seismograms components + //------------------------------------------------------------------- + switch (seismogram_type_l) { + case specfem::enums::seismogram::type::displacement: + case specfem::enums::seismogram::type::velocity: + case specfem::enums::seismogram::type::acceleration: + specfem::kokkos::array_type seismogram_components; + Kokkos::parallel_reduce( + quadrature_points.template TeamThreadRange< + specfem::enums::axes::z, specfem::enums::axes::x>( + team_member), + [=](const int xz, specfem::kokkos::array_type + &l_seismogram_components) { + receiver.compute_seismogram_components( + ireceiver_l, iseis_l, seismogram_type_l, xz, isig_step, + l_seismogram_components); + }, + specfem::kokkos::Sum >( + seismogram_components)); + auto sv_receiver_seismogram = + Kokkos::subview(receiver_seismogram, isig_step, iseis_l, + ireceiver_l, Kokkos::ALL); + Kokkos::single(Kokkos::PerTeam(team_member), [=] { + receiver.compute_seismogram(ireceiver_l, seismogram_components, + sv_receiver_seismogram); + }); + break; + } + }); +} + +#endif /* _DOMAIN_IMPL_RECEIVERS_KERNEL_TPP */ diff --git a/include/domain/impl/receivers/receiver.hpp b/include/domain/impl/receivers/receiver.hpp new file mode 100644 index 00000000..17be1a3f --- /dev/null +++ b/include/domain/impl/receivers/receiver.hpp @@ -0,0 +1,24 @@ +#ifndef DOMAIN_RECEIVER_ELEMENTS_HPP +#define DOMAIN_RECEIVER_ELEMENTS_HPP + +#include "enumerations/interface.hpp" + +namespace specfem { +namespace domain { +namespace impl { +namespace receivers { +/** + * @brief Elemental receiver class + * + * Elemental receiver class to compute the seismogram at the receiver location. + * + * @tparam properties Properties of the receiver + */ +template class receiver {}; + +} // namespace receivers +} // namespace impl +} // namespace domain +} // namespace specfem + +#endif diff --git a/include/domain/impl/sources/acoustic/acoustic2d.hpp b/include/domain/impl/sources/acoustic/acoustic2d.hpp new file mode 100644 index 00000000..10cfe4d1 --- /dev/null +++ b/include/domain/impl/sources/acoustic/acoustic2d.hpp @@ -0,0 +1,83 @@ +#ifndef _DOMAIN_SOURCE_ACOUSTIC2D_HPP +#define _DOMAIN_SOURCE_ACOUSTIC2D_HPP + +#include "domain/impl/sources/source.hpp" +#include "enumerations/interface.hpp" +#include "specfem_setup.hpp" +#include + +/** + * @brief Decltype for the field subviewed at particular global index + * + */ +using field_type = Kokkos::Subview< + specfem::kokkos::DeviceView2d, int, + std::remove_const_t >; + +namespace specfem { +namespace domain { +namespace impl { +namespace sources { +/** + * @brief Elemental source class for 2D acoustic media. + * + * Base class for all 2D acoustic elemental sources. This class contains pure + * virtual methods that must be implemented by the template specializations. + * + * @tparam quadrature_points Number of Gauss-Lobatto-Legendre quadrature points + * defined at compile time or at runtime + */ +template +class source { +public: + using dimension = specfem::enums::element::dimension::dim2; + using medium_type = specfem::enums::element::medium::acoustic; + using quadrature_points_type = quadrature_points; + /** + * @brief Compute the source time function value at a given time + * + * @param t Time + * @return type_real Source time function value + */ + KOKKOS_INLINE_FUNCTION virtual type_real + eval_stf(const type_real &t) const = 0; + + /** + * @brief Compute elemental source contribution to the global force vector + * + * @param xz Index of the quadrature point + * @param stf_value Source time function value + * @param accel Acceleration contribution to the global force vector by the + * source + */ + KOKKOS_INLINE_FUNCTION virtual void + compute_interaction(const int &xz, const type_real &stf_value, + type_real *accel) const = 0; + + /** + * @brief Update the acceleration field + * + * @param accel Acceleration contribution to the global force vector by the + * source + * @param field_dot_dot Acceleration field subviewed at global index + * ibool(ispec, iz, ix) + */ + KOKKOS_INLINE_FUNCTION virtual void + update_acceleration(const type_real *accel, + field_type field_dot_dot) const = 0; + + /** + * @brief Get the ispec index of the source + * + * @return int ispec index of the source + */ + KOKKOS_INLINE_FUNCTION virtual int get_ispec() const = 0; +}; + +} // namespace sources +} // namespace impl +} // namespace domain +} // namespace specfem + +#endif diff --git a/include/domain/impl/sources/acoustic/acoustic2d_isotropic.hpp b/include/domain/impl/sources/acoustic/acoustic2d_isotropic.hpp new file mode 100644 index 00000000..88259846 --- /dev/null +++ b/include/domain/impl/sources/acoustic/acoustic2d_isotropic.hpp @@ -0,0 +1,105 @@ +#ifndef _DOMAIN_SOURCE_ACOUSTIC_ISOTROPIC2D_HPP +#define _DOMAIN_SOURCE_ACOUSTIC_ISOTROPIC2D_HPP + +#include "compute/interface.hpp" +#include "domain/impl/sources/acoustic/acoustic2d.hpp" +#include "domain/impl/sources/source.hpp" +#include "enumerations/interface.hpp" +#include "kokkos_abstractions.h" +#include "source_time_function/source_time_function.hpp" +#include + +namespace specfem { +namespace domain { +namespace impl { +namespace sources { +/** + * @brief Elemental source specialization for 2D elastic isotropic spectral + * elements with static quadrature points + * + * @tparam NGLL Number of Gauss-Lobatto-Legendre quadrature points defined at + * compile time + */ +template +class source< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::acoustic, + specfem::enums::element::quadrature::static_quadrature_points, + specfem::enums::element::property::isotropic> { + +public: + /** + * @name Typedefs + */ + ///@{ + /** + * @brief Dimension of the element + * + */ + using dimension = specfem::enums::element::dimension::dim2; + /** + * @brief Medium of the element + * + */ + using medium_type = specfem::enums::element::medium::acoustic; + /** + * @brief Number of Gauss-Lobatto-Legendre quadrature points + */ + using quadrature_points_type = + specfem::enums::element::quadrature::static_quadrature_points; + ///@} + + /** + * @brief Default elemental source constructor + * + */ + KOKKOS_FUNCTION source() = default; + + /** + * @brief Default elemental source copy constructor + * + */ + KOKKOS_FUNCTION source(const source &) = default; + + /** + * @brief Construct a new elemental source object + * + * @param properties struct used to store material properties + * @param source_array Source array containing pre-computed lagrange + * interpolants + */ + KOKKOS_FUNCTION + source(const specfem::compute::properties &properties, + const specfem::kokkos::DeviceView4d source_array); + + /** + * @brief Compute the interaction of the source with the medium computed at + * the quadrature point xz + * + * @param isource Index of the source + * @param ispec Index of the element + * @param xz Quadrature point index in the element + * @param stf_value Value of the source time function at the current time step + * @param acceleration Acceleration contribution to the global force vector by + * the source + */ + KOKKOS_INLINE_FUNCTION void compute_interaction( + const int &isource, const int &ispec, const int &xz, + const type_real &stf_value, + specfem::kokkos::array_type + &acceleration) const; + +private: + specfem::kokkos::DeviceView3d kappa; /// kappa array + specfem::kokkos::DeviceView4d source_array; ///< Source array + ///< containing + ///< pre-computed + ///< lagrange + ///< interpolants +}; +} // namespace sources +} // namespace impl +} // namespace domain +} // namespace specfem + +#endif diff --git a/include/domain/impl/sources/acoustic/acoustic2d_isotropic.tpp b/include/domain/impl/sources/acoustic/acoustic2d_isotropic.tpp new file mode 100644 index 00000000..677d6fcd --- /dev/null +++ b/include/domain/impl/sources/acoustic/acoustic2d_isotropic.tpp @@ -0,0 +1,64 @@ +#ifndef _DOMAIN_SOURCE_ACOUSTIC_ISOTROPIC2D_TPP +#define _DOMAIN_SOURCE_ACOUSTIC_ISOTROPIC2D_TPP + +#include "compute/interface.hpp" +#include "domain/impl/sources/acoustic/acoustic2d_isotropic.hpp" +#include "domain/impl/sources/source.hpp" +#include "globals.h" +#include "kokkos_abstractions.h" +#include "source_time_function/source_time_function.hpp" +#include "enumerations/interface.hpp" +#include "specfem_setup.hpp" +#include + +using field_type = Kokkos::Subview< + specfem::kokkos::DeviceView2d, int, + std::remove_const_t >; + +// ----------------------------------------------------------------------------- +// SPECIALIZED ELEMENT +// ----------------------------------------------------------------------------- + +template +KOKKOS_FUNCTION specfem::domain::impl::sources::source< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::acoustic, + specfem::enums::element::quadrature::static_quadrature_points, + specfem::enums::element::property::isotropic>:: + source(const specfem::compute::properties &properties, + const specfem::kokkos::DeviceView4d source_array) + : source_array(source_array), kappa(properties.kappa) { + +// #ifndef NDEBUG +// assert(source_array.extent(1) == NGLL); +// assert(source_array.extent(2) == NGLL); +// assert(properties.kappa.extent(1) == NGLL); +// assert(properties.kappa.extent(2) == NGLL); +// #endif + + return; +} + +template +KOKKOS_INLINE_FUNCTION void specfem::domain::impl::sources::source< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::acoustic, + specfem::enums::element::quadrature::static_quadrature_points, + specfem::enums::element::property::isotropic>:: + compute_interaction(const int &isource, const int &ispec, const int &xz, const type_real &stf_value, + specfem::kokkos::array_type &acceleration) const { + int ix, iz; + sub2ind(xz, NGLL, iz, ix); + + static_assert(medium_type::components == 1, + "Acoustic medium must have 1 component"); + + type_real sal = source_array(isource, iz, ix, 0); + type_real kap = kappa(ispec, iz, ix); + + acceleration[0] = source_array(isource, iz, ix, 0) * stf_value / kappa(ispec, iz, ix); + + return; +} + +#endif diff --git a/include/domain/impl/sources/acoustic/interface.hpp b/include/domain/impl/sources/acoustic/interface.hpp new file mode 100644 index 00000000..6ddc9f3c --- /dev/null +++ b/include/domain/impl/sources/acoustic/interface.hpp @@ -0,0 +1,8 @@ +#ifndef _DOMAIN_IMPL_SOURCES_ACOUSTIC_INTERFACE_HPP +#define _DOMAIN_IMPL_SOURCES_ACOUSTIC_INTERFACE_HPP + +#include "acoustic2d.hpp" +#include "acoustic2d_isotropic.hpp" +#include "acoustic2d_isotropic.tpp" + +#endif // _DOMAIN_IMPL_SOURCES_ACOUSTIC_INTERFACE_HPP diff --git a/include/domain/impl/sources/container.hpp b/include/domain/impl/sources/container.hpp new file mode 100644 index 00000000..1fd451e5 --- /dev/null +++ b/include/domain/impl/sources/container.hpp @@ -0,0 +1,49 @@ +#ifndef _SOURCE_CONTAINER_HPP +#define _SOURCE_CONTAINER_HPP + +namespace specfem { +namespace domain { +namespace impl { +namespace sources { +template struct container { +public: + base_elemental_source *source; + + KOKKOS_FUNCTION + container() = default; + + KOKKOS_FUNCTION + container(base_elemental_source *source) { + this->source = source; + return; + } + + template + KOKKOS_INLINE_FUNCTION void compute_interaction(Args... values) const { + this->source->compute_interaction(values...); + return; + } + + template + KOKKOS_INLINE_FUNCTION void update_acceleration(Args... values) const { + this->source->update_acceleration(values...); + return; + } + + KOKKOS_INLINE_FUNCTION + type_real eval_stf(const type_real &t) const { + return this->source->eval_stf(t); + } + + KOKKOS_INLINE_FUNCTION + int get_ispec() const { return this->source->get_ispec(); } + + KOKKOS_FUNCTION + ~container() = default; +}; +} // namespace sources +} // namespace impl +} // namespace domain +} // namespace specfem + +#endif diff --git a/include/domain/impl/sources/elastic/elastic2d.hpp b/include/domain/impl/sources/elastic/elastic2d.hpp new file mode 100644 index 00000000..a2ad5ca6 --- /dev/null +++ b/include/domain/impl/sources/elastic/elastic2d.hpp @@ -0,0 +1,83 @@ +#ifndef _DOMAIN_SOURCE_ELASTIC2D_HPP +#define _DOMAIN_SOURCE_ELASTIC2D_HPP + +#include "domain/impl/sources/source.hpp" +#include "enumerations/interface.hpp" +#include "specfem_setup.hpp" +#include + +/** + * @brief Decltype for the field subviewed at particular global index + * + */ +using field_type = Kokkos::Subview< + specfem::kokkos::DeviceView2d, int, + std::remove_const_t >; + +namespace specfem { +namespace domain { +namespace impl { +namespace sources { +/** + * @brief Elemental source class for 2D elastic media. + * + * Base class for all 2D elastic elemental sources. This class contains pure + * virtual methods that must be implemented by the template specializations. + * + * @tparam quadrature_points Number of Gauss-Lobatto-Legendre quadrature points + * defined at compile time or at runtime + */ +template +class source { +public: + using dimension = specfem::enums::element::dimension::dim2; + using medium_type = specfem::enums::element::medium::elastic; + using quadrature_points_type = quadrature_points; + /** + * @brief Compute the source time function value at a given time + * + * @param t Time + * @return type_real Source time function value + */ + KOKKOS_INLINE_FUNCTION virtual type_real + eval_stf(const type_real &t) const = 0; + + /** + * @brief Compute elemental source contribution to the global force vector + * + * @param xz Index of the quadrature point + * @param stf_value Source time function value + * @param accel Acceleration contribution to the global force vector by the + * source + */ + KOKKOS_INLINE_FUNCTION virtual void + compute_interaction(const int &xz, const type_real &stf_value, + type_real *accel) const = 0; + + /** + * @brief Update the acceleration field + * + * @param accel Acceleration contribution to the global force vector by the + * source + * @param field_dot_dot Acceleration field subviewed at global index + * ibool(ispec, iz, ix) + */ + KOKKOS_INLINE_FUNCTION virtual void + update_acceleration(const type_real *accel, + field_type field_dot_dot) const = 0; + + /** + * @brief Get the ispec index of the source + * + * @return int ispec index of the source + */ + KOKKOS_INLINE_FUNCTION virtual int get_ispec() const = 0; +}; + +} // namespace sources +} // namespace impl +} // namespace domain +} // namespace specfem + +#endif diff --git a/include/domain/impl/sources/elastic/elastic2d_isotropic.hpp b/include/domain/impl/sources/elastic/elastic2d_isotropic.hpp new file mode 100644 index 00000000..28dbd09b --- /dev/null +++ b/include/domain/impl/sources/elastic/elastic2d_isotropic.hpp @@ -0,0 +1,102 @@ +#ifndef _DOMAIN_SOURCE_ELASTIC_ISOTROPIC2D_HPP +#define _DOMAIN_SOURCE_ELASTIC_ISOTROPIC2D_HPP + +#include "compute/interface.hpp" +#include "domain/impl/sources/elastic/elastic2d.hpp" +#include "domain/impl/sources/source.hpp" +#include "enumerations/interface.hpp" +#include "kokkos_abstractions.h" +#include "source_time_function/source_time_function.hpp" +#include + +namespace specfem { +namespace domain { +namespace impl { +namespace sources { +/** + * @brief Elemental source specialization for 2D elastic isotropic spectral + * elements with static quadrature points + * + * @tparam NGLL Number of Gauss-Lobatto-Legendre quadrature points defined at + * compile time + */ +template +class source< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::elastic, + specfem::enums::element::quadrature::static_quadrature_points, + specfem::enums::element::property::isotropic> { + +public: + /** + * @name Typedefs + */ + ///@{ + /** + * @brief Dimension of the element + * + */ + using dimension = specfem::enums::element::dimension::dim2; + /** + * @brief Medium of the element + * + */ + using medium_type = specfem::enums::element::medium::elastic; + /** + * @brief Number of Gauss-Lobatto-Legendre quadrature points + */ + using quadrature_points_type = + specfem::enums::element::quadrature::static_quadrature_points; + ///@} + + /** + * @brief Default elemental source constructor + * + */ + KOKKOS_FUNCTION source() = default; + + /** + * @brief Default elemental source copy constructor + * + */ + KOKKOS_FUNCTION source(const source &) = default; + + /** + * @brief Construct a new elemental source object + * + * @param source_array Source array containing pre-computed lagrange + * interpolants + */ + KOKKOS_FUNCTION source(const specfem::compute::properties &properties, + specfem::kokkos::DeviceView4d source_array); + + /** + * @brief Compute the interaction of the source with the medium computed at + * the quadrature point xz + * + * @param isource Index of the source + * @param ispec Index of the element + * @param xz Quadrature point index in the element + * @param stf_value Value of the source time function at the current time step + * @param acceleration Acceleration contribution to the global force vector by + * the source + */ + KOKKOS_INLINE_FUNCTION void compute_interaction( + const int &isource, const int &ispec, const int &xz, + const type_real &stf_value, + specfem::kokkos::array_type + &acceleration) const; + +private: + specfem::kokkos::DeviceView4d source_array; ///< Source array + ///< containing + ///< pre-computed + ///< lagrange + ///< interpolants +}; +} // namespace sources +} // namespace impl +} // namespace domain +} // namespace specfem + +#endif diff --git a/include/domain/impl/sources/elastic/elastic2d_isotropic.tpp b/include/domain/impl/sources/elastic/elastic2d_isotropic.tpp new file mode 100644 index 00000000..f744f1cf --- /dev/null +++ b/include/domain/impl/sources/elastic/elastic2d_isotropic.tpp @@ -0,0 +1,61 @@ +#ifndef _DOMAIN_SOURCE_ELASTIC_ISOTROPIC2D_TPP +#define _DOMAIN_SOURCE_ELASTIC_ISOTROPIC2D_TPP + +#include "compute/interface.hpp" +#include "domain/impl/sources/elastic/elastic2d_isotropic.hpp" +#include "domain/impl/sources/source.hpp" +#include "globals.h" +#include "kokkos_abstractions.h" +#include "source_time_function/source_time_function.hpp" +#include "enumerations/interface.hpp" +#include "specfem_setup.hpp" +#include + +// ----------------------------------------------------------------------------- +// SPECIALIZED ELEMENT +// ----------------------------------------------------------------------------- + +template +KOKKOS_FUNCTION specfem::domain::impl::sources::source< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::elastic, + specfem::enums::element::quadrature::static_quadrature_points, + specfem::enums::element::property::isotropic>:: + source(const specfem::compute::properties &properties, + specfem::kokkos::DeviceView4d source_array) + : source_array(source_array) { + +// #ifndef NDEBUG +// assert(source_array.extent(1) == NGLL); +// assert(source_array.extent(2) == NGLL); +// #endif + + return; +} + +template +KOKKOS_INLINE_FUNCTION void specfem::domain::impl::sources::source< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::elastic, + specfem::enums::element::quadrature::static_quadrature_points, + specfem::enums::element::property::isotropic>:: + compute_interaction(const int &isource, const int &ispec, const int &xz, + const type_real &stf_value, specfem::kokkos::array_type &acceleration) const { + int ix, iz; + sub2ind(xz, NGLL, iz, ix); + + static_assert(medium_type::components == 2, + "Elastic medium must have 2 components"); + + if (specfem::globals::simulation_wave == specfem::wave::p_sv) { + acceleration[0] = source_array(isource, iz, ix, 0) * stf_value; + acceleration[1] = source_array(isource, iz, ix, 1) * stf_value; + } else if (specfem::globals::simulation_wave == specfem::wave::sh) { + acceleration[0] = source_array(isource, iz, ix, 0) * stf_value; + acceleration[1] = 0; + } + + return; +} + +#endif diff --git a/include/domain/impl/sources/elastic/interface.hpp b/include/domain/impl/sources/elastic/interface.hpp new file mode 100644 index 00000000..33352d86 --- /dev/null +++ b/include/domain/impl/sources/elastic/interface.hpp @@ -0,0 +1,8 @@ +#ifndef _DOMAIN_IMPL_SOURCES_ELASTIC_INTERFACE_HPP +#define _DOMAIN_IMPL_SOURCES_ELASTIC_INTERFACE_HPP + +#include "elastic2d.hpp" +#include "elastic2d_isotropic.hpp" +#include "elastic2d_isotropic.tpp" + +#endif // _DOMAIN_IMPL_SOURCES_ELASTIC_INTERFACE_HPP diff --git a/include/domain/impl/sources/interface.hpp b/include/domain/impl/sources/interface.hpp new file mode 100644 index 00000000..b275c743 --- /dev/null +++ b/include/domain/impl/sources/interface.hpp @@ -0,0 +1,15 @@ +#ifndef _DOMAIN_SOURCES_INTERFACE_HPP +#define _DOMAIN_SOURCES_INTERFACE_HPP + +#include "acoustic/acoustic2d.hpp" +#include "acoustic/acoustic2d_isotropic.hpp" +#include "acoustic/acoustic2d_isotropic.tpp" +#include "container.hpp" +#include "elastic/elastic2d.hpp" +#include "elastic/elastic2d_isotropic.hpp" +#include "elastic/elastic2d_isotropic.tpp" +#include "kernel.hpp" +#include "kernel.tpp" +#include "source.hpp" + +#endif diff --git a/include/domain/impl/sources/kernel.hpp b/include/domain/impl/sources/kernel.hpp new file mode 100644 index 00000000..7bc28cd2 --- /dev/null +++ b/include/domain/impl/sources/kernel.hpp @@ -0,0 +1,53 @@ +#ifndef _DOMAIN_IMPL_SOURCES_KERNEL_HPP +#define _DOMAIN_IMPL_SOURCES_KERNEL_HPP + +#include "compute/interface.hpp" +#include "domain/impl/sources/acoustic/interface.hpp" +#include "domain/impl/sources/elastic/interface.hpp" +#include "enumerations/interface.hpp" +#include "kokkos_abstractions.h" +#include "specfem_setup.hpp" +#include + +namespace specfem { +namespace domain { +namespace impl { +namespace kernels { + +template +class source_kernel { +public: + using dimension = specfem::enums::element::dimension::dim2; + using medium_type = medium; + using quadrature_point_type = qp_type; + + source_kernel() = default; + source_kernel(const specfem::kokkos::DeviceView3d ibool, + const specfem::kokkos::DeviceView1d ispec, + const specfem::kokkos::DeviceView1d isource, + const specfem::compute::properties &properties, + const specfem::compute::sources &sources, + quadrature_point_type quadrature_points, + specfem::kokkos::DeviceView2d + field_dot_dot); + + void compute_source_interaction(const type_real timeval) const; + +private: + specfem::kokkos::DeviceView1d ispec; + specfem::kokkos::DeviceView3d ibool; + specfem::kokkos::DeviceView1d isource; + specfem::kokkos::DeviceView2d field_dot_dot; + specfem::kokkos::DeviceView1d + stf_array; + quadrature_point_type quadrature_points; + specfem::domain::impl::sources::source< + dimension, medium_type, quadrature_point_type, elemental_properties...> + source; +}; +} // namespace kernels +} // namespace impl +} // namespace domain +} // namespace specfem + +#endif // _DOMAIN_IMPL_SOURCES_KERNEL_HPP diff --git a/include/domain/impl/sources/kernel.tpp b/include/domain/impl/sources/kernel.tpp new file mode 100644 index 00000000..4e0ee411 --- /dev/null +++ b/include/domain/impl/sources/kernel.tpp @@ -0,0 +1,104 @@ +#ifndef _DOMAIN_IMPL_SOURCES_KERNEL_TPP +#define _DOMAIN_IMPL_SOURCES_KERNEL_TPP + +#include "compute/interface.hpp" +#include "domain/impl/sources/acoustic/interface.hpp" +#include "domain/impl/sources/elastic/interface.hpp" +#include "kernel.hpp" +#include "kokkos_abstractions.h" +#include "enumerations/interface.hpp" +#include "specfem_setup.hpp" +#include + +template +specfem::domain::impl::kernels:: + source_kernel::source_kernel( + const specfem::kokkos::DeviceView3d ibool, + const specfem::kokkos::DeviceView1d ispec, + const specfem::kokkos::DeviceView1d isource, + const specfem::compute::properties &properties, + const specfem::compute::sources &sources, + quadrature_point_type quadrature_points, + specfem::kokkos::DeviceView2d + field_dot_dot) + : ibool(ibool), ispec(ispec), isource(isource), + quadrature_points(quadrature_points), stf_array(sources.stf_array), + field_dot_dot(field_dot_dot) { + +#ifndef NDEBUG + assert(field_dot_dot.extent(1) == medium::components); +#endif + + const auto source_array = sources.source_array; + + source = specfem::domain::impl::sources::source( + properties, source_array); + + return; +} + +template +void specfem::domain::impl::kernels::source_kernel:: + compute_source_interaction(const type_real timeval) const { + + constexpr int components = medium::components; + const int nsources = this->ispec.extent(0); + + if (nsources == 0) + return; + + const auto ibool = this->ibool; + + Kokkos::parallel_for( + "specfem::domain::domain::compute_source_interaction", + specfem::kokkos::DeviceTeam(nsources, Kokkos::AUTO, 1), + KOKKOS_CLASS_LAMBDA( + const specfem::kokkos::DeviceTeam::member_type &team_member) { + int ngllx, ngllz; + quadrature_points.get_ngll(&ngllx, &ngllz); + int isource_l = isource(team_member.league_rank()); + const int ispec_l = ispec(team_member.league_rank()); + + type_real stf; + + Kokkos::parallel_reduce( + Kokkos::TeamThreadRange(team_member, 1), + [=](const int &, type_real &lsum) { + lsum = stf_array(isource_l).compute(timeval); + }, + stf); + + team_member.team_barrier(); + + Kokkos::parallel_for( + quadrature_points.template TeamThreadRange( + team_member), + [=](const int xz) { + int iz, ix; + sub2ind(xz, ngllx, iz, ix); + int iglob = ibool(ispec_l, iz, ix); + + specfem::kokkos::array_type acceleration; + + source.compute_interaction(isource_l, ispec_l, xz, stf, + acceleration); + +#ifndef KOKKOS_ENABLE_CUDA +#pragma unroll +#endif + for (int i = 0; i < components; i++) { + Kokkos::single(Kokkos::PerThread(team_member), [&] { + Kokkos::atomic_add(&field_dot_dot(iglob, i), acceleration[i]); + }); + } + }); + }); + + Kokkos::fence(); + return; +} + +#endif // _DOMAIN_IMPL_SOURCES_KERNEL_TPP diff --git a/include/domain/impl/sources/source.hpp b/include/domain/impl/sources/source.hpp new file mode 100644 index 00000000..d92bbbf5 --- /dev/null +++ b/include/domain/impl/sources/source.hpp @@ -0,0 +1,25 @@ +#ifndef DOMAIN_SOURCE_ELEMENTS_HPP +#define DOMAIN_SOURCE_ELEMENTS_HPP + +#include "enumerations/interface.hpp" + +namespace specfem { +namespace domain { +namespace impl { +namespace sources { +/** + * @brief Elemental source class + * + * Elemental source class to describe the source contribution to the global + * force vector. + * + * @tparam properties Properties of the source + */ +template class source {}; + +} // namespace sources +} // namespace impl +} // namespace domain +} // namespace specfem + +#endif diff --git a/include/domain/interface.hpp b/include/domain/interface.hpp index 32e25786..91931101 100644 --- a/include/domain/interface.hpp +++ b/include/domain/interface.hpp @@ -2,6 +2,6 @@ #define _DOMAIN_INTERFACE_HPP #include "domain.hpp" -#include "elastic_domain.hpp" +#include "domain.tpp" #endif diff --git a/include/enumerations/boundary_conditions/composite_boundary.hpp b/include/enumerations/boundary_conditions/composite_boundary.hpp new file mode 100644 index 00000000..819be7f8 --- /dev/null +++ b/include/enumerations/boundary_conditions/composite_boundary.hpp @@ -0,0 +1,149 @@ +#ifndef _ENUMS_BOUNDARY_CONDITIONS_HPP +#define _ENUMS_BOUNDARY_CONDITIONS_HPP + +#include "compute/interface.hpp" +#include "enumerations/boundary_conditions/dirichlet.hpp" +#include "enumerations/boundary_conditions/stacey/interface.hpp" +#include "enumerations/quadrature.hpp" +#include "enumerations/specfem_enums.hpp" +#include + +namespace specfem { +namespace enums { +namespace boundary_conditions { +/** + * @brief Composite boundary conditions + * + * @tparam BCs Boundary conditions to be combined in the composite boundary + */ +template class composite_boundary {}; + +/** + * @brief Composite boundary conditions for Stacey BC and Dirichlet BC + * + * @tparam properties Properties of the Boundary conditions + */ +template +class composite_boundary< + specfem::enums::boundary_conditions::stacey, + specfem::enums::boundary_conditions::dirichlet > { +private: + using stacey_type = typename specfem::enums::boundary_conditions::stacey< + properties...>; ///< Stacey boundary conditions + using dirichlet_type = + typename specfem::enums::boundary_conditions::dirichlet< + properties...>; ///< Dirichlet boundary conditions + +public: + /** + * @name Typedefs + * + */ + ///@{ + using medium_type = + typename stacey_type::medium_type; ///< Medium type of the boundary. + using dimension = + typename stacey_type::dimension; ///< Dimension of the boundary. + using quadrature_points_type = + typename stacey_type::quadrature_points_type; ///< Quadrature points + ///< object to define the + ///< quadrature points + ///< either at compile time + ///< or run time. + using property_type = + typename stacey_type::property_type; ///< Property type of the boundary. + ///@} + + constexpr static specfem::enums::element::boundary_tag value = + specfem::enums::element::boundary_tag:: + composite_stacey_dirichlet; ///< boundary tag + + /** + * @brief Construct a new composite boundary object + * + */ + composite_boundary(){}; + + /** + * @brief Construct a new stacey object + * + * @param boundary_conditions boundary conditions object specifying the + * boundary conditions + * @param quadrature_points Quadrature points object + */ + composite_boundary(const specfem::compute::boundaries &boundary_conditions, + const quadrature_points_type &quadrature_points); + + /** + * @brief Compute the contribution of composite boundaries to the mass term + * + * @tparam time_scheme Time scheme to be used + * @param Args Arguments to be passed to the function. The underlying BCs are + * called with the same arguments + */ + template + KOKKOS_INLINE_FUNCTION void mass_time_contribution(Args &&...args) const { + stacey.template mass_time_contribution( + std::forward(args)...); + dirichlet.template mass_time_contribution( + std::forward(args)...); + } + + /** + * @brief Compute the contribution of composite boundaries to the gradient + * term + * + * @param Args Arguments to be passed to the function. The underlying BCs are + * called with the same arguments + */ + template + KOKKOS_INLINE_FUNCTION void enforce_gradient(Args &&...args) const { + stacey.enforce_gradient(std::forward(args)...); + dirichlet.enforce_gradient(std::forward(args)...); + } + + /** + * @brief Compute the contribution of composite boundaries to the stress term + * + * @param Args Arguments to be passed to the function. The underlying BCs are + * called with the same arguments + */ + template + KOKKOS_INLINE_FUNCTION void enforce_stress(Args &&...args) const { + stacey.enforce_stress(std::forward(args)...); + dirichlet.enforce_stress(std::forward(args)...); + } + + /** + * @brief Compute the contribution of composite boundaries to the traction + * term + * + * @param Args Arguments to be passed to the function. The underlying BCs are + * called with the same arguments + */ + template + KOKKOS_INLINE_FUNCTION void enforce_traction(Args &&...args) const { + // The order of operations is important here. The Dirichlet boundary + // conditions must be applied last. + stacey.enforce_traction(std::forward(args)...); + dirichlet.enforce_traction(std::forward(args)...); + } + + /** + * @brief Convert Stacey BC to string + * + */ + inline static std::string to_string() { + return "Composite: Stacey, Dirichlet"; + } + +private: + stacey_type stacey; ///< Stacey boundary conditions + dirichlet_type dirichlet; ///< Dirichlet boundary conditions +}; + +} /* namespace boundary_conditions */ +} /* namespace enums */ +} /* namespace specfem */ + +#endif /* _ENUMS_BOUNDARY_CONDITIONS_HPP */ diff --git a/include/enumerations/boundary_conditions/composite_boundary.tpp b/include/enumerations/boundary_conditions/composite_boundary.tpp new file mode 100644 index 00000000..c408825d --- /dev/null +++ b/include/enumerations/boundary_conditions/composite_boundary.tpp @@ -0,0 +1,40 @@ +#ifndef _ENUMS_BOUNDARY_CONDITIONS_COMPOSITE_BOUNDARY_TPP_ +#define _ENUMS_BOUNDARY_CONDITIONS_COMPOSITE_BOUNDARY_TPP_ + +#include "compute/interface.hpp" +#include "enumerations/boundary_conditions/composite_boundary.hpp" +#include "enumerations/boundary_conditions/dirichlet.hpp" +#include "enumerations/boundary_conditions/stacey/interface.hpp" +#include "enumerations/quadrature.hpp" +#include "enumerations/specfem_enums.hpp" + +template +specfem::enums::boundary_conditions::composite_boundary< + specfem::enums::boundary_conditions::stacey, + specfem::enums::boundary_conditions::dirichlet >:: + composite_boundary(const specfem::compute::boundaries &boundary_conditions, + const quadrature_points_type &quadrature_points) + : stacey(quadrature_points, + boundary_conditions.composite_stacey_dirichlet.type), + dirichlet(quadrature_points, + boundary_conditions.composite_stacey_dirichlet.type) { + + static_assert( + std::is_same::value, + "Medium types must be the same for composite boundary conditions."); + static_assert( + std::is_same::value, + "Dimensions must be the same for composite boundary conditions."); + static_assert( + std::is_same::value, + "Quadrature points must be the same for composite boundary conditions."); + static_assert( + std::is_same::value, + "Property types must be the same for composite boundary conditions."); +} + +#endif /* _ENUMS_BOUNDARY_CONDITIONS_COMPOSITE_BOUNDARY_TPP_ */ diff --git a/include/enumerations/boundary_conditions/dirichlet.hpp b/include/enumerations/boundary_conditions/dirichlet.hpp new file mode 100644 index 00000000..8937b168 --- /dev/null +++ b/include/enumerations/boundary_conditions/dirichlet.hpp @@ -0,0 +1,189 @@ +#ifndef _ENUMS_BOUNDARY_CONDITIONS_DIRICHLET_HPP_ +#define _ENUMS_BOUNDARY_CONDITIONS_DIRICHLET_HPP_ + +#include "compute/compute_boundaries.hpp" +#include "enumerations/dimension.hpp" +#include "enumerations/interface.hpp" +#include "enumerations/quadrature.hpp" +#include "enumerations/specfem_enums.hpp" +#include + +namespace specfem { +namespace enums { +namespace boundary_conditions { + +/** + * @brief Dirichlet boundary condition + * + * @tparam dim Dimension of the boundary. + * @tparam medium Medium type for the element where the boundary is located. + * @tparam property Property type for the element where the boundary is located. + * @tparam qp_type Quadrature points object to define the quadrature points + * either at compile time or run time. + */ +template +class dirichlet { +public: + /** + * @name Typedefs + * + */ + ///@{ + /** + * @brief Medium type of the boundary. + * + */ + using medium_type = medium; + /** + * @brief Dimension of the boundary. + * + */ + using dimension = dim; + /** + * @brief Quadrature points object to define the quadrature points either at + * compile time or run time. + * + */ + using quadrature_points_type = qp_type; + + /** + * @brief + * + */ + using property_type = property; + ///@} + + constexpr static specfem::enums::element::boundary_tag value = specfem:: + enums::element::boundary_tag::acoustic_free_surface; ///< boundary + ///< tag + + /** + * @brief Construct a new dirichlet object + * + */ + dirichlet(){}; + + /** + * @brief Construct a new dirichlet object + * + * @param quadrature_points Quadrature points object to define the quadrature + * points either at compile time or run time. + * @param type type of the edge on an element on the boundary. + */ + dirichlet(const quadrature_points_type &quadrature_points, + const specfem::kokkos::DeviceView1d< + specfem::compute::access::boundary_types> &type) + : quadrature_points(quadrature_points), type(type) {} + + /** + * @brief Construct a new dirichlet object + * + * @param boundary_conditions boundary conditions object specifying the + * boundary conditions + * @param quadrature_points Quadrature points object to define the quadrature + * points either at compile time or run time. + */ + dirichlet(const specfem::compute::boundaries &boundary_conditions, + const quadrature_points_type &quadrature_points); + + /** + * @brief Compute the mass time contribution for the boundary condition + * + * @tparam time_scheme Time scheme to use when computing the mass time + * contribution + * @param ielement index of the element + * @param xz index of the quadrature point + * @param dt time step + * @param weight weights(x,z) for the quadrature point + * @param partial_derivatives partial derivatives of the shape functions + * @param properties properties of the element at the quadrature point + * @param mass_matrix mass matrix to update + */ + template + KOKKOS_INLINE_FUNCTION void mass_time_contribution( + const int &ielement, const int &xz, const type_real &dt, + const specfem::kokkos::array_type &weight, + const specfem::compute::element_partial_derivatives &partial_derivatives, + const specfem::compute::element_properties< + medium_type::value, property_type::value> &properties, + specfem::kokkos::array_type + &rmass_inverse) const {}; + + /** + * @brief Compute the contribuition of BC to the gradient term + * + * @param ielement index of the element + * @param xz index of the quadrature point + * @param partial_derivatives spacial derivatives at the quadrature point + * @param df_dx Gradient of field in x-direction to update + * @param df_dz Gradient of field in z-direction to update + */ + KOKKOS_INLINE_FUNCTION void enforce_gradient( + const int &ielement, const int &xz, + const specfem::compute::element_partial_derivatives &partial_derivatives, + specfem::kokkos::array_type &df_dx, + specfem::kokkos::array_type &df_dz) + const {}; + + /** + * @brief Compute the contribution of BC to the stress term + * + * @param ielement index of the element + * @param xz index of the quadrature point + * @param partial_derivatives spacial derivatives at the quadrature point + * @param properties properties of the element at the quadrature point + * @param stress_integrand_xi /f$ \sigma_{\xi} /f$ to update + * @param stress_integrand_xgamma /f$ \sigma_{\gamma} /f$ to update + * @return KOKKOS_INLINE_FUNCTION + */ + KOKKOS_INLINE_FUNCTION void enforce_stress( + const int &ielement, const int &xz, + const specfem::compute::element_partial_derivatives &partial_derivatives, + const specfem::compute::element_properties< + medium_type::value, property_type::value> &properties, + specfem::kokkos::array_type + &stress_integrand_xi, + specfem::kokkos::array_type + &stress_integrand_xgamma) const {}; + + /** + * @brief Compute the contribution of BC to the traction term + * + * @param ielement index of the element + * @param xz index of the quadrature point + * @param weight weights(x,z) for the quadrature point + * @param partial_derivatives partial derivatives of the shape functions + * @param properties properties of the element at the quadrature point + * @param velocity first derivative of the field computed from previous time + * step + * @param accelation second derivative of the field to update + * @return KOKKOS_INLINE_FUNCTION + */ + KOKKOS_FUNCTION void enforce_traction( + const int &ielement, const int &xz, + const specfem::kokkos::array_type &weight, + const specfem::compute::element_partial_derivatives &partial_derivatives, + const specfem::compute::element_properties< + medium_type::value, property_type::value> &properties, + const specfem::kokkos::array_type + &field_dot, + specfem::kokkos::array_type + &field_dot_dot) const; + + /** + * @brief Convert the boundary to a string + * + */ + inline static std::string to_string() { return "Dirichlet"; } + +private: + specfem::kokkos::DeviceView1d + type; ///< type of the edge on an element on the boundary. + quadrature_points_type quadrature_points; ///< Quadrature points object. +}; + +} // namespace boundary_conditions +} // namespace enums +} // namespace specfem + +#endif /* _ENUMS_BOUNDARY_CONDITIONS_DIRICHLET_HPP_ */ diff --git a/include/enumerations/boundary_conditions/dirichlet.tpp b/include/enumerations/boundary_conditions/dirichlet.tpp new file mode 100644 index 00000000..da9ed280 --- /dev/null +++ b/include/enumerations/boundary_conditions/dirichlet.tpp @@ -0,0 +1,58 @@ +#ifndef _ENUMS_BOUNDARY_CONDITIONS_DIRICHLET_TPP_ +#define _ENUMS_BOUNDARY_CONDITIONS_DIRICHLET_TPP_ + +#include "compute/interface.hpp" +#include "dirichlet.hpp" +#include "enumerations/dimension.hpp" +#include "enumerations/quadrature.hpp" +#include "enumerations/specfem_enums.hpp" +#include + +template +specfem::enums::boundary_conditions::dirichlet:: + dirichlet(const specfem::compute::boundaries &boundary_conditions, + const quadrature_points_type &quadrature_points) + : quadrature_points(quadrature_points), + type(boundary_conditions.acoustic_free_surface.type) { + return; +} + +template +KOKKOS_INLINE_FUNCTION void specfem::enums::boundary_conditions:: + dirichlet::enforce_traction( + const int &ielement, const int &xz, + const specfem::kokkos::array_type &weight, + const specfem::compute::element_partial_derivatives + &partial_derivatives, + const specfem::compute::element_properties< + medium_type::value, property_type::value> &properties, + const specfem::kokkos::array_type + &field_dot, + specfem::kokkos::array_type + &field_dot_dot) const { + + constexpr int components = medium_type::components; + constexpr auto value_t = value; + + int ngllx, ngllz; + quadrature_points.get_ngll(&ngllx, &ngllz); + + int ix, iz; + sub2ind(xz, ngllx, iz, ix); + + const auto itype = this->type(ielement); + if (!specfem::compute::access::is_on_boundary(value_t, itype, iz, ix, ngllz, + ngllx)) { + return; + } + +#ifdef KOKKOS_ENABLE_CUDA +#pragma unroll +#endif + for (int icomp = 0; icomp < components; ++icomp) + field_dot_dot[icomp] = 0.0; + + return; +} + +#endif /* _ENUMS_BOUNDARY_CONDITIONS_DIRICHLET_TPP_ */ diff --git a/include/enumerations/boundary_conditions/interface.hpp b/include/enumerations/boundary_conditions/interface.hpp new file mode 100644 index 00000000..ea6fe16c --- /dev/null +++ b/include/enumerations/boundary_conditions/interface.hpp @@ -0,0 +1,11 @@ +#ifndef _ENUMS_BOUNDARY_CONDITIONS_INTERFACE_HPP_ +#define _ENUMS_BOUNDARY_CONDITIONS_INTERFACE_HPP_ + +#include "composite_boundary.hpp" +#include "composite_boundary.tpp" +#include "dirichlet.hpp" +#include "dirichlet.tpp" +#include "none.hpp" +#include "stacey/interface.hpp" + +#endif /* _ENUMS_BOUNDARY_CONDITIONS_INTERFACE_HPP_ */ diff --git a/include/enumerations/boundary_conditions/none.hpp b/include/enumerations/boundary_conditions/none.hpp new file mode 100644 index 00000000..3fc820ec --- /dev/null +++ b/include/enumerations/boundary_conditions/none.hpp @@ -0,0 +1,170 @@ +#ifndef _ENUMS_BOUNDARY_CONDITIONS_NONE_HPP_ +#define _ENUMS_BOUNDARY_CONDITIONS_NONE_HPP_ + +#include "compute/interface.hpp" +#include "enumerations/dimension.hpp" +#include "enumerations/quadrature.hpp" +#include "enumerations/specfem_enums.hpp" +#include + +namespace specfem { +namespace enums { +namespace boundary_conditions { + +/** + * @brief None boundary condition (no boundary condition) + * + * @tparam dim Dimension of the boundary. + * @tparam medium Medium type for the element where the boundary is located. + * @tparam property Property type for the element where the boundary is located. + * @tparam qp_type Quadrature points object to define the quadrature points + * either at compile time or run time. + */ +template +class none { + +public: + /** + * @name Typedefs + * + */ + ///@{ + /** + * @brief Medium type of the boundary. + * + */ + using medium_type = medium; + /** + * @brief Dimension of the boundary. + * + */ + using dimension = dim; + /** + * @brief Quadrature points object to define the quadrature points either at + * compile time or run time. + * + */ + using quadrature_points_type = qp_type; + + /** + * @brief Property type of the boundary. + * + */ + using property_type = property; + ///@} + + constexpr static specfem::enums::element::boundary_tag value = + specfem::enums::element::boundary_tag::none; ///< boundary tag + + /** + * @brief Construct a new none object + * + */ + none(){}; + + /** + * @brief Construct a new none object + * + * @param quadrature_points Quadrature points object to define the quadrature + * points either at compile time or run time. + */ + none(const specfem::compute::boundaries &boundary_conditions, + const quadrature_points_type &quadrature_points){}; + + /** + * @brief Compute the mass time contribution for the boundary condition + * + * @tparam time_scheme Time scheme to use when computing the mass time + * contribution + * @param ielement index of the element + * @param xz index of the quadrature point + * @param dt time step + * @param weight weights(x,z) for the quadrature point + * @param partial_derivatives partial derivatives of the shape functions + * @param properties properties of the element at the quadrature point + * @param mass_matrix mass matrix to update + */ + template + KOKKOS_INLINE_FUNCTION void mass_time_contribution( + const int &ielement, const int &xz, const type_real &dt, + const specfem::kokkos::array_type &weight, + const specfem::compute::element_partial_derivatives &partial_derivatives, + const specfem::compute::element_properties< + medium_type::value, property_type::value> &properties, + specfem::kokkos::array_type + &rmass_inverse) const {}; + + /** + * @brief Compute the contribuition of BC to the gradient term + * + * @param ielement index of the element + * @param xz index of the quadrature point + * @param partial_derivatives spacial derivatives at the quadrature point + * @param df_dx Gradient of field in x-direction to update + * @param df_dz Gradient of field in z-direction to update + */ + KOKKOS_INLINE_FUNCTION void enforce_gradient( + const int &ielement, const int &xz, + const specfem::compute::element_partial_derivatives &partial_derivatives, + specfem::kokkos::array_type &df_dx, + specfem::kokkos::array_type &df_dz) + const {}; + + /** + * @brief Compute the contribution of BC to the stress term + * + * @param ielement index of the element + * @param xz index of the quadrature point + * @param partial_derivatives spacial derivatives at the quadrature point + * @param properties properties of the element at the quadrature point + * @param stress_integrand_xi /f$ \sigma_{\xi} /f$ to update + * @param stress_integrand_xgamma /f$ \sigma_{\gamma} /f$ to update + * @return KOKKOS_INLINE_FUNCTION + */ + KOKKOS_INLINE_FUNCTION void enforce_stress( + const int &ielement, const int &xz, + const specfem::compute::element_partial_derivatives &partial_derivatives, + const specfem::compute::element_properties< + medium_type::value, property_type::value> &properties, + specfem::kokkos::array_type + &stress_integrand_xi, + specfem::kokkos::array_type + &stress_integrand_xgamma) const {}; + + /** + * @brief Compute the contribution of BC to the traction term + * + * @param ielement index of the element + * @param xz index of the quadrature point + * @param weight weights(x,z) for the quadrature point + * @param partial_derivatives partial derivatives of the shape functions + * @param properties properties of the element at the quadrature point + * @param velocity first derivative of the field computed from previous time + * step + * @param accelation second derivative of the field to update + * @return KOKKOS_INLINE_FUNCTION + */ + KOKKOS_INLINE_FUNCTION void enforce_traction( + const int &ielement, const int &xz, + const specfem::kokkos::array_type &weight, + const specfem::compute::element_partial_derivatives &partial_derivatives, + const specfem::compute::element_properties< + medium_type::value, property_type::value> &properties, + const specfem::kokkos::array_type + &field_dot, + specfem::kokkos::array_type + &field_dot_dot) const {}; + + /** + * @brief Convert Stacey BC to string + * + * @return std::string String representation of the boundary condition + */ + inline static std::string to_string() { return ""; } +}; + +} // namespace boundary_conditions +} // namespace enums +} // namespace specfem + +#endif /* _ENUMS_BOUNDARY_CONDITIONS_NONE_HPP_ */ diff --git a/include/enumerations/boundary_conditions/stacey/interface.hpp b/include/enumerations/boundary_conditions/stacey/interface.hpp new file mode 100644 index 00000000..1304ab28 --- /dev/null +++ b/include/enumerations/boundary_conditions/stacey/interface.hpp @@ -0,0 +1,11 @@ +#ifndef _ENUMS_BOUNDARY_CONDITIONS_STACEY_INTERFACE_HPP_ +#define _ENUMS_BOUNDARY_CONDITIONS_STACEY_INTERFACE_HPP_ + +#include "stacey.hpp" +#include "stacey2d_acoustic.hpp" +#include "stacey2d_acoustic.tpp" +#include "stacey2d_elastic.hpp" +#include "stacey2d_elastic.tpp" + +#endif /* end of include guard: \ + _ENUMS_BOUNDARY_CONDITIONS_STACEY_INTERFACE_HPP_ */ diff --git a/include/enumerations/boundary_conditions/stacey/stacey.hpp b/include/enumerations/boundary_conditions/stacey/stacey.hpp new file mode 100644 index 00000000..f9f0fced --- /dev/null +++ b/include/enumerations/boundary_conditions/stacey/stacey.hpp @@ -0,0 +1,73 @@ +#ifndef _ENUMS_BOUNDARY_CONDITIONS_STACEY_2D_HPP_ +#define _ENUMS_BOUNDARY_CONDITIONS_STACEY_2D_HPP_ + +#include "compute/interface.hpp" +#include "enumerations/dimension.hpp" +#include "enumerations/quadrature.hpp" +#include "enumerations/specfem_enums.hpp" +#include + +namespace specfem { +namespace enums { +namespace boundary_conditions { +/** + * @brief Stacey boundary conditions + * + * @tparam dim Dimension of the boundary + * @tparam medium medium type for the boundary condition + * @tparam property property type for the boundary condition (iso/anisotropic) + * @tparam qp_type Quadrature points type for the boundary condition + * (compile/run time) + */ +template +class stacey { + +public: + /** + * @name Typedefs + * + */ + ///@{ + /** + * @brief Medium type of the boundary. + * + */ + using medium_type = medium; + /** + * @brief Dimension of the boundary. + * + */ + using dimension = dim; + /** + * @brief Quadrature points object to define the quadrature points either at + * compile time or run time. + * + */ + using quadrature_points_type = qp_type; + /** + * @brief Property type of the boundary. + * + */ + using property_type = property; + ///@} + + constexpr static specfem::enums::element::boundary_tag value = + specfem::enums::element::boundary_tag::stacey; ///< boundary tag + + /** + * @brief Construct a new stacey object + * + */ + stacey(){}; + + /** + * @brief Convert Stacey BC to string + * + */ + inline static std::string to_string() { return "Stacey"; } +}; +} // namespace boundary_conditions +} // namespace enums +} // namespace specfem + +#endif /* end of include guard: _ENUMS_BOUNDARY_CONDITIONS_STACEY_2D_HPP_ */ diff --git a/include/enumerations/boundary_conditions/stacey/stacey2d_acoustic.hpp b/include/enumerations/boundary_conditions/stacey/stacey2d_acoustic.hpp new file mode 100644 index 00000000..a3f943b7 --- /dev/null +++ b/include/enumerations/boundary_conditions/stacey/stacey2d_acoustic.hpp @@ -0,0 +1,188 @@ +#ifndef _ENUMS_BOUNDARY_CONDITIONS_STACEY2D_ACOUSTIC_HPP_ +#define _ENUMS_BOUNDARY_CONDITIONS_STACEY2D_ACOUSTIC_HPP_ + +#include "compute/interface.hpp" +#include "enumerations/dimension.hpp" +#include "enumerations/medium.hpp" +#include "enumerations/quadrature.hpp" +#include "enumerations/specfem_enums.hpp" +#include "kokkos_abstractions.h" +#include "stacey.hpp" +#include + +namespace specfem { +namespace enums { +namespace boundary_conditions { +/** + * @brief Stacey boundary conditions for 2D acoustic elements + * + * @tparam property property type for the boundary condition (iso/anisotropic) + * @tparam qp_type Quadrature points type for the boundary condition + * (compile/run time) + */ +template +class stacey { + +public: + /** + * @name Typedefs + * + */ + ///@{ + /** + * @brief Medium type of the boundary. + * + */ + using medium_type = specfem::enums::element::medium::acoustic; + /** + * @brief Dimension of the boundary. + * + */ + using dimension = specfem::enums::element::dimension::dim2; + /** + * @brief Quadrature points object to define the quadrature points either at + * compile time or run time. + * + */ + using quadrature_points_type = qp_type; + /** + * @brief Property type of the boundary. + * + */ + using property_type = property; + ///@} + + constexpr static specfem::enums::element::boundary_tag value = + specfem::enums::element::boundary_tag::stacey; ///< boundary tag + + /** + * @brief Construct a new stacey object + * + */ + stacey(){}; + + /** + * @brief Construct a new stacey object + * + * @param quadrature_points Quadrature points object + * @param type type of the edge on an element on the boundary (top, bottom, + * left, right etc.) + */ + stacey(const quadrature_points_type &quadrature_points, + const specfem::kokkos::DeviceView1d< + specfem::compute::access::boundary_types> &type) + : quadrature_points(quadrature_points), type(type) {} + + /** + * @brief Construct a new stacey object + * + * @param boundary_conditions boundary conditions object specifying the + * boundary conditions for the mesh + * @param quadrature_points Quadrature points object + */ + stacey(const specfem::compute::boundaries &boundary_conditions, + const quadrature_points_type &quadrature_points); + + /** + * @brief Compute the mass time contribution for the boundary condition + * + * @tparam time_scheme Time scheme to use when computing the mass time + * contribution + * @param ielement index of the element + * @param xz index of the quadrature point + * @param dt time step + * @param weight weights(x,z) for the quadrature point + * @param partial_derivatives partial derivatives of the shape functions + * @param properties properties of the element at the quadrature point + * @param mass_matrix mass matrix to update + */ + template + KOKKOS_INLINE_FUNCTION void mass_time_contribution( + const int &ielement, const int &xz, const type_real &dt, + const specfem::kokkos::array_type &weight, + const specfem::compute::element_partial_derivatives &partial_derivatives, + const specfem::compute::element_properties< + medium_type::value, property_type::value> &properties, + specfem::kokkos::array_type + &mass_matrix) const; + + /** + * @brief Compute the contribuition of BC to the gradient term + * + * @param ielement index of the element + * @param xz index of the quadrature point + * @param partial_derivatives spacial derivatives at the quadrature point + * @param df_dx Gradient of field in x-direction to update + * @param df_dz Gradient of field in z-direction to update + */ + KOKKOS_INLINE_FUNCTION + void enforce_gradient( + const int &ielement, const int &xz, + const specfem::compute::element_partial_derivatives &partial_derivatives, + specfem::kokkos::array_type &df_dx, + specfem::kokkos::array_type &df_dz) + const {}; + + /** + * @brief Compute the contribution of BC to the stress term + * + * @param ielement index of the element + * @param xz index of the quadrature point + * @param partial_derivatives spacial derivatives at the quadrature point + * @param properties properties of the element at the quadrature point + * @param stress_integrand_xi /f$ \sigma_{\xi} /f$ to update + * @param stress_integrand_xgamma /f$ \sigma_{\gamma} /f$ to update + * @return KOKKOS_INLINE_FUNCTION + */ + KOKKOS_INLINE_FUNCTION void enforce_stress( + const int &ielement, const int &xz, + const specfem::compute::element_partial_derivatives &partial_derivatives, + const specfem::compute::element_properties< + medium_type::value, property_type::value> &properties, + specfem::kokkos::array_type + &stress_integrand_xi, + specfem::kokkos::array_type + &stress_integrand_xgamma) const {}; + + /** + * @brief Compute the contribution of BC to the traction term + * + * @param ielement index of the element + * @param xz index of the quadrature point + * @param weight weights(x,z) for the quadrature point + * @param partial_derivatives partial derivatives of the shape functions + * @param properties properties of the element at the quadrature point + * @param velocity first derivative of the field computed from previous time + * step + * @param accelation second derivative of the field to update + * @return KOKKOS_INLINE_FUNCTION + */ + KOKKOS_INLINE_FUNCTION void enforce_traction( + const int &ielement, const int &xz, + const specfem::kokkos::array_type &weight, + const specfem::compute::element_partial_derivatives &partial_derivatives, + const specfem::compute::element_properties< + medium_type::value, property_type::value> &properties, + const specfem::kokkos::array_type + &velocity, + specfem::kokkos::array_type + &accelation) const; + + /** + * @brief Convert Stacey BC to string + * + * @return std::string String representation of the boundary condition + */ + inline static std::string to_string() { return "Stacey"; } + +private: + quadrature_points_type quadrature_points; ///< Quadrature points object. + specfem::kokkos::DeviceView1d + type; ///< type of the edge on an element on the boundary. +}; +} // namespace boundary_conditions +} // namespace enums +} // namespace specfem + +#endif // _ENUMS_BOUNDARY_CONDITIONS_STACEY2D_ACOUSTIC_HPP_ diff --git a/include/enumerations/boundary_conditions/stacey/stacey2d_acoustic.tpp b/include/enumerations/boundary_conditions/stacey/stacey2d_acoustic.tpp new file mode 100644 index 00000000..2dff281b --- /dev/null +++ b/include/enumerations/boundary_conditions/stacey/stacey2d_acoustic.tpp @@ -0,0 +1,223 @@ +#ifndef _ENUMS_BOUNDARY_CONDITIONS_STACEY_2D_ACOUSTIC_TPP_ +#define _ENUMS_BOUNDARY_CONDITIONS_STACEY_2D_ACOUSTIC_TPP_ + +#include "compute/interface.hpp" +#include "enumerations/dimension.hpp" +#include "enumerations/medium.hpp" +#include "enumerations/quadrature.hpp" +#include "enumerations/specfem_enums.hpp" +#include "kokkos_abstractions.h" +#include "stacey2d_acoustic.hpp" + +namespace { + +KOKKOS_INLINE_FUNCTION void enforce_traction_boundary( + const type_real &weight, + const specfem::kokkos::array_type &dn, + const specfem::compute::element_properties< + specfem::enums::element::type::acoustic, + specfem::enums::element::property_tag::isotropic> &properties, + const specfem::kokkos::array_type &field_dot, + specfem::kokkos::array_type &field_dot_dot) { + + auto jacobian1d = dn.l2_norm(); + + field_dot_dot[0] += + // jacobian1d * weight * rho_vp_inverse * velocity + -1.0 * dn.l2_norm() * weight * properties.rho_vpinverse * field_dot[0]; + return; +} + +template +KOKKOS_FUNCTION void newmark_mass_terms( + const int &ix, const int &iz, const int &ngllx, const int &ngllz, + const type_real &dt, const specfem::compute::access::boundary_types &itype, + const specfem::enums::element::boundary_tag &tag, + const specfem::kokkos::array_type &weight, + const specfem::compute::element_partial_derivatives &partial_derivatives, + const specfem::compute::element_properties< + specfem::enums::element::type::acoustic, property> &properties, + specfem::kokkos::array_type &rmass_inverse) { + + specfem::kokkos::array_type velocity; + + velocity[0] = -1.0 * dt * 0.5; + + specfem::kokkos::array_type dn; // normal vector + + // Left Boundary + if (itype.left == tag && ix == 0) { + dn = partial_derivatives + .compute_normal(); + enforce_traction_boundary(weight[1], dn, properties, velocity, + rmass_inverse); + return; + } + + // Right Boundary + if (itype.right == tag && ix == ngllx - 1) { + dn = partial_derivatives + .compute_normal(); + enforce_traction_boundary(weight[1], dn, properties, velocity, + rmass_inverse); + return; + } + + // Bottom Boundary + if (itype.bottom == tag && iz == 0) { + dn = partial_derivatives + .compute_normal(); + enforce_traction_boundary(weight[0], dn, properties, velocity, + rmass_inverse); + return; + } + + // Top Boundary + if (itype.top == tag && iz == ngllz - 1) { + dn = partial_derivatives + .compute_normal(); + enforce_traction_boundary(weight[0], dn, properties, velocity, + rmass_inverse); + return; + } + + return; +} +} // namespace + +template +specfem::enums::boundary_conditions::stacey< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::acoustic, property, + qp_type>::stacey(const specfem::compute::boundaries &boundary_conditions, + const quadrature_points_type &quadrature_points) + : quadrature_points(quadrature_points), + type(boundary_conditions.stacey.acoustic.type) { + return; +} + +template +template +KOKKOS_INLINE_FUNCTION void specfem::enums::boundary_conditions::stacey< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::acoustic, property, qp_type>:: + mass_time_contribution( + const int &ielement, const int &xz, const type_real &dt, + const specfem::kokkos::array_type &weight, + const specfem::compute::element_partial_derivatives + &partial_derivatives, + const specfem::compute::element_properties< + specfem::enums::element::type::acoustic, property_type::value> + &properties, + specfem::kokkos::array_type &rmass_inverse) const { + + // Check if the GLL point is on the boundary + // -------------------------------------------------------------------------- + + constexpr int components = 1; + constexpr auto value_t = value; + + int ngllx, ngllz; + + quadrature_points.get_ngll(&ngllx, &ngllz); + + int ix, iz; + sub2ind(xz, ngllx, iz, ix); + + const auto itype = this->type(ielement); + if (!specfem::compute::access::is_on_boundary(value_t, itype, iz, ix, ngllz, ngllx)) { + return; + } + // -------------------------------------------------------------------------- + + if constexpr (time_scheme == specfem::enums::time_scheme::type::newmark) { + newmark_mass_terms(ix, iz, ngllx, ngllz, dt, itype, value_t, weight, + partial_derivatives, properties, rmass_inverse); + return; + } + + return; +} + +template +KOKKOS_INLINE_FUNCTION void specfem::enums::boundary_conditions::stacey< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::acoustic, property, qp_type>:: + enforce_traction( + const int &ielement, const int &xz, + const specfem::kokkos::array_type &weight, + const specfem::compute::element_partial_derivatives + &partial_derivatives, + const specfem::compute::element_properties< + specfem::enums::element::type::acoustic, property_type::value> + &properties, + const specfem::kokkos::array_type &field_dot, + specfem::kokkos::array_type &field_dot_dot) const { + + // Check if the GLL point is on the boundary + // -------------------------------------------------------------------------- + constexpr int components = 1; + constexpr auto value_t = value; + + int ngllx, ngllz; + + quadrature_points.get_ngll(&ngllx, &ngllz); + + int ix, iz; + sub2ind(xz, ngllx, iz, ix); + + const auto itype = this->type(ielement); + if (!specfem::compute::access::is_on_boundary(value_t, itype, iz, ix, ngllz, ngllx)) { + return; + } + // -------------------------------------------------------------------------- + + // enforce traction condition + // -------------------------------------------------------------------------- + // If the GLL point is on the corner the left or right traction conditions are + // applied top or bottom traction conditions are ignored in this case. This + // ensures there is no conflict in calculating the normal + + specfem::kokkos::array_type dn; // normal vector + + // Left Boundary + if (itype.left == value_t && ix == 0) { + dn = partial_derivatives + .compute_normal(); + enforce_traction_boundary(weight[1], dn, properties, field_dot, + field_dot_dot); + return; + } + + // Right Boundary + if (itype.right == value_t && ix == ngllx - 1) { + dn = partial_derivatives + .compute_normal(); + enforce_traction_boundary(weight[1], dn, properties, field_dot, + field_dot_dot); + return; + } + + // Bottom Boundary + if (itype.bottom == value_t && iz == 0) { + dn = partial_derivatives + .compute_normal(); + enforce_traction_boundary(weight[0], dn, properties, field_dot, + field_dot_dot); + return; + } + + // Top Boundary + if (itype.top == value_t && iz == ngllz - 1) { + dn = partial_derivatives + .compute_normal(); + enforce_traction_boundary(weight[0], dn, properties, field_dot, + field_dot_dot); + return; + } + // -------------------------------------------------------------------------- + + return; +} + +#endif /* _ENUMS_BOUNDARY_CONDITIONS_STACEY_2D_ACOUSTIC_TPP_ */ diff --git a/include/enumerations/boundary_conditions/stacey/stacey2d_elastic.hpp b/include/enumerations/boundary_conditions/stacey/stacey2d_elastic.hpp new file mode 100644 index 00000000..2bc7cf94 --- /dev/null +++ b/include/enumerations/boundary_conditions/stacey/stacey2d_elastic.hpp @@ -0,0 +1,187 @@ +#ifndef _ENUMS_BOUNDARY_CONDITIONS_STACEY2D_ELASTIC_HPP_ +#define _ENUMS_BOUNDARY_CONDITIONS_STACEY2D_ELASTIC_HPP_ + +#include "compute/interface.hpp" +#include "enumerations/dimension.hpp" +#include "enumerations/medium.hpp" +#include "enumerations/quadrature.hpp" +#include "enumerations/specfem_enums.hpp" +#include "kokkos_abstractions.h" +#include "stacey.hpp" +#include + +namespace specfem { +namespace enums { +namespace boundary_conditions { +/** + * @brief Stacey boundary conditions for 2D elastic elements + * + * @tparam property property type for the boundary condition (iso/anisotropic) + * @tparam qp_type Quadrature points type for the boundary condition + * (compile/run time) + */ +template +class stacey { + +public: + /** + * @name Typedefs + * + */ + ///@{ + /** + * @brief Medium type of the boundary. + * + */ + using medium_type = specfem::enums::element::medium::elastic; + /** + * @brief Dimension of the boundary. + * + */ + using dimension = specfem::enums::element::dimension::dim2; + /** + * @brief Quadrature points object to define the quadrature points either at + * compile time or run time. + * + */ + using quadrature_points_type = qp_type; + /** + * @brief Property type of the boundary. + * + */ + using property_type = property; + ///@} + + constexpr static specfem::enums::element::boundary_tag value = + specfem::enums::element::boundary_tag::stacey; ///< boundary tag + + /** + * @brief Construct a new stacey object + * + */ + stacey(){}; + + /** + * @brief Construct a new stacey object + * + * @param quadrature_points Quadrature points object + * @param type Type of the boundary + */ + stacey(const quadrature_points_type &quadrature_points, + const specfem::kokkos::DeviceView1d< + specfem::compute::access::boundary_types> &type) + : quadrature_points(quadrature_points), type(type) {} + + /** + * @brief Construct a new stacey object + * + * @param boundary_conditions boundary conditions object specifying the + * boundary conditions + * @param quadrature_points Quadrature points object + */ + stacey(const specfem::compute::boundaries &boundary_conditions, + const quadrature_points_type &quadrature_points); + + /** + * @brief Compute the mass time contribution for the boundary condition + * + * @tparam time_scheme Time scheme to use when computing the mass time + * contribution + * @param ielement index of the element + * @param xz index of the quadrature point + * @param dt time step + * @param weight weights(x,z) for the quadrature point + * @param partial_derivatives partial derivatives of the shape functions + * @param properties properties of the element at the quadrature point + * @param mass_matrix mass matrix to update + */ + template + KOKKOS_INLINE_FUNCTION void mass_time_contribution( + const int &ielement, const int &xz, const type_real &dt, + const specfem::kokkos::array_type &weight, + const specfem::compute::element_partial_derivatives &partial_derivatives, + const specfem::compute::element_properties< + medium_type::value, property_type::value> &properties, + specfem::kokkos::array_type + &mass_matrix) const; + + /** + * @brief Compute the contribuition of BC to the gradient term + * + * @param ielement index of the element + * @param xz index of the quadrature point + * @param partial_derivatives spacial derivatives at the quadrature point + * @param df_dx Gradient of field in x-direction to update + * @param df_dz Gradient of field in z-direction to update + */ + KOKKOS_INLINE_FUNCTION + void enforce_gradient( + const int &ielement, const int &xz, + const specfem::compute::element_partial_derivatives &partial_derivatives, + specfem::kokkos::array_type &df_dx, + specfem::kokkos::array_type &df_dz) + const {}; + + /** + * @brief Compute the contribution of BC to the stress term + * + * @param ielement index of the element + * @param xz index of the quadrature point + * @param partial_derivatives spacial derivatives at the quadrature point + * @param properties properties of the element at the quadrature point + * @param stress_integrand_xi /f$ \sigma_{\xi} /f$ to update + * @param stress_integrand_xgamma /f$ \sigma_{\gamma} /f$ to update + * @return KOKKOS_INLINE_FUNCTION + */ + KOKKOS_INLINE_FUNCTION void enforce_stress( + const int &ielement, const int &xz, + const specfem::compute::element_partial_derivatives &partial_derivatives, + const specfem::compute::element_properties< + medium_type::value, property_type::value> &properties, + specfem::kokkos::array_type + &stress_integrand_xi, + specfem::kokkos::array_type + &stress_integrand_xgamma) const {}; + + /** + * @brief Compute the contribution of BC to the traction term + * + * @param ielement index of the element + * @param xz index of the quadrature point + * @param weight weights(x,z) for the quadrature point + * @param partial_derivatives partial derivatives of the shape functions + * @param properties properties of the element at the quadrature point + * @param velocity first derivative of the field computed from previous time + * step + * @param accelation second derivative of the field to update + * @return KOKKOS_INLINE_FUNCTION + */ + KOKKOS_INLINE_FUNCTION void enforce_traction( + const int &ielement, const int &xz, + const specfem::kokkos::array_type &weight, + const specfem::compute::element_partial_derivatives &partial_derivatives, + const specfem::compute::element_properties< + medium_type::value, property_type::value> &properties, + const specfem::kokkos::array_type + &velocity, + specfem::kokkos::array_type + &accelation) const; + + /** + * @brief Convert Stacey BC to string + * + * @return std::string String representation of the boundary condition + */ + inline static std::string to_string() { return "Stacey"; } + +private: + quadrature_points_type quadrature_points; ///< Quadrature points object. + specfem::kokkos::DeviceView1d + type; ///< type of the edge on an element on the boundary. +}; +} // namespace boundary_conditions +} // namespace enums +} // namespace specfem + +#endif // _ENUMS_BOUNDARY_CONDITIONS_STACEY2D_ELASTIC_HPP_ diff --git a/include/enumerations/boundary_conditions/stacey/stacey2d_elastic.tpp b/include/enumerations/boundary_conditions/stacey/stacey2d_elastic.tpp new file mode 100644 index 00000000..73d90344 --- /dev/null +++ b/include/enumerations/boundary_conditions/stacey/stacey2d_elastic.tpp @@ -0,0 +1,237 @@ +#ifndef _ENUMS_BOUNDARY_CONDITIONS_STACEY2D_ELASTIC_TPP_ +#define _ENUMS_BOUNDARY_CONDITIONS_STACEY2D_ELASTIC_TPP_ + +#include "compute/interface.hpp" +#include "enumerations/dimension.hpp" +#include "enumerations/medium.hpp" +#include "enumerations/quadrature.hpp" +#include "enumerations/specfem_enums.hpp" +#include "kokkos_abstractions.h" +#include "stacey2d_elastic.hpp" +#include + +namespace { +KOKKOS_FUNCTION void enforce_traction_boundary( + const type_real &weight, + const specfem::kokkos::array_type &dn, + const specfem::compute::element_properties< + specfem::enums::element::type::elastic, + specfem::enums::element::property_tag::isotropic> &properties, + const specfem::kokkos::array_type &field_dot, + specfem::kokkos::array_type &field_dot_dot) { + + auto jacobian1d = dn.l2_norm(); + + auto vn = specfem::kokkos::array_type::dot(dn, field_dot); + + specfem::kokkos::array_type traction; + +#ifdef KOKKOS_ENABLE_CUDA +#pragma unroll +#endif + for (int icomp = 0; icomp < 2; ++icomp) + traction[icomp] = ((vn * dn[icomp] / (jacobian1d * jacobian1d)) * + (properties.rho_vp - properties.rho_vs)) + + field_dot[icomp] * properties.rho_vs; + + field_dot_dot[0] += -1.0 * traction[0] * jacobian1d * weight; + field_dot_dot[1] += -1.0 * traction[1] * jacobian1d * weight; + + return; +} + +template +KOKKOS_FUNCTION void newmark_mass_terms( + const int &ix, const int &iz, const int &ngllx, const int &ngllz, + const type_real &dt, const specfem::compute::access::boundary_types &itype, + const specfem::enums::element::boundary_tag &tag, + const specfem::kokkos::array_type &weight, + const specfem::compute::element_partial_derivatives &partial_derivatives, + const specfem::compute::element_properties< + specfem::enums::element::type::elastic, property> &properties, + specfem::kokkos::array_type &rmass_inverse) { + + specfem::kokkos::array_type velocity; + + velocity[0] = -1.0 * dt * 0.5; + velocity[1] = -1.0 * dt * 0.5; + + specfem::kokkos::array_type dn; + + // Left Boundary + if (itype.left == tag && ix == 0) { + dn = partial_derivatives + .compute_normal(); + enforce_traction_boundary(weight[1], dn, properties, velocity, + rmass_inverse); + return; + } + + // Right Boundary + if (itype.right == tag && ix == ngllx - 1) { + dn = partial_derivatives + .compute_normal(); + enforce_traction_boundary(weight[1], dn, properties, velocity, + rmass_inverse); + return; + } + + // Top Boundary + if (itype.top == tag && iz == ngllz - 1) { + dn = partial_derivatives + .compute_normal(); + enforce_traction_boundary(weight[0], dn, properties, velocity, + rmass_inverse); + return; + } + + // Bottom Boundary + if (itype.bottom == tag && iz == 0) { + dn = partial_derivatives + .compute_normal(); + enforce_traction_boundary(weight[0], dn, properties, velocity, + rmass_inverse); + return; + } + + return; +} +} // namespace + +template +specfem::enums::boundary_conditions::stacey< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::elastic, property, + qp_type>::stacey(const specfem::compute::boundaries &boundary_conditions, + const quadrature_points_type &quadrature_points) + : quadrature_points(quadrature_points), + type(boundary_conditions.stacey.elastic.type) { + return; +} + +template +template +KOKKOS_INLINE_FUNCTION void specfem::enums::boundary_conditions::stacey< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::elastic, property, qp_type>:: + mass_time_contribution( + const int &ielement, const int &xz, const type_real &dt, + const specfem::kokkos::array_type &weight, + const specfem::compute::element_partial_derivatives + &partial_derivatives, + const specfem::compute::element_properties< + specfem::enums::element::type::elastic, property_type::value> + &properties, + specfem::kokkos::array_type + &rmass_inverse) const { + + // Check if the GLL point is on the boundary + //-------------------------------------------------------------------------- + constexpr int components = 2; + constexpr auto value_t = value; + + int ngllx, ngllz; + + quadrature_points.get_ngll(&ngllx, &ngllz); + + int ix, iz; + sub2ind(xz, ngllx, iz, ix); + + const auto itype = this->type(ielement); + if (!specfem::compute::access::is_on_boundary(value_t, itype, iz, ix, ngllz, ngllx)) { + return; + } + //-------------------------------------------------------------------------- + + if constexpr (time_scheme == specfem::enums::time_scheme::type::newmark) { + newmark_mass_terms(ix, iz, ngllx, ngllz, dt, itype, value_t, weight, + partial_derivatives, properties, rmass_inverse); + return; + } + + return; +} + +template +KOKKOS_INLINE_FUNCTION void specfem::enums::boundary_conditions::stacey< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::elastic, property, qp_type>:: + enforce_traction( + const int &ielement, const int &xz, + const specfem::kokkos::array_type &weight, + const specfem::compute::element_partial_derivatives + &partial_derivatives, + const specfem::compute::element_properties< + specfem::enums::element::type::elastic, property_type::value> + &properties, + const specfem::kokkos::array_type &field_dot, + specfem::kokkos::array_type &field_dot_dot) const { + + // Check if the GLL point is on the boundary + //-------------------------------------------------------------------------- + constexpr int components = 2; + constexpr auto value_t = value; + + int ngllx, ngllz; + + quadrature_points.get_ngll(&ngllx, &ngllz); + + int ix, iz; + sub2ind(xz, ngllx, iz, ix); + + const auto itype = this->type(ielement); + if (!specfem::compute::access::is_on_boundary(value_t, itype, iz, ix, + ngllz, ngllx)) { + return; + } + //-------------------------------------------------------------------------- + + // enforce traction condition + // -------------------------------------------------------------------------- + // If the GLL point is on the corner the left or right traction conditions are + // applied top or bottom traction conditions are ignored in this case. This + // ensures there is no conflict in calculating the normal + + specfem::kokkos::array_type dn; + + // Left Boundary + if (itype.left == value_t && ix == 0) { + dn = partial_derivatives + .compute_normal(); + enforce_traction_boundary(weight[1], dn, properties, field_dot, + field_dot_dot); + return; + } + + // Right Boundary + if (itype.right == value_t && ix == ngllx - 1) { + dn = partial_derivatives + .compute_normal(); + enforce_traction_boundary(weight[1], dn, properties, field_dot, + field_dot_dot); + return; + } + + // Top Boundary + if (itype.top == value_t && iz == ngllz - 1) { + dn = partial_derivatives + .compute_normal(); + enforce_traction_boundary(weight[0], dn, properties, field_dot, + field_dot_dot); + return; + } + + // Bottom Boundary + if (itype.bottom == value_t && iz == 0) { + dn = partial_derivatives + .compute_normal(); + enforce_traction_boundary(weight[0], dn, properties, field_dot, + field_dot_dot); + return; + } + // -------------------------------------------------------------------------- + + return; +} + +#endif /* _ENUMS_BOUNDARY_CONDITIONS_STACEY2D_ELASTIC_TPP_ */ diff --git a/include/enumerations/dimension.hpp b/include/enumerations/dimension.hpp new file mode 100644 index 00000000..8e75b52c --- /dev/null +++ b/include/enumerations/dimension.hpp @@ -0,0 +1,47 @@ +#ifndef _ENUMERATIONS_DIMENSION_HPP_ +#define _ENUMERATIONS_DIMENSION_HPP_ + +#include "specfem_enums.hpp" + +namespace specfem { +namespace enums { +namespace element { +/** + * @namespace dimensionality property of the element + * + */ +namespace dimension { +/** + * @brief 2D element + * + */ +class dim2 { +public: + constexpr static int dim = 2; ///< Dimensionality of the element + + /** + * @brief Convert the dimension to a string + * + */ + __inline__ static std::string to_string() { return "2D"; } +}; +/** + * @brief 3D element + * + */ +class dim3 { +public: + constexpr static int dim = 3; ///< Dimensionality of the element + + /** + * @brief Convert the dimension to a string + * + */ + __inline__ static std::string to_string() { return "3D"; } +}; +} // namespace dimension +} // namespace element +} // namespace enums +} // namespace specfem + +#endif /* _ENUMERATIONS_DIMENSION_HPP_ */ diff --git a/include/enumerations/interface.hpp b/include/enumerations/interface.hpp new file mode 100644 index 00000000..0d31f52a --- /dev/null +++ b/include/enumerations/interface.hpp @@ -0,0 +1,11 @@ +#ifndef _ENUMERATIONS_INTERFACE_HPP_ +#define _ENUMERATIONS_INTERFACE_HPP_ + +#include "boundary_conditions/interface.hpp" +#include "dimension.hpp" +#include "medium.hpp" +#include "properties.hpp" +#include "quadrature.hpp" +#include "specfem_enums.hpp" + +#endif /* _ENUMERATIONS_INTERFACE_HPP_ */ diff --git a/include/enumerations/medium.hpp b/include/enumerations/medium.hpp new file mode 100644 index 00000000..616cc405 --- /dev/null +++ b/include/enumerations/medium.hpp @@ -0,0 +1,70 @@ +#ifndef _ENUMERATIONS_MEDIUM_HPP_ +#define _ENUMERATIONS_MEDIUM_HPP_ + +#include "specfem_enums.hpp" + +namespace specfem { +namespace enums { +namespace element { + +/** + * @namespace medium property of the element + * + */ +namespace medium { +/** + * @brief Elastic medium + * + */ +class elastic { +public: + /** + * @brief constexpr defining the type of the element + * + */ + constexpr static specfem::enums::element::type value = + specfem::enums::element::type::elastic; + /** + * @brief Number of components for this medium + * + */ + constexpr static int components = 2; + + /** + * @brief Convert the medium to a string + * + */ + __inline__ static std::string to_string() { return "Elastic"; } +}; + +/** + * @brief Acoustic medium + * + */ +class acoustic { +public: + /** + * @brief constexpr defining the type of the element + * + */ + constexpr static specfem::enums::element::type value = + specfem::enums::element::type::acoustic; + /** + * @brief constexpr defining number of components for this medium. + * + */ + constexpr static int components = 1; + + /** + * @brief Convert the medium to a string + * + */ + __inline__ static std::string to_string() { return "Acoustic"; } +}; + +} // namespace medium +} // namespace element +} // namespace enums +} // namespace specfem + +#endif /* _ENUMERATIONS_MEDIUM_HPP_ */ diff --git a/include/enumerations/properties.hpp b/include/enumerations/properties.hpp new file mode 100644 index 00000000..81c2bf9f --- /dev/null +++ b/include/enumerations/properties.hpp @@ -0,0 +1,36 @@ +#ifndef _ENUMERATIONS_PROPERTIES_HPP_ +#define _ENUMERATIONS_PROPERTIES_HPP_ + +#include "specfem_enums.hpp" + +namespace specfem { +namespace enums { +namespace element { +/** + * @namespace Elemental properties + * + * Properties can be utilized to distinguish elements based on physics or to + * optimize kernel calculations for specific elements. + */ +namespace property { +/** + * @brief Isotropic element + * + */ +class isotropic { +public: + constexpr static specfem::enums::element::property_tag value = + specfem::enums::element::property_tag::isotropic; + + /** + * @brief Convert the property to a string + * + */ + __inline__ static std::string to_string() { return "Isotropic"; } +}; +} // namespace property +} // namespace element +} // namespace enums +} // namespace specfem + +#endif /* _ENUMERATIONS_PROPERTIES_HPP_ */ diff --git a/include/enumerations/quadrature.hpp b/include/enumerations/quadrature.hpp new file mode 100644 index 00000000..7319204e --- /dev/null +++ b/include/enumerations/quadrature.hpp @@ -0,0 +1,267 @@ +#ifndef _ENUMERATIONS_QUADRATURE_HPP_ +#define _ENUMERATIONS_QUADRATURE_HPP_ + +#include "kokkos_abstractions.h" +#include "specfem_enums.hpp" +#include + +namespace specfem { +namespace enums { +namespace element { +/** + * @namespace number of quadrature points defined either at compile time or at + * runtime + * + */ +namespace quadrature { + +/** + * @brief define the number of quadrature points at runtime + * + */ +class dynamic_quadrature_points { +public: + int ngllx; ///< number of quadrature points in the x direction + int ngllz; ///< number of quadrature points in the z direction + + /** + * @brief Scratch memory space. Shared memory for GPUs and thread local memory + * for CPUs. + * + */ + using scratch_memory_space = + specfem::kokkos::DevExecSpace::scratch_memory_space; + + /** + * @brief Team member type. See Kokkos TeamHandle documentation for more + * details. + * + */ + using member_type = specfem::kokkos::DeviceTeam::member_type; + + /** + * @brief Scratch view type + * + * For dynamic quadrature points, the scratch view type is a 2D dynamic view + * stored on scratch space. + * + * @tparam T Type of the scratch view + * @tparam N Number of components + */ + template + using ScratchViewType = + Kokkos::View >; + + /** + * @brief Deleted default constructor + * + */ + dynamic_quadrature_points() = delete; + + /** + * @brief Construct a new dynamic quadrature points object + * + * @param ngllz Number of quadrature points in the z direction + * @param ngllx Number of quadrature points in the x direction + */ + dynamic_quadrature_points(const int &ngllz, const int &ngllx) + : ngllx(ngllx), ngllz(ngllz){}; + + /** + * @brief Destroy the dynamic quadrature points object + * + */ + ~dynamic_quadrature_points() = default; + + /** + * @brief Get the required size of the scratch memory space for a given type T + * and axes ax1 and ax2 + * + * @tparam T Tyoe of the scratch view + * @tparam ax1 Axis 1 + * @tparam ax2 Axis 2 + * @return std::size_t Size of the scratch memory space + */ + template + std::size_t shmem_size() const { + if constexpr (ax1 == specfem::enums::axes::x && + ax2 == specfem::enums::axes::x) { + return ScratchViewType::shmem_size(this->ngllx, this->ngllx); + } else if constexpr (ax1 == specfem::enums::axes::z && + ax2 == specfem::enums::axes::z) { + return ScratchViewType::shmem_size(this->ngllz, this->ngllz); + } else { + return ScratchViewType::shmem_size(this->ngllz, this->ngllx); + } + } + + /** + * @brief Get the scratch view for a given type T and axes ax1 and ax2 + * + * @tparam T Type of the scratch view + * @tparam ax1 Axis 1 + * @tparam ax2 Axis 2 + * @param ptr Address in the scratch memory space to allocate the scratch view + * @return ScratchViewType Scratch view allocated at the address ptr + */ + template + KOKKOS_INLINE_FUNCTION ScratchViewType + ScratchView(scratch_memory_space &ptr) const { + if constexpr (ax1 == specfem::enums::axes::x && + ax2 == specfem::enums::axes::x) { + return ScratchViewType(ptr, this->ngllx, this->ngllx); + } else if constexpr (ax1 == specfem::enums::axes::z && + ax2 == specfem::enums::axes::z) { + return ScratchViewType(ptr, this->ngllz, this->ngllz); + } else { + return ScratchViewType(ptr, this->ngllz, this->ngllx); + } + }; + + /** + * @brief Get the team thread range for a given axes ax1 and ax2 + * + * @tparam ax1 Axis 1 + * @tparam ax2 Axis 2 + * @param team_member Team member + * @return Kokkos::TeamThreadRange Team thread range + */ + template + KOKKOS_INLINE_FUNCTION auto + TeamThreadRange(const member_type &team_member) const { + if constexpr (ax1 == specfem::enums::axes::x && + ax2 == specfem::enums::axes::x) { + return Kokkos::TeamThreadRange(team_member, ngllx * ngllx); + } else if constexpr (ax1 == specfem::enums::axes::z && + ax2 == specfem::enums::axes::z) { + return Kokkos::TeamThreadRange(team_member, ngllz * ngllz); + } else { + return Kokkos::TeamThreadRange(team_member, ngllz * ngllx); + } + } + + /** + * @brief Get the number of quadrature points in the x and z directions + * + * @param ngllx Number of quadrature points in the x direction + * @param ngllz Number of quadrature points in the z direction + */ + KOKKOS_INLINE_FUNCTION void get_ngll(int *ngllx, int *ngllz) const { + *ngllx = this->ngllx; + *ngllz = this->ngllz; + } +}; + +/** + * @brief define the number of quadrature points at compile time + * + * @tparam NGLL Number of quadrature points + */ +template class static_quadrature_points { + +public: + /** + * @brief Scratch memory space type + * + */ + using scratch_memory_space = + specfem::kokkos::DevExecSpace::scratch_memory_space; + + /** + * @brief Team member type. See kokkos TeamHandle documentation for more + * details. + * + */ + using member_type = specfem::kokkos::DeviceTeam::member_type; + + /** + * @brief Scratch view type for a given type T. + * + * For static quadrature points, the scratch view is a 2D view of size NGLL x + * NGLL defined at compile time. + * + * @tparam T Type of the scratch view + * @tparam N Number of components + */ + template + using ScratchViewType = + specfem::kokkos::StaticDeviceScratchView3d; + + /** + * @brief Construct a new static quadrature points object + * + */ + constexpr static_quadrature_points() = default; + /** + * @brief Destroy the static quadrature points object + * + */ + ~static_quadrature_points() = default; + + /** + * @brief Get the required size of the scratch memory space for a given type T + * and axes ax1 and ax2 + * + * @tparam T Type of the scratch view + * @tparam ax_1 Axis 1 + * @tparam ax_2 Axis 2 + * @return std::size_t Size of the scratch memory space + */ + template + std::size_t shmem_size() const { + return ScratchViewType::shmem_size(); + } + + /** + * @brief Get the scratch view for a given type T and axes ax1 and ax2 + * + * @tparam T Type of the scratch view + * @tparam ax_1 Axis 1 + * @tparam ax_2 Axis 2 + * @param ptr Address in the scratch memory space to allocate the scratch view + * @return ScratchViewType Scratch view allocated at the address ptr + */ + template + KOKKOS_INLINE_FUNCTION ScratchViewType + ScratchView(const scratch_memory_space &ptr) const { + return ScratchViewType(ptr); + } + + /** + * @brief Get the team thread range for a given axes ax1 and ax2 + * + * @tparam ax_1 Axis 1 + * @tparam ax_2 Axis 2 + * @param team_member Team member + * @return Kokkos::TeamThreadRange Team thread range + */ + template + KOKKOS_INLINE_FUNCTION auto + TeamThreadRange(const member_type &team_member) const { + return Kokkos::TeamThreadRange(team_member, NGLL * NGLL); + } + + /** + * @brief Get the number of quadrature points in the x and z directions + * + * @param ngllx Number of quadrature points in the x direction + * @param ngllz Number of quadrature points in the z direction + */ + KOKKOS_INLINE_FUNCTION constexpr void get_ngll(int *ngllx, int *ngllz) const { + *ngllx = NGLL; + *ngllz = NGLL; + } +}; + +} // namespace quadrature +} // namespace element +} // namespace enums +} // namespace specfem + +#endif /* _ENUMERATIONS_QUADRATURE_HPP_ */ diff --git a/include/enumerations/specfem_enums.hpp b/include/enumerations/specfem_enums.hpp new file mode 100644 index 00000000..1d1453d0 --- /dev/null +++ b/include/enumerations/specfem_enums.hpp @@ -0,0 +1,246 @@ +#ifndef _ENUMERATIONS_SPECFEM_ENUM_HPP_ +#define _ENUMERATIONS_SPECFEM_ENUM_HPP_ + +#include "kokkos_abstractions.h" +#include + +namespace specfem { +/** + * @namespace enums namespace is used to store enumerations. + * + */ +namespace enums { + +/** + * @brief Cartesian axes + * + */ +enum class axes { + x, ///< X axis + y, ///< Y axis + z ///< Z axis +}; + +namespace seismogram { +/** + * @brief type of seismogram + * + */ +enum class type { + displacement, ///< Displacement seismogram + velocity, ///< Velocity Seismogram + acceleration ///< Acceleration seismogram +}; + +/** + * @brief Output format of seismogram + * + */ +enum format { + seismic_unix, ///< Seismic unix output format + ascii ///< ASCII output format +}; + +} // namespace seismogram + +/** + * @namespace element namespace is used to store element properties used in the + * element class. + * + */ +namespace element { + +/** + * @brief type of element + * + * This is primarily used to label the element as elastic, acoustic or + * poroelastic. + * + */ +enum class type { + elastic, ///< elastic element + acoustic, ///< acoustic element + poroelastic ///< poroelastic element +}; + +enum class property_tag { + isotropic, ///< isotropic material +}; + +enum class boundary_tag { + // primary boundaries + none, ///< no boundary + acoustic_free_surface, ///< free surface boundary for acoustic elements + stacey, ///< stacey boundary for elements + + // composite boundaries + composite_stacey_dirichlet ///< composite boundary for acoustic elements +}; + +/** + * @brief Container class to store boundary tags + * + * + */ +class boundary_tag_container { +public: + /** + * @brief Get the tags object + * + * @return std::vector vector of boundary tags + */ + inline boundary_tag get_tag() const { return tag; } + + /** + * @brief Construct a new boundary tag container object + * + */ + boundary_tag_container(){}; + + /** + * @brief Construct a new boundary tag container object + * + * Please use operator+= to update the boundary tag container + * + * @param tag boundary tag + */ + boundary_tag_container &operator=(const boundary_tag &tag) = delete; + + /** + * @brief Update boundary tag container with new tag + * + * This function checks if a boundary can be of composite type and returns the + * correct tags + * + * @param rtag boundary tag to be added + */ + boundary_tag_container &operator+=(const boundary_tag &rtag) { + switch (rtag) { + case boundary_tag::none: + break; + case boundary_tag::acoustic_free_surface: + switch (this->tag) { + case boundary_tag::none: + this->tag = rtag; + break; + case boundary_tag::acoustic_free_surface: + case boundary_tag::composite_stacey_dirichlet: + break; + case boundary_tag::stacey: + this->tag = boundary_tag::composite_stacey_dirichlet; + break; + default: + throw std::runtime_error("Invalid boundary tag"); + break; + } + break; + case boundary_tag::stacey: + switch (this->tag) { + case boundary_tag::none: + this->tag = rtag; + break; + case boundary_tag::acoustic_free_surface: + this->tag = boundary_tag::composite_stacey_dirichlet; + break; + case boundary_tag::stacey: + case boundary_tag::composite_stacey_dirichlet: + break; + default: + throw std::runtime_error("Invalid boundary tag"); + break; + } + break; + case boundary_tag::composite_stacey_dirichlet: + switch (this->tag) { + case boundary_tag::none: + this->tag = rtag; + break; + case boundary_tag::acoustic_free_surface: + case boundary_tag::stacey: + case boundary_tag::composite_stacey_dirichlet: + break; + default: + throw std::runtime_error("Invalid boundary tag"); + break; + } + break; + default: + throw std::runtime_error("Invalid boundary tag"); + break; + } + + return *this; + } + + /** + * @brief Check if boundary tag container specifies a specific boundary tag + * + * This function checks if a boundary container specifies a specific boundary + * tag + * + * @param tag boundary tag to be checked + * @return bool true if boundary container specifies the boundary tag + */ + bool operator==(const boundary_tag &tag) const { return (tag == this->tag); } + +private: + boundary_tag tag = boundary_tag::none; ///< boundary tag +}; + +} // namespace element + +/** + * @namespace edge namespace is used to store enumerations used to describe the + * edges + * + */ +namespace edge { +/** + * @brief type of edge in the mesh + * + */ +enum type { + TOP, ///< Top edge + BOTTOM, ///< Bottom edge + LEFT, ///< Left edge + RIGHT ///< Right edge +}; + +constexpr int num_edges = 4; ///< Number of edges in the mesh +} // namespace edge + +/** + * @namespace boundaries enumeration namespace is used to store enumerations + * used to describe various parts of the boundaries in a mesh. + * + */ +namespace boundaries { +/** + * @brief type of the boundary (corner, edge) + * + */ +enum type { + TOP_LEFT, ///< Top left corner + TOP_RIGHT, ///< Top right corner + BOTTOM_LEFT, ///< Bottom left corner + BOTTOM_RIGHT, ///< Bottom right corner + TOP, ///< Top edge + LEFT, ///< Left edge + RIGHT, ///< Right edge + BOTTOM ///< Bottom edge +}; +} // namespace boundaries + +namespace time_scheme { +/** + * @brief type of time scheme + * + */ +enum class type { + newmark, ///< Newmark time scheme +}; +} // namespace time_scheme +} // namespace enums +} // namespace specfem + +#endif /* _ENUMERATIONS_SPECFEM_ENUM_HPP_ */ diff --git a/include/kokkos_abstractions.h b/include/kokkos_abstractions.h index 50d287a9..ea2164f0 100644 --- a/include/kokkos_abstractions.h +++ b/include/kokkos_abstractions.h @@ -15,6 +15,11 @@ enum kind { }; } // namespace sync +/** + * @namespace Defines views and execution policies used throughout the SPECFEM + * project + * + */ namespace kokkos { /** @name Execution Spaces */ @@ -48,6 +53,80 @@ using HostScratchSpace = HostExecSpace::scratch_memory_space; using DevScratchSpace = DevExecSpace::scratch_memory_space; ///@} +/** @name Static Device views + */ +///@{ +/** + * @tparam T view datatype + * @tparam N view size + * @tparam L view layout - default layout is LayoutRight + * @tparam Args - Args can be used to customize your views. These are passed + * directly to Kokkos::Views objects + * + * @code ... + * StridedCacheAlignedView1d = StaticDeviceView1d>(...) + * @endcode + */ +template +using StaticDeviceView1d = Kokkos::View; + +/** + * @tparam T view datatype + * @tparam N view size + * @tparam L view layout - default layout is LayoutRight + * @tparam Args - Args can be used to customize your views. These are passed + * directly to Kokkos::Views objects + */ +template +using StaticDeviceView2d = Kokkos::View; + +/** + * @tparam T view datatype + * @tparam N view size + * @tparam L view layout - default layout is LayoutRight + * @tparam Args - Args can be used to customize your views. These are passed + * directly to Kokkos::Views objects + */ +template +using StaticDeviceView3d = Kokkos::View; +///@} + +/** @name Static Host views + */ +///@{ + +/** + * @tparam T view datatype + * @tparam N view size + * @tparam L view layout - default layout is LayoutRight + * @tparam Args - Args can be used to customize your views. These are passed + * directly to Kokkos::Views objects + */ +template +using StaticHostView1d = Kokkos::View; + +/** + * @tparam T view datatype + * @tparam N view size + * @tparam L view layout - default layout is LayoutRight + * @tparam Args - Args can be used to customize your views. These are passed + * directly to Kokkos::Views objects + */ +template +using StaticHostView2d = Kokkos::View; + +/** + * @tparam T view datatype + * @tparam N view size + * @tparam L view layout - default layout is LayoutRight + * @tparam Args - Args can be used to customize your views. These are passed + * directly to Kokkos::Views objects + */ +template +using StaticHostView3d = Kokkos::View; +///@} + /** @name Device views */ ///@{ @@ -97,6 +176,16 @@ using DeviceView4d = Kokkos::View; */ template using DeviceView5d = Kokkos::View; +/** + * @brief 6d device view + * + * @tparam T view datatype + * @tparam L view layout - default layout is LayoutRight + * @tparam Args - Args can be used to customize your views. These are passed + * directly to Kokkos::Views objects + */ +template +using DeviceView6d = Kokkos::View; ///@} /** @name Host views @@ -255,6 +344,16 @@ using HostMirror4d = typename DeviceView4d::HostMirror; */ template using HostMirror5d = typename DeviceView5d::HostMirror; +/** + * @brief Host mirror of 6d device view + * + * @tparam T view datatype + * @tparam L view layout - default layout is LayoutRight + * @tparam Args - Args can be used to customize your views. These are passed + * directly to Kokkos::Views objects + */ +template +using HostMirror6d = typename DeviceView6d::HostMirror; ///@} // Scratch Views @@ -457,6 +556,193 @@ template using simd_type = Kokkos::Experimental::simd; +/** + * @brief Array to store temporary values when doing Kokkos reductions + * + * @tparam T array type + * @tparam N size of array + */ +template struct array_type { + T data[N]; ///< Data array + + /** + * @brief operator [] to access the data array + * + * @param i index + * @return T& reference to the data array + */ + KOKKOS_INLINE_FUNCTION T &operator[](const int &i) { return data[i]; } + + /** + * @brief operator [] to access the data array + * + * @param i index + * @return const T& reference to the data array + */ + KOKKOS_INLINE_FUNCTION const T &operator[](const int &i) const { + return data[i]; + } + + /** + * @brief operator += to add two arrays + * + * @param rhs right hand side array + * @return array_type& reference to the array + */ + KOKKOS_INLINE_FUNCTION array_type & + operator+=(const array_type &rhs) { +#ifdef KOKKOS_ENABLE_CUDA +#pragma unroll +#endif + for (int i = 0; i < N; i++) { + data[i] += rhs[i]; + } + return *this; + } + + /** + * @brief Initialize the array for sum reductions + * + */ + KOKKOS_INLINE_FUNCTION void init() { +#ifdef KOKKOS_ENABLE_CUDA +#pragma unroll +#endif + for (int i = 0; i < N; i++) { + data[i] = 0.0; + } + } + + // Default constructor + /** + * @brief Construct a new array type object + * + */ + KOKKOS_INLINE_FUNCTION array_type() { init(); } + + // Copy constructor + /** + * @brief Copy constructor + * + * @param other other array + */ + KOKKOS_INLINE_FUNCTION array_type(const array_type &other) { +#ifdef KOKKOS_ENABLE_CUDA +#pragma unroll +#endif + for (int i = 0; i < N; i++) { + data[i] = other[i]; + } + } + + KOKKOS_INLINE_FUNCTION type_real l2_norm() const { + type_real norm = 0.0; +#ifdef KOKKOS_ENABLE_CUDA +#pragma unroll +#endif + for (int i = 0; i < N; i++) { + norm += data[i] * data[i]; + } + return sqrt(norm); + } + + KOKKOS_INLINE_FUNCTION static type_real dot(const array_type &a, + const array_type &b) { + + type_real dot = 0.0; +#ifdef KOKKOS_ENABLE_CUDA +#pragma unroll +#endif + for (int i = 0; i < N; i++) { + dot += a[i] * b[i]; + } + return dot; + } +}; + +/** + * @name Custom reductions for Kokkos TeamThreadRange policies. + * + * These reductions are used in Kokkos nested policies. Kokkos required + * nested policy reductions to be reduced into scalar types. Use of these + * reduction policies would be appropriate when reductions need to be done into + * arrays - for example when computing seismograms (check + * domain.tpp::compute_seismograms() for examples on how to use this) + * + */ +///@{ +/** + * Sum reduction + * + * @tparam T Scalar Array types for reductions. Can be either :: + */ +template class Sum { +public: + // Required typedefs + /** + * @brief Check Kokkos custom reducers for more details + * (https://kokkos.github.io/kokkos-core-wiki/ProgrammingGuide/Custom-Reductions-Custom-Reducers.html) + * + */ + typedef T value_type; ///< Value type of reduction + typedef Sum reducer; ///< Required typedef for reduction + typedef Kokkos::View > + result_view_type; ///< Required typedef for reduction + + /** + * @brief Constructor + * + * @param value - reference to value to be reduced into + */ + KOKKOS_INLINE_FUNCTION Sum(value_type &value) : value(value) {} + + /** + * @brief init operator to initialize value to be reduced + * + * @param update value to be reduced into + * @return KOKKOS_INLINE_FUNCTION + */ + KOKKOS_INLINE_FUNCTION void init(value_type &update) const { update.init(); } + + /** + * @brief join operator to join values from different threads + * + * @param update value to be reduced into + * @param source value to be reduced from + */ + KOKKOS_INLINE_FUNCTION void join(value_type &update, + const value_type &source) const { + update += source; + } + + /** + * @brief reference operator to return reference to value to be reduced into + * + */ + KOKKOS_INLINE_FUNCTION value_type &reference() const { return value; } + + /** + * @brief view operator to return view of value to be reduced into + * + */ + KOKKOS_INLINE_FUNCTION result_view_type view() const { + return result_view_type(&value, 1); + } + + /** + * @brief references_scalar operator to return true if value to be reduced is + * a scalar type + * + */ + KOKKOS_INLINE_FUNCTION bool references_scalar() const { return true; } + +private: + value_type &value; ///< Reference to value to be reduced into +}; +///@} + } // namespace kokkos } // namespace specfem diff --git a/include/macros.hpp b/include/macros.hpp new file mode 100644 index 00000000..8f563ec5 --- /dev/null +++ b/include/macros.hpp @@ -0,0 +1,45 @@ +#ifndef MACROS_HPP +#define MACROS_HPP + +#ifndef NDEBUG +#define ASSERT(condition, message) \ + do { \ + if (!(condition)) { \ + std::cerr << "Assertion `" #condition "` failed in " << __FILE__ \ + << " line " << __LINE__ << ": " << message << std::endl; \ + std::terminate(); \ + } \ + } while (false) +#else // NDEBUG +#define ASSERT(condition, message) \ + do { \ + } while (false) +#endif + +#ifndef NDEBUG +#ifdef KOKKOS_ENABLE_CUDA +#define DEVICE_ASSERT(condition, message) \ + do { \ + if (!(condition)) { \ + printf("Assertion `%s` failed in %s line %d: %s\n", #condition, \ + __FILE__, __LINE__, message); \ + assert(false); \ + } \ + } while (false) +#else // KOKKOS_ENABLE_CUDA +#define DEVICE_ASSERT(condition, message) \ + do { \ + if (!(condition)) { \ + printf("Assertion `%s` failed in %s line %d: %s\n", #condition, \ + __FILE__, __LINE__, message); \ + std::terminate(); \ + } \ + } while (false) +#endif // KOKKOS_ENABLE_CUDA +#else // NDEBUG +#define DEVICE_ASSERT(condition, message) \ + do { \ + } while (false) +#endif // NDEBUG + +#endif /* MACROS_HPP */ diff --git a/include/material/acoustic_material.hpp b/include/material/acoustic_material.hpp index a6cccd4d..be443c6d 100644 --- a/include/material/acoustic_material.hpp +++ b/include/material/acoustic_material.hpp @@ -2,6 +2,7 @@ #define _ACOUSTIC_MATERIAL_HPP #include "constants.hpp" +#include "enumerations/specfem_enums.hpp" #include "material.hpp" #include "specfem_mpi/interface.hpp" #include "specfem_setup.hpp" @@ -11,6 +12,12 @@ namespace specfem { namespace material { +/** + * @brief Acoustic material class + * + * Defines the routines required to read and assign acoustic material properties + * to specfem mesh. + */ class acoustic_material : public material { public: /** @@ -19,14 +26,46 @@ class acoustic_material : public material { */ acoustic_material(); /** - * @brief Assign acoustic material values + * @brief Constructs a new acoustic material object + * @param density Density of the material + * @param cp Compressional wave speed + * @param Qkappa Kappa attenuation factor + * @param Qmu Mu attenuation factor + * @param compaction_grad compaction gradient * - * @param holder holder used to hold read values */ - void assign(utilities::input_holder &holder) override; + acoustic_material(const type_real &density, const type_real &cp, + const type_real &Qkappa, const type_real &Qmu, + const type_real &compaction_grad); + /** + * @brief ostream operator for acoustic material + * + * @param out Output stream + * @param h Acoustic material object + * @return std::ostream& Output stream + */ friend std::ostream &operator<<(std::ostream &out, const acoustic_material &h); - specfem::elements::type get_ispec_type() override { return ispec_type; }; + /** + * @brief Get the type of the material + * + * @return specfem::enums::element::type The type of the material + */ + specfem::enums::element::type get_ispec_type() const override { + return ispec_type; + }; + /** + * @brief Get private elastic material properties + * + * @return utilities::return_holder holder used to return elastic material + * properties + */ + utilities::return_holder get_properties() const override; + /** + * @brief Print material information to the console + * + * @return std::string String containing the material information + */ std::string print() const override; private: @@ -34,9 +73,22 @@ class acoustic_material : public material { * @brief Acoustic material properties * */ - type_real density, cs, cp, Qkappa, Qmu, compaction_grad, lambdaplus2mu, mu, - lambda, kappa, young, poisson; - specfem::elements::type ispec_type = specfem::elements::acoustic; + + ///@{ + type_real density; + type_real cp; + type_real Qkappa; + type_real Qmu; + type_real compaction_grad; + type_real lambdaplus2mu; + type_real lambda; + type_real kappa; + type_real young; + type_real poisson; + ///@} + specfem::enums::element::type ispec_type = + specfem::enums::element::type::acoustic; ///< Type or element == + ///< specfem::acoustic }; std::ostream &operator<<(std::ostream &out, diff --git a/include/material/elastic_material.hpp b/include/material/elastic_material.hpp index 6876ff3a..9d0a4865 100644 --- a/include/material/elastic_material.hpp +++ b/include/material/elastic_material.hpp @@ -2,6 +2,7 @@ #define _ELASTIC_MATERIAL_HPP #include "constants.hpp" +#include "enumerations/specfem_enums.hpp" #include "specfem_mpi/interface.hpp" #include "specfem_setup.hpp" #include "utilities/interface.hpp" @@ -24,11 +25,18 @@ class elastic_material : public material { */ elastic_material(); /** - * @brief Assign elastic material values + * @brief Construct a new elastic material object * - * @param holder holder used to hold read values + * @param density Density of the material + * @param cs Transverse wave speed + * @param cp Compressional wave speed + * @param Qkappa Kappa attenuation factor + * @param Qmu Mu attenuation factor + * @param compaction_grad compaction gradient */ - void assign(utilities::input_holder &holder) override; + elastic_material(const type_real &density, const type_real &cs, + const type_real &cp, const type_real &Qkappa, + const type_real &Qmu, const type_real &compaction_grad); /** * @brief User output * Prints the read material values and additional information on @@ -45,9 +53,15 @@ class elastic_material : public material { * @return utilities::return_holder holder used to return elastic material * properties */ - utilities::return_holder get_properties() override; - specfem::elements::type get_ispec_type() override { return ispec_type; }; - + utilities::return_holder get_properties() const override; + specfem::enums::element::type get_ispec_type() const override { + return ispec_type; + }; + /** + * @brief Print material information to the console + * + * @return std::string String containing the material information + */ std::string print() const override; private: @@ -69,8 +83,9 @@ class elastic_material : public material { type_real young; type_real poisson; ///@} - specfem::elements::type ispec_type = - specfem::elements::elastic; ///< Type or element == specfem::elastic + specfem::enums::element::type ispec_type = + specfem::enums::element::type::elastic; ///< Type or element == + ///< specfem::elastic }; std::ostream &operator<<(std::ostream &out, diff --git a/include/material/material.hpp b/include/material/material.hpp index dbcc7386..7ab4c2a6 100644 --- a/include/material/material.hpp +++ b/include/material/material.hpp @@ -2,6 +2,7 @@ #define _MATERIAL_HPP #include "constants.hpp" +#include "enumerations/specfem_enums.hpp" #include "specfem_mpi/interface.hpp" #include "specfem_setup.hpp" #include "utilities/interface.hpp" @@ -23,20 +24,30 @@ class material { */ material(){}; /** - * @brief Virtual function to assign values read from database file to - * material class members + * @brief Get the properties of the material * - * @param holder holder used to hold read values + * @return utilities::return_holder Struct containing the properties of the + * material */ - virtual void assign(utilities::input_holder &holder){}; - virtual utilities::return_holder get_properties() { + virtual utilities::return_holder get_properties() const { utilities::return_holder holder{}; return holder; }; - virtual specfem::elements::type get_ispec_type() { - return specfem::elements::elastic; + /** + * @brief Get the type of the material + * + * @return specfem::enums::element::type The type of the material + */ + virtual specfem::enums::element::type get_ispec_type() const { + throw std::runtime_error("Material is not assigned properly"); + return specfem::enums::element::type::elastic; }; + /** + * @brief Print material information to the console + * + * @return std::string String containing the material information + */ virtual std::string print() const { return ""; } }; diff --git a/include/mathematical_operators/interface.hpp b/include/mathematical_operators/interface.hpp deleted file mode 100644 index f68f09d6..00000000 --- a/include/mathematical_operators/interface.hpp +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _MATHEMATICAL_OPERATORS_INTERFACE_HPP -#define _MATHEMATICAL_OPERATORS_INTERFACE_HPP - -#include "mathematical_operators.hpp" -#include "mathematical_operators.tpp" - -#endif diff --git a/include/mathematical_operators/mathematical_operators.hpp b/include/mathematical_operators/mathematical_operators.hpp deleted file mode 100644 index 39008bc2..00000000 --- a/include/mathematical_operators/mathematical_operators.hpp +++ /dev/null @@ -1,223 +0,0 @@ -#ifndef _MATHEMATICAL_OPERATORS_HPP -#define _MATHEMATICAL_OPERATORS_HPP - -#include "kokkos_abstractions.h" -#include "specfem_setup.hpp" -#include - -namespace specfem { -namespace mathematical_operators { - -/** - * @brief Compute gradients of a 2D field within a spectral element - * - * This function is to used inside a team policy. It computes gradients of 2D - * field where is field has X and Z dimension, for example displacement field in - * Elastic domains. - * - * @todo Add example to how to use this function - * - * @param team_member Team handle to team policy of the calling team - * @param ispec spectral element number - * @param xix inverted partial derivates \f$\partial \xi / \partial x\f$ - * @param xiz inverted partial derivates \f$\partial \xi / \partial z\f$ - * @param gammax inverted partial derivates \f$\partial \gamma / \partial - * x\f$ - * @param gammaz inverted partial derivates \f$\partial \gamma / \partial - * z\f$ - * @param s_hprime_xx Derivatives of quadrature polynomials at quadrature - * points in X-dimension at every quadrature point within the ispec element. - * @param s_hprime_zz Derivatives of quadrature polynomials at quadrature - * points in Z-dimension at every quadrature point within the ispec element. - * @param field_x X component of field at every quadrature point within the - * ispec element - * @param field_z Z component of field at every quadrature point within the - * ispec element - * @param s_duxdx \f$\partial u_x / \partial x\f$ component of field at - * every quadrature point within the ispec element - * @param s_duxdz \f$\partial u_x / \partial z\f$ component of field at - * every quadrature point within the ispec element - * @param s_duzdx \f$\partial u_z / \partial x\f$ component of field at - * every quadrature point within the ispec element - * @param s_duzdz \f$\partial u_z / \partial z\f$ component of field at - * every quadrature point within the ispec element - */ -KOKKOS_FUNCTION void compute_gradients_2D( - const specfem::kokkos::DeviceTeam::member_type &team_member, - const int ispec, const specfem::kokkos::DeviceView3d xix, - const specfem::kokkos::DeviceView3d xiz, - const specfem::kokkos::DeviceView3d gammax, - const specfem::kokkos::DeviceView3d gammaz, - const specfem::kokkos::DeviceScratchView2d s_hprime_xx, - const specfem::kokkos::DeviceScratchView2d s_hprime_zz, - const specfem::kokkos::DeviceScratchView2d field_x, - const specfem::kokkos::DeviceScratchView2d field_z, - specfem::kokkos::DeviceScratchView2d s_duxdx, - specfem::kokkos::DeviceScratchView2d s_duxdz, - specfem::kokkos::DeviceScratchView2d s_duzdx, - specfem::kokkos::DeviceScratchView2d s_duzdz); - -/** - * @brief Compute gradients of a 2D field within a spectral element - * - * This function is to used inside a team policy. It computes gradients of 2D - * field where is field has X and Z dimension, for example displacement field in - * Elastic domains. - * - * @todo Add example to how to use this function - * @note This is specialized kernel when NGLL is known at compile time and NGLLX - * == NGLLZ. This is significantly faster ~10X faster than the kernel where NGLL - * is defined at runtime. - * - * @param team_member Team handle to team policy of the calling team - * @param ispec spectral element number - * @param xix inverted partial derivates \f$\partial \xi / \partial x\f$ - * @param xiz inverted partial derivates \f$\partial \xi / \partial z\f$ - * @param gammax inverted partial derivates \f$\partial \gamma / \partial - * x\f$ - * @param gammaz inverted partial derivates \f$\partial \gamma / \partial - * z\f$ - * @param s_hprime_xx Derivatives of quadrature polynomials at quadrature - * points in X-dimension at every quadrature point within the ispec element. - * @param s_hprime_zz Derivatives of quadrature polynomials at quadrature - * points in Z-dimension at every quadrature point within the ispec element. - * @param field_x X component of field at every quadrature point within the - * ispec element - * @param field_z Z component of field at every quadrature point within the - * ispec element - * @param s_duxdx \f$\partial u_x / \partial x\f$ component of field at - * every quadrature point within the ispec element - * @param s_duxdz \f$\partial u_x / \partial z\f$ component of field at - * every quadrature point within the ispec element - * @param s_duzdx \f$\partial u_z / \partial x\f$ component of field at - * every quadrature point within the ispec element - * @param s_duzdz \f$\partial u_z / \partial z\f$ component of field at - * every quadrature point within the ispec element - */ -template -KOKKOS_FUNCTION void compute_gradients_2D( - const specfem::kokkos::DeviceTeam::member_type &team_member, - const int ispec, const specfem::kokkos::DeviceView3d xix, - const specfem::kokkos::DeviceView3d xiz, - const specfem::kokkos::DeviceView3d gammax, - const specfem::kokkos::DeviceView3d gammaz, - const specfem::kokkos::StaticDeviceScratchView2d - s_hprime_xx, - const specfem::kokkos::StaticDeviceScratchView2d - s_hprime_zz, - const specfem::kokkos::StaticDeviceScratchView2d - field_x, - const specfem::kokkos::StaticDeviceScratchView2d - field_z, - specfem::kokkos::StaticDeviceScratchView2d s_duxdx, - specfem::kokkos::StaticDeviceScratchView2d s_duxdz, - specfem::kokkos::StaticDeviceScratchView2d s_duzdx, - specfem::kokkos::StaticDeviceScratchView2d s_duzdz); - -/** - * @brief Compute and contributions of stress integrands in 2D. - * - * This function is to used inside a team policy. It computes gradients the - * integrals given stress integrands and add them to second derivative of field. - * - * @param team_member Team handle to team policy of the calling team - * @param wxgll Quadrature weights in X-dimension - * @param wzgll Quadrature weights in Z-dimension - * @param s_hprimewgll_xx `s_hprimewgll_xx(iz, ix) = hprime_xx(iz, ix) - * wxgll(iz)` where h_primexx is the derivative of quadrature polynomials at - * quadrature points in X-dimension at every quadrature point within the ispec - * element. - * @param s_hprimewgll_zz `s_hprimewgll_zz(iz, ix) = hprime_zz(iz, ix) - * wzgll(iz)` where h_primexx is the derivative of quadrature polynomials at - * quadrature points in Z-dimension at every quadrature point within the ispec - * element. - * @param s_iglob 2 dimensional ScratchView used to store global numbering - * for every quadrature point within the ispec element - * @param stress_integrand_1 value of jacobian * (sigma_xx * xix + - * sigma_xz * xiz) evaluated at every quadrature point within the ispec - * element - * @param stress_integrand_2 value of `jacobian * (sigma_xz * xix + - * sigma_zz * xiz)` evaluated at every quadrature point within the ispec - * element - * @param stress_integrand_3 value of `jacobian * (sigma_xx * gammax + - * sigma_xz * gammaz)` evaluated at every quadrature point within the - * ispec element - * @param stress_integrand_4 value of `jacobian * (sigma_xz * gammax + - * sigma_zz * gammaz)` evaluated at every quadrature point within the - * ispec element - * @param field_dot_dot Second derivative of field to update - */ -KOKKOS_FUNCTION void add_contributions( - const specfem::kokkos::DeviceTeam::member_type &team_member, - const specfem::kokkos::DeviceView1d wxgll, - const specfem::kokkos::DeviceView1d wzgll, - const specfem::kokkos::DeviceScratchView2d s_hprimewgll_xx, - const specfem::kokkos::DeviceScratchView2d s_hprimewgll_zz, - const specfem::kokkos::DeviceScratchView2d s_iglob, - const specfem::kokkos::DeviceScratchView2d stress_integrand_1, - const specfem::kokkos::DeviceScratchView2d stress_integrand_2, - const specfem::kokkos::DeviceScratchView2d stress_integrand_3, - const specfem::kokkos::DeviceScratchView2d stress_integrand_4, - specfem::kokkos::DeviceView2d field_dot_dot); - -/** - * @brief Compute and contributions of stress integrands in 2D. - * - * This function is to used inside a team policy. It computes gradients the - * integrals given stress integrands and add them to second derivative of field. - * - * @note This is specialized kernel when NGLL is known at compile time and NGLLX - * == NGLLZ. This is significantly faster ~10X faster than the kernel where NGLL - * is defined at runtime. - * - * @tparam Number of quadrature points in X and Z dimensions - * @param team_member Team handle to team policy of the calling team - * @param wxgll Quadrature weights in X-dimension - * @param wzgll Quadrature weights in Z-dimension - * @param s_hprimewgll_xx `s_hprimewgll_xx(iz, ix) = hprime_xx(iz, ix) - * wxgll(iz)` where h_primexx is the derivative of quadrature - * polynomials at quadrature points in X-dimension at every quadrature point - * within the ispec element. - * @param s_hprimewgll_zz `s_hprimewgll_zz(iz, ix) = hprime_zz(iz, ix) - * wzgll(iz)` where h_primexx is the derivative of quadrature - * polynomials at quadrature points in Z-dimension at every quadrature point - * within the ispec element. - * @param s_iglob 2 dimensional ScratchView used to store global numbering - * for every quadrature point within the ispec element - * @param stress_integrand_1 value of `jacobian * (sigma_xx * xix + - * sigma_xz * xiz)` evaluated at every quadrature point within the ispec - * element - * @param stress_integrand_2 value of `jacobian * (sigma_xz * xix + - * sigma_zz * xiz)` evaluated at every quadrature point within the ispec - * element - * @param stress_integrand_3 value of `jacobian * (sigma_xx * gammax + - * sigma_xz * gammaz)` evaluated at every quadrature point within the - * ispec element - * @param stress_integrand_4 value of `jacobian * (sigma_xz * gammax + - * sigma_zz * gammaz)` evaluated at every quadrature point within the - * ispec element - * @param field_dot_dot Second derivative of field to update - */ -template -KOKKOS_FUNCTION void add_contributions( - const specfem::kokkos::DeviceTeam::member_type &team_member, - const specfem::kokkos::DeviceView1d wxgll, - const specfem::kokkos::DeviceView1d wzgll, - const specfem::kokkos::StaticDeviceScratchView2d - s_hprimewgll_xx, - const specfem::kokkos::StaticDeviceScratchView2d - s_hprimewgll_zz, - const specfem::kokkos::StaticDeviceScratchView2d s_iglob, - const specfem::kokkos::StaticDeviceScratchView2d - stress_integrand_1, - const specfem::kokkos::StaticDeviceScratchView2d - stress_integrand_2, - const specfem::kokkos::StaticDeviceScratchView2d - stress_integrand_3, - const specfem::kokkos::StaticDeviceScratchView2d - stress_integrand_4, - specfem::kokkos::DeviceView2d field_dot_dot); -} // namespace mathematical_operators -} // namespace specfem - -#endif diff --git a/include/mathematical_operators/mathematical_operators.tpp b/include/mathematical_operators/mathematical_operators.tpp deleted file mode 100644 index e0de466e..00000000 --- a/include/mathematical_operators/mathematical_operators.tpp +++ /dev/null @@ -1,137 +0,0 @@ -#ifndef _MATHEMATICAL_OPERATORS_TPP -#define _MATHEMATICAL_OPERATORS_TPP - -#include "kokkos_abstractions.h" -#include "specfem_setup.hpp" -#include - -namespace specfem { -namespace mathematical_operators { - -template -KOKKOS_FUNCTION void compute_gradients_2D( - const specfem::kokkos::DeviceTeam::member_type &team_member, - const int ispec, const specfem::kokkos::DeviceView3d xix, - const specfem::kokkos::DeviceView3d xiz, - const specfem::kokkos::DeviceView3d gammax, - const specfem::kokkos::DeviceView3d gammaz, - const specfem::kokkos::StaticDeviceScratchView2d - s_hprime_xx, - const specfem::kokkos::StaticDeviceScratchView2d - s_hprime_zz, - const specfem::kokkos::StaticDeviceScratchView2d - field_x, - const specfem::kokkos::StaticDeviceScratchView2d - field_z, - specfem::kokkos::StaticDeviceScratchView2d s_duxdx, - specfem::kokkos::StaticDeviceScratchView2d s_duxdz, - specfem::kokkos::StaticDeviceScratchView2d s_duzdx, - specfem::kokkos::StaticDeviceScratchView2d s_duzdz) { - - const int NGLL2 = NGLL * NGLL; - assert(xix.extent(1) == NGLL); - assert(xix.extent(2) == NGLL); - assert(xiz.extent(1) == NGLL); - assert(xiz.extent(2) == NGLL); - assert(gammax.extent(1) == NGLL); - assert(gammax.extent(2) == NGLL); - assert(gammaz.extent(1) == NGLL); - assert(gammaz.extent(2) == NGLL); - - const type_real NGLL_INV = 1.0 / NGLL; - - Kokkos::parallel_for( - Kokkos::TeamThreadRange(team_member, NGLL2), [&](const int xz) { - const int iz = xz * NGLL_INV; - const int ix = xz - iz * NGLL; - - const type_real xixl = xix(ispec, iz, ix); - const type_real xizl = xiz(ispec, iz, ix); - const type_real gammaxl = gammax(ispec, iz, ix); - const type_real gammazl = gammaz(ispec, iz, ix); - - type_real sum_hprime_x1 = 0.0; - type_real sum_hprime_x3 = 0.0; - type_real sum_hprime_z1 = 0.0; - type_real sum_hprime_z3 = 0.0; - - for (int l = 0; l < NGLL; l++) { - sum_hprime_x1 += s_hprime_xx(ix, l) * field_x(iz, l); - sum_hprime_x3 += s_hprime_xx(ix, l) * field_z(iz, l); - sum_hprime_z1 += s_hprime_zz(iz, l) * field_x(l, ix); - sum_hprime_z3 += s_hprime_zz(iz, l) * field_z(l, ix); - } - // duxdx - s_duxdx(iz, ix) = xixl * sum_hprime_x1 + gammaxl * sum_hprime_x3; - - // duxdz - s_duxdz(iz, ix) = xizl * sum_hprime_x1 + gammazl * sum_hprime_x3; - - // duzdx - s_duzdx(iz, ix) = xixl * sum_hprime_z1 + gammaxl * sum_hprime_z3; - - // duzdz - s_duzdz(iz, ix) = xizl * sum_hprime_z1 + gammazl * sum_hprime_z3; - }); - - return; -}; - -template -KOKKOS_FUNCTION void add_contributions( - const specfem::kokkos::DeviceTeam::member_type &team_member, - const specfem::kokkos::DeviceView1d wxgll, - const specfem::kokkos::DeviceView1d wzgll, - const specfem::kokkos::StaticDeviceScratchView2d - s_hprimewgll_xx, - const specfem::kokkos::StaticDeviceScratchView2d - s_hprimewgll_zz, - const specfem::kokkos::StaticDeviceScratchView2d s_iglob, - const specfem::kokkos::StaticDeviceScratchView2d - stress_integrand_1, - const specfem::kokkos::StaticDeviceScratchView2d - stress_integrand_2, - const specfem::kokkos::StaticDeviceScratchView2d - stress_integrand_3, - const specfem::kokkos::StaticDeviceScratchView2d - stress_integrand_4, - specfem::kokkos::DeviceView2d - field_dot_dot) { - - assert(wxgll.extent(0) == NGLL); - assert(wzgll.extent(0) == NGLL); - - constexpr int NGLL2 = NGLL * NGLL; - constexpr type_real NGLL_INV = 1.0 / NGLL; - - Kokkos::parallel_for( - Kokkos::TeamThreadRange(team_member, NGLL2), [&](const int xz) { - const int iz = xz * NGLL_INV; - const int ix = xz - iz * NGLL; - - type_real tempx1 = 0.0; - type_real tempz1 = 0.0; - type_real tempx3 = 0.0; - type_real tempz3 = 0.0; - -#pragma unroll - for (int l = 0; l < NGLL; l++) { - tempx1 += s_hprimewgll_xx(ix, l) * stress_integrand_1(iz, l); - tempz1 += s_hprimewgll_xx(ix, l) * stress_integrand_2(iz, l); - tempx3 += s_hprimewgll_zz(iz, l) * stress_integrand_3(l, ix); - tempz3 += s_hprimewgll_zz(iz, l) * stress_integrand_4(l, ix); - } - - const int iglob = s_iglob(iz, ix); - const type_real sum_terms1 = - -1.0 * (wzgll(iz) * tempx1) - (wxgll(ix) * tempx3); - const type_real sum_terms3 = - -1.0 * (wzgll(iz) * tempz1) - (wxgll(ix) * tempz3); - Kokkos::atomic_add(&field_dot_dot(iglob, 0), sum_terms1); - Kokkos::atomic_add(&field_dot_dot(iglob, 1), sum_terms3); - }); -} -} // namespace mathematical_operators -} // namespace specfem - -#endif diff --git a/include/mesh/IO/fortran/read_mesh_database.hpp b/include/mesh/IO/fortran/read_mesh_database.hpp index 2f91444b..282656d2 100644 --- a/include/mesh/IO/fortran/read_mesh_database.hpp +++ b/include/mesh/IO/fortran/read_mesh_database.hpp @@ -52,12 +52,6 @@ read_coorg_elements(std::ifstream &stream, const int npgeo, std::tuple read_mesh_database_attenuation(std::ifstream &stream, const specfem::MPI::MPI *mpi); - -void read_mesh_database_coupled(std::ifstream &stream, - const int num_fluid_solid_edges, - const int num_fluid_poro_edges, - const int num_solid_poro_edges, - const specfem::MPI::MPI *mpi); } // namespace fortran } // namespace IO } // namespace mesh diff --git a/include/mesh/boundaries/absorbing_boundaries.hpp b/include/mesh/boundaries/absorbing_boundaries.hpp index 77d82408..45d06143 100644 --- a/include/mesh/boundaries/absorbing_boundaries.hpp +++ b/include/mesh/boundaries/absorbing_boundaries.hpp @@ -1,6 +1,7 @@ #ifndef _ABSORBING_BOUNDARIES_HPP #define _ABSORBING_BOUNDARIES_HPP +#include "enumerations/specfem_enums.hpp" #include "kokkos_abstractions.h" #include "specfem_mpi/interface.hpp" @@ -14,107 +15,13 @@ namespace boundaries { */ struct absorbing_boundary { - specfem::kokkos::HostView1d numabs; ///< ispec value for the the element - ///< on the boundary + int nelements; ///< Number of elements on the absorbing boundary - specfem::kokkos::HostView1d abs_boundary_type; ///< Defines if the - ///< absorbing boundary - ///< type is top, left, - ///< right or bottom. This - ///< is only used during - ///< plotting + specfem::kokkos::HostView1d ispec; ///< ispec value for the the element + ///< on the boundary - /** - * @name Edge definitions - * - * ibegin_ defines the i or j index limits for loop iterations - * - */ - /// @{ - - /** - * @name Bottom boundary - */ - /// @{ - specfem::kokkos::HostView1d ibegin_edge1; - specfem::kokkos::HostView1d iend_edge1; - /// @} - - /** - * @name Right boundary - */ - /// @{ - specfem::kokkos::HostView1d ibegin_edge2; - specfem::kokkos::HostView1d iend_edge2; - /// @} - - /** - * @name Top boundary - */ - /// @{ - specfem::kokkos::HostView1d ibegin_edge3; - specfem::kokkos::HostView1d iend_edge3; - /// @} - - /** - * @name Left boundary - */ - /// @{ - specfem::kokkos::HostView1d ibegin_edge4; - specfem::kokkos::HostView1d iend_edge4; - /// @} - - /// @} - - /** - * @name Elements on boundary - * - * number of top/left/right/bottom elements on ith absorbing boundary - * - */ - ///@{ - specfem::kokkos::HostView1d ib_bottom; ///< Number of bottom elements on - ///< ith absorbing boundary - specfem::kokkos::HostView1d ib_top; ///< Number of top elemetns on the - ///< ith absobing boundary - specfem::kokkos::HostView1d ib_right; ///< Number of right elemetns on - ///< the ith absobing boundary - specfem::kokkos::HostView1d ib_left; ///< Number of left elemetns on the - ///< ith absobing boundary - ///@} - /** - * Specifies if an element is bottom, right, top or left absorbing boundary - * - * @code - * for elements on bottom boundary - * codeabs(i, 0) == true - * for elements on right boundary - * codeabs(i, 1) == true - * for elements on top boundary - * codeabs(i, 2) == true - * for elements on left boundary - * codeabs(i, 3) == true - *@endcode - * - */ - specfem::kokkos::HostView2d codeabs; - - /** - * Specifies if an element is bottom-left, bottom-right, top-left or top-right - * corner element - * - * @code - * for bottom-left boundary element - * codeabscorner(i, 0) == true - * for bottom-right boundary element - * codeabscorner(i, 1) == true - * for top-left boundary element - * codeabscorner(i, 2) == true - * for top-right boundary element - * codeabscorner(i, 3) == true - * @endcode - */ - specfem::kokkos::HostView2d codeabscorner; + specfem::kokkos::HostView1d + type; ///< Type of the boundary /** * @brief Default constructor diff --git a/include/mesh/boundaries/acoustic_free_surface.hpp b/include/mesh/boundaries/acoustic_free_surface.hpp new file mode 100644 index 00000000..2419636f --- /dev/null +++ b/include/mesh/boundaries/acoustic_free_surface.hpp @@ -0,0 +1,33 @@ +#ifndef _ACOUSTIC_FREE_SURFACE_HPP +#define _ACOUSTIC_FREE_SURFACE_HPP + +#include "enumerations/specfem_enums.hpp" +#include "kokkos_abstractions.h" +#include "specfem_mpi/interface.hpp" + +namespace specfem { +namespace mesh { +namespace boundaries { + +struct acoustic_free_surface { + acoustic_free_surface(){}; + acoustic_free_surface(const int nelem_acoustic_surface); + acoustic_free_surface(std::ifstream &stream, + const int &nelem_acoustic_surface, + const specfem::kokkos::HostView2d &knods, + const specfem::MPI::MPI *mpi); + + int nelem_acoustic_surface; ///< Number of elements on the acoustic free + ///< surface + specfem::kokkos::HostView1d ispec_acoustic_surface; ///< Number of + ///< elements on the + ///< acoustic free + ///< surface + specfem::kokkos::HostView1d + type; ///< Type of the boundary +}; +} // namespace boundaries +} // namespace mesh +} // namespace specfem + +#endif diff --git a/include/mesh/boundaries/boundaries.hpp b/include/mesh/boundaries/boundaries.hpp index 1e7b7a6b..01be9456 100644 --- a/include/mesh/boundaries/boundaries.hpp +++ b/include/mesh/boundaries/boundaries.hpp @@ -2,6 +2,7 @@ #define _BOUNDARIES_HPP #include "absorbing_boundaries.hpp" +#include "acoustic_free_surface.hpp" #include "forcing_boundaries.hpp" #endif diff --git a/include/mesh/coupled_interfaces/acoustic_poroelastic.hpp b/include/mesh/coupled_interfaces/acoustic_poroelastic.hpp new file mode 100644 index 00000000..7daf2f1c --- /dev/null +++ b/include/mesh/coupled_interfaces/acoustic_poroelastic.hpp @@ -0,0 +1,23 @@ +#ifndef _COUPLED_ACOUSTIC_POORELASTIC_HPP_ +#define _COUPLED_ACOUSTIC_POORELASTIC_HPP_ + +#include "kokkos_abstractions.h" +#include "specfem_mpi/interface.hpp" + +namespace specfem { +namespace mesh { +namespace coupled_interfaces { +struct acoustic_poroelastic { +public: + acoustic_poroelastic(){}; + acoustic_poroelastic(const int num_interfaces, std::ifstream &stream, + const specfem::MPI::MPI *mpi); + int num_interfaces = 0; + specfem::kokkos::HostView1d acoustic_ispec; + specfem::kokkos::HostView1d poroelastic_ispec; +}; +} // namespace coupled_interfaces +} // namespace mesh +} // namespace specfem + +#endif /* _COUPLED_ACOUSTIC_POORELASTIC_HPP_ */ diff --git a/include/mesh/coupled_interfaces/coupled_interfaces.hpp b/include/mesh/coupled_interfaces/coupled_interfaces.hpp new file mode 100644 index 00000000..1f65a4a4 --- /dev/null +++ b/include/mesh/coupled_interfaces/coupled_interfaces.hpp @@ -0,0 +1,33 @@ +#ifndef _COUPLED_INTERFACES_HPP_ +#define _COUPLED_INTERFACES_HPP_ + +#include "acoustic_poroelastic.hpp" +#include "elastic_acoustic.hpp" +#include "elastic_poroelastic.hpp" +#include "specfem_mpi/interface.hpp" + +namespace specfem { +namespace mesh { +namespace coupled_interfaces { + +struct coupled_interfaces { +public: + coupled_interfaces() + : elastic_acoustic(), acoustic_poroelastic(), elastic_poroelastic(){}; + coupled_interfaces(std::ifstream &stream, + const int num_interfaces_elastic_acoustic, + const int num_interfaces_acoustic_poroelastic, + const int num_interfaces_elastic_poroelastic, + const specfem::MPI::MPI *mpi) + : elastic_acoustic(num_interfaces_elastic_acoustic, stream, mpi), + acoustic_poroelastic(num_interfaces_acoustic_poroelastic, stream, mpi), + elastic_poroelastic(num_interfaces_elastic_poroelastic, stream, mpi){}; + specfem::mesh::coupled_interfaces::elastic_acoustic elastic_acoustic; + specfem::mesh::coupled_interfaces::elastic_poroelastic elastic_poroelastic; + specfem::mesh::coupled_interfaces::acoustic_poroelastic acoustic_poroelastic; +}; + +} // namespace coupled_interfaces +} // namespace mesh +} // namespace specfem +#endif /* _COUPLED_INTERFACES_HPP_ */ diff --git a/include/mesh/coupled_interfaces/elastic_acoustic.hpp b/include/mesh/coupled_interfaces/elastic_acoustic.hpp new file mode 100644 index 00000000..ef0080c9 --- /dev/null +++ b/include/mesh/coupled_interfaces/elastic_acoustic.hpp @@ -0,0 +1,24 @@ +#ifndef _COUPLED_ELASTIC_ACOUSTIC_HPP_ +#define _COUPLED_ELASTIC_ACOUSTIC_HPP_ + +#include "kokkos_abstractions.h" +#include "specfem_mpi/interface.hpp" + +namespace specfem { +namespace mesh { +namespace coupled_interfaces { +struct elastic_acoustic { +public: + elastic_acoustic(){}; + elastic_acoustic(const int num_interfaces, std::ifstream &stream, + const specfem::MPI::MPI *mpi); + + int num_interfaces = 0; + specfem::kokkos::HostView1d elastic_ispec; + specfem::kokkos::HostView1d acoustic_ispec; +}; +} // namespace coupled_interfaces +} // namespace mesh +} // namespace specfem + +#endif /* _COUPLED_ELASTIC_ACOUSTIC_HPP_ */ diff --git a/include/mesh/coupled_interfaces/elastic_poroelastic.hpp b/include/mesh/coupled_interfaces/elastic_poroelastic.hpp new file mode 100644 index 00000000..a18c5807 --- /dev/null +++ b/include/mesh/coupled_interfaces/elastic_poroelastic.hpp @@ -0,0 +1,23 @@ +#ifndef _COUPLED_ELASTIC_POORELASTIC_HPP_ +#define _COUPLED_ELASTIC_POORELASTIC_HPP_ + +#include "kokkos_abstractions.h" +#include "specfem_mpi/interface.hpp" + +namespace specfem { +namespace mesh { +namespace coupled_interfaces { +struct elastic_poroelastic { +public: + elastic_poroelastic(){}; + elastic_poroelastic(const int num_interfaces, std::ifstream &stream, + const specfem::MPI::MPI *mpi); + int num_interfaces = 0; + specfem::kokkos::HostView1d elastic_ispec; + specfem::kokkos::HostView1d poroelastic_ispec; +}; +} // namespace coupled_interfaces +} // namespace mesh +} // namespace specfem + +#endif /* _COUPLED_ELASTIC_POORELASTIC_HPP_ */ diff --git a/include/mesh/mesh.hpp b/include/mesh/mesh.hpp index d1485bc6..29ca2cdb 100644 --- a/include/mesh/mesh.hpp +++ b/include/mesh/mesh.hpp @@ -4,7 +4,7 @@ #include "IO/fortran/read_material_properties.hpp" #include "IO/fortran/read_mesh_database.hpp" #include "boundaries/boundaries.hpp" -#include "compute/interface.hpp" +#include "coupled_interfaces/coupled_interfaces.hpp" #include "elements/elements.hpp" #include "kokkos_abstractions.h" #include "material/interface.hpp" @@ -13,7 +13,6 @@ #include "properties/properties.hpp" #include "specfem_mpi/interface.hpp" #include "specfem_setup.hpp" -#include "surfaces/surfaces.hpp" #include namespace specfem { @@ -39,12 +38,6 @@ struct mesh { ///< material information for ///< every spectral element - // specfem::mesh::interfaces::interface interface; ///< Struct used to store - // data - // ///< required to implement - // MPI - // ///< interfaces - specfem::mesh::boundaries::absorbing_boundary abs_boundary; ///< Struct used ///< to store data ///< required to @@ -55,7 +48,11 @@ struct mesh { specfem::mesh::properties parameters; ///< Struct to store simulation launch ///< parameters - specfem::mesh::surfaces::acoustic_free_surface + specfem::mesh::coupled_interfaces::coupled_interfaces + coupled_interfaces; ///< Struct to store + ///< coupled interfaces + + specfem::mesh::boundaries::acoustic_free_surface acfree_surface; ///< Struct used to store data required to implement ///< acoustic free surface diff --git a/include/mesh/surfaces/acoustic_free_surface.hpp b/include/mesh/surfaces/acoustic_free_surface.hpp deleted file mode 100644 index e9de85b4..00000000 --- a/include/mesh/surfaces/acoustic_free_surface.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef _ACOUSTIC_FREE_SURFACE_HPP -#define _ACOUSTIC_FREE_SURFACE_HPP - -#include "kokkos_abstractions.h" -#include "specfem_mpi/interface.hpp" - -namespace specfem { -namespace mesh { -namespace surfaces { - -struct acoustic_free_surface { - specfem::kokkos::HostView1d numacfree_surface, typeacfree_surface, e1, - e2, ixmin, ixmax, izmin, izmax; - - acoustic_free_surface(){}; - acoustic_free_surface(const int nelem_acoustic_surface); - acoustic_free_surface(std::ifstream &stream, const int nelem_acoustic_surface, - const specfem::MPI::MPI *mpi); -}; -} // namespace surfaces -} // namespace mesh -} // namespace specfem - -#endif diff --git a/include/mesh/surfaces/surfaces.hpp b/include/mesh/surfaces/surfaces.hpp deleted file mode 100644 index 97cb4f4e..00000000 --- a/include/mesh/surfaces/surfaces.hpp +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef SURFACES_H -#define SURFACES_H - -#include "acoustic_free_surface.hpp" - -#endif diff --git a/include/parameter_parser/receivers.hpp b/include/parameter_parser/receivers.hpp index 194c508d..bc2b8554 100644 --- a/include/parameter_parser/receivers.hpp +++ b/include/parameter_parser/receivers.hpp @@ -1,5 +1,5 @@ -#ifndef _RUNTIME_CONFIGURATION_RECIEVERS_HPP -#define _RUNTIME_CONFIGURATION_RECIEVERS_HPP +#ifndef _RUNTIME_CONFIGURATION_RECEIVERS_HPP +#define _RUNTIME_CONFIGURATION_RECEIVERS_HPP #include "constants.hpp" #include "yaml-cpp/yaml.h" @@ -43,7 +43,7 @@ class receivers { * * @return std::vector vector seismogram types */ - std::vector get_seismogram_types() const { + std::vector get_seismogram_types() const { return stypes; } @@ -51,9 +51,10 @@ class receivers { std::string stations_file; ///< path to stations file type_real angle; ///< Angle of the receiver int nstep_between_samples; ///< Seismogram sampling frequency - std::vector stypes; ///< std::vector containing - ///< type of seismograms to be - ///< written + std::vector stypes; ///< std::vector + ///< containing type of + ///< seismograms to be + ///< written }; } // namespace runtime_configuration } // namespace specfem diff --git a/include/parameter_parser/setup.hpp b/include/parameter_parser/setup.hpp index 23e39aef..df6400d6 100644 --- a/include/parameter_parser/setup.hpp +++ b/include/parameter_parser/setup.hpp @@ -47,7 +47,8 @@ class setup { /** * @brief Instantiate the Timescheme * - * @return specfem::TimeScheme::TimeScheme* Pointer to the TimeScheme object + * @return specfem::TimeScheme::TimeScheme* Pointer to the TimeScheme + object * used in the solver algorithm */ specfem::TimeScheme::TimeScheme *instantiate_solver() { @@ -112,18 +113,21 @@ class setup { * @return std::vector Types of seismograms to be * calculated */ - std::vector get_seismogram_types() const { + std::vector get_seismogram_types() const { return this->receivers->get_seismogram_types(); } /** * @brief Instantiate a seismogram writer object * - * @param receivers Vector of pointers to receiver objects used to instantiate + * @param receivers Vector of pointers to receiver objects used to + instantiate * the writer - * @param compute_receivers Pointer to specfem::compute::receivers struct used + * @param compute_receivers Pointer to specfem::compute::receivers struct + used * to instantiate the writer - * @return specfem::writer::writer* Pointer to an instantiated writer object + * @return specfem::writer::writer* Pointer to an instantiated writer + object */ specfem::writer::writer *instantiate_seismogram_writer( std::vector &receivers, diff --git a/include/receiver/read_receiver.hpp b/include/receiver/read_receiver.hpp index c5ce097c..3cd8a220 100644 --- a/include/receiver/read_receiver.hpp +++ b/include/receiver/read_receiver.hpp @@ -7,7 +7,17 @@ namespace specfem { namespace receivers { - +/** + * @brief Read receiver station file + * + * Parse receiver stations file and create a vector of + * specfem::source::source * object + * + * @param stations_file Stations file describing receiver locations + * @param angle Angle of the receivers + * @return std::vector vector of instantiated + * receiver objects + */ std::vector read_receivers(const std::string stations_file, const type_real angle); } // namespace receivers diff --git a/include/receiver/receiver.hpp b/include/receiver/receiver.hpp index 41c2fbd9..22058ad8 100644 --- a/include/receiver/receiver.hpp +++ b/include/receiver/receiver.hpp @@ -2,6 +2,7 @@ #define _RECEIVER_HPP #include "constants.hpp" +#include "enumerations/specfem_enums.hpp" #include "kokkos_abstractions.h" #include "quadrature/interface.hpp" #include "specfem_mpi/interface.hpp" @@ -48,15 +49,16 @@ class receiver { * @param ispec_type material type for every spectral element * @param mpi Pointer to specfem MPI object */ - void locate( - const specfem::kokkos::HostView2d coord, - const specfem::kokkos::HostMirror3d h_ibool, - const specfem::kokkos::HostMirror1d xigll, - const specfem::kokkos::HostMirror1d zigll, const int nproc, - const specfem::kokkos::HostView2d coorg, - const specfem::kokkos::HostView2d knods, const int npgeo, - const specfem::kokkos::HostMirror1d ispec_type, - const specfem::MPI::MPI *mpi); + void locate(const specfem::kokkos::HostView2d coord, + const specfem::kokkos::HostMirror3d h_ibool, + const specfem::kokkos::HostMirror1d xigll, + const specfem::kokkos::HostMirror1d zigll, + const int nproc, + const specfem::kokkos::HostView2d coorg, + const specfem::kokkos::HostView2d knods, const int npgeo, + const specfem::kokkos::HostMirror1d + ispec_type, + const specfem::MPI::MPI *mpi); /** * @brief Compute the receiver array (lagrangians) for this station * @@ -134,9 +136,9 @@ class receiver { type_real z; ///< z coordinate of source int ispec; ///< ispec element number where source is located int islice; ///< MPI slice (rank) where the source is located - specfem::elements::type el_type; ///< type of the element inside which this - ///< receiver lies - type_real angle; ///< Angle to rotate components at receivers + specfem::enums::element::type el_type; ///< type of the element inside which + ///< this receiver lies + type_real angle; ///< Angle to rotate components at receivers std::string network_name; ///< Name of the network where this station lies std::string station_name; ///< Name of the station }; diff --git a/include/solver/interface.hpp b/include/solver/interface.hpp index ce385d51..302e0dc2 100644 --- a/include/solver/interface.hpp +++ b/include/solver/interface.hpp @@ -3,5 +3,6 @@ #include "solver.hpp" #include "time_marching.hpp" +#include "time_marching.tpp" #endif diff --git a/include/solver/solver.hpp b/include/solver/solver.hpp index 43233552..da9530df 100644 --- a/include/solver/solver.hpp +++ b/include/solver/solver.hpp @@ -10,6 +10,10 @@ namespace solver { /** * @brief Base solver class * + * Solver class is the base class for all solver algorithms (implicit or + * explicit). The class contains a pure virtual function run() that must be + * implemented by the derived solver implementations. + * */ class solver { @@ -18,7 +22,7 @@ class solver { * @brief Run solver algorithm * */ - virtual void run(){}; + virtual void run() = 0; }; } // namespace solver diff --git a/include/solver/time_marching.hpp b/include/solver/time_marching.hpp index 3dd8db81..9b053cf7 100644 --- a/include/solver/time_marching.hpp +++ b/include/solver/time_marching.hpp @@ -1,24 +1,54 @@ #ifndef _TIME_MARCHING_HPP #define _TIME_MARCHING_HPP +#include "coupled_interface/interface.hpp" #include "domain/interface.hpp" +#include "enumerations/interface.hpp" #include "solver.hpp" #include "timescheme/interface.hpp" namespace specfem { namespace solver { +/** + * @brief Time marching solver class + * + * Implements a forward time marching scheme given a time scheme and domains. + * Currently only acoustic and elastic domains are supported. + * + * @tparam qp_type Type defining number of quadrature points either at compile + * time or run time + */ +template class time_marching : public specfem::solver::solver { public: /** * @brief Construct a new time marching solver object * - * @param domain Pointer to specfem::Domain::Domain class - * @param it Pointer to spectem::TimeScheme::TimeScheme class + * @param acoustic_domain domain object template specialized for acoustic + * media + * @param elastic_domain domain object template specialized for elastic media + * @param it Pointer to time scheme object (it stands for iterator) */ - time_marching(specfem::Domain::Domain *domain, - specfem::TimeScheme::TimeScheme *it) - : domain(domain), it(it){}; + time_marching( + specfem::domain::domain &acoustic_domain, + specfem::domain::domain + &elastic_domain, + specfem::coupled_interface::coupled_interface< + specfem::domain::domain, + specfem::domain::domain > &acoustic_elastic_interface, + specfem::coupled_interface::coupled_interface< + specfem::domain::domain, + specfem::domain::domain > &elastic_acoustic_interface, + specfem::TimeScheme::TimeScheme *it) + : acoustic_domain(acoustic_domain), elastic_domain(elastic_domain), + acoustic_elastic_interface(acoustic_elastic_interface), + elastic_acoustic_interface(elastic_acoustic_interface), it(it){}; /** * @brief Run time-marching solver algorithm * @@ -26,7 +56,22 @@ class time_marching : public specfem::solver::solver { void run() override; private: - specfem::Domain::Domain *domain; ///< Pointer to spefem::Domain::Domain class + specfem::domain::domain + acoustic_domain; ///< Acoustic domain + specfem::domain::domain + elastic_domain; ///< Acoustic domain + specfem::coupled_interface::coupled_interface< + specfem::domain::domain, + specfem::domain::domain > + acoustic_elastic_interface; /// Acoustic elastic interface + specfem::coupled_interface::coupled_interface< + specfem::domain::domain, + specfem::domain::domain > + elastic_acoustic_interface; /// Elastic acoustic interface specfem::TimeScheme::TimeScheme *it; ///< Pointer to ///< spectem::TimeScheme::TimeScheme ///< class diff --git a/include/solver/time_marching.tpp b/include/solver/time_marching.tpp new file mode 100644 index 00000000..0c51ca15 --- /dev/null +++ b/include/solver/time_marching.tpp @@ -0,0 +1,87 @@ +#ifndef _TIME_MARCHING_TPP +#define _TIME_MARCHING_TPP + +#include "domain/interface.hpp" +#include "solver.hpp" +#include "time_marching.hpp" +#include "timescheme/interface.hpp" +#include + +template +void specfem::solver::time_marching::run() { + + auto *it = this->it; + auto acoustic_domain = this->acoustic_domain; + auto elastic_domain = this->elastic_domain; + + // Special contributions to mass matrix inverse in case of Newmark scheme + if (it->timescheme() == specfem::enums::time_scheme::type::newmark) { + elastic_domain.template mass_time_contribution< + specfem::enums::time_scheme::type::newmark>(it->get_time_increment()); + acoustic_domain.template mass_time_contribution< + specfem::enums::time_scheme::type::newmark>(it->get_time_increment()); + } + + // Compute and store the inverse of mass matrix for faster computations + elastic_domain.invert_mass_matrix(); + acoustic_domain.invert_mass_matrix(); + + const int nstep = it->get_max_timestep(); + + auto acoustic_field = acoustic_domain.get_field(); + auto acoustic_field_dot = acoustic_domain.get_field_dot(); + auto acoustic_field_dot_dot = acoustic_domain.get_field_dot_dot(); + + auto elastic_field = elastic_domain.get_field(); + auto elastic_field_dot = elastic_domain.get_field_dot(); + auto elastic_field_dot_dot = elastic_domain.get_field_dot_dot(); + + while (it->status()) { + int istep = it->get_timestep(); + + type_real timeval = it->get_time(); + + Kokkos::Profiling::pushRegion("Stiffness calculation"); + it->apply_predictor_phase(acoustic_field, acoustic_field_dot, + acoustic_field_dot_dot); + it->apply_predictor_phase(elastic_field, elastic_field_dot, + elastic_field_dot_dot); + + acoustic_elastic_interface.compute_coupling(); + acoustic_domain.compute_source_interaction(timeval); + acoustic_domain.compute_stiffness_interaction(); + acoustic_domain.divide_mass_matrix(); + + it->apply_corrector_phase(acoustic_field, acoustic_field_dot, + acoustic_field_dot_dot); + + elastic_acoustic_interface.compute_coupling(); + elastic_domain.compute_source_interaction(timeval); + elastic_domain.compute_stiffness_interaction(); + elastic_domain.divide_mass_matrix(); + + it->apply_corrector_phase(elastic_field, elastic_field_dot, + elastic_field_dot_dot); + Kokkos::Profiling::popRegion(); + + if (it->compute_seismogram()) { + int isig_step = it->get_seismogram_step(); + acoustic_domain.compute_seismogram(isig_step); + elastic_domain.compute_seismogram(isig_step); + it->increment_seismogram_step(); + } + + it->increment_time(); + + if (istep % 10 == 0) { + std::cout << "Progress : executed " << istep << " steps of " << nstep + << " steps" << std::endl; + } + } + + std::cout << std::endl; + + return; +} + +#endif diff --git a/include/source/force_source.hpp b/include/source/force_source.hpp index 40bd3e7d..16196370 100644 --- a/include/source/force_source.hpp +++ b/include/source/force_source.hpp @@ -1,6 +1,7 @@ #ifndef _FORCE_SOURCE_HPP #define _FORCE_SOURCE_HPP +#include "enumerations/specfem_enums.hpp" #include "kokkos_abstractions.h" #include "quadrature/interface.hpp" #include "source.hpp" @@ -45,15 +46,16 @@ class force : public source { * @param ispec_type material type for every spectral element * @param mpi Pointer to specfem MPI object */ - void locate( - const specfem::kokkos::HostView2d coord, - const specfem::kokkos::HostMirror3d h_ibool, - const specfem::kokkos::HostMirror1d xigll, - const specfem::kokkos::HostMirror1d zigll, const int nproc, - const specfem::kokkos::HostView2d coorg, - const specfem::kokkos::HostView2d knods, const int npgeo, - const specfem::kokkos::HostMirror1d ispec_type, - const specfem::MPI::MPI *mpi) override; + void locate(const specfem::kokkos::HostView2d coord, + const specfem::kokkos::HostMirror3d h_ibool, + const specfem::kokkos::HostMirror1d xigll, + const specfem::kokkos::HostMirror1d zigll, + const int nproc, + const specfem::kokkos::HostView2d coorg, + const specfem::kokkos::HostView2d knods, const int npgeo, + const specfem::kokkos::HostMirror1d + ispec_type, + const specfem::MPI::MPI *mpi) override; /** * @brief Precompute and store lagrangian values used to compute integrals for * sources @@ -161,8 +163,8 @@ class force : public source { type_real angle; ///< angle of the source int ispec; ///< ispec element number where source is located int islice; ///< MPI slice (rank) where the source is located - specfem::elements::type el_type; ///< type of the element inside which this - ///< source lies + specfem::enums::element::type el_type; ///< type of the element inside which + ///< this source lies specfem::forcing_function::stf *forcing_function = NULL; ///< Pointer to source time function store on the device }; diff --git a/include/source/moment_tensor_source.hpp b/include/source/moment_tensor_source.hpp index 666b2de4..ab1208a1 100644 --- a/include/source/moment_tensor_source.hpp +++ b/include/source/moment_tensor_source.hpp @@ -2,6 +2,7 @@ #define _MOMENT_TENSOR_SOURCE_HPP #include "constants.hpp" +#include "enumerations/specfem_enums.hpp" #include "kokkos_abstractions.h" #include "quadrature/interface.hpp" #include "source.hpp" @@ -45,15 +46,16 @@ class moment_tensor : public source { * @param ispec_type material type for every spectral element * @param mpi Pointer to specfem MPI object */ - void locate( - const specfem::kokkos::HostView2d coord, - const specfem::kokkos::HostMirror3d h_ibool, - const specfem::kokkos::HostMirror1d xigll, - const specfem::kokkos::HostMirror1d zigll, const int nproc, - const specfem::kokkos::HostView2d coorg, - const specfem::kokkos::HostView2d knods, const int npgeo, - const specfem::kokkos::HostMirror1d ispec_type, - const specfem::MPI::MPI *mpi) override; + void locate(const specfem::kokkos::HostView2d coord, + const specfem::kokkos::HostMirror3d h_ibool, + const specfem::kokkos::HostMirror1d xigll, + const specfem::kokkos::HostMirror1d zigll, + const int nproc, + const specfem::kokkos::HostView2d coorg, + const specfem::kokkos::HostView2d knods, const int npgeo, + const specfem::kokkos::HostMirror1d + ispec_type, + const specfem::MPI::MPI *mpi) override; /** * @brief Precompute and store lagrangian values used to compute integrals for * sources @@ -168,8 +170,8 @@ class moment_tensor : public source { specfem::forcing_function::stf *forcing_function = NULL; ///< Pointer to source time function store on the device - specfem::elements::type el_type; ///< element type where this source is - ///< located + specfem::enums::element::type el_type; ///< element type where this source is + ///< located }; } // namespace sources } // namespace specfem diff --git a/include/source/source.hpp b/include/source/source.hpp index 2735ef50..f430a565 100644 --- a/include/source/source.hpp +++ b/include/source/source.hpp @@ -2,13 +2,13 @@ #define _SOURCE_HPP #include "constants.hpp" +#include "enumerations/specfem_enums.hpp" #include "kokkos_abstractions.h" #include "quadrature/interface.hpp" #include "source_time_function/interface.hpp" #include "specfem_mpi/interface.hpp" #include "specfem_setup.hpp" #include "utilities/interface.hpp" -#include "yaml-cpp/yaml.h" #include namespace specfem { @@ -43,15 +43,16 @@ class source { * @param ispec_type material type for every spectral element * @param mpi Pointer to specfem MPI object */ - virtual void locate( - const specfem::kokkos::HostView2d coord, - const specfem::kokkos::HostMirror3d h_ibool, - const specfem::kokkos::HostMirror1d xigll, - const specfem::kokkos::HostMirror1d zigll, const int nproc, - const specfem::kokkos::HostView2d coorg, - const specfem::kokkos::HostView2d knods, const int npgeo, - const specfem::kokkos::HostMirror1d ispec_type, - const specfem::MPI::MPI *mpi){}; + virtual void + locate(const specfem::kokkos::HostView2d coord, + const specfem::kokkos::HostMirror3d h_ibool, + const specfem::kokkos::HostMirror1d xigll, + const specfem::kokkos::HostMirror1d zigll, const int nproc, + const specfem::kokkos::HostView2d coorg, + const specfem::kokkos::HostView2d knods, const int npgeo, + const specfem::kokkos::HostMirror1d + ispec_type, + const specfem::MPI::MPI *mpi){}; /** * @brief Precompute and store lagrangian values used to compute integrals for * sources diff --git a/include/source_time_function/interface.hpp b/include/source_time_function/interface.hpp index 19f129b5..80203f33 100644 --- a/include/source_time_function/interface.hpp +++ b/include/source_time_function/interface.hpp @@ -2,6 +2,7 @@ #define _SOURCE_TIME_FUNCTION_INTERFACE_HPP #include "dirac.hpp" +#include "ricker.hpp" #include "source_time_function.hpp" #endif diff --git a/include/source_time_function/ricker.hpp b/include/source_time_function/ricker.hpp new file mode 100644 index 00000000..c806c6d2 --- /dev/null +++ b/include/source_time_function/ricker.hpp @@ -0,0 +1,58 @@ +#ifndef _STF_RICKER_HPP +#define _STF_RICKER_HPP + +#include "source_time_function.hpp" +#include "specfem_setup.hpp" +#include +#include + +namespace specfem { +namespace forcing_function { +class Ricker : public stf { + +public: + /** + * @brief Contruct a Ricker source time function object + * + * @param f0 frequency f0 + * @param tshift tshift value + * @param factor factor to scale source time function + * @param use_trick_for_better_pressure + */ + KOKKOS_FUNCTION Ricker(type_real f0, type_real tshift, type_real factor, + bool use_trick_for_better_pressure); + + /** + * @brief compute the value of stf at time t + * + * @param t + * @return value of source time function at time t + */ + KOKKOS_FUNCTION type_real compute(type_real t) override; + /** + * @brief update the time shift value + * + * @param tshift new tshift value + */ + KOKKOS_FUNCTION void update_tshift(type_real tshift) override { + this->tshift = tshift; + } + /** + * @brief Get the t0 value + * + * @return t0 value + */ + KOKKOS_FUNCTION type_real get_t0() const override { return this->t0; } + +private: + type_real f0; ///< frequence f0 + type_real tshift; ///< value of tshit + type_real t0; ///< t0 value + type_real factor; ///< scaling factor + bool use_trick_for_better_pressure; +}; + +} // namespace forcing_function +} // namespace specfem + +#endif // _STF_RICKER_HPP diff --git a/include/source_time_function/source_time_function.hpp b/include/source_time_function/source_time_function.hpp index 85f1eee8..6ef1fd4f 100644 --- a/include/source_time_function/source_time_function.hpp +++ b/include/source_time_function/source_time_function.hpp @@ -61,6 +61,8 @@ std::ostream &operator<<(std::ostream &out, */ struct stf_storage { specfem::forcing_function::stf *T; + + KOKKOS_FUNCTION type_real compute(const type_real t) { return T->compute(t); } }; } // namespace forcing_function diff --git a/include/timescheme/newmark.hpp b/include/timescheme/newmark.hpp index 21774b77..f09155ce 100644 --- a/include/timescheme/newmark.hpp +++ b/include/timescheme/newmark.hpp @@ -2,6 +2,7 @@ #define _NEWMARK_HPP #include "domain/interface.hpp" +#include "enumerations/specfem_enums.hpp" #include "specfem_setup.hpp" #include "timescheme.hpp" #include @@ -15,6 +16,14 @@ namespace TimeScheme { class Newmark : public specfem::TimeScheme::TimeScheme { public: + /** + * @brief Get the timescheme type + * + * @return constexpr specfem::enums::time_scheme + */ + specfem::enums::time_scheme::type timescheme() const override { + return specfem::enums::time_scheme::type::newmark; + } /** * @brief Construct a new Newmark timescheme object * @@ -65,15 +74,21 @@ class Newmark : public specfem::TimeScheme::TimeScheme { * * @param domain_class Pointer to domain class to apply predictor phase */ - void - apply_predictor_phase(const specfem::Domain::Domain *domain_class) override; + void apply_predictor_phase( + specfem::kokkos::DeviceView2d field, + specfem::kokkos::DeviceView2d field_dot, + specfem::kokkos::DeviceView2d + field_dot_dot) override; /** * @brief Apply corrector phase of the timescheme * * @param domain_class Pointer to domain class to apply corrector phase */ - void - apply_corrector_phase(const specfem::Domain::Domain *domain_class) override; + void apply_corrector_phase( + specfem::kokkos::DeviceView2d field, + specfem::kokkos::DeviceView2d field_dot, + specfem::kokkos::DeviceView2d + field_dot_dot) override; /** * @brief Compute if seismogram needs to be calculated at this timestep * @@ -101,6 +116,12 @@ class Newmark : public specfem::TimeScheme::TimeScheme { */ void increment_seismogram_step() override { isig_step++; } + /** + * @brief Get time increment + * + */ + type_real get_time_increment() const override { return this->deltat; } + /** * @brief Log newmark timescheme information to console * diff --git a/include/timescheme/timescheme.hpp b/include/timescheme/timescheme.hpp index eabce5c1..98ad08b8 100644 --- a/include/timescheme/timescheme.hpp +++ b/include/timescheme/timescheme.hpp @@ -14,6 +14,11 @@ namespace TimeScheme { class TimeScheme { public: + /** + * @brief Get the timescheme type + * + */ + virtual specfem::enums::time_scheme::type timescheme() const = 0; /** * @brief Return the status of simulation * @@ -54,15 +59,21 @@ class TimeScheme { * * @param domain_class Pointer to domain class to apply predictor phase */ - virtual void - apply_predictor_phase(const specfem::Domain::Domain *domain_class){}; + virtual void apply_predictor_phase( + specfem::kokkos::DeviceView2d field, + specfem::kokkos::DeviceView2d field_dot, + specfem::kokkos::DeviceView2d + field_dot_dot){}; /** * @brief Apply corrector phase of the timescheme * * @param domain_class Pointer to domain class to apply corrector phase */ - virtual void - apply_corrector_phase(const specfem::Domain::Domain *domain_class){}; + virtual void apply_corrector_phase( + specfem::kokkos::DeviceView2d field, + specfem::kokkos::DeviceView2d field_dot, + specfem::kokkos::DeviceView2d + field_dot_dot){}; friend std::ostream &operator<<(std::ostream &out, TimeScheme &ts); /** @@ -91,6 +102,11 @@ class TimeScheme { * */ virtual void increment_seismogram_step(){}; + /** + * @brief Get time increment + * + */ + virtual type_real get_time_increment() const { return 0.0; } }; std::ostream &operator<<(std::ostream &out, diff --git a/include/utilities/utilities.hpp b/include/utilities/utilities.hpp index 97b0f1de..449b1f65 100644 --- a/include/utilities/utilities.hpp +++ b/include/utilities/utilities.hpp @@ -8,12 +8,6 @@ namespace specfem { namespace utilities { -struct input_holder { - // Struct to hold temporary variables read from database file - type_real val0, val1, val2, val3, val4, val5, val6, val7, val8, val9, val10, - val11, val12; - int n, indic; -}; struct return_holder { type_real rho, mu, kappa, qmu, qkappa, lambdaplus2mu; diff --git a/include/writer/seismogram.hpp b/include/writer/seismogram.hpp index 9532afc6..0ef04e92 100644 --- a/include/writer/seismogram.hpp +++ b/include/writer/seismogram.hpp @@ -31,7 +31,7 @@ class seismogram : public writer { */ seismogram(std ::vector &receivers, specfem::compute::receivers *compute_receivers, - const specfem::seismogram::format::type type, + const specfem::enums::seismogram::format type, const std::string output_folder, const type_real dt, const type_real t0, const int nstep_between_samples) : receivers(receivers), compute_receivers(compute_receivers), type(type), @@ -44,8 +44,8 @@ class seismogram : public writer { void write() override; private: - specfem::seismogram::format::type type; ///< Output format of the seismogram - ///< file + specfem::enums::seismogram::format type; ///< Output format of the seismogram + ///< file std::string output_folder; ///< Path to output folder where results will be ///< stored specfem::compute::receivers diff --git a/meshfem2d/CMakeLists.txt b/meshfem2d/CMakeLists.txt new file mode 100644 index 00000000..fa6224c2 --- /dev/null +++ b/meshfem2d/CMakeLists.txt @@ -0,0 +1,208 @@ +cmake_minimum_required(VERSION 3.10) + +message("-- Building meshfem2D along with this project") +message("-- MESHFEM2D is build without MPI support") +message("-- MESHFEM2D is build without SCOTCH support") + +unset(WITH_MPI) +unset(WITH_SCOTCH) + +# Set the Fortran compiler +enable_language(Fortran) +enable_language(C) + +set(FCFLAGS_f90 -g -O2 -fbacktrace) + +## ========= MACROS ========= +# define macro wrapper on custom command +macro(build_fortran_command module_name dependecies) + get_filename_component(source_file_name ${module_name} NAME_WE) + add_custom_command( + OUTPUT ${module_name} + COMMAND ${CMAKE_Fortran_COMPILER} ${FCFLAGS_f90} -c -o ${module_name} ${CMAKE_CURRENT_SOURCE_DIR}/${source_file_name}.f90 + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${source_file_name}.f90 ${dependecies} + ) +endmacro() + +macro(build_fortran_command_preprocess module_name dependecies) + get_filename_component(source_file_name ${module_name} NAME_WE) + add_custom_command( + OUTPUT ${module_name} + COMMAND ${CMAKE_Fortran_COMPILER} ${FCFLAGS_f90} -c -o ${module_name} ${CMAKE_CURRENT_SOURCE_DIR}/${source_file_name}.F90 + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${source_file_name}.F90 ${dependecies} + ) +endmacro() + +# define macro wrapper on custom command +macro(build_cc_command module_name) + get_filename_component(source_file_name ${module_name} NAME_WE) + add_custom_command( + OUTPUT ${module_name} + COMMAND ${CMAKE_C_COMPILER} ${CFLAGS} -c -o ${module_name} ${CMAKE_CURRENT_SOURCE_DIR}/${source_file_name}.c + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${source_file_name}.c config.h + ) +endmacro() +## ========= MACROS ========= + +set (SHARED_MODULE + shared_par.shared_module.o +) + +build_fortran_command(${SHARED_MODULE} ${CMAKE_CURRENT_SOURCE_DIR}/constants.h) + +add_custom_target(shared_module ALL + DEPENDS ${SHARED_MODULE} +) + +set (UTILITIES + command_line_arguments.mesh_utilities.o + file_management.mesh_utilities.o +) + +foreach(module_files ${UTILITIES}) + build_fortran_command(${module_files} shared_module) +endforeach() + +add_custom_target(mesh_utilities ALL + DEPENDS ${UTILITIES} +) + +# shared objects +set(shared_OBJECTS + define_shape_functions.shared.o; + gll_library.shared.o; + lagrange_poly.shared.o; + read_interfaces_file.shared.o; + read_material_table.shared.o; + read_regions.shared.o; + read_source_file.shared.o; + read_value_parameters.shared.o; + set_color_palette.shared.o; + spline_routines.shared.o; + write_VTK_data.shared.o + CACHE INTERNAL "shared objects" +) + +# Add a custom command to compile each object file +foreach(module_files ${shared_OBJECTS}) + build_fortran_command(${module_files} shared_module) +endforeach() + +# Add a library target for the shared objects +add_custom_target(shared ALL + DEPENDS ${shared_OBJECTS} +) + +set(cc_OBJECTS + force_ftz.cc.o; + param_reader.cc.o +) + + +# Add a custom command to compile each object file + +foreach(module_files ${cc_OBJECTS}) + build_cc_command(${module_files}) +endforeach() + +# Add a library target for the shared objects +add_custom_target(cc ALL + DEPENDS ${cc_OBJECTS} +) + +set(SHARED_MPI_LIBS + read_parameter_file.shared.o; + parallel.sharedmpi.o; + exit_mpi.shared.o + CACHE INTERNAL "shared MPI objects" +) + +foreach(module_files ${SHARED_MPI_LIBS}) + build_fortran_command_preprocess(${module_files} shared_module) +endforeach() + +# Add a library target for the shared objects +add_custom_target(shared_mpi ALL + DEPENDS ${SHARED_MPI_LIBS} +) + +set(MESHFEM_SHARED_OBJECTS + ${SHARED_MODULE} + ${UTILITIES} + ${shared_OBJECTS} + ${SHARED_MPI_LIBS} + ${cc_OBJECTS} +) + +set( MESHFEM_SHARED_MODULE + meshfem2D_par.mesh_module.o +) + +build_fortran_command(${MESHFEM_SHARED_MODULE} shared_module) + +add_custom_target(mesh_module ALL + DEPENDS ${MESHFEM_SHARED_MODULE} +) + +set (MESHFEM_COMPUTE_ELEMENTS_LOAD + compute_elements_load_par.mesh.o) + +build_fortran_command(${MESHFEM_COMPUTE_ELEMENTS_LOAD} mesh_module) + +add_custom_target(compute_elements_load ALL + DEPENDS ${MESHFEM_COMPUTE_ELEMENTS_LOAD} +) + +set( meshfem2D_OBJECTS + determine_abs_surface.mesh.o + determine_acoustic_surface.mesh.o + get_node_number.mesh.o + repartition_coupling.mesh.o + rotate_mesh.mesh.o + save_databases.mesh.o + save_gnuplot_file.mesh.o + save_stations_file.mesh.o +) + +foreach(module_files ${meshfem2D_OBJECTS}) + build_fortran_command(${module_files} mesh_module) +endforeach() + +add_custom_target(meshfem_mesh ALL + DEPENDS ${meshfem2D_OBJECTS} +) + +set( meshfem2D_PREPROCESSOR_OBJECTS + decompose_mesh.mesh.o + metis_partitioning.mesh.o + part_unstruct.mesh.o + read_external_mesh_files.mesh.o + read_mesh_files.mesh.o + scotch_partitioning.mesh.o + meshfem2D.mesh.o +) + +foreach(module_files ${meshfem2D_PREPROCESSOR_OBJECTS}) + build_fortran_command_preprocess(${module_files} compute_elements_load) +endforeach() + +add_custom_target(mesh_mpi ALL + DEPENDS ${meshfem2D_PREPROCESSOR_OBJECTS} +) + +set( MESHFEM_OBJECTS + ${MESHFEM_SHARED_MODULE} + ${MESHFEM_COMPUTE_ELEMENTS_LOAD} + ${meshfem2D_OBJECTS} + ${meshfem2D_PREPROCESSOR_OBJECTS} +) + +add_custom_command( + OUTPUT meshfem2D + COMMAND ${CMAKE_Fortran_COMPILER} ${FCFLAGS_f90} -o ${CMAKE_BINARY_DIR}/xmeshfem2D ${MESHFEM_OBJECTS} ${MESHFEM_SHARED_OBJECTS} + DEPENDS ${MESHFEM_OBJECTS} ${MESHFEM_SHARED_OBJECTS} +) + +add_custom_target(meshfem2D_exec ALL + DEPENDS meshfem2D +) diff --git a/meshfem2d/Makefile b/meshfem2d/Makefile new file mode 100644 index 00000000..2db5a34e --- /dev/null +++ b/meshfem2d/Makefile @@ -0,0 +1,55 @@ +#======================================================================== +# +# S P E C F E M 2 D +# ----------------- +# +# Main historical authors: Dimitri Komatitsch and Jeroen Tromp +# CNRS, France +# and Princeton University, USA +# (there are currently many more authors!) +# (c) October 2017 +# +# This software is a computer program whose purpose is to solve +# the two-dimensional viscoelastic anisotropic or poroelastic wave equation +# using a spectral-element method (SEM). +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# The full text of the license is available in file "LICENSE". +# +#======================================================================== + +DIR = shared + +# The rest of this file is generic +####################################### + +#### +#### targets +#### + +default: + $(MAKE) -C ../.. $(DIR) + +all: + $(MAKE) -C ../.. all + +clean: + $(MAKE) -C ../.. CLEAN=$(DIR) clean + +cleanall: + $(MAKE) -C ../.. clean + +.PHONY: default all clean cleanall diff --git a/meshfem2d/command_line_arguments.f90 b/meshfem2d/command_line_arguments.f90 new file mode 100644 index 00000000..38a68939 --- /dev/null +++ b/meshfem2d/command_line_arguments.f90 @@ -0,0 +1,72 @@ + +subroutine print_help_message() + + implicit none + + write(*,*) ' ' + write(*,*) 'Usage: meshfem2D [options]' + write(*,*) ' ' + write(*,*) 'Options:' + write(*,*) ' ' + write(*,*) ' -h, --help' + write(*,*) ' Print this help message' + write(*,*) ' ' + write(*,*) ' -p, --Par_File' + write(*,*) ' Specify the parameter file to use' + write(*,*) ' ' + +end subroutine print_help_message + +subroutine parse_command_line_arguments() + + use constants, only: MAX_STRING_LEN, one + use shared_parameters, only: Par_file + + implicit none + + integer :: i = 1, n_args + + character(len=MAX_STRING_LEN) :: arg + + ! get the number of command line arguments + n_args = command_argument_count() + + if (n_args == 0) then + ! print help message + call print_help_message() + ! stop the code + call stop_the_code('') + endif + + ! loop over the command line arguments + do while(.TRUE.) + ! get the i-th command line argument + call get_command_argument(i, arg) + + select case (arg) + case ('-h', '--help') + ! print help message + call print_help_message() + ! stop the code gracefully + call finalize_mpi() + call EXIT(0) + case ('-p', '--Par_File') + if (i == n_args) then + ! print error message + call stop_the_code('Error: missing command line argument for option '//trim(arg)) + endif + ! get the next command line argument + call get_command_argument(i+1, Par_file) + ! skip the next command line argument + i = i + 1 + case default + ! print error message + call stop_the_code('Error: unknown command line argument: '//trim(arg)) + end select + + if (i == n_args) exit + ! increment the counter + i = i + 1 + end do + +end subroutine parse_command_line_arguments diff --git a/meshfem2d/compute_elements_load_par.f90 b/meshfem2d/compute_elements_load_par.f90 new file mode 100644 index 00000000..c4c5f4d7 --- /dev/null +++ b/meshfem2d/compute_elements_load_par.f90 @@ -0,0 +1,289 @@ +!===================================================================== +! +! S p e c f e m 3 D V e r s i o n 3 . 0 +! --------------------------------------- +! +! Main historical authors: Dimitri Komatitsch and Jeroen Tromp +! Princeton University, USA +! and CNRS / University of Marseille, France +! (there are currently many more authors!) +! (c) Princeton University and CNRS / University of Marseille, July 2012 +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 3 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License along +! with this program; if not, write to the Free Software Foundation, Inc., +! 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +! +!===================================================================== + +module compute_elements_load_par + + + use part_unstruct_par, only: nelmnts,nb_edges,abs_surface,nelemabs,glob2loc_elmnts,abs_surface_merge,nelemabs_merge, & + nxread,nzread + + use shared_parameters, only: ATTENUATION_VISCOELASTIC,ATTENUATION_VISCOACOUSTIC,NELEM_PML_THICKNESS,PML_BOUNDARY_CONDITIONS, & + read_external_mesh,num_material,phi_read,QKappa,Qmu,absorbbottom,absorbtop,absorbleft,absorbright + + use constants, only: IMAIN,TINYVAL,myrank + + implicit none + integer, dimension(:), allocatable :: elmnts_load + integer, dimension(:), allocatable :: adjwgt + + logical, dimension(:), allocatable :: is_elastic,is_acoustic,is_viscoelastic,is_viscoacoustic,is_pml + + !! acoustic-elastic-poroelastic as well as CPML load balancing: + !! we define here the relative cost of all types of spectral elements used in the code. + integer, parameter :: ACOUSTIC_LOAD = 46 + integer, parameter :: ELASTIC_LOAD = 113 + integer, parameter :: VISCOACOUSTIC_LOAD = 123 + integer, parameter :: VISCOELASTIC_LOAD = 280 + + integer, parameter :: ACOUSTIC_LOAD_PML = 790 + integer, parameter :: ELASTIC_LOAD_PML = 1049 + integer, parameter :: VISCOACOUSTIC_LOAD_PML = 573 !! estimated based on elastic factor, better check one day... + integer, parameter :: VISCOELASTIC_LOAD_PML = 1306 + +contains + +! +!--------------------------------------------------------------------------------------- +! + + subroutine compute_elements_load() + !---------------------------------------------------------------------------------------------- + ! compute elements load for efficient partitioning + ! (a PML element take more time to calculate than a fluid element for ex) + ! Fill load_elmnts array contains the element weight to be considered in mesh decomposition + ! in order to obtain a good load inbalance + !---------------------------------------------------------------------------------------------- + + implicit none + + ! local parameters + integer :: ier,ispec + integer :: nelem_acoustic,nelem_viscoacoustic,nelem_acoustic_pml,nelem_viscoacoustic_pml + integer :: nelem_elastic,nelem_viscoelastic,nelem_elastic_pml,nelem_viscoelastic_pml + + ! Allocations WARNING indices start at zero! + allocate(elmnts_load(0:nelmnts-1), & + adjwgt(0:nb_edges-1),stat=ier) + if (ier /= 0) call stop_the_code('Error allocating arrays for weights') + + allocate(is_acoustic(0:nelmnts-1), & + is_viscoacoustic(0:nelmnts-1), & + is_elastic(0:nelmnts-1), & + is_viscoelastic(0:nelmnts-1),stat=ier) + if (ier /= 0) call stop_the_code('Error allocating arrays for is_acoustic, is_elastic and is_viscoelastic') + + ! Initialize counters and arrays + nelem_elastic = 0 + nelem_acoustic = 0 + nelem_viscoelastic = 0 + nelem_viscoacoustic = 0 + nelem_elastic_pml = 0 + nelem_acoustic_pml = 0 + nelem_viscoelastic_pml = 0 + nelem_viscoacoustic_pml = 0 + + elmnts_load(:) = ELASTIC_LOAD + adjwgt(:) = ELASTIC_LOAD + + is_acoustic(:) = .false. + is_viscoacoustic(:) = .false. + is_elastic(:) = .false. + is_viscoelastic(:) = .false. + + ! Loop on the elements to determine which element is elastic, acoustic or viscoelastic + call determine_elements_type() + + ! Determine which element is PML and which is not when the mesh has been made by internal mesher. + ! For external meshes the detection is made directly when reading the absorbing elements file in + ! read_external_mesh_file.F90 + if (PML_BOUNDARY_CONDITIONS .and. (.not. read_external_mesh)) then + call locate_pml_elements_internal() + endif + + ! Loop on the elements to fill the array elmnts_load and count the elements (for user output) + do ispec = 0,nelmnts-1 + if (is_elastic(ispec)) then + if (is_pml(ispec)) then + elmnts_load(ispec) = ELASTIC_LOAD_PML + nelem_elastic_pml = nelem_elastic_pml + 1 + else + nelem_elastic = nelem_elastic + 1 + !elmnts_load(ispec) = ELASTIC_LOAD ! Useless: it has been initialized as elastic + endif + else if (is_viscoelastic(ispec)) then + if (is_pml(ispec)) then + elmnts_load(ispec) = VISCOELASTIC_LOAD_PML + nelem_viscoelastic_pml = nelem_viscoelastic_pml + 1 + else + elmnts_load(ispec) = VISCOELASTIC_LOAD + nelem_viscoelastic = nelem_viscoelastic + 1 + endif + else if (is_acoustic(ispec)) then + if (is_pml(ispec)) then + elmnts_load(ispec) = ACOUSTIC_LOAD_PML + nelem_acoustic_pml = nelem_acoustic_pml + 1 + else + elmnts_load(ispec) = ACOUSTIC_LOAD + nelem_acoustic = nelem_acoustic + 1 + endif + else if (is_viscoacoustic(ispec)) then + if (is_pml(ispec)) then + elmnts_load(ispec) = VISCOACOUSTIC_LOAD_PML + nelem_viscoacoustic_pml = nelem_viscoacoustic_pml + 1 + else + elmnts_load(ispec) = VISCOACOUSTIC_LOAD + nelem_viscoacoustic = nelem_viscoacoustic + 1 + endif + endif + enddo + + ! User output + if (myrank == 0) then + write(IMAIN,*) '************ Computing elements load ************' + write(IMAIN,*) 'Number of elastic elements :',nelem_elastic + write(IMAIN,*) 'Number of acoustic elements :',nelem_acoustic + write(IMAIN,*) 'Number of viscoelastic elements :',nelem_viscoelastic + write(IMAIN,*) 'Number of viscoacoustic elements :',nelem_viscoacoustic + write(IMAIN,*) 'Number of elastic PML elements :',nelem_elastic_pml + write(IMAIN,*) 'Number of acoustic PML elements :',nelem_acoustic_pml + write(IMAIN,*) 'Number of viscoelastic PML elements :',nelem_viscoelastic_pml + write(IMAIN,*) 'Number of viscoacoustic PML elements :',nelem_viscoacoustic_pml + write(IMAIN,*) '*************************************************' + write(IMAIN,*) + call flush_IMAIN() + endif + + end subroutine compute_elements_load + +! +!--------------------------------------------------------------------------------------- +! + + subroutine determine_elements_type() + +! Loop on the elements to determine which element is elastic, acoustic or viscoelastic + + implicit none + + integer :: ispec + + do ispec = 0,nelmnts-1 + ! acoustic/elastic/poroelastic... + if (phi_read(num_material(ispec+1)) < TINYVAL) then + is_acoustic(ispec) = .false. + is_elastic(ispec) = .true. + else if (phi_read(num_material(ispec+1)) >= 1.d0) then + is_acoustic(ispec) = .true. + is_elastic(ispec) = .false. + else + is_acoustic(ispec) = .false. + is_elastic(ispec) = .false. + endif + + ! visco-elastic + if (ATTENUATION_VISCOELASTIC) then + if (is_elastic(ispec)) then + if (((abs(Qkappa(num_material(ispec+1)) - 9999.0d0)) > TINYVAL) .or. & + ((abs(Qmu(num_material(ispec+1)) - 9999.0d0)) > TINYVAL)) then + is_viscoelastic(ispec) = .true. + is_elastic(ispec) = .false. + is_acoustic(ispec) = .false. + endif + endif + endif + + ! visco-acoustic + if (ATTENUATION_VISCOACOUSTIC) then + if (is_acoustic(ispec)) then + if (((abs(Qkappa(num_material(ispec+1)) - 9999.0d0)) > TINYVAL)) then + is_viscoacoustic(ispec) = .true. + is_elastic(ispec) = .false. + is_acoustic(ispec) = .false. + endif + endif + endif + enddo + + end subroutine determine_elements_type + +! +!--------------------------------------------------------------------------------------- +! + + subroutine locate_pml_elements_internal() + !---------------------------------------------------------------------------------------------- + ! Determine which element is PML and which is not when the mesh has been made by the internal + ! mesher. + ! The elements are numbered like this : + ! + ! nxread + ! <-----------------------------------------------------> + ! ______________________________________________________ + ! | | | | | nxread*nzread | ^ + ! |__________|__________|____|___________|_______________| | + ! | ... | ... |....| ... | ... | | + ! |__________|__________|____|___________|_______________| | + ! | nxread+1 | nxread+2 |....|2*nxread-1 | 2*nxread | | nzread + ! |__________|__________|____|___________|_______________| | + ! | 1 | 2 |....| nxread-1 | nxread | | + ! |__________|__________|____|___________|_______________| v + ! + ! !WARNING! is_pml array starts from 0 + ! + !---------------------------------------------------------------------------------------------- + + implicit none + + ! local parameters + integer :: i,j + + ! PML Left + if (absorbleft) then + do i = 1,NELEM_PML_THICKNESS + do j = 1,nzread + is_pml((j-1)*nxread + (i-1)) = .true. + enddo + enddo + endif + ! PML Right + if (absorbright) then + do i = nxread-NELEM_PML_THICKNESS+1,nxread + do j = 1,nzread + is_pml((j-1)*nxread + (i-1)) = .true. + enddo + enddo + endif + ! PML Down + if (absorbbottom) then + do i = 1,nxread + do j = 1,NELEM_PML_THICKNESS + is_pml((j-1)*nxread + (i-1)) = .true. + enddo + enddo + endif + ! PML Up + if (absorbtop) then + do i = 1,nxread + do j = nzread-NELEM_PML_THICKNESS+1,nzread + is_pml((j-1)*nxread + (i-1)) = .true. + enddo + enddo + endif + + end subroutine locate_pml_elements_internal + +end module compute_elements_load_par diff --git a/meshfem2d/config.h b/meshfem2d/config.h new file mode 100644 index 00000000..f69816cd --- /dev/null +++ b/meshfem2d/config.h @@ -0,0 +1,107 @@ +/* setup/config.h. Generated from config.h.in by configure. */ +/* setup/config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to dummy `main' function (if any) required to link to the Fortran + libraries. */ +/* #undef FC_DUMMY_MAIN */ + +/* Define if F77 and FC dummy `main' functions are identical. */ +/* #undef FC_DUMMY_MAIN_EQ_F77 */ + +/* Define to a macro mangling the given C identifier (in lower and upper + case), which must not contain underscores, for linking with Fortran. */ +#define FC_FUNC(name, NAME) name##_ + +/* As FC_FUNC, but for C identifiers containing underscores. */ +#define FC_FUNC_(name, NAME) name##_ + +/* Define if emmintrin.h */ +#define HAVE_EMMINTRIN 1 + +/* Define if err.h */ +#define HAVE_ERR 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define if you have POSIX threads libraries and header files. */ +/* #undef HAVE_PTHREAD */ + +/* defined if Scotch is installed */ +#define HAVE_SCOTCH 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDIO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define if xmmintrin.h */ +#define HAVE_XMMINTRIN 1 + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "see the wiki" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "Specfem 2D" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "Specfem 2D 8.0.0" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "Specfem2D" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "8.0.0" + +/* Define to necessary symbol if this constant uses a non-standard name on + your system. */ +/* #undef PTHREAD_CREATE_JOINABLE */ + +/* Define GIT branch for package source. */ +#define SPECFEM2D_GIT_BRANCH "devel" + +/* Define date of GIT commit for package source. */ +#define SPECFEM2D_GIT_DATE "2023-03-21 19:54:51 +0100" + +/* Define GIT hash for package source. */ +#define SPECFEM2D_GIT_HASH "f8c66778e3bcff99be726113a1aca338255ed87e" + +/* Define git revision commit for package source. */ +#define SPECFEM2D_GIT_REVISION "v8.0.0-11-gf8c66778" + +/* Set to 0 if source is from GIT, 1 otherwise. */ +#define SPECFEM2D_RELEASE_VERSION 0 + +/* Define SPECFEM2D version */ +#define SPECFEM2D_VERSION "8.0.0" + +/* Define to 1 if all of the C90 standard headers exist (not just the ones + required in a freestanding environment). This macro is provided for + backward compatibility; new code need not use it. */ +#define STDC_HEADERS 1 + +/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a + `char[]'. */ +/* #undef YYTEXT_POINTER */ diff --git a/meshfem2d/constants.h b/meshfem2d/constants.h new file mode 100644 index 00000000..c0e984ee --- /dev/null +++ b/meshfem2d/constants.h @@ -0,0 +1,491 @@ +!===================================================================== +! +! S P E C F E M 2 D +! +!===================================================================== + +! setup/constants.h. Generated from constants.h.in by configure. + +! +! solver in single or double precision depending on the machine (4 or 8 bytes) +! +! ALSO CHANGE FILE precision.h ACCORDINGLY +! + integer, parameter :: SIZE_REAL = 4 + integer, parameter :: SIZE_DOUBLE = 8 + + +! set to SIZE_REAL to run in single precision +! set to SIZE_DOUBLE to run in double precision (increases memory size by 2) +! +! DO CHANGE precision.h accordingly +! + integer, parameter :: CUSTOM_REAL = SIZE_DOUBLE + +! Kind of some integers (such as NSTEP). Beware, if you change this the compiler may raise an issue, many lines would have to +! be updated to do this properly + integer, parameter :: RegInt_K = selected_int_kind(8) + +!----------- parameters that can be changed by the user ----------- + +!!----------------------------------------------------------- +!! +!! Gauss-Lobatto-Legendre resolution +!! +!!----------------------------------------------------------- + +! number of Gauss-Lobatto-Legendre (GLL) points (i.e., polynomial degree + 1) + integer, parameter :: NGLLX = 5 + +! number of Gauss-Lobatto-Jacobi (GLJ) points in the axial elements (i.e., polynomial degree + 1) +! the code does NOT work if NGLJ /= NGLLX so far + integer, parameter :: NGLJ = NGLLX + +! the code does NOT work if NGLLZ /= NGLLX because it then cannot handle a non-structured mesh +! due to non matching polynomial degrees along common edges + integer, parameter :: NGLLZ = NGLLX + +!!----------------------------------------------------------- +!! +!! I/O output +!! +!!----------------------------------------------------------- + +! input, output and main MPI I/O files +! note: careful with these unit numbers, we mostly use units in the 40-50 range. +! Cray Fortran e.g. reserves 0,5,6 (standard error,input,output units) and 100,101,102 (input,output,error unit) +! input and output files + integer, parameter :: ISTANDARD_OUTPUT = 6 + integer, parameter :: IIN = 40, IOUT = 41 + +! uncomment this to write to standard output (i.e. to the screen) + integer, parameter :: IMAIN = ISTANDARD_OUTPUT +! uncomment this to write messages to a text file +! integer, parameter :: IMAIN = 42 + + integer, parameter :: IOUT_UNDO_ATT = 45 + integer, parameter :: IIN_UNDO_ATT = IOUT_UNDO_ATT + +! output file for energy + integer, parameter :: IOUT_ENERGY = 77 + +! output file for visualizations + integer, parameter :: IOUT_VIS = 50, IOUT_VTK = 51 + +!!----------------------------------------------------------- +!! +!! source/receiver setup +!! +!!----------------------------------------------------------- + +! interpolates position to find the best possible location for the source, between GLL points if needed. +! note: this can be turned off to speedup location search and locate the source at the closest GLL point instead. + logical, parameter :: USE_BEST_LOCATION_FOR_SOURCE = .true. + +! maximum length of station and network name for receivers + integer, parameter :: MAX_LENGTH_STATION_NAME = 32 + integer, parameter :: MAX_LENGTH_NETWORK_NAME = 8 + +! we mimic a triangle of half duration equal to half_duration_triangle +! using a Gaussian having a very close shape, as explained in Figure 4.2 +! of the manual. This source decay rate to mimic an equivalent triangle +! was found by trial and error + double precision, parameter :: SOURCE_DECAY_MIMIC_TRIANGLE = 1.628d0 + +! Ormbsy wavelet dominant frequency +! (for Marmousi2 modeling, dominant frequency must be 35 Hz) + double precision, parameter :: F_ORMSBY = 35.0 + + +!!----------------------------------------------------------- +!! +!! poroelasticity +!! +!!----------------------------------------------------------- + +! viscid flow controlled by fluid viscosity eta_f parameter (eta_f is zero for no viscosity) +! for ideal fluid (neglecting viscosity) and inviscid flow set to .false. + logical, parameter :: USE_PORO_VISCOUS_DAMPING = .true. + + +!!----------------------------------------------------------- +!! +!! attenuation +!! +!!----------------------------------------------------------- + +! can call the old C routine to compute the Zener Standard Linear Solids (SLSs) attenuation relaxation times instead of +! the initial (least squares) step of the SolvOpt() routine when USE_SOLVOPT is false, for compatibility with older benchmarks + logical, parameter :: USE_OLD_C_ATTENUATION_ROUTINE_INSTEAD = .false. + +! for viscoacousticity + logical, parameter :: USE_A_STRONG_FORMULATION_FOR_E1 = .false. + +!!----------------------------------------------------------- +!! +!! noise simulations +!! +!!----------------------------------------------------------- + +! For noise tomography only - specify whether to reconstruct ensemble forward +! wavefield by saving everywhere or by saving only at the boundaries (the +! latter usually much faster but prone to artefacts) + logical, parameter :: NOISE_SAVE_EVERYWHERE = .false. + +! this is movie file output only in the case of noise tomography + logical,parameter :: NOISE_MOVIE_OUTPUT = .false. + +!!----------------------------------------------------------- +!! +!! kernels +!! +!!----------------------------------------------------------- + +! kernel debugging +! flag to save GLL weights for kernel benchmark examples + logical,parameter :: SAVE_WEIGHTS = .true. + +!!----------------------------------------------------------- +!! +!! image plots +!! +!!----------------------------------------------------------- + +! maximum size of the X and Z directions of a JPEG image generated by the display routine + integer, parameter :: NX_NZ_IMAGE_MAX = 60000 + +! in PostScript files about mesh quality, show all elements above this threshold + double precision, parameter :: THRESHOLD_POSTSCRIPT = 95.d0 / 100.d0 + +! option to display only part of the mesh and not the whole mesh, +! for instance to analyze Cuthill-McKee mesh partitioning etc. +! Possible values are: +! 1: display all the elements (i.e., the whole mesh) +! 2: display inner elements only +! 3: display outer elements only +! 4: display a fixed number of elements (in each partition) only + integer, parameter :: DISPLAY_SUBSET_OPTION = 1 +! number of spectral elements to display in each subset when a fixed subset size is used (option 4 above) + integer, parameter :: NSPEC_DISPLAY_SUBSET = 2300 + +! X and Z axis origin of PostScript plot in centimeters + double precision, parameter :: ORIG_X = 2.4d0 + double precision, parameter :: ORIG_Z = 2.9d0 + +! dot to centimeter conversion for PostScript + double precision, parameter :: CENTIM = 28.5d0 + +! parameters for arrows for PostScript snapshot + double precision, parameter :: ARROW_ANGLE = 20.d0 + double precision, parameter :: ARROW_RATIO = 0.40d0 + +! size of frame used for Postscript display in percentage of the size of the page + double precision, parameter :: RPERCENTX = 70.0d0,RPERCENTZ = 77.0d0 + +! color images (1 == colored / 0 == black and white) (both PostScript and JPEG) + integer,parameter :: DISPLAY_COLORS = 1 + +! adds numbers to mesh elements (1 == on / 0 == off) + integer,parameter :: DISPLAY_ELEMENT_NUMBERS_POSTSCRIPT = 0 + +! for PMLs +! remove the PMLs from JPEG images if needed: set the vector field to zero there + logical, parameter :: REMOVE_PMLS_FROM_JPEG_IMAGES = .true. + +! display all the PML layers in a different (constant) color in the PostScript vector plots if needed + logical, parameter :: DISPLAY_PML_IN_DIFFERENT_COLOR = .true. + integer, parameter :: ICOLOR_FOR_PML_DISPLAY = 100 + +!!----------------------------------------------------------- +!! +!! partitioning +!! +!!----------------------------------------------------------- + +!--- beginning of Nicolas Le Goff's constants for an unstructured CUBIT/METIS/SCOTCH mesh + +! maximum number of neighbors per element + integer, parameter :: MAX_NEIGHBORS = 40 + +! maximum number of elements that can contain the same node + integer, parameter :: MAX_NSIZE_SHARED = 40 + +!--- end of Nicolas Le Goff's constants for an unstructured CUBIT/METIS/SCOTCH mesh + +! select fast (Paul Fischer) or slow (topology only) global numbering algorithm + logical, parameter :: FAST_NUMBERING = .true. + +! relative mesh tolerance for fast global numbering + double precision, parameter :: SMALLVALTOL = 1.d-10 + +! outputs mesh files (partitioning) in VTK format + logical, parameter :: SAVE_MESHFILES_VTK_FORMAT = .true. + +!!----------------------------------------------------------- +!! +!! add a random perturbation to the mesh (as in Figure 3.12 of the PhD thesis of Dimitri Komatitsch for instance). +!! Currently only implemented for a mesh generated by the internal mesher (meshfem2D). +!! +!!----------------------------------------------------------- + +! add a random perturbation to the mesh + logical, parameter :: ADD_RANDOM_PERTURBATION_TO_THE_MESH = .false. + +! maximum absolute value of the size of the perturbation (i.e. mesh point displacement) around a given mesh point (in meters) + double precision, parameter :: RANDOM_AMPLITUDE_ALONG_X = 7.d0 + double precision, parameter :: RANDOM_AMPLITUDE_ALONG_Z = 6.d0 + +! apply the perturbation in a disk around the source only + logical, parameter :: ADD_PERTURBATION_AROUND_SOURCE_ONLY = .false. +! radius of the disk to use in that case (in meters) + double precision, parameter :: RADIUS_TO_USE_AROUND_THE_SOURCE = 300.d0 + +!!----------------------------------------------------------- +!! +!! small crack +!! +!!----------------------------------------------------------- + +! add a small crack (discontinuity) in the medium manually + logical, parameter :: ADD_A_SMALL_CRACK_IN_THE_MEDIUM = .false. + +! must be set equal to the number of spectral elements on one vertical side of the crack + integer, parameter :: NB_POINTS_TO_ADD_TO_NPGEO = 3 + +!!----------------------------------------------------------- +!! +!! CPML perfectly matched absorbing layers +!! +!!----------------------------------------------------------- + +! flags for CPML absorbing boundaries + integer, parameter :: CPML_X_ONLY = 1 + integer, parameter :: CPML_Z_ONLY = 2 + integer, parameter :: CPML_XZ = 3 + +!!----------------------------------------------------------- +!! +!! mesh coloring for GPUs (not needed any more, obsolete) +!! +!!----------------------------------------------------------- + +! for CUDA mode + logical, parameter :: USE_MESH_COLORING_GPU = .false. + +!!----------------------------------------------------------- +!! +!! enforces wavefield +!! +!!----------------------------------------------------------- + +! This option is used when we want to enforce fields values +! somewhere + logical, parameter :: USE_ENFORCE_FIELDS = .false. + +!------------------------------------------------------ +!----------- do not modify anything below ------------- +!------------------------------------------------------ + +! number of spatial dimensions + integer, parameter :: NDIM = 2 + +! number of edges and corners of each element + integer, parameter :: NEDGES = 4 + integer, parameter :: NCORNERS = 4 + +! number of points per surface element + integer, parameter :: NGLLSQUARE = NGLLX * NGLLZ + +! displacement threshold above which we consider the code became unstable + double precision, parameter :: STABILITY_THRESHOLD = 1.d+25 + +! a few useful constants + double precision, parameter :: ZERO = 0.d0,ONE = 1.d0 + double precision, parameter :: HALF = 0.5d0,TWO = 2.d0,QUARTER = 0.25d0 + +! pi + double precision, parameter :: PI = 3.141592653589793d0 + double precision, parameter :: TWO_PI = 2.d0 * PI + +! 2/3 + double precision, parameter :: TWO_THIRDS = 2.d0/3.d0 + +! 4/3 + double precision, parameter :: FOUR_THIRDS = 4.d0/3.d0 + +! 1/24 + double precision, parameter :: ONE_OVER_24 = 1.d0 / 24.d0 + +! very large and very small values + double precision, parameter :: HUGEVAL = 1.d+30,TINYVAL = 1.d-9,VERYTINYVAL = 1.d-23 + +! do not use tags for MPI messages, use dummy tag instead + integer, parameter :: itag = 0 + +! for the Gauss-Lobatto-Legendre points and weights + double precision, parameter :: GAUSSALPHA = 0.d0,GAUSSBETA = 0.d0 + +! number of lines per source in SOURCE file + integer, parameter :: NLINES_PER_SOURCE = 16 + +! number of iterations to solve the system for xi and eta +! setting it to 5 instead of 4 ensures that the result obtained is not compiler dependent +! (when using 4 only some small discrepancies were observed) + integer, parameter :: NUM_ITER = 5 + +! ignore variable name field (junk) at the beginning of each input line + logical, parameter :: IGNORE_JUNK = .true., DONT_IGNORE_JUNK = .false. + +! maximum length of strings used for paths, reading from files, etc. + integer, parameter :: MAX_STRING_LEN = 512 + + +!!----------------------------------------------------------- +!! +!! DOMAINS +!! +!!----------------------------------------------------------- + +! flag to indicate an isotropic elastic/acoustic material +! flag to indicate an anisotropic material +! flag to indicate a poroelastic material + integer, parameter :: ISOTROPIC_MATERIAL = 1 + integer, parameter :: ANISOTROPIC_MATERIAL = 2 + integer, parameter :: POROELASTIC_MATERIAL = 3 + +! file number for interface file + integer, parameter :: IIN_INTERFACES = 15 + + +! flags for Stacey absorbing boundaries + integer, parameter :: IBOTTOM = 1 + integer, parameter :: IRIGHT = 2 + integer, parameter :: ITOP = 3 + integer, parameter :: ILEFT = 4 + + integer, parameter :: IEDGE1 = 1 ! bottom + integer, parameter :: IEDGE2 = 2 ! right + integer, parameter :: IEDGE3 = 3 ! top + integer, parameter :: IEDGE4 = 4 ! left + +! flag to indicate an element type +! material domain ids (acoustic/elastic/poroelastic/gravitoacoustic) + integer, parameter :: IDOMAIN_ACOUSTIC = 1 + integer, parameter :: IDOMAIN_ELASTIC = 2 + integer, parameter :: IDOMAIN_POROELASTIC = 3 + integer, parameter :: IDOMAIN_GRAVITOACOUSTIC = 4 + + +!!----------------------------------------------------------- +!! +!! for LDDRK high-order time scheme +!! +!!----------------------------------------------------------- + +! Low-dissipation and low-dispersion fourth-order Runge-Kutta algorithm +! +! reference: +! J. Berland, C. Bogey, and C. Bailly. +! Low-dissipation and low-dispersion fourth-order Runge-Kutta algorithm. +! Computers and Fluids, 35:1459-1463, 2006 +! +! see: http://www.sciencedirect.com/science/article/pii/S0045793005000575?np=y + +! maximum number of stages for optimized (for reduced storage) LDDRK4-6 Runge-Kutta time scheme + integer, parameter :: NSTAGE_LDDRK = 6 + +! coefficients from Table 1, Berland et al. (2006) +! (parameters used in LDDRK scheme, from equation (2) of Berland et al.) + real(kind=CUSTOM_REAL), dimension(NSTAGE_LDDRK), parameter :: ALPHA_LDDRK = & + (/0.0_CUSTOM_REAL,-0.737101392796_CUSTOM_REAL, -1.634740794341_CUSTOM_REAL, & + -0.744739003780_CUSTOM_REAL,-1.469897351522_CUSTOM_REAL,-2.813971388035_CUSTOM_REAL/) + + real(kind=CUSTOM_REAL), dimension(NSTAGE_LDDRK), parameter :: BETA_LDDRK = & + (/0.032918605146_CUSTOM_REAL,0.823256998200_CUSTOM_REAL,0.381530948900_CUSTOM_REAL, & + 0.200092213184_CUSTOM_REAL,1.718581042715_CUSTOM_REAL,0.27_CUSTOM_REAL/) + + real(kind=CUSTOM_REAL), dimension(NSTAGE_LDDRK), parameter :: C_LDDRK = & + (/0.0_CUSTOM_REAL,0.032918605146_CUSTOM_REAL,0.249351723343_CUSTOM_REAL, & + 0.466911705055_CUSTOM_REAL,0.582030414044_CUSTOM_REAL,0.847252983783_CUSTOM_REAL/) + +!!----------------------------------------------------------- +!! +!! for RK4 - classical Runge-Kutta 4-th order scheme +!! +!!----------------------------------------------------------- + +! https://en.wikipedia.org/wiki/Runge-Kutta_methods +! https://scicomp.stackexchange.com/questions/22025/runge-kutta-for-wave-equation +! +! first-order derivatives for runge-kutta: +! dU/dt = A U(t) +! with +! U = [ veloc | -> dU/dt = [ d/dt veloc | = [ K(t,displ) + F(t) | = A U(t) +! | displ ] | d/dt displ ] | veloc(t) | +! +! k1 = A U(tn) +! k2 = A { + !U(tn + dt / 2) + 1 / 2 dt k1 } +! k3 = A { + !U(tn + dt / 2) + 1 / 2 dt k2 } +! k4 = A { + !U(tn + dt) + dt k3 } +! +! U(tn + dt) = 1/6 * dt * { k1 + 2 k2 + 2 k3 + k4 } + + integer, parameter :: NSTAGE_RK4 = 4 + + real(kind=CUSTOM_REAL), dimension(NSTAGE_RK4), parameter :: ALPHA_RK4 = & + (/ 0.0_CUSTOM_REAL, 0.5_CUSTOM_REAL, 0.5_CUSTOM_REAL, 1.0_CUSTOM_REAL /) + + real(kind=CUSTOM_REAL), dimension(NSTAGE_RK4), parameter :: BETA_RK4 = & + (/ 1.0_CUSTOM_REAL/6.0_CUSTOM_REAL, 1.0_CUSTOM_REAL/3.0_CUSTOM_REAL, & + 1.0_CUSTOM_REAL/3.0_CUSTOM_REAL, 1.0_CUSTOM_REAL/6.0_CUSTOM_REAL /) + + real(kind=CUSTOM_REAL), dimension(NSTAGE_RK4), parameter :: C_RK4 = & + (/ 0.0_CUSTOM_REAL, 0.5_CUSTOM_REAL, 0.5_CUSTOM_REAL, 1.0_CUSTOM_REAL /) + +!!----------------------------------------------------------- +!! +!! symplectic time scheme - Position-Extended Forest-Ruth-Like (PEFRL) scheme (4th order) +!! +!!----------------------------------------------------------- + +! see reference: +! Omelyan, I.M. Mryglod and R. Folk, 2002. +! Optimized Forest-Ruth- and Suzuki-like algorithms for integration of motion in many-body systems, +! Computer Physics communications 146, 188 +! http://arxiv.org/abs/cond-mat/0110585 + + integer, parameter :: NSTAGE_SYMPLECTIC = 4 + + ! PEFRL scheme coefficients (see Omelyan et al, 2002, eq. (20)) + double precision, parameter :: PEFRL_xi = 0.1786178958448091d0 + double precision, parameter :: PEFRL_lambda = -0.2123418310626054d0 + double precision, parameter :: PEFRL_chi = -0.06626458266981849d0 + + real(kind=CUSTOM_REAL), dimension(NSTAGE_SYMPLECTIC), parameter :: ALPHA_SYMPLECTIC = & + (/ PEFRL_xi, PEFRL_chi, 1.0_CUSTOM_REAL - 2.0_CUSTOM_REAL*(PEFRL_chi + PEFRL_xi), PEFRL_chi /) + + real(kind=CUSTOM_REAL), dimension(NSTAGE_SYMPLECTIC), parameter :: BETA_SYMPLECTIC = & + (/ 0.5_CUSTOM_REAL - PEFRL_lambda, PEFRL_lambda, PEFRL_lambda, 0.5_CUSTOM_REAL - PEFRL_lambda /) + + !! also mentioned: + !! velocity Forest-Ruth (VFR) scheme (4th order) + !! with theta = 1./(2 - 2**(1/3) ) ~ 1.3512071919596578 + !double precision, parameter :: VFR_theta = 1.3512071919596578d0 + ! + !real(kind=CUSTOM_REAL), dimension(NSTAGE_SYMPLECTIC), parameter :: ALPHA_SYMPLECTIC = & + ! (/ 0.d0, VFR_theta, 1.0_CUSTOM_REAL - 2.0_CUSTOM_REAL*VFR_theta, VFR_theta /) + !real(kind=CUSTOM_REAL), dimension(NSTAGE_SYMPLECTIC), parameter :: BETA_SYMPLECTIC = & + ! (/ 0.5d0 * VFR_theta, 0.5d0 * (1.d0 - VFR_theta), 0.5d0 * (1.d0 - VFR_theta), 0.5d0 * VFR_theta /) + +!!----------------------------------------------------------- +!! +!! directory structure +!! +!!----------------------------------------------------------- + +! paths for inputs and outputs files + character(len=*), parameter :: IN_DATA_FILES = './DATA/' + character(len=*), parameter :: OUTPUT_FILES_BASE = './OUTPUT_FILES/' diff --git a/meshfem2d/decompose_mesh.F90 b/meshfem2d/decompose_mesh.F90 new file mode 100644 index 00000000..e299f5da --- /dev/null +++ b/meshfem2d/decompose_mesh.F90 @@ -0,0 +1,282 @@ +!======================================================================== +! +! S P E C F E M 2 D +! ----------------- +! +! Main historical authors: Dimitri Komatitsch and Jeroen Tromp +! CNRS, France +! and Princeton University, USA +! (there are currently many more authors!) +! (c) October 2017 +! +! This software is a computer program whose purpose is to solve +! the two-dimensional viscoelastic anisotropic or poroelastic wave equation +! using a spectral-element method (SEM). +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 3 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License along +! with this program; if not, write to the Free Software Foundation, Inc., +! 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +! +! The full text of the license is available in file "LICENSE". +! +!======================================================================== + + + subroutine decompose_mesh() + + use constants, only: IMAIN,MAX_NEIGHBORS,NCORNERS,MAX_NSIZE_SHARED,ADD_A_SMALL_CRACK_IN_THE_MEDIUM,myrank + + use shared_parameters, only: NPROC,ADD_PERIODIC_CONDITIONS,PERIODIC_HORIZ_DIST, & + NGNOD,nbmodels,num_material,PARTITIONING_TYPE,phi_read + + use part_unstruct_par, only: part,nelmnts,xadj_g,adjncy_g,elmnts,elmnts_bis,nb_edges, & + nnodes_elmnts,nnodes,nodes_elmnts,nodes_coords,ninterfaces + + use decompose_par + use compute_elements_load_par + + implicit none + + ! local parameters + integer :: i, iproc, ier + + ! user output + if (myrank == 0) then + write(IMAIN,*) ' decomposing mesh using NPROC = ',NPROC + call flush_IMAIN() + endif + + ! allocates and initializes partitioning of elements + allocate(part(0:nelmnts-1),stat=ier) + if (ier /= 0) call stop_the_code('Error allocating partition array') + part(:) = -1 + + ! connectivity + if (NPROC > 1) then + allocate(xadj_g(0:nelmnts), & + adjncy_g(0:MAX_NEIGHBORS*nelmnts-1),stat=ier) + if (ier /= 0) call stop_the_code('Error allocating connectivity arrays') + xadj_g(:) = 0 + adjncy_g(:) = -1 + endif + + ! construction of the graph + ! user output + if (myrank == 0) then + write(IMAIN,*) + write(IMAIN,*) 'Graph construction:' + call flush_IMAIN() + endif + + ! if NGNOD == 9, we work on a subarray of elements that represents the elements with four nodes (four corners) only + ! because the adjacency of the mesh elements can be entirely determined from the knowledge of the four corners only + if (NGNOD == 9) then + allocate(elmnts_bis(0:NCORNERS*nelmnts-1),stat=ier) + if (ier /= 0) call stop_the_code('Error allocating elmnts_bis array') + + do i = 0, nelmnts-1 + elmnts_bis(i*NCORNERS:i*NCORNERS+NCORNERS-1) = elmnts(i*NGNOD:i*NGNOD+NCORNERS-1) + enddo + + if (NPROC > 1) then +!! DK DK fixed problem in the previous implementation by Nicolas Le Goff: +!! DK DK (nxread+1)*(nzread+1) is OK for a regular internal mesh only, not for non structured external meshes +!! DK DK call mesh2dual_ncommonnodes(nelmnts, (nxread+1)*(nzread+1), & +!! DK DK elmnts_bis, xadj, adjncy, nnodes_elmnts, nodes_elmnts,1) +!! DK DK the subset of element corners is not renumbered therefore we must still use the nnodes computed for 9 nodes here + ! determines maximum neighbors based on 1 common node + call mesh2dual_ncommonnodes(elmnts_bis,1,xadj_g,adjncy_g) + endif + else + if (NPROC > 1) then + ! determines maximum neighbors based on 1 common node + call mesh2dual_ncommonnodes(elmnts,1,xadj_g,adjncy_g) + endif + endif + ! user output + if (myrank == 0) then + write(IMAIN,*) ' graph adjacency done' + write(IMAIN,*) + call flush_IMAIN() + endif + + ! partitions + if (NPROC == 1) then + part(:) = 0 ! single process has rank 0 + else + ! number of common edges + nb_edges = xadj_g(nelmnts) + + ! compute elements load for efficient partitioning (a PML element take more time to calculate than a fluid element for ex) + call compute_elements_load() + + ! partitioning + select case (PARTITIONING_TYPE) + case(1) + ! analytical + if (myrank == 0) then + write(IMAIN,*) + write(IMAIN,*) 'Partitioning type: analytical' + write(IMAIN,*) + call flush_IMAIN() + endif + + do iproc = 0, NPROC-2 + part(iproc*floor(real(nelmnts)/real(NPROC)):(iproc+1)*floor(real(nelmnts)/real(NPROC))-1) = iproc + enddo + part(floor(real(nelmnts)/real(NPROC))*(NPROC-1):nelmnts-1) = NPROC - 1 + + case(2) + ! METIS + if (myrank == 0) then + write(IMAIN,*) + write(IMAIN,*) 'Partitioning type: METIS' + write(IMAIN,*) + call flush_IMAIN() + endif + + call metis_partitioning() + + case(3) + ! SCOTCH + if (myrank == 0) then + write(IMAIN,*) + write(IMAIN,*) 'Partitioning type: SCOTCH' + write(IMAIN,*) + call flush_IMAIN() + endif + + call scotch_partitioning() + + case default + call stop_the_code('Error invalid partitioning type value! must be 1, 2 or 3, please check your Par_file...') + end select + + endif + + ! user output + if (myrank == 0) then + write(IMAIN,*) 'Coupled interfaces:' + call flush_IMAIN() + endif + + ! fluid-solid edges: coupled elements are transferred to the same partition + if (NGNOD == 9) then + call acoustic_elastic_repartitioning(elmnts_bis, nbmodels, phi_read, num_material, NPROC) + else + call acoustic_elastic_repartitioning(elmnts, nbmodels, phi_read, num_material, NPROC) + endif + + ! fluid-porous edges: coupled elements are transferred to the same partition + if (NGNOD == 9) then + call acoustic_poro_repartitioning(elmnts_bis, nbmodels, phi_read, num_material, NPROC) + else + call acoustic_poro_repartitioning(elmnts, nbmodels, phi_read, num_material, NPROC) + endif + + ! porous-solid edges: coupled elements are transferred to the same partition + if (NGNOD == 9) then + call poro_elastic_repartitioning(elmnts_bis, nbmodels, phi_read, num_material, NPROC) + else + call poro_elastic_repartitioning(elmnts, nbmodels, phi_read, num_material, NPROC) + endif + + ! periodic edges: coupled elements are transferred to the same partition + if (ADD_PERIODIC_CONDITIONS .and. NPROC > 1) then + if (NGNOD == 9) then + call periodic_edges_repartitioning(elmnts_bis,nnodes,nodes_coords,PERIODIC_HORIZ_DIST) + else + call periodic_edges_repartitioning(elmnts,nnodes,nodes_coords,PERIODIC_HORIZ_DIST) + endif + endif + + ! manual crack elements + if (ADD_A_SMALL_CRACK_IN_THE_MEDIUM .and. NPROC > 1) then + ! safety check + if (NGNOD /= 4) then + call stop_the_code('must currently have NGNOD == 4 when adding a crack manually') + else + call manual_crack_repartitioning(num_material,NPROC) + endif + endif + + ! user output + if (myrank == 0) then + write(IMAIN,*) + write(IMAIN,*) 'Local numbering:' + write(IMAIN,*) ' NPROC: ', NPROC + write(IMAIN,*) ' number of elements: ',nelmnts + call flush_IMAIN() + endif + + ! local number of each element for each partition + call construct_glob2loc_elmnts(NPROC) + + if (NGNOD == 9) then + if (allocated(nnodes_elmnts) ) deallocate(nnodes_elmnts) + if (allocated(nodes_elmnts) ) deallocate(nodes_elmnts) + + allocate(nnodes_elmnts(0:nnodes-1)) + allocate(nodes_elmnts(0:MAX_NSIZE_SHARED*nnodes-1)) + + nnodes_elmnts(:) = 0 + nodes_elmnts(:) = 0 + do i = 0, NGNOD*nelmnts-1 + nodes_elmnts(elmnts(i)*MAX_NSIZE_SHARED + nnodes_elmnts(elmnts(i))) = i/NGNOD + nnodes_elmnts(elmnts(i)) = nnodes_elmnts(elmnts(i)) + 1 + enddo + else + if (NPROC < 2) then + if (.not. allocated(nnodes_elmnts) ) allocate(nnodes_elmnts(0:nnodes-1)) + if (.not. allocated(nodes_elmnts) ) allocate(nodes_elmnts(0:MAX_NSIZE_SHARED*nnodes-1)) + + nnodes_elmnts(:) = 0 + nodes_elmnts(:) = 0 + + do i = 0, NGNOD*nelmnts-1 + nodes_elmnts(elmnts(i)*MAX_NSIZE_SHARED+nnodes_elmnts(elmnts(i))) = i/NGNOD + nnodes_elmnts(elmnts(i)) = nnodes_elmnts(elmnts(i)) + 1 + enddo + endif + endif + + ! local number of each node for each partition + call Construct_glob2loc_nodes(NPROC) + + ! construct the interfaces between partitions (used for MPI assembly) + if (NPROC > 1) then + if (NGNOD == 9) then + call Construct_interfaces(NPROC, elmnts_bis, & + nbmodels, phi_read, num_material) + else + call Construct_interfaces(NPROC, elmnts, & + nbmodels, phi_read, num_material) + endif + allocate(my_interfaces(0:ninterfaces-1)) + allocate(my_nb_interfaces(0:ninterfaces-1)) + else + ! dummy allocation + ninterfaces=0 + allocate(my_interfaces(0:ninterfaces-1)) + allocate(my_nb_interfaces(0:ninterfaces-1)) + endif + + ! user output + if (myrank == 0) then + write(IMAIN,*) + write(IMAIN,*) 'decompose mesh all done' + write(IMAIN,*) + call flush_IMAIN() + endif + + end subroutine decompose_mesh diff --git a/meshfem2d/define_shape_functions.f90 b/meshfem2d/define_shape_functions.f90 new file mode 100644 index 00000000..26ebf136 --- /dev/null +++ b/meshfem2d/define_shape_functions.f90 @@ -0,0 +1,163 @@ +!======================================================================== +! +! S P E C F E M 2 D +! ----------------- +! +! Main historical authors: Dimitri Komatitsch and Jeroen Tromp +! CNRS, France +! and Princeton University, USA +! (there are currently many more authors!) +! (c) October 2017 +! +! This software is a computer program whose purpose is to solve +! the two-dimensional viscoelastic anisotropic or poroelastic wave equation +! using a spectral-element method (SEM). +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 3 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License along +! with this program; if not, write to the Free Software Foundation, Inc., +! 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +! +! The full text of the license is available in file "LICENSE". +! +!======================================================================== + + subroutine define_shape_functions(shape2D,dershape2D,xi,gamma,NGNOD) + +!======================================================================= +! +! Set up the shape functions for the superparametric transformation +! (i.e. the geometry is defined with lower-order functions than the unknowns +! of the problem; see for instance Chapter 16 of the finite-element course of +! Carlos Felippa in Colorado for a discussion about this). +! The routine can handle 4 or 9 control nodes defined as follows: +! +! 4 . . . . 7 . . . . 3 +! . . +! . gamma . +! . . +! 8 9 xi 6 +! . . +! . . +! . . +! 1 . . . . 5 . . . . 2 +! +! Local coordinate system : s,t +! +!======================================================================= + + use constants, only: QUARTER,HALF,ONE,TWO,TINYVAL,NDIM + + implicit none + + integer,intent(in) :: NGNOD + + double precision,intent(out) :: shape2D(NGNOD) + double precision,intent(out) :: dershape2D(NDIM,NGNOD) + double precision,intent(in) :: xi,gamma + + ! local parameters + double precision :: s,t,sp,sm,tp,tm,s2,t2,ss,tt,st + +! +!---- set up the shape functions and their local derivatives +! + s = xi + t = gamma + +!---- 4-node element + if (NGNOD == 4) then + sp = s + ONE + sm = s - ONE + tp = t + ONE + tm = t - ONE + +!---- corner nodes + shape2D(1) = QUARTER * sm * tm + shape2D(2) = - QUARTER * sp * tm + shape2D(3) = QUARTER * sp * tp + shape2D(4) = - QUARTER * sm * tp + + dershape2D(1,1) = QUARTER * tm + dershape2D(1,2) = - QUARTER * tm + dershape2D(1,3) = QUARTER * tp + dershape2D(1,4) = - QUARTER * tp + + dershape2D(2,1) = QUARTER * sm + dershape2D(2,2) = - QUARTER * sp + dershape2D(2,3) = QUARTER * sp + dershape2D(2,4) = - QUARTER * sm + +!---- 9-node element + else if (NGNOD == 9) then + + sp = s + ONE + sm = s - ONE + tp = t + ONE + tm = t - ONE + s2 = s * TWO + t2 = t * TWO + ss = s * s + tt = t * t + st = s * t + +!---- corner nodes + shape2D(1) = QUARTER * sm * st * tm + shape2D(2) = QUARTER * sp * st * tm + shape2D(3) = QUARTER * sp * st * tp + shape2D(4) = QUARTER * sm * st * tp + + dershape2D(1,1) = QUARTER * tm * t * (s2 - ONE) + dershape2D(1,2) = QUARTER * tm * t * (s2 + ONE) + dershape2D(1,3) = QUARTER * tp * t * (s2 + ONE) + dershape2D(1,4) = QUARTER * tp * t * (s2 - ONE) + + dershape2D(2,1) = QUARTER * sm * s * (t2 - ONE) + dershape2D(2,2) = QUARTER * sp * s * (t2 - ONE) + dershape2D(2,3) = QUARTER * sp * s * (t2 + ONE) + dershape2D(2,4) = QUARTER * sm * s * (t2 + ONE) + +!---- midside nodes + shape2D(5) = HALF * tm * t * (ONE - ss) + shape2D(6) = HALF * sp * s * (ONE - tt) + shape2D(7) = HALF * tp * t * (ONE - ss) + shape2D(8) = HALF * sm * s * (ONE - tt) + + dershape2D(1,5) = -ONE * st * tm + dershape2D(1,6) = HALF * (ONE - tt) * (s2 + ONE) + dershape2D(1,7) = -ONE * st * tp + dershape2D(1,8) = HALF * (ONE - tt) * (s2 - ONE) + + dershape2D(2,5) = HALF * (ONE - ss) * (t2 - ONE) + dershape2D(2,6) = -ONE * st * sp + dershape2D(2,7) = HALF * (ONE - ss) * (t2 + ONE) + dershape2D(2,8) = -ONE * st * sm + +!---- center node + shape2D(9) = (ONE - ss) * (ONE - tt) + + dershape2D(1,9) = -ONE * s2 * (ONE - tt) + dershape2D(2,9) = -ONE * t2 * (ONE - ss) + + else + call stop_the_code('Error: wrong number of control nodes') + endif + +!--- check the shape functions and their derivatives + ! sum of shape functions should be one + if (abs(sum(shape2D)-ONE) > TINYVAL) call stop_the_code('Error shape functions') + + ! sum of derivatives of shape functions should be zero + if (abs(sum(dershape2D(1,:))) > TINYVAL) call stop_the_code('Error deriv xi shape functions') + if (abs(sum(dershape2D(2,:))) > TINYVAL) call stop_the_code('Error deriv gamma shape functions') + + end subroutine define_shape_functions diff --git a/meshfem2d/determine_abs_surface.f90 b/meshfem2d/determine_abs_surface.f90 new file mode 100644 index 00000000..84c53297 --- /dev/null +++ b/meshfem2d/determine_abs_surface.f90 @@ -0,0 +1,122 @@ +!======================================================================== +! +! S P E C F E M 2 D +! ----------------- +! +! Main historical authors: Dimitri Komatitsch and Jeroen Tromp +! CNRS, France +! and Princeton University, USA +! (there are currently many more authors!) +! (c) October 2017 +! +! This software is a computer program whose purpose is to solve +! the two-dimensional viscoelastic anisotropic or poroelastic wave equation +! using a spectral-element method (SEM). +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 3 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License along +! with this program; if not, write to the Free Software Foundation, Inc., +! 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +! +! The full text of the license is available in file "LICENSE". +! +!======================================================================== + + + subroutine determine_abs_surface() + +! determines absorbing boundary elements + + use constants, only: IBOTTOM,IRIGHT,ITOP,ILEFT,IMAIN,myrank + + use part_unstruct_par, only: nelemabs,abs_surface,elmnts,nxread,nzread + + use shared_parameters, only: NGNOD,absorbbottom,absorbleft,absorbright,absorbtop + + implicit none + + ! local parameters + integer :: ix,iz + integer :: inumelem + + ! user output + if (myrank == 0) then + write(IMAIN,*) ' determining absorbing boundary surfaces...' + call flush_IMAIN() + endif + + ! + !--- definition of absorbing boundaries + ! + nelemabs = 0 + if (absorbbottom) nelemabs = nelemabs + nxread + if (absorbtop) nelemabs = nelemabs + nxread + if (absorbleft) nelemabs = nelemabs + nzread + if (absorbright) nelemabs = nelemabs + nzread + + allocate(abs_surface(5,nelemabs)) + abs_surface(:,:) = 0 + + ! generate the list of absorbing elements + if (nelemabs > 0) then + nelemabs = 0 + do iz = 1,nzread + do ix = 1,nxread + inumelem = (iz-1)*nxread + ix + if (absorbbottom .and. iz == 1) then + nelemabs = nelemabs + 1 + abs_surface(1,nelemabs) = inumelem-1 + abs_surface(2,nelemabs) = 2 + abs_surface(3,nelemabs) = elmnts(0+NGNOD*(inumelem-1)) + abs_surface(4,nelemabs) = elmnts(1+NGNOD*(inumelem-1)) + abs_surface(5,nelemabs) = IBOTTOM + !is_abs_surf(inumelem) = .true. + endif + if (absorbright .and. ix == nxread) then + nelemabs = nelemabs + 1 + abs_surface(1,nelemabs) = inumelem-1 + abs_surface(2,nelemabs) = 2 + abs_surface(3,nelemabs) = elmnts(1+NGNOD*(inumelem-1)) + abs_surface(4,nelemabs) = elmnts(2+NGNOD*(inumelem-1)) + abs_surface(5,nelemabs) = IRIGHT + !is_abs_surf(inumelem) = .true. + endif + if (absorbtop .and. iz == nzread) then + nelemabs = nelemabs + 1 + abs_surface(1,nelemabs) = inumelem-1 + abs_surface(2,nelemabs) = 2 + abs_surface(3,nelemabs) = elmnts(3+NGNOD*(inumelem-1)) + abs_surface(4,nelemabs) = elmnts(2+NGNOD*(inumelem-1)) + abs_surface(5,nelemabs) = ITOP + !is_abs_surf(inumelem) = .true. + endif + if (absorbleft .and. ix == 1) then + nelemabs = nelemabs + 1 + abs_surface(1,nelemabs) = inumelem-1 + abs_surface(2,nelemabs) = 2 + abs_surface(3,nelemabs) = elmnts(0+NGNOD*(inumelem-1)) + abs_surface(4,nelemabs) = elmnts(3+NGNOD*(inumelem-1)) + abs_surface(5,nelemabs) = ILEFT + !is_abs_surf(inumelem) = .true. + endif + enddo + enddo + endif + + ! user output + if (myrank == 0) then + write(IMAIN,*) ' number of elements with absorbing boundaries = ',nelemabs + write(IMAIN,*) + call flush_IMAIN() + endif + + end subroutine determine_abs_surface diff --git a/meshfem2d/determine_acoustic_surface.f90 b/meshfem2d/determine_acoustic_surface.f90 new file mode 100644 index 00000000..ecfde1a8 --- /dev/null +++ b/meshfem2d/determine_acoustic_surface.f90 @@ -0,0 +1,171 @@ +!======================================================================== +! +! S P E C F E M 2 D +! ----------------- +! +! Main historical authors: Dimitri Komatitsch and Jeroen Tromp +! CNRS, France +! and Princeton University, USA +! (there are currently many more authors!) +! (c) October 2017 +! +! This software is a computer program whose purpose is to solve +! the two-dimensional viscoelastic anisotropic or poroelastic wave equation +! using a spectral-element method (SEM). +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 3 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License along +! with this program; if not, write to the Free Software Foundation, Inc., +! 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +! +! The full text of the license is available in file "LICENSE". +! +!======================================================================== + + subroutine determine_acoustic_surface() + + use constants, only: ANISOTROPIC_MATERIAL,TINYVAL,IMAIN,myrank + + use part_unstruct_par, only: nelem_acoustic_surface,acoustic_surface, & + nxread,nzread,elmnts + + use shared_parameters, only: AXISYM,NGNOD,num_material,icodemat,phi_read,xmin_param, & + absorbbottom,absorbleft,absorbright,absorbtop + + implicit none + + ! local parameters + integer :: i,j,ier + integer :: imaterial_number + + ! user output + if (myrank == 0) then + write(IMAIN,*) ' determining acoustic free surface...' + call flush_IMAIN() + endif + + ! count the number of acoustic free-surface elements + nelem_acoustic_surface = 0 + + ! if the surface is absorbing, it cannot be free at the same time + if (.not. absorbtop) then + j = nzread + do i = 1,nxread + imaterial_number = num_material((j-1)*nxread+i) + if (icodemat(imaterial_number) /= ANISOTROPIC_MATERIAL .and. phi_read(imaterial_number) >= 1.d0) then + nelem_acoustic_surface = nelem_acoustic_surface + 1 + endif + enddo + endif + if (.not. absorbbottom) then + j = 1 + do i = 1,nxread + imaterial_number = num_material((j-1)*nxread+i) + if (icodemat(imaterial_number) /= ANISOTROPIC_MATERIAL .and. phi_read(imaterial_number) >= 1.d0) then + nelem_acoustic_surface = nelem_acoustic_surface + 1 + endif + enddo + endif + ! in the axisymmetric case if xmin == 0 the axis is a symmetry axis and thus cannot be a free surface as well + if (.not. absorbleft .and. .not. (AXISYM .and. abs(xmin_param) < TINYVAL)) then + i = 1 + do j = 1,nzread + imaterial_number = num_material((j-1)*nxread+i) + if (icodemat(imaterial_number) /= ANISOTROPIC_MATERIAL .and. phi_read(imaterial_number) >= 1.d0) then + nelem_acoustic_surface = nelem_acoustic_surface + 1 + endif + enddo + endif + if (.not. absorbright) then + i = nxread + do j = 1,nzread + imaterial_number = num_material((j-1)*nxread+i) + if (icodemat(imaterial_number) /= ANISOTROPIC_MATERIAL .and. phi_read(imaterial_number) >= 1.d0) then + nelem_acoustic_surface = nelem_acoustic_surface + 1 + endif + enddo + endif + + ! allocates surface elements + allocate(acoustic_surface(4,nelem_acoustic_surface),stat=ier) + if (ier /= 0) call stop_the_code('Error allocating acoustic_surface array') + acoustic_surface(:,:) = 0 + nelem_acoustic_surface = 0 + + ! 'acoustic_surface' contains + ! 1/ element number, + ! 2/ number of nodes that form the free surface, + ! 3/ first node on the free surface, + ! 4/ second node on the free surface, if relevant (if 2/ is equal to 2) + + if (.not. absorbtop) then + j = nzread + do i = 1,nxread + imaterial_number = num_material((j-1)*nxread+i) + if (icodemat(imaterial_number) /= ANISOTROPIC_MATERIAL .and. phi_read(imaterial_number) >= 1.d0) then + nelem_acoustic_surface = nelem_acoustic_surface + 1 + acoustic_surface(1,nelem_acoustic_surface) = (j-1)*nxread + (i-1) + acoustic_surface(2,nelem_acoustic_surface) = 2 + acoustic_surface(3,nelem_acoustic_surface) = elmnts(3+NGNOD*((j-1)*nxread+i-1)) + acoustic_surface(4,nelem_acoustic_surface) = elmnts(2+NGNOD*((j-1)*nxread+i-1)) + endif + enddo + endif + if (.not. absorbbottom) then + j = 1 + do i = 1,nxread + imaterial_number = num_material((j-1)*nxread+i) + if (icodemat(imaterial_number) /= ANISOTROPIC_MATERIAL .and. phi_read(imaterial_number) >= 1.d0) then + nelem_acoustic_surface = nelem_acoustic_surface + 1 + acoustic_surface(1,nelem_acoustic_surface) = (j-1)*nxread + (i-1) + acoustic_surface(2,nelem_acoustic_surface) = 2 + acoustic_surface(3,nelem_acoustic_surface) = elmnts(0+NGNOD*((j-1)*nxread+i-1)) + acoustic_surface(4,nelem_acoustic_surface) = elmnts(1+NGNOD*((j-1)*nxread+i-1)) + endif + enddo + endif + ! in the axisymmetric case if xmin == 0 the axis is a symmetry axis and thus cannot be a free surface as well + if (.not. absorbleft .and. .not. (AXISYM .and. abs(xmin_param) < TINYVAL)) then + i = 1 + do j = 1,nzread + imaterial_number = num_material((j-1)*nxread+i) + if (icodemat(imaterial_number) /= ANISOTROPIC_MATERIAL .and. phi_read(imaterial_number) >= 1.d0) then + nelem_acoustic_surface = nelem_acoustic_surface + 1 + acoustic_surface(1,nelem_acoustic_surface) = (j-1)*nxread + (i-1) + acoustic_surface(2,nelem_acoustic_surface) = 2 + acoustic_surface(3,nelem_acoustic_surface) = elmnts(0+NGNOD*((j-1)*nxread+i-1)) + acoustic_surface(4,nelem_acoustic_surface) = elmnts(3+NGNOD*((j-1)*nxread+i-1)) + endif + enddo + endif + if (.not. absorbright) then + i = nxread + do j = 1,nzread + imaterial_number = num_material((j-1)*nxread+i) + if (icodemat(imaterial_number) /= ANISOTROPIC_MATERIAL .and. phi_read(imaterial_number) >= 1.d0) then + nelem_acoustic_surface = nelem_acoustic_surface + 1 + acoustic_surface(1,nelem_acoustic_surface) = (j-1)*nxread + (i-1) + acoustic_surface(2,nelem_acoustic_surface) = 2 + acoustic_surface(3,nelem_acoustic_surface) = elmnts(1+NGNOD*((j-1)*nxread+i-1)) + acoustic_surface(4,nelem_acoustic_surface) = elmnts(2+NGNOD*((j-1)*nxread+i-1)) + endif + enddo + endif + + ! user output + if (myrank == 0) then + write(IMAIN,*) ' number of acoustic elements with free surface = ',nelem_acoustic_surface + write(IMAIN,*) + call flush_IMAIN() + endif + + end subroutine determine_acoustic_surface diff --git a/meshfem2d/exit_mpi.F90 b/meshfem2d/exit_mpi.F90 new file mode 100644 index 00000000..f22be853 --- /dev/null +++ b/meshfem2d/exit_mpi.F90 @@ -0,0 +1,117 @@ +!======================================================================== +! +! S P E C F E M 2 D +! ----------------- +! +! Main historical authors: Dimitri Komatitsch and Jeroen Tromp +! CNRS, France +! and Princeton University, USA +! (there are currently many more authors!) +! (c) October 2017 +! +! This software is a computer program whose purpose is to solve +! the two-dimensional viscoelastic anisotropic or poroelastic wave equation +! using a spectral-element method (SEM). +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 3 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License along +! with this program; if not, write to the Free Software Foundation, Inc., +! 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +! +! The full text of the license is available in file "LICENSE". +! +!======================================================================== + +!------------------------------------------------------------ +! subroutine to stop the code, whether sequential or parallel +!------------------------------------------------------------ + +subroutine exit_MPI(myrank,error_msg) + + use constants, only: MAX_STRING_LEN,IMAIN,ISTANDARD_OUTPUT + use shared_parameters, only: OUTPUT_FILES + + implicit none + + integer,intent(in) :: myrank + character(len=*),intent(in) :: error_msg + + ! local parameters + character(len=MAX_STRING_LEN) :: outputname + ! identifier for error message file + integer, parameter :: IERROR = 30 + + ! write error message to screen + write(*,*) error_msg(1:len(error_msg)) + write(*,*) 'Error detected, aborting MPI... proc ',myrank + +! write error message to file + write(outputname,"('/error_message',i6.6,'.txt')") myrank + open(unit=IERROR,file=trim(OUTPUT_FILES)//outputname,status='unknown') + write(IERROR,*) error_msg(1:len(error_msg)) + write(IERROR,*) 'Error detected, aborting MPI... proc ',myrank + close(IERROR) + +! close output file + if (myrank == 0 .and. IMAIN /= ISTANDARD_OUTPUT) close(IMAIN) + + ! stop all the MPI processes, and exit + if (error_msg /= 'Error, program ended in exit_MPI') call abort_mpi() + + ! otherwise: there is no standard behaviour to exit with an error code in Fortran, + ! however most compilers do recognize this as an error code stop statement; + ! to check stop code in terminal: > echo $? + stop 30 + +end subroutine exit_MPI + +!------------------------------------------------------------------------------------------------- + +! alias for exit_MPI, useful to convert stop statements to this automatically in the code cleaning script ran by Buildbot + +subroutine stop_the_code(error_msg) + + use constants, only: myrank + + implicit none + + character(len=*) :: error_msg + + call exit_MPI(myrank,error_msg) + +end subroutine stop_the_code + +!------------------------------------------------------------------------------------------------- +! +! I/O wrapper function +! +!------------------------------------------------------------------------------------------------- + +subroutine flush_IMAIN() + + use constants, only: IMAIN + + implicit none + + ! only main process writes out to main output file + ! file I/O in Fortran is buffered by default + ! + ! note: Fortran2003 includes a FLUSH statement + ! which is implemented by most compilers by now + ! + ! otherwise: + ! a) comment out the line below + ! b) try to use instead: call flush(IMAIN) + + flush(IMAIN) + +end subroutine flush_IMAIN diff --git a/meshfem2d/file_management.f90 b/meshfem2d/file_management.f90 new file mode 100644 index 00000000..3936f63f --- /dev/null +++ b/meshfem2d/file_management.f90 @@ -0,0 +1,13 @@ + +subroutine create_directory_if_doesnt_exist(directory) + + use shared_parameters, only: MAX_STRING_LEN + + implicit none + character(len=MAX_STRING_LEN), intent(in) :: directory + integer :: status + logical :: directory_exists + + call system('[[ ! -e ' // directory // ' ]] && mkdir ' // directory) + +end subroutine create_directory_if_doesnt_exist diff --git a/meshfem2d/force_ftz.c b/meshfem2d/force_ftz.c new file mode 100644 index 00000000..afeab931 --- /dev/null +++ b/meshfem2d/force_ftz.c @@ -0,0 +1,93 @@ +/* + !======================================================================== + ! + ! S P E C F E M 2 D + ! ----------------- + ! + ! Main historical authors: Dimitri Komatitsch and Jeroen Tromp + ! CNRS, France + ! and Princeton University, USA + ! (there are currently many more authors!) + ! (c) October 2017 + ! + ! This software is a computer program whose purpose is to solve + ! the two-dimensional viscoelastic anisotropic or poroelastic wave equation + ! using a spectral-element method (SEM). + ! + ! This program is free software; you can redistribute it and/or modify + ! it under the terms of the GNU General Public License as published by + ! the Free Software Foundation; either version 3 of the License, or + ! (at your option) any later version. + ! + ! This program is distributed in the hope that it will be useful, + ! but WITHOUT ANY WARRANTY; without even the implied warranty of + ! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + ! GNU General Public License for more details. + ! + ! You should have received a copy of the GNU General Public License along + ! with this program; if not, write to the Free Software Foundation, Inc., + ! 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + ! + ! The full text of the license is available in file "LICENSE". + ! + !======================================================================== + */ + +/* Dimitri Komatitsch, University of Toulouse, May 2011: */ + +/* added code to force Flush-To-Zero (FTZ) on Intel processors */ +/* otherwise Gradual Underflow can be extremely slow. With Intel */ +/* ifort one can use compiler option -ftz, but no such option exists */ +/* in gcc and gfortran therefore we call an assembler routine directly here. */ +/* Very precise description available at */ +/* http://software.intel.com/en-us/articles/x87-and-sse-floating-point-assists-in-ia-32-flush-to-zero-ftz-and-denormals-are-zero-daz/ */ +/* and at http://www.rz.uni-karlsruhe.de/rz/docs/VTune/reference/vc148.htm */ +/* from http://software.intel.com/en-us/articles/x87-and-sse-floating-point-assists-in-ia-32-flush-to-zero-ftz-and-denormals-are-zero-daz : */ + +/* Flush-To-Zero (FTZ) mode */ + +/* FTZ is a method of bypassing IEEE 754 methods of dealing with */ +/* invalid floating-point numbers due to underflows. This mode is much */ +/* faster. Two conditions must be met for FTZ processing to occur: */ + +/* * The FTZ bit (bit 15) in the MXCSR register must be masked (value = 1). */ +/* * The underflow exception (bit 11) needs to be masked (value = 1). */ + +/* This routine is not strictly necessary for SPECFEM, thus if it does not compile on your system + (since it calls some low-level system routines) just suppress all the lines below (i.e. make it an empty file) + and comment out the call to force_ftz() in the main SPECFEM program */ + +#include "config.h" + +#define FTZ_BIT 15 +#define UNDERFLOW_EXCEPTION_MASK 11 + +#ifdef __GNUC__ // only use these features on gnu compiler +#ifdef HAVE_XMMINTRIN + #define FORCE_FTZ + #include +#elif HAVE_EMMINTRIN + #include + #define FORCE_FTZ +#endif +#endif // __GNUC__ + +void +FC_FUNC_(force_ftz,FORCE_FTZ)() +{ + +// DK DK Nov 2018: uncomment this if you have any problem compiling this file +//#undef FORCE_FTZ + +#ifdef __GNUC__ +#ifdef FORCE_FTZ + unsigned int x; + + /* force FTZ by setting bits 11 and 15 to one */ + x = _mm_getcsr(); + x |= (1 << FTZ_BIT); + x |= (1 << UNDERFLOW_EXCEPTION_MASK); + _mm_setcsr(x); +#endif +#endif // __GNUC__ +} diff --git a/meshfem2d/get_node_number.f90 b/meshfem2d/get_node_number.f90 new file mode 100644 index 00000000..7ca76e9a --- /dev/null +++ b/meshfem2d/get_node_number.f90 @@ -0,0 +1,83 @@ +!======================================================================== +! +! S P E C F E M 2 D +! ----------------- +! +! Main historical authors: Dimitri Komatitsch and Jeroen Tromp +! CNRS, France +! and Princeton University, USA +! (there are currently many more authors!) +! (c) October 2017 +! +! This software is a computer program whose purpose is to solve +! the two-dimensional viscoelastic anisotropic or poroelastic wave equation +! using a spectral-element method (SEM). +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 3 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License along +! with this program; if not, write to the Free Software Foundation, Inc., +! 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +! +! The full text of the license is available in file "LICENSE". +! +!======================================================================== + + +! ******************* +! meshing subroutines +! ******************* + +!--- global node number + + integer function num(i,j,nx) + + implicit none + + integer i,j,nx + + num = j*(nx+1) + i + 1 + + end function num + + +!--- global node number (when NGNOD==4). + integer function num_4(i,j,nx) + + implicit none + + integer i,j,nx + + num_4 = j*(nx+1) + i + 1 + + end function num_4 + + +!--- global node number (when NGNOD==9). + integer function num_9(i,j,nx,nz) + + implicit none + + integer i,j,nx,nz + + + if ((mod(i,2) == 0) .and. (mod(j,2) == 0)) then + num_9 = j/2 * (nx+1) + i/2 + 1 + else + if (mod(j,2) == 0) then + num_9 = (nx+1)*(nz+1) + j/2 * nx + ceiling(real(i)/real(2)) + else + num_9 = (nx+1)*(nz+1) + nx*(nz+1) + floor(real(j)/real(2))*(nx*2+1) + i + 1 + + endif + endif + + end function num_9 diff --git a/meshfem2d/gll_library.f90 b/meshfem2d/gll_library.f90 new file mode 100644 index 00000000..8d3fd1d2 --- /dev/null +++ b/meshfem2d/gll_library.f90 @@ -0,0 +1,654 @@ +!======================================================================== +! +! S P E C F E M 2 D +! ----------------- +! +! Main historical authors: Dimitri Komatitsch and Jeroen Tromp +! CNRS, France +! and Princeton University, USA +! (there are currently many more authors!) +! (c) October 2017 +! +! This software is a computer program whose purpose is to solve +! the two-dimensional viscoelastic anisotropic or poroelastic wave equation +! using a spectral-element method (SEM). +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 3 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License along +! with this program; if not, write to the Free Software Foundation, Inc., +! 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +! +! The full text of the license is available in file "LICENSE". +! +!======================================================================== + +!======================================================================= +! +! Library to compute the Gauss-Lobatto-Legendre points and weights +! Based on Gauss-Lobatto routines from M.I.T. +! Department of Mechanical Engineering +! +!======================================================================= + +! note: this version uses zwgljd() with double precision arguments + + double precision function endw1(n,alpha,beta) + + implicit none + + integer n + double precision alpha,beta + + double precision, parameter :: zero=0.d0,one=1.d0,two=2.d0,three=3.d0,four=4.d0 + double precision apb,f1,fint1,fint2,f2,di,abn,abnn,a1,a2,a3,f3 + double precision, external :: gammaf + integer i + + f3 = zero + apb = alpha+beta + if (n == 0) then + endw1 = zero + return + endif + f1 = gammaf(alpha+two)*gammaf(beta+one)/gammaf(apb+three) + f1 = f1*(apb+two)*two**(apb+two)/two + if (n == 1) then + endw1 = f1 + return + endif + fint1 = gammaf(alpha+two)*gammaf(beta+one)/gammaf(apb+three) + fint1 = fint1*two**(apb+two) + fint2 = gammaf(alpha+two)*gammaf(beta+two)/gammaf(apb+four) + fint2 = fint2*two**(apb+three) + f2 = (-two*(beta+two)*fint1 + (apb+four)*fint2) * (apb+three)/four + if (n == 2) then + endw1 = f2 + return + endif + do i=3,n + di = dble(i-1) + abn = alpha+beta+di + abnn = abn+di + a1 = -(two*(di+alpha)*(di+beta))/(abn*abnn*(abnn+one)) + a2 = (two*(alpha-beta))/(abnn*(abnn+two)) + a3 = (two*(abn+one))/((abnn+two)*(abnn+one)) + f3 = -(a2*f2+a1*f1)/a3 + f1 = f2 + f2 = f3 + enddo + endw1 = f3 + + end function endw1 + +! +!======================================================================= +! + + double precision function endw2(n,alpha,beta) + + implicit none + + integer n + double precision alpha,beta + + double precision, parameter :: zero=0.d0,one=1.d0,two=2.d0,three=3.d0,four=4.d0 + double precision apb,f1,fint1,fint2,f2,di,abn,abnn,a1,a2,a3,f3 + double precision, external :: gammaf + integer i + + apb = alpha+beta + f3 = zero + if (n == 0) then + endw2 = zero + return + endif + f1 = gammaf(alpha+one)*gammaf(beta+two)/gammaf(apb+three) + f1 = f1*(apb+two)*two**(apb+two)/two + if (n == 1) then + endw2 = f1 + return + endif + fint1 = gammaf(alpha+one)*gammaf(beta+two)/gammaf(apb+three) + fint1 = fint1*two**(apb+two) + fint2 = gammaf(alpha+two)*gammaf(beta+two)/gammaf(apb+four) + fint2 = fint2*two**(apb+three) + f2 = (two*(alpha+two)*fint1 - (apb+four)*fint2) * (apb+three)/four + if (n == 2) then + endw2 = f2 + return + endif + do i=3,n + di = dble(i-1) + abn = alpha+beta+di + abnn = abn+di + a1 = -(two*(di+alpha)*(di+beta))/(abn*abnn*(abnn+one)) + a2 = (two*(alpha-beta))/(abnn*(abnn+two)) + a3 = (two*(abn+one))/((abnn+two)*(abnn+one)) + f3 = -(a2*f2+a1*f1)/a3 + f1 = f2 + f2 = f3 + enddo + endw2 = f3 + + end function endw2 + +! +!======================================================================= +! + + double precision function gammaf (x) + + implicit none + + double precision, parameter :: pi = 3.141592653589793d0 + + double precision x + + double precision, parameter :: half=0.5d0,one=1.d0,two=2.d0 + + gammaf = one + + if (x == -half) gammaf = -two*dsqrt(pi) + if (x == half) gammaf = dsqrt(pi) + if (x == one) gammaf = one + if (x == two) gammaf = one + if (x == 1.5d0) gammaf = dsqrt(pi)/2.d0 + if (x == 2.5d0) gammaf = 1.5d0*dsqrt(pi)/2.d0 + if (x == 3.5d0) gammaf = 2.5d0*1.5d0*dsqrt(pi)/2.d0 + if (x == 3.d0 ) gammaf = 2.d0 + if (x == 4.d0 ) gammaf = 6.d0 + if (x == 5.d0 ) gammaf = 24.d0 + if (x == 6.d0 ) gammaf = 120.d0 + + end function gammaf + +! +!===================================================================== +! + + subroutine jacg (xjac,np,alpha,beta) + +!======================================================================= +! +! computes np Gauss points, which are the zeros of the +! Jacobi polynomial with parameters alpha and beta +! +! .alpha = beta = 0.0 -> Legendre points +! .alpha = beta = -0.5 -> Chebyshev points +! +!======================================================================= + + implicit none + + integer np + double precision alpha,beta + double precision xjac(np) + + ! local parameters + integer k,j,i,jmin,jm,n + double precision xlast,dth,x,x1,x2,recsum,delx,xmin,swap + double precision p,pd,pm1,pdm1,pm2,pdm2 + + integer, parameter :: K_MAX_ITER = 10 + double precision, parameter :: zero = 0.d0, eps = 1.0d-12 + + pm1 = zero + pm2 = zero + pdm1 = zero + pdm2 = zero + + xlast = 0.d0 + n = np-1 + dth = 4.d0*datan(1.d0)/(2.d0*dble(n)+2.d0) + p = 0.d0 + pd = 0.d0 + + do j=1,np + if (j == 1) then + x = dcos((2.d0*(dble(j)-1.d0)+1.d0)*dth) + else + x1 = dcos((2.d0*(dble(j)-1.d0)+1.d0)*dth) + x2 = xlast + x = (x1+x2)/2.d0 + endif + + do k=1,K_MAX_ITER + call jacobf (p,pd,pm1,pdm1,pm2,pdm2,np,alpha,beta,x) + recsum = 0.d0 + jm = j-1 + do i=1,jm + recsum = recsum+1.d0/(x-xjac(np-i+1)) + enddo + delx = -p/(pd-recsum*p) + x = x+delx + + ! exits loop if increment too small + if (abs(delx) < eps) exit + + enddo + + ! checks bounds + if (np-j+1 < 1 .or. np-j+1 > np) call stop_the_code('error np-j+1-index in jacg') + + xjac(np-j+1) = x + xlast = x + enddo + + jmin = 0 + + ! orders xjac array in increasing values + do i=1,np + xmin = 2.d0 + jmin = i + + ! looks for index with minimum value + do j=i,np + ! note: some compilers (cray) might be too aggressive in optimizing this loop, + ! thus we need this temporary array value x to store and compare values + x = xjac(j) + + if (x < xmin) then + xmin = x + jmin = j + endif + enddo + + ! checks bounds + if (jmin < 1 .or. jmin > np) call stop_the_code('error j-index in jacg') + + if (jmin /= i) then + swap = xjac(i) + xjac(i) = xjac(jmin) + xjac(jmin) = swap + endif + + enddo + + end subroutine jacg + +! +!===================================================================== +! + + subroutine jacobf (poly,pder,polym1,pderm1,polym2,pderm2,n,alp,bet,x) + +!======================================================================= +! +! Computes the Jacobi polynomial of degree n and its derivative at x +! +!======================================================================= + + implicit none + + double precision poly,pder,polym1,pderm1,polym2,pderm2,alp,bet,x + integer n + + double precision apb,polyl,pderl,dk,a1,a2,b3,a3,a4,polyn,pdern,psave,pdsave + integer k + + apb = alp+bet + poly = 1.d0 + pder = 0.d0 + psave = 0.d0 + pdsave = 0.d0 + + if (n == 0) return + + polyl = poly + pderl = pder + poly = (alp-bet+(apb+2.d0)*x)/2.d0 + pder = (apb+2.d0)/2.d0 + if (n == 1) return + + do k=2,n + dk = dble(k) + a1 = 2.d0*dk*(dk+apb)*(2.d0*dk+apb-2.d0) + a2 = (2.d0*dk+apb-1.d0)*(alp**2-bet**2) + b3 = (2.d0*dk+apb-2.d0) + a3 = b3*(b3+1.d0)*(b3+2.d0) + a4 = 2.d0*(dk+alp-1.d0)*(dk+bet-1.d0)*(2.d0*dk+apb) + polyn = ((a2+a3*x)*poly-a4*polyl)/a1 + pdern = ((a2+a3*x)*pder-a4*pderl+a3*poly)/a1 + psave = polyl + pdsave = pderl + polyl = poly + poly = polyn + pderl = pder + pder = pdern + enddo + + polym1 = polyl + pderm1 = pderl + polym2 = psave + pderm2 = pdsave + + end subroutine jacobf + +! +!------------------------------------------------------------------------ +! + + double precision function PNDLEG (Z,N) + +!------------------------------------------------------------------------ +! +! Compute the derivative of the Nth order Legendre polynomial at Z. +! Based on the recursion formula for the Legendre polynomials. +! +!------------------------------------------------------------------------ + implicit none + + double precision z + integer n + + double precision P1,P2,P1D,P2D,P3D,DBLE_K,P3 + integer k + + P1 = 1.d0 + P2 = Z + P1D = 0.d0 + P2D = 1.d0 + P3D = 1.d0 + + do K = 1, N-1 + DBLE_K = dble(K) + P3 = ((2.d0*DBLE_K+1.d0)*Z*P2 - DBLE_K*P1)/(DBLE_K+1.d0) + P3D = ((2.d0*DBLE_K+1.d0)*P2 + (2.d0*DBLE_K+1.d0)*Z*P2D - DBLE_K*P1D) / (DBLE_K+1.d0) + P1 = P2 + P2 = P3 + P1D = P2D + P2D = P3D + enddo + + PNDLEG = P3D + + end function pndleg + +! +!------------------------------------------------------------------------ +! + + double precision function PNLEG (Z,N) + +!------------------------------------------------------------------------ +! +! Compute the value of the Nth order Legendre polynomial at Z. +! Based on the recursion formula for the Legendre polynomials. +! +!------------------------------------------------------------------------ + implicit none + + double precision z + integer n + + double precision P1,P2,P3,DBLE_K + integer k + + P1 = 1.d0 + P2 = Z + P3 = P2 + + do K = 1, N-1 + DBLE_K = dble(K) + P3 = ((2.d0*DBLE_K+1.d0)*Z*P2 - DBLE_K*P1)/(DBLE_K+1.d0) + P1 = P2 + P2 = P3 + enddo + + PNLEG = P3 + + end function pnleg + +! +!------------------------------------------------------------------------ +! + + double precision function pnormj (n,alpha,beta) + + implicit none + + double precision alpha,beta + integer n + + double precision one,two,dn,const,prod,dindx,frac + double precision, external :: gammaf + integer i + + one = 1.d0 + two = 2.d0 + dn = dble(n) + const = alpha+beta+one + + if (n <= 1) then + prod = gammaf(dn+alpha)*gammaf(dn+beta) + prod = prod/(gammaf(dn)*gammaf(dn+alpha+beta)) + pnormj = prod * two**const/(two*dn+const) + return + endif + + prod = gammaf(alpha+one)*gammaf(beta+one) + prod = prod/(two*(one+const)*gammaf(const+one)) + prod = prod*(one+alpha)*(two+alpha) + prod = prod*(one+beta)*(two+beta) + + do i=3,n + dindx = dble(i) + frac = (dindx+alpha)*(dindx+beta)/(dindx*(dindx+alpha+beta)) + prod = prod*frac + enddo + + pnormj = prod * two**const/(two*dn+const) + + end function pnormj + +! +!------------------------------------------------------------------------ +! + + subroutine zwgjd(z,w,np,alpha,beta) + +!======================================================================= +! +! Z w g j d : Generate np Gauss-Jacobi points and weights +! associated with Jacobi polynomial of degree n = np-1 +! +! Note : Coefficients alpha and beta must be greater than -1. +! ---- +!======================================================================= + + implicit none + + double precision, parameter :: zero=0.d0,one=1.d0,two=2.d0 + + integer np + double precision z(np),w(np) + double precision alpha,beta + + ! local parameters + integer n,np1,np2,i + double precision p,pd,pm1,pdm1,pm2,pdm2 + double precision apb,dnp1,dnp2,fac1,fac2,fac3,fnorm,rcoef + double precision, external :: gammaf,pnormj + + pd = zero + pm1 = zero + pm2 = zero + pdm1 = zero + pdm2 = zero + + n = np-1 + apb = alpha+beta + p = zero + pdm1 = zero + + if (np <= 0) call stop_the_code('minimum number of Gauss points is 1') + + if ((alpha <= -one) .or. (beta <= -one)) call stop_the_code('alpha and beta must be greater than -1') + + if (np == 1) then + z(1) = (beta-alpha)/(apb+two) + w(1) = gammaf(alpha+one)*gammaf(beta+one)/gammaf(apb+two) * two**(apb+one) + return + endif + + call jacg(z,np,alpha,beta) + + np1 = n+1 + np2 = n+2 + dnp1 = dble(np1) + dnp2 = dble(np2) + fac1 = dnp1+alpha+beta+one + fac2 = fac1+dnp1 + fac3 = fac2+one + fnorm = pnormj(np1,alpha,beta) + rcoef = (fnorm*fac2*fac3)/(two*fac1*dnp2) + do i=1,np + call jacobf(p,pd,pm1,pdm1,pm2,pdm2,np2,alpha,beta,z(i)) + w(i) = -rcoef/(p*pdm1) + enddo + + end subroutine zwgjd + +! +!------------------------------------------------------------------------ +! + + subroutine zwgljd(z,w,np,alpha,beta) + +!======================================================================= +! +! Z w g l j d : Generate np Gauss-Lobatto-Jacobi points and the +! ----------- weights associated with Jacobi polynomials of degree +! n = np-1. +! +! Note : alpha and beta coefficients must be greater than -1. +! Legendre polynomials are special case of Jacobi polynomials +! just by setting alpha and beta to 0. +! +!======================================================================= + + implicit none + + double precision, parameter :: zero=0.d0,one=1.d0,two=2.d0,tol_zero=1.d-30 + + integer np + double precision alpha,beta + double precision z(np), w(np) + + ! local parameters + integer n,nm1,i + double precision p,pd,pm1,pdm1,pm2,pdm2 + double precision alpg,betg + double precision, external :: endw1,endw2 + + p = zero + pm1 = zero + pm2 = zero + pdm1 = zero + pdm2 = zero + + n = np-1 + nm1 = n-1 + pd = zero + + if (np <= 1) call stop_the_code('minimum number of Gauss-Lobatto points is 2') + +! with spectral elements, use at least 3 points + if (np <= 2) call stop_the_code('minimum number of Gauss-Lobatto points for the SEM is 3') + + if ((alpha <= -one) .or. (beta <= -one)) call stop_the_code('alpha and beta must be greater than -1') + + if (nm1 > 0) then + alpg = alpha+one + betg = beta+one + call zwgjd(z(2:n),w(2:n),nm1,alpg,betg) + endif + +! start and end point at exactly -1 and 1 + z(1) = - one + z(np) = one + +! note: Jacobi polynomials with (alpha,beta) equal to zero become Legendre polynomials. +! for Legendre polynomials, if number of points is odd, the middle abscissa is exactly zero + if (abs(alpha) < tol_zero .and. abs(beta) < tol_zero) then + if (mod(np,2) /= 0) z((np-1)/2+1) = zero + endif + +! weights + do i=2,np-1 + w(i) = w(i)/(one-z(i)**2) + enddo + + call jacobf(p,pd,pm1,pdm1,pm2,pdm2,n,alpha,beta,z(1)) + w(1) = endw1(n,alpha,beta)/(two*pd) + + call jacobf(p,pd,pm1,pdm1,pm2,pdm2,n,alpha,beta,z(np)) + w(np) = endw2(n,alpha,beta)/(two*pd) + + end subroutine zwgljd + + +! +!------------------------------------------------------------------------ +! + + double precision function pnglj(z,n) + +!------------------------------------------------------------------------ +! +! Compute the value of the Nth order polynomial of the +! Gauss-Lobatto-Jacobi (0,1) at Z. from Legendre polynomials. +! +!------------------------------------------------------------------------ + + implicit none + include "constants.h" + + double precision z + integer n + double precision, external :: pnleg + + if (abs(z+1.d0) > TINYVAL) then ! if (z /= -1.d0) + pnglj = (pnleg(z,n)+pnleg(z,n+1))/(ONE+z) + else + pnglj = (dble(n)+ONE)*(-1)**n + endif + + end function pnglj + +! +!------------------------------------------------------------------------ +! + + double precision function pndglj(z,n) + +!------------------------------------------------------------------------ +! +! Compute the value of the derivative of Nth order polynomial of the +! Gauss-Lobatto-Jacobi (0,1) at Z. from Legendre polynomials. +! +!------------------------------------------------------------------------ + + implicit none + include "constants.h" + + double precision z + integer n + double precision, external :: pnleg, pndleg + + if (abs(z+1.d0) > TINYVAL) then ! if (z /= -1.d0) + pndglj = (pndleg(z,n)+pndleg(z,n+1))/(ONE+z) - (pnleg(z,n)+pnleg(z,n+1))/((ONE+z)**2) + else + pndglj = pnleg(-1.d0,n)+pnleg(-1.d0,n+1) + endif + + end function pndglj diff --git a/meshfem2d/lagrange_poly.f90 b/meshfem2d/lagrange_poly.f90 new file mode 100644 index 00000000..96b8bcc8 --- /dev/null +++ b/meshfem2d/lagrange_poly.f90 @@ -0,0 +1,287 @@ +!======================================================================== +! +! S P E C F E M 2 D +! ----------------- +! +! Main historical authors: Dimitri Komatitsch and Jeroen Tromp +! CNRS, France +! and Princeton University, USA +! (there are currently many more authors!) +! (c) October 2017 +! +! This software is a computer program whose purpose is to solve +! the two-dimensional viscoelastic anisotropic or poroelastic wave equation +! using a spectral-element method (SEM). +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 3 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License along +! with this program; if not, write to the Free Software Foundation, Inc., +! 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +! +! The full text of the license is available in file "LICENSE". +! +!======================================================================== + + subroutine lagrange_any(xi,NGLL,xigll,h,hprime) + +! subroutine to compute the Lagrange interpolants based upon the interpolation points +! and their first derivatives at any point xi in [-1,1] + + implicit none + + double precision,intent(in) :: xi + + integer,intent(in) :: NGLL + double precision,dimension(NGLL),intent(in) :: xigll + double precision,dimension(NGLL),intent(out) :: h,hprime + + ! local parameters + integer :: dgr,i,j + double precision :: prod1,prod2,prod3 + double precision :: prod2_inv + double precision :: sum + double precision :: x0,x + +! note: this routine is hit pretty hard by the mesher, optimizing the loops here will be beneficial + + do dgr = 1,NGLL + + prod1 = 1.0d0 + prod2 = 1.0d0 + + ! lagrangian interpolants + x0 = xigll(dgr) + do i = 1,NGLL + if (i /= dgr) then + x = xigll(i) + prod1 = prod1*(xi-x) + prod2 = prod2*(x0-x) + endif + enddo + + ! takes inverse to avoid additional divisions + ! (multiplications are cheaper than divisions) + prod2_inv = 1.d0/prod2 + + h(dgr) = prod1 * prod2_inv + + ! first derivatives + sum = 0.0d0 + do i = 1,NGLL + if (i /= dgr) then + prod3 = 1.0d0 + do j = 1,NGLL + if (j /= dgr .and. j /= i) prod3 = prod3*(xi-xigll(j)) + enddo + sum = sum + prod3 + endif + enddo + + hprime(dgr) = sum * prod2_inv + + enddo + + end subroutine lagrange_any + +! +!===================================================================== +! + +! subroutine to compute the derivative of the Lagrange interpolants +! at any given GLL point + + double precision function lagrange_deriv_GLL(i,j,ZGLL,NZ) + +!------------------------------------------------------------------------ +! +! Compute the value of the derivative of the I-th +! Lagrange interpolant through the +! NZ Gauss-Lobatto Legendre points ZGLL at point ZGLL(j) +! +!------------------------------------------------------------------------ + + implicit none + + integer :: i,j,nz + double precision :: zgll(0:nz-1) + + ! local parameters + integer :: degpoly + + double precision, external :: pnleg,pndleg + + degpoly = nz - 1 + if (i == 0 .and. j == 0) then + lagrange_deriv_GLL = - dble(degpoly)*(dble(degpoly)+1.d0) * 0.25d0 ! / 4.d0 + else if (i == degpoly .and. j == degpoly) then + lagrange_deriv_GLL = dble(degpoly)*(dble(degpoly)+1.d0) * 0.25d0 ! / 4.d0 + else if (i == j) then + lagrange_deriv_GLL = 0.d0 + else + lagrange_deriv_GLL = pnleg(zgll(j),degpoly) / & + (pnleg(zgll(i),degpoly)*(zgll(j)-zgll(i))) & + + (1.d0-zgll(j)*zgll(j))*pndleg(zgll(j),degpoly) / (dble(degpoly)* & + (dble(degpoly)+1.d0)*pnleg(zgll(i),degpoly)*(zgll(j)-zgll(i))*(zgll(j)-zgll(i))) + endif + + end function lagrange_deriv_GLL + +! +!======================================================================= +! + + double precision function hgll(I,Z,ZGLL,NZ) + +!------------------------------------------------------------- +! +! Compute the value of the Lagrangian interpolant L through +! the NZ Gauss-Lobatto Legendre points ZGLL at point Z +! See Nissen-Meyer et al., 2007, A two-dimensional spectral-element method for computing +! spherical-earth seismograms - I. Moment-tensor source, Geophysical Journal International, p. 1087 eq. (A19) +! !! Warning !! There is a minus sign missing in that paper (-1.d0)**(N+1)*(1.d0-Z)*PNDLEG(Z,N) / ALFAN +! +!------------------------------------------------------------- + + use constants, only: TINYVAL + + implicit none + + integer i,nz + double precision z + double precision ZGLL(0:nz-1) + + integer n + double precision EPS,DZ,ALFAN + double precision, external :: PNLEG,PNDLEG + + EPS = TINYVAL + DZ = Z - ZGLL(I) + if (abs(DZ) < EPS) then + HGLL = 1.d0 + return + endif + N = NZ - 1 + ALFAN = dble(N)*(dble(N)+1.d0) + if (I == 0) then + HGLL = (-1.d0)**(N+1)*(1.d0-Z)*PNDLEG(Z,N) / ALFAN + else if (I == N) then + HGLL = (1.d0+Z)*PNDLEG(Z,N) / ALFAN + else + HGLL = - (1.d0-Z*Z)*PNDLEG(Z,N)/ (ALFAN*PNLEG(ZGLL(I),N)*(Z-ZGLL(I))) + endif + + end function hgll + +! +!===================================================================== +! + + double precision function hglj(I,Z,ZGLJ,NZ) + +!------------------------------------------------------------- +! +! Compute the value of the Lagrangian interpolant L through +! the NZ Gauss-Lobatto Jacobi points ZGLJ at point Z +! See Nissen-Meyer et al., 2007, A two-dimensional spectral-element method for computing +! spherical-earth seismograms - I. Moment-tensor source, Geophysical Journal International, p. 1088 eq. (A26) +! +!------------------------------------------------------------- + + use constants, only: TINYVAL + + implicit none + + integer i,nz + double precision z + double precision ZGLJ(0:nz-1) + + integer n + double precision EPS,DZ,ALFAN1,ALFAN2 + double precision, external :: PNGLJ,PNDGLJ + + EPS = TINYVAL + DZ = Z - ZGLJ(I) + if (abs(DZ) < EPS) then + HGLJ = 1.d0 + return + endif + N = NZ - 1 + ALFAN1 = dble(N)+1.d0 + ALFAN2 = dble(N)*(dble(N)+2.d0) + if (I == 0) then + HGLJ = 2.d0*(-1.d0)**N*(Z-1.0d0)*PNDGLJ(Z,N) / (ALFAN1*ALFAN2) + else if (I == N) then + HGLJ = (1.d0+Z)*PNDGLJ(Z,N) / ALFAN2 + else + HGLJ = - (1.d0-Z*Z)*PNDGLJ(Z,N) / (ALFAN2*PNGLJ(ZGLJ(I),N)*(Z-ZGLJ(I))) + endif + + end function hglj + +! +!===================================================================== +! + + +! subroutine to compute the derivative of the interpolants of the GLJ +! quadrature at the GLJ points at any given GLJ point + + double precision function poly_deriv_GLJ(I,j,ZGLJ,NZ) + +!------------------------------------------------------------------------ +! +! Compute the value of the derivative of the I-th +! polynomial interpolant of the GLJ quadrature through the +! NZ Gauss-Lobatto-Jacobi (0,1) points ZGLJ at point ZGLJ(j) +! See Nissen-Meyer et al., 2007, A two-dimensional spectral-element method for computing +! spherical-earth seismograms - I. Moment-tensor source, Geophysical Journal International, p. 1088 eq. (A27) +! WARNING: there is an error at line 7 of their equation +! \partial_{\xi}\overline{l}_{i}(\overline{\xi}_{I})=\dfrac{1}{\overline{P}_{N}(\overline{\xi}_{i})(1-\overline{\xi}_{i})} +! +!------------------------------------------------------------------------ + + implicit none + + integer i,j,nz + double precision zglj(0:nz-1) + + integer degpoly + + double precision, external :: pnglj + + degpoly = nz - 1 + + if (i == 0 .and. j == 0) then ! Case 1 + poly_deriv_GLJ = -dble(degpoly)*(dble(degpoly)+2.d0)/6.d0 + else if (i == 0 .and. 0 < j .and. j < degpoly) then ! Case 2 + poly_deriv_GLJ = 2.d0*(-1)**degpoly*pnglj(zglj(j),degpoly)/((1.d0+zglj(j))*(dble(degpoly)+1.d0)) + else if (i == 0 .and. j == degpoly) then ! Case 3 + poly_deriv_GLJ = (-1)**degpoly/(dble(degpoly)+1.d0) + else if (0 < i .and. i < degpoly .and. j == 0) then ! Case 4 + poly_deriv_GLJ = (-1)**(degpoly+1)*(dble(degpoly)+1.d0)/(2.d0*pnglj(zglj(i),degpoly)*(1.d0+zglj(i))) + else if (0 < i .and. i < degpoly .and. 0 < j .and. j < degpoly .and. i /= j) then ! Case 5 + poly_deriv_GLJ = 1.d0/(zglj(j)-zglj(i))*pnglj(zglj(j),degpoly)/pnglj(zglj(i),degpoly) + else if (0 < i .and. i < degpoly .and. i == j) then ! Case 6 + poly_deriv_GLJ = -1.d0/(2.d0*(1.d0+zglj(i))) + else if (0 < i .and. i < degpoly .and. j == degpoly) then ! Case 7 + poly_deriv_GLJ = 1.d0/(pnglj(zglj(i),degpoly)*(1.d0-zglj(i))) + else if (i == degpoly .and. j == 0) then ! Case 8 + poly_deriv_GLJ = (-1)**(degpoly+1)*(dble(degpoly)+1.d0)/4.d0 + else if (i == degpoly .and. 0 < j .and. j < degpoly) then ! Case 9 + poly_deriv_GLJ = -1.d0/(1.d0-zglj(j))*pnglj(zglj(j),degpoly) + else if (i == degpoly .and. j == degpoly) then ! Case 10 + poly_deriv_GLJ = (dble(degpoly)*(dble(degpoly)+2.d0)-1.d0)/4.d0 + else + call stop_the_code('Problem in poly_deriv_GLJ: in a perfect world this would NEVER appear') + endif + + end function poly_deriv_GLJ diff --git a/meshfem2d/meshfem2D.F90 b/meshfem2d/meshfem2D.F90 new file mode 100644 index 00000000..9898de27 --- /dev/null +++ b/meshfem2d/meshfem2D.F90 @@ -0,0 +1,734 @@ +!======================================================================== +! +! S P E C F E M 2 D +! ----------------- +! +! Main historical authors: Dimitri Komatitsch and Jeroen Tromp +! CNRS, France +! and Princeton University, USA +! (there are currently many more authors!) +! (c) October 2017 +! +! This software is a computer program whose purpose is to solve +! the two-dimensional viscoelastic anisotropic or poroelastic wave equation +! using a spectral-element method (SEM). +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 3 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License along +! with this program; if not, write to the Free Software Foundation, Inc., +! 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +! +! The full text of the license is available in file "LICENSE". +! +!======================================================================== + +!======================================================================== +! +! Basic mesh generator for SPECFEM2D +! +!======================================================================== + +! If you use this code for your own research, please cite at least one article +! written by the developers of the package, for instance: +! +! @ARTICLE{TrKoLi08, +! author = {Jeroen Tromp and Dimitri Komatitsch and Qinya Liu}, +! title = {Spectral-Element and Adjoint Methods in Seismology}, +! journal = {communications in Computational Physics}, +! year = {2008}, +! volume = {3}, +! pages = {1-32}, +! number = {1}} +! +! @ARTICLE{PeKoLuMaLeCaLeMaLiBlNiBaTr11, +! author = {Daniel Peter and Dimitri Komatitsch and Yang Luo and Roland Martin +! and Nicolas {Le Goff} and Emanuele Casarotti and Pieyre {Le Loher} +! and Federica Magnoni and Qinya Liu and C\'eline Blitz and Tarje Nissen-Meyer +! and Piero Basini and Jeroen Tromp}, +! title = {Forward and adjoint simulations of seismic wave propagation on fully +! unstructured hexahedral meshes}, +! journal={Geophys. J. Int.}, +! year = {2011}, +! volume = {186}, +! pages = {721-739}, +! number = {2}, +! doi = {10.1111/j.1365-246X.2011.05044.x}} +! +! or +! +! @ARTICLE{VaCaSaKoVi99, +! author = {R. Vai and J. M. Castillo-Covarrubias and F. J. S\'anchez-Sesma and +! D. Komatitsch and J. P. Vilotte}, +! title = {Elastic wave propagation in an irregularly layered medium}, +! journal = {Soil Dynamics and Earthquake Engineering}, +! year = {1999}, +! volume = {18}, +! pages = {11-18}, +! number = {1}, +! doi = {10.1016/S0267-7261(98)00027-X}} +! +! @ARTICLE{LeChKoHuTr09, +! author = {Shiann Jong Lee and Yu Chang Chan and Dimitri Komatitsch and Bor +! Shouh Huang and Jeroen Tromp}, +! title = {Effects of realistic surface topography on seismic ground motion +! in the {Y}angminshan region of {T}aiwan based upon the spectral-element +! method and {LiDAR DTM}}, +! journal = {Bull. Seismol. Soc. Am.}, +! year = {2009}, +! volume = {99}, +! pages = {681-693}, +! number = {2A}, +! doi = {10.1785/0120080264}} +! +! @ARTICLE{LeChLiKoHuTr08, +! author = {Shiann Jong Lee and How Wei Chen and Qinya Liu and Dimitri Komatitsch +! and Bor Shouh Huang and Jeroen Tromp}, +! title = {Three-Dimensional Simulations of Seismic Wave Propagation in the +! {T}aipei Basin with Realistic Topography Based upon the Spectral-Element Method}, +! journal = {Bull. Seismol. Soc. Am.}, +! year = {2008}, +! volume = {98}, +! pages = {253-264}, +! number = {1}, +! doi = {10.1785/0120070033}} +! +! @ARTICLE{LeKoHuTr09, +! author = {S. J. Lee and Dimitri Komatitsch and B. S. Huang and J. Tromp}, +! title = {Effects of topography on seismic wave propagation: An example from +! northern {T}aiwan}, +! journal = {Bull. Seismol. Soc. Am.}, +! year = {2009}, +! volume = {99}, +! pages = {314-325}, +! number = {1}, +! doi = {10.1785/0120080020}} +! +! @ARTICLE{KoErGoMi10, +! author = {Dimitri Komatitsch and Gordon Erlebacher and Dominik G\"oddeke and +! David Mich\'ea}, +! title = {High-order finite-element seismic wave propagation modeling with +! {MPI} on a large {GPU} cluster}, +! journal = {J. Comput. Phys.}, +! year = {2010}, +! volume = {229}, +! pages = {7692-7714}, +! number = {20}, +! doi = {10.1016/j.jcp.2010.06.024}} +! +! @ARTICLE{KoGoErMi10, +! author = {Dimitri Komatitsch and Dominik G\"oddeke and Gordon Erlebacher and +! David Mich\'ea}, +! title = {Modeling the propagation of elastic waves using spectral elements +! on a cluster of 192 {GPU}s}, +! journal = {Computer Science Research and Development}, +! year = {2010}, +! volume = {25}, +! pages = {75-82}, +! number = {1-2}, +! doi = {10.1007/s00450-010-0109-1}} +! +! @ARTICLE{KoMiEr09, +! author = {Dimitri Komatitsch and David Mich\'ea and Gordon Erlebacher}, +! title = {Porting a high-order finite-element earthquake modeling application +! to {NVIDIA} graphics cards using {CUDA}}, +! journal = {Journal of Parallel and Distributed Computing}, +! year = {2009}, +! volume = {69}, +! pages = {451-460}, +! number = {5}, +! doi = {10.1016/j.jpdc.2009.01.006}} +! +! @ARTICLE{LiPoKoTr04, +! author = {Qinya Liu and Jascha Polet and Dimitri Komatitsch and Jeroen Tromp}, +! title = {Spectral-element moment tensor inversions for earthquakes in {S}outhern {C}alifornia}, +! journal={Bull. Seismol. Soc. Am.}, +! year = {2004}, +! volume = {94}, +! pages = {1748-1761}, +! number = {5}, +! doi = {10.1785/012004038}} +! +! @INCOLLECTION{ChKoViCaVaFe07, +! author = {Emmanuel Chaljub and Dimitri Komatitsch and Jean-Pierre Vilotte and +! Yann Capdeville and Bernard Valette and Gaetano Festa}, +! title = {Spectral Element Analysis in Seismology}, +! booktitle = {Advances in Wave Propagation in Heterogeneous Media}, +! publisher = {Elsevier - Academic Press}, +! year = {2007}, +! editor = {Ru-Shan Wu and Val\'erie Maupin}, +! volume = {48}, +! series = {Advances in Geophysics}, +! pages = {365-419}} +! +! @ARTICLE{KoVi98, +! author={D. Komatitsch and J. P. Vilotte}, +! title={The spectral-element method: an efficient tool to simulate the seismic response of 2{D} and 3{D} geological structures}, +! journal={Bull. Seismol. Soc. Am.}, +! year=1998, +! volume=88, +! number= 2, +! pages={368-392}} +! +! @ARTICLE{KoTr99, +! author={D. Komatitsch and J. Tromp}, +! year=1999, +! title={Introduction to the spectral-element method for 3-{D} seismic wave propagation}, +! journal={Geophys. J. Int.}, +! volume=139, +! number=3, +! pages={806-822}, +! doi={10.1046/j.1365-246x.1999.00967.x}} +! +! @ARTICLE{KoLiTrSuStSh04, +! author={Dimitri Komatitsch and Qinya Liu and Jeroen Tromp and Peter S\"{u}ss +! and Christiane Stidham and John H. Shaw}, +! year=2004, +! title={Simulations of Ground Motion in the {L}os {A}ngeles {B}asin +! based upon the Spectral-Element Method}, +! journal={Bull. Seism. Soc. Am.}, +! volume=94, +! number= 1, +! pages={187-206}} +! +! @ARTICLE{MoTr08, +! author={C. Morency and J. Tromp}, +! title={Spectral-element simulations of wave propagation in poroelastic media}, +! journal={Geophys. J. Int.}, +! year=2008, +! volume=175, +! pages={301-345}} +! +! and/or other articles from https://specfem.org/komatitsch.free.fr/publications.html +! +! If you use the kernel capabilities of the code, please cite at least one article +! written by the developers of the package, for instance: +! +! @ARTICLE{TrKoLi08, +! author = {Jeroen Tromp and Dimitri Komatitsch and Qinya Liu}, +! title = {Spectral-Element and Adjoint Methods in Seismology}, +! journal = {communications in Computational Physics}, +! year = {2008}, +! volume = {3}, +! pages = {1-32}, +! number = {1}} +! +! @ARTICLE{PeKoLuMaLeCaLeMaLiBlNiBaTr11, +! author = {Daniel Peter and Dimitri Komatitsch and Yang Luo and Roland Martin +! and Nicolas {Le Goff} and Emanuele Casarotti and Pieyre {Le Loher} +! and Federica Magnoni and Qinya Liu and C\'eline Blitz and Tarje Nissen-Meyer +! and Piero Basini and Jeroen Tromp}, +! title = {Forward and adjoint simulations of seismic wave propagation on fully +! unstructured hexahedral meshes}, +! journal={Geophys. J. Int.}, +! year = {2011}, +! volume = {186}, +! pages = {721-739}, +! number = {2}, +! doi = {10.1111/j.1365-246X.2011.05044.x}} +! +! @ARTICLE{LiTr06, +! author={Qinya Liu and Jeroen Tromp}, +! title={Finite-frequency kernels based on adjoint methods}, +! journal={Bull. Seismol. Soc. Am.}, +! year=2006, +! volume=96, +! number=6, +! pages={2383-2397}, +! doi={10.1785/0120060041}} +! +! @ARTICLE{MoLuTr09, +! author={C. Morency and Y. Luo and J. Tromp}, +! title={Finite-frequency kernels for wave propagation in porous media based upon adjoint methods}, +! year=2009, +! journal={Geophys. J. Int.}, +! doi={10.1111/j.1365-246X.2009.04332}} +! +! If you use the METIS / SCOTCH / CUBIT non-structured capabilities, please also cite: +! +! @ARTICLE{MaKoBlLe08, +! author = {R. Martin and D. Komatitsch and C. Blitz and N. {Le Goff}}, +! title = {Simulation of seismic wave propagation in an asteroid based upon +! an unstructured {MPI} spectral-element method: blocking and non-blocking +! communication strategies}, +! journal = {Lecture Notes in Computer Science}, +! year = {2008}, +! volume = {5336}, +! pages = {350-363}} +! +! +! version 8.0, Etienne Bachmann, Alexis Bottero, Bryant Chow, Paul Cristini, Rene Gassmoeller, Michael Gineste, +! Felix Halpaap, Dimitri Komatitsch, Matthieu Lefebvre, Qiancheng Liu, Qinya Liu, Zhaolun Liu, +! David Luet, Ryan Modrak, Christina Morency, Daniel Peter, Eric Rosenkrantz, Herurisa Rusmanugroho, +! Elliott Sales de Andrade, Eduardo Valero Cano, Zhinan Xie, Zhendong Zhang, December 2022: +! - various code improvements +! - GPU support +! - axisymmetric 2.5D simulations +! +! version 7.0, Dimitri Komatitsch, Zhinan Xie, Paul Cristini, Roland Martin and Rene Matzen, July 2012: +! - added support for Convolution PML absorbing layers +! - added higher-order time schemes (4th order Runge-Kutta and LDDRK4-6) +! - many small or moderate bug fixes +! +! version 6.2, many developers, April 2011: +! - restructured package source code into separate src/ directories +! - added configure & Makefile scripts and a PDF manual in doc/ +! - added user examples in EXAMPLES/ +! - added a USER_T0 parameter to fix the onset time in simulation +! +! version 6.1, Christina Morency and Pieyre Le Loher, March 2010: +! - added SH (membrane) waves calculation for elastic media +! - added support for external fully anisotropic media +! - fixed some bugs in acoustic kernels +! +! version 6.0, Christina Morency and Yang Luo, August 2009: +! - support for poroelastic media +! - adjoint method for acoustic/elastic/poroelastic +! +! version 5.2, Dimitri Komatitsch, Nicolas Le Goff and Roland Martin, February 2008: +! - support for CUBIT and GiD meshes +! - MPI implementation of the code based on domain decomposition +! with METIS or SCOTCH +! - general fluid/solid implementation with any number, shape and orientation of +! matching edges +! - fluid potential of density * displacement instead of displacement +! - absorbing edges with any normal vector +! - general numbering of absorbing and acoustic free surface edges +! - cleaned implementation of attenuation as in Carcione (1993) +! - merged loops in the solver for efficiency +! - simplified input of external model +! - added CPU time information +! - translated many comments from French to English +! +! version 5.1, Dimitri Komatitsch, January 2005: +! - more general mesher with any number of curved layers +! - Dirac and Gaussian time sources and corresponding convolution routine +! - option for acoustic medium instead of elastic +! - receivers at any location, not only grid points +! - moment-tensor source at any location, not only a grid point +! - color snapshots +! - more flexible DATA/Par_file with any number of comment lines +! - Xsu scripts for seismograms +! - subtract t0 from seismograms +! - seismograms and snapshots in pressure in addition to vector field +! +! version 5.0, Dimitri Komatitsch, May 2004: +! - got rid of useless routines, suppressed commons etc. +! - weak formulation based explicitly on stress tensor +! - implementation of full anisotropy +! - implementation of attenuation based on memory variables +! +! based on SPECFEM2D version 4.2, June 1998 +! (c) by Dimitri Komatitsch, Harvard University, USA +! and Jean-Pierre Vilotte, Institut de Physique du Globe de Paris, France +! +! itself based on SPECFEM2D version 1.0, 1995 +! (c) by Dimitri Komatitsch and Jean-Pierre Vilotte, +! Institut de Physique du Globe de Paris, France +! + +! in case of an acoustic medium, a potential Chi of (density * displacement) is used as in Chaljub and Valette, +! Geophysical Journal International, vol. 158, p. 131-141 (2004) and *NOT* a velocity potential +! as in Komatitsch and Tromp, Geophysical Journal International, vol. 150, p. 303-318 (2002). +! This permits acoustic-elastic coupling based on a non-iterative time scheme. +! Displacement is then: u = grad(Chi) / rho +! Velocity is then: v = grad(Chi_dot) / rho (Chi_dot being the time derivative of Chi) +! and pressure is: p = - Chi_dot_dot (Chi_dot_dot being the time second derivative of Chi). +! The source in an acoustic element is a pressure source. +! First-order acoustic-acoustic discontinuities are also handled automatically +! because pressure is continuous at such an interface, therefore Chi_dot_dot +! is continuous, therefore Chi is also continuous, which is consistent with +! the spectral-element basis functions and with the assembling process. +! This is the reason why a simple displacement potential u = grad(Chi) would +! not work because it would be discontinuous at such an interface and would +! therefore not be consistent with the basis functions. + +program meshfem2D + + use constants, only: IMAIN,ISTANDARD_OUTPUT,TINYVAL + + use shared_parameters + use part_unstruct_par +! use source_file_par + use compute_elements_load_par + + implicit none + + include 'version.fh' + + integer :: nspec_cpml + integer :: i,j,ier,num_elmnt + logical :: BROADCAST_AFTER_READ + + ! MPI initialization + call init_mpi() + call world_size(NPROC) + call world_rank(myrank) + + ! open main output file, only written to by process 0 + if (myrank == 0 .and. IMAIN /= ISTANDARD_OUTPUT) then + open(unit=IMAIN,file=trim(OUTPUT_FILES)//'output_meshfem2D.txt',status='unknown',iostat=ier) + if (ier /= 0) then + print *,'Error could not open output file :',trim(OUTPUT_FILES)//'output_meshfem2D.txt' + call stop_the_code('Error opening output file') + endif + endif + + ! user output + if (myrank == 0) then + write(IMAIN,*) +#ifdef WITH_MPI + write(IMAIN,*) '**********************************************' + write(IMAIN,*) '*** Specfem 2-D Mesher - MPI version ***' + write(IMAIN,*) '**********************************************' +#else + write(IMAIN,*) '**********************************************' + write(IMAIN,*) '*** Specfem 2-D Mesher - serial version ***' + write(IMAIN,*) '**********************************************' +#endif + write(IMAIN,*) + write(IMAIN,*) 'Running Git version of the code corresponding to ', git_commit_version + write(IMAIN,*) 'dating ', git_date_version + write(IMAIN,*) + call flush_IMAIN() + endif + + ! initializes + remove_min_to_start_at_zero = 0 + + ! mesher works only for single process + ! (secondary processes can sit idle) + if (myrank == 0) then + ! *** + ! *** parse command line arguments + call parse_command_line_arguments() + + ! *** + ! *** read the parameter file + ! *** + ! reads in parameters in DATA/Par_file + BROADCAST_AFTER_READ = .false. + call read_parameter_file(1,BROADCAST_AFTER_READ) + + ! reads in additional files for mesh elements + if (read_external_mesh) then + ! external meshing + ! user output + write(IMAIN,*) + write(IMAIN,*) 'Mesh from external meshing:' + call flush_IMAIN() + + ! reads in mesh + call read_external_mesh_file(mesh_file, remove_min_to_start_at_zero, NGNOD) + + ! reads in material defined in external file + call read_external_materials_file(materials_file) + + else + ! internal meshing + ! user output + write(IMAIN,*) + write(IMAIN,*) 'Mesh from internal meshing:' + call flush_IMAIN() + + allocate(elmnts(0:NGNOD*nelmnts-1),stat=ier) + if (ier /= 0) call stop_the_code('Error allocating array elmnts') + elmnts(:) = 0 + + ! stores mesh point indices in array 'elmnts' + if (NGNOD == 4) then + num_elmnt = 0 + do j = 1, nzread + do i = 1, nxread + elmnts(num_elmnt*NGNOD) = (j-1)*(nxread+1) + (i-1) + elmnts(num_elmnt*NGNOD+1) = (j-1)*(nxread+1) + (i-1) + 1 + elmnts(num_elmnt*NGNOD+2) = j*(nxread+1) + (i-1) + 1 + elmnts(num_elmnt*NGNOD+3) = j*(nxread+1) + (i-1) + num_elmnt = num_elmnt + 1 + enddo + enddo + else if (NGNOD == 9) then + num_elmnt = 0 + do j = 1, nzread + do i = 1, nxread + elmnts(num_elmnt*NGNOD) = (j-1)*(nxread+1) + (i-1) + elmnts(num_elmnt*NGNOD+1) = (j-1)*(nxread+1) + (i-1) + 1 + elmnts(num_elmnt*NGNOD+2) = j*(nxread+1) + (i-1) + 1 + elmnts(num_elmnt*NGNOD+3) = j*(nxread+1) + (i-1) + elmnts(num_elmnt*NGNOD+4) = (nxread+1)*(nzread+1) + (j-1)*nxread + (i-1) + elmnts(num_elmnt*NGNOD+5) = (nxread+1)*(nzread+1) + nxread*(nzread+1) + (j-1)*(nxread*2+1) + (i-1)*2 + 2 + elmnts(num_elmnt*NGNOD+6) = (nxread+1)*(nzread+1) + j*nxread + (i-1) + elmnts(num_elmnt*NGNOD+7) = (nxread+1)*(nzread+1) + nxread*(nzread+1) + (j-1)*(nxread*2+1) + (i-1)*2 + elmnts(num_elmnt*NGNOD+8) = (nxread+1)*(nzread+1) + nxread*(nzread+1) + (j-1)*(nxread*2+1) + (i-1)*2 + 1 + num_elmnt = num_elmnt + 1 + enddo + enddo + else + call stop_the_code('NGNOD must be either 4 or 9') + endif + + ! user output + write(IMAIN,*) ' Total number of spectral elements = ',nelmnts + write(IMAIN,*) + call flush_IMAIN() + endif + + ! PML mesh elements + ! user output + write(IMAIN,*) 'PML mesh elements:' + call flush_IMAIN() + + allocate(region_pml_external_mesh(nelmnts),stat=ier) + if (ier /= 0) call stop_the_code('Error allocating array region_pml_external_mesh') + region_pml_external_mesh(:) = 0 + + allocate(is_pml(0:nelmnts-1),stat=ier) + if (ier /= 0) call stop_the_code('Error allocating array is_pml') + is_pml(:) = .false. + nspec_cpml = 0 + + if (PML_BOUNDARY_CONDITIONS) then + if (read_external_mesh) then + call read_external_pml_element(absorbing_cpml_file, region_pml_external_mesh, nspec_cpml) + else + ! no need to read in PML values. + ! the internal mesher will assign PML elements in routine pml_init() in the solver. + nspec_cpml = 0 + write(IMAIN,*) ' using internal mesh, PML elements will be determined in solver run...' + write(IMAIN,*) + endif + else + ! no PML condition + ! user output + write(IMAIN,*) ' Total number of PML elements = ',nspec_cpml + write(IMAIN,*) + endif + + ! user output + write(IMAIN,*) 'The mesh contains ',nelmnts,' elements' + write(IMAIN,*) + write(IMAIN,*) 'Control elements have ',NGNOD,' nodes' + write(IMAIN,*) + call flush_IMAIN() + + ! reads in tangential detection + call read_mesh_tangential_curve_file() + + ! reads in node coordinates + ! user output + write(IMAIN,*) 'Node coordinates:' + call flush_IMAIN() + + if (read_external_mesh) then + call read_external_mesh_nodes_coords(nodes_coords_file) + else + ! reads interfaces and sets node coordinates + call read_mesh_nodes_coords_from_interfaces() + endif + + ! user output + write(IMAIN,*) 'Mesh surfaces:' + call flush_IMAIN() + + if (read_external_mesh) then + call read_external_acoustic_surface(free_surface_file, num_material, & + nbmodels, icodemat, phi_read, remove_min_to_start_at_zero) + + if (any_abs) then + call read_external_abs_surface(absorbing_surface_file, remove_min_to_start_at_zero) + + ! rotate the elements that are located on the edges of the mesh if needed + ! otherwise the plane wave and Bielak conditions may not be applied correctly + if (initialfield) call rotate_mesh_for_plane_wave(NGNOD) + endif + + if (ACOUSTIC_FORCING) then + call read_external_acoustic_forcing_surface(acoustic_forcing_surface_file, remove_min_to_start_at_zero) + + ! rotate the elements that are located on the edges of the mesh if needed + ! otherwise the plane wave and Bielak conditions may not be applied correctly + call rotate_mesh_for_acoustic_forcing(NGNOD) + endif + + else + ! determines acoustic free surface + call determine_acoustic_surface() + + ! determines absorbing boundary elements + call determine_abs_surface() + endif + + ! axi-symmetric mesh + if (AXISYM) then + ! user output + write(IMAIN,*) 'Axisymmetric mesh:' + call flush_IMAIN() + + if (read_external_mesh) then + ! external meshing + call read_external_axial_elements_file(axial_elements_file,remove_min_to_start_at_zero) + ! the mesh can have elements that are rotated, but for our GLJ axisymmetric implementation + ! we assume that the r axis is along the i direction; + ! thus this routine fixes that by rotating the elements backwards if needed to make sure + ! this assumption is always true + call rotate_mesh_for_axisym(NGNOD) + + else + ! internal meshing + ! if the mesh has been made by the internal mesher + if (xmin_param * xmax_param < 0) & + call stop_the_code('in axisymmetric mode xmin and xmax must have the same sign, they cannot cross the symmetry axis') + if (xmin_param < 0) & + call stop_the_code('in axisymmetric mode, case of symmetry axis on the right edge instead of left not supported yet') + + ! count the number of axial elements + nelem_on_the_axis = 0 + + ! test if the left edge is on the symmetry axis + if (abs(xmin_param) < TINYVAL) then + + ! if the surface is absorbing, it cannot be axial at the same time + if (absorbleft) call stop_the_code('in axisymmetric mode, the left edge cannot be both axial and absorbing') + + !all the elements on the left edge are axial because that edge is vertical and located in x = 0 + nelem_on_the_axis = nzread + allocate(ispec_of_axial_elements(nelem_on_the_axis),stat=ier) + if (ier /= 0) call stop_the_code('Error allocating array ispec_of_axial_elements') + + i = 1 + do j = 1,nzread + ispec_of_axial_elements(j) = (j-1)*nxread + (i-1) + 1 + enddo + + else + ! no elements on the symmetry axis + allocate(ispec_of_axial_elements(nelem_on_the_axis),stat=ier) + if (ier /= 0) call stop_the_code('Error allocating array ispec_of_axial_elements') + endif + + endif ! of if (read_external_mesh) then + ! user output + write(IMAIN,*) + write(IMAIN,*) 'Axial elements: ',nelem_on_the_axis + write(IMAIN,*) + else + ! .not. AXISYM + ! dummy allocation + nelem_on_the_axis = 0 + allocate(ispec_of_axial_elements(nelem_on_the_axis),stat=ier) + if (ier /= 0) call stop_the_code('Error allocating array ispec_of_axial_elements') + endif + + ! compute min and max of X and Z in the grid + write(IMAIN,*) + write(IMAIN,*) 'Mesh dimensions: ' + write(IMAIN,*) ' Min and max value of X in the grid = ',minval(nodes_coords(1,:)),maxval(nodes_coords(1,:)) + write(IMAIN,*) ' Min and max value of Z in the grid = ',minval(nodes_coords(2,:)),maxval(nodes_coords(2,:)) + write(IMAIN,*) + + ! create a Gnuplot file that displays the grid + if (output_grid_Gnuplot .and. .not. read_external_mesh) & + call save_gnuplot_file(NGNOD,nx_elem_internal,nz_elem_internal,grid_point_x,grid_point_z) + + ! partitioning + ! user output + write(IMAIN,*) 'Mesh partitioning:' + call flush_IMAIN() + + call decompose_mesh() + + ! setting absorbing boundaries by elements instead of edges + if (any_abs) then + ! user output + write(IMAIN,*) 'Absorbing boundaries:' + call flush_IMAIN() + + call merge_abs_boundaries(nbmodels, phi_read, num_material, NGNOD) + endif + + ! setting acoustic forcing boundaries by elements instead of edges + if (ACOUSTIC_FORCING) then + ! user output + write(IMAIN,*) 'Acoustic forcing boundaries:' + call flush_IMAIN() + + call merge_acoustic_forcing_boundaries(NGNOD) + endif + + ! generate the databases for the solver + ! user output + write(IMAIN,*) 'Saving databases:' + call flush_IMAIN() + + call save_databases() + + !--- compute position of the receivers and write the STATIONS file + if (.not. use_existing_STATIONS) then + ! user output + write(IMAIN,*) 'creating STATIONS file...' + call flush_IMAIN() + +!! DK DK for now we cannot use both record_at_surface_same_vertical and read_external_mesh +!! DK DK because we need to know splines to define the shape of the surface of the model + if (any(record_at_surface_same_vertical) .and. read_external_mesh) & + call stop_the_code('for now we cannot use both record_at_surface_same_vertical and read_external_mesh') + +!! DK DK if we read an external mesh, the splines are not defined for the shape of the surface and of the interfaces +!! DK DK therefore let us allocate dummy arrays just to be able to call the "save_stations_file" subroutine + if (read_external_mesh) then + npoints_interface_top = 1 + max_npoints_interface = 1 + allocate(xinterface_top(1)) + allocate(zinterface_top(1)) + allocate(coefs_interface_top(1)) + endif + + ! daniel todo: move to solver? + ! note that the STATIONS file will be written out here and then read in the solver to locate them. + ! in case we have record_at_surface_same_vertical(.) set to .true., the stations will be + ! placed at the surface, using splines for the top interface. + ! + ! in future, we might want to move this to the solver, to make the solver more independant + ! and work in a similar way like the 3D versions. + ! still, this would require to have these top splines in the solver... + call save_stations_file(nreceiversets,nrec_line,xdeb,zdeb,xfin,zfin,record_at_surface_same_vertical, & + xinterface_top,zinterface_top,coefs_interface_top, & + npoints_interface_top,max_npoints_interface) + endif + + ! user output + if (NPROC == 1) then + write(IMAIN,*) + write(IMAIN,*) 'This will be a serial simulation' + write(IMAIN,*) + else + write(IMAIN,*) + write(IMAIN,*) 'This will be a parallel simulation on ',NPROC,' processor cores' + write(IMAIN,*) + endif + + ! frees memory + if (allocated(nz_layer)) deallocate(nz_layer) + if (allocated(elmnts)) deallocate(elmnts) + + ! mesher works only for single process + endif ! myrank == 0 + + ! close main output file + if (myrank == 0 .and. IMAIN /= ISTANDARD_OUTPUT) close(IMAIN) + + ! secondary processes wait + call synchronize_all() + + ! MPI finish + call finalize_mpi() + +end program meshfem2D diff --git a/meshfem2d/meshfem2D_par.f90 b/meshfem2d/meshfem2D_par.f90 new file mode 100644 index 00000000..2973908f --- /dev/null +++ b/meshfem2d/meshfem2D_par.f90 @@ -0,0 +1,149 @@ +!======================================================================== +! +! S P E C F E M 2 D +! ----------------- +! +! Main historical authors: Dimitri Komatitsch and Jeroen Tromp +! CNRS, France +! and Princeton University, USA +! (there are currently many more authors!) +! (c) October 2017 +! +! This software is a computer program whose purpose is to solve +! the two-dimensional viscoelastic anisotropic or poroelastic wave equation +! using a spectral-element method (SEM). +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 3 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License along +! with this program; if not, write to the Free Software Foundation, Inc., +! 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +! +! The full text of the license is available in file "LICENSE". +! +!======================================================================== + + + module decompose_par + + implicit none + + ! variables used for storing info about the mesh and partitions + integer, dimension(:), allocatable :: my_interfaces + integer, dimension(:), allocatable :: my_nb_interfaces + + end module decompose_par + +! +!--------------------------------------------------------------------------------------- +! + + module part_unstruct_par + +! This module contains subroutines related to unstructured meshes and partitioning of the +! corresponding graphs. + + use shared_parameters, only: nelmnts,nxread,nzread,max_npoints_interface,number_of_interfaces, & + nz_layer,number_of_layers,nx_elem_internal,nz_elem_internal + + implicit none + + integer, dimension(:), allocatable :: elmnts + integer, dimension(:), allocatable :: elmnts_bis + integer, dimension(:), allocatable :: glob2loc_elmnts + integer, dimension(:), allocatable :: part + + integer :: nb_edges + + integer, dimension(:), allocatable :: xadj_g + integer, dimension(:), allocatable :: adjncy_g + + integer :: nnodes + double precision, dimension(:,:), allocatable :: nodes_coords + integer, dimension(:), allocatable :: nnodes_elmnts + integer, dimension(:), allocatable :: nodes_elmnts + integer, dimension(:), allocatable :: glob2loc_nodes_nparts + integer, dimension(:), allocatable :: glob2loc_nodes_parts + integer, dimension(:), allocatable :: glob2loc_nodes + + ! interface data + integer :: ninterfaces + integer, dimension(:), allocatable :: tab_size_interfaces, tab_interfaces + + integer :: nelem_acoustic_surface + integer, dimension(:,:), allocatable :: acoustic_surface + integer :: nelem_acoustic_surface_loc + + integer :: nelem_on_the_axis + integer, dimension(:), allocatable :: ispec_of_axial_elements + integer, dimension(:), allocatable :: inode1_axial_elements, inode2_axial_elements + integer :: nelem_on_the_axis_loc + + integer :: nelemabs + integer, dimension(:,:), allocatable :: abs_surface + logical, dimension(:,:), allocatable :: abs_surface_char + integer, dimension(:), allocatable :: abs_surface_merge,abs_surface_type + integer :: nelemabs_loc + + integer :: nelemabs_merge + integer, dimension(:), allocatable :: ibegin_edge1,iend_edge1,ibegin_edge3,iend_edge3, & + ibegin_edge4,iend_edge4,ibegin_edge2,iend_edge2 + + ! for acoustic/elastic coupled elements + integer :: nedges_coupled + integer, dimension(:,:), allocatable :: edges_coupled + + ! for acoustic/poroelastic coupled elements + integer :: nedges_acporo_coupled + integer, dimension(:,:), allocatable :: edges_acporo_coupled + + ! for poroelastic/elastic coupled elements + integer :: nedges_elporo_coupled + integer, dimension(:,:), allocatable :: edges_elporo_coupled + + ! for acoustic forcing elements + integer :: nelemacforcing + integer, dimension(:,:), allocatable :: acforcing_surface + logical, dimension(:,:), allocatable :: acforcing_surface_char + integer, dimension(:), allocatable :: acforcing_surface_merge,acforcing_surface_type + integer :: nelemacforcing_loc + + integer :: nelemacforcing_merge + integer, dimension(:), allocatable :: ibegin_edge1_acforcing,iend_edge1_acforcing, & + ibegin_edge3_acforcing,iend_edge3_acforcing,ibegin_edge4_acforcing,iend_edge4_acforcing, & + ibegin_edge2_acforcing,iend_edge2_acforcing + + ! variables used for tangential detection + integer :: nnodes_tangential_curve + double precision, dimension(:,:), allocatable :: nodes_tangential_curve + + ! coordinates of the grid points of the mesh + double precision, dimension(:,:), allocatable :: grid_point_x,grid_point_z + + integer :: npoints_interface_top + double precision, dimension(:), allocatable :: xinterface_top,zinterface_top,coefs_interface_top + + ! local coupled edges + integer :: nedges_coupled_loc + integer :: nedges_acporo_coupled_loc + integer :: nedges_elporo_coupled_loc + + ! to store the position of PML element in array region_pml_external_mesh + ! this is only useful when using PML together with external mesh + integer, dimension(:), allocatable :: region_pml_external_mesh + + integer :: remove_min_to_start_at_zero + + integer :: nspec + integer :: npgeo + integer :: iproc + + end module part_unstruct_par diff --git a/meshfem2d/metis_partitioning.F90 b/meshfem2d/metis_partitioning.F90 new file mode 100644 index 00000000..00f66ac0 --- /dev/null +++ b/meshfem2d/metis_partitioning.F90 @@ -0,0 +1,89 @@ +!======================================================================== +! +! S P E C F E M 2 D +! ----------------- +! +! Main historical authors: Dimitri Komatitsch and Jeroen Tromp +! CNRS, France +! and Princeton University, USA +! (there are currently many more authors!) +! (c) October 2017 +! +! This software is a computer program whose purpose is to solve +! the two-dimensional viscoelastic anisotropic or poroelastic wave equation +! using a spectral-element method (SEM). +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 3 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License along +! with this program; if not, write to the Free Software Foundation, Inc., +! 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +! +! The full text of the license is available in file "LICENSE". +! +!======================================================================== + + +! Partitioning using METIS + + subroutine metis_partitioning() + + use constants, only: IMAIN + +#ifdef USE_METIS + use part_unstruct_par, only: nelmnts,part,nb_edges, & + xadj => xadj_g,adjncy => adjncy_g + use compute_elements_load_par, only: elmnts_load,adjwgt + + use shared_parameters, only: nparts => NPROC +#endif + + implicit none + +! integer, intent(in) :: nelmnts, nparts, nb_edges +! integer, dimension(0:nelmnts), intent(in) :: xadj +! integer, dimension(0:MAX_NEIGHBORS*nelmnts-1), intent(in) :: adjncy +! integer, dimension(0:nelmnts-1), intent(in) :: elmnts_load +! integer, dimension(0:nb_edges-1), intent(in) :: adjwgt +! integer, dimension(:), pointer :: part + +#ifdef USE_METIS + integer, dimension(0:4) :: metis_options +#endif + + integer :: wgtflag + integer :: remove_min_to_start_at_zero + integer :: edgecut + +!! DK DK support for METIS now removed, we use SCOTCH instead + call stop_the_code('support for the METIS graph partitioner has been discontinued, please use SCOTCH (option 3) instead') + + ! initializes + remove_min_to_start_at_zero = 0 + wgtflag = 0 + edgecut = 0 + +#ifdef USE_METIS + call METIS_PartGraphRecursive(nelmnts, xadj(0), adjncy(0), elmnts_load(0), adjwgt(0), & + wgtflag, remove_min_to_start_at_zero, nparts, & + metis_options, edgecut, part(0)) + + !call METIS_PartGraphVKway(nelmnts, xadj(0), adjncy(0), elmnts_load(0), adjwgt(0), & + ! wgtflag, remove_min_to_start_at_zero, nparts, & + ! options, edgecut, part(0)) +#else + ! safety stop + write(IMAIN,*) 'This version of SPECFEM was not compiled with support of METIS.' + write(IMAIN,*) 'Please recompile with -DUSE_METIS in order to enable use of METIS.' + call stop_the_code('Metis partitioning not compiled') +#endif + + end subroutine metis_partitioning diff --git a/meshfem2d/parallel.F90 b/meshfem2d/parallel.F90 new file mode 100644 index 00000000..2188a727 --- /dev/null +++ b/meshfem2d/parallel.F90 @@ -0,0 +1,1779 @@ +!======================================================================== +! +! S P E C F E M 2 D +! ----------------- +! +! Main historical authors: Dimitri Komatitsch and Jeroen Tromp +! CNRS, France +! and Princeton University, USA +! (there are currently many more authors!) +! (c) October 2017 +! +! This software is a computer program whose purpose is to solve +! the two-dimensional viscoelastic anisotropic or poroelastic wave equation +! using a spectral-element method (SEM). +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 3 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License along +! with this program; if not, write to the Free Software Foundation, Inc., +! 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +! +! The full text of the license is available in file "LICENSE". +! +!======================================================================== + +! We added the ability to run several calculations (several earthquakes) +! in an embarrassingly-parallel fashion from within the same run; +! this can be useful when using a very large supercomputer to compute +! many earthquakes in a catalog, in which case it can be better from +! a batch job submission point of view to start fewer and much larger jobs, +! each of them computing several earthquakes in parallel. +! To turn that option on, set parameter NUMBER_OF_SIMULTANEOUS_RUNS to a value greater than 1 in the Par_file. +! To implement that, we create NUMBER_OF_SIMULTANEOUS_RUNS MPI sub-communicators, +! each of them being labeled "my_local_mpi_comm_world", and we use them +! in all the routines in "src/shared/parallel.f90", except in MPI_ABORT() because in that case +! we need to kill the entire run. +! When that option is on, of course the number of processor cores used to start +! the code in the batch system must be a multiple of NUMBER_OF_SIMULTANEOUS_RUNS, +! all the individual runs must use the same number of processor cores, +! which as usual is NPROC in the input file DATA/Par_file, +! and thus the total number of processor cores to request from the batch system +! should be NUMBER_OF_SIMULTANEOUS_RUNS * NPROC. +! All the runs to perform must be placed in directories called run0001, run0002, run0003 and so on +! (with exactly four digits). + +!------------------------------------------------------------------------------------------------- +! +! Parallel routines. All MPI calls should belong in this file! +! +!------------------------------------------------------------------------------------------------- + +module my_mpi + +! main parameter module for specfem simulations + +#ifdef WITH_MPI + ! standard include of the MPI library + use mpi +#endif + + implicit none + + integer :: my_local_mpi_comm_world, my_local_mpi_comm_for_bcast + +end module my_mpi + +!------------------------------------------------------------------------------------------------- +! +! MPI wrapper functions +! +!------------------------------------------------------------------------------------------------- + + subroutine init_mpi() + + use my_mpi + use shared_parameters, only: NUMBER_OF_SIMULTANEOUS_RUNS,BROADCAST_SAME_MESH_AND_MODEL + + implicit none + +#ifdef WITH_MPI + integer :: myrank + ! local parameters + integer :: sizeprocs + integer :: ier + + ! parallel version + call MPI_INIT(ier) + if (ier /= 0 ) call stop_the_code('Error initializing MPI') + + ! checks if getting size works + call MPI_COMM_SIZE(MPI_COMM_WORLD,sizeprocs,ier) + if (ier /= 0 ) call stop_the_code('Error getting MPI size') + ! we need to make sure that NUMBER_OF_SIMULTANEOUS_RUNS and BROADCAST_SAME_MESH_AND_MODEL are read before calling world_split() + ! thus read the parameter file + call MPI_COMM_RANK(MPI_COMM_WORLD,myrank,ier) + if (ier /= 0 ) call stop_the_code('Error getting MPI rank') + if (myrank == 0) then + call open_parameter_file_from_main_only() + ! we need to make sure that NUMBER_OF_SIMULTANEOUS_RUNS and BROADCAST_SAME_MESH_AND_MODEL are read + call read_value_integer_p(NUMBER_OF_SIMULTANEOUS_RUNS, 'NUMBER_OF_SIMULTANEOUS_RUNS') + call read_value_logical_p(BROADCAST_SAME_MESH_AND_MODEL, 'BROADCAST_SAME_MESH_AND_MODEL') + ! close parameter file + call close_parameter_file() + endif + ! broadcast parameters read from main to all processes + my_local_mpi_comm_world = MPI_COMM_WORLD + call bcast_all_singlei(NUMBER_OF_SIMULTANEOUS_RUNS) + call bcast_all_singlel(BROADCAST_SAME_MESH_AND_MODEL) +! create sub-communicators if needed, if running more than one earthquake from the same job + call world_split() + +! #else + +! NUMBER_OF_SIMULTANEOUS_RUNS = NUMBER_OF_SIMULTANEOUS_RUNS ! To avoid compiler warning +! BROADCAST_SAME_MESH_AND_MODEL = BROADCAST_SAME_MESH_AND_MODEL ! To avoid compiler warning +! ! we need to make sure that NUMBER_OF_SIMULTANEOUS_RUNS is read, thus read the parameter file +! ! initialize +! call read_parameter_file_init() +! ! open the Par_file +! call open_parameter_file() +! ! read only parameters (without receiver-line section, material tables or region definitions) +! call read_parameter_file_only() + +#endif + + end subroutine init_mpi + +! +!------------------------------------------------------------------------------------------------- +! + + subroutine finalize_mpi() + + use my_mpi + + implicit none + +#ifdef WITH_MPI + ! local parameters + integer :: ier + + ! close sub-communicators if needed, if running more than one earthquake from the same job + call world_unsplit() + + ! synchronizes all + call MPI_BARRIER(MPI_COMM_WORLD,ier) + + ! stop all the MPI processes, and exit + call MPI_FINALIZE(ier) + if (ier /= 0) call stop_the_code('Error finalizing MPI') +#endif + + end subroutine finalize_mpi + +! +!------------------------------------------------------------------------------------------------- +! + + subroutine abort_mpi() + + use my_mpi +#ifdef WITH_MPI + use constants, only: MAX_STRING_LEN,mygroup + use shared_input_parameters, only: NUMBER_OF_SIMULTANEOUS_RUNS +#endif + + implicit none + +#ifdef WITH_MPI + ! local parameters + + integer :: my_local_rank,my_global_rank,ier + logical :: run_file_exists + character(len=MAX_STRING_LEN) :: filename + + ! get my local rank and my global rank (in the case of simultaneous jobs, for which we split + ! the MPI communicator, they will be different; otherwise they are the same) + call world_rank(my_local_rank) + call MPI_COMM_RANK(MPI_COMM_WORLD,my_global_rank,ier) + + ! write a stamp file to disk to let the user know that the run failed + if (NUMBER_OF_SIMULTANEOUS_RUNS > 1) then + ! notifies which run directory failed + write(filename,"('run',i4.4,'_failed')") mygroup + 1 + inquire(file=trim(filename), exist=run_file_exists) + if (run_file_exists) then + open(unit=9765,file=trim(filename),status='old',position='append',action='write',iostat=ier) + else + open(unit=9765,file=trim(filename),status='new',action='write',iostat=ier) + endif + if (ier == 0) then + write(9765,*) 'run ',mygroup+1,' with local rank ',my_local_rank,' and global rank ',my_global_rank,' failed' + close(9765) + endif + + ! notifies which rank failed + write(filename,"('run_with_local_rank_',i8.8,'and_global_rank_',i8.8,'_failed')") my_local_rank,my_global_rank + open(unit=9765,file=trim(filename),status='unknown',action='write') + write(9765,*) 'run with local rank ',my_local_rank,' and global rank ',my_global_rank,' failed' + close(9765) + endif + + ! note: MPI_ABORT does not return, it makes the program exit with an error code of 30 + call MPI_ABORT(MPI_COMM_WORLD,30,ier) +#endif + + stop 'Error, program ended in exit_MPI' + + end subroutine abort_mpi + +! +!------------------------------------------------------------------------------------------------- +! + + subroutine synchronize_all() + + use my_mpi + + implicit none + +#ifdef WITH_MPI + ! local parameters + integer :: ier + + call MPI_BARRIER(my_local_mpi_comm_world,ier) + if (ier /= 0 ) call stop_the_code('Error synchronize MPI processes') +#endif + + end subroutine synchronize_all + +! +!------------------------------------------------------------------------------------------------- +! + + double precision function wtime() + + use my_mpi + + implicit none + +#ifdef WITH_MPI + wtime = MPI_WTIME() +#else + real :: ct + + ! note: for simplicity, we take cpu_time which returns the elapsed CPU time in seconds + ! (instead of wall clock time for parallel MPI function) + call cpu_time(ct) + wtime = ct +#endif + + end function wtime + +! +!------------------------------------------------------------------------------------------------- +! + + + subroutine wait_req(req) + + use my_mpi + + implicit none + + integer :: req + +#ifndef WITH_MPI + integer :: dummy +#endif + +#ifdef WITH_MPI + ! local parameters + integer :: ier + + call MPI_WAIT(req,MPI_STATUS_IGNORE,ier) +#else + ! to avoid compiler warning + dummy = req +#endif + + end subroutine wait_req + + +!------------------------------------------------------------------------------------------------- +! +! MPI broadcasting helper +! +!------------------------------------------------------------------------------------------------- + + + subroutine bcast_all_i(buffer, countval) + + use my_mpi + + implicit none + + integer :: countval + integer, dimension(countval) :: buffer +#ifndef WITH_MPI + integer :: dummy +#endif + +#ifdef WITH_MPI + integer :: ier + + call MPI_BCAST(buffer,countval,MPI_INTEGER,0,my_local_mpi_comm_world,ier) +#else + ! to avoid compiler warning + dummy = buffer(1) +#endif + + end subroutine bcast_all_i + +! +!------------------------------------------------------------------------------------------------- +! + + subroutine bcast_all_singlei(buffer) + + use my_mpi + + implicit none + + integer :: buffer +#ifndef WITH_MPI + integer :: dummy +#endif + +#ifdef WITH_MPI + integer :: ier + + call MPI_BCAST(buffer,1,MPI_INTEGER,0,my_local_mpi_comm_world,ier) +#else + ! to avoid compiler warning + dummy = buffer +#endif + + end subroutine bcast_all_singlei + +! +!------------------------------------------------------------------------------------------------- +! + + + subroutine bcast_all_l(buffer, countval) + + use my_mpi + + implicit none + + integer :: countval + logical, dimension(countval) :: buffer +#ifndef WITH_MPI + logical :: dummy +#endif + +#ifdef WITH_MPI + integer :: ier + + call MPI_BCAST(buffer,countval,MPI_LOGICAL,0,my_local_mpi_comm_world,ier) +#else + ! to avoid compiler warning + dummy = buffer(1) +#endif + + end subroutine bcast_all_l + +! +!------------------------------------------------------------------------------------------------- +! + + + subroutine bcast_all_singlel(buffer) + + use my_mpi + + implicit none + + logical :: buffer +#ifndef WITH_MPI + logical :: dummy +#endif + +#ifdef WITH_MPI + integer :: ier + + call MPI_BCAST(buffer,1,MPI_LOGICAL,0,my_local_mpi_comm_world,ier) +#else + ! to avoid compiler warning + dummy = buffer +#endif + + end subroutine bcast_all_singlel + + +! +!------------------------------------------------------------------------------------------------- +! + + subroutine bcast_all_dp(buffer, countval) + + use my_mpi + + implicit none + + integer :: countval + double precision, dimension(countval) :: buffer +#ifndef WITH_MPI + double precision :: dummy +#endif + +#ifdef WITH_MPI + integer :: ier + + call MPI_BCAST(buffer,countval,MPI_DOUBLE_PRECISION,0,my_local_mpi_comm_world,ier) +#else + ! to avoid compiler warning + dummy = buffer(1) +#endif + + end subroutine bcast_all_dp + +! +!------------------------------------------------------------------------------------------------- +! + + subroutine bcast_all_singledp(buffer) + + use my_mpi + + implicit none + + double precision :: buffer +#ifndef WITH_MPI + double precision :: dummy +#endif + +#ifdef WITH_MPI + integer :: ier + + call MPI_BCAST(buffer,1,MPI_DOUBLE_PRECISION,0,my_local_mpi_comm_world,ier) +#else + ! to avoid compiler warning + dummy = buffer +#endif + + end subroutine bcast_all_singledp + +! +!------------------------------------------------------------------------------------------------- +! + + subroutine bcast_all_string_array(buffer, countval) + + use my_mpi + use constants, only: MAX_STRING_LEN + + implicit none + + integer :: countval + character(len=MAX_STRING_LEN), dimension(countval) :: buffer +#ifndef WITH_MPI + character(len=MAX_STRING_LEN) :: dummy +#endif + +#ifdef WITH_MPI + integer :: ier + + call MPI_BCAST(buffer,countval*MAX_STRING_LEN,MPI_CHARACTER,0,my_local_mpi_comm_world,ier) +#else + ! to avoid compiler warning + dummy = buffer(1) +#endif + + end subroutine bcast_all_string_array + +! +!------------------------------------------------------------------------------------------------- +! + + subroutine bcast_all_string(buffer) + + use my_mpi + use constants, only: MAX_STRING_LEN + + implicit none + + character(len=MAX_STRING_LEN) :: buffer + +#ifndef WITH_MPI + character(len=MAX_STRING_LEN) :: dummy +#endif + +#ifdef WITH_MPI + integer :: ier + + call MPI_BCAST(buffer,MAX_STRING_LEN,MPI_CHARACTER,0,my_local_mpi_comm_world,ier) +#else + ! to avoid compiler warning + dummy = buffer +#endif + + end subroutine bcast_all_string + +! +!---- broadcast to send the mesh and model to other simultaneous runs +! + + subroutine bcast_all_i_for_database(buffer, countval) + + use my_mpi + use shared_parameters, only: NUMBER_OF_SIMULTANEOUS_RUNS,BROADCAST_SAME_MESH_AND_MODEL + + implicit none + integer :: countval + ! by not specifying any dimensions for the buffer here we can use this routine for arrays of any number + ! of indices, provided we call the routine using the first memory cell of that multidimensional array, + ! i.e. for instance buffer(1,1,1) if the array has three dimensions with indices that all start at 1. + integer :: buffer +#ifdef WITH_MPI + integer ier +#endif + + if (.not. (NUMBER_OF_SIMULTANEOUS_RUNS > 1 .and. BROADCAST_SAME_MESH_AND_MODEL)) return + +#ifdef WITH_MPI + call MPI_BCAST(buffer,countval,MPI_INTEGER,0,my_local_mpi_comm_for_bcast,ier) +#else + ! to avoid compiler warning + buffer = buffer + countval = countval +#endif + + end subroutine bcast_all_i_for_database + +! +!------------------------------------------------------------------------------------------------- +! +! Send/Receive MPI +! +!------------------------------------------------------------------------------------------------- + + subroutine bcast_all_l_for_database(buffer, countval) + + use my_mpi + use shared_parameters, only: NUMBER_OF_SIMULTANEOUS_RUNS,BROADCAST_SAME_MESH_AND_MODEL + + implicit none + + integer countval + ! by not specifying any dimensions for the buffer here we can use this routine for arrays of any number + ! of indices, provided we call the routine using the first memory cell of that multidimensional array, + ! i.e. for instance buffer(1,1,1) if the array has three dimensions with indices that all start at 1. + logical :: buffer + +#ifdef WITH_MPI + integer ier +#endif + + if (.not. (NUMBER_OF_SIMULTANEOUS_RUNS > 1 .and. BROADCAST_SAME_MESH_AND_MODEL)) return + +#ifdef WITH_MPI + call MPI_BCAST(buffer,countval,MPI_INTEGER,0,my_local_mpi_comm_for_bcast,ier) +#else + ! to avoid compiler warning + buffer = buffer + countval = countval +#endif + + end subroutine bcast_all_l_for_database + +! +!------------------------------------------------------------------------------------------------- +! + + subroutine bcast_all_cr_for_database(buffer, countval) + + use my_mpi + use constants, only: CUSTOM_REAL + use shared_parameters, only: NUMBER_OF_SIMULTANEOUS_RUNS,BROADCAST_SAME_MESH_AND_MODEL + + implicit none +#ifdef WITH_MPI + include "../setup/precision.h" +#endif + + integer countval + ! by not specifying any dimensions for the buffer here we can use this routine for arrays of any number + ! of indices, provided we call the routine using the first memory cell of that multidimensional array, + ! i.e. for instance buffer(1,1,1) if the array has three dimensions with indices that all start at 1. + real(kind=CUSTOM_REAL) :: buffer + +#ifdef WITH_MPI + integer ier +#endif + + if (.not. (NUMBER_OF_SIMULTANEOUS_RUNS > 1 .and. BROADCAST_SAME_MESH_AND_MODEL)) return + +#ifdef WITH_MPI + call MPI_BCAST(buffer,countval,CUSTOM_MPI_TYPE,0,my_local_mpi_comm_for_bcast,ier) +#else + ! to avoid compiler warning + buffer = buffer + countval = countval +#endif + + end subroutine bcast_all_cr_for_database + +! +!------------------------------------------------------------------------------------------------- +! + + subroutine bcast_all_dp_for_database(buffer, countval) + + use my_mpi + use shared_parameters, only: NUMBER_OF_SIMULTANEOUS_RUNS,BROADCAST_SAME_MESH_AND_MODEL + + implicit none + + integer countval + ! by not specifying any dimensions for the buffer here we can use this routine for arrays of any number + ! of indices, provided we call the routine using the first memory cell of that multidimensional array, + ! i.e. for instance buffer(1,1,1) if the array has three dimensions with indices that all start at 1. + double precision :: buffer +#ifdef USE_MP + integer ier +#endif + + if (.not. (NUMBER_OF_SIMULTANEOUS_RUNS > 1 .and. BROADCAST_SAME_MESH_AND_MODEL)) return + +#ifdef USE_MP + call MPI_BCAST(buffer,countval,MPI_DOUBLE_PRECISION,0,my_local_mpi_comm_for_bcast,ier) +#else + ! to avoid compiler warning + buffer = buffer + countval = countval +#endif + + end subroutine bcast_all_dp_for_database + +! +!------------------------------------------------------------------------------------------------- +! + + subroutine bcast_all_r_for_database(buffer, countval) + + use my_mpi + use shared_parameters, only: NUMBER_OF_SIMULTANEOUS_RUNS,BROADCAST_SAME_MESH_AND_MODEL + + implicit none + + integer countval + ! by not specifying any dimensions for the buffer here we can use this routine for arrays of any number + ! of indices, provided we call the routine using the first memory cell of that multidimensional array, + ! i.e. for instance buffer(1,1,1) if the array has three dimensions with indices that all start at 1. + real :: buffer + +#ifdef WITH_MPI + integer ier +#endif + + if (.not. (NUMBER_OF_SIMULTANEOUS_RUNS > 1 .and. BROADCAST_SAME_MESH_AND_MODEL)) return + +#ifdef WITH_MPI + call MPI_BCAST(buffer,countval,MPI_REAL,0,my_local_mpi_comm_for_bcast,ier) +#else + ! to avoid compiler warning + buffer = buffer + countval = countval +#endif + + end subroutine bcast_all_r_for_database + +!------------------------------------------------------------------------------------------------- +! +! MPI math helper +! +!------------------------------------------------------------------------------------------------- + + subroutine min_all_i(sendbuf, recvbuf) + + use my_mpi + + implicit none + + integer:: sendbuf, recvbuf + +#ifdef WITH_MPI + ! local parameters + integer ier + + call MPI_REDUCE(sendbuf,recvbuf,1,MPI_INTEGER,MPI_MIN,0,my_local_mpi_comm_world,ier) +#else + recvbuf = sendbuf +#endif + + end subroutine min_all_i + +! +!------------------------------------------------------------------------------------------------- +! + + subroutine max_all_i(sendbuf, recvbuf) + + use my_mpi + + implicit none + + integer :: sendbuf, recvbuf + +#ifdef WITH_MPI + ! local parameters + integer :: ier + + call MPI_REDUCE(sendbuf,recvbuf,1,MPI_INTEGER,MPI_MAX,0,my_local_mpi_comm_world,ier) +#else + recvbuf = sendbuf +#endif + + end subroutine max_all_i + +! +!------------------------------------------------------------------------------------------------- +! + + subroutine min_all_all_dp(sendbuf, recvbuf) + + use my_mpi + + implicit none + + double precision :: sendbuf, recvbuf + +#ifdef WITH_MPI + integer ier + + call MPI_ALLREDUCE(sendbuf,recvbuf,1,MPI_DOUBLE_PRECISION,MPI_MIN,my_local_mpi_comm_world,ier) +#else + recvbuf = sendbuf +#endif + + end subroutine min_all_all_dp + +! +!------------------------------------------------------------------------------------------------- +! + + subroutine min_all_1Darray_cr(sendbuf, recvbuf, nx) + + use my_mpi + use constants, only: CUSTOM_REAL + + implicit none + +#ifdef WITH_MPI + include "../setup/precision.h" +#endif + + integer :: nx + real(kind=CUSTOM_REAL),dimension(nx) :: sendbuf, recvbuf + +#ifdef WITH_MPI + integer :: ier + + + call MPI_REDUCE(sendbuf,recvbuf,nx,CUSTOM_MPI_TYPE,MPI_MIN,0,my_local_mpi_comm_world,ier) +#else + recvbuf(:) = sendbuf(:) +#endif + + end subroutine min_all_1Darray_cr + + +! +!------------------------------------------------------------------------------------------------- +! + + subroutine max_all_cr(sendbuf, recvbuf) + + use my_mpi + use constants, only: CUSTOM_REAL + + implicit none + +#ifdef WITH_MPI + include "../setup/precision.h" +#endif + + real(kind=CUSTOM_REAL) :: sendbuf, recvbuf + +#ifdef WITH_MPI + integer ier + + call MPI_REDUCE(sendbuf,recvbuf,1,CUSTOM_MPI_TYPE,MPI_MAX,0,my_local_mpi_comm_world,ier) +#else + recvbuf = sendbuf +#endif + + end subroutine max_all_cr + +! +!------------------------------------------------------------------------------------------------- +! + + subroutine max_all_1Darray_cr(sendbuf, recvbuf, nx) + + use my_mpi + use constants, only: CUSTOM_REAL + + implicit none + +#ifdef WITH_MPI + include "../setup/precision.h" +#endif + + integer :: nx + real(kind=CUSTOM_REAL),dimension(nx) :: sendbuf, recvbuf + +#ifdef WITH_MPI + integer :: ier + + + call MPI_REDUCE(sendbuf,recvbuf,nx,CUSTOM_MPI_TYPE,MPI_MAX,0,my_local_mpi_comm_world,ier) +#else + recvbuf(:) = sendbuf(:) +#endif + + end subroutine max_all_1Darray_cr + +! +!------------------------------------------------------------------------------------------------- +! + + subroutine max_all_all_i(sendbuf, recvbuf) + + use my_mpi + + implicit none + + integer :: sendbuf, recvbuf + +#ifdef WITH_MPI + integer ier + + call MPI_ALLREDUCE(sendbuf,recvbuf,1,MPI_INTEGER,MPI_MAX,my_local_mpi_comm_world,ier) +#else + recvbuf = sendbuf +#endif + + end subroutine max_all_all_i + + +! +!------------------------------------------------------------------------------------------------- +! + + subroutine max_all_all_dp(sendbuf, recvbuf) + + use my_mpi + + implicit none + + double precision :: sendbuf, recvbuf + +#ifdef WITH_MPI + integer ier + + call MPI_ALLREDUCE(sendbuf,recvbuf,1,MPI_DOUBLE_PRECISION,MPI_MAX,my_local_mpi_comm_world,ier) +#else + recvbuf = sendbuf +#endif + + end subroutine max_all_all_dp + +! +!------------------------------------------------------------------------------------------------- +! + + subroutine any_all_l(sendbuf, recvbuf) + + use my_mpi + + implicit none + + logical :: sendbuf, recvbuf + +#ifdef WITH_MPI + integer :: ier + + call MPI_ALLREDUCE(sendbuf,recvbuf,1,MPI_LOGICAL,MPI_LOR,my_local_mpi_comm_world,ier) +#else + recvbuf = sendbuf +#endif + + end subroutine any_all_l + +! +!------------------------------------------------------------------------------------------------- +! + +! MPI summations + + subroutine sum_all_i(sendbuf, recvbuf) + + use my_mpi + + implicit none + + integer :: sendbuf, recvbuf + +#ifdef WITH_MPI + ! local parameters + integer :: ier + + call MPI_REDUCE(sendbuf,recvbuf,1,MPI_INTEGER,MPI_SUM,0,my_local_mpi_comm_world,ier) +#else + recvbuf = sendbuf +#endif + + end subroutine sum_all_i + +! +!------------------------------------------------------------------------------------------------- +! + + subroutine sum_all_all_i(sendbuf, recvbuf) + + use my_mpi + + implicit none + + integer :: sendbuf, recvbuf + +#ifdef WITH_MPI + ! local parameters + integer :: ier + + call MPI_ALLREDUCE(sendbuf,recvbuf,1,MPI_INTEGER,MPI_SUM,my_local_mpi_comm_world,ier) +#else + recvbuf = sendbuf +#endif + + end subroutine sum_all_all_i + +! +!------------------------------------------------------------------------------------------------- +! + + subroutine sum_all_cr(sendbuf, recvbuf) + + use my_mpi + use constants, only: CUSTOM_REAL + + implicit none + +#ifdef WITH_MPI + include "../setup/precision.h" +#endif + + real(kind=CUSTOM_REAL) :: sendbuf, recvbuf + +#ifdef WITH_MPI + ! local parameters + integer :: ier + + call MPI_REDUCE(sendbuf,recvbuf,1,CUSTOM_MPI_TYPE,MPI_SUM,0,my_local_mpi_comm_world,ier) +#else + recvbuf = sendbuf +#endif + + end subroutine sum_all_cr + +! +!------------------------------------------------------------------------------------------------- +! + + subroutine sum_all_dp(sendbuf, recvbuf) + + use my_mpi + + implicit none + + double precision :: sendbuf, recvbuf + +#ifdef WITH_MPI + ! local parameters + integer :: ier + + call MPI_REDUCE(sendbuf,recvbuf,1,MPI_DOUBLE_PRECISION,MPI_SUM,0,my_local_mpi_comm_world,ier) +#else + recvbuf = sendbuf +#endif + + end subroutine sum_all_dp + +! +!------------------------------------------------------------------------------------------------- +! + + + subroutine sum_all_1Darray_i(sendbuf, recvbuf, nx) + + use my_mpi + + implicit none + + integer :: nx + integer, dimension(nx) :: sendbuf, recvbuf + +#ifdef WITH_MPI + integer :: ier + + call MPI_REDUCE(sendbuf,recvbuf,nx,MPI_INTEGER,MPI_SUM,0,my_local_mpi_comm_world,ier) +#else + ! to avoid compiler warning + recvbuf(:) = sendbuf(:) +#endif + + end subroutine sum_all_1Darray_i + +! +!------------------------------------------------------------------------------------------------- +! + + subroutine sum_all_all_dp(sendbuf, recvbuf) + + use my_mpi + + implicit none + + double precision :: sendbuf, recvbuf + +#ifdef WITH_MPI + ! local parameters + integer :: ier + + call MPI_ALLREDUCE(sendbuf,recvbuf,1,MPI_DOUBLE_PRECISION,MPI_SUM,my_local_mpi_comm_world,ier) +#else + recvbuf = sendbuf +#endif + + end subroutine sum_all_all_dp + +!------------------------------------------------------------------------------------------------- +! +! Send/Receive MPI +! +!------------------------------------------------------------------------------------------------- + +! asynchronuous send/receive + + subroutine isend_cr(sendbuf, sendcount, dest, sendtag, req) + + use my_mpi + use constants, only: CUSTOM_REAL + + implicit none + +#ifdef WITH_MPI + include "../setup/precision.h" +#endif + + integer :: sendcount, dest, sendtag, req + real(kind=CUSTOM_REAL), dimension(sendcount) :: sendbuf + +#ifndef WITH_MPI + integer :: dummy +#endif + +#ifdef WITH_MPI + integer :: ier + + call MPI_ISEND(sendbuf,sendcount,CUSTOM_MPI_TYPE,dest,sendtag,my_local_mpi_comm_world,req,ier) +#else + call stop_the_code('isend_cr not implemented for serial code') + ! to avoid compiler warning + dummy = sendbuf(1) + dummy = dest + dummy = sendtag + dummy = req +#endif + + end subroutine isend_cr + + +! +!------------------------------------------------------------------------------------------------- +! + + subroutine irecv_cr(recvbuf, recvcount, dest, recvtag, req) + + ! asynchronuous receive + + use my_mpi + use constants, only: CUSTOM_REAL + + implicit none + +#ifdef WITH_MPI + include "../setup/precision.h" +#endif + + integer :: recvcount, dest, recvtag, req + real(kind=CUSTOM_REAL), dimension(recvcount) :: recvbuf +#ifndef WITH_MPI + integer :: dummy +#endif + +#ifdef WITH_MPI + integer :: ier + + call MPI_IRECV(recvbuf,recvcount,CUSTOM_MPI_TYPE,dest,recvtag,my_local_mpi_comm_world,req,ier) +#else + call stop_the_code('irecv_cr not implemented for serial code') + ! to avoid compiler warning + dummy = recvbuf(1) + dummy = dest + dummy = recvtag + dummy = req +#endif + + end subroutine irecv_cr + +! +!------------------------------------------------------------------------------------------------- +! + +#ifdef WITH_MPI + + + subroutine send_singlei(sendbuf, dest, sendtag) + +! synchronuous/blocking send + + use my_mpi + + implicit none + + integer :: dest,sendtag + integer :: sendbuf + + integer :: ier + + call MPI_SEND(sendbuf,1,MPI_INTEGER,dest,sendtag,my_local_mpi_comm_world,ier) + + end subroutine send_singlei + +#endif + +! +!------------------------------------------------------------------------------------------------- +! +#ifdef WITH_MPI + + subroutine send_singledp(sendbuf, dest, sendtag) + +! synchronuous/blocking send + + use my_mpi + + implicit none + + integer :: dest,sendtag + double precision :: sendbuf + + integer :: ier + + call MPI_SEND(sendbuf,1,MPI_DOUBLE_PRECISION,dest,sendtag,my_local_mpi_comm_world,ier) + + end subroutine send_singledp + +#endif + +! +!------------------------------------------------------------------------------------------------- +! +#ifdef WITH_MPI + + subroutine recv_singlei(recvbuf, dest, recvtag ) + +! synchronuous/blocking receive + + use my_mpi + + implicit none + + integer :: dest,recvtag + integer :: recvbuf + + integer :: ier + + call MPI_RECV(recvbuf,1,MPI_INTEGER,dest,recvtag,my_local_mpi_comm_world,MPI_STATUS_IGNORE,ier) + + end subroutine recv_singlei + +#endif + +! +!------------------------------------------------------------------------------------------------- +! +#ifdef WITH_MPI + + subroutine recv_any_singlei(recvbuf, recvtag ) + +! synchronuous/blocking receive + + use my_mpi + + implicit none + + integer :: recvtag + integer :: recvbuf + + integer :: ier + + call MPI_RECV(recvbuf,1,MPI_INTEGER,MPI_ANY_SOURCE,recvtag,my_local_mpi_comm_world,MPI_STATUS_IGNORE,ier) + + end subroutine recv_any_singlei + +#endif + +! +!------------------------------------------------------------------------------------------------- +! + +#ifdef WITH_MPI + + subroutine recv_singledp(recvbuf, dest, recvtag ) + +! synchronuous/blocking receive + + use my_mpi + + implicit none + + integer :: dest,recvtag + double precision :: recvbuf + + integer :: ier + + call MPI_RECV(recvbuf,1,MPI_DOUBLE_PRECISION,dest,recvtag,my_local_mpi_comm_world,MPI_STATUS_IGNORE,ier) + + end subroutine recv_singledp + +#endif + +! +!------------------------------------------------------------------------------------------------- +! + +#ifdef WITH_MPI + + subroutine recv_any_singledp(recvbuf, recvtag ) + +! synchronuous/blocking receive + + use my_mpi + + implicit none + + integer :: recvtag + double precision :: recvbuf + + integer :: ier + + call MPI_RECV(recvbuf,1,MPI_DOUBLE_PRECISION,MPI_ANY_SOURCE,recvtag,my_local_mpi_comm_world,MPI_STATUS_IGNORE,ier) + + end subroutine recv_any_singledp + +#endif + + +! +!------------------------------------------------------------------------------------------------- +! + +#ifdef WITH_MPI + + + subroutine send_i(sendbuf, sendcount, dest, sendtag) + +! synchronuous/blocking send + + use my_mpi + + implicit none + + integer :: dest,sendtag + integer :: sendcount + integer,dimension(sendcount):: sendbuf + + integer :: ier + + call MPI_SEND(sendbuf,sendcount,MPI_INTEGER,dest,sendtag,my_local_mpi_comm_world,ier) + + end subroutine send_i + +#endif + +! +!------------------------------------------------------------------------------------------------- +! + +#ifdef WITH_MPI + + subroutine send_dp(sendbuf, sendcount, dest, sendtag) + +! synchronuous/blocking send + + use my_mpi + + implicit none + + integer :: dest,sendtag + integer :: sendcount + double precision,dimension(sendcount):: sendbuf + + integer :: ier + + call MPI_SEND(sendbuf,sendcount,MPI_DOUBLE_PRECISION,dest,sendtag,my_local_mpi_comm_world,ier) + + end subroutine send_dp + +#endif + +! +!------------------------------------------------------------------------------------------------- +! + +#ifdef WITH_MPI + + subroutine send_l(sendbuf, sendcount, dest, sendtag) + +! synchronuous/blocking send + + use my_mpi + + implicit none + + integer :: dest,sendtag + integer :: sendcount + logical,dimension(sendcount):: sendbuf + + integer :: ier + + call MPI_SEND(sendbuf,sendcount,MPI_LOGICAL,dest,sendtag,my_local_mpi_comm_world,ier) + + end subroutine send_l + +#endif + +! +!------------------------------------------------------------------------------------------------- +! + +#ifdef WITH_MPI + + subroutine recv_i(recvbuf,recvcount, dest, recvtag ) + +! synchronuous/blocking receive + + use my_mpi + + implicit none + + integer :: dest,recvtag + integer :: recvcount + integer,dimension(recvcount):: recvbuf + + integer :: ier + + call MPI_RECV(recvbuf,recvcount,MPI_INTEGER,dest,recvtag,my_local_mpi_comm_world,MPI_STATUS_IGNORE,ier) + + end subroutine recv_i + +#endif + +! +!------------------------------------------------------------------------------------------------- +! + +#ifdef WITH_MPI + + subroutine recv_dp(recvbuf,recvcount, dest, recvtag ) + +! synchronuous/blocking receive + + use my_mpi + + implicit none + + integer :: dest,recvtag + integer :: recvcount + double precision,dimension(recvcount):: recvbuf + + integer :: ier + + call MPI_RECV(recvbuf,recvcount,MPI_DOUBLE_PRECISION,dest,recvtag,my_local_mpi_comm_world,MPI_STATUS_IGNORE,ier) + + end subroutine recv_dp + +#endif + +! +!------------------------------------------------------------------------------------------------- +! + +#ifdef WITH_MPI + + subroutine recv_l(recvbuf,recvcount, dest, recvtag ) + +! synchronuous/blocking receive + + use my_mpi + + implicit none + + integer :: dest,recvtag + integer :: recvcount + logical,dimension(recvcount):: recvbuf + + integer :: ier + + call MPI_RECV(recvbuf,recvcount,MPI_LOGICAL,dest,recvtag,my_local_mpi_comm_world,MPI_STATUS_IGNORE,ier) + + end subroutine recv_l + +#endif + + +!------------------------------------------------------------------------------------------------- +! +! MPI gather helper +! +!------------------------------------------------------------------------------------------------- + + subroutine gather_all_i(sendbuf, sendcnt, recvbuf, recvcount, NPROC) + + use my_mpi + + implicit none + + integer :: sendcnt, recvcount, NPROC + integer, dimension(sendcnt) :: sendbuf + integer, dimension(recvcount,0:NPROC-1) :: recvbuf + +#ifdef WITH_MPI + ! local parameters + integer :: ier + + call MPI_GATHER(sendbuf,sendcnt,MPI_INTEGER,recvbuf,recvcount,MPI_INTEGER,0,my_local_mpi_comm_world,ier) +#else + recvbuf(:,0) = sendbuf(:) +#endif + + end subroutine gather_all_i + +! +!------------------------------------------------------------------------------------------------- +! + + subroutine gather_all_dp(sendbuf, sendcnt, recvbuf, recvcount, NPROC) + + use my_mpi + + implicit none + + integer :: sendcnt, recvcount, NPROC + double precision, dimension(sendcnt) :: sendbuf + double precision, dimension(recvcount,0:NPROC-1) :: recvbuf + +#ifdef WITH_MPI + ! local parameters + integer :: ier + + call MPI_GATHER(sendbuf,sendcnt,MPI_DOUBLE_PRECISION,recvbuf,recvcount,MPI_DOUBLE_PRECISION,0,my_local_mpi_comm_world,ier) +#else + recvbuf(:,0) = sendbuf(:) +#endif + + end subroutine gather_all_dp + +! +!------------------------------------------------------------------------------------------------- +! + + subroutine gather_all_singlei(sendbuf, recvbuf, NPROC) + + use my_mpi + + implicit none + + integer :: NPROC + integer :: sendbuf + integer, dimension(0:NPROC-1) :: recvbuf + +#ifdef WITH_MPI + ! local parameters + integer :: ier + + call MPI_GATHER(sendbuf,1,MPI_INTEGER,recvbuf,1,MPI_INTEGER,0,my_local_mpi_comm_world,ier) +#else + recvbuf(0) = sendbuf +#endif + + end subroutine gather_all_singlei + +! +!------------------------------------------------------------------------------------------------- +! + + subroutine gather_all_singledp(sendbuf, recvbuf, NPROC) + + use my_mpi + + implicit none + + integer :: NPROC + double precision :: sendbuf + double precision, dimension(0:NPROC-1) :: recvbuf + +#ifdef WITH_MPI + ! local parameters + integer :: ier + call MPI_GATHER(sendbuf,1,MPI_DOUBLE_PRECISION,recvbuf,1,MPI_DOUBLE_PRECISION,0,my_local_mpi_comm_world,ier) +#else + recvbuf(0) = sendbuf +#endif + +end subroutine gather_all_singledp + +! +!------------------------------------------------------------------------------------------------- +! + + subroutine gather_all_all_singlei(sendbuf, recvbuf, NPROC) + + use my_mpi + + implicit none + + integer :: NPROC + integer :: sendbuf + integer, dimension(0:NPROC-1) :: recvbuf + +#ifdef WITH_MPI + ! local parameters + integer :: ier + + call MPI_ALLGATHER(sendbuf,1,MPI_INTEGER,recvbuf,1,MPI_INTEGER,my_local_mpi_comm_world,ier) +#else + recvbuf(0) = sendbuf +#endif + + end subroutine gather_all_all_singlei + + + + +!------------------------------------------------------------------------------------------------- +! +! MPI world helper +! +!------------------------------------------------------------------------------------------------- + + subroutine world_size(sizeval) + + use my_mpi + + implicit none + + integer,intent(out) :: sizeval + +#ifdef WITH_MPI + ! local parameters + integer :: ier + + call MPI_COMM_SIZE(my_local_mpi_comm_world,sizeval,ier) + if (ier /= 0 ) call stop_the_code('Error getting MPI world size') +#else + ! single process + sizeval = 1 +#endif + + end subroutine world_size + +! +!------------------------------------------------------------------------------------------------- +! + + subroutine world_rank(rank) + + use my_mpi + + implicit none + + integer,intent(out) :: rank + +#ifdef WITH_MPI + ! local parameters + integer :: ier + + call MPI_COMM_RANK(my_local_mpi_comm_world,rank,ier) + if (ier /= 0 ) call stop_the_code('Error getting MPI rank') +#else + ! always returns main rank zero + rank = 0 +#endif + + end subroutine world_rank + +! +!------------------------------------------------------------------------------------------------- +! + + subroutine world_duplicate(comm) + + use my_mpi + + implicit none + + integer,intent(out) :: comm + +#ifdef WITH_MPI + integer :: ier + + call MPI_COMM_DUP(my_local_mpi_comm_world,comm,ier) + if (ier /= 0) call stop_the_code('error duplicating my_local_mpi_comm_world communicator') +#else + comm = comm +#endif + + end subroutine world_duplicate + +! +!------------------------------------------------------------------------------------------------- +! + + subroutine world_get_comm(comm) + + use my_mpi + + implicit none + + integer,intent(out) :: comm + + comm = my_local_mpi_comm_world + + end subroutine world_get_comm + +! +!------------------------------------------------------------------------------------------------- +! + +#ifdef WITH_MPI +! create sub-communicators if needed, if running more than one earthquake from the same job. +! create a sub-communicator for each independent run; +! if there is a single run to do, then just copy the default communicator to the new one + + subroutine world_split() + + use my_mpi + + use constants, only: MAX_STRING_LEN,OUTPUT_FILES, & + IMAIN,ISTANDARD_OUTPUT,mygroup,I_should_read_the_database + use shared_parameters, only: NUMBER_OF_SIMULTANEOUS_RUNS,BROADCAST_SAME_MESH_AND_MODEL + + implicit none + + integer :: sizeval,myrank,ier,key,my_group_for_bcast,my_local_rank_for_bcast,NPROC + + character(len=MAX_STRING_LEN) :: path_to_add + + if (NUMBER_OF_SIMULTANEOUS_RUNS <= 0) call stop_the_code('NUMBER_OF_SIMULTANEOUS_RUNS <= 0 makes no sense') + + call MPI_COMM_SIZE(MPI_COMM_WORLD,sizeval,ier) + call MPI_COMM_RANK(MPI_COMM_WORLD,myrank,ier) + + if (NUMBER_OF_SIMULTANEOUS_RUNS > 1 .and. mod(sizeval,NUMBER_OF_SIMULTANEOUS_RUNS) /= 0) then + if (myrank == 0) print *,'Error: the number of MPI processes ',sizeval, & + ' is not a multiple of NUMBER_OF_SIMULTANEOUS_RUNS = ',NUMBER_OF_SIMULTANEOUS_RUNS + call stop_the_code( & +'the number of MPI processes is not a multiple of NUMBER_OF_SIMULTANEOUS_RUNS. Make sure you call meshfem2D with mpirun.') + endif + + if (NUMBER_OF_SIMULTANEOUS_RUNS > 1 .and. IMAIN == ISTANDARD_OUTPUT) & + call stop_the_code( & +'must not have IMAIN == ISTANDARD_OUTPUT when NUMBER_OF_SIMULTANEOUS_RUNS > 1 otherwise output to screen is mingled. & + & Change this in specfem/setup/constant.h.in and recompile.') + + if (NUMBER_OF_SIMULTANEOUS_RUNS == 1) then + + my_local_mpi_comm_world = MPI_COMM_WORLD + +! no broadcast of the mesh and model databases to other runs in that case + my_group_for_bcast = 0 + my_local_mpi_comm_for_bcast = MPI_COMM_NULL + + else + +!--- create a subcommunicator for each independent run + + NPROC = sizeval / NUMBER_OF_SIMULTANEOUS_RUNS + +! create the different groups of processes, one for each independent run + mygroup = myrank / NPROC + key = myrank + if (mygroup < 0 .or. mygroup > NUMBER_OF_SIMULTANEOUS_RUNS-1) call stop_the_code('invalid value of mygroup') + +! build the sub-communicators + call MPI_COMM_SPLIT(MPI_COMM_WORLD, mygroup, key, my_local_mpi_comm_world, ier) + if (ier /= 0) call stop_the_code('error while trying to create the sub-communicators') + +! add the right directory for that run +! (group numbers start at zero, but directory names start at run0001, thus we add one) + write(path_to_add,"('run',i4.4,'/')") mygroup + 1 + OUTPUT_FILES = path_to_add(1:len_trim(path_to_add))//OUTPUT_FILES(1:len_trim(OUTPUT_FILES)) + !IN_DATA_FILES = path_to_add(1:len_trim(path_to_add))//IN_DATA_FILES(1:len_trim(IN_DATA_FILES)) + +!--- create a subcommunicator to broadcast the identical mesh and model databases if needed + if (BROADCAST_SAME_MESH_AND_MODEL) then + + call MPI_COMM_RANK(MPI_COMM_WORLD,myrank,ier) +! to broadcast the model, split along similar ranks per run instead + my_group_for_bcast = mod(myrank,NPROC) + key = myrank + if (my_group_for_bcast < 0 .or. my_group_for_bcast > NPROC-1) call stop_the_code('invalid value of my_group_for_bcast') + +! build the sub-communicators + call MPI_COMM_SPLIT(MPI_COMM_WORLD, my_group_for_bcast, key, my_local_mpi_comm_for_bcast, ier) + if (ier /= 0) call stop_the_code('error while trying to create the sub-communicators') + +! see if that process will need to read the mesh and model database and then broadcast it to others + call MPI_COMM_RANK(my_local_mpi_comm_for_bcast,my_local_rank_for_bcast,ier) + if (my_local_rank_for_bcast > 0) I_should_read_the_database = .false. + + else + +! no broadcast of the mesh and model databases to other runs in that case + my_group_for_bcast = 0 + my_local_mpi_comm_for_bcast = MPI_COMM_NULL + + endif + + endif + + end subroutine world_split + +#endif +! +!------------------------------------------------------------------------------------------------- +! + +! close sub-communicators if needed, if running more than one earthquake from the same job. + subroutine world_unsplit() + + use my_mpi +#ifdef WITH_MPI + use shared_parameters, only: NUMBER_OF_SIMULTANEOUS_RUNS,BROADCAST_SAME_MESH_AND_MODEL + + implicit none + + integer :: ier + + if (NUMBER_OF_SIMULTANEOUS_RUNS > 1) then + call MPI_COMM_FREE(my_local_mpi_comm_world,ier) + if (BROADCAST_SAME_MESH_AND_MODEL) call MPI_COMM_FREE(my_local_mpi_comm_for_bcast,ier) + endif +#endif + + end subroutine world_unsplit diff --git a/meshfem2d/param_reader.c b/meshfem2d/param_reader.c new file mode 100644 index 00000000..0287b3fb --- /dev/null +++ b/meshfem2d/param_reader.c @@ -0,0 +1,414 @@ +/* + !======================================================================== + ! + ! S P E C F E M 2 D + ! ----------------- + ! + ! Main historical authors: Dimitri Komatitsch and Jeroen Tromp + ! CNRS, France + ! and Princeton University, USA + ! (there are currently many more authors!) + ! (c) October 2017 + ! + ! This software is a computer program whose purpose is to solve + ! the viscoelastic anisotropic or poroelastic wave equation + ! using a spectral-element method (SEM). + ! + ! This program is free software; you can redistribute it and/or modify + ! it under the terms of the GNU General Public License as published by + ! the Free Software Foundation; either version 3 of the License, or + ! (at your option) any later version. + ! + ! This program is distributed in the hope that it will be useful, + ! but WITHOUT ANY WARRANTY; without even the implied warranty of + ! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + ! GNU General Public License for more details. + ! + ! You should have received a copy of the GNU General Public License along + ! with this program; if not, write to the Free Software Foundation, Inc., + ! 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + ! + ! The full text of the license is available in file "LICENSE". + ! + !======================================================================== + */ + +/* + + by Dennis McRitchie (Princeton University, USA) and others + + January 7, 2010 - par_file parsing + June 1, 2011 - Updated to support multi-word values; also a few bug fixes. + .. + You'll notice that the heart of the parser is a complex regular + expression that is compiled within the C code, and then used to split + the lines appropriately. It does all the heavy lifting. I don't know of + any way to do this in Fortran. I believe that to accomplish this in + Fortran, you'd have to write a lot of procedural string manipulation + code, for which Fortran is not very well suited. + + But Fortran-C mixes are pretty common these days, so I would not expect + any problems on that account. There are no wrapper functions used: just + the C routine called directly from a Fortran routine. Also, regarding + the use of C, I assumed this would not be a problem since there are + already a few C files that make up part of the build. + .. +*/ + +#define _GNU_SOURCE +#include "config.h" +#include +#include +#include +#include + +#ifndef LINE_MAX +#define LINE_MAX 255 +#endif + +/* + * Mac OS X's gcc does not support strnlen and strndup. + * So we define them here conditionally, to avoid duplicate definitions + * on other systems. + */ +#ifdef __APPLE__ +size_t strnlen (const char *string, size_t maxlen) +{ + const char *end = memchr (string, '\0', maxlen); + return end ? (size_t) (end - string) : maxlen; +} + +char *strndup (char const *s, size_t n) +{ + size_t len = strnlen (s, n); + char *new = malloc (len + 1); + + if (new == NULL) + return NULL; + + new[len] = '\0'; + return memcpy (new, s, len); +} +#endif +/*===============================================================*/ + +FILE * fid; + +void +FC_FUNC_(param_open,PARAM_OPEN)(char * filename, int * length, int * ierr) +{ + char * fncopy; + char * blank; + + // Trim the file name. + fncopy = strndup(filename, *length); + blank = strchr(fncopy, ' '); + if (blank != NULL) { + fncopy[blank - fncopy] = '\0'; + } + if ((fid = fopen(fncopy, "r")) == NULL) { + // DK DK purposely suppressed this for NUMBER_OF_SIMULTANEOUS_RUNS printf("Can't open '%s'\n", fncopy); + *ierr = 1; + return; + } + free(fncopy); + *ierr = 0; +} + +void +FC_FUNC_(param_close,PARAM_CLOSE)() +{ + fclose(fid); +} + +void +FC_FUNC_(param_read,PARAM_READ)(char * string_read, int * string_read_len, char * name, int * name_len, int * ierr) +{ + char * namecopy; + char * blank; + char * namecopy2; + int status; + regex_t compiled_pattern; + char line[LINE_MAX]; + int regret; + regmatch_t parameter[3]; + char * keyword; + char * value; + size_t value_len; + + // Trim the keyword name we're looking for. + namecopy = strndup(name, *name_len); + blank = strchr(namecopy, ' '); + if (blank != NULL) { + namecopy[blank - namecopy] = '\0'; + } + + // Then get rid of any dot-terminated prefix. + namecopy2 = strchr(namecopy, '.'); + if (namecopy2 != NULL) { + namecopy2 += 1; + } else { + namecopy2 = namecopy; + } + + /* Regular expression for parsing lines from param file. + ** Good luck reading this regular expression. Basically, the lines of + ** the parameter file should be of the form 'parameter = value', + ** optionally followed by a #-delimited comment. + ** 'value' can be any number of space- or tab-separated words. Blank + ** lines, lines containing only white space and lines whose first non- + ** whitespace character is '#' are ignored. White space is generally + ** ignored. As you will see later in the code, if both parameter and + ** value are not specified the line is ignored. + */ + char pattern[] = "^[ \t]*([^# \t]+)[ \t]*=[ \t]*([^# \t]+([ \t]+[^# \t]+)*)"; + + // Compile the regular expression. + status = regcomp(&compiled_pattern, pattern, REG_EXTENDED); + if (status != 0) { + printf("regcomp returned error %d\n", status); + } + // Position the open file to the beginning. + if (fseek(fid, 0, SEEK_SET) != 0) { + printf("Can't seek to beginning of parameter file\n"); + *ierr = 1; + regfree(&compiled_pattern); + return; + } + // Read every line in the file. + while (fgets(line, LINE_MAX, fid) != NULL) { + // Get rid of the ending newline. + int linelen = strlen(line); + if (line[linelen-1] == '\n') { + line[linelen-1] = '\0'; + } + /* Test if line matches the regular expression pattern, if so + ** return position of keyword and value */ + regret = regexec(&compiled_pattern, line, 3, parameter, 0); + // If no match, check the next line. + if (regret == REG_NOMATCH) { + continue; + } + // If any error, bail out with an error message. + if (regret != 0) { + printf("regexec returned error %d\n", regret); + *ierr = 1; + regfree(&compiled_pattern); + return; + } + // printf("Line read = %s\n", line); + // If we have a match, extract the keyword from the line. + keyword = strndup(line+parameter[1].rm_so, parameter[1].rm_eo-parameter[1].rm_so); + + // If the keyword is not the one we're looking for, check the next line. + if (strcmp(keyword, namecopy2) != 0) { + free(keyword); + continue; + } + free(keyword); + regfree(&compiled_pattern); + // If it matches, extract the value from the line. + value = strndup(line+parameter[2].rm_so, parameter[2].rm_eo-parameter[2].rm_so); + + // Clear out the return string with blanks, copy the value into it, and return. + memset(string_read, ' ', *string_read_len); + + value_len = strlen(value); + // makes sure there is a character left for NUL termination + if (value_len > (size_t)*string_read_len - 1) value_len = *string_read_len - 1; + + strncpy(string_read, value, value_len); + + free(value); + free(namecopy); + *ierr = 0; + return; + } + // If no keyword matches, set the error flag + free(namecopy); + regfree(&compiled_pattern); + *ierr = 1; + return; +} + + +// reads next line in file to read in parameter +void +FC_FUNC_(param_read_nextparam,PARAM_READ_NEXTPARAM)(char * string_read, int * string_read_len, char * name, int * name_len, int * ierr) +{ + char * namecopy; + char * blank; + char * namecopy2; + int status; + regex_t compiled_pattern; + char line[LINE_MAX]; + int regret; + regmatch_t parameter[3]; + char * keyword; + char * value; + size_t value_len; + + // Trim the keyword name we're looking for. + namecopy = strndup(name, *name_len); + blank = strchr(namecopy, ' '); + if (blank != NULL) { + namecopy[blank - namecopy] = '\0'; + } + // Then get rid of any dot-terminated prefix. + namecopy2 = strchr(namecopy, '.'); + if (namecopy2 != NULL) { + namecopy2 += 1; + } else { + namecopy2 = namecopy; + } + + /* Regular expression for parsing lines from param file. + ** Good luck reading this regular expression. Basically, the lines of + ** the parameter file should be of the form 'parameter = value', + ** optionally followed by a #-delimited comment. + ** 'value' can be any number of space- or tab-separated words. Blank + ** lines, lines containing only white space and lines whose first non- + ** whitespace character is '#' are ignored. White space is generally + ** ignored. As you will see later in the code, if both parameter and + ** value are not specified the line is ignored. + */ + char pattern[] = "^[ \t]*([^# \t]+)[ \t]*=[ \t]*([^# \t]+([ \t]+[^# \t]+)*)"; + + // Compile the regular expression. + status = regcomp(&compiled_pattern, pattern, REG_EXTENDED); + if (status != 0) { + printf("regcomp returned error %d\n", status); + } + + // Do not reposition to BOF - use current position where file pointer is now... + + // Read next lines in the file until we have a match. + while (fgets(line, LINE_MAX, fid) != NULL) { + // Get rid of the ending newline. + int linelen = strlen(line); + if (line[linelen-1] == '\n') { + line[linelen-1] = '\0'; + } + /* Test if line matches the regular expression pattern, if so + ** return position of keyword and value */ + regret = regexec(&compiled_pattern, line, 3, parameter, 0); + // If no match, check the next line. + if (regret == REG_NOMATCH) { + continue; + } + // If any error, bail out with an error message. + if (regret != 0) { + printf("regexec returned error %d\n", regret); + *ierr = 1; + regfree(&compiled_pattern); + return; + } + //printf("Line nextparam read: %s\n", line); + + // If we have a match, extract the keyword from the line. + keyword = strndup(line+parameter[1].rm_so, parameter[1].rm_eo-parameter[1].rm_so); + //printf("keyword: %s\n", keyword); + + // If the keyword is not the one we're looking for, return with an error. + if (strcmp(keyword, namecopy2) != 0) { + printf("keyword returned wrong parameter %s instead of %s \n", keyword,namecopy2); + free(keyword); + *ierr = 1; + regfree(&compiled_pattern); + return; + } + free(keyword); + regfree(&compiled_pattern); + + // If it matches, extract the value from the line. + value = strndup(line+parameter[2].rm_so, parameter[2].rm_eo-parameter[2].rm_so); + //printf("value: %s\n", value); + + // Clear out the return string with blanks, copy the value into it, and return. + memset(string_read, ' ', *string_read_len); + + value_len = strlen(value); + // makes sure there is a character left for NUL termination + if (value_len > (size_t)*string_read_len - 1) value_len = *string_read_len - 1; + + strncpy(string_read, value, value_len); + // printf("'%s'='%s'\n", namecopy2, value); + + free(value); + free(namecopy); + *ierr = 0; + return; + } + // If no next line matches, print out error and die. + printf("No match in parameter file for keyword '%s' on next line\n", namecopy); + free(namecopy); + regfree(&compiled_pattern); + *ierr = 1; + return; +} + + +// reads next line in file to read in parameters without need of given parameter name +void +FC_FUNC_(param_read_nextline,PARAM_READ_NEXTLINE)(char * string_read, int * string_read_len, int * ierr) +{ + int status; + regex_t compiled_pattern; + char line[LINE_MAX]; + int regret; + regmatch_t parameter[1]; + size_t value_len; + + // Regular expression to skip any comment lines. + char pattern[] = "^[ \t]*[^#]"; + + // Compile the regular expression. + status = regcomp(&compiled_pattern, pattern, REG_EXTENDED); + if (status != 0) { + printf("regcomp returned error %d\n", status); + } + + // Do not reposition to BOF - use current position where file pointer is now... + + // Read every line in the file. + while (fgets(line, LINE_MAX, fid) != NULL) { + // Get rid of the ending newline. + int linelen = strlen(line); + if (line[linelen-1] == '\n') { + line[linelen-1] = '\0'; + } + // Test if line matches the regular expression pattern + regret = regexec(&compiled_pattern, line, 1, parameter, 0); + // If no match (i.e., comment line), check the next line. + if (regret == REG_NOMATCH) { + continue; + } + // If any error, bail out with an error message. + if (regret != 0) { + printf("regexec returned error %d\n", regret); + *ierr = 1; + regfree(&compiled_pattern); + return; + } + regfree(&compiled_pattern); + //printf("Line nextline read: %s\n", line); + + // Clear out the return string with blanks, copy the value into it, and return. + memset(string_read, ' ', *string_read_len); + + + value_len = strlen(line); + // makes sure there is a character left for NUL termination + if (value_len > (size_t)*string_read_len - 1) value_len = *string_read_len - 1; + + strncpy(string_read, line, value_len); + + *ierr = 0; + return; + } + // If no next line matches, print out error and die. + printf("No match in parameter file for next line \n"); + regfree(&compiled_pattern); + *ierr = 1; + return; +} diff --git a/meshfem2d/part_unstruct.F90 b/meshfem2d/part_unstruct.F90 new file mode 100644 index 00000000..79087f70 --- /dev/null +++ b/meshfem2d/part_unstruct.F90 @@ -0,0 +1,1285 @@ +!======================================================================== +! +! S P E C F E M 2 D +! ----------------- +! +! Main historical authors: Dimitri Komatitsch and Jeroen Tromp +! CNRS, France +! and Princeton University, USA +! (there are currently many more authors!) +! (c) October 2017 +! +! This software is a computer program whose purpose is to solve +! the two-dimensional viscoelastic anisotropic or poroelastic wave equation +! using a spectral-element method (SEM). +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 3 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License along +! with this program; if not, write to the Free Software Foundation, Inc., +! 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +! +! The full text of the license is available in file "LICENSE". +! +!======================================================================== + + !----------------------------------------------- + ! Creating dual graph (adjacency is defined by 'ncommonnodes' between two elements). + !----------------------------------------------- + subroutine mesh2dual_ncommonnodes(elmnts_l,ncommonnodes,xadj,adjncy) + + use constants, only: NCORNERS,MAX_NEIGHBORS,MAX_NSIZE_SHARED + + use part_unstruct_par, only: nelmnts,nnodes,nnodes_elmnts,nodes_elmnts + + implicit none + + integer, dimension(0:NCORNERS*nelmnts-1), intent(in) :: elmnts_l + integer, intent(in) :: ncommonnodes + integer, dimension(0:nelmnts),intent(out) :: xadj + integer, dimension(0:MAX_NEIGHBORS*nelmnts-1),intent(out) :: adjncy + + ! local parameters + integer :: i, j, k, l, m, num_edges + logical :: is_neighbor + integer :: num_node, n + integer :: elem_base, elem_target + integer :: connectivity + + ! allocates memory for arrays + if (.not. allocated(nnodes_elmnts) ) allocate(nnodes_elmnts(0:nnodes-1)) + if (.not. allocated(nodes_elmnts) ) allocate(nodes_elmnts(0:MAX_NSIZE_SHARED*nnodes-1)) + + ! initializes + xadj(:) = 0 + adjncy(:) = 0 + nnodes_elmnts(:) = 0 + nodes_elmnts(:) = 0 + num_edges = 0 + + ! list of elements per node + do i = 0, NCORNERS*nelmnts-1 + nodes_elmnts(elmnts_l(i)*MAX_NSIZE_SHARED + nnodes_elmnts(elmnts_l(i))) = i/NCORNERS + nnodes_elmnts(elmnts_l(i)) = nnodes_elmnts(elmnts_l(i)) + 1 + enddo + + ! checking which elements are neighbors ('ncommonnodes' criteria) + do j = 0, nnodes-1 + do k = 0, nnodes_elmnts(j)-1 + do l = k+1, nnodes_elmnts(j)-1 + + connectivity = 0 + elem_base = nodes_elmnts(k+j*MAX_NSIZE_SHARED) + elem_target = nodes_elmnts(l+j*MAX_NSIZE_SHARED) + do n = 1, NCORNERS + num_node = elmnts_l(NCORNERS*elem_base+n-1) + do m = 0, nnodes_elmnts(num_node)-1 + if (nodes_elmnts(m+num_node*MAX_NSIZE_SHARED) == elem_target) then + connectivity = connectivity + 1 + endif + enddo + enddo + + ! sets adjacency (adjncy) and number of neighbors (xadj) + ! according to ncommonnodes criteria + if (connectivity >= ncommonnodes) then + + is_neighbor = .false. + + do m = 0, xadj(nodes_elmnts(k+j*MAX_NSIZE_SHARED)) + if (.not. is_neighbor) then + if (adjncy(nodes_elmnts(k+j*MAX_NSIZE_SHARED)*MAX_NEIGHBORS+m) == nodes_elmnts(l+j*MAX_NSIZE_SHARED)) then + is_neighbor = .true. + endif + endif + enddo + if (.not. is_neighbor) then + adjncy(nodes_elmnts(k+j*MAX_NSIZE_SHARED)*MAX_NEIGHBORS & + + xadj(nodes_elmnts(k+j*MAX_NSIZE_SHARED))) = nodes_elmnts(l+j*MAX_NSIZE_SHARED) + + xadj(nodes_elmnts(k+j*MAX_NSIZE_SHARED)) = xadj(nodes_elmnts(k+j*MAX_NSIZE_SHARED)) + 1 + if (xadj(nodes_elmnts(k+j*MAX_NSIZE_SHARED)) > MAX_NEIGHBORS) & + call stop_the_code('ERROR : too much neighbors per element, modify the mesh.') + + adjncy(nodes_elmnts(l+j*MAX_NSIZE_SHARED)*MAX_NEIGHBORS & + + xadj(nodes_elmnts(l+j*MAX_NSIZE_SHARED))) = nodes_elmnts(k+j*MAX_NSIZE_SHARED) + + xadj(nodes_elmnts(l+j*MAX_NSIZE_SHARED)) = xadj(nodes_elmnts(l+j*MAX_NSIZE_SHARED)) + 1 + if (xadj(nodes_elmnts(l+j*MAX_NSIZE_SHARED)) > MAX_NEIGHBORS) & + call stop_the_code('ERROR : too much neighbors per element, modify the mesh.') + + endif + endif + enddo + enddo + enddo + + ! making adjacency arrays compact (to be used for partitioning) + do i = 0, nelmnts-1 + k = xadj(i) + xadj(i) = num_edges + do j = 0, k-1 + adjncy(num_edges) = adjncy(i*MAX_NEIGHBORS+j) + num_edges = num_edges + 1 + enddo + enddo + + xadj(nelmnts) = num_edges + + end subroutine mesh2dual_ncommonnodes + +! +!--------------------------------------------------------------------------------------- +! + + !-------------------------------------------------- + ! construct local numbering for the elements in each partition + !-------------------------------------------------- + subroutine construct_glob2loc_elmnts(nparts) + + use part_unstruct_par, only: glob2loc_elmnts,nelmnts,part + + implicit none + integer, intent(in) :: nparts + + integer :: num_glob, num_part + integer, dimension(0:nparts-1) :: num_loc + integer :: ier + + allocate(glob2loc_elmnts(0:nelmnts-1),stat=ier) + if (ier /= 0) stop 'Error allocating array glob2loc_elmnts' + glob2loc_elmnts(:) = -1 + + ! initializes number of local elements per partition + do num_part = 0, nparts-1 + num_loc(num_part) = 0 + enddo + + ! local numbering + do num_glob = 0, nelmnts-1 + num_part = part(num_glob) + glob2loc_elmnts(num_glob) = num_loc(num_part) + num_loc(num_part) = num_loc(num_part) + 1 + enddo + + end subroutine construct_glob2loc_elmnts + +! +!--------------------------------------------------------------------------------------- +! + + !-------------------------------------------------- + ! construct local numbering for the nodes in each partition + !-------------------------------------------------- + subroutine construct_glob2loc_nodes(nparts) + + use constants, only: MAX_NSIZE_SHARED + use part_unstruct_par, only: nnodes,glob2loc_nodes_nparts,glob2loc_nodes_parts,glob2loc_nodes, & + nodes_elmnts,nnodes_elmnts,part + + implicit none + + integer, intent(in) :: nparts + + integer :: num_node + integer :: el + integer :: num_part + integer :: size_glob2loc_nodes + integer, dimension(0:nparts-1) :: parts_node + integer, dimension(0:nparts-1) :: num_parts + + allocate(glob2loc_nodes_nparts(0:nnodes)) + + size_glob2loc_nodes = 0 + parts_node(:) = 0 + + do num_node = 0, nnodes-1 + glob2loc_nodes_nparts(num_node) = size_glob2loc_nodes + do el = 0, nnodes_elmnts(num_node)-1 + parts_node(part(nodes_elmnts(el+MAX_NSIZE_SHARED*num_node))) = 1 + enddo + + do num_part = 0, nparts-1 + if (parts_node(num_part) == 1) then + size_glob2loc_nodes = size_glob2loc_nodes + 1 + parts_node(num_part) = 0 + endif + enddo + + enddo + + glob2loc_nodes_nparts(nnodes) = size_glob2loc_nodes + + allocate(glob2loc_nodes_parts(0:glob2loc_nodes_nparts(nnodes)-1)) + allocate(glob2loc_nodes(0:glob2loc_nodes_nparts(nnodes)-1)) + + glob2loc_nodes(0) = 0 + parts_node(:) = 0 + num_parts(:) = 0 + size_glob2loc_nodes = 0 + + do num_node = 0, nnodes-1 + do el = 0, nnodes_elmnts(num_node)-1 + parts_node(part(nodes_elmnts(el+MAX_NSIZE_SHARED*num_node))) = 1 + enddo + + do num_part = 0, nparts-1 + if (parts_node(num_part) == 1) then + glob2loc_nodes_parts(size_glob2loc_nodes) = num_part + glob2loc_nodes(size_glob2loc_nodes) = num_parts(num_part) + size_glob2loc_nodes = size_glob2loc_nodes + 1 + num_parts(num_part) = num_parts(num_part) + 1 + parts_node(num_part) = 0 + endif + enddo + enddo + + end subroutine construct_glob2loc_nodes + +! +!--------------------------------------------------------------------------------------- +! + + !-------------------------------------------------- + ! Construct interfaces between each partitions. + ! Two adjacent elements in distinct partitions make an entry in array tab_interfaces : + ! 1/ first element, 2/ second element, 3/ number of common nodes, 4/ first node, + ! 5/ second node, if relevant. + ! No interface between acoustic, elastic, and poroelastic elements. + !-------------------------------------------------- + subroutine construct_interfaces(nparts, elmnts_l, & + nbmodels, phi_material, num_material) + + use constants, only: NCORNERS,TINYVAL + + use part_unstruct_par, only: nelmnts,ninterfaces,tab_size_interfaces,tab_interfaces,part, & + xadj_g,adjncy_g + + implicit none + + integer, intent(in) :: nparts + integer, dimension(0:NCORNERS*nelmnts-1), intent(in) :: elmnts_l + integer, dimension(1:nelmnts), intent(in) :: num_material + integer, intent(in) :: nbmodels + double precision, dimension(1:nbmodels), intent(in) :: phi_material + + integer :: num_part, num_part_bis, el, el_adj, num_interface, num_edge, ncommon_nodes, & + num_node, num_node_bis + integer :: i, j + logical :: is_acoustic_el, is_acoustic_el_adj, is_elastic_el, is_elastic_el_adj + + ninterfaces = 0 + do i = 0, nparts-1 + do j = i+1, nparts-1 + ninterfaces = ninterfaces + 1 + enddo + enddo + + allocate(tab_size_interfaces(0:ninterfaces)) + tab_size_interfaces(:) = 0 + + num_interface = 0 + num_edge = 0 + + do num_part = 0, nparts-1 + do num_part_bis = num_part+1, nparts-1 + do el = 0, nelmnts-1 + if (part(el) == num_part) then + ! sets material flag + if (phi_material(num_material(el+1)) < TINYVAL) then + ! elastic element + is_acoustic_el = .false. + is_elastic_el = .true. + else if (phi_material(num_material(el+1)) >= 1.d0) then + ! acoustic element + is_acoustic_el = .true. + is_elastic_el = .false. + else + ! poroelastic element + is_acoustic_el = .false. + is_elastic_el = .false. + endif + + ! looks at all neighbor elements + do el_adj = xadj_g(el), xadj_g(el+1)-1 + ! sets neighbor material flag + if (phi_material(num_material(adjncy_g(el_adj)+1)) < TINYVAL) then + is_acoustic_el_adj = .false. + is_elastic_el_adj = .true. + else if (phi_material(num_material(adjncy_g(el_adj)+1)) >= 1.d0) then + is_acoustic_el_adj = .true. + is_elastic_el_adj = .false. + else + is_acoustic_el_adj = .false. + is_elastic_el_adj = .false. + endif + ! adds element if neighbor element lies in next partition + ! and belongs to same material + if ((part(adjncy_g(el_adj)) == num_part_bis) .and. & + (is_acoustic_el .eqv. is_acoustic_el_adj) .and. & + (is_elastic_el .eqv. is_elastic_el_adj)) then + num_edge = num_edge + 1 + endif + enddo + endif + enddo + ! stores number of elements at interface + tab_size_interfaces(num_interface+1) = tab_size_interfaces(num_interface) + num_edge + num_edge = 0 + num_interface = num_interface + 1 + + enddo + enddo + + ! stores element indices for elements from above search at each interface + num_interface = 0 + num_edge = 0 + + allocate(tab_interfaces(0:(tab_size_interfaces(ninterfaces)*5-1))) + tab_interfaces(:) = 0 + + do num_part = 0, nparts-1 + do num_part_bis = num_part+1, nparts-1 + do el = 0, nelmnts-1 + if (part(el) == num_part) then + if (phi_material(num_material(el+1)) < TINYVAL) then + is_acoustic_el = .false. + is_elastic_el = .true. + else if (phi_material(num_material(el+1)) >= 1.d0) then + is_acoustic_el = .true. + is_elastic_el = .false. + else + is_acoustic_el = .false. + is_elastic_el = .false. + endif + do el_adj = xadj_g(el), xadj_g(el+1)-1 + if (phi_material(num_material(adjncy_g(el_adj)+1)) < TINYVAL) then + is_acoustic_el_adj = .false. + is_elastic_el_adj = .true. + else if (phi_material(num_material(adjncy_g(el_adj)+1)) >= 1.d0) then + is_acoustic_el_adj = .true. + is_elastic_el_adj = .false. + else + is_acoustic_el_adj = .false. + is_elastic_el_adj = .false. + endif + if ((part(adjncy_g(el_adj)) == num_part_bis) .and. & + (is_acoustic_el .eqv. is_acoustic_el_adj) .and. & + (is_elastic_el .eqv. is_elastic_el_adj)) then + tab_interfaces(tab_size_interfaces(num_interface)*5+num_edge*5+0) = el + tab_interfaces(tab_size_interfaces(num_interface)*5+num_edge*5+1) = adjncy_g(el_adj) + ncommon_nodes = 0 + do num_node = 0, 4-1 + do num_node_bis = 0, 4-1 + if (elmnts_l(el*NCORNERS+num_node) == & + elmnts_l(adjncy_g(el_adj)*NCORNERS+num_node_bis)) then + tab_interfaces(tab_size_interfaces(num_interface)*5+num_edge*5+3+ncommon_nodes) & + = elmnts_l(el*NCORNERS+num_node) + ncommon_nodes = ncommon_nodes + 1 + endif + enddo + enddo + if (ncommon_nodes > 0) then + tab_interfaces(tab_size_interfaces(num_interface)*5+num_edge*5+2) = ncommon_nodes + else + print *,'Error while building interfaces! invalid number of common nodes ', ncommon_nodes + call stop_the_code('Error building interfaces') + endif + num_edge = num_edge + 1 + endif + enddo + endif + + enddo + num_edge = 0 + num_interface = num_interface + 1 + enddo + enddo + + end subroutine construct_interfaces + +! +!--------------------------------------------------------------------------------------- +! + + !-------------------------------------------------- + ! Write nodes (their coordinates) pertaining to iproc partition in the corresponding Database + !-------------------------------------------------- + subroutine write_glob2loc_nodes_database(IIN_database, iproc, npgeo, num_phase) + + use part_unstruct_par, only: nnodes,glob2loc_nodes_nparts,glob2loc_nodes_parts,glob2loc_nodes,nodes_coords + + implicit none + + integer, intent(in) :: IIN_database + integer, intent(in) :: iproc, num_phase + integer, intent(inout) :: npgeo + + integer :: i, j + + if (num_phase == 1) then + npgeo = 0 + + do i = 0, nnodes-1 + do j = glob2loc_nodes_nparts(i), glob2loc_nodes_nparts(i+1)-1 + if (glob2loc_nodes_parts(j) == iproc) then + npgeo = npgeo + 1 + endif + enddo + enddo + else + do i = 0, nnodes-1 + do j = glob2loc_nodes_nparts(i), glob2loc_nodes_nparts(i+1)-1 + if (glob2loc_nodes_parts(j) == iproc) then + write(IIN_database) glob2loc_nodes(j)+1, nodes_coords(1,i+1), nodes_coords(2,i+1) + endif + enddo + enddo + endif + + end subroutine write_glob2loc_nodes_database + +! +!--------------------------------------------------------------------------------------- +! + + !-------------------------------------------------- + ! Write elements (their nodes) pertaining to iproc partition in the corresponding Database + !-------------------------------------------------- + subroutine write_partition_database(IIN_database, iproc, nspec, & + num_modele, num_pml, NGNOD, num_phase) + + use part_unstruct_par, only: nelmnts,elmnts,part, & + glob2loc_nodes_nparts,glob2loc_nodes_parts,glob2loc_nodes,glob2loc_elmnts + + implicit none + + integer, intent(in) :: IIN_database + integer, intent(in) :: num_phase, iproc + integer, intent(inout) :: nspec + integer, dimension(1:nelmnts) :: num_modele + integer, dimension(1:nelmnts) :: num_pml + integer, intent(in) :: NGNOD + + ! local parameters + integer :: i,j,k + integer, dimension(0:NGNOD-1) :: loc_nodes + + if (num_phase == 1) then + ! only counts number of elements for this given partition iproc + nspec = 0 + do i = 0, nelmnts-1 + if (part(i) == iproc) nspec = nspec + 1 + enddo + + else + ! saves array to file + do i = 0, nelmnts-1 + if (part(i) == iproc) then + ! sets element node indices + do j = 0, NGNOD-1 + do k = glob2loc_nodes_nparts(elmnts(i*NGNOD+j)), glob2loc_nodes_nparts(elmnts(i*NGNOD+j)+1)-1 + if (glob2loc_nodes_parts(k) == iproc) loc_nodes(j) = glob2loc_nodes(k) + enddo + enddo + ! writes element entry to file + write(IIN_database) glob2loc_elmnts(i)+1, num_modele(i+1), (loc_nodes(k)+1, k=0,NGNOD-1), num_pml(i+1) + endif + enddo + endif + + end subroutine write_partition_database + +! +!--------------------------------------------------------------------------------------- +! + + !-------------------------------------------------- + ! Write interfaces (element and common nodes) pertaining to iproc partition in the corresponding Database + !-------------------------------------------------- + subroutine write_interfaces_database(IIN_database, nparts, iproc, & + my_ninterface, my_interfaces, my_nb_interfaces, num_phase) + + use part_unstruct_par, only: ninterfaces,tab_size_interfaces,tab_interfaces, & + glob2loc_elmnts,glob2loc_nodes_nparts,glob2loc_nodes_parts,glob2loc_nodes + + implicit none + + integer, intent(in) :: IIN_database + integer, intent(in) :: iproc + integer, intent(in) :: nparts + integer, intent(inout) :: my_ninterface + integer, dimension(0:ninterfaces-1), intent(inout) :: my_interfaces + integer, dimension(0:ninterfaces-1), intent(inout) :: my_nb_interfaces + + integer, dimension(2) :: local_nodes + integer :: local_elmnt + integer :: num_phase + + integer :: i, j, k, l + integer :: num_interface + integer, parameter :: minus_one = -1 + + num_interface = 0 + + if (num_phase == 1) then + + my_interfaces(:) = 0 + my_nb_interfaces(:) = 0 + + do i = 0, nparts-1 + do j = i+1, nparts-1 + if ((tab_size_interfaces(num_interface) < tab_size_interfaces(num_interface+1)) .and. & + (i == iproc .or. j == iproc)) then + my_interfaces(num_interface) = 1 + my_nb_interfaces(num_interface) = tab_size_interfaces(num_interface+1) & + - tab_size_interfaces(num_interface) + endif + num_interface = num_interface + 1 + enddo + enddo + my_ninterface = sum(my_interfaces(:)) + + else + + do i = 0, nparts-1 + do j = i+1, nparts-1 + if (my_interfaces(num_interface) == 1) then + if (i == iproc) then + write(IIN_database) j, my_nb_interfaces(num_interface) + else + write(IIN_database) i, my_nb_interfaces(num_interface) + endif + + do k = tab_size_interfaces(num_interface), tab_size_interfaces(num_interface+1)-1 + if (i == iproc) then + local_elmnt = glob2loc_elmnts(tab_interfaces(k*5+0))+1 + else + local_elmnt = glob2loc_elmnts(tab_interfaces(k*5+1))+1 + endif + + if (tab_interfaces(k*5+2) == 1) then + ! common node (single point) + do l = glob2loc_nodes_nparts(tab_interfaces(k*5+3)), & + glob2loc_nodes_nparts(tab_interfaces(k*5+3)+1)-1 + if (glob2loc_nodes_parts(l) == iproc) then + local_nodes(1) = glob2loc_nodes(l)+1 + endif + enddo + + write(IIN_database) local_elmnt, tab_interfaces(k*5+2), & + local_nodes(1), minus_one + else + if (tab_interfaces(k*5+2) == 2) then + ! common edge (two nodes) + ! first node + do l = glob2loc_nodes_nparts(tab_interfaces(k*5+3)), & + glob2loc_nodes_nparts(tab_interfaces(k*5+3)+1)-1 + if (glob2loc_nodes_parts(l) == iproc) then + local_nodes(1) = glob2loc_nodes(l)+1 + endif + enddo + ! second node + do l = glob2loc_nodes_nparts(tab_interfaces(k*5+4)), & + glob2loc_nodes_nparts(tab_interfaces(k*5+4)+1)-1 + if (glob2loc_nodes_parts(l) == iproc) then + local_nodes(2) = glob2loc_nodes(l)+1 + endif + enddo + + write(IIN_database) local_elmnt, tab_interfaces(k*5+2), & + local_nodes(1), local_nodes(2) + else + print *,"Error: write_interfaces_database", tab_interfaces(k*5+2) + call stop_the_code('Invalid interface found') + endif + endif + enddo + + endif + + num_interface = num_interface + 1 + enddo + enddo + + endif + + end subroutine write_interfaces_database + +! +!--------------------------------------------------------------------------------------- +! + + !-------------------------------------------------- + ! Write a surface (elements and nodes on the surface) pertaining to iproc partition in the corresponding Database + !-------------------------------------------------- + subroutine write_surface_database(IIN_database, nsurface, surface, & + nsurface_loc, iproc, num_phase) + + use part_unstruct_par, only: part,glob2loc_elmnts,glob2loc_nodes_nparts,glob2loc_nodes_parts,glob2loc_nodes + + implicit none + integer, intent(in) :: IIN_database + integer, intent(in) :: iproc + integer :: nsurface + integer :: nsurface_loc + integer, dimension(4,nsurface) :: surface + + integer, dimension(2) :: local_nodes + integer :: local_elmnt + integer :: num_phase + + integer :: i, l + integer, parameter :: minus_one = -1 + + if (num_phase == 1) then + + ! only counts surface elements + nsurface_loc = 0 + + do i = 1, nsurface + if (part(surface(1,i)) == iproc) then + nsurface_loc = nsurface_loc + 1 + endif + enddo + + else + + nsurface_loc = 0 + + do i = 1, nsurface + if (part(surface(1,i)) == iproc) then + nsurface_loc = nsurface_loc + 1 + + local_elmnt = glob2loc_elmnts(surface(1,i)) + 1 + + if (surface(2,i) == 1) then + do l = glob2loc_nodes_nparts(surface(3,i)), & + glob2loc_nodes_nparts(surface(3,i)+1)-1 + if (glob2loc_nodes_parts(l) == iproc) then + local_nodes(1) = glob2loc_nodes(l)+1 + endif + enddo + + write(IIN_database) local_elmnt, surface(2,i), local_nodes(1), minus_one + endif + + if (surface(2,i) == 2) then + do l = glob2loc_nodes_nparts(surface(3,i)), & + glob2loc_nodes_nparts(surface(3,i)+1)-1 + if (glob2loc_nodes_parts(l) == iproc) then + local_nodes(1) = glob2loc_nodes(l)+1 + endif + enddo + do l = glob2loc_nodes_nparts(surface(4,i)), & + glob2loc_nodes_nparts(surface(4,i)+1)-1 + if (glob2loc_nodes_parts(l) == iproc) then + local_nodes(2) = glob2loc_nodes(l)+1 + endif + enddo + + write(IIN_database) local_elmnt, surface(2,i), local_nodes(1), local_nodes(2) + endif + + endif + + enddo + + endif + + end subroutine write_surface_database + +! +!--------------------------------------------------------------------------------------- +! + + !-------------------------------------------------- + ! Set absorbing boundaries by elements instead of edges. + ! Also excludes first or last GLL integration point + ! if it has both absorbing condition and coupled fluid/solid relation + ! (this is the reason why arrays ibegin_..., iend_... are included here). + ! Under development : excluding points that have two different normals in two different elements. + !-------------------------------------------------- + + subroutine merge_abs_boundaries(nbmodels, phi_material, num_material, NGNOD) + + use constants, only: IEDGE1,IEDGE2,IEDGE3,IEDGE4,NGLLX,NGLLZ,IMAIN,myrank + + use part_unstruct_par, only: nelmnts,elmnts,nelemabs,nelemabs_merge,abs_surface, & + abs_surface_char,abs_surface_merge,abs_surface_merge,abs_surface_type, & + ibegin_edge1,iend_edge1,ibegin_edge2,iend_edge2,ibegin_edge3,iend_edge3,ibegin_edge4,iend_edge4, & + nedges_coupled,edges_coupled + + implicit none + + integer, intent(in) :: NGNOD + integer :: nbmodels + double precision, dimension(nbmodels), intent(in) :: phi_material + integer, dimension(1:nelmnts), intent(in) :: num_material + + logical, dimension(nbmodels) :: is_acoustic + integer :: num_edge, nedge_bound + integer :: match + integer :: nb_elmnts_abs + integer :: i + integer :: temp + integer :: iedge, inode1, inode2 + + allocate(abs_surface_char(4,nelemabs)) + allocate(abs_surface_merge(nelemabs)) + allocate(abs_surface_type(nelemabs)) + + abs_surface_char(:,:) = .false. + abs_surface_merge(:) = -1 + abs_surface_type(:) = -1 + + nedge_bound = nelemabs + nb_elmnts_abs = 0 + + do num_edge = 1, nedge_bound + +!! DK DK Sept 2012: in order to fix the rotated elements issue in external mesh +!! DK DK Sept 2012: we now use a type code and thus we must not merge elements that +!! DK DK Sept 2012: appear twice in the list any more because each occurrence now appears with a different type code +!! DK DK Sept 2012 match = 0 +!! DK DK Sept 2012 do i = 1, nb_elmnts_abs +!! DK DK Sept 2012 if (abs_surface(1,num_edge) == abs_surface_merge(i)) then +!! DK DK Sept 2012 match = i +!! DK DK Sept 2012 exit +!! DK DK Sept 2012 endif +!! DK DK Sept 2012 enddo + +!! DK DK Sept 2012 if (match == 0) then + nb_elmnts_abs = nb_elmnts_abs + 1 + match = nb_elmnts_abs +!! DK DK Sept 2012 endif + + abs_surface_merge(match) = abs_surface(1,num_edge) +!! DK DK Sept 2012 added the absorbing interface type for Stacey + abs_surface_type(match) = abs_surface(5,num_edge) + + if ((abs_surface(3,num_edge) == elmnts(NGNOD*abs_surface_merge(match)+0) .and. & + abs_surface(4,num_edge) == elmnts(NGNOD*abs_surface_merge(match)+1))) then + abs_surface_char(IEDGE1,match) = .true. + endif + + if ((abs_surface(4,num_edge) == elmnts(NGNOD*abs_surface_merge(match)+0) .and. & + abs_surface(3,num_edge) == elmnts(NGNOD*abs_surface_merge(match)+1))) then + temp = abs_surface(4,num_edge) + abs_surface(4,num_edge) = abs_surface(3,num_edge) + abs_surface(3,num_edge) = temp + abs_surface_char(IEDGE1,match) = .true. + endif + + if ((abs_surface(3,num_edge) == elmnts(NGNOD*abs_surface_merge(match)+0) .and. & + abs_surface(4,num_edge) == elmnts(NGNOD*abs_surface_merge(match)+3))) then + abs_surface_char(IEDGE4,match) = .true. + endif + + if ((abs_surface(4,num_edge) == elmnts(NGNOD*abs_surface_merge(match)+0) .and. & + abs_surface(3,num_edge) == elmnts(NGNOD*abs_surface_merge(match)+3))) then + temp = abs_surface(4,num_edge) + abs_surface(4,num_edge) = abs_surface(3,num_edge) + abs_surface(3,num_edge) = temp + abs_surface_char(IEDGE4,match) = .true. + endif + + if ((abs_surface(3,num_edge) == elmnts(NGNOD*abs_surface_merge(match)+1) .and. & + abs_surface(4,num_edge) == elmnts(NGNOD*abs_surface_merge(match)+2))) then + abs_surface_char(IEDGE2,match) = .true. + endif + + if ((abs_surface(4,num_edge) == elmnts(NGNOD*abs_surface_merge(match)+1) .and. & + abs_surface(3,num_edge) == elmnts(NGNOD*abs_surface_merge(match)+2))) then + temp = abs_surface(4,num_edge) + abs_surface(4,num_edge) = abs_surface(3,num_edge) + abs_surface(3,num_edge) = temp + abs_surface_char(IEDGE2,match) = .true. + endif + + if ((abs_surface(3,num_edge) == elmnts(NGNOD*abs_surface_merge(match)+2) .and. & + abs_surface(4,num_edge) == elmnts(NGNOD*abs_surface_merge(match)+3))) then + temp = abs_surface(4,num_edge) + abs_surface(4,num_edge) = abs_surface(3,num_edge) + abs_surface(3,num_edge) = temp + abs_surface_char(IEDGE3,match) = .true. + endif + + if ((abs_surface(4,num_edge) == elmnts(NGNOD*abs_surface_merge(match)+2) .and. & + abs_surface(3,num_edge) == elmnts(NGNOD*abs_surface_merge(match)+3))) then + abs_surface_char(IEDGE3,match) = .true. + endif + + enddo + + nelemabs_merge = nb_elmnts_abs + +! beware here and below that external meshes (for instance coming from CUBIT or Gmsh) +! may have rotated elements and thus edge 1 may not correspond to the bottom, +! edge 2 may not correspond to the right, edge 3 may not correspond to the top, +! and edge 4 may not correspond to the left. + allocate(ibegin_edge1(nelemabs_merge)) + allocate(iend_edge1(nelemabs_merge)) + allocate(ibegin_edge2(nelemabs_merge)) + allocate(iend_edge2(nelemabs_merge)) + allocate(ibegin_edge3(nelemabs_merge)) + allocate(iend_edge3(nelemabs_merge)) + allocate(ibegin_edge4(nelemabs_merge)) + allocate(iend_edge4(nelemabs_merge)) + + ibegin_edge1(:) = 1 + ibegin_edge2(:) = 1 + ibegin_edge3(:) = 1 + ibegin_edge4(:) = 1 + iend_edge1(:) = NGLLX + iend_edge2(:) = NGLLZ + iend_edge3(:) = NGLLX + iend_edge4(:) = NGLLZ + + is_acoustic(:) = .false. + + do i = 1, nbmodels + if (phi_material(i) >= 1.d0) then + is_acoustic(i) = .true. + endif + enddo + + do num_edge = 1, nedge_bound + +!! DK DK Sept 2012: in order to fix the rotated elements issue in external mesh +!! DK DK Sept 2012: we now use a type code and thus we must not merge elements that +!! DK DK Sept 2012: appear twice in the list any more because each occurrence now appears with a different type code. +!! DK DK Sept 2012: But here I think we must leave it because we are just fixing the fluid/solid elements in postprocessing. + match = 0 + do i = 1, nelemabs_merge + if (abs_surface(1,num_edge) == abs_surface_merge(i)) then + match = i + exit + endif + enddo + + if (is_acoustic(num_material(abs_surface(1,num_edge)+1))) then + + do iedge = 1, nedges_coupled + do inode1 = 0, 3 + + if (abs_surface(3,num_edge) == elmnts(NGNOD*edges_coupled(1,iedge)+inode1)) then + do inode2 = 0, 3 + if (abs_surface(3,num_edge) == elmnts(NGNOD*edges_coupled(2,iedge)+inode2)) then + + if (abs_surface(3,num_edge) == elmnts(NGNOD*abs_surface(1,num_edge)+0) .and. & + abs_surface(4,num_edge) == elmnts(NGNOD*abs_surface(1,num_edge)+1)) then + ibegin_edge1(match) = 2 + endif + + if (abs_surface(3,num_edge) == elmnts(NGNOD*abs_surface(1,num_edge)+1) .and. & + abs_surface(4,num_edge) == elmnts(NGNOD*abs_surface(1,num_edge)+2)) then + ibegin_edge2(match) = 2 + endif + + if (abs_surface(3,num_edge) == elmnts(NGNOD*abs_surface(1,num_edge)+3) .and. & + abs_surface(4,num_edge) == elmnts(NGNOD*abs_surface(1,num_edge)+2)) then + ibegin_edge3(match) = 2 + endif + + if (abs_surface(3,num_edge) == elmnts(NGNOD*abs_surface(1,num_edge)+0) .and. & + abs_surface(4,num_edge) == elmnts(NGNOD*abs_surface(1,num_edge)+3)) then + ibegin_edge4(match) = 2 + endif + + endif + enddo + + endif + + if (abs_surface(4,num_edge) == elmnts(NGNOD*edges_coupled(1,iedge)+inode1)) then + do inode2 = 0, 3 + if (abs_surface(4,num_edge) == elmnts(NGNOD*edges_coupled(2,iedge)+inode2)) then + if (abs_surface(3,num_edge) == elmnts(NGNOD*abs_surface(1,num_edge)+0) .and. & + abs_surface(4,num_edge) == elmnts(NGNOD*abs_surface(1,num_edge)+1)) then + iend_edge1(match) = NGLLX - 1 + endif + + if (abs_surface(3,num_edge) == elmnts(NGNOD*abs_surface(1,num_edge)+1) .and. & + abs_surface(4,num_edge) == elmnts(NGNOD*abs_surface(1,num_edge)+2)) then + iend_edge2(match) = NGLLZ - 1 + endif + + if (abs_surface(3,num_edge) == elmnts(NGNOD*abs_surface(1,num_edge)+3) .and. & + abs_surface(4,num_edge) == elmnts(NGNOD*abs_surface(1,num_edge)+2)) then + iend_edge3(match) = NGLLX - 1 + endif + + if (abs_surface(3,num_edge) == elmnts(NGNOD*abs_surface(1,num_edge)+0) .and. & + abs_surface(4,num_edge) == elmnts(NGNOD*abs_surface(1,num_edge)+3)) then + iend_edge4(match) = NGLLZ - 1 + endif + + endif + enddo + + endif + + enddo + enddo + + endif + + enddo + + ! user output + if (myrank == 0) then + write(IMAIN,*) ' nedge_bound : ',nedge_bound + write(IMAIN,*) ' nelemabs_merge: ',nelemabs_merge + write(IMAIN,*) + call flush_IMAIN() + endif + + end subroutine merge_abs_boundaries + +! +!--------------------------------------------------------------------------------------- +! + + !-------------------------------------------------- + ! Write abs surface (elements and nodes on the surface) pertaining to iproc partition in the corresponding Database + !-------------------------------------------------- + + subroutine write_abs_merge_database(IIN_database, iproc, num_phase) + + use part_unstruct_par, only: part,nelemabs_loc,nelemabs_merge,abs_surface_merge,abs_surface_char,abs_surface, & + glob2loc_elmnts,ibegin_edge1,iend_edge1,ibegin_edge2,iend_edge2,ibegin_edge3,iend_edge3,ibegin_edge4,iend_edge4 + + implicit none + + integer, intent(in) :: IIN_database + integer, intent(in) :: iproc + integer, intent(in) :: num_phase + + integer :: i + + if (num_phase == 1) then + ! only counts elements in this partition + nelemabs_loc = 0 + do i = 1, nelemabs_merge + if (part(abs_surface_merge(i)) == iproc) then + nelemabs_loc = nelemabs_loc + 1 + endif + enddo + else + do i = 1, nelemabs_merge + if (part(abs_surface_merge(i)) == iproc) then + +! beware here and below that external meshes (for instance coming from CUBIT or Gmsh) +! may have rotated elements and thus edge 1 may not correspond to the bottom, +! edge 2 may not correspond to the right, edge 3 may not correspond to the top, +! and edge 4 may not correspond to the left. + +! we add +1 to the "glob2loc_elmnts" number because internally in parts of our code numbers start at zero instead of one + write(IIN_database) glob2loc_elmnts(abs_surface_merge(i))+1, abs_surface_char(1,i), & +!! DK DK sept 2012: added absorbing element type +!! DK DK sept 2012 abs_surface_char(2,i), abs_surface_char(3,i), abs_surface_char(4,i), & + abs_surface_char(2,i), abs_surface_char(3,i), abs_surface_char(4,i), abs_surface(5,i), & + ibegin_edge1(i), iend_edge1(i), & + ibegin_edge2(i), iend_edge2(i), & + ibegin_edge3(i), iend_edge3(i), & + ibegin_edge4(i), iend_edge4(i) + endif + + enddo + endif + + end subroutine write_abs_merge_database + +! +!--------------------------------------------------------------------------------------- +! + + !-------------------------------------------------- + ! Set acoustic forcing boundaries by elements instead of edges. + ! inspired by merge_abs_boundaries upper in this file + !-------------------------------------------------- + + subroutine merge_acoustic_forcing_boundaries(NGNOD) + + use constants, only: IEDGE1,IEDGE2,IEDGE3,IEDGE4,NGLLX,NGLLZ + + use part_unstruct_par, only: elmnts,nelemacforcing,acforcing_surface, & + acforcing_surface_char,acforcing_surface_merge,acforcing_surface_type, & + ibegin_edge1_acforcing,iend_edge1_acforcing,ibegin_edge2_acforcing,iend_edge2_acforcing, & + ibegin_edge3_acforcing,iend_edge3_acforcing,ibegin_edge4_acforcing,iend_edge4_acforcing, & + nelemacforcing_merge + + implicit none + + integer, intent(in) :: NGNOD + + ! local parameters + integer :: num_edge, nedge_bound + integer :: match + integer :: nb_elmnts_acforcing + integer :: temp + + allocate(acforcing_surface_char(4,nelemacforcing)) + allocate(acforcing_surface_merge(nelemacforcing)) + allocate(acforcing_surface_type(nelemacforcing)) + + acforcing_surface_char(:,:) = .false. + acforcing_surface_merge(:) = -1 + acforcing_surface_type(:) = -1 + + nedge_bound = nelemacforcing + nb_elmnts_acforcing = 0 + do num_edge = 1, nedge_bound + + nb_elmnts_acforcing = nb_elmnts_acforcing + 1 + match = nb_elmnts_acforcing + + acforcing_surface_merge(match) = acforcing_surface(1,num_edge) + acforcing_surface_type(match) = acforcing_surface(5,num_edge) + + if ((acforcing_surface(3,num_edge) == elmnts(NGNOD*acforcing_surface_merge(match)+0) .and. & + acforcing_surface(4,num_edge) == elmnts(NGNOD*acforcing_surface_merge(match)+1))) then + acforcing_surface_char(IEDGE1,match) = .true. + endif + + if ((acforcing_surface(4,num_edge) == elmnts(NGNOD*acforcing_surface_merge(match)+0) .and. & + acforcing_surface(3,num_edge) == elmnts(NGNOD*acforcing_surface_merge(match)+1))) then + temp = acforcing_surface(4,num_edge) + acforcing_surface(4,num_edge) = acforcing_surface(3,num_edge) + acforcing_surface(3,num_edge) = temp + acforcing_surface_char(IEDGE1,match) = .true. + endif + + if ((acforcing_surface(3,num_edge) == elmnts(NGNOD*acforcing_surface_merge(match)+0) .and. & + acforcing_surface(4,num_edge) == elmnts(NGNOD*acforcing_surface_merge(match)+3))) then + acforcing_surface_char(IEDGE4,match) = .true. + endif + + if ((acforcing_surface(4,num_edge) == elmnts(NGNOD*acforcing_surface_merge(match)+0) .and. & + acforcing_surface(3,num_edge) == elmnts(NGNOD*acforcing_surface_merge(match)+3))) then + temp = acforcing_surface(4,num_edge) + acforcing_surface(4,num_edge) = acforcing_surface(3,num_edge) + acforcing_surface(3,num_edge) = temp + acforcing_surface_char(IEDGE4,match) = .true. + endif + + if ((acforcing_surface(3,num_edge) == elmnts(NGNOD*acforcing_surface_merge(match)+1) .and. & + acforcing_surface(4,num_edge) == elmnts(NGNOD*acforcing_surface_merge(match)+2))) then + acforcing_surface_char(IEDGE2,match) = .true. + endif + + if ((acforcing_surface(4,num_edge) == elmnts(NGNOD*acforcing_surface_merge(match)+1) .and. & + acforcing_surface(3,num_edge) == elmnts(NGNOD*acforcing_surface_merge(match)+2))) then + temp = acforcing_surface(4,num_edge) + acforcing_surface(4,num_edge) = acforcing_surface(3,num_edge) + acforcing_surface(3,num_edge) = temp + acforcing_surface_char(IEDGE2,match) = .true. + endif + + if ((acforcing_surface(3,num_edge) == elmnts(NGNOD*acforcing_surface_merge(match)+2) .and. & + acforcing_surface(4,num_edge) == elmnts(NGNOD*acforcing_surface_merge(match)+3))) then + temp = acforcing_surface(4,num_edge) + acforcing_surface(4,num_edge) = acforcing_surface(3,num_edge) + acforcing_surface(3,num_edge) = temp + acforcing_surface_char(IEDGE3,match) = .true. + endif + + if ((acforcing_surface(4,num_edge) == elmnts(NGNOD*acforcing_surface_merge(match)+2) .and. & + acforcing_surface(3,num_edge) == elmnts(NGNOD*acforcing_surface_merge(match)+3))) then + acforcing_surface_char(IEDGE3,match) = .true. + endif + + enddo + + nelemacforcing_merge = nb_elmnts_acforcing + +! beware here and below that external meshes (for instance coming from CUBIT or Gmsh) +! may have rotated elements and thus edge 1 may not correspond to the bottom, +! edge 2 may not correspond to the right, edge 3 may not correspond to the top, +! and edge 4 may not correspond to the left. + allocate(ibegin_edge1_acforcing(nelemacforcing_merge)) + allocate(iend_edge1_acforcing(nelemacforcing_merge)) + allocate(ibegin_edge2_acforcing(nelemacforcing_merge)) + allocate(iend_edge2_acforcing(nelemacforcing_merge)) + allocate(ibegin_edge3_acforcing(nelemacforcing_merge)) + allocate(iend_edge3_acforcing(nelemacforcing_merge)) + allocate(ibegin_edge4_acforcing(nelemacforcing_merge)) + allocate(iend_edge4_acforcing(nelemacforcing_merge)) + + ibegin_edge1_acforcing(:) = 1 + ibegin_edge2_acforcing(:) = 1 + ibegin_edge3_acforcing(:) = 1 + ibegin_edge4_acforcing(:) = 1 + iend_edge1_acforcing(:) = NGLLX + iend_edge2_acforcing(:) = NGLLZ + iend_edge3_acforcing(:) = NGLLX + iend_edge4_acforcing(:) = NGLLZ + + end subroutine merge_acoustic_forcing_boundaries + +! +!--------------------------------------------------------------------------------------- +! + + !-------------------------------------------------- + ! Write abs surface (elements and nodes on the surface) pertaining to iproc partition in the corresponding Database + ! inspired by write_abs_merge_database upper in this file + !-------------------------------------------------- + + subroutine write_acoustic_forcing_merge_database(IIN_database, iproc, num_phase) + + use part_unstruct_par, only: part,nelemacforcing_loc,nelemacforcing_merge, & + acforcing_surface_merge,acforcing_surface_char,acforcing_surface, & + glob2loc_elmnts, & + ibegin_edge1_acforcing,iend_edge1_acforcing,ibegin_edge2_acforcing,iend_edge2_acforcing, & + ibegin_edge3_acforcing,iend_edge3_acforcing,ibegin_edge4_acforcing,iend_edge4_acforcing + + implicit none + + integer, intent(in) :: IIN_database + integer, intent(in) :: iproc + integer, intent(in) :: num_phase + + ! local parameters + integer :: i + + if (num_phase == 1) then + ! only counts elements in this partition + nelemacforcing_loc = 0 + do i = 1, nelemacforcing_merge + if (part(acforcing_surface_merge(i)) == iproc) then + nelemacforcing_loc = nelemacforcing_loc + 1 + endif + enddo + else + do i = 1, nelemacforcing_merge + if (part(acforcing_surface_merge(i)) == iproc) then + +! beware here and below that external meshes (for instance coming from CUBIT or Gmsh) +! may have rotated elements and thus edge 1 may not correspond to the bottom, +! edge 2 may not correspond to the right, edge 3 may not correspond to the top, +! and edge 4 may not correspond to the left. + +! we add +1 to the "glob2loc_elmnts" number because internally in parts of our code numbers start at zero instead of one + write(IIN_database) glob2loc_elmnts(acforcing_surface_merge(i))+1, acforcing_surface_char(1,i), & + + acforcing_surface_char(2,i), acforcing_surface_char(3,i), acforcing_surface_char(4,i), acforcing_surface(5,i), & + ibegin_edge1_acforcing(i), iend_edge1_acforcing(i), & + ibegin_edge2_acforcing(i), iend_edge2_acforcing(i), & + ibegin_edge3_acforcing(i), iend_edge3_acforcing(i), & + ibegin_edge4_acforcing(i), iend_edge4_acforcing(i) + endif + enddo + endif + + end subroutine write_acoustic_forcing_merge_database + +! +!--------------------------------------------------------------------------------------- +! + + !-------------------------------------------------- + ! Write fluid/solid edges (fluid (or porous) elements and corresponding solid (or porous) elements) + ! pertaining to iproc partition in the corresponding Database + !-------------------------------------------------- + + subroutine write_fluidsolid_edges_database(IIN_database, nedges_coupled_bis, edges_coupled_bis, & + nedges_coupled_loc_bis, iproc, num_phase) + + use part_unstruct_par, only: part,glob2loc_elmnts + + implicit none + + integer, intent(in) :: IIN_database + + integer, intent(in) :: nedges_coupled_bis + integer, dimension(2,nedges_coupled_bis) :: edges_coupled_bis + + integer, intent(inout) :: nedges_coupled_loc_bis + + integer, intent(in) :: iproc + integer, intent(in) :: num_phase + + ! local parameters + integer :: i + + if (num_phase == 1) then + ! only counts elements in this partition + nedges_coupled_loc_bis = 0 + do i = 1, nedges_coupled_bis + if (part(edges_coupled_bis(1,i)) == iproc) then + nedges_coupled_loc_bis = nedges_coupled_loc_bis + 1 + endif + enddo + else + do i = 1, nedges_coupled_bis + if (part(edges_coupled_bis(1,i)) == iproc) then + write(IIN_database) glob2loc_elmnts(edges_coupled_bis(1,i))+1, glob2loc_elmnts(edges_coupled_bis(2,i))+1 + endif + enddo + endif + + end subroutine write_fluidsolid_edges_database + +! +!--------------------------------------------------------------------------------------- +! + + !-------------------------------------------------- + ! Write ispec of axial elements pertaining to iproc partition in the corresponding Database + !-------------------------------------------------- + + subroutine write_axial_elements_database(IIN_database, nelem_on_the_axis, ispec_of_axial_elements, & + nelem_on_the_axis_loc, iproc, num_phase, remove_min_to_start_at_zero) + + use part_unstruct_par, only: part,glob2loc_elmnts + + implicit none + + integer, intent(in) :: IIN_database + + integer, intent(in) :: nelem_on_the_axis + integer, dimension(nelem_on_the_axis) :: ispec_of_axial_elements + + integer, intent(inout) :: nelem_on_the_axis_loc + + integer, intent(in) :: iproc + integer, intent(in) :: num_phase + + integer, intent(in) :: remove_min_to_start_at_zero + + ! local parameters + integer :: i,ispec + + if (num_phase == 1) then + ! only counts elements in this partition + nelem_on_the_axis_loc = 0 + do i = 1, nelem_on_the_axis + if (part(ispec_of_axial_elements(i)) == iproc) then + nelem_on_the_axis_loc = nelem_on_the_axis_loc + 1 + endif + enddo + else + do i = 1, nelem_on_the_axis + ! if (part(ispec_of_axial_elements(i)) == 0 .and. iproc == 1) then + ! print *,"ispec_of_axial_elements :",ispec_of_axial_elements(i)," -----> glob2loc_elmnts :", & + ! glob2loc_elmnts(ispec_of_axial_elements(i)) + ! endif + + if (part(ispec_of_axial_elements(i)) == iproc) then + ispec = glob2loc_elmnts(ispec_of_axial_elements(i)) + remove_min_to_start_at_zero + write(IIN_database) ispec + endif + enddo + endif + + end subroutine write_axial_elements_database diff --git a/meshfem2d/precision.h b/meshfem2d/precision.h new file mode 100644 index 00000000..dabe5fd3 --- /dev/null +++ b/meshfem2d/precision.h @@ -0,0 +1,12 @@ +!= == == == == == == == == == == == == == == == == == == == == == == == == == == + == == == == == == == == !!S P E C F E M 2 D ! != == == == == == == == == + == == == == == == == == == == == == == == == == == == == == == == == == + == == + + !setup / precision.h.Generated from precision.h.in by configure. + + !!solver in single or + double precision depending on the machine !!set to MPI_REAL to run in single + precision !set to MPI_DOUBLE_PRECISION to run in double precision !!ALSO + CHANGE FILE constants.h ACCORDINGLY !integer, + parameter ::CUSTOM_MPI_TYPE = MPI_DOUBLE_PRECISION diff --git a/meshfem2d/read_external_mesh_files.F90 b/meshfem2d/read_external_mesh_files.F90 new file mode 100644 index 00000000..b7dea750 --- /dev/null +++ b/meshfem2d/read_external_mesh_files.F90 @@ -0,0 +1,758 @@ +!======================================================================== +! +! S P E C F E M 2 D +! ----------------- +! +! Main historical authors: Dimitri Komatitsch and Jeroen Tromp +! CNRS, France +! and Princeton University, USA +! (there are currently many more authors!) +! (c) October 2017 +! +! This software is a computer program whose purpose is to solve +! the two-dimensional viscoelastic anisotropic or poroelastic wave equation +! using a spectral-element method (SEM). +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 3 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License along +! with this program; if not, write to the Free Software Foundation, Inc., +! 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +! +! The full text of the license is available in file "LICENSE". +! +!======================================================================== + +! in the case of very large meshes, this option can be useful to switch from ASCII to binary for the mesh files +! #define USE_BINARY_FOR_EXTERNAL_MESH_DATABASE + + !----------------------------------------------- + ! Read the mesh and storing it in array 'elmnts' (which is allocated here). + ! 'remove_min_to_start_at_zero' is used to have the numbering of the nodes starting at '0'. + ! 'nelmnts' is the number of elements, 'nnodes' is the number of nodes in the mesh. + !----------------------------------------------- + + subroutine read_external_mesh_file(filename, remove_min_to_start_at_zero, NGNOD) + + use constants, only: MAX_STRING_LEN,IMAIN,myrank + use part_unstruct_par, only: elmnts,nelmnts,nnodes + + implicit none + + character(len=MAX_STRING_LEN), intent(in) :: filename + integer, intent(out) :: remove_min_to_start_at_zero + integer, intent(in) :: NGNOD + + integer :: i,ier + + ! user output + if (myrank == 0) then + write(IMAIN,*) ' Reading data from external mesh file: ',trim(filename) + write(IMAIN,*) ' NGNOD = ',NGNOD + call flush_IMAIN() + endif + +#ifdef USE_BINARY_FOR_EXTERNAL_MESH_DATABASE + ! note: adding access='stream' would further decrease file size + open(unit=990, file=trim(filename), form='unformatted' , status='old', action='read',iostat=ier) +#else + open(unit=990, file=trim(filename), form='formatted' , status='old', action='read',iostat=ier) +#endif + if (ier /= 0) then + print *,'Error opening file: ',trim(filename) + call stop_the_code('Error read external mesh file') + endif + +#ifdef USE_BINARY_FOR_EXTERNAL_MESH_DATABASE + read(990) nelmnts +#else + read(990,*) nelmnts +#endif + + allocate(elmnts(0:NGNOD*nelmnts-1),stat=ier) + if (ier /= 0) call stop_the_code('Error allocating elmnts array') + elmnts(:) = -1 + + do i = 0, nelmnts-1 + if (NGNOD == 4) then + ! linear elements + ! 4 corner nodal points +#ifdef USE_BINARY_FOR_EXTERNAL_MESH_DATABASE + read(990) elmnts(i*NGNOD), elmnts(i*NGNOD+1), elmnts(i*NGNOD+2), elmnts(i*NGNOD+3) +#else + read(990,*) elmnts(i*NGNOD), elmnts(i*NGNOD+1), elmnts(i*NGNOD+2), elmnts(i*NGNOD+3) +#endif + else if (NGNOD == 9) then + ! quadratic elements + ! 4 corners + 4 edge mid-points + 1 center nodal point +#ifdef USE_BINARY_FOR_EXTERNAL_MESH_DATABASE + read(990) elmnts(i*NGNOD), elmnts(i*NGNOD+1), elmnts(i*NGNOD+2), elmnts(i*NGNOD+3), & + elmnts(i*NGNOD+4), elmnts(i*NGNOD+5), elmnts(i*NGNOD+6), elmnts(i*NGNOD+7), elmnts(i*NGNOD+8) +#else + read(990,*) elmnts(i*NGNOD), elmnts(i*NGNOD+1), elmnts(i*NGNOD+2), elmnts(i*NGNOD+3), & + elmnts(i*NGNOD+4), elmnts(i*NGNOD+5), elmnts(i*NGNOD+6), elmnts(i*NGNOD+7), elmnts(i*NGNOD+8) +#endif + else + call stop_the_code('error, NGNOD should be either 4 or 9 for external meshes') + endif + enddo + + close(990) + + remove_min_to_start_at_zero = minval(elmnts(:)) + + ! checks if we missed some elements + if (remove_min_to_start_at_zero == -1) then + print *,'Error: reading elements ',nelmnts,': mesh has missing nodal points. please check NGNOD setting...' + call stop_the_code('Invalid mesh with missing nodal points') + endif + + elmnts(:) = elmnts(:) - remove_min_to_start_at_zero + + nnodes = maxval(elmnts) + 1 + + ! user output + if (myrank == 0) then + write(IMAIN,*) ' Total number of spectral elements :',nelmnts + write(IMAIN,*) ' Total number of nodal points :',nnodes + write(IMAIN,*) + call flush_IMAIN() + endif + + end subroutine read_external_mesh_file + +! +!--------------------------------------------------------------------------------------- +! + + !----------------------------------------------- + ! Read the material for each element and storing it in array 'num_materials' + !----------------------------------------------- + + subroutine read_external_materials_file(filename) + + use constants, only: MAX_STRING_LEN,IMAIN,myrank + + use part_unstruct_par, only: nelmnts + use shared_parameters, only: num_material + + implicit none + + character(len=MAX_STRING_LEN), intent(in) :: filename + + ! local parameters + integer :: i,ier + + ! user output + if (myrank == 0) then + write(IMAIN,*) ' Reading materials from external mesh file: ',trim(filename) + write(IMAIN,*) + call flush_IMAIN() + endif + + ! assigns materials to mesh elements + allocate(num_material(nelmnts),stat=ier) + if (ier /= 0) call stop_the_code('Error allocating num_material array') + num_material(:) = 0 + + ! file input +#ifdef USE_BINARY_FOR_EXTERNAL_MESH_DATABASE + ! note: adding access='stream' would further decrease file size + open(unit=992, file=trim(filename), form='unformatted' , status='old', action='read',iostat=ier) +#else + open(unit=992, file=trim(filename), form='formatted' , status='old', action='read',iostat=ier) +#endif + if (ier /= 0) then + print *,'Error opening file: ',trim(filename) + call stop_the_code('Error read external mat file') + endif + + do i = 1, nelmnts +#ifdef USE_BINARY_FOR_EXTERNAL_MESH_DATABASE + read(992) num_material(i) +#else + read(992,*) num_material(i) +#endif + enddo + close(992) + + ! quick check + if (any(num_material(:) == 0)) call stop_the_code('Error reading material array, some elements have zero material index') + + end subroutine read_external_materials_file + +! +!--------------------------------------------------------------------------------------- +! + + !----------------------------------------------- + ! Read the PML elements, storing them in array 'region_pml_external_mesh' + !----------------------------------------------- + + subroutine read_external_pml_element(filename, region_pml_external_mesh, nspec_cpml) + + use constants, only: MAX_STRING_LEN,CPML_X_ONLY,CPML_Z_ONLY,CPML_XZ,IMAIN,myrank + use part_unstruct_par, only: nelmnts + use compute_elements_load_par, only: is_pml + + implicit none + + character(len=MAX_STRING_LEN), intent(in) :: filename + integer, dimension(1:nelmnts), intent(out) :: region_pml_external_mesh + integer, intent(out) :: nspec_cpml + + integer :: i,ier,ispec,pml_flag + + ! user output + if (myrank == 0) then + write(IMAIN,*) ' Reading PML elements from external mesh file: ',trim(filename) + call flush_IMAIN() + endif + +#ifdef USE_BINARY_FOR_EXTERNAL_MESH_DATABASE + ! note: adding access='stream' would further decrease file size + open(unit=992, file=trim(filename), form='unformatted' , status='old', action='read',iostat=ier) +#else + open(unit=992, file=trim(filename), form='formatted' , status='old', action='read',iostat=ier) +#endif + if (ier /= 0) then + print *,'Error opening file: ',trim(filename) + call stop_the_code('Error read external absorbing_cpml_file') + endif + +#ifdef USE_BINARY_FOR_EXTERNAL_MESH_DATABASE + read(992) nspec_cpml +#else + read(992,*) nspec_cpml +#endif + + do i = 1, nspec_cpml +#ifdef USE_BINARY_FOR_EXTERNAL_MESH_DATABASE + read(992) ispec, pml_flag +#else + read(992,*) ispec, pml_flag +#endif + if (pml_flag /= CPML_X_ONLY .and. pml_flag /= CPML_Z_ONLY .and. pml_flag /= CPML_XZ) & + call stop_the_code('error: incorrect CPML element flag found, should be CPML_X_ONLY or CPML_Z_ONLY or CPML_XZ only') + + ! stores element + region_pml_external_mesh(ispec) = pml_flag + is_pml(ispec-1) = .true. + enddo + + close(992) + + ! user output + if (myrank == 0) then + write(IMAIN,*) ' Total number of PML elements: ',nspec_cpml + write(IMAIN,*) + call flush_IMAIN() + endif + + end subroutine read_external_pml_element + +! +!--------------------------------------------------------------------------------------- +! + + !----------------------------------------------- + ! read the node coordinates and store them in array 'nodes_coords' + !----------------------------------------------- + + subroutine read_external_mesh_nodes_coords(filename) + + use constants, only: MAX_STRING_LEN,IMAIN,myrank + use part_unstruct_par, only: nodes_coords,nnodes + + implicit none + + character(len=MAX_STRING_LEN), intent(in) :: filename + + integer :: i,ier + + ! user output + if (myrank == 0) then + write(IMAIN,*) ' Reading node coords from external mesh file: ',trim(filename) + call flush_IMAIN() + endif + +#ifdef USE_BINARY_FOR_EXTERNAL_MESH_DATABASE + ! note: adding access='stream' would further decrease file size + open(unit=991, file=trim(filename), form='unformatted' , status='old', action='read', iostat=ier) +#else + open(unit=991, file=trim(filename), form='formatted' , status='old', action='read', iostat=ier) +#endif + if (ier /= 0) then + print *,'Error opening file: ',trim(filename) + call stop_the_code('Error read external nodes coords file') + endif + +#ifdef USE_BINARY_FOR_EXTERNAL_MESH_DATABASE + read(991) nnodes +#else + read(991,*) nnodes +#endif + + allocate(nodes_coords(2,nnodes)) + nodes_coords(:,:) = 0.d0 + + do i = 1, nnodes +#ifdef USE_BINARY_FOR_EXTERNAL_MESH_DATABASE + read(991) nodes_coords(1,i), nodes_coords(2,i) +#else + read(991,*) nodes_coords(1,i), nodes_coords(2,i) +#endif + enddo + close(991) + + ! user output + if (myrank == 0) then + write(IMAIN,*) ' node coords: X min/max = ',minval(nodes_coords(1,:)),"/",maxval(nodes_coords(1,:)) + write(IMAIN,*) ' Z min/max = ',minval(nodes_coords(2,:)),"/",maxval(nodes_coords(2,:)) + write(IMAIN,*) + call flush_IMAIN() + endif + + + end subroutine read_external_mesh_nodes_coords + +! +!--------------------------------------------------------------------------------------- +! + + !----------------------------------------------- + ! Read free surface. + ! Edges from elastic elements are discarded. + ! 'acoustic_surface' contains 1/ element number, 2/ number of nodes that form the free surface, + ! 3/ first node on the free surface, 4/ second node on the free surface, if relevant (if 2/ is equal to 2) + !----------------------------------------------- + + subroutine read_external_acoustic_surface(filename, num_material, & + nbmodels, icodemat, phi_material, remove_min_to_start_at_zero) + + use constants, only: MAX_STRING_LEN,ANISOTROPIC_MATERIAL,IMAIN,myrank + use part_unstruct_par, only: nelmnts,nelem_acoustic_surface,acoustic_surface + + implicit none + + character(len=MAX_STRING_LEN), intent(in) :: filename + integer, dimension(0:nelmnts-1) :: num_material + integer, intent(in) :: nbmodels + integer, dimension(1:nbmodels), intent(in) :: icodemat + double precision, dimension(1:nbmodels), intent(in) :: phi_material + integer, intent(in) :: remove_min_to_start_at_zero + + ! local parameters + integer, dimension(:,:), allocatable :: acoustic_surface_tmp + integer :: nelmnts_surface + integer :: i,ier + integer :: imaterial_number + + ! user output + if (myrank == 0) then + write(IMAIN,*) ' Reading acoustic surface from external mesh file: ',trim(filename) + call flush_IMAIN() + endif + +#ifdef USE_BINARY_FOR_EXTERNAL_MESH_DATABASE + ! note: adding access='stream' would further decrease file size + open(unit=993, file=trim(filename), form='unformatted' , status='old', action='read', iostat=ier) +#else + open(unit=993, file=trim(filename), form='formatted' , status='old', action='read', iostat=ier) +#endif + if (ier /= 0) then + print *,'Error opening file: ',trim(filename) + call stop_the_code('Error read acoustic surface file') + endif + +#ifdef USE_BINARY_FOR_EXTERNAL_MESH_DATABASE + read(993) nelmnts_surface +#else + read(993,*) nelmnts_surface +#endif + + allocate(acoustic_surface_tmp(4,nelmnts_surface)) + + do i = 1, nelmnts_surface +#ifdef USE_BINARY_FOR_EXTERNAL_MESH_DATABASE + read(993) acoustic_surface_tmp(1,i), acoustic_surface_tmp(2,i), acoustic_surface_tmp(3,i), acoustic_surface_tmp(4,i) +#else + read(993,*) acoustic_surface_tmp(1,i), acoustic_surface_tmp(2,i), acoustic_surface_tmp(3,i), acoustic_surface_tmp(4,i) +#endif + enddo + + close(993) + + acoustic_surface_tmp(1,:) = acoustic_surface_tmp(1,:) - remove_min_to_start_at_zero + acoustic_surface_tmp(3,:) = acoustic_surface_tmp(3,:) - remove_min_to_start_at_zero + acoustic_surface_tmp(4,:) = acoustic_surface_tmp(4,:) - remove_min_to_start_at_zero + + nelem_acoustic_surface = 0 + do i = 1, nelmnts_surface + imaterial_number = num_material(acoustic_surface_tmp(1,i)) + if (icodemat(imaterial_number) /= ANISOTROPIC_MATERIAL .and. phi_material(imaterial_number) >= 1.d0) then + nelem_acoustic_surface = nelem_acoustic_surface + 1 + endif + enddo + + allocate(acoustic_surface(4,nelem_acoustic_surface),stat=ier) + if (ier /= 0) call stop_the_code('Error allocating acoustic_surface array') + + nelem_acoustic_surface = 0 + do i = 1, nelmnts_surface + imaterial_number = num_material(acoustic_surface_tmp(1,i)) + if (icodemat(imaterial_number) /= ANISOTROPIC_MATERIAL .and. phi_material(imaterial_number) >= 1.d0) then + nelem_acoustic_surface = nelem_acoustic_surface + 1 + acoustic_surface(:,nelem_acoustic_surface) = acoustic_surface_tmp(:,i) + endif + enddo + + ! user output + if (myrank == 0) then + write(IMAIN,*) ' Total number of surface elements : ',nelmnts_surface + write(IMAIN,*) ' Total number of acoustic surface elements: ',nelem_acoustic_surface + write(IMAIN,*) + call flush_IMAIN() + endif + + end subroutine read_external_acoustic_surface + +! +!--------------------------------------------------------------------------------------- +! + + !----------------------------------------------- + ! Read absorbing surface. + ! 'abs_surface' contains 1/ element number, 2/ number of nodes that form the absorbing edge + ! (which currently must always be equal to 2), + ! 3/ first node on the abs surface, 4/ second node on the abs surface + ! 5/ 1=IBOTTOM, 2=IRIGHT, 3=ITOP, 4=ILEFT + !----------------------------------------------- + subroutine read_external_abs_surface(filename, remove_min_to_start_at_zero) + + use constants, only: MAX_STRING_LEN,IMAIN,myrank + use part_unstruct_par, only: abs_surface,nelemabs + + implicit none + + character(len=MAX_STRING_LEN), intent(in) :: filename + integer, intent(in) :: remove_min_to_start_at_zero + + integer :: i,ier + + ! user output + if (myrank == 0) then + write(IMAIN,*) ' Reading absorbing surface from external mesh file: ',trim(filename) + call flush_IMAIN() + endif + +#ifdef USE_BINARY_FOR_EXTERNAL_MESH_DATABASE + ! note: adding access='stream' would further decrease file size + open(unit=994, file=trim(filename), form='unformatted' , status='old', action='read', iostat=ier) +#else + open(unit=994, file=trim(filename), form='formatted' , status='old', action='read', iostat=ier) +#endif + if (ier /= 0) then + print *,'Error opening file: ',trim(filename) + call stop_the_code('Error read absorbing surface file') + endif + +#ifdef USE_BINARY_FOR_EXTERNAL_MESH_DATABASE + read(994) nelemabs +#else + read(994,*) nelemabs +#endif + + allocate(abs_surface(5,nelemabs)) + + do i = 1, nelemabs +#ifdef USE_BINARY_FOR_EXTERNAL_MESH_DATABASE + read(994) abs_surface(1,i), abs_surface(2,i), abs_surface(3,i), abs_surface(4,i), abs_surface(5,i) +#else + read(994,*) abs_surface(1,i), abs_surface(2,i), abs_surface(3,i), abs_surface(4,i), abs_surface(5,i) +#endif + + if (abs_surface(2,i) /= 2) then + print *,'Only two nodes per absorbing element can be listed.' + print *,'If one of your elements has more than one edge along a given absorbing contour' + print *,'(e.g., if that contour has a corner) then list it twice,' + print *,'putting the first edge on the first line and the second edge on the second line.' + print *,'If one of your elements has a single point along the absording contour rather than a full edge, do NOT list it' + print *,'(it would have no weight in the contour integral anyway because it would consist of a single point).' + print *,'If you use 9-node elements, list only the first and last points of the edge and not the intermediate point' + print *,'located around the middle of the edge; the right 9-node curvature will be restored automatically by the code.' + + call stop_the_code('only two nodes per element should be listed for absorbing edges') + endif + + if (abs_surface(5,i) < 1 .or. abs_surface(5,i) > 4) then + call stop_the_code('absorbing element type must be between 1 (IBOTTOM) and 4 (ILEFT)') + endif + + enddo + + close(994) + + abs_surface(1,:) = abs_surface(1,:) - remove_min_to_start_at_zero + abs_surface(3,:) = abs_surface(3,:) - remove_min_to_start_at_zero + abs_surface(4,:) = abs_surface(4,:) - remove_min_to_start_at_zero + + ! user output + if (myrank == 0) then + write(IMAIN,*) ' Total number of absorbing surface elements: ',nelemabs + write(IMAIN,*) + call flush_IMAIN() + endif + + + end subroutine read_external_abs_surface + +! +!--------------------------------------------------------------------------------------- +! + + !----------------------------------------------- + ! Read acoustic forcing surface. + ! 'acforcing_surface' contains 1/ element number, 2/ number of nodes that form the acoustic forcing edge + ! (which currently must always be equal to 2), + ! 3/ first node on the acforcing surface, 4/ second node on the acforcing surface + ! 5/ 1=IBOTTOME, 2=IRIGHT, 3=ITOP, 4=ILEFT + !----------------------------------------------- + + subroutine read_external_acoustic_forcing_surface(filename, remove_min_to_start_at_zero) + + use constants, only: MAX_STRING_LEN,IMAIN,myrank + use part_unstruct_par, only: acforcing_surface,nelemacforcing + + implicit none + + character(len=MAX_STRING_LEN), intent(in) :: filename + integer, intent(in) :: remove_min_to_start_at_zero + + integer :: i,ier + + ! user output + if (myrank == 0) then + write(IMAIN,*) ' Reading acoustic forcing surface from external mesh file: ',trim(filename) + call flush_IMAIN() + endif + +#ifdef USE_BINARY_FOR_EXTERNAL_MESH_DATABASE + ! note: adding access='stream' would further decrease file size + open(unit=995, file=trim(filename), form='unformatted' , status='old', action='read', iostat=ier) +#else + open(unit=995, file=trim(filename), form='formatted' , status='old', action='read', iostat=ier) +#endif + if (ier /= 0) then + print *,'Error opening file: ',trim(filename) + call stop_the_code('Error read acoustic forcing surface file') + endif + +#ifdef USE_BINARY_FOR_EXTERNAL_MESH_DATABASE + read(995) nelemacforcing +#else + read(995,*) nelemacforcing +#endif + + allocate(acforcing_surface(5,nelemacforcing)) + + do i = 1, nelemacforcing +#ifdef USE_BINARY_FOR_EXTERNAL_MESH_DATABASE + read(995) acforcing_surface(1,i), acforcing_surface(2,i), acforcing_surface(3,i), acforcing_surface(4,i), & + acforcing_surface(5,i) +#else + read(995,*) acforcing_surface(1,i), acforcing_surface(2,i), acforcing_surface(3,i), acforcing_surface(4,i), & + acforcing_surface(5,i) +#endif + + if (acforcing_surface(2,i) /= 2) then + print *,'Only two nodes per acoustic forcing element can be listed.' + print *,'If one of your elements has more than one edge along a given acoustic forcing contour' + print *,'(e.g., if that contour has a corner) then list it twice,' + print *,'putting the first edge on the first line and the second edge on the second line.' + print *,'If one of your elements has a single point along the acoustic forcing contour rather than a full edge, do NOT' + print *,'list it (it would have no weight in the contour integral anyway because it would consist of a single point).' + print *,'If you use 9-node elements, list only the first and last points of the edge and not the intermediate point' + print *,'located around the middle of the edge; the right 9-node curvature will be restored automatically by the code.' + + call stop_the_code('only two nodes per element should be listed for absorbing edges') + endif + + if (acforcing_surface(5,i) < 1 .or. acforcing_surface(5,i) > 4) then + call stop_the_code('absorbing element type must be between 1 (IBOTTOM) and 4 (ILEFT)') + endif + + enddo + + close(995) + + acforcing_surface(1,:) = acforcing_surface(1,:) - remove_min_to_start_at_zero + acforcing_surface(3,:) = acforcing_surface(3,:) - remove_min_to_start_at_zero + acforcing_surface(4,:) = acforcing_surface(4,:) - remove_min_to_start_at_zero + + ! user output + if (myrank == 0) then + write(IMAIN,*) ' Total number of acoustic forcing surface elements: ',nelemacforcing + write(IMAIN,*) + call flush_IMAIN() + endif + + + end subroutine read_external_acoustic_forcing_surface + +! +!--------------------------------------------------------------------------------------- +! + + !----------------------------------------------- + ! Read axial elements file. + ! The first line of this file must be the total number of axial elements then it contains + ! the ispec of each of these elements. + ! 'axial_elements' contains the list of the ispec corresponding to axial elements + !----------------------------------------------- + + subroutine read_external_axial_elements_file(filename,remove_min_to_start_at_zero) + + use constants, only: MAX_STRING_LEN,IMAIN,myrank + use part_unstruct_par, only: ispec_of_axial_elements,nelem_on_the_axis,inode1_axial_elements,inode2_axial_elements + + implicit none + + character(len=MAX_STRING_LEN), intent(in) :: filename + integer, intent(in) :: remove_min_to_start_at_zero + + integer :: i,j,ier + integer :: dump + + ! user output + if (myrank == 0) then + write(IMAIN,*) ' Reading axial elements from external mesh file: ',trim(filename) + call flush_IMAIN() + endif + +#ifdef USE_BINARY_FOR_EXTERNAL_MESH_DATABASE + ! note: adding access='stream' would further decrease file size + open(unit=994, file=trim(filename), form='unformatted' , status='old', action='read', iostat=ier) +#else + open(unit=994, file=trim(filename), form='formatted' , status='old', action='read', iostat=ier) +#endif + if (ier /= 0) then + print *,'Error opening file: ',trim(filename) + call stop_the_code('Error read axial elements file') + endif + +#ifdef USE_BINARY_FOR_EXTERNAL_MESH_DATABASE + read(994) nelem_on_the_axis +#else + read(994,*) nelem_on_the_axis +#endif + + ! user output + write(IMAIN,*) "Number of elements on the axis: ", nelem_on_the_axis + + allocate(ispec_of_axial_elements(nelem_on_the_axis),stat=ier) + if (ier /= 0) call stop_the_code('Error allocating array ispec_of_axial_elements') + + ! needed for rotation + allocate(inode1_axial_elements(nelem_on_the_axis), & + inode2_axial_elements(nelem_on_the_axis),stat=ier) + if (ier /= 0) call stop_the_code('Error allocating array inode**_axial_elements') + + do i = 1, nelem_on_the_axis ! Dump is always 2 (old convention from absorbing surfaces) +#ifdef USE_BINARY_FOR_EXTERNAL_MESH_DATABASE + read(994) ispec_of_axial_elements(i), dump, inode1_axial_elements(i), inode2_axial_elements(i) +#else + read(994,*) ispec_of_axial_elements(i), dump, inode1_axial_elements(i), inode2_axial_elements(i) +#endif + + enddo + + close(994) + + ! this has a cost of O(nelem_on_the_axis^2), could be reduced by using a quicksort algorithm + ! and checking the sorted list + write(IMAIN,*) 'testing for duplicates in the axial element input file...' + do i = 1,nelem_on_the_axis + do j = i+1,nelem_on_the_axis + if (ispec_of_axial_elements(i) == ispec_of_axial_elements(j)) then + call stop_the_code('At least one element appears twice in the axial element file') + endif + enddo + enddo + write(IMAIN,*) 'done testing for duplicates' + write(IMAIN,*) + + ! axisym TODO : Test if the informations supplied are compatible with axisym + + ispec_of_axial_elements(:) = ispec_of_axial_elements(:) - remove_min_to_start_at_zero + inode1_axial_elements(:) = inode1_axial_elements(:) - remove_min_to_start_at_zero + inode2_axial_elements(:) = inode2_axial_elements(:) - remove_min_to_start_at_zero + + ! user output + if (myrank == 0) then + write(IMAIN,*) ' Total number of axial elements: ',nelem_on_the_axis + write(IMAIN,*) + call flush_IMAIN() + endif + + + end subroutine read_external_axial_elements_file + +! +!--------------------------------------------------------------------------------------- +! + + subroutine read_external_tangential_curve_file(filename) + +! reads in tangential detection curve file + + use constants, only: MAX_STRING_LEN,IIN,IMAIN,myrank + + use part_unstruct_par, only: nnodes_tangential_curve,nodes_tangential_curve + + implicit none + + character(len=MAX_STRING_LEN),intent(in) :: filename + + ! local parameters + integer :: i,ier + + ! user output + if (myrank == 0) then + write(IMAIN,*) ' Reading tangential curve from external mesh file: ',trim(filename) + call flush_IMAIN() + endif + + ! reads in specified external file + open(unit=IIN,file=trim(filename),status='old',action='read',iostat=ier) + if (ier /= 0) then + print *,'Error opening file: ',trim(filename) + call stop_the_code('Error read tangential curve file') + endif + + read(IIN,*) nnodes_tangential_curve + + allocate(nodes_tangential_curve(2,nnodes_tangential_curve),stat=ier) + if (ier /= 0) call stop_the_code('Error allocating tangential array') + + do i = 1, nnodes_tangential_curve + read(IIN,*) nodes_tangential_curve(1,i), nodes_tangential_curve(2,i) + enddo + close(IIN) + + ! user output + if (myrank == 0) then + write(IMAIN,*) ' Total number of tangential curve nodes: ',nnodes_tangential_curve + write(IMAIN,*) + call flush_IMAIN() + endif + + end subroutine read_external_tangential_curve_file diff --git a/meshfem2d/read_interfaces_file.f90 b/meshfem2d/read_interfaces_file.f90 new file mode 100644 index 00000000..fbeb786a --- /dev/null +++ b/meshfem2d/read_interfaces_file.f90 @@ -0,0 +1,210 @@ +!======================================================================== +! +! S P E C F E M 2 D +! ----------------- +! +! Main historical authors: Dimitri Komatitsch and Jeroen Tromp +! CNRS, France +! and Princeton University, USA +! (there are currently many more authors!) +! (c) October 2017 +! +! This software is a computer program whose purpose is to solve +! the two-dimensional viscoelastic anisotropic or poroelastic wave equation +! using a spectral-element method (SEM). +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 3 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License along +! with this program; if not, write to the Free Software Foundation, Inc., +! 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +! +! The full text of the license is available in file "LICENSE". +! +!======================================================================== + +subroutine read_interfaces_file() + + use constants, only: IMAIN,IIN_INTERFACES,DONT_IGNORE_JUNK,HUGEVAL,MAX_STRING_LEN,IN_DATA_FILES + + use shared_parameters, only: interfaces_filename,nx_param, & + nz_layer,number_of_layers, & + max_npoints_interface,number_of_interfaces,npoints_of_interfaces, & + xinterface_coords,zinterface_coords, & + nxread,nzread + + ! see comment below for uncommenting this feature + !use shared_parameters, only: NUMBER_OF_SIMULTANEOUS_RUNS + !use constants, only: mygroup + implicit none + + ! local parameters + integer :: ier,interface_current,ipoint_current,ilayer,idummy + integer :: npoints_interface + double precision :: xval,zval,xval_previous + !character(len=MAX_STRING_LEN) :: path_to_add + + ! interfaces_filename = trim(IN_DATA_FILES)//trim(interfacesfile) ! by default: DATA/.. + +! in case we want to allow for different mesh interfaces between different run setups +! +! note: this is a somewhat dangerous feature and differs from 3D version behavior. +! simultaneous runs had the original idea of using the same mesh, but allow for different source/station setups. +! thus, saving time in having to run the mesher multiple times for multiple runs. +! +! allowing to read in different interfaces here defeats this original idea for simultaneous runs +! we'll disable it for now and require the mesh setup (interface,tomography, external mesh files) +! be read from a main reference folder DATA/, not run****/DATA/.. +! +! please uncomment in case needed and make sure you know how to run your simultaneous runs properly :) + + !if (NUMBER_OF_SIMULTANEOUS_RUNS > 1 .and. mygroup >= 0) then + ! write(path_to_add,"('run',i4.4,'/')") mygroup + 1 + ! interfaces_filename = path_to_add(1:len_trim(path_to_add))//interfaces_filename(1:len_trim(interfaces_filename)) + !endif + + ! user output + write(IMAIN,*) 'Reading interface data from file: '//trim(interfaces_filename) + call flush_IMAIN() + + ! get interface data from external file to count the spectral elements along Z + open(unit=IIN_INTERFACES,file=trim(interfaces_filename),status='old',iostat=ier) + if (ier /= 0) then + print *,'Error opening file: '//trim(interfaces_filename) + call exit_MPI(0,'Error read interface file in meshfem2D') + endif + + max_npoints_interface = -1 + + ! read number of interfaces + call read_value_integer(IIN_INTERFACES,DONT_IGNORE_JUNK,number_of_interfaces) + + ! safety check + if (number_of_interfaces < 2) call stop_the_code('not enough interfaces (minimum is 2)') + + ! loop on all the interfaces + do interface_current = 1,number_of_interfaces + + call read_value_integer(IIN_INTERFACES,DONT_IGNORE_JUNK,npoints_interface) + + ! check + if (npoints_interface < 2) call stop_the_code('not enough interface points (minimum is 2)') + + max_npoints_interface = max(npoints_interface,max_npoints_interface) + + ! user output + write(IMAIN,*) 'Reading ',npoints_interface,' points for interface ',interface_current + call flush_IMAIN() + + ! loop on all the points describing this interface + xval_previous = -HUGEVAL + + do ipoint_current = 1,npoints_interface + + call read_two_interface_points(IIN_INTERFACES,DONT_IGNORE_JUNK,xval,zval) + + ! safety check + if (ipoint_current > 1 .and. xval <= xval_previous) & + call stop_the_code('interface points must be sorted in increasing X') + + xval_previous = xval + enddo + enddo + + ! allocates interface points for mesher + allocate(xinterface_coords(max_npoints_interface,number_of_interfaces), & + zinterface_coords(max_npoints_interface,number_of_interfaces),stat=ier) + if (ier /= 0) call stop_the_code('Error allocating interface arrays') + + xinterface_coords(:,:) = 0.0 + zinterface_coords(:,:) = 0.0 + + allocate(npoints_of_interfaces(number_of_interfaces),stat=ier) + if (ier /= 0) call exit_MPI(0,'Error allocating npoints_interfaces array') + npoints_of_interfaces(:) = 0 + + ! start reading from beginning to store all interface points + ! + ! note: this will avoid reading this same file again later in the mesher. + ! reading all interface information is done here once and for all. + rewind(IIN_INTERFACES) + + ! skip + call read_value_integer(IIN_INTERFACES,DONT_IGNORE_JUNK,idummy) ! number_of_interfaces + + ! loop on all the interfaces + do interface_current = 1,number_of_interfaces + ! reads number of interface points + call read_value_integer(IIN_INTERFACES,DONT_IGNORE_JUNK,npoints_interface) + + ! check + if (npoints_interface < 2) call stop_the_code('not enough interface points (minimum is 2) to store values') + + ! stores number of points + npoints_of_interfaces(interface_current) = npoints_interface + + ! loop on all the points describing this interface + xval_previous = -HUGEVAL + do ipoint_current = 1,npoints_interface + call read_two_interface_points(IIN_INTERFACES,DONT_IGNORE_JUNK,xval,zval) + + ! safety check + if (ipoint_current > 1 .and. xval <= xval_previous) & + call stop_the_code('interface points must be sorted in increasing X to store values') + + ! stores interface point + xinterface_coords(ipoint_current,interface_current) = xval + zinterface_coords(ipoint_current,interface_current) = zval + enddo + enddo + + ! define number of layers + number_of_layers = number_of_interfaces - 1 + + allocate(nz_layer(number_of_layers),stat=ier) + if (ier /= 0) call stop_the_code('Error allocating array nz_layer') + nz_layer(:) = 0 + + ! user output + write(IMAIN,*) + write(IMAIN,*) 'Total number of layers in z direction = ', number_of_layers + call flush_IMAIN() + + ! loop on all the layers + do ilayer = 1,number_of_layers + + ! read number of spectral elements in vertical direction in this layer + call read_value_integer(IIN_INTERFACES,DONT_IGNORE_JUNK,nz_layer(ilayer)) + + if (nz_layer(ilayer) < 1) call stop_the_code('not enough spectral elements along Z in layer (minimum is 1)') + + ! user output + write(IMAIN,*) 'There are ',nz_layer(ilayer),' spectral elements along Z in layer ',ilayer + call flush_IMAIN() + enddo + + ! all done reading + close(IIN_INTERFACES) + + ! compute total number of spectral elements in vertical direction + nzread = sum(nz_layer) + + ! sets number of elements along X for internal mesher + nxread = nx_param + + ! user output + write(IMAIN,*) + write(IMAIN,*) 'Total number of spectral elements along X = ',nxread + write(IMAIN,*) 'Total number of spectral elements along Z = ',nzread + write(IMAIN,*) + call flush_IMAIN() + +end subroutine read_interfaces_file diff --git a/meshfem2d/read_material_table.f90 b/meshfem2d/read_material_table.f90 new file mode 100644 index 00000000..da0fb19c --- /dev/null +++ b/meshfem2d/read_material_table.f90 @@ -0,0 +1,306 @@ +!======================================================================== +! +! S P E C F E M 2 D +! ----------------- +! +! Main historical authors: Dimitri Komatitsch and Jeroen Tromp +! CNRS, France +! and Princeton University, USA +! (there are currently many more authors!) +! (c) October 2017 +! +! This software is a computer program whose purpose is to solve +! the two-dimensional viscoelastic anisotropic or poroelastic wave equation +! using a spectral-element method (SEM). +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 3 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License along +! with this program; if not, write to the Free Software Foundation, Inc., +! 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +! +! The full text of the license is available in file "LICENSE". +! +!======================================================================== + + subroutine read_material_table() + +! reads in material definitions in DATA/Par_file + + use constants, only: IMAIN,TINYVAL,ISOTROPIC_MATERIAL,ANISOTROPIC_MATERIAL,POROELASTIC_MATERIAL + + use shared_parameters, only: AXISYM,nbmodels,icodemat,cp,cs, & + aniso3,aniso4,aniso5,aniso6,aniso7,aniso8,aniso9,aniso10,aniso11,aniso12, & + comp_g,QKappa,Qmu, & + rho_s_read,rho_f_read, & + phi_read,tortuosity_read, & + permxx_read,permxz_read,permzz_read,kappa_s_read,kappa_f_read,kappa_fr_read, & + eta_f_read,mu_fr_read + + implicit none + + ! local parameters + integer :: imaterial,i,icodematread,number_of_materials_defined_by_tomo_file + integer :: reread_nbmodels + double precision :: val0read,val1read,val2read,val3read,val4read, & + val5read,val6read,val7read,val8read,val9read,val10read,val11read,val12read + + integer,external :: err_occurred + + ! re-read number of models to reposition read-header + call read_value_integer_p(reread_nbmodels, 'mesher.nbmodels') + if (err_occurred() /= 0) call stop_the_code('error reading parameter nbmodels in Par_file') + + ! check + if (reread_nbmodels /= nbmodels) call stop_the_code('Invalid reread value of nbmodels in reading material table') + + ! safety check + if (nbmodels <= 0) call stop_the_code('Non-positive number of materials not allowed!') + + ! allocates material tables + allocate(icodemat(nbmodels)) + allocate(cp(nbmodels)) + allocate(cs(nbmodels)) + + allocate(aniso3(nbmodels)) + allocate(aniso4(nbmodels)) + allocate(aniso5(nbmodels)) + allocate(aniso6(nbmodels)) + allocate(aniso7(nbmodels)) + allocate(aniso8(nbmodels)) + allocate(aniso9(nbmodels)) + allocate(aniso10(nbmodels)) + allocate(aniso11(nbmodels)) + allocate(aniso12(nbmodels)) + + allocate(comp_g(nbmodels)) + allocate(QKappa(nbmodels)) + allocate(Qmu(nbmodels)) + + allocate(rho_s_read(nbmodels)) + allocate(rho_f_read(nbmodels)) + + allocate( phi_read(nbmodels), & + tortuosity_read(nbmodels), & + permxx_read(nbmodels), & + permxz_read(nbmodels), & + permzz_read(nbmodels), & + kappa_s_read(nbmodels), & + kappa_f_read(nbmodels), & + kappa_fr_read(nbmodels), & + eta_f_read(nbmodels), & + mu_fr_read(nbmodels)) + + ! initializes material properties + icodemat(:) = 0 + + cp(:) = 0.d0 + cs(:) = 0.d0 + + aniso3(:) = 0.d0 + aniso4(:) = 0.d0 + aniso5(:) = 0.d0 + aniso6(:) = 0.d0 + aniso7(:) = 0.d0 + aniso8(:) = 0.d0 + aniso9(:) = 0.d0 + aniso10(:) = 0.d0 + aniso11(:) = 0.d0 + + comp_g(:) = 0.0d0 + QKappa(:) = 9999.d0 + Qmu(:) = 9999.d0 + + rho_s_read(:) = 0.d0 + rho_f_read(:) = 0.d0 + + phi_read(:) = 0.d0 + tortuosity_read(:) = 0.d0 + permxx_read(:) = 0.d0 + permxz_read(:) = 0.d0 + permzz_read(:) = 0.d0 + kappa_s_read(:) = 0.d0 + kappa_f_read(:) = 0.d0 + kappa_fr_read(:) = 0.d0 + eta_f_read(:) = 0.d0 + mu_fr_read(:) = 0.d0 + + number_of_materials_defined_by_tomo_file = 0 + + ! reads in material definitions + do imaterial = 1,nbmodels + ! supported model formats: + ! acoustic - model_number 1 rho Vp 0 0 0 QKappa Qmu 0 0 0 0 0 0 + ! elastic - model_number 1 rho Vp Vs 0 0 QKappa Qmu 0 0 0 0 0 0 + ! anisotropic - model_number 2 rho c11 c13 c15 c33 c35 c55 c12 c23 c25 0 QKappa Qmu + ! anisotropic (in AXISYM) - model_number 2 rho c11 c13 c15 c33 c35 c55 c12 c23 c25 c22 QKappa Qmu + ! poroelastic - model_number 3 rhos rhof phi c kxx kxz kzz Ks Kf Kfr etaf mufr Qmu + ! tomo - model_number -1 0 0 A 0 0 0 0 0 0 0 0 0 0 + + call read_material_parameters_p(i,icodematread, & + val0read,val1read,val2read,val3read, & + val4read,val5read,val6read,val7read, & + val8read,val9read,val10read,val11read,val12read) + + ! checks material id + if (i < 1 .or. i > nbmodels) call stop_the_code('Wrong material number!') + icodemat(i) = icodematread + + ! sets material properties + if (icodemat(i) == ISOTROPIC_MATERIAL) then + ! isotropic materials + rho_s_read(i) = val0read + cp(i) = val1read + cs(i) = val2read + comp_g(i) = val3read + QKappa(i) = val5read + Qmu(i) = val6read + + ! for Cs we use a less restrictive test because acoustic media have Cs exactly equal to zero + if (rho_s_read(i) <= 0.00000001d0 .or. cp(i) <= 0.00000001d0 .or. cs(i) < 0.d0) then + write(*,*) 'rho,cp,cs=',rho_s_read(i),cp(i),cs(i) + call stop_the_code('negative value of velocity or density') + endif + if (QKappa(i) <= 0.00000001d0 .or. Qmu(i) <= 0.00000001d0) then + call stop_the_code('non-positive value of QKappa or Qmu') + endif + + aniso3(i) = val3read + aniso4(i) = val4read + if (abs(cs(i)) > TINYVAL) then + phi_read(i) = 0.d0 ! elastic + else + phi_read(i) = 1.d0 ! acoustic + endif + + else if (icodemat(i) == ANISOTROPIC_MATERIAL) then + ! anisotropic materials + rho_s_read(i) = val0read + aniso3(i) = val1read + aniso4(i) = val2read + aniso5(i) = val3read + aniso6(i) = val4read + aniso7(i) = val5read + aniso8(i) = val6read + aniso9(i) = val7read + aniso10(i) = val8read + aniso11(i) = val9read + aniso12(i) = val10read ! This value will be used only in AXISYM + + if (val11read > 0.1) QKappa(i) = val11read + if (val12read > 0.1) Qmu(i) = val12read + + else if (icodemat(i) == POROELASTIC_MATERIAL) then + ! poroelastic materials + rho_s_read(i) = val0read + rho_f_read(i) = val1read + phi_read(i) = val2read + tortuosity_read(i) = val3read + permxx_read(i) = val4read + permxz_read(i) = val5read + permzz_read(i) = val6read + kappa_s_read(i) = val7read + kappa_f_read(i) = val8read + kappa_fr_read(i) = val9read + eta_f_read(i) = val10read + mu_fr_read(i) = val11read + + if (val12read > 0.1) Qmu(i) = val12read + + if (rho_s_read(i) <= 0.d0 .or. rho_f_read(i) <= 0.d0) & + call stop_the_code('non-positive value of density') + if (phi_read(i) <= 0.d0 .or. tortuosity_read(i) <= 0.d0) & + call stop_the_code('non-positive value of porosity or tortuosity') + if (kappa_s_read(i) <= 0.d0 .or. kappa_f_read(i) <= 0.d0 .or. kappa_fr_read(i) <= 0.d0 .or. mu_fr_read(i) <= 0.d0) & + call stop_the_code('non-positive value of modulus') + if (Qmu(i) <= 0.00000001d0) & + call stop_the_code('non-positive value of Qmu') + + else if (icodemat(i) <= 0) then + ! tomographic material + number_of_materials_defined_by_tomo_file = number_of_materials_defined_by_tomo_file + 1 + + if (number_of_materials_defined_by_tomo_file > 1) & + call stop_the_code( & +'Just one material can be defined by a tomo file for now (we would need to write a nummaterial_velocity_file)') + + ! Assign dummy values for now (they will be read by the solver). Vs must be == 0 for acoustic media anyway + rho_s_read(i) = -1.0d0 + cp(i) = -1.0d0 + cs(i) = val2read + QKappa(i) = -1.0d0 + Qmu(i) = -1.0d0 + aniso3(i) = -1.0d0 + aniso4(i) = -1.0d0 + if (abs(cs(i)) > TINYVAL) then + phi_read(i) = 0.d0 ! elastic + else + phi_read(i) = 1.d0 ! acoustic + endif + + else + ! default + call stop_the_code('Unknown material code') + + endif + + enddo ! nbmodels + + ! user output + write(IMAIN,*) 'Materials:' + write(IMAIN,*) ' Nb of solid, fluid or porous materials = ',nbmodels + write(IMAIN,*) + do i = 1,nbmodels + if (i == 1) write(IMAIN,*) '--------' + if (icodemat(i) == ISOTROPIC_MATERIAL) then + ! isotropic elastic/acoustic + write(IMAIN,*) 'Material #',i,' isotropic' + write(IMAIN,*) 'rho,cp,cs = ',rho_s_read(i),cp(i),cs(i) + write(IMAIN,*) 'Qkappa, Qmu = ',QKappa(i),Qmu(i) + if (cs(i) < TINYVAL) then + write(IMAIN,*) 'Material is fluid' + else + write(IMAIN,*) 'Material is solid' + endif + else if (icodemat(i) == ANISOTROPIC_MATERIAL) then + ! anisotropic + write(IMAIN,*) 'Material #',i,' anisotropic' + write(IMAIN,*) 'rho,cp,cs = ',rho_s_read(i),cp(i),cs(i) + if (AXISYM) then + write(IMAIN,*) 'c11,c13,c15,c33,c35,c55,c12,c23,c25,c22 = ', & + aniso3(i),aniso4(i),aniso5(i),aniso6(i),aniso7(i),aniso8(i), & + aniso9(i),aniso10(i),aniso11(i),aniso12(i) + else + write(IMAIN,*) 'c11,c13,c15,c33,c35,c55,c12,c23,c25 = ', & + aniso3(i),aniso4(i),aniso5(i),aniso6(i),aniso7(i),aniso8(i), & + aniso9(i),aniso10(i),aniso11(i) + write(IMAIN,*) 'QKappa,Qmu = ',QKappa(i),Qmu(i) + endif + else if (icodemat(i) == POROELASTIC_MATERIAL) then + ! poroelastic + write(IMAIN,*) 'Material #',i,' isotropic' + write(IMAIN,*) 'rho_s, kappa_s = ',rho_s_read(i),kappa_s_read(i) + write(IMAIN,*) 'rho_f, kappa_f, eta_f = ',rho_f_read(i),kappa_f_read(i),eta_f_read(i) + write(IMAIN,*) 'phi, tortuosity = ',phi_read(i),tortuosity_read(i) + write(IMAIN,*) 'permxx, permxz, permzz = ',permxx_read(i),permxz_read(i),permzz_read(i) + write(IMAIN,*) 'kappa_fr, mu_fr, Qmu = ',kappa_fr_read(i),mu_fr_read(i),Qmu(i) + write(IMAIN,*) 'Material is porous' + else if (icodemat(i) <= 0) then + write(IMAIN,*) 'Material #',i,' will be read in an external tomography file (TOMOGRAPHY_FILE in Par_file)' + else + call stop_the_code('Unknown material code') + endif + write(IMAIN,*) '--------' + enddo + write(IMAIN,*) + call flush_IMAIN() + + end subroutine read_material_table diff --git a/meshfem2d/read_mesh_files.F90 b/meshfem2d/read_mesh_files.F90 new file mode 100644 index 00000000..bb8092b1 --- /dev/null +++ b/meshfem2d/read_mesh_files.F90 @@ -0,0 +1,340 @@ +!======================================================================== +! +! S P E C F E M 2 D +! ----------------- +! +! Main historical authors: Dimitri Komatitsch and Jeroen Tromp +! CNRS, France +! and Princeton University, USA +! (there are currently many more authors!) +! (c) October 2017 +! +! This software is a computer program whose purpose is to solve +! the two-dimensional viscoelastic anisotropic or poroelastic wave equation +! using a spectral-element method (SEM). +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 3 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License along +! with this program; if not, write to the Free Software Foundation, Inc., +! 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +! +! The full text of the license is available in file "LICENSE". +! +!======================================================================== + +subroutine read_mesh_tangential_curve_file() + +! reads in tangential detection + + use constants, only: IMAIN,myrank + + use part_unstruct_par, only: nnodes_tangential_curve + + use shared_parameters, only: force_normal_to_surface,rec_normal_to_surface,read_external_mesh, & + tangential_detection_curve_file + + implicit none + + ! initializes + nnodes_tangential_curve = 0 + + if (force_normal_to_surface .or. rec_normal_to_surface) then + ! user output + if (myrank == 0) then + write(IMAIN,*) 'Tangential curve:' + call flush_IMAIN() + endif + + ! reads in file + if (read_external_mesh) then + ! reads in specified external file + call read_external_tangential_curve_file(tangential_detection_curve_file) + else + ! safety stop + call stop_the_code('Error read_external_mesh must be set to .true. to use external tangential_dectection_curve_file') + endif + else + ! user output + if (myrank == 0) then + write(IMAIN,*) 'Normals to surface not needed' + write(IMAIN,*) + call flush_IMAIN() + endif + endif + +end subroutine read_mesh_tangential_curve_file + +! +!--------------------------------------------------------------------------------------- +! + +subroutine read_mesh_nodes_coords_from_interfaces() + + use constants, only: IMAIN,IIN_INTERFACES,DONT_IGNORE_JUNK,MAX_STRING_LEN,IN_DATA_FILES, & + ADD_RANDOM_PERTURBATION_TO_THE_MESH,RANDOM_AMPLITUDE_ALONG_X,RANDOM_AMPLITUDE_ALONG_Z, & + ADD_PERTURBATION_AROUND_SOURCE_ONLY,RADIUS_TO_USE_AROUND_THE_SOURCE,myrank + + use part_unstruct_par, only: nodes_coords, & + npoints_interface_top,xinterface_top,zinterface_top,coefs_interface_top, & + nnodes,grid_point_x,grid_point_z + + use source_file_par, only: source_surf,x_source,z_source + + use shared_parameters, only: NGNOD, & + xinterface_coords,zinterface_coords,max_npoints_interface, & + number_of_interfaces,npoints_of_interfaces, & + number_of_layers,nz_layer, & + nxread,nzread,nx_elem_internal,nz_elem_internal, & + NSOURCES,xmin_param,xmax_param, & + PML_BOUNDARY_CONDITIONS,NELEM_PML_THICKNESS + + implicit none + + ! local parameters + integer :: ilayer,ipoint_current,iinterface + integer :: num_node + + integer :: npoints_interface_bottom + double precision, dimension(:), allocatable :: xinterface_bottom,zinterface_bottom,coefs_interface_bottom + + ! to compute the coordinate transformation + integer :: ioffset + double precision :: gamma,absx,a00,a01,bot0,top0,random_value,radius_squared + double precision :: tang1,tangN + + integer :: i_source + integer :: ix,iz + integer :: i,j,ier + + logical :: need_to_add_the_perturbation + + ! external functions + integer, external :: num_4, num_9 + double precision, external :: value_spline + + ! note: at the moment, the mesher can be started in parallel, but basically only rank 0 is doing all the work + ! thus, a lot of arrays haven't been transfered to other processes after reading in the Par_file. + ! this also applies to the interface arrays used here below + + ! user output + if (myrank == 0) then + write(IMAIN,*) + write(IMAIN,*) 'reading node coordinates from interfaces...' + if (ADD_RANDOM_PERTURBATION_TO_THE_MESH) & + write(IMAIN,*) ' using add random perturbation to the mesh node locations' + write(IMAIN,*) + call flush_IMAIN() + endif + + ! safety checks + if (myrank /= 0) & + call stop_the_code('meshing using interfaces for internal models only supported on rank 0 process') + + if (number_of_interfaces < 2) & + call stop_the_code('Number of interfaces < 2, please check') + + ! allocate arrays for the grid + allocate(grid_point_x(0:nx_elem_internal,0:nz_elem_internal)) + allocate(grid_point_z(0:nx_elem_internal,0:nz_elem_internal)) + grid_point_x(:,:) = 0.d0 + grid_point_z(:,:) = 0.d0 + + ! top interface arrays (required also for station locations) + allocate(xinterface_top(max_npoints_interface)) + allocate(zinterface_top(max_npoints_interface)) + xinterface_top(:) = 0.d0 + zinterface_top(:) = 0.d0 + + allocate(coefs_interface_top(max_npoints_interface)) + coefs_interface_top(:) = 0.d0 + + ! temporary arrays + allocate(xinterface_bottom(max_npoints_interface)) + allocate(zinterface_bottom(max_npoints_interface)) + xinterface_bottom(:) = 0.d0 + zinterface_bottom(:) = 0.d0 + + allocate(coefs_interface_bottom(max_npoints_interface)) + coefs_interface_bottom(:) = 0.d0 + + ! first interface (assumed to start from the bottom) + npoints_interface_bottom = npoints_of_interfaces(1) + + ! loop on all the points describing this interface + do ipoint_current = 1,npoints_interface_bottom + xinterface_bottom(ipoint_current) = xinterface_coords(ipoint_current,1) + zinterface_bottom(ipoint_current) = zinterface_coords(ipoint_current,1) + enddo + + ! loop on all the layers + do ilayer = 1,number_of_layers + + ! note: the number of layers should be number_of_interfaces - 1 + iinterface = ilayer + 1 + ! saftey check + if (iinterface > number_of_interfaces) call stop_the_code('Invalid layer index, exceeds number of interfaces') + + ! next interface (after bottom) + npoints_interface_top = npoints_of_interfaces(iinterface) + + ! loop on all the points describing this interface + do ipoint_current = 1,npoints_interface_top + xinterface_top(ipoint_current) = xinterface_coords(ipoint_current,iinterface) + zinterface_top(ipoint_current) = zinterface_coords(ipoint_current,iinterface) + enddo + + ! compute the spline for the bottom interface, impose the tangent on both edges + tang1 = (zinterface_bottom(2)-zinterface_bottom(1)) / (xinterface_bottom(2)-xinterface_bottom(1)) + tangN = (zinterface_bottom(npoints_interface_bottom)-zinterface_bottom(npoints_interface_bottom-1)) / & + (xinterface_bottom(npoints_interface_bottom)-xinterface_bottom(npoints_interface_bottom-1)) + + call spline_construction(xinterface_bottom,zinterface_bottom,npoints_interface_bottom, & + tang1,tangN,coefs_interface_bottom) + + ! compute the spline for the top interface, impose the tangent on both edges + tang1 = (zinterface_top(2)-zinterface_top(1)) / (xinterface_top(2)-xinterface_top(1)) + tangN = (zinterface_top(npoints_interface_top)-zinterface_top(npoints_interface_top-1)) / & + (xinterface_top(npoints_interface_top)-xinterface_top(npoints_interface_top-1)) + + call spline_construction(xinterface_top,zinterface_top,npoints_interface_top, & + tang1,tangN,coefs_interface_top) + +!daniel todo: check if we need to move this ... deals with placing sources at the surface +! but, in principle we want the sources to be located only in the solver. +! by that, we would separate mesher/solver more properly and allow to run only the solver when sources change. +! + ! check if we are in the last layer, which contains topography, + ! and modify the position of the source accordingly if it is located exactly at the surface + do i_source = 1,NSOURCES + if (source_surf(i_source) .and. ilayer == number_of_layers) then + ! user output + write(IMAIN,*) 'source ', i_source + write(IMAIN,*) ' target (input) z: ', z_source(i_source) + + z_source(i_source) = value_spline(x_source(i_source),xinterface_top,zinterface_top, & + coefs_interface_top,npoints_interface_top) + + write(IMAIN,*) ' surface (actual) z: ', z_source(i_source) + endif + enddo + + ! compute the offset of this layer in terms of number of spectral elements below along Z + if (ilayer > 1) then + ioffset = sum(nz_layer(1:ilayer-1)) + else + ioffset = 0 + endif + + !--- definition of the mesh + + do ix = 0,nx_elem_internal + + ! evenly spaced points along X + absx = xmin_param + (xmax_param - xmin_param) * dble(ix) / dble(nx_elem_internal) + + ! value of the bottom and top splines + bot0 = value_spline(absx,xinterface_bottom,zinterface_bottom,coefs_interface_bottom,npoints_interface_bottom) + top0 = value_spline(absx,xinterface_top,zinterface_top,coefs_interface_top,npoints_interface_top) + + do iz = 0,nz_layer(ilayer) + + ! linear interpolation between bottom and top + gamma = dble(iz) / dble(nz_layer(ilayer)) + a00 = 1.d0 - gamma + a01 = gamma + + ! coordinates of the grid points + grid_point_x(ix,iz + ioffset) = absx + grid_point_z(ix,iz + ioffset) = a00*bot0 + a01*top0 + + ! add a random perturbation to the mesh if needed + if (ADD_RANDOM_PERTURBATION_TO_THE_MESH) then + + need_to_add_the_perturbation = .true. + + ! do not make any modification on the outer edges of the mesh (fictitious outer edges, and free surface) + if ((ilayer == 1 .and. iz == 0) & + .or. (ilayer == number_of_layers .and. iz == nz_layer(ilayer)) & + .or. ix == 0 .or. ix == nx_elem_internal) need_to_add_the_perturbation = .false. + + ! do not make any modification inside the PML layers + if (PML_BOUNDARY_CONDITIONS) then + ! this works only if the whole bottom PML is comprised inside the bottom layer + if (ilayer == 1 .and. iz <= NELEM_PML_THICKNESS) need_to_add_the_perturbation = .false. + if (ix <= NELEM_PML_THICKNESS) need_to_add_the_perturbation = .false. + if (ix > nx_elem_internal - NELEM_PML_THICKNESS - 1) need_to_add_the_perturbation = .false. + endif + + ! apply the perturbation in a disk around the source only + ! for simplicity here we assume that there is a single source + if (ADD_PERTURBATION_AROUND_SOURCE_ONLY) then + ! safety check + if (NSOURCES < 1) call stop_the_code('Invalid number of sources for ADD_PERTURBATION_AROUND_SOURCE_ONLY') + radius_squared = (grid_point_x(ix,iz + ioffset) - x_source(1))**2 & + + (grid_point_z(ix,iz + ioffset) - z_source(1))**2 + if (radius_squared > RADIUS_TO_USE_AROUND_THE_SOURCE**2) need_to_add_the_perturbation = .false. + endif + + if (need_to_add_the_perturbation) then + ! get a random number between 0. and 1. + call random_number(random_value) + ! map this random number to between -1. and +1., so that the point can be moved to the left or to the right + grid_point_x(ix,iz + ioffset) = grid_point_x(ix,iz + ioffset) + & + RANDOM_AMPLITUDE_ALONG_X * 2.d0 * (random_value - 0.5d0) + call random_number(random_value) + grid_point_z(ix,iz + ioffset) = grid_point_z(ix,iz + ioffset) + & + RANDOM_AMPLITUDE_ALONG_Z * 2.d0 * (random_value - 0.5d0) + endif + + endif + + enddo + + enddo + + ! the top interface becomes the bottom interface before switching to the next layer + npoints_interface_bottom = npoints_interface_top + xinterface_bottom(:) = xinterface_top(:) + zinterface_bottom(:) = zinterface_top(:) + + enddo + + deallocate(xinterface_bottom,zinterface_bottom,coefs_interface_bottom) + + ! sets node coordinates + nnodes = (nz_elem_internal+1)*(nx_elem_internal+1) + + allocate(nodes_coords(2,nnodes),stat=ier) + if (ier /= 0) call stop_the_code('Error allocating nodes_coords array') + nodes_coords(:,:) = 0.d0 + + if (NGNOD == 4) then + do j = 0, nz_elem_internal + do i = 0, nx_elem_internal + num_node = num_4(i,j,nxread) + nodes_coords(1, num_node) = grid_point_x(i,j) + nodes_coords(2, num_node) = grid_point_z(i,j) + enddo + enddo + else if (NGNOD == 9) then + do j = 0, nz_elem_internal + do i = 0, nx_elem_internal + num_node = num_9(i,j,nxread,nzread) + nodes_coords(1, num_node) = grid_point_x(i,j) + nodes_coords(2, num_node) = grid_point_z(i,j) + enddo + enddo + else + call stop_the_code('NGNOD should be either 4 or 9') + endif + +end subroutine read_mesh_nodes_coords_from_interfaces diff --git a/meshfem2d/read_parameter_file.F90 b/meshfem2d/read_parameter_file.F90 new file mode 100644 index 00000000..ca89843f --- /dev/null +++ b/meshfem2d/read_parameter_file.F90 @@ -0,0 +1,872 @@ +!======================================================================== +! +! S P E C F E M 2 D +! ----------------- +! +! Main historical authors: Dimitri Komatitsch and Jeroen Tromp +! CNRS, France +! and Princeton University, USA +! (there are currently many more authors!) +! (c) October 2017 +! +! This software is a computer program whose purpose is to solve +! the two-dimensional viscoelastic anisotropic or poroelastic wave equation +! using a spectral-element method (SEM). +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 3 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License along +! with this program; if not, write to the Free Software Foundation, Inc., +! 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +! +! The full text of the license is available in file "LICENSE". +! +!======================================================================== + +subroutine read_parameter_file(imesher,BROADCAST_AFTER_READ) + +! reads in DATA/Par_file + + use constants, only: IMAIN,myrank + use shared_parameters + + implicit none + + integer, intent(in) :: imesher + logical, intent(in) :: BROADCAST_AFTER_READ + + ! initializes + call read_parameter_file_init() + + ! only main process reads in Par_file + if (myrank == 0) then + + ! user output + write(IMAIN,*) 'Reading the parameter file...' + write(IMAIN,*) + call flush_IMAIN() + + ! opens file Par_file + call open_parameter_file() + + ! reads only parameters (without receiver-line section, material tables or region definitions) + call read_parameter_file_only() + + ! user output + write(IMAIN,*) 'Title of the simulation: ',trim(title) + write(IMAIN,*) + call flush_IMAIN() + + ! reads receiver lines + if (imesher == 1) then + ! user output + write(IMAIN,*) 'Receiver lines:' + write(IMAIN,*) ' Nb of line sets = ',nreceiversets + write(IMAIN,*) + call flush_IMAIN() + endif + call read_parameter_file_receiversets() + + ! only mesher needs to reads this + if (imesher == 1) then + ! reads material definitions + call read_material_table() + + ! mesher reads in internal region table for setting up mesh elements + if (.not. read_external_mesh) then + ! internal meshing + ! user output + write(IMAIN,*) + write(IMAIN,*) 'Mesh from internal meshing:' + write(IMAIN,*) + call flush_IMAIN() + + ! reads interface definitions from interface file (we need to have nxread & nzread value for checking regions) + call read_interfaces_file() + + ! internal meshing + nx_elem_internal = nxread + nz_elem_internal = nzread + + ! setup mesh array + ! multiply by 2 if elements have 9 nodes + if (NGNOD == 9) then + nx_elem_internal = nx_elem_internal * 2 + nz_elem_internal = nz_elem_internal * 2 + nz_layer(:) = nz_layer(:) * 2 + endif + + ! total number of elements + nelmnts = nxread * nzread + + ! reads material regions defined in Par_file + call read_regions() + endif + endif + + ! closes file Par_file + call close_parameter_file() + endif + + ! main process broadcasts to all + ! note: this is only needed at the moment for the solver to setup a simulation run + if (BROADCAST_AFTER_READ) then + + call bcast_all_singlei(NPROC) + call bcast_all_singlei(PARTITIONING_TYPE) + call bcast_all_singlei(NGNOD) + + ! receivers + call bcast_all_singlel(use_existing_STATIONS) + call bcast_all_singlei(nreceiversets) + call bcast_all_singledp(anglerec) + call bcast_all_singlel(rec_normal_to_surface) + + ! velocity and density models + call bcast_all_singlei(nbmodels) + call bcast_all_string(TOMOGRAPHY_FILE) + call bcast_all_singlel(read_external_mesh) + + if (read_external_mesh) then + call bcast_all_string(mesh_file) + call bcast_all_string(nodes_coords_file) + call bcast_all_string(materials_file) + call bcast_all_string(free_surface_file) + call bcast_all_string(axial_elements_file) + call bcast_all_string(absorbing_surface_file) + call bcast_all_string(acoustic_forcing_surface_file) + call bcast_all_string(absorbing_cpml_file) + call bcast_all_string(tangential_detection_curve_file) + else + call bcast_all_string(interfaces_filename) + call bcast_all_singledp(xmin_param) + call bcast_all_singledp(xmax_param) + call bcast_all_singlei(nx_param) + + call bcast_all_singlel(absorbbottom) + call bcast_all_singlel(absorbright) + call bcast_all_singlel(absorbtop) + call bcast_all_singlel(absorbleft) + call bcast_all_singlei(nbregions) + endif + endif + + ! user output + if (myrank == 0) then + write(IMAIN,*) 'Parameter file successfully read ' + write(IMAIN,*) + call flush_IMAIN() + endif + +end subroutine read_parameter_file + +! +!------------------------------------------------------------------------------------------------- +! + +subroutine read_parameter_file_init() + +! initializes the variables + + use shared_parameters + + implicit none + + ! external meshing + mesh_file = '' + nodes_coords_file = '' + materials_file = '' + free_surface_file = '' + axial_elements_file = '' + absorbing_surface_file = '' + acoustic_forcing_surface_file = '' + absorbing_cpml_file = '' + tangential_detection_curve_file = '' + + ! internal meshing + interfaces_filename = '' + xmin_param = 0.d0 + xmax_param = 0.d0 + nx_param = 0 + + absorbbottom = .false. + absorbright = .false. + absorbtop = .false. + absorbleft = .false. + + nbregions = 0 + +end subroutine read_parameter_file_init + +! +!------------------------------------------------------------------------------------------------- +! + +subroutine read_parameter_file_only() + +! reads only parameters without receiver-line section and material tables + + use constants, only: IMAIN,myrank + use shared_parameters + + implicit none + + ! local parameters + integer :: i,irange + logical :: some_parameters_missing_from_Par_file + + integer, external :: err_occurred + +!! DK DK to detect discontinued parameters + double precision :: f0_attenuation + + !-------------------------------------------------------------------- + ! + ! simulation input parameters + ! + !-------------------------------------------------------------------- + + some_parameters_missing_from_Par_file = .false. + + ! read file names and path for output + call read_value_string_p(title, 'title') + if (err_occurred() /= 0) then + some_parameters_missing_from_Par_file = .true. + write(*,'(a)') 'title = Title of my simulation' + write(*,*) + endif + + ! read info about partitioning + call read_value_integer_p(NPROC, 'NPROC') + if (err_occurred() /= 0) then + some_parameters_missing_from_Par_file = .true. + write(*,'(a)') 'NPROC = 1' + write(*,*) + endif + + call read_value_string_p(OUTPUT_FILES, 'OUTPUT_FILES') + if (err_occurred() /= 0) then + some_parameters_missing_from_Par_file = .true. + write(*,'(a)') 'OUTPUT_FILES = ./OUTPUT_FILES' + write(*,*) + endif + call create_directory_if_doesnt_exist(OUTPUT_FILES) + + ! deprecated: call read_value_integer_p(partitioning_method, 'partitioning_method') + call read_value_integer_p(PARTITIONING_TYPE, 'PARTITIONING_TYPE') + if (err_occurred() /= 0) then + ! old version + call read_value_integer_p(PARTITIONING_TYPE, 'partitioning_method') + if (err_occurred() == 0) then + ! deprecation warning + write(*,'(a)') 'Warning: Deprecated parameter partitioning_method found in Par_file.' + write(*,'(a)') ' Please use parameter PARTITIONING_TYPE in future...' + else + some_parameters_missing_from_Par_file = .true. + write(*,'(a)') 'PARTITIONING_TYPE = 3' + write(*,*) + endif + endif + + ! deprecated: call read_value_integer_p(ngnod, 'ngnod') + call read_value_integer_p(NGNOD, 'NGNOD') + if (err_occurred() /= 0) then + ! old version + call read_value_integer_p(NGNOD, 'ngnod') + if (err_occurred() == 0) then + ! deprecation warning + write(*,'(a)') 'Warning: Deprecated parameter ngnod found in Par_file.' + write(*,'(a)') ' Please use parameter NGNOD in future...' + else + some_parameters_missing_from_Par_file = .true. + write(*,'(a)') 'NGNOD = 9' + write(*,*) + endif + endif + + call read_value_string_p(database_filename, 'database_filename') + if (err_occurred() /= 0) then + some_parameters_missing_from_Par_file = .true. + write(*,'(a)') 'database_filename = ./DATA/database' + write(*,*) + endif + + !-------------------------------------------------------------------- + ! + ! receivers + ! + !-------------------------------------------------------------------- + + call read_value_logical_p(use_existing_STATIONS, 'use_existing_STATIONS') + if (err_occurred() /= 0) then + some_parameters_missing_from_Par_file = .true. + write(*,'(a)') 'use_existing_STATIONS = .false.' + write(*,*) + endif + + call read_value_integer_p(nreceiversets, 'nreceiversets') + if (err_occurred() /= 0) then + some_parameters_missing_from_Par_file = .true. + write(*,'(a)') 'nreceiversets = 1' + write(*,*) + endif + + call read_value_double_precision_p(anglerec, 'anglerec') + if (err_occurred() /= 0) then + some_parameters_missing_from_Par_file = .true. + write(*,'(a)') 'anglerec = 0.d0' + write(*,*) + endif + + call read_value_logical_p(rec_normal_to_surface, 'rec_normal_to_surface') + if (err_occurred() /= 0) then + some_parameters_missing_from_Par_file = .true. + write(*,'(a)') 'rec_normal_to_surface = .false.' + write(*,*) + endif + + call read_value_string_p(stations_filename, 'stations_filename') + if (err_occurred() /= 0) then + some_parameters_missing_from_Par_file = .true. + write(*,'(a)') 'stations_filename = ./DATA/STATIONS' + write(*,*) + endif + + ! receiver sets will be read in later... + + !-------------------------------------------------------------------- + ! + ! velocity and density models + ! + !-------------------------------------------------------------------- + + ! read the different material materials (i.e. the number of models) + call read_value_integer_p(nbmodels, 'nbmodels') + if (err_occurred() /= 0) then + some_parameters_missing_from_Par_file = .true. + write(*,'(a)') 'nbmodels = 1' + write(*,*) + endif + + ! material definitions will be read later on... + + call read_value_string_p(TOMOGRAPHY_FILE, 'TOMOGRAPHY_FILE') + if (err_occurred() /= 0) then + some_parameters_missing_from_Par_file = .true. + write(*,'(a)') 'TOMOGRAPHY_FILE = ./DATA/tomo_file.xyz' + write(*,*) + endif + + ! boolean defining whether internal or external mesh + call read_value_logical_p(read_external_mesh, 'read_external_mesh') + if (err_occurred() /= 0) then + some_parameters_missing_from_Par_file = .true. + write(*,'(a)') 'read_external_mesh = .false.' + write(*,*) + endif + + !-------------------------------------------------------------------- + ! + ! parameters external / internal meshing + ! + !-------------------------------------------------------------------- + + !----------------- + ! external mesh parameters + + if (read_external_mesh) then + + ! read info about external mesh + call read_value_string_p(mesh_file, 'mesh_file') + if (err_occurred() /= 0) then + some_parameters_missing_from_Par_file = .true. + write(*,'(a)') 'mesh_file = ./DATA/mesh_file' + write(*,*) + endif + + call read_value_string_p(nodes_coords_file, 'nodes_coords_file') + if (err_occurred() /= 0) then + some_parameters_missing_from_Par_file = .true. + write(*,'(a)') 'nodes_coords_file = ./DATA/nodes_coords_file' + write(*,*) + endif + + call read_value_string_p(materials_file, 'materials_file') + if (err_occurred() /= 0) then + some_parameters_missing_from_Par_file = .true. + write(*,'(a)') 'materials_file = ./DATA/materials_file' + write(*,*) + endif + + call read_value_string_p(free_surface_file, 'free_surface_file') + if (err_occurred() /= 0) then + some_parameters_missing_from_Par_file = .true. + write(*,'(a)') 'free_surface_file = ./DATA/free_surface_file' + write(*,*) + endif + + call read_value_string_p(axial_elements_file, 'axial_elements_file') + if (err_occurred() /= 0) then + some_parameters_missing_from_Par_file = .true. + write(*,'(a)') 'axial_elements_file = ./DATA/axial_elements_file' + write(*,*) + endif + + call read_value_string_p(absorbing_surface_file, 'absorbing_surface_file') + if (err_occurred() /= 0) then + some_parameters_missing_from_Par_file = .true. + write(*,'(a)') 'absorbing_surface_file = ./DATA/absorbing_surface_file' + write(*,*) + endif + + call read_value_string_p(acoustic_forcing_surface_file, 'acoustic_forcing_surface_file') + if (err_occurred() /= 0) then + some_parameters_missing_from_Par_file = .true. + write(*,'(a)') 'acoustic_forcing_surface_file = ./DATA/MSH/Surf_acforcing_Bottom_enforcing_mesh' + write(*,*) + endif + + call read_value_string_p(absorbing_cpml_file, 'absorbing_cpml_file') + if (err_occurred() /= 0) then + some_parameters_missing_from_Par_file = .true. + write(*,'(a)') 'absorbing_cpml_file = ./DATA/absorbing_cpml_file' + write(*,*) + endif + + call read_value_string_p(tangential_detection_curve_file, 'tangential_detection_curve_file') + if (err_occurred() /= 0) then + some_parameters_missing_from_Par_file = .true. + write(*,'(a)') 'tangential_detection_curve_file = ./DATA/courbe_eros_nodes' + write(*,*) + endif + + else + + !----------------- + ! internal mesh parameters + + ! interfaces file + call read_value_string_p(interfaces_filename, 'interfacesfile') + if (err_occurred() /= 0) then + some_parameters_missing_from_Par_file = .true. + write(*,'(a)') 'interfaces_file = DATA/interfaces_simple_topo_curved.dat' + write(*,*) + endif + + ! read grid parameters + call read_value_double_precision_p(xmin_param, 'xmin') + if (err_occurred() /= 0) then + some_parameters_missing_from_Par_file = .true. + write(*,'(a)') 'xmin = 0.d0' + write(*,*) + endif + + call read_value_double_precision_p(xmax_param, 'xmax') + if (err_occurred() /= 0) then + some_parameters_missing_from_Par_file = .true. + write(*,'(a)') 'xmax = 4000.d0' + write(*,*) + endif + + call read_value_integer_p(nx_param, 'nx') + if (err_occurred() /= 0) then + some_parameters_missing_from_Par_file = .true. + write(*,'(a)') 'nx = 80' + write(*,*) + endif + + ! read absorbing boundary parameters + call read_value_logical_p(absorbbottom, 'absorbbottom') + if (err_occurred() /= 0) then + some_parameters_missing_from_Par_file = .true. + write(*,'(a)') 'absorbbottom = .true.' + write(*,*) + endif + + call read_value_logical_p(absorbright, 'absorbright') + if (err_occurred() /= 0) then + some_parameters_missing_from_Par_file = .true. + write(*,'(a)') 'absorbright = .true.' + write(*,*) + endif + + call read_value_logical_p(absorbtop, 'absorbtop') + if (err_occurred() /= 0) then + some_parameters_missing_from_Par_file = .true. + write(*,'(a)') 'absorbtop = .false.' + write(*,*) + endif + + call read_value_logical_p(absorbleft, 'absorbleft') + if (err_occurred() /= 0) then + some_parameters_missing_from_Par_file = .true. + write(*,'(a)') 'absorbleft = .true.' + write(*,*) + endif + + call read_value_integer_p(nbregions, 'nbregions') + if (err_occurred() /= 0) then + some_parameters_missing_from_Par_file = .true. + write(*,'(a)') 'nbregions = 1' + write(*,*) + endif +! note: if internal mesh, then region tables will be read in by read_regions (from meshfem2D) + endif + + !-------------------------------------------------------------------- + ! Display parameters + !-------------------------------------------------------------------- + + call read_value_logical_p(output_grid_Gnuplot, 'output_grid_Gnuplot') + call read_value_logical_p(output_grid_ASCII, 'output_grid_ASCII') + + + + if (some_parameters_missing_from_Par_file) then + write(*,*) + write(*,*) 'All the above parameters are missing from your Par_file.' + write(*,*) 'Please cut and paste them somewhere in your Par_file (any place is fine), change their values if needed' + write(*,*) '(the above values are just default values), and restart your run.' + write(*,*) + call stop_the_code('Error: some parameters are missing in your Par_file, it is incomplete or in an older format, & + &see at the end of the standard output file of the run for detailed and easy instructions about how to fix that') + endif + + !-------------------------------------------------------------------- + + ! converts all string characters to lowercase + irange = iachar('a') - iachar('A') + do i = 1,len_trim(MODEL) + if (lge(MODEL(i:i),'A') .and. lle(MODEL(i:i),'Z')) then + MODEL(i:i) = achar(iachar(MODEL(i:i)) + irange) + endif + enddo + do i = 1,len_trim(SAVE_MODEL) + if (lge(SAVE_MODEL(i:i),'A') .and. lle(SAVE_MODEL(i:i),'Z')) then + SAVE_MODEL(i:i) = achar(iachar(SAVE_MODEL(i:i)) + irange) + endif + enddo + + ! checks input parameters + call check_parameters() + +end subroutine read_parameter_file_only + +! +!------------------------------------------------------------------------------------------------- +! + +subroutine check_parameters() + + use shared_parameters + + implicit none + + ! checks partitioning + if (NPROC <= 0) then + print *, 'Error: Number of processes (NPROC) must be greater than or equal to one.' + call stop_the_code('Error invalid NPROC value') + endif + +#ifndef WITH_MPI + if (NPROC > 1) then + print *, 'Error: Number of processes (NPROC) must be equal to one when not using MPI.' + print *, 'Please recompile with -DWITH_MPI in order to enable use of MPI.' + call stop_the_code('Error invalid NPROC value') + endif +#endif + + if (PARTITIONING_TYPE /= 1 .and. PARTITIONING_TYPE /= 3) then + print *, 'Error: Invalid partitioning method number.' + print *, 'Partitioning type ',PARTITIONING_TYPE,' was requested, but is not available.' + print *, 'Support for the METIS graph partitioner has been discontinued, please use SCOTCH (option 3) instead.' + call stop_the_code('Error invalid partitioning method') + endif + + if (NGNOD /= 4 .and. NGNOD /= 9) & + call stop_the_code('NGNOD should be either 4 or 9!') + + ! reads in material definitions + if (nbmodels <= 0) & + call stop_the_code('Non-positive number of materials not allowed!') + + ! check regions + if (read_external_mesh .eqv. .false.) then + if (nbregions <= 0) call stop_the_code('Negative number of regions not allowed for internal meshing!') + endif + +end subroutine check_parameters + +! +!------------------------------------------------------------------------------------------------- +! + +subroutine read_parameter_file_receiversets() + + use constants, only: IMAIN,IIN,IN_DATA_FILES,mygroup + + use shared_parameters + + implicit none + + ! local parameters + integer :: ireceiverlines,ier,nrec + logical :: reread_rec_normal_to_surface + character(len=MAX_STRING_LEN) :: path_to_add,dummystring + + integer,external :: err_occurred + + ! re-reads rec_normal_to_surface parameter to reposition read header for following next-line reads + call read_value_logical_p(reread_rec_normal_to_surface, 'rec_normal_to_surface') + if (err_occurred() /= 0) call stop_the_code('error reading parameter rec_normal_to_surface in Par_file') + + ! checks + if (reread_rec_normal_to_surface .neqv. rec_normal_to_surface) & + call stop_the_code('Invalid re-reading of rec_normal_to_surface parameter') + + ! reads in receiver sets + if (use_existing_STATIONS) then + ! checks if STATIONS file exisits + + ! adds specific run folder to path + ! for example: run0001/DATA/STATIONS + if (NUMBER_OF_SIMULTANEOUS_RUNS > 1 .and. mygroup >= 0) then + write(path_to_add,"('run',i4.4,'/')") mygroup + 1 + stations_filename = path_to_add(1:len_trim(path_to_add))//stations_filename(1:len_trim(stations_filename)) + endif + + ! user output + write(IMAIN,*) ' using existing STATIONS file: ',trim(stations_filename) + call flush_IMAIN() + + ! counts entries + open(unit=IIN,file=trim(stations_filename),status='old',action='read',iostat=ier) + if (ier /= 0 ) then + print *, 'Error could not open existing STATIONS file:',trim(stations_filename) + print *, 'Please check if file exists.' + call stop_the_code('Error opening STATIONS file') + endif + + nrec = 0 + do while(ier == 0) + read(IIN,"(a)",iostat=ier) dummystring + if (ier == 0) then + ! skip empty lines + if (len_trim(dummystring) == 0) cycle + + ! skip comment lines + dummystring = adjustl(dummystring) + if (dummystring(1:1) == "#") cycle + + ! increase counter + nrec = nrec + 1 + endif + enddo + close(IIN) + + write(IMAIN,*) ' file name is ',trim(stations_filename) + write(IMAIN,*) ' found ',nrec,' receivers' + write(IMAIN,*) + + else + ! receiver lines specified in Par_file + ! only valid if at least 1 receiver line is specified + if (nreceiversets < 1) & + call stop_the_code('number of receiver sets must be greater than 1') + + ! allocate receiver line arrays + allocate(nrec_line(nreceiversets)) + allocate(xdeb(nreceiversets)) + allocate(zdeb(nreceiversets)) + allocate(xfin(nreceiversets)) + allocate(zfin(nreceiversets)) + allocate(record_at_surface_same_vertical(nreceiversets),stat=ier) + if (ier /= 0 ) call stop_the_code('Error allocating receiver lines') + + nrec_line(:) = 0 + xdeb(:) = 0.d0 + zdeb(:) = 0.d0 + xfin(:) = 0.d0 + zfin(:) = 0.d0 + record_at_surface_same_vertical(:) = .false. + + ! loop on all the receiver lines + do ireceiverlines = 1,nreceiversets + call read_value_integer_next_p(nrec_line(ireceiverlines),'nrec') + if (err_occurred() /= 0) call stop_the_code('error reading parameter nrec in Par_file') + + call read_value_double_prec_next_p(xdeb(ireceiverlines),'xdeb') + if (err_occurred() /= 0) call stop_the_code('error reading parameter xdeb in Par_file') + + call read_value_double_prec_next_p(zdeb(ireceiverlines),'zdeb') + if (err_occurred() /= 0) call stop_the_code('error reading parameter zdeb in Par_file') + + call read_value_double_prec_next_p(xfin(ireceiverlines),'xfin') + if (err_occurred() /= 0) call stop_the_code('error reading parameter xfin in Par_file') + + call read_value_double_prec_next_p(zfin(ireceiverlines),'zfin') + if (err_occurred() /= 0) call stop_the_code('error reading parameter zfin in Par_file') + + call read_value_logical_next_p(record_at_surface_same_vertical(ireceiverlines),'record_at_surface_same_vertical') + if (err_occurred() /= 0) call stop_the_code('error reading parameter record_at_surface_same_vertical in Par_file') + + if (read_external_mesh .and. record_at_surface_same_vertical(ireceiverlines)) then + call stop_the_code('Cannot use record_at_surface_same_vertical with external meshes!') + endif + enddo + endif + +end subroutine read_parameter_file_receiversets + +! +!------------------------------------------------------------------------------------------------- +! + +subroutine read_parameter_file_derive_flags() + + use shared_parameters + + implicit none + + ! derives additional flags based on input parameters + + ! sets overal Bielak flag + add_Bielak_conditions = add_Bielak_conditions_bottom .or. add_Bielak_conditions_right .or. & + add_Bielak_conditions_top .or. add_Bielak_conditions_left + + ! boundary conditions + if (add_Bielak_conditions .and. .not. STACEY_ABSORBING_CONDITIONS) & + call stop_the_code('need STACEY_ABSORBING_CONDITIONS set to .true. in order to use add_Bielak_conditions') + + ! solve the conflict in value of PML_BOUNDARY_CONDITIONS and STACEY_ABSORBING_CONDITIONS + if (PML_BOUNDARY_CONDITIONS) any_abs = .true. + if (STACEY_ABSORBING_CONDITIONS) any_abs = .true. + + ! initializes flags for absorbing boundaries + if (.not. any_abs) then + absorbbottom = .false. + absorbright = .false. + absorbtop = .false. + absorbleft = .false. + endif + + ! can use only one point to display lower-left corner only for interpolated snapshot + if (pointsdisp < 3) then + pointsdisp = 3 + plot_lowerleft_corner_only = .true. + else + plot_lowerleft_corner_only = .false. + endif + +end subroutine read_parameter_file_derive_flags + +! +!------------------------------------------------------------------------------------------------- +! + +subroutine open_parameter_file_from_main_only() + + use constants, only: MAX_STRING_LEN,IN_DATA_FILES + + implicit none + + character(len=MAX_STRING_LEN) :: filename_main,filename_run0001 + logical :: exists_main_Par_file,exists_run0001_Par_file + integer :: ier + + filename_main = IN_DATA_FILES(1:len_trim(IN_DATA_FILES))//'Par_file' + +! also see if we are running several independent runs in parallel +! to do so, add the right directory for that run for the main process only here + filename_run0001 = 'run0001/'//filename_main(1:len_trim(filename_main)) + call param_open(filename_main, len(filename_main), ier) + if (ier == 0) then + exists_main_Par_file = .true. + call close_parameter_file() + else + exists_main_Par_file = .false. + endif + call param_open(filename_run0001, len(filename_run0001), ier) + if (ier == 0) then + exists_run0001_Par_file = .true. + call close_parameter_file() + else + exists_run0001_Par_file = .false. + endif + + !if (exists_main_Par_file .and. exists_run0001_Par_file) then ! TODO why is it like that in the 3D version?? + ! print * + ! print *,'cannot have both DATA/Par_file and run0001/DATA/Par_file present, please remove one of them' + ! stop 'error: two different copies of the Par_file' + !endif + + call param_open(filename_main, len(filename_main), ier) + if (ier /= 0) then + call param_open(filename_run0001, len(filename_run0001), ier) + if (ier /= 0) then + print * + print *,'opening file failed, please check your file path and run-directory.' + call stop_the_code('error opening Par_file') + endif + endif + +end subroutine open_parameter_file_from_main_only + +! +!------------------------------------------------------------------------------------------------- +! + +subroutine open_parameter_file() + + use constants, only: MAX_STRING_LEN,mygroup,IN_DATA_FILES + use shared_parameters, only: NUMBER_OF_SIMULTANEOUS_RUNS, Par_File + + implicit none + + integer ierr + common /param_err_common/ ierr + character(len=MAX_STRING_LEN) filename,path_to_add + + ! Par_file filename with path + filename = Par_File + + ! see if we are running several independent runs in parallel + ! if so, add the right directory for that run + ! (group numbers start at zero, but directory names start at run0001, thus we add one) + ! + ! a negative value for "mygroup" is a convention that indicates that groups (i.e. sub-communicators, one per run) are off + if (NUMBER_OF_SIMULTANEOUS_RUNS > 1 .and. mygroup >= 0) then + write(path_to_add,"('run',i4.4,'/')") mygroup + 1 + filename = path_to_add(1:len_trim(path_to_add))//filename(1:len_trim(filename)) + endif + + ! to use c routines for reading/parsing file content + call param_open(filename, len_trim(filename), ierr) + if (ierr /= 0) then + print * + print *,'opening file failed, please check your file path and run-directory.' + call stop_the_code('error opening Par_file') + endif + +end subroutine open_parameter_file + +! +!------------------------------------------------------------------------------------------------- +! + +subroutine close_parameter_file() + + implicit none + + ! to use C routines + call param_close() + +end subroutine close_parameter_file diff --git a/meshfem2d/read_regions.f90 b/meshfem2d/read_regions.f90 new file mode 100644 index 00000000..9b1d46c7 --- /dev/null +++ b/meshfem2d/read_regions.f90 @@ -0,0 +1,196 @@ +!======================================================================== +! +! S P E C F E M 2 D +! ----------------- +! +! Main historical authors: Dimitri Komatitsch and Jeroen Tromp +! CNRS, France +! and Princeton University, USA +! (there are currently many more authors!) +! (c) October 2017 +! +! This software is a computer program whose purpose is to solve +! the two-dimensional viscoelastic anisotropic or poroelastic wave equation +! using a spectral-element method (SEM). +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 3 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License along +! with this program; if not, write to the Free Software Foundation, Inc., +! 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +! +! The full text of the license is available in file "LICENSE". +! +!======================================================================== + + subroutine read_regions() + +! reads in material definitions in DATA/Par_file and outputs to num_material + + use constants, only: IMAIN,ANISOTROPIC_MATERIAL,POROELASTIC_MATERIAL,TINYVAL,myrank + + use shared_parameters, only: nbregions,nbmodels,num_material,icodemat, & + cp,cs, & + rho_s_read,QKappa,Qmu, & + aniso3,aniso4,aniso5,aniso6,aniso7,aniso8,aniso9,aniso10,aniso11, & + nelmnts,nxread,nzread + + implicit none + + ! local parameters + integer :: iregion,ix_start,ix_end,iz_start,iz_end,imaterial_number + integer :: i,j,ielem,ier + integer :: reread_nbregions + double precision :: vpregion,vsregion,poisson_ratio + logical :: is_overwriting + integer :: id_already_set + + integer,external :: err_occurred + + ! safety check + ! only main process is supposed to read in file parameters + if (myrank /= 0) call stop_the_code('Only main process should read regions, exiting...') + + ! user output + write(IMAIN,*) 'Regions:' + write(IMAIN,*) ' Nb of regions in the mesh = ',nbregions + write(IMAIN,*) + + ! assigns materials to mesh elements + allocate(num_material(nelmnts),stat=ier) + if (ier /= 0) call stop_the_code('Error allocating num_material array') + num_material(:) = 0 + + ! this call positions again the read header to the line with nbregions. we can then call next line to get the table + call read_value_integer_p(reread_nbregions, 'mesher.nbregions') + if (err_occurred() /= 0) call stop_the_code('Error reading parameter nbregions in Par_file') + + ! checks + if (reread_nbregions /= nbregions) call stop_the_code('Error re-reading parameter nbregions in Par_file') + if (nbmodels < 1) call stop_the_code('Invalid number of model definitions') + + ! read the material numbers for each region + do iregion = 1,nbregions + + ! reads in region range + ! format: #ix_start #ix_end #iz_start #iz_end #imaterial_number + call read_region_coordinates_p(ix_start,ix_end,iz_start,iz_end,imaterial_number) + + ! check + if (imaterial_number < 1) call stop_the_code('Negative material number not allowed!') + if (ix_start < 1) call stop_the_code('Left coordinate of region negative!') + if (ix_end > nxread) call stop_the_code('Right coordinate of region too high!') + if (iz_start < 1) call stop_the_code('Bottom coordinate of region negative!') + if (iz_end > nzread) call stop_the_code('Top coordinate of region too high!') + + if (iregion == 1) write(IMAIN,*) '------' + write(IMAIN,*) 'Region ',iregion + write(IMAIN,*) 'IX from ',ix_start,' to ',ix_end + write(IMAIN,*) 'IZ from ',iz_start,' to ',iz_end + + ! note on supported model formats: + ! acoustic - model_number 1 rho Vp 0 0 0 QKappa Qmu 0 0 0 0 0 0 + ! elastic - model_number 1 rho Vp Vs 0 0 QKappa Qmu 0 0 0 0 0 0 + ! anisotropic - model_number 2 rho c11 c13 c15 c33 c35 c55 c12 c23 c25 0 QKappa Qmu + ! anisotropic (in AXISYM) - model_number 2 rho c11 c13 c15 c33 c35 c55 c12 c23 c25 c22 QKappa Qmu + ! poroelastic - model_number 3 rhos rhof phi c kxx kxz kzz Ks Kf Kfr etaf mufr Qmu + ! tomo - model_number -1 0 0 A 0 0 0 0 0 0 0 0 0 0 + ! + ! in particular, icodemat(imaterial_number) can be negative for tomographic models + + ! determines region domain + if (icodemat(imaterial_number) /= ANISOTROPIC_MATERIAL .and. icodemat(imaterial_number) /= POROELASTIC_MATERIAL) then + ! isotropic material + vpregion = cp(imaterial_number) + vsregion = cs(imaterial_number) + + write(IMAIN,*) 'Material # ',imaterial_number,' isotropic' + if (vsregion < TINYVAL) then + write(IMAIN,*) 'Material is fluid' + else + write(IMAIN,*) 'Material is solid' + endif + write(IMAIN,*) 'vp = ',sngl(vpregion) + write(IMAIN,*) 'vs = ',sngl(vsregion) + write(IMAIN,*) 'rho = ',sngl(rho_s_read(imaterial_number)) + if (vpregion == vsregion) stop 'Materials cannot have Vs = Vp, there is an error in your input file' + + ! Poisson ratio (only for non-tomographic models, where vp/vs have been defined) + if (icodemat(imaterial_number) > 0) then + poisson_ratio = 0.5d0*(vpregion*vpregion - 2.d0*vsregion*vsregion) / (vpregion*vpregion - vsregion*vsregion) + write(IMAIN,*) 'Poisson''s ratio = ',sngl(poisson_ratio) + write(IMAIN,*) 'QKappa = ',sngl(QKappa(imaterial_number)) + write(IMAIN,*) 'Qmu = ',sngl(Qmu(imaterial_number)) + + if (poisson_ratio <= -1.00001d0 .or. poisson_ratio >= 0.50001d0) call stop_the_code('incorrect value of Poisson''s ratio') + else + ! tomographic material + write(IMAIN,*) 'tomographic material = ',icodemat(imaterial_number) + endif + + else if (icodemat(imaterial_number) == POROELASTIC_MATERIAL) then + ! poroelastic material + write(IMAIN,*) 'Material # ',imaterial_number,' isotropic' + write(IMAIN,*) 'Material is poroelastic' + + else + ! anisotropic material + write(IMAIN,*) 'Material # ',imaterial_number,' anisotropic' + write(IMAIN,*) 'cp = ',sngl(cp(imaterial_number)) + write(IMAIN,*) 'cs = ',sngl(cs(imaterial_number)) + write(IMAIN,*) 'c11 = ',sngl(aniso3(imaterial_number)) + write(IMAIN,*) 'c13 = ',sngl(aniso4(imaterial_number)) + write(IMAIN,*) 'c15 = ',sngl(aniso5(imaterial_number)) + write(IMAIN,*) 'c33 = ',sngl(aniso6(imaterial_number)) + write(IMAIN,*) 'c35 = ',sngl(aniso7(imaterial_number)) + write(IMAIN,*) 'c55 = ',sngl(aniso8(imaterial_number)) + write(IMAIN,*) 'c12 = ',sngl(aniso9(imaterial_number)) + write(IMAIN,*) 'c23 = ',sngl(aniso10(imaterial_number)) + write(IMAIN,*) 'c25 = ',sngl(aniso11(imaterial_number)) + write(IMAIN,*) 'rho = ',sngl(rho_s_read(imaterial_number)) + write(IMAIN,*) 'QKappa = ',sngl(QKappa(imaterial_number)) + write(IMAIN,*) 'Qmu = ',sngl(Qmu(imaterial_number)) + endif + + ! store density and velocity model + is_overwriting = .false. + do j = iz_start,iz_end + do i = ix_start,ix_end + ! element index + ielem = (j-1)*nxread+i + ! checks if element has been already assigned + if (num_material(ielem) /= 0) then + is_overwriting = .true. + id_already_set = num_material(ielem) + endif + ! sets new material id for element + num_material(ielem) = imaterial_number + enddo + enddo + + ! user output + if (is_overwriting) then + write(IMAIN,*) '*************************************' + write(IMAIN,*) 'Warning: Element range from this region is overwriting material numbers previously set on elements.' + write(IMAIN,*) ' This indicates that your region range is overlapping the region for material ',id_already_set + write(IMAIN,*) ' If your regions should be exclusive, please fix the region definitions in the Par_file!' + write(IMAIN,*) '*************************************' + endif + write(IMAIN,*) '------' + call flush_IMAIN() + + enddo + write(IMAIN,*) + call flush_IMAIN() + + if (minval(num_material(:)) <= 0) call stop_the_code('Velocity model not entirely set...') + + end subroutine read_regions diff --git a/meshfem2d/read_source_file.f90 b/meshfem2d/read_source_file.f90 new file mode 100644 index 00000000..e7686592 --- /dev/null +++ b/meshfem2d/read_source_file.f90 @@ -0,0 +1,354 @@ +!======================================================================== +! +! S P E C F E M 2 D +! ----------------- +! +! Main historical authors: Dimitri Komatitsch and Jeroen Tromp +! CNRS, France +! and Princeton University, USA +! (there are currently many more authors!) +! (c) October 2017 +! +! This software is a computer program whose purpose is to solve +! the two-dimensional viscoelastic anisotropic or poroelastic wave equation +! using a spectral-element method (SEM). +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 3 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License along +! with this program; if not, write to the Free Software Foundation, Inc., +! 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +! +! The full text of the license is available in file "LICENSE". +! +!======================================================================== + + subroutine read_source_file(NSOURCES,BROADCAST_AFTER_READ) + + ! reads in source file DATA/SOURCE + + use constants, only: IMAIN,IGNORE_JUNK,NLINES_PER_SOURCE,TINYVAL,PI, & + mygroup,IN_DATA_FILES,myrank + + use shared_parameters, only: DT,initialfield + + use source_file_par + + implicit none + + integer,intent(in) :: NSOURCES + logical,intent(in) :: BROADCAST_AFTER_READ + + ! local parameters + integer :: ier,icounter,i_source,num_sources + character(len=256) string_read + character(len=MAX_STRING_LEN) :: source_filename,path_to_add + integer, parameter :: IIN_SOURCE = 22 + + ! user output + if (myrank == 0) then + write(IMAIN,*) 'Reading in SOURCE file...' + write(IMAIN,*) + call flush_IMAIN() + endif + + ! allocates memory arrays + allocate(source_surf(NSOURCES), & + x_source(NSOURCES), & + z_source(NSOURCES), & + source_type(NSOURCES), & + time_function_type(NSOURCES), & + name_of_source_file(NSOURCES), & + burst_band_width(NSOURCES), & + f0_source(NSOURCES), & + tshift_src(NSOURCES), & + anglesource(NSOURCES), & + Mxx(NSOURCES), & + Mxz(NSOURCES), & + Mzz(NSOURCES), & + factor(NSOURCES), & + vx_source(NSOURCES), & + vz_source(NSOURCES), stat=ier) + if (ier /= 0) call stop_the_code('Error allocating source arrays') + + ! initializes + x_source(:) = 0.d0 + z_source(:) = 0.d0 + + vx_source(:) = 0.d0 + vz_source(:) = 0.d0 + + source_type(:) = 0 + time_function_type(:) = 0 + + f0_source(:) = 0.d0 + tshift_src(:) = 0.d0 + anglesource(:) = 0.d0 + Mxx(:) = 0.d0 + Mxz(:) = 0.d0 + Mzz(:) = 0.d0 + + ! only main process reads file + if (myrank == 0) then + source_filename = trim(IN_DATA_FILES)//'SOURCE' + + ! mygroup has been initialized with negative value. It is positive just in the case NUMBER_OF_SIMULTANEOUS_RUNS > 1 + if (mygroup >= 0) then + write(path_to_add,"('run',i4.4,'/')") mygroup + 1 + source_filename = path_to_add(1:len_trim(path_to_add))//source_filename(1:len_trim(source_filename)) + endif + + ! opens source file + open(unit=IIN_SOURCE,file=trim(source_filename),status='old',action='read',iostat=ier) + if (ier /= 0) call stop_the_code('Error opening source file, please make sure file exists...') + + ! counts number of lines + icounter = 0 + do while(ier == 0) + read(IIN_SOURCE,"(a)",iostat=ier) string_read + + if (ier == 0) then + ! suppress trailing carriage return (ASCII code 13) if any (e.g. if input text file coming from Windows/DOS) + if (index(string_read,achar(13)) > 0) string_read = string_read(1:index(string_read,achar(13))-1) + + ! suppress leading and trailing white spaces, if any + string_read = adjustl(string_read) + string_read = string_read(1:len_trim(string_read)) + + ! if the line is not empty and is not a comment, count it + if (len_trim(string_read) > 0 .and. (index(string_read,'#') == 0 .or. index(string_read,'#') > 1)) then + ! increases number of lines + icounter = icounter + 1 + ! debug + !print *,'debug: SOURCE line: ',trim(string_read) + endif + endif + enddo + close(IIN_SOURCE) + + ! checks counter + if (mod(icounter,NLINES_PER_SOURCE) /= 0) then + print *,'Error: invalid number of (non-blank and non-comment) lines per source ',icounter + print *,' should be a multiple of NLINES_PER_SOURCE = ',NLINES_PER_SOURCE + call stop_the_code('total number of non-blank and non-comment lines in SOURCE file & + &should be a multiple of NLINES_PER_SOURCE') + endif + + ! total number of sources + num_sources = icounter / NLINES_PER_SOURCE + + ! checks number of sources + if (num_sources < 1) call stop_the_code('need at least one source in SOURCE file') + if (num_sources /= NSOURCES) then + print *,'Error invalid num_sources :',num_sources + print *,'NSOURCES :',NSOURCES + call stop_the_code('Error: Total number of sources in DATA/SOURCE is different from that declared in the Par_file, & + &please check...') + endif + + ! reads in source parameters + open(unit=IIN_SOURCE,file=trim(source_filename),status='old',action='read',iostat=ier) + if (ier /= 0) call stop_the_code('Error opening source file, please make sure file exists...') + + ! reads in all source informations + do i_source = 1,NSOURCES + + ! source set to surface + call read_value_logical(IIN_SOURCE,IGNORE_JUNK,source_surf(i_source)) + + ! x/z location + call read_value_double_precision(IIN_SOURCE,IGNORE_JUNK,x_source(i_source)) + call read_value_double_precision(IIN_SOURCE,IGNORE_JUNK,z_source(i_source)) + + ! source and source time function type + call read_value_integer(IIN_SOURCE,IGNORE_JUNK,source_type(i_source)) + call read_value_integer(IIN_SOURCE,IGNORE_JUNK,time_function_type(i_source)) + + ! external source time function file (sft type == 8) + name_of_source_file(i_source) = '' + call read_value_string(IIN_SOURCE,IGNORE_JUNK,name_of_source_file(i_source)) + + ! burst (stf type == 9) + call read_value_double_precision(IIN_SOURCE,IGNORE_JUNK,burst_band_width(i_source)) + + ! dominant frequency + call read_value_double_precision(IIN_SOURCE,IGNORE_JUNK,f0_source(i_source)) + + ! time shift + call read_value_double_precision(IIN_SOURCE,IGNORE_JUNK,tshift_src(i_source)) + + ! force source angle + call read_value_double_precision(IIN_SOURCE,IGNORE_JUNK,anglesource(i_source)) + + ! moment tensor + call read_value_double_precision(IIN_SOURCE,IGNORE_JUNK,Mxx(i_source)) + call read_value_double_precision(IIN_SOURCE,IGNORE_JUNK,Mzz(i_source)) + call read_value_double_precision(IIN_SOURCE,IGNORE_JUNK,Mxz(i_source)) + + ! amplification factor + call read_value_double_precision(IIN_SOURCE,IGNORE_JUNK,factor(i_source)) + + ! x/z velocity (moving source) + call read_value_double_precision(IIN_SOURCE,IGNORE_JUNK,vx_source(i_source)) + call read_value_double_precision(IIN_SOURCE,IGNORE_JUNK,vz_source(i_source)) + + ! Set flag SOURCE_IS_MOVING + if (any(abs(vx_source) > TINYVAL) .or. any(abs(vz_source) > TINYVAL)) then + SOURCE_IS_MOVING = .true. + else + SOURCE_IS_MOVING = .false. + endif + + ! Dirac/Heaviside + ! if Dirac source time function, use a very thin Gaussian instead + ! if Heaviside source time function, use a very thin error function instead + if (time_function_type(i_source) == 4 .or. time_function_type(i_source) == 5) then + f0_source(i_source) = 1.d0 / (10.d0 * DT) + endif + + ! checks source frequency + if (abs(f0_source(i_source)) < TINYVAL) then + call exit_MPI(0,'Error: source frequency is zero') + endif + + ! convert angle from degrees to radians + anglesource(i_source) = anglesource(i_source) * PI / 180.d0 + + ! user output + ! note: we will further process source info in solver, + ! here we just read in the given specifics and show them + write(IMAIN,*) 'Source', i_source + if (SOURCE_IS_MOVING) then + write(IMAIN,*) ' Initial position xs, zs = ',x_source(i_source),z_source(i_source) + write(IMAIN,*) ' Velocities vx, vz = ',vx_source(i_source),vz_source(i_source) + else + write(IMAIN,*) ' Position xs, zs = ',x_source(i_source),z_source(i_source) + endif + write(IMAIN,*) + + ! source type + if (initialfield) then + write(IMAIN,*) ' Source type (1=force, 2=moment tensor, 3=Rayleigh wave, 4=plane incident P, & + &5=plane incident S,6=mode): ',source_type(i_source) + else + write(IMAIN,*) ' Source type (1=force, 2=moment tensor): ',source_type(i_source) + endif + select case (source_type(i_source)) + case (1) + ! force + write(IMAIN,*) ' Force source:' + write(IMAIN,*) ' Angle of the source (deg) = ',anglesource(i_source) + case (2) + ! moment tensor + write(IMAIN,*) ' Moment tensor source:' + write(IMAIN,*) ' Mxx of the source = ',Mxx(i_source) + write(IMAIN,*) ' Mzz of the source = ',Mzz(i_source) + write(IMAIN,*) ' Mxz of the source = ',Mxz(i_source) + case (3) + ! Rayleigh wave + write(IMAIN,*) ' Rayleigh wave source:' + case (4) + ! plane P wave without converted/refracted phases + write(IMAIN,*) ' Plane P-wave source without converted/refracted phases:' + write(IMAIN,*) ' Angle of the incident wave (deg) = ',anglesource(i_source) + case (5) + ! plane S wave without converted/refracted phases + write(IMAIN,*) ' Plane S-wave source without converted/refracted phases:' + write(IMAIN,*) ' Angle of the incident wave (deg) = ',anglesource(i_source) + case (6) + ! initial mode displacement + write(IMAIN,*) ' Initial mode displacement for initialfield' + case default + ! not supported yet + call stop_the_code('Error invalid source type! must be 1, 2, 3, 4, 5 or 6 exiting...') + end select + write(IMAIN,*) + + ! STF + write(IMAIN,*) ' Time function type (1=Ricker, 2=First derivative, 3=Gaussian, 4=Dirac, 5=Heaviside, & + &6,7=ocean type, 8=Read from file, 9=burst, 10=Sinusoidal, 11=Ormsby):',time_function_type(i_source) + select case (time_function_type(i_source)) + case (1) + write(IMAIN,*) ' Ricker wavelet (second-derivative):' + write(IMAIN,*) ' Frequency, delay = ',f0_source(i_source),tshift_src(i_source) + case (2) + write(IMAIN,*) ' Ricker wavelet (first-derivative):' + write(IMAIN,*) ' Frequency, delay = ',f0_source(i_source),tshift_src(i_source) + case (3) + write(IMAIN,*) ' Gaussian:' + write(IMAIN,*) ' Frequency, delay = ',f0_source(i_source),tshift_src(i_source) + case (4) + write(IMAIN,*) ' Dirac:' + write(IMAIN,*) ' Frequency, delay = ',f0_source(i_source),tshift_src(i_source) + case (5) + write(IMAIN,*) ' Heaviside:' + write(IMAIN,*) ' Frequency, delay = ',f0_source(i_source),tshift_src(i_source) + case (6) + write(IMAIN,*) ' Ocean acoustics (type I):' + write(IMAIN,*) ' Frequency, delay = ',f0_source(i_source),tshift_src(i_source) + case (7) + write(IMAIN,*) ' Ocean acoustics (type II):' + write(IMAIN,*) ' Frequency, delay = ',f0_source(i_source),tshift_src(i_source) + case (8) + write(IMAIN,*) ' External source time function file:' + write(IMAIN,*) ' Source read from file: ',trim(name_of_source_file(i_source)) + case (9) + write(IMAIN,*) ' Burst wavelet:' + write(IMAIN,*) ' Burst band width: ',burst_band_width(i_source) + case (10) + write(IMAIN,*) ' Sinusoidal source time function:' + write(IMAIN,*) ' Frequency, delay = ',f0_source(i_source),tshift_src(i_source) + case (11) + write(IMAIN,*) ' Ormsby source time function:' + write(IMAIN,*) ' Frequency, delay = ',f0_source(i_source),tshift_src(i_source) + case default + call stop_the_code('Error invalid source time function type! must be between 1 and 9, exiting...') + end select + write(IMAIN,*) ' Multiplying factor = ',factor(i_source) + write(IMAIN,*) + + enddo ! do i_source= 1,NSOURCES + close(IIN_SOURCE) + + endif ! myrank == 0 + + ! broadcast to all processes + if (BROADCAST_AFTER_READ) then + call bcast_all_i(source_type,NSOURCES) + call bcast_all_i(time_function_type,NSOURCES) + + call bcast_all_dp(x_source,NSOURCES) + call bcast_all_dp(z_source,NSOURCES) + call bcast_all_dp(burst_band_width,NSOURCES) + call bcast_all_dp(f0_source,NSOURCES) + call bcast_all_dp(tshift_src,NSOURCES) + call bcast_all_dp(anglesource,NSOURCES) + call bcast_all_dp(Mxx,NSOURCES) + call bcast_all_dp(Mxz,NSOURCES) + call bcast_all_dp(Mzz,NSOURCES) + call bcast_all_dp(factor,NSOURCES) + call bcast_all_dp(vx_source,NSOURCES) + call bcast_all_dp(vz_source,NSOURCES) + + call bcast_all_l(source_surf,NSOURCES) + + call bcast_all_string_array(name_of_source_file,NSOURCES) + call bcast_all_singlel(SOURCE_IS_MOVING) + endif + + ! user output + if (myrank == 0) then + write(IMAIN,*) 'all sources are okay' + write(IMAIN,*) + call flush_IMAIN() + endif + + end subroutine read_source_file diff --git a/meshfem2d/read_value_parameters.f90 b/meshfem2d/read_value_parameters.f90 new file mode 100644 index 00000000..ed930a78 --- /dev/null +++ b/meshfem2d/read_value_parameters.f90 @@ -0,0 +1,411 @@ +!======================================================================== +! +! S P E C F E M 2 D +! ----------------- +! +! Main historical authors: Dimitri Komatitsch and Jeroen Tromp +! CNRS, France +! and Princeton University, USA +! (there are currently many more authors!) +! (c) October 2017 +! +! This software is a computer program whose purpose is to solve +! the two-dimensional viscoelastic anisotropic or poroelastic wave equation +! using a spectral-element method (SEM). +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 3 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License along +! with this program; if not, write to the Free Software Foundation, Inc., +! 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +! +! The full text of the license is available in file "LICENSE". +! +!======================================================================== + +! read values from parameter file, ignoring white lines and comments + + subroutine read_value_integer(iin,ignore_junk,value_to_read) + + use constants, only: MAX_STRING_LEN + + implicit none + + integer :: iin + logical :: ignore_junk + integer :: value_to_read + character(len=MAX_STRING_LEN) :: string_read + + call read_next_line(iin,ignore_junk,string_read) + read(string_read,*) value_to_read + + end subroutine read_value_integer + +!-------------------- + + subroutine read_value_double_precision(iin,ignore_junk,value_to_read) + + use constants, only: MAX_STRING_LEN + + implicit none + + integer :: iin + logical :: ignore_junk + double precision :: value_to_read + character(len=MAX_STRING_LEN) :: string_read + + call read_next_line(iin,ignore_junk,string_read) + read(string_read,*) value_to_read + + end subroutine read_value_double_precision + +!-------------------- + + subroutine read_value_logical(iin,ignore_junk,value_to_read) + + use constants, only: MAX_STRING_LEN + + implicit none + + integer :: iin + logical :: ignore_junk + logical :: value_to_read + character(len=MAX_STRING_LEN) :: string_read + + call read_next_line(iin,ignore_junk,string_read) + read(string_read,*) value_to_read + + end subroutine read_value_logical + +!-------------------- + + subroutine read_value_string(iin,ignore_junk,value_to_read) + + use constants, only: MAX_STRING_LEN + + implicit none + + integer :: iin + logical :: ignore_junk + character(len=MAX_STRING_LEN) :: value_to_read + character(len=MAX_STRING_LEN) :: string_read + + call read_next_line(iin,ignore_junk,string_read) + read(string_read,'(a)') value_to_read + + end subroutine read_value_string + +!-------------------- + + subroutine read_two_interface_points(iin,ignore_junk,value_to_read_1,value_to_read_2) + + use constants, only: MAX_STRING_LEN + + implicit none + + integer :: iin + logical :: ignore_junk + double precision :: value_to_read_1,value_to_read_2 + character(len=MAX_STRING_LEN) :: string_read + + call read_next_line(iin,ignore_junk,string_read) + read(string_read,*) value_to_read_1,value_to_read_2 + + end subroutine read_two_interface_points + +!-------------------- + + subroutine read_next_line(iin,ignore_junk,string_read) + + use constants, only: MAX_STRING_LEN + + implicit none + + logical :: ignore_junk + character(len=MAX_STRING_LEN) :: string_read + + integer :: ios,iin,index_equal_sign + + do + ! daniel: actually MAX_STRING_LEN set to 512... + read(unit=iin,fmt="(a256)",iostat=ios) string_read + if (ios /= 0) call stop_the_code('error while reading input file') + +! suppress leading white spaces, if any + string_read = adjustl(string_read) + +! suppress trailing carriage return (ASCII code 13) if any (e.g. if input text file coming from Windows/DOS) + if (index(string_read,achar(13)) > 0) string_read = string_read(1:index(string_read,achar(13))-1) + +! exit loop when we find the first line that is not a comment or a white line + if (len_trim(string_read) == 0) cycle + if (string_read(1:1) /= '#') exit + + enddo + +! suppress trailing white spaces, if any + string_read = string_read(1:len_trim(string_read)) + +! suppress trailing comments, if any + if (index(string_read,'#') > 0) string_read = string_read(1:index(string_read,'#')-1) + +! suppress leading junk (up to the first equal sign, included) if needed + if (ignore_junk) then + index_equal_sign = index(string_read,'=') + if (index_equal_sign <= 1 .or. index_equal_sign == len_trim(string_read)) call stop_the_code( & +'incorrect syntax detected in DATA/Par_file') + string_read = string_read(index_equal_sign + 1:len_trim(string_read)) + endif + +! suppress leading and trailing white spaces again, if any, after having suppressed the leading junk + string_read = adjustl(string_read) + string_read = string_read(1:len_trim(string_read)) + + end subroutine read_next_line + +!-------------------- + + + + +!-------------------- +!-------------------- +! uses param_reader.c functions +!-------------------- +!-------------------- + + + subroutine read_value_integer_p(value_to_read, name) + + use constants, only: MAX_STRING_LEN + + implicit none + + integer :: value_to_read + character(len=*) :: name + character(len=MAX_STRING_LEN) :: string_read + integer :: ierr + common /param_err_common/ ierr + + call param_read(string_read, len(string_read), name, len(name), ierr) + if (ierr /= 0) return + read(string_read,*) value_to_read + + end subroutine read_value_integer_p + +!-------------------- + + subroutine read_value_double_precision_p(value_to_read, name) + + use constants, only: MAX_STRING_LEN + + implicit none + + double precision :: value_to_read + character(len=*) :: name + character(len=MAX_STRING_LEN) :: string_read + integer :: ierr + common /param_err_common/ ierr + + call param_read(string_read, len(string_read), name, len(name), ierr) + if (ierr /= 0) return + read(string_read,*) value_to_read + + end subroutine read_value_double_precision_p + +!-------------------- + + subroutine read_value_logical_p(value_to_read, name) + + use constants, only: MAX_STRING_LEN + + implicit none + + logical :: value_to_read + character(len=*) :: name + character(len=MAX_STRING_LEN) :: string_read + integer :: ierr + common /param_err_common/ ierr + + call param_read(string_read, len(string_read), name, len(name), ierr) + if (ierr /= 0) return + read(string_read,*) value_to_read + + end subroutine read_value_logical_p + +!-------------------- + + subroutine read_value_string_p(value_to_read, name) + + use constants, only: MAX_STRING_LEN + + implicit none + + character(len=*) :: value_to_read + character(len=*) :: name + character(len=MAX_STRING_LEN) :: string_read + integer :: ierr + common /param_err_common/ ierr + + call param_read(string_read, len(string_read), name, len(name), ierr) + if (ierr /= 0) return + value_to_read = string_read + + end subroutine read_value_string_p + +!-------------------- + + subroutine read_value_integer_next_p(value_to_read, name) + + use constants, only: MAX_STRING_LEN + + implicit none + + integer :: value_to_read + character(len=*) :: name + character(len=MAX_STRING_LEN) :: string_read + integer :: ierr + common /param_err_common/ ierr + + call param_read_nextparam(string_read, len(string_read), name, len(name), ierr) + if (ierr /= 0) return + read(string_read,*) value_to_read + + end subroutine read_value_integer_next_p + +!-------------------- + + subroutine read_value_double_prec_next_p(value_to_read, name) + + use constants, only: MAX_STRING_LEN + + implicit none + + double precision :: value_to_read + character(len=*) :: name + character(len=MAX_STRING_LEN) :: string_read + integer :: ierr + common /param_err_common/ ierr + + call param_read_nextparam(string_read, len(string_read), name, len(name), ierr) + if (ierr /= 0) return + read(string_read,*) value_to_read + + end subroutine read_value_double_prec_next_p + +!-------------------- + + subroutine read_value_logical_next_p(value_to_read, name) + + use constants, only: MAX_STRING_LEN + + implicit none + + logical :: value_to_read + character(len=*) :: name + character(len=MAX_STRING_LEN) :: string_read + integer :: ierr + common /param_err_common/ ierr + + call param_read_nextparam(string_read, len(string_read), name, len(name), ierr) + if (ierr /= 0) return + read(string_read,*) value_to_read + + end subroutine read_value_logical_next_p + + +!-------------------- + + subroutine read_material_parameters_p(i,icodematread,val0read,val1read,val2read,val3read, & + val4read,val5read,val6read,val7read,val8read,val9read,val10read, & + val11read,val12read) + + use constants, only: MAX_STRING_LEN + + implicit none + + integer :: i,icodematread + double precision :: val0read,val1read,val2read,val3read,val4read,val5read,val6read,val7read, & + val8read,val9read,val10read,val11read,val12read + + character(len=MAX_STRING_LEN) :: string_read + integer :: ierr + common /param_err_common/ ierr + + call param_read_nextline(string_read, len(string_read), ierr) + if (ierr /= 0) call stop_the_code('error reading material parameter') + + !print *,trim(string_read) + + read(string_read,*,iostat=ierr) i,icodematread,val0read,val1read,val2read,val3read,val4read,val5read, & + val6read,val7read,val8read,val9read,val10read,val11read,val12read + + if (ierr /= 0) call stop_the_code('error reading material parameters line') + + end subroutine read_material_parameters_p + +!-------------------- + + subroutine read_region_coordinates_p(value_to_read_1,value_to_read_2, & + value_to_read_3,value_to_read_4,value_to_read_5) + + use constants, only: MAX_STRING_LEN + + implicit none + + integer :: value_to_read_1,value_to_read_2,value_to_read_3,value_to_read_4,value_to_read_5 + character(len=MAX_STRING_LEN) :: string_read + integer :: ierr + common /param_err_common/ ierr + + call param_read_nextline(string_read, len(string_read), ierr) + if (ierr /= 0) call stop_the_code('error reading region coordinates') + + !print *,string_read + + read(string_read,*,iostat=ierr) value_to_read_1,value_to_read_2,value_to_read_3,value_to_read_4,value_to_read_5 + + if (ierr /= 0) call stop_the_code('error reading region coordinates line') + + end subroutine read_region_coordinates_p + + +!-------------------- + + integer function err_occurred() + + implicit none + + integer :: ierr + common /param_err_common/ ierr + + err_occurred = ierr + + end function err_occurred + +!-------------------- +!-------------------- +!-------------------- + + subroutine dummy_routine() + +! dummy routine that does nothing, it is there just to fix an Intel ifort compiler bug +! with some releases of that compiler, in file src/specfem2D/locate_receivers.F90 + + implicit none + + integer :: i,j,k + + i = 12 + j = 14 + k = i + j + + end subroutine dummy_routine diff --git a/meshfem2d/repartition_coupling.f90 b/meshfem2d/repartition_coupling.f90 new file mode 100644 index 00000000..e8d09c1a --- /dev/null +++ b/meshfem2d/repartition_coupling.f90 @@ -0,0 +1,514 @@ +!======================================================================== +! +! S P E C F E M 2 D +! ----------------- +! +! Main historical authors: Dimitri Komatitsch and Jeroen Tromp +! CNRS, France +! and Princeton University, USA +! (there are currently many more authors!) +! (c) October 2017 +! +! This software is a computer program whose purpose is to solve +! the two-dimensional viscoelastic anisotropic or poroelastic wave equation +! using a spectral-element method (SEM). +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 3 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License along +! with this program; if not, write to the Free Software Foundation, Inc., +! 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +! +! The full text of the license is available in file "LICENSE". +! +!======================================================================== + + !-------------------------------------------------- + ! repartitioning: coupled acoustic/elastic elements are transferred to the same partition + !-------------------------------------------------- + + subroutine acoustic_elastic_repartitioning(elmnts_l, nbmodels, phi_material, num_material, nproc) + + use constants, only: IMAIN,NCORNERS,MAX_NEIGHBORS,TINYVAL + use part_unstruct_par, only: nelmnts,edges_coupled,nedges_coupled + + implicit none + + integer, dimension(0:NCORNERS*nelmnts-1), intent(in) :: elmnts_l + integer, intent(in) :: nproc, nbmodels + double precision, dimension(nbmodels), intent(in) :: phi_material + integer, dimension(1:nelmnts), intent(in) :: num_material + + ! local parameters + integer, dimension(:), allocatable :: xadj_l + integer, dimension(:), allocatable :: adjncy_l + logical, dimension(nbmodels) :: is_acoustic, is_elastic + integer :: i, ier + integer :: el, el_adj + + allocate(xadj_l(0:nelmnts)) + allocate(adjncy_l(0:MAX_NEIGHBORS*nelmnts-1)) + + ! sets domain flags + is_acoustic(:) = .false. + is_elastic(:) = .false. + + do i = 1, nbmodels + if (phi_material(i) >= 1.d0) then + is_acoustic(i) = .true. + endif + if (phi_material(i) < TINYVAL) then + is_elastic(i) = .true. + endif + enddo + + ! determines maximum neighbors based on 2 common nodes (common edge) + call mesh2dual_ncommonnodes(elmnts_l, 2, xadj_l, adjncy_l) + + nedges_coupled = 0 + do el = 0, nelmnts-1 + ! for acoustic element + if (is_acoustic(num_material(el+1))) then + ! loops over adjacent elements + do el_adj = xadj_l(el), xadj_l(el+1) - 1 + ! adds its elastic neighbor + if (is_elastic(num_material(adjncy_l(el_adj)+1))) then + nedges_coupled = nedges_coupled + 1 + endif + enddo + endif + enddo + + ! user output + write(IMAIN,*) 'nedges_coupled (acoustic/elastic) = ', nedges_coupled + + allocate(edges_coupled(2,nedges_coupled),stat=ier) + if (ier /= 0) call stop_the_code('Error allocating array edges_coupled') + edges_coupled(:,:) = 0 + + ! repartitions elements + if (nedges_coupled > 0) then + call repartition_coupled_edges(nproc,nedges_coupled,edges_coupled, & + num_material,nbmodels, & + is_acoustic,is_elastic,xadj_l,adjncy_l) + endif + + deallocate(xadj_l,adjncy_l) + + end subroutine acoustic_elastic_repartitioning + + +! +!--------------------------------------------------------------------------------------- +! + + !-------------------------------------------------- + ! repartitioning: coupled acoustic/poroelastic elements are transferred to the same partition + !-------------------------------------------------- + + subroutine acoustic_poro_repartitioning(elmnts_l, nbmodels, phi_material, num_material, nproc) + + use constants, only: IMAIN,NCORNERS,MAX_NEIGHBORS,TINYVAL + use part_unstruct_par, only: nelmnts,edges_acporo_coupled,nedges_acporo_coupled + + implicit none + + integer, dimension(0:NCORNERS*nelmnts-1), intent(in) :: elmnts_l + integer, intent(in) :: nproc, nbmodels + double precision, dimension(nbmodels), intent(in) :: phi_material + integer, dimension(1:nelmnts), intent(in) :: num_material + + ! local parameters + integer, dimension(:), allocatable :: xadj_l + integer, dimension(:), allocatable :: adjncy_l + logical, dimension(nbmodels) :: is_acoustic,is_poroelastic + integer :: i, ier + integer :: el, el_adj + + allocate(xadj_l(0:nelmnts)) + allocate(adjncy_l(0:MAX_NEIGHBORS*nelmnts-1)) + + is_acoustic(:) = .false. + is_poroelastic(:) = .false. + + do i = 1, nbmodels + if (phi_material(i) >= 1.d0) then + is_acoustic(i) = .true. + endif + if (phi_material(i) < 1.d0 .and. phi_material(i) > TINYVAL) then + is_poroelastic(i) = .true. + endif + enddo + + ! determines maximum neighbors based on 2 common nodes (common edge) + call mesh2dual_ncommonnodes(elmnts_l, 2, xadj_l, adjncy_l) + + nedges_acporo_coupled = 0 + do el = 0, nelmnts-1 + if (is_acoustic(num_material(el+1))) then + do el_adj = xadj_l(el), xadj_l(el+1) - 1 + if (is_poroelastic(num_material(adjncy_l(el_adj)+1))) then + nedges_acporo_coupled = nedges_acporo_coupled + 1 + endif + enddo + endif + enddo + + ! user output + write(IMAIN,*) 'nedges_coupled (acoustic/poroelastic) = ', nedges_acporo_coupled + + allocate(edges_acporo_coupled(2,nedges_acporo_coupled),stat=ier) + if (ier /= 0) call stop_the_code('Error allocating array edges_acporo_coupled') + edges_acporo_coupled(:,:) = 0 + + ! repartitions elements + if (nedges_acporo_coupled > 0) then + call repartition_coupled_edges(nproc,nedges_acporo_coupled,edges_acporo_coupled, & + num_material,nbmodels, & + is_acoustic,is_poroelastic,xadj_l,adjncy_l) + endif + + deallocate(xadj_l,adjncy_l) + + end subroutine acoustic_poro_repartitioning + +! +!--------------------------------------------------------------------------------------- +! + + !-------------------------------------------------- + ! repartitioning: coupled poroelastic/elastic elements are transferred to the same partition + !-------------------------------------------------- + + subroutine poro_elastic_repartitioning(elmnts_l, nbmodels, phi_material, num_material, nproc) + + use constants, only: IMAIN,NCORNERS,MAX_NEIGHBORS,TINYVAL + use part_unstruct_par, only: nelmnts,nedges_elporo_coupled,edges_elporo_coupled + + implicit none + + integer, dimension(0:NCORNERS*nelmnts-1), intent(in) :: elmnts_l + integer, intent(in) :: nproc, nbmodels + double precision, dimension(nbmodels), intent(in) :: phi_material + integer, dimension(1:nelmnts), intent(in) :: num_material + + ! local parameters + integer, dimension(:), allocatable :: xadj_l + integer, dimension(:), allocatable :: adjncy_l + logical, dimension(nbmodels) :: is_elastic,is_poroelastic + integer :: i, ier + integer :: el, el_adj + + allocate(xadj_l(0:nelmnts)) + allocate(adjncy_l(0:MAX_NEIGHBORS*nelmnts-1)) + + is_elastic(:) = .false. + is_poroelastic(:) = .false. + + do i = 1, nbmodels + if (phi_material(i) < TINYVAL) then + is_elastic(i) = .true. + endif + if (phi_material(i) < 1.d0 .and. phi_material(i) > TINYVAL) then + is_poroelastic(i) = .true. + endif + enddo + + ! determines maximum neighbors based on 2 common nodes (common edge) + call mesh2dual_ncommonnodes(elmnts_l, 2, xadj_l, adjncy_l) + + nedges_elporo_coupled = 0 + do el = 0, nelmnts-1 + if (is_poroelastic(num_material(el+1))) then + do el_adj = xadj_l(el), xadj_l(el+1) - 1 + if (is_elastic(num_material(adjncy_l(el_adj)+1))) then + nedges_elporo_coupled = nedges_elporo_coupled + 1 + endif + enddo + endif + enddo + + ! user output + write(IMAIN,*) 'nedges_coupled (poroelastic/elastic) = ', nedges_elporo_coupled + + allocate(edges_elporo_coupled(2,nedges_elporo_coupled),stat=ier) + if (ier /= 0) call stop_the_code('Error allocating array edges_elporo_coupled') + edges_elporo_coupled(:,:) = 0 + + ! repartitions elements + if (nedges_elporo_coupled > 0) then + call repartition_coupled_edges(nproc,nedges_elporo_coupled,edges_elporo_coupled, & + num_material,nbmodels, & + is_poroelastic,is_elastic,xadj_l,adjncy_l) + endif + + deallocate(xadj_l,adjncy_l) + + end subroutine poro_elastic_repartitioning + +! +!--------------------------------------------------------------------------------------- +! + + subroutine repartition_coupled_edges(nproc,nedges_coupled,edges_coupled, & + num_material,nbmodels, & + is_domain_A,is_domain_B,xadj_l,adjncy_l) + + use constants, only: IMAIN,MAX_NEIGHBORS + use part_unstruct_par, only: nelmnts,part + + implicit none + + integer, intent(in) :: nproc, nedges_coupled + integer, dimension(2,nedges_coupled),intent(inout) :: edges_coupled + + integer, dimension(1:nelmnts), intent(in) :: num_material + + integer,intent(in) :: nbmodels + logical, dimension(nbmodels),intent(in) :: is_domain_A, is_domain_B + + integer, dimension(0:nelmnts),intent(in) :: xadj_l + integer, dimension(0:MAX_NEIGHBORS*nelmnts-1),intent(in) :: adjncy_l + + ! local parameters + integer :: i, iedge + integer :: el, el_adj + logical :: is_repartitioned + + ! sets edges + iedge = 0 + do el = 0, nelmnts-1 + ! reference element + if (is_domain_A(num_material(el+1))) then + ! loops over adjacent elements + do el_adj = xadj_l(el), xadj_l(el+1) - 1 + ! adds coupled edge + if (is_domain_B(num_material(adjncy_l(el_adj)+1))) then + iedge = iedge + 1 + edges_coupled(1,iedge) = el + edges_coupled(2,iedge) = adjncy_l(el_adj) + endif + enddo + endif + enddo + if (iedge /= nedges_coupled) call stop_the_code('Error in setting domain edges, number of edges invalid') + + ! only in case we have different partitions + if (nproc > 1) then + do i = 1, nedges_coupled * nproc + is_repartitioned = .false. + do iedge = 1, nedges_coupled + ! puts coupled element in same partition + if (part(edges_coupled(1,iedge)) /= part(edges_coupled(2,iedge))) then + ! moves element into partition with smaller process id + if (part(edges_coupled(1,iedge)) < part(edges_coupled(2,iedge))) then + part(edges_coupled(2,iedge)) = part(edges_coupled(1,iedge)) + else + part(edges_coupled(1,iedge)) = part(edges_coupled(2,iedge)) + endif + is_repartitioned = .true. + endif + enddo + ! check if there is still work to do + if (.not. is_repartitioned) then + exit + endif + enddo + + ! checks if initial coupled edges are repartitioned + if (is_repartitioned) then + ! checks count in case we need more + i = 0 + do iedge = 1, nedges_coupled + if (part(edges_coupled(1,iedge)) /= part(edges_coupled(2,iedge))) i = i + 1 + enddo + write(IMAIN,*) ' repartitioning edges left = ',i + if (i /= 0) then + write(IMAIN,*) 'Error: repartitioning edges has still edges left = ',i + call stop_the_code('Error: repartitioning coupled elements needs more iterations') + else + ! for user output + i = nedges_coupled * nproc + endif + endif + write(IMAIN,*) ' after iteration ',i,'repartitioning of all coupled elements done' + endif + + end subroutine repartition_coupled_edges + +! +!--------------------------------------------------------------------------------------- +! + + !-------------------------------------------------- + ! repartitioning: coupled periodic elements are transferred to the same partition + !-------------------------------------------------- + + subroutine periodic_edges_repartitioning(elmnts_l,nnodes,nodes_coords,PERIODIC_HORIZ_DIST) + + use constants, only: IMAIN,NCORNERS + use part_unstruct_par, only: nelmnts,part + + implicit none + + integer, dimension(0:NCORNERS*nelmnts-1), intent(in) :: elmnts_l + + integer :: nnodes + double precision, dimension(2,nnodes) :: nodes_coords + double precision :: PERIODIC_HORIZ_DIST + + ! local parameters + logical, dimension(0:nelmnts-1) :: is_periodic + + integer :: el,el2,icorner,icorner2,num_node,num_node2,ifirst_partition_found + + double precision :: xtol,xtypdist + double precision :: x,y,x2,y2 + +! set up a local geometric tolerance by computing the typical horizontal size of an element. +! the sqrt() assumes that the geometrical model is 'not too elongated' and thus 'not too far from a square' +! and thus contains more or less the same number of points along X and Y. If this is not the case i.e. +! if the model is very elongated then this trick will work anyway because we just want to have a rough idea +! of a typical length in the mesh, even if it is not very accurate it will work anyway. + xtypdist = (maxval(nodes_coords(1,:)) - minval(nodes_coords(1,:))) / sqrt(dble(nnodes)) + +! define a tolerance, small with respect to the minimum size + xtol = 1.d-4 * xtypdist + +! detect the points that are on the same horizontal line (i.e. at the same height Z) +! and that have a value of the horizontal coordinate X that differs by exactly the periodicity length; +! if so, make them all have the same global number, which will then implement periodic boundary conditions automatically. +! We select the smallest value of iglob and assign it to all the points that are the same due to periodicity, +! this way the maximum value of the ibool() array will remain as small as possible. +! +! *** IMPORTANT: this simple algorithm will be slow for large meshes because it has a cost of NGLOB^2 / 2 +! (where NGLOB is the number of points per MPI slice, not of the whole mesh though). This could be +! reduced to O(NGLOB log(NGLOB)) by using a quicksort algorithm on the coordinates of the points to detect the multiples +! (as implemented in routine createnum_fast() elsewhere in the code). This could be done one day if needed instead +! of the very simple double loop below. + + ! user output + write(IMAIN,*) 'start detecting points for periodic boundary conditions & + &(the current algorithm can be slow and could be improved)...' + + is_periodic(:) = .false. + +! loop on all the elements + do el = 0, nelmnts-2 ! we call stop_the_code(one element before the end in order for the second loop to be OK in all cases) + do el2 = el+1, nelmnts-1 + if (is_periodic(el2)) cycle + ! it is sufficient to loop on the four corners to determine if this element has at least one periodic point + do icorner = 0,NCORNERS-1 + num_node = elmnts_l(icorner + NCORNERS*el) + 1 ! the plus one is because elmnts_l() starts at zero + x = nodes_coords(1,num_node) + y = nodes_coords(2,num_node) + do icorner2 = 0,NCORNERS-1 + num_node2 = elmnts_l(icorner2 + NCORNERS*el2) + 1 ! the plus one is because elmnts_l() starts at zero + x2 = nodes_coords(1,num_node2) + y2 = nodes_coords(2,num_node2) + ! if the two points are at the same height Y + if (abs(y2 - y) < xtol) then + ! if in addition their X coordinates differ by exactly the periodicity distance + if (abs(abs(x2 - x) - PERIODIC_HORIZ_DIST) < xtol) then + ! then these two elements are in contact by a periodic edge + is_periodic(el) = .true. + is_periodic(el2) = .true. + goto 100 + endif + endif + enddo + enddo + 100 continue + enddo + enddo + + ! user output + write(IMAIN,*) 'done detecting points for periodic boundary conditions.' + write(IMAIN,*) 'number of periodic elements found and grouped in the same partition: ',count(is_periodic) + call flush_IMAIN() + + ! loop on all the elements to find the first partition that contains a periodic element + ifirst_partition_found = -1 + do el = 0, nelmnts-1 + if (is_periodic(el)) then + ifirst_partition_found = part(el) + exit + endif + enddo + if (ifirst_partition_found < 0) call stop_the_code( & +'error: no periodic element found, even though ADD_PERIODIC_CONDITIONS is set') + + ! loop on all the elements to move all periodic elements to the first partition found + do el = 0, nelmnts-1 + if (is_periodic(el)) part(el) = ifirst_partition_found + enddo + + end subroutine periodic_edges_repartitioning + +! +!--------------------------------------------------------------------------------------- +! + + subroutine manual_crack_repartitioning(num_material,NPROC) + +! puts elements along manual crack into the same partition +! +! note: For now, elements material numbers are hard-coded and must be 2 (for left side) and 3 (right side) +! to indicate an element along the crack. +! To split nodes, see routine in add_manual_crack.f90 + + use constants, only: IMAIN,NCORNERS,ADD_A_SMALL_CRACK_IN_THE_MEDIUM + use part_unstruct_par, only: nelmnts,part + + implicit none + + integer, intent(in) :: nproc + integer, dimension(1:nelmnts), intent(in) :: num_material + + ! local parameters + logical, dimension(0:nelmnts-1) :: is_crack_element + integer :: ipartition_crack + integer :: el + + ! checks if anything to do + if (.not. ADD_A_SMALL_CRACK_IN_THE_MEDIUM) return + + ! user output + write(IMAIN,*) + write(IMAIN,*) 'detecting elements for manual crack.' + + ! sets flags for elements along the crack (material number 2 and 3) + is_crack_element(:) = .false. + ipartition_crack = nproc + 1 + do el = 0, nelmnts-1 + ! crack between material number 2 and 3 + if (num_material(el+1) == 2 .or. num_material(el+1) == 3) then + is_crack_element(el) = .true. + ! puts all crack elements into lowest partition possible + if (part(el) < ipartition_crack) ipartition_crack = part(el) + endif + enddo + + ! user output + write(IMAIN,*) 'number of crack elements ',count(is_crack_element),' found and grouped in the same partition ',ipartition_crack + call flush_IMAIN() + + if (count(is_crack_element) == 0) & + call stop_the_code('Error: no crack element found, even though ADD_A_SMALL_CRACK_IN_THE_MEDIUM is set') + if (ipartition_crack > nproc) & + call stop_the_code('Error: invalid partition number for crack elements') + + ! we will put all crack elements into the same partition + do el = 0, nelmnts-1 + if (is_crack_element(el)) part(el) = ipartition_crack + enddo + + end subroutine manual_crack_repartitioning diff --git a/meshfem2d/rotate_mesh.f90 b/meshfem2d/rotate_mesh.f90 new file mode 100644 index 00000000..1203e678 --- /dev/null +++ b/meshfem2d/rotate_mesh.f90 @@ -0,0 +1,728 @@ +!======================================================================== +! +! S P E C F E M 2 D +! ----------------- +! +! Main historical authors: Dimitri Komatitsch and Jeroen Tromp +! CNRS, France +! and Princeton University, USA +! (there are currently many more authors!) +! (c) October 2017 +! +! This software is a computer program whose purpose is to solve +! the two-dimensional viscoelastic anisotropic or poroelastic wave equation +! using a spectral-element method (SEM). +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 3 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License along +! with this program; if not, write to the Free Software Foundation, Inc., +! 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +! +! The full text of the license is available in file "LICENSE". +! +!======================================================================== + + !----------------------------------------------- + ! rotate_mesh_for_plane_wave. + ! rotate mesh elements to make sure topological absorbing surface + ! is aligned with physical absorbing surface, since this is the surface + ! that we use to impose the plane wave and Bielak boundary conditions. + !----------------------------------------------- + + subroutine rotate_mesh_for_plane_wave(NGNOD) + + use part_unstruct_par, only: elmnts,nelmnts,nelemabs,abs_surface + + implicit none + + integer, intent(in) :: NGNOD + + ! local parameters + integer :: i,j,ispec,i1,i2,inode,iswap + logical :: found_this_point + integer, dimension(:,:), allocatable :: ibool,ibool_rotated +!! DK DK beware here, "ibool" applies to the mesh corners (4 or 9 points) only, +!! DK DK not to the GLL points because there are no GLL points in the Gmsh mesh files + integer :: index_rotation1,index_rotation2,index_rotation3,index_rotation4, & + index_rotation5,index_rotation6,index_rotation7,index_rotation8,index_edge + + allocate(ibool(NGNOD,nelmnts)) + allocate(ibool_rotated(NGNOD,nelmnts)) + + ! At the end of the loop, thank to ibool we can access to the global number of + ! each node from the ispec of the element to which it belongs and from its + ! geometrical position : + ! 4 . . 7 . . 3 + ! . . + ! . . + ! 8 9 6 + ! . . + ! . . + ! 1 . . 5 . . 2 + ! --> we just create a copy in an easier format for ease of use in this routine + do ispec = 1, nelmnts + if (NGNOD == 4) then + ibool(1,ispec) = elmnts((ispec-1)*NGNOD) + ibool(2,ispec) = elmnts((ispec-1)*NGNOD+1) + ibool(3,ispec) = elmnts((ispec-1)*NGNOD+2) + ibool(4,ispec) = elmnts((ispec-1)*NGNOD+3) + else if (NGNOD == 9) then + ibool(1,ispec) = elmnts((ispec-1)*NGNOD) + ibool(2,ispec) = elmnts((ispec-1)*NGNOD+1) + ibool(3,ispec) = elmnts((ispec-1)*NGNOD+2) + ibool(4,ispec) = elmnts((ispec-1)*NGNOD+3) + ibool(5,ispec) = elmnts((ispec-1)*NGNOD+4) + ibool(6,ispec) = elmnts((ispec-1)*NGNOD+5) + ibool(7,ispec) = elmnts((ispec-1)*NGNOD+6) + ibool(8,ispec) = elmnts((ispec-1)*NGNOD+7) + ibool(9,ispec) = elmnts((ispec-1)*NGNOD+8) + else + call stop_the_code('error, NGNOD should be either 4 or 9 for external meshes') + endif + enddo + + do j = 1, 4 + if (j == 1) then + index_edge=3 + ibool_rotated(:,:) = ibool(:,:) + else if (j == 2) then + index_edge=1 + ibool(:,:) = ibool_rotated(:,:) + else if (j == 3) then + index_edge=4 + ibool(:,:) = ibool_rotated(:,:) + else if (j == 4) then + index_edge=2 + ibool(:,:) = ibool_rotated(:,:) + else + call stop_the_code('j should be >= 1 and <= 4') + endif + + if (index_edge == 1) then + ! bottom edge + index_rotation1 = 1 + index_rotation2 = 2 + index_rotation3 = 2 + index_rotation4 = 3 + index_rotation5 = 3 + index_rotation6 = 4 + index_rotation7 = 1 + index_rotation8 = 4 + ! index_rotation9 does not need to exist because the center rotates on itself + else if (index_edge == 2) then + ! right edge + index_rotation1 = 2 + index_rotation2 = 3 + index_rotation3 = 3 + index_rotation4 = 4 + index_rotation5 = 1 + index_rotation6 = 4 + index_rotation7 = 1 + index_rotation8 = 2 + ! index_rotation9 does not need to exist because the center rotates on itself + else if (index_edge == 3) then + ! top edge + index_rotation1 = 3 + index_rotation2 = 4 + index_rotation3 = 1 + index_rotation4 = 4 + index_rotation5 = 1 + index_rotation6 = 2 + index_rotation7 = 2 + index_rotation8 = 3 + ! index_rotation9 does not need to exist because the center rotates on itself + else if (index_edge == 4) then + ! left edge + index_rotation1 = 1 + index_rotation2 = 4 + index_rotation3 = 1 + index_rotation4 = 2 + index_rotation5 = 2 + index_rotation6 = 3 + index_rotation7 = 3 + index_rotation8 = 4 + ! index_rotation9 does not need to exist because the center rotates on itself + else + call stop_the_code('The edge on which abs_nodes is located should be defined') + endif + + do i = 1,nelemabs + if (index_edge == abs_surface(5,i)) then + ispec = abs_surface(1,i) + 1 !!!! be careful: ispec from abs_surface(1,i) start at zero + found_this_point = .false. + do inode = 1,NGNOD + if (ibool(inode,ispec) == abs_surface(3,i)) then + i1 = inode + found_this_point = .true. + exit + endif + enddo + + if (.not. found_this_point) call stop_the_code('point not found') + + found_this_point = .false. + do inode = 1,4 + if (ibool(inode,ispec) == abs_surface(4,i)) then + i2 = inode + found_this_point = .true. + exit + endif + enddo + if (.not. found_this_point) call stop_the_code('point not found') + + ! swap points if needed for clarity, to avoid testing both cases each time below + if (i1 > i2) then + iswap = i1 + i1 = i2 + i2 = iswap + endif + + ! test orientation + if (i1 == index_rotation1 .and. i2 == index_rotation2) then + ! print *,'orientation of element ',i,' is already good' + + else if (i1 == index_rotation3 .and. i2 == index_rotation4) then + !for this one, remember that we have swapped, thus 41 is 14 + ! print *,'element ',i,' must be rotated 3 times' + ibool_rotated(4,ispec) = ibool(1,ispec) + ibool_rotated(1,ispec) = ibool(2,ispec) + ibool_rotated(2,ispec) = ibool(3,ispec) + ibool_rotated(3,ispec) = ibool(4,ispec) + if (NGNOD == 9) then + ibool_rotated(8,ispec) = ibool(5,ispec) + ibool_rotated(5,ispec) = ibool(6,ispec) + ibool_rotated(6,ispec) = ibool(7,ispec) + ibool_rotated(7,ispec) = ibool(8,ispec) + ! 9th point is at the element center and thus never changes when we rotate an element + endif + + else if (i1 == index_rotation5 .and. i2 == index_rotation6) then + ! print *,'element ',i,ispec,' must be rotated 2 times top' + ibool_rotated(3,ispec) = ibool(1,ispec) + ibool_rotated(4,ispec) = ibool(2,ispec) + ibool_rotated(1,ispec) = ibool(3,ispec) + ibool_rotated(2,ispec) = ibool(4,ispec) + if (NGNOD == 9) then + ibool_rotated(7,ispec) = ibool(5,ispec) + ibool_rotated(8,ispec) = ibool(6,ispec) + ibool_rotated(5,ispec) = ibool(7,ispec) + ibool_rotated(6,ispec) = ibool(8,ispec) + ! 9th point is at the element center and thus never changes when we rotate an element + endif + + else if (i1 == index_rotation7 .and. i2 == index_rotation8) then + ! print *,'element ',i,' must be rotated 1 time' + ibool_rotated(2,ispec) = ibool(1,ispec) + ibool_rotated(3,ispec) = ibool(2,ispec) + ibool_rotated(4,ispec) = ibool(3,ispec) + ibool_rotated(1,ispec) = ibool(4,ispec) + if (NGNOD == 9) then + ibool_rotated(6,ispec) = ibool(5,ispec) + ibool_rotated(7,ispec) = ibool(6,ispec) + ibool_rotated(8,ispec) = ibool(7,ispec) + ibool_rotated(5,ispec) = ibool(8,ispec) + ! 9th point is at the element center and thus never changes when we rotate an element + endif + else + call stop_the_code('problem in an element') + endif + endif + enddo + enddo + +! here we put the result back in the not-so-easy to use format at the end of the routine + do ispec = 1, nelmnts + if (NGNOD == 4) then + elmnts((ispec-1)*NGNOD) = ibool_rotated(1,ispec) + elmnts((ispec-1)*NGNOD+1) = ibool_rotated(2,ispec) + elmnts((ispec-1)*NGNOD+2) = ibool_rotated(3,ispec) + elmnts((ispec-1)*NGNOD+3) = ibool_rotated(4,ispec) + else if (NGNOD == 9) then + elmnts((ispec-1)*NGNOD) = ibool_rotated(1,ispec) + elmnts((ispec-1)*NGNOD+1) = ibool_rotated(2,ispec) + elmnts((ispec-1)*NGNOD+2) = ibool_rotated(3,ispec) + elmnts((ispec-1)*NGNOD+3) = ibool_rotated(4,ispec) + elmnts((ispec-1)*NGNOD+4) = ibool_rotated(5,ispec) + elmnts((ispec-1)*NGNOD+5) = ibool_rotated(6,ispec) + elmnts((ispec-1)*NGNOD+6) = ibool_rotated(7,ispec) + elmnts((ispec-1)*NGNOD+7) = ibool_rotated(8,ispec) + elmnts((ispec-1)*NGNOD+8) = ibool_rotated(9,ispec) + else + call stop_the_code('error, NGNOD should be either 4 or 9 for external meshes') + endif + enddo + + end subroutine rotate_mesh_for_plane_wave + +! +!--------------------------------------------------------------------------------------- +! + + subroutine rotate_mesh_for_axisym(NGNOD) + +! This routine is almost the same than the one above with index_edge = 4 (left side of the model) +! It allows us to know that if i == 1 (first GLL point) we are on the axis. +! From axisymmetric elements mesh file with just know the ispec of the elements on the axis and the ibool of +! the two points that describe it : +! Ex : +! +! x=0 +! ... +! | +! O ibool = 235 ---> We want that index to be saved in ibool(1,ispec) or ibool(4,ispec) +! | +! | +! | ispec = 15 +! | +! | +! O ibool = 423 ---> We want that index to be saved in ibool(4,ispec) or ibool(1,ispec) +! | +! ... +! +! Indeed when we are using external mesher for axisymmetric simulations we do not control how the elements +! will be orientated. We could have code everything taking that into account but we have preferred +! to rotate the mesh. After that for each element on the axis we have got: +! +! r=0 +! | +! 4 . . 7 . . 3 +! . . +! . . +! 8 9 6 +! . . +! . . +! 1 . . 5 . . 2 +! | +! r=0 + + use part_unstruct_par, only: elmnts,nelmnts,nelem_on_the_axis,ispec_of_axial_elements, & + inode1_axial_elements,inode2_axial_elements + + implicit none + + integer, intent(in) :: NGNOD + integer :: i,ispec,i1,i2,inode,iswap + logical :: found_this_point + integer, dimension(:,:), allocatable :: ibool,ibool_rotated + !! DK DK be careful here, "ibool" applies to the mesh corners (4 or 9 points) only, + + allocate(ibool(NGNOD,nelmnts)) + allocate(ibool_rotated(NGNOD,nelmnts)) + + do ispec = 1, nelmnts ! Loop on the elements + ! At the end of the loop, thank to ibool we can access to the global number of + ! each node from the ispec of the element to which it belongs and from its + ! geometrical position : + ! 4 . . 7 . . 3 + ! . . + ! . . + ! 8 9 6 + ! . . + ! . . + ! 1 . . 5 . . 2 + ! --> we just create a copy in an easier format for ease of use in this routine + if (NGNOD == 4) then + ibool(1,ispec) = elmnts((ispec-1)*NGNOD) ! Have to be zero if ispec is on the axis + ibool(2,ispec) = elmnts((ispec-1)*NGNOD+1) + ibool(3,ispec) = elmnts((ispec-1)*NGNOD+2) + ibool(4,ispec) = elmnts((ispec-1)*NGNOD+3) ! Have to be zero if ispec is on the axis + else if (NGNOD == 9) then + ibool(1,ispec) = elmnts((ispec-1)*NGNOD) ! Have to be zero if ispec is on the axis + ibool(2,ispec) = elmnts((ispec-1)*NGNOD+1) + ibool(3,ispec) = elmnts((ispec-1)*NGNOD+2) + ibool(4,ispec) = elmnts((ispec-1)*NGNOD+3) ! Have to be zero if ispec is on the axis + ibool(5,ispec) = elmnts((ispec-1)*NGNOD+4) + ibool(6,ispec) = elmnts((ispec-1)*NGNOD+5) + ibool(7,ispec) = elmnts((ispec-1)*NGNOD+6) + ibool(8,ispec) = elmnts((ispec-1)*NGNOD+7) + ibool(9,ispec) = elmnts((ispec-1)*NGNOD+8) + else + call stop_the_code('rotate_mesh_for_axisym: error, NGNOD should be either 4 or 9 for external meshes') + endif + enddo + + ibool_rotated(:,:) = ibool(:,:) ! We make a copy of ibool in ibool_rotated + + ! print *," Loop on the elements on the axis... : " + do i = 1,nelem_on_the_axis ! Loop on the elements on the axis (read from the axisym file) + ispec = ispec_of_axial_elements(i) + 1 ! ispec_of_axial_elements starts from 0 + found_this_point = .false. + ! print *," Loop on the control points and look for ", inode1_axial_elements(i) + do inode = 1,4 ! loop on the corners of axial element ispec_of_axial_elements(i) to see if we find inode1_axial_elements(i) + if (ibool(inode,ispec) == inode1_axial_elements(i)) then + i1 = inode + found_this_point = .true. + exit + endif + enddo + if (.not. found_this_point) call stop_the_code('rotate_mesh_for_axisym: point not found 1') + found_this_point = .false. + do inode = 1,4 ! loop on the corners of axial element ispec_of_axial_elements(i) to see if we find inode2_axial_elements(i) + if (ibool(inode,ispec) == inode2_axial_elements(i)) then + i2 = inode + found_this_point = .true. + exit + endif + enddo + if (.not. found_this_point) call stop_the_code('rotate_mesh_for_axisym: point not found 2') + if (i1 > i2) then + ! swap points if needed for clarity, to avoid testing both cases each time below + ! Otherwise we would have done : if ((i1 == 1 .and. i2 == 4) .or. (i1 == 4 .and. i2 == 1)) then + ! print *,'orientation of element ',i,' is already good' + ! ... + iswap = i1 + i1 = i2 + i2 = iswap + endif + + ! print *,"point 1 (with coord 0):",inode1_axial_elements(i) + ! print *,"point 2 (with coord 0):",inode2_axial_elements(i) + ! print *,"ibool of this element :" + ! print *," ibool(1,ispec) :",ibool(1,ispec) + ! print *," ibool(2,ispec) :",ibool(2,ispec) + ! print *," ibool(3,ispec) :",ibool(3,ispec) + ! print *," ibool(4,ispec) :",ibool(4,ispec) + ! print *," i1 -->",i1 + ! print *," i2 -->",i2 + + ! test orientation + if (i1 == 1 .and. i2 == 4) then ! Orientation of this element is already good' + ! print *,'orientation of element ',i,' is already good' + else if (i1 == 1 .and. i2 == 2) then ! Remember that we have swapped, thus no need to test i1 == 1 and i2 == 1 + ! Element must be rotated 3 times + ! print *,'element ',i,' must be rotated 3 times' + ibool_rotated(4,ispec) = ibool(1,ispec) + ibool_rotated(1,ispec) = ibool(2,ispec) + ibool_rotated(2,ispec) = ibool(3,ispec) + ibool_rotated(3,ispec) = ibool(4,ispec) + if (NGNOD == 9) then + ibool_rotated(8,ispec) = ibool(5,ispec) + ibool_rotated(5,ispec) = ibool(6,ispec) + ibool_rotated(6,ispec) = ibool(7,ispec) + ibool_rotated(7,ispec) = ibool(8,ispec) + ! 9th point is at the element center and thus never changes when we rotate an element + endif + else if (i1 == 2 .and. i2 == 3) then ! Element must be rotated 2 times + ! print *,'element ',i,ispec,' must be rotated 2 times top' + ibool_rotated(3,ispec) = ibool(1,ispec) + ibool_rotated(4,ispec) = ibool(2,ispec) + ibool_rotated(1,ispec) = ibool(3,ispec) + ibool_rotated(2,ispec) = ibool(4,ispec) + if (NGNOD == 9) then + ibool_rotated(7,ispec) = ibool(5,ispec) + ibool_rotated(8,ispec) = ibool(6,ispec) + ibool_rotated(5,ispec) = ibool(7,ispec) + ibool_rotated(6,ispec) = ibool(8,ispec) + ! 9th point is at the element center and thus never changes when we rotate an element + endif + else if (i1 == 3 .and. i2 == 4) then ! Element must be rotated 1 time + ! print *,'element ',i,' must be rotated 1 time' + ibool_rotated(2,ispec) = ibool(1,ispec) + ibool_rotated(3,ispec) = ibool(2,ispec) + ibool_rotated(4,ispec) = ibool(3,ispec) + ibool_rotated(1,ispec) = ibool(4,ispec) + if (NGNOD == 9) then + ibool_rotated(6,ispec) = ibool(5,ispec) + ibool_rotated(7,ispec) = ibool(6,ispec) + ibool_rotated(8,ispec) = ibool(7,ispec) + ibool_rotated(5,ispec) = ibool(8,ispec) + ! 9th point is at the element center and thus never changes when we rotate an element + endif + else + call stop_the_code('rotate_mesh_for_axisym: problem in an element') + endif + enddo + + ! Here we put the result back in the not-so-easy to use format at the end of the routine + do ispec = 1, nelmnts + if (NGNOD == 4) then + elmnts((ispec-1)*NGNOD) = ibool_rotated(1,ispec) + elmnts((ispec-1)*NGNOD+1) = ibool_rotated(2,ispec) + elmnts((ispec-1)*NGNOD+2) = ibool_rotated(3,ispec) + elmnts((ispec-1)*NGNOD+3) = ibool_rotated(4,ispec) + else if (NGNOD == 9) then + elmnts((ispec-1)*NGNOD) = ibool_rotated(1,ispec) + elmnts((ispec-1)*NGNOD+1) = ibool_rotated(2,ispec) + elmnts((ispec-1)*NGNOD+2) = ibool_rotated(3,ispec) + elmnts((ispec-1)*NGNOD+3) = ibool_rotated(4,ispec) + elmnts((ispec-1)*NGNOD+4) = ibool_rotated(5,ispec) + elmnts((ispec-1)*NGNOD+5) = ibool_rotated(6,ispec) + elmnts((ispec-1)*NGNOD+6) = ibool_rotated(7,ispec) + elmnts((ispec-1)*NGNOD+7) = ibool_rotated(8,ispec) + elmnts((ispec-1)*NGNOD+8) = ibool_rotated(9,ispec) + else + call stop_the_code('rotate_mesh_for_axisym: error, NGNOD should be either 4 or 9 for external meshes') + endif + enddo + + end subroutine rotate_mesh_for_axisym + +! +!--------------------------------------------------------------------------------------- +! + + subroutine rotate_mesh_for_acoustic_forcing(NGNOD) + +! This routine is almost the same than the one at the top but for the acoustic forced elements +! Ex : +! +! x=0 +! ... +! | +! O ibool = 235 ---> We want that index to be saved in ibool(1,ispec) or ibool(4,ispec) +! | +! | +! | ispec = 15 +! | +! | +! O ibool = 423 ---> We want that index to be saved in ibool(4,ispec) or ibool(1,ispec) +! | +! ... +! +! Indeed when we are using external mesher we do not control how the elements +! will be orientated. We could have code everything taking that into account but we have preferred +! to rotate the mesh. After that for each element on the axis we have got: +! +! r=0 +! | +! 4 . . 7 . . 3 +! . . +! . . +! 8 9 6 +! . . +! . . +! 1 . . 5 . . 2 +! | +! r=0 + + use part_unstruct_par, only: elmnts,nelmnts,nelemacforcing,acforcing_surface + + implicit none + + integer, intent(in) :: NGNOD + + ! local parameters + integer :: i,j,ispec,i1,i2,inode,iswap + logical :: found_this_point + integer, dimension(:,:), allocatable :: ibool,ibool_rotated +!! DK DK be careful here, "ibool" applies to the mesh corners (4 or 9 points) only, +!! DK DK not to the GLL points because there are no GLL points in the Gmsh mesh files + integer :: index_rotation1,index_rotation2,index_rotation3,index_rotation4, & + index_rotation5,index_rotation6,index_rotation7,index_rotation8,index_edge + + allocate(ibool(NGNOD,nelmnts)) + allocate(ibool_rotated(NGNOD,nelmnts)) + + ! At the end of the loop, thank to ibool we can access to the global number of + ! each node from the ispec of the element to which it belongs and from its + ! geometrical position : + ! 4 . . 7 . . 3 + ! . . + ! . . + ! 8 9 6 + ! . . + ! . . + ! 1 . . 5 . . 2 + ! --> we just create a copy in an easier format for ease of use in this routine + do ispec = 1, nelmnts + if (NGNOD == 4) then + ibool(1,ispec) = elmnts((ispec-1)*NGNOD) + ibool(2,ispec) = elmnts((ispec-1)*NGNOD+1) + ibool(3,ispec) = elmnts((ispec-1)*NGNOD+2) + ibool(4,ispec) = elmnts((ispec-1)*NGNOD+3) + else if (NGNOD == 9) then + ibool(1,ispec) = elmnts((ispec-1)*NGNOD) + ibool(2,ispec) = elmnts((ispec-1)*NGNOD+1) + ibool(3,ispec) = elmnts((ispec-1)*NGNOD+2) + ibool(4,ispec) = elmnts((ispec-1)*NGNOD+3) + ibool(5,ispec) = elmnts((ispec-1)*NGNOD+4) + ibool(6,ispec) = elmnts((ispec-1)*NGNOD+5) + ibool(7,ispec) = elmnts((ispec-1)*NGNOD+6) + ibool(8,ispec) = elmnts((ispec-1)*NGNOD+7) + ibool(9,ispec) = elmnts((ispec-1)*NGNOD+8) + else + call stop_the_code('error, NGNOD should be either 4 or 9 for external meshes') + endif + enddo + + do j = 1, 4 + if (j == 1) then + index_edge=3 + ibool_rotated(:,:) = ibool(:,:) + else if (j == 2) then + index_edge=1 + ibool(:,:) = ibool_rotated(:,:) + else if (j == 3) then + index_edge=4 + ibool(:,:) = ibool_rotated(:,:) + else if (j == 4) then + index_edge=2 + ibool(:,:) = ibool_rotated(:,:) + else + call stop_the_code('j should be >= 1 and <= 4') + endif + + if (index_edge == 1) then + ! bottom edge + index_rotation1 = 1 + index_rotation2 = 2 + index_rotation3 = 2 + index_rotation4 = 3 + index_rotation5 = 3 + index_rotation6 = 4 + index_rotation7 = 1 + index_rotation8 = 4 + ! index_rotation9 does not need to exist because the center rotates on itself + else if (index_edge == 2) then + ! right edge + index_rotation1 = 2 + index_rotation2 = 3 + index_rotation3 = 3 + index_rotation4 = 4 + index_rotation5 = 1 + index_rotation6 = 4 + index_rotation7 = 1 + index_rotation8 = 2 + ! index_rotation9 does not need to exist because the center rotates on itself + else if (index_edge == 3) then + ! top edge + index_rotation1 = 3 + index_rotation2 = 4 + index_rotation3 = 1 + index_rotation4 = 4 + index_rotation5 = 1 + index_rotation6 = 2 + index_rotation7 = 2 + index_rotation8 = 3 + ! index_rotation9 does not need to exist because the center rotates on itself + else if (index_edge == 4) then + ! left edge + index_rotation1 = 1 + index_rotation2 = 4 + index_rotation3 = 1 + index_rotation4 = 2 + index_rotation5 = 2 + index_rotation6 = 3 + index_rotation7 = 3 + index_rotation8 = 4 + ! index_rotation9 does not need to exist because the center rotates on itself + else + call stop_the_code('The edge on which abs_nodes is located should be defined') + endif + + do i = 1,nelemacforcing + if (index_edge == acforcing_surface(5,i)) then + ispec = acforcing_surface(1,i) + 1 !!!! be careful: ispec from acforcing_surface(1,i) start at zero + found_this_point = .false. + do inode = 1,NGNOD + if (ibool(inode,ispec) == acforcing_surface(3,i)) then + i1 = inode + found_this_point = .true. + exit + endif + enddo + + if (.not. found_this_point) call stop_the_code('point not found') + + found_this_point = .false. + do inode = 1,4 + if (ibool(inode,ispec) == acforcing_surface(4,i)) then + i2 = inode + found_this_point = .true. + exit + endif + enddo + if (.not. found_this_point) call stop_the_code('point not found') + + ! swap points if needed for clarity, to avoid testing both cases each time below + if (i1 > i2) then + iswap = i1 + i1 = i2 + i2 = iswap + endif + + ! test orientation + if (i1 == index_rotation1 .and. i2 == index_rotation2) then + ! print *,'orientation of element ',i,' is already good' + + else if (i1 == index_rotation3 .and. i2 == index_rotation4) then + !for this one, remember that we have swapped, thus 41 is 14 + ! print *,'element ',i,' must be rotated 3 times' + ibool_rotated(4,ispec) = ibool(1,ispec) + ibool_rotated(1,ispec) = ibool(2,ispec) + ibool_rotated(2,ispec) = ibool(3,ispec) + ibool_rotated(3,ispec) = ibool(4,ispec) + if (NGNOD == 9) then + ibool_rotated(8,ispec) = ibool(5,ispec) + ibool_rotated(5,ispec) = ibool(6,ispec) + ibool_rotated(6,ispec) = ibool(7,ispec) + ibool_rotated(7,ispec) = ibool(8,ispec) + ! 9th point is at the element center and thus never changes when we rotate an element + endif + + else if (i1 == index_rotation5 .and. i2 == index_rotation6) then + ! print *,'element ',i,ispec,' must be rotated 2 times top' + ibool_rotated(3,ispec) = ibool(1,ispec) + ibool_rotated(4,ispec) = ibool(2,ispec) + ibool_rotated(1,ispec) = ibool(3,ispec) + ibool_rotated(2,ispec) = ibool(4,ispec) + if (NGNOD == 9) then + ibool_rotated(7,ispec) = ibool(5,ispec) + ibool_rotated(8,ispec) = ibool(6,ispec) + ibool_rotated(5,ispec) = ibool(7,ispec) + ibool_rotated(6,ispec) = ibool(8,ispec) + ! 9th point is at the element center and thus never changes when we rotate an element + endif + + else if (i1 == index_rotation7 .and. i2 == index_rotation8) then + ! print *,'element ',i,' must be rotated 1 time' + ibool_rotated(2,ispec) = ibool(1,ispec) + ibool_rotated(3,ispec) = ibool(2,ispec) + ibool_rotated(4,ispec) = ibool(3,ispec) + ibool_rotated(1,ispec) = ibool(4,ispec) + if (NGNOD == 9) then + ibool_rotated(6,ispec) = ibool(5,ispec) + ibool_rotated(7,ispec) = ibool(6,ispec) + ibool_rotated(8,ispec) = ibool(7,ispec) + ibool_rotated(5,ispec) = ibool(8,ispec) + ! 9th point is at the element center and thus never changes when we rotate an element + endif + else + call stop_the_code('problem in an element') + endif + endif + enddo + enddo + +! here we put the result back in the not-so-easy to use format at the end of the routine + do ispec = 1, nelmnts + if (NGNOD == 4) then + elmnts((ispec-1)*NGNOD) = ibool_rotated(1,ispec) + elmnts((ispec-1)*NGNOD+1) = ibool_rotated(2,ispec) + elmnts((ispec-1)*NGNOD+2) = ibool_rotated(3,ispec) + elmnts((ispec-1)*NGNOD+3) = ibool_rotated(4,ispec) + else if (NGNOD == 9) then + elmnts((ispec-1)*NGNOD) = ibool_rotated(1,ispec) + elmnts((ispec-1)*NGNOD+1) = ibool_rotated(2,ispec) + elmnts((ispec-1)*NGNOD+2) = ibool_rotated(3,ispec) + elmnts((ispec-1)*NGNOD+3) = ibool_rotated(4,ispec) + elmnts((ispec-1)*NGNOD+4) = ibool_rotated(5,ispec) + elmnts((ispec-1)*NGNOD+5) = ibool_rotated(6,ispec) + elmnts((ispec-1)*NGNOD+6) = ibool_rotated(7,ispec) + elmnts((ispec-1)*NGNOD+7) = ibool_rotated(8,ispec) + elmnts((ispec-1)*NGNOD+8) = ibool_rotated(9,ispec) + else + call stop_the_code('error, NGNOD should be either 4 or 9 for external meshes') + endif + enddo + + end subroutine rotate_mesh_for_acoustic_forcing diff --git a/meshfem2d/rules.mk b/meshfem2d/rules.mk new file mode 100644 index 00000000..be46e802 --- /dev/null +++ b/meshfem2d/rules.mk @@ -0,0 +1,110 @@ +#======================================================================== +# +# S P E C F E M 2 D +# ----------------- +# +# Main historical authors: Dimitri Komatitsch and Jeroen Tromp +# Princeton University, USA +# and CNRS / University of Marseille, France +# (there are currently many more authors!) +# (c) Princeton University and CNRS / University of Marseille, April 2014 +# +# This software is a computer program whose purpose is to solve +# the two-dimensional viscoelastic anisotropic or poroelastic wave equation +# using a spectral-element method (SEM). +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# The full text of the license is available in file "LICENSE". +# +#======================================================================== + +## compilation directories +S := ${S_TOP}/src/shared +$(shared_OBJECTS): S = ${S_TOP}/src/shared + +####################################### + +shared_TARGETS = \ + $(shared_OBJECTS) \ + $(EMPTY_MACRO) + + +shared_OBJECTS = \ + $O/shared_par.shared_module.o \ + $O/define_shape_functions.shared.o \ + $O/exit_mpi.shared.o \ + $O/force_ftz.cc.o \ + $O/gll_library.shared.o \ + $O/lagrange_poly.shared.o \ + $O/parallel.sharedmpi.o \ + $O/param_reader.cc.o \ + $O/read_interfaces_file.shared.o \ + $O/read_material_table.shared.o \ + $O/read_parameter_file.shared.o \ + $O/read_regions.shared.o \ + $O/read_source_file.shared.o \ + $O/read_value_parameters.shared.o \ + $O/set_color_palette.shared.o \ + $O/spline_routines.shared.o \ + $O/write_VTK_data.shared.o \ + $(EMPTY_MACRO) + + +shared_MODULES = \ + $(FC_MODDIR)/constants.$(FC_MODEXT) \ + $(FC_MODDIR)/shared_input_parameters.$(FC_MODEXT) \ + $(FC_MODDIR)/shared_parameters.$(FC_MODEXT) \ + $(FC_MODDIR)/my_mpi.$(FC_MODEXT) \ + $(FC_MODDIR)/source_file_par.$(FC_MODEXT) \ + $(EMPTY_MACRO) + + +####################################### + +#### +#### rule for each .o file below +#### + + +## +## shared +## + +$O/%.shared_module.o: $S/%.f90 ${SETUP}/constants.h + ${FCCOMPILE_CHECK} ${FCFLAGS_f90} -c -o $@ $< + +$O/%.shared_module.o: $S/%.F90 ${SETUP}/constants.h + ${FCCOMPILE_CHECK} ${FCFLAGS_f90} -c -o $@ $< + +$O/%.shared.o: $S/%.f90 $O/shared_par.shared_module.o + ${FCCOMPILE_CHECK} ${FCFLAGS_f90} -c -o $@ $< + +$O/%.shared.o: $S/%.F90 $O/shared_par.shared_module.o + ${FCCOMPILE_CHECK} ${FCFLAGS_f90} -c -o $@ $< + +$O/%.sharedmpi.o: $S/%.f90 $O/shared_par.shared_module.o + ${MPIFCCOMPILE_CHECK} ${FCFLAGS_f90} -c -o $@ $< + +$O/%.sharedmpi.o: $S/%.F90 $O/shared_par.shared_module.o + ${MPIFCCOMPILE_CHECK} ${FCFLAGS_f90} -c -o $@ $< + + +## +## C compilation +## + +$O/%.cc.o: $S/%.c ${SETUP}/config.h + ${CC} -c $(CPPFLAGS) $(CFLAGS) -o $@ $< diff --git a/meshfem2d/save_databases.f90 b/meshfem2d/save_databases.f90 new file mode 100644 index 00000000..d8274208 --- /dev/null +++ b/meshfem2d/save_databases.f90 @@ -0,0 +1,814 @@ +!======================================================================== +! +! S P E C F E M 2 D +! ----------------- +! +! Main historical authors: Dimitri Komatitsch and Jeroen Tromp +! CNRS, France +! and Princeton University, USA +! (there are currently many more authors!) +! (c) October 2017 +! +! This software is a computer program whose purpose is to solve +! the two-dimensional viscoelastic anisotropic or poroelastic wave equation +! using a spectral-element method (SEM). +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 3 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License along +! with this program; if not, write to the Free Software Foundation, Inc., +! 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +! +! The full text of the license is available in file "LICENSE". +! +!======================================================================== + +subroutine save_databases() + +! generates the databases for the solver + + use constants, only: IMAIN,IOUT,MAX_STRING_LEN,SAVE_MESHFILES_VTK_FORMAT,myrank + use part_unstruct_par, only: nspec,iproc + use shared_parameters, only: NPROC, database_filename, OUTPUT_FILES + + implicit none + + ! local parameters + integer :: ier + character(len=MAX_STRING_LEN) :: prname + + do iproc = 0, NPROC-1 + + ! filename + prname = database_filename + + ! user output + if (myrank == 0) then + write(IMAIN,*) ' database file: ',trim(prname) + call flush_IMAIN() + endif + + ! opens Database file + ! note: adding access='stream' would further decrease file size + open(unit=IOUT,file=trim(prname),status='unknown',action='write',form='unformatted',iostat=ier) + if (ier /= 0 ) call stop_the_code('Error saving databases; check that directory OUTPUT_FILES exists') + + ! saves header infos and simulation setup + call save_databases_init() + + ! sources setup + !call save_databases_sources() + + ! mesh node coordinates and mesh properties + call save_databases_coorg_elem() + + ! attenuation + call save_databases_attenuation() + + ! material properties + call save_databases_materials() + + ! saves mpi/partition interface + call save_databases_interfaces() + + ! absorbing boundary + call save_databases_absorbing() + + ! acoustic forcing + call save_databases_acoustic_forcing() + + ! acoustic free surface + call save_databases_free_surf() + + ! coupled domain edges + call save_databases_coupled() + + ! tangential detection curve + call save_databases_tangential() + + ! axial elements + call save_databases_axial_elements() + + ! closes Database file + close(IOUT) + + ! user output + if (myrank == 0) then + write(IMAIN,*) ' slice ',iproc,' has number of spectral elements =',nspec + write(IMAIN,*) + call flush_IMAIN() + endif + + enddo + + ! mesh file output for visualization + if (SAVE_MESHFILES_VTK_FORMAT) call save_databases_VTK_files() + +end subroutine save_databases + + +!------------------------------------------------------------------------------- + +subroutine save_databases_init() + + use constants, only: IOUT,ADD_RANDOM_PERTURBATION_TO_THE_MESH,ADD_PERTURBATION_AROUND_SOURCE_ONLY + use shared_parameters + use part_unstruct_par, only: iproc,nspec,npgeo,region_pml_external_mesh + + implicit none + + ! prepare total numbers + ! only counts number of nodes (npgeo) for this partition (iproc) + call write_glob2loc_nodes_database(IOUT, iproc, npgeo, 1) + + ! only counts number of elements (nspec) for this partition (iproc) + ! DK DK add support for using PML in MPI mode with external mesh + ! call write_partition_database(IOUT, iproc, nspec, num_material, NGNOD, 1) + call write_partition_database(IOUT, iproc, nspec, num_material, region_pml_external_mesh, NGNOD, 1) + + ! file output + ! note: older version used ascii-output and annotated all parameters + ! since this is now in binary format, we remove the text strings as they were not used any further + ! header infos and simulation setup + ! '# Database for SPECFEM2D' + + ! 'Title of the simulation' + write(IOUT) title + + ! 'Type of simulation' + write(IOUT) NOISE_TOMOGRAPHY, UNDO_ATTENUATION_AND_OR_PML + + ! 'nspec' + write(IOUT) nspec + + ! 'npgeo NPROC' + write(IOUT) npgeo,NPROC + + ! 'output_grid_Gnuplot interpol' + write(IOUT) output_grid_Gnuplot,interpol + + ! 'NTSTEP_BETWEEN_OUTPUT_INFO' + write(IOUT) NTSTEP_BETWEEN_OUTPUT_INFO + + ! 'NTSTEP_BETWEEN_OUTPUT_SEISMOS' + write(IOUT) NTSTEP_BETWEEN_OUTPUT_SEISMOS + + ! 'NTSTEP_BETWEEN_OUTPUT_IMAGES' + write(IOUT) NTSTEP_BETWEEN_OUTPUT_IMAGES + + ! 'PML_BOUNDARY_CONDITIONS' + write(IOUT) PML_BOUNDARY_CONDITIONS + + ! 'ROTATE_PML_ACTIVATE' + write(IOUT) ROTATE_PML_ACTIVATE + + ! 'ROTATE_PML_ANGLE' + write(IOUT) ROTATE_PML_ANGLE + + ! 'K_MIN_PML' + write(IOUT) K_MIN_PML + + ! 'K_MAX_PML' + write(IOUT) K_MAX_PML + + ! 'damping_change_factor_acoustic' + write(IOUT) damping_change_factor_acoustic + + ! 'damping_change_factor_elastic' + write(IOUT) damping_change_factor_elastic + + ! 'PML_PARAMETER_ADJUSTMENT' + write(IOUT) PML_PARAMETER_ADJUSTMENT + + ! 'read_external_mesh' + write(IOUT) read_external_mesh + + ! 'NELEM_PML_THICKNESS' + write(IOUT) NELEM_PML_THICKNESS + + ! 'NTSTEP_BETWEEN_OUTPUT_SAMPLE imagetype_JPEG imagetype_wavefield_dumps' + write(IOUT) NTSTEP_BETWEEN_OUTPUT_SAMPLE,imagetype_JPEG,imagetype_wavefield_dumps + + ! 'output_postscript_snapshot output_color_image' + write(IOUT) output_postscript_snapshot,output_color_image + + ! 'meshvect modelvect boundvect cutsnaps subsamp_postscript sizemax_arrows' + write(IOUT) meshvect,modelvect,boundvect,cutsnaps,subsamp_postscript,sizemax_arrows + + ! 'anglerec' + write(IOUT) anglerec + + ! 'initialfield' + write(IOUT) initialfield + + ! 'add_Bielak_conditions_bottom','add_Bielak_conditions_right','add_Bielak_conditions_top','add_Bielak_conditions_left' + write(IOUT) add_Bielak_conditions_bottom,add_Bielak_conditions_right,add_Bielak_conditions_top,add_Bielak_conditions_left + + ! 'seismotype imagetype_postscript' + write(IOUT) seismotype,imagetype_postscript + + ! 'MODEL' + write(IOUT) MODEL + + ! 'SAVE_MODEL' + write(IOUT) SAVE_MODEL + + ! 'TOMOGRAPHY_FILE' + write(IOUT) TOMOGRAPHY_FILE + + ! 'output_grid_ASCII OUTPUT_ENERGY NTSTEP_BETWEEN_OUTPUT_ENERGY output_wavefield_dumps' + write(IOUT) output_grid_ASCII,OUTPUT_ENERGY,NTSTEP_BETWEEN_OUTPUT_ENERGY,output_wavefield_dumps + + ! 'use_binary_for_wavefield_dumps' + write(IOUT) use_binary_for_wavefield_dumps + + ! 'ATTENUATION_VISCOELASTIC ATTENUATION_PORO_FLUID_PART ATTENUATION_VISCOACOUSTIC' + write(IOUT) ATTENUATION_VISCOELASTIC,ATTENUATION_PORO_FLUID_PART,ATTENUATION_VISCOACOUSTIC + + ! 'USE_SOLVOPT' + write(IOUT) USE_SOLVOPT + + ! 'save_ASCII_seismograms' + write(IOUT) save_ASCII_seismograms + + ! 'save_binary_seismograms_single save_binary_seismograms_double' + write(IOUT) save_binary_seismograms_single,save_binary_seismograms_double + + ! 'USE_TRICK_FOR_BETTER_PRESSURE' + write(IOUT) USE_TRICK_FOR_BETTER_PRESSURE + + ! 'COMPUTE_INTEGRATED_ENERGY_FIELD' + write(IOUT) COMPUTE_INTEGRATED_ENERGY_FIELD + + ! 'save_ASCII_kernels' + write(IOUT) save_ASCII_kernels + + ! 'NTSTEP_BETWEEN_COMPUTE_KERNELS' + write(IOUT) NTSTEP_BETWEEN_COMPUTE_KERNELS + + ! 'APPROXIMATE_HESS_KL' + write(IOUT) APPROXIMATE_HESS_KL + + ! 'NO_BACKWARD_RECONSTRUCTION' + write(IOUT) NO_BACKWARD_RECONSTRUCTION + + ! 'DRAW_SOURCES_AND_RECEIVERS' + write(IOUT) DRAW_SOURCES_AND_RECEIVERS + + ! 'Q0_poroelastic freq0_poroelastic' + write(IOUT) Q0_poroelastic,freq0_poroelastic + + ! 'Axisymmetric (2.5D, .true.) or Cartesian planar (2D; .false.) simulation' + write(IOUT) AXISYM + + ! 'P_SV' + write(IOUT) P_SV + + ! 'factor_subsample_image' + write(IOUT) factor_subsample_image + + ! 'USE_CONSTANT_MAX_AMPLITUDE' + write(IOUT) USE_CONSTANT_MAX_AMPLITUDE + + ! 'CONSTANT_MAX_AMPLITUDE_TO_USE' + write(IOUT) CONSTANT_MAX_AMPLITUDE_TO_USE + + ! 'USE_SNAPSHOT_NUMBER_IN_FILENAME' + write(IOUT) USE_SNAPSHOT_NUMBER_IN_FILENAME + + ! 'DRAW_WATER_IN_BLUE' + write(IOUT) DRAW_WATER_IN_BLUE + + ! 'US_LETTER' + write(IOUT) US_LETTER + + ! 'POWER_DISPLAY_COLOR' + write(IOUT) POWER_DISPLAY_COLOR + + ! 'SU_FORMAT' + write(IOUT) SU_FORMAT + + ! 'USER_T0' + write(IOUT) USER_T0 + + ! 'time_stepping_scheme' + write(IOUT) time_stepping_scheme + + ! 'ADD_PERIODIC_CONDITIONS' + write(IOUT) ADD_PERIODIC_CONDITIONS + + ! 'PERIODIC_HORIZ_DIST' + write(IOUT) PERIODIC_HORIZ_DIST + + ! 'GPU_MODE' + write(IOUT) GPU_MODE + + ! 'setup_with_binary_database" + write(IOUT) setup_with_binary_database + + ! 'NSTEP DT' + write(IOUT) NSTEP,DT + + ! 'NT_DUMP_ATTENUATION' + write(IOUT) NT_DUMP_ATTENUATION + + ! 'ACOUSTIC_FORCING' + write(IOUT) ACOUSTIC_FORCING + + ! 'NUMBER_OF_SIMULTANEOUS_RUNS' + write(IOUT) NUMBER_OF_SIMULTANEOUS_RUNS + + ! 'BROADCAST_SAME_MESH_AND_MODEL' + write(IOUT) BROADCAST_SAME_MESH_AND_MODEL + + ! 'ADD_RANDOM_PERTURBATION_TO_THE_MESH,ADD_PERTURBATION_AROUND_SOURCE_ONLY' + write(IOUT) ADD_RANDOM_PERTURBATION_TO_THE_MESH,ADD_PERTURBATION_AROUND_SOURCE_ONLY + +end subroutine save_databases_init + +!------------------------------------------------------------------------------- + +! original routine left here for reference... +! +! subroutine save_databases_sources() +! +! use constants, only: IOUT +! use source_file_par +! use shared_parameters +! +! implicit none +! ! local parameters +! integer :: i_source +! +! ! sources setup +! ! 'NSOURCES' +! write(IOUT) NSOURCES +! +! do i_source = 1,NSOURCES +! write(IOUT) source_type(i_source),time_function_type(i_source) +! write(IOUT) name_of_source_file(i_source) +! write(IOUT) burst_band_width(i_source) +! write(IOUT) xs(i_source),zs(i_source) +! write(IOUT) f0_source(i_source),tshift_src(i_source) +! write(IOUT) factor(i_source),anglesource(i_source) +! write(IOUT) Mxx(i_source),Mzz(i_source),Mxz(i_source) +! enddo +! +! end subroutine save_databases_sources +! + +!------------------------------------------------------------------------------- + +subroutine save_databases_coorg_elem() + + use constants, only: IOUT + use part_unstruct_par + use shared_parameters + + implicit none + + ! 'Coordinates of macrobloc mesh (coorg):' + + call write_glob2loc_nodes_database(IOUT, iproc, npgeo, 2) + + ! 'numat NGNOD nspec pointsdisp plot_lowerleft_corner_only' + write(IOUT) nbmodels,NGNOD,nspec,pointsdisp,plot_lowerleft_corner_only + + ! counts number of absorbing elements + if (any_abs) then + call write_abs_merge_database(IOUT, iproc, 1) + else + nelemabs_loc = 0 + endif + + ! counts number of acoustic forcing elements + if (ACOUSTIC_FORCING) then + call write_acoustic_forcing_merge_database(IOUT, iproc, 1) + else + nelemacforcing_loc = 0 + endif + + ! counts number of acoustic surface elements + call write_surface_database(IOUT, nelem_acoustic_surface, acoustic_surface, nelem_acoustic_surface_loc,iproc, 1) + + ! counts number of coupling edges + ! fluid-solid + call write_fluidsolid_edges_database(IOUT, nedges_coupled, edges_coupled, nedges_coupled_loc, iproc, 1) + ! fluid-poroelastic + call write_fluidsolid_edges_database(IOUT, nedges_acporo_coupled, edges_acporo_coupled, nedges_acporo_coupled_loc, iproc, 1) + ! solid-poroelastic + call write_fluidsolid_edges_database(IOUT, nedges_elporo_coupled, edges_elporo_coupled, nedges_elporo_coupled_loc, iproc, 1) + + ! counts number of axial elements + call write_axial_elements_database(IOUT, nelem_on_the_axis, ispec_of_axial_elements, & + nelem_on_the_axis_loc, iproc, 1, remove_min_to_start_at_zero) + + ! 'nelemabs nelemacforcing nelem_acoustic_surface num_fluid_solid_edges' + ! 'num_fluid_poro_edges num_solid_poro_edges' + ! 'nnodes_tangential_curve nelem_on_the_axis' + write(IOUT) nelemabs_loc,nelemacforcing_loc,nelem_acoustic_surface_loc, & + nedges_coupled_loc,nedges_acporo_coupled_loc, & + nedges_elporo_coupled_loc,nnodes_tangential_curve, & + nelem_on_the_axis_loc + +end subroutine save_databases_coorg_elem + +!------------------------------------------------------------------------------- + +subroutine save_databases_attenuation() + + use constants, only: IOUT + use part_unstruct_par + use shared_parameters + + implicit none + + ! attenuation setting + ! 'attenuation' + write(IOUT) N_SLS, ATTENUATION_f0_REFERENCE, READ_VELOCITIES_AT_f0 + +end subroutine save_databases_attenuation + +!------------------------------------------------------------------------------- + +subroutine save_databases_materials() + + use constants, only: IOUT,ISOTROPIC_MATERIAL,ANISOTROPIC_MATERIAL,POROELASTIC_MATERIAL + use part_unstruct_par + use shared_parameters + + implicit none + + ! local parameters + double precision :: val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12 + integer :: i,indic + + ! material set header + ! Material sets (num 1 rho vp vs 0 0 QKappa Qmu 0 0 0 0 0 0) acoustic/elastic + ! (num 2 rho c11 c13 c15 c33 c35 c55 c12 c23 c25 c22 Qkappa Qmu) anisotropic + ! (num 3 rhos rhof phi c k_xx k_xz k_zz Ks Kf Kfr etaf mufr Qmu) poroelastic + + do i = 1,nbmodels + ! material type + indic = icodemat(i) + + if (indic == ISOTROPIC_MATERIAL) then + ! isotropic elastic/acoustic + val0 = rho_s_read(i) + val1 = cp(i) + val2 = cs(i) + val3 = comp_g(i) + val4 = 0.d0 + val5 = QKappa(i) + val6 = Qmu(i) + val7 = 0.d0 + val8 = 0.d0 + val9 = 0.d0 + val10 = 0.d0 + val11 = 0.d0 + val12 = 0.d0 + ! old + !write(IOUT) i,icodemat(i),rho_s_read(i),cp(i),cs(i),0,0,QKappa(i),Qmu(i),0,0,0,0,0,0 + + else if (indic == ANISOTROPIC_MATERIAL) then + ! anisotropic + val0 = rho_s_read(i) + val1 = aniso3(i) + val2 = aniso4(i) + val3 = aniso5(i) + val4 = aniso6(i) + val5 = aniso7(i) + val6 = aniso8(i) + val7 = aniso9(i) + val8 = aniso10(i) + val9 = aniso11(i) + val10 = aniso12(i) + val11 = QKappa(i) + val12 = Qmu(i) + ! old + !write(IOUT) i,icodemat(i),rho_s_read(i), & + ! aniso3(i),aniso4(i),aniso5(i),aniso6(i), & + ! aniso7(i),aniso8(i),aniso9(i),aniso10(i),aniso11(i),aniso12(i),0,0 + + else if (indic == POROELASTIC_MATERIAL) then + ! poro-elastic + val0 = rho_s_read(i) + val1 = rho_f_read(i) + val2 = phi_read(i) + val3 = tortuosity_read(i) + val4 = permxx_read(i) + val5 = permxz_read(i) + val6 = permzz_read(i) + val7 = kappa_s_read(i) + val8 = kappa_f_read(i) + val9 = kappa_fr_read(i) + val10 = eta_f_read(i) + val11 = mu_fr_read(i) + val12 = Qmu(i) + ! old + !write(IOUT) i,icodemat(i),rho_s_read(i),rho_f_read(i),phi_read(i),tortuosity_read(i), & + ! permxx_read(i),permxz_read(i),permzz_read(i),kappa_s_read(i), & + ! kappa_f_read(i),kappa_fr_read(i),eta_f_read(i),mu_fr_read(i),Qmu(i) + + else if (indic <= 0) then + ! external material + ! The values will be read from an external tomo file + val0 = rho_s_read(i) + val1 = cp(i) + val2 = cs(i) + val3 = 0.d0 + val4 = 0.d0 + val5 = QKappa(i) + val6 = Qmu(i) + val7 = 0.d0 + val8 = 0.d0 + val9 = 0.d0 + val10 = 0.d0 + val11 = 0.d0 + val12 = 0.d0 + ! old + !write(IOUT) i,icodemat(i),rho_s_read(i),cp(i),cs(i),0,0,QKappa(i),Qmu(i),0,0,0,0,0,0 + else + ! case should not occur + call stop_the_code('Unknown material code') + endif + + ! check format with file src/specfem2D/read_materials.f90 + write(IOUT) i,indic,val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12 + enddo + + ! writes out material properties + ! 'Arrays kmato and knods for each bloc:' + +! DK DK add support for using PML in MPI mode with external mesh +! call write_partition_database(IOUT, iproc, nspec, num_material, NGNOD, 2) + call write_partition_database(IOUT, iproc, nspec, num_material, region_pml_external_mesh, NGNOD, 2) + +end subroutine save_databases_materials + +!------------------------------------------------------------------------------- + +subroutine save_databases_interfaces() + + use constants, only: IOUT + use part_unstruct_par + use decompose_par + use shared_parameters, only: NPROC + + implicit none + + ! local parameters + integer :: idummy + integer :: max_interfaces + integer :: my_ninterface + + if (NPROC /= 1) then + ! counts interfaces + call write_interfaces_database(IOUT, NPROC, iproc,my_ninterface, my_interfaces, my_nb_interfaces, 1) + + max_interfaces = maxval(my_nb_interfaces) + + ! 'Interfaces:' + write(IOUT) my_ninterface, max_interfaces + + ! writes out interface infos + call write_interfaces_database(IOUT, NPROC, iproc,my_ninterface, my_interfaces, my_nb_interfaces, 2) + + else + ! single partition, no interfaces + ! dummy + idummy = 0 + ! 'Interfaces:' + write(IOUT) idummy, idummy + endif + +end subroutine save_databases_interfaces + +!------------------------------------------------------------------------------- + +subroutine save_databases_absorbing() + + use constants, only: IOUT + use shared_parameters, only: any_abs + use part_unstruct_par, only: iproc + + implicit none + + ! 'List of absorbing elements (edge1 edge2 edge3 edge4 type):' + if (any_abs) then + ! writes out absorbing boundaries + call write_abs_merge_database(IOUT, iproc, 2) + endif + +end subroutine save_databases_absorbing + +!------------------------------------------------------------------------------- + +subroutine save_databases_acoustic_forcing() + + use constants, only: IOUT + use shared_parameters, only: ACOUSTIC_FORCING + use part_unstruct_par, only: iproc + + implicit none + + ! 'List of acoustic forcing elements (edge1 edge2 edge3 edge4 type):' + if (ACOUSTIC_FORCING) then + ! writes out acoustic forcing edges + call write_acoustic_forcing_merge_database(IOUT, iproc, 2) + endif + +end subroutine save_databases_acoustic_forcing + +!------------------------------------------------------------------------------- + +subroutine save_databases_free_surf() + + use constants, only: IOUT + use part_unstruct_par + + implicit none + + ! 'List of acoustic free-surface elements:' + call write_surface_database(IOUT, nelem_acoustic_surface, acoustic_surface, nelem_acoustic_surface_loc,iproc, 2) + +end subroutine save_databases_free_surf + +!------------------------------------------------------------------------------- + +subroutine save_databases_coupled() + + use constants, only: IOUT + use part_unstruct_par + + implicit none + + ! 'List of acoustic elastic coupled edges:' + call write_fluidsolid_edges_database(IOUT, nedges_coupled, edges_coupled, nedges_coupled_loc, iproc, 2) + + ! 'List of acoustic poroelastic coupled edges:' + call write_fluidsolid_edges_database(IOUT, nedges_acporo_coupled, edges_acporo_coupled, nedges_acporo_coupled_loc, iproc, 2) + + ! 'List of poroelastic elastic coupled edges:' + call write_fluidsolid_edges_database(IOUT, nedges_elporo_coupled, edges_elporo_coupled, nedges_elporo_coupled_loc, iproc, 2) + +end subroutine save_databases_coupled + +!------------------------------------------------------------------------------- + +subroutine save_databases_tangential() + + use constants, only: IOUT + use part_unstruct_par + use shared_parameters + + implicit none + + ! local parameters + integer :: i + + ! 'List of tangential detection curve nodes:' + write(IOUT) force_normal_to_surface,rec_normal_to_surface + + if (force_normal_to_surface .or. rec_normal_to_surface) then + do i = 1, nnodes_tangential_curve + write(IOUT) nodes_tangential_curve(1,i),nodes_tangential_curve(2,i) + enddo + endif + +end subroutine save_databases_tangential + +!------------------------------------------------------------------------------- + +subroutine save_databases_axial_elements + + use constants, only: IOUT + use part_unstruct_par + + implicit none + + ! 'List of axial elements:' + call write_axial_elements_database(IOUT, nelem_on_the_axis, ispec_of_axial_elements, & + nelem_on_the_axis_loc, iproc, 2, remove_min_to_start_at_zero) + +end subroutine save_databases_axial_elements + +!------------------------------------------------------------------------------- + + +subroutine save_databases_VTK_files() + +! saves mesh files as VTK file + + use constants, only: MAX_STRING_LEN,SAVE_MESHFILES_VTK_FORMAT,IMAIN,myrank + use part_unstruct_par, only: part,elmnts,nodes_coords,nelmnts,nnodes + use shared_parameters, only: NGNOD,num_material,NPROC,OUTPUT_FILES + + implicit none + + ! vtk output + integer :: ispec,i,j,inum,iproc,nspec + integer,dimension(:,:),allocatable :: tmp_elmnts + integer, dimension(:),allocatable :: tmp_elem_flag + double precision,dimension(:),allocatable :: xstore_dummy,zstore_dummy + character(len=MAX_STRING_LEN) :: filename + + ! checks if anything to do + if (.not. SAVE_MESHFILES_VTK_FORMAT) return + + ! user output + if (myrank == 0) then + write(IMAIN,*) ' VTK mesh files:' + call flush_IMAIN() + endif + + ! outputs material flag assignment on elements + allocate(tmp_elmnts(NGNOD,nelmnts)) + allocate(tmp_elem_flag(nelmnts)) + do ispec = 1, nelmnts + do j = 1, NGNOD + tmp_elmnts(j,ispec) = elmnts((ispec-1)*NGNOD+(j-1))+1 + enddo + tmp_elem_flag(ispec) = num_material(ispec) + enddo + + allocate(xstore_dummy(nnodes),zstore_dummy(nnodes)) + xstore_dummy(:) = nodes_coords(1,:) + zstore_dummy(:) = nodes_coords(2,:) + + ! materials + filename = trim(OUTPUT_FILES)//'/mesh_materials.vtk' + call write_VTK_data_ngnod_elem_i(nelmnts,nnodes,NGNOD,xstore_dummy,zstore_dummy, & + tmp_elmnts,tmp_elem_flag,filename) + ! user output + if (myrank == 0) write(IMAIN,*) ' written file: ',trim(filename) + + ! partitioning number + do ispec = 1, nelmnts + tmp_elem_flag(ispec) = part(ispec-1) + enddo + filename = trim(OUTPUT_FILES)//'/mesh_partition_number.vtk' + call write_VTK_data_ngnod_elem_i(nelmnts,nnodes,NGNOD,xstore_dummy,zstore_dummy, & + tmp_elmnts,tmp_elem_flag,filename) + ! user output + if (myrank == 0) write(IMAIN,*) ' written file: ',trim(filename) + + deallocate(tmp_elmnts,tmp_elem_flag) + deallocate(xstore_dummy,zstore_dummy) + + ! debug + ! outputs single file per partition with partition number + if (.false.) then + ! stores only elements in this partition + do iproc = 0,NPROC-1 + + ! only counts number of elements for this given partition iproc + nspec = 0 + do i = 0, nelmnts-1 + if (part(i) == iproc) nspec = nspec + 1 + enddo + + allocate(tmp_elmnts(NGNOD,nspec)) + tmp_elmnts(:,:) = 0 + allocate(tmp_elem_flag(nspec)) + tmp_elem_flag(:) = -1 + inum = 0 + do ispec = 1,nelmnts + if (part(ispec-1) == iproc) then + inum = inum + 1 + do j = 1, NGNOD + tmp_elmnts(j,inum) = elmnts((ispec-1)*NGNOD+(j-1))+1 + enddo + tmp_elem_flag(inum) = iproc + endif + enddo + if (inum /= nspec) then + print *,'Error: inum ',inum,'should be equal to nspec ',nspec + stop 'Error invalid inum for writing partition vtk file' + endif + ! saves as vtk file + write(filename,'(a,i6.6,a)') trim(OUTPUT_FILES)//'/proc',iproc,'_partition_number.vtk' + call write_VTK_data_ngnod_elem_i(nspec,nnodes,NGNOD,xstore_dummy,zstore_dummy, & + tmp_elmnts,tmp_elem_flag,filename) + if (myrank == 0) write(IMAIN,*) ' written file: ',trim(filename) + deallocate(tmp_elmnts,tmp_elem_flag) + deallocate(xstore_dummy,zstore_dummy) + enddo + endif + + ! user output + if (myrank == 0) then + write(IMAIN,*) ' done' + write(IMAIN,*) + call flush_IMAIN() + endif + +end subroutine save_databases_VTK_files diff --git a/meshfem2d/save_gnuplot_file.f90 b/meshfem2d/save_gnuplot_file.f90 new file mode 100644 index 00000000..d8ae00cd --- /dev/null +++ b/meshfem2d/save_gnuplot_file.f90 @@ -0,0 +1,123 @@ +!======================================================================== +! +! S P E C F E M 2 D +! ----------------- +! +! Main historical authors: Dimitri Komatitsch and Jeroen Tromp +! CNRS, France +! and Princeton University, USA +! (there are currently many more authors!) +! (c) October 2017 +! +! This software is a computer program whose purpose is to solve +! the two-dimensional viscoelastic anisotropic or poroelastic wave equation +! using a spectral-element method (SEM). +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 3 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License along +! with this program; if not, write to the Free Software Foundation, Inc., +! 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +! +! The full text of the license is available in file "LICENSE". +! +!======================================================================== + + subroutine save_gnuplot_file(NGNOD,nx,nz,x,z) + +! creates a Gnuplot file that displays the grid + + use constants, only: IMAIN,IOUT_VIS,myrank + use shared_parameters, only: OUTPUT_FILES + + implicit none + + integer :: NGNOD,nx,nz + double precision, dimension(0:nx,0:nz) :: x,z + + ! local parameters + integer :: ier,istepx,istepz,ili,icol + + ! user output + if (myrank == 0) then + write(IMAIN,*) + write(IMAIN,*) 'Saving the grid in Gnuplot format...' + write(IMAIN,*) + call flush_IMAIN() + endif + + open(unit=IOUT_VIS,file=trim(OUTPUT_FILES)//'/gridfile.gnu',status='unknown',iostat=ier) + if (ier /= 0 ) then + print *,'Error opening gnuplot file for writing: ',trim(OUTPUT_FILES)//'/gridfile.gnu' + print *,'Please make sure directory ',trim(OUTPUT_FILES),' exists...' + call stop_the_code('Error saving gnuplot file') + endif + + ! draw horizontal lines of the grid + if (myrank == 0) write(IMAIN,*) 'drawing horizontal lines of the grid' + istepx = 1 + if (NGNOD == 4) then + istepz = 1 + else + istepz = 2 + endif + do ili=0,nz,istepz + do icol=0,nx-istepx,istepx + write(IOUT_VIS,*) sngl(x(icol,ili)),sngl(z(icol,ili)) + write(IOUT_VIS,*) sngl(x(icol+istepx,ili)),sngl(z(icol+istepx,ili)) + write(IOUT_VIS,10) + enddo + enddo + + ! draw vertical lines of the grid + if (myrank == 0) write(IMAIN,*) 'drawing vertical lines of the grid' + if (NGNOD == 4) then + istepx = 1 + else + istepx = 2 + endif + istepz = 1 + do icol=0,nx,istepx + do ili=0,nz-istepz,istepz + write(IOUT_VIS,*) sngl(x(icol,ili)),sngl(z(icol,ili)) + write(IOUT_VIS,*) sngl(x(icol,ili+istepz)),sngl(z(icol,ili+istepz)) + write(IOUT_VIS,10) + enddo + enddo + +10 format('') + + close(IOUT_VIS) + + ! create a Gnuplot script to display the grid + open(unit=IOUT_VIS,file=trim(OUTPUT_FILES)//'/plot_gridfile.gnu',status='unknown',iostat=ier) + if (ier /= 0 ) call stop_the_code('Error saving plotgnu file') + + write(IOUT_VIS,*) '#set term wxt' + write(IOUT_VIS,*) 'set term postscript landscape monochrome solid "Helvetica" 22' + write(IOUT_VIS,*) 'set output "',trim(OUTPUT_FILES)//'/gridfile.ps"' + write(IOUT_VIS,*) '#set xrange [',sngl(minval(x)),':',sngl(maxval(x)),']' + write(IOUT_VIS,*) '#set yrange [',sngl(minval(z)),':',sngl(maxval(z)),']' + ! use same unit length on both X and Y axes + write(IOUT_VIS,*) 'set size ratio -1' + write(IOUT_VIS,*) 'set loadpath "'//trim(OUTPUT_FILES)//'"' + write(IOUT_VIS,*) 'plot "gridfile.gnu" title "Macrobloc mesh" w l' + write(IOUT_VIS,*) 'pause -1 "Hit any key..."' + close(IOUT_VIS) + + ! user output + if (myrank == 0) then + write(IMAIN,*) 'Grid saved in Gnuplot format...' + write(IMAIN,*) + call flush_IMAIN() + endif + + end subroutine save_gnuplot_file diff --git a/meshfem2d/save_stations_file.f90 b/meshfem2d/save_stations_file.f90 new file mode 100644 index 00000000..02c5a9ec --- /dev/null +++ b/meshfem2d/save_stations_file.f90 @@ -0,0 +1,119 @@ +!======================================================================== +! +! S P E C F E M 2 D +! ----------------- +! +! Main historical authors: Dimitri Komatitsch and Jeroen Tromp +! CNRS, France +! and Princeton University, USA +! (there are currently many more authors!) +! (c) October 2017 +! +! This software is a computer program whose purpose is to solve +! the two-dimensional viscoelastic anisotropic or poroelastic wave equation +! using a spectral-element method (SEM). +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 3 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License along +! with this program; if not, write to the Free Software Foundation, Inc., +! 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +! +! The full text of the license is available in file "LICENSE". +! +!======================================================================== + + subroutine save_stations_file(nreceiversets,nrec_line,xdeb,zdeb,xfin,zfin,record_at_surface_same_vertical, & + xinterface_top,zinterface_top,coefs_interface_top, & + npoints_interface_top,max_npoints_interface) + + use constants, only: IOUT,IMAIN,MAX_STRING_LEN,mygroup,IN_DATA_FILES + use shared_parameters, only: stations_filename + + implicit none + + integer,intent(in) :: nreceiversets + integer, dimension(nreceiversets) :: nrec_line + double precision, dimension(nreceiversets) :: xdeb,zdeb,xfin,zfin + logical, dimension(nreceiversets) :: record_at_surface_same_vertical + + integer :: max_npoints_interface + double precision, dimension(max_npoints_interface) :: xinterface_top, & + zinterface_top,coefs_interface_top + integer :: npoints_interface_top + + !local parameters + integer :: ireceiverlines,irec,irec_global_number,ios + integer :: nrec_total + double precision :: xrec,zrec + double precision, external :: value_spline + + ! if (NUMBER_OF_SIMULTANEOUS_RUNS > 1 .and. mygroup >= 0) then + ! write(path_to_add,"('run',i4.4,'/')") mygroup + 1 + ! stations_filename = path_to_add(1:len_trim(path_to_add))//stations_filename(1:len_trim(stations_filename)) + ! endif + + ! user output + write(IMAIN,*) + write(IMAIN,*) 'writing the '//trim(stations_filename)//' file' + write(IMAIN,*) + + ! total number of receivers in all the receiver lines + nrec_total = sum(nrec_line(:)) + + write(IMAIN,*) + write(IMAIN,*) 'There are ',nrec_total,' receivers' + + write(IMAIN,*) + write(IMAIN,*) 'Target positions (x,z) of the ',nrec_total,' receivers' + write(IMAIN,*) + call flush_IMAIN() + + open(unit=IOUT,file=trim(stations_filename),status='unknown',iostat=ios) + if (ios /= 0 ) call stop_the_code('error saving STATIONS file') + + irec_global_number = 0 + + ! loop on all the receiver lines + do ireceiverlines = 1,nreceiversets + + ! loop on all the receivers of this receiver line + do irec = 1,nrec_line(ireceiverlines) + + ! compute global receiver number + irec_global_number = irec_global_number + 1 + + ! compute coordinates of the receiver + if (nrec_line(ireceiverlines) > 1) then + xrec = xdeb(ireceiverlines) + dble(irec-1)*(xfin(ireceiverlines) & + -xdeb(ireceiverlines))/dble(nrec_line(ireceiverlines)-1) + zrec = zdeb(ireceiverlines) + dble(irec-1)*(zfin(ireceiverlines) & + -zdeb(ireceiverlines))/dble(nrec_line(ireceiverlines)-1) + else + xrec = xdeb(ireceiverlines) + zrec = zdeb(ireceiverlines) + endif + + ! modify position of receiver if we must record exactly at the surface + if (record_at_surface_same_vertical(ireceiverlines)) & + zrec = value_spline(xrec,xinterface_top,zinterface_top,coefs_interface_top,npoints_interface_top) + + ! display position of the receiver + write(IMAIN,*) 'Receiver ',irec_global_number,' = ',xrec,zrec + + write(IOUT,"('S',i4.4,' AA ',f20.7,1x,f20.7,' 0.0 0.0')") irec_global_number,xrec,zrec + + enddo + enddo + + close(IOUT) + + end subroutine save_stations_file diff --git a/meshfem2d/scotch_partitioning.F90 b/meshfem2d/scotch_partitioning.F90 new file mode 100644 index 00000000..2f38d18e --- /dev/null +++ b/meshfem2d/scotch_partitioning.F90 @@ -0,0 +1,141 @@ +!======================================================================== +! +! S P E C F E M 2 D +! ----------------- +! +! Main historical authors: Dimitri Komatitsch and Jeroen Tromp +! CNRS, France +! and Princeton University, USA +! (there are currently many more authors!) +! (c) October 2017 +! +! This software is a computer program whose purpose is to solve +! the two-dimensional viscoelastic anisotropic or poroelastic wave equation +! using a spectral-element method (SEM). +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 3 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License along +! with this program; if not, write to the Free Software Foundation, Inc., +! 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +! +! The full text of the license is available in file "LICENSE". +! +!======================================================================== + +! Partitioning using SCOTCH + + subroutine scotch_partitioning() + +#ifdef USE_SCOTCH + use part_unstruct_par, only: nb_edges,part,nelmnts,xadj_g,adjncy_g + use compute_elements_load_par, only: elmnts_load,adjwgt + + use shared_parameters, only: nparts => NPROC +#endif + + implicit none + +#ifdef USE_SCOTCH + include "scotchf.h" + + double precision, dimension(SCOTCH_GRAPHDIM) :: SCOTCHGRAPH + double precision, dimension(SCOTCH_STRATDIM) :: SCOTCHSTRAT + integer :: ier + +! workflow preferred by F. Pellegrini (SCOTCH): +!! +!!This comes from the fact that, in version 5.1.8, the name +!!for the "recursive bisection" method has changed from "b" +!!("bipartitioning") to "r" ("recursive"). +!! +!!As a general rule, do not try to set up strategies by +!!yourself. The default strategy in Scotch will most probably +!!provide better results. To use it, just call: +!! +!!SCOTCHFstratInit (), +!! +!!and use this "empty" strategy in the mapping routine +!!(consequently, no call to SCOTCHFstratGraphMap () is +!!required). +!! +!!This will make you independent from further changes +!!(improvements) in the strategy syntax. +!!And you should see an improvement in performance, too, +!!as your hand-made strategy did not make use of the +!!multi-level framework. + + ! we use the default strategy for partitioning + ! thus no need to define an explicit strategy + call scotchfstratinit (SCOTCHSTRAT(1), ier) + if (ier /= 0) then + print *, 'ERROR : MAIN : Cannot initialize strategy' + call stop_the_code('Error scotch init') + endif + + ! resets SCOTCH random number generator to produce deterministic partitions + call scotchfrandomReset() + + ! initializes graph + call scotchfgraphinit (SCOTCHGRAPH (1), ier) + if (ier /= 0) then + print *, 'ERROR : MAIN : Cannot initialize graph' + call stop_the_code('Error scotch graph') + endif + + ! fills graph structure : see user manual (scotch_user5.1.pdf, page 72/73) + ! arguments: #(1) graph_structure #(2) baseval(either 0/1) #(3) number_of_vertices + ! #(4) adjacency_index_array #(5) adjacency_end_index_array (optional) + ! #(6) vertex_load_array (optional) #(7) vertex_label_array + ! #(7) number_of_arcs #(8) adjacency_array + ! #(9) arc_load_array (optional) #(10) ierror + call scotchfgraphbuild (SCOTCHGRAPH (1), 0, nelmnts, & + xadj_g(0), xadj_g(0), & + elmnts_load(0), xadj_g(0), & + nb_edges, & + adjncy_g(0), adjwgt (0), ier) + if (ier /= 0) then + print *, 'ERROR : MAIN : Cannot build graph' + call stop_the_code('Error scotch graphbuild') + endif + + call scotchfgraphcheck (SCOTCHGRAPH (1), ier) + if (ier /= 0) then + print *, 'ERROR : MAIN : Invalid check' + call stop_the_code('Error scotch graphcheck') + endif + + call scotchfgraphpart (SCOTCHGRAPH (1), nparts, SCOTCHSTRAT(1), part(0), ier) + if (ier /= 0) then + print *, 'ERROR : MAIN : Cannot part graph' + call stop_the_code('Error scotch graphpart') + endif + + call SCOTCHFGRAPHEXIT (SCOTCHGRAPH (1), ier) + if (ier /= 0) then + print *, 'ERROR : MAIN : Cannot destroy graph' + call stop_the_code('Error scotch graphexit') + endif + + call scotchfstratexit (SCOTCHSTRAT(1), ier) + if (ier /= 0) then + print *, 'ERROR : MAIN : Cannot destroy strat' + call stop_the_code('Error scotch exit') + endif + +#else + ! safety stop + print *, 'This version of SPECFEM was not compiled with support of SCOTCH.' + print *, 'Please recompile with -DUSE_SCOTCH in order to enable use of SCOTCH.' + call stop_the_code('Error SCOTCH partitioning not compiled') +#endif + + end subroutine scotch_partitioning diff --git a/meshfem2d/set_color_palette.f90 b/meshfem2d/set_color_palette.f90 new file mode 100644 index 00000000..cd364ef8 --- /dev/null +++ b/meshfem2d/set_color_palette.f90 @@ -0,0 +1,1226 @@ +!======================================================================== +! +! S P E C F E M 2 D +! ----------------- +! +! Main historical authors: Dimitri Komatitsch and Jeroen Tromp +! CNRS, France +! and Princeton University, USA +! (there are currently many more authors!) +! (c) October 2017 +! +! This software is a computer program whose purpose is to solve +! the two-dimensional viscoelastic anisotropic or poroelastic wave equation +! using a spectral-element method (SEM). +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 3 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License along +! with this program; if not, write to the Free Software Foundation, Inc., +! 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +! +! The full text of the license is available in file "LICENSE". +! +!======================================================================== + + + subroutine set_color_palette(red,green,blue,NUM_COLORS) + +! color palette + + implicit none + + integer,intent(in) :: NUM_COLORS + double precision, dimension(NUM_COLORS),intent(out) :: red,green,blue + + if (NUM_COLORS /= 236 ) call stop_the_code('check NUM_COLORS, must be equal to 236 in set_color_palette.f90') + +! red + red(1) = 1.00000000000000 + green(1) = 0.000000000000000E+000 + blue(1) = 0.000000000000000E+000 + +! DodgerBlue2 + red(2) = 0.109803921568627 + green(2) = 0.525490196078431 + blue(2) = 0.933333333333333 + +! gold + red(3) = 1.00000000000000 + green(3) = 0.840000000000000 + blue(3) = 0.000000000000000E+000 + +! springgreen + red(4) = 0.000000000000000E+000 + green(4) = 1.00000000000000 + blue(4) = 0.500000000000000 + +! NavajoWhite + red(5) = 1.00000000000000 + green(5) = 0.870588235294118 + blue(5) = 0.678431372549020 + +! SteelBlue3 + red(6) = 0.309803921568627 + green(6) = 0.580392156862745 + blue(6) = 0.803921568627451 + +! Ivory3 + red(7) = 0.803921568627451 + green(7) = 0.803921568627451 + blue(7) = 0.756862745098039 + +! SkyBlue4 + red(8) = 0.290196078431373 + green(8) = 0.439215686274510 + blue(8) = 0.545098039215686 + +! Snow + red(9) = 0.980392156862745 + green(9) = 0.980392156862745 + blue(9) = 0.980392156862745 + +! SteelBlue + red(10) = 0.274509803921569 + green(10) = 0.509803921568627 + blue(10) = 0.705882352941177 + +! Bisque3 + red(11) = 0.803921568627451 + green(11) = 0.717647058823529 + blue(11) = 0.619607843137255 + +! Salmon + red(12) = 0.980392156862745 + green(12) = 0.501960784313725 + blue(12) = 0.447058823529412 + +! SlateBlue2 + red(13) = 0.478431372549020 + green(13) = 0.403921568627451 + blue(13) = 0.933333333333333 + +! NavajoWhite2 + red(14) = 0.933333333333333 + green(14) = 0.811764705882353 + blue(14) = 0.631372549019608 + +! MediumBlue + red(15) = 0.000000000000000E+000 + green(15) = 0.000000000000000E+000 + blue(15) = 0.803921568627451 + +! LightCoral + red(16) = 0.941176470588235 + green(16) = 0.501960784313725 + blue(16) = 0.501960784313725 + +! FloralWhite + red(17) = 1.00000000000000 + green(17) = 0.980392156862745 + blue(17) = 0.941176470588235 + +! Cornsilk3 + red(18) = 0.803921568627451 + green(18) = 0.784313725490196 + blue(18) = 0.694117647058824 + +! GhostWhite + red(19) = 0.972549019607843 + green(19) = 0.972549019607843 + blue(19) = 1.00000000000000 + +! blue + red(20) = 0.000000000000000E+000 + green(20) = 0.000000000000000E+000 + blue(20) = 1.00000000000000 + +! Linen + red(21) = 0.980392156862745 + green(21) = 0.941176470588235 + blue(21) = 0.901960784313726 + +! peachpuff + red(22) = 1.00000000000000 + green(22) = 0.850000000000000 + blue(22) = 0.730000000000000 + +! Cornsilk1 + red(23) = 1.00000000000000 + green(23) = 0.972549019607843 + blue(23) = 0.862745098039216 + +! LightSalmon + red(24) = 1.00000000000000 + green(24) = 0.627450980392157 + blue(24) = 0.478431372549020 + +! DeepSkyBlue1 + red(25) = 0.000000000000000E+000 + green(25) = 0.749019607843137 + blue(25) = 1.00000000000000 + +! LemonChiffon4 + red(26) = 0.545098039215686 + green(26) = 0.537254901960784 + blue(26) = 0.439215686274510 + +! PeachPuff1 + red(27) = 1.00000000000000 + green(27) = 0.854901960784314 + blue(27) = 0.725490196078431 + +! BlanchedAlmond + red(28) = 1.00000000000000 + green(28) = 0.921568627450980 + blue(28) = 0.803921568627451 + +! SlateBlue3 + red(29) = 0.411764705882353 + green(29) = 0.349019607843137 + blue(29) = 0.803921568627451 + +! LightSkyBlue1 + red(30) = 0.690196078431373 + green(30) = 0.886274509803922 + blue(30) = 1.00000000000000 + +! DarkViolet + red(31) = 0.580392156862745 + green(31) = 0.000000000000000E+000 + blue(31) = 0.827450980392157 + +! Azure3 + red(32) = 0.756862745098039 + green(32) = 0.803921568627451 + blue(32) = 0.803921568627451 + +! LavenderBlush3 + red(33) = 0.803921568627451 + green(33) = 0.756862745098039 + blue(33) = 0.772549019607843 + +! Honeydew1 + red(34) = 0.941176470588235 + green(34) = 1.00000000000000 + blue(34) = 0.941176470588235 + +! Ivory2 + red(35) = 0.933333333333333 + green(35) = 0.933333333333333 + blue(35) = 0.878431372549020 + +! RosyBrown + red(36) = 0.737254901960784 + green(36) = 0.560784313725490 + blue(36) = 0.560784313725490 + +! Thistle + red(37) = 0.847058823529412 + green(37) = 0.749019607843137 + blue(37) = 0.847058823529412 + +! Orange + red(38) = 1.00000000000000 + green(38) = 0.647058823529412 + blue(38) = 0.000000000000000E+000 + +! DarkSeaGreen + red(39) = 0.560784313725490 + green(39) = 0.737254901960784 + blue(39) = 0.560784313725490 + +! Moccasin + red(40) = 1.00000000000000 + green(40) = 0.894117647058824 + blue(40) = 0.709803921568627 + +! DeepSkyBlue2 + red(41) = 0.000000000000000E+000 + green(41) = 0.698039215686274 + blue(41) = 0.933333333333333 + +! SlateGray4 + red(42) = 0.423529411764706 + green(42) = 0.482352941176471 + blue(42) = 0.545098039215686 + +! Beige + red(43) = 0.960784313725490 + green(43) = 0.960784313725490 + blue(43) = 0.862745098039216 + +! Gold + red(44) = 1.00000000000000 + green(44) = 0.843137254901961 + blue(44) = 0.000000000000000E+000 + +! SlateBlue + red(45) = 0.415686274509804 + green(45) = 0.352941176470588 + blue(45) = 0.803921568627451 + +! SteelBlue1 + red(46) = 0.388235294117647 + green(46) = 0.721568627450980 + blue(46) = 1.00000000000000 + +! SaddleBrown + red(47) = 0.545098039215686 + green(47) = 0.270588235294118 + blue(47) = 7.450980392156863E-002 + +! Pink + red(48) = 1.00000000000000 + green(48) = 0.752941176470588 + blue(48) = 0.796078431372549 + +! Black + red(49) = 0.000000000000000E+000 + green(49) = 0.000000000000000E+000 + blue(49) = 0.000000000000000E+000 + +! SlateGrey + red(50) = 0.439215686274510 + green(50) = 0.501960784313725 + blue(50) = 0.564705882352941 + +! Ivory + red(51) = 1.00000000000000 + green(51) = 1.00000000000000 + blue(51) = 0.941176470588235 + +! OliveDrab + red(52) = 0.419607843137255 + green(52) = 0.556862745098039 + blue(52) = 0.137254901960784 + +! Ivory1 + red(53) = 1.00000000000000 + green(53) = 1.00000000000000 + blue(53) = 0.941176470588235 + +! SkyBlue + red(54) = 0.529411764705882 + green(54) = 0.807843137254902 + blue(54) = 0.921568627450980 + +! MistyRose3 + red(55) = 0.803921568627451 + green(55) = 0.717647058823529 + blue(55) = 0.709803921568627 + +! LimeGreen + red(56) = 0.196078431372549 + green(56) = 0.803921568627451 + blue(56) = 0.196078431372549 + +! Purple + red(57) = 0.627450980392157 + green(57) = 0.125490196078431 + blue(57) = 0.941176470588235 + +! SkyBlue2 + red(58) = 0.494117647058824 + green(58) = 0.752941176470588 + blue(58) = 0.933333333333333 + +! Red + red(59) = 1.00000000000000 + green(59) = 0.000000000000000E+000 + blue(59) = 0.000000000000000E+000 + +! DarkKhaki + red(60) = 0.741176470588235 + green(60) = 0.717647058823529 + blue(60) = 0.419607843137255 + +! MediumTurquoise + red(61) = 0.282352941176471 + green(61) = 0.819607843137255 + blue(61) = 0.800000000000000 + +! Grey + red(62) = 0.745098039215686 + green(62) = 0.745098039215686 + blue(62) = 0.745098039215686 + +! Coral + red(63) = 1.00000000000000 + green(63) = 0.498039215686275 + blue(63) = 0.313725490196078 + +! NavajoWhite4 + red(64) = 0.545098039215686 + green(64) = 0.474509803921569 + blue(64) = 0.368627450980392 + +! SlateBlue4 + red(65) = 0.278431372549020 + green(65) = 0.235294117647059 + blue(65) = 0.545098039215686 + +! RoyalBlue4 + red(66) = 0.152941176470588 + green(66) = 0.250980392156863 + blue(66) = 0.545098039215686 + +! YellowGreen + red(67) = 0.603921568627451 + green(67) = 0.803921568627451 + blue(67) = 0.196078431372549 + +! DeepSkyBlue3 + red(68) = 0.000000000000000E+000 + green(68) = 0.603921568627451 + blue(68) = 0.803921568627451 + +! goldenrod + red(69) = 0.854901960784314 + green(69) = 0.647058823529412 + blue(69) = 0.125490196078431 + +! AntiqueWhite4 + red(70) = 0.545098039215686 + green(70) = 0.513725490196078 + blue(70) = 0.470588235294118 + +! lemonchiffon + red(71) = 1.00000000000000 + green(71) = 0.980000000000000 + blue(71) = 0.800000000000000 + +! GreenYellow + red(72) = 0.678431372549020 + green(72) = 1.00000000000000 + blue(72) = 0.184313725490196 + +! LightSlateGray + red(73) = 0.466666666666667 + green(73) = 0.533333333333333 + blue(73) = 0.600000000000000 + +! RoyalBlue + red(74) = 0.254901960784314 + green(74) = 0.411764705882353 + blue(74) = 0.882352941176471 + +! DarkGreen + red(75) = 0.000000000000000E+000 + green(75) = 0.392156862745098 + blue(75) = 0.000000000000000E+000 + +! NavajoWhite3 + red(76) = 0.803921568627451 + green(76) = 0.701960784313725 + blue(76) = 0.545098039215686 + +! Azure1 + red(77) = 0.941176470588235 + green(77) = 1.00000000000000 + blue(77) = 1.00000000000000 + +! PowderBlue + red(78) = 0.690196078431373 + green(78) = 0.878431372549020 + blue(78) = 0.901960784313726 + +! slateblue + red(79) = 0.420000000000000 + green(79) = 0.350000000000000 + blue(79) = 0.800000000000000 + +! MediumOrchid + red(80) = 0.729411764705882 + green(80) = 0.333333333333333 + blue(80) = 0.827450980392157 + +! turquoise + red(81) = 0.250000000000000 + green(81) = 0.880000000000000 + blue(81) = 0.820000000000000 + +! Snow1 + red(82) = 1.00000000000000 + green(82) = 0.980392156862745 + blue(82) = 0.980392156862745 + +! violet + red(83) = 0.930000000000000 + green(83) = 0.510000000000000 + blue(83) = 0.930000000000000 + +! DeepPink + red(84) = 1.00000000000000 + green(84) = 7.843137254901961E-002 + blue(84) = 0.576470588235294 + +! MistyRose4 + red(85) = 0.545098039215686 + green(85) = 0.490196078431373 + blue(85) = 0.482352941176471 + +! PeachPuff3 + red(86) = 0.803921568627451 + green(86) = 0.686274509803922 + blue(86) = 0.584313725490196 + +! MediumSeaGreen + red(87) = 0.235294117647059 + green(87) = 0.701960784313725 + blue(87) = 0.443137254901961 + +! Honeydew4 + red(88) = 0.513725490196078 + green(88) = 0.545098039215686 + blue(88) = 0.513725490196078 + +! Tan + red(89) = 0.823529411764706 + green(89) = 0.705882352941177 + blue(89) = 0.549019607843137 + +! DarkGoldenrod + red(90) = 0.721568627450980 + green(90) = 0.525490196078431 + blue(90) = 4.313725490196078E-002 + +! Blue2 + red(91) = 0.000000000000000E+000 + green(91) = 0.000000000000000E+000 + blue(91) = 0.933333333333333 + +! Maroon + red(92) = 0.690196078431373 + green(92) = 0.188235294117647 + blue(92) = 0.376470588235294 + +! LightSkyBlue3 + red(93) = 0.552941176470588 + green(93) = 0.713725490196078 + blue(93) = 0.803921568627451 + +! LemonChiffon2 + red(94) = 0.933333333333333 + green(94) = 0.913725490196078 + blue(94) = 0.749019607843137 + +! Snow3 + red(95) = 0.803921568627451 + green(95) = 0.788235294117647 + blue(95) = 0.788235294117647 + +! Ivory4 + red(96) = 0.545098039215686 + green(96) = 0.545098039215686 + blue(96) = 0.513725490196078 + +! AntiqueWhite3 + red(97) = 0.803921568627451 + green(97) = 0.752941176470588 + blue(97) = 0.690196078431373 + +! Bisque4 + red(98) = 0.545098039215686 + green(98) = 0.490196078431373 + blue(98) = 0.419607843137255 + +! Snow2 + red(99) = 0.933333333333333 + green(99) = 0.913725490196078 + blue(99) = 0.913725490196078 + +! SlateGray1 + red(100) = 0.776470588235294 + green(100) = 0.886274509803922 + blue(100) = 1.00000000000000 + +! Seashell2 + red(101) = 0.933333333333333 + green(101) = 0.898039215686275 + blue(101) = 0.870588235294118 + +! Aquamarine + red(102) = 0.498039215686275 + green(102) = 1.00000000000000 + blue(102) = 0.831372549019608 + +! SlateGray2 + red(103) = 0.725490196078431 + green(103) = 0.827450980392157 + blue(103) = 0.933333333333333 + +! White + red(104) = 1.00000000000000 + green(104) = 1.00000000000000 + blue(104) = 1.00000000000000 + +! LavenderBlush + red(105) = 1.00000000000000 + green(105) = 0.941176470588235 + blue(105) = 0.960784313725490 + +! DodgerBlue3 + red(106) = 9.411764705882353E-002 + green(106) = 0.454901960784314 + blue(106) = 0.803921568627451 + +! RoyalBlue3 + red(107) = 0.227450980392157 + green(107) = 0.372549019607843 + blue(107) = 0.803921568627451 + +! LightYellow + red(108) = 1.00000000000000 + green(108) = 1.00000000000000 + blue(108) = 0.878431372549020 + +! DeepSkyBlue + red(109) = 0.000000000000000E+000 + green(109) = 0.749019607843137 + blue(109) = 1.00000000000000 + +! AntiqueWhite2 + red(110) = 0.933333333333333 + green(110) = 0.874509803921569 + blue(110) = 0.800000000000000 + +! CornflowerBlue + red(111) = 0.392156862745098 + green(111) = 0.584313725490196 + blue(111) = 0.929411764705882 + +! PeachPuff4 + red(112) = 0.545098039215686 + green(112) = 0.466666666666667 + blue(112) = 0.396078431372549 + +! SpringGreen + red(113) = 0.000000000000000E+000 + green(113) = 1.00000000000000 + blue(113) = 0.498039215686275 + +! Honeydew + red(114) = 0.941176470588235 + green(114) = 1.00000000000000 + blue(114) = 0.941176470588235 + +! Honeydew2 + red(115) = 0.878431372549020 + green(115) = 0.933333333333333 + blue(115) = 0.878431372549020 + +! LightSeaGreen + red(116) = 0.125490196078431 + green(116) = 0.698039215686274 + blue(116) = 0.666666666666667 + +! NavyBlue + red(117) = 0.000000000000000E+000 + green(117) = 0.000000000000000E+000 + blue(117) = 0.501960784313725 + +! Azure4 + red(118) = 0.513725490196078 + green(118) = 0.545098039215686 + blue(118) = 0.545098039215686 + +! MediumAquamarine + red(119) = 0.400000000000000 + green(119) = 0.803921568627451 + blue(119) = 0.666666666666667 + +! SkyBlue3 + red(120) = 0.423529411764706 + green(120) = 0.650980392156863 + blue(120) = 0.803921568627451 + +! LavenderBlush2 + red(121) = 0.933333333333333 + green(121) = 0.878431372549020 + blue(121) = 0.898039215686275 + +! Bisque1 + red(122) = 1.00000000000000 + green(122) = 0.894117647058824 + blue(122) = 0.768627450980392 + +! DarkOrange + red(123) = 1.00000000000000 + green(123) = 0.549019607843137 + blue(123) = 0.000000000000000E+000 + +! LightSteelBlue + red(124) = 0.690196078431373 + green(124) = 0.768627450980392 + blue(124) = 0.870588235294118 + +! SteelBlue2 + red(125) = 0.360784313725490 + green(125) = 0.674509803921569 + blue(125) = 0.933333333333333 + +! LemonChiffon3 + red(126) = 0.803921568627451 + green(126) = 0.788235294117647 + blue(126) = 0.647058823529412 + +! DarkSlateBlue + red(127) = 0.282352941176471 + green(127) = 0.239215686274510 + blue(127) = 0.545098039215686 + +! Seashell + red(128) = 1.00000000000000 + green(128) = 0.960784313725490 + blue(128) = 0.933333333333333 + +! Firebrick + red(129) = 0.698039215686274 + green(129) = 0.133333333333333 + blue(129) = 0.133333333333333 + +! LightGray + red(130) = 0.827450980392157 + green(130) = 0.827450980392157 + blue(130) = 0.827450980392157 + +! Blue + red(131) = 0.000000000000000E+000 + green(131) = 0.000000000000000E+000 + blue(131) = 1.00000000000000 + +! Bisque2 + red(132) = 0.933333333333333 + green(132) = 0.835294117647059 + blue(132) = 0.717647058823529 + +! WhiteSmoke + red(133) = 0.960784313725490 + green(133) = 0.960784313725490 + blue(133) = 0.960784313725490 + +! SeaGreen + red(134) = 0.180392156862745 + green(134) = 0.545098039215686 + blue(134) = 0.341176470588235 + +! Burlywood + red(135) = 0.870588235294118 + green(135) = 0.721568627450980 + blue(135) = 0.529411764705882 + +! RoyalBlue2 + red(136) = 0.262745098039216 + green(136) = 0.431372549019608 + blue(136) = 0.933333333333333 + +! RoyalBlue1 + red(137) = 0.282352941176471 + green(137) = 0.462745098039216 + blue(137) = 1.00000000000000 + +! SteelBlue4 + red(138) = 0.211764705882353 + green(138) = 0.392156862745098 + blue(138) = 0.545098039215686 + +! AliceBlue + red(139) = 0.941176470588235 + green(139) = 0.972549019607843 + blue(139) = 1.00000000000000 + +! LightSlateBlue + red(140) = 0.517647058823529 + green(140) = 0.439215686274510 + blue(140) = 1.00000000000000 + +! MistyRose1 + red(141) = 1.00000000000000 + green(141) = 0.894117647058824 + blue(141) = 0.882352941176471 + +! SandyBrown + red(142) = 0.956862745098039 + green(142) = 0.643137254901961 + blue(142) = 0.376470588235294 + +! DarkOliveGreen + red(143) = 0.333333333333333 + green(143) = 0.419607843137255 + blue(143) = 0.184313725490196 + +! Yellow + red(144) = 1.00000000000000 + green(144) = 1.00000000000000 + blue(144) = 0.000000000000000E+000 + +! SlateGray3 + red(145) = 0.623529411764706 + green(145) = 0.713725490196078 + blue(145) = 0.803921568627451 + +! HotPink + red(146) = 1.00000000000000 + green(146) = 0.411764705882353 + blue(146) = 0.705882352941177 + +! Violet + red(147) = 0.933333333333333 + green(147) = 0.509803921568627 + blue(147) = 0.933333333333333 + +! LightSkyBlue + red(148) = 0.529411764705882 + green(148) = 0.807843137254902 + blue(148) = 0.980392156862745 + +! Cornsilk2 + red(149) = 0.933333333333333 + green(149) = 0.909803921568627 + blue(149) = 0.803921568627451 + +! MidnightBlue + red(150) = 9.803921568627451E-002 + green(150) = 9.803921568627451E-002 + blue(150) = 0.439215686274510 + +! AntiqueWhite + red(151) = 0.980392156862745 + green(151) = 0.921568627450980 + blue(151) = 0.843137254901961 + +! PaleGreen + red(152) = 0.596078431372549 + green(152) = 0.984313725490196 + blue(152) = 0.596078431372549 + +! MedSpringGreen + red(153) = 0.000000000000000E+000 + green(153) = 0.980392156862745 + blue(153) = 0.603921568627451 + +! DodgerBlue1 + red(154) = 0.117647058823529 + green(154) = 0.564705882352941 + blue(154) = 1.00000000000000 + +! Blue3 + red(155) = 0.000000000000000E+000 + green(155) = 0.000000000000000E+000 + blue(155) = 0.803921568627451 + +! Cyan + red(156) = 0.000000000000000E+000 + green(156) = 1.00000000000000 + blue(156) = 1.00000000000000 + +! LemonChiffon + red(157) = 1.00000000000000 + green(157) = 0.980392156862745 + blue(157) = 0.803921568627451 + +! mediumorchid + red(158) = 0.730000000000000 + green(158) = 0.330000000000000 + blue(158) = 0.830000000000000 + +! Turquoise + red(159) = 0.250980392156863 + green(159) = 0.878431372549020 + blue(159) = 0.815686274509804 + +! IndianRed + red(160) = 0.803921568627451 + green(160) = 0.360784313725490 + blue(160) = 0.360784313725490 + +! DodgerBlue + red(161) = 0.117647058823529 + green(161) = 0.564705882352941 + blue(161) = 1.00000000000000 + +! Seashell3 + red(162) = 0.803921568627451 + green(162) = 0.772549019607843 + blue(162) = 0.749019607843137 + +! BlueViolet + red(163) = 0.541176470588235 + green(163) = 0.168627450980392 + blue(163) = 0.886274509803922 + +! DeepSkyBlue4 + red(164) = 0.000000000000000E+000 + green(164) = 0.407843137254902 + blue(164) = 0.545098039215686 + +! PaleVioletRed + red(165) = 0.858823529411765 + green(165) = 0.439215686274510 + blue(165) = 0.576470588235294 + +! Azure2 + red(166) = 0.878431372549020 + green(166) = 0.933333333333333 + blue(166) = 0.933333333333333 + +! greenyellow + red(167) = 0.680000000000000 + green(167) = 1.00000000000000 + blue(167) = 0.180000000000000 + +! LightGoldenrod + red(168) = 0.933333333333333 + green(168) = 0.866666666666667 + blue(168) = 0.509803921568627 + +! MistyRose + red(169) = 1.00000000000000 + green(169) = 0.894117647058824 + blue(169) = 0.882352941176471 + +! LightSkyBlue4 + red(170) = 0.376470588235294 + green(170) = 0.482352941176471 + blue(170) = 0.545098039215686 + +! OrangeRed + red(171) = 1.00000000000000 + green(171) = 0.270588235294118 + blue(171) = 0.000000000000000E+000 + +! DimGrey + red(172) = 0.411764705882353 + green(172) = 0.411764705882353 + blue(172) = 0.411764705882353 + +! MediumVioletRed + red(173) = 0.780392156862745 + green(173) = 8.235294117647059E-002 + blue(173) = 0.521568627450980 + +! DarkSlateGray + red(174) = 0.184313725490196 + green(174) = 0.309803921568627 + blue(174) = 0.309803921568627 + +! yellow + red(175) = 1.00000000000000 + green(175) = 1.00000000000000 + blue(175) = 0.000000000000000E+000 + +! Plum + red(176) = 0.866666666666667 + green(176) = 0.627450980392157 + blue(176) = 0.866666666666667 + +! DarkTurquoise + red(177) = 0.000000000000000E+000 + green(177) = 0.807843137254902 + blue(177) = 0.819607843137255 + +! DodgerBlue4 + red(178) = 6.274509803921569E-002 + green(178) = 0.305882352941176 + blue(178) = 0.545098039215686 + +! Cornsilk + red(179) = 1.00000000000000 + green(179) = 0.972549019607843 + blue(179) = 0.862745098039216 + +! SkyBlue1 + red(180) = 0.529411764705882 + green(180) = 0.807843137254902 + blue(180) = 1.00000000000000 + +! Seashell1 + red(181) = 1.00000000000000 + green(181) = 0.960784313725490 + blue(181) = 0.933333333333333 + +! lavender + red(182) = 0.901960784313726 + green(182) = 0.901960784313726 + blue(182) = 0.980392156862745 + +! Snow4 + red(183) = 0.545098039215686 + green(183) = 0.537254901960784 + blue(183) = 0.537254901960784 + +! Peru + red(184) = 0.803921568627451 + green(184) = 0.521568627450980 + blue(184) = 0.247058823529412 + +! PeachPuff + red(185) = 1.00000000000000 + green(185) = 0.854901960784314 + blue(185) = 0.725490196078431 + +! Green + red(186) = 0.000000000000000E+000 + green(186) = 1.00000000000000 + blue(186) = 0.000000000000000E+000 + +! Blue1 + red(187) = 0.000000000000000E+000 + green(187) = 0.000000000000000E+000 + blue(187) = 1.00000000000000 + +! Seashell4 + red(188) = 0.545098039215686 + green(188) = 0.525490196078431 + blue(188) = 0.509803921568627 + +! dodgerblue + red(189) = 0.120000000000000 + green(189) = 0.560000000000000 + blue(189) = 1.00000000000000 + +! MistyRose2 + red(190) = 0.933333333333333 + green(190) = 0.835294117647059 + blue(190) = 0.823529411764706 + +! Tomato + red(191) = 1.00000000000000 + green(191) = 0.388235294117647 + blue(191) = 0.278431372549020 + +! Wheat + red(192) = 0.960784313725490 + green(192) = 0.870588235294118 + blue(192) = 0.701960784313725 + +! LightBlue + red(193) = 0.678431372549020 + green(193) = 0.847058823529412 + blue(193) = 0.901960784313726 + +! Chocolate + red(194) = 0.823529411764706 + green(194) = 0.411764705882353 + blue(194) = 0.117647058823529 + +! Blue4 + red(195) = 0.000000000000000E+000 + green(195) = 0.000000000000000E+000 + blue(195) = 0.545098039215686 + +! LavenderBlush1 + red(196) = 1.00000000000000 + green(196) = 0.941176470588235 + blue(196) = 0.960784313725490 + +! Magenta + red(197) = 1.00000000000000 + green(197) = 0.000000000000000E+000 + blue(197) = 1.00000000000000 + +! darkturquoise + red(198) = 0.000000000000000E+000 + green(198) = 0.810000000000000 + blue(198) = 0.820000000000000 + +! blueviolet + red(199) = 0.540000000000000 + green(199) = 0.170000000000000 + blue(199) = 0.890000000000000 + +! MintCream + red(200) = 0.960784313725490 + green(200) = 1.00000000000000 + blue(200) = 0.980392156862745 + +! PaleGoldenrod + red(201) = 0.933333333333333 + green(201) = 0.909803921568627 + blue(201) = 0.666666666666667 + +! MediumPurple + red(202) = 0.576470588235294 + green(202) = 0.439215686274510 + blue(202) = 0.858823529411765 + +! PapayaWhip + red(203) = 1.00000000000000 + green(203) = 0.937254901960784 + blue(203) = 0.835294117647059 + +! LavenderBlush4 + red(204) = 0.545098039215686 + green(204) = 0.513725490196078 + blue(204) = 0.525490196078431 + +! Cornsilk4 + red(205) = 0.545098039215686 + green(205) = 0.533333333333333 + blue(205) = 0.470588235294118 + +! LtGoldenrodYello + red(206) = 0.980392156862745 + green(206) = 0.980392156862745 + blue(206) = 0.823529411764706 + +! limegreen + red(207) = 0.200000000000000 + green(207) = 0.800000000000000 + blue(207) = 0.200000000000000 + +! LemonChiffon1 + red(208) = 1.00000000000000 + green(208) = 0.980392156862745 + blue(208) = 0.803921568627451 + +! DarkOrchid + red(209) = 0.600000000000000 + green(209) = 0.196078431372549 + blue(209) = 0.800000000000000 + +! SlateBlue1 + red(210) = 0.513725490196078 + green(210) = 0.435294117647059 + blue(210) = 1.00000000000000 + +! chartreuse + red(211) = 0.500000000000000 + green(211) = 1.00000000000000 + blue(211) = 0.000000000000000E+000 + +! PaleTurquoise + red(212) = 0.686274509803922 + green(212) = 0.933333333333333 + blue(212) = 0.933333333333333 + +! NavajoWhite1 + red(213) = 1.00000000000000 + green(213) = 0.870588235294118 + blue(213) = 0.678431372549020 + +! LightSkyBlue2 + red(214) = 0.643137254901961 + green(214) = 0.827450980392157 + blue(214) = 0.933333333333333 + +! VioletRed + red(215) = 0.815686274509804 + green(215) = 0.125490196078431 + blue(215) = 0.564705882352941 + +! mocassin + red(216) = 1.00000000000000 + green(216) = 0.890000000000000 + blue(216) = 0.710000000000000 + +! OldLace + red(217) = 0.992156862745098 + green(217) = 0.960784313725490 + blue(217) = 0.901960784313726 + +! deeppink + red(218) = 1.00000000000000 + green(218) = 8.000000000000000E-002 + blue(218) = 0.580000000000000 + +! Honeydew3 + red(219) = 0.756862745098039 + green(219) = 0.803921568627451 + blue(219) = 0.756862745098039 + +! Gainsboro + red(220) = 0.862745098039216 + green(220) = 0.862745098039216 + blue(220) = 0.862745098039216 + +! DarkSalmon + red(221) = 0.913725490196078 + green(221) = 0.588235294117647 + blue(221) = 0.478431372549020 + +! AntiqueWhite1 + red(222) = 1.00000000000000 + green(222) = 0.937254901960784 + blue(222) = 0.858823529411765 + +! LightCyan + red(223) = 0.878431372549020 + green(223) = 1.00000000000000 + blue(223) = 1.00000000000000 + +! ForestGreen + red(224) = 0.133333333333333 + green(224) = 0.545098039215686 + blue(224) = 0.133333333333333 + +! Orchid + red(225) = 0.854901960784314 + green(225) = 0.439215686274510 + blue(225) = 0.839215686274510 + +! PeachPuff2 + red(226) = 0.933333333333333 + green(226) = 0.796078431372549 + blue(226) = 0.678431372549020 + +! LightPink + red(227) = 1.00000000000000 + green(227) = 0.713725490196078 + blue(227) = 0.756862745098039 + +! Sienna + red(228) = 0.627450980392157 + green(228) = 0.321568627450980 + blue(228) = 0.176470588235294 + +! darkorchid + red(229) = 0.600000000000000 + green(229) = 0.200000000000000 + blue(229) = 0.800000000000000 + +! MediumSlateBlue + red(230) = 0.482352941176471 + green(230) = 0.407843137254902 + blue(230) = 0.933333333333333 + +! CadetBlue + red(231) = 0.372549019607843 + green(231) = 0.619607843137255 + blue(231) = 0.627450980392157 + +! LawnGreen + red(232) = 0.486274509803922 + green(232) = 0.988235294117647 + blue(232) = 0.000000000000000E+000 + +! Chartreuse + red(233) = 0.498039215686275 + green(233) = 1.00000000000000 + blue(233) = 0.000000000000000E+000 + +! Brown + red(234) = 0.647058823529412 + green(234) = 0.164705882352941 + blue(234) = 0.164705882352941 + +! Azure + red(235) = 0.941176470588235 + green(235) = 1.00000000000000 + blue(235) = 1.00000000000000 + +! Bisque + red(236) = 1.00000000000000 + green(236) = 0.894117647058824 + blue(236) = 0.768627450980392 + + end subroutine set_color_palette diff --git a/meshfem2d/shared_par.f90 b/meshfem2d/shared_par.f90 new file mode 100644 index 00000000..41101b33 --- /dev/null +++ b/meshfem2d/shared_par.f90 @@ -0,0 +1,479 @@ +!======================================================================== +! +! S P E C F E M 2 D +! ----------------- +! +! Main historical authors: Dimitri Komatitsch and Jeroen Tromp +! CNRS, France +! and Princeton University, USA +! (there are currently many more authors!) +! (c) October 2017 +! +! This software is a computer program whose purpose is to solve +! the two-dimensional viscoelastic anisotropic or poroelastic wave equation +! using a spectral-element method (SEM). +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 3 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License along +! with this program; if not, write to the Free Software Foundation, Inc., +! 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +! +! The full text of the license is available in file "LICENSE". +! +!======================================================================== + +! note: the filename ending is .F90 to have pre-compilation with pragmas +! (like #ifndef WITH_MPI) working properly + +module constants + + include "constants.h" + + ! proc number for MPI process + integer :: myrank + + ! a negative initial value is a convention that indicates that groups (i.e. sub-communicators, one per run) are off by default + integer :: mygroup = -1 + + ! if doing simultaneous runs for the same mesh and model, see who should read the mesh and the model and broadcast it to others + ! we put a default value here + logical :: I_should_read_the_database = .true. + +end module constants + +! +!======================================================================== +! + +module shared_input_parameters + +! holds input parameters given in DATA/Par_file + + use constants, only: MAX_STRING_LEN, RegInt_K + + implicit none + + !-------------------------------------------------------------- + ! variables for preparation for compuation (simulation type, mesher, et al) + !-------------------------------------------------------------- + ! name assigned to the running example + character(len=MAX_STRING_LEN) :: title + + ! simulation type + integer :: SIMULATION_TYPE + + ! NOISE_TOMOGRAPHY = 0 - turn noise tomography subroutines off; setting + ! NOISE_TOMOGRAPHY equal to 0, in other words, results in an earthquake + ! simulation rather than a noise simulation + ! + ! NOISE_TOMOGRAPHY = 1 - compute "generating" wavefield and store the result; + ! this stored wavefield is then used to compute the "ensemble forward" + ! wavefield in the next noise simulation + ! + ! NOISE_TOMOGRAPHY = 2 - compute "ensemble forward" wavefield and store the + ! result; if an adjoint simulation is planned, users need to store + ! seismograms (actually, cross-correlograms) for later processing + ! + ! NOISE_TOMOGRAPHY = 3 - carry out adjoint simulation; users need to supply + ! adjoint sources constructed from cross-correlograms computed during the + ! "ensemble forward" step + ! + ! For an explanation of terms and concepts in noise tomography, see "Tromp et + ! al., 2011, Noise Cross-Correlation Sensitivity Kernels, Geophysical Journal + ! International" + integer :: NOISE_TOMOGRAPHY + + ! save forward arrays at the end of the simulation + logical :: SAVE_FORWARD + + ! variables used for partitioning + integer :: NPROC, PARTITIONING_TYPE + + ! number of control nodes + integer :: NGNOD + + ! number of time steps + integer (kind=RegInt_K) :: NSTEP + + ! time step size + double precision :: DT + + ! value of time_stepping_scheme to decide which time scheme will be used + ! 1 = Newmark (2nd order), + ! 2 = LDDRK4-6 (4th-order 6-stage low storage Runge-Kutta), + ! 3 = classical 4th-order 4-stage Runge-Kutta + integer :: time_stepping_scheme + + ! simulation + logical :: AXISYM + + logical :: P_SV + + ! computational platform type + logical :: GPU_MODE + + ! creates/reads a binary database that allows to skip all time consuming setup steps in initialization + ! 0 = does not read/create database + ! 1 = creates database + ! 2 = reads database + integer :: setup_with_binary_database + + ! mesh files when using external mesh + character(len=MAX_STRING_LEN) :: MODEL, SAVE_MODEL + + !#----------------------------------------------------------------------------- + !# + !# attenuation + !# + !#----------------------------------------------------------------------------- + ! variables used for attenuation + logical :: ATTENUATION_VISCOELASTIC + logical :: ATTENUATION_PORO_FLUID_PART + logical :: ATTENUATION_VISCOACOUSTIC + double precision :: Q0_poroelastic,freq0_poroelastic + + integer :: N_SLS + double precision :: ATTENUATION_f0_REFERENCE + logical :: READ_VELOCITIES_AT_f0 + logical :: USE_SOLVOPT + + ! undo attenuation + logical :: UNDO_ATTENUATION_AND_OR_PML + ! variables used for iteration + integer :: NT_DUMP_ATTENUATION + + !#----------------------------------------------------------------------------- + !# + !# sources + !# + !#----------------------------------------------------------------------------- + ! variables used for source-receiver geometry + integer :: NSOURCES + logical :: force_normal_to_surface + + ! variables used for plane wave incidence + logical :: initialfield + logical :: add_Bielak_conditions_bottom,add_Bielak_conditions_right,add_Bielak_conditions_top,add_Bielak_conditions_left + + ! acoustic forcing of an acoustic medium at a rigid interface + logical :: ACOUSTIC_FORCING + + ! noise simulations - source time function type + integer :: noise_source_time_function_type + + ! Flag for writing moving source databases or not + logical :: write_moving_sources_database + + !#----------------------------------------------------------------------------- + !# + !# receivers + !# + !#----------------------------------------------------------------------------- + integer :: NSIGTYPE + character(len=MAX_STRING_LEN) :: seismotype + + ! subsampling + integer :: NTSTEP_BETWEEN_OUTPUT_SAMPLE ! depreated: subsamp_seismos, renamed to NTSTEP_BETWEEN_OUTPUT_SAMPLE + + ! for better accuracy of pressure output (uses 2nd time-derivatives of the initial source time function) + logical :: USE_TRICK_FOR_BETTER_PRESSURE + + integer :: NTSTEP_BETWEEN_OUTPUT_SEISMOS ! deprecated: NSTEP_BETWEEN_OUTPUT_SEISMOS has been renamed + + ! Integrated energy field output + logical :: COMPUTE_INTEGRATED_ENERGY_FIELD + + ! use this t0 as earliest starting time rather than the automatically calculated one + ! (must be positive and bigger than the automatically one to be effective; + ! simulation will start at t = - t0) + double precision :: USER_T0 + + ! seismogram format + logical :: save_ASCII_seismograms + logical :: save_binary_seismograms_single,save_binary_seismograms_double + ! output seismograms in Seismic Unix format (adjoint traces will be read in the same format) + logical :: SU_FORMAT + + logical :: use_existing_STATIONS + + integer :: nreceiversets + + double precision :: anglerec + logical :: rec_normal_to_surface + + ! receiver sets + integer, dimension(:),allocatable :: nrec_line + double precision, dimension(:),allocatable :: xdeb,zdeb,xfin,zfin + logical, dimension(:),allocatable :: record_at_surface_same_vertical + + !#----------------------------------------------------------------------------- + !# + !# adjoint kernel outputs + !# + !#----------------------------------------------------------------------------- + ! kernel output in case of adjoint simulation + logical :: save_ASCII_kernels + integer :: NTSTEP_BETWEEN_COMPUTE_KERNELS + logical :: APPROXIMATE_HESS_KL + logical :: NO_BACKWARD_RECONSTRUCTION + + !#----------------------------------------------------------------------------- + !# + !# boundary conditions + !# + !#----------------------------------------------------------------------------- + + ! PML + logical :: PML_BOUNDARY_CONDITIONS + integer :: NELEM_PML_THICKNESS + logical :: ROTATE_PML_ACTIVATE + double precision :: ROTATE_PML_ANGLE + double precision :: K_MIN_PML + double precision :: K_MAX_PML + double precision :: damping_change_factor_acoustic + double precision :: damping_change_factor_elastic + logical :: PML_PARAMETER_ADJUSTMENT + + ! Stacey + logical :: STACEY_ABSORBING_CONDITIONS + + ! for horizontal periodic conditions: detect common points between left and right edges + logical :: ADD_PERIODIC_CONDITIONS + ! horizontal periodicity distance for periodic conditions + double precision :: PERIODIC_HORIZ_DIST + + !#----------------------------------------------------------------------------- + !# + !# velocity and density models + !# + !#----------------------------------------------------------------------------- + ! to store density and velocity model + ! (actual material table will be read in in src/meshfem2D/read_material_table.f90) + integer :: nbmodels + + ! input file name of TOMOGRAPHY + character(len=MAX_STRING_LEN) :: TOMOGRAPHY_FILE + + logical :: read_external_mesh + + !#----------------------------------------------------------------------------- + !# + !# PARAMETERS FOR EXTERNAL MESHING + !# + !#----------------------------------------------------------------------------- + character(len=MAX_STRING_LEN) :: mesh_file, nodes_coords_file, materials_file + + character(len=MAX_STRING_LEN) :: free_surface_file + character(len=MAX_STRING_LEN) :: absorbing_surface_file + character(len=MAX_STRING_LEN) :: acoustic_forcing_surface_file + character(len=MAX_STRING_LEN) :: axial_elements_file + character(len=MAX_STRING_LEN) :: absorbing_cpml_file + character(len=MAX_STRING_LEN) :: tangential_detection_curve_file + + !#----------------------------------------------------------------------------- + !# + !# PARAMETERS FOR INTERNAL MESHING + !# + !#----------------------------------------------------------------------------- + ! input parameter for in-house mesher + character(len=MAX_STRING_LEN) :: interfaces_filename + + double precision :: xmin_param,xmax_param + integer :: nx_param + + ! variables used for absorbing boundary condition + logical :: absorbbottom,absorbright,absorbtop,absorbleft + + ! number of regions + ! (see reading in of regions table in read_regions.f90 file) + integer :: nbregions + + !#----------------------------------------------------------------------------- + !# + !# display parameters + !# + !#----------------------------------------------------------------------------- + ! general information during the computation and for information of the stability behavior during the simulation + integer :: NTSTEP_BETWEEN_OUTPUT_INFO + + ! for later check of the grid + logical :: output_grid_Gnuplot,output_grid_ASCII + + ! for plotting the curve of energy + logical :: OUTPUT_ENERGY + integer :: NTSTEP_BETWEEN_OUTPUT_ENERGY + + !#----------------------------------------------------------------------------- + !# + !# movies/images/snaphots + !# + !#----------------------------------------------------------------------------- + ! time step interval for image output + integer :: NTSTEP_BETWEEN_OUTPUT_IMAGES + + ! threshold value + double precision :: cutsnaps + + ! JPEG image + logical :: output_color_image + integer :: imagetype_JPEG + ! factor to subsample color images output by the code (useful for very large models) + double precision :: factor_subsample_image + ! by default the code normalizes each image independently to its maximum; use this option to use the global maximum below instead + logical :: USE_CONSTANT_MAX_AMPLITUDE + ! constant maximum amplitude to use for all color images if the USE_CONSTANT_MAX_AMPLITUDE option is true + double precision :: CONSTANT_MAX_AMPLITUDE_TO_USE + ! nonlinear display to enhance small amplitudes in color images + double precision :: POWER_DISPLAY_COLOR + logical :: DRAW_SOURCES_AND_RECEIVERS + ! display acoustic layers as constant blue, because they likely correspond to water in the case of ocean acoustics + ! or in the case of offshore oil industry experiments. + ! (if off, display them as greyscale, as for elastic or poroelastic elements) + logical :: DRAW_WATER_IN_BLUE + ! use snapshot number in the file name of JPG color snapshots instead of the time step + logical :: USE_SNAPSHOT_NUMBER_IN_FILENAME + + ! Postscript image + logical :: output_postscript_snapshot + integer :: imagetype_postscript + logical :: meshvect,modelvect,boundvect,interpol + ! number of interpolation points + integer :: pointsdisp + ! subsampling + integer :: subsamp_postscript + double precision :: sizemax_arrows + ! US letter paper or European A4 + logical :: US_LETTER + + ! Wave field dumps + logical :: output_wavefield_dumps + integer :: imagetype_wavefield_dumps + logical :: use_binary_for_wavefield_dumps + + ! NUMBER_OF_SIMULTANEOUS_RUNS + integer :: NUMBER_OF_SIMULTANEOUS_RUNS + logical :: BROADCAST_SAME_MESH_AND_MODEL + +end module shared_input_parameters + +! +!======================================================================== +! + +module shared_parameters + +! for now, this just holds all input parameters given in DATA/Par_file +! in future, we might want both mesher and solver to read in the Par_file, similar to how 3D versions are handled + + use shared_input_parameters + + implicit none + + ! for Bielak condition + logical :: add_Bielak_conditions + ! for PML or Stacey boundary condition + logical :: any_abs + ! for interpolated snapshot + logical :: plot_lowerleft_corner_only + + + ! Parameter File + character(len=MAX_STRING_LEN) :: Par_file + + ! Database filename + character(len=MAX_STRING_LEN) :: database_filename + + ! output folder + character(len=MAX_STRING_LEN) :: OUTPUT_FILES + + ! Stations filename + character(len=MAX_STRING_LEN) :: stations_filename + + ! to store density and velocity model + integer, dimension(:),allocatable :: num_material + integer, dimension(:),allocatable :: icodemat + + double precision, dimension(:),allocatable :: rho_s_read + double precision, dimension(:),allocatable :: rho_f_read + + ! acoustic/elastic/anisotropic + double precision, dimension(:),allocatable :: cp,cs, & + aniso3,aniso4,aniso5,aniso6,aniso7,aniso8,aniso9,aniso10,aniso11,aniso12,comp_g,QKappa,Qmu + + ! poroelastic + ! note: adds ending _read to indicate these are readin values and to distinguish from solver arrays + ! one could check if the solver arrays could be omitted and replaced with this ones in future... + double precision, dimension(:),allocatable :: phi_read,tortuosity_read,permxx_read,permxz_read, & + permzz_read,kappa_s_read,kappa_f_read,kappa_fr_read,eta_f_read,mu_fr_read + + ! mesh setup + ! total number of elements + integer :: nelmnts + + ! interface file data + integer :: nx_elem_internal,nz_elem_internal + integer :: nxread,nzread + + ! from interfaces file + integer :: max_npoints_interface,number_of_interfaces + integer, dimension(:), allocatable :: npoints_of_interfaces + double precision, dimension(:,:), allocatable :: xinterface_coords,zinterface_coords + + ! vertical layers + integer :: number_of_layers + integer, dimension(:), allocatable :: nz_layer + + ! seismogram output + logical, parameter :: WRITE_SEISMOGRAMS_BY_MAIN = .true. + +end module shared_parameters + +! +!======================================================================== +! + +module source_file_par + + use constants, only: MAX_STRING_LEN + + implicit none + + ! source type parameters + integer, dimension(:),allocatable :: source_type,time_function_type + + ! location + double precision, dimension(:),allocatable :: x_source,z_source + + ! moment tensor + double precision, dimension(:),allocatable :: Mxx,Mzz,Mxz + + ! force + double precision, dimension(:),allocatable :: anglesource + double precision, dimension(:),allocatable :: factor + + ! source parameters + double precision, dimension(:),allocatable :: tshift_src + double precision, dimension(:),allocatable :: f0_source,burst_band_width + + ! horizontal and vertical velocities (for moving sources) + double precision, dimension(:),allocatable :: vx_source,vz_source + + ! flag for fixation to surface (works only for internal meshes, not external ones) + logical, dimension(:),allocatable :: source_surf + + ! File name can't exceed MAX_STRING_LEN characters + character(len=MAX_STRING_LEN), dimension(:),allocatable :: name_of_source_file + + ! Flag for moving sources + logical :: SOURCE_IS_MOVING + +end module source_file_par diff --git a/meshfem2d/spline_routines.f90 b/meshfem2d/spline_routines.f90 new file mode 100644 index 00000000..ceb88db6 --- /dev/null +++ b/meshfem2d/spline_routines.f90 @@ -0,0 +1,163 @@ +!======================================================================== +! +! S P E C F E M 2 D +! ----------------- +! +! Main historical authors: Dimitri Komatitsch and Jeroen Tromp +! CNRS, France +! and Princeton University, USA +! (there are currently many more authors!) +! (c) October 2017 +! +! This software is a computer program whose purpose is to solve +! the two-dimensional viscoelastic anisotropic or poroelastic wave equation +! using a spectral-element method (SEM). +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 3 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License along +! with this program; if not, write to the Free Software Foundation, Inc., +! 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +! +! The full text of the license is available in file "LICENSE". +! +!======================================================================== + +! compute spline coefficients + + subroutine spline_construction(xpoint,ypoint,npoint,tangent_first_point,tangent_last_point,spline_coefficients) + + implicit none + +! tangent to the spline imposed at the first and last points + double precision, intent(in) :: tangent_first_point,tangent_last_point + +! number of input points and coordinates of the input points + integer, intent(in) :: npoint + double precision, dimension(npoint), intent(in) :: xpoint,ypoint + +! spline coefficients output by the routine + double precision, dimension(npoint), intent(out) :: spline_coefficients + + integer :: i + + double precision, dimension(:), allocatable :: temporary_array + + allocate(temporary_array(npoint)) + + spline_coefficients(1) = - 1.d0 / 2.d0 + + temporary_array(1) = (3.d0/(xpoint(2)-xpoint(1)))*((ypoint(2)-ypoint(1))/(xpoint(2)-xpoint(1))-tangent_first_point) + + do i = 2,npoint-1 + + spline_coefficients(i) = ((xpoint(i)-xpoint(i-1))/(xpoint(i+1)-xpoint(i-1))-1.d0) & + / ((xpoint(i)-xpoint(i-1))/(xpoint(i+1)-xpoint(i-1))*spline_coefficients(i-1)+2.d0) + + temporary_array(i) = (6.d0*((ypoint(i+1)-ypoint(i))/(xpoint(i+1)-xpoint(i)) & + - (ypoint(i)-ypoint(i-1))/(xpoint(i)-xpoint(i-1)))/(xpoint(i+1)-xpoint(i-1)) & + - (xpoint(i)-xpoint(i-1))/(xpoint(i+1)-xpoint(i-1))*temporary_array(i-1)) & + / ((xpoint(i)-xpoint(i-1))/(xpoint(i+1)-xpoint(i-1))*spline_coefficients(i-1)+2.d0) + + enddo + + spline_coefficients(npoint) = ((3.d0/(xpoint(npoint)-xpoint(npoint-1))) & + * (tangent_last_point-(ypoint(npoint)-ypoint(npoint-1))/(xpoint(npoint)-xpoint(npoint-1))) & + - 1.d0/2.d0*temporary_array(npoint-1))/(1.d0/2.d0*spline_coefficients(npoint-1)+1.d0) + + do i = npoint-1,1,-1 + spline_coefficients(i) = spline_coefficients(i)*spline_coefficients(i+1) + temporary_array(i) + enddo + + deallocate(temporary_array) + + end subroutine spline_construction + +! +! ------------------------------------------------------------------------------------------------ +! + +! evaluate a spline + + subroutine spline_evaluation(xpoint,ypoint,spline_coefficients,npoint,x_evaluate_spline,y_spline_obtained) + + implicit none + +! number of input points and coordinates of the input points + integer, intent(in) :: npoint + double precision, dimension(npoint), intent(in) :: xpoint,ypoint + +! spline coefficients to use + double precision, dimension(npoint), intent(in) :: spline_coefficients + +! abscissa at which we need to evaluate the value of the spline + double precision, intent(in):: x_evaluate_spline + +! ordinate evaluated by the routine for the spline at this abscissa + double precision, intent(out):: y_spline_obtained + + integer :: index_loop,index_lower,index_higher + + double precision :: coef1,coef2 + +! initialize to the whole interval + index_lower = 1 + index_higher = npoint + +! determine the right interval to use, by dichotomy + do while (index_higher - index_lower > 1) +! compute the middle of the interval + index_loop = (index_higher + index_lower) / 2 + if (xpoint(index_loop) > x_evaluate_spline) then + index_higher = index_loop + else + index_lower = index_loop + endif + enddo + +! test that the interval obtained does not have a size of zero +! (this could happen for instance in the case of duplicates in the input list of points) + if (xpoint(index_higher) == xpoint(index_lower)) call stop_the_code('incorrect interval found in spline evaluation') + + coef1 = (xpoint(index_higher) - x_evaluate_spline) / (xpoint(index_higher) - xpoint(index_lower)) + coef2 = (x_evaluate_spline - xpoint(index_lower)) / (xpoint(index_higher) - xpoint(index_lower)) + + y_spline_obtained = coef1*ypoint(index_lower) + coef2*ypoint(index_higher) + & + ((coef1**3 - coef1)*spline_coefficients(index_lower) + & + (coef2**3 - coef2)*spline_coefficients(index_higher))*((xpoint(index_higher) - xpoint(index_lower))**2)/6.d0 + + end subroutine spline_evaluation + +! +! ------------------------------------------------------------------------------------------------ +! + +!--- spline to describe the interfaces + + double precision function value_spline(x,xinterface,zinterface,coefs_interface,npoints_interface) + + implicit none + + integer npoints_interface + double precision x,xp + double precision, dimension(npoints_interface) :: xinterface,zinterface,coefs_interface + + value_spline = 0.d0 + + xp = x + + ! assign the value on the edge if point is outside the model + if (xp < xinterface(1)) xp = xinterface(1) + if (xp > xinterface(npoints_interface)) xp = xinterface(npoints_interface) + + call spline_evaluation(xinterface,zinterface,coefs_interface,npoints_interface,xp,value_spline) + + end function value_spline diff --git a/meshfem2d/version.fh b/meshfem2d/version.fh new file mode 100644 index 00000000..e3b26aa5 --- /dev/null +++ b/meshfem2d/version.fh @@ -0,0 +1,4 @@ +! version information +character(len=*), parameter :: git_package_version = "v8.0.0-11-gf8c66778" +character(len=*), parameter :: git_commit_version = "f8c66778e3bcff99be726113a1aca338255ed87e" +character(len=*), parameter :: git_date_version = "2023-03-21 19:54:51 +0100" diff --git a/meshfem2d/write_VTK_data.f90 b/meshfem2d/write_VTK_data.f90 new file mode 100644 index 00000000..f8b75010 --- /dev/null +++ b/meshfem2d/write_VTK_data.f90 @@ -0,0 +1,128 @@ +!======================================================================== +! +! S P E C F E M 2 D +! ----------------- +! +! Main historical authors: Dimitri Komatitsch and Jeroen Tromp +! CNRS, France +! and Princeton University, USA +! (there are currently many more authors!) +! (c) October 2017 +! +! This software is a computer program whose purpose is to solve +! the two-dimensional viscoelastic anisotropic or poroelastic wave equation +! using a spectral-element method (SEM). +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 3 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License along +! with this program; if not, write to the Free Software Foundation, Inc., +! 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +! +! The full text of the license is available in file "LICENSE". +! +!======================================================================== + + +!------------------------------------------------------------------------------------ +! +! VTK routines for meshfem3D +! +!------------------------------------------------------------------------------------ + +! for details: +! +! VTK type definition numbers: +! https://vtk.org/doc/nightly/html/vtkCellType_8h_source.html +! ordering images see e.g.: +! https://lorensen.github.io/VTKExamples/site/VTKBook/05Chapter5/ + + + subroutine write_VTK_data_ngnod_elem_i(nspec,nglob,NGNOD, & + xstore_dummy,zstore_dummy,elmnts, & + elem_flag,filename) + +! stores element flags (integers) on 2D quad mesh + + use constants, only: IOUT_VTK,MAX_STRING_LEN + + implicit none + + integer :: nspec,nglob,NGNOD + + ! global coordinates + integer, dimension(NGNOD,nspec) :: elmnts + double precision, dimension(nglob) :: xstore_dummy,zstore_dummy + + ! element flag array + integer, dimension(nspec) :: elem_flag + + ! file name + character(len=MAX_STRING_LEN) :: filename + + ! local parameters + integer :: ispec,i,itype + + ! safety check + if (NGNOD == 4) then + ! VTK_QUAD == 8 type + itype = 8 + else if (NGNOD == 9) then + ! VTK_BIQUADRATIC_QUAD = 28 type + itype = 28 + else + stop 'Error invalid NGNOD in write_VTK_data_ngnod_elem_i routine' + endif + + ! debug + !print *,'debug:',itype,nglob,nspec,xstore_dummy(1),zstore_dummy(1) + !print *,'debug:',elmnts(:,1) ! index values should start at 0 + + ! write source and receiver VTK files for Paraview + open(IOUT_VTK,file=trim(filename),status='unknown') + write(IOUT_VTK,'(a)') '# vtk DataFile Version 3.1' + write(IOUT_VTK,'(a)') 'material model VTK file' + write(IOUT_VTK,'(a)') 'ASCII' + write(IOUT_VTK,'(a)') 'DATASET UNSTRUCTURED_GRID' + write(IOUT_VTK, '(a,i12,a)') 'POINTS ', nglob, ' float' + do i = 1,nglob + write(IOUT_VTK,'(3e18.6)') xstore_dummy(i),0.0,zstore_dummy(i) ! assuming Y-coordinate at zero + enddo + write(IOUT_VTK,*) "" + + ! note: indices for vtk start at 0 + write(IOUT_VTK,'(a,i12,i12)') "CELLS ",nspec,nspec*(NGNOD+1) + do ispec = 1,nspec + if (NGNOD == 4) then + ! quad4 element using an indexing (left,bottom),(right,bottom),(right,top),(left,top) + write(IOUT_VTK,'(9i12)') NGNOD,elmnts(1,ispec)-1,elmnts(2,ispec)-1,elmnts(4,ispec)-1,elmnts(3,ispec)-1 + else + ! quad9 element + write(IOUT_VTK,'(9i12)') NGNOD,(elmnts(i,ispec)-1,i=1,NGNOD) + endif + enddo + write(IOUT_VTK,*) "" + + ! type: hexahedrons + write(IOUT_VTK,'(a,i12)') "CELL_TYPES ",nspec + write(IOUT_VTK,'(6i12)') (itype,ispec=1,nspec) + write(IOUT_VTK,*) "" + + write(IOUT_VTK,'(a,i12)') "CELL_DATA ",nspec + write(IOUT_VTK,'(a)') "SCALARS elem_flag integer" + write(IOUT_VTK,'(a)') "LOOKUP_TABLE default" + do ispec = 1,nspec + write(IOUT_VTK,*) elem_flag(ispec) + enddo + write(IOUT_VTK,*) "" + close(IOUT_VTK) + + end subroutine write_VTK_data_ngnod_elem_i diff --git a/nsys_demo.nsys-rep b/nsys_demo.nsys-rep new file mode 100644 index 00000000..6624ed9d Binary files /dev/null and b/nsys_demo.nsys-rep differ diff --git a/src/compute/compute.cpp b/src/compute/compute.cpp index 58a75e7b..52ba7ff6 100644 --- a/src/compute/compute.cpp +++ b/src/compute/compute.cpp @@ -197,8 +197,8 @@ specfem::compute::compute::compute( Kokkos::parallel_for( Kokkos::TeamThreadRange(teamMember, ngllxz), [&](const int xz) { - const int ix = xz % ngllz; - const int iz = xz / ngllz; + int ix, iz; + sub2ind(xz, ngllx, iz, ix); const int iloc = ispec * (ngllxz) + xz; // Get x and y coordinates for (ix, iz) point diff --git a/src/compute/compute_boundaries.cpp b/src/compute/compute_boundaries.cpp new file mode 100644 index 00000000..f8e0e27c --- /dev/null +++ b/src/compute/compute_boundaries.cpp @@ -0,0 +1,214 @@ +#include "compute/compute_boundaries.hpp" +#include "enumerations/specfem_enums.hpp" +#include "kokkos_abstractions.h" +#include "macros.hpp" +#include "mesh/mesh.hpp" +#include + +namespace { + +// Every element is tagged with a boundary type +// An element can be either of the follwing types: +// 1. Stacey +// 2. Acoustic Free Surface (Dirichlet) +// 3. Stacey and Acoustic Free Surface (Composite Stacey-Dirichlet) +void tag_elements( + const specfem::kokkos::HostView1d &kmato, + const specfem::enums::element::type &medium, + const std::vector &materials, + const specfem::mesh::boundaries::absorbing_boundary &absorbing_boundaries, + const specfem::mesh::boundaries::acoustic_free_surface + &acoustic_free_surface, + std::vector &boundary_tag, + std::vector &boundary_types) { + const int nspec = kmato.extent(0); + + ASSERT(boundary_tag.size() == nspec, "Error: Boundary tag size mismatch"); + ASSERT(boundary_types.size() == nspec, "Error: Boundary types size mismatch"); + + for (int i = 0; i < absorbing_boundaries.nelements; ++i) { + const int ispec = absorbing_boundaries.ispec(i); + // Only tag acoustic elements + if (materials[kmato(ispec)]->get_ispec_type() == medium) { + boundary_tag[ispec] += specfem::enums::element::boundary_tag::stacey; + boundary_types[ispec].update_boundary_type( + absorbing_boundaries.type(i), + specfem::enums::element::boundary_tag::stacey); + } + } + + for (int i = 0; i < acoustic_free_surface.nelem_acoustic_surface; ++i) { + const int ispec = acoustic_free_surface.ispec_acoustic_surface(i); + if (materials[kmato(ispec)]->get_ispec_type() != + specfem::enums::element::type::acoustic) { + throw std::invalid_argument( + "Error: Acoustic free surface boundary is not an acoustic element"); + } + boundary_tag[ispec] += + specfem::enums::element::boundary_tag::acoustic_free_surface; + boundary_types[ispec].update_boundary_type( + acoustic_free_surface.type(i), + specfem::enums::element::boundary_tag::acoustic_free_surface); + } +} + +template +void assign_boundary( + const std::vector + boundary_tag, + const std::vector boundary_types, + const specfem::enums::element::boundary_tag tag, boundary_type *boundary) { + const int nspec = boundary_tag.size(); + + boundary->nelements = + std::count(boundary_tag.begin(), boundary_tag.end(), tag); + + boundary->ispec = specfem::kokkos::DeviceView1d( + "specfem::compute::boundaries::composite_stacey_dirichlet::ispec", + boundary->nelements); + boundary->type = + specfem::kokkos::DeviceView1d( + "specfem::compute::boundaries::composite_stacey_dirichlet::type", + boundary->nelements); + + boundary->h_ispec = Kokkos::create_mirror_view(boundary->ispec); + boundary->h_type = Kokkos::create_mirror_view(boundary->type); + + int index = 0; + for (int ispec = 0; ispec < nspec; ++ispec) { + if (boundary_tag[ispec] == tag) { + boundary->h_ispec(index) = ispec; + boundary->h_type(index) = boundary_types[ispec]; + index++; + } + } + + assert(index == boundary->nelements); + + Kokkos::deep_copy(boundary->ispec, boundary->h_ispec); + Kokkos::deep_copy(boundary->type, boundary->h_type); +} +} // namespace + +specfem::compute::acoustic_free_surface::acoustic_free_surface( + const specfem::kokkos::HostView1d kmato, + const std::vector materials, + const specfem::mesh::boundaries::absorbing_boundary &absorbing_boundaries, + const specfem::mesh::boundaries::acoustic_free_surface + &acoustic_free_surface) { + const int nspec = kmato.extent(0); + if (acoustic_free_surface.nelem_acoustic_surface > 0) { + std::vector boundary_tag( + nspec); + std::vector boundary_types(nspec); + tag_elements(kmato, specfem::enums::element::type::acoustic, materials, + absorbing_boundaries, acoustic_free_surface, boundary_tag, + boundary_types); + assign_boundary( + boundary_tag, boundary_types, + specfem::enums::element::boundary_tag::acoustic_free_surface, this); + } else { + this->nelements = 0; + } +} + +specfem::compute::stacey_medium::stacey_medium( + const specfem::enums::element::type medium, + const specfem::kokkos::HostView1d kmato, + const std::vector materials, + const specfem::mesh::boundaries::absorbing_boundary &absorbing_boundaries, + const specfem::mesh::boundaries::acoustic_free_surface + &acoustic_free_surface) { + + const int nspec = kmato.extent(0); + if (absorbing_boundaries.nelements > 0) { + std::vector boundary_tag( + nspec); + std::vector boundary_types(nspec); + tag_elements(kmato, medium, materials, absorbing_boundaries, + acoustic_free_surface, boundary_tag, boundary_types); + assign_boundary(boundary_tag, boundary_types, + specfem::enums::element::boundary_tag::stacey, this); + } else { + this->nelements = 0; + } +} + +specfem::compute::stacey::stacey( + const specfem::kokkos::HostView1d kmato, + const std::vector materials, + const specfem::mesh::boundaries::absorbing_boundary &absorbing_boundaries, + const specfem::mesh::boundaries::acoustic_free_surface + &acoustic_free_surface) { + this->elastic = specfem::compute::stacey_medium( + specfem::enums::element::type::elastic, kmato, materials, + absorbing_boundaries, acoustic_free_surface); + this->acoustic = specfem::compute::stacey_medium( + specfem::enums::element::type::acoustic, kmato, materials, + absorbing_boundaries, acoustic_free_surface); + this->nelements = this->elastic.nelements + this->acoustic.nelements; +} + +specfem::compute::composite_stacey_dirichlet::composite_stacey_dirichlet( + const specfem::kokkos::HostView1d kmato, + const std::vector materials, + const specfem::mesh::boundaries::absorbing_boundary &absorbing_boundaries, + const specfem::mesh::boundaries::acoustic_free_surface + &acoustic_free_surface) { + + const int nspec = kmato.extent(0); + if (absorbing_boundaries.nelements > 0 && + acoustic_free_surface.nelem_acoustic_surface > 0) { + std::vector boundary_tag( + nspec); + std::vector boundary_types(nspec); + tag_elements(kmato, specfem::enums::element::type::acoustic, materials, + absorbing_boundaries, acoustic_free_surface, boundary_tag, + boundary_types); + assign_boundary( + boundary_tag, boundary_types, + specfem::enums::element::boundary_tag::composite_stacey_dirichlet, + this); + } else { + this->nelements = 0; + } +} + +void specfem::compute::access::boundary_types::update_boundary_type( + const specfem::enums::boundaries::type &type, + const specfem::enums::element::boundary_tag &tag) { + if (type == specfem::enums::boundaries::type::TOP) { + top = tag; + } else if (type == specfem::enums::boundaries::type::BOTTOM) { + bottom = tag; + } else if (type == specfem::enums::boundaries::type::LEFT) { + left = tag; + } else if (type == specfem::enums::boundaries::type::RIGHT) { + right = tag; + } else if (type == specfem::enums::boundaries::type::BOTTOM_RIGHT) { + bottom_right = tag; + } else if (type == specfem::enums::boundaries::type::BOTTOM_LEFT) { + bottom_left = tag; + } else if (type == specfem::enums::boundaries::type::TOP_RIGHT) { + top_right = tag; + } else if (type == specfem::enums::boundaries::type::TOP_LEFT) { + top_left = tag; + } else { + DEVICE_ASSERT(false, "Error: Unknown boundary type"); + } +} + +KOKKOS_FUNCTION +bool specfem::compute::access::is_on_boundary( + const specfem::enums::element::boundary_tag &tag, + const specfem::compute::access::boundary_types &type, const int &iz, + const int &ix, const int &ngllz, const int &ngllx) { + + return (type.top == tag && iz == ngllz - 1) || + (type.bottom == tag && iz == 0) || (type.left == tag && ix == 0) || + (type.right == tag && ix == ngllx - 1) || + (type.bottom_right == tag && iz == 0 && ix == ngllx - 1) || + (type.bottom_left == tag && iz == 0 && ix == 0) || + (type.top_right == tag && iz == ngllz - 1 && ix == ngllx - 1) || + (type.top_left == tag && iz == ngllz - 1 && ix == 0); +} diff --git a/src/compute/compute_partial_derivatives.cpp b/src/compute/compute_partial_derivatives.cpp index 7fe85d6c..da379581 100644 --- a/src/compute/compute_partial_derivatives.cpp +++ b/src/compute/compute_partial_derivatives.cpp @@ -1,6 +1,7 @@ #include "compute/interface.hpp" #include "jacobian/interface.hpp" #include "kokkos_abstractions.h" +#include "macros.hpp" #include specfem::compute::partial_derivatives::partial_derivatives(const int nspec, @@ -100,8 +101,8 @@ specfem::compute::partial_derivatives::partial_derivatives( Kokkos::parallel_for( Kokkos::TeamThreadRange(teamMember, ngllxz), [&](const int xz) { - const int ix = xz % ngllz; - const int iz = xz / ngllz; + int ix, iz; + sub2ind(xz, ngllx, iz, ix); // Get x and y coordinates for (ix, iz) point auto sv_shape2D = Kokkos::subview(shape2D, iz, ix, Kokkos::ALL); @@ -139,3 +140,30 @@ void specfem::compute::partial_derivatives::sync_views() { Kokkos::deep_copy(gammaz, h_gammaz); Kokkos::deep_copy(jacobian, h_jacobian); } + +// KOKKOS_FUNCTION specfem::kokkos::array_type +// specfem::compute::element_partial_derivatives::compute_normal( +// const specfem::enums::boundaries::type type) const { + +// switch (type) { +// case specfem::enums::boundaries::type::BOTTOM: +// return this->compute_normal(); +// break; +// case specfem::enums::boundaries::type::TOP: +// return this->compute_normal(); +// break; +// case specfem::enums::boundaries::type::LEFT: +// return this->compute_normal(); +// break; +// case specfem::enums::boundaries::type::RIGHT: +// return this->compute_normal(); +// break; +// default: +// #ifndef NDEBUG +// ASSERT(false, "Invalid boundary type"); +// #endif +// break; +// } + +// return specfem::kokkos::array_type(); +// } diff --git a/src/compute/compute_properties.cpp b/src/compute/compute_properties.cpp index a4dc7337..2006c6ac 100644 --- a/src/compute/compute_properties.cpp +++ b/src/compute/compute_properties.cpp @@ -10,7 +10,7 @@ specfem::compute::properties::properties(const int nspec, const int ngllz, "specfem::compute::properties::rho", nspec, ngllz, ngllx)), mu(specfem::kokkos::DeviceView3d( "specfem::compute::properties::mu", nspec, ngllz, ngllx)), - kappa(specfem::kokkos::HostView3d( + kappa(specfem::kokkos::DeviceView3d( "specfem::compute::properties::kappa", nspec, ngllz, ngllx)), qmu(specfem::kokkos::HostView3d( "specfem::compute::properties::qmu", nspec, ngllz, ngllx)), @@ -22,13 +22,21 @@ specfem::compute::properties::properties(const int nspec, const int ngllz, "specfem::compute::properties::rho_vs", nspec, ngllz, ngllx)), lambdaplus2mu(specfem::kokkos::DeviceView3d( "specfem::compute::properties::lambdaplus2mu", nspec, ngllz, ngllx)), - ispec_type(specfem::kokkos::DeviceView1d( - "specfem::compute::properties::ispec_type", nspec)) { + ispec_type(specfem::kokkos::DeviceView1d( + "specfem::compute::properties::ispec_type", nspec)), + rho_inverse(specfem::kokkos::DeviceView3d( + "specfem::compute::properties::rho_inverse", nspec, ngllz, ngllx)), + lambdaplus2mu_inverse(specfem::kokkos::DeviceView3d( + "specfem::compute::properties::lambdaplus2mu_inverse", nspec, ngllz, + ngllx)) { h_rho = Kokkos::create_mirror_view(rho); h_mu = Kokkos::create_mirror_view(mu); + h_kappa = Kokkos::create_mirror_view(kappa); h_lambdaplus2mu = Kokkos::create_mirror_view(lambdaplus2mu); h_ispec_type = Kokkos::create_mirror_view(ispec_type); + h_rho_inverse = Kokkos::create_mirror_view(rho_inverse); + h_lambdaplus2mu_inverse = Kokkos::create_mirror_view(lambdaplus2mu_inverse); }; specfem::compute::properties::properties( @@ -56,7 +64,7 @@ specfem::compute::properties::properties( holder.qkappa, holder.lambdaplus2mu); this->h_rho(ispec, iz, ix) = rho; this->h_mu(ispec, iz, ix) = mu; - this->kappa(ispec, iz, ix) = kappa; + this->h_kappa(ispec, iz, ix) = kappa; this->qmu(ispec, iz, ix) = qmu; this->qkappa(ispec, iz, ix) = qkappa; @@ -66,6 +74,8 @@ specfem::compute::properties::properties( this->rho_vp(ispec, iz, ix) = rho * vp; this->rho_vs(ispec, iz, ix) = rho * vs; + this->h_rho_inverse(ispec, iz, ix) = 1.0 / rho; + this->h_lambdaplus2mu_inverse(ispec, iz, ix) = 1.0 / lambdaplus2mu; this->h_lambdaplus2mu(ispec, iz, ix) = lambdaplus2mu; }); @@ -82,8 +92,11 @@ specfem::compute::properties::properties( void specfem::compute::properties::sync_views() { Kokkos::deep_copy(rho, h_rho); Kokkos::deep_copy(mu, h_mu); + Kokkos::deep_copy(kappa, h_kappa); Kokkos::deep_copy(lambdaplus2mu, h_lambdaplus2mu); Kokkos::deep_copy(ispec_type, h_ispec_type); + Kokkos::deep_copy(rho_inverse, h_rho_inverse); + Kokkos::deep_copy(lambdaplus2mu_inverse, h_lambdaplus2mu_inverse); return; } diff --git a/src/compute/compute_receivers.cpp b/src/compute/compute_receivers.cpp index ee53d93d..66a768af 100644 --- a/src/compute/compute_receivers.cpp +++ b/src/compute/compute_receivers.cpp @@ -10,7 +10,7 @@ specfem::compute::receivers::receivers( const std::vector &receivers, - const std::vector &stypes, + const std::vector &stypes, const specfem::quadrature::quadrature *quadx, const specfem::quadrature::quadrature *quadz, const type_real xmax, const type_real xmin, const type_real zmax, const type_real zmin, @@ -71,7 +71,7 @@ specfem::compute::receivers::receivers( } this->seismogram_types = - specfem::kokkos::DeviceView1d( + specfem::kokkos::DeviceView1d( "specfem::compute::receivers::seismogram_types", stypes.size()); this->h_seismogram_types = Kokkos::create_mirror_view(this->seismogram_types); @@ -80,6 +80,12 @@ specfem::compute::receivers::receivers( this->h_seismogram_types(i) = stypes[i]; } + this->receiver_field = specfem::kokkos::DeviceView6d( + "specfem::compute::receivers::receiver_field", max_sig_step, + my_receivers.size(), stypes.size(), 2, quadz->get_N(), quadx->get_N()); + + this->h_receiver_field = Kokkos::create_mirror_view(this->receiver_field); + this->sync_views(); return; diff --git a/src/compute/coupled_interfaces.cpp b/src/compute/coupled_interfaces.cpp new file mode 100644 index 00000000..3e828a26 --- /dev/null +++ b/src/compute/coupled_interfaces.cpp @@ -0,0 +1,512 @@ +#include "compute/coupled_interfaces.hpp" +// #include "compute/coupled_interfaces.tpp" +#include "enumerations/specfem_enums.hpp" +#include "kokkos_abstractions.h" +#include "macros.hpp" +#include "mesh/coupled_interfaces/coupled_interfaces.hpp" + +// Topological map ordering for coupled elements + +// +-----------------+ +-----------------+ +// | | | | +// | R | ^ ^ | L | +// | I | | | | E | +// | G | | | | F | +// | H | | | | T | +// | T | | | | | +// | BOTTOM | | BOTTOM | +// +-----------------+ +-----------------+ +// --------------> --------------> +// --------------> --------------> +// +-----------------+ +-----------------+ +// | TOP | | TOP | +// | R | ^ ^ | L | +// | I | | | | E | +// | G | | | | F | +// | H | | | | T | +// | T | | | | | +// | | | | +// +-----------------+ +-----------------+ + +// Given an edge, return the range of i, j indices to iterate over the edge in +// correct order The range is normalized to [0,1] +void get_edge_range(const specfem::enums::edge::type &edge, int &ibegin, + int &jbegin, int &iend, int &jend) { + switch (edge) { + case specfem::enums::edge::type::BOTTOM: + ibegin = 0; + jbegin = 0; + iend = 1; + jend = 0; + break; + case specfem::enums::edge::type::TOP: + ibegin = 1; + jbegin = 1; + iend = 0; + jend = 1; + break; + case specfem::enums::edge::type::LEFT: + ibegin = 0; + jbegin = 1; + iend = 0; + jend = 0; + break; + case specfem::enums::edge::type::RIGHT: + ibegin = 1; + jbegin = 0; + iend = 1; + jend = 1; + break; + default: + throw std::runtime_error("Invalid edge type"); + } +} + +// Given an edge, return the number of points along the edge +// This ends up being important when ngllx != ngllz +KOKKOS_FUNCTION +int specfem::compute::coupled_interfaces::access::npoints( + const specfem::enums::edge::type &edge, const int ngllx, const int ngllz) { + + switch (edge) { + case specfem::enums::edge::type::BOTTOM: + case specfem::enums::edge::type::TOP: + return ngllx; + break; + case specfem::enums::edge::type::LEFT: + case specfem::enums::edge::type::RIGHT: + return ngllz; + break; + default: + assert(false && "Invalid edge type"); + return 0; + } +} + +KOKKOS_FUNCTION +void specfem::compute::coupled_interfaces::access::self_iterator( + const int &ipoint, const specfem::enums::edge::type &edge, const int ngllx, + const int ngllz, int &i, int &j) { + + switch (edge) { + case specfem::enums::edge::type::BOTTOM: + i = ipoint; + j = 0; + break; + case specfem::enums::edge::type::TOP: + i = ngllx - 1 - ipoint; + j = ngllz - 1; + break; + case specfem::enums::edge::type::LEFT: + i = 0; + j = ipoint; + break; + case specfem::enums::edge::type::RIGHT: + i = ngllx - 1; + j = ngllz - 1 - ipoint; + break; + default: + assert(false && "Invalid edge type"); + } +} + +KOKKOS_FUNCTION +void specfem::compute::coupled_interfaces::access::coupled_iterator( + const int &ipoint, const specfem::enums::edge::type &edge, const int ngllx, + const int ngllz, int &i, int &j) { + + switch (edge) { + case specfem::enums::edge::type::BOTTOM: + i = ngllx - 1 - ipoint; + j = 0; + break; + case specfem::enums::edge::type::TOP: + i = ipoint; + j = ngllz - 1; + break; + case specfem::enums::edge::type::LEFT: + i = ngllx - 1; + j = ngllz - 1 - ipoint; + break; + case specfem::enums::edge::type::RIGHT: + i = 0; + j = ipoint; + break; + default: + assert(false && "Invalid edge type"); + } +} + +bool check_if_edges_are_connected( + const specfem::kokkos::HostView3d h_ibool, + const specfem::enums::edge::type &edge1, + const specfem::enums::edge::type &edge2, const int &ispec1, + const int &ispec2) { + + // Check that edge1 in element1 is coupling with edge2 in element2 + // The coupling should be in inverse order for the two elements + // (e.g. BOTTOM-TOP, LEFT-RIGHT) + // Check the diagram above + + const int ngllx = h_ibool.extent(2); + const int ngllz = h_ibool.extent(1); + + // Get the range of the two edges + int ibegin1, jbegin1, iend1, jend1; + int ibegin2, jbegin2, iend2, jend2; + + get_edge_range(edge1, ibegin1, jbegin1, iend1, jend1); + get_edge_range(edge2, ibegin2, jbegin2, iend2, jend2); + + // Get the global index range of the two edges + ibegin1 = ibegin1 * (ngllx - 1); + iend1 = iend1 * (ngllx - 1); + jbegin1 = jbegin1 * (ngllz - 1); + jend1 = jend1 * (ngllz - 1); + + ibegin2 = ibegin2 * (ngllx - 1); + iend2 = iend2 * (ngllx - 1); + jbegin2 = jbegin2 * (ngllz - 1); + jend2 = jend2 * (ngllz - 1); + + // Check if the corners of the two elements have the same global index + + return (h_ibool(ispec1, jbegin1, ibegin1) == h_ibool(ispec2, jend2, iend2)) && + (h_ibool(ispec2, jbegin2, ibegin2) == h_ibool(ispec1, jend1, iend1)); +} + +void compute_edges( + const specfem::kokkos::HostMirror3d h_ibool, + const specfem::kokkos::HostMirror1d ispec1, + const specfem::kokkos::HostMirror1d ispec2, + specfem::kokkos::HostMirror1d edge1, + specfem::kokkos::HostMirror1d edge2) { + + const int num_interfaces = ispec1.extent(0); + + for (int inum = 0; inum < num_interfaces; inum++) { + const int ispec1l = ispec1(inum); + const int ispec2l = ispec2(inum); + + int num_connected = 0; + for (int edge1l = 0; edge1l < specfem::enums::edge::num_edges; edge1l++) { + for (int edge2l = 0; edge2l < specfem::enums::edge::num_edges; edge2l++) { + if (check_if_edges_are_connected( + h_ibool, static_cast(edge1l), + static_cast(edge2l), ispec1l, + ispec2l)) { + // Check that the two edges are different + ASSERT(edge1l != edge2l, "Invalid edge1 and edge2"); + // BOTTOM-TOP, LEFT-RIGHT coupling + ASSERT((((static_cast(edge1l) == + specfem::enums::edge::type::BOTTOM) && + (static_cast(edge2l) == + specfem::enums::edge::type::TOP)) || + ((static_cast(edge1l) == + specfem::enums::edge::type::TOP) && + (static_cast(edge2l) == + specfem::enums::edge::type::BOTTOM)) || + ((static_cast(edge1l) == + specfem::enums::edge::type::LEFT) && + (static_cast(edge2l) == + specfem::enums::edge::type::RIGHT)) || + ((static_cast(edge1l) == + specfem::enums::edge::type::RIGHT) && + (static_cast(edge2l) == + specfem::enums::edge::type::LEFT))), + "Invalid edge1 and edge2"); + + edge1(inum) = static_cast(edge1l); + edge2(inum) = static_cast(edge2l); + num_connected++; + } + } + } + ASSERT(num_connected == 1, "More than one edge is connected"); + } + + return; +} + +void check_edges( + const specfem::kokkos::HostMirror3d h_ibool, + const specfem::kokkos::HostView2d coord, + const specfem::kokkos::HostMirror1d ispec1, + const specfem::kokkos::HostMirror1d ispec2, + const specfem::kokkos::HostMirror1d edge1, + const specfem::kokkos::HostMirror1d edge2) { + + const int num_interfaces = ispec1.extent(0); + const int ngllx = h_ibool.extent(2); + const int ngllz = h_ibool.extent(1); + + for (int interface = 0; interface < num_interfaces; interface++) { + const int ispec1l = ispec1(interface); + const int ispec2l = ispec2(interface); + + const auto edge1l = edge1(interface); + const auto edge2l = edge2(interface); + + // iterate over the edge + int npoints = specfem::compute::coupled_interfaces::access::npoints( + edge1l, ngllx, ngllz); + + for (int ipoint = 0; ipoint < npoints; ipoint++) { + // Get ipoint along the edge in element1 + int i1, j1; + specfem::compute::coupled_interfaces::access::self_iterator( + ipoint, edge1l, ngllx, ngllz, i1, j1); + const int iglob1 = h_ibool(ispec1l, j1, i1); + + // Get ipoint along the edge in element2 + int i2, j2; + specfem::compute::coupled_interfaces::access::coupled_iterator( + ipoint, edge2l, ngllx, ngllz, i2, j2); + const int iglob2 = h_ibool(ispec2l, j2, i2); + + // Check that the distance between the two points is small + + type_real distance = (((coord(0, iglob1) - coord(0, iglob2)) * + (coord(0, iglob1) - coord(0, iglob2))) + + ((coord(1, iglob1) - coord(1, iglob2)) * + (coord(1, iglob1) - coord(1, iglob2)))); + + ASSERT((((coord(0, iglob1) - coord(0, iglob2)) * + (coord(0, iglob1) - coord(0, iglob2))) + + ((coord(1, iglob1) - coord(1, iglob2)) * + (coord(1, iglob1) - coord(1, iglob2)))) < 1.e-10, + "Invalid edge1 and edge2"); + } + } +} + +specfem::compute::coupled_interfaces::elastic_acoustic::elastic_acoustic( + const specfem::kokkos::HostMirror3d h_ibool, + const specfem::kokkos::HostView2d coord, + const specfem::kokkos::HostView1d + h_ispec_type, + const specfem::mesh::coupled_interfaces::elastic_acoustic &elastic_acoustic) + : num_interfaces(elastic_acoustic.num_interfaces), + elastic_ispec( + "compute::coupled_interfaces::elastic_acoustic::elastic_ispec", + elastic_acoustic.num_interfaces), + acoustic_ispec( + "compute::coupled_interfaces::elastic_acoustic::acoustic_ispec", + elastic_acoustic.num_interfaces), + elastic_edge( + "compute::coupled_interfaces::elastic_acoustic::elastic_edge", + elastic_acoustic.num_interfaces), + acoustic_edge( + "compute::coupled_interfaces::elastic_acoustic::acoustic_edge", + elastic_acoustic.num_interfaces) { + + if (num_interfaces == 0) + return; + + h_elastic_ispec = Kokkos::create_mirror_view(elastic_ispec); + h_acoustic_ispec = Kokkos::create_mirror_view(acoustic_ispec); + h_elastic_edge = Kokkos::create_mirror_view(elastic_edge); + h_acoustic_edge = Kokkos::create_mirror_view(acoustic_edge); + + h_elastic_ispec = elastic_acoustic.elastic_ispec; + h_acoustic_ispec = elastic_acoustic.acoustic_ispec; + + ASSERT(h_elastic_ispec.extent(0) == num_interfaces, "Invalid elastic_ispec"); + ASSERT(h_acoustic_ispec.extent(0) == num_interfaces, + "Invalid acoustic_ispec"); + ASSERT(elastic_edge.extent(0) == num_interfaces, "Invalid elastic_edge"); + ASSERT(h_acoustic_edge.extent(0) == num_interfaces, "Invalid acoustic_edge"); + +#ifndef NDEBUG + for (int i = 0; i < num_interfaces; i++) { + int ispec_elastic = h_elastic_ispec(i); + int ispec_acoustic = h_acoustic_ispec(i); + + // Check that the interface is between an elastic and an acoustic element + + ASSERT(((ispec_elastic != ispec_acoustic) && + (h_ispec_type(ispec_elastic) == + specfem::enums::element::type::elastic) && + (h_ispec_type(ispec_acoustic) == + specfem::enums::element::type::acoustic)), + "Invalid interface"); + } +#endif + + compute_edges(h_ibool, h_elastic_ispec, h_acoustic_ispec, h_elastic_edge, + h_acoustic_edge); + +#ifndef NDEBUG + check_edges(h_ibool, coord, h_elastic_ispec, h_acoustic_ispec, h_elastic_edge, + h_acoustic_edge); +#endif + + Kokkos::deep_copy(elastic_ispec, h_elastic_ispec); + Kokkos::deep_copy(acoustic_ispec, h_acoustic_ispec); + Kokkos::deep_copy(elastic_edge, h_elastic_edge); + Kokkos::deep_copy(acoustic_edge, h_acoustic_edge); + + return; +} + +specfem::compute::coupled_interfaces::elastic_poroelastic::elastic_poroelastic( + const specfem::kokkos::HostMirror3d h_ibool, + const specfem::kokkos::HostView2d coord, + const specfem::kokkos::HostView1d + h_ispec_type, + const specfem::mesh::coupled_interfaces::elastic_poroelastic + &elastic_poroelastic) + : num_interfaces(elastic_poroelastic.num_interfaces), + elastic_ispec( + "compute::coupled_interfaces::elastic_poroelastic::elastic_ispec", + elastic_poroelastic.num_interfaces), + poroelastic_ispec("compute::coupled_interfaces::elastic_poroelastic::" + "poroelastic_ispec", + elastic_poroelastic.num_interfaces), + elastic_edge( + "compute::coupled_interfaces::elastic_poroelastic::elastic_edge", + elastic_poroelastic.num_interfaces), + poroelastic_edge("compute::coupled_interfaces::elastic_poroelastic::" + "poroelastic_edge", + elastic_poroelastic.num_interfaces) { + + if (num_interfaces == 0) + return; + + h_elastic_ispec = Kokkos::create_mirror_view(elastic_ispec); + h_poroelastic_ispec = Kokkos::create_mirror_view(poroelastic_ispec); + h_elastic_edge = Kokkos::create_mirror_view(elastic_edge); + h_poroelastic_edge = Kokkos::create_mirror_view(poroelastic_edge); + + h_elastic_ispec = elastic_poroelastic.elastic_ispec; + h_poroelastic_ispec = elastic_poroelastic.poroelastic_ispec; + + ASSERT(h_elastic_ispec.extent(0) == num_interfaces, "Invalid elastic_ispec"); + ASSERT(h_poroelastic_ispec.extent(0) == num_interfaces, + "Invalid poroelastic_ispec"); + ASSERT(elastic_edge.extent(0) == num_interfaces, "Invalid elastic_edge"); + ASSERT(h_poroelastic_edge.extent(0) == num_interfaces, + "Invalid poroelastic_edge"); + +#ifndef NDEBUG + for (int i = 0; i < num_interfaces; i++) { + int ispec_elastic = h_elastic_ispec(i); + int ispec_poroelastic = h_poroelastic_ispec(i); + + // Check that the interface is between an elastic and a poroelastic + // element + ASSERT(((ispec_elastic != ispec_poroelastic) && + (h_ispec_type(ispec_elastic) == + specfem::enums::element::type::elastic) && + (h_ispec_type(ispec_poroelastic) == + specfem::enums::element::type::poroelastic)), + "Invalid interface"); + } +#endif + + compute_edges(h_ibool, h_elastic_ispec, h_poroelastic_ispec, h_elastic_edge, + h_poroelastic_edge); + +#ifndef NDEBUG + check_edges(h_ibool, coord, h_elastic_ispec, h_poroelastic_ispec, + h_elastic_edge, h_poroelastic_edge); +#endif + + Kokkos::deep_copy(elastic_ispec, h_elastic_ispec); + Kokkos::deep_copy(poroelastic_ispec, h_poroelastic_ispec); + Kokkos::deep_copy(elastic_edge, h_elastic_edge); + Kokkos::deep_copy(poroelastic_edge, h_poroelastic_edge); + + return; +} + +specfem::compute::coupled_interfaces::acoustic_poroelastic:: + acoustic_poroelastic( + const specfem::kokkos::HostMirror3d h_ibool, + const specfem::kokkos::HostView2d coord, + const specfem::kokkos::HostView1d + h_ispec_type, + const specfem::mesh::coupled_interfaces::acoustic_poroelastic + &acoustic_poroelastic) + : num_interfaces(acoustic_poroelastic.num_interfaces), + acoustic_ispec( + "compute::coupled_interfaces::acoustic_poroelastic::acoustic_ispec", + acoustic_poroelastic.num_interfaces), + poroelastic_ispec("compute::coupled_interfaces::acoustic_poroelastic::" + "poroelastic_ispec", + acoustic_poroelastic.num_interfaces), + acoustic_edge( + "compute::coupled_interfaces::acoustic_poroelastic::acoustic_edge", + acoustic_poroelastic.num_interfaces), + poroelastic_edge("compute::coupled_interfaces::acoustic_poroelastic::" + "poroelastic_edge", + acoustic_poroelastic.num_interfaces) { + + if (num_interfaces == 0) + return; + + h_acoustic_ispec = Kokkos::create_mirror_view(acoustic_ispec); + h_poroelastic_ispec = Kokkos::create_mirror_view(poroelastic_ispec); + h_acoustic_edge = Kokkos::create_mirror_view(acoustic_edge); + h_poroelastic_edge = Kokkos::create_mirror_view(poroelastic_edge); + + h_acoustic_ispec = acoustic_poroelastic.acoustic_ispec; + h_poroelastic_ispec = acoustic_poroelastic.poroelastic_ispec; + + ASSERT(h_acoustic_ispec.extent(0) == num_interfaces, + "Invalid acoustic_ispec"); + ASSERT(h_poroelastic_ispec.extent(0) == num_interfaces, + "Invalid poroelastic_ispec"); + ASSERT(acoustic_edge.extent(0) == num_interfaces, "Invalid acoustic_edge"); + ASSERT(h_poroelastic_edge.extent(0) == num_interfaces, + "Invalid poroelastic_edge"); + +#ifndef NDEBUG + for (int i = 0; i < num_interfaces; i++) { + int ispec_acoustic = h_acoustic_ispec(i); + int ispec_poroelastic = h_poroelastic_ispec(i); + + // Check that the interface is between an acoustic and a poroelastic + // element + ASSERT(((ispec_acoustic != ispec_poroelastic) && + (h_ispec_type(ispec_acoustic) == + specfem::enums::element::type::acoustic) && + (h_ispec_type(ispec_poroelastic) == + specfem::enums::element::type::poroelastic)), + "Invalid interface"); + } +#endif + + compute_edges(h_ibool, h_acoustic_ispec, h_poroelastic_ispec, h_acoustic_edge, + h_poroelastic_edge); + +#ifndef NDEBUG + check_edges(h_ibool, coord, h_acoustic_ispec, h_poroelastic_ispec, + h_acoustic_edge, h_poroelastic_edge); +#endif + + Kokkos::deep_copy(acoustic_ispec, h_acoustic_ispec); + Kokkos::deep_copy(poroelastic_ispec, h_poroelastic_ispec); + Kokkos::deep_copy(acoustic_edge, h_acoustic_edge); + Kokkos::deep_copy(poroelastic_edge, h_poroelastic_edge); + + return; +} + +specfem::compute::coupled_interfaces::coupled_interfaces::coupled_interfaces( + const specfem::kokkos::HostMirror3d h_ibool, + const specfem::kokkos::HostView2d coord, + const specfem::kokkos::HostView1d + h_ispec_type, + const specfem::mesh::coupled_interfaces::coupled_interfaces + &coupled_interfaces) + : elastic_acoustic(specfem::compute::coupled_interfaces::elastic_acoustic( + h_ibool, coord, h_ispec_type, coupled_interfaces.elastic_acoustic)), + elastic_poroelastic( + specfem::compute::coupled_interfaces::elastic_poroelastic( + h_ibool, coord, h_ispec_type, + coupled_interfaces.elastic_poroelastic)), + acoustic_poroelastic( + specfem::compute::coupled_interfaces::acoustic_poroelastic( + h_ibool, coord, h_ispec_type, + coupled_interfaces.acoustic_poroelastic)) {} diff --git a/src/domain/elastic_domain.cpp b/src/domain/elastic_domain.cpp deleted file mode 100644 index 95a96442..00000000 --- a/src/domain/elastic_domain.cpp +++ /dev/null @@ -1,848 +0,0 @@ -#include "compute/interface.hpp" -#include "constants.hpp" -#include "domain/interface.hpp" -#include "globals.h" -#include "kokkos_abstractions.h" -#include "mathematical_operators/interface.hpp" -#include "quadrature/interface.hpp" -#include "specfem_setup.hpp" -#include -#include - -specfem::Domain::Elastic::Elastic(const int ndim, const int nglob) - : field(specfem::kokkos::DeviceView2d( - "specfem::Domain::Elastic::field", nglob, ndim)), - field_dot(specfem::kokkos::DeviceView2d( - "specfem::Domain::Elastic::field_dot", nglob, ndim)), - field_dot_dot( - specfem::kokkos::DeviceView2d( - "specfem::Domain::Elastic::field_dot_dot", nglob, ndim)), - rmass_inverse( - specfem::kokkos::DeviceView2d( - "specfem::Domain::Elastic::rmass_inverse", nglob, ndim)) { - - this->h_field = Kokkos::create_mirror_view(this->field); - this->h_field_dot = Kokkos::create_mirror_view(this->field_dot); - this->h_field_dot_dot = Kokkos::create_mirror_view(this->field_dot_dot); - this->h_rmass_inverse = Kokkos::create_mirror_view(this->rmass_inverse); - - return; -} - -specfem::Domain::Elastic::Elastic( - const int ndim, const int nglob, specfem::compute::compute *compute, - specfem::compute::properties *material_properties, - specfem::compute::partial_derivatives *partial_derivatives, - specfem::compute::sources *sources, specfem::compute::receivers *receivers, - specfem::quadrature::quadrature *quadx, - specfem::quadrature::quadrature *quadz) - : field(specfem::kokkos::DeviceView2d( - "specfem::Domain::Elastic::field", nglob, ndim)), - field_dot(specfem::kokkos::DeviceView2d( - "specfem::Domain::Elastic::field_dot", nglob, ndim)), - field_dot_dot( - specfem::kokkos::DeviceView2d( - "specfem::Domain::Elastic::field_dot_dot", nglob, ndim)), - rmass_inverse( - specfem::kokkos::DeviceView2d( - "specfem::Domain::Elastic::rmass_inverse", nglob, ndim)), - compute(compute), material_properties(material_properties), - partial_derivatives(partial_derivatives), sources(sources), - receivers(receivers), quadx(quadx), quadz(quadz) { - - this->h_field = Kokkos::create_mirror_view(this->field); - this->h_field_dot = Kokkos::create_mirror_view(this->field_dot); - this->h_field_dot_dot = Kokkos::create_mirror_view(this->field_dot_dot); - this->h_rmass_inverse = Kokkos::create_mirror_view(this->rmass_inverse); - - const auto ibool = compute->ibool; - const int nspec = ibool.extent(0); - const int ngllz = ibool.extent(1); - const int ngllx = ibool.extent(2); - - this->assign_views(); - - return; -}; - -KOKKOS_IMPL_HOST_FUNCTION -void specfem::Domain::Elastic::assign_views() { - - const auto ibool = compute->ibool; - const int nspec = ibool.extent(0); - const int ngllz = ibool.extent(1); - const int ngllx = ibool.extent(2); - const int nglob = field.extent(0); - - // Inverse of mass matrix - //---------------------------------------------------------------------------- - // Initialize views - Kokkos::parallel_for( - "specfem::Domain::Elastic::initiaze_views", - specfem::kokkos::DeviceMDrange<2, Kokkos::Iterate::Left>({ 0, 0 }, - { nglob, ndim }), - KOKKOS_CLASS_LAMBDA(const int iglob, const int idim) { - this->field(iglob, idim) = 0; - this->field_dot(iglob, idim) = 0; - this->field_dot_dot(iglob, idim) = 0; - this->rmass_inverse(iglob, idim) = 0; - }); - - // Compute the mass matrix - specfem::kokkos::DeviceScatterView2d results( - rmass_inverse); - auto wxgll = quadx->get_w(); - auto wzgll = quadz->get_w(); - auto rho = this->material_properties->rho; - auto ispec_type = this->material_properties->ispec_type; - auto jacobian = this->partial_derivatives->jacobian; - Kokkos::parallel_for( - "specfem::Domain::Elastic::compute_mass_matrix", - specfem::kokkos::DeviceMDrange<3, Kokkos::Iterate::Left>( - { 0, 0, 0 }, { nspec, ngllz, ngllx }), - KOKKOS_CLASS_LAMBDA(const int ispec, const int iz, const int ix) { - int iglob = ibool(ispec, iz, ix); - type_real rhol = rho(ispec, iz, ix); - auto access = results.access(); - if (ispec_type(ispec) == specfem::elements::elastic) { - access(iglob, 0) += - wxgll(ix) * wzgll(iz) * rhol * jacobian(ispec, iz, ix); - access(iglob, 1) += - wxgll(ix) * wzgll(iz) * rhol * jacobian(ispec, iz, ix); - } - }); - - Kokkos::Experimental::contribute(rmass_inverse, results); - - // invert the mass matrix - Kokkos::parallel_for( - "specfem::Domain::Elastic::Invert_mass_matrix", - specfem::kokkos::DeviceRange(0, nglob), - KOKKOS_CLASS_LAMBDA(const int iglob) { - if (rmass_inverse(iglob, 0) > 0.0) { - rmass_inverse(iglob, 0) = 1.0 / rmass_inverse(iglob, 0); - rmass_inverse(iglob, 1) = 1.0 / rmass_inverse(iglob, 1); - } else { - rmass_inverse(iglob, 0) = 1.0; - rmass_inverse(iglob, 1) = 1.0; - } - }); - // ---------------------------------------------------------------------- - - // Domain type - // ---------------------------------------------------------------------- - this->nelem_domain = 0; - for (int ispec = 0; ispec < nspec; ispec++) { - if (material_properties->h_ispec_type(ispec) == - specfem::elements::elastic) { - this->nelem_domain++; - } - } - - this->ispec_domain = specfem::kokkos::DeviceView1d( - "specfem::Domain::Elastic::ispec_domain", this->nelem_domain); - this->h_ispec_domain = Kokkos::create_mirror_view(ispec_domain); - - int index = 0; - for (int ispec = 0; ispec < nspec; ispec++) { - if (material_properties->h_ispec_type(ispec) == - specfem::elements::elastic) { - this->h_ispec_domain(index) = ispec; - index++; - } - } - - Kokkos::deep_copy(ispec_domain, h_ispec_domain); - - return; -} - -void specfem::Domain::Elastic::sync_field(specfem::sync::kind kind) { - - if (kind == specfem::sync::DeviceToHost) { - Kokkos::deep_copy(h_field, field); - } else if (kind == specfem::sync::HostToDevice) { - Kokkos::deep_copy(field, h_field); - } else { - throw std::runtime_error("Could not recognize the kind argument"); - } - - return; -} - -void specfem::Domain::Elastic::sync_field_dot(specfem::sync::kind kind) { - - if (kind == specfem::sync::DeviceToHost) { - Kokkos::deep_copy(h_field_dot, field_dot); - } else if (kind == specfem::sync::HostToDevice) { - Kokkos::deep_copy(field_dot, h_field_dot); - } else { - throw std::runtime_error("Could not recognize the kind argument"); - } - - return; -} - -void specfem::Domain::Elastic::sync_field_dot_dot(specfem::sync::kind kind) { - - if (kind == specfem::sync::DeviceToHost) { - Kokkos::deep_copy(h_field_dot_dot, field_dot_dot); - } else if (kind == specfem::sync::HostToDevice) { - Kokkos::deep_copy(field_dot_dot, h_field_dot_dot); - } else { - throw std::runtime_error("Could not recognize the kind argument"); - } - - return; -} - -void specfem::Domain::Elastic::sync_rmass_inverse(specfem::sync::kind kind) { - - if (kind == specfem::sync::DeviceToHost) { - Kokkos::deep_copy(h_rmass_inverse, rmass_inverse); - } else if (kind == specfem::sync::HostToDevice) { - Kokkos::deep_copy(rmass_inverse, h_rmass_inverse); - } else { - throw std::runtime_error("Could not recognize the kind argument"); - } - - return; -} - -// Specialized kernel when NGLLX == NGLLZ -// This kernel is templated for compiler optimizations. -// Specific instances of this kernel should be instantiated inside the kernel -// calling routine -template -void specfem::Domain::Elastic::compute_stiffness_interaction() { - - const auto hprime_xx = this->quadx->get_hprime(); - const auto hprime_zz = this->quadz->get_hprime(); - const auto xix = this->partial_derivatives->xix; - const auto xiz = this->partial_derivatives->xiz; - const auto gammax = this->partial_derivatives->gammax; - const auto gammaz = this->partial_derivatives->gammaz; - const auto ibool = this->compute->ibool; - const auto lambdaplus2mu = this->material_properties->lambdaplus2mu; - const auto mu = this->material_properties->mu; - const auto jacobian = this->partial_derivatives->jacobian; - const auto wxgll = this->quadx->get_w(); - const auto wzgll = this->quadz->get_w(); - const auto ispec_domain = this->ispec_domain; - const auto field = this->field; - auto field_dot_dot = this->field_dot_dot; - - constexpr int NGLL2 = NGLL * NGLL; - constexpr type_real NGLL_INV = 1.0 / NGLL; - - static_assert(NGLL2 == NGLL * NGLL); - - assert(hprime_zz.extent(0) == NGLL); - assert(hprime_xx.extent(0) == NGLL); - assert(hprime_zz.extent(1) == NGLL); - assert(hprime_xx.extent(1) == NGLL); - assert(xix.extent(1) == NGLL); - assert(xix.extent(2) == NGLL); - assert(xiz.extent(1) == NGLL); - assert(xiz.extent(2) == NGLL); - assert(gammax.extent(1) == NGLL); - assert(gammax.extent(2) == NGLL); - assert(gammaz.extent(1) == NGLL); - assert(gammaz.extent(2) == NGLL); - assert(ibool.extent(1) == NGLL); - assert(ibool.extent(2) == NGLL); - assert(lambdaplus2mu.extent(1) == NGLL); - assert(lambdaplus2mu.extent(2) == NGLL); - assert(mu.extent(1) == NGLL); - assert(mu.extent(1) == NGLL); - - int scratch_size = - 10 * specfem::kokkos::StaticDeviceScratchView2d::shmem_size(); - - scratch_size += - specfem::kokkos::StaticDeviceScratchView2d::shmem_size(); - - Kokkos::parallel_for( - "specfem::Domain::Elastic::compute_gradients", - specfem::kokkos::DeviceTeam(this->nelem_domain, NTHREADS, NLANES) - .set_scratch_size(0, Kokkos::PerTeam(scratch_size)), - KOKKOS_LAMBDA( - const specfem::kokkos::DeviceTeam::member_type &team_member) { - const int ispec = ispec_domain(team_member.league_rank()); - - // Assign scratch views - // Assign scratch views for views that are required by every thread - // during summations - specfem::kokkos::StaticDeviceScratchView2d - s_hprime_xx(team_member.team_scratch(0)); - specfem::kokkos::StaticDeviceScratchView2d - s_hprime_zz(team_member.team_scratch(0)); - specfem::kokkos::StaticDeviceScratchView2d - s_hprimewgll_xx(team_member.team_scratch(0)); - specfem::kokkos::StaticDeviceScratchView2d - s_hprimewgll_zz(team_member.team_scratch(0)); - specfem::kokkos::StaticDeviceScratchView2d s_iglob( - team_member.team_scratch(0)); - - // Temporary scratch arrays used in calculation of integrals - specfem::kokkos::StaticDeviceScratchView2d - s_fieldx(team_member.team_scratch(0)); - specfem::kokkos::StaticDeviceScratchView2d - s_fieldz(team_member.team_scratch(0)); - specfem::kokkos::StaticDeviceScratchView2d - s_temp1(team_member.team_scratch(0)); - specfem::kokkos::StaticDeviceScratchView2d - s_temp2(team_member.team_scratch(0)); - specfem::kokkos::StaticDeviceScratchView2d - s_temp3(team_member.team_scratch(0)); - specfem::kokkos::StaticDeviceScratchView2d - s_temp4(team_member.team_scratch(0)); - - Kokkos::parallel_for( - Kokkos::TeamThreadRange(team_member, NGLL2), [&](const int xz) { - const int iz = xz * NGLL_INV; - const int ix = xz - iz * NGLL; - const int iglob = ibool(ispec, iz, ix); - s_fieldx(iz, ix) = field(iglob, 0); - s_fieldz(iz, ix) = field(iglob, 1); - s_temp1(iz, ix) = 0.0; - s_temp2(iz, ix) = 0.0; - s_temp3(iz, ix) = 0.0; - s_temp4(iz, ix) = 0.0; - s_hprime_xx(iz, ix) = hprime_xx(iz, ix); - s_hprime_zz(iz, ix) = hprime_zz(iz, ix); - s_hprimewgll_xx(ix, iz) = wxgll(iz) * hprime_xx(iz, ix); - s_hprimewgll_zz(ix, iz) = wzgll(iz) * hprime_zz(iz, ix); - s_iglob(iz, ix) = iglob; - }); - - team_member.team_barrier(); - - specfem::mathematical_operators::compute_gradients_2D( - team_member, ispec, xix, xiz, gammax, gammaz, s_hprime_xx, - s_hprime_zz, s_fieldx, s_fieldz, s_temp1, s_temp2, s_temp3, - s_temp4); - - Kokkos::parallel_for( - Kokkos::TeamThreadRange(team_member, NGLL2), [&](const int xz) { - const int iz = xz * NGLL_INV; - const int ix = xz - iz * NGLL; - - const type_real lambdaplus2mul = lambdaplus2mu(ispec, iz, ix); - const type_real mul = mu(ispec, iz, ix); - const type_real lambdal = lambdaplus2mul - 2.0 * mul; - - const type_real xixl = xix(ispec, iz, ix); - const type_real xizl = xiz(ispec, iz, ix); - const type_real gammaxl = gammax(ispec, iz, ix); - const type_real gammazl = gammaz(ispec, iz, ix); - const type_real jacobianl = jacobian(ispec, iz, ix); - - type_real sigma_xx, sigma_zz, sigma_xz; - - if (specfem::globals::simulation_wave == specfem::wave::p_sv) { - // P_SV case - // sigma_xx - sigma_xx = lambdaplus2mul * s_temp1(iz, ix) + - lambdal * s_temp4(iz, ix); - - // sigma_zz - sigma_zz = lambdaplus2mul * s_temp4(iz, ix) + - lambdal * s_temp1(iz, ix); - - // sigma_xz - sigma_xz = mul * (s_temp3(iz, ix) + s_temp2(iz, ix)); - } else if (specfem::globals::simulation_wave == - specfem::wave::sh) { - // SH-case - // sigma_xx - sigma_xx = mul * s_temp1(iz, ix); // would be sigma_xy in - // CPU-version - - // sigma_xz - sigma_xz = mul * s_temp2(iz, ix); // sigma_zy - } - - s_temp1(iz, ix) = jacobianl * (sigma_xx * xixl + sigma_xz * xizl); - s_temp2(iz, ix) = jacobianl * (sigma_xz * xixl + sigma_zz * xizl); - s_temp3(iz, ix) = - jacobianl * (sigma_xx * gammaxl + sigma_xz * gammazl); - s_temp4(iz, ix) = - jacobianl * (sigma_xz * gammaxl + sigma_zz * gammazl); - }); - - team_member.team_barrier(); - - specfem::mathematical_operators::add_contributions( - team_member, wxgll, wzgll, s_hprimewgll_xx, s_hprimewgll_zz, - s_iglob, s_temp1, s_temp2, s_temp3, s_temp4, field_dot_dot); - }); - - Kokkos::fence(); - - return; -} - -void specfem::Domain::Elastic::compute_stiffness_interaction() { - - const auto hprime_xx = this->quadx->get_hprime(); - const auto hprime_zz = this->quadz->get_hprime(); - const auto xix = this->partial_derivatives->xix; - const auto xiz = this->partial_derivatives->xiz; - const auto gammax = this->partial_derivatives->gammax; - const auto gammaz = this->partial_derivatives->gammaz; - const auto ibool = this->compute->ibool; - const auto lambdaplus2mu = this->material_properties->lambdaplus2mu; - const auto mu = this->material_properties->mu; - const auto jacobian = this->partial_derivatives->jacobian; - const auto wxgll = this->quadx->get_w(); - const auto wzgll = this->quadz->get_w(); - const auto ispec_domain = this->ispec_domain; - const auto field = this->field; - auto field_dot_dot = this->field_dot_dot; - - const int ngllz = xix.extent(1); - const int ngllx = xiz.extent(2); - - const int ngll2 = ngllz * ngllx; - - int scratch_size = - 2 * - specfem::kokkos::DeviceScratchView2d::shmem_size(ngllx, ngllx); - - scratch_size += - 2 * - specfem::kokkos::DeviceScratchView2d::shmem_size(ngllz, ngllz); - - scratch_size += - 7 * - specfem::kokkos::DeviceScratchView2d::shmem_size(ngllz, ngllx); - - scratch_size += - specfem::kokkos::DeviceScratchView2d::shmem_size(ngllz, ngllx); - - Kokkos::parallel_for( - "specfem::Domain::Elastic::compute_gradients", - specfem::kokkos::DeviceTeam(this->nelem_domain, NTHREADS, NLANES) - .set_scratch_size(0, Kokkos::PerTeam(scratch_size)), - KOKKOS_LAMBDA( - const specfem::kokkos::DeviceTeam::member_type &team_member) { - const int ispec = ispec_domain(team_member.league_rank()); - - // Assign scratch views - // Assign scratch views for views that are required by every thread - // during summations - specfem::kokkos::DeviceScratchView2d s_hprime_xx( - team_member.team_scratch(0), ngllx, ngllx); - specfem::kokkos::DeviceScratchView2d s_hprime_zz( - team_member.team_scratch(0), ngllz, ngllz); - specfem::kokkos::DeviceScratchView2d s_hprimewgll_xx( - team_member.team_scratch(0), ngllx, ngllx); - specfem::kokkos::DeviceScratchView2d s_hprimewgll_zz( - team_member.team_scratch(0), ngllz, ngllz); - specfem::kokkos::DeviceScratchView2d s_iglob( - team_member.team_scratch(0), ngllz, ngllx); - - // Temporary scratch arrays used in calculation of integrals - specfem::kokkos::DeviceScratchView2d s_fieldx( - team_member.team_scratch(0), ngllz, ngllx); - specfem::kokkos::DeviceScratchView2d s_fieldz( - team_member.team_scratch(0), ngllz, ngllx); - specfem::kokkos::DeviceScratchView2d s_temp1( - team_member.team_scratch(0), ngllz, ngllx); - specfem::kokkos::DeviceScratchView2d s_temp2( - team_member.team_scratch(0), ngllz, ngllx); - specfem::kokkos::DeviceScratchView2d s_temp3( - team_member.team_scratch(0), ngllz, ngllx); - specfem::kokkos::DeviceScratchView2d s_temp4( - team_member.team_scratch(0), ngllz, ngllx); - - // ---------- Allocate shared views ------------------------------- - Kokkos::parallel_for( - Kokkos::TeamThreadRange(team_member, ngllx * ngllx), - [&](const int xz) { - int iz, ix; - sub2ind(xz, ngllx, iz, ix); - s_hprime_xx(iz, ix) = hprime_xx(iz, ix); - s_hprimewgll_xx(ix, iz) = wxgll(iz) * hprime_xx(iz, ix); - }); - - Kokkos::parallel_for( - Kokkos::TeamThreadRange(team_member, ngllz * ngllz), - [&](const int xz) { - int iz, ix; - sub2ind(xz, ngllz, iz, ix); - s_hprime_zz(iz, ix) = hprime_zz(iz, ix); - s_hprimewgll_zz(ix, iz) = wzgll(iz) * hprime_zz(iz, ix); - }); - - Kokkos::parallel_for(Kokkos::TeamThreadRange(team_member, ngll2), - [&](const int xz) { - int iz, ix; - sub2ind(xz, ngllx, iz, ix); - const int iglob = ibool(ispec, iz, ix); - s_fieldx(iz, ix) = field(iglob, 0); - s_fieldz(iz, ix) = field(iglob, 1); - s_temp1(iz, ix) = 0.0; - s_temp2(iz, ix) = 0.0; - s_temp3(iz, ix) = 0.0; - s_temp4(iz, ix) = 0.0; - s_iglob(iz, ix) = iglob; - }); - - // ------------------------------------------------------------------ - - team_member.team_barrier(); - - specfem::mathematical_operators::compute_gradients_2D( - team_member, ispec, xix, xiz, gammax, gammaz, s_hprime_xx, - s_hprime_zz, s_fieldx, s_fieldz, s_temp1, s_temp2, s_temp3, - s_temp4); - - Kokkos::parallel_for( - Kokkos::TeamThreadRange(team_member, ngll2), [&](const int xz) { - int iz, ix; - sub2ind(xz, ngllz, iz, ix); - - const type_real lambdaplus2mul = lambdaplus2mu(ispec, iz, ix); - const type_real mul = mu(ispec, iz, ix); - const type_real lambdal = lambdaplus2mul - 2.0 * mul; - - const type_real xixl = xix(ispec, iz, ix); - const type_real xizl = xiz(ispec, iz, ix); - const type_real gammaxl = gammax(ispec, iz, ix); - const type_real gammazl = gammaz(ispec, iz, ix); - const type_real jacobianl = jacobian(ispec, iz, ix); - - type_real sigma_xx, sigma_zz, sigma_xz; - - if (specfem::globals::simulation_wave == specfem::wave::p_sv) { - // P_SV case - // sigma_xx - sigma_xx = lambdaplus2mul * s_temp1(iz, ix) + - lambdal * s_temp4(iz, ix); - - // sigma_zz - sigma_zz = lambdaplus2mul * s_temp4(iz, ix) + - lambdal * s_temp1(iz, ix); - - // sigma_xz - sigma_xz = mul * (s_temp3(iz, ix) + s_temp2(iz, ix)); - } else if (specfem::globals::simulation_wave == - specfem::wave::sh) { - // SH-case - // sigma_xx - sigma_xx = mul * s_temp1(iz, ix); // would be sigma_xy in - // CPU-version - - // sigma_xz - sigma_xz = mul * s_temp2(iz, ix); // sigma_zy - } - - s_temp1(iz, ix) = jacobianl * (sigma_xx * xixl + sigma_xz * xizl); - s_temp2(iz, ix) = jacobianl * (sigma_xz * xixl + sigma_zz * xizl); - s_temp3(iz, ix) = - jacobianl * (sigma_xx * gammaxl + sigma_xz * gammazl); - s_temp4(iz, ix) = - jacobianl * (sigma_xz * gammaxl + sigma_zz * gammazl); - }); - - team_member.team_barrier(); - - specfem::mathematical_operators::add_contributions( - team_member, wxgll, wzgll, s_hprimewgll_xx, s_hprimewgll_zz, - s_iglob, s_temp1, s_temp2, s_temp3, s_temp4, field_dot_dot); - }); - - Kokkos::fence(); - - return; -} - -void specfem::Domain::Elastic::compute_stiffness_interaction_calling_routine() { - - const int ngllx = this->partial_derivatives->xix.extent(1); - const int ngllz = this->partial_derivatives->xix.extent(2); - - if (ngllx == 5 && (ngllx == ngllz)) { - this->compute_stiffness_interaction<5>(); - } else if (ngllx == 8 && (ngllx == ngllz)) { - this->compute_stiffness_interaction<8>(); - } else { - this->compute_stiffness_interaction(); - } - - return; -} - -KOKKOS_IMPL_HOST_FUNCTION -void specfem::Domain::Elastic::divide_mass_matrix() { - - const int nglob = this->rmass_inverse.extent(0); - - Kokkos::parallel_for( - "specfem::Domain::Elastic::divide_mass_matrix", - specfem::kokkos::DeviceRange(0, ndim * nglob), - KOKKOS_CLASS_LAMBDA(const int in) { - const int iglob = in % nglob; - const int idim = in / nglob; - this->field_dot_dot(iglob, idim) = - this->field_dot_dot(iglob, idim) * this->rmass_inverse(iglob, idim); - }); - - // Kokkos::fence(); - - return; -} - -void specfem::Domain::Elastic::compute_source_interaction( - const type_real timeval) { - - const int nsources = this->sources->source_array.extent(0); - const int ngllz = this->sources->source_array.extent(1); - const int ngllx = this->sources->source_array.extent(2); - const int ngllxz = ngllx * ngllz; - const auto ispec_array = this->sources->ispec_array; - const auto ispec_type = this->material_properties->ispec_type; - const auto stf_array = this->sources->stf_array; - const auto source_array = this->sources->source_array; - const auto ibool = this->compute->ibool; - - Kokkos::parallel_for( - "specfem::Domain::Elastic::compute_source_interaction", - specfem::kokkos::DeviceTeam(nsources, Kokkos::AUTO, 1), - KOKKOS_CLASS_LAMBDA( - const specfem::kokkos::DeviceTeam::member_type &team_member) { - int isource = team_member.league_rank(); - int ispec = ispec_array(isource); - auto sv_ibool = Kokkos::subview(ibool, ispec, Kokkos::ALL, Kokkos::ALL); - - if (ispec_type(ispec) == specfem::elements::elastic) { - - type_real stf; - - Kokkos::parallel_reduce( - Kokkos::TeamThreadRange(team_member, 1), - [=](const int &, type_real &lsum) { - lsum = stf_array(isource).T->compute(timeval); - }, - stf); - - team_member.team_barrier(); - - Kokkos::parallel_for( - Kokkos::TeamThreadRange(team_member, ngllxz), [=](const int xz) { - const int ix = xz % ngllz; - const int iz = xz / ngllz; - int iglob = sv_ibool(iz, ix); - - if (specfem::globals::simulation_wave == specfem::wave::p_sv) { - const type_real accelx = - source_array(isource, iz, ix, 0) * stf; - const type_real accelz = - source_array(isource, iz, ix, 1) * stf; - Kokkos::single(Kokkos::PerThread(team_member), [=] { - Kokkos::atomic_add(&this->field_dot_dot(iglob, 0), accelx); - Kokkos::atomic_add(&this->field_dot_dot(iglob, 1), accelz); - }); - } else if (specfem::globals::simulation_wave == - specfem::wave::sh) { - const type_real accelx = - source_array(isource, iz, ix, 0) * stf; - Kokkos::atomic_add(&this->field_dot_dot(iglob, 0), accelx); - } - }); - } - }); - - // Kokkos::fence(); - return; -} - -// Compute the seismogram using field view -KOKKOS_FUNCTION -void compute_receiver_seismogram( - const specfem::kokkos::DeviceTeam::member_type &team_member, - specfem::kokkos::DeviceView1d sv_seismogram, - const specfem::kokkos::DeviceView3d field, - const specfem::seismogram::type type, - const specfem::kokkos::DeviceView3d sv_receiver_array, - const type_real cos_irec, const type_real sin_irec) { - - const int ngllx = sv_receiver_array.extent(0); - const int ngllz = sv_receiver_array.extent(1); - const int ngllxz = ngllx * ngllz; - switch (type) { - case specfem::seismogram::displacement: - case specfem::seismogram::velocity: - case specfem::seismogram::acceleration: - - type_real vx = 0.0; - type_real vz = 0.0; - - if (specfem::globals::simulation_wave == specfem::wave::p_sv) { - Kokkos::parallel_reduce( - Kokkos::TeamThreadRange(team_member, ngllxz), - [=](const int xz, type_real &l_vx) { - const int ix = xz % ngllz; - const int iz = xz / ngllz; - const type_real hlagrange = sv_receiver_array(iz, ix, 0); - const type_real field_v = field(0, iz, ix); - - l_vx += field_v * hlagrange; - }, - vx); - Kokkos::parallel_reduce( - Kokkos::TeamThreadRange(team_member, ngllxz), - [=](const int xz, type_real &l_vz) { - const int ix = xz % ngllz; - const int iz = xz / ngllz; - const type_real hlagrange = sv_receiver_array(iz, ix, 0); - const type_real field_v = field(1, iz, ix); - - l_vz += field_v * hlagrange; - }, - vz); - } else if (specfem::globals::simulation_wave == specfem::wave::sh) { - Kokkos::parallel_reduce( - Kokkos::TeamThreadRange(team_member, ngllxz), - [=](const int xz, type_real &l_vx) { - const int ix = xz % ngllz; - const int iz = xz / ngllz; - const type_real hlagrange = sv_receiver_array(iz, ix, 0); - const type_real field_v = field(0, iz, ix); - - l_vx += field_v * hlagrange; - }, - vx); - } - - Kokkos::single(Kokkos::PerTeam(team_member), [=] { - if (specfem::globals::simulation_wave == specfem::wave::p_sv) { - sv_seismogram(0) = cos_irec * vx + sin_irec * vz; - sv_seismogram(1) = sin_irec * vx + cos_irec * vz; - } else if ((specfem::globals::simulation_wave == specfem::wave::sh)) { - sv_seismogram(0) = cos_irec * vx + sin_irec * vz; - sv_seismogram(1) = 0; - } - }); - - break; - } - - return; -} - -void specfem::Domain::Elastic::compute_seismogram(const int isig_step) { - - const auto seismogram_types = this->receivers->seismogram_types; - const int nsigtype = seismogram_types.extent(0); - const int nreceivers = this->receivers->receiver_array.extent(0); - const auto ispec_array = this->receivers->ispec_array; - const auto ispec_type = this->material_properties->ispec_type; - const auto receiver_array = this->receivers->receiver_array; - const auto ibool = this->compute->ibool; - const auto cos_recs = this->receivers->cos_recs; - const auto sin_recs = this->receivers->sin_recs; - auto field = this->receivers->field; - const int ngllx = ibool.extent(1); - const int ngllz = ibool.extent(2); - const int ngllxz = ngllx * ngllz; - auto seismogram = Kokkos::subview(this->receivers->seismogram, isig_step, - Kokkos::ALL, Kokkos::ALL, Kokkos::ALL); - specfem::kokkos::DeviceView2d copy_field; - - Kokkos::parallel_for( - "specfem::Domain::Elastic::compute_seismogram", - specfem::kokkos::DeviceTeam(nsigtype * nreceivers, Kokkos::AUTO, 1), - KOKKOS_CLASS_LAMBDA( - const specfem::kokkos::DeviceTeam::member_type &team_member) { - const int isigtype = team_member.league_rank() / nreceivers; - const int irec = team_member.league_rank() % nreceivers; - const int ispec = ispec_array(irec); - if (ispec_type(ispec) == specfem::elements::elastic) { - - const specfem::seismogram::type type = seismogram_types(isigtype); - const auto sv_ibool = - Kokkos::subview(ibool, ispec, Kokkos::ALL, Kokkos::ALL); - auto sv_field = Kokkos::subview(field, isigtype, irec, Kokkos::ALL, - Kokkos::ALL, Kokkos::ALL); - // Get seismogram field - // ---------------------------------------------------------------- - switch (type) { - // Get the displacement field - case specfem::seismogram::displacement: - Kokkos::parallel_for( - Kokkos::TeamThreadRange(team_member, ngllxz), - [=](const int xz) { - const int ix = xz % ngllz; - const int iz = xz / ngllz; - const int iglob = sv_ibool(iz, ix); - - if (specfem::globals::simulation_wave == - specfem::wave::p_sv) { - sv_field(0, iz, ix) = this->field(iglob, 0); - sv_field(1, iz, ix) = this->field(iglob, 1); - } else if (specfem::globals::simulation_wave == - specfem::wave::sh) { - sv_field(0, iz, ix) = this->field(iglob, 0); - } - }); - break; - // Get the velocity field - case specfem::seismogram::velocity: - Kokkos::parallel_for( - Kokkos::TeamThreadRange(team_member, ngllxz), - [=](const int xz) { - const int ix = xz % ngllz; - const int iz = xz / ngllz; - const int iglob = sv_ibool(iz, ix); - - if (specfem::globals::simulation_wave == - specfem::wave::p_sv) { - sv_field(0, iz, ix) = this->field_dot(iglob, 0); - sv_field(1, iz, ix) = this->field_dot(iglob, 1); - } else if (specfem::globals::simulation_wave == - specfem::wave::sh) { - sv_field(0, iz, ix) = this->field_dot(iglob, 0); - } - }); - break; - // Get the acceleration field - case specfem::seismogram::acceleration: - Kokkos::parallel_for( - Kokkos::TeamThreadRange(team_member, ngllxz), - [=](const int xz) { - const int ix = xz % ngllz; - const int iz = xz / ngllz; - const int iglob = sv_ibool(iz, ix); - - if (specfem::globals::simulation_wave == - specfem::wave::p_sv) { - sv_field(0, iz, ix) = this->field_dot_dot(iglob, 0); - sv_field(1, iz, ix) = this->field_dot_dot(iglob, 1); - } else if (specfem::globals::simulation_wave == - specfem::wave::sh) { - sv_field(0, iz, ix) = this->field_dot_dot(iglob, 0); - } - }); - break; - } - //------------------------------------------------------------------- - - // compute seismograms - const auto sv_receiver_array = Kokkos::subview( - receiver_array, irec, Kokkos::ALL, Kokkos::ALL, Kokkos::ALL); - const type_real cos_irec = cos_recs(irec); - const type_real sin_irec = sin_recs(irec); - auto sv_seismogram = - Kokkos::subview(seismogram, isigtype, irec, Kokkos::ALL); - compute_receiver_seismogram(team_member, sv_seismogram, sv_field, - type, sv_receiver_array, cos_irec, - sin_irec); - } - }); - - // Kokkos::fence(); -} diff --git a/src/domain/impl/elements/elastic/elastic2d_isotropic.cpp b/src/domain/impl/elements/elastic/elastic2d_isotropic.cpp new file mode 100644 index 00000000..c285bca2 --- /dev/null +++ b/src/domain/impl/elements/elastic/elastic2d_isotropic.cpp @@ -0,0 +1,233 @@ +#include "compute/interface.hpp" +#include "domain/interface.hpp" +#include "enumerations/interface.hpp" +#include "kokkos_abstractions.h" + +specfem::compute::partial_derivatives specfem::domain::impl::elements::element< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::elastic, + specfem::enums::element::quadrature::dynamic_quadrature_points, + specfem::enums::element::property::isotropic>::partial_derivatives; + +specfem::compute::properties specfem::domain::impl::elements::element< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::elastic, + specfem::enums::element::quadrature::dynamic_quadrature_points, + specfem::enums::element::property::isotropic>::properties; + +specfem::kokkos::DeviceView2d + specfem::domain::impl::elements::element< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::elastic, + specfem::enums::element::quadrature::dynamic_quadrature_points, + specfem::enums::element::property::isotropic>::field_dot_dot; + +KOKKOS_FUNCTION specfem::domain::impl::elements::element< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::elastic, + specfem::enums::element::quadrature::dynamic_quadrature_points, + specfem::enums::element::property::isotropic>:: + element(const int ispec, + const specfem::compute::partial_derivatives partial_derivatives, + const specfem::compute::properties properties, + const specfem::kokkos::DeviceView2d + field_dot_dot) + : ispec(ispec) { + + this->partial_derivatives = partial_derivatives; + this->properties = properties; + this->field_dot_dot = field_dot_dot; + + this->ngllx = partial_derivatives.xix.extent(2); + this->ngllz = partial_derivatives.xix.extent(1); + + assert(partial_derivatives.xiz.extent(1) == ngllz); + assert(partial_derivatives.xiz.extent(2) == ngllx); + assert(partial_derivatives.gammax.extent(1) == ngllz); + assert(partial_derivatives.gammax.extent(2) == ngllx); + assert(partial_derivatives.gammaz.extent(1) == ngllz); + assert(partial_derivatives.gammaz.extent(2) == ngllx); + assert(partial_derivatives.jacobian.extent(1) == ngllz); + assert(partial_derivatives.jacobian.extent(2) == ngllx); + assert(properties.lambdaplus2mu.extent(1) == ngllz); + assert(properties.lambdaplus2mu.extent(2) == ngllx); + assert(properties.mu.extent(1) == ngllz); + assert(properties.mu.extent(2) == ngllx); + + return; +} + +KOKKOS_FUNCTION void specfem::domain::impl::elements::element< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::elastic, + specfem::enums::element::quadrature::dynamic_quadrature_points, + specfem::enums::element::property::isotropic>:: + compute_gradient(const int &xz, + const DynamicScratchViewType s_hprime_xx, + const DynamicScratchViewType s_hprime_zz, + const DynamicScratchViewType field_x, + const DynamicScratchViewType field_z, + type_real &duxdxl, type_real &duxdzl, type_real &duzdxl, + type_real &duzdzl) const { + + assert(s_hprime_xx.extent(0) == ngllx); + assert(s_hprime_xx.extent(1) == ngllx); + + assert(s_hprime_xx.extent(0) == ngllz); + assert(s_hprime_xx.extent(1) == ngllz); + + assert(field_x.extent(0) == ngllz); + assert(field_x.extent(1) == ngllx); + assert(field_z.extent(0) == ngllz); + assert(field_z.extent(1) == ngllx); + + int iz, ix; + sub2ind(xz, ngllx, iz, ix); + + const type_real xixl = this->partial_derivatives.xix(this->ispec, iz, ix); + const type_real xizl = this->partial_derivatives.xiz(this->ispec, iz, ix); + const type_real gammaxl = + this->partial_derivatives.gammax(this->ispec, iz, ix); + const type_real gammazl = + this->partial_derivatives.gammaz(this->ispec, iz, ix); + + type_real sum_hprime_x1 = 0.0; + type_real sum_hprime_x3 = 0.0; + type_real sum_hprime_z1 = 0.0; + type_real sum_hprime_z3 = 0.0; + + for (int l = 0; l < ngllx; l++) { + sum_hprime_x1 += s_hprime_xx(ix, l) * field_x(iz, l); + sum_hprime_x3 += s_hprime_xx(ix, l) * field_z(iz, l); + } + + for (int l = 0; l < ngllz; l++) { + sum_hprime_z1 += s_hprime_zz(iz, l) * field_x(l, ix); + sum_hprime_z3 += s_hprime_zz(iz, l) * field_z(l, ix); + } + // duxdx + duxdxl = xixl * sum_hprime_x1 + gammaxl * sum_hprime_x3; + + // duxdz + duxdzl = xizl * sum_hprime_x1 + gammazl * sum_hprime_x3; + + // duzdx + duzdxl = xixl * sum_hprime_z1 + gammaxl * sum_hprime_z3; + + // duzdz + duzdzl = xizl * sum_hprime_z1 + gammazl * sum_hprime_z3; + + return; +} + +KOKKOS_FUNCTION void specfem::domain::impl::elements::element< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::elastic, + specfem::enums::element::quadrature::dynamic_quadrature_points, + specfem::enums::element::property::isotropic>:: + compute_stress(const int &xz, const type_real &duxdxl, + const type_real &duxdzl, const type_real &duzdxl, + const type_real &duzdzl, type_real &stress_integrand_1l, + type_real &stress_integrand_2l, + type_real &stress_integrand_3l, + type_real &stress_integrand_4l) const { + + int ix, iz; + sub2ind(xz, ngllx, iz, ix); + + const type_real lambdaplus2mul = + this->properties.lambdaplus2mu(this->ispec, iz, ix); + const type_real mul = this->properties.mu(this->ispec, iz, ix); + const type_real lambdal = lambdaplus2mul - 2.0 * mul; + + const type_real xixl = this->partial_derivatives.xix(this->ispec, iz, ix); + const type_real xizl = this->partial_derivatives.xiz(this->ispec, iz, ix); + const type_real gammaxl = + this->partial_derivatives.gammax(this->ispec, iz, ix); + const type_real gammazl = + this->partial_derivatives.gammaz(this->ispec, iz, ix); + const type_real jacobianl = + this->partial_derivatives.jacobian(this->ispec, iz, ix); + + type_real sigma_xx, sigma_zz, sigma_xz; + + if (specfem::globals::simulation_wave == specfem::wave::p_sv) { + // P_SV case + // sigma_xx + sigma_xx = lambdaplus2mul * duxdxl + lambdal * duzdzl; + + // sigma_zz + sigma_zz = lambdaplus2mul * duzdzl + lambdal * duxdxl; + + // sigma_xz + sigma_xz = mul * (duzdxl + duxdzl); + } else if (specfem::globals::simulation_wave == specfem::wave::sh) { + // SH-case + // sigma_xx + sigma_xx = mul * duxdxl; // would be sigma_xy in + // CPU-version + + // sigma_xz + sigma_xz = mul * duxdzl; // sigma_zy + } + + stress_integrand_1l = jacobianl * (sigma_xx * xixl + sigma_xz * xizl); + stress_integrand_2l = jacobianl * (sigma_xz * xixl + sigma_zz * xizl); + stress_integrand_3l = jacobianl * (sigma_xx * gammaxl + sigma_xz * gammazl); + stress_integrand_4l = jacobianl * (sigma_xz * gammaxl + sigma_zz * gammazl); + + return; +} + +KOKKOS_FUNCTION void specfem::domain::impl::elements::element< + specfem::enums::element::dimension::dim2, + specfem::enums::element::medium::elastic, + specfem::enums::element::quadrature::dynamic_quadrature_points, + specfem::enums::element::property::isotropic>:: + update_acceleration( + const int &xz, const int &iglob, const type_real &wxglll, + const type_real &wzglll, + const DynamicScratchViewType stress_integrand_1, + const DynamicScratchViewType stress_integrand_2, + const DynamicScratchViewType stress_integrand_3, + const DynamicScratchViewType stress_integrand_4, + const DynamicScratchViewType s_hprimewgll_xx, + const DynamicScratchViewType s_hprimewgll_zz) const { + + assert(s_hprimewgll_xx.extent(0) == ngllx); + assert(s_hprimewgll_xx.extent(1) == ngllx); + + assert(s_hprimewgll_zz.extent(0) == ngllz); + assert(s_hprimewgll_zz.extent(1) == ngllz); + + assert(stress_integrand_2.extent(0) == ngllz); + assert(stress_integrand_2.extent(1) == ngllx); + + assert(stress_integrand_3.extent(0) == ngllz); + assert(stress_integrand_3.extent(1) == ngllx); + + assert(stress_integrand_4.extent(0) == ngllz); + assert(stress_integrand_4.extent(1) == ngllx); + + int ix, iz; + sub2ind(xz, ngllx, iz, ix); + type_real tempx1 = 0.0; + type_real tempz1 = 0.0; + type_real tempx3 = 0.0; + type_real tempz3 = 0.0; + + for (int l = 0; l < ngllx; l++) { + tempx1 += s_hprimewgll_xx(ix, l) * stress_integrand_1(iz, l); + tempz1 += s_hprimewgll_xx(ix, l) * stress_integrand_2(iz, l); + } + + for (int l = 0; l < ngllz; l++) { + tempx3 += s_hprimewgll_zz(iz, l) * stress_integrand_3(l, ix); + tempz3 += s_hprimewgll_zz(iz, l) * stress_integrand_4(l, ix); + } + + const type_real sum_terms1 = -1.0 * (wzglll * tempx1) - (wxglll * tempx3); + const type_real sum_terms3 = -1.0 * (wzglll * tempz1) - (wxglll * tempz3); + Kokkos::atomic_add(&field_dot_dot(iglob, 0), sum_terms1); + Kokkos::atomic_add(&field_dot_dot(iglob, 1), sum_terms3); +} diff --git a/src/material/acoustic_material.cpp b/src/material/acoustic_material.cpp index 70de2d7e..fa57b37e 100644 --- a/src/material/acoustic_material.cpp +++ b/src/material/acoustic_material.cpp @@ -6,9 +6,8 @@ #include specfem::material::acoustic_material::acoustic_material() - : density(0.0), cs(0.0), cp(0.0), Qkappa(9999.0), Qmu(9999.0), - compaction_grad(0.0), lambdaplus2mu(0.0), mu(0.0), lambda(0.0), - kappa(0.0), young(0.0), poisson(0.0){}; + : density(0.0), cp(0.0), Qkappa(9999.0), Qmu(9999.0), compaction_grad(0.0), + lambdaplus2mu(0.0), lambda(0.0), kappa(0.0), young(0.0), poisson(0.0){}; std::string specfem::material::acoustic_material::print() const { std::ostringstream message; @@ -16,51 +15,55 @@ std::string specfem::material::acoustic_material::print() const { message << "- Acoustic Material : \n" << " Properties:\n" << " density : " << this->density << "\n" - << " cs : " << this->cs << "\n" << " cp : " << this->cp << "\n" << " kappa : " << this->kappa << "\n" - << " mu : " << this->mu << "\n" << " Qkappa : " << this->Qkappa << "\n" - << " Qmu : " << this->Qmu << "\n" << " lambda : " << this->lambda << "\n" - << " mu : " << this->mu << "\n" << " youngs modulus : " << this->young << "\n" << " poisson ratio : " << this->poisson << "\n"; return message.str(); } -void specfem::material::acoustic_material::assign( - utilities::input_holder &holder) { - // element type is defined in specfem_setup.hpp - this->ispec_type = specfem::elements::acoustic; - // density - this->density = holder.val0; - // P and S velocity - this->cp = holder.val1; - this->cs = holder.val2; - this->compaction_grad = holder.val3; +specfem::material::acoustic_material::acoustic_material( + const type_real &density, const type_real &cp, const type_real &Qkappa, + const type_real &Qmu, const type_real &compaction_grad) + : density(density), cp(cp), Qkappa(Qkappa), Qmu(Qmu), + compaction_grad(compaction_grad) { + + this->ispec_type = specfem::enums::element::type::acoustic; - // Qkappa and Qmu values - this->Qkappa = holder.val5; - this->Qmu = holder.val6; if (this->Qkappa <= 0.0 || this->Qmu <= 0.0) { std::runtime_error( "negative or null values of Q attenuation factor not allowed; set " "them equal to 9999 to indicate no attenuation"); } - // Lame parameters - this->lambdaplus2mu = this->density * this->cp * this->cp; - this->mu = this->density * this->cs * this->cs; - this->lambda = this->lambdaplus2mu - 2.0 * this->mu; + + // Lame parameters: note these are identical since mu = 0 + this->lambdaplus2mu = density * cp * cp; + this->lambda = this->lambdaplus2mu; + // Bulk modulus - this->kappa = this->lambda + this->mu; - // Youngs modulus - this->young = 9.0 * this->kappa * this->mu / (3.0 * this->kappa + this->mu); - // Poisson's ratio - this->poisson = 0.5 * (this->cp * this->cp - 2.0 * this->cs * this->cs) / - (this->cp * this->cp - this->cs * this->cs); + this->kappa = this->lambda; + // Youngs modulus - for fluid always 0 + this->young = 0.0; + // Poisson's ratio - for fluid always 0 + this->poisson = 0.5; if (this->poisson < -1.0 || this->poisson > 0.5) std::runtime_error("Poisson's ratio out of range"); + + return; +} + +specfem::utilities::return_holder +specfem::material::acoustic_material::get_properties() const { + utilities::return_holder holder; + holder.rho = this->density; + holder.kappa = this->kappa; + holder.qmu = this->Qmu; + holder.qkappa = this->Qkappa; + holder.lambdaplus2mu = this->lambdaplus2mu; + + return holder; } diff --git a/src/material/elastic_material.cpp b/src/material/elastic_material.cpp index 9583f569..5bb919de 100644 --- a/src/material/elastic_material.cpp +++ b/src/material/elastic_material.cpp @@ -30,42 +30,39 @@ std::string specfem::material::elastic_material::print() const { return message.str(); } -void specfem::material::elastic_material::assign( - utilities::input_holder &holder) { - this->ispec_type = specfem::elements::elastic; - // density - this->density = holder.val0; - // P and S velocity - this->cp = holder.val1; - this->cs = holder.val2; - this->compaction_grad = holder.val3; +specfem::material::elastic_material::elastic_material( + const type_real &density, const type_real &cs, const type_real &cp, + const type_real &Qkappa, const type_real &Qmu, + const type_real &compaction_grad) + : density(density), cs(cs), cp(cp), Qkappa(Qkappa), Qmu(Qmu), + compaction_grad(compaction_grad) { + this->ispec_type = specfem::enums::element::type::elastic; - // Qkappa and Qmu values - this->Qkappa = holder.val5; - this->Qmu = holder.val6; if (this->Qkappa <= 0.0 || this->Qmu <= 0.0) { std::runtime_error( "negative or null values of Q attenuation factor not allowed; set " "them equal to 9999 to indicate no attenuation"); } + // Lame parameters - this->lambdaplus2mu = this->density * this->cp * this->cp; - this->mu = this->density * this->cs * this->cs; + this->lambdaplus2mu = density * cp * cp; + this->mu = density * cs * cs; this->lambda = this->lambdaplus2mu - 2.0 * this->mu; // Bulk modulus this->kappa = this->lambda + this->mu; // Youngs modulus this->young = 9.0 * this->kappa * this->mu / (3.0 * this->kappa + this->mu); // Poisson's ratio - this->poisson = 0.5 * (this->cp * this->cp - 2.0 * this->cs * this->cs) / - (this->cp * this->cp - this->cs * this->cs); + this->poisson = 0.5 * (cp * cp - 2.0 * cs * cs) / (cp * cp - cs * cs); if (this->poisson < -1.0 || this->poisson > 0.5) std::runtime_error("Poisson's ratio out of range"); + + return; } specfem::utilities::return_holder -specfem::material::elastic_material::get_properties() { +specfem::material::elastic_material::get_properties() const { utilities::return_holder holder; holder.rho = this->density; holder.mu = this->mu; diff --git a/src/mathematical_operators/mathematical_operators.cpp b/src/mathematical_operators/mathematical_operators.cpp deleted file mode 100644 index a028badd..00000000 --- a/src/mathematical_operators/mathematical_operators.cpp +++ /dev/null @@ -1,163 +0,0 @@ -#include "kokkos_abstractions.h" -#include "mathematical_operators/interface.hpp" -#include "specfem_setup.hpp" -#include - -KOKKOS_FUNCTION void specfem::mathematical_operators::compute_gradients_2D( - const specfem::kokkos::DeviceTeam::member_type &team_member, - const int ispec, const specfem::kokkos::DeviceView3d xix, - const specfem::kokkos::DeviceView3d xiz, - const specfem::kokkos::DeviceView3d gammax, - const specfem::kokkos::DeviceView3d gammaz, - const specfem::kokkos::DeviceScratchView2d s_hprime_xx, - const specfem::kokkos::DeviceScratchView2d s_hprime_zz, - const specfem::kokkos::DeviceScratchView2d field_x, - const specfem::kokkos::DeviceScratchView2d field_z, - specfem::kokkos::DeviceScratchView2d s_duxdx, - specfem::kokkos::DeviceScratchView2d s_duxdz, - specfem::kokkos::DeviceScratchView2d s_duzdx, - specfem::kokkos::DeviceScratchView2d s_duzdz) { - - const int ngllz = xix.extent(1); - const int ngllx = xix.extent(2); - const int ngll2 = ngllz * ngllx; - - assert(xiz.extent(1) == ngllz); - assert(xiz.extent(2) == ngllx); - assert(gammax.extent(1) == ngllz); - assert(gammax.extent(2) == ngllx); - assert(gammaz.extent(1) == ngllz); - assert(gammaz.extent(2) == ngllx); - - assert(s_hprime_xx.extent(0) == ngllx); - assert(s_hprime_xx.extent(1) == ngllx); - - assert(s_hprime_xx.extent(0) == ngllz); - assert(s_hprime_xx.extent(1) == ngllz); - - assert(field_x.extent(0) == ngllz); - assert(field_x.extent(1) == ngllx); - assert(field_z.extent(0) == ngllz); - assert(field_z.extent(1) == ngllx); - - assert(s_duxdx.extent(0) == ngllz); - assert(s_duxdx.extent(1) == ngllx); - assert(s_duxdz.extent(0) == ngllz); - assert(s_duxdz.extent(1) == ngllx); - assert(s_duzdx.extent(0) == ngllz); - assert(s_duzdx.extent(1) == ngllx); - assert(s_duzdz.extent(0) == ngllz); - assert(s_duzdz.extent(1) == ngllx); - - Kokkos::parallel_for( - Kokkos::TeamThreadRange(team_member, ngll2), [&](const int xz) { - int iz, ix; - sub2ind(xz, ngllx, iz, ix); - - const type_real xixl = xix(ispec, iz, ix); - const type_real xizl = xiz(ispec, iz, ix); - const type_real gammaxl = gammax(ispec, iz, ix); - const type_real gammazl = gammaz(ispec, iz, ix); - - type_real sum_hprime_x1 = 0.0; - type_real sum_hprime_x3 = 0.0; - type_real sum_hprime_z1 = 0.0; - type_real sum_hprime_z3 = 0.0; - - for (int l = 0; l < ngllx; l++) { - sum_hprime_x1 += s_hprime_xx(ix, l) * field_x(iz, l); - sum_hprime_x3 += s_hprime_xx(ix, l) * field_z(iz, l); - } - - for (int l = 0; l < ngllz; l++) { - sum_hprime_z1 += s_hprime_zz(iz, l) * field_x(l, ix); - sum_hprime_z3 += s_hprime_zz(iz, l) * field_z(l, ix); - } - // duxdx - s_duxdx(iz, ix) = xixl * sum_hprime_x1 + gammaxl * sum_hprime_x3; - - // duxdz - s_duxdz(iz, ix) = xizl * sum_hprime_x1 + gammazl * sum_hprime_x3; - - // duzdx - s_duzdx(iz, ix) = xixl * sum_hprime_z1 + gammaxl * sum_hprime_z3; - - // duzdz - s_duzdz(iz, ix) = xizl * sum_hprime_z1 + gammazl * sum_hprime_z3; - }); - - return; -}; - -KOKKOS_FUNCTION void specfem::mathematical_operators::add_contributions( - const specfem::kokkos::DeviceTeam::member_type &team_member, - const specfem::kokkos::DeviceView1d wxgll, - const specfem::kokkos::DeviceView1d wzgll, - const specfem::kokkos::DeviceScratchView2d s_hprimewgll_xx, - const specfem::kokkos::DeviceScratchView2d s_hprimewgll_zz, - const specfem::kokkos::DeviceScratchView2d s_iglob, - const specfem::kokkos::DeviceScratchView2d integrand_1, - const specfem::kokkos::DeviceScratchView2d integrand_2, - const specfem::kokkos::DeviceScratchView2d integrand_3, - const specfem::kokkos::DeviceScratchView2d integrand_4, - specfem::kokkos::DeviceView2d - field_dot_dot) { - - const int ngllz = integrand_1.extent(0); - const int ngllx = integrand_1.extent(1); - - assert(s_hprimewgll_xx.extent(0) == ngllx); - assert(s_hprimewgll_xx.extent(1) == ngllx); - - assert(s_hprimewgll_zz.extent(0) == ngllz); - assert(s_hprimewgll_zz.extent(1) == ngllz); - - assert(s_iglob.extent(0) == ngllz); - assert(s_iglob.extent(1) == ngllx); - - assert(integrand_1.extent(0) == ngllz); - assert(integrand_1.extent(1) == ngllx); - - assert(integrand_2.extent(0) == ngllz); - assert(integrand_2.extent(1) == ngllx); - - assert(integrand_3.extent(0) == ngllz); - assert(integrand_3.extent(1) == ngllx); - - assert(integrand_4.extent(0) == ngllz); - assert(integrand_4.extent(1) == ngllx); - - assert(wxgll.extent(0) == ngllx); - assert(wzgll.extent(0) == ngllz); - - const int ngll2 = ngllx * ngllz; - - Kokkos::parallel_for( - Kokkos::TeamThreadRange(team_member, ngll2), [&](const int xz) { - int iz, ix; - sub2ind(xz, ngllz, iz, ix); - - type_real tempx1 = 0.0; - type_real tempz1 = 0.0; - type_real tempx3 = 0.0; - type_real tempz3 = 0.0; - - for (int l = 0; l < ngllx; l++) { - tempx1 += s_hprimewgll_xx(ix, l) * integrand_1(iz, l); - tempz1 += s_hprimewgll_xx(ix, l) * integrand_2(iz, l); - } - - for (int l = 0; l < ngllz; l++) { - tempx3 += s_hprimewgll_zz(iz, l) * integrand_3(l, ix); - tempz3 += s_hprimewgll_zz(iz, l) * integrand_4(l, ix); - } - - const int iglob = s_iglob(iz, ix); - const type_real sum_terms1 = - -1.0 * (wzgll(iz) * tempx1) - (wxgll(ix) * tempx3); - const type_real sum_terms3 = - -1.0 * (wzgll(iz) * tempz1) - (wxgll(ix) * tempz3); - Kokkos::atomic_add(&field_dot_dot(iglob, 0), sum_terms1); - Kokkos::atomic_add(&field_dot_dot(iglob, 1), sum_terms3); - }); -} diff --git a/src/mesh/IO/fortran/read_material_properties.cpp b/src/mesh/IO/fortran/read_material_properties.cpp index 208cb257..0ff7ce75 100644 --- a/src/mesh/IO/fortran/read_material_properties.cpp +++ b/src/mesh/IO/fortran/read_material_properties.cpp @@ -5,11 +5,18 @@ #include "utilities/interface.hpp" #include +struct input_holder { + // Struct to hold temporary variables read from database file + type_real val0, val1, val2, val3, val4, val5, val6, val7, val8, val9, val10, + val11, val12; + int n, indic; +}; + std::vector specfem::mesh::IO::fortran::read_material_properties( std::ifstream &stream, const int numat, const specfem::MPI::MPI *mpi) { - specfem::utilities::input_holder read_values; + input_holder read_values; std::vector materials(numat); @@ -36,20 +43,33 @@ specfem::mesh::IO::fortran::read_material_properties( } if (read_values.indic == 1) { + // Acoustic Material if (read_values.val2 == 0) { + const type_real density = read_values.val0; + const type_real cp = read_values.val1; + const type_real compaction_grad = read_values.val3; + const type_real Qkappa = read_values.val5; + const type_real Qmu = read_values.val6; specfem::material::acoustic_material *acoustic_holder = - new specfem::material::acoustic_material(); - acoustic_holder->assign(read_values); + new specfem::material::acoustic_material(density, cp, Qkappa, Qmu, + compaction_grad); + materials[read_values.n - 1] = acoustic_holder; } else { + const type_real density = read_values.val0; + const type_real cp = read_values.val1; + const type_real cs = read_values.val2; + const type_real compaction_grad = read_values.val3; + const type_real Qkappa = read_values.val5; + const type_real Qmu = read_values.val6; specfem::material::elastic_material *elastic_holder = - new specfem::material::elastic_material(); - elastic_holder->assign(read_values); + new specfem::material::elastic_material(density, cs, cp, Qkappa, + Qmu, compaction_grad); materials[read_values.n - 1] = elastic_holder; } } else { throw std::runtime_error( - "Only elastic & acoutsic material has been developed still"); + "Error reading material properties. Invalid material type"); } } diff --git a/src/mesh/IO/fortran/read_mesh_database.cpp b/src/mesh/IO/fortran/read_mesh_database.cpp index 3b167e59..54778087 100644 --- a/src/mesh/IO/fortran/read_mesh_database.cpp +++ b/src/mesh/IO/fortran/read_mesh_database.cpp @@ -197,40 +197,12 @@ specfem::mesh::IO::fortran::read_mesh_database_attenuation( specfem::fortran_IO::fortran_read_line( stream, &n_sls, &attenuation_f0_reference, &read_velocities_at_f0); - if (n_sls < 1) { - throw std::runtime_error("must have N_SLS >= 1 even if attenuation if off " - "because it is used to assign some arrays"); - } + // if (n_sls < 1) { + // throw std::runtime_error("must have N_SLS >= 1 even if attenuation if + // off " + // "because it is used to assign some arrays"); + // } return std::make_tuple(n_sls, attenuation_f0_reference, read_velocities_at_f0); } - -void specfem::mesh::IO::fortran::read_mesh_database_coupled( - std::ifstream &stream, const int num_fluid_solid_edges, - const int num_fluid_poro_edges, const int num_solid_poro_edges, - const specfem::MPI::MPI *mpi) { - - int dummy_i, dummy_i1; - - if (num_fluid_solid_edges > 0 || num_fluid_poro_edges > 0 || - num_solid_poro_edges > 0) { - mpi->cout("\n Warning coupled surfaces haven't been implemented yet \n"); - } - - if (num_fluid_solid_edges > 0) { - for (int inum = 0; inum < num_fluid_solid_edges; inum++) - specfem::fortran_IO::fortran_read_line(stream, &dummy_i, &dummy_i1); - } - - if (num_fluid_poro_edges > 0) { - for (int inum = 0; inum < num_fluid_poro_edges; inum++) - specfem::fortran_IO::fortran_read_line(stream, &dummy_i, &dummy_i1); - } - - if (num_solid_poro_edges > 0) { - for (int inum = 0; inum < num_solid_poro_edges; inum++) - specfem::fortran_IO::fortran_read_line(stream, &dummy_i, &dummy_i1); - } - return; -} diff --git a/src/mesh/boundaries/absorbing_boundaries.cpp b/src/mesh/boundaries/absorbing_boundaries.cpp index e9bb2221..3ad4c414 100644 --- a/src/mesh/boundaries/absorbing_boundaries.cpp +++ b/src/mesh/boundaries/absorbing_boundaries.cpp @@ -1,135 +1,120 @@ #include "fortranio/interface.hpp" #include "mesh/boundaries/boundaries.hpp" #include "specfem_mpi/interface.hpp" -#include "utilities.cpp" #include #include specfem::mesh::boundaries::absorbing_boundary::absorbing_boundary( const int num_abs_boundary_faces) { if (num_abs_boundary_faces > 0) { - this->numabs = specfem::kokkos::HostView1d( - "specfem::mesh::absorbing_boundary::numabs", num_abs_boundary_faces); - this->abs_boundary_type = specfem::kokkos::HostView1d( - "specfem::mesh::absorbing_boundary::abs_boundary_type", - num_abs_boundary_faces); - this->ibegin_edge1 = specfem::kokkos::HostView1d( - "specfem::mesh::absorbing_boundary::ibegin_edge1", - num_abs_boundary_faces); - this->ibegin_edge2 = specfem::kokkos::HostView1d( - "specfem::mesh::absorbing_boundary::ibegin_edge2", - num_abs_boundary_faces); - this->ibegin_edge3 = specfem::kokkos::HostView1d( - "specfem::mesh::absorbing_boundary::ibegin_edge3", - num_abs_boundary_faces); - this->ibegin_edge4 = specfem::kokkos::HostView1d( - "specfem::mesh::absorbing_boundary::ibegin_edge4", - num_abs_boundary_faces); - this->iend_edge1 = specfem::kokkos::HostView1d( - "specfem::mesh::absorbing_boundary::iend_edge1", - num_abs_boundary_faces); - this->iend_edge2 = specfem::kokkos::HostView1d( - "specfem::mesh::absorbing_boundary::iend_edge2", - num_abs_boundary_faces); - this->iend_edge3 = specfem::kokkos::HostView1d( - "specfem::mesh::absorbing_boundary::iend_edge3", - num_abs_boundary_faces); - this->iend_edge4 = specfem::kokkos::HostView1d( - "specfem::mesh::absorbing_boundary::iend_edge4", - num_abs_boundary_faces); - this->ib_bottom = specfem::kokkos::HostView1d( - "specfem::mesh::absorbing_boundary::ib_bottom", num_abs_boundary_faces); - this->ib_top = specfem::kokkos::HostView1d( - "specfem::mesh::absorbing_boundary::ib_top", num_abs_boundary_faces); - this->ib_right = specfem::kokkos::HostView1d( - "specfem::mesh::absorbing_boundary::ib_right", num_abs_boundary_faces); - this->ib_left = specfem::kokkos::HostView1d( - "specfem::mesh::absorbing_boundary::ib_left", num_abs_boundary_faces); + this->nelements = num_abs_boundary_faces; + this->ispec = specfem::kokkos::HostView1d( + "specfem::mesh::absorbing_boundary::ispec", num_abs_boundary_faces); + this->type = specfem::kokkos::HostView1d( + "specfem::mesh::absorbing_boundary::type", num_abs_boundary_faces); } else { - this->numabs = specfem::kokkos::HostView1d( - "specfem::mesh::absorbing_boundary::numabs", 1); - this->abs_boundary_type = specfem::kokkos::HostView1d( - "specfem::mesh::absorbing_boundary::abs_boundary_type", 1); - this->ibegin_edge1 = specfem::kokkos::HostView1d( - "specfem::mesh::absorbing_boundary::ibegin_edge1", 1); - this->ibegin_edge2 = specfem::kokkos::HostView1d( - "specfem::mesh::absorbing_boundary::ibegin_edge2", 1); - this->ibegin_edge3 = specfem::kokkos::HostView1d( - "specfem::mesh::absorbing_boundary::ibegin_edge3", 1); - this->ibegin_edge4 = specfem::kokkos::HostView1d( - "specfem::mesh::absorbing_boundary::ibegin_edge4", 1); - this->iend_edge1 = specfem::kokkos::HostView1d( - "specfem::mesh::absorbing_boundary::iend_edge1", 1); - this->iend_edge2 = specfem::kokkos::HostView1d( - "specfem::mesh::absorbing_boundary::iend_edge2", 1); - this->iend_edge3 = specfem::kokkos::HostView1d( - "specfem::mesh::absorbing_boundary::iend_edge3", 1); - this->iend_edge4 = specfem::kokkos::HostView1d( - "specfem::mesh::absorbing_boundary::iend_edge4", 1); - this->ib_bottom = specfem::kokkos::HostView1d( - "specfem::mesh::absorbing_boundary::ib_bottom", 1); - this->ib_top = specfem::kokkos::HostView1d( - "specfem::mesh::absorbing_boundary::ib_top", 1); - this->ib_right = specfem::kokkos::HostView1d( - "specfem::mesh::absorbing_boundary::ib_right", 1); - this->ib_left = specfem::kokkos::HostView1d( - "specfem::mesh::absorbing_boundary::ib_left", 1); + this->nelements = 0; } - if (num_abs_boundary_faces > 0) { - this->codeabs = specfem::kokkos::HostView2d( - "specfem::mesh::absorbing_boundary::codeabs", num_abs_boundary_faces, - 4); - this->codeabscorner = specfem::kokkos::HostView2d( - "specfem::mesh::absorbing_boundary::codeabs_corner", - num_abs_boundary_faces, 4); - } else { - this->codeabs = specfem::kokkos::HostView2d( - "specfem::mesh::absorbing_boundary::codeabs", 1, 1); - this->codeabscorner = specfem::kokkos::HostView2d( - "specfem::mesh::absorbing_boundary::codeabs_corner", 1, 1); + return; +} + +static std::tuple< + specfem::kokkos::HostView1d, + specfem::kokkos::HostView1d > +find_corners(const specfem::kokkos::HostView1d ispec_edge, + const specfem::kokkos::HostView1d + type_edge) { + + int ncorner = 0; + int num_abs_boundary_faces = ispec_edge.extent(0); + for (int inum = 0; inum < num_abs_boundary_faces; inum++) { + if (type_edge(inum) == specfem::enums::boundaries::type::BOTTOM) { + for (int inum_duplicate = 0; inum_duplicate < num_abs_boundary_faces; + inum_duplicate++) { + if (inum != inum_duplicate) { + if (ispec_edge(inum) == ispec_edge(inum_duplicate)) { + if (type_edge(inum) == specfem::enums::boundaries::type::LEFT) { + ncorner++; + } + if (type_edge(inum) == specfem::enums::boundaries::type::RIGHT) { + ncorner++; + } + } + } + } + if (type_edge(inum) == specfem::enums::boundaries::type::TOP) { + for (int inum_duplicate = 0; inum_duplicate < num_abs_boundary_faces; + inum_duplicate++) { + if (inum != inum_duplicate) { + if (ispec_edge(inum) == ispec_edge(inum_duplicate)) { + if (type_edge(inum) == specfem::enums::boundaries::type::LEFT) { + ncorner++; + } + if (type_edge(inum) == specfem::enums::boundaries::type::RIGHT) { + ncorner++; + } + } + } + } + } + } } - if (num_abs_boundary_faces > 0) { - for (int n = 0; n < num_abs_boundary_faces; n++) { - this->numabs(n) = 0; - this->abs_boundary_type(n) = 0; - this->ibegin_edge1(n) = 0; - this->ibegin_edge2(n) = 0; - this->ibegin_edge3(n) = 0; - this->ibegin_edge4(n) = 0; - this->iend_edge1(n) = 0; - this->iend_edge2(n) = 0; - this->iend_edge3(n) = 0; - this->iend_edge4(n) = 0; - this->ib_bottom(n) = 0; - this->ib_left(n) = 0; - this->ib_top(n) = 0; - this->ib_right(n) = 0; - for (int i = 0; i < 4; i++) { - this->codeabs(n, i) = false; - this->codeabscorner(n, i) = false; + specfem::kokkos::HostView1d ispec_corners( + "specfem::mesh::absorbing_boundary::ispec_corners", ncorner); + + specfem::kokkos::HostView1d type_corners( + "specfem::mesh::absorbing_boundary::type_corners", ncorner); + + int icorner = 0; + + for (int inum = 0; inum < num_abs_boundary_faces; inum++) { + if (type_edge(inum) == specfem::enums::boundaries::type::BOTTOM) { + for (int inum_duplicate = 0; inum_duplicate < num_abs_boundary_faces; + inum_duplicate++) { + if (inum != inum_duplicate) { + if (ispec_edge(inum) == ispec_edge(inum_duplicate)) { + if (type_edge(inum) == specfem::enums::boundaries::type::LEFT) { + ispec_corners(icorner) = ispec_edge(inum); + type_corners(icorner) = + specfem::enums::boundaries::type::BOTTOM_LEFT; + icorner++; + } + if (type_edge(inum) == specfem::enums::boundaries::type::RIGHT) { + ispec_corners(icorner) = ispec_edge(inum); + type_corners(icorner) = + specfem::enums::boundaries::type::BOTTOM_RIGHT; + icorner++; + } + } + } + } + if (type_edge(inum) == specfem::enums::boundaries::type::TOP) { + for (int inum_duplicate = 0; inum_duplicate < num_abs_boundary_faces; + inum_duplicate++) { + if (inum != inum_duplicate) { + if (ispec_edge(inum) == ispec_edge(inum_duplicate)) { + if (type_edge(inum) == specfem::enums::boundaries::type::LEFT) { + ispec_corners(icorner) = ispec_edge(inum); + type_corners(icorner) = + specfem::enums::boundaries::type::TOP_LEFT; + icorner++; + } + if (type_edge(inum) == specfem::enums::boundaries::type::RIGHT) { + ispec_corners(icorner) = ispec_edge(inum); + type_corners(icorner) = + specfem::enums::boundaries::type::TOP_RIGHT; + icorner++; + } + } + } + } } } - } else { - this->numabs(1) = 0; - this->abs_boundary_type(1) = 0; - this->ibegin_edge1(1) = 0; - this->ibegin_edge2(1) = 0; - this->ibegin_edge3(1) = 0; - this->ibegin_edge4(1) = 0; - this->iend_edge1(1) = 0; - this->iend_edge2(1) = 0; - this->iend_edge3(1) = 0; - this->iend_edge4(1) = 0; - this->ib_bottom(1) = 0; - this->ib_left(1) = 0; - this->ib_top(1) = 0; - this->ib_right(1) = 0; - this->codeabs(1, 1) = false; - this->codeabscorner(1, 1) = false; } - return; + + return std::make_tuple(ispec_corners, type_corners); } specfem::mesh::boundaries::absorbing_boundary::absorbing_boundary( @@ -147,47 +132,65 @@ specfem::mesh::boundaries::absorbing_boundary::absorbing_boundary( num_abs_boundary_faces = 0; } - *this = specfem::mesh::boundaries::absorbing_boundary(num_abs_boundary_faces); + specfem::kokkos::HostView1d type_edge( + "specfem::mesh::absorbing_boundary::type_edge", num_abs_boundary_faces); + + specfem::kokkos::HostView1d ispec_edge( + "specfem::mesh::absorbing_boundary::ispec_edge", num_abs_boundary_faces); if (num_abs_boundary_faces > 0) { for (int inum = 0; inum < num_abs_boundary_faces; inum++) { specfem::fortran_IO::fortran_read_line( stream, &numabsread, &codeabsread1, &codeabsread2, &codeabsread3, &codeabsread4, &typeabsread, &iedgeread); - std::vector codeabsread(4, false); if (numabsread < 1 || numabsread > nspec) throw std::runtime_error("Wrong absorbing element number"); - this->numabs(inum) = numabsread - 1; - this->abs_boundary_type(inum) = typeabsread; - codeabsread[0] = codeabsread1; - codeabsread[1] = codeabsread2; - codeabsread[2] = codeabsread3; - codeabsread[3] = codeabsread4; + ispec_edge(inum) = numabsread - 1; + std::vector codeabsread = { codeabsread1, codeabsread2, + codeabsread3, codeabsread4 }; if (std::count(codeabsread.begin(), codeabsread.end(), true) != 1) { throw std::runtime_error("must have one and only one absorbing edge " "per absorbing line cited"); } - this->codeabs(inum, 0) = codeabsread[0]; - this->codeabs(inum, 1) = codeabsread[1]; - this->codeabs(inum, 2) = codeabsread[2]; - this->codeabs(inum, 3) = codeabsread[3]; - this->ibegin_edge1(inum) = iedgeread[0]; - this->iend_edge1(inum) = iedgeread[1]; - this->ibegin_edge2(inum) = iedgeread[2]; - this->iend_edge2(inum) = iedgeread[3]; - this->ibegin_edge3(inum) = iedgeread[4]; - this->iend_edge3(inum) = iedgeread[5]; - this->ibegin_edge4(inum) = iedgeread[6]; - this->iend_edge4(inum) = iedgeread[7]; + if (codeabsread1) + type_edge(inum) = specfem::enums::boundaries::type::BOTTOM; + + if (codeabsread2) + type_edge(inum) = specfem::enums::boundaries::type::RIGHT; + + if (codeabsread3) + type_edge(inum) = specfem::enums::boundaries::type::TOP; + + if (codeabsread4) + type_edge(inum) = specfem::enums::boundaries::type::LEFT; } // Find corner elements - find_corners(this->numabs, this->codeabs, this->codeabscorner, - num_abs_boundary_faces, mpi); + auto [ispec_corners, type_corners] = find_corners(ispec_edge, type_edge); + + const int nelements = ispec_corners.extent(0) + ispec_edge.extent(0); + + this->nelements = nelements; - // populate ib_bottom, ib_top, ib_left, ib_right arrays - calculate_ib(this->codeabs, this->ib_bottom, this->ib_top, this->ib_left, - this->ib_right, num_abs_boundary_faces); + this->ispec = specfem::kokkos::HostView1d( + "specfem::mesh::absorbing_boundary::ispec", nelements); + + this->type = specfem::kokkos::HostView1d( + "specfem::mesh::absorbing_boundary::type", nelements); + + // Populate ispec and type arrays + + for (int inum = 0; inum < ispec_edge.extent(0); inum++) { + this->ispec(inum) = ispec_edge(inum); + this->type(inum) = type_edge(inum); + } + + for (int inum = 0; inum < ispec_corners.extent(0); inum++) { + this->ispec(inum + ispec_edge.extent(0)) = ispec_corners(inum); + this->type(inum + ispec_edge.extent(0)) = type_corners(inum); + } + } else { + this->nelements = 0; } return; diff --git a/src/mesh/boundaries/acoustic_free_surface.cpp b/src/mesh/boundaries/acoustic_free_surface.cpp new file mode 100644 index 00000000..0fa09f6d --- /dev/null +++ b/src/mesh/boundaries/acoustic_free_surface.cpp @@ -0,0 +1,93 @@ +#include "mesh/boundaries/acoustic_free_surface.hpp" +#include "fortranio/interface.hpp" +#include "specfem_mpi/interface.hpp" +#include + +using view_type = + Kokkos::Subview, + std::remove_const_t, int>; + +/** + * @brief Get the type of boundary + * + * @param type int indicating if the boundary is edge of node + * @param e1 control node index for the starting node of the if the boundary is + * edge else control node index of the node if the boundary is node + * @param e2 control node index for the ending node of the if the boundary is + * edge + * @return specfem::enums::boundaries::type type of the boundary + */ +specfem::enums::boundaries::type +get_boundary_type(const int type, const int e1, const int e2, + const view_type &control_nodes) { + + // if this is a node type + if (type == 1) { + if (e1 == control_nodes(0)) { + return specfem::enums::boundaries::type::BOTTOM_LEFT; + } else if (e1 == control_nodes(1)) { + return specfem::enums::boundaries::type::BOTTOM_RIGHT; + } else if (e1 == control_nodes(2)) { + return specfem::enums::boundaries::type::TOP_RIGHT; + } else if (e1 == control_nodes(3)) { + return specfem::enums::boundaries::type::TOP_LEFT; + } else { + throw std::invalid_argument( + "Error: Could not generate type of acoustic free surface boundary"); + } + } else { + if ((e1 == control_nodes(0) && e2 == control_nodes(1)) || + (e1 == control_nodes(1) && e2 == control_nodes(0))) { + return specfem::enums::boundaries::type::BOTTOM; + } else if ((e1 == control_nodes(0) && e2 == control_nodes(3)) || + (e1 == control_nodes(3) && e2 == control_nodes(0))) { + return specfem::enums::boundaries::type::LEFT; + } else if ((e1 == control_nodes(1) && e2 == control_nodes(2)) || + (e1 == control_nodes(2) && e2 == control_nodes(1))) { + return specfem::enums::boundaries::type::RIGHT; + } else if ((e1 == control_nodes(2) && e2 == control_nodes(3)) || + (e1 == control_nodes(3) && e2 == control_nodes(2))) { + return specfem::enums::boundaries::type::TOP; + } else { + throw std::invalid_argument( + "Error: Could not generate type of acoustic free surface boundary"); + } + } +} + +specfem::mesh::boundaries::acoustic_free_surface::acoustic_free_surface( + const int nelem_acoustic_surface) + : nelem_acoustic_surface(nelem_acoustic_surface) { + if (nelem_acoustic_surface > 0) { + this->ispec_acoustic_surface = specfem::kokkos::HostView1d( + "specfem::mesh::acoustic_free_surface::ispec_acoustic_surface", + nelem_acoustic_surface); + this->type = specfem::kokkos::HostView1d( + "specfem::mesh::acoustic_free_surface::type", nelem_acoustic_surface); + } + return; +} + +specfem::mesh::boundaries::acoustic_free_surface::acoustic_free_surface( + std::ifstream &stream, const int &nelem_acoustic_surface, + const specfem::kokkos::HostView2d &knods, + const specfem::MPI::MPI *mpi) { + + std::vector acfree_edge(4, 0); + *this = + specfem::mesh::boundaries::acoustic_free_surface(nelem_acoustic_surface); + + if (nelem_acoustic_surface > 0) { + for (int inum = 0; inum < nelem_acoustic_surface; inum++) { + specfem::fortran_IO::fortran_read_line(stream, &acfree_edge); + this->ispec_acoustic_surface(inum) = acfree_edge[0] - 1; + const auto control_nodes = Kokkos::subview( + knods, Kokkos::ALL, this->ispec_acoustic_surface(inum)); + this->type(inum) = get_boundary_type(acfree_edge[1], acfree_edge[2] - 1, + acfree_edge[3] - 1, control_nodes); + } + } + + mpi->sync_all(); + return; +} diff --git a/src/mesh/coupled_interfaces/acoustic_poroelastic.cpp b/src/mesh/coupled_interfaces/acoustic_poroelastic.cpp new file mode 100644 index 00000000..7ccae258 --- /dev/null +++ b/src/mesh/coupled_interfaces/acoustic_poroelastic.cpp @@ -0,0 +1,24 @@ +#include "mesh/coupled_interfaces/acoustic_poroelastic.hpp" +#include "fortranio/interface.hpp" + +specfem::mesh::coupled_interfaces::acoustic_poroelastic::acoustic_poroelastic( + const int num_interfaces, std::ifstream &stream, + const specfem::MPI::MPI *mpi) + : num_interfaces(num_interfaces), + acoustic_ispec("acoustic_ispec", num_interfaces), + poroelastic_ispec("poroelastic_ispec", num_interfaces) { + + if (!num_interfaces) + return; + + int acoustic_ispec_l, poroelastic_ispec_l; + + for (int i = 0; i < num_interfaces; i++) { + specfem::fortran_IO::fortran_read_line(stream, &poroelastic_ispec_l, + &acoustic_ispec_l); + acoustic_ispec(i) = acoustic_ispec_l - 1; + poroelastic_ispec(i) = poroelastic_ispec_l - 1; + } + + return; +} diff --git a/src/mesh/coupled_interfaces/elastic_acoustic.cpp b/src/mesh/coupled_interfaces/elastic_acoustic.cpp new file mode 100644 index 00000000..ff20e234 --- /dev/null +++ b/src/mesh/coupled_interfaces/elastic_acoustic.cpp @@ -0,0 +1,24 @@ +#include "mesh/coupled_interfaces/elastic_acoustic.hpp" +#include "fortranio/interface.hpp" + +specfem::mesh::coupled_interfaces::elastic_acoustic::elastic_acoustic( + const int num_interfaces, std::ifstream &stream, + const specfem::MPI::MPI *mpi) + : num_interfaces(num_interfaces), + elastic_ispec("elastic_ispec", num_interfaces), + acoustic_ispec("acoustic_ispec", num_interfaces) { + + if (!num_interfaces) + return; + + int elastic_ispec_l, acoustic_ispec_l; + + for (int i = 0; i < num_interfaces; i++) { + specfem::fortran_IO::fortran_read_line(stream, &acoustic_ispec_l, + &elastic_ispec_l); + elastic_ispec(i) = elastic_ispec_l - 1; + acoustic_ispec(i) = acoustic_ispec_l - 1; + } + + return; +} diff --git a/src/mesh/coupled_interfaces/elastic_poroelastic.cpp b/src/mesh/coupled_interfaces/elastic_poroelastic.cpp new file mode 100644 index 00000000..fe3a80e0 --- /dev/null +++ b/src/mesh/coupled_interfaces/elastic_poroelastic.cpp @@ -0,0 +1,24 @@ +#include "mesh/coupled_interfaces/elastic_poroelastic.hpp" +#include "fortranio/interface.hpp" + +specfem::mesh::coupled_interfaces::elastic_poroelastic::elastic_poroelastic( + const int num_interfaces, std::ifstream &stream, + const specfem::MPI::MPI *mpi) + : num_interfaces(num_interfaces), + elastic_ispec("elastic_ispec", num_interfaces), + poroelastic_ispec("poroelastic_ispec", num_interfaces) { + + if (!num_interfaces) + return; + + int elastic_ispec_l, poroelastic_ispec_l; + + for (int i = 0; i < num_interfaces; i++) { + specfem::fortran_IO::fortran_read_line(stream, &poroelastic_ispec_l, + &elastic_ispec_l); + elastic_ispec(i) = elastic_ispec_l - 1; + poroelastic_ispec(i) = poroelastic_ispec_l - 1; + } + + return; +} diff --git a/src/mesh/mesh.cpp b/src/mesh/mesh.cpp index 3817f765..d256b53a 100644 --- a/src/mesh/mesh.cpp +++ b/src/mesh/mesh.cpp @@ -1,5 +1,5 @@ #include "mesh/mesh.hpp" -#include "compute/interface.hpp" +#include "enumerations/specfem_enums.hpp" #include "kokkos_abstractions.h" #include "material/interface.hpp" #include "specfem_mpi/interface.hpp" @@ -119,17 +119,19 @@ specfem::mesh::mesh::mesh(const std::string filename, } try { - this->acfree_surface = specfem::mesh::surfaces::acoustic_free_surface( - stream, this->parameters.nelem_acoustic_surface, mpi); + this->acfree_surface = specfem::mesh::boundaries::acoustic_free_surface( + stream, this->parameters.nelem_acoustic_surface, + this->material_ind.knods, mpi); } catch (std::runtime_error &e) { throw; } try { - specfem::mesh::IO::fortran::read_mesh_database_coupled( - stream, this->parameters.num_fluid_solid_edges, - this->parameters.num_fluid_poro_edges, - this->parameters.num_solid_poro_edges, mpi); + this->coupled_interfaces = + specfem::mesh::coupled_interfaces::coupled_interfaces( + stream, this->parameters.num_fluid_solid_edges, + this->parameters.num_fluid_poro_edges, + this->parameters.num_solid_poro_edges, mpi); } catch (std::runtime_error &e) { throw; } @@ -169,10 +171,11 @@ std::string specfem::mesh::mesh::print( "setup_compute::properties_ispec", specfem::kokkos::HostRange(0, nspec), [=](const int ispec, int &l_elastic, int &l_acoustic) { const int imat = this->material_ind.kmato(ispec); - if (materials[imat]->get_ispec_type() == specfem::elements::elastic) { + if (materials[imat]->get_ispec_type() == + specfem::enums::element::type::elastic) { l_elastic++; } else if (materials[imat]->get_ispec_type() == - specfem::elements::acoustic) { + specfem::enums::element::type::acoustic) { l_acoustic++; } }, diff --git a/src/mesh/surfaces/acoustic_free_surface.cpp b/src/mesh/surfaces/acoustic_free_surface.cpp deleted file mode 100644 index 8c17eefc..00000000 --- a/src/mesh/surfaces/acoustic_free_surface.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "fortranio/interface.hpp" -#include "mesh/surfaces/surfaces.hpp" -#include "specfem_mpi/interface.hpp" - -specfem::mesh::surfaces::acoustic_free_surface::acoustic_free_surface( - const int nelem_acoustic_surface) { - if (nelem_acoustic_surface > 0) { - this->numacfree_surface = specfem::kokkos::HostView1d( - "specfem::mesh::acoustic_free_surface::numacfree_surface", - nelem_acoustic_surface); - this->typeacfree_surface = specfem::kokkos::HostView1d( - "specfem::mesh::acoustic_free_surface::typeacfree_surface", - nelem_acoustic_surface); - this->e1 = specfem::kokkos::HostView1d( - "specfem::mesh::acoustic_free_surface::e1", nelem_acoustic_surface); - this->e2 = specfem::kokkos::HostView1d( - "specfem::mesh::acoustic_free_surface::e2", nelem_acoustic_surface); - this->ixmin = specfem::kokkos::HostView1d( - "specfem::mesh::acoustic_free_surface::ixmin", nelem_acoustic_surface); - this->ixmax = specfem::kokkos::HostView1d( - "specfem::mesh::acoustic_free_surface::ixmax", nelem_acoustic_surface); - this->izmin = specfem::kokkos::HostView1d( - "specfem::mesh::acoustic_free_surface::izmin", nelem_acoustic_surface); - this->izmax = specfem::kokkos::HostView1d( - "specfem::mesh::acoustic_free_surface::izmax", nelem_acoustic_surface); - } - return; -} - -specfem::mesh::surfaces::acoustic_free_surface::acoustic_free_surface( - std::ifstream &stream, const int nelem_acoustic_surface, - const specfem::MPI::MPI *mpi) { - - std::vector acfree_edge(4, 0); - *this = - specfem::mesh::surfaces::acoustic_free_surface(nelem_acoustic_surface); - - if (nelem_acoustic_surface > 0) { - for (int inum = 0; inum < nelem_acoustic_surface; inum++) { - specfem::fortran_IO::fortran_read_line(stream, &acfree_edge); - this->numacfree_surface(inum) = acfree_edge[0]; - this->typeacfree_surface(inum) = acfree_edge[1]; - this->e1(inum) = acfree_edge[2]; - this->e2(inum) = acfree_edge[3]; - } - } - - mpi->sync_all(); - return; -} diff --git a/src/parameter_parser/receivers.cpp b/src/parameter_parser/receivers.cpp index 571a0d14..b28462fb 100644 --- a/src/parameter_parser/receivers.cpp +++ b/src/parameter_parser/receivers.cpp @@ -22,15 +22,17 @@ specfem::runtime_configuration::receivers::receivers(const YAML::Node &Node) { for (YAML::Node seismogram_type : Node["seismogram-type"]) { if (seismogram_type.as() == "displacement") { - this->stypes.push_back(specfem::seismogram::displacement); + this->stypes.push_back(specfem::enums::seismogram::type::displacement); } else if (seismogram_type.as() == "velocity") { - this->stypes.push_back(specfem::seismogram::velocity); + this->stypes.push_back(specfem::enums::seismogram::type::velocity); } else if (seismogram_type.as() == "acceleration") { - this->stypes.push_back(specfem::seismogram::acceleration); + this->stypes.push_back(specfem::enums::seismogram::type::acceleration); } else { std::ostringstream message; message << "Error reading specfem receiver configuration. \n"; + message << "Unknown seismogram type: " + << seismogram_type.as() << "\n"; std::runtime_error(message.str()); } diff --git a/src/parameter_parser/setup.cpp b/src/parameter_parser/setup.cpp index 67dadef3..94643050 100644 --- a/src/parameter_parser/setup.cpp +++ b/src/parameter_parser/setup.cpp @@ -2,9 +2,24 @@ #include "yaml-cpp/yaml.h" #include #include +#include #include +#include #include +void create_folder_if_not_exists(const std::string &folder_name) { + struct stat info; + + if (stat(folder_name.c_str(), &info) != 0) { + std::cout << "Creating folder: " << folder_name << std::endl; + mkdir(folder_name.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + } else if (info.st_mode & S_IFDIR) { + std::cout << "Folder already exists: " << folder_name << std::endl; + } else { + std::cout << "Error: " << folder_name << " is not a directory" << std::endl; + } +} + specfem::runtime_configuration::setup::setup(const std::string ¶meter_file, const std::string &default_file) { YAML::Node parameter_yaml = YAML::LoadFile(parameter_file); @@ -78,7 +93,14 @@ specfem::runtime_configuration::setup::setup(const std::string ¶meter_file, std::make_unique( runtime_config["seismogram"]); } catch (YAML::InvalidNode &e) { - this->seismogram = NULL; + YAML::Node seismogram; + seismogram["seismogram-format"] = "ascii"; + std::string folder_name = "results"; + create_folder_if_not_exists(folder_name); + seismogram["output-folder"] = folder_name; + this->seismogram = + std::make_unique( + seismogram); } try { diff --git a/src/parameter_parser/writer.cpp b/src/parameter_parser/writer.cpp index e22405f9..1f1c4897 100644 --- a/src/parameter_parser/writer.cpp +++ b/src/parameter_parser/writer.cpp @@ -9,12 +9,12 @@ specfem::runtime_configuration::seismogram::instantiate_seismogram_writer( specfem::compute::receivers *compute_receivers, const type_real dt, const type_real t0, const int nstep_between_samples) const { - specfem::seismogram::format::type type; + specfem::enums::seismogram::format type; if (this->seismogram_format == "seismic_unix" || this->seismogram_format == "su") { - type = specfem::seismogram::format::seismic_unix; + type = specfem::enums::seismogram::format::seismic_unix; } else if (this->seismogram_format == "ascii") { - type = specfem::seismogram::format::ascii; + type = specfem::enums::seismogram::format::ascii; } specfem::writer::writer *writer = new specfem::writer::seismogram( diff --git a/src/receiver/receiver.cpp b/src/receiver/receiver.cpp index 5ec0cff4..5eb65463 100644 --- a/src/receiver/receiver.cpp +++ b/src/receiver/receiver.cpp @@ -12,7 +12,8 @@ void specfem::receivers::receiver::locate( const specfem::kokkos::HostMirror1d zigll, const int nproc, const specfem::kokkos::HostView2d coorg, const specfem::kokkos::HostView2d knods, const int npgeo, - const specfem::kokkos::HostMirror1d ispec_type, + const specfem::kokkos::HostMirror1d + ispec_type, const specfem::MPI::MPI *mpi) { std::tie(this->xi, this->gamma, this->ispec, this->islice) = specfem::utilities::locate(coord, h_ibool, xigll, zigll, nproc, this->x, diff --git a/src/solver/time_marching.cpp b/src/solver/time_marching.cpp deleted file mode 100644 index 91edf993..00000000 --- a/src/solver/time_marching.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "domain/interface.hpp" -#include "solver/interface.hpp" -#include "timescheme/interface.hpp" -#include - -void specfem::solver::time_marching::run() { - - specfem::TimeScheme::TimeScheme *it = this->it; - specfem::Domain::Domain *domain = this->domain; - - const int nstep = it->get_max_timestep(); - - while (it->status()) { - int istep = it->get_timestep(); - - type_real timeval = it->get_time(); - - Kokkos::Profiling::pushRegion("Stiffness calculation"); - it->apply_predictor_phase(domain); - - domain->compute_stiffness_interaction_calling_routine(); - domain->compute_source_interaction(timeval); - domain->divide_mass_matrix(); - - it->apply_corrector_phase(domain); - - if (it->compute_seismogram()) { - int isig_step = it->get_seismogram_step(); - domain->compute_seismogram(isig_step); - it->increment_seismogram_step(); - } - Kokkos::Profiling::popRegion(); - - if (istep % 10 == 0) { - std::cout << "Progress : executed " << istep << " steps of " << nstep - << " steps" << std::endl; - } - - it->increment_time(); - } - - std::cout << std::endl; - - return; -} diff --git a/src/source/force_source.cpp b/src/source/force_source.cpp index de8aeb38..1078ab91 100644 --- a/src/source/force_source.cpp +++ b/src/source/force_source.cpp @@ -1,3 +1,4 @@ +#include "enumerations/specfem_enums.hpp" #include "globals.h" #include "kokkos_abstractions.h" #include "quadrature/interface.hpp" @@ -17,7 +18,8 @@ void specfem::sources::force::locate( const specfem::kokkos::HostMirror1d zigll, const int nproc, const specfem::kokkos::HostView2d coorg, const specfem::kokkos::HostView2d knods, const int npgeo, - const specfem::kokkos::HostMirror1d ispec_type, + const specfem::kokkos::HostMirror1d + ispec_type, const specfem::MPI::MPI *mpi) { std::tie(this->xi, this->gamma, this->ispec, this->islice) = specfem::utilities::locate(coord, h_ibool, xigll, zigll, nproc, @@ -36,7 +38,7 @@ void specfem::sources::force::compute_source_array( type_real xi = this->xi; type_real gamma = this->gamma; type_real angle = this->angle; - specfem::elements::type el_type = this->el_type; + specfem::enums::element::type el_type = this->el_type; auto [hxis, hpxis] = specfem::quadrature::gll::Lagrange::compute_lagrange_interpolants( @@ -54,14 +56,14 @@ void specfem::sources::force::compute_source_array( for (int j = 0; j < nquadz; j++) { hlagrange = hxis(i) * hgammas(j); - if (el_type == specfem::elements::acoustic || - (el_type == specfem::elements::elastic && + if (el_type == specfem::enums::element::type::acoustic || + (el_type == specfem::enums::element::type::elastic && specfem::globals::simulation_wave == specfem::wave::sh)) { source_array(j, i, 0) = hlagrange; source_array(j, i, 1) = hlagrange; - } else if ((el_type == specfem::elements::elastic && + } else if ((el_type == specfem::enums::element::type::elastic && specfem::globals::simulation_wave == specfem::wave::p_sv) || - el_type == specfem::elements::poroelastic) { + el_type == specfem::enums::element::type::poroelastic) { type_real tempx = sin(angle) * hlagrange; source_array(j, i, 0) = tempx; type_real tempz = -1.0 * cos(angle) * hlagrange; @@ -92,6 +94,11 @@ specfem::sources::force::force(YAML::Node &Node, const type_real dt) if (YAML::Node Dirac = Node["Dirac"]) { this->forcing_function = assign_dirac(Dirac, dt, use_trick_for_better_pressure); + } else if (YAML::Node Ricker = Node["Ricker"]) { + this->forcing_function = + assign_ricker(Ricker, dt, use_trick_for_better_pressure); + } else { + throw std::runtime_error("Only Dirac and Ricker sources are supported."); } }; @@ -134,6 +141,19 @@ void specfem::sources::source::print(std::ostream &out) const { } void specfem::sources::force::print(std::ostream &out) const { + + std::string element_type; + + if (this->el_type == specfem::enums::element::type::acoustic) { + element_type = "acoustic"; + } else if (this->el_type == specfem::enums::element::type::elastic) { + element_type = "elastic"; + } else if (this->el_type == specfem::enums::element::type::poroelastic) { + element_type = "poroelastic"; + } else { + element_type = "unknown"; + } + out << "Force Source: \n" << " Source Location: \n" << " x = " << this->x << "\n" @@ -141,13 +161,26 @@ void specfem::sources::force::print(std::ostream &out) const { << " xi = " << this->xi << "\n" << " gamma = " << this->gamma << "\n" << " ispec = " << this->ispec << "\n" - << " islice = " << this->islice << "\n"; + << " islice = " << this->islice << "\n" + << " element type = " << element_type << "\n"; // out << *(this->forcing_function); return; } std::string specfem::sources::force::print() const { + std::string element_type; + + if (this->el_type == specfem::enums::element::type::acoustic) { + element_type = "acoustic"; + } else if (this->el_type == specfem::enums::element::type::elastic) { + element_type = "elastic"; + } else if (this->el_type == specfem::enums::element::type::poroelastic) { + element_type = "poroelastic"; + } else { + element_type = "unknown"; + } + std::ostringstream message; message << "- Force Source: \n" << " Source Location: \n" @@ -156,7 +189,8 @@ std::string specfem::sources::force::print() const { << " xi = " << this->xi << "\n" << " gamma = " << this->gamma << "\n" << " ispec = " << this->ispec << "\n" - << " islice = " << this->islice << "\n"; + << " islice = " << this->islice << "\n" + << " element type = " << element_type << "\n"; return message.str(); } diff --git a/src/source/moment_tensor_source.cpp b/src/source/moment_tensor_source.cpp index 5779e3b1..5277d8ee 100644 --- a/src/source/moment_tensor_source.cpp +++ b/src/source/moment_tensor_source.cpp @@ -18,7 +18,8 @@ void specfem::sources::moment_tensor::locate( const specfem::kokkos::HostMirror1d zigll, const int nproc, const specfem::kokkos::HostView2d coorg, const specfem::kokkos::HostView2d knods, const int npgeo, - const specfem::kokkos::HostMirror1d ispec_type, + const specfem::kokkos::HostMirror1d + ispec_type, const specfem::MPI::MPI *mpi) { std::tie(this->xi, this->gamma, this->ispec, this->islice) = specfem::utilities::locate(coord, h_ibool, xigll, zigll, nproc, @@ -26,11 +27,11 @@ void specfem::sources::moment_tensor::locate( npgeo, mpi); if (this->islice == mpi->get_rank()) { - if (ispec_type(ispec) != specfem::elements::elastic) { + if (ispec_type(ispec) != specfem::enums::element::type::elastic) { throw std::runtime_error( "Found a Moment-tensor source in acoustic/poroelastic element"); } else { - this->el_type = specfem::elements::elastic; + this->el_type = specfem::enums::element::type::elastic; } } int ngnod = knods.extent(0); @@ -124,6 +125,11 @@ specfem::sources::moment_tensor::moment_tensor(YAML::Node &Node, if (YAML::Node Dirac = Node["Dirac"]) { this->forcing_function = assign_dirac(Dirac, dt, use_trick_for_better_pressure); + } else if (YAML::Node Ricker = Node["Ricker"]) { + this->forcing_function = + assign_ricker(Ricker, dt, use_trick_for_better_pressure); + } else { + throw std::runtime_error("Only Dirac and Ricker sources are supported"); } }; diff --git a/src/source/utilities.cpp b/src/source/utilities.cpp index 0ace5fc4..55abdb6b 100644 --- a/src/source/utilities.cpp +++ b/src/source/utilities.cpp @@ -23,6 +23,21 @@ specfem::forcing_function::stf *assign_stf(std::string forcing_type, }); Kokkos::fence(); + } else if (forcing_type == "Ricker") { + forcing_function = (specfem::forcing_function::stf *) + Kokkos::kokkos_malloc( + sizeof(specfem::forcing_function::Ricker)); + + Kokkos::parallel_for( + "specfem::sources::moment_tensor::moment_tensor::allocate_stf", + specfem::kokkos::DeviceRange(0, 1), KOKKOS_LAMBDA(const int &) { + new (forcing_function) specfem::forcing_function::Ricker( + f0, tshift, factor, use_trick_for_better_pressure); + }); + + Kokkos::fence(); + } else { + assert(false && "Unknown forcing type"); } return forcing_function; @@ -53,3 +68,29 @@ assign_dirac(YAML::Node &Dirac, type_real dt, return forcing_function; } + +KOKKOS_INLINE_FUNCTION +specfem::forcing_function::stf * +assign_ricker(YAML::Node &Ricker, type_real dt, + bool use_trick_for_better_pressure) { + + specfem::forcing_function::stf *forcing_function; + forcing_function = (specfem::forcing_function::stf *) + Kokkos::kokkos_malloc( + sizeof(specfem::forcing_function::Ricker)); + + type_real f0 = Ricker["f0"].as(); + type_real tshift = Ricker["tshift"].as(); + type_real factor = Ricker["factor"].as(); + + Kokkos::parallel_for( + "specfem::sources::moment_tensor::moment_tensor::allocate_stf", + specfem::kokkos::DeviceRange(0, 1), KOKKOS_LAMBDA(const int &) { + new (forcing_function) specfem::forcing_function::Ricker( + f0, tshift, factor, use_trick_for_better_pressure); + }); + + Kokkos::fence(); + + return forcing_function; +} diff --git a/src/source_time_function/ricker.cpp b/src/source_time_function/ricker.cpp new file mode 100644 index 00000000..702f995f --- /dev/null +++ b/src/source_time_function/ricker.cpp @@ -0,0 +1,31 @@ +#include "source_time_function/interface.hpp" +#include "specfem_setup.hpp" +#include "utilities.cpp" +#include +#include + +KOKKOS_FUNCTION +specfem::forcing_function::Ricker::Ricker(type_real f0, type_real tshift, + type_real factor, + bool use_trick_for_better_pressure) + : f0(f0), factor(factor), tshift(tshift), + use_trick_for_better_pressure(use_trick_for_better_pressure) { + + type_real hdur = 1.0 / this->f0; + + this->t0 = 1.2 * hdur + this->tshift; +} + +KOKKOS_FUNCTION +type_real specfem::forcing_function::Ricker::compute(type_real t) { + + type_real val; + + if (this->use_trick_for_better_pressure) { + val = -1.0 * this->factor * d4gaussian(t - this->tshift, this->f0); + } else { + val = -1.0 * this->factor * d2gaussian(t - this->tshift, this->f0); + } + + return val; +} diff --git a/src/source_time_function/utilities.cpp b/src/source_time_function/utilities.cpp index c51571a9..79747652 100644 --- a/src/source_time_function/utilities.cpp +++ b/src/source_time_function/utilities.cpp @@ -3,7 +3,7 @@ #include KOKKOS_INLINE_FUNCTION -type_real gaussian(type_real t, type_real f0) { +type_real gaussian(const type_real t, const type_real f0) { // Gaussian wavelet i.e. second integral of a Ricker wavelet constexpr auto pi = Kokkos::numbers::pi_v; type_real a = pi * pi * f0 * f0; @@ -13,7 +13,7 @@ type_real gaussian(type_real t, type_real f0) { } KOKKOS_INLINE_FUNCTION -type_real d2gaussian(type_real t, type_real f0) { +type_real d2gaussian(const type_real t, const type_real f0) { constexpr auto pi = Kokkos::numbers::pi_v; type_real a = pi * pi * f0 * f0; @@ -21,3 +21,17 @@ type_real d2gaussian(type_real t, type_real f0) { return d2gaussian; } + +KOKKOS_INLINE_FUNCTION +type_real d4gaussian(const type_real t, const type_real f0) { + + constexpr auto pi = Kokkos::numbers::pi_v; + + type_real a = pi * pi * f0 * f0; + + type_real d4gaussian = + -2.0 * a * (3.0 - 12.0 * a * t * t + 4.0 * a * a * t * t * t * t) * + Kokkos::exp(-a * t * t); + + return d4gaussian; +} diff --git a/src/specfem2d.cpp b/src/specfem2d.cpp index f895cdd6..d331aef5 100644 --- a/src/specfem2d.cpp +++ b/src/specfem2d.cpp @@ -1,4 +1,5 @@ #include "compute/interface.hpp" +#include "coupled_interface/interface.hpp" #include "domain/interface.hpp" #include "kokkos_abstractions.h" #include "material/interface.hpp" @@ -116,6 +117,12 @@ void execute(const std::string ¶meter_file, const std::string &default_file, specfem::compute::properties material_properties( mesh.material_ind.kmato, materials, mesh.nspec, gllx->get_N(), gllz->get_N()); + specfem::compute::coupled_interfaces::coupled_interfaces coupled_interfaces( + compute.h_ibool, compute.coordinates.coord, + material_properties.h_ispec_type, mesh.coupled_interfaces); + specfem::compute::boundaries boundary_conditions( + mesh.material_ind.kmato, materials, mesh.acfree_surface, + mesh.abs_boundary); // Print spectral element information mpi->cout(mesh.print(materials)); @@ -176,15 +183,38 @@ void execute(const std::string ¶meter_file, const std::string &default_file, // Instantiate domain classes const int nglob = specfem::utilities::compute_nglob(compute.h_ibool); - specfem::Domain::Domain *domains = new specfem::Domain::Elastic( - ndim, nglob, &compute, &material_properties, &partial_derivatives, - &compute_sources, &compute_receivers, gllx, gllz); + specfem::enums::element::quadrature::static_quadrature_points<5> qp5; + specfem::domain::domain< + specfem::enums::element::medium::acoustic, + specfem::enums::element::quadrature::static_quadrature_points<5> > + acoustic_domain_static(nglob, qp5, &compute, material_properties, + partial_derivatives, boundary_conditions, + compute_sources, compute_receivers, gllx, gllz); + specfem::domain::domain< + specfem::enums::element::medium::elastic, + specfem::enums::element::quadrature::static_quadrature_points<5> > + elastic_domain_static(nglob, qp5, &compute, material_properties, + partial_derivatives, boundary_conditions, + compute_sources, compute_receivers, gllx, gllz); + + // Instantiate coupled interfaces + specfem::coupled_interface::coupled_interface acoustic_elastic_interface( + acoustic_domain_static, elastic_domain_static, coupled_interfaces, qp5, + partial_derivatives, compute.ibool, gllx->get_w(), gllz->get_w()); + + specfem::coupled_interface::coupled_interface elastic_acoustic_interface( + elastic_domain_static, acoustic_domain_static, coupled_interfaces, qp5, + partial_derivatives, compute.ibool, gllx->get_w(), gllz->get_w()); + + // Instantiate the writer auto writer = setup.instantiate_seismogram_writer(receivers, &compute_receivers); - specfem::solver::solver *solver = - new specfem::solver::time_marching(domains, it); + specfem::solver::solver *solver = new specfem::solver::time_marching< + specfem::enums::element::quadrature::static_quadrature_points<5> >( + acoustic_domain_static, elastic_domain_static, acoustic_elastic_interface, + elastic_acoustic_interface, it); mpi->cout("Executing time loop:"); mpi->cout("-------------------------------"); @@ -220,7 +250,6 @@ void execute(const std::string ¶meter_file, const std::string &default_file, } delete it; - delete domains; delete solver; delete writer; diff --git a/src/timescheme/newmark.cpp b/src/timescheme/newmark.cpp index 9e9976bf..5518c7cd 100644 --- a/src/timescheme/newmark.cpp +++ b/src/timescheme/newmark.cpp @@ -24,19 +24,18 @@ void specfem::TimeScheme::Newmark::reset_time() { return; } -KOKKOS_IMPL_HOST_FUNCTION void specfem::TimeScheme::Newmark::apply_predictor_phase( - const specfem::Domain::Domain *domain) { - auto field = domain->get_field(); - auto field_dot = domain->get_field_dot(); - auto field_dot_dot = domain->get_field_dot_dot(); + specfem::kokkos::DeviceView2d field, + specfem::kokkos::DeviceView2d field_dot, + specfem::kokkos::DeviceView2d + field_dot_dot) { const int nglob = field.extent(0); - // const int ndim = field.extent(1); + const int components = field.extent(1); Kokkos::parallel_for( "specfem::TimeScheme::Newmark::apply_predictor_phase", - specfem::kokkos::DeviceRange(0, ndim * nglob), + specfem::kokkos::DeviceRange(0, components * nglob), KOKKOS_CLASS_LAMBDA(const int in) { const int iglob = in % nglob; const int idim = in / nglob; @@ -49,33 +48,28 @@ void specfem::TimeScheme::Newmark::apply_predictor_phase( this->deltatover2 * field_dot_dot(iglob, idim); // reset acceleration field_dot_dot(iglob, idim) = 0; - // field(iglob, 1) += this->deltat * field_dot(iglob, 1) + - // this->deltatsquareover2 * field_dot_dot(iglob, 1); - // // apply predictor phase - // field_dot(iglob, 1) += this->deltatover2 * field_dot_dot(iglob, 1); - // // reset acceleration - // field_dot_dot(iglob, 1) = 0; }); return; } -KOKKOS_IMPL_HOST_FUNCTION void specfem::TimeScheme::Newmark::apply_corrector_phase( - const specfem::Domain::Domain *domain) { - - auto field_dot = domain->get_field_dot(); - auto field_dot_dot = domain->get_field_dot_dot(); + specfem::kokkos::DeviceView2d field, + specfem::kokkos::DeviceView2d field_dot, + specfem::kokkos::DeviceView2d + field_dot_dot) { const int nglob = field_dot.extent(0); - // const int ndim = field_dot.extent(1); + const int components = field_dot.extent(1); Kokkos::parallel_for( "specfem::TimeScheme::Newmark::apply_corrector_phase", - specfem::kokkos::DeviceRange(0, ndim * nglob), + specfem::kokkos::DeviceRange(0, components * nglob), KOKKOS_CLASS_LAMBDA(const int in) { const int iglob = in % nglob; const int idim = in / nglob; + type_real acceleration = field_dot_dot(iglob, idim); + type_real velocity = field_dot(iglob, idim); // apply corrector phase field_dot(iglob, idim) += this->deltatover2 * field_dot_dot(iglob, idim); diff --git a/src/utilities/utilities.cpp b/src/utilities/utilities.cpp index 9c93c61a..c3b6c599 100644 --- a/src/utilities/utilities.cpp +++ b/src/utilities/utilities.cpp @@ -288,5 +288,5 @@ int specfem::utilities::compute_nglob( }, Kokkos::Max(nglob)); - return nglob; + return nglob + 1; } diff --git a/src/writer/seismogram.cpp b/src/writer/seismogram.cpp index 8ab6691c..9cc01a2e 100644 --- a/src/writer/seismogram.cpp +++ b/src/writer/seismogram.cpp @@ -18,7 +18,7 @@ void specfem::writer::seismogram::write() { std::cout << "output folder : " << this->output_folder << "\n"; switch (this->type) { - case specfem::seismogram::format::ascii: + case specfem::enums::seismogram::ascii: // Open stream for (int irec = 0; irec < n_receivers; irec++) { std::string network_name = receivers[irec]->get_network_name(); @@ -27,29 +27,24 @@ void specfem::writer::seismogram::write() { std::vector filename; auto stype = this->compute_receivers->h_seismogram_types(isig); switch (stype) { - case specfem::seismogram::displacement: + case specfem::enums::seismogram::type::displacement: filename = { this->output_folder + "/" + network_name + station_name + "BXX" + ".semd", this->output_folder + "/" + network_name + station_name + "BXZ" + ".semd" }; break; - case specfem::seismogram::velocity: + case specfem::enums::seismogram::type::velocity: filename = { this->output_folder + "/" + network_name + station_name + "BXX" + ".semv", this->output_folder + "/" + network_name + station_name + "BXZ" + ".semv" }; break; - case specfem::seismogram::acceleration: + case specfem::enums::seismogram::type::acceleration: filename = { this->output_folder + "/" + network_name + station_name + "BXX" + ".sema", this->output_folder + "/" + network_name + station_name + "BXZ" + ".sema" }; break; - default: - std::ostringstream message; - message << "seismogram type " << stype - << " has not been implemented yet."; - throw std::runtime_error(message.str()); } for (int iorientation = 0; iorientation < filename.size(); diff --git a/tests/regression-tests/compare_regression_results.cpp b/tests/regression-tests/compare_regression_results.cpp index 89002557..bad57b31 100644 --- a/tests/regression-tests/compare_regression_results.cpp +++ b/tests/regression-tests/compare_regression_results.cpp @@ -62,6 +62,14 @@ int run_test(const std::string &PR_regression_results_file, assert(PR_results.IsSequence()); assert(main_results.IsSequence()); + std::ostringstream message; + + message << "===================================================\n" + << "------------Checking regression results------------\n" + << "==================================================="; + + std::cout << message.str() << std::endl; + for (YAML::const_iterator it = main_results.begin(); it != main_results.end(); ++it) { std::string test_name = it->first.as(); @@ -69,17 +77,30 @@ int run_test(const std::string &PR_regression_results_file, if (PR_results[test_name]) { if (value / PR_results[test_name].as() < threshhold) { - std::ostringstream message; + message.clear(); message << "Performance for test : " << test_name << " not within limits.\n" << " Test performance on main branch : " << value << "\n" << " Test performance on PR branch : " << PR_results[test_name].as(); throw std::runtime_error(message.str()); + } else { + message.clear(); + message << test_name << " ........... " + << "PASSED"; + std::cout << message.str() << std::endl; } } } + message.clear(); + + message << "===================================================\n" + << "-----------------------Done------------------------\n" + << "==================================================="; + + std::cout << message.str() << std::endl; + return 0; } diff --git a/tests/regression-tests/elastic_acoustic_domain/gpu/STATIONS b/tests/regression-tests/elastic_acoustic_domain/gpu/STATIONS new file mode 100644 index 00000000..f4533a3b --- /dev/null +++ b/tests/regression-tests/elastic_acoustic_domain/gpu/STATIONS @@ -0,0 +1 @@ +S0001 AA 2500.0000000 2933.3333300 0.0 0.0 diff --git a/tests/regression-tests/elastic_acoustic_domain/gpu/databases/database.bin b/tests/regression-tests/elastic_acoustic_domain/gpu/databases/database.bin new file mode 100644 index 00000000..8357f7e4 Binary files /dev/null and b/tests/regression-tests/elastic_acoustic_domain/gpu/databases/database.bin differ diff --git a/tests/unit-tests/CMakeLists.txt b/tests/unit-tests/CMakeLists.txt index b683985a..1a5fb368 100644 --- a/tests/unit-tests/CMakeLists.txt +++ b/tests/unit-tests/CMakeLists.txt @@ -104,7 +104,7 @@ target_link_libraries( add_executable( compute_partial_derivatives_tests - compute/compute_partial_derivatives_tests.cpp + compute/partial_derivatives/compute_partial_derivatives_tests.cpp ) target_link_libraries( @@ -121,12 +121,30 @@ target_link_libraries( ) add_executable( - compute_properties_tests - compute/compute_properties_tests.cpp + compute_elastic_tests + compute/elastic/compute_properties_tests.cpp ) target_link_libraries( - compute_properties_tests + compute_elastic_tests + mesh + compute + quadrature + mpi_environment + kokkos_environment + yaml-cpp + compare_arrays + material_class + -lpthread -lm +) + +add_executable( + compute_acoustic_tests + compute/acoustic/compute_properties_tests.cpp +) + +target_link_libraries( + compute_acoustic_tests mesh compute quadrature @@ -140,7 +158,7 @@ target_link_libraries( add_executable( compute_tests - compute/compute_tests.cpp + compute/index/compute_tests.cpp ) target_link_libraries( @@ -190,18 +208,16 @@ target_link_libraries( compute parameter_reader compare_arrays - domain - writer -lpthread -lm ) add_executable( - newmark_tests + displacement_newmark_tests displacement_tests/Newmark/newmark_tests.cpp ) target_link_libraries( - newmark_tests + displacement_newmark_tests quadrature mesh material_class @@ -211,19 +227,17 @@ target_link_libraries( compute parameter_reader compare_arrays - domain timescheme - solver -lpthread -lm ) add_executable( - seismogram_tests - seismogram/seismogram_tests.cpp + seismogram_elastic_tests + seismogram/elastic/seismogram_tests.cpp ) target_link_libraries( - seismogram_tests + seismogram_elastic_tests quadrature mesh yaml-cpp @@ -231,11 +245,45 @@ target_link_libraries( mpi_environment compute parameter_reader - domain writer -lpthread -lm ) +add_executable( + seismogram_acoustic_tests + seismogram/acoustic/seismogram_tests.cpp +) + +target_link_libraries( + seismogram_acoustic_tests + quadrature + mesh + yaml-cpp + kokkos_environment + mpi_environment + compute + parameter_reader + writer + -lpthread -lm +) + +add_executable( + compute_coupled_interfaces_tests + compute/coupled_interfaces/coupled_interfaces_tests.cpp +) + +target_link_libraries( + compute_coupled_interfaces_tests + quadrature + mesh + yaml-cpp + kokkos_environment + mpi_environment + compute + compare_arrays + -lpthread -lm +) + # Link to gtest only if MPI is enabled if (NOT MPI_PARALLEL) include(GoogleTest) @@ -244,10 +292,13 @@ if (NOT MPI_PARALLEL) gtest_discover_tests(fortranio_test) gtest_discover_tests(mesh_tests) gtest_discover_tests(compute_partial_derivatives_tests) - gtest_discover_tests(compute_properties_tests) + gtest_discover_tests(compute_elastic_tests) + gtest_discover_tests(compute_acoustic_tests) + gtest_discover_tests(compute_coupled_interfaces_tests) gtest_discover_tests(compute_tests) gtest_discover_tests(source_location_tests) gtest_discover_tests(rmass_inverse_tests) - gtest_discover_tests(newmark_tests) - gtest_discover_tests(seismogram_tests) + gtest_discover_tests(displacement_newmark_tests) + gtest_discover_tests(seismogram_elastic_tests) + gtest_discover_tests(seismogram_acoustic_tests) endif(NOT MPI_PARALLEL) diff --git a/tests/unit-tests/compute/acoustic/compute_properties_tests.cpp b/tests/unit-tests/compute/acoustic/compute_properties_tests.cpp new file mode 100644 index 00000000..81c13120 --- /dev/null +++ b/tests/unit-tests/compute/acoustic/compute_properties_tests.cpp @@ -0,0 +1,128 @@ +#include "../../Kokkos_Environment.hpp" +#include "../../MPI_environment.hpp" +#include "../../utilities/include/compare_array.h" +#include "compute/interface.hpp" +#include "material/interface.hpp" +#include "mesh/mesh.hpp" +#include "quadrature/interface.hpp" +#include "yaml-cpp/yaml.h" +#include +#include +#include +#include + +// ------------------------------------------------------------------------ +// Reading test config +struct test_config { + std::string database_filename, rho_file, kappa_file, mu_file, rho_vs_file, + rho_vp_file, qkappa_file, qmu_file; +}; + +void operator>>(YAML::Node &Node, test_config &test_config) { + test_config.database_filename = Node["database_file"].as(); + test_config.rho_file = Node["rho_file"].as(); + test_config.kappa_file = Node["kappa_file"].as(); + test_config.mu_file = Node["mu_file"].as(); + test_config.rho_vs_file = Node["rho_vs_file"].as(); + test_config.rho_vp_file = Node["rho_vp_file"].as(); + test_config.qkappa_file = Node["qkappa_file"].as(); + test_config.qmu_file = Node["qmu_file"].as(); + + return; +} + +test_config get_test_config(std::string config_filename, + specfem::MPI::MPI *mpi) { + // read test config file + YAML::Node yaml = YAML::LoadFile(config_filename); + test_config test_config{}; + if (mpi->get_size() == 1) { + YAML::Node Node = yaml["SerialTest"]; + YAML::Node database = Node["database"]; + assert(database.IsSequence()); + assert(database.size() == 1); + for (auto N : database) + N >> test_config; + } else { + YAML::Node Node = yaml["ParallelTest"]; + YAML::Node database = Node["database"]; + assert(database.IsSequence()); + assert(database.size() == Node["config"]["nproc"].as()); + assert(mpi->get_size() == Node["config"]["nproc"].as()); + for (auto N : database) { + if (N["processor"].as() == mpi->get_rank()) + N >> test_config; + } + } + + return test_config; +} +// --------------------------------------------------------------------------- + +/** + * + * This test should be run on single and multiple nodes + * + */ +TEST(COMPUTE_TESTS, compute_acoustic_properties) { + + std::string config_filename = + "../../../tests/unit-tests/compute/elastic/test_config.yml"; + test_config test_config = + get_test_config(config_filename, MPIEnvironment::mpi_); + + // Set up GLL quadrature points + specfem::quadrature::quadrature *gllx = + new specfem::quadrature::gll::gll(0.0, 0.0, 5); + specfem::quadrature::quadrature *gllz = + new specfem::quadrature::gll::gll(0.0, 0.0, 5); + std::vector materials; + + specfem::mesh::mesh mesh(test_config.database_filename, materials, + MPIEnvironment::mpi_); + + specfem::compute::properties properties(mesh.material_ind.kmato, materials, + mesh.nspec, gllz->get_N(), + gllx->get_N()); + + specfem::kokkos::HostView3d h_kappa = + properties.h_kappa; + EXPECT_NO_THROW(specfem::testing::test_array(h_kappa, test_config.kappa_file, + mesh.nspec, gllz->get_N(), + gllx->get_N())); + + // specfem::kokkos::HostView3d h_kappa = + // properties.h_kappa; + // EXPECT_NO_THROW(specfem::testing::test_array(h_kappa, + // test_config.kappa_file, + // mesh.nspec, gllz->get_N(), + // gllx->get_N())); + + specfem::kokkos::HostView3d h_mu = + properties.h_mu; + EXPECT_NO_THROW(specfem::testing::test_array( + h_mu, test_config.mu_file, mesh.nspec, gllz->get_N(), gllx->get_N())); + + EXPECT_NO_THROW( + specfem::testing::test_array(properties.rho_vp, test_config.rho_vp_file, + mesh.nspec, gllz->get_N(), gllx->get_N())); + + EXPECT_NO_THROW( + specfem::testing::test_array(properties.rho_vs, test_config.rho_vs_file, + mesh.nspec, gllz->get_N(), gllx->get_N())); + + EXPECT_NO_THROW( + specfem::testing::test_array(properties.qkappa, test_config.qkappa_file, + mesh.nspec, gllz->get_N(), gllx->get_N())); + + EXPECT_NO_THROW(specfem::testing::test_array(properties.qmu, + test_config.qmu_file, mesh.nspec, + gllz->get_N(), gllx->get_N())); +} + +int main(int argc, char *argv[]) { + ::testing::InitGoogleTest(&argc, argv); + ::testing::AddGlobalTestEnvironment(new MPIEnvironment); + ::testing::AddGlobalTestEnvironment(new KokkosEnvironment); + return RUN_ALL_TESTS(); +} diff --git a/tests/unit-tests/compute/acoustic/serial/Database00000.bin b/tests/unit-tests/compute/acoustic/serial/Database00000.bin new file mode 100644 index 00000000..699c950e Binary files /dev/null and b/tests/unit-tests/compute/acoustic/serial/Database00000.bin differ diff --git a/tests/unit-tests/compute/acoustic/serial/kappa_00000.bin b/tests/unit-tests/compute/acoustic/serial/kappa_00000.bin new file mode 100644 index 00000000..ae51e101 Binary files /dev/null and b/tests/unit-tests/compute/acoustic/serial/kappa_00000.bin differ diff --git a/tests/unit-tests/compute/acoustic/serial/mu_00000.bin b/tests/unit-tests/compute/acoustic/serial/mu_00000.bin new file mode 100644 index 00000000..850f38ac Binary files /dev/null and b/tests/unit-tests/compute/acoustic/serial/mu_00000.bin differ diff --git a/tests/unit-tests/compute/acoustic/serial/qkappa_attenuation_00000.bin b/tests/unit-tests/compute/acoustic/serial/qkappa_attenuation_00000.bin new file mode 100644 index 00000000..02304605 Binary files /dev/null and b/tests/unit-tests/compute/acoustic/serial/qkappa_attenuation_00000.bin differ diff --git a/tests/unit-tests/compute/acoustic/serial/qmu_attenuation_00000.bin b/tests/unit-tests/compute/acoustic/serial/qmu_attenuation_00000.bin new file mode 100644 index 00000000..02304605 Binary files /dev/null and b/tests/unit-tests/compute/acoustic/serial/qmu_attenuation_00000.bin differ diff --git a/tests/unit-tests/compute/acoustic/serial/rho_00000.bin b/tests/unit-tests/compute/acoustic/serial/rho_00000.bin new file mode 100644 index 00000000..fea4686c Binary files /dev/null and b/tests/unit-tests/compute/acoustic/serial/rho_00000.bin differ diff --git a/tests/unit-tests/compute/acoustic/serial/rho_vp_00000.bin b/tests/unit-tests/compute/acoustic/serial/rho_vp_00000.bin new file mode 100644 index 00000000..cefb746f Binary files /dev/null and b/tests/unit-tests/compute/acoustic/serial/rho_vp_00000.bin differ diff --git a/tests/unit-tests/compute/acoustic/test_config.yml b/tests/unit-tests/compute/acoustic/test_config.yml new file mode 100644 index 00000000..9d0ce523 --- /dev/null +++ b/tests/unit-tests/compute/acoustic/test_config.yml @@ -0,0 +1,13 @@ +SerialTest: + config: + nproc : 1 + database: + - processor : 0 + database_file : "../../../tests/unit-tests/compute/acoustic/serial/Database00000.bin" + # rho_file: "../../../tests/unit-tests/compute/acoustic/serial/kappa_00000.bin" + kappa_file: "../../../tests/unit-tests/compute/acoustic/serial/kappa_00000.bin" + mu_file: "../../../tests/unit-tests/compute/acoustic/serial/mu_00000.bin" + qkappa_file: "../../../tests/unit-tests/compute/acoustic/serial/qkappa_attenuation_00000.bin" + qmu_file: "../../../tests/unit-tests/compute/acoustic/serial/qmu_attenuation_00000.bin" + rho_vp_file: "../../../tests/unit-tests/compute/acoustic/serial/rho_vp_00000.bin" + rho_vs_file: "../../../tests/unit-tests/compute/acoustic/serial/rho_vs_00000.bin" diff --git a/tests/unit-tests/compute/coupled_interfaces/coupled_interfaces_tests.cpp b/tests/unit-tests/compute/coupled_interfaces/coupled_interfaces_tests.cpp new file mode 100644 index 00000000..e6e9e746 --- /dev/null +++ b/tests/unit-tests/compute/coupled_interfaces/coupled_interfaces_tests.cpp @@ -0,0 +1,295 @@ +#include "../../Kokkos_Environment.hpp" +#include "../../MPI_environment.hpp" +#include "../../utilities/include/compare_array.h" +#include "compute/interface.hpp" +#include "material/interface.hpp" +#include "mesh/mesh.hpp" +#include "quadrature/interface.hpp" +#include "yaml-cpp/yaml.h" +#include +#include +#include +#include + +// ------------------------------------------------------------------------ +// Reading test config + +namespace test_config { +struct mesh { +public: + std::string database_filename; +}; + +struct elastic_acoustic { + std::string elastic_ispec_file; + std::string acoustic_ispec_file; +}; + +struct elastic_poroelastic { + std::string elastic_ispec_file; + std::string poroelastic_ispec_file; +}; + +struct acoustic_poroelastic { + std::string acoustic_ispec_file; + std::string poroelastic_ispec_file; +}; + +struct databases { +public: + test_config::mesh mesh; + test_config::elastic_acoustic elastic_acoustic; + test_config::elastic_poroelastic elastic_poroelastic; + test_config::acoustic_poroelastic acoustic_poroelastic; +}; + +struct configuration { +public: + int processors; +}; + +struct Test { +public: + Test(const YAML::Node &Node) { + name = Node["name"].as(); + description = Node["description"].as(); + YAML::Node config = Node["config"]; + configuration.processors = config["nproc"].as(); + YAML::Node database = Node["databases"]; + + assert(database.IsMap()); + + YAML::Node elastic_acoustic = database["elastic_acoustic"]; + YAML::Node elastic_poroelastic = database["elastic_poroelastic"]; + YAML::Node acoustic_poroelastic = database["acoustic_poroelastic"]; + YAML::Node mesh = database["mesh"]; + + assert(elastic_acoustic.IsMap()); + assert(elastic_poroelastic.IsMap()); + assert(acoustic_poroelastic.IsMap()); + + databases.mesh.database_filename = mesh["database"].as(); + + databases.elastic_acoustic.elastic_ispec_file = + elastic_acoustic["elastic_ispec"].as(); + databases.elastic_acoustic.acoustic_ispec_file = + elastic_acoustic["acoustic_ispec"].as(); + + databases.elastic_poroelastic.elastic_ispec_file = + elastic_poroelastic["elastic_ispec"].as(); + databases.elastic_poroelastic.poroelastic_ispec_file = + elastic_poroelastic["poroelastic_ispec"].as(); + + databases.acoustic_poroelastic.acoustic_ispec_file = + acoustic_poroelastic["acoustic_ispec"].as(); + databases.acoustic_poroelastic.poroelastic_ispec_file = + acoustic_poroelastic["poroelastic_ispec"].as(); + + return; + } + std::string name; + std::string description; + test_config::configuration configuration; + test_config::databases databases; +}; +} // namespace test_config +// ------------------------------------------------------------------------ + +// ------------------------------------------------------------------------ +// Reading test config + +void parse_test_config(const YAML::Node &yaml, + std::vector &tests) { + YAML::Node all_tests = yaml["Tests"]; + assert(all_tests.IsSequence()); + + for (auto N : all_tests) + tests.push_back(test_config::Test(N)); + + return; +} + +// --------------------------------------------------------------------------- + +void test_edges( + const specfem::kokkos::HostMirror3d h_ibool, + const specfem::kokkos::HostView2d coord, + const specfem::kokkos::HostMirror1d ispec1, + const specfem::kokkos::HostMirror1d ispec2, + const specfem::kokkos::HostMirror1d edge1, + const specfem::kokkos::HostMirror1d edge2) { + + const int num_interfaces = ispec1.extent(0); + const int ngllx = h_ibool.extent(2); + const int ngllz = h_ibool.extent(1); + + for (int interface = 0; interface < num_interfaces; interface++) { + const int ispec1l = ispec1(interface); + const int ispec2l = ispec2(interface); + + const auto edge1l = edge1(interface); + const auto edge2l = edge2(interface); + + // iterate over the edge + int npoints = specfem::compute::coupled_interfaces::access::npoints( + edge1l, ngllx, ngllz); + + for (int ipoint = 0; ipoint < npoints; ipoint++) { + // Get ipoint along the edge in element1 + int i1, j1; + specfem::compute::coupled_interfaces::access::coupled_iterator( + ipoint, edge1l, ngllx, ngllz, i1, j1); + const int iglob1 = h_ibool(ispec1l, j1, i1); + + // Get ipoint along the edge in element2 + int i2, j2; + specfem::compute::coupled_interfaces::access::self_iterator( + ipoint, edge2l, ngllx, ngllz, i2, j2); + const int iglob2 = h_ibool(ispec2l, j2, i2); + + // Check that the distance between the two points is small + + ASSERT_TRUE((((coord(0, iglob1) - coord(0, iglob2)) * + (coord(0, iglob1) - coord(0, iglob2))) + + ((coord(1, iglob1) - coord(1, iglob2)) * + (coord(1, iglob1) - coord(1, iglob2)))) < 1.e-10) + << "Invalid edges found at interface number " << interface; + } + } +} + +TEST(COMPUTE_TESTS, coupled_interfaces_tests) { + + std::string config_filename = + "../../../tests/unit-tests/compute/coupled_interfaces/test_config.yaml"; + + std::vector tests; + parse_test_config(YAML::LoadFile(config_filename), tests); + + // Set up GLL quadrature points + specfem::quadrature::quadrature *gllx = + new specfem::quadrature::gll::gll(0.0, 0.0, 5); + specfem::quadrature::quadrature *gllz = + new specfem::quadrature::gll::gll(0.0, 0.0, 5); + std::vector materials; + + for (auto Test : tests) { + std::cout << "Executing test: " << Test.name << std::endl; + + // Read mesh generated MESHFEM + specfem::mesh::mesh mesh(Test.databases.mesh.database_filename, materials, + MPIEnvironment::mpi_); + + // Generate compute structs to be used by the solver + specfem::compute::compute compute(mesh.coorg, mesh.material_ind.knods, gllx, + gllz); + + // Generate properties struct to be used by the solver + specfem::compute::properties properties(mesh.material_ind.kmato, materials, + mesh.nspec, gllz->get_N(), + gllx->get_N()); + + try { + // Generate coupled interfaces struct to be used by the solver + specfem::compute::coupled_interfaces::coupled_interfaces + coupled_interfaces(compute.h_ibool, compute.coordinates.coord, + properties.h_ispec_type, mesh.coupled_interfaces); + + // Test coupled interfaces + // Check if the mesh was read correctly + specfem::kokkos::HostView1d h_elastic_ispec; + specfem::kokkos::HostView1d h_acoustic_ispec; + specfem::kokkos::HostView1d h_poroelastic_ispec; + + if (Test.databases.elastic_acoustic.elastic_ispec_file != "NULL") { + h_elastic_ispec = coupled_interfaces.elastic_acoustic.h_elastic_ispec; + specfem::testing::test_array( + h_elastic_ispec, Test.databases.elastic_acoustic.elastic_ispec_file, + coupled_interfaces.elastic_acoustic.num_interfaces); + + h_acoustic_ispec = coupled_interfaces.elastic_acoustic.h_acoustic_ispec; + specfem::testing::test_array( + h_acoustic_ispec, + Test.databases.elastic_acoustic.acoustic_ispec_file, + coupled_interfaces.elastic_acoustic.num_interfaces); + + // test if the edges match + test_edges(compute.h_ibool, compute.coordinates.coord, + coupled_interfaces.elastic_acoustic.h_elastic_ispec, + coupled_interfaces.elastic_acoustic.h_acoustic_ispec, + coupled_interfaces.elastic_acoustic.h_elastic_edge, + coupled_interfaces.elastic_acoustic.h_acoustic_edge); + } else { + ASSERT_TRUE(coupled_interfaces.elastic_acoustic.num_interfaces == 0); + } + // Check if the mesh was read correctly + if (Test.databases.elastic_poroelastic.elastic_ispec_file != "NULL") { + h_elastic_ispec = + coupled_interfaces.elastic_poroelastic.h_elastic_ispec; + specfem::testing::test_array( + h_elastic_ispec, + Test.databases.elastic_poroelastic.elastic_ispec_file, + coupled_interfaces.elastic_poroelastic.num_interfaces); + + h_poroelastic_ispec = + coupled_interfaces.elastic_poroelastic.h_poroelastic_ispec; + specfem::testing::test_array( + h_poroelastic_ispec, + Test.databases.elastic_poroelastic.poroelastic_ispec_file, + coupled_interfaces.elastic_poroelastic.num_interfaces); + + // test if the edges match + test_edges(compute.h_ibool, compute.coordinates.coord, + coupled_interfaces.elastic_poroelastic.h_elastic_ispec, + coupled_interfaces.elastic_poroelastic.h_poroelastic_ispec, + coupled_interfaces.elastic_poroelastic.h_elastic_edge, + coupled_interfaces.elastic_poroelastic.h_poroelastic_edge); + } else { + ASSERT_TRUE(coupled_interfaces.elastic_poroelastic.num_interfaces == 0); + } + + // Check if the mesh was read correctly + if (Test.databases.acoustic_poroelastic.acoustic_ispec_file != "NULL") { + h_poroelastic_ispec = + coupled_interfaces.acoustic_poroelastic.h_poroelastic_ispec; + specfem::testing::test_array( + h_poroelastic_ispec, + Test.databases.acoustic_poroelastic.poroelastic_ispec_file, + coupled_interfaces.acoustic_poroelastic.num_interfaces); + + h_acoustic_ispec = + coupled_interfaces.acoustic_poroelastic.h_acoustic_ispec; + specfem::testing::test_array( + h_acoustic_ispec, + Test.databases.acoustic_poroelastic.acoustic_ispec_file, + coupled_interfaces.acoustic_poroelastic.num_interfaces); + + // test if the edges match + test_edges(compute.h_ibool, compute.coordinates.coord, + coupled_interfaces.acoustic_poroelastic.h_poroelastic_ispec, + coupled_interfaces.acoustic_poroelastic.h_acoustic_ispec, + coupled_interfaces.acoustic_poroelastic.h_poroelastic_edge, + coupled_interfaces.acoustic_poroelastic.h_acoustic_edge); + } else { + ASSERT_TRUE(coupled_interfaces.acoustic_poroelastic.num_interfaces == + 0); + } + + std::cout << " - Test passed\n"; + } catch (std::exception &e) { + std::cout << " - Error: " << e.what() << std::endl; + FAIL() << " Test failed\n" + << " - Test name: " << Test.name << "\n" + << " - Number of MPI processors: " << Test.configuration.processors + << "\n" + << " - Error: " << e.what() << std::endl; + } + } +} + +int main(int argc, char *argv[]) { + ::testing::InitGoogleTest(&argc, argv); + ::testing::AddGlobalTestEnvironment(new MPIEnvironment); + ::testing::AddGlobalTestEnvironment(new KokkosEnvironment); + return RUN_ALL_TESTS(); +} diff --git a/tests/unit-tests/compute/coupled_interfaces/serial/test1/elastic_acoustic/acoustic_ispec.bin b/tests/unit-tests/compute/coupled_interfaces/serial/test1/elastic_acoustic/acoustic_ispec.bin new file mode 100644 index 00000000..efb63902 Binary files /dev/null and b/tests/unit-tests/compute/coupled_interfaces/serial/test1/elastic_acoustic/acoustic_ispec.bin differ diff --git a/tests/unit-tests/compute/coupled_interfaces/serial/test1/elastic_acoustic/elastic_ispec.bin b/tests/unit-tests/compute/coupled_interfaces/serial/test1/elastic_acoustic/elastic_ispec.bin new file mode 100644 index 00000000..50f29b19 Binary files /dev/null and b/tests/unit-tests/compute/coupled_interfaces/serial/test1/elastic_acoustic/elastic_ispec.bin differ diff --git a/tests/unit-tests/compute/coupled_interfaces/serial/test1/mesh/database.bin b/tests/unit-tests/compute/coupled_interfaces/serial/test1/mesh/database.bin new file mode 100644 index 00000000..7319363f Binary files /dev/null and b/tests/unit-tests/compute/coupled_interfaces/serial/test1/mesh/database.bin differ diff --git a/tests/unit-tests/compute/coupled_interfaces/test_config.yaml b/tests/unit-tests/compute/coupled_interfaces/test_config.yaml new file mode 100644 index 00000000..8575a3d1 --- /dev/null +++ b/tests/unit-tests/compute/coupled_interfaces/test_config.yaml @@ -0,0 +1,18 @@ +Tests: + - name: "SerialTest1 : Coupled elastic acoustic interface" + description: | + Coupled elastic acoustic interface. Test is run on a single MPI process. + config: + nproc: 1 + databases: + mesh: + database: "../../../tests/unit-tests/compute/coupled_interfaces/serial/test1/mesh/database.bin" + elastic_acoustic: + elastic_ispec: "../../../tests/unit-tests/compute/coupled_interfaces/serial/test1/elastic_acoustic/elastic_ispec.bin" + acoustic_ispec: "../../../tests/unit-tests/compute/coupled_interfaces/serial/test1/elastic_acoustic/acoustic_ispec.bin" + elastic_poroelastic: + elastic_ispec: "NULL" + poroelastic_ispec: "NULL" + acoustic_poroelastic: + acoustic_ispec: "NULL" + poroelastic_ispec: "NULL" diff --git a/tests/unit-tests/compute/compute_properties_tests.cpp b/tests/unit-tests/compute/elastic/compute_properties_tests.cpp similarity index 88% rename from tests/unit-tests/compute/compute_properties_tests.cpp rename to tests/unit-tests/compute/elastic/compute_properties_tests.cpp index 9b75ac59..7ad40d69 100644 --- a/tests/unit-tests/compute/compute_properties_tests.cpp +++ b/tests/unit-tests/compute/elastic/compute_properties_tests.cpp @@ -1,6 +1,6 @@ -#include "../Kokkos_Environment.hpp" -#include "../MPI_environment.hpp" -#include "../utilities/include/compare_array.h" +#include "../../Kokkos_Environment.hpp" +#include "../../MPI_environment.hpp" +#include "../../utilities/include/compare_array.h" #include "compute/interface.hpp" #include "material/interface.hpp" #include "mesh/mesh.hpp" @@ -64,10 +64,10 @@ test_config get_test_config(std::string config_filename, * This test should be run on single and multiple nodes * */ -TEST(COMPUTE_TESTS, compute_properties) { +TEST(COMPUTE_TESTS, compute_elastic_properties) { std::string config_filename = - "../../../tests/unit-tests/compute/test_config.yml"; + "../../../tests/unit-tests/compute/elastic/test_config.yml"; test_config test_config = get_test_config(config_filename, MPIEnvironment::mpi_); @@ -90,9 +90,11 @@ TEST(COMPUTE_TESTS, compute_properties) { EXPECT_NO_THROW(specfem::testing::test_array( h_rho, test_config.rho_file, mesh.nspec, gllz->get_N(), gllx->get_N())); - EXPECT_NO_THROW( - specfem::testing::test_array(properties.kappa, test_config.kappa_file, - mesh.nspec, gllz->get_N(), gllx->get_N())); + specfem::kokkos::HostView3d h_kappa = + properties.h_kappa; + EXPECT_NO_THROW(specfem::testing::test_array(h_kappa, test_config.kappa_file, + mesh.nspec, gllz->get_N(), + gllx->get_N())); specfem::kokkos::HostView3d h_mu = properties.h_mu; diff --git a/tests/unit-tests/compute/serial/data/Database00000.bin b/tests/unit-tests/compute/elastic/serial/Database00000.bin similarity index 100% rename from tests/unit-tests/compute/serial/data/Database00000.bin rename to tests/unit-tests/compute/elastic/serial/Database00000.bin diff --git a/tests/unit-tests/compute/serial/data/kappa_00000.bin b/tests/unit-tests/compute/elastic/serial/kappa_00000.bin similarity index 100% rename from tests/unit-tests/compute/serial/data/kappa_00000.bin rename to tests/unit-tests/compute/elastic/serial/kappa_00000.bin diff --git a/tests/unit-tests/compute/serial/data/mu_00000.bin b/tests/unit-tests/compute/elastic/serial/mu_00000.bin similarity index 100% rename from tests/unit-tests/compute/serial/data/mu_00000.bin rename to tests/unit-tests/compute/elastic/serial/mu_00000.bin diff --git a/tests/unit-tests/compute/serial/data/qkappa_attenuation_00000.bin b/tests/unit-tests/compute/elastic/serial/qkappa_attenuation_00000.bin similarity index 100% rename from tests/unit-tests/compute/serial/data/qkappa_attenuation_00000.bin rename to tests/unit-tests/compute/elastic/serial/qkappa_attenuation_00000.bin diff --git a/tests/unit-tests/compute/serial/data/qmu_attenuation_00000.bin b/tests/unit-tests/compute/elastic/serial/qmu_attenuation_00000.bin similarity index 100% rename from tests/unit-tests/compute/serial/data/qmu_attenuation_00000.bin rename to tests/unit-tests/compute/elastic/serial/qmu_attenuation_00000.bin diff --git a/tests/unit-tests/compute/serial/data/rho_00000.bin b/tests/unit-tests/compute/elastic/serial/rho_00000.bin similarity index 100% rename from tests/unit-tests/compute/serial/data/rho_00000.bin rename to tests/unit-tests/compute/elastic/serial/rho_00000.bin diff --git a/tests/unit-tests/compute/serial/data/rho_vp_00000.bin b/tests/unit-tests/compute/elastic/serial/rho_vp_00000.bin similarity index 100% rename from tests/unit-tests/compute/serial/data/rho_vp_00000.bin rename to tests/unit-tests/compute/elastic/serial/rho_vp_00000.bin diff --git a/tests/unit-tests/compute/serial/data/rho_vs_00000.bin b/tests/unit-tests/compute/elastic/serial/rho_vs_00000.bin similarity index 100% rename from tests/unit-tests/compute/serial/data/rho_vs_00000.bin rename to tests/unit-tests/compute/elastic/serial/rho_vs_00000.bin diff --git a/tests/unit-tests/compute/elastic/test_config.yml b/tests/unit-tests/compute/elastic/test_config.yml new file mode 100644 index 00000000..88c2803a --- /dev/null +++ b/tests/unit-tests/compute/elastic/test_config.yml @@ -0,0 +1,13 @@ +SerialTest: + config: + nproc : 1 + database: + - processor : 0 + database_file : "../../../tests/unit-tests/compute/elastic/serial/Database00000.bin" + rho_file: "../../../tests/unit-tests/compute/elastic/serial/rho_00000.bin" + kappa_file: "../../../tests/unit-tests/compute/elastic/serial/kappa_00000.bin" + mu_file: "../../../tests/unit-tests/compute/elastic/serial/mu_00000.bin" + qkappa_file: "../../../tests/unit-tests/compute/elastic/serial/qkappa_attenuation_00000.bin" + qmu_file: "../../../tests/unit-tests/compute/elastic/serial/qmu_attenuation_00000.bin" + rho_vp_file: "../../../tests/unit-tests/compute/elastic/serial/rho_vp_00000.bin" + rho_vs_file: "../../../tests/unit-tests/compute/elastic/serial/rho_vs_00000.bin" diff --git a/tests/unit-tests/compute/compute_tests.cpp b/tests/unit-tests/compute/index/compute_tests.cpp similarity index 93% rename from tests/unit-tests/compute/compute_tests.cpp rename to tests/unit-tests/compute/index/compute_tests.cpp index 6663f80a..7774245c 100644 --- a/tests/unit-tests/compute/compute_tests.cpp +++ b/tests/unit-tests/compute/index/compute_tests.cpp @@ -1,6 +1,6 @@ -#include "../Kokkos_Environment.hpp" -#include "../MPI_environment.hpp" -#include "../utilities/include/compare_array.h" +#include "../../Kokkos_Environment.hpp" +#include "../../MPI_environment.hpp" +#include "../../utilities/include/compare_array.h" #include "compute/interface.hpp" #include "material/interface.hpp" #include "mesh/mesh.hpp" @@ -61,7 +61,7 @@ TEST(COMPUTE_TESTS, compute_ibool) { std::cout << "Hello -2" << std::endl; std::string config_filename = - "../../../tests/unit-tests/compute/test_config.yml"; + "../../../tests/unit-tests/compute/index/test_config.yml"; test_config test_config = get_test_config(config_filename, MPIEnvironment::mpi_); diff --git a/tests/unit-tests/compute/index/serial/Database00000.bin b/tests/unit-tests/compute/index/serial/Database00000.bin new file mode 100644 index 00000000..b9007977 Binary files /dev/null and b/tests/unit-tests/compute/index/serial/Database00000.bin differ diff --git a/tests/unit-tests/compute/serial/data/ibool_00000.bin b/tests/unit-tests/compute/index/serial/ibool_00000.bin similarity index 100% rename from tests/unit-tests/compute/serial/data/ibool_00000.bin rename to tests/unit-tests/compute/index/serial/ibool_00000.bin diff --git a/tests/unit-tests/compute/index/test_config.yml b/tests/unit-tests/compute/index/test_config.yml new file mode 100644 index 00000000..135d0be4 --- /dev/null +++ b/tests/unit-tests/compute/index/test_config.yml @@ -0,0 +1,7 @@ +SerialTest: + config: + nproc : 1 + database: + - processor : 0 + database_file : "../../../tests/unit-tests/compute/index/serial/Database00000.bin" + ibool_file : "../../../tests/unit-tests/compute/index/serial/ibool_00000.bin" diff --git a/tests/unit-tests/compute/compute_partial_derivatives_tests.cpp b/tests/unit-tests/compute/partial_derivatives/compute_partial_derivatives_tests.cpp similarity index 95% rename from tests/unit-tests/compute/compute_partial_derivatives_tests.cpp rename to tests/unit-tests/compute/partial_derivatives/compute_partial_derivatives_tests.cpp index 481d3add..095342bc 100644 --- a/tests/unit-tests/compute/compute_partial_derivatives_tests.cpp +++ b/tests/unit-tests/compute/partial_derivatives/compute_partial_derivatives_tests.cpp @@ -1,6 +1,6 @@ -#include "../Kokkos_Environment.hpp" -#include "../MPI_environment.hpp" -#include "../utilities/include/compare_array.h" +#include "../../Kokkos_Environment.hpp" +#include "../../MPI_environment.hpp" +#include "../../utilities/include/compare_array.h" #include "compute/interface.hpp" #include "material/interface.hpp" #include "mesh/mesh.hpp" @@ -64,7 +64,7 @@ test_config get_test_config(std::string config_filename, TEST(COMPUTE_TESTS, compute_partial_derivatives) { std::string config_filename = - "../../../tests/unit-tests/compute/test_config.yml"; + "../../../tests/unit-tests/compute/partial_derivatives/test_config.yml"; test_config test_config = get_test_config(config_filename, MPIEnvironment::mpi_); diff --git a/tests/unit-tests/compute/partial_derivatives/serial/Database00000.bin b/tests/unit-tests/compute/partial_derivatives/serial/Database00000.bin new file mode 100644 index 00000000..b9007977 Binary files /dev/null and b/tests/unit-tests/compute/partial_derivatives/serial/Database00000.bin differ diff --git a/tests/unit-tests/compute/serial/data/gammax_00000.bin b/tests/unit-tests/compute/partial_derivatives/serial/gammax_00000.bin similarity index 100% rename from tests/unit-tests/compute/serial/data/gammax_00000.bin rename to tests/unit-tests/compute/partial_derivatives/serial/gammax_00000.bin diff --git a/tests/unit-tests/compute/serial/data/gammaz_00000.bin b/tests/unit-tests/compute/partial_derivatives/serial/gammaz_00000.bin similarity index 100% rename from tests/unit-tests/compute/serial/data/gammaz_00000.bin rename to tests/unit-tests/compute/partial_derivatives/serial/gammaz_00000.bin diff --git a/tests/unit-tests/compute/serial/data/jacobian_00000.bin b/tests/unit-tests/compute/partial_derivatives/serial/jacobian_00000.bin similarity index 100% rename from tests/unit-tests/compute/serial/data/jacobian_00000.bin rename to tests/unit-tests/compute/partial_derivatives/serial/jacobian_00000.bin diff --git a/tests/unit-tests/compute/serial/data/xix_00000.bin b/tests/unit-tests/compute/partial_derivatives/serial/xix_00000.bin similarity index 100% rename from tests/unit-tests/compute/serial/data/xix_00000.bin rename to tests/unit-tests/compute/partial_derivatives/serial/xix_00000.bin diff --git a/tests/unit-tests/compute/serial/data/xiz_00000.bin b/tests/unit-tests/compute/partial_derivatives/serial/xiz_00000.bin similarity index 100% rename from tests/unit-tests/compute/serial/data/xiz_00000.bin rename to tests/unit-tests/compute/partial_derivatives/serial/xiz_00000.bin diff --git a/tests/unit-tests/compute/partial_derivatives/test_config.yml b/tests/unit-tests/compute/partial_derivatives/test_config.yml new file mode 100644 index 00000000..041cc6bc --- /dev/null +++ b/tests/unit-tests/compute/partial_derivatives/test_config.yml @@ -0,0 +1,11 @@ +SerialTest: + config: + nproc : 1 + database: + - processor : 0 + database_file : "../../../tests/unit-tests/compute/partial_derivatives/serial/Database00000.bin" + xix_file: "../../../tests/unit-tests/compute/partial_derivatives/serial/xix_00000.bin" + xiz_file: "../../../tests/unit-tests/compute/partial_derivatives/serial/xiz_00000.bin" + gammax_file: "../../../tests/unit-tests/compute/partial_derivatives/serial/gammax_00000.bin" + gammaz_file: "../../../tests/unit-tests/compute/partial_derivatives/serial/gammaz_00000.bin" + jacobian_file: "../../../tests/unit-tests/compute/partial_derivatives/serial/jacobian_00000.bin" diff --git a/tests/unit-tests/compute/test_config.yml b/tests/unit-tests/compute/test_config.yml deleted file mode 100644 index a644ff34..00000000 --- a/tests/unit-tests/compute/test_config.yml +++ /dev/null @@ -1,43 +0,0 @@ -SerialTest: - config: - nproc : 1 - database: - - processor : 0 - database_file : "../../../tests/unit-tests/compute/serial/data/Database00000.bin" - ibool_file : "../../../tests/unit-tests/compute/serial/data/ibool_00000.bin" - xix_file: "../../../tests/unit-tests/compute/serial/data/xix_00000.bin" - xiz_file: "../../../tests/unit-tests/compute/serial/data/xiz_00000.bin" - gammax_file: "../../../tests/unit-tests/compute/serial/data/gammax_00000.bin" - gammaz_file: "../../../tests/unit-tests/compute/serial/data/gammaz_00000.bin" - jacobian_file: "../../../tests/unit-tests/compute/serial/data/jacobian_00000.bin" - rho_file: "../../../tests/unit-tests/compute/serial/data/rho_00000.bin" - kappa_file: "../../../tests/unit-tests/compute/serial/data/kappa_00000.bin" - mu_file: "../../../tests/unit-tests/compute/serial/data/mu_00000.bin" - qkappa_file: "../../../tests/unit-tests/compute/serial/data/qkappa_attenuation_00000.bin" - qmu_file: "../../../tests/unit-tests/compute/serial/data/qmu_attenuation_00000.bin" - rho_vp_file: "../../../tests/unit-tests/compute/serial/data/rho_vp_00000.bin" - rho_vs_file: "../../../tests/unit-tests/compute/serial/data/rho_vs_00000.bin" -# ParallelTest: -# config: -# nproc : 10 -# database: -# - processor : 0 -# database_file : "../../../tests/unittests/compute/parallel/Database00000.bin" -# - processor : 1 -# database_file : "../../../tests/unittests/compute/parallel/Database00001.bin" -# - processor : 2 -# database_file : "../../../tests/unittests/compute/parallel/Database00002.bin" -# - processor : 3 -# database_file : "../../../tests/unittests/compute/parallel/Database00003.bin" -# - processor : 4 -# database_file : "../../../tests/unittests/compute/parallel/Database00004.bin" -# - processor : 5 -# database_file : "../../../tests/unittests/compute/parallel/Database00005.bin" -# - processor : 6 -# database_file : "../../../tests/unittests/compute/parallel/Database00006.bin" -# - processor : 7 -# database_file : "../../../tests/unittests/compute/parallel/Database00007.bin" -# - processor : 8 -# database_file : "../../../tests/unittests/compute/parallel/Database00008.bin" -# - processor : 9 -# database_file : "../../../tests/unittests/compute/parallel/Database00009.bin" diff --git a/tests/unit-tests/displacement_tests/Newmark/acoustic/newmark_tests.cpp b/tests/unit-tests/displacement_tests/Newmark/acoustic/newmark_tests.cpp new file mode 100644 index 00000000..fefe2773 --- /dev/null +++ b/tests/unit-tests/displacement_tests/Newmark/acoustic/newmark_tests.cpp @@ -0,0 +1,171 @@ +#include "../../../Kokkos_Environment.hpp" +#include "../../../MPI_environment.hpp" +#include "../../../utilities/include/compare_array.h" +#include "compute/interface.hpp" +#include "constants.hpp" +#include "domain/interface.hpp" +#include "material/interface.hpp" +#include "mesh/mesh.hpp" +#include "parameter_parser/interface.hpp" +#include "quadrature/interface.hpp" +#include "solver/interface.hpp" +#include "timescheme/interface.hpp" +#include "yaml-cpp/yaml.h" + +// ----- Parse test config ------------- // + +struct test_config { + std::string specfem_config, solutions_file; +}; + +void operator>>(const YAML::Node &Node, test_config &test_config) { + test_config.specfem_config = Node["specfem_config"].as(); + test_config.solutions_file = Node["solutions_file"].as(); + + return; +} + +test_config parse_test_config(std::string test_configuration_file, + specfem::MPI::MPI *mpi) { + + YAML::Node yaml = YAML::LoadFile(test_configuration_file); + const YAML::Node &tests = yaml["Tests"]; + const YAML::Node &serial = tests["serial"]; + + test_config test_config; + if (mpi->get_size() == 1) { + serial >> test_config; + } + + return test_config; +} + +// ------------------------------------- // + +TEST(DISPLACEMENT_TESTS, newmark_scheme_tests) { + std::string config_filename = "../../../tests/unit-tests/displacement_tests/" + "Newmark/acoustic/test_config.yaml"; + + specfem::MPI::MPI *mpi = MPIEnvironment::mpi_; + + test_config test_config = parse_test_config(config_filename, mpi); + + const std::string parameter_file = test_config.specfem_config; + + specfem::runtime_configuration::setup setup(parameter_file, __default_file__); + + const auto [database_file, sources_file] = setup.get_databases(); + // mpi->cout(setup.print_header()); + + // Set up GLL quadrature points + auto [gllx, gllz] = setup.instantiate_quadrature(); + + // Read mesh generated MESHFEM + std::vector materials; + specfem::mesh::mesh mesh(database_file, materials, mpi); + + // Read sources + // if start time is not explicitly specified then t0 is determined using + // source frequencies and time shift + auto [sources, t0] = + specfem::sources::read_sources(sources_file, setup.get_dt(), mpi); + + // Generate compute structs to be used by the solver + specfem::compute::compute compute(mesh.coorg, mesh.material_ind.knods, gllx, + gllz); + specfem::compute::partial_derivatives partial_derivatives( + mesh.coorg, mesh.material_ind.knods, gllx, gllz); + specfem::compute::properties material_properties( + mesh.material_ind.kmato, materials, mesh.nspec, gllx->get_N(), + gllz->get_N()); + specfem::compute::coupled_interfaces::coupled_interfaces coupled_interfaces( + compute.h_ibool, compute.coordinates.coord, + material_properties.h_ispec_type, mesh.coupled_interfaces); + + // Locate the sources + for (auto &source : sources) + source->locate(compute.coordinates.coord, compute.h_ibool, gllx->get_hxi(), + gllz->get_hxi(), mesh.nproc, mesh.coorg, + mesh.material_ind.knods, mesh.npgeo, + material_properties.h_ispec_type, mpi); + + // User output + for (auto &source : sources) { + if (mpi->main_proc()) + std::cout << *source << std::endl; + } + + // Update solver intialization time + setup.update_t0(-1.0 * t0); + + // Instantiate the solver and timescheme + auto it = setup.instantiate_solver(); + + // User output + if (mpi->main_proc()) + std::cout << *it << std::endl; + + // Setup solver compute struct + const type_real xmax = compute.coordinates.xmax; + const type_real xmin = compute.coordinates.xmin; + const type_real zmax = compute.coordinates.zmax; + const type_real zmin = compute.coordinates.zmin; + + specfem::compute::sources compute_sources(sources, gllx, gllz, xmax, xmin, + zmax, zmin, mpi); + specfem::compute::receivers compute_receivers; + + // Instantiate domain classes + const int nglob = specfem::utilities::compute_nglob(compute.h_ibool); + + specfem::enums::element::quadrature::static_quadrature_points<5> qp5; + specfem::domain::domain< + specfem::enums::element::medium::acoustic, + specfem::enums::element::quadrature::static_quadrature_points<5> > + acoustic_domain_static(nglob, qp5, &compute, material_properties, + partial_derivatives, compute_sources, + compute_receivers, gllx, gllz); + specfem::domain::domain< + specfem::enums::element::medium::elastic, + specfem::enums::element::quadrature::static_quadrature_points<5> > + elastic_domain_static(nglob, qp5, &compute, material_properties, + partial_derivatives, compute_sources, + compute_receivers, gllx, gllz); + + // Instantiate coupled interfaces + specfem::coupled_interface::coupled_interface acoustic_elastic_interface( + acoustic_domain_static, elastic_domain_static, coupled_interfaces, qp5, + partial_derivatives, compute.h_ibool, gllx->get_xi(), gllz->get_xi()); + + specfem::coupled_interface::coupled_interface elastic_acoustic_interface( + elastic_domain_static, acoustic_domain_static, coupled_interfaces, qp5, + partial_derivatives, compute.h_ibool, gllx->get_xi(), gllz->get_xi()); + + specfem::solver::solver *solver = new specfem::solver::time_marching< + specfem::enums::element::quadrature::static_quadrature_points<5> >( + acoustic_domain_static, elastic_domain_static, acoustic_elastic_interface, + elastic_acoustic_interface, it); + + solver->run(); + + acoustic_domain_static.sync_field(specfem::sync::DeviceToHost); + + // specfem::kokkos::HostView2d field = + // acoustic_domain_static.get_host_field(); + + specfem::kokkos::HostView1d field = + Kokkos::subview(acoustic_domain_static.get_host_field(), Kokkos::ALL(), + 0); + + type_real tolerance = 0.01; + + EXPECT_NO_THROW(specfem::testing::compare_norm( + field, test_config.solutions_file, nglob, tolerance)); +} + +int main(int argc, char *argv[]) { + ::testing::InitGoogleTest(&argc, argv); + ::testing::AddGlobalTestEnvironment(new MPIEnvironment); + ::testing::AddGlobalTestEnvironment(new KokkosEnvironment); + return RUN_ALL_TESTS(); +} diff --git a/tests/unit-tests/displacement_tests/Newmark/acoustic/serial/Database00000.bin b/tests/unit-tests/displacement_tests/Newmark/acoustic/serial/Database00000.bin new file mode 100644 index 00000000..699c950e Binary files /dev/null and b/tests/unit-tests/displacement_tests/Newmark/acoustic/serial/Database00000.bin differ diff --git a/tests/unit-tests/displacement_tests/Newmark/acoustic/serial/potential_acoustic_00000.bin b/tests/unit-tests/displacement_tests/Newmark/acoustic/serial/potential_acoustic_00000.bin new file mode 100644 index 00000000..a626c09e Binary files /dev/null and b/tests/unit-tests/displacement_tests/Newmark/acoustic/serial/potential_acoustic_00000.bin differ diff --git a/tests/unit-tests/displacement_tests/Newmark/serial/sources.yaml b/tests/unit-tests/displacement_tests/Newmark/acoustic/serial/sources.yaml similarity index 100% rename from tests/unit-tests/displacement_tests/Newmark/serial/sources.yaml rename to tests/unit-tests/displacement_tests/Newmark/acoustic/serial/sources.yaml diff --git a/tests/unit-tests/displacement_tests/Newmark/acoustic/serial/specfem_config.yaml b/tests/unit-tests/displacement_tests/Newmark/acoustic/serial/specfem_config.yaml new file mode 100644 index 00000000..8e2da812 --- /dev/null +++ b/tests/unit-tests/displacement_tests/Newmark/acoustic/serial/specfem_config.yaml @@ -0,0 +1,51 @@ +parameters: + + header: + ## Header information is used for logging. It is good practice to give your simulations explicit names + title: Isotropic Elastic simulation # name for your simulation + # A detailed description for your simulation + description: | + Material systems : Elastic domain (1) + Interfaces : None + Sources : Force source (1) + Boundary conditions : Neumann BCs on all edges + + simulation-setup: + ## quadrature setup + quadrature: + alpha: 0.0 + beta: 0.0 + ngllx: 5 + ngllz: 5 + + ## Solver setup + solver: + time-marching: + type-of-simulation: forward + time-scheme: + type: Newmark + dt: 1.1e-3 + nstep: 100 + + receivers: + stations-file: "../DATA/STATIONS" + angle: 0.0 + seismogram-type: + - displacement + - velocity + nstep_between_samples: 1 + + ## Runtime setup + run-setup: + number-of-processors: 1 + number-of-runs: 1 + + ## databases + databases: + mesh-database: "../../../tests/unit-tests/displacement_tests/Newmark/acoustic/serial/Database00000.bin" + source-file: "../../../tests/unit-tests/displacement_tests/Newmark/acoustic/serial/sources.yaml" + + # seismogram output + seismogram: + seismogram-format: ascii + output-folder: "." diff --git a/tests/unit-tests/displacement_tests/Newmark/acoustic/test_config.yaml b/tests/unit-tests/displacement_tests/Newmark/acoustic/test_config.yaml new file mode 100644 index 00000000..803b42b8 --- /dev/null +++ b/tests/unit-tests/displacement_tests/Newmark/acoustic/test_config.yaml @@ -0,0 +1,5 @@ +Tests: + + serial: + specfem_config: "../../../tests/unit-tests/displacement_tests/Newmark/acoustic/serial/specfem_config.yaml" + solutions_file: "../../../tests/unit-tests/displacement_tests/Newmark/acoustic/serial/potential_acoustic_00000.bin" diff --git a/tests/unit-tests/displacement_tests/Newmark/elastic/newmark_tests.cpp b/tests/unit-tests/displacement_tests/Newmark/elastic/newmark_tests.cpp new file mode 100644 index 00000000..8960d32f --- /dev/null +++ b/tests/unit-tests/displacement_tests/Newmark/elastic/newmark_tests.cpp @@ -0,0 +1,166 @@ +#include "../../../Kokkos_Environment.hpp" +#include "../../../MPI_environment.hpp" +#include "../../../utilities/include/compare_array.h" +#include "compute/interface.hpp" +#include "constants.hpp" +#include "domain/interface.hpp" +#include "material/interface.hpp" +#include "mesh/mesh.hpp" +#include "parameter_parser/interface.hpp" +#include "quadrature/interface.hpp" +#include "solver/interface.hpp" +#include "timescheme/interface.hpp" +#include "yaml-cpp/yaml.h" + +// ----- Parse test config ------------- // + +struct test_config { + std::string specfem_config, solutions_file; +}; + +void operator>>(const YAML::Node &Node, test_config &test_config) { + test_config.specfem_config = Node["specfem_config"].as(); + test_config.solutions_file = Node["solutions_file"].as(); + + return; +} + +test_config parse_test_config(std::string test_configuration_file, + specfem::MPI::MPI *mpi) { + + YAML::Node yaml = YAML::LoadFile(test_configuration_file); + const YAML::Node &tests = yaml["Tests"]; + const YAML::Node &serial = tests["serial"]; + + test_config test_config; + if (mpi->get_size() == 1) { + serial >> test_config; + } + + return test_config; +} + +// ------------------------------------- // + +TEST(DISPLACEMENT_TESTS, newmark_scheme_tests) { + std::string config_filename = "../../../tests/unit-tests/displacement_tests/" + "Newmark/elastic/test_config.yaml"; + + specfem::MPI::MPI *mpi = MPIEnvironment::mpi_; + + test_config test_config = parse_test_config(config_filename, mpi); + + const std::string parameter_file = test_config.specfem_config; + + specfem::runtime_configuration::setup setup(parameter_file, __default_file__); + + const auto [database_file, sources_file] = setup.get_databases(); + // mpi->cout(setup.print_header()); + + // Set up GLL quadrature points + auto [gllx, gllz] = setup.instantiate_quadrature(); + + // Read mesh generated MESHFEM + std::vector materials; + specfem::mesh::mesh mesh(database_file, materials, mpi); + + // Read sources + // if start time is not explicitly specified then t0 is determined using + // source frequencies and time shift + auto [sources, t0] = + specfem::sources::read_sources(sources_file, setup.get_dt(), mpi); + + // Generate compute structs to be used by the solver + specfem::compute::compute compute(mesh.coorg, mesh.material_ind.knods, gllx, + gllz); + specfem::compute::partial_derivatives partial_derivatives( + mesh.coorg, mesh.material_ind.knods, gllx, gllz); + specfem::compute::properties material_properties( + mesh.material_ind.kmato, materials, mesh.nspec, gllx->get_N(), + gllz->get_N()); + specfem::compute::coupled_interfaces::coupled_interfaces coupled_interfaces( + compute.h_ibool, compute.coordinates.coord, + material_properties.h_ispec_type, mesh.coupled_interfaces); + + // Locate the sources + for (auto &source : sources) + source->locate(compute.coordinates.coord, compute.h_ibool, gllx->get_hxi(), + gllz->get_hxi(), mesh.nproc, mesh.coorg, + mesh.material_ind.knods, mesh.npgeo, + material_properties.h_ispec_type, mpi); + + // User output + for (auto &source : sources) { + if (mpi->main_proc()) + std::cout << *source << std::endl; + } + + // Update solver intialization time + setup.update_t0(-1.0 * t0); + + // Instantiate the solver and timescheme + auto it = setup.instantiate_solver(); + + // User output + if (mpi->main_proc()) + std::cout << *it << std::endl; + + // Setup solver compute struct + const type_real xmax = compute.coordinates.xmax; + const type_real xmin = compute.coordinates.xmin; + const type_real zmax = compute.coordinates.zmax; + const type_real zmin = compute.coordinates.zmin; + + specfem::compute::sources compute_sources(sources, gllx, gllz, xmax, xmin, + zmax, zmin, mpi); + specfem::compute::receivers compute_receivers; + + // Instantiate domain classes + const int nglob = specfem::utilities::compute_nglob(compute.h_ibool); + specfem::enums::element::quadrature::static_quadrature_points<5> qp5; + specfem::domain::domain< + specfem::enums::element::medium::acoustic, + specfem::enums::element::quadrature::static_quadrature_points<5> > + acoustic_domain_static(nglob, qp5, &compute, material_properties, + partial_derivatives, compute_sources, + compute_receivers, gllx, gllz); + specfem::domain::domain< + specfem::enums::element::medium::elastic, + specfem::enums::element::quadrature::static_quadrature_points<5> > + elastic_domain_static(nglob, qp5, &compute, material_properties, + partial_derivatives, compute_sources, + compute_receivers, gllx, gllz); + + // Instantiate coupled interfaces + specfem::coupled_interface::coupled_interface acoustic_elastic_interface( + acoustic_domain_static, elastic_domain_static, coupled_interfaces, qp5, + partial_derivatives, compute.h_ibool, gllx->get_xi(), gllz->get_xi()); + + specfem::coupled_interface::coupled_interface elastic_acoustic_interface( + elastic_domain_static, acoustic_domain_static, coupled_interfaces, qp5, + partial_derivatives, compute.h_ibool, gllx->get_xi(), gllz->get_xi()); + + specfem::solver::solver *solver = new specfem::solver::time_marching< + specfem::enums::element::quadrature::static_quadrature_points<5> >( + acoustic_domain_static, elastic_domain_static, acoustic_elastic_interface, + elastic_acoustic_interface, it); + + solver->run(); + + elastic_domain_static.sync_field(specfem::sync::DeviceToHost); + + specfem::kokkos::HostView2d field = + elastic_domain_static.get_host_field(); + + type_real tolerance = 0.01; + + EXPECT_NO_THROW(specfem::testing::compare_norm( + field, test_config.solutions_file, nglob, ndim, tolerance)); +} + +int main(int argc, char *argv[]) { + ::testing::InitGoogleTest(&argc, argv); + ::testing::AddGlobalTestEnvironment(new MPIEnvironment); + ::testing::AddGlobalTestEnvironment(new KokkosEnvironment); + return RUN_ALL_TESTS(); +} diff --git a/tests/unit-tests/displacement_tests/Newmark/serial/Database00000.bin b/tests/unit-tests/displacement_tests/Newmark/elastic/serial/Database00000.bin similarity index 100% rename from tests/unit-tests/displacement_tests/Newmark/serial/Database00000.bin rename to tests/unit-tests/displacement_tests/Newmark/elastic/serial/Database00000.bin diff --git a/tests/unit-tests/displacement_tests/Newmark/serial/displs_00000.bin b/tests/unit-tests/displacement_tests/Newmark/elastic/serial/displs_00000.bin similarity index 100% rename from tests/unit-tests/displacement_tests/Newmark/serial/displs_00000.bin rename to tests/unit-tests/displacement_tests/Newmark/elastic/serial/displs_00000.bin diff --git a/tests/unit-tests/displacement_tests/Newmark/elastic/serial/sources.yaml b/tests/unit-tests/displacement_tests/Newmark/elastic/serial/sources.yaml new file mode 100644 index 00000000..ed49a37f --- /dev/null +++ b/tests/unit-tests/displacement_tests/Newmark/elastic/serial/sources.yaml @@ -0,0 +1,12 @@ +number-of-sources: 1 +sources: + - force: + x : 2500.0 + z : 2500.0 + source_surf: false + angle : 0.0 + vx : 0.0 + vz : 0.0 + Dirac: + factor: 1e10 + tshift: 0.0 diff --git a/tests/unit-tests/displacement_tests/Newmark/elastic/serial/specfem_config.yaml b/tests/unit-tests/displacement_tests/Newmark/elastic/serial/specfem_config.yaml new file mode 100644 index 00000000..ec76404a --- /dev/null +++ b/tests/unit-tests/displacement_tests/Newmark/elastic/serial/specfem_config.yaml @@ -0,0 +1,50 @@ +parameters: + + header: + ## Header information is used for logging. It is good practice to give your simulations explicit names + title: Isotropic Elastic simulation # name for your simulation + # A detailed description for your simulation + description: | + Material systems : Elastic domain (1) + Interfaces : None + Sources : Force source (1) + Boundary conditions : Neumann BCs on all edges + + simulation-setup: + ## quadrature setup + quadrature: + alpha: 0.0 + beta: 0.0 + ngllx: 5 + ngllz: 5 + + ## Solver setup + solver: + time-marching: + type-of-simulation: forward + time-scheme: + type: Newmark + dt: 1.1e-3 + nstep: 100 + + receivers: + stations-file: "../DATA/STATIONS" + angle: 0.0 + seismogram-type: + - displacement + - velocity + nstep_between_samples: 1 + + ## Runtime setup + run-setup: + number-of-processors: 1 + number-of-runs: 1 + + ## databases + databases: + mesh-database: "../../../tests/unit-tests/displacement_tests/Newmark/elastic/serial/Database00000.bin" + source-file: "../../../tests/unit-tests/displacement_tests/Newmark/elastic/serial/sources.yaml" + + seismogram: + seismogram-format: ascii + output-folder: "." diff --git a/tests/unit-tests/displacement_tests/Newmark/elastic/test_config.yaml b/tests/unit-tests/displacement_tests/Newmark/elastic/test_config.yaml new file mode 100644 index 00000000..b6b93208 --- /dev/null +++ b/tests/unit-tests/displacement_tests/Newmark/elastic/test_config.yaml @@ -0,0 +1,5 @@ +Tests: + + serial: + specfem_config: "../../../tests/unit-tests/displacement_tests/Newmark/elastic/serial/specfem_config.yaml" + solutions_file: "../../../tests/unit-tests/displacement_tests/Newmark/elastic/serial/displs_00000.bin" diff --git a/tests/unit-tests/displacement_tests/Newmark/newmark_tests.cpp b/tests/unit-tests/displacement_tests/Newmark/newmark_tests.cpp index 850273b2..4f3bc098 100644 --- a/tests/unit-tests/displacement_tests/Newmark/newmark_tests.cpp +++ b/tests/unit-tests/displacement_tests/Newmark/newmark_tests.cpp @@ -12,126 +12,247 @@ #include "timescheme/interface.hpp" #include "yaml-cpp/yaml.h" -// ----- Parse test config ------------- // +// ------------------------------------- // +// ------- Test configuration ----------- // + +namespace test_config { +struct database { +public: + database() + : specfem_config(""), elastic_domain_field("NULL"), + acoustic_domain_field("NULL"){}; + database(const YAML::Node &Node) { + specfem_config = Node["specfem_config"].as(); + // check if node elastic_domain_field exists + if (Node["elastic_domain_field"]) + elastic_domain_field = Node["elastic_domain_field"].as(); + + // check if node acoustic_domain_field exists + if (Node["acoustic_domain_field"]) + acoustic_domain_field = Node["acoustic_domain_field"].as(); + } + std::string specfem_config; + std::string elastic_domain_field = "NULL"; + std::string acoustic_domain_field = "NULL"; +}; -struct test_config { - std::string specfem_config, solutions_file; +struct configuration { +public: + configuration() : number_of_processors(0){}; + configuration(const YAML::Node &Node) { + number_of_processors = Node["nproc"].as(); + } + int number_of_processors; }; -void operator>>(const YAML::Node &Node, test_config &test_config) { - test_config.specfem_config = Node["specfem_config"].as(); - test_config.solutions_file = Node["solutions_file"].as(); +struct Test { +public: + Test(const YAML::Node &Node) { + name = Node["name"].as(); + description = Node["description"].as(); + YAML::Node config = Node["config"]; + configuration = test_config::configuration(config); + + YAML::Node database_node = Node["databases"]; + database = test_config::database(database_node); + return; + } - return; -} + std::string name; + std::string description; + test_config::database database; + test_config::configuration configuration; +}; +} // namespace test_config -test_config parse_test_config(std::string test_configuration_file, - specfem::MPI::MPI *mpi) { +// ------------------------------------- // - YAML::Node yaml = YAML::LoadFile(test_configuration_file); +// ----- Parse test config ------------- // + +std::vector parse_test_config(std::string test_config_file, + specfem::MPI::MPI *mpi) { + YAML::Node yaml = YAML::LoadFile(test_config_file); const YAML::Node &tests = yaml["Tests"]; - const YAML::Node &serial = tests["serial"]; - test_config test_config; - if (mpi->get_size() == 1) { - serial >> test_config; - } + assert(tests.IsSequence()); + + std::vector test_configurations; + for (auto N : tests) + test_configurations.push_back(test_config::Test(N)); - return test_config; + return test_configurations; } // ------------------------------------- // TEST(DISPLACEMENT_TESTS, newmark_scheme_tests) { - std::string config_filename = - "../../../tests/unit-tests/displacement_tests/Newmark/test_config.yaml"; + std::string config_filename = "../../../tests/unit-tests/displacement_tests/" + "Newmark/test_config.yaml"; specfem::MPI::MPI *mpi = MPIEnvironment::mpi_; - test_config test_config = parse_test_config(config_filename, mpi); - - const std::string parameter_file = test_config.specfem_config; - - specfem::runtime_configuration::setup setup(parameter_file, __default_file__); - - const auto [database_file, sources_file] = setup.get_databases(); - // mpi->cout(setup.print_header()); - - // Set up GLL quadrature points - auto [gllx, gllz] = setup.instantiate_quadrature(); - - // Read mesh generated MESHFEM - std::vector materials; - specfem::mesh::mesh mesh(database_file, materials, mpi); - - // Read sources - // if start time is not explicitly specified then t0 is determined using - // source frequencies and time shift - auto [sources, t0] = - specfem::sources::read_sources(sources_file, setup.get_dt(), mpi); - - // Generate compute structs to be used by the solver - specfem::compute::compute compute(mesh.coorg, mesh.material_ind.knods, gllx, - gllz); - specfem::compute::partial_derivatives partial_derivatives( - mesh.coorg, mesh.material_ind.knods, gllx, gllz); - specfem::compute::properties material_properties( - mesh.material_ind.kmato, materials, mesh.nspec, gllx->get_N(), - gllz->get_N()); - - // Locate the sources - for (auto &source : sources) - source->locate(compute.coordinates.coord, compute.h_ibool, gllx->get_hxi(), - gllz->get_hxi(), mesh.nproc, mesh.coorg, - mesh.material_ind.knods, mesh.npgeo, - material_properties.h_ispec_type, mpi); - - // User output - for (auto &source : sources) { + auto Tests = parse_test_config(config_filename, mpi); + + for (auto &Test : Tests) { + std::cout << "-------------------------------------------------------\n" + << "\033[0;32m[RUNNING]\033[0m Test: " << Test.name << "\n" + << "-------------------------------------------------------\n\n" + << std::endl; + + const auto parameter_file = Test.database.specfem_config; + + specfem::runtime_configuration::setup setup(parameter_file, + __default_file__); + + const auto [database_file, sources_file] = setup.get_databases(); + + // Set up GLL quadrature points + auto [gllx, gllz] = setup.instantiate_quadrature(); + + // Read mesh generated MESHFEM + std::vector materials; + specfem::mesh::mesh mesh(database_file, materials, mpi); + + // Read sources + // if start time is not explicitly specified then t0 is determined using + // source frequencies and time shift + auto [sources, t0] = + specfem::sources::read_sources(sources_file, setup.get_dt(), mpi); + + // Generate compute structs to be used by the solver + specfem::compute::compute compute(mesh.coorg, mesh.material_ind.knods, gllx, + gllz); + specfem::compute::partial_derivatives partial_derivatives( + mesh.coorg, mesh.material_ind.knods, gllx, gllz); + specfem::compute::properties material_properties( + mesh.material_ind.kmato, materials, mesh.nspec, gllx->get_N(), + gllz->get_N()); + specfem::compute::coupled_interfaces::coupled_interfaces coupled_interfaces( + compute.h_ibool, compute.coordinates.coord, + material_properties.h_ispec_type, mesh.coupled_interfaces); + + // Set up boundary conditions + specfem::compute::boundaries boundary_conditions( + mesh.material_ind.kmato, materials, mesh.acfree_surface, + mesh.abs_boundary); + + // Locate the sources + for (auto &source : sources) + source->locate(compute.coordinates.coord, compute.h_ibool, + gllx->get_hxi(), gllz->get_hxi(), mesh.nproc, mesh.coorg, + mesh.material_ind.knods, mesh.npgeo, + material_properties.h_ispec_type, mpi); + + // User output + for (auto &source : sources) { + if (mpi->main_proc()) + std::cout << *source << std::endl; + } + + // Update solver intialization time + setup.update_t0(-1.0 * t0); + + // Instantiate the solver and timescheme + auto it = setup.instantiate_solver(); + + // User output if (mpi->main_proc()) - std::cout << *source << std::endl; + std::cout << *it << std::endl; + + // Setup solver compute struct + const type_real xmax = compute.coordinates.xmax; + const type_real xmin = compute.coordinates.xmin; + const type_real zmax = compute.coordinates.zmax; + const type_real zmin = compute.coordinates.zmin; + + specfem::compute::sources compute_sources(sources, gllx, gllz, xmax, xmin, + zmax, zmin, mpi); + + specfem::compute::receivers compute_receivers; + + // Instantiate domain classes + + try { + + const int nglob = specfem::utilities::compute_nglob(compute.h_ibool); + specfem::enums::element::quadrature::static_quadrature_points<5> qp5; + + specfem::domain::domain< + specfem::enums::element::medium::elastic, + specfem::enums::element::quadrature::static_quadrature_points<5> > + elastic_domain_static(nglob, qp5, &compute, material_properties, + partial_derivatives, boundary_conditions, + compute_sources, compute_receivers, gllx, gllz); + + specfem::domain::domain< + specfem::enums::element::medium::acoustic, + specfem::enums::element::quadrature::static_quadrature_points<5> > + acoustic_domain_static(nglob, qp5, &compute, material_properties, + partial_derivatives, boundary_conditions, + compute_sources, compute_receivers, gllx, + gllz); + + // Instantiate coupled interfaces + specfem::coupled_interface::coupled_interface acoustic_elastic_interface( + acoustic_domain_static, elastic_domain_static, coupled_interfaces, + qp5, partial_derivatives, compute.ibool, gllx->get_w(), + gllz->get_w()); + + specfem::coupled_interface::coupled_interface elastic_acoustic_interface( + elastic_domain_static, acoustic_domain_static, coupled_interfaces, + qp5, partial_derivatives, compute.ibool, gllx->get_w(), + gllz->get_w()); + + specfem::solver::solver *solver = new specfem::solver::time_marching< + specfem::enums::element::quadrature::static_quadrature_points<5> >( + acoustic_domain_static, elastic_domain_static, + acoustic_elastic_interface, elastic_acoustic_interface, it); + + solver->run(); + + elastic_domain_static.sync_field(specfem::sync::DeviceToHost); + acoustic_domain_static.sync_field(specfem::sync::DeviceToHost); + + if (Test.database.elastic_domain_field != "NULL") { + specfem::kokkos::HostView2d + field_elastic = elastic_domain_static.get_host_field(); + + type_real tolerance = 0.01; + + specfem::testing::compare_norm(field_elastic, + Test.database.elastic_domain_field, + nglob, ndim, tolerance); + } + + if (Test.database.acoustic_domain_field != "NULL") { + specfem::kokkos::HostView1d + field_acoustic = Kokkos::subview( + acoustic_domain_static.get_host_field(), Kokkos::ALL(), 0); + + type_real tolerance = 0.01; + + specfem::testing::compare_norm(field_acoustic, + Test.database.acoustic_domain_field, + nglob, tolerance); + } + + std::cout << "--------------------------------------------------\n" + << "\033[0;32m[PASSED]\033[0m Test: " << Test.name << "\n" + << "--------------------------------------------------\n\n" + << std::endl; + + } catch (std::runtime_error &e) { + std::cout << " - Error: " << e.what() << std::endl; + FAIL() << "--------------------------------------------------\n" + << "\033[0;31m[FAILED]\033[0m Test failed\n" + << " - Test name: " << Test.name << "\n" + << " - Number of MPI processors: " + << Test.configuration.number_of_processors << "\n" + << " - Error: " << e.what() << "\n" + << "--------------------------------------------------\n\n" + << std::endl; + } } - - // Update solver intialization time - setup.update_t0(-1.0 * t0); - - // Instantiate the solver and timescheme - auto it = setup.instantiate_solver(); - - // User output - if (mpi->main_proc()) - std::cout << *it << std::endl; - - // Setup solver compute struct - const type_real xmax = compute.coordinates.xmax; - const type_real xmin = compute.coordinates.xmin; - const type_real zmax = compute.coordinates.zmax; - const type_real zmin = compute.coordinates.zmin; - - specfem::compute::sources compute_sources(sources, gllx, gllz, xmax, xmin, - zmax, zmin, mpi); - specfem::compute::receivers compute_receivers; - - // Instantiate domain classes - const int nglob = specfem::utilities::compute_nglob(compute.h_ibool); - specfem::Domain::Domain *domains = new specfem::Domain::Elastic( - ndim, nglob, &compute, &material_properties, &partial_derivatives, - &compute_sources, &compute_receivers, gllx, gllz); - - specfem::solver::solver *solver = - new specfem::solver::time_marching(domains, it); - - solver->run(); - - domains->sync_field(specfem::sync::DeviceToHost); - - specfem::kokkos::HostView2d field = - domains->get_host_field(); - - type_real tolerance = 0.01; - - EXPECT_NO_THROW(specfem::testing::compare_norm( - field, test_config.solutions_file, nglob, ndim, tolerance)); } int main(int argc, char *argv[]) { diff --git a/tests/unit-tests/displacement_tests/Newmark/serial/test1/database.bin b/tests/unit-tests/displacement_tests/Newmark/serial/test1/database.bin new file mode 100644 index 00000000..74013281 Binary files /dev/null and b/tests/unit-tests/displacement_tests/Newmark/serial/test1/database.bin differ diff --git a/tests/unit-tests/displacement_tests/Newmark/serial/test1/displacement.bin b/tests/unit-tests/displacement_tests/Newmark/serial/test1/displacement.bin new file mode 100644 index 00000000..7681d7b8 Binary files /dev/null and b/tests/unit-tests/displacement_tests/Newmark/serial/test1/displacement.bin differ diff --git a/tests/unit-tests/displacement_tests/Newmark/serial/test1/sources.yaml b/tests/unit-tests/displacement_tests/Newmark/serial/test1/sources.yaml new file mode 100644 index 00000000..ed49a37f --- /dev/null +++ b/tests/unit-tests/displacement_tests/Newmark/serial/test1/sources.yaml @@ -0,0 +1,12 @@ +number-of-sources: 1 +sources: + - force: + x : 2500.0 + z : 2500.0 + source_surf: false + angle : 0.0 + vx : 0.0 + vz : 0.0 + Dirac: + factor: 1e10 + tshift: 0.0 diff --git a/tests/unit-tests/displacement_tests/Newmark/serial/specfem_config.yaml b/tests/unit-tests/displacement_tests/Newmark/serial/test1/specfem_config.yaml similarity index 89% rename from tests/unit-tests/displacement_tests/Newmark/serial/specfem_config.yaml rename to tests/unit-tests/displacement_tests/Newmark/serial/test1/specfem_config.yaml index 9a4f4408..0ad3fe3d 100644 --- a/tests/unit-tests/displacement_tests/Newmark/serial/specfem_config.yaml +++ b/tests/unit-tests/displacement_tests/Newmark/serial/test1/specfem_config.yaml @@ -42,5 +42,9 @@ parameters: ## databases databases: - mesh-database: "../../../tests/unit-tests/displacement_tests/Newmark/serial/Database00000.bin" - source-file: "../../../tests/unit-tests/displacement_tests/Newmark/serial/sources.yaml" + mesh-database: "../../../tests/unit-tests/displacement_tests/Newmark/serial/test1/database.bin" + source-file: "../../../tests/unit-tests/displacement_tests/Newmark/serial/test1/sources.yaml" + + seismogram: + seismogram-format: ascii + output-folder: "." diff --git a/tests/unit-tests/displacement_tests/Newmark/serial/test2/database.bin b/tests/unit-tests/displacement_tests/Newmark/serial/test2/database.bin new file mode 100644 index 00000000..699c950e Binary files /dev/null and b/tests/unit-tests/displacement_tests/Newmark/serial/test2/database.bin differ diff --git a/tests/unit-tests/displacement_tests/Newmark/serial/test2/potential_acoustic.bin b/tests/unit-tests/displacement_tests/Newmark/serial/test2/potential_acoustic.bin new file mode 100644 index 00000000..a626c09e Binary files /dev/null and b/tests/unit-tests/displacement_tests/Newmark/serial/test2/potential_acoustic.bin differ diff --git a/tests/unit-tests/displacement_tests/Newmark/serial/test2/sources.yaml b/tests/unit-tests/displacement_tests/Newmark/serial/test2/sources.yaml new file mode 100644 index 00000000..ed49a37f --- /dev/null +++ b/tests/unit-tests/displacement_tests/Newmark/serial/test2/sources.yaml @@ -0,0 +1,12 @@ +number-of-sources: 1 +sources: + - force: + x : 2500.0 + z : 2500.0 + source_surf: false + angle : 0.0 + vx : 0.0 + vz : 0.0 + Dirac: + factor: 1e10 + tshift: 0.0 diff --git a/tests/unit-tests/displacement_tests/Newmark/serial/test2/specfem_config.yaml b/tests/unit-tests/displacement_tests/Newmark/serial/test2/specfem_config.yaml new file mode 100644 index 00000000..cee965ee --- /dev/null +++ b/tests/unit-tests/displacement_tests/Newmark/serial/test2/specfem_config.yaml @@ -0,0 +1,51 @@ +parameters: + + header: + ## Header information is used for logging. It is good practice to give your simulations explicit names + title: Isotropic Elastic simulation # name for your simulation + # A detailed description for your simulation + description: | + Material systems : Elastic domain (1) + Interfaces : None + Sources : Force source (1) + Boundary conditions : Neumann BCs on all edges + + simulation-setup: + ## quadrature setup + quadrature: + alpha: 0.0 + beta: 0.0 + ngllx: 5 + ngllz: 5 + + ## Solver setup + solver: + time-marching: + type-of-simulation: forward + time-scheme: + type: Newmark + dt: 1.1e-3 + nstep: 100 + + receivers: + stations-file: "../DATA/STATIONS" + angle: 0.0 + seismogram-type: + - displacement + - velocity + nstep_between_samples: 1 + + ## Runtime setup + run-setup: + number-of-processors: 1 + number-of-runs: 1 + + ## databases + databases: + mesh-database: "../../../tests/unit-tests/displacement_tests/Newmark/serial/test2/database.bin" + source-file: "../../../tests/unit-tests/displacement_tests/Newmark/serial/test2/sources.yaml" + + # seismogram output + seismogram: + seismogram-format: ascii + output-folder: "." diff --git a/tests/unit-tests/displacement_tests/Newmark/serial/test3/database.bin b/tests/unit-tests/displacement_tests/Newmark/serial/test3/database.bin new file mode 100644 index 00000000..7686edce Binary files /dev/null and b/tests/unit-tests/displacement_tests/Newmark/serial/test3/database.bin differ diff --git a/tests/unit-tests/displacement_tests/Newmark/serial/test3/displacement.bin b/tests/unit-tests/displacement_tests/Newmark/serial/test3/displacement.bin new file mode 100644 index 00000000..5b67dbbb Binary files /dev/null and b/tests/unit-tests/displacement_tests/Newmark/serial/test3/displacement.bin differ diff --git a/tests/unit-tests/displacement_tests/Newmark/serial/test3/potential_acoustic.bin b/tests/unit-tests/displacement_tests/Newmark/serial/test3/potential_acoustic.bin new file mode 100644 index 00000000..1b83e332 Binary files /dev/null and b/tests/unit-tests/displacement_tests/Newmark/serial/test3/potential_acoustic.bin differ diff --git a/tests/unit-tests/displacement_tests/Newmark/serial/test3/sources.yaml b/tests/unit-tests/displacement_tests/Newmark/serial/test3/sources.yaml new file mode 100644 index 00000000..6e5485ab --- /dev/null +++ b/tests/unit-tests/displacement_tests/Newmark/serial/test3/sources.yaml @@ -0,0 +1,13 @@ +number-of-sources: 1 +sources: + - force: + x : 1575.0 + z : 2420.0 + source_surf: false + angle : 0.0 + vx : 0.0 + vz : 0.0 + Ricker: + factor: 1e9 + tshift: 0.0 + f0: 10.0 diff --git a/tests/unit-tests/displacement_tests/Newmark/serial/test3/specfem_config.yaml b/tests/unit-tests/displacement_tests/Newmark/serial/test3/specfem_config.yaml new file mode 100644 index 00000000..5adebc18 --- /dev/null +++ b/tests/unit-tests/displacement_tests/Newmark/serial/test3/specfem_config.yaml @@ -0,0 +1,53 @@ +## Coupling interfaces have code flow that is dependent on orientation of the interface. +## This test is to check the code flow for horizontal acoustic-elastic interface with acoustic domain on top. + +parameters: + + header: + ## Header information is used for logging. It is good practice to give your simulations explicit names + title: Heterogeneous acoustic-elastic medium with 1 acoustic-elastic interface (orientation horizontal) # name for your simulation + # A detailed description for your simulation + description: | + Material systems : Elastic domain (1), Acoustic domain (1) + Interfaces : Acoustic-elastic interface (1) (orientation horizontal with acoustic domain on top) + Sources : Force source (1) + Boundary conditions : Neumann BCs on all edges + + simulation-setup: + ## quadrature setup + quadrature: + alpha: 0.0 + beta: 0.0 + ngllx: 5 + ngllz: 5 + + ## Solver setup + solver: + time-marching: + type-of-simulation: forward + time-scheme: + type: Newmark + dt: 1.90e-3 + nstep: 100 + + receivers: + stations-file: "../DATA/STATIONS" + angle: 0.0 + seismogram-type: + - displacement + - velocity + nstep_between_samples: 1 + + ## Runtime setup + run-setup: + number-of-processors: 1 + number-of-runs: 1 + + ## databases + databases: + mesh-database: "../../../tests/unit-tests/displacement_tests/Newmark/serial/test3/database.bin" + source-file: "../../../tests/unit-tests/displacement_tests/Newmark/serial/test3/sources.yaml" + + seismogram: + seismogram-format: ascii + output-folder: "." diff --git a/tests/unit-tests/displacement_tests/Newmark/serial/test4/database.bin b/tests/unit-tests/displacement_tests/Newmark/serial/test4/database.bin new file mode 100644 index 00000000..e73fcc60 Binary files /dev/null and b/tests/unit-tests/displacement_tests/Newmark/serial/test4/database.bin differ diff --git a/tests/unit-tests/displacement_tests/Newmark/serial/test4/displacement.bin b/tests/unit-tests/displacement_tests/Newmark/serial/test4/displacement.bin new file mode 100644 index 00000000..8a41956d Binary files /dev/null and b/tests/unit-tests/displacement_tests/Newmark/serial/test4/displacement.bin differ diff --git a/tests/unit-tests/displacement_tests/Newmark/serial/test4/potential_acoustic.bin b/tests/unit-tests/displacement_tests/Newmark/serial/test4/potential_acoustic.bin new file mode 100644 index 00000000..1dade099 Binary files /dev/null and b/tests/unit-tests/displacement_tests/Newmark/serial/test4/potential_acoustic.bin differ diff --git a/tests/unit-tests/displacement_tests/Newmark/serial/test4/sources.yaml b/tests/unit-tests/displacement_tests/Newmark/serial/test4/sources.yaml new file mode 100644 index 00000000..6e5485ab --- /dev/null +++ b/tests/unit-tests/displacement_tests/Newmark/serial/test4/sources.yaml @@ -0,0 +1,13 @@ +number-of-sources: 1 +sources: + - force: + x : 1575.0 + z : 2420.0 + source_surf: false + angle : 0.0 + vx : 0.0 + vz : 0.0 + Ricker: + factor: 1e9 + tshift: 0.0 + f0: 10.0 diff --git a/tests/unit-tests/displacement_tests/Newmark/serial/test4/specfem_config.yaml b/tests/unit-tests/displacement_tests/Newmark/serial/test4/specfem_config.yaml new file mode 100644 index 00000000..709c5432 --- /dev/null +++ b/tests/unit-tests/displacement_tests/Newmark/serial/test4/specfem_config.yaml @@ -0,0 +1,53 @@ +## Coupling interfaces have code flow that is dependent on orientation of the interface. +## This test is to check the code flow for horizontal acoustic-elastic interface with acoustic domain on bottom. + +parameters: + + header: + ## Header information is used for logging. It is good practice to give your simulations explicit names + title: Heterogeneous acoustic-elastic medium with 1 acoustic-elastic interface (orientation horizontal) # name for your simulation + # A detailed description for your simulation + description: | + Material systems : Elastic domain (1), Acoustic domain (1) + Interfaces : Acoustic-elastic interface (1) (orientation horizontal with acoustic domain on bottom) + Sources : Force source (1) + Boundary conditions : Neumann BCs on all edges + + simulation-setup: + ## quadrature setup + quadrature: + alpha: 0.0 + beta: 0.0 + ngllx: 5 + ngllz: 5 + + ## Solver setup + solver: + time-marching: + type-of-simulation: forward + time-scheme: + type: Newmark + dt: 1.90e-3 + nstep: 100 + + receivers: + stations-file: "../DATA/STATIONS" + angle: 0.0 + seismogram-type: + - displacement + - velocity + nstep_between_samples: 1 + + ## Runtime setup + run-setup: + number-of-processors: 1 + number-of-runs: 1 + + ## databases + databases: + mesh-database: "../../../tests/unit-tests/displacement_tests/Newmark/serial/test4/database.bin" + source-file: "../../../tests/unit-tests/displacement_tests/Newmark/serial/test4/sources.yaml" + + seismogram: + seismogram-format: ascii + output-folder: "." diff --git a/tests/unit-tests/displacement_tests/Newmark/serial/test5/database.bin b/tests/unit-tests/displacement_tests/Newmark/serial/test5/database.bin new file mode 100644 index 00000000..006e525f Binary files /dev/null and b/tests/unit-tests/displacement_tests/Newmark/serial/test5/database.bin differ diff --git a/tests/unit-tests/displacement_tests/Newmark/serial/test5/potential_acoustic.bin b/tests/unit-tests/displacement_tests/Newmark/serial/test5/potential_acoustic.bin new file mode 100644 index 00000000..a32768d6 Binary files /dev/null and b/tests/unit-tests/displacement_tests/Newmark/serial/test5/potential_acoustic.bin differ diff --git a/tests/unit-tests/displacement_tests/Newmark/serial/test5/sources.yaml b/tests/unit-tests/displacement_tests/Newmark/serial/test5/sources.yaml new file mode 100644 index 00000000..0c40b6cf --- /dev/null +++ b/tests/unit-tests/displacement_tests/Newmark/serial/test5/sources.yaml @@ -0,0 +1,13 @@ +number-of-sources: 1 +sources: + - force: + x : 300.0 + z : 225.0 + source_surf: false + angle : 0.0 + vx : 0.0 + vz : 0.0 + Ricker: + factor: 1e9 + tshift: 0.0 + f0: 10.0 diff --git a/tests/unit-tests/displacement_tests/Newmark/serial/test5/specfem_config.yaml b/tests/unit-tests/displacement_tests/Newmark/serial/test5/specfem_config.yaml new file mode 100644 index 00000000..40865a6b --- /dev/null +++ b/tests/unit-tests/displacement_tests/Newmark/serial/test5/specfem_config.yaml @@ -0,0 +1,51 @@ + +parameters: + + header: + ## Header information is used for logging. It is good practice to give your simulations explicit names + title: Homogeneous acoustic domain with dirichlet BCs # name for your simulation + # A detailed description for your simulation + description: | + Material systems : Acoustic domain (1) + Interfaces : None + Sources : Force source (1) + Boundary conditions : Dirichlet BCs on all edges + + simulation-setup: + ## quadrature setup + quadrature: + alpha: 0.0 + beta: 0.0 + ngllx: 5 + ngllz: 5 + + ## Solver setup + solver: + time-marching: + type-of-simulation: forward + time-scheme: + type: Newmark + dt: 1.0e-3 + nstep: 300 + + receivers: + stations-file: "../DATA/STATIONS" + angle: 0.0 + seismogram-type: + - displacement + - velocity + nstep_between_samples: 1 + + ## Runtime setup + run-setup: + number-of-processors: 1 + number-of-runs: 1 + + ## databases + databases: + mesh-database: "../../../tests/unit-tests/displacement_tests/Newmark/serial/test5/database.bin" + source-file: "../../../tests/unit-tests/displacement_tests/Newmark/serial/test5/sources.yaml" + + seismogram: + seismogram-format: ascii + output-folder: "." diff --git a/tests/unit-tests/displacement_tests/Newmark/serial/test6/database.bin b/tests/unit-tests/displacement_tests/Newmark/serial/test6/database.bin new file mode 100644 index 00000000..10fc4fba Binary files /dev/null and b/tests/unit-tests/displacement_tests/Newmark/serial/test6/database.bin differ diff --git a/tests/unit-tests/displacement_tests/Newmark/serial/test6/potential_acoustic.bin b/tests/unit-tests/displacement_tests/Newmark/serial/test6/potential_acoustic.bin new file mode 100644 index 00000000..1a4c7038 Binary files /dev/null and b/tests/unit-tests/displacement_tests/Newmark/serial/test6/potential_acoustic.bin differ diff --git a/tests/unit-tests/displacement_tests/Newmark/serial/test6/sources.yaml b/tests/unit-tests/displacement_tests/Newmark/serial/test6/sources.yaml new file mode 100644 index 00000000..7c789b6d --- /dev/null +++ b/tests/unit-tests/displacement_tests/Newmark/serial/test6/sources.yaml @@ -0,0 +1,13 @@ +number-of-sources: 1 +sources: + - force: + x : 325.0 + z : 250.0 + source_surf: false + angle : 0.0 + vx : 0.0 + vz : 0.0 + Ricker: + factor: 1e9 + tshift: 0.0 + f0: 10.0 diff --git a/tests/unit-tests/displacement_tests/Newmark/serial/test6/specfem_config.yaml b/tests/unit-tests/displacement_tests/Newmark/serial/test6/specfem_config.yaml new file mode 100644 index 00000000..504579e7 --- /dev/null +++ b/tests/unit-tests/displacement_tests/Newmark/serial/test6/specfem_config.yaml @@ -0,0 +1,51 @@ + +parameters: + + header: + ## Header information is used for logging. It is good practice to give your simulations explicit names + title: Homogeneous acoustic domain with stacey BCs # name for your simulation + # A detailed description for your simulation + description: | + Material systems : Acoustic domain (1) + Interfaces : None + Sources : Force source (1) + Boundary conditions : Stacey BCs on all edges + + simulation-setup: + ## quadrature setup + quadrature: + alpha: 0.0 + beta: 0.0 + ngllx: 5 + ngllz: 5 + + ## Solver setup + solver: + time-marching: + type-of-simulation: forward + time-scheme: + type: Newmark + dt: 1.0e-3 + nstep: 300 + + receivers: + stations-file: "../DATA/STATIONS" + angle: 0.0 + seismogram-type: + - displacement + - velocity + nstep_between_samples: 1 + + ## Runtime setup + run-setup: + number-of-processors: 1 + number-of-runs: 1 + + ## databases + databases: + mesh-database: "../../../tests/unit-tests/displacement_tests/Newmark/serial/test6/database.bin" + source-file: "../../../tests/unit-tests/displacement_tests/Newmark/serial/test6/sources.yaml" + + seismogram: + seismogram-format: ascii + output-folder: "." diff --git a/tests/unit-tests/displacement_tests/Newmark/serial/test7/database.bin b/tests/unit-tests/displacement_tests/Newmark/serial/test7/database.bin new file mode 100644 index 00000000..fa03f27a Binary files /dev/null and b/tests/unit-tests/displacement_tests/Newmark/serial/test7/database.bin differ diff --git a/tests/unit-tests/displacement_tests/Newmark/serial/test7/displacement.bin b/tests/unit-tests/displacement_tests/Newmark/serial/test7/displacement.bin new file mode 100644 index 00000000..4036ec24 Binary files /dev/null and b/tests/unit-tests/displacement_tests/Newmark/serial/test7/displacement.bin differ diff --git a/tests/unit-tests/displacement_tests/Newmark/serial/test7/sources.yaml b/tests/unit-tests/displacement_tests/Newmark/serial/test7/sources.yaml new file mode 100644 index 00000000..213f873b --- /dev/null +++ b/tests/unit-tests/displacement_tests/Newmark/serial/test7/sources.yaml @@ -0,0 +1,13 @@ +number-of-sources: 1 +sources: + - force: + x : 1000.0 + z : 850.0 + source_surf: false + angle : 0.0 + vx : 0.0 + vz : 0.0 + Ricker: + factor: 1e10 + tshift: 0.0 + f0: 10.0 diff --git a/tests/unit-tests/displacement_tests/Newmark/serial/test7/specfem_config.yaml b/tests/unit-tests/displacement_tests/Newmark/serial/test7/specfem_config.yaml new file mode 100644 index 00000000..a30facb0 --- /dev/null +++ b/tests/unit-tests/displacement_tests/Newmark/serial/test7/specfem_config.yaml @@ -0,0 +1,51 @@ + +parameters: + + header: + ## Header information is used for logging. It is good practice to give your simulations explicit names + title: Homogeneous elastic domain with stacey BCs # name for your simulation + # A detailed description for your simulation + description: | + Material systems : Elastic domain (1) + Interfaces : None + Sources : Force source (1) + Boundary conditions : Stacey BCs on all edges + + simulation-setup: + ## quadrature setup + quadrature: + alpha: 0.0 + beta: 0.0 + ngllx: 5 + ngllz: 5 + + ## Solver setup + solver: + time-marching: + type-of-simulation: forward + time-scheme: + type: Newmark + dt: 1.0e-3 + nstep: 500 + + receivers: + stations-file: "../DATA/STATIONS" + angle: 0.0 + seismogram-type: + - displacement + - velocity + nstep_between_samples: 1 + + ## Runtime setup + run-setup: + number-of-processors: 1 + number-of-runs: 1 + + ## databases + databases: + mesh-database: "../../../tests/unit-tests/displacement_tests/Newmark/serial/test7/database.bin" + source-file: "../../../tests/unit-tests/displacement_tests/Newmark/serial/test7/sources.yaml" + + seismogram: + seismogram-format: ascii + output-folder: "." diff --git a/tests/unit-tests/displacement_tests/Newmark/serial/test8/database.bin b/tests/unit-tests/displacement_tests/Newmark/serial/test8/database.bin new file mode 100644 index 00000000..f48e407d Binary files /dev/null and b/tests/unit-tests/displacement_tests/Newmark/serial/test8/database.bin differ diff --git a/tests/unit-tests/displacement_tests/Newmark/serial/test8/potential_acoustic.bin b/tests/unit-tests/displacement_tests/Newmark/serial/test8/potential_acoustic.bin new file mode 100644 index 00000000..1c5cf208 Binary files /dev/null and b/tests/unit-tests/displacement_tests/Newmark/serial/test8/potential_acoustic.bin differ diff --git a/tests/unit-tests/displacement_tests/Newmark/serial/test8/source.yaml b/tests/unit-tests/displacement_tests/Newmark/serial/test8/source.yaml new file mode 100644 index 00000000..2a40027f --- /dev/null +++ b/tests/unit-tests/displacement_tests/Newmark/serial/test8/source.yaml @@ -0,0 +1,13 @@ +number-of-sources: 1 +sources: + - force: + x : 725.0 + z : 1400.0 + source_surf: false + angle : 0.0 + vx : 0.0 + vz : 0.0 + Ricker: + factor: 1e9 + tshift: 0.0 + f0: 10.0 diff --git a/tests/unit-tests/displacement_tests/Newmark/serial/test8/specfem_config.yaml b/tests/unit-tests/displacement_tests/Newmark/serial/test8/specfem_config.yaml new file mode 100644 index 00000000..84f89b7f --- /dev/null +++ b/tests/unit-tests/displacement_tests/Newmark/serial/test8/specfem_config.yaml @@ -0,0 +1,51 @@ + +parameters: + + header: + ## Header information is used for logging. It is good practice to give your simulations explicit names + title: Homogeneous elastic domain with composite stacey dirichlet BCs # name for your simulation + # A detailed description for your simulation + description: | + Material systems : Elastic domain (1) + Interfaces : None + Sources : Force source (1) + Boundary conditions : Stacey BCs on (bottom, left, right) and Dirichlet BCs on tops + + simulation-setup: + ## quadrature setup + quadrature: + alpha: 0.0 + beta: 0.0 + ngllx: 5 + ngllz: 5 + + ## Solver setup + solver: + time-marching: + type-of-simulation: forward + time-scheme: + type: Newmark + dt: 1.65e-3 + nstep: 600 + + receivers: + stations-file: "../DATA/STATIONS" + angle: 0.0 + seismogram-type: + - displacement + - velocity + nstep_between_samples: 1 + + ## Runtime setup + run-setup: + number-of-processors: 1 + number-of-runs: 1 + + ## databases + databases: + mesh-database: "../../../tests/unit-tests/displacement_tests/Newmark/serial/test8/database.bin" + source-file: "../../../tests/unit-tests/displacement_tests/Newmark/serial/test8/source.yaml" + + seismogram: + seismogram-format: ascii + output-folder: "." diff --git a/tests/unit-tests/displacement_tests/Newmark/test_config.yaml b/tests/unit-tests/displacement_tests/Newmark/test_config.yaml index 154e7404..070c42a7 100644 --- a/tests/unit-tests/displacement_tests/Newmark/test_config.yaml +++ b/tests/unit-tests/displacement_tests/Newmark/test_config.yaml @@ -1,5 +1,74 @@ Tests: + - name : "SerialTest1 : Homogeneous elastic domain" + description: > + Testing newmark time-marching solver on a homogeneous elastic domain with no interfaces. Test is run on a single MPI process. + config: + nproc : 1 + databases: + specfem_config: "../../../tests/unit-tests/displacement_tests/Newmark/serial/test1/specfem_config.yaml" + elastic_domain_field: "../../../tests/unit-tests/displacement_tests/Newmark/serial/test1/displacement.bin" - serial: - specfem_config: "../../../tests/unit-tests/displacement_tests/Newmark/serial/specfem_config.yaml" - solutions_file: "../../../tests/unit-tests/displacement_tests/Newmark/serial/displs_00000.bin" + - name : "SerialTest2 : Homogeneous acoustic domain" + description: > + Testing newmark time-marching solver on a homogeneous acoustic domain with no interfaces. Test is run on a single MPI process. + config: + nproc : 1 + databases: + specfem_config: "../../../tests/unit-tests/displacement_tests/Newmark/serial/test2/specfem_config.yaml" + acoustic_domain_field: "../../../tests/unit-tests/displacement_tests/Newmark/serial/test2/potential_acoustic.bin" + + - name : "SerialTest3 : Acoustic-Elastic coupled domain (Test 1/2)" + description: > + Testing newmark time-marching solver on a coupled acoustic-elastic domain with 1 elastic-acoustic interface. The orientation of the interface is horizontal with acoustic domain on top. Test is run on a single MPI process. + config: + nproc : 1 + databases: + specfem_config: "../../../tests/unit-tests/displacement_tests/Newmark/serial/test3/specfem_config.yaml" + acoustic_domain_field: "../../../tests/unit-tests/displacement_tests/Newmark/serial/test3/potential_acoustic.bin" + elastic_domain_field: "../../../tests/unit-tests/displacement_tests/Newmark/serial/test3/displacement.bin" + + - name : "SerialTest4 : Acoustic-Elastic coupled domain (Test 2/2)" + description: > + Testing newmark time-marching solver on a coupled acoustic-elastic domain with 1 elastic-acoustic interface. The orientation of the interface is horizontal with acoustic domain on bottom. Test is run on a single MPI process. + config: + nproc : 1 + databases: + specfem_config: "../../../tests/unit-tests/displacement_tests/Newmark/serial/test4/specfem_config.yaml" + acoustic_domain_field: "../../../tests/unit-tests/displacement_tests/Newmark/serial/test4/potential_acoustic.bin" + elastic_domain_field: "../../../tests/unit-tests/displacement_tests/Newmark/serial/test4/displacement.bin" + + - name : "SerialTest5 : Homogeneous acoustic domain (dirichlet BC)" + description: > + Testing newmark time-marching solver on a homogeneous acoustic domain with no interfaces. Test is run on a single MPI process. Dirichlet boundary conditions are applied on all boundaries. + config: + nproc : 1 + databases: + specfem_config: "../../../tests/unit-tests/displacement_tests/Newmark/serial/test5/specfem_config.yaml" + acoustic_domain_field: "../../../tests/unit-tests/displacement_tests/Newmark/serial/test5/potential_acoustic.bin" + + - name : "SerialTest6 : Homogeneous acoustic domain (stacey BC)" + description: > + Testing newmark time-marching solver on a homogeneous acoustic domain with no interfaces. Test is run on a single MPI process. Stacey BC are applied on top/right/left/bottom boundaries. + config: + nproc : 1 + databases: + specfem_config: "../../../tests/unit-tests/displacement_tests/Newmark/serial/test6/specfem_config.yaml" + acoustic_domain_field: "../../../tests/unit-tests/displacement_tests/Newmark/serial/test6/potential_acoustic.bin" + + - name : "SerialTest7 : Homogeneous elastic domain (stacey BC)" + description: > + Testing newmark time-marching solver on a homogeneous elastic domain with no interfaces. Test is run on a single MPI process. Stacey BC are applied on top/right/left/bottom boundaries. + config: + nproc : 1 + databases: + specfem_config: "../../../tests/unit-tests/displacement_tests/Newmark/serial/test7/specfem_config.yaml" + elastic_domain_field: "../../../tests/unit-tests/displacement_tests/Newmark/serial/test7/displacement.bin" + + # - name : "SerialTest8 : Homogeneous acoustic domain (composite stacey dirichlet BC)" + # description: > + # Testing newmark time-marching solver on a homogeneous acoustic domain with no interfaces. Test is run on a single MPI process. Stacey BC are applied on (bottom, left, right) and Dirichlet BC are applied on tops. + # config: + # nproc : 1 + # databases: + # specfem_config: "../../../tests/unit-tests/displacement_tests/Newmark/serial/test8/specfem_config.yaml" + # acoustic_domain_field: "../../../tests/unit-tests/displacement_tests/Newmark/serial/test8/potential_acoustic.bin" diff --git a/tests/unit-tests/domain/acoustic/rmass_inverse_tests.cpp b/tests/unit-tests/domain/acoustic/rmass_inverse_tests.cpp new file mode 100644 index 00000000..786fa87e --- /dev/null +++ b/tests/unit-tests/domain/acoustic/rmass_inverse_tests.cpp @@ -0,0 +1,168 @@ +#include "../../Kokkos_Environment.hpp" +#include "../../MPI_environment.hpp" +#include "../../utilities/include/compare_array.h" +#include "compute/interface.hpp" +#include "constants.hpp" +#include "domain/interface.hpp" +#include "material/interface.hpp" +#include "mesh/mesh.hpp" +#include "parameter_parser/interface.hpp" +#include "quadrature/interface.hpp" +#include "yaml-cpp/yaml.h" + +// ----- Parse test config ------------- // + +struct test_config { + std::string specfem_config, solutions_file; +}; + +void operator>>(const YAML::Node &Node, test_config &test_config) { + test_config.specfem_config = Node["specfem_config"].as(); + test_config.solutions_file = Node["solutions_file"].as(); + + return; +} + +test_config parse_test_config(std::string test_configuration_file, + specfem::MPI::MPI *mpi) { + + YAML::Node yaml = YAML::LoadFile(test_configuration_file); + const YAML::Node &tests = yaml["Tests"]; + const YAML::Node &serial = tests["serial"]; + + test_config test_config; + if (mpi->get_size() == 1) { + serial >> test_config; + } + + return test_config; +} + +// ------------------------------------- // + +TEST(DOMAIN_TESTS, rmass_inverse_elastic_test) { + std::string config_filename = + "../../../tests/unit-tests/domain/acoustic/test_config.yaml"; + + specfem::MPI::MPI *mpi = MPIEnvironment::mpi_; + + test_config test_config = parse_test_config(config_filename, mpi); + + const std::string parameter_file = test_config.specfem_config; + + specfem::runtime_configuration::setup setup(parameter_file, __default_file__); + + const auto [database_file, sources_file] = setup.get_databases(); + + // Set up GLL quadrature points + auto [gllx, gllz] = setup.instantiate_quadrature(); + + // Read mesh generated MESHFEM + std::vector materials; + specfem::mesh::mesh mesh(database_file, materials, mpi); + + // Read sources + // if start time is not explicitly specified then t0 is determined using + // source frequencies and time shift + auto [sources, t0] = specfem::sources::read_sources(sources_file, 1e-5, mpi); + + // Generate compute structs to be used by the solver + specfem::compute::compute compute(mesh.coorg, mesh.material_ind.knods, gllx, + gllz); + specfem::compute::partial_derivatives partial_derivatives( + mesh.coorg, mesh.material_ind.knods, gllx, gllz); + specfem::compute::properties material_properties( + mesh.material_ind.kmato, materials, mesh.nspec, gllx->get_N(), + gllz->get_N()); + + // Set up boundary conditions + specfem::compute::boundaries boundary_conditions( + mesh.material_ind.kmato, materials, mesh.acfree_surface, + mesh.abs_boundary); + + // Locate the sources + for (auto &source : sources) + source->locate(compute.coordinates.coord, compute.h_ibool, gllx->get_hxi(), + gllz->get_hxi(), mesh.nproc, mesh.coorg, + mesh.material_ind.knods, mesh.npgeo, + material_properties.h_ispec_type, mpi); + + // User output + for (auto &source : sources) { + if (mpi->main_proc()) + std::cout << *source << std::endl; + } + + // Update solver intialization time + setup.update_t0(t0); + + // Update solver intialization time + setup.update_t0(t0); + + // Instantiate the solver and timescheme + auto it = setup.instantiate_solver(); + + // User output + if (mpi->main_proc()) + std::cout << *it << std::endl; + + // Setup solver compute struct + const type_real xmax = compute.coordinates.xmax; + const type_real xmin = compute.coordinates.xmin; + const type_real zmax = compute.coordinates.zmax; + const type_real zmin = compute.coordinates.zmin; + + specfem::compute::sources compute_sources(sources, gllx, gllz, xmax, xmin, + zmax, zmin, mpi); + specfem::compute::receivers compute_receivers; + + // Instantiate domain classes + const int nglob = specfem::utilities::compute_nglob(compute.h_ibool); + + specfem::enums::element::quadrature::static_quadrature_points<5> qp5; + specfem::domain::domain< + specfem::enums::element::medium::acoustic, + specfem::enums::element::quadrature::static_quadrature_points<5> > + acoustic_domain_static(nglob, qp5, &compute, material_properties, + partial_derivatives, boundary_conditions, + compute_sources, compute_receivers, gllx, gllz); + + acoustic_domain_static.invert_mass_matrix(); + + acoustic_domain_static.sync_rmass_inverse(specfem::sync::DeviceToHost); + + specfem::kokkos::HostView2d + h_rmass_inverse_static = acoustic_domain_static.get_host_rmass_inverse(); + + EXPECT_NO_THROW(specfem::testing::test_array( + h_rmass_inverse_static, test_config.solutions_file, nglob, 1)); + + // const int ngllx = gllx->get_N(); + // const int ngllz = gllz->get_N(); + + // specfem::enums::element::quadrature::dynamic_quadrature_points qp(ngllz, + // ngllx); + + // specfem::domain::domain< + // specfem::enums::element::medium::elastic, + // specfem::enums::element::quadrature::dynamic_quadrature_points> + // elastic_domain_dynamic(ndim, nglob, qp, &compute, material_properties, + // partial_derivatives, &compute_sources, + // &compute_receivers, gllx, gllz); + + // elastic_domain_dynamic.sync_rmass_inverse(specfem::sync::DeviceToHost); + + // specfem::kokkos::HostView2d + // h_rmass_inverse_dynamic = + // elastic_domain_dynamic.get_host_rmass_inverse(); + + // EXPECT_NO_THROW(specfem::testing::test_array( + // h_rmass_inverse_dynamic, test_config.solutions_file, nglob, ndim)); +} + +int main(int argc, char *argv[]) { + ::testing::InitGoogleTest(&argc, argv); + ::testing::AddGlobalTestEnvironment(new MPIEnvironment); + ::testing::AddGlobalTestEnvironment(new KokkosEnvironment); + return RUN_ALL_TESTS(); +} diff --git a/tests/unit-tests/domain/acoustic/test_config.yaml b/tests/unit-tests/domain/acoustic/test_config.yaml new file mode 100644 index 00000000..e3ab8e21 --- /dev/null +++ b/tests/unit-tests/domain/acoustic/test_config.yaml @@ -0,0 +1,5 @@ +Tests: + + serial: + specfem_config: "../../../tests/unit-tests/domain/acoustic/serial/specfem_config.yaml" + solutions_file: "../../../tests/unit-tests/domain/acoustic/serial/rmass_inverse_acoustic_00000.bin" diff --git a/tests/unit-tests/domain/elastic/rmass_inverse_tests.cpp b/tests/unit-tests/domain/elastic/rmass_inverse_tests.cpp new file mode 100644 index 00000000..1bc740bc --- /dev/null +++ b/tests/unit-tests/domain/elastic/rmass_inverse_tests.cpp @@ -0,0 +1,168 @@ +#include "../../Kokkos_Environment.hpp" +#include "../../MPI_environment.hpp" +#include "../../utilities/include/compare_array.h" +#include "compute/interface.hpp" +#include "constants.hpp" +#include "domain/interface.hpp" +#include "material/interface.hpp" +#include "mesh/mesh.hpp" +#include "parameter_parser/interface.hpp" +#include "quadrature/interface.hpp" +#include "yaml-cpp/yaml.h" + +// ----- Parse test config ------------- // + +struct test_config { + std::string specfem_config, solutions_file; +}; + +void operator>>(const YAML::Node &Node, test_config &test_config) { + test_config.specfem_config = Node["specfem_config"].as(); + test_config.solutions_file = Node["solutions_file"].as(); + + return; +} + +test_config parse_test_config(std::string test_configuration_file, + specfem::MPI::MPI *mpi) { + + YAML::Node yaml = YAML::LoadFile(test_configuration_file); + const YAML::Node &tests = yaml["Tests"]; + const YAML::Node &serial = tests["serial"]; + + test_config test_config; + if (mpi->get_size() == 1) { + serial >> test_config; + } + + return test_config; +} + +// ------------------------------------- // + +TEST(DOMAIN_TESTS, rmass_inverse_elastic_test) { + std::string config_filename = + "../../../tests/unit-tests/domain/elastic/test_config.yaml"; + + specfem::MPI::MPI *mpi = MPIEnvironment::mpi_; + + test_config test_config = parse_test_config(config_filename, mpi); + + const std::string parameter_file = test_config.specfem_config; + + specfem::runtime_configuration::setup setup(parameter_file, __default_file__); + + const auto [database_file, sources_file] = setup.get_databases(); + + // Set up GLL quadrature points + auto [gllx, gllz] = setup.instantiate_quadrature(); + + // Read mesh generated MESHFEM + std::vector materials; + specfem::mesh::mesh mesh(database_file, materials, mpi); + + // Read sources + // if start time is not explicitly specified then t0 is determined using + // source frequencies and time shift + auto [sources, t0] = specfem::sources::read_sources(sources_file, 1e-5, mpi); + + // Generate compute structs to be used by the solver + specfem::compute::compute compute(mesh.coorg, mesh.material_ind.knods, gllx, + gllz); + specfem::compute::partial_derivatives partial_derivatives( + mesh.coorg, mesh.material_ind.knods, gllx, gllz); + specfem::compute::properties material_properties( + mesh.material_ind.kmato, materials, mesh.nspec, gllx->get_N(), + gllz->get_N()); + + // Set up boundary conditions + specfem::compute::boundaries boundary_conditions( + mesh.material_ind.kmato, materials, mesh.acfree_surface, + mesh.abs_boundary); + + // Locate the sources + for (auto &source : sources) + source->locate(compute.coordinates.coord, compute.h_ibool, gllx->get_hxi(), + gllz->get_hxi(), mesh.nproc, mesh.coorg, + mesh.material_ind.knods, mesh.npgeo, + material_properties.h_ispec_type, mpi); + + // User output + for (auto &source : sources) { + if (mpi->main_proc()) + std::cout << *source << std::endl; + } + + // Update solver intialization time + setup.update_t0(t0); + + // Update solver intialization time + setup.update_t0(t0); + + // Instantiate the solver and timescheme + auto it = setup.instantiate_solver(); + + // User output + if (mpi->main_proc()) + std::cout << *it << std::endl; + + // Setup solver compute struct + const type_real xmax = compute.coordinates.xmax; + const type_real xmin = compute.coordinates.xmin; + const type_real zmax = compute.coordinates.zmax; + const type_real zmin = compute.coordinates.zmin; + + specfem::compute::sources compute_sources(sources, gllx, gllz, xmax, xmin, + zmax, zmin, mpi); + specfem::compute::receivers compute_receivers; + + // Instantiate domain classes + const int nglob = specfem::utilities::compute_nglob(compute.h_ibool); + + specfem::enums::element::quadrature::static_quadrature_points<5> qp5; + specfem::domain::domain< + specfem::enums::element::medium::elastic, + specfem::enums::element::quadrature::static_quadrature_points<5> > + elastic_domain_static(nglob, qp5, &compute, material_properties, + partial_derivatives, boundary_conditions, + compute_sources, compute_receivers, gllx, gllz); + + elastic_domain_static.invert_mass_matrix(); + + elastic_domain_static.sync_rmass_inverse(specfem::sync::DeviceToHost); + + specfem::kokkos::HostView2d + h_rmass_inverse_static = elastic_domain_static.get_host_rmass_inverse(); + + EXPECT_NO_THROW(specfem::testing::test_array( + h_rmass_inverse_static, test_config.solutions_file, nglob, ndim)); + + // const int ngllx = gllx->get_N(); + // const int ngllz = gllz->get_N(); + + // specfem::enums::element::quadrature::dynamic_quadrature_points qp(ngllz, + // ngllx); + + // specfem::domain::domain< + // specfem::enums::element::medium::elastic, + // specfem::enums::element::quadrature::dynamic_quadrature_points> + // elastic_domain_dynamic(ndim, nglob, qp, &compute, material_properties, + // partial_derivatives, &compute_sources, + // &compute_receivers, gllx, gllz); + + // elastic_domain_dynamic.sync_rmass_inverse(specfem::sync::DeviceToHost); + + // specfem::kokkos::HostView2d + // h_rmass_inverse_dynamic = + // elastic_domain_dynamic.get_host_rmass_inverse(); + + // EXPECT_NO_THROW(specfem::testing::test_array( + // h_rmass_inverse_dynamic, test_config.solutions_file, nglob, ndim)); +} + +int main(int argc, char *argv[]) { + ::testing::InitGoogleTest(&argc, argv); + ::testing::AddGlobalTestEnvironment(new MPIEnvironment); + ::testing::AddGlobalTestEnvironment(new KokkosEnvironment); + return RUN_ALL_TESTS(); +} diff --git a/tests/unit-tests/domain/elastic/test_config.yaml b/tests/unit-tests/domain/elastic/test_config.yaml new file mode 100644 index 00000000..606ef81b --- /dev/null +++ b/tests/unit-tests/domain/elastic/test_config.yaml @@ -0,0 +1,5 @@ +Tests: + + serial: + specfem_config: "../../../tests/unit-tests/domain/elastic/serial/specfem_config.yaml" + solutions_file: "../../../tests/unit-tests/domain/elastic/serial/rmass_inverse_elastic_00000.bin" diff --git a/tests/unit-tests/domain/rmass_inverse_tests.cpp b/tests/unit-tests/domain/rmass_inverse_tests.cpp index 0931ecf5..5fe18b3e 100644 --- a/tests/unit-tests/domain/rmass_inverse_tests.cpp +++ b/tests/unit-tests/domain/rmass_inverse_tests.cpp @@ -10,122 +10,195 @@ #include "quadrature/interface.hpp" #include "yaml-cpp/yaml.h" -// ----- Parse test config ------------- // +// ------------------------------------- // +// ------- Test configuration ----------- // + +namespace test_config { +struct database { +public: + database() + : specfem_config(""), elastic_mass_matrix("NULL"), + acoustic_mass_matrix("NULL"){}; + database(const YAML::Node &Node) { + specfem_config = Node["specfem_config"].as(); + // check if node elastic_mass_matrix exists + if (Node["elastic_mass_matrix"]) + elastic_mass_matrix = Node["elastic_mass_matrix"].as(); + + // check if node acoustic_mass_matrix exists + if (Node["acoustic_mass_matrix"]) + acoustic_mass_matrix = Node["acoustic_mass_matrix"].as(); + } + std::string specfem_config; + std::string elastic_mass_matrix = "NULL"; + std::string acoustic_mass_matrix = "NULL"; +}; -struct test_config { - std::string specfem_config, solutions_file; +struct configuration { +public: + configuration() : number_of_processors(0){}; + configuration(const YAML::Node &Node) { + number_of_processors = Node["nproc"].as(); + } + int number_of_processors; }; -void operator>>(const YAML::Node &Node, test_config &test_config) { - test_config.specfem_config = Node["specfem_config"].as(); - test_config.solutions_file = Node["solutions_file"].as(); +struct Test { +public: + Test(const YAML::Node &Node) { + name = Node["name"].as(); + description = Node["description"].as(); + YAML::Node config = Node["config"]; + configuration = test_config::configuration(config); + + YAML::Node database_node = Node["databases"]; + database = test_config::database(database_node); + return; + } - return; -} + std::string name; + std::string description; + test_config::database database; + test_config::configuration configuration; +}; +} // namespace test_config -test_config parse_test_config(std::string test_configuration_file, - specfem::MPI::MPI *mpi) { +// ------------------------------------- // + +// ----- Parse test config ------------- // - YAML::Node yaml = YAML::LoadFile(test_configuration_file); +std::vector parse_test_config(std::string test_config_file, + specfem::MPI::MPI *mpi) { + YAML::Node yaml = YAML::LoadFile(test_config_file); const YAML::Node &tests = yaml["Tests"]; - const YAML::Node &serial = tests["serial"]; - test_config test_config; - if (mpi->get_size() == 1) { - serial >> test_config; - } + assert(tests.IsSequence()); - return test_config; + std::vector test_configurations; + for (auto N : tests) + test_configurations.push_back(test_config::Test(N)); + + return test_configurations; } // ------------------------------------- // -TEST(DOMAIN_TESTS, rmass_inverse_elastic_test) { +TEST(DOMAIN_TESTS, rmass_inverse) { std::string config_filename = "../../../tests/unit-tests/domain/test_config.yaml"; specfem::MPI::MPI *mpi = MPIEnvironment::mpi_; - test_config test_config = parse_test_config(config_filename, mpi); - - const std::string parameter_file = test_config.specfem_config; - - specfem::runtime_configuration::setup setup(parameter_file, __default_file__); - - const auto [database_file, sources_file] = setup.get_databases(); - - // Set up GLL quadrature points - auto [gllx, gllz] = setup.instantiate_quadrature(); - - // Read mesh generated MESHFEM - std::vector materials; - specfem::mesh::mesh mesh(database_file, materials, mpi); - - // Read sources - // if start time is not explicitly specified then t0 is determined using - // source frequencies and time shift - auto [sources, t0] = - specfem::sources::read_sources(sources_file, setup.get_dt(), mpi); - - // Generate compute structs to be used by the solver - specfem::compute::compute compute(mesh.coorg, mesh.material_ind.knods, gllx, - gllz); - specfem::compute::partial_derivatives partial_derivatives( - mesh.coorg, mesh.material_ind.knods, gllx, gllz); - specfem::compute::properties material_properties( - mesh.material_ind.kmato, materials, mesh.nspec, gllx->get_N(), - gllz->get_N()); - - // Locate the sources - for (auto &source : sources) - source->locate(compute.coordinates.coord, compute.h_ibool, gllx->get_hxi(), - gllz->get_hxi(), mesh.nproc, mesh.coorg, - mesh.material_ind.knods, mesh.npgeo, - material_properties.h_ispec_type, mpi); - - // User output - for (auto &source : sources) { - if (mpi->main_proc()) - std::cout << *source << std::endl; + auto Tests = parse_test_config(config_filename, mpi); + + for (auto &Test : Tests) { + std::cout << "-------------------------------------------------------\n" + << "\033[0;32m[RUNNING]\033[0m Test: " << Test.name << "\n" + << "-------------------------------------------------------\n\n" + << std::endl; + + const auto parameter_file = Test.database.specfem_config; + + specfem::runtime_configuration::setup setup(parameter_file, + __default_file__); + + const auto [database_file, sources_file] = setup.get_databases(); + + // Set up GLL quadrature points + auto [gllx, gllz] = setup.instantiate_quadrature(); + + // Read mesh generated MESHFEM + std::vector materials; + specfem::mesh::mesh mesh(database_file, materials, mpi); + + // Generate compute structs to be used by the solver + specfem::compute::compute compute(mesh.coorg, mesh.material_ind.knods, gllx, + gllz); + specfem::compute::partial_derivatives partial_derivatives( + mesh.coorg, mesh.material_ind.knods, gllx, gllz); + specfem::compute::properties material_properties( + mesh.material_ind.kmato, materials, mesh.nspec, gllx->get_N(), + gllz->get_N()); + specfem::compute::boundaries boundary_conditions( + mesh.material_ind.kmato, materials, mesh.acfree_surface, + mesh.abs_boundary); + + try { + + const int nglob = specfem::utilities::compute_nglob(compute.h_ibool); + specfem::enums::element::quadrature::static_quadrature_points<5> qp5; + + specfem::domain::domain< + specfem::enums::element::medium::elastic, + specfem::enums::element::quadrature::static_quadrature_points<5> > + elastic_domain_static(nglob, qp5, &compute, material_properties, + partial_derivatives, boundary_conditions, + specfem::compute::sources(), + specfem::compute::receivers(), gllx, gllz); + + specfem::domain::domain< + specfem::enums::element::medium::acoustic, + specfem::enums::element::quadrature::static_quadrature_points<5> > + acoustic_domain_static(nglob, qp5, &compute, material_properties, + partial_derivatives, boundary_conditions, + specfem::compute::sources(), + specfem::compute::receivers(), gllx, gllz); + + elastic_domain_static.template mass_time_contribution< + specfem::enums::time_scheme::type::newmark>(setup.get_dt()); + acoustic_domain_static.template mass_time_contribution< + specfem::enums::time_scheme::type::newmark>(setup.get_dt()); + + elastic_domain_static.invert_mass_matrix(); + acoustic_domain_static.invert_mass_matrix(); + + elastic_domain_static.sync_rmass_inverse(specfem::sync::DeviceToHost); + acoustic_domain_static.sync_rmass_inverse(specfem::sync::DeviceToHost); + + if (Test.database.elastic_mass_matrix != "NULL") { + specfem::kokkos::HostView2d + h_rmass_inverse_static = + elastic_domain_static.get_host_rmass_inverse(); + + type_real tolerance = 1e-5; + + specfem::testing::compare_norm(h_rmass_inverse_static, + Test.database.elastic_mass_matrix, nglob, + ndim, tolerance); + } + + if (Test.database.acoustic_mass_matrix != "NULL") { + specfem::kokkos::HostView1d + h_rmass_inverse_static = + Kokkos::subview(acoustic_domain_static.get_host_rmass_inverse(), + Kokkos::ALL(), 0); + + type_real tolerance = 1e-5; + + specfem::testing::compare_norm(h_rmass_inverse_static, + Test.database.acoustic_mass_matrix, + nglob, tolerance); + } + + std::cout << "--------------------------------------------------\n" + << "\033[0;32m[PASSED]\033[0m Test: " << Test.name << "\n" + << "--------------------------------------------------\n\n" + << std::endl; + + } catch (const std::exception &e) { + std::cout << " - Error: " << e.what() << std::endl; + FAIL() << "--------------------------------------------------\n" + << "\033[0;31m[FAILED]\033[0m Test failed\n" + << " - Test name: " << Test.name << "\n" + << " - Number of MPI processors: " + << Test.configuration.number_of_processors << "\n" + << " - Error: " << e.what() << "\n" + << "--------------------------------------------------\n\n" + << std::endl; + } } - // Update solver intialization time - setup.update_t0(t0); - - // Update solver intialization time - setup.update_t0(t0); - - // Instantiate the solver and timescheme - auto it = setup.instantiate_solver(); - - // User output - if (mpi->main_proc()) - std::cout << *it << std::endl; - - // Setup solver compute struct - const type_real xmax = compute.coordinates.xmax; - const type_real xmin = compute.coordinates.xmin; - const type_real zmax = compute.coordinates.zmax; - const type_real zmin = compute.coordinates.zmin; - - specfem::compute::sources compute_sources(sources, gllx, gllz, xmax, xmin, - zmax, zmin, mpi); - specfem::compute::receivers compute_receivers; - - // Instantiate domain classes - const int nglob = specfem::utilities::compute_nglob(compute.h_ibool); - - specfem::Domain::Domain *domains = new specfem::Domain::Elastic( - ndim, nglob, &compute, &material_properties, &partial_derivatives, - &compute_sources, &compute_receivers, gllx, gllz); - - domains->sync_rmass_inverse(specfem::sync::DeviceToHost); - - specfem::kokkos::HostView2d h_rmass_inverse = - domains->get_host_rmass_inverse(); - - EXPECT_NO_THROW(specfem::testing::test_array( - h_rmass_inverse, test_config.solutions_file, nglob, ndim)); + return; } int main(int argc, char *argv[]) { diff --git a/tests/unit-tests/domain/serial/data/Database00000.bin b/tests/unit-tests/domain/serial/test1/database.bin similarity index 100% rename from tests/unit-tests/domain/serial/data/Database00000.bin rename to tests/unit-tests/domain/serial/test1/database.bin diff --git a/tests/unit-tests/domain/serial/data/rmass_inverse_elastic_00000.bin b/tests/unit-tests/domain/serial/test1/rmass_inverse_elastic.bin similarity index 100% rename from tests/unit-tests/domain/serial/data/rmass_inverse_elastic_00000.bin rename to tests/unit-tests/domain/serial/test1/rmass_inverse_elastic.bin diff --git a/tests/unit-tests/domain/serial/data/source.yaml b/tests/unit-tests/domain/serial/test1/source.yaml similarity index 100% rename from tests/unit-tests/domain/serial/data/source.yaml rename to tests/unit-tests/domain/serial/test1/source.yaml diff --git a/tests/unit-tests/domain/serial/data/specfem_config.yaml b/tests/unit-tests/domain/serial/test1/specfem_config.yaml similarity index 78% rename from tests/unit-tests/domain/serial/data/specfem_config.yaml rename to tests/unit-tests/domain/serial/test1/specfem_config.yaml index eccf3dbc..2321df77 100644 --- a/tests/unit-tests/domain/serial/data/specfem_config.yaml +++ b/tests/unit-tests/domain/serial/test1/specfem_config.yaml @@ -36,5 +36,9 @@ parameters: number-of-runs: 1 databases: - mesh-database: "../../../tests/unit-tests/domain/serial/data/Database00000.bin" - source-file: "../../../tests/unit-tests/domain/serial/data/source.yaml" + mesh-database: "../../../tests/unit-tests/domain/serial/test1/database.bin" + source-file: "../../../tests/unit-tests/domain/serial/test1/source.yaml" + + seismogram: + seismogram-format: ascii + output-folder: "." diff --git a/tests/unit-tests/domain/serial/test2/database.bin b/tests/unit-tests/domain/serial/test2/database.bin new file mode 100644 index 00000000..699c950e Binary files /dev/null and b/tests/unit-tests/domain/serial/test2/database.bin differ diff --git a/tests/unit-tests/domain/serial/test2/rmass_inverse_acoustic.bin b/tests/unit-tests/domain/serial/test2/rmass_inverse_acoustic.bin new file mode 100644 index 00000000..ec4f8bed Binary files /dev/null and b/tests/unit-tests/domain/serial/test2/rmass_inverse_acoustic.bin differ diff --git a/tests/unit-tests/domain/serial/test2/source.yaml b/tests/unit-tests/domain/serial/test2/source.yaml new file mode 100644 index 00000000..ed49a37f --- /dev/null +++ b/tests/unit-tests/domain/serial/test2/source.yaml @@ -0,0 +1,12 @@ +number-of-sources: 1 +sources: + - force: + x : 2500.0 + z : 2500.0 + source_surf: false + angle : 0.0 + vx : 0.0 + vz : 0.0 + Dirac: + factor: 1e10 + tshift: 0.0 diff --git a/tests/unit-tests/domain/serial/test2/specfem_config.yaml b/tests/unit-tests/domain/serial/test2/specfem_config.yaml new file mode 100644 index 00000000..0b188262 --- /dev/null +++ b/tests/unit-tests/domain/serial/test2/specfem_config.yaml @@ -0,0 +1,44 @@ +parameters: + + header: + ## Header information is used for logging. It is good practice to give your simulations explicit names + title: Elastic simulation # name for your simulation + description: None # A detailed description for your simulation + + simulation-setup: + ## quadrature setup + quadrature: + alpha: 0.0 + beta: 0.0 + ngllx: 5 + ngllz: 5 + + ## Solver setup + solver: + time-marching: + type-of-simulation: forward + time-scheme: + type: Newmark + dt: 1e-3 + nstep: 1600 + + receivers: + stations-file: "../DATA/STATIONS" + angle: 0.0 + seismogram-type: + - displacement + - velocity + nstep_between_samples: 1 + + ## Runtime setup + run-setup: + number-of-processors: 1 + number-of-runs: 1 + + databases: + mesh-database: "../../../tests/unit-tests/domain/serial/test2/database.bin" + source-file: "../../../tests/unit-tests/domain/serial/test2/source.yaml" + + seismogram: + seismogram-format: ascii + output-folder: "." diff --git a/tests/unit-tests/domain/serial/test3/database.bin b/tests/unit-tests/domain/serial/test3/database.bin new file mode 100644 index 00000000..0daa2adb Binary files /dev/null and b/tests/unit-tests/domain/serial/test3/database.bin differ diff --git a/tests/unit-tests/domain/serial/test3/rmass_inverse_acoustic.bin b/tests/unit-tests/domain/serial/test3/rmass_inverse_acoustic.bin new file mode 100644 index 00000000..5e96c199 Binary files /dev/null and b/tests/unit-tests/domain/serial/test3/rmass_inverse_acoustic.bin differ diff --git a/tests/unit-tests/domain/serial/test3/source.yaml b/tests/unit-tests/domain/serial/test3/source.yaml new file mode 100644 index 00000000..4718d6e6 --- /dev/null +++ b/tests/unit-tests/domain/serial/test3/source.yaml @@ -0,0 +1,12 @@ +number-of-sources: 1 +sources: + - force: + x : 1575.0 + z : 2900.0 + source_surf: false + angle : 0.0 + vx : 0.0 + vz : 0.0 + Dirac: + factor: 1e10 + tshift: 0.0 diff --git a/tests/unit-tests/domain/serial/test3/specfem_config.yaml b/tests/unit-tests/domain/serial/test3/specfem_config.yaml new file mode 100644 index 00000000..e05a2bbf --- /dev/null +++ b/tests/unit-tests/domain/serial/test3/specfem_config.yaml @@ -0,0 +1,44 @@ +parameters: + + header: + ## Header information is used for logging. It is good practice to give your simulations explicit names + title: Elastic simulation # name for your simulation + description: None # A detailed description for your simulation + + simulation-setup: + ## quadrature setup + quadrature: + alpha: 0.0 + beta: 0.0 + ngllx: 5 + ngllz: 5 + + ## Solver setup + solver: + time-marching: + type-of-simulation: forward + time-scheme: + type: Newmark + dt: 0.85e-3 + nstep: 4500 + + receivers: + stations-file: "../DATA/STATIONS" + angle: 0.0 + seismogram-type: + - displacement + - velocity + nstep_between_samples: 1 + + ## Runtime setup + run-setup: + number-of-processors: 1 + number-of-runs: 1 + + databases: + mesh-database: "../../../tests/unit-tests/domain/serial/test3/database.bin" + source-file: "../../../tests/unit-tests/domain/serial/test3/source.yaml" + + seismogram: + seismogram-format: ascii + output-folder: "." diff --git a/tests/unit-tests/domain/serial/test4/database.bin b/tests/unit-tests/domain/serial/test4/database.bin new file mode 100644 index 00000000..6cea7b06 Binary files /dev/null and b/tests/unit-tests/domain/serial/test4/database.bin differ diff --git a/tests/unit-tests/domain/serial/test4/rmass_inverse_elastic.bin b/tests/unit-tests/domain/serial/test4/rmass_inverse_elastic.bin new file mode 100644 index 00000000..c6508676 Binary files /dev/null and b/tests/unit-tests/domain/serial/test4/rmass_inverse_elastic.bin differ diff --git a/tests/unit-tests/domain/serial/test4/source.yaml b/tests/unit-tests/domain/serial/test4/source.yaml new file mode 100644 index 00000000..ed49a37f --- /dev/null +++ b/tests/unit-tests/domain/serial/test4/source.yaml @@ -0,0 +1,12 @@ +number-of-sources: 1 +sources: + - force: + x : 2500.0 + z : 2500.0 + source_surf: false + angle : 0.0 + vx : 0.0 + vz : 0.0 + Dirac: + factor: 1e10 + tshift: 0.0 diff --git a/tests/unit-tests/domain/serial/test4/specfem_config.yaml b/tests/unit-tests/domain/serial/test4/specfem_config.yaml new file mode 100644 index 00000000..25056713 --- /dev/null +++ b/tests/unit-tests/domain/serial/test4/specfem_config.yaml @@ -0,0 +1,44 @@ +parameters: + + header: + ## Header information is used for logging. It is good practice to give your simulations explicit names + title: Elastic simulation # name for your simulation + description: None # A detailed description for your simulation + + simulation-setup: + ## quadrature setup + quadrature: + alpha: 0.0 + beta: 0.0 + ngllx: 5 + ngllz: 5 + + ## Solver setup + solver: + time-marching: + type-of-simulation: forward + time-scheme: + type: Newmark + dt: 0.85e-3 + nstep: 800 + + receivers: + stations-file: "../DATA/STATIONS" + angle: 0.0 + seismogram-type: + - displacement + - velocity + nstep_between_samples: 1 + + ## Runtime setup + run-setup: + number-of-processors: 1 + number-of-runs: 1 + + databases: + mesh-database: "../../../tests/unit-tests/domain/serial/test4/database.bin" + source-file: "../../../tests/unit-tests/domain/serial/test4/source.yaml" + + seismogram: + seismogram-format: ascii + output-folder: "." diff --git a/tests/unit-tests/domain/test_config.yaml b/tests/unit-tests/domain/test_config.yaml index 5db50c56..e1122c5d 100644 --- a/tests/unit-tests/domain/test_config.yaml +++ b/tests/unit-tests/domain/test_config.yaml @@ -1,5 +1,36 @@ Tests: + - name : "SerialTest1 : Homogeneous elastic domain" + description: > + Testing inverse of mass matrix for homogeneous elastic domain with no interfaces. Test is run on a single MPI process. + config: + nproc : 1 + databases: + specfem_config: "../../../tests/unit-tests/domain/serial/test1/specfem_config.yaml" + elastic_domain_field: "../../../tests/unit-tests/domain/serial/test1/displacement.bin" - serial: - specfem_config: "../../../tests/unit-tests/domain/serial/data/specfem_config.yaml" - solutions_file: "../../../tests/unit-tests/domain/serial/data/rmass_inverse_elastic_00000.bin" + - name : "SerialTest2 : Homogeneous acoustic domain" + description: > + Testing inverse of mass matrix on a homogeneous acoustic domain with no interfaces. Test is run on a single MPI process. + config: + nproc : 1 + databases: + specfem_config: "../../../tests/unit-tests/domain/serial/test2/specfem_config.yaml" + acoustic_domain_field: "../../../tests/unit-tests/domain/serial/test2/potential_acoustic.bin" + + - name : "SerialTest3 : Homogeneous acoustic domain (stacey BC)" + description: > + Testing inverse of mass matrix on a homogeneous acoustic domain with no interfaces. Test is run on a single MPI process. Stacey BC are applied on top/right/left/bottom boundaries. + config: + nproc : 1 + databases: + specfem_config: "../../../tests/unit-tests/domain/serial/test3/specfem_config.yaml" + acoustic_domain_field: "../../../tests/unit-tests/domain/serial/test3/potential_acoustic.bin" + + - name : "SerialTest4 : Homogeneous elastic domain (stacey BC)" + description: > + Testing inverse of mass matrix on a homogeneous elastic domain with no interfaces. Test is run on a single MPI process. Stacey BC are applied on top/right/left/bottom boundaries. + config: + nproc : 1 + databases: + specfem_config: "../../../tests/unit-tests/domain/serial/test4/specfem_config.yaml" + elastic_domain_field: "../../../tests/unit-tests/domain/serial/test4/displacement.bin" diff --git a/tests/unit-tests/mesh/mesh_tests.cpp b/tests/unit-tests/mesh/mesh_tests.cpp index 16b84c9e..b39d6fa3 100644 --- a/tests/unit-tests/mesh/mesh_tests.cpp +++ b/tests/unit-tests/mesh/mesh_tests.cpp @@ -8,42 +8,75 @@ #include // ------------------------------------------------------------------------ -// Reading test config -struct test_config { - std::string database_filename; +// Test configuration +namespace test_configuration { +struct configuration { +public: + int processors; }; -void operator>>(YAML::Node &Node, test_config &test_config) { - test_config.database_filename = Node["database_file"].as(); +void operator>>(YAML::Node &Node, configuration &configuration) { + configuration.processors = Node["nproc"].as(); return; } -test_config get_test_config(std::string config_filename, - specfem::MPI::MPI *mpi) { - // read test config file - YAML::Node yaml = YAML::LoadFile(config_filename); - test_config test_config{}; - if (mpi->get_size() == 1) { - YAML::Node Node = yaml["SerialTest"]; - YAML::Node database = Node["database"]; +struct databases { +public: + databases() : processors(0){}; + databases(const int &nproc) : processors(nproc), filenames(nproc){}; + + void append(const YAML::Node &Node) { + filenames[Node["processor"].as()] = Node["filename"].as(); + } + int processors; + std::vector filenames; +}; + +struct Test { +public: + Test(const YAML::Node &Node) { + name = Node["name"].as(); + description = Node["description"].as(); + YAML::Node config = Node["config"]; + config >> configuration; + YAML::Node database = Node["databases"]; + assert(database.IsSequence()); - assert(database.size() == 1); + assert(database.size() == configuration.processors); + + databases = test_configuration::databases(configuration.processors); + + assert(databases.filenames.size() == configuration.processors); + for (auto N : database) - N >> test_config; - } else { - YAML::Node Node = yaml["ParallelTest"]; - YAML::Node database = Node["database"]; - assert(database.IsSequence()); - assert(database.size() == Node["config"]["nproc"].as()); - assert(mpi->get_size() == Node["config"]["nproc"].as()); - for (auto N : database) { - if (N["processor"].as() == mpi->get_rank()) - N >> test_config; - } + databases.append(N); + + assert(databases.filenames.size() == configuration.processors); + + return; } - return test_config; + std::string name; + std::string description; + test_configuration::databases databases; + test_configuration::configuration configuration; +}; +} // namespace test_configuration + +// ------------------------------------------------------------------------ +// Reading test config + +void parse_test_config(const YAML::Node &yaml, + std::vector &tests) { + YAML::Node all_tests = yaml["Tests"]; + assert(all_tests.IsSequence()); + + for (auto N : all_tests) + tests.push_back(test_configuration::Test(N)); + + return; } + // --------------------------------------------------------------------------- /** @@ -57,12 +90,28 @@ TEST(MESH_TESTS, fortran_binary_reader) { std::string config_filename = "../../../tests/unit-tests/mesh/test_config.yaml"; - test_config test_config = - get_test_config(config_filename, MPIEnvironment::mpi_); + std::vector tests; + parse_test_config(YAML::LoadFile(config_filename), tests); - std::vector materials; - EXPECT_NO_THROW(specfem::mesh::mesh mesh(test_config.database_filename, - materials, MPIEnvironment::mpi_)); + for (auto test : tests) { + std::vector materials; + std::cout << "Executing test: " << test.description << std::endl; + try { + specfem::mesh::mesh mesh( + test.databases.filenames[test.configuration.processors - 1], + materials, MPIEnvironment::mpi_); + std::cout << " - Test passed\n" << std::endl; + } catch (std::runtime_error &e) { + std::cout << " - Error: " << e.what() << std::endl; + FAIL() << " Test failed\n" + << " - Test name: " << test.name << "\n" + << " - Number of MPI processors: " << test.configuration.processors + << "\n" + << " - Error: " << e.what() << std::endl; + } + } + SUCCEED(); + return; } int main(int argc, char *argv[]) { diff --git a/tests/unit-tests/mesh/serial/test1/database.bin b/tests/unit-tests/mesh/serial/test1/database.bin new file mode 100644 index 00000000..83aa4900 Binary files /dev/null and b/tests/unit-tests/mesh/serial/test1/database.bin differ diff --git a/tests/unit-tests/mesh/serial/test2/database.bin b/tests/unit-tests/mesh/serial/test2/database.bin new file mode 100644 index 00000000..4c7ee7b5 Binary files /dev/null and b/tests/unit-tests/mesh/serial/test2/database.bin differ diff --git a/tests/unit-tests/mesh/serial/database.bin b/tests/unit-tests/mesh/serial/test3/database.bin similarity index 100% rename from tests/unit-tests/mesh/serial/database.bin rename to tests/unit-tests/mesh/serial/test3/database.bin diff --git a/tests/unit-tests/mesh/test_config.yaml b/tests/unit-tests/mesh/test_config.yaml index a67bc930..0b33bd80 100644 --- a/tests/unit-tests/mesh/test_config.yaml +++ b/tests/unit-tests/mesh/test_config.yaml @@ -1,30 +1,28 @@ -SerialTest: - config: - nproc : 1 - database: - - processor : 0 - database_file : "../../../tests/unit-tests/mesh/serial/database.bin" -ParallelTest: - config: - nproc : 10 - database: - - processor : 0 - database_file : "../../../tests/unit-tests/mesh/parallel/Database00000.bin" - - processor : 1 - database_file : "../../../tests/unit-tests/mesh/parallel/Database00001.bin" - - processor : 2 - database_file : "../../../tests/unit-tests/mesh/parallel/Database00002.bin" - - processor : 3 - database_file : "../../../tests/unit-tests/mesh/parallel/Database00003.bin" - - processor : 4 - database_file : "../../../tests/unit-tests/mesh/parallel/Database00004.bin" - - processor : 5 - database_file : "../../../tests/unit-tests/mesh/parallel/Database00005.bin" - - processor : 6 - database_file : "../../../tests/unit-tests/mesh/parallel/Database00006.bin" - - processor : 7 - database_file : "../../../tests/unit-tests/mesh/parallel/Database00007.bin" - - processor : 8 - database_file : "../../../tests/unit-tests/mesh/parallel/Database00008.bin" - - processor : 9 - database_file : "../../../tests/unit-tests/mesh/parallel/Database00009.bin" +Tests: + # Test 1: + - name : "SerialTest1 : Homogeneous elastic domain" + description: > + Serial mesh IO test. Homogeneous elastic domain. + config: + nproc : 1 + databases: + - processor : 0 + filename : "../../../tests/unit-tests/mesh/serial/test1/database.bin" + # Test 2: + - name : "SerialTest2 : Homogeneous acoustic domain" + description: > + Serial mesh IO test. Homogeneous acoustic domain. + config: + nproc : 1 + databases: + - processor : 0 + filename : "../../../tests/unit-tests/mesh/serial/test2/database.bin" + # Test 3: + - name : "SerialTest3 : Heterogeneous elastic acoustic domain" + description: > + Serial mesh IO test. Heterogeneous elastic acoustic domain. + config: + nproc : 1 + databases: + - processor : 0 + filename : "../../../tests/unit-tests/mesh/serial/test3/database.bin" diff --git a/tests/unit-tests/seismogram/acoustic/seismogram_tests.cpp b/tests/unit-tests/seismogram/acoustic/seismogram_tests.cpp new file mode 100644 index 00000000..ae4839a1 --- /dev/null +++ b/tests/unit-tests/seismogram/acoustic/seismogram_tests.cpp @@ -0,0 +1,198 @@ +#include "../../Kokkos_Environment.hpp" +#include "../../MPI_environment.hpp" +#include "../../utilities/include/compare_array.h" +#include "compute/interface.hpp" +#include "constants.hpp" +#include "domain/interface.hpp" +#include "material/interface.hpp" +#include "mesh/mesh.hpp" +#include "parameter_parser/interface.hpp" +#include "quadrature/interface.hpp" +#include "receiver/interface.hpp" +#include "solver/interface.hpp" +#include "timescheme/interface.hpp" +#include "yaml-cpp/yaml.h" + +// ----- Parse test config ------------- // + +struct test_config { + std::string specfem_config, displacement_field, velocity_field, + acceleration_field; +}; + +void operator>>(const YAML::Node &Node, test_config &test_config) { + test_config.specfem_config = Node["specfem_config"].as(); + test_config.displacement_field = Node["displacement_field"].as(); + test_config.velocity_field = Node["velocity_field"].as(); + test_config.acceleration_field = Node["acceleration_field"].as(); + + return; +} + +test_config parse_test_config(std::string test_configuration_file, + specfem::MPI::MPI *mpi) { + + YAML::Node yaml = YAML::LoadFile(test_configuration_file); + const YAML::Node &tests = yaml["Tests"]; + const YAML::Node &serial = tests["serial"]; + + test_config test_config; + if (mpi->get_size() == 1) { + serial >> test_config; + } + + return test_config; +} + +// ------------------------------------- // + +// read field from fortran binary file +void read_field( + const std::string filename, + specfem::kokkos::HostMirror2d field, + const int n1, const int n2) { + + assert(field.extent(0) == n1); + assert(field.extent(1) == n2); + + std::ifstream stream; + stream.open(filename); + + type_real ref_value; + for (int i1 = 0; i1 < n1; i1++) { + for (int i2 = 0; i2 < n2; i2++) { + specfem::fortran_IO::fortran_read_line(stream, &ref_value); + field(i1, i2) = ref_value; + } + } + + stream.close(); + + return; +} + +TEST(SEISMOGRAM_TESTS, elastic_seismograms_test) { + std::string config_filename = + "../../../tests/unit-tests/seismogram/acoustic/test_config.yaml"; + + specfem::MPI::MPI *mpi = MPIEnvironment::mpi_; + + test_config test_config = parse_test_config(config_filename, mpi); + + const std::string parameter_file = test_config.specfem_config; + + specfem::runtime_configuration::setup setup(parameter_file, __default_file__); + + const auto [database_file, sources_file] = setup.get_databases(); + // mpi->cout(setup.print_header()); + + // Set up GLL quadrature points + auto [gllx, gllz] = setup.instantiate_quadrature(); + + const auto angle = setup.get_receiver_angle(); + const auto stations_filename = setup.get_stations_file(); + auto receivers = specfem::receivers::read_receivers(stations_filename, angle); + + // Read mesh generated MESHFEM + std::vector materials; + specfem::mesh::mesh mesh(database_file, materials, mpi); + + // Generate compute structs to be used by the solver + specfem::compute::compute compute(mesh.coorg, mesh.material_ind.knods, gllx, + gllz); + specfem::compute::partial_derivatives partial_derivatives( + mesh.coorg, mesh.material_ind.knods, gllx, gllz); + specfem::compute::properties material_properties( + mesh.material_ind.kmato, materials, mesh.nspec, gllx->get_N(), + gllz->get_N()); + + specfem::compute::boundaries boundary_conditions( + mesh.material_ind.kmato, materials, mesh.acfree_surface, + mesh.abs_boundary); + + // locate the recievers + for (auto &receiver : receivers) + receiver->locate(compute.coordinates.coord, compute.h_ibool, + gllx->get_hxi(), gllz->get_hxi(), mesh.nproc, mesh.coorg, + mesh.material_ind.knods, mesh.npgeo, + material_properties.h_ispec_type, mpi); + + // Setup solver compute struct + + const type_real xmax = compute.coordinates.xmax; + const type_real xmin = compute.coordinates.xmin; + const type_real zmax = compute.coordinates.zmax; + const type_real zmin = compute.coordinates.zmin; + + const auto stypes = setup.get_seismogram_types(); + + specfem::compute::receivers compute_receivers(receivers, stypes, gllx, gllz, + xmax, xmin, zmax, zmin, 1, mpi); + + const int nglob = specfem::utilities::compute_nglob(compute.h_ibool); + specfem::enums::element::quadrature::static_quadrature_points<5> qp5; + specfem::domain::domain< + specfem::enums::element::medium::acoustic, + specfem::enums::element::quadrature::static_quadrature_points<5> > + acoustic_domain_static(nglob, qp5, &compute, material_properties, + partial_derivatives, boundary_conditions, + specfem::compute::sources(), compute_receivers, + gllx, gllz); + + const auto displacement_field = acoustic_domain_static.get_host_field(); + const auto velocity_field = acoustic_domain_static.get_host_field_dot(); + const auto acceleration_field = + acoustic_domain_static.get_host_field_dot_dot(); + + read_field(test_config.displacement_field, displacement_field, nglob, 1); + read_field(test_config.velocity_field, velocity_field, nglob, 1); + read_field(test_config.acceleration_field, acceleration_field, nglob, 1); + + acoustic_domain_static.sync_field(specfem::sync::HostToDevice); + acoustic_domain_static.sync_field_dot(specfem::sync::HostToDevice); + acoustic_domain_static.sync_field_dot_dot(specfem::sync::HostToDevice); + + acoustic_domain_static.compute_seismogram(0); + + compute_receivers.sync_seismograms(); + + type_real tol = 1e-5; + + std::vector ground_truth = { + 0.0000000000000000, -3.0960039922602422E-011, + 0.0000000000000000, -8.3379189277645219E-011, + 4.4439509143591454E-010, 1.8368718019109921E-010, + -3.8585618629325063E-010, 2.5444961269509465E-010, + 0.0000000000000000, 7.1296417833791251E-008, + 0.0000000000000000, 2.4165936811725470E-008, + 5.6330467200175704E-007, 3.5364862913830020E-007, + -9.3482598617042963E-008, -3.6004231966844085E-007, + 0.0000000000000000, 2.0541840830987639E-005, + 0.0000000000000000, 9.0448554680095616E-006, + -3.3644759982233034E-004, -3.5943211587533610E-004, + 3.1162494730438027E-004, -2.9608074956535943E-004 + }; + + int index = 0; + + for (int isys = 0; isys < stypes.size(); isys++) { + for (int irec = 0; irec < receivers.size(); irec++) { + for (int idim = 0; idim < 2; idim++) { + EXPECT_NEAR(compute_receivers.h_seismogram(0, isys, irec, idim), + ground_truth[index], std::fabs(tol * ground_truth[index])); + index++; + } + } + } + + assert(index == ground_truth.size()); + + return; +} + +int main(int argc, char *argv[]) { + ::testing::InitGoogleTest(&argc, argv); + ::testing::AddGlobalTestEnvironment(new MPIEnvironment); + ::testing::AddGlobalTestEnvironment(new KokkosEnvironment); + return RUN_ALL_TESTS(); +} diff --git a/tests/unit-tests/seismogram/serial/STATIONS b/tests/unit-tests/seismogram/acoustic/serial/STATIONS similarity index 100% rename from tests/unit-tests/seismogram/serial/STATIONS rename to tests/unit-tests/seismogram/acoustic/serial/STATIONS diff --git a/tests/unit-tests/seismogram/acoustic/serial/database.bin b/tests/unit-tests/seismogram/acoustic/serial/database.bin new file mode 100644 index 00000000..699c950e Binary files /dev/null and b/tests/unit-tests/seismogram/acoustic/serial/database.bin differ diff --git a/tests/unit-tests/seismogram/acoustic/serial/potential_acoustic_00000.bin b/tests/unit-tests/seismogram/acoustic/serial/potential_acoustic_00000.bin new file mode 100644 index 00000000..ae7df968 Binary files /dev/null and b/tests/unit-tests/seismogram/acoustic/serial/potential_acoustic_00000.bin differ diff --git a/tests/unit-tests/seismogram/acoustic/serial/potential_acoustic_dot_00000.bin b/tests/unit-tests/seismogram/acoustic/serial/potential_acoustic_dot_00000.bin new file mode 100644 index 00000000..b034c40f Binary files /dev/null and b/tests/unit-tests/seismogram/acoustic/serial/potential_acoustic_dot_00000.bin differ diff --git a/tests/unit-tests/seismogram/acoustic/serial/potential_acoustic_dot_dot_00000.bin b/tests/unit-tests/seismogram/acoustic/serial/potential_acoustic_dot_dot_00000.bin new file mode 100644 index 00000000..6bf441a2 Binary files /dev/null and b/tests/unit-tests/seismogram/acoustic/serial/potential_acoustic_dot_dot_00000.bin differ diff --git a/tests/unit-tests/seismogram/acoustic/serial/specfem_config.yaml b/tests/unit-tests/seismogram/acoustic/serial/specfem_config.yaml new file mode 100644 index 00000000..4e2140bf --- /dev/null +++ b/tests/unit-tests/seismogram/acoustic/serial/specfem_config.yaml @@ -0,0 +1,49 @@ +parameters: + + header: + ## Header information is used for logging. It is good practice to give your simulations explicit names + title: Seismogram Test # name for your simulation + # A detailed description for your simulation + description: > + This test does not iterate the solver. + It just interpolates a given field at specified stations. + + simulation-setup: + ## quadrature setup + quadrature: + alpha: 0.0 + beta: 0.0 + ngllx: 5 + ngllz: 5 + + ## Solver setup + solver: + time-marching: + type-of-simulation: forward + time-scheme: + type: Newmark + dt: 1.1e-5 + nstep: 100 + + receivers: + stations-file: "../../../tests/unit-tests/seismogram/acoustic/serial/STATIONS" + angle: 0.0 + seismogram-type: + - displacement + - velocity + - acceleration + nstep_between_samples: 1 + + ## Runtime setup + run-setup: + number-of-processors: 1 + number-of-runs: 1 + + ## databases + databases: + mesh-database: "../../../tests/unit-tests/seismogram/acoustic/serial/database.bin" + source-file: "dummy-source.yaml" + + seismogram: + seismogram-format: ascii + output-folder: "." diff --git a/tests/unit-tests/seismogram/acoustic/test_config.yaml b/tests/unit-tests/seismogram/acoustic/test_config.yaml new file mode 100644 index 00000000..b9e00b0f --- /dev/null +++ b/tests/unit-tests/seismogram/acoustic/test_config.yaml @@ -0,0 +1,7 @@ +Tests: + + serial: + specfem_config: "../../../tests/unit-tests/seismogram/acoustic/serial/specfem_config.yaml" + displacement_field: "../../../tests/unit-tests/seismogram/acoustic/serial/potential_acoustic_00000.bin" + velocity_field: "../../../tests/unit-tests/seismogram/acoustic/serial/potential_acoustic_dot_00000.bin" + acceleration_field: "../../../tests/unit-tests/seismogram/acoustic/serial/potential_acoustic_dot_dot_00000.bin" diff --git a/tests/unit-tests/seismogram/seismogram_tests.cpp b/tests/unit-tests/seismogram/elastic/seismogram_tests.cpp similarity index 81% rename from tests/unit-tests/seismogram/seismogram_tests.cpp rename to tests/unit-tests/seismogram/elastic/seismogram_tests.cpp index 32417de5..6884568b 100644 --- a/tests/unit-tests/seismogram/seismogram_tests.cpp +++ b/tests/unit-tests/seismogram/elastic/seismogram_tests.cpp @@ -1,6 +1,6 @@ -#include "../Kokkos_Environment.hpp" -#include "../MPI_environment.hpp" -#include "../utilities/include/compare_array.h" +#include "../../Kokkos_Environment.hpp" +#include "../../MPI_environment.hpp" +#include "../../utilities/include/compare_array.h" #include "compute/interface.hpp" #include "constants.hpp" #include "domain/interface.hpp" @@ -73,7 +73,7 @@ void read_field( TEST(SEISMOGRAM_TESTS, elastic_seismograms_test) { std::string config_filename = - "../../../tests/unit-tests/seismogram/test_config.yaml"; + "../../../tests/unit-tests/seismogram/elastic/test_config.yaml"; specfem::MPI::MPI *mpi = MPIEnvironment::mpi_; @@ -106,6 +106,11 @@ TEST(SEISMOGRAM_TESTS, elastic_seismograms_test) { mesh.material_ind.kmato, materials, mesh.nspec, gllx->get_N(), gllz->get_N()); + // Setup boundary conditions + specfem::compute::boundaries boundary_conditions( + mesh.material_ind.kmato, materials, mesh.acfree_surface, + mesh.abs_boundary); + // locate the recievers for (auto &receiver : receivers) receiver->locate(compute.coordinates.coord, compute.h_ibool, @@ -126,23 +131,29 @@ TEST(SEISMOGRAM_TESTS, elastic_seismograms_test) { xmax, xmin, zmax, zmin, 1, mpi); const int nglob = specfem::utilities::compute_nglob(compute.h_ibool); - specfem::Domain::Domain *domain = new specfem::Domain::Elastic( - 2, nglob, &compute, &material_properties, &partial_derivatives, NULL, - &compute_receivers, gllx, gllz); - - const auto displacement_field = domain->get_host_field(); - const auto velocity_field = domain->get_host_field_dot(); - const auto acceleration_field = domain->get_host_field_dot_dot(); + specfem::enums::element::quadrature::static_quadrature_points<5> qp5; + specfem::domain::domain< + specfem::enums::element::medium::elastic, + specfem::enums::element::quadrature::static_quadrature_points<5> > + elastic_domain_static(nglob, qp5, &compute, material_properties, + partial_derivatives, boundary_conditions, + specfem::compute::sources(), compute_receivers, + gllx, gllz); + + const auto displacement_field = elastic_domain_static.get_host_field(); + const auto velocity_field = elastic_domain_static.get_host_field_dot(); + const auto acceleration_field = + elastic_domain_static.get_host_field_dot_dot(); read_field(test_config.displacement_field, displacement_field, nglob, 2); read_field(test_config.velocity_field, velocity_field, nglob, 2); read_field(test_config.acceleration_field, acceleration_field, nglob, 2); - domain->sync_field(specfem::sync::HostToDevice); - domain->sync_field_dot(specfem::sync::HostToDevice); - domain->sync_field_dot_dot(specfem::sync::HostToDevice); + elastic_domain_static.sync_field(specfem::sync::HostToDevice); + elastic_domain_static.sync_field_dot(specfem::sync::HostToDevice); + elastic_domain_static.sync_field_dot_dot(specfem::sync::HostToDevice); - domain->compute_seismogram(0); + elastic_domain_static.compute_seismogram(0); compute_receivers.sync_seismograms(); diff --git a/tests/unit-tests/seismogram/elastic/serial/STATIONS b/tests/unit-tests/seismogram/elastic/serial/STATIONS new file mode 100644 index 00000000..0fbd6638 --- /dev/null +++ b/tests/unit-tests/seismogram/elastic/serial/STATIONS @@ -0,0 +1,4 @@ +S0005 AA 2200.0000000 3000.0000000 0.0 0.0 +S0007 AA 2700.0000000 3000.0000000 0.0 0.0 +S0012 AA 2500.0000000 2500.0000000 0.0 0.0 +S0013 AA 2500.0000000 2250.0000000 0.0 0.0 diff --git a/tests/unit-tests/seismogram/serial/accel_00000.bin b/tests/unit-tests/seismogram/elastic/serial/accel_00000.bin similarity index 100% rename from tests/unit-tests/seismogram/serial/accel_00000.bin rename to tests/unit-tests/seismogram/elastic/serial/accel_00000.bin diff --git a/tests/unit-tests/seismogram/serial/database.bin b/tests/unit-tests/seismogram/elastic/serial/database.bin similarity index 100% rename from tests/unit-tests/seismogram/serial/database.bin rename to tests/unit-tests/seismogram/elastic/serial/database.bin diff --git a/tests/unit-tests/seismogram/serial/displs_00000.bin b/tests/unit-tests/seismogram/elastic/serial/displs_00000.bin similarity index 100% rename from tests/unit-tests/seismogram/serial/displs_00000.bin rename to tests/unit-tests/seismogram/elastic/serial/displs_00000.bin diff --git a/tests/unit-tests/seismogram/serial/specfem_config.yaml b/tests/unit-tests/seismogram/elastic/serial/specfem_config.yaml similarity index 80% rename from tests/unit-tests/seismogram/serial/specfem_config.yaml rename to tests/unit-tests/seismogram/elastic/serial/specfem_config.yaml index 3063c0c8..d3e995db 100644 --- a/tests/unit-tests/seismogram/serial/specfem_config.yaml +++ b/tests/unit-tests/seismogram/elastic/serial/specfem_config.yaml @@ -26,7 +26,7 @@ parameters: nstep: 100 receivers: - stations-file: "../../../tests/unit-tests/seismogram/serial/STATIONS" + stations-file: "../../../tests/unit-tests/seismogram/elastic/serial/STATIONS" angle: 0.0 seismogram-type: - displacement @@ -41,5 +41,9 @@ parameters: ## databases databases: - mesh-database: "../../../tests/unit-tests/seismogram/serial/database.bin" + mesh-database: "../../../tests/unit-tests/seismogram/elastic/serial/database.bin" source-file: "dummy-source.yaml" + + seismogram: + seismogram-format: ascii + output-folder: "." diff --git a/tests/unit-tests/seismogram/serial/veloc_00000.bin b/tests/unit-tests/seismogram/elastic/serial/veloc_00000.bin similarity index 100% rename from tests/unit-tests/seismogram/serial/veloc_00000.bin rename to tests/unit-tests/seismogram/elastic/serial/veloc_00000.bin diff --git a/tests/unit-tests/seismogram/elastic/test_config.yaml b/tests/unit-tests/seismogram/elastic/test_config.yaml new file mode 100644 index 00000000..578813c0 --- /dev/null +++ b/tests/unit-tests/seismogram/elastic/test_config.yaml @@ -0,0 +1,7 @@ +Tests: + + serial: + specfem_config: "../../../tests/unit-tests/seismogram/elastic/serial/specfem_config.yaml" + displacement_field: "../../../tests/unit-tests/seismogram/elastic/serial/displs_00000.bin" + velocity_field: "../../../tests/unit-tests/seismogram/elastic/serial/veloc_00000.bin" + acceleration_field: "../../../tests/unit-tests/seismogram/elastic/serial/accel_00000.bin" diff --git a/tests/unit-tests/seismogram/test_config.yaml b/tests/unit-tests/seismogram/test_config.yaml deleted file mode 100644 index f595d730..00000000 --- a/tests/unit-tests/seismogram/test_config.yaml +++ /dev/null @@ -1,7 +0,0 @@ -Tests: - - serial: - specfem_config: "../../../tests/unit-tests/seismogram/serial/specfem_config.yaml" - displacement_field: "../../../tests/unit-tests/seismogram/serial/displs_00000.bin" - velocity_field: "../../../tests/unit-tests/seismogram/serial/veloc_00000.bin" - acceleration_field: "../../../tests/unit-tests/seismogram/serial/accel_00000.bin" diff --git a/tests/unit-tests/utilities/src/compare_array.cpp b/tests/unit-tests/utilities/src/compare_array.cpp index 0c6d46f1..af25830c 100644 --- a/tests/unit-tests/utilities/src/compare_array.cpp +++ b/tests/unit-tests/utilities/src/compare_array.cpp @@ -45,7 +45,9 @@ void equate_norm(type_real error_norm, type_real computed_norm, if (percent_norm > tolerance) { std::ostringstream ss; ss << "Normalized error is = " << percent_norm - << " which is greater than specified tolerance = " << tolerance; + << " which is greater than specified tolerance = " << tolerance + << " computed norm = " << computed_norm + << " error norm = " << error_norm; throw std::runtime_error(ss.str()); } @@ -469,7 +471,7 @@ void specfem::testing::test_array( } } - type_real tol = 10 * fabs(max_val + min_val) / 2; + type_real tol = 1e-2 * fabs(max_val + min_val) / 2; type_real ref_value; std::ifstream stream; @@ -555,10 +557,6 @@ void specfem::testing::compare_norm( computed_norm += std::sqrt((computed_array(i1) * computed_array(i1))); } - std::cout << error_norm << std::endl; - - std::cout << computed_norm << std::endl; - stream.close(); equate_norm(error_norm, computed_norm, tolerance); @@ -580,11 +578,11 @@ void specfem::testing::compare_norm( for (int i1 = 0; i1 < n1; i1++) { for (int i2 = 0; i2 < n2; i2++) { specfem::fortran_IO::fortran_read_line(stream, &ref_value); + type_real computed_value = computed_array(i1, i2); - error_norm += std::sqrt((computed_array(i1, i2) - ref_value) * - (computed_array(i1, i2) - ref_value)); - computed_norm += - std::sqrt((computed_array(i1, i2) * computed_array(i1, i2))); + error_norm += std::sqrt((computed_value - ref_value) * + (computed_value - ref_value)); + computed_norm += std::sqrt((computed_value * computed_value)); } }