diff --git a/.github/workflows/repo-check.yml b/.github/workflows/repo-check.yml new file mode 100644 index 0000000000..deb4140b08 --- /dev/null +++ b/.github/workflows/repo-check.yml @@ -0,0 +1,42 @@ +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced +# at the Lawrence Livermore National Laboratory. All Rights reserved. See files +# LICENSE and NOTICE for details. LLNL-CODE-806117. +# +# This file is part of the MFEM library. For more information and source code +# availability visit https://mfem.org. +# +# MFEM is free software; you can redistribute it and/or modify it under the +# terms of the BSD-3 license. We welcome feedback and contributions, see file +# CONTRIBUTING.md for details. + +name: repo-check + +on: + push: + branches: + - master + pull_request: + branches: + - master + +jobs: + copyright-check: + runs-on: ubuntu-latest + + steps: + - name: checkout mfem + uses: actions/checkout@v2 + with: + path: mfem + + - name: copyright check + run: | + cd mfem + if git grep -l "^#.*\-2020" > matches.txt + then + echo "Please update the following files to Copyright (c) 2010-2021:" + cat matches.txt + exit 1 + else + echo "No outdated copyright found." + fi diff --git a/.gitignore b/.gitignore index 427db5ccae..cd799bc3a6 100644 --- a/.gitignore +++ b/.gitignore @@ -66,6 +66,7 @@ examples/sol_u.* examples/sol_p.* examples/sol_r.* examples/sol_i.* +examples/ex6p-checkpoint.* examples/ex9.mesh examples/ex9-mesh.* examples/ex9-init.* @@ -264,6 +265,8 @@ miniapps/toys/lissajous.mesh miniapps/toys/lissajous.gf miniapps/toys/mondrian.mesh +miniapps/solvers/block-solvers + # Unit test binary and outputs tests/unit/output_meshes tests/unit/unit_tests diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 39d404adb8..8d242e23c9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/.gitlab/lassen.yml b/.gitlab/lassen.yml index 511605f96b..62c08fadce 100644 --- a/.gitlab/lassen.yml +++ b/.gitlab/lassen.yml @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/.gitlab/quartz.yml b/.gitlab/quartz.yml index e168b81126..0f1350b9f5 100644 --- a/.gitlab/quartz.yml +++ b/.gitlab/quartz.yml @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/.travis.yml b/.travis.yml index f957af4918..fcb0c530ad 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/CHANGELOG b/CHANGELOG index fd07362a48..38ee04d1d5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -11,23 +11,86 @@ Version 4.2.1 (development) =========================== +- Added a new miniapp block-solvers that compares the performance of various + solvers for mixed finite element discretization of the second order scalar + elliptic equations. Currently available solvers in the miniapp include a + block-diagonal preconditioner that is based on approximate Schur complement + (implemented in ex5p), and a newly implemented solver DivFreeSolver, which + exploits a multilevel decomposition of the Raviart-Thomas space and its + divergence-free subspace. See the miniapps/solvers directory for more details. + +- Added matrix-free GPU-enabled implementations of GradientInterpolator and + IdentityInterpolator. + - Added interface to MUMPS direct solver. Its usage is demonstrated in ex25p. See http://mumps.enseeiht.fr/ for more details. Supported versions >= 5.1.1. - Added three ESDIRK time integrators: implicit trapezoid rule, L-stable ESDIRK-32, and A-stable ESDIRK-33. +- Introduced a new non-conforming mesh format that fixes known inconsistencies + of legacy "MFEM mesh v1.1" NC format and works consistently in both serial and + parallel. ParMesh::ParPrint can now print non-conforming AMR meshes that can + be used to restart a parallel AMR computation. Example 6p has been extended to + demonstrate restarting from a previously saved checkpoint. Note that parallel + NC data files are compatible with serial code, e.g., can be viewed with serial + GLVis. Loading of legacy NC mesh files is still supported. + - Added a "scaled Jacobian" visualization option in the Mesh Explorer miniapp to help identify elements with poor mesh quality. +- Added support for the "BR2" discontinuous Galerkin discretization for + diffusion via DGDiffusionBR2Integrator (see Example 14/14p). + +- Generalized the Multigrid class to support non-geometric multigrid. The + previous functionality, based on FiniteElementSpaceHierarchy, is now available + in the derived class GeometricMultigrid. + - Upgraded the Catch unit test framework from version 2.13.0 to version 2.13.2. - Implemented a filter method for the Navier miniapp to stabilize highly turbulent flows in direct numerical simulation. +- Added HIP support to the CMake build system. + +- Added support for reading high-order Lagrange meshes in VTK format. Arbitrary- + orders and all element types are supported. See the VTK blog for more info: + https://blog.kitware.com/wp-content/uploads/2018/09/Source_Issue_43.pdf. + +- Added support for reading VTK meshes in XML format. + +- Added partial assembly and device support to Example 25/25p, with diagonal + preconditioning. + - Implemented a variable step-size IMEX (VSSIMEX) method for the Navier miniapp. -- Added new mesh quality metrics for TMOP-based mesh optimization. +- Added new mesh quality metrics and improved the untangling capabilities of the + TMOP-based mesh optimization algorithms. + +- Added convective and skew-symmetric integrators for the nonlinear term in the + Navier-Stokes equations. + +- Changed the interface for the error estimator. + +- Implemented the parallel Kelly error indicator for scalar-valued problems. + +- Added new classes DenseSymmetricMatrix and SymmetricMatrixCoefficient for + efficient evaluation of symmetric matrix coefficients. This replaces the now + deprecated EvalSymmetric in MatrixCoefficient. Added DiagonalMatrixCoefficient + for clarity, which is a typedef of VectorCoefficient. + +- Added support for AMG preconditioners for non-symmetric systems (e.g. + advection-dominated problems) using hypre's approximate ideal restriction + (AIR) AMG. Requires hypre version 2.14.0 or newer. Usage is illustrated in + example 9/9p. + +- Implemented an adaptive linear solver tolerance option for NewtonSolver based + on the algorithm of Eisenstat and Walker. + +- Added support for nonscalar coefficient with VectorDiffusionIntegrator. + +- Extending support for L2 basis functions using MapTypes VALUE and INTEGRAL in + linear interpolators and GridFunction "GetValue" methods. Version 4.2, released on October 30, 2020 diff --git a/CMakeLists.txt b/CMakeLists.txt index 71c1137d02..c62c2a2104 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # @@ -9,7 +9,8 @@ # terms of the BSD-3 license. We welcome feedback and contributions, see file # CONTRIBUTING.md for details. -cmake_minimum_required(VERSION 2.8.11) +# The variable CMAKE_CXX_STANDARD and related were introduced in CMake v3.1 +cmake_minimum_required(VERSION 3.1) set(USER_CONFIG "${CMAKE_CURRENT_SOURCE_DIR}/config/user.cmake" CACHE PATH "Path to optional user configuration file.") @@ -87,6 +88,9 @@ include("${CMAKE_CURRENT_SOURCE_DIR}/config/XSDKDefaults.cmake") # Enable languages. enable_language(CXX) if (MFEM_USE_CUDA) + if (MFEM_USE_HIP) + message(FATAL_ERROR " *** MFEM_USE_HIP cannot be combined with MFEM_USE_CUDA.") + endif() # MFEM_USE_CUDA requires CMake 3.8 or newer (for direct CUDA support) cmake_minimum_required(VERSION 3.8 FATAL_ERROR) # Use ${CMAKE_CXX_COMPILER} as the cuda host compiler. @@ -356,6 +360,15 @@ if (MFEM_USE_UMPIRE) find_package(UMPIRE REQUIRED) endif() +# AMD HIP +if (MFEM_USE_HIP) + find_package(HIP REQUIRED) + if (HIP_ARCH) + message(STATUS "Using HIP architecture: ${HIP_ARCH}") + list(APPEND HIP_HIPCC_FLAGS "--amdgpu-target=${HIP_ARCH}") + endif() +endif() + # ADIOS2 for parallel I/O if (MFEM_USE_ADIOS2) find_package(ADIOS2 REQUIRED) @@ -431,9 +444,9 @@ foreach(DIR IN LISTS MFEM_SOURCE_DIRS) endforeach() if (MFEM_USE_CUDA) - foreach(file IN LISTS SOURCES) - set_property(SOURCE ${file} PROPERTY LANGUAGE CUDA) - endforeach() + set_source_files_properties(${SOURCES} PROPERTIES LANGUAGE CUDA) +elseif(MFEM_USE_HIP) + set_source_files_properties(${SOURCES} PROPERTIES HIP_SOURCE_PROPERTY_FORMAT TRUE) endif() add_subdirectory(config) @@ -452,7 +465,7 @@ set(MFEM_INSTALL_DIR ${CMAKE_INSTALL_PREFIX} CACHE PATH "The MFEM install directory" FORCE) # Declaring the library -add_library(mfem ${SOURCES} ${HEADERS} ${MASTER_HEADERS}) +mfem_add_library(mfem ${SOURCES} ${HEADERS} ${MASTER_HEADERS}) # message(STATUS "TPL_LIBRARIES = ${TPL_LIBRARIES}") if (CMAKE_VERSION VERSION_GREATER 2.8.11) target_link_libraries(mfem PUBLIC ${TPL_LIBRARIES}) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b122e24375..24367b3076 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -118,6 +118,7 @@ The MFEM source code has the following structure: │ ├── navier │ ├── nurbs │ ├── performance + │ ├── solvers │ ├── tools │ └── toys └── tests diff --git a/INSTALL b/INSTALL index f507a362a0..58cf4ff150 100644 --- a/INSTALL +++ b/INSTALL @@ -710,10 +710,10 @@ The specific libraries and their options are: Versions: libCEED >= 0.7. - RAJA (optional), used when MFEM_USE_RAJA = YES. - Beginning with MFEM v4.1, only RAJA v0.10.0+ is supported. + Beginning with MFEM v4.3, only RAJA v0.13.0+ is supported. URL: https://github.com/LLNL/RAJA Options: RAJA_DIR, RAJA_OPT, RAJA_LIB. - Versions: RAJA >= 0.10.0. + Versions: RAJA >= 0.13.0. - Umpire, used when MFEM_USE_UMPIRE = YES. URL: https://github.com/LLNL/Umpire diff --git a/LICENSE b/LICENSE index 627765dec3..ed91693fe0 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ BSD 3-Clause License -Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC +Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/NOTICE b/NOTICE index ba56233219..9e4f8920ad 100644 --- a/NOTICE +++ b/NOTICE @@ -29,4 +29,5 @@ license files. These software products and their licenses are as follows: * Catch++ (tests/unit/catch.hpp) -- Boost 1.0 license * Gecko (general/gecko.{cpp,hpp}) -- BSD 3-clause license * Picojson (fem/picojson.h) -- Custom 2-clause license +* TinyXML2 (general/tinyxml2.{cpp,h}) -- zlib license * Zstr (general/zstr.hpp) -- MIT license diff --git a/config/CMakeLists.txt b/config/CMakeLists.txt index 59393cb422..4de8df0b9e 100644 --- a/config/CMakeLists.txt +++ b/config/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/config/cmake/MFEMConfig.cmake.in b/config/cmake/MFEMConfig.cmake.in index f0062d464f..6a39548362 100644 --- a/config/cmake/MFEMConfig.cmake.in +++ b/config/cmake/MFEMConfig.cmake.in @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/config/cmake/config.hpp.in b/config/cmake/config.hpp.in index 4475692620..0c47e92adf 100644 --- a/config/cmake/config.hpp.in +++ b/config/cmake/config.hpp.in @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -132,6 +132,10 @@ // Requires a CUDA compiler (nvcc). #cmakedefine MFEM_USE_CUDA +// Build the HIP-enabled version of the MFEM library. +// Requires a HIP compiler (hipcc). +#cmakedefine MFEM_USE_HIP + // Enable MFEM functionality based on the RAJA library #cmakedefine MFEM_USE_RAJA diff --git a/config/cmake/modules/FindAMGX.cmake b/config/cmake/modules/FindAMGX.cmake index f351d8c4a8..8d1880a895 100644 --- a/config/cmake/modules/FindAMGX.cmake +++ b/config/cmake/modules/FindAMGX.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/config/cmake/modules/FindAxom.cmake b/config/cmake/modules/FindAxom.cmake index 6195c43a7a..f36a029a5d 100644 --- a/config/cmake/modules/FindAxom.cmake +++ b/config/cmake/modules/FindAxom.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/config/cmake/modules/FindCXXABIDemangle.cmake b/config/cmake/modules/FindCXXABIDemangle.cmake index 4176348e23..d5b8d39463 100644 --- a/config/cmake/modules/FindCXXABIDemangle.cmake +++ b/config/cmake/modules/FindCXXABIDemangle.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/config/cmake/modules/FindConduit.cmake b/config/cmake/modules/FindConduit.cmake index 45cfd350f1..b30add4959 100644 --- a/config/cmake/modules/FindConduit.cmake +++ b/config/cmake/modules/FindConduit.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/config/cmake/modules/FindGSLIB.cmake b/config/cmake/modules/FindGSLIB.cmake index 4c0d71bbc1..d48c676fc6 100644 --- a/config/cmake/modules/FindGSLIB.cmake +++ b/config/cmake/modules/FindGSLIB.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/config/cmake/modules/FindHIOP.cmake b/config/cmake/modules/FindHIOP.cmake index 5b57e24375..9c72ffb527 100644 --- a/config/cmake/modules/FindHIOP.cmake +++ b/config/cmake/modules/FindHIOP.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/config/cmake/modules/FindHIP.cmake b/config/cmake/modules/FindHIP.cmake new file mode 100644 index 0000000000..6b698374a1 --- /dev/null +++ b/config/cmake/modules/FindHIP.cmake @@ -0,0 +1,692 @@ +############################################################################### +# FindHIP.cmake +############################################################################### +include(CheckCXXCompilerFlag) +############################################################################### +# SET: Variable defaults +############################################################################### +# User defined flags +set(HIP_HIPCC_FLAGS "" CACHE STRING "Semicolon delimited flags for HIPCC") +set(HIP_HCC_FLAGS "" CACHE STRING "Semicolon delimited flags for HCC") +set(HIP_CLANG_FLAGS "" CACHE STRING "Semicolon delimited flags for CLANG") +set(HIP_NVCC_FLAGS "" CACHE STRING "Semicolon delimted flags for NVCC") +mark_as_advanced(HIP_HIPCC_FLAGS HIP_HCC_FLAGS HIP_CLANG_FLAGS HIP_NVCC_FLAGS) + +set(_hip_configuration_types ${CMAKE_CONFIGURATION_TYPES} ${CMAKE_BUILD_TYPE} Debug MinSizeRel Release RelWithDebInfo) +list(REMOVE_DUPLICATES _hip_configuration_types) +foreach(config ${_hip_configuration_types}) + string(TOUPPER ${config} config_upper) + set(HIP_HIPCC_FLAGS_${config_upper} "" CACHE STRING "Semicolon delimited flags for HIPCC") + set(HIP_HCC_FLAGS_${config_upper} "" CACHE STRING "Semicolon delimited flags for HCC") + set(HIP_CLANG_FLAGS_${config_upper} "" CACHE STRING "Semicolon delimited flags for CLANG") + set(HIP_NVCC_FLAGS_${config_upper} "" CACHE STRING "Semicolon delimited flags for NVCC") + mark_as_advanced(HIP_HIPCC_FLAGS_${config_upper} HIP_HCC_FLAGS_${config_upper} HIP_CLANG_FLAGS_${config_upper} HIP_NVCC_FLAGS_${config_upper}) +endforeach() +option(HIP_HOST_COMPILATION_CPP "Host code compilation mode" ON) +option(HIP_VERBOSE_BUILD "Print out the commands run while compiling the HIP source file. With the Makefile generator this defaults to VERBOSE variable specified on the command line, but can be forced on with this option." OFF) +mark_as_advanced(HIP_HOST_COMPILATION_CPP) + +############################################################################### +# FIND: HIP and associated helper binaries +############################################################################### + +get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_DIR}/../" REALPATH) + +# HIP is supported on Linux only +if(UNIX AND NOT APPLE AND NOT CYGWIN) + # Search for HIP installation + if(NOT HIP_ROOT_DIR) + # Search in user specified path first + find_path( + HIP_ROOT_DIR + NAMES bin/hipconfig + PATHS + "$ENV{ROCM_PATH}/hip" + ENV HIP_PATH + ${_IMPORT_PREFIX} + /opt/rocm/hip + DOC "HIP installed location" + NO_DEFAULT_PATH + ) + if(NOT EXISTS ${HIP_ROOT_DIR}) + if(HIP_FIND_REQUIRED) + message(FATAL_ERROR "Specify HIP_ROOT_DIR") + elseif(NOT HIP_FIND_QUIETLY) + message("HIP_ROOT_DIR not found or specified") + endif() + endif() + # And push it back to the cache + set(HIP_ROOT_DIR ${HIP_ROOT_DIR} CACHE PATH "HIP installed location" FORCE) + endif() + + # Find HIPCC executable + find_program( + HIP_HIPCC_EXECUTABLE + NAMES hipcc + PATHS + "${HIP_ROOT_DIR}" + ENV ROCM_PATH + ENV HIP_PATH + /opt/rocm + /opt/rocm/hip + PATH_SUFFIXES bin + NO_DEFAULT_PATH + ) + if(NOT HIP_HIPCC_EXECUTABLE) + # Now search in default paths + find_program(HIP_HIPCC_EXECUTABLE hipcc) + endif() + mark_as_advanced(HIP_HIPCC_EXECUTABLE) + + # Find HIPCONFIG executable + find_program( + HIP_HIPCONFIG_EXECUTABLE + NAMES hipconfig + PATHS + "${HIP_ROOT_DIR}" + ENV ROCM_PATH + ENV HIP_PATH + /opt/rocm + /opt/rocm/hip + PATH_SUFFIXES bin + NO_DEFAULT_PATH + ) + if(NOT HIP_HIPCONFIG_EXECUTABLE) + # Now search in default paths + find_program(HIP_HIPCONFIG_EXECUTABLE hipconfig) + endif() + mark_as_advanced(HIP_HIPCONFIG_EXECUTABLE) + + # Find HIPCC_CMAKE_LINKER_HELPER executable + find_program( + HIP_HIPCC_CMAKE_LINKER_HELPER + NAMES hipcc_cmake_linker_helper + PATHS + "${HIP_ROOT_DIR}" + ENV ROCM_PATH + ENV HIP_PATH + /opt/rocm + /opt/rocm/hip + PATH_SUFFIXES bin + NO_DEFAULT_PATH + ) + if(NOT HIP_HIPCC_CMAKE_LINKER_HELPER) + # Now search in default paths + find_program(HIP_HIPCC_CMAKE_LINKER_HELPER hipcc_cmake_linker_helper) + endif() + mark_as_advanced(HIP_HIPCC_CMAKE_LINKER_HELPER) + + if(HIP_HIPCONFIG_EXECUTABLE AND NOT HIP_VERSION) + # Compute the version + execute_process( + COMMAND ${HIP_HIPCONFIG_EXECUTABLE} --version + OUTPUT_VARIABLE _hip_version + ERROR_VARIABLE _hip_error + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_STRIP_TRAILING_WHITESPACE + ) + if(NOT _hip_error) + set(HIP_VERSION ${_hip_version} CACHE STRING "Version of HIP as computed from hipcc") + else() + set(HIP_VERSION "0.0.0" CACHE STRING "Version of HIP as computed by FindHIP()") + endif() + mark_as_advanced(HIP_VERSION) + endif() + if(HIP_VERSION) + string(REPLACE "." ";" _hip_version_list "${HIP_VERSION}") + list(GET _hip_version_list 0 HIP_VERSION_MAJOR) + list(GET _hip_version_list 1 HIP_VERSION_MINOR) + list(GET _hip_version_list 2 HIP_VERSION_PATCH) + set(HIP_VERSION_STRING "${HIP_VERSION}") + endif() + + if(HIP_HIPCONFIG_EXECUTABLE AND NOT HIP_PLATFORM) + # Compute the platform + execute_process( + COMMAND ${HIP_HIPCONFIG_EXECUTABLE} --platform + OUTPUT_VARIABLE _hip_platform + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + set(HIP_PLATFORM ${_hip_platform} CACHE STRING "HIP platform as computed by hipconfig") + mark_as_advanced(HIP_PLATFORM) + endif() + + if(HIP_HIPCONFIG_EXECUTABLE AND NOT HIP_COMPILER) + # Compute the compiler + execute_process( + COMMAND ${HIP_HIPCONFIG_EXECUTABLE} --compiler + OUTPUT_VARIABLE _hip_compiler + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + set(HIP_COMPILER ${_hip_compiler} CACHE STRING "HIP compiler as computed by hipconfig") + mark_as_advanced(HIP_COMPILER) + endif() + + if(HIP_HIPCONFIG_EXECUTABLE AND NOT HIP_RUNTIME) + # Compute the runtime + execute_process( + COMMAND ${HIP_HIPCONFIG_EXECUTABLE} --runtime + OUTPUT_VARIABLE _hip_runtime + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + set(HIP_RUNTIME ${_hip_runtime} CACHE STRING "HIP runtime as computed by hipconfig") + mark_as_advanced(HIP_RUNTIME) + endif() +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args( + HIP + REQUIRED_VARS + HIP_ROOT_DIR + HIP_HIPCC_EXECUTABLE + HIP_HIPCONFIG_EXECUTABLE + HIP_PLATFORM + HIP_COMPILER + HIP_RUNTIME + VERSION_VAR HIP_VERSION + ) + +############################################################################### +# Set HIP CMAKE Flags +############################################################################### +# Copy the invocation styles from CXX to HIP +set(CMAKE_HIP_ARCHIVE_CREATE ${CMAKE_CXX_ARCHIVE_CREATE}) +set(CMAKE_HIP_ARCHIVE_APPEND ${CMAKE_CXX_ARCHIVE_APPEND}) +set(CMAKE_HIP_ARCHIVE_FINISH ${CMAKE_CXX_ARCHIVE_FINISH}) +set(CMAKE_SHARED_LIBRARY_SONAME_HIP_FLAG ${CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG}) +set(CMAKE_SHARED_LIBRARY_CREATE_HIP_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS}) +set(CMAKE_SHARED_LIBRARY_HIP_FLAGS ${CMAKE_SHARED_LIBRARY_CXX_FLAGS}) +#set(CMAKE_SHARED_LIBRARY_LINK_HIP_FLAGS ${CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS}) +set(CMAKE_SHARED_LIBRARY_RUNTIME_HIP_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG}) +set(CMAKE_SHARED_LIBRARY_RUNTIME_HIP_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG_SEP}) +set(CMAKE_SHARED_LIBRARY_LINK_STATIC_HIP_FLAGS ${CMAKE_SHARED_LIBRARY_LINK_STATIC_CXX_FLAGS}) +set(CMAKE_SHARED_LIBRARY_LINK_DYNAMIC_HIP_FLAGS ${CMAKE_SHARED_LIBRARY_LINK_DYNAMIC_CXX_FLAGS}) + +set(HIP_CLANG_PARALLEL_BUILD_COMPILE_OPTIONS "") +set(HIP_CLANG_PARALLEL_BUILD_LINK_OPTIONS "") + +if("${HIP_COMPILER}" STREQUAL "nvcc") + # Set the CMake Flags to use the nvcc Compiler. + set(CMAKE_HIP_CREATE_SHARED_LIBRARY "${HIP_HIPCC_CMAKE_LINKER_HELPER} -o ") + set(CMAKE_HIP_CREATE_SHARED_MODULE "${HIP_HIPCC_CMAKE_LINKER_HELPER} -o -shared" ) + set(CMAKE_HIP_LINK_EXECUTABLE "${HIP_HIPCC_CMAKE_LINKER_HELPER} -o ") +elseif("${HIP_COMPILER}" STREQUAL "hcc") + # Set the CMake Flags to use the hcc Compiler. + set(CMAKE_HIP_CREATE_SHARED_LIBRARY "${HIP_HIPCC_CMAKE_LINKER_HELPER} ${HCC_HOME} -o ") + set(CMAKE_HIP_CREATE_SHARED_MODULE "${HIP_HIPCC_CMAKE_LINKER_HELPER} ${HCC_HOME} -o -shared" ) + set(CMAKE_HIP_LINK_EXECUTABLE "${HIP_HIPCC_CMAKE_LINKER_HELPER} ${HCC_HOME} -o ") +elseif("${HIP_COMPILER}" STREQUAL "clang") + #Number of parallel jobs by default is 1 + if(NOT DEFINED HIP_CLANG_NUM_PARALLEL_JOBS) + set(HIP_CLANG_NUM_PARALLEL_JOBS 1) + endif() + #Add support for parallel build and link + if(${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang") + check_cxx_compiler_flag("-parallel-jobs=1" HIP_CLANG_SUPPORTS_PARALLEL_JOBS) + endif() + if(HIP_CLANG_NUM_PARALLEL_JOBS GREATER 1) + if(${HIP_CLANG_SUPPORTS_PARALLEL_JOBS}) + set(HIP_CLANG_PARALLEL_BUILD_COMPILE_OPTIONS "-Wno-format-nonliteral -parallel-jobs=${HIP_CLANG_NUM_PARALLEL_JOBS}") + set(HIP_CLANG_PARALLEL_BUILD_LINK_OPTIONS "-parallel-jobs=${HIP_CLANG_NUM_PARALLEL_JOBS}") + else() + message("clang compiler doesn't support parallel jobs") + endif() + endif() + + # Set the CMake Flags to use the HIP-Clang Compiler. + set(CMAKE_HIP_CREATE_SHARED_LIBRARY "${HIP_HIPCC_CMAKE_LINKER_HELPER} ${HIP_CLANG_PATH} ${HIP_CLANG_PARALLEL_BUILD_LINK_OPTIONS} -o ") + set(CMAKE_HIP_CREATE_SHARED_MODULE "${HIP_HIPCC_CMAKE_LINKER_HELPER} ${HIP_CLANG_PATH} ${HIP_CLANG_PARALLEL_BUILD_LINK_OPTIONS} -o -shared" ) + set(CMAKE_HIP_LINK_EXECUTABLE "${HIP_HIPCC_CMAKE_LINKER_HELPER} ${HIP_CLANG_PATH} ${HIP_CLANG_PARALLEL_BUILD_LINK_OPTIONS} -o ") + + if("${HIP_RUNTIME}" STREQUAL "rocclr") + if(TARGET host) + message(STATUS "host interface - found") + set(HIP_HOST_INTERFACE host) + endif() + endif() +endif() + +############################################################################### +# MACRO: Locate helper files +############################################################################### +macro(HIP_FIND_HELPER_FILE _name _extension) + set(_hip_full_name "${_name}.${_extension}") + get_filename_component(CMAKE_CURRENT_LIST_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) + set(HIP_${_name} "${CMAKE_CURRENT_LIST_DIR}/FindHIP/${_hip_full_name}") + if(NOT EXISTS "${HIP_${_name}}") + set(error_message "${_hip_full_name} not found in ${CMAKE_CURRENT_LIST_DIR}/FindHIP") + if(HIP_FIND_REQUIRED) + message(FATAL_ERROR "${error_message}") + else() + if(NOT HIP_FIND_QUIETLY) + message(STATUS "${error_message}") + endif() + endif() + endif() + # Set this variable as internal, so the user isn't bugged with it. + set(HIP_${_name} ${HIP_${_name}} CACHE INTERNAL "Location of ${_full_name}" FORCE) +endmacro() + +############################################################################### +hip_find_helper_file(run_make2cmake cmake) +hip_find_helper_file(run_hipcc cmake) +############################################################################### + +############################################################################### +# MACRO: Reset compiler flags +############################################################################### +macro(HIP_RESET_FLAGS) + unset(HIP_HIPCC_FLAGS) + unset(HIP_HCC_FLAGS) + unset(HIP_CLANG_FLAGS) + unset(HIP_NVCC_FLAGS) + foreach(config ${_hip_configuration_types}) + string(TOUPPER ${config} config_upper) + unset(HIP_HIPCC_FLAGS_${config_upper}) + unset(HIP_HCC_FLAGS_${config_upper}) + unset(HIP_CLANG_FLAGS_${config_upper}) + unset(HIP_NVCC_FLAGS_${config_upper}) + endforeach() +endmacro() + +############################################################################### +# MACRO: Separate the options from the sources +############################################################################### +macro(HIP_GET_SOURCES_AND_OPTIONS _sources _cmake_options _hipcc_options _hcc_options _clang_options _nvcc_options) + set(${_sources}) + set(${_cmake_options}) + set(${_hipcc_options}) + set(${_hcc_options}) + set(${_clang_options}) + set(${_nvcc_options}) + set(_hipcc_found_options FALSE) + set(_hcc_found_options FALSE) + set(_clang_found_options FALSE) + set(_nvcc_found_options FALSE) + foreach(arg ${ARGN}) + if("x${arg}" STREQUAL "xHIPCC_OPTIONS") + set(_hipcc_found_options TRUE) + set(_hcc_found_options FALSE) + set(_clang_found_options FALSE) + set(_nvcc_found_options FALSE) + elseif("x${arg}" STREQUAL "xHCC_OPTIONS") + set(_hipcc_found_options FALSE) + set(_hcc_found_options TRUE) + set(_clang_found_options FALSE) + set(_nvcc_found_options FALSE) + elseif("x${arg}" STREQUAL "xCLANG_OPTIONS") + set(_hipcc_found_options FALSE) + set(_hcc_found_options FALSE) + set(_clang_found_options TRUE) + set(_nvcc_found_options FALSE) + elseif("x${arg}" STREQUAL "xNVCC_OPTIONS") + set(_hipcc_found_options FALSE) + set(_hcc_found_options FALSE) + set(_clang_found_options FALSE) + set(_nvcc_found_options TRUE) + elseif( + "x${arg}" STREQUAL "xEXCLUDE_FROM_ALL" OR + "x${arg}" STREQUAL "xSTATIC" OR + "x${arg}" STREQUAL "xSHARED" OR + "x${arg}" STREQUAL "xMODULE" + ) + list(APPEND ${_cmake_options} ${arg}) + else() + if(_hipcc_found_options) + list(APPEND ${_hipcc_options} ${arg}) + elseif(_hcc_found_options) + list(APPEND ${_hcc_options} ${arg}) + elseif(_clang_found_options) + list(APPEND ${_clang_options} ${arg}) + elseif(_nvcc_found_options) + list(APPEND ${_nvcc_options} ${arg}) + else() + # Assume this is a file + list(APPEND ${_sources} ${arg}) + endif() + endif() + endforeach() +endmacro() + +############################################################################### +# MACRO: Add include directories to pass to the hipcc command +############################################################################### +set(HIP_HIPCC_INCLUDE_ARGS_USER "") +macro(HIP_INCLUDE_DIRECTORIES) + foreach(dir ${ARGN}) + list(APPEND HIP_HIPCC_INCLUDE_ARGS_USER $<$:-I${dir}>) + endforeach() +endmacro() + +############################################################################### +# FUNCTION: Helper to avoid clashes of files with the same basename but different paths +############################################################################### +function(HIP_COMPUTE_BUILD_PATH path build_path) + # Convert to cmake style paths + file(TO_CMAKE_PATH "${path}" bpath) + if(IS_ABSOLUTE "${bpath}") + string(FIND "${bpath}" "${CMAKE_CURRENT_BINARY_DIR}" _binary_dir_pos) + if(_binary_dir_pos EQUAL 0) + file(RELATIVE_PATH bpath "${CMAKE_CURRENT_BINARY_DIR}" "${bpath}") + else() + file(RELATIVE_PATH bpath "${CMAKE_CURRENT_SOURCE_DIR}" "${bpath}") + endif() + endif() + + # Remove leading / + string(REGEX REPLACE "^[/]+" "" bpath "${bpath}") + # Avoid absolute paths by removing ':' + string(REPLACE ":" "_" bpath "${bpath}") + # Avoid relative paths that go up the tree + string(REPLACE "../" "__/" bpath "${bpath}") + # Avoid spaces + string(REPLACE " " "_" bpath "${bpath}") + # Strip off the filename + get_filename_component(bpath "${bpath}" PATH) + + set(${build_path} "${bpath}" PARENT_SCOPE) +endfunction() + +############################################################################### +# MACRO: Parse OPTIONS from ARGN & set variables prefixed by _option_prefix +############################################################################### +macro(HIP_PARSE_HIPCC_OPTIONS _option_prefix) + set(_hip_found_config) + foreach(arg ${ARGN}) + # Determine if we are dealing with a per-configuration flag + foreach(config ${_hip_configuration_types}) + string(TOUPPER ${config} config_upper) + if(arg STREQUAL "${config_upper}") + set(_hip_found_config _${arg}) + # Clear arg to prevent it from being processed anymore + set(arg) + endif() + endforeach() + if(arg) + list(APPEND ${_option_prefix}${_hip_found_config} "${arg}") + endif() + endforeach() +endmacro() + +############################################################################### +# MACRO: Try and include dependency file if it exists +############################################################################### +macro(HIP_INCLUDE_HIPCC_DEPENDENCIES dependency_file) + set(HIP_HIPCC_DEPEND) + set(HIP_HIPCC_DEPEND_REGENERATE FALSE) + + # Create the dependency file if it doesn't exist + if(NOT EXISTS ${dependency_file}) + file(WRITE ${dependency_file} "# Generated by: FindHIP.cmake. Do not edit.\n") + endif() + # Include the dependency file + include(${dependency_file}) + + # Verify the existence of all the included files + if(HIP_HIPCC_DEPEND) + foreach(f ${HIP_HIPCC_DEPEND}) + if(NOT EXISTS ${f}) + # If they aren't there, regenerate the file again + set(HIP_HIPCC_DEPEND_REGENERATE TRUE) + endif() + endforeach() + else() + # No dependencies, so regenerate the file + set(HIP_HIPCC_DEPEND_REGENERATE TRUE) + endif() + + # Regenerate the dependency file if needed + if(HIP_HIPCC_DEPEND_REGENERATE) + set(HIP_HIPCC_DEPEND ${dependency_file}) + file(WRITE ${dependency_file} "# Generated by: FindHIP.cmake. Do not edit.\n") + endif() +endmacro() + +############################################################################### +# MACRO: Prepare cmake commands for the target +############################################################################### +macro(HIP_PREPARE_TARGET_COMMANDS _target _format _generated_files _source_files) + set(_hip_flags "") + string(TOUPPER "${CMAKE_BUILD_TYPE}" _hip_build_configuration) + if(HIP_HOST_COMPILATION_CPP) + set(HIP_C_OR_CXX CXX) + else() + set(HIP_C_OR_CXX C) + endif() + set(generated_extension ${CMAKE_${HIP_C_OR_CXX}_OUTPUT_EXTENSION}) + + # Initialize list of includes with those specified by the user. Append with + # ones specified to cmake directly. + set(HIP_HIPCC_INCLUDE_ARGS ${HIP_HIPCC_INCLUDE_ARGS_USER}) + + # Add the include directories + set(include_directories_generator "$") + list(APPEND HIP_HIPCC_INCLUDE_ARGS "$<$:-I$>") + + get_directory_property(_hip_include_directories INCLUDE_DIRECTORIES) + list(REMOVE_DUPLICATES _hip_include_directories) + if(_hip_include_directories) + foreach(dir ${_hip_include_directories}) + list(APPEND HIP_HIPCC_INCLUDE_ARGS $<$:-I${dir}>) + endforeach() + endif() + + HIP_GET_SOURCES_AND_OPTIONS(_hip_sources _hip_cmake_options _hipcc_options _hcc_options _clang_options _nvcc_options ${ARGN}) + HIP_PARSE_HIPCC_OPTIONS(HIP_HIPCC_FLAGS ${_hipcc_options}) + HIP_PARSE_HIPCC_OPTIONS(HIP_HCC_FLAGS ${_hcc_options}) + HIP_PARSE_HIPCC_OPTIONS(HIP_CLANG_FLAGS ${_clang_options}) + HIP_PARSE_HIPCC_OPTIONS(HIP_NVCC_FLAGS ${_nvcc_options}) + + # Add the compile definitions + set(compile_definition_generator "$") + list(APPEND HIP_HIPCC_FLAGS "$<$:-D$>") + + # Check if we are building shared library. + set(_hip_build_shared_libs FALSE) + list(FIND _hip_cmake_options SHARED _hip_found_SHARED) + list(FIND _hip_cmake_options MODULE _hip_found_MODULE) + if(_hip_found_SHARED GREATER -1 OR _hip_found_MODULE GREATER -1) + set(_hip_build_shared_libs TRUE) + endif() + list(FIND _hip_cmake_options STATIC _hip_found_STATIC) + if(_hip_found_STATIC GREATER -1) + set(_hip_build_shared_libs FALSE) + endif() + + # If we are building a shared library, add extra flags to HIP_HIPCC_FLAGS + if(_hip_build_shared_libs) + list(APPEND HIP_HCC_FLAGS "-fPIC") + list(APPEND HIP_CLANG_FLAGS "-fPIC") + list(APPEND HIP_NVCC_FLAGS "--shared -Xcompiler '-fPIC'") + endif() + + # Set host compiler + set(HIP_HOST_COMPILER "${CMAKE_${HIP_C_OR_CXX}_COMPILER}") + + # Set compiler flags + set(_HIP_HOST_FLAGS "set(CMAKE_HOST_FLAGS ${CMAKE_${HIP_C_OR_CXX}_FLAGS})") + set(_HIP_HIPCC_FLAGS "set(HIP_HIPCC_FLAGS ${HIP_HIPCC_FLAGS})") + set(_HIP_HCC_FLAGS "set(HIP_HCC_FLAGS ${HIP_HCC_FLAGS})") + set(_HIP_CLANG_FLAGS "set(HIP_CLANG_FLAGS ${HIP_CLANG_FLAGS})") + set(_HIP_NVCC_FLAGS "set(HIP_NVCC_FLAGS ${HIP_NVCC_FLAGS})") + foreach(config ${_hip_configuration_types}) + string(TOUPPER ${config} config_upper) + set(_HIP_HOST_FLAGS "${_HIP_HOST_FLAGS}\nset(CMAKE_HOST_FLAGS_${config_upper} ${CMAKE_${HIP_C_OR_CXX}_FLAGS_${config_upper}})") + set(_HIP_HIPCC_FLAGS "${_HIP_HIPCC_FLAGS}\nset(HIP_HIPCC_FLAGS_${config_upper} ${HIP_HIPCC_FLAGS_${config_upper}})") + set(_HIP_HCC_FLAGS "${_HIP_HCC_FLAGS}\nset(HIP_HCC_FLAGS_${config_upper} ${HIP_HCC_FLAGS_${config_upper}})") + set(_HIP_CLANG_FLAGS "${_HIP_CLANG_FLAGS}\nset(HIP_CLANG_FLAGS_${config_upper} ${HIP_CLANG_FLAGS_${config_upper}})") + set(_HIP_NVCC_FLAGS "${_HIP_NVCC_FLAGS}\nset(HIP_NVCC_FLAGS_${config_upper} ${HIP_NVCC_FLAGS_${config_upper}})") + endforeach() + + # Reset the output variable + set(_hip_generated_files "") + set(_hip_source_files "") + + # Iterate over all arguments and create custom commands for all source files + foreach(file ${ARGN}) + # Ignore any file marked as a HEADER_FILE_ONLY + get_source_file_property(_is_header ${file} HEADER_FILE_ONLY) + # Allow per source file overrides of the format. Also allows compiling non .cu files. + get_source_file_property(_hip_source_format ${file} HIP_SOURCE_PROPERTY_FORMAT) + if((${file} MATCHES "\\.cu$" OR _hip_source_format) AND NOT _is_header) + set(host_flag FALSE) + else() + set(host_flag TRUE) + endif() + + if(NOT host_flag) + # Determine output directory + HIP_COMPUTE_BUILD_PATH("${file}" hip_build_path) + set(hip_compile_output_dir "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${_target}.dir/${hip_build_path}") + + get_filename_component(basename ${file} NAME) + set(generated_file_path "${hip_compile_output_dir}/${CMAKE_CFG_INTDIR}") + set(generated_file_basename "${_target}_generated_${basename}${generated_extension}") + + # Set file names + set(generated_file "${generated_file_path}/${generated_file_basename}") + set(cmake_dependency_file "${hip_compile_output_dir}/${generated_file_basename}.depend") + set(custom_target_script_pregen "${hip_compile_output_dir}/${generated_file_basename}.cmake.pre-gen") + set(custom_target_script "${hip_compile_output_dir}/${generated_file_basename}.cmake") + + # Set properties for object files + set_source_files_properties("${generated_file}" + PROPERTIES + EXTERNAL_OBJECT true # This is an object file not to be compiled, but only be linked + ) + + # Don't add CMAKE_CURRENT_SOURCE_DIR if the path is already an absolute path + get_filename_component(file_path "${file}" PATH) + if(IS_ABSOLUTE "${file_path}") + set(source_file "${file}") + else() + set(source_file "${CMAKE_CURRENT_SOURCE_DIR}/${file}") + endif() + + # Bring in the dependencies + HIP_INCLUDE_HIPCC_DEPENDENCIES(${cmake_dependency_file}) + + # Configure the build script + configure_file("${HIP_run_hipcc}" "${custom_target_script_pregen}" @ONLY) + file(GENERATE + OUTPUT "${custom_target_script}" + INPUT "${custom_target_script_pregen}" + ) + set(main_dep DEPENDS ${source_file}) + if(CMAKE_GENERATOR MATCHES "Makefiles") + set(verbose_output "$(VERBOSE)") + elseif(HIP_VERBOSE_BUILD) + set(verbose_output ON) + else() + set(verbose_output OFF) + endif() + + # Create up the comment string + file(RELATIVE_PATH generated_file_relative_path "${CMAKE_BINARY_DIR}" "${generated_file}") + set(hip_build_comment_string "Building HIPCC object ${generated_file_relative_path}") + + # Build the generated file and dependency file + add_custom_command( + OUTPUT ${generated_file} + # These output files depend on the source_file and the contents of cmake_dependency_file + ${main_dep} + DEPENDS ${HIP_HIPCC_DEPEND} + DEPENDS ${custom_target_script} + # Make sure the output directory exists before trying to write to it. + COMMAND ${CMAKE_COMMAND} -E make_directory "${generated_file_path}" + COMMAND ${CMAKE_COMMAND} ARGS + -D verbose:BOOL=${verbose_output} + -D build_configuration:STRING=${_hip_build_configuration} + -D "generated_file:STRING=${generated_file}" + -P "${custom_target_script}" + WORKING_DIRECTORY "${hip_compile_output_dir}" + COMMENT "${hip_build_comment_string}" + ) + + # Make sure the build system knows the file is generated + set_source_files_properties(${generated_file} PROPERTIES GENERATED TRUE) + list(APPEND _hip_generated_files ${generated_file}) + list(APPEND _hip_source_files ${file}) + endif() + endforeach() + + # Set the return parameter + set(${_generated_files} ${_hip_generated_files}) + set(${_source_files} ${_hip_source_files}) +endmacro() + +############################################################################### +# HIP_ADD_EXECUTABLE +############################################################################### +macro(HIP_ADD_EXECUTABLE hip_target) + # Separate the sources from the options + HIP_GET_SOURCES_AND_OPTIONS(_sources _cmake_options _hipcc_options _hcc_options _clang_options _nvcc_options ${ARGN}) + HIP_PREPARE_TARGET_COMMANDS(${hip_target} OBJ _generated_files _source_files ${_sources} HIPCC_OPTIONS ${_hipcc_options} HCC_OPTIONS ${_hcc_options} CLANG_OPTIONS ${_clang_options} NVCC_OPTIONS ${_nvcc_options}) + if(_source_files) + list(REMOVE_ITEM _sources ${_source_files}) + endif() + if("${HIP_COMPILER}" STREQUAL "hcc") + if("x${HCC_HOME}" STREQUAL "x") + if (DEFINED ENV{ROCM_PATH}) + set(HCC_HOME "$ENV{ROCM_PATH}/hcc") + elseif(DEFINED ENV{HIP_PATH}) + set(HCC_HOME "$ENV{HIP_PATH}/../hcc") + else() + set(HCC_HOME "/opt/rocm/hcc") + endif() + endif() + set(CMAKE_HIP_LINK_EXECUTABLE "${HIP_HIPCC_CMAKE_LINKER_HELPER} ${HCC_HOME} -o ") + elseif("${HIP_COMPILER}" STREQUAL "clang") + if("x${HIP_CLANG_PATH}" STREQUAL "x") + if(DEFINED ENV{HIP_CLANG_PATH}) + set(HIP_CLANG_PATH $ENV{HIP_CLANG_PATH}) + elseif(DEFINED ENV{ROCM_PATH}) + set(HIP_CLANG_PATH "$ENV{ROCM_PATH}/llvm/bin") + elseif(DEFINED ENV{HIP_PATH}) + set(HIP_CLANG_PATH "$ENV{HIP_PATH}/../llvm/bin") + else() + set(HIP_CLANG_PATH "/opt/rocm/llvm/bin") + endif() + endif() + set(CMAKE_HIP_LINK_EXECUTABLE "${HIP_HIPCC_CMAKE_LINKER_HELPER} ${HIP_CLANG_PATH} ${HIP_CLANG_PARALLEL_BUILD_LINK_OPTIONS} -o ") + else() + set(CMAKE_HIP_LINK_EXECUTABLE "${HIP_HIPCC_CMAKE_LINKER_HELPER} -o ") + endif() + if ("${_sources}" STREQUAL "") + add_executable(${hip_target} ${_cmake_options} ${_generated_files} "") + else() + add_executable(${hip_target} ${_cmake_options} ${_generated_files} ${_sources}) + endif() + set_target_properties(${hip_target} PROPERTIES LINKER_LANGUAGE HIP) + # Link with host + if (HIP_HOST_INTERFACE) + # hip rt should be rocclr, compiler should be clang + target_link_libraries(${hip_target} ${HIP_HOST_INTERFACE}) + endif() +endmacro() + +############################################################################### +# HIP_ADD_LIBRARY +############################################################################### +macro(HIP_ADD_LIBRARY hip_target) + # Separate the sources from the options + HIP_GET_SOURCES_AND_OPTIONS(_sources _cmake_options _hipcc_options _hcc_options _clang_options _nvcc_options ${ARGN}) + HIP_PREPARE_TARGET_COMMANDS(${hip_target} OBJ _generated_files _source_files ${_sources} ${_cmake_options} HIPCC_OPTIONS ${_hipcc_options} HCC_OPTIONS ${_hcc_options} CLANG_OPTIONS ${_clang_options} NVCC_OPTIONS ${_nvcc_options}) + if(_source_files) + list(REMOVE_ITEM _sources ${_source_files}) + endif() + if ("${_sources}" STREQUAL "") + add_library(${hip_target} ${_cmake_options} ${_generated_files} "") + else() + add_library(${hip_target} ${_cmake_options} ${_generated_files} ${_sources}) + endif() + set_target_properties(${hip_target} PROPERTIES LINKER_LANGUAGE ${HIP_C_OR_CXX}) + # Link with host + if (HIP_HOST_INTERFACE) + # hip rt should be rocclr, compiler should be clang + target_link_libraries(${hip_target} ${HIP_HOST_INTERFACE}) + endif() +endmacro() + +# vim: ts=4:sw=4:expandtab:smartindent diff --git a/config/cmake/modules/FindHIP/run_hipcc.cmake b/config/cmake/modules/FindHIP/run_hipcc.cmake new file mode 100644 index 0000000000..ce0b406ce7 --- /dev/null +++ b/config/cmake/modules/FindHIP/run_hipcc.cmake @@ -0,0 +1,182 @@ +############################################################################### +# Runs commands using HIPCC +############################################################################### + +############################################################################### +# This file runs the hipcc commands to produce the desired output file +# along with the dependency file needed by CMake to compute dependencies. +# +# Input variables: +# +# verbose:BOOL=<> OFF: Be as quiet as possible (default) +# ON : Describe each step +# build_configuration:STRING=<> Build configuration. Defaults to Debug. +# generated_file:STRING=<> File to generate. Mandatory argument. + +if(NOT build_configuration) + set(build_configuration Debug) +endif() +if(NOT generated_file) + message(FATAL_ERROR "You must specify generated_file on the command line") +endif() + +# Set these up as variables to make reading the generated file easier +set(HIP_HIPCC_EXECUTABLE "@HIP_HIPCC_EXECUTABLE@") # path +set(HIP_HIPCONFIG_EXECUTABLE "@HIP_HIPCONFIG_EXECUTABLE@") #path +set(HIP_HOST_COMPILER "@HIP_HOST_COMPILER@") # path +set(CMAKE_COMMAND "@CMAKE_COMMAND@") # path +set(HIP_run_make2cmake "@HIP_run_make2cmake@") # path +set(HCC_HOME "@HCC_HOME@") #path +set(HIP_CLANG_PATH "@HIP_CLANG_PATH@") #path +set(HIP_CLANG_PARALLEL_BUILD_COMPILE_OPTIONS "@HIP_CLANG_PARALLEL_BUILD_COMPILE_OPTIONS@") + +@HIP_HOST_FLAGS@ +@_HIP_HIPCC_FLAGS@ +@_HIP_HCC_FLAGS@ +@_HIP_CLANG_FLAGS@ +@_HIP_NVCC_FLAGS@ +#Needed to bring the HIP_HIPCC_INCLUDE_ARGS variable in scope +set(HIP_HIPCC_INCLUDE_ARGS @HIP_HIPCC_INCLUDE_ARGS@) # list + +set(cmake_dependency_file "@cmake_dependency_file@") # path +set(source_file "@source_file@") # path +set(host_flag "@host_flag@") # bool + +# Determine compiler and compiler flags +execute_process(COMMAND ${HIP_HIPCONFIG_EXECUTABLE} --platform OUTPUT_VARIABLE HIP_PLATFORM OUTPUT_STRIP_TRAILING_WHITESPACE) +execute_process(COMMAND ${HIP_HIPCONFIG_EXECUTABLE} --compiler OUTPUT_VARIABLE HIP_COMPILER OUTPUT_STRIP_TRAILING_WHITESPACE) +execute_process(COMMAND ${HIP_HIPCONFIG_EXECUTABLE} --runtime OUTPUT_VARIABLE HIP_RUNTIME OUTPUT_STRIP_TRAILING_WHITESPACE) +if(NOT host_flag) + set(__CC ${HIP_HIPCC_EXECUTABLE}) + if("${HIP_PLATFORM}" STREQUAL "amd") + if("${HIP_COMPILER}" STREQUAL "hcc") + if(NOT "x${HCC_HOME}" STREQUAL "x") + set(ENV{HCC_HOME} ${HCC_HOME}) + endif() + set(__CC_FLAGS ${HIP_HIPCC_FLAGS} ${HIP_HCC_FLAGS} ${HIP_HIPCC_FLAGS_${build_configuration}} ${HIP_HCC_FLAGS_${build_configuration}}) + elseif("${HIP_COMPILER}" STREQUAL "clang") + if(NOT "x${HIP_CLANG_PATH}" STREQUAL "x") + set(ENV{HIP_CLANG_PATH} ${HIP_CLANG_PATH}) + endif() + # Temporarily include HIP_HCC_FLAGS for HIP-Clang for PyTorch builds + set(__CC_FLAGS ${HIP_CLANG_PARALLEL_BUILD_COMPILE_OPTIONS} ${HIP_HIPCC_FLAGS} ${HIP_HCC_FLAGS} ${HIP_CLANG_FLAGS} ${HIP_HIPCC_FLAGS_${build_configuration}} ${HIP_HCC_FLAGS_${build_configuration}} ${HIP_CLANG_FLAGS_${build_configuration}}) + endif() + else() + set(__CC_FLAGS ${HIP_HIPCC_FLAGS} ${HIP_NVCC_FLAGS} ${HIP_HIPCC_FLAGS_${build_configuration}} ${HIP_NVCC_FLAGS_${build_configuration}}) + endif() +else() + set(__CC ${HIP_HOST_COMPILER}) + set(__CC_FLAGS ${CMAKE_HOST_FLAGS} ${CMAKE_HOST_FLAGS_${build_configuration}}) +endif() +set(__CC_INCLUDES ${HIP_HIPCC_INCLUDE_ARGS}) + +# hip_execute_process - Executes a command with optional command echo and status message. +# status - Status message to print if verbose is true +# command - COMMAND argument from the usual execute_process argument structure +# ARGN - Remaining arguments are the command with arguments +# HIP_result - Return value from running the command +macro(hip_execute_process status command) + set(_command ${command}) + if(NOT "x${_command}" STREQUAL "xCOMMAND") + message(FATAL_ERROR "Malformed call to hip_execute_process. Missing COMMAND as second argument. (command = ${command})") + endif() + if(verbose) + execute_process(COMMAND "${CMAKE_COMMAND}" -E echo -- ${status}) + # Build command string to print + set(hip_execute_process_string) + foreach(arg ${ARGN}) + # Escape quotes if any + string(REPLACE "\"" "\\\"" arg ${arg}) + # Surround args with spaces with quotes + if(arg MATCHES " ") + list(APPEND hip_execute_process_string "\"${arg}\"") + else() + list(APPEND hip_execute_process_string ${arg}) + endif() + endforeach() + # Echo the command + execute_process(COMMAND ${CMAKE_COMMAND} -E echo ${hip_execute_process_string}) + endif() + # Run the command + execute_process(COMMAND ${ARGN} RESULT_VARIABLE HIP_result) +endmacro() + +# Delete the target file +hip_execute_process( + "Removing ${generated_file}" + COMMAND "${CMAKE_COMMAND}" -E remove "${generated_file}" + ) + +# Generate the dependency file +hip_execute_process( + "Generating dependency file: ${cmake_dependency_file}.pre" + COMMAND "${__CC}" + -M + "${source_file}" + -o "${cmake_dependency_file}.pre" + ${__CC_FLAGS} + ${__CC_INCLUDES} + ) + +if(HIP_result) + message(FATAL_ERROR "Error generating ${generated_file}") +endif() + +# Generate the cmake readable dependency file to a temp file +hip_execute_process( + "Generating temporary cmake readable file: ${cmake_dependency_file}.tmp" + COMMAND "${CMAKE_COMMAND}" + -D "input_file:FILEPATH=${cmake_dependency_file}.pre" + -D "output_file:FILEPATH=${cmake_dependency_file}.tmp" + -D "verbose=${verbose}" + -P "${HIP_run_make2cmake}" + ) + +if(HIP_result) + message(FATAL_ERROR "Error generating ${generated_file}") +endif() + +# Copy the file if it is different +hip_execute_process( + "Copy if different ${cmake_dependency_file}.tmp to ${cmake_dependency_file}" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${cmake_dependency_file}.tmp" "${cmake_dependency_file}" + ) + +if(HIP_result) + message(FATAL_ERROR "Error generating ${generated_file}") +endif() + +# Delete the temporary file +hip_execute_process( + "Removing ${cmake_dependency_file}.tmp and ${cmake_dependency_file}.pre" + COMMAND "${CMAKE_COMMAND}" -E remove "${cmake_dependency_file}.tmp" "${cmake_dependency_file}.pre" + ) + +if(HIP_result) + message(FATAL_ERROR "Error generating ${generated_file}") +endif() + +# Generate the output file +hip_execute_process( + "Generating ${generated_file}" + COMMAND "${__CC}" + -c + "${source_file}" + -o "${generated_file}" + ${__CC_FLAGS} + ${__CC_INCLUDES} + ) + +if(HIP_result) + # Make sure that we delete the output file + hip_execute_process( + "Removing ${generated_file}" + COMMAND "${CMAKE_COMMAND}" -E remove "${generated_file}" + ) + message(FATAL_ERROR "Error generating file ${generated_file}") +else() + if(verbose) + message("Generated ${generated_file} successfully.") + endif() +endif() +# vim: ts=4:sw=4:expandtab:smartindent diff --git a/config/cmake/modules/FindHIP/run_make2cmake.cmake b/config/cmake/modules/FindHIP/run_make2cmake.cmake new file mode 100644 index 0000000000..d2e3eb5169 --- /dev/null +++ b/config/cmake/modules/FindHIP/run_make2cmake.cmake @@ -0,0 +1,50 @@ +############################################################################### +# Computes dependencies using HIPCC +############################################################################### + +############################################################################### +# This file converts dependency files generated using hipcc to a format that +# cmake can understand. + +# Input variables: +# +# input_file:STRING=<> Dependency file to parse. Required argument +# output_file:STRING=<> Output file to generate. Required argument + +if(NOT input_file OR NOT output_file) + message(FATAL_ERROR "You must specify input_file and output_file on the command line") +endif() + +file(READ ${input_file} depend_text) + +if (NOT "${depend_text}" STREQUAL "") + string(REPLACE " /" "\n/" depend_text ${depend_text}) + string(REGEX REPLACE "^.*:" "" depend_text ${depend_text}) + string(REGEX REPLACE "[ \\\\]*\n" ";" depend_text ${depend_text}) + + set(dependency_list "") + + foreach(file ${depend_text}) + string(REGEX REPLACE "^ +" "" file ${file}) + if(NOT EXISTS "${file}") + message(WARNING " Removing non-existent dependency file: ${file}") + set(file "") + endif() + + if(NOT IS_DIRECTORY "${file}") + get_filename_component(file_absolute "${file}" ABSOLUTE) + list(APPEND dependency_list "${file_absolute}") + endif() + endforeach() +endif() + +# Remove the duplicate entries and sort them. +list(REMOVE_DUPLICATES dependency_list) +list(SORT dependency_list) + +foreach(file ${dependency_list}) + set(hip_hipcc_depend "${hip_hipcc_depend} \"${file}\"\n") +endforeach() + +file(WRITE ${output_file} "# Generated by: FindHIP.cmake. Do not edit.\nSET(HIP_HIPCC_DEPEND\n ${hip_hipcc_depend})\n\n") +# vim: ts=4:sw=4:expandtab:smartindent diff --git a/config/cmake/modules/FindHYPRE.cmake b/config/cmake/modules/FindHYPRE.cmake index e79515e1d9..7387d6505c 100644 --- a/config/cmake/modules/FindHYPRE.cmake +++ b/config/cmake/modules/FindHYPRE.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/config/cmake/modules/FindLIBDL.cmake b/config/cmake/modules/FindLIBDL.cmake index be5760b5bb..2c0b0ee884 100644 --- a/config/cmake/modules/FindLIBDL.cmake +++ b/config/cmake/modules/FindLIBDL.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/config/cmake/modules/FindLibunwind.cmake b/config/cmake/modules/FindLibunwind.cmake index bbc74bb20f..8a607fa31a 100644 --- a/config/cmake/modules/FindLibunwind.cmake +++ b/config/cmake/modules/FindLibunwind.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/config/cmake/modules/FindMETIS.cmake b/config/cmake/modules/FindMETIS.cmake index 0fdf24522a..3eab2b9fa8 100644 --- a/config/cmake/modules/FindMETIS.cmake +++ b/config/cmake/modules/FindMETIS.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # @@ -25,16 +25,16 @@ mfem_find_package(METIS METIS METIS_DIR "include;Lib" "metis.h" int main() { - int n = 10; - int nparts = 5; - int edgecut; - int* partitioning = new int[10]; - int* I = partitioning, + idx_t n = 10; + idx_t nparts = 5; + idx_t edgecut; + idx_t* partitioning = new idx_t[10]; + idx_t* I = partitioning, * J = partitioning; - int ncon = 1; + idx_t ncon = 1; int err; - int options[40]; + idx_t options[40]; METIS_SetDefaultOptions(options); options[10] = 1; // set METIS_OPTION_CONTIG diff --git a/config/cmake/modules/FindMFEMBacktrace.cmake b/config/cmake/modules/FindMFEMBacktrace.cmake index 818bb34923..08473ceb35 100644 --- a/config/cmake/modules/FindMFEMBacktrace.cmake +++ b/config/cmake/modules/FindMFEMBacktrace.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/config/cmake/modules/FindMKL_CPARDISO.cmake b/config/cmake/modules/FindMKL_CPARDISO.cmake index 5334d97539..c0507000c8 100644 --- a/config/cmake/modules/FindMKL_CPARDISO.cmake +++ b/config/cmake/modules/FindMKL_CPARDISO.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/config/cmake/modules/FindMPFR.cmake b/config/cmake/modules/FindMPFR.cmake index 79f74d499b..32e58f56a6 100644 --- a/config/cmake/modules/FindMPFR.cmake +++ b/config/cmake/modules/FindMPFR.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/config/cmake/modules/FindMUMPS.cmake b/config/cmake/modules/FindMUMPS.cmake index e09551a7d7..a5fa61b994 100644 --- a/config/cmake/modules/FindMUMPS.cmake +++ b/config/cmake/modules/FindMUMPS.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/config/cmake/modules/FindMesquite.cmake b/config/cmake/modules/FindMesquite.cmake index 72a1e8c70c..413e8d9ac2 100644 --- a/config/cmake/modules/FindMesquite.cmake +++ b/config/cmake/modules/FindMesquite.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/config/cmake/modules/FindNetCDF.cmake b/config/cmake/modules/FindNetCDF.cmake index 9b9caf3e89..f2aa79ebb5 100644 --- a/config/cmake/modules/FindNetCDF.cmake +++ b/config/cmake/modules/FindNetCDF.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/config/cmake/modules/FindOCCA.cmake b/config/cmake/modules/FindOCCA.cmake index 59e3c14624..b3e010237b 100644 --- a/config/cmake/modules/FindOCCA.cmake +++ b/config/cmake/modules/FindOCCA.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/config/cmake/modules/FindPOSIXClocks.cmake b/config/cmake/modules/FindPOSIXClocks.cmake index c369d472ed..910c62359a 100644 --- a/config/cmake/modules/FindPOSIXClocks.cmake +++ b/config/cmake/modules/FindPOSIXClocks.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/config/cmake/modules/FindParMETIS.cmake b/config/cmake/modules/FindParMETIS.cmake index e4e42db11b..c9ebd0cde6 100644 --- a/config/cmake/modules/FindParMETIS.cmake +++ b/config/cmake/modules/FindParMETIS.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/config/cmake/modules/FindRAJA.cmake b/config/cmake/modules/FindRAJA.cmake index 5cf350ace4..82035114e8 100644 --- a/config/cmake/modules/FindRAJA.cmake +++ b/config/cmake/modules/FindRAJA.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/config/cmake/modules/FindSLEPc.cmake b/config/cmake/modules/FindSLEPc.cmake index fa02139910..53d2a58715 100644 --- a/config/cmake/modules/FindSLEPc.cmake +++ b/config/cmake/modules/FindSLEPc.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/config/cmake/modules/FindSTRUMPACK.cmake b/config/cmake/modules/FindSTRUMPACK.cmake index 93f3981745..d7696bccc6 100644 --- a/config/cmake/modules/FindSTRUMPACK.cmake +++ b/config/cmake/modules/FindSTRUMPACK.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/config/cmake/modules/FindSUNDIALS.cmake b/config/cmake/modules/FindSUNDIALS.cmake index 51d7adab49..23341e5059 100644 --- a/config/cmake/modules/FindSUNDIALS.cmake +++ b/config/cmake/modules/FindSUNDIALS.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/config/cmake/modules/FindScotch.cmake b/config/cmake/modules/FindScotch.cmake index e78ad1c21d..f3b82369b3 100644 --- a/config/cmake/modules/FindScotch.cmake +++ b/config/cmake/modules/FindScotch.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/config/cmake/modules/FindSuiteSparse.cmake b/config/cmake/modules/FindSuiteSparse.cmake index 328ca3e8a3..4a1777a2d8 100644 --- a/config/cmake/modules/FindSuiteSparse.cmake +++ b/config/cmake/modules/FindSuiteSparse.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/config/cmake/modules/FindSuperLUDist.cmake b/config/cmake/modules/FindSuperLUDist.cmake index 96e4e98422..ccb326bf9f 100644 --- a/config/cmake/modules/FindSuperLUDist.cmake +++ b/config/cmake/modules/FindSuperLUDist.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/config/cmake/modules/FindUMPIRE.cmake b/config/cmake/modules/FindUMPIRE.cmake index c49e3bdccc..4dc929c52e 100644 --- a/config/cmake/modules/FindUMPIRE.cmake +++ b/config/cmake/modules/FindUMPIRE.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/config/cmake/modules/Find_GnuTLS.cmake b/config/cmake/modules/Find_GnuTLS.cmake index c288b7146a..4e0b229256 100644 --- a/config/cmake/modules/Find_GnuTLS.cmake +++ b/config/cmake/modules/Find_GnuTLS.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/config/cmake/modules/FindlibCEED.cmake b/config/cmake/modules/FindlibCEED.cmake index adc3486b3a..47d5693247 100644 --- a/config/cmake/modules/FindlibCEED.cmake +++ b/config/cmake/modules/FindlibCEED.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/config/cmake/modules/MfemCmakeUtilities.cmake b/config/cmake/modules/MfemCmakeUtilities.cmake index d56b72ecd6..89bf1dcf88 100644 --- a/config/cmake/modules/MfemCmakeUtilities.cmake +++ b/config/cmake/modules/MfemCmakeUtilities.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # @@ -43,6 +43,24 @@ function(convert_filenames_to_full_paths NAMES) set(${NAMES} ${tmp_names} PARENT_SCOPE) endfunction() +# Wrapper for add_executable that calls the HIP wrapper if applicable +macro(mfem_add_executable NAME) + if (MFEM_USE_HIP) + hip_add_executable(${NAME} ${ARGN}) + else() + add_executable(${NAME} ${ARGN}) + endif() +endmacro() + +# Wrapper for add_library that calls the HIP wrapper if applicable +macro(mfem_add_library NAME) + if (MFEM_USE_HIP) + hip_add_library(${NAME} ${ARGN}) + else() + add_library(${NAME} ${ARGN}) + endif() +endmacro() + # Simple shortcut to add_custom_target() with option to add the target to the # main target. function(add_mfem_target TARGET_NAME ADD_TO_ALL) @@ -56,7 +74,7 @@ function(add_mfem_target TARGET_NAME ADD_TO_ALL) endfunction() # Add mfem examples -function(add_mfem_examples EXE_SRCS) +macro(add_mfem_examples EXE_SRCS) set(EXE_PREFIX "") set(EXE_PREREQUISITE "") set(EXE_NEEDED_BY "") @@ -72,13 +90,15 @@ function(add_mfem_examples EXE_SRCS) foreach(SRC_FILE IN LISTS ${EXE_SRCS}) # If CUDA is enabled, tag source files to be compiled with nvcc. if (MFEM_USE_CUDA) - set_property(SOURCE ${SRC_FILE} PROPERTY LANGUAGE CUDA) + set_source_files_properties(${SRC_FILE} PROPERTIES LANGUAGE CUDA) + elseif(MFEM_USE_HIP) + set_source_files_properties(${SRC_FILE} PROPERTIES HIP_SOURCE_PROPERTY_FORMAT TRUE) endif() get_filename_component(SRC_FILENAME ${SRC_FILE} NAME) string(REPLACE ".cpp" "" EXE_NAME "${EXE_PREFIX}${SRC_FILENAME}") - add_executable(${EXE_NAME} ${SRC_FILE}) + mfem_add_executable(${EXE_NAME} ${SRC_FILE}) add_dependencies(${MFEM_ALL_EXAMPLES_TARGET_NAME} ${EXE_NAME}) if (EXE_NEEDED_BY) add_dependencies(${EXE_NEEDED_BY} ${EXE_NAME}) @@ -107,10 +127,10 @@ function(add_mfem_examples EXE_SRCS) endif() endif() endforeach(SRC_FILE) -endfunction() +endmacro() # A slightly more versatile function for adding miniapps to MFEM -function(add_mfem_miniapp MFEM_EXE_NAME) +macro(add_mfem_miniapp MFEM_EXE_NAME) # Parse the input arguments looking for the things we need set(POSSIBLE_ARGS "MAIN" "EXTRA_SOURCES" "EXTRA_HEADERS" "EXTRA_OPTIONS" "EXTRA_DEFINES" "LIBRARIES") set(CURRENT_ARG) @@ -126,8 +146,7 @@ function(add_mfem_miniapp MFEM_EXE_NAME) # If CUDA is enabled, tag source files to be compiled with nvcc. if (MFEM_USE_CUDA) - set_property(SOURCE ${MAIN_LIST} ${EXTRA_SOURCES_LIST} - PROPERTY LANGUAGE CUDA) + set_source_files_properties(${MAIN_LIST} ${EXTRA_SOURCES_LIST} PROPERTIES LANGUAGE CUDA) if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0) list(TRANSFORM EXTRA_OPTIONS_LIST PREPEND "-Xcompiler=") else() @@ -137,11 +156,13 @@ function(add_mfem_miniapp MFEM_EXE_NAME) endforeach() set(EXTRA_OPTIONS_LIST ${LIST_}) endif() + elseif(MFEM_USE_HIP) + set_source_files_properties(${MAIN_LIST} ${EXTRA_SOURCES_LIST} PROPERTIES HIP_SOURCE_PROPERTY_FORMAT TRUE) endif() # Actually add the executable - add_executable(${MFEM_EXE_NAME} ${MAIN_LIST} - ${EXTRA_SOURCES_LIST} ${EXTRA_HEADERS_LIST}) + mfem_add_executable(${MFEM_EXE_NAME} ${MAIN_LIST} + ${EXTRA_SOURCES_LIST} ${EXTRA_HEADERS_LIST}) add_dependencies(${MFEM_ALL_MINIAPPS_TARGET_NAME} ${MFEM_EXE_NAME}) add_dependencies(${MFEM_EXE_NAME} ${MFEM_EXEC_PREREQUISITES_TARGET_NAME}) @@ -194,7 +215,7 @@ function(add_mfem_miniapp MFEM_EXE_NAME) LINK_FLAGS "${MPI_CXX_LINK_FLAGS}") endif() endif() -endfunction() +endmacro() # Auxiliary function, used in mfem_find_package(). @@ -754,7 +775,13 @@ function(mfem_export_mk_files) set(MFEM_CXX ${CMAKE_CXX_COMPILER}) set(MFEM_HOST_CXX ${MFEM_CXX}) set(MFEM_CPPFLAGS "") - string(STRIP "${CMAKE_CXX_FLAGS_${BUILD_TYPE}} ${CMAKE_CXX_FLAGS}" + get_target_property(cxx_std mfem CXX_STANDARD) + # For now, we ignore the setting of the CXX_EXTENSIONS property. If this + # property is set, then we need to use a variable like: + # CMAKE_CXX11_EXTENSION_COMPILE_OPTION + set(cxx_std_flag ${CMAKE_CXX${cxx_std}_STANDARD_COMPILE_OPTION}) + string(STRIP + "${cxx_std_flag} ${CMAKE_CXX_FLAGS_${BUILD_TYPE}} ${CMAKE_CXX_FLAGS}" MFEM_CXXFLAGS) set(MFEM_TPLFLAGS "") foreach(dir ${MFEM_TPL_INCLUDE_DIRS}) diff --git a/config/config.hpp b/config/config.hpp index 9aed248ed2..bd67282df9 100644 --- a/config/config.hpp +++ b/config/config.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/config/config.hpp.in b/config/config.hpp.in index 719f3367d2..c26cc15d27 100644 --- a/config/config.hpp.in +++ b/config/config.hpp.in @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/config/config.mk.in b/config/config.mk.in index 33ccf429d7..7f4499c65b 100644 --- a/config/config.mk.in +++ b/config/config.mk.in @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/config/defaults.cmake b/config/defaults.cmake index 2f99e56533..9cf41e8abe 100644 --- a/config/defaults.cmake +++ b/config/defaults.cmake @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # @@ -76,6 +76,9 @@ option(MFEM_ENABLE_MINIAPPS "Build all of the miniapps" OFF) # Set the target CUDA architecture set(CUDA_ARCH "sm_60" CACHE STRING "Target CUDA architecture.") +# Set the target HIP architecture +set(HIP_ARCH "gfx900" CACHE STRING "Target HIP architecture.") + set(MFEM_DIR ${CMAKE_CURRENT_SOURCE_DIR}) # The *_DIR paths below will be the first place searched for the corresponding diff --git a/config/defaults.mk b/config/defaults.mk index 93fcbe0d92..a778d3105d 100644 --- a/config/defaults.mk +++ b/config/defaults.mk @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # @@ -161,7 +161,7 @@ endif ZLIB_DIR = ZLIB_OPT = $(if $(ZLIB_DIR),-I$(ZLIB_DIR)/include) ZLIB_LIB = $(if $(ZLIB_DIR),$(ZLIB_RPATH) -L$(ZLIB_DIR)/lib ,)-lz -ZLIB_RPATH = -Wl,-rpath,$(ZLIB_DIR)/lib +ZLIB_RPATH = $(XLINKER)-rpath,$(ZLIB_DIR)/lib LIBUNWIND_OPT = -g LIBUNWIND_LIB = $(if $(NOTMAC),-lunwind -ldl,) @@ -231,19 +231,21 @@ MESQUITE_LIB = -L$(MESQUITE_DIR)/lib -lmesquite LIB_RT = $(if $(NOTMAC),-lrt,) SUITESPARSE_DIR = @MFEM_DIR@/../SuiteSparse SUITESPARSE_OPT = -I$(SUITESPARSE_DIR)/include -SUITESPARSE_LIB = -Wl,-rpath,$(SUITESPARSE_DIR)/lib -L$(SUITESPARSE_DIR)/lib\ - -lklu -lbtf -lumfpack -lcholmod -lcolamd -lamd -lcamd -lccolamd\ - -lsuitesparseconfig $(LIB_RT) $(METIS_LIB) $(LAPACK_LIB) +SUITESPARSE_LIB = $(XLINKER)-rpath,$(SUITESPARSE_DIR)/lib\ + -L$(SUITESPARSE_DIR)/lib -lklu -lbtf -lumfpack -lcholmod -lcolamd -lamd -lcamd\ + -lccolamd -lsuitesparseconfig $(LIB_RT) $(METIS_LIB) $(LAPACK_LIB) # SuperLU library configuration ifeq ($(MFEM_USE_SUPERLU5),YES) SUPERLU_DIR = @MFEM_DIR@/../SuperLU_DIST_5.1.0 SUPERLU_OPT = -I$(SUPERLU_DIR)/include - SUPERLU_LIB = -Wl,-rpath,$(SUPERLU_DIR)/lib -L$(SUPERLU_DIR)/lib -lsuperlu_dist_5.1.0 + SUPERLU_LIB = $(XLINKER)-rpath,$(SUPERLU_DIR)/lib -L$(SUPERLU_DIR)/lib\ + -lsuperlu_dist_5.1.0 else SUPERLU_DIR = @MFEM_DIR@/../SuperLU_DIST_6.3.1 SUPERLU_OPT = -I$(SUPERLU_DIR)/include - SUPERLU_LIB = -Wl,-rpath,$(SUPERLU_DIR)/lib64 -L$(SUPERLU_DIR)/lib64 -lsuperlu_dist -lblas + SUPERLU_LIB = $(XLINKER)-rpath,$(SUPERLU_DIR)/lib64 -L$(SUPERLU_DIR)/lib64\ + -lsuperlu_dist -lblas endif # SCOTCH library configuration (required by STRUMPACK <= v2.1.0, optional in @@ -269,7 +271,7 @@ MPI_FORTRAN_LIB = -lmpifort # MUMPS library configuration MUMPS_DIR = @MFEM_DIR@/../MUMPS_5.2.0 MUMPS_OPT = -I$(MUMPS_DIR)/include -MUMPS_LIB = -Wl,-rpath,$(MUMPS_DIR)/lib -L$(MUMPS_DIR)/lib -ldmumps\ +MUMPS_LIB = $(XLINKER)-rpath,$(MUMPS_DIR)/lib -L$(MUMPS_DIR)/lib -ldmumps\ -lmumps_common -lpord $(SCALAPACK_LIB) $(LAPACK_LIB) $(MPI_FORTRAN_LIB) # STRUMPACK library configuration @@ -299,8 +301,8 @@ GNUTLS_LIB = -lgnutls NETCDF_DIR = $(HOME)/local HDF5_DIR = $(HOME)/local NETCDF_OPT = -I$(NETCDF_DIR)/include -I$(HDF5_DIR)/include $(ZLIB_OPT) -NETCDF_LIB = -Wl,-rpath,$(NETCDF_DIR)/lib -L$(NETCDF_DIR)/lib\ - -Wl,-rpath,$(HDF5_DIR)/lib -L$(HDF5_DIR)/lib\ +NETCDF_LIB = $(XLINKER)-rpath,$(NETCDF_DIR)/lib -L$(NETCDF_DIR)/lib\ + $(XLINKER)-rpath,$(HDF5_DIR)/lib -L$(HDF5_DIR)/lib\ -lnetcdf -lhdf5_hl -lhdf5 $(ZLIB_LIB) # PETSc library configuration (version greater or equal to 3.8 or the dev branch) @@ -312,9 +314,10 @@ PETSC_INC_VAR = PETSC_CC_INCLUDES PETSC_LIB_VAR = PETSC_EXTERNAL_LIB_BASIC ifeq ($(PETSC_FOUND),YES) PETSC_OPT := $(shell sed -n "s/$(PETSC_INC_VAR) = *//p" $(PETSC_VARS)) - PETSC_LIB := $(shell sed -n "s/$(PETSC_LIB_VAR) = *//p" $(PETSC_VARS)) - PETSC_LIB := -Wl,-rpath,$(abspath $(PETSC_DIR))/lib\ - -L$(abspath $(PETSC_DIR))/lib -lpetsc $(PETSC_LIB) + PETSC_DEP := $(shell sed -n "s/$(PETSC_LIB_VAR) = *//p" $(PETSC_VARS)) + PETSC_LIB = $(XLINKER)-rpath,$(abspath $(PETSC_DIR))/lib\ + -L$(abspath $(PETSC_DIR))/lib -lpetsc\ + $(subst $(CXX_XLINKER),$(XLINKER),$(PETSC_DEP)) endif SLEPC_DIR := $(MFEM_DIR)/../slepc @@ -326,9 +329,10 @@ ifeq ($(SLEPC_FOUND),YES) SLEPC_OPT := $(shell sed -n "s/$(SLEPC_INC_VAR) *= *//p" $(SLEPC_VARS)) # Some additional external libraries might be defined in this file -include ${SLEPC_DIR}/${PETSC_ARCH}/lib/slepc/conf/slepcvariables - SLEPC_LIB := $(shell sed -n "s/$(SLEPC_LIB_VAR) *= *//p" $(SLEPC_VARS)) - SLEPC_LIB := -Wl,-rpath,$(abspath $(SLEPC_DIR))/$(PETSC_ARCH)/lib\ - -L$(abspath $(SLEPC_DIR))/$(PETSC_ARCH)/lib -lslepc $(SLEPC_LIB) + SLEPC_DEP := $(shell sed -n "s/$(SLEPC_LIB_VAR) *= *//p" $(SLEPC_VARS)) + SLEPC_LIB = $(XLINKER)-rpath,$(abspath $(SLEPC_DIR))/$(PETSC_ARCH)/lib\ + -L$(abspath $(SLEPC_DIR))/$(PETSC_ARCH)/lib -lslepc\ + $(subst $(CXX_XLINKER),$(XLINKER),$(SLEPC_DEP)) endif # MPFR library configuration @@ -339,7 +343,7 @@ MPFR_LIB = -lmpfr CONDUIT_DIR = @MFEM_DIR@/../conduit CONDUIT_OPT = -I$(CONDUIT_DIR)/include/conduit CONDUIT_LIB = \ - -Wl,-rpath,$(CONDUIT_DIR)/lib -L$(CONDUIT_DIR)/lib \ + $(XLINKER)-rpath,$(CONDUIT_DIR)/lib -L$(CONDUIT_DIR)/lib \ -lconduit -lconduit_relay -lconduit_blueprint -ldl # Check if Conduit was built with hdf5 support, by looking @@ -347,7 +351,7 @@ CONDUIT_LIB = \ CONDUIT_HDF5_HEADER=$(CONDUIT_DIR)/include/conduit/conduit_relay_hdf5.hpp ifneq (,$(wildcard $(CONDUIT_HDF5_HEADER))) CONDUIT_OPT += -I$(HDF5_DIR)/include - CONDUIT_LIB += -Wl,-rpath,$(HDF5_DIR)/lib -L$(HDF5_DIR)/lib \ + CONDUIT_LIB += $(XLINKER)-rpath,$(HDF5_DIR)/lib -L$(HDF5_DIR)/lib \ -lhdf5 $(ZLIB_LIB) endif @@ -357,9 +361,9 @@ SIDRE_DIR = @MFEM_DIR@/../axom SIDRE_OPT = -I$(SIDRE_DIR)/include -I$(CONDUIT_DIR)/include/conduit\ -I$(HDF5_DIR)/include SIDRE_LIB = \ - -Wl,-rpath,$(SIDRE_DIR)/lib -L$(SIDRE_DIR)/lib \ - -Wl,-rpath,$(CONDUIT_DIR)/lib -L$(CONDUIT_DIR)/lib \ - -Wl,-rpath,$(HDF5_DIR)/lib -L$(HDF5_DIR)/lib \ + $(XLINKER)-rpath,$(SIDRE_DIR)/lib -L$(SIDRE_DIR)/lib \ + $(XLINKER)-rpath,$(CONDUIT_DIR)/lib -L$(CONDUIT_DIR)/lib \ + $(XLINKER)-rpath,$(HDF5_DIR)/lib -L$(HDF5_DIR)/lib \ -laxom -lconduit -lconduit_relay -lconduit_blueprint -lhdf5 $(ZLIB_LIB) -ldl # PUMI @@ -415,9 +419,9 @@ MKL_CPARDISO_DIR ?= MKL_MPI_WRAPPER ?= mkl_blacs_mpich_lp64 MKL_LIBRARY_SUBDIR ?= lib MKL_CPARDISO_OPT = -I$(MKL_CPARDISO_DIR)/include -MKL_CPARDISO_LIB = -Wl,-rpath,$(MKL_CPARDISO_DIR)/$(MKL_LIBRARY_SUBDIR)\ - -L$(MKL_CPARDISO_DIR)/$(MKL_LIBRARY_SUBDIR) -l$(MKL_MPI_WRAPPER)\ - -lmkl_intel_lp64 -lmkl_sequential -lmkl_core +MKL_CPARDISO_LIB = $(XLINKER)-rpath,$(MKL_CPARDISO_DIR)/$(MKL_LIBRARY_SUBDIR)\ + -L$(MKL_CPARDISO_DIR)/$(MKL_LIBRARY_SUBDIR) -l$(MKL_MPI_WRAPPER)\ + -lmkl_intel_lp64 -lmkl_sequential -lmkl_core # If YES, enable some informational messages VERBOSE = NO diff --git a/config/get_hypre_version.cpp b/config/get_hypre_version.cpp index 06af3d6448..94d3daacb7 100644 --- a/config/get_hypre_version.cpp +++ b/config/get_hypre_version.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/config/get_mumps_version.cpp b/config/get_mumps_version.cpp index f8e394769c..466782bbf3 100644 --- a/config/get_mumps_version.cpp +++ b/config/get_mumps_version.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/config/makefile b/config/makefile index 10b79a6aaa..509a39127e 100644 --- a/config/makefile +++ b/config/makefile @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/config/sample-runs.sh b/config/sample-runs.sh index 63a2ba9fe5..4d49e5e982 100755 --- a/config/sample-runs.sh +++ b/config/sample-runs.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/config/tconfig.hpp b/config/tconfig.hpp index a10ae8f4b6..2a78c3cea7 100644 --- a/config/tconfig.hpp +++ b/config/tconfig.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/config/test.mk b/config/test.mk index c6ea57567b..87e3de110e 100644 --- a/config/test.mk +++ b/config/test.mk @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/data/amr-hex.mesh b/data/amr-hex.mesh index cba05e3ed8..b2ad01be0e 100644 --- a/data/amr-hex.mesh +++ b/data/amr-hex.mesh @@ -1,241 +1,257 @@ -MFEM mesh v1.1 +MFEM NC mesh v1.0 -# -# MFEM Geometry Types (see mesh/geom.hpp): -# -# POINT = 0 -# SEGMENT = 1 +# NCMesh supported geometry types: # TRIANGLE = 2 # SQUARE = 3 # TETRAHEDRON = 4 # CUBE = 5 -# +# PRISM = 6 dimension 3 +# rank attr geom ref_type nodes/children elements -120 -1 5 0 27 81 30 35 82 87 85 -1 5 30 81 29 11 85 87 84 38 -1 5 85 87 84 38 34 86 33 24 -1 5 35 82 87 85 16 31 86 34 -1 5 82 36 83 87 31 21 32 86 -1 5 180 94 181 185 93 32 95 184 -1 5 92 180 185 183 86 93 184 97 -1 5 183 185 182 99 97 184 96 33 -1 5 185 181 98 182 184 95 26 96 -1 5 179 89 37 90 185 181 98 182 -1 5 91 179 90 84 183 185 182 99 -1 5 87 88 179 91 92 180 185 183 -1 5 88 83 89 179 180 94 181 185 -1 5 81 28 20 29 87 83 37 84 -1 5 27 8 28 81 82 36 83 87 -1 5 8 39 100 28 36 101 105 83 -1 5 36 101 105 83 21 42 104 32 -1 5 101 45 102 105 42 17 43 104 -1 5 39 1 40 100 101 45 102 105 -1 5 100 40 9 41 105 102 46 103 -1 5 105 102 46 103 104 43 22 44 -1 5 186 107 103 108 191 188 112 189 -1 5 106 105 107 186 187 110 188 191 -1 5 187 110 188 191 109 104 111 190 -1 5 191 188 112 189 190 111 44 113 -1 5 181 191 189 98 95 190 113 26 -1 5 94 187 191 181 32 109 190 95 -1 5 83 106 186 89 94 187 191 181 -1 5 89 186 108 37 181 191 189 98 -1 5 28 100 41 20 83 105 103 37 -1 5 20 41 114 49 37 103 119 117 -1 5 37 108 192 122 98 189 197 195 -1 5 122 192 121 117 195 197 194 127 -1 5 195 197 194 127 125 196 124 52 -1 5 98 189 197 195 26 113 196 125 -1 5 189 112 193 197 113 44 123 196 -1 5 197 193 126 194 196 123 118 124 -1 5 192 120 119 121 197 193 126 194 -1 5 108 103 120 192 189 112 193 197 -1 5 103 46 115 119 44 22 50 118 -1 5 41 9 47 114 103 46 115 119 -1 5 114 47 3 48 119 115 53 116 -1 5 119 115 53 116 118 50 18 51 -1 5 117 119 116 54 52 118 51 23 -1 5 49 114 48 10 117 119 116 54 -1 5 128 49 10 55 132 117 54 129 -1 5 56 128 55 2 130 132 129 59 -1 5 11 29 128 56 38 84 132 130 -1 5 29 20 49 128 84 37 117 132 -1 5 84 90 198 133 99 182 202 200 -1 5 90 37 122 198 182 98 195 202 -1 5 198 122 117 134 202 195 127 199 -1 5 133 198 134 132 200 202 199 136 -1 5 200 202 199 136 135 201 137 131 -1 5 202 195 127 199 201 125 52 137 -1 5 182 98 195 202 96 26 125 201 -1 5 99 182 202 200 33 96 201 135 -1 5 38 84 132 130 24 33 131 58 -1 5 130 132 129 59 58 131 57 19 -1 5 132 117 54 129 131 52 23 57 -1 5 131 52 23 57 143 139 77 140 -1 5 58 131 57 19 141 143 140 80 -1 5 24 33 131 58 67 138 143 141 -1 5 33 96 201 135 145 203 208 206 -1 5 96 26 125 201 203 150 204 208 -1 5 201 125 52 137 208 204 151 205 -1 5 135 201 137 131 206 208 205 146 -1 5 206 208 205 146 144 207 149 143 -1 5 208 204 151 205 207 148 139 149 -1 5 203 150 204 208 147 66 148 207 -1 5 145 203 208 206 138 147 207 144 -1 5 138 66 139 143 62 25 75 142 -1 5 67 138 143 141 15 62 142 79 -1 5 141 143 140 80 79 142 78 6 -1 5 143 139 77 140 142 75 14 78 -1 5 139 156 154 77 75 155 74 14 -1 5 52 118 51 23 139 156 154 77 -1 5 118 50 18 51 156 153 76 154 -1 5 156 153 76 154 155 73 7 74 -1 5 152 72 153 156 70 13 73 155 -1 5 44 22 50 118 152 72 153 156 -1 5 209 160 210 213 157 152 158 212 -1 5 213 210 161 211 212 158 156 159 -1 5 196 123 118 124 213 210 161 211 -1 5 113 44 123 196 209 160 210 213 -1 5 26 113 196 125 150 209 213 204 -1 5 125 196 124 52 204 213 211 151 -1 5 204 213 211 151 148 212 159 139 -1 5 150 209 213 204 66 157 212 148 -1 5 66 152 156 139 25 70 155 75 -1 5 164 166 152 66 61 165 70 25 -1 5 216 218 209 150 171 217 157 66 -1 5 169 214 218 216 164 167 217 171 -1 5 32 109 190 95 169 214 218 216 -1 5 95 190 113 26 216 218 209 150 -1 5 190 111 44 113 218 215 160 209 -1 5 109 104 111 190 214 168 215 218 -1 5 214 168 215 218 167 166 170 217 -1 5 218 215 160 209 217 170 152 157 -1 5 104 43 22 44 166 163 72 152 -1 5 166 163 72 152 165 69 13 70 -1 5 162 71 163 166 68 5 69 165 -1 5 42 17 43 104 162 71 163 166 -1 5 21 42 104 32 65 162 166 164 -1 5 65 162 166 164 12 68 165 61 -1 5 172 65 164 175 60 12 61 174 -1 5 175 164 66 138 174 61 25 62 -1 5 219 169 216 222 177 164 171 221 -1 5 176 219 222 220 175 177 221 178 -1 5 220 222 203 145 178 221 147 138 -1 5 222 216 150 203 221 171 66 147 -1 5 184 95 26 96 222 216 150 203 -1 5 97 184 96 33 220 222 203 145 -1 5 86 93 184 97 176 219 222 220 -1 5 93 32 95 184 219 169 216 222 -1 5 31 21 32 86 172 65 164 175 -1 5 16 31 86 34 64 172 175 173 -1 5 34 86 33 24 173 175 138 67 -1 5 173 175 138 67 63 174 62 15 -1 5 64 172 175 173 4 60 174 63 +137 +-1 1 5 7 1 18 35 52 69 86 103 120 +-1 1 5 7 2 3 4 5 6 7 8 17 +0 1 5 0 0 27 81 30 35 82 87 85 +0 1 5 0 27 8 28 81 82 36 83 87 +0 1 5 0 81 28 20 29 87 83 37 84 +0 1 5 0 30 81 29 11 85 87 84 38 +0 1 5 0 35 82 87 85 16 31 86 34 +0 1 5 0 82 36 83 87 31 21 32 86 +-1 1 5 7 9 10 11 12 13 14 15 16 +0 1 5 0 87 88 179 91 92 180 185 183 +0 1 5 0 88 83 89 179 180 94 181 185 +0 1 5 0 179 89 37 90 185 181 98 182 +0 1 5 0 91 179 90 84 183 185 182 99 +0 1 5 0 92 180 185 183 86 93 184 97 +0 1 5 0 180 94 181 185 93 32 95 184 +0 1 5 0 185 181 98 182 184 95 26 96 +0 1 5 0 183 185 182 99 97 184 96 33 +0 1 5 0 85 87 84 38 34 86 33 24 +-1 1 5 7 19 20 21 22 23 24 25 26 +0 1 5 0 8 39 100 28 36 101 105 83 +0 1 5 0 39 1 40 100 101 45 102 105 +0 1 5 0 100 40 9 41 105 102 46 103 +0 1 5 0 28 100 41 20 83 105 103 37 +0 1 5 0 36 101 105 83 21 42 104 32 +0 1 5 0 101 45 102 105 42 17 43 104 +0 1 5 0 105 102 46 103 104 43 22 44 +-1 1 5 7 27 28 29 30 31 32 33 34 +0 1 5 0 83 106 186 89 94 187 191 181 +0 1 5 0 106 105 107 186 187 110 188 191 +0 1 5 0 186 107 103 108 191 188 112 189 +0 1 5 0 89 186 108 37 181 191 189 98 +0 1 5 0 94 187 191 181 32 109 190 95 +0 1 5 0 187 110 188 191 109 104 111 190 +0 1 5 0 191 188 112 189 190 111 44 113 +0 1 5 0 181 191 189 98 95 190 113 26 +-1 1 5 7 36 37 38 39 40 49 50 51 +0 1 5 0 20 41 114 49 37 103 119 117 +0 1 5 0 41 9 47 114 103 46 115 119 +0 1 5 0 114 47 3 48 119 115 53 116 +0 1 5 0 49 114 48 10 117 119 116 54 +-1 1 5 7 41 42 43 44 45 46 47 48 +0 1 5 0 37 108 192 122 98 189 197 195 +0 1 5 0 108 103 120 192 189 112 193 197 +0 1 5 0 192 120 119 121 197 193 126 194 +0 1 5 0 122 192 121 117 195 197 194 127 +0 1 5 0 98 189 197 195 26 113 196 125 +0 1 5 0 189 112 193 197 113 44 123 196 +0 1 5 0 197 193 126 194 196 123 118 124 +0 1 5 0 195 197 194 127 125 196 124 52 +0 1 5 0 103 46 115 119 44 22 50 118 +0 1 5 0 119 115 53 116 118 50 18 51 +0 1 5 0 117 119 116 54 52 118 51 23 +-1 1 5 7 53 54 55 56 57 58 67 68 +0 1 5 0 11 29 128 56 38 84 132 130 +0 1 5 0 29 20 49 128 84 37 117 132 +0 1 5 0 128 49 10 55 132 117 54 129 +0 1 5 0 56 128 55 2 130 132 129 59 +0 1 5 0 38 84 132 130 24 33 131 58 +-1 1 5 7 59 60 61 62 63 64 65 66 +0 1 5 0 84 90 198 133 99 182 202 200 +0 1 5 0 90 37 122 198 182 98 195 202 +0 1 5 0 198 122 117 134 202 195 127 199 +0 1 5 0 133 198 134 132 200 202 199 136 +0 1 5 0 99 182 202 200 33 96 201 135 +0 1 5 0 182 98 195 202 96 26 125 201 +0 1 5 0 202 195 127 199 201 125 52 137 +0 1 5 0 200 202 199 136 135 201 137 131 +0 1 5 0 132 117 54 129 131 52 23 57 +0 1 5 0 130 132 129 59 58 131 57 19 +-1 1 5 7 70 71 72 81 82 83 84 85 +0 1 5 0 16 31 86 34 64 172 175 173 +0 1 5 0 31 21 32 86 172 65 164 175 +-1 1 5 7 73 74 75 76 77 78 79 80 +0 1 5 0 86 93 184 97 176 219 222 220 +0 1 5 0 93 32 95 184 219 169 216 222 +0 1 5 0 184 95 26 96 222 216 150 203 +0 1 5 0 97 184 96 33 220 222 203 145 +0 1 5 0 176 219 222 220 175 177 221 178 +0 1 5 0 219 169 216 222 177 164 171 221 +0 1 5 0 222 216 150 203 221 171 66 147 +0 1 5 0 220 222 203 145 178 221 147 138 +0 1 5 0 34 86 33 24 173 175 138 67 +0 1 5 0 64 172 175 173 4 60 174 63 +0 1 5 0 172 65 164 175 60 12 61 174 +0 1 5 0 175 164 66 138 174 61 25 62 +0 1 5 0 173 175 138 67 63 174 62 15 +-1 1 5 7 87 88 89 90 99 100 101 102 +0 1 5 0 21 42 104 32 65 162 166 164 +0 1 5 0 42 17 43 104 162 71 163 166 +0 1 5 0 104 43 22 44 166 163 72 152 +-1 1 5 7 91 92 93 94 95 96 97 98 +0 1 5 0 32 109 190 95 169 214 218 216 +0 1 5 0 109 104 111 190 214 168 215 218 +0 1 5 0 190 111 44 113 218 215 160 209 +0 1 5 0 95 190 113 26 216 218 209 150 +0 1 5 0 169 214 218 216 164 167 217 171 +0 1 5 0 214 168 215 218 167 166 170 217 +0 1 5 0 218 215 160 209 217 170 152 157 +0 1 5 0 216 218 209 150 171 217 157 66 +0 1 5 0 65 162 166 164 12 68 165 61 +0 1 5 0 162 71 163 166 68 5 69 165 +0 1 5 0 166 163 72 152 165 69 13 70 +0 1 5 0 164 166 152 66 61 165 70 25 +-1 1 5 7 104 113 114 115 116 117 118 119 +-1 1 5 7 105 106 107 108 109 110 111 112 +0 1 5 0 26 113 196 125 150 209 213 204 +0 1 5 0 113 44 123 196 209 160 210 213 +0 1 5 0 196 123 118 124 213 210 161 211 +0 1 5 0 125 196 124 52 204 213 211 151 +0 1 5 0 150 209 213 204 66 157 212 148 +0 1 5 0 209 160 210 213 157 152 158 212 +0 1 5 0 213 210 161 211 212 158 156 159 +0 1 5 0 204 213 211 151 148 212 159 139 +0 1 5 0 44 22 50 118 152 72 153 156 +0 1 5 0 118 50 18 51 156 153 76 154 +0 1 5 0 52 118 51 23 139 156 154 77 +0 1 5 0 66 152 156 139 25 70 155 75 +0 1 5 0 152 72 153 156 70 13 73 155 +0 1 5 0 156 153 76 154 155 73 7 74 +0 1 5 0 139 156 154 77 75 155 74 14 +-1 1 5 7 121 122 131 132 133 134 135 136 +0 1 5 0 24 33 131 58 67 138 143 141 +-1 1 5 7 123 124 125 126 127 128 129 130 +0 1 5 0 33 96 201 135 145 203 208 206 +0 1 5 0 96 26 125 201 203 150 204 208 +0 1 5 0 201 125 52 137 208 204 151 205 +0 1 5 0 135 201 137 131 206 208 205 146 +0 1 5 0 145 203 208 206 138 147 207 144 +0 1 5 0 203 150 204 208 147 66 148 207 +0 1 5 0 208 204 151 205 207 148 139 149 +0 1 5 0 206 208 205 146 144 207 149 143 +0 1 5 0 131 52 23 57 143 139 77 140 +0 1 5 0 58 131 57 19 141 143 140 80 +0 1 5 0 67 138 143 141 15 62 142 79 +0 1 5 0 138 66 139 143 62 25 75 142 +0 1 5 0 143 139 77 140 142 75 14 78 +0 1 5 0 141 143 140 80 79 142 78 6 +# attr geom nodes boundary 96 1 3 30 81 27 0 2 3 0 27 82 35 5 3 30 0 35 85 +1 3 81 28 8 27 +2 3 27 8 36 82 +1 3 29 20 28 81 1 3 11 29 81 30 5 3 11 30 85 38 -5 3 38 85 34 24 2 3 35 82 31 16 5 3 85 35 16 34 2 3 82 36 21 31 -1 3 29 20 28 81 -1 3 81 28 8 27 -2 3 27 8 36 82 +5 3 38 85 34 24 1 3 28 100 39 8 2 3 8 39 101 36 -2 3 36 101 42 21 -2 3 101 45 17 42 -3 3 45 102 43 17 1 3 100 40 1 39 2 3 39 1 45 101 3 3 1 40 102 45 1 3 41 9 40 100 3 3 40 9 46 102 -3 3 102 46 22 43 1 3 20 41 100 28 +2 3 36 101 42 21 +2 3 101 45 17 42 +3 3 45 102 43 17 +3 3 102 46 22 43 1 3 49 114 41 20 -3 3 46 115 50 22 1 3 114 47 9 41 3 3 9 47 115 46 1 3 48 3 47 114 3 3 47 3 53 115 4 3 3 48 116 53 +1 3 10 48 114 49 +4 3 48 10 54 116 +3 3 46 115 50 22 3 3 115 53 18 50 4 3 53 116 51 18 4 3 116 54 23 51 -1 3 10 48 114 49 -4 3 48 10 54 116 +1 3 56 128 29 11 +5 3 56 11 38 130 +1 3 128 49 20 29 1 3 55 10 49 128 4 3 10 55 129 54 1 3 2 55 128 56 4 3 55 2 59 129 5 3 2 56 130 59 -1 3 56 128 29 11 -5 3 56 11 38 130 -1 3 128 49 20 29 5 3 130 38 24 58 +4 3 54 129 57 23 4 3 129 59 19 57 5 3 59 130 58 19 -4 3 54 129 57 23 -4 3 23 57 140 77 -4 3 57 19 80 140 -5 3 19 58 141 80 -5 3 58 24 67 141 -6 3 62 25 75 142 -5 3 141 67 15 79 -6 3 15 62 142 79 -4 3 140 80 6 78 -5 3 80 141 79 6 -6 3 79 142 78 6 -4 3 77 140 78 14 -6 3 142 75 14 78 -4 3 154 77 14 74 -6 3 75 155 74 14 -4 3 51 23 77 154 -3 3 50 18 76 153 -4 3 18 51 154 76 -3 3 153 76 7 73 -4 3 76 154 74 7 -6 3 155 73 7 74 -3 3 72 153 73 13 -6 3 70 13 73 155 -3 3 22 50 153 72 -6 3 25 70 155 75 -6 3 61 165 70 25 -3 3 43 22 72 163 -3 3 163 72 13 69 -6 3 165 69 13 70 -2 3 162 71 5 68 -3 3 71 163 69 5 -6 3 68 5 69 165 -2 3 42 17 71 162 -3 3 17 43 163 71 -2 3 21 42 162 65 -2 3 65 162 68 12 -6 3 12 68 165 61 -2 3 172 65 12 60 -6 3 60 12 61 174 -6 3 174 61 25 62 -2 3 31 21 65 172 2 3 16 31 172 64 5 3 34 16 64 173 +2 3 31 21 65 172 5 3 24 34 173 67 -5 3 67 173 63 15 -6 3 63 174 62 15 2 3 64 172 60 4 5 3 173 64 4 63 6 3 4 60 174 63 +2 3 172 65 12 60 +6 3 60 12 61 174 +6 3 174 61 25 62 +5 3 67 173 63 15 +6 3 63 174 62 15 +2 3 21 42 162 65 +2 3 42 17 71 162 +3 3 17 43 163 71 +3 3 43 22 72 163 +2 3 65 162 68 12 +6 3 12 68 165 61 +2 3 162 71 5 68 +3 3 71 163 69 5 +6 3 68 5 69 165 +3 3 163 72 13 69 +6 3 165 69 13 70 +6 3 61 165 70 25 +3 3 22 50 153 72 +3 3 50 18 76 153 +4 3 18 51 154 76 +4 3 51 23 77 154 +6 3 25 70 155 75 +3 3 72 153 73 13 +6 3 70 13 73 155 +3 3 153 76 7 73 +4 3 76 154 74 7 +6 3 155 73 7 74 +4 3 154 77 14 74 +6 3 75 155 74 14 +5 3 58 24 67 141 +4 3 23 57 140 77 +4 3 57 19 80 140 +5 3 19 58 141 80 +5 3 141 67 15 79 +6 3 15 62 142 79 +6 3 62 25 75 142 +4 3 77 140 78 14 +6 3 142 75 14 78 +4 3 140 80 6 78 +5 3 80 141 79 6 +6 3 79 142 78 6 +# vert_id p1 p2 vertex_parents 215 8 0 1 @@ -454,28 +470,9 @@ vertex_parents 221 171 178 222 203 219 -coarse_elements -17 -7 11 12 9 10 6 5 8 7 -7 0 14 13 1 3 4 120 2 -7 27 22 21 28 26 23 24 25 -7 15 18 19 29 16 17 20 122 -7 31 38 37 32 34 35 36 33 -7 30 40 41 44 124 39 42 43 -7 49 50 51 52 56 55 54 53 -7 47 48 45 46 57 126 59 58 -7 113 114 111 112 108 107 110 109 -7 116 115 128 117 119 105 106 118 -7 93 96 95 94 92 97 98 91 -7 103 102 99 130 104 101 100 90 -7 85 84 83 86 88 81 82 87 -7 132 80 77 76 89 79 78 75 -7 63 64 65 66 70 69 68 67 -7 62 134 60 61 72 71 74 73 -7 121 123 125 127 129 131 133 135 - -vertices -223 +# top-level node coordinates +coordinates +8 3 0 0 0 1 0 0 @@ -485,218 +482,5 @@ vertices 1 0 1 0 1 1 1 1 1 -0.5 0 0 -1 0.5 0 -0.5 1 0 -0 0.5 0 -0.5 0 1 -1 0.5 1 -0.5 1 1 -0 0.5 1 -0 0 0.5 -1 0 0.5 -1 1 0.5 -0 1 0.5 -0.5 0.5 0 -0.5 0 0.5 -1 0.5 0.5 -0.5 1 0.5 -0 0.5 0.5 -0.5 0.5 1 -0.5 0.5 0.5 -0.25 0 0 -0.5 0.25 0 -0.25 0.5 0 -0 0.25 0 -0.25 0 0.5 -0.5 0.25 0.5 -0.25 0.5 0.5 -0 0.25 0.5 -0 0 0.25 -0.5 0 0.25 -0.5 0.5 0.25 -0 0.5 0.25 -0.75 0 0 -1 0.25 0 -0.75 0.5 0 -0.75 0 0.5 -1 0.25 0.5 -0.75 0.5 0.5 -1 0 0.25 -1 0.5 0.25 -1 0.75 0 -0.75 1 0 -0.5 0.75 0 -1 0.75 0.5 -0.75 1 0.5 -0.5 0.75 0.5 -1 1 0.25 -0.5 1 0.25 -0.25 1 0 -0 0.75 0 -0.25 1 0.5 -0 0.75 0.5 -0 1 0.25 -0.25 0 1 -0.5 0.25 1 -0.25 0.5 1 -0 0.25 1 -0 0 0.75 -0.5 0 0.75 -0.5 0.5 0.75 -0 0.5 0.75 -0.75 0 1 -1 0.25 1 -0.75 0.5 1 -1 0 0.75 -1 0.5 0.75 -1 0.75 1 -0.75 1 1 -0.5 0.75 1 -1 1 0.75 -0.5 1 0.75 -0.25 1 1 -0 0.75 1 -0 1 0.75 -0.25 0.25 0 -0.25 0 0.25 -0.5 0.25 0.25 -0.25 0.5 0.25 -0 0.25 0.25 -0.25 0.25 0.5 -0.25 0.25 0.25 -0.375 0.25 0.25 -0.5 0.375 0.25 -0.375 0.5 0.25 -0.25 0.375 0.25 -0.25 0.25 0.375 -0.375 0.25 0.5 -0.5 0.25 0.375 -0.5 0.375 0.5 -0.375 0.5 0.5 -0.25 0.375 0.5 -0.5 0.5 0.375 -0.25 0.5 0.375 -0.75 0.25 0 -0.75 0 0.25 -1 0.25 0.25 -0.75 0.5 0.25 -0.75 0.25 0.5 -0.75 0.25 0.25 -0.625 0.25 0.25 -0.75 0.375 0.25 -0.625 0.5 0.25 -0.625 0.25 0.5 -0.75 0.25 0.375 -0.75 0.375 0.5 -0.75 0.5 0.375 -0.625 0.5 0.5 -0.75 0.75 0 -1 0.75 0.25 -0.75 1 0.25 -0.5 0.75 0.25 -0.75 0.75 0.5 -0.75 0.75 0.25 -0.75 0.625 0.25 -0.625 0.75 0.25 -0.5 0.625 0.25 -0.75 0.625 0.5 -0.625 0.75 0.5 -0.5 0.625 0.5 -0.75 0.75 0.375 -0.5 0.75 0.375 -0.25 0.75 0 -0.25 1 0.25 -0 0.75 0.25 -0.25 0.75 0.5 -0.25 0.75 0.25 -0.25 0.625 0.25 -0.375 0.75 0.25 -0.25 0.625 0.5 -0.25 0.75 0.375 -0.375 0.75 0.5 -0.25 0.5 0.75 -0.5 0.75 0.75 -0.25 1 0.75 -0 0.75 0.75 -0.25 0.75 1 -0.25 0.75 0.75 -0.25 0.625 0.75 -0.25 0.5 0.625 -0.25 0.75 0.625 -0.375 0.5 0.75 -0.5 0.625 0.75 -0.375 0.75 0.75 -0.5 0.5 0.625 -0.5 0.75 0.625 -0.75 0.5 0.75 -1 0.75 0.75 -0.75 1 0.75 -0.75 0.75 1 -0.75 0.75 0.75 -0.625 0.5 0.75 -0.75 0.625 0.75 -0.625 0.75 0.75 -0.75 0.5 0.625 -0.75 0.75 0.625 -0.75 0 0.75 -1 0.25 0.75 -0.5 0.25 0.75 -0.75 0.25 1 -0.75 0.25 0.75 -0.625 0.25 0.75 -0.75 0.25 0.625 -0.5 0.25 0.625 -0.75 0.375 0.75 -0.5 0.375 0.75 -0.25 0 0.75 -0 0.25 0.75 -0.25 0.25 1 -0.25 0.25 0.75 -0.25 0.25 0.625 -0.375 0.25 0.75 -0.25 0.375 0.75 -0.375 0.375 0.25 -0.375 0.25 0.375 -0.5 0.375 0.375 -0.375 0.5 0.375 -0.25 0.375 0.375 -0.375 0.375 0.5 -0.375 0.375 0.375 -0.625 0.375 0.25 -0.625 0.25 0.375 -0.75 0.375 0.375 -0.625 0.5 0.375 -0.625 0.375 0.5 -0.625 0.375 0.375 -0.625 0.625 0.25 -0.75 0.625 0.375 -0.625 0.75 0.375 -0.5 0.625 0.375 -0.625 0.625 0.5 -0.625 0.625 0.375 -0.375 0.625 0.25 -0.375 0.75 0.375 -0.25 0.625 0.375 -0.375 0.625 0.5 -0.375 0.625 0.375 -0.375 0.5 0.625 -0.5 0.625 0.625 -0.375 0.75 0.625 -0.25 0.625 0.625 -0.375 0.625 0.75 -0.375 0.625 0.625 -0.625 0.5 0.625 -0.75 0.625 0.625 -0.625 0.75 0.625 -0.625 0.625 0.75 -0.625 0.625 0.625 -0.625 0.25 0.625 -0.75 0.375 0.625 -0.5 0.375 0.625 -0.625 0.375 0.75 -0.625 0.375 0.625 -0.375 0.25 0.625 -0.25 0.375 0.625 -0.375 0.375 0.75 -0.375 0.375 0.625 + +mfem_mesh_end diff --git a/data/amr-quad.mesh b/data/amr-quad.mesh index 8281885b68..f2b20c134d 100644 --- a/data/amr-quad.mesh +++ b/data/amr-quad.mesh @@ -1,56 +1,63 @@ -MFEM mesh v1.1 +MFEM NC mesh v1.0 -# -# MFEM Geometry Types (see mesh/geom.hpp): -# -# POINT = 0 -# SEGMENT = 1 +# NCMesh supported geometry types: # TRIANGLE = 2 # SQUARE = 3 # TETRAHEDRON = 4 # CUBE = 5 -# +# PRISM = 6 dimension 2 +# rank attr geom ref_type nodes/children elements -28 -1 3 0 9 21 12 -1 3 12 21 11 7 -1 3 21 22 37 25 -1 3 25 37 24 11 -1 3 37 23 8 24 -1 3 22 10 23 37 -1 3 9 4 10 21 -1 3 4 13 26 10 -1 3 13 1 14 26 -1 3 26 14 5 15 -1 3 38 28 15 29 -1 3 27 26 28 38 -1 3 10 27 38 23 -1 3 23 38 29 8 -1 3 8 29 39 33 -1 3 33 39 32 18 -1 3 39 31 30 32 -1 3 29 15 31 39 -1 3 15 5 16 30 -1 3 30 16 3 17 -1 3 18 30 17 6 -1 3 34 18 6 19 -1 3 40 33 18 36 -1 3 24 8 33 40 -1 3 11 24 40 35 -1 3 35 40 36 34 -1 3 7 11 34 20 -1 3 20 34 19 2 +37 +-1 1 3 3 1 10 19 28 +-1 1 3 3 2 3 4 9 +0 1 3 0 0 9 21 12 +0 1 3 0 9 4 10 21 +-1 1 3 3 5 6 7 8 +0 1 3 0 21 22 37 25 +0 1 3 0 22 10 23 37 +0 1 3 0 37 23 8 24 +0 1 3 0 25 37 24 11 +0 1 3 0 12 21 11 7 +-1 1 3 3 11 12 13 14 +0 1 3 0 4 13 26 10 +0 1 3 0 13 1 14 26 +0 1 3 0 26 14 5 15 +-1 1 3 3 15 16 17 18 +0 1 3 0 10 27 38 23 +0 1 3 0 27 26 28 38 +0 1 3 0 38 28 15 29 +0 1 3 0 23 38 29 8 +-1 1 3 3 20 25 26 27 +-1 1 3 3 21 22 23 24 +0 1 3 0 8 29 39 33 +0 1 3 0 29 15 31 39 +0 1 3 0 39 31 30 32 +0 1 3 0 33 39 32 18 +0 1 3 0 15 5 16 30 +0 1 3 0 30 16 3 17 +0 1 3 0 18 30 17 6 +-1 1 3 3 29 30 35 36 +0 1 3 0 7 11 34 20 +-1 1 3 3 31 32 33 34 +0 1 3 0 11 24 40 35 +0 1 3 0 24 8 33 40 +0 1 3 0 40 33 18 36 +0 1 3 0 35 40 36 34 +0 1 3 0 34 18 6 19 +0 1 3 0 20 34 19 2 +# attr geom nodes boundary 16 1 1 0 9 4 1 12 0 -4 1 7 12 1 1 9 4 +4 1 7 12 1 1 4 13 1 1 13 1 2 1 1 14 @@ -59,11 +66,12 @@ boundary 2 1 16 3 3 1 3 17 3 1 17 6 -3 1 6 19 4 1 20 7 +3 1 6 19 3 1 19 2 4 1 2 20 +# vert_id p1 p2 vertex_parents 37 4 0 1 @@ -104,59 +112,13 @@ vertex_parents 39 29 32 40 24 36 -coarse_elements -9 -3 2 5 4 3 -3 0 6 28 1 -3 12 11 10 13 -3 7 8 9 30 -3 14 17 16 15 -3 32 18 19 20 -3 24 23 22 25 -3 26 34 21 27 -3 29 31 33 35 - -vertices -41 +# top-level node coordinates +coordinates +4 2 0 0 1 0 0 1 1 1 -0.5 0 -1 0.5 -0.5 1 -0 0.5 -0.5 0.5 -0.25 0 -0.5 0.25 -0.25 0.5 -0 0.25 -0.75 0 -1 0.25 -0.75 0.5 -1 0.75 -0.75 1 -0.5 0.75 -0.25 1 -0 0.75 -0.25 0.25 -0.375 0.25 -0.5 0.375 -0.375 0.5 -0.25 0.375 -0.75 0.25 -0.625 0.25 -0.75 0.375 -0.625 0.5 -0.75 0.75 -0.75 0.625 -0.625 0.75 -0.5 0.625 -0.25 0.75 -0.25 0.625 -0.375 0.75 -0.375 0.375 -0.625 0.375 -0.625 0.625 -0.375 0.625 + +mfem_mesh_end diff --git a/data/beam-quad-amr.mesh b/data/beam-quad-amr.mesh index a6691070bf..27fb966faf 100644 --- a/data/beam-quad-amr.mesh +++ b/data/beam-quad-amr.mesh @@ -1,51 +1,42 @@ -MFEM mesh v1.1 +MFEM NC mesh v1.0 -# -# MFEM Geometry Types (see mesh/geom.hpp): -# -# POINT = 0 -# SEGMENT = 1 +# NCMesh supported geometry types: # TRIANGLE = 2 # SQUARE = 3 # TETRAHEDRON = 4 # CUBE = 5 -# +# PRISM = 6 dimension 2 +# rank attr geom ref_type nodes/children elements -17 -1 3 0 23 30 26 -1 3 26 30 25 21 -1 3 30 24 22 25 -1 3 23 18 24 30 -1 3 18 1 19 22 -1 3 22 19 10 20 -1 3 31 27 20 28 -1 3 25 22 27 31 -1 3 21 25 31 29 -1 3 29 31 28 9 -1 3 1 2 11 10 -1 3 2 3 12 11 -1 3 3 4 13 12 -2 3 4 5 14 13 -2 3 5 6 15 14 -2 3 6 7 16 15 -2 3 7 8 17 16 +20 +0 1 3 0 1 2 11 10 +0 1 3 0 2 3 12 11 +0 1 3 0 3 4 13 12 +0 2 3 0 4 5 14 13 +0 2 3 0 5 6 15 14 +0 2 3 0 6 7 16 15 +0 2 3 0 7 8 17 16 +-1 1 3 3 8 13 14 15 +-1 1 3 3 9 10 11 12 +0 1 3 0 0 23 30 26 +0 1 3 0 23 18 24 30 +0 1 3 0 30 24 22 25 +0 1 3 0 26 30 25 21 +0 1 3 0 18 1 19 22 +0 1 3 0 22 19 10 20 +-1 1 3 3 16 17 18 19 +0 1 3 0 21 25 31 29 +0 1 3 0 25 22 27 31 +0 1 3 0 31 27 20 28 +0 1 3 0 29 31 28 9 +# attr geom nodes boundary 25 -3 1 0 23 -1 1 26 0 -1 1 21 26 -3 1 23 18 -3 1 18 1 -3 1 10 20 -3 1 20 28 -1 1 29 21 -3 1 28 9 -1 1 9 29 3 1 1 2 3 1 11 10 3 1 2 3 @@ -61,7 +52,18 @@ boundary 3 1 7 8 2 1 8 17 3 1 17 16 +3 1 0 23 +1 1 26 0 +3 1 23 18 +1 1 21 26 +3 1 18 1 +3 1 10 20 +1 1 29 21 +3 1 20 28 +3 1 28 9 +1 1 9 29 +# vert_id p1 p2 vertex_parents 14 18 0 1 @@ -79,14 +81,21 @@ vertex_parents 30 23 25 31 25 28 -coarse_elements -3 -3 0 3 2 1 -3 8 7 6 9 -3 17 4 5 18 +# root element orientation +root_state +8 +1 +1 +1 +1 +1 +1 +0 +0 -vertices -32 +# top-level node coordinates +coordinates +18 2 0 0 1 0 @@ -106,17 +115,5 @@ vertices 6 1 7 1 8 1 -0.5 0 -1 0.5 -0.5 1 -0 0.5 -0.5 0.5 -0.25 0 -0.5 0.25 -0.25 0.5 -0 0.25 -0.5 0.75 -0.25 1 -0 0.75 -0.25 0.25 -0.25 0.75 + +mfem_mesh_end diff --git a/data/fichera-amr.mesh b/data/fichera-amr.mesh index 3d625705c4..0ec67ee97e 100644 --- a/data/fichera-amr.mesh +++ b/data/fichera-amr.mesh @@ -1,544 +1,667 @@ -MFEM mesh v1.1 +MFEM NC mesh v1.0 -# -# MFEM Geometry Types (see mesh/geom.hpp): -# -# POINT = 0 -# SEGMENT = 1 +# NCMesh supported geometry types: # TRIANGLE = 2 # SQUARE = 3 # TETRAHEDRON = 4 # CUBE = 5 -# +# PRISM = 6 dimension 3 +# rank attr geom ref_type nodes/children elements -522 -1 5 0 26 77 29 34 78 83 81 -1 5 26 1 27 77 78 35 79 83 -1 5 77 27 4 28 83 79 36 80 -1 5 29 84 198 90 81 86 199 92 -1 5 84 77 87 198 86 83 88 199 -1 5 198 87 28 89 199 88 80 91 -1 5 90 200 358 205 92 201 359 207 -1 5 200 198 202 358 201 199 203 359 -1 5 358 202 89 204 359 203 91 206 -1 5 205 360 557 365 207 361 558 367 -1 5 360 358 362 557 361 359 363 558 -1 5 557 362 204 364 558 363 206 366 -1 5 365 559 795 564 367 560 796 566 -1 5 559 557 561 795 560 558 562 796 -1 5 795 561 364 563 796 562 366 565 -1 5 564 795 563 3 566 796 565 37 -1 5 199 88 80 91 213 209 100 210 -1 5 92 201 359 207 211 215 368 218 -1 5 201 199 203 359 215 213 216 368 -1 5 359 203 91 206 368 216 210 217 -1 5 207 361 558 367 218 369 567 372 -1 5 361 359 363 558 369 368 370 567 -1 5 558 363 206 366 567 370 217 371 -1 5 367 560 796 566 372 568 797 571 -1 5 560 558 562 796 568 567 569 797 -1 5 796 562 366 565 797 569 371 570 -1 5 566 796 565 37 571 797 570 103 -1 5 81 86 199 92 98 208 213 211 -1 5 86 83 88 199 208 97 209 213 -1 5 208 97 209 213 94 82 99 212 -1 5 98 214 215 211 221 373 374 224 -1 5 214 208 213 215 373 222 223 374 -1 5 373 222 223 374 219 94 212 220 -1 5 221 375 376 224 381 572 573 382 -1 5 375 373 374 376 572 377 378 573 -1 5 572 377 378 573 379 219 220 380 -1 5 381 574 575 382 580 798 799 581 -1 5 574 572 573 575 798 576 577 799 -1 5 798 576 577 799 578 379 380 579 -1 5 580 798 799 581 33 578 579 102 -1 5 374 223 383 387 220 212 225 386 -1 5 215 213 216 368 374 223 383 387 -1 5 211 215 368 218 224 374 387 385 -1 5 224 376 388 385 382 573 582 394 -1 5 376 374 387 388 573 378 393 582 -1 5 573 378 393 582 380 220 386 392 -1 5 382 575 583 394 581 799 800 586 -1 5 575 573 582 583 799 577 584 800 -1 5 799 577 584 800 579 380 392 585 -1 5 581 799 800 586 102 579 585 228 -1 5 385 388 587 391 394 582 592 590 -1 5 394 583 594 590 586 800 801 603 -1 5 583 582 592 594 800 584 602 801 -1 5 800 584 602 801 585 392 591 601 -1 5 586 800 801 603 228 585 601 398 -1 5 582 393 588 592 392 386 395 591 -1 5 388 387 389 587 582 393 588 592 -1 5 587 389 384 390 592 588 396 589 -1 5 592 588 396 589 591 395 227 397 -1 5 802 596 589 599 807 803 605 804 -1 5 594 592 596 802 801 602 803 807 -1 5 801 602 803 807 601 591 604 806 -1 5 807 803 605 804 806 604 397 606 -1 5 805 807 804 608 607 806 606 12 -1 5 603 801 807 805 398 601 806 607 -1 5 590 594 802 600 603 801 807 805 -1 5 600 802 599 399 805 807 804 608 -1 5 391 593 808 598 590 594 802 600 -1 5 593 587 595 808 594 592 596 802 -1 5 808 595 390 597 802 596 589 599 -1 5 598 808 597 229 600 802 599 399 -1 5 218 369 567 372 385 388 587 391 -1 5 369 368 370 567 388 387 389 587 -1 5 567 370 217 371 587 389 384 390 -1 5 372 568 797 571 391 593 808 598 -1 5 568 567 569 797 593 587 595 808 -1 5 797 569 371 570 808 595 390 597 -1 5 571 797 570 103 598 808 597 229 -1 5 368 216 210 217 387 383 226 384 -1 5 387 383 226 384 386 225 101 227 -1 5 213 209 100 210 212 99 32 101 -1 5 83 79 36 80 82 31 13 32 -1 5 78 35 79 83 30 10 31 82 -1 5 34 85 86 81 95 230 208 98 -1 5 85 78 83 86 230 96 97 208 -1 5 230 96 97 208 93 30 82 94 -1 5 95 231 214 98 234 400 373 221 -1 5 231 230 208 214 400 232 222 373 -1 5 400 232 222 373 233 93 94 219 -1 5 234 401 375 221 404 609 572 381 -1 5 401 400 373 375 609 402 377 572 -1 5 609 402 377 572 403 233 219 379 -1 5 404 610 574 381 613 809 798 580 -1 5 610 609 572 574 809 611 576 798 -1 5 809 611 576 798 612 403 379 578 -1 5 613 809 798 580 9 612 578 33 -1 5 3 563 810 618 37 565 811 621 -1 5 563 364 616 810 565 366 619 811 -1 5 810 616 614 617 811 619 615 620 -1 5 618 810 617 409 621 811 620 412 -1 5 364 204 407 614 366 206 410 615 -1 5 614 407 405 408 615 410 406 411 -1 5 409 614 408 239 412 615 411 242 -1 5 204 89 237 405 206 91 240 406 -1 5 405 237 235 238 406 240 236 241 -1 5 239 405 238 112 242 406 241 115 -1 5 89 28 110 235 91 80 113 236 -1 5 235 110 104 111 236 113 109 114 -1 5 112 235 111 40 115 236 114 107 -1 5 28 4 38 104 80 36 105 109 -1 5 104 38 7 39 109 105 44 106 -1 5 40 104 39 6 107 109 106 45 -1 5 107 109 106 45 43 108 42 15 -1 5 109 105 44 106 108 41 16 42 -1 5 80 36 105 109 32 13 41 108 -1 5 210 100 243 247 101 32 116 246 -1 5 247 243 119 244 246 116 108 117 -1 5 236 113 109 114 247 243 119 244 -1 5 91 80 113 236 210 100 243 247 -1 5 37 565 811 621 103 570 812 625 -1 5 565 366 619 811 570 371 623 812 -1 5 811 619 615 620 812 623 622 624 -1 5 621 811 620 412 625 812 624 416 -1 5 366 206 410 615 371 217 414 622 -1 5 615 410 406 411 622 414 413 415 -1 5 412 615 411 242 416 622 415 250 -1 5 206 91 240 406 217 210 248 413 -1 5 406 240 236 241 413 248 247 249 -1 5 242 406 241 115 250 413 249 245 -1 5 115 236 114 107 245 247 244 120 -1 5 245 247 244 120 118 246 117 43 -1 5 419 421 418 255 253 420 252 118 -1 5 250 413 249 245 419 421 418 255 -1 5 413 248 247 249 421 417 254 418 -1 5 421 417 254 418 420 251 246 252 -1 5 384 226 417 421 227 101 251 420 -1 5 217 210 248 413 384 226 417 421 -1 5 103 570 812 625 229 597 813 629 -1 5 570 371 623 812 597 390 627 813 -1 5 812 623 622 624 813 627 626 628 -1 5 625 812 624 416 629 813 628 424 -1 5 371 217 414 622 390 384 422 626 -1 5 622 414 413 415 626 422 421 423 -1 5 416 622 415 250 424 626 423 419 -1 5 229 597 813 629 399 599 814 637 -1 5 597 390 627 813 599 589 635 814 -1 5 813 627 626 628 814 635 634 636 -1 5 629 813 628 424 637 814 636 632 -1 5 390 384 422 626 589 396 630 634 -1 5 626 422 421 423 634 630 428 631 -1 5 424 626 423 419 632 634 631 429 -1 5 632 634 631 429 427 633 426 253 -1 5 634 630 428 631 633 425 420 426 -1 5 589 396 630 634 397 227 425 633 -1 5 804 605 815 819 606 397 638 818 -1 5 819 815 641 816 818 638 633 639 -1 5 814 635 634 636 819 815 641 816 -1 5 599 589 635 814 804 605 815 819 -1 5 399 599 814 637 608 804 819 817 -1 5 637 814 636 632 817 819 816 642 -1 5 817 819 816 642 640 818 639 427 -1 5 608 804 819 817 12 606 818 640 -1 5 2 46 121 48 52 122 126 124 -1 5 46 130 256 127 122 132 257 128 -1 5 130 260 430 258 132 262 431 259 -1 5 260 434 643 432 262 436 644 433 -1 5 434 647 820 645 436 649 821 646 -1 5 647 3 618 820 649 37 621 821 -1 5 820 618 409 648 821 621 412 650 -1 5 645 820 648 643 646 821 650 644 -1 5 643 409 239 435 644 412 242 437 -1 5 432 643 435 430 433 644 437 431 -1 5 430 239 112 261 431 242 115 263 -1 5 258 430 261 256 259 431 263 257 -1 5 256 112 40 131 257 115 107 133 -1 5 127 256 131 121 128 257 133 126 -1 5 121 40 6 47 126 107 45 123 -1 5 48 121 47 5 124 126 123 53 -1 5 124 126 123 53 51 125 50 14 -1 5 126 107 45 123 125 43 15 50 -1 5 266 268 265 138 134 267 141 125 -1 5 128 257 133 126 266 268 265 138 -1 5 257 115 107 133 268 245 120 265 -1 5 268 245 120 265 267 118 43 141 -1 5 438 250 245 272 443 419 255 440 -1 5 443 419 255 440 442 253 118 280 -1 5 441 443 440 277 273 442 280 267 -1 5 269 438 272 268 441 443 440 277 -1 5 264 271 438 269 276 439 443 441 -1 5 276 439 445 446 453 454 651 652 -1 5 446 445 443 441 652 651 455 456 -1 5 453 454 653 654 657 658 822 823 -1 5 654 653 651 652 823 822 659 660 -1 5 657 658 822 823 140 279 655 656 -1 5 823 822 659 660 656 655 451 452 -1 5 652 651 455 456 452 451 442 273 -1 5 439 449 661 445 454 662 665 651 -1 5 445 661 450 443 651 665 663 455 -1 5 651 665 663 455 451 664 458 442 -1 5 454 662 667 653 658 673 824 822 -1 5 653 667 665 651 822 824 674 659 -1 5 658 673 824 822 279 457 672 655 -1 5 822 824 674 659 655 672 664 451 -1 5 824 829 827 674 672 828 676 664 -1 5 673 826 829 824 457 675 828 672 -1 5 662 670 825 667 673 826 829 824 -1 5 667 825 671 665 824 829 827 674 -1 5 825 637 632 671 829 817 642 827 -1 5 670 399 637 825 826 608 817 829 -1 5 826 608 817 829 675 12 640 828 -1 5 829 817 642 827 828 640 427 676 -1 5 665 632 429 663 664 427 253 458 -1 5 661 424 419 450 665 632 429 663 -1 5 449 668 830 666 662 670 825 667 -1 5 668 229 629 830 670 399 637 825 -1 5 830 629 424 669 825 637 632 671 -1 5 666 830 669 661 667 825 671 665 -1 5 271 447 677 444 439 449 661 445 -1 5 447 679 831 678 449 668 830 666 -1 5 679 103 625 831 668 229 629 830 -1 5 831 625 416 680 830 629 424 669 -1 5 678 831 680 677 666 830 669 661 -1 5 677 416 250 448 661 424 419 450 -1 5 444 677 448 438 445 661 450 443 -1 5 132 262 431 259 264 271 438 269 -1 5 262 436 644 433 271 447 677 444 -1 5 436 649 821 646 447 679 831 678 -1 5 649 37 621 821 679 103 625 831 -1 5 821 621 412 650 831 625 416 680 -1 5 646 821 650 644 678 831 680 677 -1 5 644 412 242 437 677 416 250 448 -1 5 433 644 437 431 444 677 448 438 -1 5 431 242 115 263 438 250 245 272 -1 5 259 431 263 257 269 438 272 268 -1 5 122 132 257 128 137 264 268 266 -1 5 137 264 269 270 275 276 441 459 -1 5 270 269 268 266 459 441 277 278 -1 5 275 276 446 460 462 453 652 681 -1 5 460 446 441 459 681 652 456 463 -1 5 462 453 654 682 684 657 823 832 -1 5 682 654 652 681 832 823 660 685 -1 5 684 657 823 832 49 140 656 683 -1 5 832 823 660 685 683 656 452 461 -1 5 681 652 456 463 461 452 273 274 -1 5 459 441 277 278 274 273 267 134 -1 5 52 122 128 129 136 137 266 281 -1 5 129 128 126 124 281 266 138 139 -1 5 136 137 270 282 284 275 459 464 -1 5 282 270 266 281 464 459 278 285 -1 5 284 275 460 465 467 462 681 686 -1 5 465 460 459 464 686 681 463 468 -1 5 467 462 682 687 689 684 832 833 -1 5 687 682 681 686 833 832 685 690 -1 5 689 684 832 833 11 49 683 688 -1 5 833 832 685 690 688 683 461 466 -1 5 686 681 463 468 466 461 274 283 -1 5 464 459 278 285 283 274 134 135 -1 5 281 266 138 139 135 134 125 51 -1 5 8 54 142 55 60 143 148 146 -1 5 54 152 153 142 149 286 287 150 -1 5 152 290 291 153 288 469 470 289 -1 5 290 473 474 291 471 691 692 472 -1 5 473 695 696 474 693 834 835 694 -1 5 695 9 33 696 834 699 700 835 -1 5 834 699 700 835 697 477 478 698 -1 5 693 834 835 694 691 697 698 692 -1 5 691 477 478 692 475 294 295 476 -1 5 471 691 692 472 469 475 476 470 -1 5 469 294 295 470 292 156 157 293 -1 5 288 469 470 289 286 292 293 287 -1 5 286 156 157 287 154 61 144 155 -1 5 149 286 287 150 143 154 155 148 -1 5 142 153 296 158 150 287 301 299 -1 5 150 287 301 299 148 155 300 161 -1 5 287 157 297 301 155 144 159 300 -1 5 153 291 304 296 289 470 479 302 -1 5 291 474 481 304 472 692 701 480 -1 5 474 696 703 481 694 835 836 702 -1 5 696 33 102 703 835 700 705 836 -1 5 835 700 705 836 698 478 483 704 -1 5 694 835 836 702 692 698 704 701 -1 5 692 478 483 701 476 295 306 482 -1 5 472 692 701 480 470 476 482 479 -1 5 470 295 306 479 293 157 297 305 -1 5 289 470 479 302 287 293 305 301 -1 5 479 306 485 489 305 297 308 488 -1 5 304 481 492 484 480 701 706 490 -1 5 481 703 708 492 702 836 837 707 -1 5 703 102 228 708 836 705 710 837 -1 5 836 705 710 837 704 483 494 709 -1 5 702 836 837 707 701 704 709 706 -1 5 701 483 494 706 482 306 485 493 -1 5 480 701 706 490 479 482 493 489 -1 5 296 304 484 307 302 479 489 487 -1 5 302 479 489 487 301 305 488 310 -1 5 487 489 486 312 310 488 309 298 -1 5 307 484 495 501 491 490 711 712 -1 5 501 495 715 716 714 713 838 839 -1 5 716 715 279 140 839 838 719 720 -1 5 714 713 838 839 712 711 717 718 -1 5 839 838 719 720 718 717 500 503 -1 5 491 490 711 712 487 489 498 502 -1 5 712 711 500 503 502 498 486 312 -1 5 711 725 723 500 498 724 497 486 -1 5 490 706 725 711 489 493 724 498 -1 5 484 492 721 495 490 706 725 711 -1 5 495 721 730 715 713 726 840 838 -1 5 715 730 457 279 838 840 735 719 -1 5 713 726 840 838 711 725 733 717 -1 5 838 840 735 719 717 733 723 500 -1 5 721 727 841 730 726 842 846 840 -1 5 730 841 675 457 840 846 844 735 -1 5 840 846 844 735 733 845 732 723 -1 5 726 842 846 840 725 728 845 733 -1 5 842 729 843 846 728 722 731 845 -1 5 846 843 734 844 845 731 499 732 -1 5 841 607 12 675 846 843 734 844 -1 5 727 398 607 841 842 729 843 846 -1 5 492 708 727 721 707 837 842 726 -1 5 708 228 398 727 837 710 729 842 -1 5 837 710 729 842 709 494 722 728 -1 5 707 837 842 726 706 709 728 725 -1 5 706 494 722 725 493 485 496 724 -1 5 725 722 499 723 724 496 311 497 -1 5 489 485 311 486 488 308 162 309 -1 5 301 297 162 298 300 159 62 160 -1 5 299 301 298 163 161 300 160 145 -1 5 158 296 307 313 303 302 487 504 -1 5 313 307 501 506 505 491 712 736 -1 5 506 501 716 738 737 714 839 847 -1 5 738 716 140 49 847 839 720 740 -1 5 737 714 839 847 736 712 718 739 -1 5 847 839 720 740 739 718 503 508 -1 5 505 491 712 736 504 487 502 507 -1 5 736 712 503 508 507 502 312 315 -1 5 303 302 487 504 299 301 310 314 -1 5 504 487 312 315 314 310 298 163 -1 5 55 142 158 164 151 150 299 316 -1 5 164 158 313 318 317 303 504 509 -1 5 318 313 506 511 510 505 736 741 -1 5 511 506 738 743 742 737 847 848 -1 5 743 738 49 11 848 847 740 745 -1 5 742 737 847 848 741 736 739 744 -1 5 848 847 740 745 744 739 508 513 -1 5 510 505 736 741 509 504 507 512 -1 5 741 736 508 513 512 507 315 320 -1 5 317 303 504 509 316 299 314 319 -1 5 509 504 315 320 319 314 163 166 -1 5 151 150 299 316 146 148 161 165 -1 5 316 299 163 166 165 161 145 63 -1 5 146 148 145 63 59 147 58 20 -1 5 148 144 62 145 147 57 21 58 -1 5 143 61 144 148 56 18 57 147 -1 5 60 143 148 146 17 56 147 59 -1 5 9 612 578 33 699 849 850 700 -1 5 612 403 379 578 849 750 751 850 -1 5 849 750 751 850 748 746 747 749 -1 5 699 849 850 700 477 748 749 478 -1 5 403 233 219 379 746 518 519 747 -1 5 746 518 519 747 516 514 515 517 -1 5 477 746 747 478 294 516 517 295 -1 5 233 93 94 219 514 325 326 515 -1 5 514 325 326 515 323 321 322 324 -1 5 294 514 515 295 156 323 324 157 -1 5 93 30 82 94 321 174 175 322 -1 5 321 174 175 322 172 167 171 173 -1 5 156 321 322 157 61 172 173 144 -1 5 30 10 31 82 167 67 168 171 -1 5 82 31 13 32 171 168 68 169 -1 5 212 99 32 101 330 327 177 328 -1 5 386 225 101 227 524 521 334 522 -1 5 524 521 334 522 523 333 328 335 -1 5 485 524 522 311 308 523 335 162 -1 5 722 756 754 499 496 755 531 311 -1 5 843 855 853 734 731 854 763 499 -1 5 729 851 855 843 722 758 854 731 -1 5 398 601 806 607 729 851 855 843 -1 5 607 806 606 12 843 855 853 734 -1 5 806 604 397 606 855 852 762 853 -1 5 601 591 604 806 851 760 852 855 -1 5 851 760 852 855 758 756 761 854 -1 5 855 852 762 853 854 761 754 763 -1 5 591 395 227 397 756 753 530 754 -1 5 756 753 530 754 755 529 522 531 -1 5 752 528 753 756 526 524 529 755 -1 5 392 386 395 591 752 528 753 756 -1 5 228 585 601 398 710 856 851 729 -1 5 585 392 591 601 856 759 760 851 -1 5 856 759 760 851 757 752 756 758 -1 5 710 856 851 729 494 757 758 722 -1 5 494 752 756 722 485 526 755 496 -1 5 102 579 585 228 705 857 856 710 -1 5 579 380 392 585 857 766 759 856 -1 5 857 766 759 856 765 764 752 757 -1 5 705 857 856 710 483 765 757 494 -1 5 380 220 386 392 764 527 528 752 -1 5 764 527 528 752 525 520 524 526 -1 5 483 764 752 494 306 525 526 485 -1 5 306 520 524 485 297 331 523 308 -1 5 520 332 521 524 331 330 333 523 -1 5 220 212 225 386 520 332 521 524 -1 5 33 578 579 102 700 850 857 705 -1 5 578 379 380 579 850 751 766 857 -1 5 850 751 766 857 749 747 764 765 -1 5 700 850 857 705 478 749 765 483 -1 5 379 219 220 380 747 519 527 764 -1 5 747 519 527 764 517 515 520 525 -1 5 478 747 764 483 295 517 525 306 -1 5 219 94 212 220 515 326 332 520 -1 5 515 326 332 520 324 322 330 331 -1 5 295 515 520 306 157 324 331 297 -1 5 94 82 99 212 322 175 327 330 -1 5 322 175 327 330 173 171 176 329 -1 5 157 322 330 297 144 173 329 159 -1 5 297 330 328 162 159 329 178 62 -1 5 330 327 177 328 329 176 169 178 -1 5 144 171 169 62 57 170 66 21 -1 5 171 168 68 169 170 65 22 66 -1 5 167 67 168 171 64 19 65 170 -1 5 61 167 171 144 18 64 170 57 -1 5 12 606 818 640 734 853 862 860 -1 5 640 818 639 427 860 862 859 776 -1 5 860 862 859 776 774 861 773 769 -1 5 734 853 862 860 499 763 861 774 -1 5 853 762 858 862 763 754 772 861 -1 5 862 858 775 859 861 772 771 773 -1 5 818 638 633 639 862 858 775 859 -1 5 606 397 638 818 853 762 858 862 -1 5 397 227 425 633 754 530 767 771 -1 5 633 425 420 426 771 767 540 768 -1 5 427 633 426 253 769 771 768 541 -1 5 769 771 768 541 539 770 538 534 -1 5 771 767 540 768 770 537 536 538 -1 5 754 530 767 771 531 522 537 770 -1 5 499 754 771 769 311 531 770 539 -1 5 311 522 536 534 162 335 535 343 -1 5 522 334 532 536 335 328 341 535 -1 5 227 101 251 420 522 334 532 536 -1 5 420 251 246 252 536 532 344 533 -1 5 536 532 344 533 535 341 340 342 -1 5 534 536 533 345 343 535 342 338 -1 5 253 420 252 118 534 536 533 345 -1 5 118 246 117 43 338 340 337 188 -1 5 338 340 337 188 186 339 185 181 -1 5 162 328 340 338 62 178 339 186 -1 5 328 177 336 340 178 169 184 339 -1 5 340 336 187 337 339 184 183 185 -1 5 246 116 108 117 340 336 187 337 -1 5 101 32 116 246 328 177 336 340 -1 5 32 13 41 108 169 68 179 183 -1 5 108 41 16 42 183 179 72 180 -1 5 43 108 42 15 181 183 180 73 -1 5 181 183 180 73 71 182 70 24 -1 5 183 179 72 180 182 69 25 70 -1 5 169 68 179 183 66 22 69 182 -1 5 62 169 183 181 21 66 182 71 -1 5 11 49 683 688 745 740 863 864 -1 5 688 683 461 466 864 863 781 782 -1 5 745 740 863 864 513 508 779 780 -1 5 864 863 781 782 780 779 777 778 -1 5 466 461 274 283 778 777 546 547 -1 5 513 508 777 778 320 315 544 545 -1 5 778 777 546 547 545 544 542 543 -1 5 283 274 134 135 543 542 350 351 -1 5 320 315 542 543 166 163 348 349 -1 5 543 542 350 351 349 348 346 347 -1 5 135 134 125 51 347 346 195 196 -1 5 166 163 346 347 63 145 193 194 -1 5 347 346 195 196 194 193 192 190 -1 5 49 140 656 683 740 720 865 863 -1 5 683 656 452 461 863 865 785 781 -1 5 740 720 865 863 508 503 784 779 -1 5 863 865 785 781 779 784 783 777 -1 5 461 452 273 274 777 783 550 546 -1 5 508 503 783 777 315 312 549 544 -1 5 777 783 550 546 544 549 548 542 -1 5 274 273 267 134 542 548 356 350 -1 5 315 312 548 542 163 298 355 348 -1 5 542 548 356 350 348 355 354 346 -1 5 163 298 354 346 145 160 353 193 -1 5 298 162 338 354 160 62 186 353 -1 5 486 311 534 553 309 162 343 552 -1 5 723 499 769 789 497 311 539 788 -1 5 789 769 541 786 788 539 534 556 -1 5 664 427 253 458 789 769 541 786 -1 5 828 640 427 676 869 860 776 866 -1 5 675 12 640 828 844 734 860 869 -1 5 844 734 860 869 732 499 774 868 -1 5 869 860 776 866 868 774 769 794 -1 5 867 869 866 792 790 868 794 789 -1 5 735 844 869 867 723 732 868 790 -1 5 457 675 828 672 735 844 869 867 -1 5 672 828 676 664 867 869 866 792 -1 5 279 457 672 655 719 735 867 870 -1 5 655 672 664 451 870 867 792 793 -1 5 719 735 867 870 500 723 790 791 -1 5 870 867 792 793 791 790 789 787 -1 5 451 664 458 442 787 789 786 555 -1 5 787 789 786 555 554 788 556 553 -1 5 500 723 789 787 486 497 788 554 -1 5 140 279 655 656 720 719 870 865 -1 5 656 655 451 452 865 870 793 785 -1 5 720 719 870 865 503 500 791 784 -1 5 865 870 793 785 784 791 787 783 -1 5 452 451 442 273 783 787 555 550 -1 5 503 500 787 783 312 486 554 549 -1 5 783 787 555 550 549 554 553 548 -1 5 312 486 553 548 298 309 552 355 -1 5 548 553 551 356 355 552 357 354 -1 5 273 442 280 267 548 553 551 356 -1 5 442 253 118 280 553 534 345 551 -1 5 553 534 345 551 552 343 338 357 -1 5 267 118 43 141 354 338 188 352 -1 5 354 338 188 352 353 186 181 197 -1 5 346 354 352 195 193 353 197 192 -1 5 134 267 141 125 346 354 352 195 -1 5 125 43 15 50 192 181 73 189 -1 5 51 125 50 14 190 192 189 76 -1 5 190 192 189 76 75 191 74 23 -1 5 192 181 73 189 191 71 24 74 -1 5 145 62 181 192 58 21 71 191 -1 5 63 145 192 190 20 58 191 75 +647 +-1 1 5 7 7 8 9 10 27 44 45 46 +-1 1 5 7 127 144 145 146 147 204 205 206 +-1 1 5 7 207 208 225 226 227 244 325 326 +-1 1 5 7 327 328 345 426 443 444 445 446 +-1 1 5 7 447 464 465 466 523 524 525 526 +-1 1 5 7 527 560 561 562 563 564 565 566 +-1 1 5 7 567 584 641 642 643 644 645 646 +0 1 5 0 0 26 77 29 34 78 83 81 +0 1 5 0 26 1 27 77 78 35 79 83 +0 1 5 0 77 27 4 28 83 79 36 80 +-1 1 5 3 11 12 13 14 +0 1 5 0 29 84 198 90 81 86 199 92 +0 1 5 0 84 77 87 198 86 83 88 199 +0 1 5 0 198 87 28 89 199 88 80 91 +-1 1 5 3 15 16 17 18 +0 1 5 0 90 200 358 205 92 201 359 207 +0 1 5 0 200 198 202 358 201 199 203 359 +0 1 5 0 358 202 89 204 359 203 91 206 +-1 1 5 3 19 20 21 22 +0 1 5 0 205 360 557 365 207 361 558 367 +0 1 5 0 360 358 362 557 361 359 363 558 +0 1 5 0 557 362 204 364 558 363 206 366 +-1 1 5 3 23 24 25 26 +0 1 5 0 365 559 795 564 367 560 796 566 +0 1 5 0 559 557 561 795 560 558 562 796 +0 1 5 0 795 561 364 563 796 562 366 565 +0 1 5 0 564 795 563 3 566 796 565 37 +-1 1 5 5 28 29 30 31 +0 1 5 0 34 85 86 81 95 230 208 98 +0 1 5 0 85 78 83 86 230 96 97 208 +0 1 5 0 230 96 97 208 93 30 82 94 +-1 1 5 5 32 33 34 35 +0 1 5 0 95 231 214 98 234 400 373 221 +0 1 5 0 231 230 208 214 400 232 222 373 +0 1 5 0 400 232 222 373 233 93 94 219 +-1 1 5 5 36 37 38 39 +0 1 5 0 234 401 375 221 404 609 572 381 +0 1 5 0 401 400 373 375 609 402 377 572 +0 1 5 0 609 402 377 572 403 233 219 379 +-1 1 5 5 40 41 42 43 +0 1 5 0 404 610 574 381 613 809 798 580 +0 1 5 0 610 609 572 574 809 611 576 798 +0 1 5 0 809 611 576 798 612 403 379 578 +0 1 5 0 613 809 798 580 9 612 578 33 +0 1 5 0 78 35 79 83 30 10 31 82 +0 1 5 0 83 79 36 80 82 31 13 32 +-1 1 5 7 47 48 49 50 63 76 77 78 +0 1 5 0 81 86 199 92 98 208 213 211 +0 1 5 0 86 83 88 199 208 97 209 213 +0 1 5 0 199 88 80 91 213 209 100 210 +-1 1 5 3 51 52 53 54 +0 1 5 0 92 201 359 207 211 215 368 218 +0 1 5 0 201 199 203 359 215 213 216 368 +0 1 5 0 359 203 91 206 368 216 210 217 +-1 1 5 3 55 56 57 58 +0 1 5 0 207 361 558 367 218 369 567 372 +0 1 5 0 361 359 363 558 369 368 370 567 +0 1 5 0 558 363 206 366 567 370 217 371 +-1 1 5 3 59 60 61 62 +0 1 5 0 367 560 796 566 372 568 797 571 +0 1 5 0 560 558 562 796 568 567 569 797 +0 1 5 0 796 562 366 565 797 569 371 570 +0 1 5 0 566 796 565 37 571 797 570 103 +-1 1 5 5 64 65 66 67 +0 1 5 0 98 214 215 211 221 373 374 224 +0 1 5 0 214 208 213 215 373 222 223 374 +0 1 5 0 373 222 223 374 219 94 212 220 +-1 1 5 5 68 69 70 71 +0 1 5 0 221 375 376 224 381 572 573 382 +0 1 5 0 375 373 374 376 572 377 378 573 +0 1 5 0 572 377 378 573 379 219 220 380 +-1 1 5 5 72 73 74 75 +0 1 5 0 381 574 575 382 580 798 799 581 +0 1 5 0 574 572 573 575 798 576 577 799 +0 1 5 0 798 576 577 799 578 379 380 579 +0 1 5 0 580 798 799 581 33 578 579 102 +0 1 5 0 208 97 209 213 94 82 99 212 +0 1 5 0 213 209 100 210 212 99 32 101 +-1 1 5 7 79 80 81 82 91 100 101 102 +0 1 5 0 211 215 368 218 224 374 387 385 +0 1 5 0 215 213 216 368 374 223 383 387 +0 1 5 0 368 216 210 217 387 383 226 384 +-1 1 5 3 83 84 85 86 +0 1 5 0 218 369 567 372 385 388 587 391 +0 1 5 0 369 368 370 567 388 387 389 587 +0 1 5 0 567 370 217 371 587 389 384 390 +-1 1 5 3 87 88 89 90 +0 1 5 0 372 568 797 571 391 593 808 598 +0 1 5 0 568 567 569 797 593 587 595 808 +0 1 5 0 797 569 371 570 808 595 390 597 +0 1 5 0 571 797 570 103 598 808 597 229 +-1 1 5 5 92 93 94 95 +0 1 5 0 224 376 388 385 382 573 582 394 +0 1 5 0 376 374 387 388 573 378 393 582 +0 1 5 0 573 378 393 582 380 220 386 392 +-1 1 5 5 96 97 98 99 +0 1 5 0 382 575 583 394 581 799 800 586 +0 1 5 0 575 573 582 583 799 577 584 800 +0 1 5 0 799 577 584 800 579 380 392 585 +0 1 5 0 581 799 800 586 102 579 585 228 +0 1 5 0 374 223 383 387 220 212 225 386 +0 1 5 0 387 383 226 384 386 225 101 227 +-1 1 5 7 103 104 105 106 111 116 117 118 +0 1 5 0 385 388 587 391 394 582 592 590 +0 1 5 0 388 387 389 587 582 393 588 592 +0 1 5 0 587 389 384 390 592 588 396 589 +-1 1 5 3 107 108 109 110 +0 1 5 0 391 593 808 598 590 594 802 600 +0 1 5 0 593 587 595 808 594 592 596 802 +0 1 5 0 808 595 390 597 802 596 589 599 +0 1 5 0 598 808 597 229 600 802 599 399 +-1 1 5 5 112 113 114 115 +0 1 5 0 394 583 594 590 586 800 801 603 +0 1 5 0 583 582 592 594 800 584 602 801 +0 1 5 0 800 584 602 801 585 392 591 601 +0 1 5 0 586 800 801 603 228 585 601 398 +0 1 5 0 582 393 588 592 392 386 395 591 +0 1 5 0 592 588 396 589 591 395 227 397 +-1 1 5 7 119 120 121 122 123 124 125 126 +0 1 5 0 590 594 802 600 603 801 807 805 +0 1 5 0 594 592 596 802 801 602 803 807 +0 1 5 0 802 596 589 599 807 803 605 804 +0 1 5 0 600 802 599 399 805 807 804 608 +0 1 5 0 603 801 807 805 398 601 806 607 +0 1 5 0 801 602 803 807 601 591 604 806 +0 1 5 0 807 803 605 804 806 604 397 606 +0 1 5 0 805 807 804 608 607 806 606 12 +-1 1 5 3 128 141 142 143 +-1 1 5 3 129 138 139 140 +-1 1 5 3 130 135 136 137 +-1 1 5 3 131 132 133 134 +0 1 5 0 3 563 810 618 37 565 811 621 +0 1 5 0 563 364 616 810 565 366 619 811 +0 1 5 0 810 616 614 617 811 619 615 620 +0 1 5 0 618 810 617 409 621 811 620 412 +0 1 5 0 364 204 407 614 366 206 410 615 +0 1 5 0 614 407 405 408 615 410 406 411 +0 1 5 0 409 614 408 239 412 615 411 242 +0 1 5 0 204 89 237 405 206 91 240 406 +0 1 5 0 405 237 235 238 406 240 236 241 +0 1 5 0 239 405 238 112 242 406 241 115 +0 1 5 0 89 28 110 235 91 80 113 236 +0 1 5 0 235 110 104 111 236 113 109 114 +0 1 5 0 112 235 111 40 115 236 114 107 +0 1 5 0 28 4 38 104 80 36 105 109 +0 1 5 0 104 38 7 39 109 105 44 106 +0 1 5 0 40 104 39 6 107 109 106 45 +-1 1 5 7 148 161 162 163 164 201 202 203 +-1 1 5 3 149 158 159 160 +-1 1 5 3 150 155 156 157 +-1 1 5 3 151 152 153 154 +0 1 5 0 37 565 811 621 103 570 812 625 +0 1 5 0 565 366 619 811 570 371 623 812 +0 1 5 0 811 619 615 620 812 623 622 624 +0 1 5 0 621 811 620 412 625 812 624 416 +0 1 5 0 366 206 410 615 371 217 414 622 +0 1 5 0 615 410 406 411 622 414 413 415 +0 1 5 0 412 615 411 242 416 622 415 250 +0 1 5 0 206 91 240 406 217 210 248 413 +0 1 5 0 406 240 236 241 413 248 247 249 +0 1 5 0 242 406 241 115 250 413 249 245 +0 1 5 0 91 80 113 236 210 100 243 247 +0 1 5 0 236 113 109 114 247 243 119 244 +0 1 5 0 115 236 114 107 245 247 244 120 +-1 1 5 7 165 174 175 176 177 198 199 200 +-1 1 5 3 166 171 172 173 +-1 1 5 3 167 168 169 170 +0 1 5 0 103 570 812 625 229 597 813 629 +0 1 5 0 570 371 623 812 597 390 627 813 +0 1 5 0 812 623 622 624 813 627 626 628 +0 1 5 0 625 812 624 416 629 813 628 424 +0 1 5 0 371 217 414 622 390 384 422 626 +0 1 5 0 622 414 413 415 626 422 421 423 +0 1 5 0 416 622 415 250 424 626 423 419 +0 1 5 0 217 210 248 413 384 226 417 421 +0 1 5 0 413 248 247 249 421 417 254 418 +0 1 5 0 250 413 249 245 419 421 418 255 +-1 1 5 7 178 183 184 185 186 195 196 197 +-1 1 5 3 179 180 181 182 +0 1 5 0 229 597 813 629 399 599 814 637 +0 1 5 0 597 390 627 813 599 589 635 814 +0 1 5 0 813 627 626 628 814 635 634 636 +0 1 5 0 629 813 628 424 637 814 636 632 +0 1 5 0 390 384 422 626 589 396 630 634 +0 1 5 0 626 422 421 423 634 630 428 631 +0 1 5 0 424 626 423 419 632 634 631 429 +-1 1 5 7 187 188 189 190 191 192 193 194 +0 1 5 0 399 599 814 637 608 804 819 817 +0 1 5 0 599 589 635 814 804 605 815 819 +0 1 5 0 814 635 634 636 819 815 641 816 +0 1 5 0 637 814 636 632 817 819 816 642 +0 1 5 0 608 804 819 817 12 606 818 640 +0 1 5 0 804 605 815 819 606 397 638 818 +0 1 5 0 819 815 641 816 818 638 633 639 +0 1 5 0 817 819 816 642 640 818 639 427 +0 1 5 0 589 396 630 634 397 227 425 633 +0 1 5 0 634 630 428 631 633 425 420 426 +0 1 5 0 632 634 631 429 427 633 426 253 +0 1 5 0 384 226 417 421 227 101 251 420 +0 1 5 0 421 417 254 418 420 251 246 252 +0 1 5 0 419 421 418 255 253 420 252 118 +0 1 5 0 210 100 243 247 101 32 116 246 +0 1 5 0 247 243 119 244 246 116 108 117 +0 1 5 0 245 247 244 120 118 246 117 43 +0 1 5 0 80 36 105 109 32 13 41 108 +0 1 5 0 109 105 44 106 108 41 16 42 +0 1 5 0 107 109 106 45 43 108 42 15 +0 1 5 0 2 46 121 48 52 122 126 124 +-1 1 5 3 209 210 223 224 +0 1 5 0 46 130 256 127 122 132 257 128 +-1 1 5 3 211 212 221 222 +0 1 5 0 130 260 430 258 132 262 431 259 +-1 1 5 3 213 214 219 220 +0 1 5 0 260 434 643 432 262 436 644 433 +-1 1 5 3 215 216 217 218 +0 1 5 0 434 647 820 645 436 649 821 646 +0 1 5 0 647 3 618 820 649 37 621 821 +0 1 5 0 820 618 409 648 821 621 412 650 +0 1 5 0 645 820 648 643 646 821 650 644 +0 1 5 0 643 409 239 435 644 412 242 437 +0 1 5 0 432 643 435 430 433 644 437 431 +0 1 5 0 430 239 112 261 431 242 115 263 +0 1 5 0 258 430 261 256 259 431 263 257 +0 1 5 0 256 112 40 131 257 115 107 133 +0 1 5 0 127 256 131 121 128 257 133 126 +0 1 5 0 121 40 6 47 126 107 45 123 +0 1 5 0 48 121 47 5 124 126 123 53 +-1 1 5 6 228 229 230 243 +0 1 5 0 52 122 128 129 136 137 266 281 +0 1 5 0 129 128 126 124 281 266 138 139 +-1 1 5 6 231 232 233 242 +0 1 5 0 136 137 270 282 284 275 459 464 +0 1 5 0 282 270 266 281 464 459 278 285 +-1 1 5 6 234 235 236 241 +0 1 5 0 284 275 460 465 467 462 681 686 +0 1 5 0 465 460 459 464 686 681 463 468 +-1 1 5 6 237 238 239 240 +0 1 5 0 467 462 682 687 689 684 832 833 +0 1 5 0 687 682 681 686 833 832 685 690 +0 1 5 0 689 684 832 833 11 49 683 688 +0 1 5 0 833 832 685 690 688 683 461 466 +0 1 5 0 686 681 463 468 466 461 274 283 +0 1 5 0 464 459 278 285 283 274 134 135 +0 1 5 0 281 266 138 139 135 134 125 51 +-1 1 5 7 245 246 259 260 261 274 323 324 +0 1 5 0 122 132 257 128 137 264 268 266 +-1 1 5 3 247 248 257 258 +0 1 5 0 132 262 431 259 264 271 438 269 +-1 1 5 3 249 250 255 256 +0 1 5 0 262 436 644 433 271 447 677 444 +-1 1 5 3 251 252 253 254 +0 1 5 0 436 649 821 646 447 679 831 678 +0 1 5 0 649 37 621 821 679 103 625 831 +0 1 5 0 821 621 412 650 831 625 416 680 +0 1 5 0 646 821 650 644 678 831 680 677 +0 1 5 0 644 412 242 437 677 416 250 448 +0 1 5 0 433 644 437 431 444 677 448 438 +0 1 5 0 431 242 115 263 438 250 245 272 +0 1 5 0 259 431 263 257 269 438 272 268 +0 1 5 0 257 115 107 133 268 245 120 265 +0 1 5 0 128 257 133 126 266 268 265 138 +-1 1 5 6 262 263 264 273 +0 1 5 0 137 264 269 270 275 276 441 459 +0 1 5 0 270 269 268 266 459 441 277 278 +-1 1 5 6 265 266 267 272 +0 1 5 0 275 276 446 460 462 453 652 681 +0 1 5 0 460 446 441 459 681 652 456 463 +-1 1 5 6 268 269 270 271 +0 1 5 0 462 453 654 682 684 657 823 832 +0 1 5 0 682 654 652 681 832 823 660 685 +0 1 5 0 684 657 823 832 49 140 656 683 +0 1 5 0 832 823 660 685 683 656 452 461 +0 1 5 0 681 652 456 463 461 452 273 274 +0 1 5 0 459 441 277 278 274 273 267 134 +-1 1 5 7 275 276 285 286 287 296 321 322 +0 1 5 0 264 271 438 269 276 439 443 441 +-1 1 5 3 277 278 283 284 +0 1 5 0 271 447 677 444 439 449 661 445 +-1 1 5 3 279 280 281 282 +0 1 5 0 447 679 831 678 449 668 830 666 +0 1 5 0 679 103 625 831 668 229 629 830 +0 1 5 0 831 625 416 680 830 629 424 669 +0 1 5 0 678 831 680 677 666 830 669 661 +0 1 5 0 677 416 250 448 661 424 419 450 +0 1 5 0 444 677 448 438 445 661 450 443 +0 1 5 0 438 250 245 272 443 419 255 440 +0 1 5 0 269 438 272 268 441 443 440 277 +-1 1 5 6 288 289 290 295 +0 1 5 0 276 439 445 446 453 454 651 652 +0 1 5 0 446 445 443 441 652 651 455 456 +-1 1 5 6 291 292 293 294 +0 1 5 0 453 454 653 654 657 658 822 823 +0 1 5 0 654 653 651 652 823 822 659 660 +0 1 5 0 657 658 822 823 140 279 655 656 +0 1 5 0 823 822 659 660 656 655 451 452 +0 1 5 0 652 651 455 456 452 451 442 273 +-1 1 5 7 297 298 303 304 305 310 319 320 +0 1 5 0 439 449 661 445 454 662 665 651 +-1 1 5 3 299 300 301 302 +0 1 5 0 449 668 830 666 662 670 825 667 +0 1 5 0 668 229 629 830 670 399 637 825 +0 1 5 0 830 629 424 669 825 637 632 671 +0 1 5 0 666 830 669 661 667 825 671 665 +0 1 5 0 661 424 419 450 665 632 429 663 +0 1 5 0 445 661 450 443 651 665 663 455 +-1 1 5 6 306 307 308 309 +0 1 5 0 454 662 667 653 658 673 824 822 +0 1 5 0 653 667 665 651 822 824 674 659 +0 1 5 0 658 673 824 822 279 457 672 655 +0 1 5 0 822 824 674 659 655 672 664 451 +-1 1 5 7 311 312 313 314 315 316 317 318 +0 1 5 0 662 670 825 667 673 826 829 824 +0 1 5 0 670 399 637 825 826 608 817 829 +0 1 5 0 825 637 632 671 829 817 642 827 +0 1 5 0 667 825 671 665 824 829 827 674 +0 1 5 0 673 826 829 824 457 675 828 672 +0 1 5 0 826 608 817 829 675 12 640 828 +0 1 5 0 829 817 642 827 828 640 427 676 +0 1 5 0 824 829 827 674 672 828 676 664 +0 1 5 0 665 632 429 663 664 427 253 458 +0 1 5 0 651 665 663 455 451 664 458 442 +0 1 5 0 443 419 255 440 442 253 118 280 +0 1 5 0 441 443 440 277 273 442 280 267 +0 1 5 0 268 245 120 265 267 118 43 141 +0 1 5 0 266 268 265 138 134 267 141 125 +0 1 5 0 126 107 45 123 125 43 15 50 +0 1 5 0 124 126 123 53 51 125 50 14 +0 1 5 0 8 54 142 55 60 143 148 146 +-1 1 5 5 329 330 343 344 +0 1 5 0 54 152 153 142 149 286 287 150 +-1 1 5 5 331 332 341 342 +0 1 5 0 152 290 291 153 288 469 470 289 +-1 1 5 5 333 334 339 340 +0 1 5 0 290 473 474 291 471 691 692 472 +-1 1 5 5 335 336 337 338 +0 1 5 0 473 695 696 474 693 834 835 694 +0 1 5 0 695 9 33 696 834 699 700 835 +0 1 5 0 834 699 700 835 697 477 478 698 +0 1 5 0 693 834 835 694 691 697 698 692 +0 1 5 0 691 477 478 692 475 294 295 476 +0 1 5 0 471 691 692 472 469 475 476 470 +0 1 5 0 469 294 295 470 292 156 157 293 +0 1 5 0 288 469 470 289 286 292 293 287 +0 1 5 0 286 156 157 287 154 61 144 155 +0 1 5 0 149 286 287 150 143 154 155 148 +-1 1 5 7 346 347 360 409 422 423 424 425 +0 1 5 0 142 153 296 158 150 287 301 299 +-1 1 5 5 348 349 358 359 +0 1 5 0 153 291 304 296 289 470 479 302 +-1 1 5 5 350 351 356 357 +0 1 5 0 291 474 481 304 472 692 701 480 +-1 1 5 5 352 353 354 355 +0 1 5 0 474 696 703 481 694 835 836 702 +0 1 5 0 696 33 102 703 835 700 705 836 +0 1 5 0 835 700 705 836 698 478 483 704 +0 1 5 0 694 835 836 702 692 698 704 701 +0 1 5 0 692 478 483 701 476 295 306 482 +0 1 5 0 472 692 701 480 470 476 482 479 +0 1 5 0 470 295 306 479 293 157 297 305 +0 1 5 0 289 470 479 302 287 293 305 301 +-1 1 5 7 361 362 371 396 405 406 407 408 +0 1 5 0 296 304 484 307 302 479 489 487 +-1 1 5 5 363 364 369 370 +0 1 5 0 304 481 492 484 480 701 706 490 +-1 1 5 5 365 366 367 368 +0 1 5 0 481 703 708 492 702 836 837 707 +0 1 5 0 703 102 228 708 836 705 710 837 +0 1 5 0 836 705 710 837 704 483 494 709 +0 1 5 0 702 836 837 707 701 704 709 706 +0 1 5 0 701 483 494 706 482 306 485 493 +0 1 5 0 480 701 706 490 479 482 493 489 +-1 1 5 7 372 373 378 387 392 393 394 395 +0 1 5 0 484 492 721 495 490 706 725 711 +-1 1 5 5 374 375 376 377 +0 1 5 0 492 708 727 721 707 837 842 726 +0 1 5 0 708 228 398 727 837 710 729 842 +0 1 5 0 837 710 729 842 709 494 722 728 +0 1 5 0 707 837 842 726 706 709 728 725 +-1 1 5 7 379 380 381 382 383 384 385 386 +0 1 5 0 721 727 841 730 726 842 846 840 +0 1 5 0 727 398 607 841 842 729 843 846 +0 1 5 0 841 607 12 675 846 843 734 844 +0 1 5 0 730 841 675 457 840 846 844 735 +0 1 5 0 726 842 846 840 725 728 845 733 +0 1 5 0 842 729 843 846 728 722 731 845 +0 1 5 0 846 843 734 844 845 731 499 732 +0 1 5 0 840 846 844 735 733 845 732 723 +-1 1 5 6 388 389 390 391 +0 1 5 0 495 721 730 715 713 726 840 838 +0 1 5 0 715 730 457 279 838 840 735 719 +0 1 5 0 713 726 840 838 711 725 733 717 +0 1 5 0 838 840 735 719 717 733 723 500 +0 1 5 0 490 706 725 711 489 493 724 498 +0 1 5 0 706 494 722 725 493 485 496 724 +0 1 5 0 725 722 499 723 724 496 311 497 +0 1 5 0 711 725 723 500 498 724 497 486 +-1 1 5 6 397 398 403 404 +0 1 5 0 307 484 495 501 491 490 711 712 +-1 1 5 6 399 400 401 402 +0 1 5 0 501 495 715 716 714 713 838 839 +0 1 5 0 716 715 279 140 839 838 719 720 +0 1 5 0 714 713 838 839 712 711 717 718 +0 1 5 0 839 838 719 720 718 717 500 503 +0 1 5 0 491 490 711 712 487 489 498 502 +0 1 5 0 712 711 500 503 502 498 486 312 +0 1 5 0 302 479 489 487 301 305 488 310 +0 1 5 0 479 306 485 489 305 297 308 488 +0 1 5 0 489 485 311 486 488 308 162 309 +0 1 5 0 487 489 486 312 310 488 309 298 +-1 1 5 6 410 411 420 421 +0 1 5 0 158 296 307 313 303 302 487 504 +-1 1 5 6 412 413 418 419 +0 1 5 0 313 307 501 506 505 491 712 736 +-1 1 5 6 414 415 416 417 +0 1 5 0 506 501 716 738 737 714 839 847 +0 1 5 0 738 716 140 49 847 839 720 740 +0 1 5 0 737 714 839 847 736 712 718 739 +0 1 5 0 847 839 720 740 739 718 503 508 +0 1 5 0 505 491 712 736 504 487 502 507 +0 1 5 0 736 712 503 508 507 502 312 315 +0 1 5 0 303 302 487 504 299 301 310 314 +0 1 5 0 504 487 312 315 314 310 298 163 +0 1 5 0 150 287 301 299 148 155 300 161 +0 1 5 0 287 157 297 301 155 144 159 300 +0 1 5 0 301 297 162 298 300 159 62 160 +0 1 5 0 299 301 298 163 161 300 160 145 +-1 1 5 6 427 428 441 442 +0 1 5 0 55 142 158 164 151 150 299 316 +-1 1 5 6 429 430 439 440 +0 1 5 0 164 158 313 318 317 303 504 509 +-1 1 5 6 431 432 437 438 +0 1 5 0 318 313 506 511 510 505 736 741 +-1 1 5 6 433 434 435 436 +0 1 5 0 511 506 738 743 742 737 847 848 +0 1 5 0 743 738 49 11 848 847 740 745 +0 1 5 0 742 737 847 848 741 736 739 744 +0 1 5 0 848 847 740 745 744 739 508 513 +0 1 5 0 510 505 736 741 509 504 507 512 +0 1 5 0 741 736 508 513 512 507 315 320 +0 1 5 0 317 303 504 509 316 299 314 319 +0 1 5 0 509 504 315 320 319 314 163 166 +0 1 5 0 151 150 299 316 146 148 161 165 +0 1 5 0 316 299 163 166 165 161 145 63 +0 1 5 0 60 143 148 146 17 56 147 59 +0 1 5 0 143 61 144 148 56 18 57 147 +0 1 5 0 148 144 62 145 147 57 21 58 +0 1 5 0 146 148 145 63 59 147 58 20 +-1 1 5 5 448 461 462 463 +-1 1 5 5 449 458 459 460 +-1 1 5 5 450 455 456 457 +-1 1 5 5 451 452 453 454 +0 1 5 0 9 612 578 33 699 849 850 700 +0 1 5 0 612 403 379 578 849 750 751 850 +0 1 5 0 849 750 751 850 748 746 747 749 +0 1 5 0 699 849 850 700 477 748 749 478 +0 1 5 0 403 233 219 379 746 518 519 747 +0 1 5 0 746 518 519 747 516 514 515 517 +0 1 5 0 477 746 747 478 294 516 517 295 +0 1 5 0 233 93 94 219 514 325 326 515 +0 1 5 0 514 325 326 515 323 321 322 324 +0 1 5 0 294 514 515 295 156 323 324 157 +0 1 5 0 93 30 82 94 321 174 175 322 +0 1 5 0 321 174 175 322 172 167 171 173 +0 1 5 0 156 321 322 157 61 172 173 144 +0 1 5 0 30 10 31 82 167 67 168 171 +0 1 5 0 82 31 13 32 171 168 68 169 +-1 1 5 7 467 480 481 482 519 520 521 522 +-1 1 5 5 468 477 478 479 +-1 1 5 5 469 474 475 476 +-1 1 5 5 470 471 472 473 +0 1 5 0 33 578 579 102 700 850 857 705 +0 1 5 0 578 379 380 579 850 751 766 857 +0 1 5 0 850 751 766 857 749 747 764 765 +0 1 5 0 700 850 857 705 478 749 765 483 +0 1 5 0 379 219 220 380 747 519 527 764 +0 1 5 0 747 519 527 764 517 515 520 525 +0 1 5 0 478 747 764 483 295 517 525 306 +0 1 5 0 219 94 212 220 515 326 332 520 +0 1 5 0 515 326 332 520 324 322 330 331 +0 1 5 0 295 515 520 306 157 324 331 297 +0 1 5 0 94 82 99 212 322 175 327 330 +0 1 5 0 212 99 32 101 330 327 177 328 +-1 1 5 7 483 492 493 494 515 516 517 518 +-1 1 5 5 484 489 490 491 +-1 1 5 5 485 486 487 488 +0 1 5 0 102 579 585 228 705 857 856 710 +0 1 5 0 579 380 392 585 857 766 759 856 +0 1 5 0 857 766 759 856 765 764 752 757 +0 1 5 0 705 857 856 710 483 765 757 494 +0 1 5 0 380 220 386 392 764 527 528 752 +0 1 5 0 764 527 528 752 525 520 524 526 +0 1 5 0 483 764 752 494 306 525 526 485 +0 1 5 0 220 212 225 386 520 332 521 524 +0 1 5 0 386 225 101 227 524 521 334 522 +-1 1 5 7 495 500 501 502 511 512 513 514 +-1 1 5 5 496 497 498 499 +0 1 5 0 228 585 601 398 710 856 851 729 +0 1 5 0 585 392 591 601 856 759 760 851 +0 1 5 0 856 759 760 851 757 752 756 758 +0 1 5 0 710 856 851 729 494 757 758 722 +0 1 5 0 392 386 395 591 752 528 753 756 +0 1 5 0 591 395 227 397 756 753 530 754 +-1 1 5 7 503 504 505 506 507 508 509 510 +0 1 5 0 398 601 806 607 729 851 855 843 +0 1 5 0 601 591 604 806 851 760 852 855 +0 1 5 0 806 604 397 606 855 852 762 853 +0 1 5 0 607 806 606 12 843 855 853 734 +0 1 5 0 729 851 855 843 722 758 854 731 +0 1 5 0 851 760 852 855 758 756 761 854 +0 1 5 0 855 852 762 853 854 761 754 763 +0 1 5 0 843 855 853 734 731 854 763 499 +0 1 5 0 494 752 756 722 485 526 755 496 +0 1 5 0 752 528 753 756 526 524 529 755 +0 1 5 0 756 753 530 754 755 529 522 531 +0 1 5 0 722 756 754 499 496 755 531 311 +0 1 5 0 306 520 524 485 297 331 523 308 +0 1 5 0 520 332 521 524 331 330 333 523 +0 1 5 0 524 521 334 522 523 333 328 335 +0 1 5 0 485 524 522 311 308 523 335 162 +0 1 5 0 157 322 330 297 144 173 329 159 +0 1 5 0 322 175 327 330 173 171 176 329 +0 1 5 0 330 327 177 328 329 176 169 178 +0 1 5 0 297 330 328 162 159 329 178 62 +0 1 5 0 61 167 171 144 18 64 170 57 +0 1 5 0 167 67 168 171 64 19 65 170 +0 1 5 0 171 168 68 169 170 65 22 66 +0 1 5 0 144 171 169 62 57 170 66 21 +-1 1 5 7 528 553 554 555 556 557 558 559 +-1 1 5 7 529 546 547 548 549 550 551 552 +-1 1 5 7 530 539 540 541 542 543 544 545 +-1 1 5 7 531 532 533 534 535 536 537 538 +0 1 5 0 12 606 818 640 734 853 862 860 +0 1 5 0 606 397 638 818 853 762 858 862 +0 1 5 0 818 638 633 639 862 858 775 859 +0 1 5 0 640 818 639 427 860 862 859 776 +0 1 5 0 734 853 862 860 499 763 861 774 +0 1 5 0 853 762 858 862 763 754 772 861 +0 1 5 0 862 858 775 859 861 772 771 773 +0 1 5 0 860 862 859 776 774 861 773 769 +0 1 5 0 397 227 425 633 754 530 767 771 +0 1 5 0 633 425 420 426 771 767 540 768 +0 1 5 0 427 633 426 253 769 771 768 541 +0 1 5 0 499 754 771 769 311 531 770 539 +0 1 5 0 754 530 767 771 531 522 537 770 +0 1 5 0 771 767 540 768 770 537 536 538 +0 1 5 0 769 771 768 541 539 770 538 534 +0 1 5 0 227 101 251 420 522 334 532 536 +0 1 5 0 420 251 246 252 536 532 344 533 +0 1 5 0 253 420 252 118 534 536 533 345 +0 1 5 0 311 522 536 534 162 335 535 343 +0 1 5 0 522 334 532 536 335 328 341 535 +0 1 5 0 536 532 344 533 535 341 340 342 +0 1 5 0 534 536 533 345 343 535 342 338 +0 1 5 0 101 32 116 246 328 177 336 340 +0 1 5 0 246 116 108 117 340 336 187 337 +0 1 5 0 118 246 117 43 338 340 337 188 +0 1 5 0 162 328 340 338 62 178 339 186 +0 1 5 0 328 177 336 340 178 169 184 339 +0 1 5 0 340 336 187 337 339 184 183 185 +0 1 5 0 338 340 337 188 186 339 185 181 +0 1 5 0 32 13 41 108 169 68 179 183 +0 1 5 0 108 41 16 42 183 179 72 180 +0 1 5 0 43 108 42 15 181 183 180 73 +0 1 5 0 62 169 183 181 21 66 182 71 +0 1 5 0 169 68 179 183 66 22 69 182 +0 1 5 0 183 179 72 180 182 69 25 70 +0 1 5 0 181 183 180 73 71 182 70 24 +-1 1 5 6 568 581 582 583 +-1 1 5 6 569 578 579 580 +-1 1 5 6 570 575 576 577 +-1 1 5 6 571 572 573 574 +0 1 5 0 11 49 683 688 745 740 863 864 +0 1 5 0 688 683 461 466 864 863 781 782 +0 1 5 0 745 740 863 864 513 508 779 780 +0 1 5 0 864 863 781 782 780 779 777 778 +0 1 5 0 466 461 274 283 778 777 546 547 +0 1 5 0 513 508 777 778 320 315 544 545 +0 1 5 0 778 777 546 547 545 544 542 543 +0 1 5 0 283 274 134 135 543 542 350 351 +0 1 5 0 320 315 542 543 166 163 348 349 +0 1 5 0 543 542 350 351 349 348 346 347 +0 1 5 0 135 134 125 51 347 346 195 196 +0 1 5 0 166 163 346 347 63 145 193 194 +0 1 5 0 347 346 195 196 194 193 192 190 +-1 1 5 7 585 598 635 636 637 638 639 640 +-1 1 5 6 586 595 596 597 +-1 1 5 6 587 592 593 594 +-1 1 5 6 588 589 590 591 +0 1 5 0 49 140 656 683 740 720 865 863 +0 1 5 0 683 656 452 461 863 865 785 781 +0 1 5 0 740 720 865 863 508 503 784 779 +0 1 5 0 863 865 785 781 779 784 783 777 +0 1 5 0 461 452 273 274 777 783 550 546 +0 1 5 0 508 503 783 777 315 312 549 544 +0 1 5 0 777 783 550 546 544 549 548 542 +0 1 5 0 274 273 267 134 542 548 356 350 +0 1 5 0 315 312 548 542 163 298 355 348 +0 1 5 0 542 548 356 350 348 355 354 346 +-1 1 5 7 599 608 629 630 631 632 633 634 +-1 1 5 6 600 605 606 607 +-1 1 5 6 601 602 603 604 +0 1 5 0 140 279 655 656 720 719 870 865 +0 1 5 0 656 655 451 452 865 870 793 785 +0 1 5 0 720 719 870 865 503 500 791 784 +0 1 5 0 865 870 793 785 784 791 787 783 +0 1 5 0 452 451 442 273 783 787 555 550 +0 1 5 0 503 500 787 783 312 486 554 549 +0 1 5 0 783 787 555 550 549 554 553 548 +-1 1 5 7 609 614 623 624 625 626 627 628 +-1 1 5 6 610 611 612 613 +0 1 5 0 279 457 672 655 719 735 867 870 +0 1 5 0 655 672 664 451 870 867 792 793 +0 1 5 0 719 735 867 870 500 723 790 791 +0 1 5 0 870 867 792 793 791 790 789 787 +-1 1 5 7 615 616 617 618 619 620 621 622 +0 1 5 0 457 675 828 672 735 844 869 867 +0 1 5 0 675 12 640 828 844 734 860 869 +0 1 5 0 828 640 427 676 869 860 776 866 +0 1 5 0 672 828 676 664 867 869 866 792 +0 1 5 0 735 844 869 867 723 732 868 790 +0 1 5 0 844 734 860 869 732 499 774 868 +0 1 5 0 869 860 776 866 868 774 769 794 +0 1 5 0 867 869 866 792 790 868 794 789 +0 1 5 0 664 427 253 458 789 769 541 786 +0 1 5 0 451 664 458 442 787 789 786 555 +0 1 5 0 500 723 789 787 486 497 788 554 +0 1 5 0 723 499 769 789 497 311 539 788 +0 1 5 0 789 769 541 786 788 539 534 556 +0 1 5 0 787 789 786 555 554 788 556 553 +0 1 5 0 442 253 118 280 553 534 345 551 +0 1 5 0 273 442 280 267 548 553 551 356 +0 1 5 0 312 486 553 548 298 309 552 355 +0 1 5 0 486 311 534 553 309 162 343 552 +0 1 5 0 553 534 345 551 552 343 338 357 +0 1 5 0 548 553 551 356 355 552 357 354 +0 1 5 0 267 118 43 141 354 338 188 352 +0 1 5 0 134 267 141 125 346 354 352 195 +0 1 5 0 163 298 354 346 145 160 353 193 +0 1 5 0 298 162 338 354 160 62 186 353 +0 1 5 0 354 338 188 352 353 186 181 197 +0 1 5 0 346 354 352 195 193 353 197 192 +0 1 5 0 125 43 15 50 192 181 73 189 +0 1 5 0 51 125 50 14 190 192 189 76 +0 1 5 0 63 145 192 190 20 58 191 75 +0 1 5 0 145 62 181 192 58 21 71 191 +0 1 5 0 192 181 73 189 191 71 24 74 +0 1 5 0 190 192 189 76 75 191 74 23 +# attr geom nodes boundary 300 3 3 29 77 26 0 @@ -567,34 +690,6 @@ boundary 3 3 563 364 561 795 3 3 3 563 795 564 18 3 3 564 566 37 -18 3 207 92 211 218 -18 3 367 207 218 372 -18 3 566 367 372 571 -18 3 37 566 571 103 -18 3 92 81 98 211 -18 3 211 98 221 224 -18 3 224 221 381 382 -18 3 382 381 580 581 -18 3 581 580 33 102 -18 3 218 211 224 385 -18 3 385 224 382 394 -18 3 394 382 581 586 -18 3 586 581 102 228 -18 3 391 385 394 590 -18 3 590 394 586 603 -18 3 603 586 228 398 -18 3 608 805 607 12 -18 3 805 603 398 607 -18 3 600 590 603 805 -18 3 399 600 805 608 -18 3 598 391 590 600 -18 3 229 598 600 399 -18 3 372 218 385 391 -18 3 571 372 391 598 -18 3 103 571 598 229 -9 3 79 36 13 31 -6 3 78 35 10 30 -9 3 35 79 31 10 6 3 34 85 230 95 18 3 81 34 95 98 6 3 85 78 96 230 @@ -613,6 +708,34 @@ boundary 6 3 809 611 403 612 6 3 613 809 612 9 18 3 580 613 9 33 +6 3 78 35 10 30 +9 3 35 79 31 10 +9 3 79 36 13 31 +18 3 92 81 98 211 +18 3 207 92 211 218 +18 3 367 207 218 372 +18 3 566 367 372 571 +18 3 37 566 571 103 +18 3 211 98 221 224 +18 3 224 221 381 382 +18 3 382 381 580 581 +18 3 581 580 33 102 +18 3 218 211 224 385 +18 3 372 218 385 391 +18 3 571 372 391 598 +18 3 103 571 598 229 +18 3 385 224 382 394 +18 3 394 382 581 586 +18 3 586 581 102 228 +18 3 391 385 394 590 +18 3 598 391 590 600 +18 3 229 598 600 399 +18 3 590 394 586 603 +18 3 603 586 228 398 +18 3 600 590 603 805 +18 3 399 600 805 608 +18 3 805 603 398 607 +18 3 608 805 607 12 2 3 618 810 563 3 2 3 810 616 364 563 2 3 617 614 616 810 @@ -633,10 +756,10 @@ boundary 13 3 7 39 106 44 2 3 6 39 104 40 13 3 39 6 45 106 -13 3 106 45 15 42 +10 3 36 105 41 13 10 3 105 44 16 41 13 3 44 106 42 16 -10 3 36 105 41 13 +13 3 106 45 15 42 1 3 48 121 46 2 5 3 2 46 122 52 17 3 48 2 52 124 @@ -663,34 +786,6 @@ boundary 1 3 5 47 121 48 14 3 47 5 53 123 17 3 5 48 124 53 -14 3 123 53 14 50 -17 3 53 124 51 14 -14 3 45 123 50 15 -5 3 264 271 439 276 -5 3 276 439 454 453 -5 3 453 454 658 657 -5 3 657 658 279 140 -5 3 439 449 662 454 -5 3 454 662 673 658 -5 3 658 673 457 279 -5 3 673 826 675 457 -5 3 662 670 826 673 -5 3 670 399 608 826 -5 3 826 608 12 675 -5 3 449 668 670 662 -5 3 668 229 399 670 -5 3 271 447 449 439 -5 3 447 679 668 449 -5 3 679 103 229 668 -5 3 132 262 271 264 -5 3 262 436 447 271 -5 3 436 649 679 447 -5 3 649 37 103 679 -5 3 122 132 264 137 -5 3 137 264 276 275 -5 3 275 276 453 462 -5 3 462 453 657 684 -5 3 684 657 140 49 5 3 52 122 137 136 17 3 129 52 136 281 17 3 124 129 281 139 @@ -709,6 +804,34 @@ boundary 17 3 468 686 466 283 17 3 285 464 283 135 17 3 139 281 135 51 +5 3 122 132 264 137 +5 3 132 262 271 264 +5 3 262 436 447 271 +5 3 436 649 679 447 +5 3 649 37 103 679 +5 3 137 264 276 275 +5 3 275 276 453 462 +5 3 462 453 657 684 +5 3 684 657 140 49 +5 3 264 271 439 276 +5 3 271 447 449 439 +5 3 447 679 668 449 +5 3 679 103 229 668 +5 3 276 439 454 453 +5 3 453 454 658 657 +5 3 657 658 279 140 +5 3 439 449 662 454 +5 3 449 668 670 662 +5 3 668 229 399 670 +5 3 454 662 673 658 +5 3 658 673 457 279 +5 3 662 670 826 673 +5 3 670 399 608 826 +5 3 673 826 675 457 +5 3 826 608 12 675 +14 3 45 123 50 15 +14 3 123 53 14 50 +17 3 53 124 51 14 4 3 55 142 54 8 8 3 8 54 143 60 19 3 55 8 60 146 @@ -735,22 +858,22 @@ boundary 4 3 304 481 474 291 4 3 481 703 696 474 4 3 703 102 33 696 +4 3 307 484 304 296 4 3 484 492 481 304 4 3 492 708 703 481 4 3 708 228 102 703 -4 3 307 484 304 296 +4 3 495 721 492 484 +4 3 721 727 708 492 +4 3 727 398 228 708 +4 3 730 841 727 721 +4 3 841 607 398 727 +4 3 675 12 607 841 +4 3 457 675 841 730 +4 3 715 730 721 495 +4 3 279 457 730 715 4 3 501 495 484 307 4 3 716 715 495 501 4 3 140 279 715 716 -4 3 495 721 492 484 -4 3 715 730 721 495 -4 3 279 457 730 715 -4 3 730 841 727 721 -4 3 457 675 841 730 -4 3 675 12 607 841 -4 3 841 607 398 727 -4 3 721 727 708 492 -4 3 727 398 228 708 4 3 313 307 296 158 4 3 506 501 307 313 4 3 738 716 501 506 @@ -773,14 +896,14 @@ boundary 19 3 320 509 319 166 19 3 316 151 146 165 19 3 166 316 165 63 -19 3 63 146 59 20 -21 3 59 147 58 20 -21 3 147 57 21 58 -8 3 143 61 18 56 -21 3 56 18 57 147 8 3 60 143 56 17 19 3 146 60 17 59 21 3 17 56 147 59 +8 3 143 61 18 56 +21 3 56 18 57 147 +21 3 147 57 21 58 +19 3 63 146 59 20 +21 3 59 147 58 20 7 3 9 612 849 699 7 3 612 403 750 849 7 3 849 750 746 748 @@ -797,26 +920,26 @@ boundary 7 3 30 10 67 167 12 3 10 31 168 67 12 3 31 13 68 168 -22 3 57 170 66 21 -12 3 168 68 22 65 -22 3 170 65 22 66 +7 3 61 167 64 18 +22 3 18 64 170 57 7 3 167 67 19 64 12 3 67 168 65 19 22 3 64 19 65 170 -7 3 61 167 64 18 -22 3 18 64 170 57 +12 3 168 68 22 65 +22 3 170 65 22 66 +22 3 57 170 66 21 11 3 13 41 179 68 11 3 41 16 72 179 16 3 16 42 180 72 16 3 42 15 73 180 -16 3 180 73 24 70 -23 3 71 182 70 24 +23 3 21 66 182 71 +11 3 68 179 69 22 +23 3 66 22 69 182 11 3 179 72 25 69 16 3 72 180 70 25 23 3 182 69 25 70 -11 3 68 179 69 22 -23 3 66 22 69 182 -23 3 21 66 182 71 +16 3 180 73 24 70 +23 3 71 182 70 24 20 3 688 11 745 864 20 3 466 688 864 782 20 3 864 745 513 780 @@ -833,15 +956,16 @@ boundary 15 3 15 50 189 73 15 3 50 14 76 189 20 3 14 51 190 76 +20 3 190 63 20 75 +24 3 20 58 191 75 +24 3 58 21 71 191 +15 3 73 189 74 24 +24 3 191 71 24 74 15 3 189 76 23 74 20 3 76 190 75 23 24 3 75 191 74 23 -15 3 73 189 74 24 -24 3 191 71 24 74 -24 3 58 21 71 191 -20 3 190 63 20 75 -24 3 20 58 191 75 +# vert_id p1 p2 vertex_parents 845 26 0 1 @@ -1690,136 +1814,20 @@ vertex_parents 869 844 866 870 719 793 -coarse_elements -125 -3 12 13 14 15 -3 9 10 11 522 -3 6 7 8 523 -3 3 4 5 524 -5 92 93 94 95 -5 89 90 91 526 -5 86 87 88 527 -5 83 84 85 528 -3 23 24 25 26 -3 20 21 22 530 -3 17 18 19 531 -5 36 37 38 39 -5 33 34 35 533 -5 30 31 32 534 -3 74 75 76 77 -3 71 72 73 536 -5 46 47 48 49 -5 43 44 45 538 -3 67 68 69 70 -5 51 52 53 54 -7 65 60 59 66 64 61 62 63 -7 50 56 57 540 541 55 58 542 -7 42 41 78 537 539 40 79 543 -7 27 28 16 532 535 29 80 544 -7 0 1 2 525 529 82 81 545 -3 96 97 98 99 -3 547 100 101 102 -3 548 103 104 105 -3 549 106 107 108 -3 119 120 121 122 -3 551 123 124 125 -3 552 126 127 128 -3 137 138 139 140 -3 554 141 142 143 -3 144 145 146 147 -7 158 157 156 159 161 154 155 160 -7 556 148 149 150 557 153 152 151 -7 555 136 133 132 558 135 134 131 -7 553 118 117 129 559 115 116 130 -7 550 109 110 111 560 114 113 112 -3 166 167 168 169 -3 165 562 170 171 -3 164 563 172 173 -3 163 564 174 175 -6 251 252 253 254 -6 249 250 566 255 -6 247 248 567 256 -6 245 246 568 257 -3 226 227 228 229 -3 225 570 230 231 -3 224 571 232 233 -6 239 240 241 242 -6 237 238 573 243 -6 235 236 574 244 -3 218 219 220 221 -3 217 576 222 223 -6 191 192 193 194 -6 189 190 578 195 -3 213 214 215 216 -6 199 200 201 202 -7 205 208 207 206 204 209 210 203 -7 196 580 212 197 581 582 211 198 -7 188 577 184 187 579 583 185 186 -7 234 572 182 181 575 584 183 180 -7 162 565 176 177 569 585 179 178 -5 262 263 264 265 -5 261 587 266 267 -5 260 588 268 269 -5 259 589 270 271 -5 277 278 279 280 -5 276 591 281 282 -5 275 592 283 284 -5 287 288 289 290 -5 286 594 291 292 -5 318 319 320 321 -7 310 317 316 311 313 314 315 312 -6 306 307 308 309 -7 305 596 597 598 304 322 323 303 -6 297 298 299 300 -6 296 600 301 302 -7 293 595 599 601 294 285 324 295 -6 329 330 331 332 -6 328 603 333 334 -6 327 604 335 336 -7 272 593 602 605 273 274 325 326 -6 340 341 342 343 -6 339 607 344 345 -6 338 608 346 347 -6 337 609 348 349 -7 258 590 606 610 353 352 351 350 -5 354 355 356 357 -5 612 358 359 360 -5 613 361 362 363 -5 614 364 365 366 -5 401 402 403 404 -5 616 405 406 407 -5 617 408 409 410 -5 391 392 393 394 -5 619 395 396 397 -5 386 387 388 389 -7 376 379 378 377 375 380 381 374 -7 621 385 382 622 390 384 383 373 -7 620 400 370 623 398 399 371 372 -7 618 411 369 624 413 412 415 414 -7 615 367 368 625 419 418 417 416 -7 420 427 426 421 423 424 425 422 -7 627 428 429 430 434 433 432 431 -7 628 437 438 441 435 436 439 440 -7 629 448 447 442 444 445 446 443 -7 630 449 450 451 455 454 453 452 -6 456 457 458 459 -6 632 460 461 462 -6 633 463 464 465 -6 634 466 467 468 -6 469 470 471 472 -6 636 473 474 475 -6 637 476 477 478 -6 500 501 502 503 -6 639 504 505 506 -6 493 494 495 496 -7 491 486 485 492 490 487 488 489 -7 641 642 484 497 499 482 483 498 -7 640 643 510 509 507 481 511 508 -7 638 644 512 515 479 480 513 514 -7 635 645 516 517 521 520 519 518 +# root element orientation +root_state +7 +2 +0 +17 +9 +9 +4 +3 -vertices -871 +# top-level node coordinates +coordinates +26 3 0 -1 -1 1 -1 -1 @@ -1847,848 +1855,5 @@ vertices -1 1 1 0 1 1 1 1 1 -0.5 -1 -1 -1 -0.5 -1 -0.5 0 -1 -0 -0.5 -1 -0.5 -1 0 -1 -0.5 0 -0.5 0 0 -0 -0.5 0 -0 -1 -0.5 -1 -1 -0.5 -1 0 -0.5 -0 0 -0.5 -1 0.5 -1 -0.5 1 -1 -0 0.5 -1 -1 0.5 0 -0.5 1 0 -0 0.5 0 -1 1 -0.5 -0 1 -0.5 --0.5 0 -1 --0.5 1 -1 --1 0.5 -1 --0.5 0 0 --0.5 1 0 --1 0.5 0 --1 0 -0.5 --1 1 -0.5 --0.5 -1 0 --1 -0.5 0 --0.5 -1 1 -0 -0.5 1 --0.5 0 1 --1 -0.5 1 --1 -1 0.5 -0 -1 0.5 -0 0 0.5 --1 0 0.5 -0.5 -1 1 -1 -0.5 1 -0.5 0 1 -1 -1 0.5 -1 0 0.5 -1 0.5 1 -0.5 1 1 -0 0.5 1 -1 1 0.5 -0 1 0.5 --0.5 1 1 --1 0.5 1 --1 1 0.5 -0.5 -0.5 -1 -0.5 -1 -0.5 -1 -0.5 -0.5 -0.5 0 -0.5 -0 -0.5 -0.5 -0.5 -0.5 0 -0.5 -0.5 -0.5 -0.25 -0.5 -1 -0.25 -1 -0.5 -0.25 -0.5 -0.5 -0.5 -0.25 -1 -0.5 -0.25 -0.5 -0.25 0 -1 -0 -0.25 -1 -0.25 0 -0.5 -0 -0.25 -0.5 -0.25 -1 0 -0.25 -0.5 0 -0 -1 -0.25 -0.5 -1 -0.25 -0.5 -0.5 -0.25 -0 -0.5 -0.25 -0.5 -0.25 0 -0.5 0 -0.25 -0.25 0 0 -0 -0.25 0 -0 0 -0.25 -0.5 0.5 -1 -1 0.5 -0.5 -0.5 1 -0.5 -0 0.5 -0.5 -0.5 0.5 0 -0.5 0.5 -0.5 -0.5 0.25 -1 -0.25 0.5 -1 -0 0.25 -1 -0.5 0.25 -0.5 -0.25 0.5 -0.5 -0 0.25 -0.5 -0.5 0.25 0 -0.25 0.5 0 -0 0.25 0 -0.5 0.5 -0.25 -0 0.5 -0.25 --0.5 0.5 -1 --0.5 0 -0.5 --0.5 1 -0.5 --1 0.5 -0.5 --0.5 0.5 0 --0.5 0.5 -0.5 --0.5 0.25 -1 --0.5 0.25 -0.5 --1 0.25 -0.5 --0.25 0 -1 --0.25 0.5 -1 --0.25 0 -0.5 --0.25 0.5 -0.5 --0.5 0.25 0 --1 0.25 0 --1 0 -0.25 --0.5 0 -0.25 --0.5 0.5 -0.25 --1 0.5 -0.25 --0.25 0 0 --0.25 0.5 0 --0.5 -0.5 0 --0.5 -1 0.5 -0 -0.5 0.5 --0.5 0 0.5 --1 -0.5 0.5 --0.5 -0.5 1 --0.5 -0.5 0.5 --0.5 -1 0.25 --0.5 -0.5 0.25 --1 -0.5 0.25 --0.25 -1 0 --0.25 -0.5 0 --0.25 -1 0.5 --0.25 -0.5 0.5 -0 -1 0.25 -0 -0.5 0.25 --0.5 -0.25 0 -0 -0.25 0.5 --0.25 0 0.5 --0.5 -0.25 0.5 -0 0 0.25 --0.5 0 0.25 --1 -0.25 0 --1 -0.25 0.5 --1 0 0.25 -0.5 -1 0.5 -1 -0.5 0.5 -0.5 0 0.5 -0.5 -0.5 1 -0.5 -0.5 0.5 -0.25 -1 0.5 -0.25 -0.5 0.5 -0.5 -1 0.25 -0.5 -0.5 0.25 -0.5 -0.25 0.5 -0.5 0 0.25 -0.25 0 0.5 -1 0.5 0.5 -0.5 1 0.5 -0 0.5 0.5 -0.5 0.5 1 -0.5 0.5 0.5 -0.5 0.25 0.5 -0.25 0.5 0.5 -0 0.25 0.5 -0.5 0.5 0.25 -0 0.5 0.25 --0.5 1 0.5 --1 0.5 0.5 --0.5 0.5 1 --0.5 0.5 0.5 --0.5 0.25 0.5 --1 0.25 0.5 --0.5 0.5 0.25 --1 0.5 0.25 --0.25 0.5 0.5 -0.25 -0.25 -1 -0.25 -0.25 -0.5 -0.125 -0.25 -1 -0.125 -0.25 -0.5 -0.25 -0.125 -1 -0.25 -0.125 -0.5 -0.125 0 -1 -0 -0.125 -1 -0.125 0 -0.5 -0 -0.125 -0.5 -0.25 -0.5 -0.25 -0.5 -0.25 -0.25 -0.25 0 -0.25 -0 -0.25 -0.25 -0.25 -0.25 0 -0.25 -0.25 -0.25 -0.125 -0.5 -0.25 -0.125 -0.25 -0.25 -0.25 -0.125 -0.25 -0.125 0 -0.25 -0 -0.125 -0.25 -0.125 -0.5 0 -0.125 -0.25 0 -0 -0.5 -0.125 -0.25 -0.5 -0.125 -0.25 -0.25 -0.125 -0 -0.25 -0.125 -0.25 -0.125 0 -0.25 0 -0.125 -0.125 0 0 -0 -0.125 0 -0 0 -0.125 -0.25 -1 -0.25 -0.125 -1 -0.25 -0.25 -1 -0.125 -0.125 -1 0 -0 -1 -0.125 -0.25 0.25 -1 -0.25 0.25 -0.5 -0.25 0.125 -1 -0.125 0.25 -1 -0 0.125 -1 -0.25 0.125 -0.5 -0.125 0.25 -0.5 -0 0.125 -0.5 -0.5 0.25 -0.25 -0.25 0.5 -0.25 -0 0.25 -0.25 -0.25 0.25 0 -0.25 0.25 -0.25 -0.25 0.125 -0.25 -0.125 0.25 -0.25 -0 0.125 -0.25 -0.25 0.125 0 -0.125 0.25 0 -0 0.125 0 -0.25 0.25 -0.125 -0 0.25 -0.125 --0.25 0.25 -1 --0.25 0.25 -0.5 --0.25 0.125 -1 --0.25 0.125 -0.5 --0.125 0 -1 --0.125 0.25 -1 --0.125 0 -0.5 --0.125 0.25 -0.5 --0.25 0 -0.25 --0.25 0.5 -0.25 --0.5 0.25 -0.25 --0.25 0.25 0 --0.25 0.25 -0.25 --0.25 0.125 -0.25 --0.5 0.125 -0.25 --0.125 0 -0.25 --0.125 0.25 -0.25 --0.25 0.125 0 --0.5 0.125 0 --0.5 0 -0.125 --0.25 0 -0.125 --0.25 0.25 -0.125 --0.5 0.25 -0.125 --0.125 0 0 --0.125 0.25 0 --1 0.25 -0.25 --1 0.125 -0.25 --1 0.125 0 --1 0 -0.125 --1 0.25 -0.125 --0.25 -1 0.25 --0.25 -0.5 0.25 --0.25 -1 0.125 --0.25 -0.5 0.125 --0.125 -1 0 --0.125 -0.5 0 --0.125 -1 0.25 --0.125 -0.5 0.25 -0 -1 0.125 -0 -0.5 0.125 --0.25 -0.25 0 -0 -0.25 0.25 --0.25 0 0.25 --0.5 -0.25 0.25 --0.25 -0.25 0.5 --0.25 -0.25 0.25 --0.25 -0.25 0.125 --0.5 -0.25 0.125 --0.125 -0.25 0 --0.125 -0.25 0.25 -0 -0.25 0.125 --0.25 -0.125 0 -0 -0.125 0.25 --0.125 0 0.25 --0.25 -0.125 0.25 -0 0 0.125 --0.25 0 0.125 --0.5 -0.125 0 --0.5 -0.125 0.25 --0.5 0 0.125 --1 -0.25 0.25 --1 -0.25 0.125 --1 -0.125 0 --1 -0.125 0.25 --1 0 0.125 -0.25 -1 0.25 -0.25 -0.5 0.25 -0.125 -1 0.25 -0.125 -0.5 0.25 -0.25 -1 0.125 -0.25 -0.5 0.125 -0.5 -0.25 0.25 -0.25 0 0.25 -0.25 -0.25 0.5 -0.25 -0.25 0.25 -0.125 -0.25 0.25 -0.25 -0.25 0.125 -0.25 -0.125 0.25 -0.25 0 0.125 -0.125 0 0.25 -0.5 0.25 0.25 -0.25 0.5 0.25 -0 0.25 0.25 -0.25 0.25 0.5 -0.25 0.25 0.25 -0.25 0.125 0.25 -0.125 0.25 0.25 -0 0.125 0.25 -0.25 0.25 0.125 -0 0.25 0.125 --0.5 0.25 0.25 --1 0.25 0.25 --0.5 0.125 0.25 --1 0.125 0.25 --0.5 0.25 0.125 --1 0.25 0.125 --0.25 0.5 0.25 --0.25 0.25 0.5 --0.25 0.25 0.25 --0.25 0.125 0.25 --0.25 0.25 0.125 --0.125 0.25 0.25 -0.125 -0.125 -1 -0.125 -0.125 -0.5 -0.0625 -0.125 -1 -0.0625 -0.125 -0.5 -0.125 -0.0625 -1 -0.125 -0.0625 -0.5 -0.0625 0 -1 -0 -0.0625 -1 -0.0625 0 -0.5 -0 -0.0625 -0.5 -0.125 -0.125 -0.25 -0.0625 -0.125 -0.25 -0.125 -0.0625 -0.25 -0.0625 0 -0.25 -0 -0.0625 -0.25 -0.125 -0.5 -0.125 -0.125 -0.25 -0.125 -0.0625 -0.5 -0.125 -0.0625 -0.25 -0.125 -0.125 -0.5 -0.0625 -0.125 -0.25 -0.0625 -0.0625 -0.5 0 -0.0625 -0.25 0 -0 -0.5 -0.0625 -0 -0.25 -0.0625 -0.25 -0.125 -0.125 -0.125 0 -0.125 -0 -0.125 -0.125 -0.125 -0.125 0 -0.125 -0.125 -0.125 -0.0625 -0.125 -0.125 -0.125 -0.0625 -0.125 -0.0625 0 -0.125 -0 -0.0625 -0.125 -0.0625 -0.125 0 -0.125 -0.125 -0.0625 -0 -0.125 -0.0625 -0.125 -0.0625 0 -0.125 0 -0.0625 -0.0625 0 0 -0 -0.0625 0 -0 0 -0.0625 -0.125 -1 -0.125 -0.0625 -1 -0.125 -0.125 -1 -0.0625 -0.0625 -1 0 -0 -1 -0.0625 -0.125 0.125 -1 -0.125 0.125 -0.5 -0.125 0.0625 -1 -0.0625 0.125 -1 -0 0.0625 -1 -0.125 0.0625 -0.5 -0.0625 0.125 -0.5 -0 0.0625 -0.5 -0.125 0.125 -0.25 -0.125 0.0625 -0.25 -0.0625 0.125 -0.25 -0 0.0625 -0.25 -0.25 0.125 -0.125 -0.125 0.25 -0.125 -0 0.125 -0.125 -0.125 0.125 0 -0.125 0.125 -0.125 -0.125 0.0625 -0.125 -0.0625 0.125 -0.125 -0 0.0625 -0.125 -0.125 0.0625 0 -0.0625 0.125 0 -0 0.0625 0 -0.125 0.125 -0.0625 -0 0.125 -0.0625 --0.125 0.125 -1 --0.125 0.125 -0.5 --0.125 0.0625 -1 --0.125 0.0625 -0.5 --0.0625 0 -1 --0.0625 0.125 -1 --0.0625 0 -0.5 --0.0625 0.125 -0.5 --0.125 0.125 -0.25 --0.125 0 -0.125 --0.125 0.25 -0.125 --0.25 0.125 -0.125 --0.125 0.125 0 --0.125 0.125 -0.125 --0.125 0.0625 -0.25 --0.125 0.0625 -0.125 --0.25 0.0625 -0.125 --0.0625 0 -0.25 --0.0625 0.125 -0.25 --0.0625 0 -0.125 --0.0625 0.125 -0.125 --0.125 0.0625 0 --0.25 0.0625 0 --0.25 0 -0.0625 --0.125 0 -0.0625 --0.125 0.125 -0.0625 --0.25 0.125 -0.0625 --0.0625 0 0 --0.0625 0.125 0 --0.5 0.125 -0.125 --0.5 0.0625 -0.125 --0.5 0.0625 0 --0.5 0 -0.0625 --0.5 0.125 -0.0625 --1 0.125 -0.125 --1 0.0625 -0.125 --1 0.0625 0 --1 0 -0.0625 --1 0.125 -0.0625 --0.125 -1 0.125 --0.125 -0.5 0.125 --0.125 -1 0.0625 --0.125 -0.5 0.0625 --0.0625 -1 0 --0.0625 -0.5 0 --0.0625 -1 0.125 --0.0625 -0.5 0.125 -0 -1 0.0625 -0 -0.5 0.0625 --0.125 -0.25 0.125 --0.125 -0.25 0.0625 --0.0625 -0.25 0 --0.0625 -0.25 0.125 -0 -0.25 0.0625 --0.125 -0.125 0 -0 -0.125 0.125 --0.125 0 0.125 --0.25 -0.125 0.125 --0.125 -0.125 0.25 --0.125 -0.125 0.125 --0.125 -0.125 0.0625 --0.25 -0.125 0.0625 --0.0625 -0.125 0 --0.0625 -0.125 0.125 -0 -0.125 0.0625 --0.125 -0.0625 0 -0 -0.0625 0.125 --0.0625 0 0.125 --0.125 -0.0625 0.125 -0 0 0.0625 --0.125 0 0.0625 --0.25 -0.0625 0 --0.25 -0.0625 0.125 --0.25 0 0.0625 --0.5 -0.125 0.125 --0.5 -0.125 0.0625 --0.5 -0.0625 0 --0.5 -0.0625 0.125 --0.5 0 0.0625 --1 -0.125 0.125 --1 -0.125 0.0625 --1 -0.0625 0 --1 -0.0625 0.125 --1 0 0.0625 -0.125 -1 0.125 -0.125 -0.5 0.125 -0.0625 -1 0.125 -0.0625 -0.5 0.125 -0.125 -1 0.0625 -0.125 -0.5 0.0625 -0.125 -0.25 0.125 -0.25 -0.125 0.125 -0.125 0 0.125 -0.125 -0.125 0.25 -0.125 -0.125 0.125 -0.0625 -0.25 0.125 -0.0625 -0.125 0.125 -0.125 -0.25 0.0625 -0.125 -0.125 0.0625 -0.125 -0.0625 0.125 -0.125 0 0.0625 -0.0625 0 0.125 -0.25 0.125 0.125 -0.125 0.25 0.125 -0 0.125 0.125 -0.125 0.125 0.25 -0.125 0.125 0.125 -0.125 0.0625 0.125 -0.0625 0.125 0.125 -0 0.0625 0.125 -0.125 0.125 0.0625 -0 0.125 0.0625 --0.5 0.125 0.125 --1 0.125 0.125 --0.5 0.0625 0.125 --1 0.0625 0.125 --0.5 0.125 0.0625 --1 0.125 0.0625 --0.25 0.125 0.125 --0.25 0.0625 0.125 --0.25 0.125 0.0625 --0.125 0.25 0.125 --0.125 0.125 0.25 --0.125 0.125 0.125 --0.125 0.0625 0.125 --0.125 0.125 0.0625 --0.0625 0.125 0.125 -0.0625 -0.0625 -1 -0.0625 -0.0625 -0.5 -0.03125 -0.0625 -1 -0.03125 -0.0625 -0.5 -0.0625 -0.03125 -1 -0.0625 -0.03125 -0.5 -0.03125 0 -1 -0 -0.03125 -1 -0.03125 0 -0.5 -0 -0.03125 -0.5 -0.0625 -0.0625 -0.25 -0.03125 -0.0625 -0.25 -0.0625 -0.03125 -0.25 -0.03125 0 -0.25 -0 -0.03125 -0.25 -0.0625 -0.5 -0.0625 -0.0625 -0.25 -0.0625 -0.03125 -0.5 -0.0625 -0.03125 -0.25 -0.0625 -0.0625 -0.5 -0.03125 -0.0625 -0.25 -0.03125 -0.03125 -0.5 0 -0.03125 -0.25 0 -0 -0.5 -0.03125 -0 -0.25 -0.03125 -0.0625 -0.125 -0.0625 -0.03125 -0.125 -0.0625 -0.0625 -0.125 -0.03125 -0.03125 -0.125 0 -0 -0.125 -0.03125 -0.0625 -0.0625 -0.125 -0.125 -0.0625 -0.0625 -0.0625 0 -0.0625 -0 -0.0625 -0.0625 -0.0625 -0.0625 0 -0.0625 -0.0625 -0.0625 -0.03125 -0.0625 -0.125 -0.03125 -0.0625 -0.0625 -0.0625 -0.03125 -0.125 -0.0625 -0.03125 -0.0625 -0.03125 0 -0.125 -0 -0.03125 -0.125 -0.03125 0 -0.0625 -0 -0.03125 -0.0625 -0.03125 -0.0625 0 -0.0625 -0.0625 -0.03125 -0 -0.0625 -0.03125 -0.0625 -0.03125 0 -0.0625 0 -0.03125 -0.03125 0 0 -0 -0.03125 0 -0 0 -0.03125 -0.0625 -1 -0.0625 -0.03125 -1 -0.0625 -0.0625 -1 -0.03125 -0.03125 -1 0 -0 -1 -0.03125 -0.0625 0.0625 -1 -0.0625 0.0625 -0.5 -0.0625 0.03125 -1 -0.03125 0.0625 -1 -0 0.03125 -1 -0.0625 0.03125 -0.5 -0.03125 0.0625 -0.5 -0 0.03125 -0.5 -0.0625 0.0625 -0.25 -0.0625 0.03125 -0.25 -0.03125 0.0625 -0.25 -0 0.03125 -0.25 -0.0625 0.0625 -0.125 -0.0625 0.03125 -0.125 -0.03125 0.0625 -0.125 -0 0.03125 -0.125 -0.125 0.0625 -0.0625 -0.0625 0.125 -0.0625 -0 0.0625 -0.0625 -0.0625 0.0625 0 -0.0625 0.0625 -0.0625 -0.0625 0.03125 -0.0625 -0.03125 0.0625 -0.0625 -0 0.03125 -0.0625 -0.0625 0.03125 0 -0.03125 0.0625 0 -0 0.03125 0 -0.0625 0.0625 -0.03125 -0 0.0625 -0.03125 --0.0625 0.0625 -1 --0.0625 0.0625 -0.5 --0.0625 0.03125 -1 --0.0625 0.03125 -0.5 --0.03125 0 -1 --0.03125 0.0625 -1 --0.03125 0 -0.5 --0.03125 0.0625 -0.5 --0.125 0.0625 -0.0625 --0.25 0.0625 -0.0625 --0.125 0.03125 -0.0625 --0.25 0.03125 -0.0625 --0.125 0.03125 0 --0.25 0.03125 0 --0.25 0 -0.03125 --0.125 0 -0.03125 --0.125 0.0625 -0.03125 --0.25 0.0625 -0.03125 --0.0625 0.0625 -0.125 --0.0625 0 -0.0625 --0.0625 0.125 -0.0625 --0.0625 0.0625 0 --0.0625 0.0625 -0.0625 --0.0625 0.03125 -0.125 --0.0625 0.03125 -0.0625 --0.03125 0 -0.125 --0.03125 0.0625 -0.125 --0.03125 0 -0.0625 --0.03125 0.0625 -0.0625 --0.0625 0.03125 0 --0.0625 0 -0.03125 --0.0625 0.0625 -0.03125 --0.03125 0 0 --0.03125 0.0625 0 --0.0625 0.0625 -0.25 --0.0625 0.03125 -0.25 --0.03125 0 -0.25 --0.03125 0.0625 -0.25 --0.5 0.0625 -0.0625 --0.5 0.03125 -0.0625 --0.5 0.03125 0 --0.5 0 -0.03125 --0.5 0.0625 -0.03125 --1 0.0625 -0.0625 --1 0.03125 -0.0625 --1 0.03125 0 --1 0 -0.03125 --1 0.0625 -0.03125 --0.0625 -1 0.0625 --0.0625 -0.5 0.0625 --0.0625 -1 0.03125 --0.0625 -0.5 0.03125 --0.03125 -1 0 --0.03125 -0.5 0 --0.03125 -1 0.0625 --0.03125 -0.5 0.0625 -0 -1 0.03125 -0 -0.5 0.03125 --0.0625 -0.25 0.0625 --0.0625 -0.25 0.03125 --0.03125 -0.25 0 --0.03125 -0.25 0.0625 -0 -0.25 0.03125 --0.0625 -0.125 0.0625 --0.0625 -0.125 0.03125 --0.03125 -0.125 0 --0.03125 -0.125 0.0625 -0 -0.125 0.03125 --0.125 -0.0625 0.0625 --0.25 -0.0625 0.0625 --0.125 -0.0625 0.03125 --0.25 -0.0625 0.03125 --0.125 -0.03125 0 --0.25 -0.03125 0 --0.125 -0.03125 0.0625 --0.25 -0.03125 0.0625 --0.125 0 0.03125 --0.25 0 0.03125 --0.0625 -0.0625 0 -0 -0.0625 0.0625 --0.0625 0 0.0625 --0.0625 -0.0625 0.125 --0.0625 -0.0625 0.0625 --0.0625 -0.0625 0.03125 --0.03125 -0.0625 0 --0.03125 -0.0625 0.0625 -0 -0.0625 0.03125 --0.0625 -0.03125 0 -0 -0.03125 0.0625 --0.03125 0 0.0625 --0.0625 -0.03125 0.0625 -0 0 0.03125 --0.0625 0 0.03125 --0.5 -0.0625 0.0625 --0.5 -0.0625 0.03125 --0.5 -0.03125 0 --0.5 -0.03125 0.0625 --0.5 0 0.03125 --1 -0.0625 0.0625 --1 -0.0625 0.03125 --1 -0.03125 0 --1 -0.03125 0.0625 --1 0 0.03125 -0.0625 -1 0.0625 -0.0625 -0.5 0.0625 -0.03125 -1 0.0625 -0.03125 -0.5 0.0625 -0.0625 -1 0.03125 -0.0625 -0.5 0.03125 -0.0625 -0.125 0.0625 -0.125 -0.0625 0.0625 -0.0625 0 0.0625 -0.0625 -0.0625 0.125 -0.0625 -0.0625 0.0625 -0.03125 -0.125 0.0625 -0.03125 -0.0625 0.0625 -0.0625 -0.125 0.03125 -0.0625 -0.0625 0.03125 -0.0625 -0.03125 0.0625 -0.0625 0 0.03125 -0.03125 0 0.0625 -0.0625 -0.25 0.0625 -0.03125 -0.25 0.0625 -0.0625 -0.25 0.03125 -0.125 0.0625 0.0625 -0.0625 0.125 0.0625 -0 0.0625 0.0625 -0.0625 0.0625 0.125 -0.0625 0.0625 0.0625 -0.0625 0.03125 0.0625 -0.03125 0.0625 0.0625 -0 0.03125 0.0625 -0.0625 0.0625 0.03125 -0 0.0625 0.03125 --0.5 0.0625 0.0625 --1 0.0625 0.0625 --0.5 0.03125 0.0625 --1 0.03125 0.0625 --0.5 0.0625 0.03125 --1 0.0625 0.03125 --0.25 0.0625 0.0625 --0.25 0.03125 0.0625 --0.25 0.0625 0.03125 --0.0625 0.125 0.0625 --0.125 0.0625 0.0625 --0.0625 0.0625 0.125 --0.0625 0.0625 0.0625 --0.0625 0.03125 0.0625 --0.125 0.03125 0.0625 --0.0625 0.0625 0.03125 --0.125 0.0625 0.03125 --0.03125 0.0625 0.0625 -0.03125 -0.03125 -1 -0.03125 -0.03125 -0.5 -0.03125 -0.03125 -0.25 -0.03125 -0.5 -0.03125 -0.03125 -0.25 -0.03125 -0.03125 -0.125 -0.03125 -0.03125 -0.0625 -0.03125 -0.03125 -0.03125 -0.0625 -0.0625 -0.03125 -0.03125 -0.03125 0 -0.03125 -0 -0.03125 -0.03125 -0.03125 -0.03125 0 -0.03125 -0.03125 -0.03125 -0.03125 -0.03125 -0.125 -0.03125 -1 -0.03125 -0.03125 0.03125 -1 -0.03125 0.03125 -0.5 -0.03125 0.03125 -0.25 -0.03125 0.03125 -0.125 -0.03125 0.03125 -0.0625 -0.0625 0.03125 -0.03125 -0.03125 0.0625 -0.03125 -0 0.03125 -0.03125 -0.03125 0.03125 0 -0.03125 0.03125 -0.03125 --0.03125 0.03125 -1 --0.03125 0.03125 -0.5 --0.125 0.03125 -0.03125 --0.25 0.03125 -0.03125 --0.0625 0.03125 -0.03125 --0.03125 0.03125 -0.0625 --0.03125 0 -0.03125 --0.03125 0.0625 -0.03125 --0.03125 0.03125 0 --0.03125 0.03125 -0.03125 --0.03125 0.03125 -0.125 --0.03125 0.03125 -0.25 --0.5 0.03125 -0.03125 --1 0.03125 -0.03125 --0.03125 -1 0.03125 --0.03125 -0.5 0.03125 --0.03125 -0.25 0.03125 --0.03125 -0.125 0.03125 --0.125 -0.03125 0.03125 --0.25 -0.03125 0.03125 --0.0625 -0.03125 0.03125 --0.03125 -0.03125 0 --0.03125 -0.0625 0.03125 -0 -0.03125 0.03125 --0.03125 0 0.03125 --0.03125 -0.03125 0.0625 --0.03125 -0.03125 0.03125 --0.5 -0.03125 0.03125 --1 -0.03125 0.03125 -0.03125 -1 0.03125 -0.03125 -0.5 0.03125 -0.03125 -0.0625 0.03125 -0.0625 -0.03125 0.03125 -0.03125 0 0.03125 -0.03125 -0.03125 0.0625 -0.03125 -0.03125 0.03125 -0.03125 -0.125 0.03125 -0.03125 -0.25 0.03125 -0.0625 0.03125 0.03125 -0.03125 0.0625 0.03125 -0 0.03125 0.03125 -0.03125 0.03125 0.0625 -0.03125 0.03125 0.03125 --0.5 0.03125 0.03125 --1 0.03125 0.03125 --0.25 0.03125 0.03125 --0.03125 0.0625 0.03125 --0.0625 0.03125 0.03125 --0.03125 0.03125 0.0625 --0.03125 0.03125 0.03125 --0.125 0.03125 0.03125 + +mfem_mesh_end diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 8a1f00b41a..be15aca598 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/doc/CodeDocumentation.conf.in b/doc/CodeDocumentation.conf.in index 994271ea4c..a7540555d5 100644 --- a/doc/CodeDocumentation.conf.in +++ b/doc/CodeDocumentation.conf.in @@ -819,7 +819,9 @@ RECURSIVE = NO # run. EXCLUDE = @MFEM_SOURCE_DIR@/config/_config.hpp \ - @MFEM_SOURCE_DIR@/config/get_hypre_version.cpp + @MFEM_SOURCE_DIR@/config/get_hypre_version.cpp \ + @MFEM_SOURCE_DIR@/general/tinyxml2.h \ + @MFEM_SOURCE_DIR@/general/tinyxml2.cpp # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded diff --git a/doc/makefile b/doc/makefile index 424649220e..f782cac367 100644 --- a/doc/makefile +++ b/doc/makefile @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 3b3cf2540a..3219067bb2 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/examples/amgx/CMakeLists.txt b/examples/amgx/CMakeLists.txt index d29b473eb3..0b5eecf9ac 100644 --- a/examples/amgx/CMakeLists.txt +++ b/examples/amgx/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/examples/amgx/ex1.cpp b/examples/amgx/ex1.cpp index 612fe091e6..9314ab54db 100644 --- a/examples/amgx/ex1.cpp +++ b/examples/amgx/ex1.cpp @@ -205,10 +205,14 @@ int main(int argc, char *argv[]) if (amgx_solver) { + amgx.SetConvergenceCheck(true); amgx.Mult(B,X); } else { + // Omit convergence check at the AmgX level when using as a + // preconditioner. + amgx.SetConvergenceCheck(false); PCG(*A.As(), amgx, B, X, 3, 40, 1e-12, 0.0); } } diff --git a/examples/amgx/ex1p.cpp b/examples/amgx/ex1p.cpp index a92cf15d3d..ba40e6f99c 100644 --- a/examples/amgx/ex1p.cpp +++ b/examples/amgx/ex1p.cpp @@ -264,6 +264,7 @@ int main(int argc, char *argv[]) } amgx.SetOperator(*A.As()); + amgx.SetConvergenceCheck(true); amgx.Mult(B, X); // Release MPI communicators and resources created by AmgX diff --git a/examples/amgx/makefile b/examples/amgx/makefile index e0950a87b1..beb4586b3e 100644 --- a/examples/amgx/makefile +++ b/examples/amgx/makefile @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/examples/ex1.cpp b/examples/ex1.cpp index c4d0a8215b..803a207bf6 100644 --- a/examples/ex1.cpp +++ b/examples/ex1.cpp @@ -30,6 +30,7 @@ // Device sample runs: // ex1 -pa -d cuda // ex1 -pa -d raja-cuda +// * ex1 -pa -d raja-hip // ex1 -pa -d occa-cuda // ex1 -pa -d raja-omp // ex1 -pa -d occa-omp diff --git a/examples/ex10p.cpp b/examples/ex10p.cpp index ab11f20d42..aaf9f072a7 100644 --- a/examples/ex10p.cpp +++ b/examples/ex10p.cpp @@ -178,6 +178,7 @@ int main(int argc, char *argv[]) double visc = 1e-2; double mu = 0.25; double K = 5.0; + bool adaptive_lin_rtol = true; bool visualization = true; int vis_steps = 1; @@ -206,6 +207,9 @@ int main(int argc, char *argv[]) "Shear modulus in the Neo-Hookean hyperelastic model."); args.AddOption(&K, "-K", "--bulk-modulus", "Bulk modulus in the Neo-Hookean hyperelastic model."); + args.AddOption(&adaptive_lin_rtol, "-alrtol", "--adaptive-lin-rtol", + "-no-alrtol", "--no-adaptive-lin-rtol", + "Enable or disable adaptive linear solver rtol."); args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", "--no-visualization", "Enable or disable GLVis visualization."); @@ -574,6 +578,7 @@ HyperelasticOperator::HyperelasticOperator(ParFiniteElementSpace &f, newton_solver.SetPrintLevel(1); // print Newton iterations newton_solver.SetRelTol(rel_tol); newton_solver.SetAbsTol(0.0); + newton_solver.SetAdaptiveLinRtol(2, 0.5, 0.9); newton_solver.SetMaxIter(10); } diff --git a/examples/ex14.cpp b/examples/ex14.cpp index 0dfcd1797d..1603704b7c 100644 --- a/examples/ex14.cpp +++ b/examples/ex14.cpp @@ -5,6 +5,7 @@ // Sample runs: ex14 -m ../data/inline-quad.mesh -o 0 // ex14 -m ../data/star.mesh -r 4 -o 2 // ex14 -m ../data/star-mixed.mesh -r 4 -o 2 +// ex14 -m ../data/star-mixed.mesh -r 2 -o 2 -k 0 -e 1 // ex14 -m ../data/escher.mesh -s 1 // ex14 -m ../data/fichera.mesh -s 1 -k 1 // ex14 -m ../data/fichera-mixed.mesh -s 1 -k 1 @@ -44,6 +45,7 @@ int main(int argc, char *argv[]) int order = 1; double sigma = -1.0; double kappa = -1.0; + double eta = 0.0; bool visualization = 1; OptionsParser args(argc, argv); @@ -54,11 +56,12 @@ int main(int argc, char *argv[]) args.AddOption(&order, "-o", "--order", "Finite element order (polynomial degree) >= 0."); args.AddOption(&sigma, "-s", "--sigma", - "One of the two DG penalty parameters, typically +1/-1." + "One of the three DG penalty parameters, typically +1/-1." " See the documentation of class DGDiffusionIntegrator."); args.AddOption(&kappa, "-k", "--kappa", - "One of the two DG penalty parameters, should be positive." + "One of the three DG penalty parameters, should be positive." " Negative values are replaced with (order+1)^2."); + args.AddOption(&eta, "-e", "--eta", "BR2 penalty parameter."); args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", "--no-visualization", "Enable or disable GLVis visualization."); @@ -130,6 +133,11 @@ int main(int argc, char *argv[]) a->AddDomainIntegrator(new DiffusionIntegrator(one)); a->AddInteriorFaceIntegrator(new DGDiffusionIntegrator(one, sigma, kappa)); a->AddBdrFaceIntegrator(new DGDiffusionIntegrator(one, sigma, kappa)); + if (eta > 0) + { + a->AddInteriorFaceIntegrator(new DGDiffusionBR2Integrator(fespace, eta)); + a->AddBdrFaceIntegrator(new DGDiffusionBR2Integrator(fespace, eta)); + } a->Assemble(); a->Finalize(); const SparseMatrix &A = a->SpMat(); diff --git a/examples/ex14p.cpp b/examples/ex14p.cpp index 471d9c9410..f7d0c0da06 100644 --- a/examples/ex14p.cpp +++ b/examples/ex14p.cpp @@ -5,6 +5,7 @@ // Sample runs: mpirun -np 4 ex14p -m ../data/inline-quad.mesh -o 0 // mpirun -np 4 ex14p -m ../data/star.mesh -o 2 // mpirun -np 4 ex14p -m ../data/star-mixed.mesh -o 2 +// mpirun -np 4 ex14p -m ../data/star-mixed.mesh -o 2 -k 0 -e 1 // mpirun -np 4 ex14p -m ../data/escher.mesh -s 1 // mpirun -np 4 ex14p -m ../data/fichera.mesh -s 1 -k 1 // mpirun -np 4 ex14p -m ../data/fichera-mixed.mesh -s 1 -k 1 @@ -82,6 +83,7 @@ int main(int argc, char *argv[]) int order = 1; double sigma = -1.0; double kappa = -1.0; + double eta = 0.0; bool visualization = 1; OptionsParser args(argc, argv); @@ -95,11 +97,12 @@ int main(int argc, char *argv[]) args.AddOption(&order, "-o", "--order", "Finite element order (polynomial degree) >= 0."); args.AddOption(&sigma, "-s", "--sigma", - "One of the two DG penalty parameters, typically +1/-1." + "One of the three DG penalty parameters, typically +1/-1." " See the documentation of class DGDiffusionIntegrator."); args.AddOption(&kappa, "-k", "--kappa", - "One of the two DG penalty parameters, should be positive." + "One of the three DG penalty parameters, should be positive." " Negative values are replaced with (order+1)^2."); + args.AddOption(&eta, "-e", "--eta", "BR2 penalty parameter."); args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", "--no-visualization", "Enable or disable GLVis visualization."); @@ -194,6 +197,11 @@ int main(int argc, char *argv[]) a->AddDomainIntegrator(new DiffusionIntegrator(one)); a->AddInteriorFaceIntegrator(new DGDiffusionIntegrator(one, sigma, kappa)); a->AddBdrFaceIntegrator(new DGDiffusionIntegrator(one, sigma, kappa)); + if (eta > 0) + { + a->AddInteriorFaceIntegrator(new DGDiffusionBR2Integrator(fespace, eta)); + a->AddBdrFaceIntegrator(new DGDiffusionBR2Integrator(fespace, eta)); + } a->Assemble(); a->Finalize(); diff --git a/examples/ex15p.cpp b/examples/ex15p.cpp index 9ef9b6f400..600b825431 100644 --- a/examples/ex15p.cpp +++ b/examples/ex15p.cpp @@ -19,6 +19,13 @@ // mpirun -np 4 ex15p -m ../data/square-disc.mesh // mpirun -np 4 ex15p -m ../data/escher.mesh -r 2 -tf 0.3 // +// Different estimators: +// +// mpirun -np 4 ex15p -est 0 -e 1e-4 +// mpirun -np 4 ex15p -est 1 -e 1e-6 +// mpirun -np 4 ex15p -est 1 -o 3 -tf 0.3 +// mpirun -np 4 ex15p -est 2 -o 2 +// // Description: Building on Example 6, this example demonstrates dynamic AMR. // The mesh is adapted to a time-dependent solution by refinement // as well as by derefinement. For simplicity, the solution is @@ -28,8 +35,11 @@ // At each outer iteration the right hand side function is changed // to mimic a time dependent problem. Within each inner iteration // the problem is solved on a sequence of meshes which are locally -// refined according to a simple ZZ error estimator. At the end -// of the inner iteration the error estimates are also used to +// refined according to a chosen error estimator. Currently there +// are three error estimators supported: A L2 formulation of the +// Zienkiewicz-Zhu error estimator (0), a Kelly error indicator (1) +// and a traditional Zienkiewicz-Zhu error estimator (2). At the +// end of the inner iteration the error estimates are also used to // identify any elements which may be over-refined and a single // derefinement step is performed. After each refinement or // derefinement step a rebalance operation is performed to keep @@ -87,6 +97,7 @@ int main(int argc, char *argv[]) int nc_limit = 3; // maximum level of hanging nodes bool visualization = true; bool visit = false; + int which_estimator = 0; OptionsParser args(argc, argv); args.AddOption(&mesh_file, "-m", "--mesh", @@ -107,6 +118,9 @@ int main(int argc, char *argv[]) "Maximum level of hanging nodes."); args.AddOption(&t_final, "-tf", "--t-final", "Final time; start time is 0."); + args.AddOption(&which_estimator, "-est", "--estimator", + "Which estimator to use: " + "0 = L2ZZ, 1 = Kelly, 2 = ZZ. Defaults to L2ZZ."); args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", "--no-visualization", "Enable or disable GLVis visualization."); @@ -214,17 +228,43 @@ int main(int argc, char *argv[]) // provide the method ComputeElementFlux. We supply an L2 space for the // discontinuous flux and an H(div) space for the smoothed flux. L2_FECollection flux_fec(order, dim); - ParFiniteElementSpace flux_fes(&pmesh, &flux_fec, sdim); RT_FECollection smooth_flux_fec(order-1, dim); - ParFiniteElementSpace smooth_flux_fes(&pmesh, &smooth_flux_fec); - L2ZienkiewiczZhuEstimator estimator(*integ, x, flux_fes, smooth_flux_fes); + ErrorEstimator* estimator; + switch (which_estimator) + { + case 1: + { + auto flux_fes = new ParFiniteElementSpace(&pmesh, &flux_fec, sdim); + estimator = new KellyErrorEstimator(*integ, x, flux_fes); + break; + } + case 2: + { + auto flux_fes = new ParFiniteElementSpace(&pmesh, &fec, sdim); + estimator = new ZienkiewiczZhuEstimator(*integ, x, flux_fes); + break; + } + + default: + if (myid == 0) + { + std::cout << "Unkown estimator. Falling back to L2ZZ." << std::endl; + } + case 0: + { + auto flux_fes = new ParFiniteElementSpace(&pmesh, &flux_fec, sdim); + auto smooth_flux_fes = new ParFiniteElementSpace(&pmesh, &smooth_flux_fec); + estimator = new L2ZienkiewiczZhuEstimator(*integ, x, flux_fes, smooth_flux_fes); + break; + } + } // 11. As in Example 6p, we also need a refiner. This time the refinement // strategy is based on a fixed threshold that is applied locally to each // element. The global threshold is turned off by setting the total error // fraction to zero. We also enforce a maximum refinement ratio between // adjacent elements. - ThresholdRefiner refiner(estimator); + ThresholdRefiner refiner(*estimator); refiner.SetTotalErrorFraction(0.0); // use purely local threshold refiner.SetLocalErrorGoal(max_elem_error); refiner.PreferConformingRefinement(); @@ -233,7 +273,7 @@ int main(int argc, char *argv[]) // 12. A derefiner selects groups of elements that can be coarsened to form // a larger element. A conservative enough threshold needs to be set to // prevent derefining elements that would immediately be refined again. - ThresholdDerefiner derefiner(estimator); + ThresholdDerefiner derefiner(*estimator); derefiner.SetThreshold(hysteresis * max_elem_error); derefiner.SetNCLimit(nc_limit); @@ -316,7 +356,7 @@ int main(int argc, char *argv[]) refiner.Apply(pmesh); if (myid == 0) { - cout << ", total error: " << estimator.GetTotalError() << endl; + cout << ", total error: " << estimator->GetTotalError() << endl; } // 21. Quit the AMR loop if the termination criterion has been met @@ -346,6 +386,8 @@ int main(int argc, char *argv[]) } } + delete estimator; + // 25. Exit MPI_Finalize(); return 0; diff --git a/examples/ex25.cpp b/examples/ex25.cpp index 280ee783b2..00324d79ea 100644 --- a/examples/ex25.cpp +++ b/examples/ex25.cpp @@ -10,6 +10,10 @@ // ex25 -o 2 -f 8.0 -ref 3 -prob 4 -m ../data/inline-quad.mesh // ex25 -o 2 -f 2.0 -ref 1 -prob 4 -m ../data/inline-hex.mesh // +// Device sample runs: +// ex25 -o 2 -f 8.0 -ref 3 -prob 4 -m ../data/inline-quad.mesh -pa -d cuda +// ex25 -o 2 -f 2.0 -ref 1 -prob 4 -m ../data/inline-hex.mesh -pa -d cuda +// // Description: This example code solves a simple electromagnetic wave // propagation problem corresponding to the second order // indefinite Maxwell equation @@ -157,7 +161,10 @@ int main(int argc, char *argv[]) int iprob = 4; double freq = 5.0; bool herm_conv = true; + bool umf_solver = false; bool visualization = 1; + bool pa = false; + const char *device_config = "cpu"; OptionsParser args(argc, argv); args.AddOption(&mesh_file, "-m", "--mesh", @@ -176,15 +183,28 @@ int main(int argc, char *argv[]) "Frequency (in Hz)."); args.AddOption(&herm_conv, "-herm", "--hermitian", "-no-herm", "--no-hermitian", "Use convention for Hermitian operators."); +#ifdef MFEM_USE_SUITESPARSE + args.AddOption(&umf_solver, "-umf", "--umfpack", "-no-umf", + "--no-umfpack", "Use the UMFPack Solver."); +#endif args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", "--no-visualization", "Enable or disable GLVis visualization."); + args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa", + "--no-partial-assembly", "Enable Partial Assembly."); + args.AddOption(&device_config, "-d", "--device", + "Device configuration string, see Device::Configure()."); args.Parse(); if (iprob > 4) { iprob = 4; } prob = (prob_type)iprob; - // 2. Setup the mesh + // 2. Enable hardware devices such as GPUs, and programming models such as + // CUDA, OCCA, RAJA and OpenMP based on command line options. + Device device(device_config); + device.Print(); + + // 3. Setup the mesh if (!mesh_file) { exact_known = true; @@ -225,7 +245,7 @@ int main(int argc, char *argv[]) // Setup PML length Array2D length(dim, 2); length = 0.0; - // 3. Setup the Cartesian PML region. + // 4. Setup the Cartesian PML region. switch (prob) { case disc: @@ -251,17 +271,17 @@ int main(int argc, char *argv[]) comp_domain_bdr = pml->GetCompDomainBdr(); domain_bdr = pml->GetDomainBdr(); - // 4. Refine the mesh to increase the resolution. + // 5. Refine the mesh to increase the resolution. for (int l = 0; l < ref_levels; l++) { mesh->UniformRefinement(); } - // 5. Set element attributes in order to distinguish elements in the + // 6. Set element attributes in order to distinguish elements in the // PML region pml->SetAttributes(mesh); - // 6. Define a finite element space on the mesh. Here we use the Nedelec + // 7. Define a finite element space on the mesh. Here we use the Nedelec // finite elements of the specified order. FiniteElementCollection *fec = new ND_FECollection(order, dim); FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec); @@ -269,7 +289,7 @@ int main(int argc, char *argv[]) cout << "Number of finite element unknowns: " << size << endl; - // 7. Determine the list of true essential boundary dofs. In this example, + // 8. Determine the list of true essential boundary dofs. In this example, // the boundary conditions are defined based on the specific mesh and the // problem type. Array ess_tdof_list; @@ -311,12 +331,12 @@ int main(int argc, char *argv[]) } fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list); - // 8. Setup Complex Operator convention + // 9. Setup Complex Operator convention ComplexOperator::Convention conv = herm_conv ? ComplexOperator::HERMITIAN : ComplexOperator::BLOCK_SYMMETRIC; - // 9. Set up the linear form b(.) which corresponds to the right-hand side of - // the FEM linear system. + // 10. Set up the linear form b(.) which corresponds to the right-hand side of + // the FEM linear system. VectorFunctionCoefficient f(dim, source); ComplexLinearForm b(fespace, conv); if (prob == load_src) @@ -326,7 +346,7 @@ int main(int argc, char *argv[]) b.Vector::operator=(0.0); b.Assemble(); - // 10. Define the solution vector x as a complex finite element grid function + // 11. Define the solution vector x as a complex finite element grid function // corresponding to fespace. ComplexGridFunction x(fespace); x = 0.0; @@ -334,7 +354,7 @@ int main(int argc, char *argv[]) VectorFunctionCoefficient E_Im(dim, E_bdr_data_Im); x.ProjectBdrCoefficientTangent(E_Re, E_Im, ess_bdr); - // 11. Set up the sesquilinear form a(.,.) + // 12. Set up the sesquilinear form a(.,.) // // In Comp // Domain: 1/mu (Curl E, Curl F) - omega^2 * epsilon (E,F) @@ -388,32 +408,35 @@ int main(int argc, char *argv[]) a.AddDomainIntegrator(new VectorFEMassIntegrator(restr_c2_Re), new VectorFEMassIntegrator(restr_c2_Im)); - // 12. Assemble the bilinear form and the corresponding linear system, + // 13. Assemble the bilinear form and the corresponding linear system, // applying any necessary transformations such as: assembly, eliminating // boundary conditions, applying conforming constraints for // non-conforming AMR, etc. + if (pa) { a.SetAssemblyLevel(AssemblyLevel::PARTIAL); } a.Assemble(0); OperatorPtr A; Vector B, X; a.FormLinearSystem(ess_tdof_list, x, b, A, X, B); - // 13. Solve using a direct or an iterative solver + // 14. Solve using a direct or an iterative solver #ifdef MFEM_USE_SUITESPARSE + if (!pa && umf_solver) { ComplexUMFPackSolver csolver(*A.As()); csolver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS; csolver.SetPrintLevel(1); csolver.Mult(B, X); } -#else - // 13a. Set up the Bilinear form a(.,.) for the preconditioner +#endif + // 14a. Set up the Bilinear form a(.,.) for the preconditioner // // In Comp // Domain: 1/mu (Curl E, Curl F) + omega^2 * epsilon (E,F) // // In PML: 1/mu (abs(1/det(J) J^T J) Curl E, Curl F) // + omega^2 * epsilon (abs(det(J) * (J^T J)^-1) * E, F) + if (pa || !umf_solver) { ConstantCoefficient absomeg(pow(omega, 2) * epsilon); RestrictedCoefficient restr_absomeg(absomeg,attr); @@ -433,39 +456,57 @@ int main(int argc, char *argv[]) prec.AddDomainIntegrator(new CurlCurlIntegrator(restr_c1_abs)); prec.AddDomainIntegrator(new VectorFEMassIntegrator(restr_c2_abs)); + if (pa) { prec.SetAssemblyLevel(AssemblyLevel::PARTIAL); } prec.Assemble(); - OperatorPtr PCOpAh; - prec.FormSystemMatrix(ess_tdof_list, PCOpAh); - - // 13b. Define and apply a GMRES solver for AU=B with a block diagonal - // preconditioner based on the Gauss-Seidel sparse smoother. + // 14b. Define and apply a GMRES solver for AU=B with a block diagonal + // preconditioner based on the Gauss-Seidel or Jacobi sparse smoother. Array offsets(3); offsets[0] = 0; offsets[1] = fespace->GetTrueVSize(); offsets[2] = fespace->GetTrueVSize(); offsets.PartialSum(); - GSSmoother gs00(*PCOpAh.As()); - BlockDiagonalPreconditioner BlockGS(offsets); - ScaledOperator gs11(&gs00, - (conv == ComplexOperator::HERMITIAN) ? -1.0 : 1.0); - BlockGS.SetDiagonalBlock(0,&gs00); - BlockGS.SetDiagonalBlock(1,&gs11); + Operator *pc_r = nullptr; + Operator *pc_i = nullptr; + int s = (conv == ComplexOperator::HERMITIAN) ? -1.0 : 1.0; + if (pa) + { + // Jacobi Smoother + OperatorJacobiSmoother *d00 = new OperatorJacobiSmoother(prec, ess_tdof_list); + ScaledOperator *d11 = new ScaledOperator(d00, s); + pc_r = d00; + pc_i = d11; + } + else + { + OperatorPtr PCOpAh; + prec.SetDiagonalPolicy(mfem::Operator::DIAG_ONE); + prec.FormSystemMatrix(ess_tdof_list, PCOpAh); + + // Gauss-Seidel Smoother + GSSmoother *gs00 = new GSSmoother(*PCOpAh.As()); + ScaledOperator *gs11 = new ScaledOperator(gs00, s); + pc_r = gs00; + pc_i = gs11; + } + + BlockDiagonalPreconditioner BlockDP(offsets); + BlockDP.SetDiagonalBlock(0, pc_r); + BlockDP.SetDiagonalBlock(1, pc_i); GMRESSolver gmres; gmres.SetPrintLevel(1); gmres.SetKDim(200); - gmres.SetMaxIter(2000); + gmres.SetMaxIter(pa ? 5000 : 2000); gmres.SetRelTol(1e-5); gmres.SetAbsTol(0.0); gmres.SetOperator(*A); - gmres.SetPreconditioner(BlockGS); + gmres.SetPreconditioner(BlockDP); gmres.Mult(B, X); } -#endif - // 14. Recover the solution as a finite element grid function and compute the + // 15. Recover the solution as a finite element grid function and compute the // errors if the exact solution is known. a.RecoverFEMSolution(X, b, x); @@ -502,7 +543,7 @@ int main(int argc, char *argv[]) << sqrt(L2Error_Re*L2Error_Re + L2Error_Im*L2Error_Im) << "\n\n"; } - // 15. Save the refined mesh and the solution. This output can be viewed + // 16. Save the refined mesh and the solution. This output can be viewed // later using GLVis: "glvis -m mesh -g sol". { ofstream mesh_ofs("ex25.mesh"); @@ -517,7 +558,7 @@ int main(int argc, char *argv[]) x.imag().Save(sol_i_ofs); } - // 16. Send the solution by socket to a GLVis server. + // 17. Send the solution by socket to a GLVis server. if (visualization) { // Define visualization keys for GLVis (see GLVis documentation) @@ -568,7 +609,7 @@ int main(int argc, char *argv[]) } } - // 17. Free the used memory. + // 18. Free the used memory. delete pml; delete fespace; delete fec; @@ -914,7 +955,14 @@ void CartesianPML::SetBoundaries() void CartesianPML::SetAttributes(Mesh *mesh_) { + // Initialize bdr attributes + for (int i = 0; i < mesh_->GetNBE(); ++i) + { + mesh_->GetBdrElement(i)->SetAttribute(i+1); + } + int nrelem = mesh_->GetNE(); + elems.SetSize(nrelem); // Loop through the elements and identify which of them are in the PML diff --git a/examples/ex25p.cpp b/examples/ex25p.cpp index 503592f9a7..5811f57596 100644 --- a/examples/ex25p.cpp +++ b/examples/ex25p.cpp @@ -10,6 +10,10 @@ // mpirun -np 4 ex25p -o 2 -f 8.0 -rs 2 -rp 2 -prob 4 -m ../data/inline-quad.mesh // mpirun -np 4 ex25p -o 2 -f 2.0 -rs 1 -rp 1 -prob 4 -m ../data/inline-hex.mesh // +// Device sample runs: +// mpirun -np 4 ex25p -o 1 -f 3.0 -rs 3 -rp 1 -prob 2 -pa -d cuda +// mpirun -np 4 ex25p -o 2 -f 1.0 -rs 1 -rp 1 -prob 3 -pa -d cuda +// // Description: This example code solves a simple electromagnetic wave // propagation problem corresponding to the second order // indefinite Maxwell equation @@ -167,6 +171,8 @@ int main(int argc, char *argv[]) bool slu_solver = false; bool mumps_solver = false; bool visualization = 1; + bool pa = false; + const char *device_config = "cpu"; OptionsParser args(argc, argv); args.AddOption(&mesh_file, "-m", "--mesh", @@ -198,6 +204,10 @@ int main(int argc, char *argv[]) args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", "--no-visualization", "Enable or disable GLVis visualization."); + args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa", + "--no-partial-assembly", "Enable Partial Assembly."); + args.AddOption(&device_config, "-d", "--device", + "Device configuration string, see Device::Configure()."); args.Parse(); if (slu_solver && mumps_solver) { @@ -211,7 +221,12 @@ int main(int argc, char *argv[]) if (iprob > 4) { iprob = 4; } prob = (prob_type)iprob; - // 3. Setup the (serial) mesh on all processors. + // 3. Enable hardware devices such as GPUs, and programming models such as + // CUDA, OCCA, RAJA and OpenMP based on command line options. + Device device(device_config); + if (myid == 0) { device.Print(); } + + // 4. Setup the (serial) mesh on all processors. if (!mesh_file) { exact_known = true; @@ -259,7 +274,7 @@ int main(int argc, char *argv[]) // Setup PML length Array2D length(dim, 2); length = 0.0; - // 4. Setup the Cartesian PML region. + // 5. Setup the Cartesian PML region. switch (prob) { case disc: @@ -285,13 +300,13 @@ int main(int argc, char *argv[]) comp_domain_bdr = pml->GetCompDomainBdr(); domain_bdr = pml->GetDomainBdr(); - // 5. Refine the serial mesh on all processors to increase the resolution. + // 6. Refine the serial mesh on all processors to increase the resolution. for (int l = 0; l < ref_levels; l++) { mesh->UniformRefinement(); } - // 6. Define a parallel mesh by a partitioning of the serial mesh. + // 7. Define a parallel mesh by a partitioning of the serial mesh. ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh); delete mesh; { @@ -301,10 +316,10 @@ int main(int argc, char *argv[]) } } - // 7. Set element attributes in order to distinguish elements in the PML + // 8. Set element attributes in order to distinguish elements in the PML pml->SetAttributes(pmesh); - // 8. Define a parallel finite element space on the parallel mesh. Here we + // 9. Define a parallel finite element space on the parallel mesh. Here we // use the Nedelec finite elements of the specified order. FiniteElementCollection *fec = new ND_FECollection(order, dim); ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec); @@ -314,9 +329,9 @@ int main(int argc, char *argv[]) cout << "Number of finite element unknowns: " << size << endl; } - // 9. Determine the list of true (i.e. parallel conforming) essential - // boundary dofs. In this example, the boundary conditions are defined - // based on the specific mesh and the problem type. + // 10. Determine the list of true (i.e. parallel conforming) essential + // boundary dofs. In this example, the boundary conditions are defined + // based on the specific mesh and the problem type. Array ess_tdof_list; Array ess_bdr; if (pmesh->bdr_attributes.Size()) @@ -356,11 +371,11 @@ int main(int argc, char *argv[]) } fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list); - // 10. Setup Complex Operator convention + // 11. Setup Complex Operator convention ComplexOperator::Convention conv = herm_conv ? ComplexOperator::HERMITIAN : ComplexOperator::BLOCK_SYMMETRIC; - // 11. Set up the parallel linear form b(.) which corresponds to the + // 12. Set up the parallel linear form b(.) which corresponds to the // right-hand side of the FEM linear system. VectorFunctionCoefficient f(dim, source); ParComplexLinearForm b(fespace, conv); @@ -371,7 +386,7 @@ int main(int argc, char *argv[]) b.Vector::operator=(0.0); b.Assemble(); - // 12. Define the solution vector x as a parallel complex finite element grid + // 13. Define the solution vector x as a parallel complex finite element grid // function corresponding to fespace. ParComplexGridFunction x(fespace); x = 0.0; @@ -379,7 +394,7 @@ int main(int argc, char *argv[]) VectorFunctionCoefficient E_Im(dim, E_bdr_data_Im); x.ProjectBdrCoefficientTangent(E_Re, E_Im, ess_bdr); - // 13. Set up the parallel sesquilinear form a(.,.) + // 14. Set up the parallel sesquilinear form a(.,.) // // In Comp // Domain: 1/mu (Curl E, Curl F) - omega^2 * epsilon (E,F) @@ -433,19 +448,20 @@ int main(int argc, char *argv[]) a.AddDomainIntegrator(new VectorFEMassIntegrator(restr_c2_Re), new VectorFEMassIntegrator(restr_c2_Im)); - // 14. Assemble the parallel bilinear form and the corresponding linear + // 15. Assemble the parallel bilinear form and the corresponding linear // system, applying any necessary transformations such as: parallel // assembly, eliminating boundary conditions, applying conforming // constraints for non-conforming AMR, etc. + if (pa) { a.SetAssemblyLevel(AssemblyLevel::PARTIAL); } a.Assemble(); OperatorPtr Ah; Vector B, X; a.FormLinearSystem(ess_tdof_list, x, b, Ah, X, B); - // 15. Solve using a direct or an iterative solver + // 16. Solve using a direct or an iterative solver #ifdef MFEM_USE_SUPERLU - if (slu_solver) + if (!pa && slu_solver) { // Transform to monolithic HypreParMatrix HypreParMatrix *A = Ah.As()->GetSystemMatrix(); @@ -460,7 +476,7 @@ int main(int argc, char *argv[]) } #endif #ifdef MFEM_USE_MUMPS - if (mumps_solver) + if (!pa && mumps_solver) { HypreParMatrix *A = Ah.As()->GetSystemMatrix(); MUMPSSolver mumps; @@ -478,7 +494,7 @@ int main(int argc, char *argv[]) // // In PML: 1/mu (abs(1/det(J) J^T J) Curl E, Curl F) // + omega^2 * epsilon (abs(det(J) * (J^T J)^-1) * E, F) - if (!slu_solver && !mumps_solver) + if (pa || (!slu_solver && !mumps_solver)) { ConstantCoefficient absomeg(pow(omega, 2) * epsilon); RestrictedCoefficient restr_absomeg(absomeg,attr); @@ -498,11 +514,9 @@ int main(int argc, char *argv[]) prec.AddDomainIntegrator(new CurlCurlIntegrator(restr_c1_abs)); prec.AddDomainIntegrator(new VectorFEMassIntegrator(restr_c2_abs)); + if (pa) { prec.SetAssemblyLevel(AssemblyLevel::PARTIAL); } prec.Assemble(); - OperatorPtr PCOpAh; - prec.FormSystemMatrix(ess_tdof_list, PCOpAh); - // 16b. Define and apply a parallel GMRES solver for AU=B with a block // diagonal preconditioner based on hypre's AMS preconditioner. Array offsets(3); @@ -511,21 +525,41 @@ int main(int argc, char *argv[]) offsets[2] = fespace->GetTrueVSize(); offsets.PartialSum(); - HypreAMS ams00(*PCOpAh.As(),fespace); - BlockDiagonalPreconditioner BlockAMS(offsets); - ScaledOperator ams11(&ams00, - (conv == ComplexOperator::HERMITIAN) ? -1.0 : 1.0); - BlockAMS.SetDiagonalBlock(0,&ams00); - BlockAMS.SetDiagonalBlock(1,&ams11); + Operator *pc_r = nullptr; + Operator *pc_i = nullptr; + int s = (conv == ComplexOperator::HERMITIAN) ? -1.0 : 1.0; + if (pa) + { + // Jacobi Smoother + OperatorJacobiSmoother *d00 = new OperatorJacobiSmoother(prec, ess_tdof_list); + ScaledOperator *d11 = new ScaledOperator(d00, s); + pc_r = d00; + pc_i = d11; + } + else + { + OperatorPtr PCOpAh; + prec.FormSystemMatrix(ess_tdof_list, PCOpAh); + + // Hypre AMS + HypreAMS *ams00 = new HypreAMS(*PCOpAh.As(), fespace); + ScaledOperator *ams11 = new ScaledOperator(ams00, s); + pc_r = ams00; + pc_i = ams11; + } + + BlockDiagonalPreconditioner BlockDP(offsets); + BlockDP.SetDiagonalBlock(0, pc_r); + BlockDP.SetDiagonalBlock(1, pc_i); GMRESSolver gmres(MPI_COMM_WORLD); gmres.SetPrintLevel(1); gmres.SetKDim(200); - gmres.SetMaxIter(2000); + gmres.SetMaxIter(pa ? 5000 : 2000); gmres.SetRelTol(1e-5); gmres.SetAbsTol(0.0); gmres.SetOperator(*Ah); - gmres.SetPreconditioner(BlockAMS); + gmres.SetPreconditioner(BlockDP); gmres.Mult(B, X); } @@ -1000,8 +1034,12 @@ void CartesianPML::SetBoundaries() void CartesianPML::SetAttributes(ParMesh *pmesh) { - int myid; - MPI_Comm_rank(MPI_COMM_WORLD,&myid); + // Initialize bdr attributes + for (int i = 0; i < pmesh->GetNBE(); ++i) + { + pmesh->GetBdrElement(i)->SetAttribute(i+1); + } + int nrelem = pmesh->GetNE(); // Initialize list with 1 diff --git a/examples/ex26.cpp b/examples/ex26.cpp index 5ddd1ed8e4..564d013df3 100644 --- a/examples/ex26.cpp +++ b/examples/ex26.cpp @@ -40,7 +40,7 @@ using namespace mfem; // in the FiniteElementSpaceHierarchy. The preconditioner uses a CG solver on // the coarsest level and second order Chebyshev accelerated smoothers on the // other levels. -class DiffusionMultigrid : public Multigrid +class DiffusionMultigrid : public GeometricMultigrid { private: ConstantCoefficient one; @@ -49,7 +49,7 @@ public: // Constructs a diffusion multigrid for the given FiniteElementSpaceHierarchy // and the array of essential boundaries DiffusionMultigrid(FiniteElementSpaceHierarchy& fespaces, Array& ess_bdr) - : Multigrid(fespaces), one(1.0) + : GeometricMultigrid(fespaces), one(1.0) { ConstructCoarseOperatorAndSolver(fespaces.GetFESpaceAtLevel(0), ess_bdr); diff --git a/examples/ex26p.cpp b/examples/ex26p.cpp index f72f07a8cf..98d07293b8 100644 --- a/examples/ex26p.cpp +++ b/examples/ex26p.cpp @@ -37,7 +37,7 @@ using namespace mfem; // all spaces except the coarsest one in the ParFiniteElementSpaceHierarchy. // The multigrid uses a PCG solver preconditioned with AMG on the coarsest level // and second order Chebyshev accelerated smoothers on the other levels. -class DiffusionMultigrid : public Multigrid +class DiffusionMultigrid : public GeometricMultigrid { private: ConstantCoefficient one; @@ -48,7 +48,7 @@ public: // and the array of essential boundaries DiffusionMultigrid(ParFiniteElementSpaceHierarchy& fespaces, Array& ess_bdr) - : Multigrid(fespaces), one(1.0) + : GeometricMultigrid(fespaces), one(1.0) { ConstructCoarseOperatorAndSolver(fespaces.GetFESpaceAtLevel(0), ess_bdr); diff --git a/examples/ex6p.cpp b/examples/ex6p.cpp index 0cc6fc1236..fcb970efdb 100644 --- a/examples/ex6p.cpp +++ b/examples/ex6p.cpp @@ -4,9 +4,11 @@ // // Sample runs: mpirun -np 4 ex6p -m ../data/square-disc.mesh -o 1 // mpirun -np 4 ex6p -m ../data/square-disc.mesh -o 2 +// mpirun -np 4 ex6p -m ../data/square-disc.mesh -o 2 -ns // mpirun -np 4 ex6p -m ../data/square-disc-nurbs.mesh -o 2 // mpirun -np 4 ex6p -m ../data/star.mesh -o 3 // mpirun -np 4 ex6p -m ../data/escher.mesh -o 2 +// mpirun -np 4 ex6p -m ../data/escher.mesh -o 2 -ns // mpirun -np 4 ex6p -m ../data/fichera.mesh -o 2 // mpirun -np 4 ex6p -m ../data/disc-nurbs.mesh -o 2 // mpirun -np 4 ex6p -m ../data/ball-nurbs.mesh @@ -14,6 +16,7 @@ // mpirun -np 4 ex6p -m ../data/star-surf.mesh -o 2 // mpirun -np 4 ex6p -m ../data/square-disc-surf.mesh -o 2 // mpirun -np 4 ex6p -m ../data/amr-quad.mesh +// mpirun -np 4 ex6p --restart // // Device sample runs: // mpirun -np 4 ex6p -pa -d cuda @@ -34,8 +37,8 @@ // The example demonstrates MFEM's capability to work with both // conforming and nonconforming refinements, in 2D and 3D, on // linear, curved and surface meshes. Interpolation of functions -// from coarse to fine meshes, as well as persistent GLVis -// visualization are also illustrated. +// from coarse to fine meshes, restarting from a checkpoint, as +// well as persistent GLVis visualization are also illustrated. // // We recommend viewing Example 1 before viewing this example. @@ -59,6 +62,9 @@ int main(int argc, char *argv[]) int order = 1; bool pa = false; const char *device_config = "cpu"; + bool nc_simplices = false; + int max_dofs = 100000; + bool restart = false; bool visualization = true; OptionsParser args(argc, argv); @@ -70,6 +76,14 @@ int main(int argc, char *argv[]) "--no-partial-assembly", "Enable Partial Assembly."); args.AddOption(&device_config, "-d", "--device", "Device configuration string, see Device::Configure()."); + args.AddOption(&nc_simplices, "-ns", "--nonconforming-simplices", + "-cs", "--conforming-simplices", + "For simplicial meshes, enable/disable nonconforming" + " refinement"); + args.AddOption(&max_dofs, "-md", "--max-dofs", + "Stop after reaching this many degrees of freedom."); + args.AddOption(&restart, "-res", "--restart", "-no-res", "--no-restart", + "Restart computation from the last checkpoint."); args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", "--no-visualization", "Enable or disable GLVis visualization."); @@ -93,39 +107,52 @@ int main(int argc, char *argv[]) Device device(device_config); if (myid == 0) { device.Print(); } - // 4. Read the (serial) mesh from the given mesh file on all processors. We - // can handle triangular, quadrilateral, tetrahedral, hexahedral, surface - // and volume meshes with the same code. - Mesh *mesh = new Mesh(mesh_file, 1, 1); - int dim = mesh->Dimension(); - int sdim = mesh->SpaceDimension(); - - // 5. Refine the serial mesh on all processors to increase the resolution. - // Also project a NURBS mesh to a piecewise-quadratic curved mesh. Make - // sure that the mesh is non-conforming. - if (mesh->NURBSext) + ParMesh *pmesh; + if (!restart) { - mesh->UniformRefinement(); - mesh->SetCurvature(2); + // 4. Read the (serial) mesh from the given mesh file on all processors. + // We can handle triangular, quadrilateral, tetrahedral, hexahedral, + // surface and volume meshes with the same code. + Mesh mesh(mesh_file, 1, 1); + + // 5. Refine the serial mesh on all processors to increase the resolution. + // Also project a NURBS mesh to a piecewise-quadratic curved mesh. Make + // sure that the mesh is non-conforming. + if (mesh.NURBSext) + { + mesh.UniformRefinement(); + mesh.SetCurvature(2); + } + mesh.EnsureNCMesh(nc_simplices); + + // 6. Define a parallel mesh by partitioning the serial mesh. + // Once the parallel mesh is defined, the serial mesh can be deleted. + pmesh = new ParMesh(MPI_COMM_WORLD, mesh); + } + else + { + // 7. We can also restart the computation by loading the mesh from a + // previously saved check-point. + string fname(MakeParFilename("ex6p-checkpoint.", myid)); + ifstream ifs(fname); + MFEM_VERIFY(ifs.good(), "Checkpoint file " << fname << " not found."); + pmesh = new ParMesh(MPI_COMM_WORLD, ifs); } - mesh->EnsureNCMesh(); - // 6. Define a parallel mesh by partitioning the serial mesh. - // Once the parallel mesh is defined, the serial mesh can be deleted. - ParMesh pmesh(MPI_COMM_WORLD, *mesh); - delete mesh; + int dim = pmesh->Dimension(); + int sdim = pmesh->SpaceDimension(); - MFEM_VERIFY(pmesh.bdr_attributes.Size() > 0, + MFEM_VERIFY(pmesh->bdr_attributes.Size() > 0, "Boundary attributes required in the mesh."); - Array ess_bdr(pmesh.bdr_attributes.Max()); + Array ess_bdr(pmesh->bdr_attributes.Max()); ess_bdr = 1; - // 7. Define a finite element space on the mesh. The polynomial order is + // 8. Define a finite element space on the mesh. The polynomial order is // one (linear) by default, but this can be changed on the command line. H1_FECollection fec(order, dim); - ParFiniteElementSpace fespace(&pmesh, &fec); + ParFiniteElementSpace fespace(pmesh, &fec); - // 8. As in Example 1p, we set up bilinear and linear forms corresponding to + // 9. As in Example 1p, we set up bilinear and linear forms corresponding to // the Laplace problem -\Delta u = 1. We don't assemble the discrete // problem yet, this will be done in the main loop. ParBilinearForm a(&fespace); @@ -142,12 +169,12 @@ int main(int argc, char *argv[]) a.AddDomainIntegrator(integ); b.AddDomainIntegrator(new DomainLFIntegrator(one)); - // 9. The solution vector x and the associated finite element grid function - // will be maintained over the AMR iterations. We initialize it to zero. + // 10. The solution vector x and the associated finite element grid function + // will be maintained over the AMR iterations. We initialize it to zero. ParGridFunction x(&fespace); x = 0; - // 10. Connect to GLVis. + // 11. Connect to GLVis. char vishost[] = "localhost"; int visport = 19916; @@ -169,30 +196,29 @@ int main(int argc, char *argv[]) sout.precision(8); } - // 11. Set up an error estimator. Here we use the Zienkiewicz-Zhu estimator + // 12. Set up an error estimator. Here we use the Zienkiewicz-Zhu estimator // with L2 projection in the smoothing step to better handle hanging // nodes and parallel partitioning. We need to supply a space for the // discontinuous flux (L2) and a space for the smoothed flux (H(div) is // used here). L2_FECollection flux_fec(order, dim); - ParFiniteElementSpace flux_fes(&pmesh, &flux_fec, sdim); + ParFiniteElementSpace flux_fes(pmesh, &flux_fec, sdim); RT_FECollection smooth_flux_fec(order-1, dim); - ParFiniteElementSpace smooth_flux_fes(&pmesh, &smooth_flux_fec); + ParFiniteElementSpace smooth_flux_fes(pmesh, &smooth_flux_fec); // Another possible option for the smoothed flux space: // H1_FECollection smooth_flux_fec(order, dim); - // ParFiniteElementSpace smooth_flux_fes(&pmesh, &smooth_flux_fec, dim); + // ParFiniteElementSpace smooth_flux_fes(pmesh, &smooth_flux_fec, dim); L2ZienkiewiczZhuEstimator estimator(*integ, x, flux_fes, smooth_flux_fes); - // 12. A refiner selects and refines elements based on a refinement strategy. + // 13. A refiner selects and refines elements based on a refinement strategy. // The strategy here is to refine elements with errors larger than a // fraction of the maximum element error. Other strategies are possible. // The refiner will call the given error estimator. ThresholdRefiner refiner(estimator); refiner.SetTotalErrorFraction(0.7); - // 13. The main AMR loop. In each iteration we solve the problem on the + // 14. The main AMR loop. In each iteration we solve the problem on the // current mesh, visualize the solution, and refine the mesh. - const int max_dofs = 100000; for (int it = 0; ; it++) { HYPRE_Int global_dofs = fespace.GlobalTrueVSize(); @@ -202,19 +228,19 @@ int main(int argc, char *argv[]) cout << "Number of unknowns: " << global_dofs << endl; } - // 14. Assemble the right-hand side and determine the list of true + // 15. Assemble the right-hand side and determine the list of true // (i.e. parallel conforming) essential boundary dofs. Array ess_tdof_list; fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list); b.Assemble(); - // 15. Assemble the stiffness matrix. Note that MFEM doesn't care at this + // 16. Assemble the stiffness matrix. Note that MFEM doesn't care at this // point that the mesh is nonconforming and parallel. The FE space is // considered 'cut' along hanging edges/faces, and also across // processor boundaries. a.Assemble(); - // 16. Create the parallel linear system: eliminate boundary conditions. + // 17. Create the parallel linear system: eliminate boundary conditions. // The system will be solved for true (unconstrained/unique) DOFs only. OperatorPtr A; Vector B, X; @@ -222,7 +248,7 @@ int main(int argc, char *argv[]) const int copy_interior = 1; a.FormLinearSystem(ess_tdof_list, x, b, A, X, B, copy_interior); - // 17. Solve the linear system A X = B. + // 18. Solve the linear system A X = B. // * With full assembly, use the BoomerAMG preconditioner from hypre. // * With partial assembly, use a diagonal preconditioner. Solver *M = NULL; @@ -245,19 +271,19 @@ int main(int argc, char *argv[]) cg.Mult(B, X); delete M; - // 18. Switch back to the host and extract the parallel grid function + // 19. Switch back to the host and extract the parallel grid function // corresponding to the finite element approximation X. This is the // local solution on each processor. a.RecoverFEMSolution(X, b, x); - // 19. Send the solution by socket to a GLVis server. + // 20. Send the solution by socket to a GLVis server. if (visualization) { sout << "parallel " << num_procs << " " << myid << "\n"; - sout << "solution\n" << pmesh << x << flush; + sout << "solution\n" << *pmesh << x << flush; } - if (global_dofs > max_dofs) + if (global_dofs >= max_dofs) { if (myid == 0) { @@ -266,11 +292,11 @@ int main(int argc, char *argv[]) break; } - // 20. Call the refiner to modify the mesh. The refiner calls the error + // 21. Call the refiner to modify the mesh. The refiner calls the error // estimator to obtain element errors, then it selects elements to be // refined and finally it modifies the mesh. The Stop() method can be // used to determine if a stopping criterion was met. - refiner.Apply(pmesh); + refiner.Apply(*pmesh); if (refiner.Stop()) { if (myid == 0) @@ -280,7 +306,7 @@ int main(int argc, char *argv[]) break; } - // 21. Update the finite element space (recalculate the number of DOFs, + // 22. Update the finite element space (recalculate the number of DOFs, // etc.) and create a grid function update matrix. Apply the matrix // to any GridFunctions over the space. In this case, the update // matrix is an interpolation matrix so the updated GridFunction will @@ -288,11 +314,11 @@ int main(int argc, char *argv[]) fespace.Update(); x.Update(); - // 22. Load balance the mesh, and update the space and solution. Currently + // 23. Load balance the mesh, and update the space and solution. Currently // available only for nonconforming meshes. - if (pmesh.Nonconforming()) + if (pmesh->Nonconforming()) { - pmesh.Rebalance(); + pmesh->Rebalance(); // Update the space and the GridFunction. This time the update matrix // redistributes the GridFunction among the processors. @@ -300,12 +326,30 @@ int main(int argc, char *argv[]) x.Update(); } - // 23. Inform also the bilinear and linear forms that the space has + // 24. Inform also the bilinear and linear forms that the space has // changed. a.Update(); b.Update(); + + // 25. Save the current state of the mesh every 5 iterations. The + // computation can be restarted from this point. Note that unlike in + // visualization, we need to use the 'ParPrint' method to save all + // internal parallel data structures. + if ((it + 1) % 5 == 0) + { + ofstream ofs(MakeParFilename("ex6p-checkpoint.", myid)); + ofs.precision(8); + pmesh->ParPrint(ofs); + + if (myid == 0) + { + cout << "\nCheckpoint saved." << endl; + } + } } + delete pmesh; + MPI_Finalize(); return 0; } diff --git a/examples/ex9.cpp b/examples/ex9.cpp index c8a6e70832..d2e483e7b6 100644 --- a/examples/ex9.cpp +++ b/examples/ex9.cpp @@ -290,15 +290,16 @@ int main(int argc, char *argv[]) k.SetAssemblyLevel(AssemblyLevel::FULL); } m.AddDomainIntegrator(new MassIntegrator); - k.AddDomainIntegrator(new ConvectionIntegrator(velocity, -1.0)); + constexpr double alpha = -1.0; + k.AddDomainIntegrator(new ConvectionIntegrator(velocity, alpha)); k.AddInteriorFaceIntegrator( - new TransposeIntegrator(new DGTraceIntegrator(velocity, 1.0, -0.5))); + new NonconservativeDGTraceIntegrator(velocity, alpha)); k.AddBdrFaceIntegrator( - new TransposeIntegrator(new DGTraceIntegrator(velocity, 1.0, -0.5))); + new NonconservativeDGTraceIntegrator(velocity, alpha)); LinearForm b(&fes); b.AddBdrFaceIntegrator( - new BoundaryFlowIntegrator(inflow, velocity, -1.0, -0.5)); + new BoundaryFlowIntegrator(inflow, velocity, alpha)); m.Assemble(); int skip_zeros = 0; diff --git a/examples/ex9p.cpp b/examples/ex9p.cpp index 418f2dc14a..e890314c89 100644 --- a/examples/ex9p.cpp +++ b/examples/ex9p.cpp @@ -64,6 +64,66 @@ double inflow_function(const Vector &x); // Mesh bounding box Vector bb_min, bb_max; +// Type of preconditioner for implicit time integrator +enum class PrecType : int +{ + ILU = 0, + AIR = 1 +}; + +#if MFEM_HYPRE_VERSION >= 21800 +// Algebraic multigrid preconditioner for advective problems based on +// approximate ideal restriction (AIR). Most effective when matrix is +// first scaled by DG block inverse, and AIR applied to scaled matrix. +// See https://doi.org/10.1137/17M1144350. +class AIR_prec : public Solver +{ +private: + const HypreParMatrix *A; + // Copy of A scaled by block-diagonal inverse + HypreParMatrix A_s; + + HypreBoomerAMG *AIR_solver; + int blocksize; + +public: + AIR_prec(int blocksize_) : AIR_solver(NULL), blocksize(blocksize_) { } + + void SetOperator(const Operator &op) + { + width = op.Width(); + height = op.Height(); + + A = dynamic_cast(&op); + MFEM_VERIFY(A != NULL, "AIR_prec requires a HypreParMatrix.") + + // Scale A by block-diagonal inverse + BlockInverseScale(A, &A_s, NULL, NULL, blocksize, + BlockInverseScaleJob::MATRIX_ONLY); + delete AIR_solver; + AIR_solver = new HypreBoomerAMG(A_s); + AIR_solver->SetAdvectiveOptions(1, "", "FA"); + AIR_solver->SetPrintLevel(0); + AIR_solver->SetMaxLevels(50); + } + + virtual void Mult(const Vector &x, Vector &y) const + { + // Scale the rhs by block inverse and solve system + HypreParVector z_s; + BlockInverseScale(A, NULL, &x, &z_s, blocksize, + BlockInverseScaleJob::RHS_ONLY); + AIR_solver->Mult(z_s, y); + } + + ~AIR_prec() + { + delete AIR_solver; + } +}; +#endif + + class DG_Solver : public Solver { private: @@ -71,24 +131,37 @@ private: SparseMatrix M_diag; HypreParMatrix *A; GMRESSolver linear_solver; - BlockILU prec; + Solver *prec; double dt; public: - DG_Solver(HypreParMatrix &M_, HypreParMatrix &K_, const FiniteElementSpace &fes) + DG_Solver(HypreParMatrix &M_, HypreParMatrix &K_, const FiniteElementSpace &fes, + PrecType prec_type) : M(M_), K(K_), A(NULL), linear_solver(M.GetComm()), - prec(fes.GetFE(0)->GetDof(), - BlockILU::Reordering::MINIMUM_DISCARDED_FILL), dt(-1.0) { + int block_size = fes.GetFE(0)->GetDof(); + if (prec_type == PrecType::ILU) + { + prec = new BlockILU(block_size, + BlockILU::Reordering::MINIMUM_DISCARDED_FILL); + } + else if (prec_type == PrecType::AIR) + { +#if MFEM_HYPRE_VERSION >= 21800 + prec = new AIR_prec(block_size); +#else + MFEM_ABORT("Must have MFEM_HYPRE_VERSION >= 21800 to use AIR.\n"); +#endif + } linear_solver.iterative_mode = false; linear_solver.SetRelTol(1e-9); linear_solver.SetAbsTol(0.0); linear_solver.SetMaxIter(100); linear_solver.SetPrintLevel(0); - linear_solver.SetPreconditioner(prec); + linear_solver.SetPreconditioner(*prec); M.GetDiag(M_diag); } @@ -121,10 +194,12 @@ public: ~DG_Solver() { + delete prec; delete A; } }; + /** A time-dependent operator for the right-hand side of the ODE. The DG weak form of du/dt = -v.grad(u) is M du/dt = K u + b, where M and K are the mass and advection matrices, and b describes the flow on the boundary. This can @@ -142,7 +217,8 @@ private: mutable Vector z; public: - FE_Evolution(ParBilinearForm &_M, ParBilinearForm &_K, const Vector &_b); + FE_Evolution(ParBilinearForm &_M, ParBilinearForm &_K, const Vector &_b, + PrecType prec_type); virtual void Mult(const Vector &x, Vector &y) const; virtual void ImplicitSolve(const double dt, const Vector &x, Vector &k); @@ -154,10 +230,9 @@ public: int main(int argc, char *argv[]) { // 1. Initialize MPI. - int num_procs, myid; - MPI_Init(&argc, &argv); - MPI_Comm_size(MPI_COMM_WORLD, &num_procs); - MPI_Comm_rank(MPI_COMM_WORLD, &myid); + MPI_Session mpi; + int num_procs = mpi.WorldSize(); + int myid = mpi.WorldRank(); // 2. Parse command-line options. problem = 0; @@ -178,7 +253,11 @@ int main(int argc, char *argv[]) bool adios2 = false; bool binary = false; int vis_steps = 5; - +#if MFEM_HYPRE_VERSION >= 21800 + PrecType prec_type = PrecType::AIR; +#else + PrecType prec_type = PrecType::ILU; +#endif int precision = 8; cout.precision(precision); @@ -212,6 +291,8 @@ int main(int argc, char *argv[]) "Final time; start time is 0."); args.AddOption(&dt, "-dt", "--time-step", "Time step."); + args.AddOption((int *)&prec_type, "-pt", "--prec-type", "Preconditioner for " + "implicit solves. 0 for ILU, 1 for pAIR-AMG."); args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", "--no-visualization", "Enable or disable GLVis visualization."); @@ -232,20 +313,19 @@ int main(int argc, char *argv[]) args.Parse(); if (!args.Good()) { - if (myid == 0) + if (mpi.Root()) { args.PrintUsage(cout); } - MPI_Finalize(); return 1; } - if (myid == 0) + if (mpi.Root()) { args.PrintOptions(cout); } Device device(device_config); - if (myid == 0) { device.Print(); } + if (mpi.Root()) { device.Print(); } // 3. Read the serial mesh from the given mesh file on all processors. We can // handle geometrically periodic meshes in this code. @@ -272,12 +352,11 @@ int main(int argc, char *argv[]) case 23: ode_solver = new SDIRK23Solver; break; case 24: ode_solver = new SDIRK34Solver; break; default: - if (myid == 0) + if (mpi.Root()) { cout << "Unknown ODE solver type: " << ode_solver_type << '\n'; } delete mesh; - MPI_Finalize(); return 3; } @@ -311,7 +390,7 @@ int main(int argc, char *argv[]) ParFiniteElementSpace *fes = new ParFiniteElementSpace(pmesh, &fec); HYPRE_Int global_vSize = fes->GlobalTrueVSize(); - if (myid == 0) + if (mpi.Root()) { cout << "Number of unknowns: " << global_vSize << endl; } @@ -342,15 +421,16 @@ int main(int argc, char *argv[]) } m->AddDomainIntegrator(new MassIntegrator); - k->AddDomainIntegrator(new ConvectionIntegrator(velocity, -1.0)); + constexpr double alpha = -1.0; + k->AddDomainIntegrator(new ConvectionIntegrator(velocity, alpha)); k->AddInteriorFaceIntegrator( - new TransposeIntegrator(new DGTraceIntegrator(velocity, 1.0, -0.5))); + new NonconservativeDGTraceIntegrator(velocity, alpha)); k->AddBdrFaceIntegrator( - new TransposeIntegrator(new DGTraceIntegrator(velocity, 1.0, -0.5))); + new NonconservativeDGTraceIntegrator(velocity, alpha)); ParLinearForm *b = new ParLinearForm(fes); b->AddBdrFaceIntegrator( - new BoundaryFlowIntegrator(inflow, velocity, -1.0, -0.5)); + new BoundaryFlowIntegrator(inflow, velocity, alpha)); int skip_zeros = 0; m->Assemble(); @@ -451,11 +531,11 @@ int main(int argc, char *argv[]) sout.open(vishost, visport); if (!sout) { - if (myid == 0) + if (mpi.Root()) cout << "Unable to connect to GLVis server at " << vishost << ':' << visport << endl; visualization = false; - if (myid == 0) + if (mpi.Root()) { cout << "GLVis visualization disabled.\n"; } @@ -467,7 +547,7 @@ int main(int argc, char *argv[]) sout << "solution\n" << *pmesh << *u; sout << "pause\n"; sout << flush; - if (myid == 0) + if (mpi.Root()) cout << "GLVis visualization paused." << " Press space (in the GLVis window) to resume it.\n"; } @@ -476,7 +556,7 @@ int main(int argc, char *argv[]) // 10. Define the time-dependent evolution operator describing the ODE // right-hand side, and perform time-integration (looping over the time // iterations, ti, with a time-step dt). - FE_Evolution adv(*m, *k, *B); + FE_Evolution adv(*m, *k, *B, prec_type); double t = 0.0; adv.SetTime(t); @@ -493,7 +573,7 @@ int main(int argc, char *argv[]) if (done || ti % vis_steps == 0) { - if (myid == 0) + if (mpi.Root()) { cout << "time step: " << ti << ", time: " << t << endl; } @@ -564,16 +644,14 @@ int main(int argc, char *argv[]) #endif delete dc; - MPI_Finalize(); return 0; } // Implementation of class FE_Evolution FE_Evolution::FE_Evolution(ParBilinearForm &_M, ParBilinearForm &_K, - const Vector &_b) - : TimeDependentOperator(_M.Height()), - b(_b), + const Vector &_b, PrecType prec_type) + : TimeDependentOperator(_M.Height()), b(_b), M_solver(_M.ParFESpace()->GetComm()), z(_M.Height()) { @@ -598,7 +676,7 @@ FE_Evolution::FE_Evolution(ParBilinearForm &_M, ParBilinearForm &_K, HypreSmoother *hypre_prec = new HypreSmoother(M_mat, HypreSmoother::Jacobi); M_prec = hypre_prec; - dg_solver = new DG_Solver(M_mat, K_mat, *_M.FESpace()); + dg_solver = new DG_Solver(M_mat, K_mat, *_M.FESpace(), prec_type); } else { @@ -614,6 +692,10 @@ FE_Evolution::FE_Evolution(ParBilinearForm &_M, ParBilinearForm &_K, M_solver.SetPrintLevel(0); } +// Solve the equation: +// u_t = M^{-1}(Ku + b), +// by solving associated linear system +// (M - dt*K) d = K*u + b void FE_Evolution::ImplicitSolve(const double dt, const Vector &x, Vector &k) { K->Mult(x, z); diff --git a/examples/ex_nd_amr_p.cpp b/examples/ex_nd_amr_p.cpp new file mode 100644 index 0000000000..733326c249 --- /dev/null +++ b/examples/ex_nd_amr_p.cpp @@ -0,0 +1,367 @@ +// MFEM Example 6 - Parallel Version +// +// Compile with: make ex6p +// +// Sample runs: mpirun -np 4 ex6p -m ../data/square-disc.mesh -o 1 +// mpirun -np 4 ex6p -m ../data/square-disc.mesh -o 2 +// mpirun -np 4 ex6p -m ../data/square-disc-nurbs.mesh -o 2 +// mpirun -np 4 ex6p -m ../data/star.mesh -o 3 +// mpirun -np 4 ex6p -m ../data/escher.mesh -o 2 +// mpirun -np 4 ex6p -m ../data/fichera.mesh -o 2 +// mpirun -np 4 ex6p -m ../data/disc-nurbs.mesh -o 2 +// mpirun -np 4 ex6p -m ../data/ball-nurbs.mesh +// mpirun -np 4 ex6p -m ../data/pipe-nurbs.mesh +// mpirun -np 4 ex6p -m ../data/star-surf.mesh -o 2 +// mpirun -np 4 ex6p -m ../data/square-disc-surf.mesh -o 2 +// mpirun -np 4 ex6p -m ../data/amr-quad.mesh +// +// Device sample runs: +// mpirun -np 4 ex6p -pa -d cuda +// mpirun -np 4 ex6p -pa -d occa-cuda +// mpirun -np 4 ex6p -pa -d raja-omp +// mpirun -np 4 ex6p -pa -d ceed-cpu +// * mpirun -np 4 ex6p -pa -d ceed-cuda +// mpirun -np 4 ex6p -pa -d ceed-cuda:/gpu/cuda/shared +// +// Description: This is a version of Example 1 with a simple adaptive mesh +// refinement loop. The problem being solved is again the Laplace +// equation -Delta u = 1 with homogeneous Dirichlet boundary +// conditions. The problem is solved on a sequence of meshes which +// are locally refined in a conforming (triangles, tetrahedrons) +// or non-conforming (quadrilaterals, hexahedra) manner according +// to a simple ZZ error estimator. +// +// The example demonstrates MFEM's capability to work with both +// conforming and nonconforming refinements, in 2D and 3D, on +// linear, curved and surface meshes. Interpolation of functions +// from coarse to fine meshes, as well as persistent GLVis +// visualization are also illustrated. +// +// We recommend viewing Example 1 before viewing this example. + +#include "mfem.hpp" +#include +#include + +using namespace std; +using namespace mfem; + +void A_exact(const Vector &x, Vector &A); + +int main(int argc, char *argv[]) +{ + // 1. Initialize MPI. + int num_procs, myid; + MPI_Init(&argc, &argv); + MPI_Comm_size(MPI_COMM_WORLD, &num_procs); + MPI_Comm_rank(MPI_COMM_WORLD, &myid); + + // 2. Parse command-line options. + const char *mesh_file = "../data/star.mesh"; + int order = 1; + bool pa = false; + const char *device_config = "cpu"; + bool visualization = true; + + OptionsParser args(argc, argv); + args.AddOption(&mesh_file, "-m", "--mesh", + "Mesh file to use."); + args.AddOption(&order, "-o", "--order", + "Finite element order (polynomial degree)."); + args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa", + "--no-partial-assembly", "Enable Partial Assembly."); + args.AddOption(&device_config, "-d", "--device", + "Device configuration string, see Device::Configure()."); + args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", + "--no-visualization", + "Enable or disable GLVis visualization."); + args.Parse(); + if (!args.Good()) + { + if (myid == 0) + { + args.PrintUsage(cout); + } + MPI_Finalize(); + return 1; + } + if (myid == 0) + { + args.PrintOptions(cout); + } + + // 3. Enable hardware devices such as GPUs, and programming models such as + // CUDA, OCCA, RAJA and OpenMP based on command line options. + Device device(device_config); + if (myid == 0) { device.Print(); } + + // 4. Read the (serial) mesh from the given mesh file on all processors. We + // can handle triangular, quadrilateral, tetrahedral, hexahedral, surface + // and volume meshes with the same code. + Mesh *mesh = new Mesh(mesh_file, 1, 1); + int dim = mesh->Dimension(); + + // 5. Refine the serial mesh on all processors to increase the resolution. + // Also project a NURBS mesh to a piecewise-quadratic curved mesh. Make + // sure that the mesh is non-conforming. + if (mesh->NURBSext) + { + mesh->UniformRefinement(); + mesh->SetCurvature(2); + } + mesh->EnsureNCMesh(); + + // 6. Define a parallel mesh by partitioning the serial mesh. + // Once the parallel mesh is defined, the serial mesh can be deleted. + ParMesh pmesh(MPI_COMM_WORLD, *mesh); + delete mesh; + + MFEM_VERIFY(pmesh.bdr_attributes.Size() > 0, + "Boundary attributes required in the mesh."); + Array ess_bdr(pmesh.bdr_attributes.Max()); + ess_bdr = 1; + + // 7. Define a finite element space on the mesh. The polynomial order is + // one (linear) by default, but this can be changed on the command line. + ND_FECollection fec(order, dim); + ParFiniteElementSpace fespace(&pmesh, &fec); + + // 8. As in Example 1p, we set up bilinear and linear forms corresponding to + // the Laplace problem -\Delta u = 1. We don't assemble the discrete + // problem yet, this will be done in the main loop. + ParBilinearForm a(&fespace); + if (pa) + { + a.SetAssemblyLevel(AssemblyLevel::PARTIAL); + a.SetDiagonalPolicy(Operator::DIAG_ONE); + } + ParLinearForm b(&fespace); + + ConstantCoefficient one(1.0); + Vector oneVec(dim); oneVec = 1.0; + VectorConstantCoefficient oneVecCoef(oneVec); + VectorFunctionCoefficient ACoef(dim, A_exact); + + BilinearFormIntegrator *integ = new CurlCurlIntegrator(one); + a.AddDomainIntegrator(integ); + a.AddDomainIntegrator(new VectorFEMassIntegrator(one)); + b.AddDomainIntegrator(new VectorFEDomainLFIntegrator(oneVecCoef)); + + // 9. The solution vector x and the associated finite element grid function + // will be maintained over the AMR iterations. We initialize it to zero. + ParGridFunction x(&fespace); + x = 0; + + // 10. Connect to GLVis. + char vishost[] = "localhost"; + int visport = 19916; + + socketstream sout; + if (visualization) + { + sout.open(vishost, visport); + if (!sout) + { + if (myid == 0) + { + cout << "Unable to connect to GLVis server at " + << vishost << ':' << visport << endl; + cout << "GLVis visualization disabled.\n"; + } + visualization = false; + } + + sout.precision(8); + } + + ofstream ofsErr("ex_nd_amr_p_err.out"); + + // 11. Set up an error estimator. Here we use the Zienkiewicz-Zhu estimator + // with L2 projection in the smoothing step to better handle hanging + // nodes and parallel partitioning. We need to supply a space for the + // discontinuous flux (L2) and a space for the smoothed flux (H(div) is + // used here). + RT_FECollection flux_fec(order-1, dim); + ParFiniteElementSpace flux_fes(&pmesh, &flux_fec); + H1_FECollection smooth_flux_fec(order, dim); + ParFiniteElementSpace smooth_flux_fes(&pmesh, &smooth_flux_fec, dim); + // Another possible option for the smoothed flux space: + // ND_FECollection smooth_flux_fec(order, dim); + // ParFiniteElementSpace smooth_flux_fes(&pmesh, &smooth_flux_fec); + L2ZienkiewiczZhuEstimator estimator(*integ, x, flux_fes, smooth_flux_fes); + + // 12. A refiner selects and refines elements based on a refinement strategy. + // The strategy here is to refine elements with errors larger than a + // fraction of the maximum element error. Other strategies are possible. + // The refiner will call the given error estimator. + ThresholdRefiner refiner(estimator); + refiner.SetTotalErrorFraction(0.7); + + // 13. The main AMR loop. In each iteration we solve the problem on the + // current mesh, visualize the solution, and refine the mesh. + const int max_dofs = 100000; + for (int it = 0; ; it++) + { + HYPRE_Int global_dofs = fespace.GlobalTrueVSize(); + if (myid == 0) + { + cout << "\nAMR iteration " << it << endl; + cout << "Number of unknowns: " << global_dofs << endl; + } + + // 14. Assemble the right-hand side and determine the list of true + // (i.e. parallel conforming) essential boundary dofs. + Array ess_tdof_list; + fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list); + b.Assemble(); + + // 15. Assemble the stiffness matrix. Note that MFEM doesn't care at this + // point that the mesh is nonconforming and parallel. The FE space is + // considered 'cut' along hanging edges/faces, and also across + // processor boundaries. + a.Assemble(); + + // 16. Create the parallel linear system: eliminate boundary conditions. + // The system will be solved for true (unconstrained/unique) DOFs only. + OperatorPtr A; + Vector B, X; + + const int copy_interior = 1; + a.FormLinearSystem(ess_tdof_list, x, b, A, X, B, copy_interior); + + // 17. Solve the linear system A X = B. + // * With full assembly, use the BoomerAMG preconditioner from hypre. + // * With partial assembly, use a diagonal preconditioner. + Solver *M = NULL; + if (pa) + { + M = new OperatorJacobiSmoother(a, ess_tdof_list); + + } + else + { + ParFiniteElementSpace *prec_fespace = + (a.StaticCondensationIsEnabled() ? a.SCParFESpace() : &fespace); + HypreAMS *ams = new HypreAMS(*A.As(), prec_fespace); + ams->SetPrintLevel(0); + M = ams; + } + + CGSolver cg(MPI_COMM_WORLD); + cg.SetRelTol(1e-6); + cg.SetMaxIter(2000); + cg.SetPrintLevel(3); // print the first and the last iterations only + cg.SetPreconditioner(*M); + cg.SetOperator(*A); + cg.Mult(B, X); + delete M; + + // 18. Switch back to the host and extract the parallel grid function + // corresponding to the finite element approximation X. This is the + // local solution on each processor. + a.RecoverFEMSolution(X, b, x); + + double err = x.ComputeL2Error(ACoef); + mfem::out << "Error " << err << endl; + ofsErr << it << '\t' << global_dofs << '\t' << err << '\n'; + + // 19. Send the solution by socket to a GLVis server. + if (visualization) + { + sout << "parallel " << num_procs << " " << myid << "\n"; + sout << "solution\n" << pmesh << x << flush; + } + + if (global_dofs > max_dofs) + { + if (myid == 0) + { + cout << "Reached the maximum number of dofs. Stop." << endl; + } + break; + } + + // 20. Call the refiner to modify the mesh. The refiner calls the error + // estimator to obtain element errors, then it selects elements to be + // refined and finally it modifies the mesh. The Stop() method can be + // used to determine if a stopping criterion was met. + refiner.Apply(pmesh); + if (refiner.Stop()) + { + if (myid == 0) + { + cout << "Stopping criterion satisfied. Stop." << endl; + } + break; + } + + // 21. Update the finite element space (recalculate the number of DOFs, + // etc.) and create a grid function update matrix. Apply the matrix + // to any GridFunctions over the space. In this case, the update + // matrix is an interpolation matrix so the updated GridFunction will + // still represent the same function as before refinement. + fespace.Update(); + x.Update(); + + // 22. Load balance the mesh, and update the space and solution. Currently + // available only for nonconforming meshes. + if (pmesh.Nonconforming()) + { + pmesh.Rebalance(); + + // Update the space and the GridFunction. This time the update matrix + // redistributes the GridFunction among the processors. + fespace.Update(); + x.Update(); + } + + // 23. Inform also the bilinear and linear forms that the space has + // changed. + a.Update(); + b.Update(); + } + ofsErr.close(); + + MPI_Finalize(); + return 0; +} + +void A_exact(const Vector &x, Vector &A) +{ + int dim = x.Size(); + A.SetSize(dim); + A = 0.0; + + if (dim == 2) + { + int mmax = 10; + for (int m=0; m<=mmax; m++) + { + int M = 2 * m + 1; + A[0] += sin(M * M_PI * x[1]) / + (M * (1.0 + (M * M) * M_PI * M_PI)); + A[1] += sin(M * M_PI * x[0]) / + (M * (1.0 + (M * M) * M_PI * M_PI)); + } + A *= 4.0 / M_PI; + } + else + { + int nmax = 10; + for (int m=0; m<=nmax; m++) + { + int M = 2 * m + 1; + for (int n=0; n<=nmax-m; n++) + { + int N = 2 * n + 1; + A[0] += sin(M * M_PI * x[1]) * sin(N * M_PI * x[2]) / + (M * N * (1.0 + (M * M + N * N) * M_PI * M_PI)); + A[1] += sin(M * M_PI * x[2]) * sin(N * M_PI * x[0]) / + (M * N * (1.0 + (M * M + N * N) * M_PI * M_PI)); + A[2] += sin(M * M_PI * x[0]) * sin(N * M_PI * x[1]) / + (M * N * (1.0 + (M * M + N * N) * M_PI * M_PI)); + } + } + A *= 16.0 / (M_PI * M_PI); + } +} diff --git a/examples/ginkgo/CMakeLists.txt b/examples/ginkgo/CMakeLists.txt index d9821d5c06..c6b40e3a11 100644 --- a/examples/ginkgo/CMakeLists.txt +++ b/examples/ginkgo/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/examples/ginkgo/makefile b/examples/ginkgo/makefile index 67916d09aa..f571dd32d7 100644 --- a/examples/ginkgo/makefile +++ b/examples/ginkgo/makefile @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/examples/hiop/CMakeLists.txt b/examples/hiop/CMakeLists.txt index 879e133760..f66a0000ff 100644 --- a/examples/hiop/CMakeLists.txt +++ b/examples/hiop/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/examples/hiop/makefile b/examples/hiop/makefile index b711aa8052..c3b264acd5 100644 --- a/examples/hiop/makefile +++ b/examples/hiop/makefile @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/examples/makefile b/examples/makefile index cf999dff17..c9105c5f29 100644 --- a/examples/makefile +++ b/examples/makefile @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # @@ -144,7 +144,7 @@ clean-build: rm -rf *.dSYM *.TVD.*breakpoints clean-exec: - @rm -f refined.mesh displaced.mesh mesh.* ex5.mesh + @rm -f refined.mesh displaced.mesh mesh.* ex5.mesh ex6p-checkpoint.* @rm -rf Example5* Example9* Example15* Example16* Example23* ParaView @rm -f sphere_refined.* sol.* sol_u.* sol_p.* sol_r.* sol_i.* @rm -f ex9.mesh ex9-mesh.* ex9-init.* ex9-final.* diff --git a/examples/petsc/CMakeLists.txt b/examples/petsc/CMakeLists.txt index 66b8f7839c..1d17d68f92 100644 --- a/examples/petsc/CMakeLists.txt +++ b/examples/petsc/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/examples/petsc/makefile b/examples/petsc/makefile index 93a68188d9..c5a5850236 100644 --- a/examples/petsc/makefile +++ b/examples/petsc/makefile @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/examples/pumi/CMakeLists.txt b/examples/pumi/CMakeLists.txt index 3eef1cf8b7..3fe92c0dde 100644 --- a/examples/pumi/CMakeLists.txt +++ b/examples/pumi/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/examples/pumi/makefile b/examples/pumi/makefile index 003d1bdfa9..4af014aef8 100644 --- a/examples/pumi/makefile +++ b/examples/pumi/makefile @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/examples/sundials/CMakeLists.txt b/examples/sundials/CMakeLists.txt index 88b92897b0..48465a5112 100644 --- a/examples/sundials/CMakeLists.txt +++ b/examples/sundials/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/examples/sundials/makefile b/examples/sundials/makefile index e86ccf7180..bfadced910 100644 --- a/examples/sundials/makefile +++ b/examples/sundials/makefile @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/examples/superlu/CMakeLists.txt b/examples/superlu/CMakeLists.txt index 8caeffe854..64d48dc03a 100644 --- a/examples/superlu/CMakeLists.txt +++ b/examples/superlu/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/examples/superlu/makefile b/examples/superlu/makefile index 22abebc465..52b1609189 100644 --- a/examples/superlu/makefile +++ b/examples/superlu/makefile @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/examples/test_eigs_nd.cpp b/examples/test_eigs_nd.cpp index b361261be0..6138ab42db 100644 --- a/examples/test_eigs_nd.cpp +++ b/examples/test_eigs_nd.cpp @@ -1,5 +1,12 @@ // MFEM Brick Eigenvalue test // +// To test the ND_TetrahedronElement this should be run with the "-m +// 13" command line option to request a tetrahedral mesh. To test +// face dof orientations the basis function order should be set to at +// least 3 for tetrahedral elements (2 for hexahedral elements). +// +// The eigenvalues for the 2D meshes should come out to be 1, 2, and 3. +// The eigenvalues for the 3D meshes should come out to be 3, 4, and 5. #include "mfem.hpp" #include diff --git a/fem/CMakeLists.txt b/fem/CMakeLists.txt index 96b3a92dbf..bb16ce8a94 100644 --- a/fem/CMakeLists.txt +++ b/fem/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # @@ -13,6 +13,7 @@ set(SRCS bilinearform.cpp bilinearform_ext.cpp bilininteg.cpp + bilininteg_br2.cpp bilininteg_convection_pa.cpp bilininteg_convection_ea.cpp bilininteg_dgtrace_pa.cpp diff --git a/fem/adios2datacollection.cpp b/fem/adios2datacollection.cpp index 1af16f499a..84744df6fb 100644 --- a/fem/adios2datacollection.cpp +++ b/fem/adios2datacollection.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/adios2datacollection.hpp b/fem/adios2datacollection.hpp index c7062a461e..c193c84218 100644 --- a/fem/adios2datacollection.hpp +++ b/fem/adios2datacollection.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/bilinearform.cpp b/fem/bilinearform.cpp index bd5f07a1f5..493a83ce8a 100644 --- a/fem/bilinearform.cpp +++ b/fem/bilinearform.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -1469,9 +1469,9 @@ void MixedBilinearForm::Assemble (int skip_zeros) ftr = mesh->GetBdrFaceTransformations(i); if (ftr) { - trial_fes->GetFaceVDofs(i, tr_vdofs); + trial_fes->GetFaceVDofs(ftr->ElementNo, tr_vdofs); test_fes->GetElementVDofs(ftr->Elem1No, te_vdofs); - trial_face_fe = trial_fes->GetFaceElement(i); + trial_face_fe = trial_fes->GetFaceElement(ftr->ElementNo); test_fe1 = test_fes->GetFE(ftr->Elem1No); // The test_fe2 object is really a dummy and not used on the // boundaries, but we can't dereference a NULL pointer, and we don't @@ -1802,9 +1802,41 @@ MixedBilinearForm::~MixedBilinearForm() delete ext; } +void DiscreteLinearOperator::SetAssemblyLevel(AssemblyLevel assembly_level) +{ + if (ext) + { + MFEM_ABORT("the assembly level has already been set!"); + } + assembly = assembly_level; + switch (assembly) + { + case AssemblyLevel::LEGACYFULL: + case AssemblyLevel::FULL: + // Use the original implementation for now + break; + case AssemblyLevel::ELEMENT: + mfem_error("Element assembly not supported yet... stay tuned!"); + break; + case AssemblyLevel::PARTIAL: + ext = new PADiscreteLinearOperatorExtension(this); + break; + case AssemblyLevel::NONE: + mfem_error("Matrix-free action not supported yet... stay tuned!"); + break; + default: + mfem_error("Unknown assembly level"); + } +} void DiscreteLinearOperator::Assemble(int skip_zeros) { + if (ext) + { + ext->Assemble(); + return; + } + Array dom_vdofs, ran_vdofs; ElementTransformation *T; DofTransformation * dom_dof_trans; diff --git a/fem/bilinearform.hpp b/fem/bilinearform.hpp index acf5cda084..02e6d44cc8 100644 --- a/fem/bilinearform.hpp +++ b/fem/bilinearform.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -53,6 +53,8 @@ enum class AssemblyLevel SetAssemblyLevel() function. */ class BilinearForm : public Matrix { + friend FABilinearFormExtension; + protected: /// Sparse matrix \f$ M \f$ to be associated with the form. Owned. SparseMatrix *mat; @@ -376,6 +378,13 @@ public: /// Get the output finite element space prolongation matrix virtual const Operator *GetOutputProlongation() const { return GetProlongation(); } + /** @brief Returns the output fe space restriction matrix, transposed + + Logically, this is the transpose of GetOutputRestriction, but in + practice it is convenient to have it in transposed form for + construction of RAP operators in matrix-free methods. */ + virtual const Operator *GetOutputRestrictionTranspose() const + { return GetOutputProlongation(); } /// Get the output finite element space restriction matrix virtual const Operator *GetOutputRestriction() const { return GetRestriction(); } @@ -847,9 +856,9 @@ public: This returns the same operator as FormRectangularLinearSystem(), but does without the transformations of the right-hand side. */ - void FormRectangularSystemMatrix(const Array &trial_tdof_list, - const Array &test_tdof_list, - OperatorHandle &A); + virtual void FormRectangularSystemMatrix(const Array &trial_tdof_list, + const Array &test_tdof_list, + OperatorHandle &A); /** @brief Form the column-constrained linear system matrix A. See FormRectangularSystemMatrix() for details. @@ -876,10 +885,11 @@ public: Return in @a A a *reference* to the system matrix that is column-constrained. The reference will be invalidated when SetOperatorType(), Update(), or the destructor is called. */ - void FormRectangularLinearSystem(const Array &trial_tdof_list, - const Array &test_tdof_list, - Vector &x, Vector &b, - OperatorHandle &A, Vector &X, Vector &B); + virtual void FormRectangularLinearSystem(const Array &trial_tdof_list, + const Array &test_tdof_list, + Vector &x, Vector &b, + OperatorHandle &A, Vector &X, + Vector &B); /** @brief Form the linear system A X = B, corresponding to this bilinear form and the linear form @a b(.). @@ -977,9 +987,18 @@ public: /// Access all interpolators added with AddDomainInterpolator(). Array *GetDI() { return &dbfi; } + /// Set the desired assembly level. The default is AssemblyLevel::FULL. + /** This method must be called before assembly. */ + void SetAssemblyLevel(AssemblyLevel assembly_level); + /** @brief Construct the internal matrix representation of the discrete linear operator. */ virtual void Assemble(int skip_zeros = 1); + + /** @brief Get the output finite element space restriction matrix in + transposed form. */ + virtual const Operator *GetOutputRestrictionTranspose() const + { return test_fes->GetRestrictionTransposeOperator(); } }; } diff --git a/fem/bilinearform_ext.cpp b/fem/bilinearform_ext.cpp index 9899c1b8db..4ff2929633 100644 --- a/fem/bilinearform_ext.cpp +++ b/fem/bilinearform_ext.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -14,6 +14,7 @@ #include "../general/forall.hpp" #include "bilinearform.hpp" +#include "pbilinearform.hpp" #include "libceed/ceed.hpp" #include "pgridfunc.hpp" @@ -821,20 +822,14 @@ void EABilinearFormExtension::MultTranspose(const Vector &x, Vector &y) const // Data and methods for fully-assembled bilinear forms FABilinearFormExtension::FABilinearFormExtension(BilinearForm *form) : EABilinearFormExtension(form), - mat(form->FESpace()->GetVSize(),form->FESpace()->GetVSize(),0), - face_mat(form->FESpace()->GetVSize(),0,0), - use_face_mat(false) + mat(a->mat) { #ifdef MFEM_USE_MPI - if ( ParFiniteElementSpace* pfes = - dynamic_cast(form->FESpace()) ) + ParFiniteElementSpace *pfes = nullptr; + if ( a->GetFBFI()->Size()>0 && + (pfes = dynamic_cast(form->FESpace())) ) { - if (pfes->IsDGSpace()) - { - use_face_mat = true; - pfes->ExchangeFaceNbrData(); - face_mat.SetWidth(pfes->GetFaceNbrVSize()); - } + pfes->ExchangeFaceNbrData(); } #endif } @@ -843,111 +838,225 @@ void FABilinearFormExtension::Assemble() { EABilinearFormExtension::Assemble(); FiniteElementSpace &fes = *a->FESpace(); - if (fes.IsDGSpace()) + int width = fes.GetVSize(); + int height = fes.GetVSize(); + bool keep_nbr_block = false; +#ifdef MFEM_USE_MPI + ParFiniteElementSpace *pfes = nullptr; + if ( a->GetFBFI()->Size()>0 && + (pfes = dynamic_cast(&fes)) ) { - const L2ElementRestriction *restE = - static_cast(elem_restrict); - const L2FaceRestriction *restF = - static_cast(int_face_restrict_lex); - // 1. Fill I - // 1.1 Increment with restE - restE->FillI(mat); - // 1.2 Increment with restF - if (restF) { restF->FillI(mat, face_mat); } - // 1.3 Sum the non-zeros in I - auto h_I = mat.HostReadWriteI(); - int cpt = 0; - const int vd = fes.GetVDim(); - const int ndofs = ne*elemDofs*vd; - for (int i = 0; i < ndofs; i++) + pfes->ExchangeFaceNbrData(); + width += pfes->GetFaceNbrVSize(); + dg_x.SetSize(width); + ParBilinearForm *pb = nullptr; + if ((pb = dynamic_cast(a)) && (pb->keep_nbr_block)) { - const int nnz = h_I[i]; - h_I[i] = cpt; - cpt += nnz; - } - const int nnz = cpt; - h_I[ndofs] = nnz; - mat.GetMemoryJ().New(nnz, mat.GetMemoryJ().GetMemoryType()); - mat.GetMemoryData().New(nnz, mat.GetMemoryData().GetMemoryType()); - if (use_face_mat && restF) - { - auto h_I_face = face_mat.HostReadWriteI(); - int cpt = 0; - for (int i = 0; i < ndofs; i++) - { - const int nnz = h_I_face[i]; - h_I_face[i] = cpt; - cpt += nnz; - } - const int nnz_face = cpt; - h_I_face[ndofs] = nnz_face; - face_mat.GetMemoryJ().New(nnz_face, - face_mat.GetMemoryJ().GetMemoryType()); - face_mat.GetMemoryData().New(nnz_face, - face_mat.GetMemoryData().GetMemoryType()); - } - // 2. Fill J and Data - // 2.1 Fill J and Data with Elem ea_data - restE->FillJAndData(ea_data, mat); - // 2.2 Fill J and Data with Face ea_data_ext - if (restF) { restF->FillJAndData(ea_data_ext, mat, face_mat); } - // 2.3 Shift indirections in I back to original - auto I = mat.HostReadWriteI(); - for (int i = ndofs; i > 0; i--) - { - I[i] = I[i-1]; - } - I[0] = 0; - if (use_face_mat && restF) - { - auto I_face = face_mat.HostReadWriteI(); - for (int i = ndofs; i > 0; i--) - { - I_face[i] = I_face[i-1]; - } - I_face[0] = 0; + height += pfes->GetFaceNbrVSize(); + dg_y.SetSize(height); + keep_nbr_block = true; } } - else // continuous Galerkin case +#endif + if (a->mat) // We reuse the sparse matrix memory { - const ElementRestriction &rest = - static_cast(*elem_restrict); - rest.FillSparseMatrix(ea_data, mat); + if (fes.IsDGSpace()) + { + const L2ElementRestriction *restE = + static_cast(elem_restrict); + const L2FaceRestriction *restF = + static_cast(int_face_restrict_lex); + // 1. Fill J and Data + // 1.1 Fill J and Data with Elem ea_data + restE->FillJAndData(ea_data, *mat); + // 1.2 Fill J and Data with Face ea_data_ext + if (restF) { restF->FillJAndData(ea_data_ext, *mat, keep_nbr_block); } + // 1.3 Shift indirections in I back to original + auto I = mat->HostReadWriteI(); + for (int i = height; i > 0; i--) + { + I[i] = I[i-1]; + } + I[0] = 0; + } + else + { + const ElementRestriction &rest = + static_cast(*elem_restrict); + rest.FillJAndData(ea_data, *mat); + } + } + else // We create, compute the sparsity, and fill the sparse matrix + { + mat = new SparseMatrix(height, width, 0); + if (fes.IsDGSpace()) + { + const L2ElementRestriction *restE = + static_cast(elem_restrict); + const L2FaceRestriction *restF = + static_cast(int_face_restrict_lex); + // 1. Fill I + mat->GetMemoryI().New(height+1, mat->GetMemoryI().GetMemoryType()); + // 1.1 Increment with restE + restE->FillI(*mat); + // 1.2 Increment with restF + if (restF) { restF->FillI(*mat, keep_nbr_block); } + // 1.3 Sum the non-zeros in I + auto h_I = mat->HostReadWriteI(); + int cpt = 0; + for (int i = 0; i < height; i++) + { + const int nnz = h_I[i]; + h_I[i] = cpt; + cpt += nnz; + } + const int nnz = cpt; + h_I[height] = nnz; + mat->GetMemoryJ().New(nnz, mat->GetMemoryJ().GetMemoryType()); + mat->GetMemoryData().New(nnz, mat->GetMemoryData().GetMemoryType()); + // 2. Fill J and Data + // 2.1 Fill J and Data with Elem ea_data + restE->FillJAndData(ea_data, *mat); + // 2.2 Fill J and Data with Face ea_data_ext + if (restF) { restF->FillJAndData(ea_data_ext, *mat, keep_nbr_block); } + // 2.3 Shift indirections in I back to original + auto I = mat->HostReadWriteI(); + for (int i = height; i > 0; i--) + { + I[i] = I[i-1]; + } + I[0] = 0; + } + else // continuous Galerkin case + { + const ElementRestriction &rest = + static_cast(*elem_restrict); + rest.FillSparseMatrix(ea_data, *mat); + } + a->mat = mat; + } +} + +void FABilinearFormExtension::DGMult(const Vector &x, Vector &y) const +{ +#ifdef MFEM_USE_MPI + const ParFiniteElementSpace *pfes; + if ( (pfes = dynamic_cast(testFes)) ) + { + // DG Prolongation + ParGridFunction x_gf; + x_gf.MakeRef(const_cast(pfes), + const_cast(x),0); + x_gf.ExchangeFaceNbrData(); + Vector &shared_x = x_gf.FaceNbrData(); + const int local_size = a->FESpace()->GetVSize(); + auto dg_x_ptr = dg_x.Write(); + auto x_ptr = x.Read(); + MFEM_FORALL(i,local_size, + { + dg_x_ptr[i] = x_ptr[i]; + }); + const int shared_size = shared_x.Size(); + auto shared_x_ptr = shared_x.Read(); + MFEM_FORALL(i,shared_size, + { + dg_x_ptr[local_size+i] = shared_x_ptr[i]; + }); + ParBilinearForm *pform = nullptr; + if ((pform = dynamic_cast(a)) && (pform->keep_nbr_block)) + { + mat->Mult(dg_x, dg_y); + // DG Restriction + auto dg_y_ptr = dg_y.Read(); + auto y_ptr = y.ReadWrite(); + MFEM_FORALL(i,local_size, + { + y_ptr[i] += dg_y_ptr[i]; + }); + } + else + { + mat->Mult(dg_x, y); + } + } + else +#endif + { + mat->Mult(x, y); } } void FABilinearFormExtension::Mult(const Vector &x, Vector &y) const { - mat.Mult(x, y); -#ifdef MFEM_USE_MPI - if (const ParFiniteElementSpace *pfes = - dynamic_cast(testFes)) + if ( a->GetFBFI()->Size()>0 ) { + DGMult(x, y); + } + else + { + mat->Mult(x, y); + } +} + +void FABilinearFormExtension::DGMultTranspose(const Vector &x, Vector &y) const +{ +#ifdef MFEM_USE_MPI + const ParFiniteElementSpace *pfes; + if ( (pfes = dynamic_cast(testFes)) ) + { + // DG Prolongation ParGridFunction x_gf; x_gf.MakeRef(const_cast(pfes), const_cast(x),0); x_gf.ExchangeFaceNbrData(); Vector &shared_x = x_gf.FaceNbrData(); - if (shared_x.Size()) { face_mat.AddMult(shared_x, y); } + const int local_size = a->FESpace()->GetVSize(); + auto dg_x_ptr = dg_x.Write(); + auto x_ptr = x.Read(); + MFEM_FORALL(i,local_size, + { + dg_x_ptr[i] = x_ptr[i]; + }); + const int shared_size = shared_x.Size(); + auto shared_x_ptr = shared_x.Read(); + MFEM_FORALL(i,shared_size, + { + dg_x_ptr[local_size+i] = shared_x_ptr[i]; + }); + ParBilinearForm *pb = nullptr; + if ((pb = dynamic_cast(a)) && (pb->keep_nbr_block)) + { + mat->MultTranspose(dg_x, dg_y); + // DG Restriction + auto dg_y_ptr = dg_y.Read(); + auto y_ptr = y.ReadWrite(); + MFEM_FORALL(i,local_size, + { + y_ptr[i] += dg_y_ptr[i]; + }); + } + else + { + mat->MultTranspose(dg_x, y); + } } + else #endif + { + mat->MultTranspose(x, y); + } } void FABilinearFormExtension::MultTranspose(const Vector &x, Vector &y) const { - mat.MultTranspose(x, y); -#ifdef MFEM_USE_MPI - if (const ParFiniteElementSpace *pfes = - dynamic_cast(testFes)) + if ( a->GetFBFI()->Size()>0 ) { - ParGridFunction x_gf; - x_gf.MakeRef(const_cast(pfes), - const_cast(x),0); - x_gf.ExchangeFaceNbrData(); - Vector &shared_x = x_gf.FaceNbrData(); - if (shared_x.Size()) { face_mat.AddMultTranspose(shared_x, y); } + DGMultTranspose(x, y); + } + else + { + mat->MultTranspose(x, y); } -#endif } @@ -1021,7 +1130,6 @@ void PAMixedBilinearFormExtension::Update() localTrial.UseDevice(true); localTrial.SetSize(elem_restrict_trial->Height(), Device::GetMemoryType()); - } if (elem_restrict_test) { @@ -1221,4 +1329,134 @@ void PAMixedBilinearFormExtension::AssembleDiagonal_ADAt(const Vector &D, } } +PADiscreteLinearOperatorExtension::PADiscreteLinearOperatorExtension( + DiscreteLinearOperator *linop) : + PAMixedBilinearFormExtension(linop) +{ +} + +const +Operator *PADiscreteLinearOperatorExtension::GetOutputRestrictionTranspose() +const +{ + return a->GetOutputRestrictionTranspose(); +} + +void PADiscreteLinearOperatorExtension::Assemble() +{ + Array &integrators = *a->GetDBFI(); + const int integratorCount = integrators.Size(); + for (int i = 0; i < integratorCount; ++i) + { + integrators[i]->AssemblePA(*trialFes, *testFes); + } + + test_multiplicity.UseDevice(true); + test_multiplicity.SetSize(elem_restrict_test->Width()); // l-vector + Vector ones(elem_restrict_test->Height()); // e-vector + ones = 1.0; + + const ElementRestriction* elem_restrict = + dynamic_cast(elem_restrict_test); + if (elem_restrict) + { + elem_restrict->MultTransposeUnsigned(ones, test_multiplicity); + } + else + { + mfem_error("A real ElementRestriction is required in this setting!"); + } + + auto tm = test_multiplicity.ReadWrite(); + MFEM_FORALL(i, test_multiplicity.Size(), + { + tm[i] = 1.0 / tm[i]; + }); +} + +void PADiscreteLinearOperatorExtension::AddMult( + const Vector &x, Vector &y, const double c) const +{ + Array &integrators = *a->GetDBFI(); + const int iSz = integrators.Size(); + + // * G operation + SetupMultInputs(elem_restrict_trial, x, localTrial, + elem_restrict_test, y, localTest, c); + + // * B^TDB operation + for (int i = 0; i < iSz; ++i) + { + integrators[i]->AddMultPA(localTrial, localTest); + } + + // do a kind of "set" rather than "add" in the below + // operation as compared to the BilinearForm case + // * G^T operation (kind of...) + const ElementRestriction* elem_restrict = + dynamic_cast(elem_restrict_test); + if (elem_restrict) + { + tempY.SetSize(y.Size()); + elem_restrict->MultLeftInverse(localTest, tempY); + y += tempY; + } + else + { + mfem_error("In this setting you need a real ElementRestriction!"); + } +} + +void PADiscreteLinearOperatorExtension::AddMultTranspose( + const Vector &x, Vector &y, const double c) const +{ + Array &integrators = *a->GetDBFI(); + const int iSz = integrators.Size(); + + // do a kind of "set" rather than "add" in the below + // operation as compared to the BilinearForm case + // * G operation (kinda) + Vector xscaled(x); + MFEM_VERIFY(x.Size() == test_multiplicity.Size(), "Input vector of wrong size"); + auto xs = xscaled.ReadWrite(); + auto tm = test_multiplicity.Read(); + MFEM_FORALL(i, x.Size(), + { + xs[i] *= tm[i]; + }); + SetupMultInputs(elem_restrict_test, xscaled, localTest, + elem_restrict_trial, y, localTrial, c); + + // * B^TD^TB operation + for (int i = 0; i < iSz; ++i) + { + integrators[i]->AddMultTransposePA(localTest, localTrial); + } + + // * G^T operation + if (elem_restrict_trial) + { + tempY.SetSize(y.Size()); + elem_restrict_trial->MultTranspose(localTrial, tempY); + y += tempY; + } + else + { + mfem_error("Trial ElementRestriction not defined"); + } +} + +void PADiscreteLinearOperatorExtension::FormRectangularSystemOperator( + const Array& ess1, const Array& ess2, OperatorHandle &A) +{ + const Operator *Pi = this->GetProlongation(); + const Operator *RoT = this->GetOutputRestrictionTranspose(); + Operator *rap = SetupRAP(Pi, RoT); + + RectangularConstrainedOperator *Arco + = new RectangularConstrainedOperator(rap, ess1, ess2, rap != this); + + A.Reset(Arco); +} + } // namespace mfem diff --git a/fem/bilinearform_ext.hpp b/fem/bilinearform_ext.hpp index 8f30e9e624..6ae3fb6274 100644 --- a/fem/bilinearform_ext.hpp +++ b/fem/bilinearform_ext.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -21,6 +21,7 @@ namespace mfem class BilinearForm; class MixedBilinearForm; +class DiscreteLinearOperator; /// Class extending the BilinearForm class to support different AssemblyLevels. /** FA - Full Assembly @@ -117,10 +118,8 @@ public: class FABilinearFormExtension : public EABilinearFormExtension { private: - SparseMatrix mat; - /// face_mat handles parallelism for DG face terms. - SparseMatrix face_mat; - bool use_face_mat; + SparseMatrix *mat; + mutable Vector dg_x, dg_y; public: FABilinearFormExtension(BilinearForm *form); @@ -128,6 +127,11 @@ public: void Assemble(); void Mult(const Vector &x, Vector &y) const; void MultTranspose(const Vector &x, Vector &y) const; + + /** DGMult and DGMultTranspose use the extended L-vector to perform the + computation. */ + void DGMult(const Vector &x, Vector &y) const; + void DGMultTranspose(const Vector &x, Vector &y) const; }; /// Data and methods for matrix-free bilinear forms @@ -212,7 +216,7 @@ protected: mutable Vector localTrial, localTest, tempY; const Operator *elem_restrict_trial; // Not owned const Operator *elem_restrict_test; // Not owned -private: + /// Helper function to set up inputs/outputs for Mult or MultTranspose void SetupMultInputs(const Operator *elem_restrict_x, const Vector &x, Vector &localX, @@ -258,6 +262,35 @@ public: void Update(); }; + +/** + @brief Partial assembly extension for DiscreteLinearOperator + + This acts very much like PAMixedBilinearFormExtension, but its + FormRectangularSystemOperator implementation emulates 'Set' rather than + 'Add' in the assembly case. +*/ +class PADiscreteLinearOperatorExtension : public PAMixedBilinearFormExtension +{ +public: + PADiscreteLinearOperatorExtension(DiscreteLinearOperator *linop); + + /// Partial assembly of all internal integrators + void Assemble(); + + void AddMult(const Vector &x, Vector &y, const double c) const; + + void AddMultTranspose(const Vector &x, Vector &y, const double c=1.0) const; + + void FormRectangularSystemOperator(const Array&, const Array&, + OperatorHandle& A); + + const Operator * GetOutputRestrictionTranspose() const; + +private: + Vector test_multiplicity; +}; + } #endif diff --git a/fem/bilininteg.cpp b/fem/bilininteg.cpp index 69eab64f75..6f0586ac1c 100644 --- a/fem/bilininteg.cpp +++ b/fem/bilininteg.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -22,14 +22,14 @@ namespace mfem void BilinearFormIntegrator::AssemblePA(const FiniteElementSpace&) { - mfem_error ("BilinearFormIntegrator::AssemblePA(...)\n" + mfem_error ("BilinearFormIntegrator::AssemblePA(fes)\n" " is not implemented for this class."); } void BilinearFormIntegrator::AssemblePA(const FiniteElementSpace&, const FiniteElementSpace&) { - mfem_error ("BilinearFormIntegrator::AssemblePA(...)\n" + mfem_error ("BilinearFormIntegrator::AssemblePA(fes, fes)\n" " is not implemented for this class."); } @@ -92,7 +92,7 @@ void BilinearFormIntegrator::AddMultPA(const Vector &, Vector &) const void BilinearFormIntegrator::AddMultTransposePA(const Vector &, Vector &) const { - mfem_error ("BilinearFormIntegrator::MultAssembledTranspose(...)\n" + mfem_error ("BilinearFormIntegrator::AddMultTransposePA(...)\n" " is not implemented for this class."); } @@ -229,6 +229,159 @@ void SumIntegrator::AssembleElementMatrix( } } +void SumIntegrator::AssembleElementMatrix2( + const FiniteElement &el1, const FiniteElement &el2, + ElementTransformation &Trans, DenseMatrix &elmat) +{ + MFEM_ASSERT(integrators.Size() > 0, "empty SumIntegrator."); + + integrators[0]->AssembleElementMatrix2(el1, el2, Trans, elmat); + for (int i = 1; i < integrators.Size(); i++) + { + integrators[i]->AssembleElementMatrix2(el1, el2, Trans, elem_mat); + elmat += elem_mat; + } +} + +void SumIntegrator::AssembleFaceMatrix( + const FiniteElement &el1, const FiniteElement &el2, + FaceElementTransformations &Trans, DenseMatrix &elmat) +{ + MFEM_ASSERT(integrators.Size() > 0, "empty SumIntegrator."); + + integrators[0]->AssembleFaceMatrix(el1, el2, Trans, elmat); + for (int i = 1; i < integrators.Size(); i++) + { + integrators[i]->AssembleFaceMatrix(el1, el2, Trans, elem_mat); + elmat += elem_mat; + } +} + +void SumIntegrator::AssembleFaceMatrix( + const FiniteElement &tr_fe, + const FiniteElement &te_fe1, const FiniteElement &te_fe2, + FaceElementTransformations &Trans, DenseMatrix &elmat) +{ + MFEM_ASSERT(integrators.Size() > 0, "empty SumIntegrator."); + + integrators[0]->AssembleFaceMatrix(tr_fe, te_fe1, te_fe2, Trans, elmat); + for (int i = 1; i < integrators.Size(); i++) + { + integrators[i]->AssembleFaceMatrix(tr_fe, te_fe1, te_fe2, Trans, elem_mat); + elmat += elem_mat; + } +} + +void SumIntegrator::AssemblePA(const FiniteElementSpace& fes) +{ + for (int i = 0; i < integrators.Size(); i++) + { + integrators[i]->AssemblePA(fes); + } +} + +void SumIntegrator::AssembleDiagonalPA(Vector &diag) +{ + for (int i = 0; i < integrators.Size(); i++) + { + integrators[i]->AssembleDiagonalPA(diag); + } +} + +void SumIntegrator::AssemblePAInteriorFaces(const FiniteElementSpace &fes) +{ + for (int i = 0; i < integrators.Size(); i++) + { + integrators[i]->AssemblePAInteriorFaces(fes); + } +} + +void SumIntegrator::AssemblePABoundaryFaces(const FiniteElementSpace &fes) +{ + for (int i = 0; i < integrators.Size(); i++) + { + integrators[i]->AssemblePABoundaryFaces(fes); + } +} + +void SumIntegrator::AddMultPA(const Vector& x, Vector& y) const +{ + for (int i = 0; i < integrators.Size(); i++) + { + integrators[i]->AddMultPA(x, y); + } +} + +void SumIntegrator::AddMultTransposePA(const Vector &x, Vector &y) const +{ + for (int i = 0; i < integrators.Size(); i++) + { + integrators[i]->AddMultTransposePA(x, y); + } +} + +void SumIntegrator::AssembleMF(const FiniteElementSpace &fes) +{ + for (int i = 0; i < integrators.Size(); i++) + { + integrators[i]->AssembleMF(fes); + } +} + +void SumIntegrator::AddMultMF(const Vector& x, Vector& y) const +{ + for (int i = 0; i < integrators.Size(); i++) + { + integrators[i]->AddMultTransposeMF(x, y); + } +} + +void SumIntegrator::AddMultTransposeMF(const Vector &x, Vector &y) const +{ + for (int i = 0; i < integrators.Size(); i++) + { + integrators[i]->AddMultMF(x, y); + } +} + +void SumIntegrator::AssembleDiagonalMF(Vector &diag) +{ + for (int i = 0; i < integrators.Size(); i++) + { + integrators[i]->AssembleDiagonalMF(diag); + } +} + +void SumIntegrator::AssembleEA(const FiniteElementSpace &fes, Vector &emat, + const bool add) +{ + for (int i = 0; i < integrators.Size(); i++) + { + integrators[i]->AssembleEA(fes, emat, add); + } +} + +void SumIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace &fes, + Vector &ea_data_int, + Vector &ea_data_ext, + const bool add) +{ + for (int i = 0; i < integrators.Size(); i++) + { + integrators[i]->AssembleEAInteriorFaces(fes,ea_data_int,ea_data_ext,add); + } +} + +void SumIntegrator::AssembleEABoundaryFaces(const FiniteElementSpace &fes, + Vector &ea_data_bdr, + const bool add) +{ + for (int i = 0; i < integrators.Size(); i++) + { + integrators[i]->AssembleEABoundaryFaces(fes, ea_data_bdr, add); + } +} + SumIntegrator::~SumIntegrator() { if (own_integrators) @@ -1913,12 +2066,12 @@ void VectorFEMassIntegrator::AssembleElementMatrix( double w; #ifdef MFEM_THREAD_SAFE - Vector D(VQ ? VQ->GetVDim() : 0); + Vector D(DQ ? DQ->GetVDim() : 0); DenseMatrix trial_vshape(dof, spaceDim); DenseMatrix K(MQ ? MQ->GetVDim() : 0, MQ ? MQ->GetVDim() : 0); #else trial_vshape.SetSize(dof, spaceDim); - D.SetSize(VQ ? VQ->GetVDim() : 0); + D.SetSize(DQ ? DQ->GetVDim() : 0); K.SetSize(MQ ? MQ->GetVDim() : 0, MQ ? MQ->GetVDim() : 0); #endif DenseMatrix tmp(trial_vshape.Height(), K.Width()); @@ -1950,9 +2103,9 @@ void VectorFEMassIntegrator::AssembleElementMatrix( Mult(trial_vshape,K,tmp); AddMultABt(tmp,trial_vshape,elmat); } - else if (VQ) + else if (DQ) { - VQ->Eval(D, Trans, ip); + DQ->Eval(D, Trans, ip); D *= w; AddMultADAt(trial_vshape, D, elmat); } @@ -1984,12 +2137,12 @@ void VectorFEMassIntegrator::AssembleElementMatrix2( #ifdef MFEM_THREAD_SAFE DenseMatrix trial_vshape(trial_dof, spaceDim); Vector shape(test_dof); - Vector D(VQ ? VQ->GetVDim() : 0); + Vector D(DQ ? DQ->GetVDim() : 0); DenseMatrix K(MQ ? MQ->GetVDim() : 0, MQ ? MQ->GetVDim() : 0); #else trial_vshape.SetSize(trial_dof, spaceDim); shape.SetSize(test_dof); - D.SetSize(VQ ? VQ->GetVDim() : 0); + D.SetSize(DQ ? DQ->GetVDim() : 0); K.SetSize(MQ ? MQ->GetVDim() : 0, MQ ? MQ->GetVDim() : 0); #endif @@ -2013,9 +2166,9 @@ void VectorFEMassIntegrator::AssembleElementMatrix2( test_fe.CalcShape(ip, shape); w = ip.weight * Trans.Weight(); - if (VQ) + if (DQ) { - VQ->Eval(D, Trans, ip); + DQ->Eval(D, Trans, ip); D *= w; for (int d = 0; d < vdim; d++) { @@ -2081,12 +2234,12 @@ void VectorFEMassIntegrator::AssembleElementMatrix2( #ifdef MFEM_THREAD_SAFE DenseMatrix trial_vshape(trial_dof,spaceDim); DenseMatrix test_vshape(test_dof,spaceDim); - Vector D(VQ ? VQ->GetVDim() : 0); + Vector D(DQ ? DQ->GetVDim() : 0); DenseMatrix K(MQ ? MQ->GetVDim() : 0, MQ ? MQ->GetVDim() : 0); #else trial_vshape.SetSize(trial_dof,spaceDim); test_vshape.SetSize(test_dof,spaceDim); - D.SetSize(VQ ? VQ->GetVDim() : 0); + D.SetSize(DQ ? DQ->GetVDim() : 0); K.SetSize(MQ ? MQ->GetVDim() : 0, MQ ? MQ->GetVDim() : 0); #endif DenseMatrix tmp(test_vshape.Height(), K.Width()); @@ -2118,9 +2271,9 @@ void VectorFEMassIntegrator::AssembleElementMatrix2( Mult(test_vshape,K,tmp); AddMultABt(tmp,trial_vshape,elmat); } - else if (VQ) + else if (DQ) { - VQ->Eval(D, Trans, ip); + DQ->Eval(D, Trans, ip); D *= w; AddMultADBt(test_vshape,D,trial_vshape,elmat); } @@ -2253,13 +2406,24 @@ void VectorDiffusionIntegrator::AssembleElementMatrix( const int dim = el.GetDim(); const int dof = el.GetDof(); const int sdim = Trans.GetSpaceDim(); - const bool square = (dim == sdim); - double w; - elmat.SetSize(sdim * dof); + // If vdim is not set, set it to the space dimension; + vdim = (vdim <= 0) ? sdim : vdim; + const bool square = (dim == sdim); + + if (VQ) + { + vcoeff.SetSize(vdim); + } + else if (MQ) + { + mcoeff.SetSize(vdim); + } dshape.SetSize(dof, dim); dshapedxt.SetSize(dof, sdim); + + elmat.SetSize(vdim * dof); pelmat.SetSize(dof); const IntegrationRule *ir = IntRule; @@ -2269,28 +2433,48 @@ void VectorDiffusionIntegrator::AssembleElementMatrix( } elmat = 0.0; - pelmat = 0.0; for (int i = 0; i < ir -> GetNPoints(); i++) { + const IntegrationPoint &ip = ir->IntPoint(i); - el.CalcDShape (ip, dshape); - Trans.SetIntPoint (&ip); - w = Trans.Weight(); + el.CalcDShape(ip, dshape); + + Trans.SetIntPoint(&ip); + double w = Trans.Weight(); w = ip.weight / (square ? w : w*w*w); // AdjugateJacobian = / adj(J), if J is square // \ adj(J^t.J).J^t, otherwise Mult(dshape, Trans.AdjugateJacobian(), dshapedxt); - if (Q) { w *= Q -> Eval (Trans, ip); } - AddMult_a_AAt(w, dshapedxt, pelmat); - } - for (int d = 0; d < sdim; d++) - { - for (int k = 0; k < dof; k++) + + if (VQ) { - for (int l = 0; l < dof; l++) + VQ->Eval(vcoeff, Trans, ip); + for (int k = 0; k < vdim; ++k) { - elmat(dof*d+k, dof*d+l) = pelmat(k, l); + Mult_a_AAt(w*vcoeff(k), dshapedxt, pelmat); + elmat.AddMatrix(pelmat, dof*k, dof*k); + } + } + else if (MQ) + { + MQ->Eval(mcoeff, Trans, ip); + for (int i = 0; i < vdim; ++i) + { + for (int j = 0; j < vdim; ++j) + { + Mult_a_AAt(w*mcoeff(i,j), dshapedxt, pelmat); + elmat.AddMatrix(pelmat, dof*i, dof*j); + } + } + } + else + { + if (Q) { w *= Q->Eval(Trans, ip); } + Mult_a_AAt(w, dshapedxt, pelmat); + for (int k = 0; k < vdim; ++k) + { + elmat.AddMatrix(pelmat, dof*k, dof*k); } } } @@ -2300,16 +2484,32 @@ void VectorDiffusionIntegrator::AssembleElementVector( const FiniteElement &el, ElementTransformation &Tr, const Vector &elfun, Vector &elvect) { - int dim = el.GetDim(); // assuming vector_dim == reference_dim - int dof = el.GetDof(); - double w; + const int dim = el.GetDim(); + const int dof = el.GetDof(); + const int sdim = Tr.GetSpaceDim(); + + // If vdim is not set, set it to the space dimension; + vdim = (vdim <= 0) ? sdim : vdim; + const bool square = (dim == sdim); + + if (VQ) + { + vcoeff.SetSize(vdim); + } + else if (MQ) + { + mcoeff.SetSize(vdim); + } - Jinv.SetSize(dim); dshape.SetSize(dof, dim); - pelmat.SetSize(dim); - gshape.SetSize(dim); + dshapedxt.SetSize(dof, dim); + // pelmat.SetSize(dim); elvect.SetSize(dim*dof); + + // NOTE: DenseMatrix is in column-major order. This is consistent with + // vectors ordered byNODES. In the resulting DenseMatrix, each column + // corresponds to a particular vdim. DenseMatrix mat_in(elfun.GetData(), dof, dim); DenseMatrix mat_out(elvect.GetData(), dof, dim); @@ -2323,22 +2523,50 @@ void VectorDiffusionIntegrator::AssembleElementVector( for (int i = 0; i < ir->GetNPoints(); i++) { const IntegrationPoint &ip = ir->IntPoint(i); - - Tr.SetIntPoint(&ip); - CalcAdjugate(Tr.Jacobian(), Jinv); - w = ip.weight / Tr.Weight(); - if (Q) - { - w *= Q->Eval(Tr, ip); - } - MultAAt(Jinv, gshape); - gshape *= w; - el.CalcDShape(ip, dshape); - MultAtB(mat_in, dshape, pelmat); - MultABt(pelmat, gshape, Jinv); - AddMultABt(dshape, Jinv, mat_out); + Tr.SetIntPoint(&ip); + double w = Tr.Weight(); + w = ip.weight / (square ? w : w*w*w); + Mult(dshape, Tr.AdjugateJacobian(), dshapedxt); + MultAAt(dshapedxt, pelmat); + + if (VQ) + { + VQ->Eval(vcoeff, Tr, ip); + for (int k = 0; k < vdim; ++k) + { + pelmat *= w*vcoeff(k); + const Vector vec_in(mat_in.GetColumn(k), dof); + Vector vec_out(mat_out.GetColumn(k), dof); + pelmat.AddMult(vec_in, vec_out); + } + } + else if (MQ) + { + MQ->Eval(mcoeff, Tr, ip); + for (int i = 0; i < vdim; ++i) + { + Vector vec_out(mat_out.GetColumn(i), dof); + for (int j = 0; j < vdim; ++j) + { + pelmat *= w*mcoeff(i,j); + const Vector vec_in(mat_in.GetColumn(j), dof); + pelmat.Mult(vec_in, vec_out); + } + } + } + else + { + if (Q) { w *= Q->Eval(Tr, ip); } + pelmat *= w; + for (int k = 0; k < vdim; ++k) + { + const Vector vec_in(mat_in.GetColumn(k), dof); + Vector vec_out(mat_out.GetColumn(k), dof); + pelmat.AddMult(vec_in, vec_out); + } + } } } @@ -3515,6 +3743,48 @@ VectorScalarProductInterpolator::AssembleElementMatrix2( } +void +ScalarCrossProductInterpolator::AssembleElementMatrix2( + const FiniteElement &dom_fe, + const FiniteElement &ran_fe, + ElementTransformation &Trans, + DenseMatrix &elmat) +{ + // Vector coefficient product with vector shape functions + struct VCrossVShapeCoefficient : public VectorCoefficient + { + VectorCoefficient &VQ; + const FiniteElement &fe; + DenseMatrix vshape; + Vector vc; + + VCrossVShapeCoefficient(VectorCoefficient &vq, const FiniteElement &fe_) + : VectorCoefficient(fe_.GetDof()), VQ(vq), fe(fe_), + vshape(vdim, vq.GetVDim()), vc(vq.GetVDim()) { } + + using VectorCoefficient::Eval; + virtual void Eval(Vector &V, ElementTransformation &T, + const IntegrationPoint &ip) + { + V.SetSize(vdim); + VQ.Eval(vc, T, ip); + fe.CalcPhysVShape(T, vshape); + for (int k = 0; k < vdim; k++) + { + V(k) = vc(0) * vshape(k,1) - vc(1) * vshape(k,0); + } + } + }; + + VCrossVShapeCoefficient dom_shape_coeff(*VQ, dom_fe); + + elmat.SetSize(ran_fe.GetDof(),dom_fe.GetDof()); + + Vector elmat_as_vec(elmat.Data(), elmat.Height()*elmat.Width()); + + ran_fe.Project(dom_shape_coeff, Trans, elmat_as_vec); +} + void VectorCrossProductInterpolator::AssembleElementMatrix2( const FiniteElement &dom_fe, diff --git a/fem/bilininteg.hpp b/fem/bilininteg.hpp index 2e32c60778..26a75561bf 100644 --- a/fem/bilininteg.hpp +++ b/fem/bilininteg.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -355,7 +355,7 @@ class SumIntegrator : public BilinearFormIntegrator { private: int own_integrators; - DenseMatrix elem_mat; + mutable DenseMatrix elem_mat; Array integrators; public: @@ -367,6 +367,55 @@ public: virtual void AssembleElementMatrix(const FiniteElement &el, ElementTransformation &Trans, DenseMatrix &elmat); + virtual void AssembleElementMatrix2(const FiniteElement &trial_fe, + const FiniteElement &test_fe, + ElementTransformation &Trans, + DenseMatrix &elmat); + + using BilinearFormIntegrator::AssembleFaceMatrix; + virtual void AssembleFaceMatrix(const FiniteElement &el1, + const FiniteElement &el2, + FaceElementTransformations &Trans, + DenseMatrix &elmat); + + virtual void AssembleFaceMatrix(const FiniteElement &trial_face_fe, + const FiniteElement &test_fe1, + const FiniteElement &test_fe2, + FaceElementTransformations &Trans, + DenseMatrix &elmat); + + using BilinearFormIntegrator::AssemblePA; + virtual void AssemblePA(const FiniteElementSpace& fes); + + virtual void AssembleDiagonalPA(Vector &diag); + + virtual void AssemblePAInteriorFaces(const FiniteElementSpace &fes); + + virtual void AssemblePABoundaryFaces(const FiniteElementSpace &fes); + + virtual void AddMultTransposePA(const Vector &x, Vector &y) const; + + virtual void AddMultPA(const Vector& x, Vector& y) const; + + virtual void AssembleMF(const FiniteElementSpace &fes); + + virtual void AddMultMF(const Vector &x, Vector &y) const; + + virtual void AddMultTransposeMF(const Vector &x, Vector &y) const; + + virtual void AssembleDiagonalMF(Vector &diag); + + virtual void AssembleEA(const FiniteElementSpace &fes, Vector &emat, + const bool add); + + virtual void AssembleEAInteriorFaces(const FiniteElementSpace &fes, + Vector &ea_data_int, + Vector &ea_data_ext, + const bool add); + + virtual void AssembleEABoundaryFaces(const FiniteElementSpace &fes, + Vector &ea_data_bdr, + const bool add); virtual ~SumIntegrator(); }; @@ -465,8 +514,8 @@ protected: : same_calc_shape(false), Q(NULL), VQ(NULL), DQ(NULL), MQ(NULL) {} MixedVectorIntegrator(Coefficient &q) : same_calc_shape(false), Q(&q), VQ(NULL), DQ(NULL), MQ(NULL) {} - MixedVectorIntegrator(VectorCoefficient &dq, bool diag = true) - : same_calc_shape(false), Q(NULL), VQ(diag?NULL:&dq), DQ(diag?&dq:NULL), + MixedVectorIntegrator(VectorCoefficient &vq, bool diag = true) + : same_calc_shape(false), Q(NULL), VQ(diag?NULL:&vq), DQ(diag?&vq:NULL), MQ(NULL) {} MixedVectorIntegrator(MatrixCoefficient &mq) : same_calc_shape(false), Q(NULL), VQ(NULL), DQ(NULL), MQ(&mq) {} @@ -503,7 +552,7 @@ protected: Coefficient *Q; VectorCoefficient *VQ; - VectorCoefficient *DQ; + DiagonalMatrixCoefficient *DQ; MatrixCoefficient *MQ; private: @@ -901,7 +950,7 @@ public: MixedVectorMassIntegrator() { same_calc_shape = true; } MixedVectorMassIntegrator(Coefficient &q) : MixedVectorIntegrator(q) { same_calc_shape = true; } - MixedVectorMassIntegrator(VectorCoefficient &dq) + MixedVectorMassIntegrator(DiagonalMatrixCoefficient &dq) : MixedVectorIntegrator(dq, true) { same_calc_shape = true; } MixedVectorMassIntegrator(MatrixCoefficient &mq) : MixedVectorIntegrator(mq) { same_calc_shape = true; } @@ -1019,7 +1068,7 @@ public: MixedGradGradIntegrator() { same_calc_shape = true; } MixedGradGradIntegrator(Coefficient &q) : MixedVectorIntegrator(q) { same_calc_shape = true; } - MixedGradGradIntegrator(VectorCoefficient &dq) + MixedGradGradIntegrator(DiagonalMatrixCoefficient &dq) : MixedVectorIntegrator(dq, true) { same_calc_shape = true; } MixedGradGradIntegrator(MatrixCoefficient &mq) : MixedVectorIntegrator(mq) { same_calc_shape = true; } @@ -1107,7 +1156,7 @@ public: MixedCurlCurlIntegrator() { same_calc_shape = true; } MixedCurlCurlIntegrator(Coefficient &q) : MixedVectorIntegrator(q) { same_calc_shape = true; } - MixedCurlCurlIntegrator(VectorCoefficient &dq) + MixedCurlCurlIntegrator(DiagonalMatrixCoefficient &dq) : MixedVectorIntegrator(dq, true) { same_calc_shape = true; } MixedCurlCurlIntegrator(MatrixCoefficient &mq) : MixedVectorIntegrator(mq) { same_calc_shape = true; } @@ -1651,7 +1700,7 @@ public: MixedVectorGradientIntegrator() {} MixedVectorGradientIntegrator(Coefficient &q) : MixedVectorIntegrator(q) {} - MixedVectorGradientIntegrator(VectorCoefficient &dq) + MixedVectorGradientIntegrator(DiagonalMatrixCoefficient &dq) : MixedVectorIntegrator(dq, true) {} MixedVectorGradientIntegrator(MatrixCoefficient &mq) : MixedVectorIntegrator(mq) {} @@ -1705,7 +1754,7 @@ public: MixedVectorCurlIntegrator() {} MixedVectorCurlIntegrator(Coefficient &q) : MixedVectorIntegrator(q) {} - MixedVectorCurlIntegrator(VectorCoefficient &dq) + MixedVectorCurlIntegrator(DiagonalMatrixCoefficient &dq) : MixedVectorIntegrator(dq, true) {} MixedVectorCurlIntegrator(MatrixCoefficient &mq) : MixedVectorIntegrator(mq) {} @@ -1760,7 +1809,7 @@ public: MixedVectorWeakCurlIntegrator() {} MixedVectorWeakCurlIntegrator(Coefficient &q) : MixedVectorIntegrator(q) {} - MixedVectorWeakCurlIntegrator(VectorCoefficient &dq) + MixedVectorWeakCurlIntegrator(DiagonalMatrixCoefficient &dq) : MixedVectorIntegrator(dq, true) {} MixedVectorWeakCurlIntegrator(MatrixCoefficient &mq) : MixedVectorIntegrator(mq) {} @@ -1813,7 +1862,7 @@ public: MixedVectorWeakDivergenceIntegrator() {} MixedVectorWeakDivergenceIntegrator(Coefficient &q) : MixedVectorIntegrator(q) {} - MixedVectorWeakDivergenceIntegrator(VectorCoefficient &dq) + MixedVectorWeakDivergenceIntegrator(DiagonalMatrixCoefficient &dq) : MixedVectorIntegrator(dq, true) {} MixedVectorWeakDivergenceIntegrator(MatrixCoefficient &mq) : MixedVectorIntegrator(mq) {} @@ -1844,8 +1893,10 @@ protected: }; /** Class for integrating the bilinear form a(u,v) := (Q grad u, v) where Q is a - scalar coefficient, and v is a vector with components v_i in the same space - as u. */ + scalar coefficient, and v is a vector with components v_i in the same (H1) space + as u. + + See also MixedVectorGradientIntegrator when v is in H(curl). */ class GradientIntegrator : public BilinearFormIntegrator { protected: @@ -1900,6 +1951,7 @@ protected: Coefficient *Q; VectorCoefficient *VQ; MatrixCoefficient *MQ; + SymmetricMatrixCoefficient *SMQ; private: Vector vec, pointflux, shape; @@ -1922,19 +1974,28 @@ private: public: /// Construct a diffusion integrator with coefficient Q = 1 DiffusionIntegrator() - : Q(NULL), VQ(NULL), MQ(NULL), maps(NULL), geom(NULL), ceedDataPtr(NULL) { } + : Q(NULL), VQ(NULL), MQ(NULL), SMQ(NULL), maps(NULL), geom(NULL), + ceedDataPtr(NULL) { } /// Construct a diffusion integrator with a scalar coefficient q DiffusionIntegrator(Coefficient &q) - : Q(&q), VQ(NULL), MQ(NULL), maps(NULL), geom(NULL), ceedDataPtr(NULL) { } + : Q(&q), VQ(NULL), MQ(NULL), SMQ(NULL), maps(NULL), geom(NULL), + ceedDataPtr(NULL) { } /// Construct a diffusion integrator with a vector coefficient q DiffusionIntegrator(VectorCoefficient &q) - : Q(NULL), VQ(&q), MQ(NULL), maps(NULL), geom(NULL), ceedDataPtr(NULL) { } + : Q(NULL), VQ(&q), MQ(NULL), SMQ(NULL), maps(NULL), geom(NULL), + ceedDataPtr(NULL) { } /// Construct a diffusion integrator with a matrix coefficient q DiffusionIntegrator(MatrixCoefficient &q) - : Q(NULL), VQ(NULL), MQ(&q), maps(NULL), geom(NULL), ceedDataPtr(NULL) { } + : Q(NULL), VQ(NULL), MQ(&q), SMQ(NULL), maps(NULL), geom(NULL), + ceedDataPtr(NULL) { } + + /// Construct a diffusion integrator with a symmetric matrix coefficient q + DiffusionIntegrator(SymmetricMatrixCoefficient &q) + : Q(NULL), VQ(NULL), MQ(NULL), SMQ(&q), maps(NULL), geom(NULL), + ceedDataPtr(NULL) { } virtual ~DiffusionIntegrator() { @@ -1984,6 +2045,8 @@ public: virtual void AddMultPA(const Vector&, Vector&) const; + virtual void AddMultTransposePA(const Vector&, Vector&) const; + static const IntegrationRule &GetRule(const FiniteElement &trial_fe, const FiniteElement &test_fe); }; @@ -2047,6 +2110,8 @@ public: virtual void AddMultPA(const Vector&, Vector&) const; + virtual void AddMultTransposePA(const Vector&, Vector&) const; + static const IntegrationRule &GetRule(const FiniteElement &trial_fe, const FiniteElement &test_fe, ElementTransformation &Trans); @@ -2108,6 +2173,17 @@ public: ElementTransformation &Trans); }; +// Alias for @ConvectionIntegrator. +using NonconservativeConvectionIntegrator = ConvectionIntegrator; + +/// -alpha (u, q . grad v), negative transpose of ConvectionIntegrator +class ConservativeConvectionIntegrator : public TransposeIntegrator +{ +public: + ConservativeConvectionIntegrator(VectorCoefficient &q, double a = 1.0) + : TransposeIntegrator(new ConvectionIntegrator(q, -a)) { } +}; + /// alpha (q . grad u, v) using the "group" FE discretization class GroupConvectionIntegrator : public BilinearFormIntegrator { @@ -2333,8 +2409,9 @@ private: protected: Coefficient *Q; - VectorCoefficient *DQ; + DiagonalMatrixCoefficient *DQ; MatrixCoefficient *MQ; + SymmetricMatrixCoefficient *SMQ; // PA extension Vector pa_data; @@ -2345,14 +2422,18 @@ protected: bool symmetric = true; ///< False if using a nonsymmetric matrix coefficient public: - CurlCurlIntegrator() { Q = NULL; DQ = NULL; MQ = NULL; } + CurlCurlIntegrator() { Q = NULL; DQ = NULL; MQ = NULL; SMQ = NULL; } /// Construct a bilinear form integrator for Nedelec elements CurlCurlIntegrator(Coefficient &q, const IntegrationRule *ir = NULL) : - BilinearFormIntegrator(ir), Q(&q) { DQ = NULL; MQ = NULL; } - CurlCurlIntegrator(VectorCoefficient &dq, const IntegrationRule *ir = NULL) : - BilinearFormIntegrator(ir), DQ(&dq) { Q = NULL; MQ = NULL; } + BilinearFormIntegrator(ir), Q(&q), DQ(NULL), MQ(NULL), SMQ(NULL) { } + CurlCurlIntegrator(DiagonalMatrixCoefficient &dq, + const IntegrationRule *ir = NULL) : + BilinearFormIntegrator(ir), Q(NULL), DQ(&dq), MQ(NULL), SMQ(NULL) { } CurlCurlIntegrator(MatrixCoefficient &mq, const IntegrationRule *ir = NULL) : - BilinearFormIntegrator(ir), MQ(&mq) { Q = NULL; DQ = NULL; } + BilinearFormIntegrator(ir), Q(NULL), DQ(NULL), MQ(&mq), SMQ(NULL) { } + CurlCurlIntegrator(SymmetricMatrixCoefficient &smq, + const IntegrationRule *ir = NULL) : + BilinearFormIntegrator(ir), Q(NULL), DQ(NULL), MQ(NULL), SMQ(&smq) { } /* Given a particular Finite Element, compute the element curl-curl matrix elmat */ @@ -2409,8 +2490,9 @@ public: class VectorFEMassIntegrator: public BilinearFormIntegrator { private: - void Init(Coefficient *q, VectorCoefficient *vq, MatrixCoefficient *mq) - { Q = q; VQ = vq; MQ = mq; } + void Init(Coefficient *q, DiagonalMatrixCoefficient *dq, MatrixCoefficient *mq, + SymmetricMatrixCoefficient *smq) + { Q = q; DQ = dq; MQ = mq; SMQ = smq; } #ifndef MFEM_THREAD_SAFE Vector shape; @@ -2423,8 +2505,9 @@ private: protected: Coefficient *Q; - VectorCoefficient *VQ; + DiagonalMatrixCoefficient *DQ; MatrixCoefficient *MQ; + SymmetricMatrixCoefficient *SMQ; // PA extension Vector pa_data; @@ -2437,13 +2520,15 @@ protected: bool symmetric = true; ///< False if using a nonsymmetric matrix coefficient public: - VectorFEMassIntegrator() { Init(NULL, NULL, NULL); } - VectorFEMassIntegrator(Coefficient *_q) { Init(_q, NULL, NULL); } - VectorFEMassIntegrator(Coefficient &q) { Init(&q, NULL, NULL); } - VectorFEMassIntegrator(VectorCoefficient *_vq) { Init(NULL, _vq, NULL); } - VectorFEMassIntegrator(VectorCoefficient &vq) { Init(NULL, &vq, NULL); } - VectorFEMassIntegrator(MatrixCoefficient *_mq) { Init(NULL, NULL, _mq); } - VectorFEMassIntegrator(MatrixCoefficient &mq) { Init(NULL, NULL, &mq); } + VectorFEMassIntegrator() { Init(NULL, NULL, NULL, NULL); } + VectorFEMassIntegrator(Coefficient *_q) { Init(_q, NULL, NULL, NULL); } + VectorFEMassIntegrator(Coefficient &q) { Init(&q, NULL, NULL, NULL); } + VectorFEMassIntegrator(DiagonalMatrixCoefficient *_dq) { Init(NULL, _dq, NULL, NULL); } + VectorFEMassIntegrator(DiagonalMatrixCoefficient &dq) { Init(NULL, &dq, NULL, NULL); } + VectorFEMassIntegrator(MatrixCoefficient *_mq) { Init(NULL, NULL, _mq, NULL); } + VectorFEMassIntegrator(MatrixCoefficient &mq) { Init(NULL, NULL, &mq, NULL); } + VectorFEMassIntegrator(SymmetricMatrixCoefficient &smq) { Init(NULL, NULL, NULL, &smq); } + VectorFEMassIntegrator(SymmetricMatrixCoefficient *smq) { Init(NULL, NULL, NULL, smq); } virtual void AssembleElementMatrix(const FiniteElement &el, ElementTransformation &Trans, @@ -2542,15 +2627,24 @@ public: }; /** Integrator for + (Q grad u, grad v) = sum_i (Q grad u_i, grad v_i) e_i e_i^T - for FE spaces defined by 'dim' copies of a scalar FE space. Where e_i - is the unit vector in the i-th direction. The resulting local element - matrix is a block-diagonal matrix consisting of 'dim' copies of a scalar - diffusion matrix in each diagonal block. */ + + for vector FE spaces, where e_i is the unit vector in the i-th direction. + The resulting local element matrix is square, of size vdim*dof , + where \c vdim is the vector dimension space and \c dof is the local degrees + of freedom. The integrator is not aware of the true vector dimension and + must use \c VectorCoefficient, \c MatrixCoefficient, or a caller-specified + value to determine the vector space. For a scalar coefficient, the caller + may manually specify the vector dimension or the vector dimension is assumed + to be the spatial dimension (i.e. 2-dimension or 3-dimension). +*/ class VectorDiffusionIntegrator : public BilinearFormIntegrator { protected: - Coefficient *Q; + Coefficient *Q = NULL; + VectorCoefficient *VQ = NULL; + MatrixCoefficient *MQ = NULL; // PA extension const DofToQuad *maps; ///< Not owned @@ -2559,17 +2653,62 @@ protected: Vector pa_data; // CEED extension - CeedData* ceedDataPtr; + CeedData* ceedDataPtr = NULL; private: DenseMatrix dshape, dshapedxt, pelmat; - DenseMatrix Jinv, gshape; + int vdim = -1; + DenseMatrix mcoeff; + Vector vcoeff; public: - VectorDiffusionIntegrator() - : Q(NULL), ceedDataPtr(NULL) { } + VectorDiffusionIntegrator() { } + + /** \brief Integrator with unit coefficient for caller-specified vector + dimension. + + If the vector dimension does not match the true dimension of the space, + the resulting element matrix will be mathematically invalid. */ + VectorDiffusionIntegrator(int vector_dimension) + : vdim(vector_dimension) { } + VectorDiffusionIntegrator(Coefficient &q) - : Q(&q), ceedDataPtr(NULL) { } + : Q(&q) { } + + /** \brief Integrator with scalar coefficient for caller-specified vector + dimension. + + The element matrix is block-diagonal with \c vdim copies of the element + matrix integrated with the \c Coefficient. + + If the vector dimension does not match the true dimension of the space, + the resulting element matrix will be mathematically invalid. */ + VectorDiffusionIntegrator(Coefficient &q, int vector_dimension) + : Q(&q), vdim(vector_dimension) { } + + /** \brief Integrator with \c VectorCoefficient. The vector dimension of the + \c FiniteElementSpace is assumed to be the same as the dimension of the + \c Vector. + + The element matrix is block-diagonal and each block is integrated with + coefficient q_i. + + If the vector dimension does not match the true dimension of the space, + the resulting element matrix will be mathematically invalid. */ + VectorDiffusionIntegrator(VectorCoefficient &vq) + : VQ(&vq), vdim(vq.GetVDim()) { } + + /** \brief Integrator with \c MatrixCoefficient. The vector dimension of the + \c FiniteElementSpace is assumed to be the same as the dimension of the + \c Matrix. + + The element matrix is populated in each block. Each block is integrated + with coefficient q_ij. + + If the vector dimension does not match the true dimension of the space, + the resulting element matrix will be mathematically invalid. */ + VectorDiffusionIntegrator(MatrixCoefficient& mq) + : MQ(&mq), vdim(mq.GetVDim()) { } virtual ~VectorDiffusionIntegrator() { @@ -2652,11 +2791,28 @@ public: /** Integrator for the DG form: alpha < rho_u (u.n) {v},[w] > + beta < rho_u |u.n| [v],[w] >, where v and w are the trial and test variables, respectively, and rho/u are - given scalar/vector coefficients. The vector coefficient, u, is assumed to - be continuous across the faces and when given the scalar coefficient, rho, - is assumed to be discontinuous. The integrator uses the upwind value of rho, - rho_u, which is value from the side into which the vector coefficient, u, - points. */ + given scalar/vector coefficients. {v} represents the average value of v on + the face and [v] is the jump such that {v}=(v1+v2)/2 and [v]=(v1-v2) for the + face between elements 1 and 2. For boundary elements, v2=0. The vector + coefficient, u, is assumed to be continuous across the faces and when given + the scalar coefficient, rho, is assumed to be discontinuous. The integrator + uses the upwind value of rho, rho_u, which is value from the side into which + the vector coefficient, u, points. + + One use case for this integrator is to discretize the operator -u.grad(v) + with a DG formulation. The resulting formulation uses the + ConvectionIntegrator (with coefficient u, and parameter alpha = -1) and the + transpose of the DGTraceIntegrator (with coefficient u, and parameters alpha + = 1, beta = -1/2 to use the upwind face flux, see also + NonconservativeDGTraceIntegrator). This discretization and the handling of + the inflow and outflow boundaries is illustrated in Example 9/9p. + + Another use case for this integrator is to discretize the operator -div(u v) + with a DG formulation. The resulting formulation is conservative and + consists of the ConservativeConvectionIntegrator (with coefficient u, and + parameter alpha = -1) plus the DGTraceIntegrator (with coefficient u, and + parameters alpha = -1, beta = -1/2 to use the upwind face flux). + */ class DGTraceIntegrator : public BilinearFormIntegrator { protected: @@ -2673,13 +2829,17 @@ private: Vector shape1, shape2; public: - /// Construct integrator with rho = 1. - DGTraceIntegrator(VectorCoefficient &_u, double a, double b) - { rho = NULL; u = &_u; alpha = a; beta = b; } + /// Construct integrator with rho = 1, b = 0.5*a. + DGTraceIntegrator(VectorCoefficient &u_, double a) + { rho = NULL; u = &u_; alpha = a; beta = 0.5*a; } - DGTraceIntegrator(Coefficient &_rho, VectorCoefficient &_u, + /// Construct integrator with rho = 1. + DGTraceIntegrator(VectorCoefficient &u_, double a, double b) + { rho = NULL; u = &u_; alpha = a; beta = b; } + + DGTraceIntegrator(Coefficient &_rho, VectorCoefficient &u_, double a, double b) - { rho = &_rho; u = &_u; alpha = a; beta = b; } + { rho = &_rho; u = &u_; alpha = a; beta = b; } using BilinearFormIntegrator::AssembleFaceMatrix; virtual void AssembleFaceMatrix(const FiniteElement &el1, @@ -2713,6 +2873,30 @@ private: void SetupPA(const FiniteElementSpace &fes, FaceType type); }; +// Alias for @a DGTraceIntegrator. +using ConservativeDGTraceIntegrator = DGTraceIntegrator; + +/** Integrator that represents the face terms used for the non-conservative + DG discretization of the convection equation: + -alpha < rho_u (u.n) {v},[w] > + beta < rho_u |u.n| [v],[w] >. + + This integrator can be used with together with ConvectionIntegrator to + implement an upwind DG discretization in non-conservative form, see ex9 and + ex9p. */ +class NonconservativeDGTraceIntegrator : public TransposeIntegrator +{ +public: + NonconservativeDGTraceIntegrator(VectorCoefficient &u, double a) + : TransposeIntegrator(new DGTraceIntegrator(u, -a, 0.5*a)) { } + + NonconservativeDGTraceIntegrator(VectorCoefficient &u, double a, double b) + : TransposeIntegrator(new DGTraceIntegrator(u, -a, b)) { } + + NonconservativeDGTraceIntegrator(Coefficient &rho, VectorCoefficient &u, + double a, double b) + : TransposeIntegrator(new DGTraceIntegrator(rho, u, -a, b)) { } +}; + /** Integrator for the DG form: - < {(Q grad(u)).n}, [v] > + sigma < [u], {(Q grad(v)).n} > @@ -2750,6 +2934,51 @@ public: DenseMatrix &elmat); }; +/** Integrator for the "BR2" diffusion stabilization term + + sum_e eta (r_e([u]), r_e([v])) + + where r_e is the lifting operator defined on each edge e. The parameter eta + can be chosen to be one to obtain a stable discretization. The constructor + for this integrator requires the finite element space because the lifting + operator depends on the element-wise inverse mass matrix. + + BR2 stands for the second method of Bassi and Rebay: + + - F. Bassi and S. Rebay. A high order discontinuous Galerkin method for + compressible turbulent flows. In B. Cockburn, G. E. Karniadakis, and + C.-W. Shu, editors, Discontinuous Galerkin Methods, pages 77–88. Springer + Berlin Heidelberg, 2000. + - D. N. Arnold, F. Brezzi, B. Cockburn, and L. D. Marini. Unified analysis + of discontinuous Galerkin methods for elliptic problems. SIAM Journal on + Numerical Analysis, 39(5):1749–1779, 2002. +*/ +class DGDiffusionBR2Integrator : public BilinearFormIntegrator +{ +protected: + double eta; + + // Block factorizations of local mass matrices, with offsets for the case of + // not equally sized blocks (mixed meshes, p-refinement) + Array Minv; + Array ipiv; + Array ipiv_offsets, Minv_offsets; + + Vector shape1, shape2; + + DenseMatrix R11, R12, R21, R22; + DenseMatrix MinvR11, MinvR12, MinvR21, MinvR22; + DenseMatrix Re, MinvRe; + +public: + DGDiffusionBR2Integrator(class FiniteElementSpace *fes, double e = 1.0); + using BilinearFormIntegrator::AssembleFaceMatrix; + virtual void AssembleFaceMatrix(const FiniteElement &el1, + const FiniteElement &el2, + FaceElementTransformations &Trans, + DenseMatrix &elmat); +}; + /** Integrator for the DG elasticity form, for the formulations see: - PhD Thesis of Jonas De Basabe, High-Order Finite %Element Methods for Seismic Wave Propagation, UT Austin, 2009, p. 23, and references therein @@ -2908,11 +3137,36 @@ class DiscreteInterpolator : public BilinearFormIntegrator { }; class GradientInterpolator : public DiscreteInterpolator { public: + GradientInterpolator() : dofquad_fe(NULL) { } + virtual ~GradientInterpolator() { delete dofquad_fe; } + virtual void AssembleElementMatrix2(const FiniteElement &h1_fe, const FiniteElement &nd_fe, ElementTransformation &Trans, DenseMatrix &elmat) { nd_fe.ProjectGrad(h1_fe, Trans, elmat); } + + using BilinearFormIntegrator::AssemblePA; + + /** @brief Setup method for PA data. + + @param[in] trial_fes H1 Lagrange space + @param[in] test_fes H(curl) Nedelec space + */ + virtual void AssemblePA(const FiniteElementSpace &trial_fes, + const FiniteElementSpace &test_fes); + + virtual void AddMultPA(const Vector &x, Vector &y) const; + virtual void AddMultTransposePA(const Vector &x, Vector &y) const; + +private: + /// 1D finite element that generates and owns the 1D DofToQuad maps below + FiniteElement * dofquad_fe; + + bool B_id; // is the B basis operator (maps_C_C) the identity? + const DofToQuad *maps_C_C; // one-d map with Lobatto rows, Lobatto columns + const DofToQuad *maps_O_C; // one-d map with Legendre rows, Lobatto columns + int dim, ne, o_dofs1D, c_dofs1D; }; @@ -2927,6 +3181,24 @@ public: ElementTransformation &Trans, DenseMatrix &elmat) { ran_fe.Project(dom_fe, Trans, elmat); } + + using BilinearFormIntegrator::AssemblePA; + + virtual void AssemblePA(const FiniteElementSpace &trial_fes, + const FiniteElementSpace &test_fes); + + virtual void AddMultPA(const Vector &x, Vector &y) const; + virtual void AddMultTransposePA(const Vector &x, Vector &y) const; + +private: + /// 1D finite element that generates and owns the 1D DofToQuad maps below + FiniteElement * dofquad_fe; + + const DofToQuad *maps_C_C; // one-d map with Lobatto rows, Lobatto columns + const DofToQuad *maps_O_C; // one-d map with Legendre rows, Lobatto columns + int dim, ne, o_dofs1D, c_dofs1D; + + Vector pa_data; }; @@ -3026,6 +3298,22 @@ protected: VectorCoefficient *VQ; }; +/** Interpolator of the 2D cross product between a vector coefficient and an + H(curl)-conforming field onto an L2-conforming field. */ +class ScalarCrossProductInterpolator : public DiscreteInterpolator +{ +public: + ScalarCrossProductInterpolator(VectorCoefficient & vc) + : VQ(&vc) { } + + virtual void AssembleElementMatrix2(const FiniteElement &nd_fe, + const FiniteElement &l2_fe, + ElementTransformation &Trans, + DenseMatrix &elmat); +protected: + VectorCoefficient *VQ; +}; + /** Interpolator of the cross product between a vector coefficient and an H(curl)-conforming field onto an H(div)-conforming field. The range space can also be vector L2. */ diff --git a/fem/bilininteg_br2.cpp b/fem/bilininteg_br2.cpp new file mode 100644 index 0000000000..c84263bd1b --- /dev/null +++ b/fem/bilininteg_br2.cpp @@ -0,0 +1,242 @@ +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-806117. +// +// This file is part of the MFEM library. For more information and source code +// availability visit https://mfem.org. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. + +#include "bilininteg.hpp" +#include "pfespace.hpp" +#include + +namespace mfem +{ + +DGDiffusionBR2Integrator::DGDiffusionBR2Integrator(FiniteElementSpace *fes, + double e) : eta(e) +{ + // Precompute local mass matrix inverses needed for the lifting operators + // First compute offsets and total size needed (e.g. for mixed meshes or + // p-refinement) + int nel = fes->GetNE(); + Minv_offsets.SetSize(nel+1); + ipiv_offsets.SetSize(nel+1); + ipiv_offsets[0] = 0; + Minv_offsets[0] = 0; + for (int i=0; iGetFE(i)->GetDof(); + ipiv_offsets[i+1] = ipiv_offsets[i] + dof; + Minv_offsets[i+1] = Minv_offsets[i] + dof*dof; + } + +#ifdef MFEM_USE_MPI + // When running in parallel, we also need to compute the local mass matrices + // of face neighbor elements + ParFiniteElementSpace *pfes = dynamic_cast(fes); + if (pfes != NULL) + { + ParMesh *pmesh = pfes->GetParMesh(); + pfes->ExchangeFaceNbrData(); + int nel_nbr = pmesh->GetNFaceNeighborElements(); + Minv_offsets.SetSize(nel+nel_nbr+1); + ipiv_offsets.SetSize(nel+nel_nbr+1); + for (int i=0; iGetFaceNbrFE(i)->GetDof(); + ipiv_offsets[nel+i+1] = ipiv_offsets[nel+i] + dof; + Minv_offsets[nel+i+1] = Minv_offsets[nel+i] + dof*dof; + } + nel += nel_nbr; + } +#endif + // The final "offset" is the total size of all the blocks + Minv.SetSize(Minv_offsets[nel]); + ipiv.SetSize(ipiv_offsets[nel]); + + // Assemble the local mass matrices and compute LU factorization + MassIntegrator mi; + for (int i=0; iGetNE()) + { + fe = fes->GetFE(i); + tr = fes->GetElementTransformation(i); + } + else + { +#ifdef MFEM_USE_MPI + int inbr = i - fes->GetNE(); + fe = pfes->GetFaceNbrFE(inbr); + tr = pfes->GetParMesh()->GetFaceNbrElementTransformation(inbr); +#endif + } + int dof = fe->GetDof(); + double *Minv_el = &Minv[Minv_offsets[i]]; + int *ipiv_el = &ipiv[ipiv_offsets[i]]; + DenseMatrix Me(Minv_el, dof, dof); + mi.AssembleElementMatrix(*fe, *tr, Me); + LUFactors lu(Minv_el, ipiv_el); + lu.Factor(dof); + } +} + +void DGDiffusionBR2Integrator::AssembleFaceMatrix( + const FiniteElement &el1, const FiniteElement &el2, + FaceElementTransformations &Trans, DenseMatrix &elmat) +{ + int ndof1 = el1.GetDof(); + shape1.SetSize(ndof1); + + R11.SetSize(ndof1, ndof1); + R11 = 0.0; + LUFactors M1inv(&Minv[Minv_offsets[Trans.Elem1No]], + &ipiv[ipiv_offsets[Trans.Elem1No]]); + LUFactors M2inv; + + double factor = Geometries.NumBdr(Trans.Elem1->GetGeometryType()); + + int ndof2; + if (Trans.Elem2No >= 0) + { + ndof2 = el2.GetDof(); + shape2.SetSize(ndof2); + R12.SetSize(ndof1, ndof2); + R21.SetSize(ndof2, ndof1); + R22.SetSize(ndof2, ndof2); + M2inv.data = &Minv[Minv_offsets[Trans.Elem2No]]; + M2inv.ipiv = &ipiv[ipiv_offsets[Trans.Elem2No]]; + + R12 = 0.0; + R21 = 0.0; + R22 = 0.0; + + Geometry::Type geom2 = Trans.Elem2->GetGeometryType(); + factor = std::max(factor, double(Geometries.NumBdr(geom2))); + } + else + { + ndof2 = 0; + } + + int ndofs = ndof1 + ndof2; + + Re.SetSize(ndofs, ndofs); + MinvRe.SetSize(ndofs, ndofs); + + elmat.SetSize(ndofs); + elmat = 0.0; + + const IntegrationRule *ir = IntRule; + if (ir == NULL) + { + int order; + if (ndof2) + { + order = 2*std::max(el1.GetOrder(), el2.GetOrder()); + } + else + { + order = 2*el1.GetOrder(); + } + ir = &IntRules.Get(Trans.FaceGeom, order); + } + + for (int p = 0; p < ir->GetNPoints(); p++) + { + const IntegrationPoint &ip = ir->IntPoint(p); + IntegrationPoint eip1, eip2; + + Trans.Loc1.Transform(ip, eip1); + el1.CalcShape(eip1, shape1); + if (ndof2) + { + Trans.Loc2.Transform(ip, eip2); + el2.CalcShape(eip2, shape2); + } + + double w = factor*sqrt(eta)*ip.weight*Trans.Face->Weight(); + if (ndof2) + { + w /= 2; + } + + for (int i = 0; i < ndof1; i++) + { + const double wsi = w*shape1(i); + for (int j = 0; j < ndof1; j++) + { + R11(i, j) += wsi*shape1(j); + } + } + + if (ndof2) + { + for (int i = 0; i < ndof2; i++) + { + const double wsi = w*shape2(i); + for (int j = 0; j < ndof1; j++) + { + R21(i, j) += wsi*shape1(j); + R12(j, i) -= wsi*shape1(j); + } + for (int j = 0; j < ndof2; j++) + { + R22(i, j) -= wsi*shape2(j); + } + } + } + } + + MinvR11 = R11; + M1inv.Solve(ndof1, ndof1, MinvR11.Data()); + for (int i = 0; i < ndof1; i++) + { + for (int j = 0; j < ndof1; j++) + { + Re(i, j) = R11(i, j); + MinvRe(i, j) = MinvR11(i, j); + } + } + + if (ndof2) + { + MinvR12 = R12; + MinvR21 = R21; + MinvR22 = R22; + M1inv.Solve(ndof1, ndof2, MinvR12.Data()); + M2inv.Solve(ndof2, ndof1, MinvR21.Data()); + M2inv.Solve(ndof2, ndof2, MinvR22.Data()); + + for (int i = 0; i < ndof2; i++) + { + for (int j = 0; j < ndof1; j++) + { + Re(ndof1 + i, j) = R21(i, j); + MinvRe(ndof1 + i, j) = MinvR21(i, j); + + Re(j, ndof1 + i) = R12(j, i); + MinvRe(j, ndof1 + i) = MinvR12(j, i); + } + for (int j = 0; j < ndof2; j++) + { + Re(ndof1 + i, ndof1 + j) = R22(i, j); + MinvRe(ndof1 + i, ndof1 + j) = MinvR22(i, j); + } + } + } + + // Compute the matrix associated with (r_e([u]), r_e([u])). + // The matrix for r_e([u]) is `MinvRe`, and so we need to form the product + // `(MinvRe)^T M MinvRe`. Using `Minv^T M = Minv M = I`, we obtain + // `Re^T MinvRe`. + MultAtB(Re, MinvRe, elmat); +} + +} diff --git a/fem/bilininteg_convection_ea.cpp b/fem/bilininteg_convection_ea.cpp index f1f7ddeaf0..89a5dc9ad8 100644 --- a/fem/bilininteg_convection_ea.cpp +++ b/fem/bilininteg_convection_ea.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/bilininteg_convection_pa.cpp b/fem/bilininteg_convection_pa.cpp index 84e772a056..b06c5bec94 100644 --- a/fem/bilininteg_convection_pa.cpp +++ b/fem/bilininteg_convection_pa.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/bilininteg_dgtrace_ea.cpp b/fem/bilininteg_dgtrace_ea.cpp index 5574ab2588..0dae47ea7f 100644 --- a/fem/bilininteg_dgtrace_ea.cpp +++ b/fem/bilininteg_dgtrace_ea.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/bilininteg_dgtrace_pa.cpp b/fem/bilininteg_dgtrace_pa.cpp index a1a54ecaa5..3144441c27 100644 --- a/fem/bilininteg_dgtrace_pa.cpp +++ b/fem/bilininteg_dgtrace_pa.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/bilininteg_diffusion_ea.cpp b/fem/bilininteg_diffusion_ea.cpp index 6c1c9b5258..7bee981986 100644 --- a/fem/bilininteg_diffusion_ea.cpp +++ b/fem/bilininteg_diffusion_ea.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/bilininteg_diffusion_mf.cpp b/fem/bilininteg_diffusion_mf.cpp index cfb0934923..67abf5aa05 100644 --- a/fem/bilininteg_diffusion_mf.cpp +++ b/fem/bilininteg_diffusion_mf.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/bilininteg_diffusion_pa.cpp b/fem/bilininteg_diffusion_pa.cpp index 25a6fab5eb..3278f6dcd0 100644 --- a/fem/bilininteg_diffusion_pa.cpp +++ b/fem/bilininteg_diffusion_pa.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -379,51 +379,54 @@ void DiffusionIntegrator::AssemblePA(const FiniteElementSpace &fes) const int MQfullDim = MQ ? MQ->GetHeight() * MQ->GetWidth() : 0; if (MQ) { + symmetric = false; MFEM_VERIFY(MQ->GetHeight() == dim && MQ->GetWidth() == dim, ""); - const int MQsymmDim = MQ->GetWidth() * (MQ->GetWidth() + 1) / 2; - const int MQdim = MQ->IsSymmetric() ? MQsymmDim : MQfullDim; - coeffDim = MQdim; + coeffDim = MQfullDim; - coeff.SetSize(MQdim * nq * ne); - symmetric = MQ ? MQ->IsSymmetric() : true; + coeff.SetSize(MQfullDim * nq * ne); DenseMatrix M; - Vector Msymm; - if (symmetric) - { - Msymm.SetSize(MQsymmDim); - } - else - { - M.SetSize(dim); - } + M.SetSize(dim); - auto C = Reshape(coeff.HostWrite(), MQdim, nq, ne); + auto C = Reshape(coeff.HostWrite(), MQfullDim, nq, ne); for (int e=0; eGetElementTransformation(e); for (int p=0; pIsSymmetric()) - { - MQ->EvalSymmetric(Msymm, *tr, ir->IntPoint(p)); - - for (int i=0; iEval(M, *tr, ir->IntPoint(p)); + for (int i=0; iEval(M, *tr, ir->IntPoint(p)); + } + } + } + else if (SMQ) + { + MFEM_VERIFY(SMQ->GetSize() == dim, ""); + coeffDim = symmDims; + coeff.SetSize(symmDims * nq * ne); - for (int i=0; iGetElementTransformation(e); + for (int p=0; pEval(M, *tr, ir->IntPoint(p)); + int cnt = 0; + for (int i=0; iGetElementTransformation(0)); + const int dims = el->GetDim(); MFEM_VERIFY(dims == 2 || dims == 3, ""); @@ -949,12 +950,12 @@ void CurlCurlIntegrator::AssemblePA(const FiniteElementSpace &fes) MFEM_VERIFY(dofs1D == mapsO->ndof + 1 && quad1D == mapsO->nqpt, ""); - const int MQsymmDim = MQ ? (MQ->GetWidth() * (MQ->GetWidth() + 1)) / 2 : 0; + const int MQsymmDim = SMQ ? (SMQ->GetSize() * (SMQ->GetSize() + 1)) / 2 : 0; const int MQfullDim = MQ ? (MQ->GetHeight() * MQ->GetWidth()) : 0; - const int MQdim = MQ ? (MQ->IsSymmetric() ? MQsymmDim : MQfullDim) : 0; - const int coeffDim = MQ ? MQdim : (DQ ? DQ->GetVDim() : 1); + const int MQdim = MQ ? MQfullDim : MQsymmDim; + const int coeffDim = (MQ || SMQ) ? MQdim : (DQ ? DQ->GetVDim() : 1); - symmetric = MQ ? MQ->IsSymmetric() : true; + symmetric = (MQ == NULL); const int symmDims = (dims * (dims + 1)) / 2; // 1x1: 1, 2x2: 3, 3x3: 6 const int ndata = (dim == 2) ? 1 : (symmetric ? symmDims : MQfullDim); @@ -963,22 +964,11 @@ void CurlCurlIntegrator::AssemblePA(const FiniteElementSpace &fes) Vector coeff(coeffDim * ne * nq); coeff = 1.0; auto coeffh = Reshape(coeff.HostWrite(), coeffDim, nq, ne); - if (Q || DQ || MQ) + if (Q || DQ || MQ || SMQ) { Vector D(DQ ? coeffDim : 0); DenseMatrix M; - Vector Msymm; - if (MQ) - { - if (symmetric) - { - Msymm.SetSize(MQsymmDim); - } - else - { - M.SetSize(dimc); - } - } + DenseSymmetricMatrix SM; if (DQ) { @@ -986,9 +976,15 @@ void CurlCurlIntegrator::AssemblePA(const FiniteElementSpace &fes) } if (MQ) { + M.SetSize(dimc); MFEM_VERIFY(coeffDim == MQdim, ""); MFEM_VERIFY(MQ->GetHeight() == dimc && MQ->GetWidth() == dimc, ""); } + if (SMQ) + { + SM.SetSize(dimc); + MFEM_VERIFY(SMQ->GetSize() == dimc, ""); + } for (int e=0; eIsSymmetric()) - { - MQ->EvalSymmetric(Msymm, *tr, ir->IntPoint(p)); + MQ->Eval(M, *tr, ir->IntPoint(p)); - for (int i=0; iEval(SM, *tr, ir->IntPoint(p)); + + int cnt = 0; + for (int i=0; iEval(M, *tr, ir->IntPoint(p)); - for (int i=0; i &B_, + const Array &G_, + const Vector &x_, + Vector &y_) +{ + auto B = Reshape(B_.Read(), c_dofs1D, c_dofs1D); + auto G = Reshape(G_.Read(), o_dofs1D, c_dofs1D); + + auto x = Reshape(x_.Read(), c_dofs1D, c_dofs1D, NE); + auto y = Reshape(y_.ReadWrite(), 2 * c_dofs1D * o_dofs1D, NE); + + constexpr static int MAX_D1D = HCURL_MAX_D1D; + MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, ""); + + MFEM_FORALL(e, NE, + { + double w[MAX_D1D][MAX_D1D]; + + // horizontal part + for (int dx = 0; dx < c_dofs1D; ++dx) + { + for (int ey = 0; ey < c_dofs1D; ++ey) + { + w[dx][ey] = 0.0; + for (int dy = 0; dy < c_dofs1D; ++dy) + { + w[dx][ey] += B(ey, dy) * x(dx, dy, e); + } + } + } + + for (int ey = 0; ey < c_dofs1D; ++ey) + { + for (int ex = 0; ex < o_dofs1D; ++ex) + { + double s = 0.0; + for (int dx = 0; dx < c_dofs1D; ++dx) + { + s += G(ex, dx) * w[dx][ey]; + } + const int local_index = ey*o_dofs1D + ex; + y(local_index, e) += s; + } + } + + // vertical part + for (int dx = 0; dx < c_dofs1D; ++dx) + { + for (int ey = 0; ey < o_dofs1D; ++ey) + { + w[dx][ey] = 0.0; + for (int dy = 0; dy < c_dofs1D; ++dy) + { + w[dx][ey] += G(ey, dy) * x(dx, dy, e); + } + } + } + + for (int ey = 0; ey < o_dofs1D; ++ey) + { + for (int ex = 0; ex < c_dofs1D; ++ex) + { + double s = 0.0; + for (int dx = 0; dx < c_dofs1D; ++dx) + { + s += B(ex, dx) * w[dx][ey]; + } + const int local_index = c_dofs1D * o_dofs1D + ey*c_dofs1D + ex; + y(local_index, e) += s; + } + } + }); +} + +// Specialization of PAHcurlApplyGradient2D to the case where B is identity +static void PAHcurlApplyGradient2DBId(const int c_dofs1D, + const int o_dofs1D, + const int NE, + const Array &G_, + const Vector &x_, + Vector &y_) +{ + auto G = Reshape(G_.Read(), o_dofs1D, c_dofs1D); + + auto x = Reshape(x_.Read(), c_dofs1D, c_dofs1D, NE); + auto y = Reshape(y_.ReadWrite(), 2 * c_dofs1D * o_dofs1D, NE); + + constexpr static int MAX_D1D = HCURL_MAX_D1D; + MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, ""); + + MFEM_FORALL(e, NE, + { + double w[MAX_D1D][MAX_D1D]; + + // horizontal part + for (int dx = 0; dx < c_dofs1D; ++dx) + { + for (int ey = 0; ey < c_dofs1D; ++ey) + { + const int dy = ey; + w[dx][ey] = x(dx, dy, e); + } + } + + for (int ey = 0; ey < c_dofs1D; ++ey) + { + for (int ex = 0; ex < o_dofs1D; ++ex) + { + double s = 0.0; + for (int dx = 0; dx < c_dofs1D; ++dx) + { + s += G(ex, dx) * w[dx][ey]; + } + const int local_index = ey*o_dofs1D + ex; + y(local_index, e) += s; + } + } + + // vertical part + for (int dx = 0; dx < c_dofs1D; ++dx) + { + for (int ey = 0; ey < o_dofs1D; ++ey) + { + w[dx][ey] = 0.0; + for (int dy = 0; dy < c_dofs1D; ++dy) + { + w[dx][ey] += G(ey, dy) * x(dx, dy, e); + } + } + } + + for (int ey = 0; ey < o_dofs1D; ++ey) + { + for (int ex = 0; ex < c_dofs1D; ++ex) + { + const int dx = ex; + const double s = w[dx][ey]; + const int local_index = c_dofs1D * o_dofs1D + ey*c_dofs1D + ex; + y(local_index, e) += s; + } + } + }); +} + +static void PAHcurlApplyGradientTranspose2D( + const int c_dofs1D, const int o_dofs1D, const int NE, + const Array &B_, const Array &G_, + const Vector &x_, Vector &y_) +{ + auto B = Reshape(B_.Read(), c_dofs1D, c_dofs1D); + auto G = Reshape(G_.Read(), o_dofs1D, c_dofs1D); + + auto x = Reshape(x_.Read(), 2 * c_dofs1D * o_dofs1D, NE); + auto y = Reshape(y_.ReadWrite(), c_dofs1D, c_dofs1D, NE); + + constexpr static int MAX_D1D = HCURL_MAX_D1D; + MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, ""); + + MFEM_FORALL(e, NE, + { + double w[MAX_D1D][MAX_D1D]; + + // horizontal part (open x, closed y) + for (int dy = 0; dy < c_dofs1D; ++dy) + { + for (int ex = 0; ex < o_dofs1D; ++ex) + { + w[dy][ex] = 0.0; + for (int ey = 0; ey < c_dofs1D; ++ey) + { + const int local_index = ey*o_dofs1D + ex; + w[dy][ex] += B(ey, dy) * x(local_index, e); + } + } + } + + for (int dy = 0; dy < c_dofs1D; ++dy) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + double s = 0.0; + for (int ex = 0; ex < o_dofs1D; ++ex) + { + s += G(ex, dx) * w[dy][ex]; + } + y(dx, dy, e) += s; + } + } + + // vertical part (open y, closed x) + for (int dy = 0; dy < c_dofs1D; ++dy) + { + for (int ex = 0; ex < c_dofs1D; ++ex) + { + w[dy][ex] = 0.0; + for (int ey = 0; ey < o_dofs1D; ++ey) + { + const int local_index = c_dofs1D * o_dofs1D + ey*c_dofs1D + ex; + w[dy][ex] += G(ey, dy) * x(local_index, e); + } + } + } + + for (int dy = 0; dy < c_dofs1D; ++dy) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + double s = 0.0; + for (int ex = 0; ex < c_dofs1D; ++ex) + { + s += B(ex, dx) * w[dy][ex]; + } + y(dx, dy, e) += s; + } + } + }); +} + +// Specialization of PAHcurlApplyGradientTranspose2D to the case where +// B is identity +static void PAHcurlApplyGradientTranspose2DBId( + const int c_dofs1D, const int o_dofs1D, const int NE, + const Array &G_, + const Vector &x_, Vector &y_) +{ + auto G = Reshape(G_.Read(), o_dofs1D, c_dofs1D); + + auto x = Reshape(x_.Read(), 2 * c_dofs1D * o_dofs1D, NE); + auto y = Reshape(y_.ReadWrite(), c_dofs1D, c_dofs1D, NE); + + constexpr static int MAX_D1D = HCURL_MAX_D1D; + MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, ""); + + MFEM_FORALL(e, NE, + { + double w[MAX_D1D][MAX_D1D]; + + // horizontal part (open x, closed y) + for (int dy = 0; dy < c_dofs1D; ++dy) + { + for (int ex = 0; ex < o_dofs1D; ++ex) + { + const int ey = dy; + const int local_index = ey*o_dofs1D + ex; + w[dy][ex] = x(local_index, e); + } + } + + for (int dy = 0; dy < c_dofs1D; ++dy) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + double s = 0.0; + for (int ex = 0; ex < o_dofs1D; ++ex) + { + s += G(ex, dx) * w[dy][ex]; + } + y(dx, dy, e) += s; + } + } + + // vertical part (open y, closed x) + for (int dy = 0; dy < c_dofs1D; ++dy) + { + for (int ex = 0; ex < c_dofs1D; ++ex) + { + w[dy][ex] = 0.0; + for (int ey = 0; ey < o_dofs1D; ++ey) + { + const int local_index = c_dofs1D * o_dofs1D + ey*c_dofs1D + ex; + w[dy][ex] += G(ey, dy) * x(local_index, e); + } + } + } + + for (int dy = 0; dy < c_dofs1D; ++dy) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + const int ex = dx; + const double s = w[dy][ex]; + y(dx, dy, e) += s; + } + } + }); +} + +static void PAHcurlApplyGradient3D(const int c_dofs1D, + const int o_dofs1D, + const int NE, + const Array &B_, + const Array &G_, + const Vector &x_, + Vector &y_) +{ + auto B = Reshape(B_.Read(), c_dofs1D, c_dofs1D); + auto G = Reshape(G_.Read(), o_dofs1D, c_dofs1D); + + auto x = Reshape(x_.Read(), c_dofs1D, c_dofs1D, c_dofs1D, NE); + auto y = Reshape(y_.ReadWrite(), (3 * c_dofs1D * c_dofs1D * o_dofs1D), NE); + + constexpr static int MAX_D1D = HCURL_MAX_D1D; + MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, ""); + + MFEM_FORALL(e, NE, + { + double w1[MAX_D1D][MAX_D1D][MAX_D1D]; + double w2[MAX_D1D][MAX_D1D][MAX_D1D]; + + // --- + // dofs that point parallel to x-axis (open in x, closed in y, z) + // --- + + // contract in z + for (int ez = 0; ez < c_dofs1D; ++ez) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + for (int dy = 0; dy < c_dofs1D; ++dy) + { + w1[dx][dy][ez] = 0.0; + for (int dz = 0; dz < c_dofs1D; ++dz) + { + w1[dx][dy][ez] += B(ez, dz) * x(dx, dy, dz, e); + } + } + } + } + + // contract in y + for (int ez = 0; ez < c_dofs1D; ++ez) + { + for (int ey = 0; ey < c_dofs1D; ++ey) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + w2[dx][ey][ez] = 0.0; + for (int dy = 0; dy < c_dofs1D; ++dy) + { + w2[dx][ey][ez] += B(ey, dy) * w1[dx][dy][ez]; + } + } + } + } + + // contract in x + for (int ez = 0; ez < c_dofs1D; ++ez) + { + for (int ey = 0; ey < c_dofs1D; ++ey) + { + for (int ex = 0; ex < o_dofs1D; ++ex) + { + double s = 0.0; + for (int dx = 0; dx < c_dofs1D; ++dx) + { + s += G(ex, dx) * w2[dx][ey][ez]; + } + const int local_index = ez*c_dofs1D*o_dofs1D + ey*o_dofs1D + ex; + y(local_index, e) += s; + } + } + } + + // --- + // dofs that point parallel to y-axis (open in y, closed in x, z) + // --- + + // contract in z + for (int ez = 0; ez < c_dofs1D; ++ez) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + for (int dy = 0; dy < c_dofs1D; ++dy) + { + w1[dx][dy][ez] = 0.0; + for (int dz = 0; dz < c_dofs1D; ++dz) + { + w1[dx][dy][ez] += B(ez, dz) * x(dx, dy, dz, e); + } + } + } + } + + // contract in y + for (int ez = 0; ez < c_dofs1D; ++ez) + { + for (int ey = 0; ey < o_dofs1D; ++ey) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + w2[dx][ey][ez] = 0.0; + for (int dy = 0; dy < c_dofs1D; ++dy) + { + w2[dx][ey][ez] += G(ey, dy) * w1[dx][dy][ez]; + } + } + } + } + + // contract in x + for (int ez = 0; ez < c_dofs1D; ++ez) + { + for (int ey = 0; ey < o_dofs1D; ++ey) + { + for (int ex = 0; ex < c_dofs1D; ++ex) + { + double s = 0.0; + for (int dx = 0; dx < c_dofs1D; ++dx) + { + s += B(ex, dx) * w2[dx][ey][ez]; + } + const int local_index = c_dofs1D*c_dofs1D*o_dofs1D + + ez*c_dofs1D*o_dofs1D + ey*c_dofs1D + ex; + y(local_index, e) += s; + } + } + } + + // --- + // dofs that point parallel to z-axis (open in z, closed in x, y) + // --- + + // contract in z + for (int ez = 0; ez < o_dofs1D; ++ez) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + for (int dy = 0; dy < c_dofs1D; ++dy) + { + w1[dx][dy][ez] = 0.0; + for (int dz = 0; dz < c_dofs1D; ++dz) + { + w1[dx][dy][ez] += G(ez, dz) * x(dx, dy, dz, e); + } + } + } + } + + // contract in y + for (int ez = 0; ez < o_dofs1D; ++ez) + { + for (int ey = 0; ey < c_dofs1D; ++ey) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + w2[dx][ey][ez] = 0.0; + for (int dy = 0; dy < c_dofs1D; ++dy) + { + w2[dx][ey][ez] += B(ey, dy) * w1[dx][dy][ez]; + } + } + } + } + + // contract in x + for (int ez = 0; ez < o_dofs1D; ++ez) + { + for (int ey = 0; ey < c_dofs1D; ++ey) + { + for (int ex = 0; ex < c_dofs1D; ++ex) + { + double s = 0.0; + for (int dx = 0; dx < c_dofs1D; ++dx) + { + s += B(ex, dx) * w2[dx][ey][ez]; + } + const int local_index = 2*c_dofs1D*c_dofs1D*o_dofs1D + + ez*c_dofs1D*c_dofs1D + ey*c_dofs1D + ex; + y(local_index, e) += s; + } + } + } + }); +} + +// Specialization of PAHcurlApplyGradient3D to the case where +static void PAHcurlApplyGradient3DBId(const int c_dofs1D, + const int o_dofs1D, + const int NE, + const Array &G_, + const Vector &x_, + Vector &y_) +{ + auto G = Reshape(G_.Read(), o_dofs1D, c_dofs1D); + + auto x = Reshape(x_.Read(), c_dofs1D, c_dofs1D, c_dofs1D, NE); + auto y = Reshape(y_.ReadWrite(), (3 * c_dofs1D * c_dofs1D * o_dofs1D), NE); + + constexpr static int MAX_D1D = HCURL_MAX_D1D; + MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, ""); + + MFEM_FORALL(e, NE, + { + double w1[MAX_D1D][MAX_D1D][MAX_D1D]; + double w2[MAX_D1D][MAX_D1D][MAX_D1D]; + + // --- + // dofs that point parallel to x-axis (open in x, closed in y, z) + // --- + + // contract in z + for (int ez = 0; ez < c_dofs1D; ++ez) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + for (int dy = 0; dy < c_dofs1D; ++dy) + { + const int dz = ez; + w1[dx][dy][ez] = x(dx, dy, dz, e); + } + } + } + + // contract in y + for (int ez = 0; ez < c_dofs1D; ++ez) + { + for (int ey = 0; ey < c_dofs1D; ++ey) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + const int dy = ey; + w2[dx][ey][ez] = w1[dx][dy][ez]; + } + } + } + + // contract in x + for (int ez = 0; ez < c_dofs1D; ++ez) + { + for (int ey = 0; ey < c_dofs1D; ++ey) + { + for (int ex = 0; ex < o_dofs1D; ++ex) + { + double s = 0.0; + for (int dx = 0; dx < c_dofs1D; ++dx) + { + s += G(ex, dx) * w2[dx][ey][ez]; + } + const int local_index = ez*c_dofs1D*o_dofs1D + ey*o_dofs1D + ex; + y(local_index, e) += s; + } + } + } + + // --- + // dofs that point parallel to y-axis (open in y, closed in x, z) + // --- + + // contract in z + for (int ez = 0; ez < c_dofs1D; ++ez) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + for (int dy = 0; dy < c_dofs1D; ++dy) + { + const int dz = ez; + w1[dx][dy][ez] = x(dx, dy, dz, e); + } + } + } + + // contract in y + for (int ez = 0; ez < c_dofs1D; ++ez) + { + for (int ey = 0; ey < o_dofs1D; ++ey) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + w2[dx][ey][ez] = 0.0; + for (int dy = 0; dy < c_dofs1D; ++dy) + { + w2[dx][ey][ez] += G(ey, dy) * w1[dx][dy][ez]; + } + } + } + } + + // contract in x + for (int ez = 0; ez < c_dofs1D; ++ez) + { + for (int ey = 0; ey < o_dofs1D; ++ey) + { + for (int ex = 0; ex < c_dofs1D; ++ex) + { + const int dx = ex; + const double s = w2[dx][ey][ez]; + const int local_index = c_dofs1D*c_dofs1D*o_dofs1D + + ez*c_dofs1D*o_dofs1D + ey*c_dofs1D + ex; + y(local_index, e) += s; + } + } + } + + // --- + // dofs that point parallel to z-axis (open in z, closed in x, y) + // --- + + // contract in z + for (int ez = 0; ez < o_dofs1D; ++ez) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + for (int dy = 0; dy < c_dofs1D; ++dy) + { + w1[dx][dy][ez] = 0.0; + for (int dz = 0; dz < c_dofs1D; ++dz) + { + w1[dx][dy][ez] += G(ez, dz) * x(dx, dy, dz, e); + } + } + } + } + + // contract in y + for (int ez = 0; ez < o_dofs1D; ++ez) + { + for (int ey = 0; ey < c_dofs1D; ++ey) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + const int dy = ey; + w2[dx][ey][ez] = w1[dx][dy][ez]; + } + } + } + + // contract in x + for (int ez = 0; ez < o_dofs1D; ++ez) + { + for (int ey = 0; ey < c_dofs1D; ++ey) + { + for (int ex = 0; ex < c_dofs1D; ++ex) + { + const int dx = ex; + const double s = w2[dx][ey][ez]; + const int local_index = 2*c_dofs1D*c_dofs1D*o_dofs1D + + ez*c_dofs1D*c_dofs1D + ey*c_dofs1D + ex; + y(local_index, e) += s; + } + } + } + }); +} + +static void PAHcurlApplyGradientTranspose3D( + const int c_dofs1D, const int o_dofs1D, const int NE, + const Array &B_, const Array &G_, + const Vector &x_, Vector &y_) +{ + auto B = Reshape(B_.Read(), c_dofs1D, c_dofs1D); + auto G = Reshape(G_.Read(), o_dofs1D, c_dofs1D); + + auto x = Reshape(x_.Read(), (3 * c_dofs1D * c_dofs1D * o_dofs1D), NE); + auto y = Reshape(y_.ReadWrite(), c_dofs1D, c_dofs1D, c_dofs1D, NE); + + constexpr static int MAX_D1D = HCURL_MAX_D1D; + MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, ""); + + MFEM_FORALL(e, NE, + { + double w1[MAX_D1D][MAX_D1D][MAX_D1D]; + double w2[MAX_D1D][MAX_D1D][MAX_D1D]; + // --- + // dofs that point parallel to x-axis (open in x, closed in y, z) + // --- + + // contract in z + for (int dz = 0; dz < c_dofs1D; ++dz) + { + for (int ex = 0; ex < o_dofs1D; ++ex) + { + for (int ey = 0; ey < c_dofs1D; ++ey) + { + w1[ex][ey][dz] = 0.0; + for (int ez = 0; ez < c_dofs1D; ++ez) + { + const int local_index = ez*c_dofs1D*o_dofs1D + ey*o_dofs1D + ex; + w1[ex][ey][dz] += B(ez, dz) * x(local_index, e); + } + } + } + } + + // contract in y + for (int dz = 0; dz < c_dofs1D; ++dz) + { + for (int dy = 0; dy < c_dofs1D; ++dy) + { + for (int ex = 0; ex < o_dofs1D; ++ex) + { + w2[ex][dy][dz] = 0.0; + for (int ey = 0; ey < c_dofs1D; ++ey) + { + w2[ex][dy][dz] += B(ey, dy) * w1[ex][ey][dz]; + } + } + } + } + + // contract in x + for (int dz = 0; dz < c_dofs1D; ++dz) + { + for (int dy = 0; dy < c_dofs1D; ++dy) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + double s = 0.0; + for (int ex = 0; ex < o_dofs1D; ++ex) + { + s += G(ex, dx) * w2[ex][dy][dz]; + } + y(dx, dy, dz, e) += s; + } + } + } + + // --- + // dofs that point parallel to y-axis (open in y, closed in x, z) + // --- + + // contract in z + for (int dz = 0; dz < c_dofs1D; ++dz) + { + for (int ex = 0; ex < c_dofs1D; ++ex) + { + for (int ey = 0; ey < o_dofs1D; ++ey) + { + w1[ex][ey][dz] = 0.0; + for (int ez = 0; ez < c_dofs1D; ++ez) + { + const int local_index = c_dofs1D*c_dofs1D*o_dofs1D + + ez*c_dofs1D*o_dofs1D + ey*c_dofs1D + ex; + w1[ex][ey][dz] += B(ez, dz) * x(local_index, e); + } + } + } + } + + // contract in y + for (int dz = 0; dz < c_dofs1D; ++dz) + { + for (int dy = 0; dy < c_dofs1D; ++dy) + { + for (int ex = 0; ex < c_dofs1D; ++ex) + { + w2[ex][dy][dz] = 0.0; + for (int ey = 0; ey < o_dofs1D; ++ey) + { + w2[ex][dy][dz] += G(ey, dy) * w1[ex][ey][dz]; + } + } + } + } + + // contract in x + for (int dz = 0; dz < c_dofs1D; ++dz) + { + for (int dy = 0; dy < c_dofs1D; ++dy) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + double s = 0.0; + for (int ex = 0; ex < c_dofs1D; ++ex) + { + s += B(ex, dx) * w2[ex][dy][dz]; + } + y(dx, dy, dz, e) += s; + } + } + } + + // --- + // dofs that point parallel to z-axis (open in z, closed in x, y) + // --- + + // contract in z + for (int dz = 0; dz < c_dofs1D; ++dz) + { + for (int ex = 0; ex < c_dofs1D; ++ex) + { + for (int ey = 0; ey < c_dofs1D; ++ey) + { + w1[ex][ey][dz] = 0.0; + for (int ez = 0; ez < o_dofs1D; ++ez) + { + const int local_index = 2*c_dofs1D*c_dofs1D*o_dofs1D + + ez*c_dofs1D*c_dofs1D + ey*c_dofs1D + ex; + w1[ex][ey][dz] += G(ez, dz) * x(local_index, e); + } + } + } + } + + // contract in y + for (int dz = 0; dz < c_dofs1D; ++dz) + { + for (int dy = 0; dy < c_dofs1D; ++dy) + { + for (int ex = 0; ex < c_dofs1D; ++ex) + { + w2[ex][dy][dz] = 0.0; + for (int ey = 0; ey < c_dofs1D; ++ey) + { + w2[ex][dy][dz] += B(ey, dy) * w1[ex][ey][dz]; + } + } + } + } + + // contract in x + for (int dz = 0; dz < c_dofs1D; ++dz) + { + for (int dy = 0; dy < c_dofs1D; ++dy) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + double s = 0.0; + for (int ex = 0; ex < c_dofs1D; ++ex) + { + s += B(ex, dx) * w2[ex][dy][dz]; + } + y(dx, dy, dz, e) += s; + } + } + } + }); +} + +// Specialization of PAHcurlApplyGradientTranspose3D to the case where +static void PAHcurlApplyGradientTranspose3DBId( + const int c_dofs1D, const int o_dofs1D, const int NE, + const Array &G_, + const Vector &x_, Vector &y_) +{ + auto G = Reshape(G_.Read(), o_dofs1D, c_dofs1D); + + auto x = Reshape(x_.Read(), (3 * c_dofs1D * c_dofs1D * o_dofs1D), NE); + auto y = Reshape(y_.ReadWrite(), c_dofs1D, c_dofs1D, c_dofs1D, NE); + + constexpr static int MAX_D1D = HCURL_MAX_D1D; + MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, ""); + + MFEM_FORALL(e, NE, + { + double w1[MAX_D1D][MAX_D1D][MAX_D1D]; + double w2[MAX_D1D][MAX_D1D][MAX_D1D]; + // --- + // dofs that point parallel to x-axis (open in x, closed in y, z) + // --- + + // contract in z + for (int dz = 0; dz < c_dofs1D; ++dz) + { + for (int ex = 0; ex < o_dofs1D; ++ex) + { + for (int ey = 0; ey < c_dofs1D; ++ey) + { + const int ez = dz; + const int local_index = ez*c_dofs1D*o_dofs1D + ey*o_dofs1D + ex; + w1[ex][ey][dz] = x(local_index, e); + } + } + } + + // contract in y + for (int dz = 0; dz < c_dofs1D; ++dz) + { + for (int dy = 0; dy < c_dofs1D; ++dy) + { + for (int ex = 0; ex < o_dofs1D; ++ex) + { + const int ey = dy; + w2[ex][dy][dz] = w1[ex][ey][dz]; + } + } + } + + // contract in x + for (int dz = 0; dz < c_dofs1D; ++dz) + { + for (int dy = 0; dy < c_dofs1D; ++dy) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + double s = 0.0; + for (int ex = 0; ex < o_dofs1D; ++ex) + { + s += G(ex, dx) * w2[ex][dy][dz]; + } + y(dx, dy, dz, e) += s; + } + } + } + + // --- + // dofs that point parallel to y-axis (open in y, closed in x, z) + // --- + + // contract in z + for (int dz = 0; dz < c_dofs1D; ++dz) + { + for (int ex = 0; ex < c_dofs1D; ++ex) + { + for (int ey = 0; ey < o_dofs1D; ++ey) + { + const int ez = dz; + const int local_index = c_dofs1D*c_dofs1D*o_dofs1D + + ez*c_dofs1D*o_dofs1D + ey*c_dofs1D + ex; + w1[ex][ey][dz] = x(local_index, e); + } + } + } + + // contract in y + for (int dz = 0; dz < c_dofs1D; ++dz) + { + for (int dy = 0; dy < c_dofs1D; ++dy) + { + for (int ex = 0; ex < c_dofs1D; ++ex) + { + w2[ex][dy][dz] = 0.0; + for (int ey = 0; ey < o_dofs1D; ++ey) + { + w2[ex][dy][dz] += G(ey, dy) * w1[ex][ey][dz]; + } + } + } + } + + // contract in x + for (int dz = 0; dz < c_dofs1D; ++dz) + { + for (int dy = 0; dy < c_dofs1D; ++dy) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + const int ex = dx; + double s = w2[ex][dy][dz]; + y(dx, dy, dz, e) += s; + } + } + } + + // --- + // dofs that point parallel to z-axis (open in z, closed in x, y) + // --- + + // contract in z + for (int dz = 0; dz < c_dofs1D; ++dz) + { + for (int ex = 0; ex < c_dofs1D; ++ex) + { + for (int ey = 0; ey < c_dofs1D; ++ey) + { + w1[ex][ey][dz] = 0.0; + for (int ez = 0; ez < o_dofs1D; ++ez) + { + const int local_index = 2*c_dofs1D*c_dofs1D*o_dofs1D + + ez*c_dofs1D*c_dofs1D + ey*c_dofs1D + ex; + w1[ex][ey][dz] += G(ez, dz) * x(local_index, e); + } + } + } + } + + // contract in y + for (int dz = 0; dz < c_dofs1D; ++dz) + { + for (int dy = 0; dy < c_dofs1D; ++dy) + { + for (int ex = 0; ex < c_dofs1D; ++ex) + { + const int ey = dy; + w2[ex][dy][dz] = w1[ex][ey][dz]; + } + } + } + + // contract in x + for (int dz = 0; dz < c_dofs1D; ++dz) + { + for (int dy = 0; dy < c_dofs1D; ++dy) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + const int ex = dx; + double s = w2[ex][dy][dz]; + y(dx, dy, dz, e) += s; + } + } + } + }); +} + +void GradientInterpolator::AssemblePA(const FiniteElementSpace &trial_fes, + const FiniteElementSpace &test_fes) +{ + // Assumes tensor-product elements, with a vector test space and H^1 trial space. + Mesh *mesh = trial_fes.GetMesh(); + const FiniteElement *trial_fel = trial_fes.GetFE(0); + const FiniteElement *test_fel = test_fes.GetFE(0); + + const NodalTensorFiniteElement *trial_el = + dynamic_cast(trial_fel); + MFEM_VERIFY(trial_el != NULL, "Only NodalTensorFiniteElement is supported!"); + + const VectorTensorFiniteElement *test_el = + dynamic_cast(test_fel); + MFEM_VERIFY(test_el != NULL, "Only VectorTensorFiniteElement is supported!"); + + const int dims = trial_el->GetDim(); + MFEM_VERIFY(dims == 2 || dims == 3, "Bad dimension!"); + dim = mesh->Dimension(); + MFEM_VERIFY(dim == 2 || dim == 3, "Bad dimension!"); + MFEM_VERIFY(trial_el->GetOrder() == test_el->GetOrder(), + "Orders do not match!"); + ne = trial_fes.GetNE(); + + const int order = trial_el->GetOrder(); + dofquad_fe = new H1_SegmentElement(order, trial_el->GetBasisType()); + mfem::QuadratureFunctions1D qf1d; + mfem::IntegrationRule closed_ir; + closed_ir.SetSize(order + 1); + qf1d.GaussLobatto(order + 1, &closed_ir); + mfem::IntegrationRule open_ir; + open_ir.SetSize(order); + qf1d.GaussLegendre(order, &open_ir); + + maps_O_C = &dofquad_fe->GetDofToQuad(open_ir, DofToQuad::TENSOR); + o_dofs1D = maps_O_C->nqpt; + if (trial_el->GetBasisType() == BasisType::GaussLobatto) + { + B_id = true; + c_dofs1D = maps_O_C->ndof; + } + else + { + B_id = false; + maps_C_C = &dofquad_fe->GetDofToQuad(closed_ir, DofToQuad::TENSOR); + c_dofs1D = maps_C_C->nqpt; + } +} + +void GradientInterpolator::AddMultPA(const Vector &x, Vector &y) const +{ + if (dim == 3) + { + if (B_id) + { + PAHcurlApplyGradient3DBId(c_dofs1D, o_dofs1D, ne, + maps_O_C->G, x, y); + } + else + { + PAHcurlApplyGradient3D(c_dofs1D, o_dofs1D, ne, maps_C_C->B, + maps_O_C->G, x, y); + } + } + else if (dim == 2) + { + if (B_id) + { + PAHcurlApplyGradient2DBId(c_dofs1D, o_dofs1D, ne, + maps_O_C->G, x, y); + } + else + { + PAHcurlApplyGradient2D(c_dofs1D, o_dofs1D, ne, maps_C_C->B, maps_O_C->G, + x, y); + } + } + else + { + mfem_error("Bad dimension!"); + } +} + +void GradientInterpolator::AddMultTransposePA(const Vector &x, Vector &y) const +{ + if (dim == 3) + { + if (B_id) + { + PAHcurlApplyGradientTranspose3DBId(c_dofs1D, o_dofs1D, ne, + maps_O_C->G, x, y); + } + else + { + PAHcurlApplyGradientTranspose3D(c_dofs1D, o_dofs1D, ne, maps_C_C->B, + maps_O_C->G, x, y); + } + } + else if (dim == 2) + { + if (B_id) + { + PAHcurlApplyGradientTranspose2DBId(c_dofs1D, o_dofs1D, ne, + maps_O_C->G, x, y); + } + else + { + PAHcurlApplyGradientTranspose2D(c_dofs1D, o_dofs1D, ne, maps_C_C->B, + maps_O_C->G, x, y); + } + } + else + { + mfem_error("Bad dimension!"); + } +} + +static void PAHcurlVecH1IdentityApply3D(const int c_dofs1D, + const int o_dofs1D, + const int NE, + const Array &Bclosed, + const Array &Bopen, + const Vector &pa_data, + const Vector &x_, + Vector &y_) +{ + auto Bc = Reshape(Bclosed.Read(), c_dofs1D, c_dofs1D); + auto Bo = Reshape(Bopen.Read(), o_dofs1D, c_dofs1D); + + auto x = Reshape(x_.Read(), c_dofs1D, c_dofs1D, c_dofs1D, 3, NE); + auto y = Reshape(y_.ReadWrite(), (3 * c_dofs1D * c_dofs1D * o_dofs1D), NE); + + auto vk = Reshape(pa_data.Read(), 3, (3 * c_dofs1D * c_dofs1D * o_dofs1D), + NE); + + constexpr static int MAX_D1D = HCURL_MAX_D1D; + MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, ""); + + MFEM_FORALL(e, NE, + { + double w1[3][MAX_D1D][MAX_D1D][MAX_D1D]; + double w2[3][MAX_D1D][MAX_D1D][MAX_D1D]; + + // dofs that point parallel to x-axis (open in x, closed in y, z) + + // contract in z + for (int ez = 0; ez < c_dofs1D; ++ez) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + for (int dy = 0; dy < c_dofs1D; ++dy) + { + for (int j=0; j<3; ++j) + { + w1[j][dx][dy][ez] = 0.0; + for (int dz = 0; dz < c_dofs1D; ++dz) + { + w1[j][dx][dy][ez] += Bc(ez, dz) * x(dx, dy, dz, j, e); + } + } + } + } + } + + // contract in y + for (int ez = 0; ez < c_dofs1D; ++ez) + { + for (int ey = 0; ey < c_dofs1D; ++ey) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + for (int j=0; j<3; ++j) + { + w2[j][dx][ey][ez] = 0.0; + for (int dy = 0; dy < c_dofs1D; ++dy) + { + w2[j][dx][ey][ez] += Bc(ey, dy) * w1[j][dx][dy][ez]; + } + } + } + } + } + + // contract in x + for (int ez = 0; ez < c_dofs1D; ++ez) + { + for (int ey = 0; ey < c_dofs1D; ++ey) + { + for (int ex = 0; ex < o_dofs1D; ++ex) + { + for (int j=0; j<3; ++j) + { + double s = 0.0; + for (int dx = 0; dx < c_dofs1D; ++dx) + { + s += Bo(ex, dx) * w2[j][dx][ey][ez]; + } + const int local_index = ez*c_dofs1D*o_dofs1D + ey*o_dofs1D + ex; + y(local_index, e) += s * vk(j, local_index, e); + } + } + } + } + + // dofs that point parallel to y-axis (open in y, closed in x, z) + + // contract in z + for (int ez = 0; ez < c_dofs1D; ++ez) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + for (int dy = 0; dy < c_dofs1D; ++dy) + { + for (int j=0; j<3; ++j) + { + w1[j][dx][dy][ez] = 0.0; + for (int dz = 0; dz < c_dofs1D; ++dz) + { + w1[j][dx][dy][ez] += Bc(ez, dz) * x(dx, dy, dz, j, e); + } + } + } + } + } + + // contract in y + for (int ez = 0; ez < c_dofs1D; ++ez) + { + for (int ey = 0; ey < o_dofs1D; ++ey) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + for (int j=0; j<3; ++j) + { + w2[j][dx][ey][ez] = 0.0; + for (int dy = 0; dy < c_dofs1D; ++dy) + { + w2[j][dx][ey][ez] += Bo(ey, dy) * w1[j][dx][dy][ez]; + } + } + } + } + } + + // contract in x + for (int ez = 0; ez < c_dofs1D; ++ez) + { + for (int ey = 0; ey < o_dofs1D; ++ey) + { + for (int ex = 0; ex < c_dofs1D; ++ex) + { + for (int j=0; j<3; ++j) + { + double s = 0.0; + for (int dx = 0; dx < c_dofs1D; ++dx) + { + s += Bc(ex, dx) * w2[j][dx][ey][ez]; + } + const int local_index = c_dofs1D*c_dofs1D*o_dofs1D + + ez*c_dofs1D*o_dofs1D + ey*c_dofs1D + ex; + y(local_index, e) += s * vk(j, local_index, e); + } + } + } + } + + // dofs that point parallel to z-axis (open in z, closed in x, y) + + // contract in z + for (int ez = 0; ez < o_dofs1D; ++ez) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + for (int dy = 0; dy < c_dofs1D; ++dy) + { + for (int j=0; j<3; ++j) + { + w1[j][dx][dy][ez] = 0.0; + for (int dz = 0; dz < c_dofs1D; ++dz) + { + w1[j][dx][dy][ez] += Bo(ez, dz) * x(dx, dy, dz, j, e); + } + } + } + } + } + + // contract in y + for (int ez = 0; ez < o_dofs1D; ++ez) + { + for (int ey = 0; ey < c_dofs1D; ++ey) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + for (int j=0; j<3; ++j) + { + w2[j][dx][ey][ez] = 0.0; + for (int dy = 0; dy < c_dofs1D; ++dy) + { + w2[j][dx][ey][ez] += Bc(ey, dy) * w1[j][dx][dy][ez]; + } + } + } + } + } + + // contract in x + for (int ez = 0; ez < o_dofs1D; ++ez) + { + for (int ey = 0; ey < c_dofs1D; ++ey) + { + for (int ex = 0; ex < c_dofs1D; ++ex) + { + for (int j=0; j<3; ++j) + { + double s = 0.0; + for (int dx = 0; dx < c_dofs1D; ++dx) + { + s += Bc(ex, dx) * w2[j][dx][ey][ez]; + } + const int local_index = 2*c_dofs1D*c_dofs1D*o_dofs1D + + ez*c_dofs1D*c_dofs1D + ey*c_dofs1D + ex; + y(local_index, e) += s * vk(j, local_index, e); + } + } + } + } + }); +} + +static void PAHcurlVecH1IdentityApplyTranspose3D(const int c_dofs1D, + const int o_dofs1D, + const int NE, + const Array &Bclosed, + const Array &Bopen, + const Vector &pa_data, + const Vector &x_, + Vector &y_) +{ + auto Bc = Reshape(Bclosed.Read(), c_dofs1D, c_dofs1D); + auto Bo = Reshape(Bopen.Read(), o_dofs1D, c_dofs1D); + + auto x = Reshape(x_.Read(), (3 * c_dofs1D * c_dofs1D * o_dofs1D), NE); + auto y = Reshape(y_.ReadWrite(), c_dofs1D, c_dofs1D, c_dofs1D, 3, NE); + + auto vk = Reshape(pa_data.Read(), 3, (3 * c_dofs1D * c_dofs1D * o_dofs1D), + NE); + + constexpr static int MAX_D1D = HCURL_MAX_D1D; + + MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, ""); + + MFEM_FORALL(e, NE, + { + double w1[3][MAX_D1D][MAX_D1D][MAX_D1D]; + double w2[3][MAX_D1D][MAX_D1D][MAX_D1D]; + + // dofs that point parallel to x-axis (open in x, closed in y, z) + + // contract in x + for (int ez = 0; ez < c_dofs1D; ++ez) + { + for (int ey = 0; ey < c_dofs1D; ++ey) + { + for (int j=0; j<3; ++j) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + w2[j][dx][ey][ez] = 0.0; + } + for (int ex = 0; ex < o_dofs1D; ++ex) + { + const int local_index = ez*c_dofs1D*o_dofs1D + ey*o_dofs1D + ex; + const double xv = x(local_index, e) * vk(j, local_index, e); + for (int dx = 0; dx < c_dofs1D; ++dx) + { + w2[j][dx][ey][ez] += xv * Bo(ex, dx); + } + } + } + } + } + + // contract in y + for (int ez = 0; ez < c_dofs1D; ++ez) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + for (int dy = 0; dy < c_dofs1D; ++dy) + { + for (int j=0; j<3; ++j) + { + w1[j][dx][dy][ez] = 0.0; + for (int ey = 0; ey < c_dofs1D; ++ey) + { + w1[j][dx][dy][ez] += w2[j][dx][ey][ez] * Bc(ey, dy); + } + } + } + } + } + + // contract in z + for (int dx = 0; dx < c_dofs1D; ++dx) + { + for (int dy = 0; dy < c_dofs1D; ++dy) + { + for (int dz = 0; dz < c_dofs1D; ++dz) + { + for (int j=0; j<3; ++j) + { + double s = 0.0; + for (int ez = 0; ez < c_dofs1D; ++ez) + { + s += w1[j][dx][dy][ez] * Bc(ez, dz); + } + y(dx, dy, dz, j, e) += s; + } + } + } + } + + // dofs that point parallel to y-axis (open in y, closed in x, z) + + // contract in x + for (int ez = 0; ez < c_dofs1D; ++ez) + { + for (int ey = 0; ey < o_dofs1D; ++ey) + { + for (int j=0; j<3; ++j) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + w2[j][dx][ey][ez] = 0.0; + } + for (int ex = 0; ex < c_dofs1D; ++ex) + { + const int local_index = c_dofs1D*c_dofs1D*o_dofs1D + + ez*c_dofs1D*o_dofs1D + ey*c_dofs1D + ex; + const double xv = x(local_index, e) * vk(j, local_index, e); + for (int dx = 0; dx < c_dofs1D; ++dx) + { + w2[j][dx][ey][ez] += xv * Bc(ex, dx); + } + } + } + } + } + + // contract in y + for (int ez = 0; ez < c_dofs1D; ++ez) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + for (int dy = 0; dy < c_dofs1D; ++dy) + { + for (int j=0; j<3; ++j) + { + w1[j][dx][dy][ez] = 0.0; + for (int ey = 0; ey < o_dofs1D; ++ey) + { + w1[j][dx][dy][ez] += w2[j][dx][ey][ez] * Bo(ey, dy); + } + } + } + } + } + + // contract in z + for (int dx = 0; dx < c_dofs1D; ++dx) + { + for (int dy = 0; dy < c_dofs1D; ++dy) + { + for (int dz = 0; dz < c_dofs1D; ++dz) + { + for (int j=0; j<3; ++j) + { + double s = 0.0; + for (int ez = 0; ez < c_dofs1D; ++ez) + { + s += w1[j][dx][dy][ez] * Bc(ez, dz); + } + y(dx, dy, dz, j, e) += s; + } + } + } + } + + // dofs that point parallel to z-axis (open in z, closed in x, y) + + // contract in x + for (int ez = 0; ez < o_dofs1D; ++ez) + { + for (int ey = 0; ey < c_dofs1D; ++ey) + { + for (int j=0; j<3; ++j) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + w2[j][dx][ey][ez] = 0.0; + } + for (int ex = 0; ex < c_dofs1D; ++ex) + { + const int local_index = 2*c_dofs1D*c_dofs1D*o_dofs1D + + ez*c_dofs1D*c_dofs1D + ey*c_dofs1D + ex; + const double xv = x(local_index, e) * vk(j, local_index, e); + for (int dx = 0; dx < c_dofs1D; ++dx) + { + w2[j][dx][ey][ez] += xv * Bc(ex, dx); + } + } + } + } + } + + // contract in y + for (int ez = 0; ez < o_dofs1D; ++ez) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + for (int dy = 0; dy < c_dofs1D; ++dy) + { + for (int j=0; j<3; ++j) + { + w1[j][dx][dy][ez] = 0.0; + for (int ey = 0; ey < c_dofs1D; ++ey) + { + w1[j][dx][dy][ez] += w2[j][dx][ey][ez] * Bc(ey, dy); + } + } + } + } + } + + // contract in z + for (int dx = 0; dx < c_dofs1D; ++dx) + { + for (int dy = 0; dy < c_dofs1D; ++dy) + { + for (int dz = 0; dz < c_dofs1D; ++dz) + { + for (int j=0; j<3; ++j) + { + double s = 0.0; + for (int ez = 0; ez < o_dofs1D; ++ez) + { + s += w1[j][dx][dy][ez] * Bo(ez, dz); + } + y(dx, dy, dz, j, e) += s; + } + } + } + } + }); +} + +static void PAHcurlVecH1IdentityApply2D(const int c_dofs1D, + const int o_dofs1D, + const int NE, + const Array &Bclosed, + const Array &Bopen, + const Vector &pa_data, + const Vector &x_, + Vector &y_) +{ + auto Bc = Reshape(Bclosed.Read(), c_dofs1D, c_dofs1D); + auto Bo = Reshape(Bopen.Read(), o_dofs1D, c_dofs1D); + + auto x = Reshape(x_.Read(), c_dofs1D, c_dofs1D, 2, NE); + auto y = Reshape(y_.ReadWrite(), (2 * c_dofs1D * o_dofs1D), NE); + + auto vk = Reshape(pa_data.Read(), 2, (2 * c_dofs1D * o_dofs1D), NE); + + constexpr static int MAX_D1D = HCURL_MAX_D1D; + + MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, ""); + + MFEM_FORALL(e, NE, + { + double w[2][MAX_D1D][MAX_D1D]; + + // dofs that point parallel to x-axis (open in x, closed in y) + + // contract in y + for (int ey = 0; ey < c_dofs1D; ++ey) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + for (int j=0; j<2; ++j) + { + w[j][dx][ey] = 0.0; + for (int dy = 0; dy < c_dofs1D; ++dy) + { + w[j][dx][ey] += Bc(ey, dy) * x(dx, dy, j, e); + } + } + } + } + + // contract in x + for (int ey = 0; ey < c_dofs1D; ++ey) + { + for (int ex = 0; ex < o_dofs1D; ++ex) + { + for (int j=0; j<2; ++j) + { + double s = 0.0; + for (int dx = 0; dx < c_dofs1D; ++dx) + { + s += Bo(ex, dx) * w[j][dx][ey]; + } + const int local_index = ey*o_dofs1D + ex; + y(local_index, e) += s * vk(j, local_index, e); + } + } + } + + // dofs that point parallel to y-axis (open in y, closed in x) + + // contract in y + for (int ey = 0; ey < o_dofs1D; ++ey) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + for (int j=0; j<2; ++j) + { + w[j][dx][ey] = 0.0; + for (int dy = 0; dy < c_dofs1D; ++dy) + { + w[j][dx][ey] += Bo(ey, dy) * x(dx, dy, j, e); + } + } + } + } + + // contract in x + for (int ey = 0; ey < o_dofs1D; ++ey) + { + for (int ex = 0; ex < c_dofs1D; ++ex) + { + for (int j=0; j<2; ++j) + { + double s = 0.0; + for (int dx = 0; dx < c_dofs1D; ++dx) + { + s += Bc(ex, dx) * w[j][dx][ey]; + } + const int local_index = c_dofs1D*o_dofs1D + ey*c_dofs1D + ex; + y(local_index, e) += s * vk(j, local_index, e); + } + } + } + }); +} + +static void PAHcurlVecH1IdentityApplyTranspose2D(const int c_dofs1D, + const int o_dofs1D, + const int NE, + const Array &Bclosed, + const Array &Bopen, + const Vector &pa_data, + const Vector &x_, + Vector &y_) +{ + auto Bc = Reshape(Bclosed.Read(), c_dofs1D, c_dofs1D); + auto Bo = Reshape(Bopen.Read(), o_dofs1D, c_dofs1D); + + auto x = Reshape(x_.Read(), (2 * c_dofs1D * o_dofs1D), NE); + auto y = Reshape(y_.ReadWrite(), c_dofs1D, c_dofs1D, 2, NE); + + auto vk = Reshape(pa_data.Read(), 2, (2 * c_dofs1D * o_dofs1D), NE); + + constexpr static int MAX_D1D = HCURL_MAX_D1D; + //constexpr static int MAX_Q1D = HCURL_MAX_Q1D; + + MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, ""); + + MFEM_FORALL(e, NE, + { + double w[2][MAX_D1D][MAX_D1D]; + + // dofs that point parallel to x-axis (open in x, closed in y) + + // contract in x + for (int ey = 0; ey < c_dofs1D; ++ey) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + for (int j=0; j<2; ++j) { w[j][dx][ey] = 0.0; } + } + for (int ex = 0; ex < o_dofs1D; ++ex) + { + const int local_index = ey*o_dofs1D + ex; + const double xd = x(local_index, e); + + for (int dx = 0; dx < c_dofs1D; ++dx) + { + for (int j=0; j<2; ++j) + { + w[j][dx][ey] += Bo(ex, dx) * xd * vk(j, local_index, e); + } + } + } + } + + // contract in y + for (int dx = 0; dx < c_dofs1D; ++dx) + { + for (int dy = 0; dy < c_dofs1D; ++dy) + { + for (int j=0; j<2; ++j) + { + double s = 0.0; + for (int ey = 0; ey < c_dofs1D; ++ey) + { + s += w[j][dx][ey] * Bc(ey, dy); + } + y(dx, dy, j, e) += s; + } + } + } + + // dofs that point parallel to y-axis (open in y, closed in x) + + // contract in x + for (int ey = 0; ey < o_dofs1D; ++ey) + { + for (int dx = 0; dx < c_dofs1D; ++dx) + { + for (int j=0; j<2; ++j) { w[j][dx][ey] = 0.0; } + } + for (int ex = 0; ex < c_dofs1D; ++ex) + { + const int local_index = c_dofs1D*o_dofs1D + ey*c_dofs1D + ex; + const double xd = x(local_index, e); + for (int dx = 0; dx < c_dofs1D; ++dx) + { + for (int j=0; j<2; ++j) + { + w[j][dx][ey] += Bc(ex, dx) * xd * vk(j, local_index, e); + } + } + } + } + + // contract in y + for (int dx = 0; dx < c_dofs1D; ++dx) + { + for (int dy = 0; dy < c_dofs1D; ++dy) + { + for (int j=0; j<2; ++j) + { + double s = 0.0; + for (int ey = 0; ey < o_dofs1D; ++ey) + { + s += w[j][dx][ey] * Bo(ey, dy); + } + y(dx, dy, j, e) += s; + } + } + } + }); +} + +void IdentityInterpolator::AssemblePA(const FiniteElementSpace &trial_fes, + const FiniteElementSpace &test_fes) +{ + // Assumes tensor-product elements, with a vector test space and H^1 trial space. + Mesh *mesh = trial_fes.GetMesh(); + const FiniteElement *trial_fel = trial_fes.GetFE(0); + const FiniteElement *test_fel = test_fes.GetFE(0); + + const NodalTensorFiniteElement *trial_el = + dynamic_cast(trial_fel); + MFEM_VERIFY(trial_el != NULL, "Only NodalTensorFiniteElement is supported!"); + + const VectorTensorFiniteElement *test_el = + dynamic_cast(test_fel); + MFEM_VERIFY(test_el != NULL, "Only VectorTensorFiniteElement is supported!"); + + const int dims = trial_el->GetDim(); + MFEM_VERIFY(dims == 2 || dims == 3, ""); + + dim = mesh->Dimension(); + MFEM_VERIFY(dim == 2 || dim == 3, ""); + + MFEM_VERIFY(trial_el->GetOrder() == test_el->GetOrder(), ""); + + ne = trial_fes.GetNE(); + + const int order = trial_el->GetOrder(); + dofquad_fe = new H1_SegmentElement(order); + mfem::QuadratureFunctions1D qf1d; + mfem::IntegrationRule closed_ir; + closed_ir.SetSize(order + 1); + qf1d.GaussLobatto(order + 1, &closed_ir); + mfem::IntegrationRule open_ir; + open_ir.SetSize(order); + qf1d.GaussLegendre(order, &open_ir); + + maps_C_C = &dofquad_fe->GetDofToQuad(closed_ir, DofToQuad::TENSOR); + maps_O_C = &dofquad_fe->GetDofToQuad(open_ir, DofToQuad::TENSOR); + + o_dofs1D = maps_O_C->nqpt; + c_dofs1D = maps_C_C->nqpt; + MFEM_VERIFY(maps_O_C->ndof == c_dofs1D && + maps_C_C->ndof == c_dofs1D, "Discrepancy in the number of DOFs"); + + const int ndof_test = (dim == 3) ? 3 * c_dofs1D * c_dofs1D * o_dofs1D + : 2 * c_dofs1D * o_dofs1D; + + const IntegrationRule & Nodes = test_el->GetNodes(); + + pa_data.SetSize(dim * ndof_test * ne, Device::GetMemoryType()); + auto op = Reshape(pa_data.HostWrite(), dim, ndof_test, ne); + + const Array &dofmap = test_el->GetDofMap(); + + if (dim == 3) + { + // Note that ND_HexahedronElement uses 6 vectors in tk rather than 3, with + // the last 3 having negative signs. Here the signs are all positive, as + // signs are applied in ElementRestriction. + + const double tk[9] = { 1.,0.,0., 0.,1.,0., 0.,0.,1. }; + + for (int c=0; c<3; ++c) + { + for (int i=0; i= 0) ? dofmap[d] : -1 - dofmap[d]; + + for (int e=0; eGetElementTransformation(e); + tr->SetIntPoint(&Nodes.IntPoint(id)); + tr->Jacobian().Mult(tk + dof2tk*dim, v); + + for (int j=0; j<3; ++j) + { + op(j,d,e) = v[j]; + } + } + } + } + } + else // 2D case + { + const double tk[4] = { 1.,0., 0.,1. }; + for (int c=0; c<2; ++c) + { + for (int i=0; i= 0) ? dofmap[d] : -1 - dofmap[d]; + + for (int e=0; eGetElementTransformation(e); + tr->SetIntPoint(&Nodes.IntPoint(id)); + tr->Jacobian().Mult(tk + dof2tk*dim, v); + + for (int j=0; j<2; ++j) + { + op(j,d,e) = v[j]; + } + } + } + } + } +} + +void IdentityInterpolator::AddMultPA(const Vector &x, Vector &y) const +{ + if (dim == 3) + { + PAHcurlVecH1IdentityApply3D(c_dofs1D, o_dofs1D, ne, maps_C_C->B, maps_O_C->B, + pa_data, x, y); + } + else if (dim == 2) + { + PAHcurlVecH1IdentityApply2D(c_dofs1D, o_dofs1D, ne, maps_C_C->B, maps_O_C->B, + pa_data, x, y); + } + else + { + mfem_error("Bad dimension!"); + } +} + +void IdentityInterpolator::AddMultTransposePA(const Vector &x, Vector &y) const +{ + if (dim == 3) + { + PAHcurlVecH1IdentityApplyTranspose3D(c_dofs1D, o_dofs1D, ne, maps_C_C->B, + maps_O_C->B, pa_data, x, y); + } + else if (dim == 2) + { + PAHcurlVecH1IdentityApplyTranspose2D(c_dofs1D, o_dofs1D, ne, maps_C_C->B, + maps_O_C->B, pa_data, x, y); + } + else + { + mfem_error("Bad dimension!"); + } +} + template void SmemPAHcurlMassAssembleDiagonal3D<0,0>(const int D1D, const int Q1D, const int NE, diff --git a/fem/bilininteg_hdiv.cpp b/fem/bilininteg_hdiv.cpp index 88a76bd620..593918e8bd 100644 --- a/fem/bilininteg_hdiv.cpp +++ b/fem/bilininteg_hdiv.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/bilininteg_mass_ea.cpp b/fem/bilininteg_mass_ea.cpp index f7e27bdfcb..8650095680 100644 --- a/fem/bilininteg_mass_ea.cpp +++ b/fem/bilininteg_mass_ea.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/bilininteg_mass_mf.cpp b/fem/bilininteg_mass_mf.cpp index 79eeaad542..2552f6f292 100644 --- a/fem/bilininteg_mass_mf.cpp +++ b/fem/bilininteg_mass_mf.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/bilininteg_mass_pa.cpp b/fem/bilininteg_mass_pa.cpp index d22f1c1a16..9fca9c02ca 100644 --- a/fem/bilininteg_mass_pa.cpp +++ b/fem/bilininteg_mass_pa.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -1226,4 +1226,10 @@ void MassIntegrator::AddMultPA(const Vector &x, Vector &y) const } } +void MassIntegrator::AddMultTransposePA(const Vector &x, Vector &y) const +{ + // Mass integrator is symmetric + AddMultPA(x, y); +} + } // namespace mfem diff --git a/fem/bilininteg_transpose_ea.cpp b/fem/bilininteg_transpose_ea.cpp index 77ccc428bc..9c7d62f921 100644 --- a/fem/bilininteg_transpose_ea.cpp +++ b/fem/bilininteg_transpose_ea.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/bilininteg_vecdiffusion.cpp b/fem/bilininteg_vecdiffusion.cpp index eaa98ef563..0f857a7713 100644 --- a/fem/bilininteg_vecdiffusion.cpp +++ b/fem/bilininteg_vecdiffusion.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/bilininteg_vecdiffusion_mf.cpp b/fem/bilininteg_vecdiffusion_mf.cpp index 1eae93d8b4..7449162f3c 100644 --- a/fem/bilininteg_vecdiffusion_mf.cpp +++ b/fem/bilininteg_vecdiffusion_mf.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/bilininteg_vecmass.cpp b/fem/bilininteg_vecmass.cpp index 94dbeabed7..27f862cc45 100644 --- a/fem/bilininteg_vecmass.cpp +++ b/fem/bilininteg_vecmass.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/bilininteg_vecmass_mf.cpp b/fem/bilininteg_vecmass_mf.cpp index b5101e245a..b042344e4d 100644 --- a/fem/bilininteg_vecmass_mf.cpp +++ b/fem/bilininteg_vecmass_mf.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/bilininteg_vectorfe.cpp b/fem/bilininteg_vectorfe.cpp index afdb504258..d57d7a22a1 100644 --- a/fem/bilininteg_vectorfe.cpp +++ b/fem/bilininteg_vectorfe.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -761,12 +761,12 @@ void VectorFEMassIntegrator::AssemblePA(const FiniteElementSpace &trial_fes, trial_fetype = trial_el->GetDerivType(); test_fetype = test_el->GetDerivType(); - const int MQsymmDim = MQ ? (MQ->GetWidth() * (MQ->GetWidth() + 1)) / 2 : 0; + const int MQsymmDim = SMQ ? (SMQ->GetSize() * (SMQ->GetSize() + 1)) / 2 : 0; const int MQfullDim = MQ ? (MQ->GetHeight() * MQ->GetWidth()) : 0; - const int MQdim = MQ ? (MQ->IsSymmetric() ? MQsymmDim : MQfullDim) : 0; - const int coeffDim = MQ ? MQdim : (VQ ? VQ->GetVDim() : 1); + const int MQdim = MQ ? MQfullDim : MQsymmDim; + const int coeffDim = (MQ || SMQ) ? MQdim : (DQ ? DQ->GetVDim() : 1); - symmetric = MQ ? MQ->IsSymmetric() : true; + symmetric = (MQ == NULL); const bool trial_curl = (trial_fetype == mfem::FiniteElement::CURL); const bool trial_div = (trial_fetype == mfem::FiniteElement::DIV); @@ -783,24 +783,13 @@ void VectorFEMassIntegrator::AssemblePA(const FiniteElementSpace &trial_fes, Vector coeff(coeffDim * ne * nq); coeff = 1.0; auto coeffh = Reshape(coeff.HostWrite(), coeffDim, nq, ne); - if (Q || VQ || MQ) + if (Q || DQ || MQ || SMQ) { - Vector D(VQ ? coeffDim : 0); + Vector D(DQ ? coeffDim : 0); DenseMatrix M; - Vector Msymm; - if (MQ) - { - if (symmetric) - { - Msymm.SetSize(MQsymmDim); - } - else - { - M.SetSize(dim); - } - } + DenseSymmetricMatrix SM; - if (VQ) + if (DQ) { MFEM_VERIFY(coeffDim == dim, ""); } @@ -808,6 +797,12 @@ void VectorFEMassIntegrator::AssemblePA(const FiniteElementSpace &trial_fes, { MFEM_VERIFY(coeffDim == MQdim, ""); MFEM_VERIFY(MQ->GetHeight() == dim && MQ->GetWidth() == dim, ""); + M.SetSize(dim); + } + if (SMQ) + { + MFEM_VERIFY(SMQ->GetSize() == dim, ""); + SM.SetSize(dim); } for (int e=0; eIsSymmetric()) - { - MQ->EvalSymmetric(Msymm, *tr, ir->IntPoint(p)); + MQ->Eval(M, *tr, ir->IntPoint(p)); - for (int i=0; iEval(M, *tr, ir->IntPoint(p)); - - for (int i=0; iEval(D, *tr, ir->IntPoint(p)); + SMQ->Eval(SM, *tr, ir->IntPoint(p)); + int cnt = 0; + for (int i=0; iEval(D, *tr, ir->IntPoint(p)); for (int i=0; iB, mapsC->B, mapsOtest->Bt, mapsCtest->Bt, pa_data, x, y); } else if (trial_div && test_curl) { - const bool scalarCoeff = !(VQ || MQ); + const bool scalarCoeff = !(DQ || MQ || SMQ); PAHcurlHdivMassApply3D(dofs1D, dofs1Dtest, quad1D, ne, scalarCoeff, false, mapsO->B, mapsC->B, mapsOtest->Bt, mapsCtest->Bt, pa_data, x, y); @@ -1038,7 +1031,7 @@ void VectorFEMassIntegrator::AddMultPA(const Vector &x, Vector &y) const } else if ((trial_curl && test_div) || (trial_div && test_curl)) { - const bool scalarCoeff = !(VQ || MQ); + const bool scalarCoeff = !(DQ || MQ || SMQ); PAHcurlHdivMassApply2D(dofs1D, dofs1Dtest, quad1D, ne, scalarCoeff, trial_curl, mapsO->B, mapsC->B, mapsOtest->Bt, mapsCtest->Bt, pa_data, x, y); diff --git a/fem/coefficient.cpp b/fem/coefficient.cpp index ba73e271a9..a33ad04c34 100644 --- a/fem/coefficient.cpp +++ b/fem/coefficient.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -301,7 +301,7 @@ void MatrixFunctionCoefficient::Eval(DenseMatrix &K, ElementTransformation &T, K.SetSize(height, width); - if (symmetric) // Use SymmFunction + if (symmetric) // Use SymmFunction (deprecated version) { MFEM_VERIFY(height == width && SymmFunction, "MatrixFunctionCoefficient is not symmetric"); @@ -371,6 +371,36 @@ void MatrixFunctionCoefficient::EvalSymmetric(Vector &K, } } +void SymmetricMatrixFunctionCoefficient::Eval(DenseSymmetricMatrix &K, + ElementTransformation &T, + const IntegrationPoint &ip) +{ + double x[3]; + Vector transip(x, 3); + + T.Transform(ip, transip); + + K.SetSize(dim); + + if (Function) + { + Function(transip, K); + } + else if (TDFunction) + { + TDFunction(transip, GetTime(), K); + } + else + { + K = mat; + } + + if (Q) + { + K *= Q->Eval(T, ip, GetTime()); + } +} + MatrixArrayCoefficient::MatrixArrayCoefficient (int dim) : MatrixCoefficient (dim) { @@ -595,6 +625,7 @@ void MatrixVectorProductCoefficient::Eval(Vector &V, ElementTransformation &T, { a->Eval(ma, T, ip); b->Eval(vb, T, ip); + V.SetSize(vdim); ma.Mult(vb, V); } diff --git a/fem/coefficient.hpp b/fem/coefficient.hpp index fab0855c1f..bd65b5fed2 100644 --- a/fem/coefficient.hpp +++ b/fem/coefficient.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -688,6 +688,7 @@ public: const IntegrationRule &ir); }; +typedef VectorCoefficient DiagonalMatrixCoefficient; /// Base class for Matrix Coefficients that optionally depend on time and space. class MatrixCoefficient @@ -695,7 +696,7 @@ class MatrixCoefficient protected: int height, width; double time; - bool symmetric; + bool symmetric; // deprecated public: /// Construct a dim x dim matrix coefficient. @@ -721,6 +722,7 @@ public: /// For backward compatibility get the width of the matrix. int GetVDim() const { return width; } + /** @deprecated Use SymmetricMatrixCoefficient instead */ bool IsSymmetric() const { return symmetric; } /** @brief Evaluate the matrix coefficient in the element described by @a T @@ -731,11 +733,13 @@ public: virtual void Eval(DenseMatrix &K, ElementTransformation &T, const IntegrationPoint &ip) = 0; + /// (DEPRECATED) Evaluate a symmetric matrix coefficient. /** @brief Evaluate the upper triangular entries of the matrix coefficient in the symmetric case, similarly to Eval. Matrix entry (i,j) is stored in K[j - i + os_i] for 0 <= i <= j < width, os_0 = 0, os_{i+1} = os_i + width - i. That is, K = {M(0,0), ..., M(0,w-1), - M(1,1), ..., M(1,w-1), ..., M(w-1,w-1) with w = width. */ + M(1,1), ..., M(1,w-1), ..., M(w-1,w-1) with w = width. + @deprecated Use Eval() instead. */ virtual void EvalSymmetric(Vector &K, ElementTransformation &T, const IntegrationPoint &ip) { mfem_error("MatrixCoefficient::EvalSymmetric"); } @@ -767,7 +771,7 @@ class MatrixFunctionCoefficient : public MatrixCoefficient { private: std::function Function; - std::function SymmFunction; + std::function SymmFunction; // deprecated std::function TDFunction; Coefficient *Q; @@ -791,6 +795,18 @@ public: : MatrixCoefficient(m.Height(), m.Width()), Q(&q), mat(m) { } + /** @brief Define a time-independent symmetric square matrix coefficient from + a std function */ + /** \param dim - the size of the matrix + \param SymmF - function used in EvalSymmetric + \param q - optional scalar Coefficient to scale the matrix coefficient + @deprecated Use another constructor without setting SymmFunction. */ + MatrixFunctionCoefficient(int dim, + std::function SymmF, + Coefficient *q = NULL) + : MatrixCoefficient(dim, true), SymmFunction(std::move(SymmF)), Q(q), mat(0) + { } + /// Define a time-dependent square matrix coefficient from a std function /** \param dim - the size of the matrix \param TDF - time-dependent function @@ -801,22 +817,12 @@ public: : MatrixCoefficient(dim), TDFunction(std::move(TDF)), Q(q) { } - /** @brief Define a time-independent symmetric square matrix coefficient from - a std function */ - /** \param dim - the size of the matrix - \param SymmF - function used in EvalSymmetric - \param q - optional scalar Coefficient to scale the matrix coefficient */ - MatrixFunctionCoefficient(int dim, - std::function SymmF, - Coefficient *q = NULL) - : MatrixCoefficient(dim, true), SymmFunction(std::move(SymmF)), Q(q), mat(0) - { } - /// Evaluate the matrix coefficient at @a ip. virtual void Eval(DenseMatrix &K, ElementTransformation &T, const IntegrationPoint &ip); - /// Evaluate the symmetric matrix coefficient at @a ip. + /// (DEPRECATED) Evaluate the symmetric matrix coefficient at @a ip. + /** @deprecated Use Eval() instead. */ virtual void EvalSymmetric(Vector &K, ElementTransformation &T, const IntegrationPoint &ip); @@ -824,7 +830,6 @@ public: }; - /** @brief Matrix coefficient defined by a matrix of scalar coefficients. Coefficients that are not set will evaluate to zero in the vector. The coefficient is stored as a flat Array with indexing (i,j) -> i*width+j. */ @@ -940,6 +945,106 @@ public: } }; + +/// Base class for symmetric matrix coefficients that optionally depend on time and space. +class SymmetricMatrixCoefficient +{ +protected: + int dim; + double time; + +public: + /// Construct a dim x dim matrix coefficient. + explicit SymmetricMatrixCoefficient(int dimension) + { dim = dimension; time = 0.; } + + /// Set the time for time dependent coefficients + void SetTime(double t) { time = t; } + + /// Get the time for time dependent coefficients + double GetTime() { return time; } + + /// Get the size of the matrix. + int GetSize() const { return dim; } + + /** @brief Evaluate the matrix coefficient in the element described by @a T + at the point @a ip, storing the result in @a K. */ + /** @note When this method is called, the caller must make sure that the + IntegrationPoint associated with @a T is the same as @a ip. This can be + achieved by calling T.SetIntPoint(&ip). */ + virtual void Eval(DenseSymmetricMatrix &K, ElementTransformation &T, + const IntegrationPoint &ip) = 0; + + virtual ~SymmetricMatrixCoefficient() { } +}; + + +/// A matrix coefficient that is constant in space and time. +class SymmetricMatrixConstantCoefficient : public SymmetricMatrixCoefficient +{ +private: + DenseSymmetricMatrix mat; + +public: + ///Construct using matrix @a m for the constant. + SymmetricMatrixConstantCoefficient(const DenseSymmetricMatrix &m) + : SymmetricMatrixCoefficient(m.Height()), mat(m) { } + using SymmetricMatrixCoefficient::Eval; + /// Evaluate the matrix coefficient at @a ip. + virtual void Eval(DenseSymmetricMatrix &M, ElementTransformation &T, + const IntegrationPoint &ip) { M = mat; } +}; + + +/** @brief A matrix coefficient with an optional scalar coefficient multiplier + \a q. The matrix function can either be represented by a std function or + a constant matrix provided when constructing this object. */ +class SymmetricMatrixFunctionCoefficient : public SymmetricMatrixCoefficient +{ +private: + std::function Function; + std::function TDFunction; + + Coefficient *Q; + DenseSymmetricMatrix mat; + +public: + /// Define a time-independent symmetric matrix coefficient from a std function + /** \param dim - the size of the matrix + \param F - time-independent function + \param q - optional scalar Coefficient to scale the matrix coefficient */ + SymmetricMatrixFunctionCoefficient(int dim, + std::function F, + Coefficient *q = nullptr) + : SymmetricMatrixCoefficient(dim), Function(std::move(F)), Q(q), mat(0) + { } + + /// Define a constant matrix coefficient times a scalar Coefficient + /** \param m - constant matrix + \param q - optional scalar Coefficient to scale the matrix coefficient */ + SymmetricMatrixFunctionCoefficient(const DenseSymmetricMatrix &m, + Coefficient &q) + : SymmetricMatrixCoefficient(m.Height()), Q(&q), mat(m) + { } + + /// Define a time-dependent square matrix coefficient from a std function + /** \param dim - the size of the matrix + \param TDF - time-dependent function + \param q - optional scalar Coefficient to scale the matrix coefficient */ + SymmetricMatrixFunctionCoefficient(int dim, + std::function TDF, + Coefficient *q = nullptr) + : SymmetricMatrixCoefficient(dim), TDFunction(std::move(TDF)), Q(q) + { } + + /// Evaluate the matrix coefficient at @a ip. + virtual void Eval(DenseSymmetricMatrix &K, ElementTransformation &T, + const IntegrationPoint &ip); + + virtual ~SymmetricMatrixFunctionCoefficient() { } +}; + + /** @brief Scalar coefficient defined as the product of two scalar coefficients or a scalar and a scalar coefficient. */ class ProductCoefficient : public Coefficient diff --git a/fem/complex_fem.cpp b/fem/complex_fem.cpp index f2696cffe1..44199d39b9 100644 --- a/fem/complex_fem.cpp +++ b/fem/complex_fem.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -1204,6 +1204,7 @@ ParSesquilinearForm::FormLinearSystem(const Array &ess_tdof_list, }); // Modify offdiagonal blocks (imaginary parts of the matrix) to conform // with standard essential BC treatment + ess_tdof_list.HostRead(); if (A_i.Type() == Operator::Hypre_ParCSR) { HypreParMatrix * Ah; diff --git a/fem/complex_fem.hpp b/fem/complex_fem.hpp index 1efb69998e..146568e9ff 100644 --- a/fem/complex_fem.hpp +++ b/fem/complex_fem.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/conduitdatacollection.cpp b/fem/conduitdatacollection.cpp index b9ae39926e..bacd9585b8 100644 --- a/fem/conduitdatacollection.cpp +++ b/fem/conduitdatacollection.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/conduitdatacollection.hpp b/fem/conduitdatacollection.hpp index 17c3b5eb21..7f1c7e04c5 100644 --- a/fem/conduitdatacollection.hpp +++ b/fem/conduitdatacollection.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/convergence.hpp b/fem/convergence.hpp index 5184896b1f..d0c3de12fb 100644 --- a/fem/convergence.hpp +++ b/fem/convergence.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/datacollection.cpp b/fem/datacollection.cpp index ff12d6b613..a030272eaf 100644 --- a/fem/datacollection.cpp +++ b/fem/datacollection.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/datacollection.hpp b/fem/datacollection.hpp index 5bcc3df160..738b4e795c 100644 --- a/fem/datacollection.hpp +++ b/fem/datacollection.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/eltrans.cpp b/fem/eltrans.cpp index ad35ed27a9..c8bea0b74d 100644 --- a/fem/eltrans.cpp +++ b/fem/eltrans.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/eltrans.hpp b/fem/eltrans.hpp index 4e91240d4e..5d1ec3899c 100644 --- a/fem/eltrans.hpp +++ b/fem/eltrans.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/estimators.cpp b/fem/estimators.cpp index a0289b5cca..ac9e7aafab 100644 --- a/fem/estimators.cpp +++ b/fem/estimators.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -48,8 +48,373 @@ void L2ZienkiewiczZhuEstimator::ComputeEstimates() current_sequence = solution->FESpace()->GetMesh()->GetSequence(); } + +KellyErrorEstimator::KellyErrorEstimator(BilinearFormIntegrator& di_, + ParGridFunction& sol_, + ParFiniteElementSpace& flux_fespace_, + const Array &attributes_) + : attributes(attributes_) + , flux_integrator(&di_) + , solution(&sol_) + , flux_space(&flux_fespace_) + , own_flux_fespace(false) +{ + ResetCoefficientFunctions(); +} + +KellyErrorEstimator::KellyErrorEstimator(BilinearFormIntegrator& di_, + ParGridFunction& sol_, + ParFiniteElementSpace* flux_fespace_, + const Array &attributes_) + : attributes(attributes_) + , flux_integrator(&di_) + , solution(&sol_) + , flux_space(flux_fespace_) + , own_flux_fespace(true) +{ + ResetCoefficientFunctions(); +} + +KellyErrorEstimator::~KellyErrorEstimator() +{ + if (own_flux_fespace) + { + delete flux_space; + } +} + +void KellyErrorEstimator::ResetCoefficientFunctions() +{ + compute_element_coefficient = [](ParMesh* pmesh, const int e) + { + return 1.0; + }; + + compute_face_coefficient = [](ParMesh* pmesh, const int f, + const bool shared_face) + { + auto FT = [&]() + { + if (shared_face) + { + return pmesh->GetSharedFaceTransformations(f); + } + return pmesh->GetFaceElementTransformations(f); + }(); + const auto order = FT->GetFE()->GetOrder(); + + // Poor man's face diameter. + double diameter = 0.0; + + Vector p1(pmesh->SpaceDimension()); + Vector p2(pmesh->SpaceDimension()); + // NOTE: We have no direct access to vertices for shared faces, + // so we fall back to compute the positions from the element. + // This can also be modified to compute the diameter for non-linear + // geometries by sampling along geometry-specific lines. + auto vtx_intrule = Geometries.GetVertices(FT->GetGeometryType()); + const auto nip = vtx_intrule->GetNPoints(); + for (int i = 0; i < nip; i++) + { + // Evaluate flux vector at integration point + auto fip1 = vtx_intrule->IntPoint(i); + FT->Transform(fip1, p1); + + for (int j = 0; j < nip; j++) + { + auto fip2 = vtx_intrule->IntPoint(j); + FT->Transform(fip2, p2); + + diameter = std::max(diameter, p2.DistanceTo(p1)); + } + } + return diameter/(2.0*order); + }; +} + +void KellyErrorEstimator::ComputeEstimates() +{ + // Remarks: + // For some context you may have to consult the documentation of + // the FaceInfo class [1]. Also, the FaceElementTransformations + // documentation [2] may be helpful to grasp what is going on. Note + // that the FaceElementTransformations also works in the non- + // conforming case to transfer the gauss points from the slave to + // the master element. + // [1] + // https://github.com/mfem/mfem/blob/02d0bfe9c18ce049c3c93a6a4208080fcfc96991/mesh/mesh.hpp#L94 + // [2] + // https://github.com/mfem/mfem/blob/02d0bfe9c18ce049c3c93a6a4208080fcfc96991/fem/eltrans.hpp#L435 + + flux_space->Update(false); + + auto xfes = solution->ParFESpace(); + MFEM_ASSERT(xfes->GetVDim() == 1, + "Estimation for vector-valued problems not implemented yet."); + auto pmesh = xfes->GetParMesh(); + + this->error_estimates.SetSize(xfes->GetNE()); + this->error_estimates = 0.0; + + // 1. Compute fluxes in discontinuous space + ParGridFunction flux(flux_space); + flux = 0.0; + + // We pre-sort the array to speed up the search in the following loops. + if (attributes.Size()) + { + attributes.Sort(); + } + + Array xdofs, fdofs; + Vector el_x, el_f; + for (int e = 0; e < xfes->GetNE(); e++) + { + auto attr = xfes->GetAttribute(e); + if (attributes.Size() && attributes.FindSorted(attr) == -1) + { + continue; + } + + xfes->GetElementVDofs(e, xdofs); + solution->GetSubVector(xdofs, el_x); + + ElementTransformation* Transf = xfes->GetElementTransformation(e); + flux_integrator->ComputeElementFlux(*xfes->GetFE(e), *Transf, el_x, + *flux_space->GetFE(e), el_f, true); + + flux_space->GetElementVDofs(e, fdofs); + flux.AddElementVector(fdofs, el_f); + } + + // 2. Add error contribution from local interior faces + for (int f = 0; f < pmesh->GetNumFaces(); f++) + { + auto FT = pmesh->GetFaceElementTransformations(f); + + auto &int_rule = IntRules.Get(FT->FaceGeom, 2 * xfes->GetFaceOrder(f)); + const auto nip = int_rule.GetNPoints(); + + if (pmesh->FaceIsInterior(f)) + { + int Inf1, Inf2, NCFace; + pmesh->GetFaceInfos(f, &Inf1, &Inf2, &NCFace); + + // Convention + // * Conforming face: Face side with smaller element id handles + // the integration + // * Non-conforming face: The slave handles the integration. + // See FaceInfo documentation for details. + bool isNCSlave = FT->Elem2No >= 0 && NCFace >= 0; + bool isConforming = FT->Elem2No >= 0 && NCFace == -1; + if ((FT->Elem1No < FT->Elem2No && isConforming) || isNCSlave) + { + if (attributes.Size() && + (attributes.FindSorted(FT->Elem1->Attribute) == -1 + || attributes.FindSorted(FT->Elem2->Attribute) == -1)) + { + continue; + } + + IntegrationRule eir; + Vector jumps(nip); + + // Integral over local half face on the side of e₁ + // i.e. the numerical integration of ∫ flux ⋅ n dS₁ + for (int i = 0; i < nip; i++) + { + // Evaluate flux at IP + auto &fip = int_rule.IntPoint(i); + IntegrationPoint ip; + FT->Loc1.Transform(fip, ip); + + Vector val(flux_space->GetVDim()); + flux.GetVectorValue(FT->Elem1No, ip, val); + + // And build scalar product with normal + Vector normal(pmesh->SpaceDimension()); + FT->Face->SetIntPoint(&fip); + if (pmesh->Dimension() == pmesh->SpaceDimension()) + { + CalcOrtho(FT->Face->Jacobian(), normal); + } + else + { + Vector ref_normal(pmesh->Dimension()); + FT->Loc1.Transf.SetIntPoint(&fip); + CalcOrtho(FT->Loc1.Transf.Jacobian(), ref_normal); + auto &e1 = FT->GetElement1Transformation(); + e1.AdjugateJacobian().MultTranspose(ref_normal, normal); + normal /= e1.Weight(); + } + jumps(i) = val * normal * fip.weight * FT->Face->Weight(); + } + + // Subtract integral over half face of e₂ + // i.e. the numerical integration of ∫ flux ⋅ n dS₂ + for (int i = 0; i < nip; i++) + { + // Evaluate flux vector at IP + auto &fip = int_rule.IntPoint(i); + IntegrationPoint ip; + FT->Loc2.Transform(fip, ip); + + Vector val(flux_space->GetVDim()); + flux.GetVectorValue(FT->Elem2No, ip, val); + + // And build scalar product with normal + Vector normal(pmesh->SpaceDimension()); + FT->Face->SetIntPoint(&fip); + if (pmesh->Dimension() == pmesh->SpaceDimension()) + { + CalcOrtho(FT->Face->Jacobian(), normal); + } + else + { + Vector ref_normal(pmesh->Dimension()); + FT->Loc1.Transf.SetIntPoint(&fip); + CalcOrtho(FT->Loc1.Transf.Jacobian(), ref_normal); + auto &e1 = FT->GetElement1Transformation(); + e1.AdjugateJacobian().MultTranspose(ref_normal, normal); + normal /= e1.Weight(); + } + + jumps(i) -= val * normal * fip.weight * FT->Face->Weight(); + } + + // Finalize "local" L₂ contribution + for (int i = 0; i < nip; i++) + { + jumps(i) *= jumps(i); + } + auto h_k_face = compute_face_coefficient(pmesh, f, false); + double jump_integral = h_k_face*jumps.Sum(); + + // A local face is shared between two local elements, so we + // can get away with integrating the jump only once and add + // it to both elements. To minimize communication, the jump + // of shared faces is computed locally by each process. + error_estimates(FT->Elem1No) += jump_integral; + error_estimates(FT->Elem2No) += jump_integral; + } + } + } + + // 3. Add error contribution from shared interior faces + // Synchronize face data. + flux.ExchangeFaceNbrData(); + + for (int sf = 0; sf < pmesh->GetNSharedFaces(); sf++) + { + auto FT = pmesh->GetSharedFaceTransformations(sf, true); + if (attributes.Size() && + (attributes.FindSorted(FT->Elem1->Attribute) == -1 + || attributes.FindSorted(FT->Elem2->Attribute) == -1)) + { + continue; + } + + auto &int_rule = IntRules.Get(FT->FaceGeom, 2 * xfes->GetFaceOrder(0)); + const auto nip = int_rule.GetNPoints(); + + IntegrationRule eir; + Vector jumps(nip); + + // Integral over local half face on the side of e₁ + // i.e. the numerical integration of ∫ flux ⋅ n dS₁ + for (int i = 0; i < nip; i++) + { + // Evaluate flux vector at integration point + auto &fip = int_rule.IntPoint(i); + IntegrationPoint ip; + FT->Loc1.Transform(fip, ip); + + Vector val(flux_space->GetVDim()); + flux.GetVectorValue(FT->Elem1No, ip, val); + + Vector normal(pmesh->SpaceDimension()); + FT->Face->SetIntPoint(&fip); + if (pmesh->Dimension() == pmesh->SpaceDimension()) + { + CalcOrtho(FT->Face->Jacobian(), normal); + } + else + { + Vector ref_normal(pmesh->Dimension()); + FT->Loc1.Transf.SetIntPoint(&fip); + CalcOrtho(FT->Loc1.Transf.Jacobian(), ref_normal); + auto &e1 = FT->GetElement1Transformation(); + e1.AdjugateJacobian().MultTranspose(ref_normal, normal); + normal /= e1.Weight(); + } + + jumps(i) = val * normal * fip.weight * FT->Face->Weight(); + } + + // Subtract integral over non-local half face of e₂ + // i.e. the numerical integration of ∫ flux ⋅ n dS₂ + for (int i = 0; i < nip; i++) + { + // Evaluate flux vector at integration point + auto &fip = int_rule.IntPoint(i); + IntegrationPoint ip; + FT->Loc2.Transform(fip, ip); + + Vector val(flux_space->GetVDim()); + flux.GetVectorValue(FT->Elem2No, ip, val); + + // Evaluate gauss point + Vector normal(pmesh->SpaceDimension()); + FT->Face->SetIntPoint(&fip); + if (pmesh->Dimension() == pmesh->SpaceDimension()) + { + CalcOrtho(FT->Face->Jacobian(), normal); + } + else + { + Vector ref_normal(pmesh->Dimension()); + CalcOrtho(FT->Loc1.Transf.Jacobian(), ref_normal); + auto &e1 = FT->GetElement1Transformation(); + e1.AdjugateJacobian().MultTranspose(ref_normal, normal); + normal /= e1.Weight(); + } + + jumps(i) -= val * normal * fip.weight * FT->Face->Weight(); + } + + // Finalize "local" L₂ contribution + for (int i = 0; i < nip; i++) + { + jumps(i) *= jumps(i); + } + auto h_k_face = compute_face_coefficient(pmesh, sf, true); + double jump_integral = h_k_face*jumps.Sum(); + + error_estimates(FT->Elem1No) += jump_integral; + // We skip "error_estimates(FT->Elem2No) += jump_integral" + // because the error is stored on the remote process and + // recomputed there. + } + + // Finalize element errors + for (int e = 0; e < xfes->GetNE(); e++) + { + auto factor = compute_element_coefficient(pmesh, e); + // The sqrt belongs to the norm and hₑ to the indicator. + error_estimates(e) = sqrt(factor * error_estimates(e)); + } + + current_sequence = solution->FESpace()->GetMesh()->GetSequence(); + + // Finish by computing the global error. + double process_local_error = error_estimates.Sum(); + MPI_Allreduce(&process_local_error, &total_error, 1, MPI_DOUBLE, + MPI_SUM, xfes->GetComm()); +} + #endif // MFEM_USE_MPI + void LpErrorEstimator::ComputeEstimates() { MFEM_VERIFY(coef != NULL || vcoef != NULL, @@ -64,6 +429,17 @@ void LpErrorEstimator::ComputeEstimates() { sol->ComputeElementLpErrors(local_norm_p, *vcoef, error_estimates); } +#ifdef MFEM_USE_MPI + total_error = error_estimates.Sum(); + auto pfes = dynamic_cast(sol->FESpace()); + if (pfes) + { + auto process_local_error = total_error; + MPI_Allreduce(&process_local_error, &total_error, 1, MPI_DOUBLE, + MPI_SUM, pfes->GetComm()); + } +#endif // MFEM_USE_MPI + total_error = pow(total_error, 1.0/local_norm_p); current_sequence = sol->FESpace()->GetMesh()->GetSequence(); } diff --git a/fem/estimators.hpp b/fem/estimators.hpp index 16f66024de..76b1dd20ad 100644 --- a/fem/estimators.hpp +++ b/fem/estimators.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -12,6 +12,8 @@ #ifndef MFEM_ERROR_ESTIMATORS #define MFEM_ERROR_ESTIMATORS +#include + #include "../config/config.hpp" #include "../linalg/vector.hpp" #include "bilinearform.hpp" @@ -39,6 +41,11 @@ public: class ErrorEstimator : public AbstractErrorEstimator { public: + /// Return the total error from the last error estimate. + /** @note This method is optional for derived classes to override and the + base class implementation simply returns 0. */ + virtual double GetTotalError() const { return 0.0; } + /// Get a Vector with all element errors. virtual const Vector &GetLocalErrors() = 0; @@ -148,8 +155,8 @@ public: own_flux_fes(false) { } - /** @brief Consider the coefficient in BilinearFormIntegrator to calculate the - fluxes for the error estimator.*/ + /** @brief Consider the coefficient in BilinearFormIntegrator to calculate + the fluxes for the error estimator.*/ void SetWithCoeff(bool w_coeff = true) { with_coeff = w_coeff; } /** @brief Enable/disable anisotropic estimates. To enable this option, the @@ -166,10 +173,10 @@ public: void SetFluxAveraging(int fa) { flux_averaging = fa; } /// Return the total error from the last error estimate. - double GetTotalError() const { return total_error; } + virtual double GetTotalError() const override { return total_error; } /// Get a Vector with all element errors. - virtual const Vector &GetLocalErrors() + virtual const Vector &GetLocalErrors() override { if (MeshIsModified()) { ComputeEstimates(); } return error_estimates; @@ -178,14 +185,14 @@ public: /** @brief Get an Array with anisotropic flags for all mesh elements. Return an empty array when anisotropic estimates are not available or enabled. */ - virtual const Array &GetAnisotropicFlags() + virtual const Array &GetAnisotropicFlags() override { if (MeshIsModified()) { ComputeEstimates(); } return aniso_flags; } /// Reset the error estimator. - virtual void Reset() { current_sequence = -1; } + virtual void Reset() override { current_sequence = -1; } /** @brief Destroy a ZienkiewiczZhuEstimator object. Destroys, if owned, the FiniteElementSpace, flux_space. */ @@ -292,17 +299,17 @@ public: void SetLocalErrorNormP(int p) { local_norm_p = p; } /// Return the total error from the last error estimate. - double GetTotalError() const { return total_error; } + virtual double GetTotalError() const override { return total_error; } /// Get a Vector with all element errors. - virtual const Vector &GetLocalErrors() + virtual const Vector &GetLocalErrors() override { if (MeshIsModified()) { ComputeEstimates(); } return error_estimates; } /// Reset the error estimator. - virtual void Reset() { current_sequence = -1; } + virtual void Reset() override { current_sequence = -1; } /** @brief Destroy a L2ZienkiewiczZhuEstimator object. Destroys, if owned, the FiniteElementSpace, flux_space. */ @@ -314,6 +321,7 @@ public: #endif // MFEM_USE_MPI + /** @brief The LpErrorEstimator class compares the solution to a known coefficient. @@ -332,6 +340,8 @@ protected: int local_norm_p; Vector error_estimates; + double total_error = 0.0; + Coefficient * coef; VectorCoefficient * vcoef; GridFunction * sol; @@ -383,10 +393,10 @@ public: void SetCoef(VectorCoefficient &A) { vcoef = &A; } /// Reset the error estimator. - virtual void Reset() { current_sequence = -1; } + virtual void Reset() override { current_sequence = -1; } /// Get a Vector with all element errors. - virtual const Vector &GetLocalErrors() + virtual const Vector &GetLocalErrors() override { if (MeshIsModified()) { ComputeEstimates(); } return error_estimates; @@ -396,6 +406,174 @@ public: virtual ~LpErrorEstimator() {} }; + +#ifdef MFEM_USE_MPI +/** @brief The KellyErrorEstimator class provides a fast error indication + strategy for smooth scalar parallel problems. + + The Kelly error indicator is based on the following papers: + + Kelly, D. W., et al. "A posteriori error analysis and adaptive processes in + the finite element method: Part I—Error analysis." International journal for + numerical methods in engineering 19.11 (1983): 1593-1619. + + De SR Gago, J. P., et al. "A posteriori error analysis and adaptive + processes in the finite element method: Part II—Adaptive mesh refinement." + International journal for numerical methods in engineering 19.11 (1983): + 1621-1656. + + It can be roughly described by: + ||∇(u-uₕ)||ₑ ≦ √( C hₑ ∑ₖ (hₖ ∫ |J[∇uₕ]|²) dS ) + where "e" denotes an element, ||⋅||ₑ the corresponding local norm and k the + corresponding faces. u is the analytic solution and uₕ the discretized + solution. hₖ and hₑ are factors dependend on the face and element geometry. + J is the jump function, i.e. the difference between the limits at each point + for each side of the face. A custom method to compute hₖ can be provided. It + is also possible to estimate the error only on a subspace by feeding this + class an attribute array describing the subspace. + + @note This algorithm is only for Poisson problems a proper error esimator. + The current implementation does not reflect this, because the "C" factor is + not included. + It further assumes that the approximation error at the boundary is small + enough, as the implementation ignores boundary faces. +*/ +class KellyErrorEstimator final : public ErrorEstimator +{ +public: + /// Function type to compute the local coefficient hₑ of an element. + using ElementCoefficientFunction = + std::function; + /** @brief Function type to compute the local coefficient hₖ of a face. The + third argument is true for shared faces and false for local faces. */ + using FaceCoefficientFunction = + std::function; + +private: + int current_sequence = -1; + + Vector error_estimates; + + double total_error = 0.0; + + Array attributes; + + /** @brief A method to compute hₑ on per-element basis. + + This method weights the error approximation on the element level. + + Defaults to hₑ=1.0. + */ + ElementCoefficientFunction compute_element_coefficient; + + /** @brief A method to compute hₖ on per-face basis. + + This method weights the error approximation on the face level. The + background here is that classical Kelly error estimator implementations + approximate the geometrical characteristic hₖ with the face diameter, + which should be also be a possibility in this implementation. + + Defaults to hₖ=diameter/2p. + */ + FaceCoefficientFunction compute_face_coefficient; + + BilinearFormIntegrator* flux_integrator; ///< Not owned. + ParGridFunction* solution; ///< Not owned. + + ParFiniteElementSpace* + flux_space; /**< @brief Ownership based on own_flux_fes. */ + bool own_flux_fespace; ///< Ownership flag for flux_space. + + /// Check if the mesh of the solution was modified. + bool MeshIsModified() + { + long mesh_sequence = solution->FESpace()->GetMesh()->GetSequence(); + MFEM_ASSERT(mesh_sequence >= current_sequence, + "improper mesh update sequence"); + return (mesh_sequence > current_sequence); + } + + /** @brief Compute the element error estimates. + + Algorithm outline: + 1. Compute flux field for each element + 2. Add error contribution from local interior faces + 3. Add error contribution from shared interior faces + 4. Finalize by computing hₖ and scale errors. + */ + void ComputeEstimates(); + +public: + /** @brief Construct a new KellyErrorEstimator object for a scalar field. + @param di_ The bilinearform to compute the interface flux. + @param sol_ The solution field whose error is to be estimated. + @param flux_fes_ The finite element space for the interface flux. + @param attributes_ The attributes of the subdomain(s) for which the + error should be estimated. An empty array results in + estimating the error over the complete domain. + */ + KellyErrorEstimator(BilinearFormIntegrator& di_, ParGridFunction& sol_, + ParFiniteElementSpace& flux_fes_, + const Array &attributes_ = Array()); + + /** @brief Construct a new KellyErrorEstimator object for a scalar field. + @param di_ The bilinearform to compute the interface flux. + @param sol_ The solution field whose error is to be estimated. + @param flux_fes_ The finite element space for the interface flux. + @param attributes_ The attributes of the subdomain(s) for which the + error should be estimated. An empty array results in + estimating the error over the complete domain. + */ + KellyErrorEstimator(BilinearFormIntegrator& di_, ParGridFunction& sol_, + ParFiniteElementSpace* flux_fes_, + const Array &attributes_ = Array()); + + ~KellyErrorEstimator(); + + /// Get a Vector with all element errors. + const Vector& GetLocalErrors() override + { + if (MeshIsModified()) + { + ComputeEstimates(); + } + return error_estimates; + } + + /// Reset the error estimator. + void Reset() override { current_sequence = -1; }; + + virtual double GetTotalError() const override { return total_error; } + + /** @brief Change the method to compute hₑ on a per-element basis. + @param compute_element_coefficient_ + A function taking a mesh and an element index to + compute the local hₑ for the element. + */ + void SetElementCoefficientFunction(ElementCoefficientFunction + compute_element_coefficient_) + { + compute_element_coefficient = compute_element_coefficient_; + } + + /** @brief Change the method to compute hₖ on a per-element basis. + @param compute_face_coefficient_ + A function taking a mesh and a face index to + compute the local hₖ for the face. + */ + void SetFaceCoefficientFunction( + FaceCoefficientFunction + compute_face_coefficient_) + { + compute_face_coefficient = compute_face_coefficient_; + } + + /// Change the coefficients back to default as described above. + void ResetCoefficientFunctions(); +}; + +#endif // MFEM_USE_MPI + } // namespace mfem #endif // MFEM_ERROR_ESTIMATORS diff --git a/fem/fe.cpp b/fem/fe.cpp index 24e9036c57..eea61b6cc3 100644 --- a/fem/fe.cpp +++ b/fem/fe.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -596,17 +596,22 @@ void NodalFiniteElement::ProjectCurl_2D( const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &curl) const { - MFEM_ASSERT(GetMapType() == FiniteElement::INTEGRAL, ""); - DenseMatrix curl_shape(fe.GetDof(), 1); curl.SetSize(dof, fe.GetDof()); for (int i = 0; i < dof; i++) { fe.CalcCurlShape(Nodes.IntPoint(i), curl_shape); + + double w = 1.0; + if (GetMapType() == FiniteElement::VALUE) + { + Trans.SetIntPoint(&Nodes.IntPoint(i)); + w /= Trans.Weight(); + } for (int j = 0; j < fe.GetDof(); j++) { - curl(i,j) = curl_shape(j,0); + curl(i,j) = w * curl_shape(j,0); } } } @@ -722,17 +727,34 @@ void NodalFiniteElement::Project( { if (fe.GetRangeType() == SCALAR) { - MFEM_ASSERT(map_type == fe.GetMapType(), ""); - Vector shape(fe.GetDof()); I.SetSize(dof, fe.GetDof()); - for (int k = 0; k < dof; k++) + if (map_type == fe.GetMapType()) { - fe.CalcShape(Nodes.IntPoint(k), shape); - for (int j = 0; j < shape.Size(); j++) + for (int k = 0; k < dof; k++) { - I(k,j) = (fabs(shape(j)) < 1e-12) ? 0.0 : shape(j); + fe.CalcShape(Nodes.IntPoint(k), shape); + for (int j = 0; j < shape.Size(); j++) + { + I(k,j) = (fabs(shape(j)) < 1e-12) ? 0.0 : shape(j); + } + } + } + else + { + for (int k = 0; k < dof; k++) + { + Trans.SetIntPoint(&Nodes.IntPoint(k)); + fe.CalcPhysShape(Trans, shape); + if (map_type == INTEGRAL) + { + shape *= Trans.Weight(); + } + for (int j = 0; j < shape.Size(); j++) + { + I(k,j) = (fabs(shape(j)) < 1e-12) ? 0.0 : shape(j); + } } } } @@ -1031,6 +1053,8 @@ void VectorFiniteElement::Project_RT( fe.CalcShape(ip, shape); Trans.SetIntPoint(&ip); + // Transform RT face normals from reference to physical space + // vk = adj(J)^T nk Trans.AdjugateJacobian().MultTranspose(nk + d2n[k]*dim, vk); if (fe.GetMapType() == INTEGRAL) { @@ -1048,6 +1072,8 @@ void VectorFiniteElement::Project_RT( { s = 0.0; } + // Project scalar basis function multiplied by each coordinate + // direction onto the transformed face normals for (int d = 0; d < sdim; d++) { I(k,j+d*shape.Size()) = s*vk[d]; @@ -1057,7 +1083,31 @@ void VectorFiniteElement::Project_RT( } else { - mfem_error("VectorFiniteElement::Project_RT (fe version)"); + int sdim = Trans.GetSpaceDim(); + double vk[Geometry::MaxDim]; + DenseMatrix vshape(fe.GetDof(), sdim); + Vector vshapenk(fe.GetDof()); + const bool square_J = (dim == sdim); + + I.SetSize(dof, fe.GetDof()); + for (int k = 0; k < dof; k++) + { + const IntegrationPoint &ip = Nodes.IntPoint(k); + + Trans.SetIntPoint(&ip); + // Transform RT face normals from reference to physical space + // vk = adj(J)^T nk + Trans.AdjugateJacobian().MultTranspose(nk + d2n[k]*dim, vk); + // Compute fe basis functions in physical space + fe.CalcVShape(Trans, vshape); + // Project fe basis functions onto transformed face normals + vshape.Mult(vk, vshapenk); + if (!square_J) { vshapenk /= Trans.Weight(); } + for (int j=0; j 1 ? FunctionSpace::Qk : FunctionSpace::Pk), - TensorBasisElement(dims, p, VerifyNodal(btype), dmtype) { } + TensorBasisElement(dims, p, VerifyNodal(btype), dmtype) +{ + lex_ordering = dof_map; +} PositiveTensorFiniteElement::PositiveTensorFiniteElement( @@ -8405,23 +8484,33 @@ H1_TriangleElement::H1_TriangleElement(const int p, const int btype) Vector shape_x(p + 1), shape_y(p + 1), shape_l(p + 1); #endif + int p2p3 = 2*p + 3; + auto idx = [p2p3](int i, int j) { return ((p2p3-j)*j)/2+i; }; + lex_ordering.SetSize(dof); + // vertices + lex_ordering[idx(0,0)] = 0; Nodes.IntPoint(0).Set2(cp[0], cp[0]); + lex_ordering[idx(p,0)] = 1; Nodes.IntPoint(1).Set2(cp[p], cp[0]); + lex_ordering[idx(0,p)] = 2; Nodes.IntPoint(2).Set2(cp[0], cp[p]); // edges int o = 3; for (int i = 1; i < p; i++) { + lex_ordering[idx(i,0)] = o; Nodes.IntPoint(o++).Set2(cp[i], cp[0]); } for (int i = 1; i < p; i++) { + lex_ordering[idx(p-i,i)] = o; Nodes.IntPoint(o++).Set2(cp[p-i], cp[i]); } for (int i = 1; i < p; i++) { + lex_ordering[idx(0,p-i)] = o; Nodes.IntPoint(o++).Set2(cp[0], cp[p-i]); } @@ -8430,6 +8519,7 @@ H1_TriangleElement::H1_TriangleElement(const int p, const int btype) for (int i = 1; i + j < p; i++) { const double w = cp[i] + cp[j] + cp[p-i-j]; + lex_ordering[idx(i,j)] = o; Nodes.IntPoint(o++).Set2(cp[i]/w, cp[j]/w); } @@ -8563,36 +8653,56 @@ H1_TetrahedronElement::H1_TetrahedronElement(const int p, const int btype) Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_l(p + 1); #endif + auto tri = [](int k) { return (k*(k + 1))/2; }; + auto tet = [](int k) { return (k*(k + 1)*(k + 2))/6; }; + int ndof = tet(p+1); + auto idx = [tri, tet, p, ndof](int i, int j, int k) + { + return ndof - tet(p - k) - tri(p + 1 - k - j) + i; + }; + + lex_ordering.SetSize(dof); + // vertices + lex_ordering[idx(0,0,0)] = 0; Nodes.IntPoint(0).Set3(cp[0], cp[0], cp[0]); + lex_ordering[idx(p,0,0)] = 1; Nodes.IntPoint(1).Set3(cp[p], cp[0], cp[0]); + lex_ordering[idx(0,p,0)] = 2; Nodes.IntPoint(2).Set3(cp[0], cp[p], cp[0]); + lex_ordering[idx(0,0,p)] = 3; Nodes.IntPoint(3).Set3(cp[0], cp[0], cp[p]); // edges (see Tetrahedron::edges in mesh/tetrahedron.cpp) int o = 4; for (int i = 1; i < p; i++) // (0,1) { + lex_ordering[idx(i,0,0)] = o; Nodes.IntPoint(o++).Set3(cp[i], cp[0], cp[0]); } for (int i = 1; i < p; i++) // (0,2) { + lex_ordering[idx(0,i,0)] = o; Nodes.IntPoint(o++).Set3(cp[0], cp[i], cp[0]); } for (int i = 1; i < p; i++) // (0,3) { + lex_ordering[idx(0,0,i)] = o; Nodes.IntPoint(o++).Set3(cp[0], cp[0], cp[i]); } for (int i = 1; i < p; i++) // (1,2) { + lex_ordering[idx(p-i,i,0)] = o; Nodes.IntPoint(o++).Set3(cp[p-i], cp[i], cp[0]); } for (int i = 1; i < p; i++) // (1,3) { + lex_ordering[idx(p-i,0,i)] = o; Nodes.IntPoint(o++).Set3(cp[p-i], cp[0], cp[i]); } for (int i = 1; i < p; i++) // (2,3) { + lex_ordering[idx(0,p-i,i)] = o; Nodes.IntPoint(o++).Set3(cp[0], cp[p-i], cp[i]); } @@ -8600,24 +8710,28 @@ H1_TetrahedronElement::H1_TetrahedronElement(const int p, const int btype) for (int j = 1; j < p; j++) for (int i = 1; i + j < p; i++) // (1,2,3) { + lex_ordering[idx(p-i-j,i,j)] = o; double w = cp[i] + cp[j] + cp[p-i-j]; Nodes.IntPoint(o++).Set3(cp[p-i-j]/w, cp[i]/w, cp[j]/w); } for (int j = 1; j < p; j++) for (int i = 1; i + j < p; i++) // (0,3,2) { + lex_ordering[idx(0,j,i)] = o; double w = cp[i] + cp[j] + cp[p-i-j]; Nodes.IntPoint(o++).Set3(cp[0], cp[j]/w, cp[i]/w); } for (int j = 1; j < p; j++) for (int i = 1; i + j < p; i++) // (0,1,3) { + lex_ordering[idx(i,0,j)] = o; double w = cp[i] + cp[j] + cp[p-i-j]; Nodes.IntPoint(o++).Set3(cp[i]/w, cp[0], cp[j]/w); } for (int j = 1; j < p; j++) for (int i = 1; i + j < p; i++) // (0,2,1) { + lex_ordering[idx(j,i,0)] = o; double w = cp[i] + cp[j] + cp[p-i-j]; Nodes.IntPoint(o++).Set3(cp[j]/w, cp[i]/w, cp[0]); } @@ -8627,6 +8741,7 @@ H1_TetrahedronElement::H1_TetrahedronElement(const int p, const int btype) for (int j = 1; j + k < p; j++) for (int i = 1; i + j + k < p; i++) { + lex_ordering[idx(i,j,k)] = o; double w = cp[i] + cp[j] + cp[k] + cp[p-i-j-k]; Nodes.IntPoint(o++).Set3(cp[i]/w, cp[j]/w, cp[k]/w); } @@ -9171,7 +9286,22 @@ H1_WedgeElement::H1_WedgeElement(const int p, t_dof.SetSize(dof); s_dof.SetSize(dof); + int p2p3 = 2*p + 3, ntri = ((p + 1)*(p + 2))/2; + auto idx = [p2p3,ntri](int i, int j, int k) + { + return k*ntri + ((p2p3-j)*j)/2+i; + }; + + lex_ordering.SetSize(dof); + int o = 0; + // Nodal DoFs + lex_ordering[idx(0,0,0)] = o++; + lex_ordering[idx(p,0,0)] = o++; + lex_ordering[idx(0,p,0)] = o++; + lex_ordering[idx(0,0,p)] = o++; + lex_ordering[idx(p,0,p)] = o++; + lex_ordering[idx(0,p,p)] = o++; t_dof[0] = 0; s_dof[0] = 0; t_dof[1] = 1; s_dof[1] = 0; t_dof[2] = 2; s_dof[2] = 0; @@ -9180,9 +9310,19 @@ H1_WedgeElement::H1_WedgeElement(const int p, t_dof[5] = 2; s_dof[5] = 1; // Edge DoFs + int k = 0; int ne = p-1; for (int i=1; i lex_ordering; void ProjectCurl_2D(const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &curl) const; @@ -740,6 +747,29 @@ public: virtual void ProjectDiv(const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &div) const; + + /** @brief Get an Array that maps lexicographically ordered indices to + the indices of the respective nodes/dofs/basis functions. Lexicographic + ordering of nodes is defined in terms of reference-space coordinates + (x,y,z). Lexicographically ordered nodes are listed first in order of + increasing x-coordinate, and then in order of increasing y-coordinate, + and finally in order of increasing z-coordinate. + + For example, the six nodes of a quadratic triangle are lexicographically + ordered as follows: + + 5 + |\ + 3 4 + | \ + 0-1-2 + + The resulting array may be empty if the DOFs are already ordered + lexicographically, or if the finite element does not support creating + this permutation. The array returned is the same as the array given by + TensorBasisElement::GetDofMap, but it is also available for non-tensor + elements. */ + const Array &GetLexicographicOrdering() const { return lex_ordering; } }; /** @brief Class for finite elements utilizing the @@ -813,11 +843,25 @@ protected: void CalcVShape_ND(ElementTransformation &Trans, DenseMatrix &shape) const; + /** @brief Project a vector coefficient onto the RT basis functions + @param nk Face normal vectors for this element type + @param d2n Offset into nk for each degree of freedom + @param vc Vector coefficient to be projected + @param Trans Transformation from reference to physical coordinates + @param dofs Expansion coefficients for the approximation of vc + */ void Project_RT(const double *nk, const Array &d2n, VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const; /// Projects the vector of values given at FE nodes to RT space + /** Project vector values onto the RT basis functions + @param nk Face normal vectors for this element type + @param d2n Offset into nk for each degree of freedom + @param vc Vector values at each interpolation point + @param Trans Transformation from reference to physical coordinates + @param dofs Expansion coefficients for the approximation of vc + */ void Project_RT(const double *nk, const Array &d2n, Vector &vc, ElementTransformation &Trans, Vector &dofs) const; @@ -827,6 +871,19 @@ protected: const double *nk, const Array &d2n, MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const; + /** @brief Project vector-valued basis functions onto the RT basis functions + @param nk Face normal vectors for this element type + @param d2n Offset into nk for each degree of freedom + @param fe Vector-valued finite element basis + @param Trans Transformation from reference to physical coordinates + @param I Expansion coefficients for the approximation of each basis + function + + Note: If the FiniteElement, fe, is scalar-valued the projection will + assume that a FiniteElementSpace is being used to define a vector + field using the scalar basis functions for each component of the + vector field. + */ void Project_RT(const double *nk, const Array &d2n, const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &I) const; @@ -846,11 +903,25 @@ protected: const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &curl) const; + /** @brief Project a vector coefficient onto the ND basis functions + @param tk Edge tangent vectors for this element type + @param d2t Offset into tk for each degree of freedom + @param vc Vector coefficient to be projected + @param Trans Transformation from reference to physical coordinates + @param dofs Expansion coefficients for the approximation of vc + */ void Project_ND(const double *tk, const Array &d2t, VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const; /// Projects the vector of values given at FE nodes to ND space + /** Project vector values onto the ND basis functions + @param tk Edge tangent vectors for this element type + @param d2t Offset into tk for each degree of freedom + @param vc Vector values at each interpolation point + @param Trans Transformation from reference to physical coordinates + @param dofs Expansion coefficients for the approximation of vc + */ void Project_ND(const double *tk, const Array &d2t, Vector &vc, ElementTransformation &Trans, Vector &dofs) const; @@ -860,6 +931,19 @@ protected: const double *tk, const Array &d2t, MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const; + /** @brief Project vector-valued basis functions onto the ND basis functions + @param tk Edge tangent vectors for this element type + @param d2t Offset into tk for each degree of freedom + @param fe Vector-valued finite element basis + @param Trans Transformation from reference to physical coordinates + @param I Expansion coefficients for the approximation of each basis + function + + Note: If the FiniteElement, fe, is scalar-valued the projection will + assume that a FiniteElementSpace is being used to define a vector + field using the scalar basis functions for each component of the + vector field. + */ void Project_ND(const double *tk, const Array &d2t, const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &I) const; diff --git a/fem/fe_coll.cpp b/fem/fe_coll.cpp index 896811d57d..9ee809d989 100644 --- a/fem/fe_coll.cpp +++ b/fem/fe_coll.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -1854,19 +1854,16 @@ const int *H1_FECollection::GetDofMap(Geometry::Type GeomType) const { const int *dof_map = NULL; const FiniteElement *fe = H1_Elements[GeomType]; - switch (GeomType) + const NodalFiniteElement *nodal_fe = + dynamic_cast(fe); + if (nodal_fe) { - case Geometry::SEGMENT: - case Geometry::SQUARE: - case Geometry::CUBE: - dof_map = dynamic_cast(fe) - ->GetDofMap().GetData(); - break; - default: - MFEM_ABORT("Geometry type " << Geometry::Name[GeomType] << " is not " - "implemented"); - // The "Cartesian" ordering for other geometries is defined by the - // class GeometryRefiner. + dof_map = nodal_fe->GetLexicographicOrdering().GetData(); + } + else + { + MFEM_ABORT("Geometry type " << Geometry::Name[GeomType] << " is not " + "implemented"); } return dof_map; } @@ -1991,7 +1988,7 @@ L2_FECollection::L2_FECollection(const int p, const int dim, const int btype, // Trace element use the default Gauss-Legendre nodal points for positive basis if (b_type == BasisType::Positive) { - Tr_Elements[Geometry::SEGMENT] = new L2_SegmentElement(p); + Tr_Elements[Geometry::SEGMENT] = new L2Pos_SegmentElement(p); } else { @@ -2047,8 +2044,8 @@ L2_FECollection::L2_FECollection(const int p, const int dim, const int btype, // Trace element use the default Gauss-Legendre nodal points for positive basis if (b_type == BasisType::Positive) { - Tr_Elements[Geometry::TRIANGLE] = new L2_TriangleElement(p); - Tr_Elements[Geometry::SQUARE] = new L2_QuadrilateralElement(p); + Tr_Elements[Geometry::TRIANGLE] = new L2Pos_TriangleElement(p); + Tr_Elements[Geometry::SQUARE] = new L2Pos_QuadrilateralElement(p); } else { diff --git a/fem/fe_coll.hpp b/fem/fe_coll.hpp index 13de7cd562..da22ea9b63 100644 --- a/fem/fe_coll.hpp +++ b/fem/fe_coll.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/fem.hpp b/fem/fem.hpp index 3f7e5313d0..424c4c5b94 100644 --- a/fem/fem.hpp +++ b/fem/fem.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/fespace.cpp b/fem/fespace.cpp index 0626cb2c00..edb34a26a7 100644 --- a/fem/fespace.cpp +++ b/fem/fespace.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -2901,9 +2901,9 @@ const Operator &GridTransfer::MakeTrueOperator( else // Parallel() == true { #ifdef MFEM_USE_MPI - const SparseMatrix *out_R = fes_out.GetRestrictionMatrix(); if (oper_type == Operator::Hypre_ParCSR) { + const SparseMatrix *out_R = fes_out.GetRestrictionMatrix(); const ParFiniteElementSpace *pfes_in = dynamic_cast(&fes_in); const ParFiniteElementSpace *pfes_out = @@ -2931,6 +2931,7 @@ const Operator &GridTransfer::MakeTrueOperator( } else if (oper_type == Operator::ANY_TYPE) { + const Operator *out_R = fes_out.GetRestrictionOperator(); t_oper.Reset(new TripleProductOperator( out_R, &oper, fes_in.GetProlongationMatrix(), false, false, false)); diff --git a/fem/fespace.hpp b/fem/fespace.hpp index 4b01d685a8..fb2fa676d3 100644 --- a/fem/fespace.hpp +++ b/fem/fespace.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -350,6 +350,18 @@ public: virtual const Operator *GetProlongationMatrix() const { return GetConformingProlongation(); } + /// Return an operator that performs the transpose of GetRestrictionOperator + /** The returned operator is owned by the FiniteElementSpace. In serial this + is the same as GetProlongationMatrix() */ + virtual const Operator *GetRestrictionTransposeOperator() const + { return GetConformingProlongation(); } + + /// An abstract operator that performs the same action as GetRestrictionMatrix + /** In some cases this is an optimized matrix-free implementation. The + returned operator is owned by the FiniteElementSpace. */ + virtual const Operator *GetRestrictionOperator() const + { return GetConformingRestriction(); } + /// The returned SparseMatrix is owned by the FiniteElementSpace. virtual const SparseMatrix *GetRestrictionMatrix() const { return GetConformingRestriction(); } @@ -593,7 +605,7 @@ public: /** @brief Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th element in the mesh object. */ - const FiniteElement *GetFE(int i) const; + virtual const FiniteElement *GetFE(int i) const; /** @brief Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th boundary face in the mesh object. */ @@ -778,6 +790,9 @@ public: /// Return the total number of quadrature points. int GetSize() const { return size; } + /// Return the order of the quadrature rule(s) used by all elements. + int GetOrder() const { return order; } + /// Returns the mesh inline Mesh *GetMesh() const { return mesh; } diff --git a/fem/fespacehierarchy.cpp b/fem/fespacehierarchy.cpp index 477c419715..8dc80f52c3 100644 --- a/fem/fespacehierarchy.cpp +++ b/fem/fespacehierarchy.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/fespacehierarchy.hpp b/fem/fespacehierarchy.hpp index 36e11efa76..3956812700 100644 --- a/fem/fespacehierarchy.hpp +++ b/fem/fespacehierarchy.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/geom.cpp b/fem/geom.cpp index 089b7c15f7..fb5d1b910c 100644 --- a/fem/geom.cpp +++ b/fem/geom.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -1165,24 +1165,31 @@ RefinedGeometry * GeometryRefiner::Refine(Geometry::Type Geom, Array vi((n+1)*(n+1)*(n+1)); vi = -1; m = 0; - for (k = 0; k <= n; k++) - for (j = 0; j <= k; j++) - for (i = 0; i <= j; i++) + + // vertices are given in lexicographic ordering on the reference + // element + for (int kk = 0; kk <= n; kk++) + for (int jj = 0; jj <= n-kk; jj++) + for (int ii = 0; ii <= n-jj-kk; ii++) { IntegrationPoint &ip = RG->RefPts.IntPoint(m); - // map the coordinates to the reference tetrahedron - // (0,0,0) -> (0,0,0) - // (0,0,1) -> (1,0,0) - // (1,1,1) -> (0,1,0) - // (0,1,1) -> (0,0,1) - double w = cp[k-j] + cp[i] + cp[j-i] + cp[Times-k]; - ip.x = cp[k-j]/w; - ip.y = cp[i]/w; - ip.z = cp[j-i]/w; + double w = cp[ii] + cp[jj] + cp[kk] + cp[Times-ii-jj-kk]; + ip.x = cp[ii]/w; + ip.y = cp[jj]/w; + ip.z = cp[kk]/w; + // (ii,jj,kk) are coordinates in the reference tetrahedron, + // transform to coordinates (i,j,k) in the auxiliary + // tetrahedron defined by (0,0,0), (0,0,1), (1,1,1), (0,1,1) + int i = jj; + int j = jj+kk; + int k = ii+jj+kk; l = i + (j + k * (n+1)) * (n+1); + // map from linear Cartesian hex index in the auxiliary tet + // to lexicographic in the reference tet vi[l] = m; m++; } + if (m != (n+3)*(n+2)*(n+1)/6) { mfem_error("GeometryRefiner::Refine() for TETRAHEDRON #1"); @@ -1269,18 +1276,9 @@ RefinedGeometry * GeometryRefiner::Refine(Geometry::Type Geom, for (i = 0; i <= n-j; i++, l++) { IntegrationPoint &ip = RG->RefPts.IntPoint(l); - if (type == 0) - { - ip.x = double(i) / n; - ip.y = double(j) / n; - ip.z = double(k) / n; - } - else - { - ip.x = cp[i]/(cp[i] + cp[j] + cp[n-i-j]); - ip.y = cp[j]/(cp[i] + cp[j] + cp[n-i-j]); - ip.z = cp[k]; - } + ip.x = cp[i]/(cp[i] + cp[j] + cp[n-i-j]); + ip.y = cp[j]/(cp[i] + cp[j] + cp[n-i-j]); + ip.z = cp[k]; m++; } if (m != (n+1)*(n+1)*(n+2)/2) diff --git a/fem/geom.hpp b/fem/geom.hpp index 6a4dfce0a0..e24d643e30 100644 --- a/fem/geom.hpp +++ b/fem/geom.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/gridfunc.cpp b/fem/gridfunc.cpp index e9c8c93762..26b3159257 100644 --- a/fem/gridfunc.cpp +++ b/fem/gridfunc.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -15,6 +15,10 @@ #include "../mesh/nurbs.hpp" #include "../general/text.hpp" +#ifdef MFEM_USE_MPI +#include "pfespace.hpp" +#endif + #include #include #include @@ -22,6 +26,7 @@ #include #include + namespace mfem { @@ -57,6 +62,13 @@ GridFunction::GridFunction(Mesh *m, std::istream &input) else { Vector::Load(input, fes->GetVSize()); + + // if the mesh is a legacy (v1.1) NC mesh, it has old vertex ordering + if (fes->Nonconforming() && + fes->GetMesh()->ncmesh->IsLegacyLoaded()) + { + LegacyNCReorder(); + } } sequence = fes->GetSequence(); } @@ -507,8 +519,6 @@ const DofTransformation * doftrans = fes->GetElementDofs(i, dofs); fes->DofsToVDofs(vdim-1, dofs); const FiniteElement *FElem = fes->GetFE(i); - MFEM_ASSERT(FElem->GetMapType() == FiniteElement::VALUE, - "invalid FE map type"); int dof = FElem->GetDof(); Vector DofVal(dof), loc_data(dof); if (doftrans) @@ -522,10 +532,24 @@ const GetSubVector(dofs, loc_data); } for (int k = 0; k < n; k++) - { - FElem->CalcShape(ir.IntPoint(k), DofVal); - vals(k) = DofVal * loc_data; - } + if (FElem->GetMapType() == FiniteElement::VALUE) + { + for (int k = 0; k < n; k++) + { + FElem->CalcShape(ir.IntPoint(k), DofVal); + vals(k) = DofVal * loc_data; + } + } + else + { + ElementTransformation *Tr = fes->GetElementTransformation(i); + for (int k = 0; k < n; k++) + { + Tr->SetIntPoint(&ir.IntPoint(k)); + FElem->CalcPhysShape(*Tr, DofVal); + vals(k) = DofVal * loc_data; + } + } } void GridFunction::GetValues(int i, const IntegrationRule &ir, Vector &vals, @@ -1057,15 +1081,14 @@ void GridFunction::GetVectorValues(ElementTransformation &T, if (FElem->GetRangeType() == FiniteElement::SCALAR) { - MFEM_ASSERT(FElem->GetMapType() == FiniteElement::VALUE, - "invalid FE map type"); Vector shape(dof); int vdim = fes->GetVDim(); vals.SetSize(vdim, nip); for (int j = 0; j < nip; j++) { const IntegrationPoint &ip = ir.IntPoint(j); - FElem->CalcShape(ip, shape); + T.SetIntPoint(&ip); + FElem->CalcPhysShape(T, shape); for (int k = 0; k < vdim; k++) { @@ -1671,27 +1694,16 @@ void GridFunction::GetGradient(ElementTransformation &T, Vector &grad) const { case ElementTransformation::ELEMENT: { - const FiniteElement * fe = fes->GetFE(T.ElementNo); + const FiniteElement *fe = fes->GetFE(T.ElementNo); MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE, "invalid FE map type"); int spaceDim = fes->GetMesh()->SpaceDimension(); int dim = fe->GetDim(), dof = fe->GetDof(); DenseMatrix dshape(dof, dim); Vector lval, gh(dim); - Array dofs; grad.SetSize(spaceDim); - DofTransformation * doftrans = fes->GetElementDofs(T.ElementNo, dofs); - if (doftrans) - { - Vector lval_t; - GetSubVector(dofs, lval_t); - doftrans->InvTransformPrimal(lval_t, lval); - } - else - { - GetSubVector(dofs, lval); - } + GetElementDofValues(T.ElementNo, lval); fe->CalcDShape(T.GetIntPoint(), dshape); dshape.MultTranspose(lval, gh); T.InverseJacobian().MultTranspose(gh, grad); @@ -1888,6 +1900,22 @@ void GridFunction::GetElementAverages(GridFunction &avgs) const } } +void GridFunction::GetElementDofValues(int el, Vector &dof_vals) const +{ + Array dof_idx; + DofTransformation * doftrans = fes->GetElementVDofs(el, dof_idx); + if (doftrans) + { + Vector dof_vals_t; + GetSubVector(dof_idx, dof_vals_t); + doftrans->InvTransformPrimal(dof_vals_t, dof_vals); + } + else + { + GetSubVector(dof_idx, dof_vals); + } +} + void GridFunction::ProjectGridFunction(const GridFunction &src) { Mesh *mesh = fes->GetMesh(); @@ -3897,6 +3925,68 @@ std::ostream &operator<<(std::ostream &out, const GridFunction &sol) return out; } +void GridFunction::LegacyNCReorder() +{ + const Mesh* mesh = fes->GetMesh(); + MFEM_ASSERT(mesh->Nonconforming(), ""); + + // get the mapping (old_vertex_index -> new_vertex_index) + Array new_vertex, old_vertex; + mesh->ncmesh->LegacyToNewVertexOrdering(new_vertex); + MFEM_ASSERT(new_vertex.Size() == mesh->GetNV(), ""); + + // get the mapping (new_vertex_index -> old_vertex_index) + old_vertex.SetSize(new_vertex.Size()); + for (int i = 0; i < new_vertex.Size(); i++) + { + old_vertex[new_vertex[i]] = i; + } + + Vector tmp = *this; + + // reorder vertex DOFs + Array old_vdofs, new_vdofs; + for (int i = 0; i < mesh->GetNV(); i++) + { + fes->GetVertexVDofs(i, old_vdofs); + fes->GetVertexVDofs(new_vertex[i], new_vdofs); + + for (int j = 0; j < new_vdofs.Size(); j++) + { + tmp(new_vdofs[j]) = (*this)(old_vdofs[j]); + } + } + + // reorder edge DOFs -- edge orientation has changed too + Array dofs, ev; + for (int i = 0; i < mesh->GetNEdges(); i++) + { + mesh->GetEdgeVertices(i, ev); + if (old_vertex[ev[0]] > old_vertex[ev[1]]) + { + const int *ind = fec->DofOrderForOrientation(Geometry::SEGMENT, -1); + + fes->GetEdgeInteriorDofs(i, dofs); + for (int k = 0; k < dofs.Size(); k++) + { + int new_dof = dofs[k]; + int old_dof = dofs[(ind[k] < 0) ? -1-ind[k] : ind[k]]; + + for (int j = 0; j < fes->GetVDim(); j++) + { + int new_vdof = fes->DofToVDof(new_dof, j); + int old_vdof = fes->DofToVDof(old_dof, j); + + double sign = (ind[k] < 0) ? -1.0 : 1.0; + tmp(new_vdof) = sign * (*this)(old_vdof); + } + } + } + } + + Vector::Swap(tmp); +} + QuadratureFunction::QuadratureFunction(Mesh *mesh, std::istream &in) { @@ -4024,7 +4114,15 @@ double ZZErrorEstimator(BilinearFormIntegrator &blfi, } } } - +#ifdef MFEM_USE_MPI + auto pfes = dynamic_cast(ufes); + if (pfes) + { + auto process_local_error = total_error; + MPI_Allreduce(&process_local_error, &total_error, 1, MPI_DOUBLE, + MPI_SUM, pfes->GetComm()); + } +#endif // MFEM_USE_MPI return std::sqrt(total_error); } diff --git a/fem/gridfunc.hpp b/fem/gridfunc.hpp index 9b894c7ec9..9a384fd1cd 100644 --- a/fem/gridfunc.hpp +++ b/fem/gridfunc.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -67,6 +67,9 @@ protected: degree of freedom. */ void ProjectDiscCoefficient(VectorCoefficient &coeff, Array &dof_attr); + /// Loading helper. + void LegacyNCReorder(); + void Destroy(); public: @@ -325,6 +328,10 @@ public: Both FE spaces should be scalar and on the same mesh. */ void GetElementAverages(GridFunction &avgs) const; + /** Sets the output vector @a dof_vals to the values of the degrees of + freedom of element @a el. */ + virtual void GetElementDofValues(int el, Vector &dof_vals) const; + /** Impose the given bounds on the function's DOFs while preserving its local * integral (described in terms of the given weights) on the i'th element * through SLBPQ optimization. @@ -345,14 +352,30 @@ public: projection matrix. */ void ProjectGridFunction(const GridFunction &src); + /** @brief Project @a coeff Coefficient to @a this GridFunction. The + projection computation depends on the choice of the FiniteElementSpace + #fes. Note that this is usually interpolation at the degrees of freedom + in each element (not L2 projection). */ virtual void ProjectCoefficient(Coefficient &coeff); + /** @brief Project @a coeff Coefficient to @a this GridFunction, using one + element for each degree of freedom in @a dofs and nodal interpolation on + that element. */ void ProjectCoefficient(Coefficient &coeff, Array &dofs, int vd = 0); + /** @brief Project @a vcoeff VectorCoefficient to @a this GridFunction. The + projection computation depends on the choice of the FiniteElementSpace + #fes. Note that this is usually interpolation at the degrees of freedom + in each element (not L2 projection).*/ void ProjectCoefficient(VectorCoefficient &vcoeff); + /** @brief Project @a vcoeff VectorCoefficient to @a this GridFunction, using + one element for each degree of freedom in @a dofs and nodal interpolation + on that element. */ void ProjectCoefficient(VectorCoefficient &vcoeff, Array &dofs); + /** @brief Analogous to the version with argument @a vcoeff VectorCoefficient + but using an array of scalar coefficients for each component. */ void ProjectCoefficient(Coefficient *coeff[]); /** @brief Project a discontinuous vector coefficient as a grid function on @@ -462,11 +485,10 @@ public: /// Returns the Face Jumps error for L2 elements, with 1/h scaling. MFEM_DEPRECATED - virtual double ComputeDGFaceJumpError(Coefficient *exsol, - Coefficient *ell_coeff, - double Nu, - const IntegrationRule *irs[] = NULL) - const; + double ComputeDGFaceJumpError(Coefficient *exsol, + Coefficient *ell_coeff, + double Nu, + const IntegrationRule *irs[] = NULL) const; /** This method is kept for backward compatibility. diff --git a/fem/gslib.cpp b/fem/gslib.cpp index 31f514d580..27d9a95262 100644 --- a/fem/gslib.cpp +++ b/fem/gslib.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/gslib.hpp b/fem/gslib.hpp index 15598f42f2..89ee2ac092 100644 --- a/fem/gslib.hpp +++ b/fem/gslib.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/hybridization.cpp b/fem/hybridization.cpp index a3b9040125..0a3eb7bbc6 100644 --- a/fem/hybridization.cpp +++ b/fem/hybridization.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/hybridization.hpp b/fem/hybridization.hpp index cbe1e074ba..5fe211b314 100644 --- a/fem/hybridization.hpp +++ b/fem/hybridization.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/intrules.cpp b/fem/intrules.cpp index ea99fd3f2a..96d1c2f850 100644 --- a/fem/intrules.cpp +++ b/fem/intrules.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/intrules.hpp b/fem/intrules.hpp index 49c33a1959..b0a753517c 100644 --- a/fem/intrules.hpp +++ b/fem/intrules.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/libceed/ceed.cpp b/fem/libceed/ceed.cpp index c2fac02832..1004f6e653 100644 --- a/fem/libceed/ceed.cpp +++ b/fem/libceed/ceed.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/libceed/ceed.hpp b/fem/libceed/ceed.hpp index 58909450c6..909ee7821d 100644 --- a/fem/libceed/ceed.hpp +++ b/fem/libceed/ceed.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/libceed/diffusion.cpp b/fem/libceed/diffusion.cpp index a45adaaa5b..623351b49e 100644 --- a/fem/libceed/diffusion.cpp +++ b/fem/libceed/diffusion.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/libceed/diffusion.h b/fem/libceed/diffusion.h index d9d39ab03e..ff26a39f29 100644 --- a/fem/libceed/diffusion.h +++ b/fem/libceed/diffusion.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/libceed/diffusion.hpp b/fem/libceed/diffusion.hpp index ce014406e8..d9c53eab21 100644 --- a/fem/libceed/diffusion.hpp +++ b/fem/libceed/diffusion.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/libceed/mass.cpp b/fem/libceed/mass.cpp index ca9ec56ca6..dfa41b24ca 100644 --- a/fem/libceed/mass.cpp +++ b/fem/libceed/mass.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/libceed/mass.h b/fem/libceed/mass.h index 1bd0507715..653fc8ade1 100644 --- a/fem/libceed/mass.h +++ b/fem/libceed/mass.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/libceed/mass.hpp b/fem/libceed/mass.hpp index 84904cb656..93a62456a5 100644 --- a/fem/libceed/mass.hpp +++ b/fem/libceed/mass.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/linearform.cpp b/fem/linearform.cpp index cb9bf0b44c..f6661e51f0 100644 --- a/fem/linearform.cpp +++ b/fem/linearform.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/linearform.hpp b/fem/linearform.hpp index 5f13053cff..03bde70d72 100644 --- a/fem/linearform.hpp +++ b/fem/linearform.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/lininteg.cpp b/fem/lininteg.cpp index 0663ce7f03..022fd965a9 100644 --- a/fem/lininteg.cpp +++ b/fem/lininteg.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/lininteg.hpp b/fem/lininteg.hpp index 8ab13ee814..25dcf6aa3e 100644 --- a/fem/lininteg.hpp +++ b/fem/lininteg.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -406,6 +406,10 @@ private: Vector shape; public: + BoundaryFlowIntegrator(Coefficient &_f, VectorCoefficient &_u, + double a) + { f = &_f; u = &_u; alpha = a; beta = 0.5*a; } + BoundaryFlowIntegrator(Coefficient &_f, VectorCoefficient &_u, double a, double b) { f = &_f; u = &_u; alpha = a; beta = b; } diff --git a/fem/multigrid.cpp b/fem/multigrid.cpp index a7c15e1aa8..570dde9571 100644 --- a/fem/multigrid.cpp +++ b/fem/multigrid.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -14,11 +14,40 @@ namespace mfem { -Multigrid::Multigrid(const FiniteElementSpaceHierarchy& fespaces_) - : fespaces(fespaces_), cycleType(CycleType::VCYCLE), preSmoothingSteps(1), - postSmoothingSteps(1) +Multigrid::Multigrid() + : cycleType(CycleType::VCYCLE), preSmoothingSteps(1), postSmoothingSteps(1) {} +Multigrid::Multigrid(const Array& operators_, + const Array& smoothers_, + const Array& prolongations_, + const Array& ownedOperators_, + const Array& ownedSmoothers_, + const Array& ownedProlongations_) + : Solver(operators_.Last()->NumRows()), cycleType(CycleType::VCYCLE), + preSmoothingSteps(1), postSmoothingSteps(1), + X(operators_.Size()), Y(X.Size()), R(X.Size()), Z(X.Size()) +{ + operators_.Copy(operators); + smoothers_.Copy(smoothers); + prolongations_.Copy(prolongations); + ownedOperators_.Copy(ownedOperators); + ownedSmoothers_.Copy(ownedSmoothers); + ownedProlongations_.Copy(ownedProlongations); + + for (int level = 0; level < operators.Size(); ++level) + { + X[level] = new Vector(operators[level]->NumRows()); + *X[level] = 0.0; + Y[level] = new Vector(operators[level]->NumRows()); + *Y[level] = 0.0; + R[level] = new Vector(operators[level]->NumRows()); + *R[level] = 0.0; + Z[level] = new Vector(operators[level]->NumRows()); + *Z[level] = 0.0; + } +} + Multigrid::~Multigrid() { for (int i = 0; i < operators.Size(); ++i) @@ -37,26 +66,21 @@ Multigrid::~Multigrid() delete Z[i]; } + for (int i = 0; i < prolongations.Size(); ++i) + { + if (ownedProlongations[i]) + { + delete prolongations[i]; + } + } + operators.DeleteAll(); smoothers.DeleteAll(); + prolongations.DeleteAll(); X.DeleteAll(); Y.DeleteAll(); R.DeleteAll(); Z.DeleteAll(); - - for (int i = 0; i < bfs.Size(); ++i) - { - delete bfs[i]; - } - - bfs.DeleteAll(); - - for (int i = 0; i < essentialTrueDofs.Size(); ++i) - { - delete essentialTrueDofs[i]; - } - - essentialTrueDofs.DeleteAll(); } void Multigrid::AddLevel(Operator* opr, Solver* smoother, bool ownOperator, @@ -168,8 +192,7 @@ void Multigrid::Cycle(int level) const subtract(*X[level], *R[level], *R[level]); // Restrict residual - fespaces.GetProlongationAtLevel(level - 1)->MultTranspose(*R[level], - *X[level - 1]); + GetProlongationAtLevel(level - 1)->MultTranspose(*R[level], *X[level - 1]); // Init zeros *Y[level - 1] = 0.0; @@ -186,7 +209,7 @@ void Multigrid::Cycle(int level) const } // Prolongate - fespaces.GetProlongationAtLevel(level - 1)->Mult(*Y[level - 1], *R[level]); + GetProlongationAtLevel(level - 1)->Mult(*Y[level - 1], *R[level]); // Add update *Y[level] += *R[level]; @@ -198,16 +221,44 @@ void Multigrid::Cycle(int level) const } } -void Multigrid::FormFineLinearSystem(Vector& x, Vector& b, OperatorHandle& A, - Vector& X, Vector& B) +const Operator* Multigrid::GetProlongationAtLevel(int level) const +{ + return prolongations[level]; +} + +GeometricMultigrid::~GeometricMultigrid() +{ + for (int i = 0; i < bfs.Size(); ++i) + { + delete bfs[i]; + } + + bfs.DeleteAll(); + + for (int i = 0; i < essentialTrueDofs.Size(); ++i) + { + delete essentialTrueDofs[i]; + } + + essentialTrueDofs.DeleteAll(); +} + +void GeometricMultigrid::FormFineLinearSystem(Vector& x, Vector& b, + OperatorHandle& A, + Vector& X, Vector& B) { bfs.Last()->FormLinearSystem(*essentialTrueDofs.Last(), x, b, A, X, B); } -void Multigrid::RecoverFineFEMSolution(const Vector& X, const Vector& b, - Vector& x) +void GeometricMultigrid::RecoverFineFEMSolution(const Vector& X, + const Vector& b, Vector& x) { bfs.Last()->RecoverFEMSolution(X, b, x); } +const Operator* GeometricMultigrid::GetProlongationAtLevel(int level) const +{ + return fespaces.GetProlongationAtLevel(level); +} + } // namespace mfem diff --git a/fem/multigrid.hpp b/fem/multigrid.hpp index 66f249cdfd..b536a76d2c 100644 --- a/fem/multigrid.hpp +++ b/fem/multigrid.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -32,16 +32,13 @@ public: }; protected: - const FiniteElementSpaceHierarchy& fespaces; - Array*> essentialTrueDofs; - Array bfs; - -private: Array operators; Array smoothers; + Array prolongations; Array ownedOperators; Array ownedSmoothers; + Array ownedProlongations; CycleType cycleType; int preSmoothingSteps; @@ -53,8 +50,16 @@ private: mutable Array Z; public: - /// Constructs an empty multigrid for the given FiniteElementSpaceHierarchy - Multigrid(const FiniteElementSpaceHierarchy& fespaces_); + /// Constructs an empty multigrid hierarchy. + Multigrid(); + + /// Constructs a multigrid hierarchy from the given inputs. + /** Inputs include operators and smoothers on all levels, prolongation + operators that go from coarser to finer levels, and ownership of the + given operators, smoothers, and prolongations. */ + Multigrid(const Array& operators_, const Array& smoothers_, + const Array& prolongations_, const Array& ownedOperators_, + const Array& ownedSmoothers_, const Array& ownedProlongations_); /// Destructor virtual ~Multigrid(); @@ -89,7 +94,7 @@ public: /// Returns smoother at given level Solver* GetSmootherAtLevel(int level); - /// Set the cycle type and number of pre- and post-smoothing steps used by Mult + /// Set cycle type and number of pre- and post-smoothing steps used by Mult void SetCycleType(CycleType cycleType_, int preSmoothingSteps_, int postSmoothingSteps_); @@ -99,7 +104,36 @@ public: /// Not supported for multigrid virtual void SetOperator(const Operator& op) override; - /// Form the linear system A X = B, corresponding to the operator on the finest level +private: + /// Application of a smoothing step at particular level + void SmoothingStep(int level, bool transpose) const; + + /// Application of a multigrid cycle at particular level + void Cycle(int level) const; + + /// Returns prolongation operator at given level + virtual const Operator* GetProlongationAtLevel(int level) const; +}; + +/// Geometric multigrid associated with a hierarchy of finite element spaces +class GeometricMultigrid : public Multigrid +{ +protected: + const FiniteElementSpaceHierarchy& fespaces; + Array*> essentialTrueDofs; + Array bfs; + +public: + /** Construct an empty multigrid object for the given finite element space + hierarchy @a fespaces_ */ + GeometricMultigrid(const FiniteElementSpaceHierarchy& fespaces_) + : Multigrid(), fespaces(fespaces_) { } + + /// Destructor + virtual ~GeometricMultigrid(); + + /** Form the linear system A X = B, corresponding to the operator on the + finest level of the geometric multigrid hierarchy */ void FormFineLinearSystem(Vector& x, Vector& b, OperatorHandle& A, Vector& X, Vector& B); @@ -107,11 +141,8 @@ public: void RecoverFineFEMSolution(const Vector& X, const Vector& b, Vector& x); private: - /// Application of a smoothing step at particular level - void SmoothingStep(int level, bool transpose) const; - - /// Application of a cycle at particular level - void Cycle(int level) const; + /// Returns prolongation operator at given level + virtual const Operator* GetProlongationAtLevel(int level) const override; }; } // namespace mfem diff --git a/fem/nonlinearform.cpp b/fem/nonlinearform.cpp index a3f1bfa571..d1a8d4600e 100644 --- a/fem/nonlinearform.cpp +++ b/fem/nonlinearform.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/nonlinearform.hpp b/fem/nonlinearform.hpp index 0f61533ab0..ca35f1c4c3 100644 --- a/fem/nonlinearform.hpp +++ b/fem/nonlinearform.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/nonlinearform_ext.cpp b/fem/nonlinearform_ext.cpp index 027da610f9..8f15b5c67f 100644 --- a/fem/nonlinearform_ext.cpp +++ b/fem/nonlinearform_ext.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/nonlinearform_ext.hpp b/fem/nonlinearform_ext.hpp index aeb0c44d94..3f5396eade 100644 --- a/fem/nonlinearform_ext.hpp +++ b/fem/nonlinearform_ext.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/nonlininteg.cpp b/fem/nonlininteg.cpp index 3ca9c62135..35439187ff 100644 --- a/fem/nonlininteg.cpp +++ b/fem/nonlininteg.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -729,6 +729,7 @@ void VectorConvectionNLFIntegrator::AssembleElementVector( el.CalcPhysDShape(T, dshape); double w = ip.weight * T.Weight(); if (Q) { w *= Q->Eval(T, ip); } + MultAtB(EF, dshape, gradEF); EF.MultTranspose(shape, vec1); gradEF.Mult(vec1, vec2); @@ -743,8 +744,8 @@ void VectorConvectionNLFIntegrator::AssembleElementGrad( const Vector &elfun, DenseMatrix &elmat) { - int nd = el.GetDof(); - int dim = el.GetDim(); + const int nd = el.GetDof(); + const int dim = el.GetDim(); shape.SetSize(nd); dshape.SetSize(nd, dim); @@ -813,4 +814,109 @@ void VectorConvectionNLFIntegrator::AssembleElementGrad( } } + +void ConvectiveVectorConvectionNLFIntegrator::AssembleElementGrad( + const FiniteElement &el, + ElementTransformation &trans, + const Vector &elfun, + DenseMatrix &elmat) +{ + const int nd = el.GetDof(); + const int dim = el.GetDim(); + + shape.SetSize(nd); + dshape.SetSize(nd, dim); + dshapex.SetSize(nd, dim); + elmat.SetSize(nd * dim); + elmat_comp.SetSize(nd); + gradEF.SetSize(dim); + + EF.UseExternalData(elfun.GetData(), nd, dim); + + Vector vec1(dim), vec2(dim), vec3(nd); + + const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, trans); + + elmat = 0.0; + for (int i = 0; i < ir->GetNPoints(); i++) + { + const IntegrationPoint &ip = ir->IntPoint(i); + trans.SetIntPoint(&ip); + + el.CalcShape(ip, shape); + el.CalcDShape(ip, dshape); + + const double w = Q ? Q->Eval(trans, ip) * ip.weight : ip.weight; + + EF.MultTranspose(shape, vec1); // u^n + + trans.AdjugateJacobian().Mult(vec1, vec2); + + vec2 *= w; + dshape.Mult(vec2, vec3); // (u^n \cdot grad u^{n+1}) + MultVWt(shape, vec3, elmat_comp); // (u^n \cdot grad u^{n+1},v) + + for (int i = 0; i < dim; i++) + { + elmat.AddMatrix(elmat_comp, i * nd, i * nd); + } + } +} + + +void SkewSymmetricVectorConvectionNLFIntegrator::AssembleElementGrad( + const FiniteElement &el, + ElementTransformation &trans, + const Vector &elfun, + DenseMatrix &elmat) +{ + const int nd = el.GetDof(); + const int dim = el.GetDim(); + + shape.SetSize(nd); + dshape.SetSize(nd, dim); + dshapex.SetSize(nd, dim); + elmat.SetSize(nd * dim); + elmat_comp.SetSize(nd); + gradEF.SetSize(dim); + + DenseMatrix elmat_comp_T(nd); + + EF.UseExternalData(elfun.GetData(), nd, dim); + + Vector vec1(dim), vec2(dim), vec3(nd), vec4(dim), vec5(nd); + + const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, trans); + + elmat = 0.0; + elmat_comp_T = 0.0; + for (int i = 0; i < ir->GetNPoints(); i++) + { + const IntegrationPoint &ip = ir->IntPoint(i); + trans.SetIntPoint(&ip); + + el.CalcShape(ip, shape); + el.CalcDShape(ip, dshape); + + Mult(dshape, trans.InverseJacobian(), dshapex); + + const double w = Q ? Q->Eval(trans, ip) * ip.weight : ip.weight; + + EF.MultTranspose(shape, vec1); // u^n + + trans.AdjugateJacobian().Mult(vec1, vec2); + + vec2 *= w; + dshape.Mult(vec2, vec3); // (u^n \cdot grad u^{n+1}) + MultVWt(shape, vec3, elmat_comp); // (u^n \cdot grad u^{n+1},v) + elmat_comp_T.Transpose(elmat_comp); + + for (int i = 0; i < dim; i++) + { + elmat.AddMatrix(.5, elmat_comp, i * nd, i * nd); + elmat.AddMatrix(-.5, elmat_comp_T, i * nd, i * nd); + } + } +} + } diff --git a/fem/nonlininteg.hpp b/fem/nonlininteg.hpp index 5c9975455d..37b17c3124 100644 --- a/fem/nonlininteg.hpp +++ b/fem/nonlininteg.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -305,6 +305,7 @@ public: const Array2D &elmats); }; + class VectorConvectionNLFIntegrator : public NonlinearFormIntegrator { private: @@ -341,6 +342,51 @@ public: virtual void AddMultPA(const Vector &x, Vector &y) const; }; + +/** This class is used to assemble the convective form of the nonlinear term + arising in the Navier-Stokes equations \f$(u \cdot \nabla v, w )\f$ */ +class ConvectiveVectorConvectionNLFIntegrator : + public VectorConvectionNLFIntegrator +{ +private: + Coefficient *Q{}; + DenseMatrix dshape, dshapex, EF, gradEF, ELV, elmat_comp; + Vector shape; + +public: + ConvectiveVectorConvectionNLFIntegrator(Coefficient &q): Q(&q) { } + + ConvectiveVectorConvectionNLFIntegrator() = default; + + virtual void AssembleElementGrad(const FiniteElement &el, + ElementTransformation &trans, + const Vector &elfun, + DenseMatrix &elmat); +}; + + +/** This class is used to assemble the skew-symmetric form of the nonlinear term + arising in the Navier-Stokes equations + \f$.5*(u \cdot \nabla v, w ) - .5*(u \cdot \nabla w, v )\f$ */ +class SkewSymmetricVectorConvectionNLFIntegrator : + public VectorConvectionNLFIntegrator +{ +private: + Coefficient *Q{}; + DenseMatrix dshape, dshapex, EF, gradEF, ELV, elmat_comp; + Vector shape; + +public: + SkewSymmetricVectorConvectionNLFIntegrator(Coefficient &q): Q(&q) { } + + SkewSymmetricVectorConvectionNLFIntegrator() = default; + + virtual void AssembleElementGrad(const FiniteElement &el, + ElementTransformation &trans, + const Vector &elfun, + DenseMatrix &elmat); +}; + } #endif diff --git a/fem/nonlininteg_vectorconvection.cpp b/fem/nonlininteg_vectorconvection.cpp index 4a551984f1..50e390af6c 100644 --- a/fem/nonlininteg_vectorconvection.cpp +++ b/fem/nonlininteg_vectorconvection.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/occa.okl b/fem/occa.okl index ce9aa513d6..8197abf6b3 100644 --- a/fem/occa.okl +++ b/fem/occa.okl @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/pbilinearform.cpp b/fem/pbilinearform.cpp index fab3845e26..11bc26235b 100644 --- a/fem/pbilinearform.cpp +++ b/fem/pbilinearform.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -233,10 +233,13 @@ void ParBilinearForm::AssembleSharedFaces(int skip_zeros) void ParBilinearForm::Assemble(int skip_zeros) { - if (mat == NULL && fbfi.Size() > 0) + if (fbfi.Size() > 0) { pfes->ExchangeFaceNbrData(); - pAllocMat(); + if (!ext && mat == NULL) + { + pAllocMat(); + } } BilinearForm::Assemble(skip_zeros); @@ -565,6 +568,38 @@ HypreParMatrix* ParDiscreteLinearOperator::ParallelAssemble() const return RAP; } +void ParDiscreteLinearOperator::ParallelAssemble(OperatorHandle &A) +{ + // construct the rectangular block-diagonal matrix dA + OperatorHandle dA(A.Type()); + dA.MakeRectangularBlockDiag(domain_fes->GetComm(), + range_fes->GlobalVSize(), + domain_fes->GlobalVSize(), + range_fes->GetDofOffsets(), + domain_fes->GetDofOffsets(), + mat); + + OperatorHandle R_test_transpose(A.Type()), P_trial(A.Type()); + + // TODO - construct the Dof_TrueDof_Matrix directly in the required format. + R_test_transpose.ConvertFrom(range_fes->Dof_TrueDof_Matrix()); + P_trial.ConvertFrom(domain_fes->Dof_TrueDof_Matrix()); + + A.MakeRAP(R_test_transpose, dA, P_trial); +} + +void ParDiscreteLinearOperator::FormRectangularSystemMatrix(OperatorHandle &A) +{ + if (ext) + { + Array empty; + ext->FormRectangularSystemOperator(empty, empty, A); + return; + } + + mfem_error("not implemented!"); +} + void ParDiscreteLinearOperator::GetParBlocks(Array2D &blocks) const { diff --git a/fem/pbilinearform.hpp b/fem/pbilinearform.hpp index a3e19455e2..38e88ab754 100644 --- a/fem/pbilinearform.hpp +++ b/fem/pbilinearform.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -27,6 +27,7 @@ namespace mfem /// Class for parallel bilinear form class ParBilinearForm : public BilinearForm { + friend FABilinearFormExtension; protected: ParFiniteElementSpace *pfes; ///< Points to the same object as #fes @@ -160,6 +161,9 @@ public: /// Get the parallel finite element space prolongation matrix virtual const Operator *GetProlongation() const { return pfes->GetProlongationMatrix(); } + /// Get the transpose of GetRestriction, useful for matrix-free RAP + virtual const Operator *GetRestrictionTranspose() const + { return pfes->GetRestrictionTransposeOperator(); } /// Get the parallel finite element space restriction matrix virtual const Operator *GetRestriction() const { return pfes->GetRestrictionMatrix(); } @@ -246,6 +250,9 @@ public: @a A. */ void ParallelAssemble(OperatorHandle &A); + using MixedBilinearForm::FormRectangularSystemMatrix; + using MixedBilinearForm::FormRectangularLinearSystem; + /** @brief Return in @a A a parallel (on truedofs) version of this operator. This returns the same operator as FormRectangularLinearSystem(), but does @@ -301,10 +308,20 @@ public: /// Returns the matrix "assembled" on the true dofs HypreParMatrix *ParallelAssemble() const; + /** @brief Returns the matrix assembled on the true dofs, i.e. + @a A = R_test A_local P_trial, in the format (type id) specified by + @a A. */ + void ParallelAssemble(OperatorHandle &A); + /** Extract the parallel blocks corresponding to the vector dimensions of the domain and range parallel finite element spaces */ void GetParBlocks(Array2D &blocks) const; + using MixedBilinearForm::FormRectangularSystemMatrix; + + /** @brief Return in @a A a parallel (on truedofs) version of this operator. */ + virtual void FormRectangularSystemMatrix(OperatorHandle &A); + virtual ~ParDiscreteLinearOperator() { } }; diff --git a/fem/pfespace.cpp b/fem/pfespace.cpp index 345eb5cae8..e16800d66d 100644 --- a/fem/pfespace.cpp +++ b/fem/pfespace.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -91,7 +91,7 @@ ParNURBSExtension *ParFiniteElementSpace::MakeLocalNURBSext( void ParFiniteElementSpace::ParInit(ParMesh *pm) { pmesh = pm; - pncmesh = pm->pncmesh; + pncmesh = NULL; MyComm = pmesh->GetComm(); NRanks = pmesh->GetNRanks(); @@ -101,6 +101,8 @@ void ParFiniteElementSpace::ParInit(ParMesh *pm) P = NULL; Pconf = NULL; + Rconf = NULL; + R_transpose = NULL; R = NULL; num_face_nbr_dofs = -1; @@ -145,6 +147,8 @@ void ParFiniteElementSpace::Construct() } else // Nonconforming() { + pncmesh = pmesh->pncmesh; + // Initialize 'gcomm' for the cut (aka "partially conforming") space. // In the process, the array 'ldof_ltdof' is also initialized (for the cut // space) and used; however, it will be overwritten below with the real @@ -523,6 +527,12 @@ void ParFiniteElementSpace::GetFaceDofs(int i, Array &dofs) const } } +const FiniteElement *ParFiniteElementSpace::GetFE(int i) const +{ + int ne = mesh->GetNE(); + if (i >= ne) { return GetFaceNbrFE(i - ne); } + else { return FiniteElementSpace::GetFE(i); } +} const Operator *ParFiniteElementSpace::GetFaceRestriction( ElementDofOrdering e_ordering, FaceType type, L2FaceValues mul) const @@ -1153,6 +1163,45 @@ const Operator *ParFiniteElementSpace::GetProlongationMatrix() const } } +const Operator *ParFiniteElementSpace::GetRestrictionOperator() const +{ + if (Conforming()) + { + if (Rconf) { return Rconf; } + + if (NRanks == 1) + { + R_transpose = new IdentityOperator(GetTrueVSize()); + } + else + { + if (!Device::Allows(Backend::DEVICE_MASK)) + { + R_transpose = new ConformingProlongationOperator(*this, true); + } + else + { + R_transpose = + new DeviceConformingProlongationOperator(*this, true); + } + } + Rconf = new TransposeOperator(R_transpose); + return Rconf; + } + else + { + Dof_TrueDof_Matrix(); + R_transpose = new TransposeOperator(R); + return R; + } +} + +const Operator *ParFiniteElementSpace::GetRestrictionTransposeOperator() const +{ + GetRestrictionOperator(); + return R_transpose; +} + void ParFiniteElementSpace::ExchangeFaceNbrData() { if (num_face_nbr_dofs >= 0) { return; } @@ -3087,6 +3136,8 @@ void ParFiniteElementSpace::Destroy() delete P; P = NULL; delete Pconf; Pconf = NULL; + delete Rconf; Rconf = NULL; + delete R_transpose; R_transpose = NULL; delete R; R = NULL; delete gcomm; gcomm = NULL; @@ -3217,12 +3268,12 @@ void ParFiniteElementSpace::Update(bool want_transform) } } - ConformingProlongationOperator::ConformingProlongationOperator( - const ParFiniteElementSpace &pfes) + const ParFiniteElementSpace &pfes, bool local_) : Operator(pfes.GetVSize(), pfes.GetTrueVSize()), external_ldofs(), - gc(pfes.GroupComm()) + gc(pfes.GroupComm()), + local(local_) { MFEM_VERIFY(pfes.Conforming(), ""); const Table &group_ldof = gc.GroupLDofTable(); @@ -3271,7 +3322,14 @@ void ConformingProlongationOperator::Mult(const Vector &x, Vector &y) const const int m = external_ldofs.Size(); const int in_layout = 2; // 2 - input is ltdofs array - gc.BcastBegin(const_cast(xdata), in_layout); + if (local) + { + y = 0.0; + } + else + { + gc.BcastBegin(const_cast(xdata), in_layout); + } int j = 0; for (int i = 0; i < m; i++) @@ -3283,7 +3341,10 @@ void ConformingProlongationOperator::Mult(const Vector &x, Vector &y) const std::copy(xdata+j-m, xdata+Width(), ydata+j); const int out_layout = 0; // 0 - output is ldofs array - gc.BcastEnd(ydata, out_layout); + if (!local) + { + gc.BcastEnd(ydata, out_layout); + } } void ConformingProlongationOperator::MultTranspose( @@ -3296,7 +3357,10 @@ void ConformingProlongationOperator::MultTranspose( double *ydata = y.HostWrite(); const int m = external_ldofs.Size(); - gc.ReduceBegin(xdata); + if (!local) + { + gc.ReduceBegin(xdata); + } int j = 0; for (int i = 0; i < m; i++) @@ -3308,13 +3372,18 @@ void ConformingProlongationOperator::MultTranspose( std::copy(xdata+j, xdata+Height(), ydata+j-m); const int out_layout = 2; // 2 - output is an array on all ltdofs - gc.ReduceEnd(ydata, out_layout, GroupCommunicator::Sum); + if (!local) + { + gc.ReduceEnd(ydata, out_layout, GroupCommunicator::Sum); + } } DeviceConformingProlongationOperator::DeviceConformingProlongationOperator( - const ParFiniteElementSpace &pfes) : + const ParFiniteElementSpace &pfes, + bool local_) : ConformingProlongationOperator(pfes), - mpi_gpu_aware(Device::GetGPUAwareMPI()) + mpi_gpu_aware(Device::GetGPUAwareMPI()), + local(local_) { MFEM_ASSERT(pfes.Conforming(), "internal error"); const SparseMatrix *R = pfes.GetRestrictionMatrix(); @@ -3431,32 +3500,42 @@ void DeviceConformingProlongationOperator::Mult(const Vector &x, Vector &y) const { const GroupTopology >opo = gc.GetGroupTopology(); - BcastBeginCopy(x); // copy to 'shr_buf' int req_counter = 0; - for (int nbr = 1; nbr < gtopo.GetNumNeighbors(); nbr++) + if (local) { - const int send_offset = shr_buf_offsets[nbr]; - const int send_size = shr_buf_offsets[nbr+1] - send_offset; - if (send_size > 0) + y = 0.0; + } + else + { + BcastBeginCopy(x); // copy to 'shr_buf' + for (int nbr = 1; nbr < gtopo.GetNumNeighbors(); nbr++) { - auto send_buf = mpi_gpu_aware ? shr_buf.Read() : shr_buf.HostRead(); - MPI_Isend(send_buf + send_offset, send_size, MPI_DOUBLE, - gtopo.GetNeighborRank(nbr), 41822, - gtopo.GetComm(), &requests[req_counter++]); - } - const int recv_offset = ext_buf_offsets[nbr]; - const int recv_size = ext_buf_offsets[nbr+1] - recv_offset; - if (recv_size > 0) - { - auto recv_buf = mpi_gpu_aware ? ext_buf.Write() : ext_buf.HostWrite(); - MPI_Irecv(recv_buf + recv_offset, recv_size, MPI_DOUBLE, - gtopo.GetNeighborRank(nbr), 41822, - gtopo.GetComm(), &requests[req_counter++]); + const int send_offset = shr_buf_offsets[nbr]; + const int send_size = shr_buf_offsets[nbr+1] - send_offset; + if (send_size > 0) + { + auto send_buf = mpi_gpu_aware ? shr_buf.Read() : shr_buf.HostRead(); + MPI_Isend(send_buf + send_offset, send_size, MPI_DOUBLE, + gtopo.GetNeighborRank(nbr), 41822, + gtopo.GetComm(), &requests[req_counter++]); + } + const int recv_offset = ext_buf_offsets[nbr]; + const int recv_size = ext_buf_offsets[nbr+1] - recv_offset; + if (recv_size > 0) + { + auto recv_buf = mpi_gpu_aware ? ext_buf.Write() : ext_buf.HostWrite(); + MPI_Irecv(recv_buf + recv_offset, recv_size, MPI_DOUBLE, + gtopo.GetNeighborRank(nbr), 41822, + gtopo.GetComm(), &requests[req_counter++]); + } } } BcastLocalCopy(x, y); - MPI_Waitall(req_counter, requests, MPI_STATUSES_IGNORE); - BcastEndCopy(y); // copy from 'ext_buf' + if (!local) + { + MPI_Waitall(req_counter, requests, MPI_STATUSES_IGNORE); + BcastEndCopy(y); // copy from 'ext_buf' + } } DeviceConformingProlongationOperator::~DeviceConformingProlongationOperator() @@ -3519,32 +3598,38 @@ void DeviceConformingProlongationOperator::MultTranspose(const Vector &x, Vector &y) const { const GroupTopology >opo = gc.GetGroupTopology(); - ReduceBeginCopy(x); // copy to 'ext_buf' int req_counter = 0; - for (int nbr = 1; nbr < gtopo.GetNumNeighbors(); nbr++) + if (!local) { - const int send_offset = ext_buf_offsets[nbr]; - const int send_size = ext_buf_offsets[nbr+1] - send_offset; - if (send_size > 0) + ReduceBeginCopy(x); // copy to 'ext_buf' + for (int nbr = 1; nbr < gtopo.GetNumNeighbors(); nbr++) { - auto send_buf = mpi_gpu_aware ? ext_buf.Read() : ext_buf.HostRead(); - MPI_Isend(send_buf + send_offset, send_size, MPI_DOUBLE, - gtopo.GetNeighborRank(nbr), 41823, - gtopo.GetComm(), &requests[req_counter++]); - } - const int recv_offset = shr_buf_offsets[nbr]; - const int recv_size = shr_buf_offsets[nbr+1] - recv_offset; - if (recv_size > 0) - { - auto recv_buf = mpi_gpu_aware ? shr_buf.Write() : shr_buf.HostWrite(); - MPI_Irecv(recv_buf + recv_offset, recv_size, MPI_DOUBLE, - gtopo.GetNeighborRank(nbr), 41823, - gtopo.GetComm(), &requests[req_counter++]); + const int send_offset = ext_buf_offsets[nbr]; + const int send_size = ext_buf_offsets[nbr+1] - send_offset; + if (send_size > 0) + { + auto send_buf = mpi_gpu_aware ? ext_buf.Read() : ext_buf.HostRead(); + MPI_Isend(send_buf + send_offset, send_size, MPI_DOUBLE, + gtopo.GetNeighborRank(nbr), 41823, + gtopo.GetComm(), &requests[req_counter++]); + } + const int recv_offset = shr_buf_offsets[nbr]; + const int recv_size = shr_buf_offsets[nbr+1] - recv_offset; + if (recv_size > 0) + { + auto recv_buf = mpi_gpu_aware ? shr_buf.Write() : shr_buf.HostWrite(); + MPI_Irecv(recv_buf + recv_offset, recv_size, MPI_DOUBLE, + gtopo.GetNeighborRank(nbr), 41823, + gtopo.GetComm(), &requests[req_counter++]); + } } } ReduceLocalCopy(x, y); - MPI_Waitall(req_counter, requests, MPI_STATUSES_IGNORE); - ReduceEndAssemble(y); // assemble from 'shr_buf' + if (!local) + { + MPI_Waitall(req_counter, requests, MPI_STATUSES_IGNORE); + ReduceEndAssemble(y); // assemble from 'shr_buf' + } } } // namespace mfem diff --git a/fem/pfespace.hpp b/fem/pfespace.hpp index 3c4941ff1f..8798947183 100644 --- a/fem/pfespace.hpp +++ b/fem/pfespace.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -75,6 +75,12 @@ private: /// The (block-diagonal) matrix R (restriction of dof to true dof). Owned. mutable SparseMatrix *R; + /// Optimized action-only restriction operator for conforming meshes. Owned. + mutable Operator *Rconf; + /** Transpose of R or Rconf. For conforming mesh, this is a matrix-free + (Device)ConformingProlongationOperator, for a non-conforming mesh + this is a TransposeOperator wrapping R. */ + mutable Operator *R_transpose; /// Flag indicating the existence of shared triangles with interior ND dofs bool nd_strias; @@ -274,6 +280,12 @@ public: including the dofs for the edges and the vertices of the face. */ virtual void GetFaceDofs(int i, Array &dofs) const; + /** Returns pointer to the FiniteElement in the FiniteElementCollection + associated with i'th element in the mesh object. If @a i is greater than + or equal to the number of local mesh elements, @a i will be interpreted + as a shifted index of a face neigbor element. */ + virtual const FiniteElement *GetFE(int i) const; + /** Returns an Operator that converts L-vectors to E-vectors on each face. The parallel version is different from the serial one because of the presence of shared faces. Shared faces are treated as interior faces, @@ -345,6 +357,16 @@ public: HYPRE_Int GetMyTDofOffset() const; virtual const Operator *GetProlongationMatrix() const; + /** @brief Return logical transpose of restriction matrix, but in + non-assembled optimized matrix-free form. + + The implementation is like GetProlongationMatrix, but it sets local + DOFs to the true DOF values if owned locally, otherwise zero. */ + virtual const Operator *GetRestrictionTransposeOperator() const; + /** Get an Operator that performs the action of GetRestrictionMatrix(), + but potentially with a non-assembled optimized matrix-free + implementation. */ + virtual const Operator *GetRestrictionOperator() const; /// Get the R matrix which restricts a local dof vector to true dof vector. virtual const SparseMatrix *GetRestrictionMatrix() const { Dof_TrueDof_Matrix(); return R; } @@ -401,9 +423,11 @@ class ConformingProlongationOperator : public Operator protected: Array external_ldofs; const GroupCommunicator &gc; + bool local; public: - ConformingProlongationOperator(const ParFiniteElementSpace &pfes); + ConformingProlongationOperator(const ParFiniteElementSpace &pfes, + bool local_=false); virtual void Mult(const Vector &x, Vector &y) const; @@ -422,6 +446,8 @@ protected: Array ltdof_ldof, unq_ltdof; Array unq_shr_i, unq_shr_j; MPI_Request *requests; + bool local; + // Kernel: copy ltdofs from 'src' to 'shr_buf' - prepare for send. // shr_buf[i] = src[shr_ltdof[i]] void BcastBeginCopy(const Vector &src) const; @@ -447,7 +473,8 @@ protected: void ReduceEndAssemble(Vector &dst) const; public: - DeviceConformingProlongationOperator(const ParFiniteElementSpace &pfes); + DeviceConformingProlongationOperator(const ParFiniteElementSpace &pfes, + bool local_=false); virtual ~DeviceConformingProlongationOperator(); diff --git a/fem/pgridfunc.cpp b/fem/pgridfunc.cpp index 1668df76dc..64035cda26 100644 --- a/fem/pgridfunc.cpp +++ b/fem/pgridfunc.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -491,6 +491,25 @@ void ParGridFunction::GetVectorValue(ElementTransformation &T, } } +void ParGridFunction::GetElementDofValues(int el, Vector &dof_vals) const +{ + int ne = fes->GetNE(); + if (el >= ne) + { + MFEM_ASSERT(face_nbr_data.Size() > 0, + "ParGridFunction::GetElementDofValues: ExchangeFaceNbrData " + "must be called before accessing face neighbor elements."); + // Face neighbor element + Array dof_idx; + pfes->GetFaceNbrElementVDofs(el - ne, dof_idx); + face_nbr_data.GetSubVector(dof_idx, dof_vals); + } + else + { + GridFunction::GetElementDofValues(el, dof_vals); + } +} + void ParGridFunction::ProjectCoefficient(Coefficient &coeff) { DeltaCoefficient *delta_c = dynamic_cast(&coeff); diff --git a/fem/pgridfunc.hpp b/fem/pgridfunc.hpp index d9d7d0a9cf..bc8e08ae15 100644 --- a/fem/pgridfunc.hpp +++ b/fem/pgridfunc.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -221,6 +221,12 @@ public: const IntegrationPoint &ip, Vector &val, Vector *tr = NULL) const; + /** Sets the output vector @a dof_vals to the values of the degrees of + freedom of element @a el. If @a el is greater than or equal to the number + of local elements, it will be interpreted as a shifted index of a face + neighbor element. */ + virtual void GetElementDofValues(int el, Vector &dof_vals) const; + using GridFunction::ProjectCoefficient; virtual void ProjectCoefficient(Coefficient &coeff); diff --git a/fem/plinearform.cpp b/fem/plinearform.cpp index 7696741710..5e2f75354e 100644 --- a/fem/plinearform.cpp +++ b/fem/plinearform.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/plinearform.hpp b/fem/plinearform.hpp index a08cbd3bfb..5fb53a69c2 100644 --- a/fem/plinearform.hpp +++ b/fem/plinearform.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/pnonlinearform.cpp b/fem/pnonlinearform.cpp index 5ba1734e70..19453aaa39 100644 --- a/fem/pnonlinearform.cpp +++ b/fem/pnonlinearform.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/pnonlinearform.hpp b/fem/pnonlinearform.hpp index 4c705a347d..47e3d59d0f 100644 --- a/fem/pnonlinearform.hpp +++ b/fem/pnonlinearform.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/prestriction.cpp b/fem/prestriction.cpp index 32054f888c..60394c0adb 100644 --- a/fem/prestriction.cpp +++ b/fem/prestriction.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -334,6 +334,35 @@ static MFEM_HOST_DEVICE int AddNnz(const int iE, int *I, const int dofs) return val; } +void ParL2FaceRestriction::FillI(SparseMatrix &mat, + const bool keep_nbr_block) const +{ + if (keep_nbr_block) + { + return L2FaceRestriction::FillI(mat, keep_nbr_block); + } + const int face_dofs = dof; + const int Ndofs = ndofs; + auto d_indices1 = scatter_indices1.Read(); + auto d_indices2 = scatter_indices2.Read(); + auto I = mat.ReadWriteI(); + MFEM_FORALL(fdof, nf*face_dofs, + { + const int f = fdof/face_dofs; + const int iF = fdof%face_dofs; + const int iE1 = d_indices1[f*face_dofs+iF]; + if (iE1 < Ndofs) + { + AddNnz(iE1,I,face_dofs); + } + const int iE2 = d_indices2[f*face_dofs+iF]; + if (iE2 < Ndofs) + { + AddNnz(iE2,I,face_dofs); + } + }); +} + void ParL2FaceRestriction::FillI(SparseMatrix &mat, SparseMatrix &face_mat) const { @@ -386,6 +415,51 @@ void ParL2FaceRestriction::FillI(SparseMatrix &mat, }); } +void ParL2FaceRestriction::FillJAndData(const Vector &ea_data, + SparseMatrix &mat, + const bool keep_nbr_block) const +{ + if (keep_nbr_block) + { + return L2FaceRestriction::FillJAndData(ea_data, mat, keep_nbr_block); + } + const int face_dofs = dof; + const int Ndofs = ndofs; + auto d_indices1 = scatter_indices1.Read(); + auto d_indices2 = scatter_indices2.Read(); + auto mat_fea = Reshape(ea_data.Read(), face_dofs, face_dofs, 2, nf); + auto I = mat.ReadWriteI(); + auto J = mat.WriteJ(); + auto Data = mat.WriteData(); + MFEM_FORALL(fdof, nf*face_dofs, + { + const int f = fdof/face_dofs; + const int iF = fdof%face_dofs; + const int iE1 = d_indices1[f*face_dofs+iF]; + if (iE1 < Ndofs) + { + const int offset = AddNnz(iE1,I,face_dofs); + for (int jF = 0; jF < face_dofs; jF++) + { + const int jE2 = d_indices2[f*face_dofs+jF]; + J[offset+jF] = jE2; + Data[offset+jF] = mat_fea(jF,iF,1,f); + } + } + const int iE2 = d_indices2[f*face_dofs+iF]; + if (iE2 < Ndofs) + { + const int offset = AddNnz(iE2,I,face_dofs); + for (int jF = 0; jF < face_dofs; jF++) + { + const int jE1 = d_indices1[f*face_dofs+jF]; + J[offset+jF] = jE1; + Data[offset+jF] = mat_fea(jF,iF,0,f); + } + } + }); +} + void ParL2FaceRestriction::FillJAndData(const Vector &ea_data, SparseMatrix &mat, SparseMatrix &face_mat) const diff --git a/fem/prestriction.hpp b/fem/prestriction.hpp index 0319d4908f..3844206692 100644 --- a/fem/prestriction.hpp +++ b/fem/prestriction.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -34,13 +34,23 @@ public: L2FaceValues m = L2FaceValues::DoubleValued); void Mult(const Vector &x, Vector &y) const; /** Fill the I array of SparseMatrix corresponding to the sparsity pattern - given by this ParL2FaceRestriction. */ - void FillI(SparseMatrix &mat, SparseMatrix &face_mat) const; + given by this L2FaceRestriction. */ + virtual void FillI(SparseMatrix &mat, const bool keep_nbr_block = false) const; + /** Fill the I array of SparseMatrix corresponding to the sparsity pattern + given by this L2FaceRestriction. @a mat contains the interior dofs + contribution, the @a face_mat contains the shared dofs contribution.*/ + virtual void FillI(SparseMatrix &mat, SparseMatrix &face_mat) const; /** Fill the J and Data arrays of SparseMatrix corresponding to the sparsity - pattern given by this ParL2FaceRestriction, and the values of ea_data. */ - void FillJAndData(const Vector &ea_data, - SparseMatrix &mat, - SparseMatrix &face_mat) const; + pattern given by this L2FaceRestriction, and the values of ea_data. + @a mat contains the interior dofs contribution, the @a face_mat contains + the shared dofs contribution.*/ + virtual void FillJAndData(const Vector &ea_data, + SparseMatrix &mat, + SparseMatrix &face_mat) const; + + virtual void FillJAndData(const Vector &ea_data, + SparseMatrix &mat, + const bool keep_nbr_block = false) const; }; } diff --git a/fem/quadinterpolator.cpp b/fem/quadinterpolator.cpp index 90b441402d..07c450e01d 100644 --- a/fem/quadinterpolator.cpp +++ b/fem/quadinterpolator.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -420,6 +420,35 @@ void QuadratureInterpolator::MultTranspose( MFEM_ABORT("this method is not implemented yet"); } +static void D2QValues1D(const int NE, + const Array &b_, + const Vector &x_, + Vector &y_, + const int vdim = 1, + const int d1d = 0, + const int q1d = 0) +{ + auto b = Reshape(b_.Read(), q1d, d1d); + auto x = Reshape(x_.Read(), d1d, vdim, NE); + auto y = Reshape(y_.Write(), vdim, q1d, NE); + + MFEM_FORALL(e, NE, + { + for (int c = 0; c < vdim; c++) + { + for (int q = 0; q < q1d; ++q) + { + double val = 0.0; + for (int d = 0; d < d1d; ++d) + { + val += b(q, d) * x(d, c, e); + } + y(c, q, e) = val; + } + } + }); +} + template static void D2QValues2D(const int NE, @@ -631,6 +660,15 @@ static void D2QValues(const FiniteElementSpace &fes, const int Q1D = maps->nqpt; const int id = (vdim<<8) | (D1D<<4) | Q1D; + if (dim == 1) + { + MFEM_VERIFY(D1D <= MAX_D1D, "Orders higher than " << MAX_D1D-1 + << " are not supported!"); + MFEM_VERIFY(Q1D <= MAX_Q1D, "Quadrature rules with more than " + << MAX_Q1D << " 1D points are not supported!"); + D2QValues1D(NE, maps->B, e_vec, q_val, vdim, D1D, Q1D); + return; + } if (dim == 2) { switch (id) diff --git a/fem/quadinterpolator.hpp b/fem/quadinterpolator.hpp index 9d63b05d8c..d928047ea9 100644 --- a/fem/quadinterpolator.hpp +++ b/fem/quadinterpolator.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/quadinterpolator_face.cpp b/fem/quadinterpolator_face.cpp index 3d1994a7d7..3d4c810f1e 100644 --- a/fem/quadinterpolator_face.cpp +++ b/fem/quadinterpolator_face.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/quadinterpolator_face.hpp b/fem/quadinterpolator_face.hpp index 96aa9a7db9..30ffb680b3 100644 --- a/fem/quadinterpolator_face.hpp +++ b/fem/quadinterpolator_face.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/restriction.cpp b/fem/restriction.cpp index 82f076ed15..63b955dfe0 100644 --- a/fem/restriction.cpp +++ b/fem/restriction.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -195,6 +195,31 @@ void ElementRestriction::MultTransposeUnsigned(const Vector& x, Vector& y) const }); } +void ElementRestriction::MultLeftInverse(const Vector& x, Vector& y) const +{ + // Assumes all elements have the same number of dofs + const int nd = dof; + const int vd = vdim; + const bool t = byvdim; + auto d_offsets = offsets.Read(); + auto d_indices = indices.Read(); + auto d_x = Reshape(x.Read(), nd, vd, ne); + auto d_y = Reshape(y.Write(), t?vd:ndofs, t?ndofs:vd); + MFEM_FORALL(i, ndofs, + { + const int nextOffset = d_offsets[i + 1]; + for (int c = 0; c < vd; ++c) + { + double dofValue = 0; + const int j = nextOffset - 1; + const int idx_j = (d_indices[j] >= 0) ? d_indices[j] : -1 - d_indices[j]; + dofValue = (d_indices[j] >= 0) ? d_x(idx_j % nd, c, idx_j / nd) : + -d_x(idx_j % nd, c, idx_j / nd); + d_y(t?c:i,t?i:c) = dofValue; + } + }); +} + void ElementRestriction::BooleanMask(Vector& y) const { // Assumes all elements have the same number of dofs @@ -500,9 +525,11 @@ void L2ElementRestriction::FillI(SparseMatrix &mat) const const int elem_dofs = ndof; const int vd = vdim; auto I = mat.WriteI(); - MFEM_FORALL(dof, ne*elem_dofs*vd, + const int isize = mat.Height() + 1; + const int interior_dofs = ne*elem_dofs*vd; + MFEM_FORALL(dof, isize, { - I[dof] = elem_dofs; + I[dof] = dof ie; public: - TMOP_Metric_022(double &t0): tau0(t0) {} + TMOP_Metric_022(double &t0): min_detT(t0) {} // W = 0.5(|J|^2 - 2det(J)) / (det(J) - tau0). virtual double EvalW(const DenseMatrix &Jpt) const; @@ -474,7 +474,45 @@ protected: mutable InvariantsEvaluator3D ie; public: - // W = |J|^2 / 3 * det(J)^(2/3) - 1. + // W = |J|^2 / 3 * det(J)^(-2/3) - 1. + virtual double EvalW(const DenseMatrix &Jpt) const; + + virtual void EvalP(const DenseMatrix &Jpt, DenseMatrix &P) const; + + virtual void AssembleH(const DenseMatrix &Jpt, const DenseMatrix &DS, + const double weight, DenseMatrix &A) const; +}; + +/// 3D Size (V) untangling metric. +class TMOP_Metric_311 : public TMOP_QualityMetric +{ +protected: + const double eps; + mutable InvariantsEvaluator3D ie; + +public: + TMOP_Metric_311(double epsilon = 1e-4) : eps(epsilon) { } + + // W = (det(J) - 1)^2 - det(J) + (det(J)^2 + eps)^(1/2). + virtual double EvalW(const DenseMatrix &Jpt) const; + + virtual void EvalP(const DenseMatrix &Jpt, DenseMatrix &P) const; + + virtual void AssembleH(const DenseMatrix &Jpt, const DenseMatrix &DS, + const double weight, DenseMatrix &A) const; +}; + +/// 3D Shape (S) metric, untangling version of 303. +class TMOP_Metric_313 : public TMOP_QualityMetric +{ +protected: + double &min_detT; + mutable InvariantsEvaluator3D ie; + +public: + TMOP_Metric_313(double &mindet) : min_detT(mindet) { } + + // W = 1/3 |J|^2 / [det(J)-tau0]^(-2/3). virtual double EvalW(const DenseMatrix &Jpt) const; virtual void EvalP(const DenseMatrix &Jpt, DenseMatrix &P) const; diff --git a/fem/tmop_tools.cpp b/fem/tmop_tools.cpp index dc1a716c84..5a774f3b41 100644 --- a/fem/tmop_tools.cpp +++ b/fem/tmop_tools.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -331,10 +331,6 @@ double TMOPNewtonSolver::ComputeScalingFactor(const Vector &x, energy_in = nlf->GetEnergy(x); } - const int NE = fes->GetMesh()->GetNE(), dim = fes->GetMesh()->Dimension(); - Array xdofs; - DenseMatrix Jpr(dim); - // Get the local prolongation of the solution vector. Vector x_out_loc(fes->GetVSize()); if (serial) @@ -350,51 +346,32 @@ double TMOPNewtonSolver::ComputeScalingFactor(const Vector &x, } #endif - // Check if the starting mesh (given by x) is inverted. - // Note that x hasn't been modified by the Newton update yet. - double min_detJ = infinity(); - for (int i = 0; i < NE; i++) + // Check if the starting mesh (given by x) is inverted. Note that x hasn't + // been modified by the Newton update yet. + const double min_detT_in = ComputeMinDet(x_out_loc, *fes); + const bool untangling = (min_detT_in <= 0.0) ? true : false; + const double untangle_factor = 1.5; + if (untangling) { - const int dof = fes->GetFE(i)->GetDof(); - DenseMatrix dshape(dof, dim), pos(dof, dim); - Vector posV(pos.Data(), dof * dim); - - fes->GetElementVDofs(i, xdofs); - x_out_loc.GetSubVector(xdofs, posV); - - const IntegrationRule &irule = GetIntegrationRule(*fes->GetFE(i)); - const int nsp = irule.GetNPoints(); - for (int j = 0; j < nsp; j++) - { - fes->GetFE(i)->CalcDShape(irule.IntPoint(j), dshape); - MultAtB(pos, dshape, Jpr); - min_detJ = std::min(min_detJ, Jpr.Det()); - } + // Needed for the line search below. The untangling metrics see this + // reference to detect deteriorations. + *min_det_ptr = untangle_factor * min_detT_in; } - double min_detJ_all = min_detJ; -#ifdef MFEM_USE_MPI - if (parallel) - { - MPI_Allreduce(&min_detJ, &min_detJ_all, 1, MPI_DOUBLE, MPI_MIN, - p_nlf->ParFESpace()->GetComm()); - } -#endif - const bool untangling = (min_detJ_all <= 0) ? true : false; const bool have_b = (b.Size() == Height()); Vector x_out(x.Size()); bool x_out_ok = false; - double scale = 1.0, energy_out = 0.0; - const double norm0 = Norm(r); + double scale = 1.0, energy_out = 0.0, min_detT_out; + const double norm_in = Norm(r); const double detJ_factor = (solver_type == 1) ? 0.25 : 0.5; // Perform the line search. for (int i = 0; i < 12; i++) { + // Update the mesh and get the L-vector in x_out_loc. add(x, -scale, c, x_out); - if (serial) { const SparseMatrix *cP = fes->GetConformingProlongation(); @@ -408,47 +385,29 @@ double TMOPNewtonSolver::ComputeScalingFactor(const Vector &x, } #endif - // Check det(Jpr) > 0. - if (!untangling) + // Check the changes in detJ. + min_detT_out = ComputeMinDet(x_out_loc, *fes); + if (untangling == false && min_detT_out < 0.0) { - int jac_ok = 1; - for (int i = 0; i < NE; i++) - { - const int dof = fes->GetFE(i)->GetDof(); - DenseMatrix dshape(dof, dim), pos(dof, dim); - Vector posV(pos.Data(), dof * dim); + // No untangling, and detJ got negative -- no good. + if (print_level >= 0) + { mfem::out << "Scale = " << scale << " Neg det(J) found.\n"; } + scale *= detJ_factor; continue; + } + if (untangling == true && min_detT_out < *min_det_ptr) + { + // Untangling, and detJ got even more negative -- no good. + if (print_level >= 0) + { mfem::out << "Scale = " << scale << " Neg det(J) decreased.\n"; } + scale *= detJ_factor; continue; + } - fes->GetElementVDofs(i, xdofs); - x_out_loc.GetSubVector(xdofs, posV); - - const IntegrationRule &irule = GetIntegrationRule(*fes->GetFE(i)); - const int nsp = irule.GetNPoints(); - for (int j = 0; j < nsp; j++) - { - fes->GetFE(i)->CalcDShape(irule.IntPoint(j), dshape); - MultAtB(pos, dshape, Jpr); - if (Jpr.Det() <= 0.0) { jac_ok = 0; goto break2; } - } - } - - break2: - int jac_ok_all = jac_ok; -#ifdef MFEM_USE_MPI - if (parallel) - { - MPI_Allreduce(&jac_ok, &jac_ok_all, 1, MPI_INT, MPI_LAND, - p_nlf->ParFESpace()->GetComm()); - } -#endif - - if (jac_ok_all == 0) - { - if (print_level >= 0) - { mfem::out << "Scale = " << scale << " Neg det(J) found.\n"; } - scale *= detJ_factor; continue; - } - } // endif(!untangling) + // Skip the energy and residual checks when we're untangling. The + // untangling metrics change their denominators, which can affect the + // energy and residual, so their increase/decrease is not relevant. + if (untangling) { x_out_ok = true; break; } + // Check the changes in total energy. ProcessNewState(x_out); if (serial) { @@ -460,43 +419,55 @@ double TMOPNewtonSolver::ComputeScalingFactor(const Vector &x, energy_out = p_nlf->GetParGridFunctionEnergy(x_out_loc); } #endif - - if (untangling) + if (energy_out > 1.2*energy_in || std::isnan(energy_out) != 0) { - if (energy_out > energy_in || std::isnan(energy_out) != 0) + if (print_level >= 0) { - scale *= 0.5; + mfem::out << "Scale = " << scale << " Increasing energy.\n"; } - else { x_out_ok = true; break; } + scale *= 0.5; continue; } - else + + // Check the changes in the Newton residual. + oper->Mult(x_out, r); + if (have_b) { r -= b; } + double norm_out = Norm(r); + + if (norm_out > 1.2*norm_in) { - if (energy_out > 1.2*energy_in || std::isnan(energy_out) != 0) - { - if (print_level >= 0) - { mfem::out << "Scale = " << scale << " Increasing energy.\n"; } - scale *= 0.5; continue; - } + if (print_level >= 0) + { mfem::out << "Scale = " << scale << " Norm increased.\n"; } + scale *= 0.5; continue; + } + else { x_out_ok = true; break; } + } // end line search - oper->Mult(x_out, r); - if (have_b) { r -= b; } - double norm = Norm(r); - - if (norm > 1.2*norm0) - { - if (print_level >= 0) - { mfem::out << "Scale = " << scale << " Norm increased.\n"; } - scale *= 0.5; continue; - } - else { x_out_ok = true; break; } - } // endif (untangling) - } // enddo (i) + if (untangling) + { + // Update the global min detJ. Untangling metrics see this min_det_ptr. + if (min_detT_out > 0.0) + { + *min_det_ptr = 0.0; + if (print_level >= 0) + { mfem::out << "The mesh has been untangled at the used points!\n"; } + } + else { *min_det_ptr = untangle_factor * min_detT_out; } + } if (print_level >= 0) { - mfem::out << "Energy decrease: " - << (energy_in - energy_out) / energy_in * 100.0 - << "% with " << scale << " scaling.\n"; + if (untangling) + { + mfem::out << "Min det(T) change: " + << min_detT_in << " -> " << min_detT_out + << " with " << scale << " scaling.\n"; + } + else + { + mfem::out << "Energy decrease: " + << (energy_in - energy_out) / energy_in * 100.0 + << "% with " << scale << " scaling.\n"; + } } if (x_out_ok == false) { scale = 0.0; } @@ -508,8 +479,8 @@ void TMOPNewtonSolver::ProcessNewState(const Vector &x) const const NonlinearForm *nlf = dynamic_cast(oper); const Array &integs = *nlf->GetDNFI(); - // Reset the update flags of all TargetConstructors. - // This is done to avoid repeated updates of shared TargetConstructors. + // Reset the update flags of all TargetConstructors. This is done to avoid + // repeated updates of shared TargetConstructors. TMOP_Integrator *ti = NULL; TMOPComboIntegrator *co = NULL; DiscreteAdaptTC *dtc = NULL; @@ -617,6 +588,47 @@ void TMOPNewtonSolver::UpdateDiscreteTC(const TMOP_Integrator &ti, } } +double TMOPNewtonSolver::ComputeMinDet(const Vector &x_loc, + const FiniteElementSpace &fes) const +{ + double min_detJ = infinity(); + const int NE = fes.GetNE(), dim = fes.GetMesh()->Dimension(); + Array xdofs; + DenseMatrix Jpr(dim); + for (int i = 0; i < NE; i++) + { + const int dof = fes.GetFE(i)->GetDof(); + DenseMatrix dshape(dof, dim), pos(dof, dim); + Vector posV(pos.Data(), dof * dim); + + fes.GetElementVDofs(i, xdofs); + x_loc.GetSubVector(xdofs, posV); + + const IntegrationRule &irule = GetIntegrationRule(*fes.GetFE(i)); + const int nsp = irule.GetNPoints(); + for (int j = 0; j < nsp; j++) + { + fes.GetFE(i)->CalcDShape(irule.IntPoint(j), dshape); + MultAtB(pos, dshape, Jpr); + min_detJ = std::min(min_detJ, Jpr.Det()); + } + } + double min_detT_all = min_detJ; +#ifdef MFEM_USE_MPI + if (parallel) + { + auto p_nlf = dynamic_cast(oper); + MPI_Allreduce(&min_detJ, &min_detT_all, 1, MPI_DOUBLE, MPI_MIN, + p_nlf->ParFESpace()->GetComm()); + } +#endif + const DenseMatrix &Wideal = + Geometries.GetGeomToPerfGeomJac(fes.GetFE(0)->GetGeomType()); + min_detT_all /= Wideal.Det(); + + return min_detT_all; +} + #ifdef MFEM_USE_MPI // Metric values are visualized by creating an L2 finite element functions and // computing the metric values at the nodes. diff --git a/fem/tmop_tools.hpp b/fem/tmop_tools.hpp index 8f90409955..67bcd80a83 100644 --- a/fem/tmop_tools.hpp +++ b/fem/tmop_tools.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -114,6 +114,9 @@ protected: int solver_type; bool parallel; + // Minimum determinant over the whole mesh. Used for mesh untangling. + double *min_det_ptr = nullptr; + // Quadrature points that are checked for negative Jacobians etc. const IntegrationRule &ir; // These fields are relevant for mixed meshes. @@ -131,6 +134,9 @@ protected: void UpdateDiscreteTC(const TMOP_Integrator &ti, const Vector &x_new) const; + double ComputeMinDet(const Vector &x_loc, + const FiniteElementSpace &fes) const; + public: #ifdef MFEM_USE_MPI TMOPNewtonSolver(MPI_Comm comm, const IntegrationRule &irule, int type = 0) @@ -150,6 +156,8 @@ public: integ_order = order; } + void SetMinDetPtr(double *md_ptr) { min_det_ptr = md_ptr; } + virtual double ComputeScalingFactor(const Vector &x, const Vector &b) const; virtual void ProcessNewState(const Vector &x) const; diff --git a/fem/transfer.cpp b/fem/transfer.cpp index edbd9866db..1a93d5be93 100644 --- a/fem/transfer.cpp +++ b/fem/transfer.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/fem/transfer.hpp b/fem/transfer.hpp index 620a64ce96..613f6315a3 100644 --- a/fem/transfer.hpp +++ b/fem/transfer.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/CMakeLists.txt b/general/CMakeLists.txt index df6cd1dba9..bab5334c06 100644 --- a/general/CMakeLists.txt +++ b/general/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # @@ -27,7 +27,9 @@ list(APPEND SRCS stable3d.cpp table.cpp tic_toc.cpp + tinyxml2.cpp version.cpp + hip.cpp ) list(APPEND HDRS @@ -55,8 +57,10 @@ list(APPEND HDRS table.hpp tassign.hpp tic_toc.hpp + tinyxml2.h text.hpp version.hpp + hip.hpp ) if (MFEM_USE_MPI) diff --git a/general/adios2stream.cpp b/general/adios2stream.cpp index 8dc3088f0b..0a12b7256a 100644 --- a/general/adios2stream.cpp +++ b/general/adios2stream.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/adios2stream.hpp b/general/adios2stream.hpp index 08a9e5b172..7230cbbbec 100644 --- a/general/adios2stream.hpp +++ b/general/adios2stream.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/array.cpp b/general/array.cpp index ace1b07975..38b4312c71 100644 --- a/general/array.cpp +++ b/general/array.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/array.hpp b/general/array.hpp index 46c7f6684f..3757f47624 100644 --- a/general/array.hpp +++ b/general/array.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/backends.hpp b/general/backends.hpp index 1b6372cf5e..7ad37064d0 100644 --- a/general/backends.hpp +++ b/general/backends.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/binaryio.cpp b/general/binaryio.cpp index 2752975c1b..62c225dbf3 100644 --- a/general/binaryio.cpp +++ b/general/binaryio.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/binaryio.hpp b/general/binaryio.hpp index 75a2300202..70362ff886 100644 --- a/general/binaryio.hpp +++ b/general/binaryio.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/communication.cpp b/general/communication.cpp index 7e177b7b85..a84aaffbf7 100644 --- a/general/communication.cpp +++ b/general/communication.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/communication.hpp b/general/communication.hpp index 8542420822..68501fade1 100644 --- a/general/communication.hpp +++ b/general/communication.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/cuda.cpp b/general/cuda.cpp index c796eff880..f15e133dd2 100644 --- a/general/cuda.cpp +++ b/general/cuda.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/cuda.hpp b/general/cuda.hpp index e26d6031d2..42b30d8e33 100644 --- a/general/cuda.hpp +++ b/general/cuda.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/device.cpp b/general/device.cpp index badcd745be..20647e74f1 100644 --- a/general/device.cpp +++ b/general/device.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -43,7 +43,7 @@ CeedRestrMap ceed_restr_map; static const Backend::Id backend_list[Backend::NUM_BACKENDS] = { Backend::CEED_CUDA, Backend::OCCA_CUDA, Backend::RAJA_CUDA, Backend::CUDA, - Backend::CEED_HIP, Backend::HIP, Backend::DEBUG_DEVICE, + Backend::CEED_HIP, Backend::RAJA_HIP, Backend::HIP, Backend::DEBUG_DEVICE, Backend::OCCA_OMP, Backend::RAJA_OMP, Backend::OMP, Backend::CEED_CPU, Backend::OCCA_CPU, Backend::RAJA_CPU, Backend::CPU }; @@ -52,7 +52,7 @@ static const Backend::Id backend_list[Backend::NUM_BACKENDS] = static const char *backend_name[Backend::NUM_BACKENDS] = { "ceed-cuda", "occa-cuda", "raja-cuda", "cuda", - "ceed-hip", "hip", "debug", + "ceed-hip", "raja-hip", "hip", "debug", "occa-omp", "raja-omp", "omp", "ceed-cpu", "occa-cpu", "raja-cpu", "cpu" }; @@ -394,6 +394,8 @@ static void RajaDeviceSetup(const int dev, int &ngpu) { #ifdef MFEM_USE_CUDA if (ngpu <= 0) { DeviceSetup(dev, ngpu); } +#elif defined(MFEM_USE_HIP) + HipDeviceSetup(dev, ngpu); #else MFEM_CONTRACT_VAR(dev); MFEM_CONTRACT_VAR(ngpu); @@ -507,7 +509,8 @@ void Device::Setup(const int device) #endif if (Allows(Backend::CUDA)) { CudaDeviceSetup(dev, ngpu); } if (Allows(Backend::HIP)) { HipDeviceSetup(dev, ngpu); } - if (Allows(Backend::RAJA_CUDA)) { RajaDeviceSetup(dev, ngpu); } + if (Allows(Backend::RAJA_CUDA) || Allows(Backend::RAJA_HIP)) + { RajaDeviceSetup(dev, ngpu); } // The check for MFEM_USE_OCCA is in the function OccaDeviceSetup(). if (Allows(Backend::OCCA_MASK)) { OccaDeviceSetup(dev); } if (Allows(Backend::CEED_CPU)) diff --git a/general/device.hpp b/general/device.hpp index 1c702c8a0e..eb9e148aad 100644 --- a/general/device.hpp +++ b/general/device.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -46,30 +46,33 @@ struct Backend /** @brief [device] RAJA CUDA backend. Enabled when MFEM_USE_RAJA = YES and MFEM_USE_CUDA = YES. */ RAJA_CUDA = 1 << 6, + /** @brief [device] RAJA HIP backend. Enabled when MFEM_USE_RAJA = YES + and MFEM_USE_HIP = YES. */ + RAJA_HIP = 1 << 7, /** @brief [host] OCCA CPU backend: sequential execution on each MPI rank. Enabled when MFEM_USE_OCCA = YES. */ - OCCA_CPU = 1 << 7, + OCCA_CPU = 1 << 8, /// [host] OCCA OpenMP backend. Enabled when MFEM_USE_OCCA = YES. - OCCA_OMP = 1 << 8, + OCCA_OMP = 1 << 9, /** @brief [device] OCCA CUDA backend. Enabled when MFEM_USE_OCCA = YES and MFEM_USE_CUDA = YES. */ - OCCA_CUDA = 1 << 9, + OCCA_CUDA = 1 << 10, /** @brief [host] CEED CPU backend. GPU backends can still be used, but with expensive memory transfers. Enabled when MFEM_USE_CEED = YES. */ - CEED_CPU = 1 << 10, + CEED_CPU = 1 << 11, /** @brief [device] CEED CUDA backend working together with the CUDA backend. Enabled when MFEM_USE_CEED = YES and MFEM_USE_CUDA = YES. NOTE: The current default libCEED CUDA backend is non-deterministic! */ - CEED_CUDA = 1 << 11, + CEED_CUDA = 1 << 12, /** @brief [device] CEED HIP backend working together with the HIP backend. Enabled when MFEM_USE_CEED = YES and MFEM_USE_HIP = YES. */ - CEED_HIP = 1 << 12, + CEED_HIP = 1 << 13, /** @brief [device] Debug backend: host memory is READ/WRITE protected while a device is in use. It allows to test the "device" code-path (using separate host/device memory pools and host <-> device transfers) without any GPU hardware. As 'DEBUG' is sometimes used as a macro, `_DEVICE` has been added to avoid conflicts. */ - DEBUG_DEVICE = 1 << 13 + DEBUG_DEVICE = 1 << 14 }; /** @brief Additional useful constants. For example, the *_MASK constants can @@ -77,14 +80,14 @@ struct Backend enum { /// Number of backends: from (1 << 0) to (1 << (NUM_BACKENDS-1)). - NUM_BACKENDS = 14, + NUM_BACKENDS = 15, /// Biwise-OR of all CPU backends CPU_MASK = CPU | RAJA_CPU | OCCA_CPU | CEED_CPU, /// Biwise-OR of all CUDA backends CUDA_MASK = CUDA | RAJA_CUDA | OCCA_CUDA | CEED_CUDA, /// Biwise-OR of all HIP backends - HIP_MASK = HIP | CEED_HIP, + HIP_MASK = HIP | RAJA_HIP | CEED_HIP, /// Biwise-OR of all OpenMP backends OMP_MASK = OMP | RAJA_OMP | OCCA_OMP, /// Bitwise-OR of all CEED backends @@ -93,7 +96,7 @@ struct Backend DEVICE_MASK = CUDA_MASK | HIP_MASK | DEBUG_DEVICE, /// Biwise-OR of all RAJA backends - RAJA_MASK = RAJA_CPU | RAJA_OMP | RAJA_CUDA, + RAJA_MASK = RAJA_CPU | RAJA_OMP | RAJA_CUDA | RAJA_HIP, /// Biwise-OR of all OCCA backends OCCA_MASK = OCCA_CPU | OCCA_OMP | OCCA_CUDA }; diff --git a/general/error.cpp b/general/error.cpp index 0e74fc2527..559e76757a 100644 --- a/general/error.cpp +++ b/general/error.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/error.hpp b/general/error.hpp index e7e29d9fbe..957aef944d 100644 --- a/general/error.hpp +++ b/general/error.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/forall.hpp b/general/forall.hpp index 05b67692bc..2048479a72 100644 --- a/general/forall.hpp +++ b/general/forall.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -31,7 +31,7 @@ const int MAX_Q1D = 14; // MFEM_UNROLL pragma macro that can be used inside MFEM_FORALL macros. #if defined(MFEM_USE_CUDA) -#define MFEM_UNROLL(N) MFEM_PRAGMA(unroll N) +#define MFEM_UNROLL(N) MFEM_PRAGMA(unroll(N)) #else #define MFEM_UNROLL(N) #endif @@ -86,77 +86,157 @@ void OmpWrap(const int N, HBODY &&h_body) } -/// RAJA Cuda backend +/// RAJA Cuda and Hip backends #if defined(MFEM_USE_RAJA) && defined(RAJA_ENABLE_CUDA) - -#if RAJA_VERSION_MAJOR == 0 && RAJA_VERSION_MINOR < 12 -using RAJA::statement::Segs; -#else -using RAJA::Segs; +using cuda_launch_policy = + RAJA::expt::LaunchPolicy>; +using cuda_teams_x = + RAJA::expt::LoopPolicy; +using cuda_threads_z = + RAJA::expt::LoopPolicy; #endif +#if defined(MFEM_USE_RAJA) && defined(RAJA_ENABLE_HIP) +using hip_launch_policy = + RAJA::expt::LaunchPolicy>; +using hip_teams_x = + RAJA::expt::LoopPolicy; +using hip_threads_z = + RAJA::expt::LoopPolicy; +#endif + +#if defined(MFEM_USE_RAJA) && defined(RAJA_ENABLE_CUDA) template -void RajaCudaWrap1D(const int N, DBODY &&d_body) +void RajaCuWrap1D(const int N, DBODY &&d_body) { - // true denotes asynchronous kernel + //true denotes asynchronous kernel RAJA::forall>(RAJA::RangeSegment(0,N),d_body); } template -void RajaCudaWrap2D(const int N, DBODY &&d_body, - const int X, const int Y, const int BZ) +void RajaCuWrap2D(const int N, DBODY &&d_body, + const int X, const int Y, const int BZ) { MFEM_VERIFY(N>0, ""); MFEM_VERIFY(BZ>0, ""); const int G = (N+BZ-1)/BZ; - RAJA::kernel>>>>>>>> - (RAJA::make_tuple(RAJA::RangeSegment(0,G), RAJA::RangeSegment(0,X), - RAJA::RangeSegment(0,Y), RAJA::RangeSegment(0,BZ)), - [=] RAJA_DEVICE (const int n) + + using namespace RAJA::expt; + using RAJA::RangeSegment; + + launch + (DEVICE, Resources(Teams(G), Threads(X, Y, BZ)), + [=] RAJA_DEVICE (LaunchContext ctx) { - const int k = n*BZ + threadIdx.z; - if (k >= N) { return; } - d_body(k); + + loop(ctx, RangeSegment(0, G), [&] (const int n) + { + + loop(ctx, RangeSegment(0, BZ), [&] (const int tz) + { + + const int k = n*BZ + tz; + if (k >= N) { return; } + d_body(k); + + }); + + }); + }); + MFEM_GPU_CHECK(cudaGetLastError()); } template -void RajaCudaWrap3D(const int N, DBODY &&d_body, - const int X, const int Y, const int Z) +void RajaCuWrap3D(const int N, DBODY &&d_body, + const int X, const int Y, const int Z) { MFEM_VERIFY(N>0, ""); - RAJA::kernel>>>>>>>> - (RAJA::make_tuple(RAJA::RangeSegment(0,N), RAJA::RangeSegment(0,X), - RAJA::RangeSegment(0,Y), RAJA::RangeSegment(0,Z)), - [=] RAJA_DEVICE (const int k) { d_body(k); }); + using namespace RAJA::expt; + using RAJA::RangeSegment; + + launch + (DEVICE, Resources(Teams(N), Threads(X, Y, Z)), + [=] RAJA_DEVICE (LaunchContext ctx) + { + + loop(ctx, RangeSegment(0, N), d_body); + + }); + MFEM_GPU_CHECK(cudaGetLastError()); } #endif +#if defined(MFEM_USE_RAJA) && defined(RAJA_ENABLE_HIP) +template +void RajaHipWrap1D(const int N, DBODY &&d_body) +{ + //true denotes asynchronous kernel + RAJA::forall>(RAJA::RangeSegment(0,N),d_body); +} + +template +void RajaHipWrap2D(const int N, DBODY &&d_body, + const int X, const int Y, const int BZ) +{ + MFEM_VERIFY(N>0, ""); + MFEM_VERIFY(BZ>0, ""); + const int G = (N+BZ-1)/BZ; + + using namespace RAJA::expt; + using RAJA::RangeSegment; + + launch + (DEVICE, Resources(Teams(G), Threads(X, Y, BZ)), + [=] RAJA_DEVICE (LaunchContext ctx) + { + + loop(ctx, RangeSegment(0, G), [&] (const int n) + { + + loop(ctx, RangeSegment(0, BZ), [&] (const int tz) + { + + const int k = n*BZ + tz; + if (k >= N) { return; } + d_body(k); + + }); + + }); + + }); + + MFEM_GPU_CHECK(hipGetLastError()); +} + +template +void RajaHipWrap3D(const int N, DBODY &&d_body, + const int X, const int Y, const int Z) +{ + MFEM_VERIFY(N>0, ""); + using namespace RAJA::expt; + using RAJA::RangeSegment; + + launch + (DEVICE, Resources(Teams(N), Threads(X, Y, Z)), + [=] RAJA_DEVICE (LaunchContext ctx) + { + + loop(ctx, RangeSegment(0, N), d_body); + + }); + + MFEM_GPU_CHECK(hipGetLastError()); +} +#endif /// RAJA OpenMP backend #if defined(MFEM_USE_RAJA) && defined(RAJA_ENABLE_OPENMP) -#if RAJA_VERSION_MAJOR == 0 && RAJA_VERSION_MINOR < 12 -using RAJA::statement::Segs; -#else -using RAJA::Segs; -#endif - template void RajaOmpWrap(const int N, HBODY &&h_body) { @@ -319,9 +399,19 @@ inline void ForallWrap(const bool use_dev, const int N, // If Backend::RAJA_CUDA is allowed, use it if (Device::Allows(Backend::RAJA_CUDA)) { - if (DIM == 1) { return RajaCudaWrap1D(N, d_body); } - if (DIM == 2) { return RajaCudaWrap2D(N, d_body, X, Y, Z); } - if (DIM == 3) { return RajaCudaWrap3D(N, d_body, X, Y, Z); } + if (DIM == 1) { return RajaCuWrap1D(N, d_body); } + if (DIM == 2) { return RajaCuWrap2D(N, d_body, X, Y, Z); } + if (DIM == 3) { return RajaCuWrap3D(N, d_body, X, Y, Z); } + } +#endif + +#if defined(MFEM_USE_RAJA) && defined(RAJA_ENABLE_HIP) + // If Backend::RAJA_HIP is allowed, use it + if (Device::Allows(Backend::RAJA_HIP)) + { + if (DIM == 1) { return RajaHipWrap1D(N, d_body); } + if (DIM == 2) { return RajaHipWrap2D(N, d_body, X, Y, Z); } + if (DIM == 3) { return RajaHipWrap3D(N, d_body, X, Y, Z); } } #endif diff --git a/general/gecko.cpp b/general/gecko.cpp index 46e41517e4..930fa3a67a 100644 --- a/general/gecko.cpp +++ b/general/gecko.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -19,7 +19,7 @@ // BSD 3-Clause License // -// Copyright (c) 2019-2020, Lawrence Livermore National Security, LLC +// Copyright (c) 2019-2021, Lawrence Livermore National Security, LLC // All rights reserved. // // Redistribution and use in source and binary forms, with or without @@ -49,7 +49,7 @@ // ------------------------------------------------------------------------------ -// Copyright (c) 2019-2020, Lawrence Livermore National Security, LLC and other +// Copyright (c) 2019-2021, Lawrence Livermore National Security, LLC and other // gecko project contributors. See the above license for details. // SPDX-License-Identifier: BSD-3-Clause // LLNL-CODE-800597 diff --git a/general/gecko.hpp b/general/gecko.hpp index 2eea6598ef..d2e80ffbe1 100644 --- a/general/gecko.hpp +++ b/general/gecko.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -20,7 +20,7 @@ // BSD 3-Clause License // -// Copyright (c) 2019-2020, Lawrence Livermore National Security, LLC +// Copyright (c) 2019-2021, Lawrence Livermore National Security, LLC // All rights reserved. // // Redistribution and use in source and binary forms, with or without @@ -50,7 +50,7 @@ // ------------------------------------------------------------------------------ -// Copyright (c) 2019-2020, Lawrence Livermore National Security, LLC and other +// Copyright (c) 2019-2021, Lawrence Livermore National Security, LLC and other // gecko project contributors. See the above license for details. // SPDX-License-Identifier: BSD-3-Clause // LLNL-CODE-800597 diff --git a/general/globals.cpp b/general/globals.cpp index f56d0ca8dc..08851458d9 100644 --- a/general/globals.cpp +++ b/general/globals.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/globals.hpp b/general/globals.hpp index 9b14b5341b..17faece88e 100644 --- a/general/globals.hpp +++ b/general/globals.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/hash.hpp b/general/hash.hpp index 3360cc2670..655b562bf1 100644 --- a/general/hash.hpp +++ b/general/hash.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -116,6 +116,15 @@ public: /// Remove all items. void DeleteAll(); + /// Allocate an item at 'id'. Enlarge the underlying BlockArray if necessary. + /** This is a special purpose method used when loading data from a file. + Does nothing if the slot 'id' has already been allocated. */ + void Alloc(int id, int p1, int p2); + + /// Reinitialize the internal list of unallocated items. + /** This is a special purpose method used when loading data from a file. */ + void UpdateUnused(); + /// Make an item hashed under different parent IDs. void Reparent(int id, int new_p1, int new_p2); void Reparent(int id, int new_p1, int new_p2, int new_p3, int new_p4 = -1); @@ -213,7 +222,10 @@ HashTable::HashTable(int block_size, int init_hash_size) MFEM_VERIFY(!(init_hash_size & mask), "init_size must be a power of two."); table = new int[init_hash_size]; - for (int i = 0; i < init_hash_size; i++) { table[i] = -1; } + for (int i = 0; i < init_hash_size; i++) + { + table[i] = -1; + } } template @@ -483,6 +495,36 @@ void HashTable::DeleteAll() unused.DeleteAll(); } +template +void HashTable::Alloc(int id, int p1, int p2) +{ + // enlarge the BlockArray to hold 'id' + while (id >= Base::Size()) + { + Base::At(Base::Append()).next = -2; // append "unused" items + } + + T& item = Base::At(id); + if (item.next == -2) + { + item.next = -1; + item.p1 = p1; + item.p2 = p2; + + Insert(Hash(p1, p2), id, item); + } +} + +template +void HashTable::UpdateUnused() +{ + unused.DeleteAll(); + for (int i = 0; i < Base::Size(); i++) + { + if (Base::At(i).next == -2) { unused.Append(i); } + } +} + template void HashTable::Reparent(int id, int new_p1, int new_p2) { diff --git a/general/hip.cpp b/general/hip.cpp index 200772e92c..8f59b0a07c 100644 --- a/general/hip.cpp +++ b/general/hip.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -125,7 +125,7 @@ void* HipMemcpyDtoDAsync(void* dst, const void *src, size_t bytes) void* HipMemcpyDtoH(void *dst, const void *src, size_t bytes) { #ifdef MFEM_USE_HIP -#ifdef MFEM_TRACK_HPI_MEM +#ifdef MFEM_TRACK_HIP_MEM mfem::out << "HipMemcpyDtoH(): copying " << bytes << " bytes from " << src << " to " << dst << " ... " << std::flush; #endif diff --git a/general/hip.hpp b/general/hip.hpp index a061f2c8a7..428415a845 100644 --- a/general/hip.hpp +++ b/general/hip.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/isockstream.cpp b/general/isockstream.cpp index 48a167f3c6..d9d2f6fa7d 100644 --- a/general/isockstream.cpp +++ b/general/isockstream.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/isockstream.hpp b/general/isockstream.hpp index 4937944515..edd460b464 100644 --- a/general/isockstream.hpp +++ b/general/isockstream.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/mem_alloc.hpp b/general/mem_alloc.hpp index 19c66b509a..c2e4eda5c6 100644 --- a/general/mem_alloc.hpp +++ b/general/mem_alloc.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/mem_manager.cpp b/general/mem_manager.cpp index 748f6e673b..5f322fffbc 100644 --- a/general/mem_manager.cpp +++ b/general/mem_manager.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/mem_manager.hpp b/general/mem_manager.hpp index 5661d33cec..7108da419e 100644 --- a/general/mem_manager.hpp +++ b/general/mem_manager.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/occa.cpp b/general/occa.cpp index 24edf49e18..7aa87d7773 100644 --- a/general/occa.cpp +++ b/general/occa.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/occa.hpp b/general/occa.hpp index 07af32f4a5..803f3a9ae0 100644 --- a/general/occa.hpp +++ b/general/occa.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/optparser.cpp b/general/optparser.cpp index 02e6bb7360..09da3ffb33 100644 --- a/general/optparser.cpp +++ b/general/optparser.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/optparser.hpp b/general/optparser.hpp index 00c68da136..7395e7e674 100644 --- a/general/optparser.hpp +++ b/general/optparser.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/osockstream.cpp b/general/osockstream.cpp index c66413b6f0..2a97dc4791 100644 --- a/general/osockstream.cpp +++ b/general/osockstream.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/osockstream.hpp b/general/osockstream.hpp index 85e34f245d..193b0c1cb2 100644 --- a/general/osockstream.hpp +++ b/general/osockstream.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/sets.cpp b/general/sets.cpp index 7df7454f92..e003083bf2 100644 --- a/general/sets.cpp +++ b/general/sets.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/sets.hpp b/general/sets.hpp index b3e92b8521..8f2f3249e5 100644 --- a/general/sets.hpp +++ b/general/sets.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/socketstream.cpp b/general/socketstream.cpp index bdf8c1d361..628df2d20f 100644 --- a/general/socketstream.cpp +++ b/general/socketstream.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -45,6 +45,40 @@ typedef int ssize_t; namespace mfem { +// Helper class for handling Winsock initialization calls. +class WinsockWrapper +{ +public: + WinsockWrapper() + { +#ifdef _WIN32 + WSADATA wsaData; + int err = WSAStartup(MAKEWORD(2,2), &wsaData); + if (err != 0) + { + mfem::out << "Error occured during initialization of WinSock." + << std::endl; + return; + } +#endif + initialized = true; + } + +#ifdef _WIN32 + ~WinsockWrapper() { WSACleanup(); } +#endif + + WinsockWrapper(const WinsockWrapper&) = delete; + WinsockWrapper& operator=(const WinsockWrapper&) = delete; + + bool Initialized() { return initialized; } +private: + bool initialized = false; +}; + +// If available, Winsock is initialized when this object is constructed. +static WinsockWrapper wsInit_; + int socketbuf::attach(int sd) { int old_sd = socket_descriptor; @@ -60,6 +94,11 @@ int socketbuf::open(const char hostname[], int port) struct sockaddr_in sa; struct hostent *hp; + if (!wsInit_.Initialized()) + { + mfem_error("Attempting to open socket, but Winsock not initialized."); + } + close(); setg(NULL, NULL, NULL); setp(obuf, obuf + buflen); diff --git a/general/socketstream.hpp b/general/socketstream.hpp index 8397948730..457040b095 100644 --- a/general/socketstream.hpp +++ b/general/socketstream.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/sort_pairs.hpp b/general/sort_pairs.hpp index 4a272699d3..9c9e070293 100644 --- a/general/sort_pairs.hpp +++ b/general/sort_pairs.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/stable3d.cpp b/general/stable3d.cpp index a6d4af55b6..3477f529be 100644 --- a/general/stable3d.cpp +++ b/general/stable3d.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/stable3d.hpp b/general/stable3d.hpp index c1380003a2..668c2fbf8b 100644 --- a/general/stable3d.hpp +++ b/general/stable3d.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/table.cpp b/general/table.cpp index 419b333ea8..db55fc09d4 100644 --- a/general/table.cpp +++ b/general/table.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/table.hpp b/general/table.hpp index 9702139e74..4b71ae2c08 100644 --- a/general/table.hpp +++ b/general/table.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/tassign.hpp b/general/tassign.hpp index 8dd6eb4bc2..109843c4d2 100644 --- a/general/tassign.hpp +++ b/general/tassign.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/text.hpp b/general/text.hpp index b55be16546..49c4a34619 100644 --- a/general/text.hpp +++ b/general/text.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/tic_toc.cpp b/general/tic_toc.cpp index d96efe909d..958dc5e5ef 100644 --- a/general/tic_toc.cpp +++ b/general/tic_toc.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/tic_toc.hpp b/general/tic_toc.hpp index 36a06697ad..9c86b46f83 100644 --- a/general/tic_toc.hpp +++ b/general/tic_toc.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/tinyxml2.cpp b/general/tinyxml2.cpp new file mode 100644 index 0000000000..13b5ce03a0 --- /dev/null +++ b/general/tinyxml2.cpp @@ -0,0 +1,2969 @@ +/* +Original code by Lee Thomason (www.grinninglizard.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include "tinyxml2.h" + +#include // yes, this one new style header, is in the Android SDK. +#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__) +# include +# include +#else +# include +# include +#endif + +#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE) + // Microsoft Visual Studio, version 2005 and higher. Not WinCE. + /*int _snprintf_s( + char *buffer, + size_t sizeOfBuffer, + size_t count, + const char *format [, + argument] ... + );*/ + static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... ) + { + va_list va; + va_start( va, format ); + const int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va ); + va_end( va ); + return result; + } + + static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va ) + { + const int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va ); + return result; + } + + #define TIXML_VSCPRINTF _vscprintf + #define TIXML_SSCANF sscanf_s +#elif defined _MSC_VER + // Microsoft Visual Studio 2003 and earlier or WinCE + #define TIXML_SNPRINTF _snprintf + #define TIXML_VSNPRINTF _vsnprintf + #define TIXML_SSCANF sscanf + #if (_MSC_VER < 1400 ) && (!defined WINCE) + // Microsoft Visual Studio 2003 and not WinCE. + #define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have. + #else + // Microsoft Visual Studio 2003 and earlier or WinCE. + static inline int TIXML_VSCPRINTF( const char* format, va_list va ) + { + int len = 512; + for (;;) { + len = len*2; + char* str = new char[len](); + const int required = _vsnprintf(str, len, format, va); + delete[] str; + if ( required != -1 ) { + TIXMLASSERT( required >= 0 ); + len = required; + break; + } + } + TIXMLASSERT( len >= 0 ); + return len; + } + #endif +#else + // GCC version 3 and higher + //#warning( "Using sn* functions." ) + #define TIXML_SNPRINTF snprintf + #define TIXML_VSNPRINTF vsnprintf + static inline int TIXML_VSCPRINTF( const char* format, va_list va ) + { + int len = vsnprintf( 0, 0, format, va ); + TIXMLASSERT( len >= 0 ); + return len; + } + #define TIXML_SSCANF sscanf +#endif + +#if defined(_WIN64) + #define TIXML_FSEEK _fseeki64 + #define TIXML_FTELL _ftelli64 +#elif defined(__APPLE__) || (__FreeBSD__) + #define TIXML_FSEEK fseeko + #define TIXML_FTELL ftello +#elif defined(__unix__) && defined(__x86_64__) + #define TIXML_FSEEK fseeko64 + #define TIXML_FTELL ftello64 +#else + #define TIXML_FSEEK fseek + #define TIXML_FTELL ftell +#endif + + +static const char LINE_FEED = static_cast(0x0a); // all line endings are normalized to LF +static const char LF = LINE_FEED; +static const char CARRIAGE_RETURN = static_cast(0x0d); // CR gets filtered out +static const char CR = CARRIAGE_RETURN; +static const char SINGLE_QUOTE = '\''; +static const char DOUBLE_QUOTE = '\"'; + +// Bunch of unicode info at: +// http://www.unicode.org/faq/utf_bom.html +// ef bb bf (Microsoft "lead bytes") - designates UTF-8 + +static const unsigned char TIXML_UTF_LEAD_0 = 0xefU; +static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; +static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; + +namespace tinyxml2 +{ + +struct Entity { + const char* pattern; + int length; + char value; +}; + +static const int NUM_ENTITIES = 5; +static const Entity entities[NUM_ENTITIES] = { + { "quot", 4, DOUBLE_QUOTE }, + { "amp", 3, '&' }, + { "apos", 4, SINGLE_QUOTE }, + { "lt", 2, '<' }, + { "gt", 2, '>' } +}; + + +StrPair::~StrPair() +{ + Reset(); +} + + +void StrPair::TransferTo( StrPair* other ) +{ + if ( this == other ) { + return; + } + // This in effect implements the assignment operator by "moving" + // ownership (as in auto_ptr). + + TIXMLASSERT( other != 0 ); + TIXMLASSERT( other->_flags == 0 ); + TIXMLASSERT( other->_start == 0 ); + TIXMLASSERT( other->_end == 0 ); + + other->Reset(); + + other->_flags = _flags; + other->_start = _start; + other->_end = _end; + + _flags = 0; + _start = 0; + _end = 0; +} + + +void StrPair::Reset() +{ + if ( _flags & NEEDS_DELETE ) { + delete [] _start; + } + _flags = 0; + _start = 0; + _end = 0; +} + + +void StrPair::SetStr( const char* str, int flags ) +{ + TIXMLASSERT( str ); + Reset(); + size_t len = strlen( str ); + TIXMLASSERT( _start == 0 ); + _start = new char[ len+1 ]; + memcpy( _start, str, len+1 ); + _end = _start + len; + _flags = flags | NEEDS_DELETE; +} + + +char* StrPair::ParseText( char* p, const char* endTag, int strFlags, int* curLineNumPtr ) +{ + TIXMLASSERT( p ); + TIXMLASSERT( endTag && *endTag ); + TIXMLASSERT(curLineNumPtr); + + char* start = p; + const char endChar = *endTag; + size_t length = strlen( endTag ); + + // Inner loop of text parsing. + while ( *p ) { + if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) { + Set( start, p, strFlags ); + return p + length; + } else if (*p == '\n') { + ++(*curLineNumPtr); + } + ++p; + TIXMLASSERT( p ); + } + return 0; +} + + +char* StrPair::ParseName( char* p ) +{ + if ( !p || !(*p) ) { + return 0; + } + if ( !XMLUtil::IsNameStartChar( (unsigned char) *p ) ) { + return 0; + } + + char* const start = p; + ++p; + while ( *p && XMLUtil::IsNameChar( (unsigned char) *p ) ) { + ++p; + } + + Set( start, p, 0 ); + return p; +} + + +void StrPair::CollapseWhitespace() +{ + // Adjusting _start would cause undefined behavior on delete[] + TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 ); + // Trim leading space. + _start = XMLUtil::SkipWhiteSpace( _start, 0 ); + + if ( *_start ) { + const char* p = _start; // the read pointer + char* q = _start; // the write pointer + + while( *p ) { + if ( XMLUtil::IsWhiteSpace( *p )) { + p = XMLUtil::SkipWhiteSpace( p, 0 ); + if ( *p == 0 ) { + break; // don't write to q; this trims the trailing space. + } + *q = ' '; + ++q; + } + *q = *p; + ++q; + ++p; + } + *q = 0; + } +} + + +const char* StrPair::GetStr() +{ + TIXMLASSERT( _start ); + TIXMLASSERT( _end ); + if ( _flags & NEEDS_FLUSH ) { + *_end = 0; + _flags ^= NEEDS_FLUSH; + + if ( _flags ) { + const char* p = _start; // the read pointer + char* q = _start; // the write pointer + + while( p < _end ) { + if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) { + // CR-LF pair becomes LF + // CR alone becomes LF + // LF-CR becomes LF + if ( *(p+1) == LF ) { + p += 2; + } + else { + ++p; + } + *q = LF; + ++q; + } + else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) { + if ( *(p+1) == CR ) { + p += 2; + } + else { + ++p; + } + *q = LF; + ++q; + } + else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) { + // Entities handled by tinyXML2: + // - special entities in the entity table [in/out] + // - numeric character reference [in] + // 中 or 中 + + if ( *(p+1) == '#' ) { + const int buflen = 10; + char buf[buflen] = { 0 }; + int len = 0; + const char* adjusted = const_cast( XMLUtil::GetCharacterRef( p, buf, &len ) ); + if ( adjusted == 0 ) { + *q = *p; + ++p; + ++q; + } + else { + TIXMLASSERT( 0 <= len && len <= buflen ); + TIXMLASSERT( q + len <= adjusted ); + p = adjusted; + memcpy( q, buf, len ); + q += len; + } + } + else { + bool entityFound = false; + for( int i = 0; i < NUM_ENTITIES; ++i ) { + const Entity& entity = entities[i]; + if ( strncmp( p + 1, entity.pattern, entity.length ) == 0 + && *( p + entity.length + 1 ) == ';' ) { + // Found an entity - convert. + *q = entity.value; + ++q; + p += entity.length + 2; + entityFound = true; + break; + } + } + if ( !entityFound ) { + // fixme: treat as error? + ++p; + ++q; + } + } + } + else { + *q = *p; + ++p; + ++q; + } + } + *q = 0; + } + // The loop below has plenty going on, and this + // is a less useful mode. Break it out. + if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) { + CollapseWhitespace(); + } + _flags = (_flags & NEEDS_DELETE); + } + TIXMLASSERT( _start ); + return _start; +} + + + + +// --------- XMLUtil ----------- // + +const char* XMLUtil::writeBoolTrue = "true"; +const char* XMLUtil::writeBoolFalse = "false"; + +void XMLUtil::SetBoolSerialization(const char* writeTrue, const char* writeFalse) +{ + static const char* defTrue = "true"; + static const char* defFalse = "false"; + + writeBoolTrue = (writeTrue) ? writeTrue : defTrue; + writeBoolFalse = (writeFalse) ? writeFalse : defFalse; +} + + +const char* XMLUtil::ReadBOM( const char* p, bool* bom ) +{ + TIXMLASSERT( p ); + TIXMLASSERT( bom ); + *bom = false; + const unsigned char* pu = reinterpret_cast(p); + // Check for BOM: + if ( *(pu+0) == TIXML_UTF_LEAD_0 + && *(pu+1) == TIXML_UTF_LEAD_1 + && *(pu+2) == TIXML_UTF_LEAD_2 ) { + *bom = true; + p += 3; + } + TIXMLASSERT( p ); + return p; +} + + +void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) +{ + const unsigned long BYTE_MASK = 0xBF; + const unsigned long BYTE_MARK = 0x80; + const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + + if (input < 0x80) { + *length = 1; + } + else if ( input < 0x800 ) { + *length = 2; + } + else if ( input < 0x10000 ) { + *length = 3; + } + else if ( input < 0x200000 ) { + *length = 4; + } + else { + *length = 0; // This code won't convert this correctly anyway. + return; + } + + output += *length; + + // Scary scary fall throughs are annotated with carefully designed comments + // to suppress compiler warnings such as -Wimplicit-fallthrough in gcc + switch (*length) { + case 4: + --output; + *output = static_cast((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + //fall through + case 3: + --output; + *output = static_cast((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + //fall through + case 2: + --output; + *output = static_cast((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + //fall through + case 1: + --output; + *output = static_cast(input | FIRST_BYTE_MARK[*length]); + break; + default: + TIXMLASSERT( false ); + } +} + + +const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length ) +{ + // Presume an entity, and pull it out. + *length = 0; + + if ( *(p+1) == '#' && *(p+2) ) { + unsigned long ucs = 0; + TIXMLASSERT( sizeof( ucs ) >= 4 ); + ptrdiff_t delta = 0; + unsigned mult = 1; + static const char SEMICOLON = ';'; + + if ( *(p+2) == 'x' ) { + // Hexadecimal. + const char* q = p+3; + if ( !(*q) ) { + return 0; + } + + q = strchr( q, SEMICOLON ); + + if ( !q ) { + return 0; + } + TIXMLASSERT( *q == SEMICOLON ); + + delta = q-p; + --q; + + while ( *q != 'x' ) { + unsigned int digit = 0; + + if ( *q >= '0' && *q <= '9' ) { + digit = *q - '0'; + } + else if ( *q >= 'a' && *q <= 'f' ) { + digit = *q - 'a' + 10; + } + else if ( *q >= 'A' && *q <= 'F' ) { + digit = *q - 'A' + 10; + } + else { + return 0; + } + TIXMLASSERT( digit < 16 ); + TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit ); + const unsigned int digitScaled = mult * digit; + TIXMLASSERT( ucs <= ULONG_MAX - digitScaled ); + ucs += digitScaled; + TIXMLASSERT( mult <= UINT_MAX / 16 ); + mult *= 16; + --q; + } + } + else { + // Decimal. + const char* q = p+2; + if ( !(*q) ) { + return 0; + } + + q = strchr( q, SEMICOLON ); + + if ( !q ) { + return 0; + } + TIXMLASSERT( *q == SEMICOLON ); + + delta = q-p; + --q; + + while ( *q != '#' ) { + if ( *q >= '0' && *q <= '9' ) { + const unsigned int digit = *q - '0'; + TIXMLASSERT( digit < 10 ); + TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit ); + const unsigned int digitScaled = mult * digit; + TIXMLASSERT( ucs <= ULONG_MAX - digitScaled ); + ucs += digitScaled; + } + else { + return 0; + } + TIXMLASSERT( mult <= UINT_MAX / 10 ); + mult *= 10; + --q; + } + } + // convert the UCS to UTF-8 + ConvertUTF32ToUTF8( ucs, value, length ); + return p + delta + 1; + } + return p+1; +} + + +void XMLUtil::ToStr( int v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%d", v ); +} + + +void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%u", v ); +} + + +void XMLUtil::ToStr( bool v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? writeBoolTrue : writeBoolFalse); +} + +/* + ToStr() of a number is a very tricky topic. + https://github.com/leethomason/tinyxml2/issues/106 +*/ +void XMLUtil::ToStr( float v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v ); +} + + +void XMLUtil::ToStr( double v, char* buffer, int bufferSize ) +{ + TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v ); +} + + +void XMLUtil::ToStr( int64_t v, char* buffer, int bufferSize ) +{ + // horrible syntax trick to make the compiler happy about %lld + TIXML_SNPRINTF(buffer, bufferSize, "%lld", static_cast(v)); +} + +void XMLUtil::ToStr( uint64_t v, char* buffer, int bufferSize ) +{ + // horrible syntax trick to make the compiler happy about %llu + TIXML_SNPRINTF(buffer, bufferSize, "%llu", (long long)v); +} + +bool XMLUtil::ToInt(const char* str, int* value) +{ + if (IsPrefixHex(str)) { + unsigned v; + if (TIXML_SSCANF(str, "%x", &v) == 1) { + *value = static_cast(v); + return true; + } + } + else { + if (TIXML_SSCANF(str, "%d", value) == 1) { + return true; + } + } + return false; +} + +bool XMLUtil::ToUnsigned(const char* str, unsigned* value) +{ + if (TIXML_SSCANF(str, IsPrefixHex(str) ? "%x" : "%u", value) == 1) { + return true; + } + return false; +} + +bool XMLUtil::ToBool( const char* str, bool* value ) +{ + int ival = 0; + if ( ToInt( str, &ival )) { + *value = (ival==0) ? false : true; + return true; + } + static const char* TRUE_VALS[] = { "true", "True", "TRUE", 0 }; + static const char* FALSE_VALS[] = { "false", "False", "FALSE", 0 }; + + for (int i = 0; TRUE_VALS[i]; ++i) { + if (StringEqual(str, TRUE_VALS[i])) { + *value = true; + return true; + } + } + for (int i = 0; FALSE_VALS[i]; ++i) { + if (StringEqual(str, FALSE_VALS[i])) { + *value = false; + return true; + } + } + return false; +} + + +bool XMLUtil::ToFloat( const char* str, float* value ) +{ + if ( TIXML_SSCANF( str, "%f", value ) == 1 ) { + return true; + } + return false; +} + + +bool XMLUtil::ToDouble( const char* str, double* value ) +{ + if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) { + return true; + } + return false; +} + + +bool XMLUtil::ToInt64(const char* str, int64_t* value) +{ + if (IsPrefixHex(str)) { + unsigned long long v = 0; // horrible syntax trick to make the compiler happy about %llx + if (TIXML_SSCANF(str, "%llx", &v) == 1) { + *value = static_cast(v); + return true; + } + } + else { + long long v = 0; // horrible syntax trick to make the compiler happy about %lld + if (TIXML_SSCANF(str, "%lld", &v) == 1) { + *value = static_cast(v); + return true; + } + } + return false; +} + + +bool XMLUtil::ToUnsigned64(const char* str, uint64_t* value) { + unsigned long long v = 0; // horrible syntax trick to make the compiler happy about %llu + if(TIXML_SSCANF(str, IsPrefixHex(str) ? "%llx" : "%llu", &v) == 1) { + *value = (uint64_t)v; + return true; + } + return false; +} + + +char* XMLDocument::Identify( char* p, XMLNode** node ) +{ + TIXMLASSERT( node ); + TIXMLASSERT( p ); + char* const start = p; + int const startLine = _parseCurLineNum; + p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum ); + if( !*p ) { + *node = 0; + TIXMLASSERT( p ); + return p; + } + + // These strings define the matching patterns: + static const char* xmlHeader = { "( _commentPool ); + returnNode->_parseLineNum = _parseCurLineNum; + p += xmlHeaderLen; + } + else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) { + returnNode = CreateUnlinkedNode( _commentPool ); + returnNode->_parseLineNum = _parseCurLineNum; + p += commentHeaderLen; + } + else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) { + XMLText* text = CreateUnlinkedNode( _textPool ); + returnNode = text; + returnNode->_parseLineNum = _parseCurLineNum; + p += cdataHeaderLen; + text->SetCData( true ); + } + else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) { + returnNode = CreateUnlinkedNode( _commentPool ); + returnNode->_parseLineNum = _parseCurLineNum; + p += dtdHeaderLen; + } + else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) { + returnNode = CreateUnlinkedNode( _elementPool ); + returnNode->_parseLineNum = _parseCurLineNum; + p += elementHeaderLen; + } + else { + returnNode = CreateUnlinkedNode( _textPool ); + returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character + p = start; // Back it up, all the text counts. + _parseCurLineNum = startLine; + } + + TIXMLASSERT( returnNode ); + TIXMLASSERT( p ); + *node = returnNode; + return p; +} + + +bool XMLDocument::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + if ( visitor->VisitEnter( *this ) ) { + for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) { + if ( !node->Accept( visitor ) ) { + break; + } + } + } + return visitor->VisitExit( *this ); +} + + +// --------- XMLNode ----------- // + +XMLNode::XMLNode( XMLDocument* doc ) : + _document( doc ), + _parent( 0 ), + _value(), + _parseLineNum( 0 ), + _firstChild( 0 ), _lastChild( 0 ), + _prev( 0 ), _next( 0 ), + _userData( 0 ), + _memPool( 0 ) +{ +} + + +XMLNode::~XMLNode() +{ + DeleteChildren(); + if ( _parent ) { + _parent->Unlink( this ); + } +} + +const char* XMLNode::Value() const +{ + // Edge case: XMLDocuments don't have a Value. Return null. + if ( this->ToDocument() ) + return 0; + return _value.GetStr(); +} + +void XMLNode::SetValue( const char* str, bool staticMem ) +{ + if ( staticMem ) { + _value.SetInternedStr( str ); + } + else { + _value.SetStr( str ); + } +} + +XMLNode* XMLNode::DeepClone(XMLDocument* target) const +{ + XMLNode* clone = this->ShallowClone(target); + if (!clone) return 0; + + for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) { + XMLNode* childClone = child->DeepClone(target); + TIXMLASSERT(childClone); + clone->InsertEndChild(childClone); + } + return clone; +} + +void XMLNode::DeleteChildren() +{ + while( _firstChild ) { + TIXMLASSERT( _lastChild ); + DeleteChild( _firstChild ); + } + _firstChild = _lastChild = 0; +} + + +void XMLNode::Unlink( XMLNode* child ) +{ + TIXMLASSERT( child ); + TIXMLASSERT( child->_document == _document ); + TIXMLASSERT( child->_parent == this ); + if ( child == _firstChild ) { + _firstChild = _firstChild->_next; + } + if ( child == _lastChild ) { + _lastChild = _lastChild->_prev; + } + + if ( child->_prev ) { + child->_prev->_next = child->_next; + } + if ( child->_next ) { + child->_next->_prev = child->_prev; + } + child->_next = 0; + child->_prev = 0; + child->_parent = 0; +} + + +void XMLNode::DeleteChild( XMLNode* node ) +{ + TIXMLASSERT( node ); + TIXMLASSERT( node->_document == _document ); + TIXMLASSERT( node->_parent == this ); + Unlink( node ); + TIXMLASSERT(node->_prev == 0); + TIXMLASSERT(node->_next == 0); + TIXMLASSERT(node->_parent == 0); + DeleteNode( node ); +} + + +XMLNode* XMLNode::InsertEndChild( XMLNode* addThis ) +{ + TIXMLASSERT( addThis ); + if ( addThis->_document != _document ) { + TIXMLASSERT( false ); + return 0; + } + InsertChildPreamble( addThis ); + + if ( _lastChild ) { + TIXMLASSERT( _firstChild ); + TIXMLASSERT( _lastChild->_next == 0 ); + _lastChild->_next = addThis; + addThis->_prev = _lastChild; + _lastChild = addThis; + + addThis->_next = 0; + } + else { + TIXMLASSERT( _firstChild == 0 ); + _firstChild = _lastChild = addThis; + + addThis->_prev = 0; + addThis->_next = 0; + } + addThis->_parent = this; + return addThis; +} + + +XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis ) +{ + TIXMLASSERT( addThis ); + if ( addThis->_document != _document ) { + TIXMLASSERT( false ); + return 0; + } + InsertChildPreamble( addThis ); + + if ( _firstChild ) { + TIXMLASSERT( _lastChild ); + TIXMLASSERT( _firstChild->_prev == 0 ); + + _firstChild->_prev = addThis; + addThis->_next = _firstChild; + _firstChild = addThis; + + addThis->_prev = 0; + } + else { + TIXMLASSERT( _lastChild == 0 ); + _firstChild = _lastChild = addThis; + + addThis->_prev = 0; + addThis->_next = 0; + } + addThis->_parent = this; + return addThis; +} + + +XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ) +{ + TIXMLASSERT( addThis ); + if ( addThis->_document != _document ) { + TIXMLASSERT( false ); + return 0; + } + + TIXMLASSERT( afterThis ); + + if ( afterThis->_parent != this ) { + TIXMLASSERT( false ); + return 0; + } + if ( afterThis == addThis ) { + // Current state: BeforeThis -> AddThis -> OneAfterAddThis + // Now AddThis must disappear from it's location and then + // reappear between BeforeThis and OneAfterAddThis. + // So just leave it where it is. + return addThis; + } + + if ( afterThis->_next == 0 ) { + // The last node or the only node. + return InsertEndChild( addThis ); + } + InsertChildPreamble( addThis ); + addThis->_prev = afterThis; + addThis->_next = afterThis->_next; + afterThis->_next->_prev = addThis; + afterThis->_next = addThis; + addThis->_parent = this; + return addThis; +} + + + + +const XMLElement* XMLNode::FirstChildElement( const char* name ) const +{ + for( const XMLNode* node = _firstChild; node; node = node->_next ) { + const XMLElement* element = node->ToElementWithName( name ); + if ( element ) { + return element; + } + } + return 0; +} + + +const XMLElement* XMLNode::LastChildElement( const char* name ) const +{ + for( const XMLNode* node = _lastChild; node; node = node->_prev ) { + const XMLElement* element = node->ToElementWithName( name ); + if ( element ) { + return element; + } + } + return 0; +} + + +const XMLElement* XMLNode::NextSiblingElement( const char* name ) const +{ + for( const XMLNode* node = _next; node; node = node->_next ) { + const XMLElement* element = node->ToElementWithName( name ); + if ( element ) { + return element; + } + } + return 0; +} + + +const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const +{ + for( const XMLNode* node = _prev; node; node = node->_prev ) { + const XMLElement* element = node->ToElementWithName( name ); + if ( element ) { + return element; + } + } + return 0; +} + + +char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) +{ + // This is a recursive method, but thinking about it "at the current level" + // it is a pretty simple flat list: + // + // + // + // With a special case: + // + // + // + // + // Where the closing element (/foo) *must* be the next thing after the opening + // element, and the names must match. BUT the tricky bit is that the closing + // element will be read by the child. + // + // 'endTag' is the end tag for this node, it is returned by a call to a child. + // 'parentEnd' is the end tag for the parent, which is filled in and returned. + + XMLDocument::DepthTracker tracker(_document); + if (_document->Error()) + return 0; + + while( p && *p ) { + XMLNode* node = 0; + + p = _document->Identify( p, &node ); + TIXMLASSERT( p ); + if ( node == 0 ) { + break; + } + + const int initialLineNum = node->_parseLineNum; + + StrPair endTag; + p = node->ParseDeep( p, &endTag, curLineNumPtr ); + if ( !p ) { + DeleteNode( node ); + if ( !_document->Error() ) { + _document->SetError( XML_ERROR_PARSING, initialLineNum, 0); + } + break; + } + + const XMLDeclaration* const decl = node->ToDeclaration(); + if ( decl ) { + // Declarations are only allowed at document level + // + // Multiple declarations are allowed but all declarations + // must occur before anything else. + // + // Optimized due to a security test case. If the first node is + // a declaration, and the last node is a declaration, then only + // declarations have so far been added. + bool wellLocated = false; + + if (ToDocument()) { + if (FirstChild()) { + wellLocated = + FirstChild() && + FirstChild()->ToDeclaration() && + LastChild() && + LastChild()->ToDeclaration(); + } + else { + wellLocated = true; + } + } + if ( !wellLocated ) { + _document->SetError( XML_ERROR_PARSING_DECLARATION, initialLineNum, "XMLDeclaration value=%s", decl->Value()); + DeleteNode( node ); + break; + } + } + + XMLElement* ele = node->ToElement(); + if ( ele ) { + // We read the end tag. Return it to the parent. + if ( ele->ClosingType() == XMLElement::CLOSING ) { + if ( parentEndTag ) { + ele->_value.TransferTo( parentEndTag ); + } + node->_memPool->SetTracked(); // created and then immediately deleted. + DeleteNode( node ); + return p; + } + + // Handle an end tag returned to this level. + // And handle a bunch of annoying errors. + bool mismatch = false; + if ( endTag.Empty() ) { + if ( ele->ClosingType() == XMLElement::OPEN ) { + mismatch = true; + } + } + else { + if ( ele->ClosingType() != XMLElement::OPEN ) { + mismatch = true; + } + else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) { + mismatch = true; + } + } + if ( mismatch ) { + _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, initialLineNum, "XMLElement name=%s", ele->Name()); + DeleteNode( node ); + break; + } + } + InsertEndChild( node ); + } + return 0; +} + +/*static*/ void XMLNode::DeleteNode( XMLNode* node ) +{ + if ( node == 0 ) { + return; + } + TIXMLASSERT(node->_document); + if (!node->ToDocument()) { + node->_document->MarkInUse(node); + } + + MemPool* pool = node->_memPool; + node->~XMLNode(); + pool->Free( node ); +} + +void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const +{ + TIXMLASSERT( insertThis ); + TIXMLASSERT( insertThis->_document == _document ); + + if (insertThis->_parent) { + insertThis->_parent->Unlink( insertThis ); + } + else { + insertThis->_document->MarkInUse(insertThis); + insertThis->_memPool->SetTracked(); + } +} + +const XMLElement* XMLNode::ToElementWithName( const char* name ) const +{ + const XMLElement* element = this->ToElement(); + if ( element == 0 ) { + return 0; + } + if ( name == 0 ) { + return element; + } + if ( XMLUtil::StringEqual( element->Name(), name ) ) { + return element; + } + return 0; +} + +// --------- XMLText ---------- // +char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) +{ + if ( this->CData() ) { + p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr ); + if ( !p ) { + _document->SetError( XML_ERROR_PARSING_CDATA, _parseLineNum, 0 ); + } + return p; + } + else { + int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES; + if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) { + flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING; + } + + p = _value.ParseText( p, "<", flags, curLineNumPtr ); + if ( p && *p ) { + return p-1; + } + if ( !p ) { + _document->SetError( XML_ERROR_PARSING_TEXT, _parseLineNum, 0 ); + } + } + return 0; +} + + +XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern? + text->SetCData( this->CData() ); + return text; +} + + +bool XMLText::ShallowEqual( const XMLNode* compare ) const +{ + TIXMLASSERT( compare ); + const XMLText* text = compare->ToText(); + return ( text && XMLUtil::StringEqual( text->Value(), Value() ) ); +} + + +bool XMLText::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + return visitor->Visit( *this ); +} + + +// --------- XMLComment ---------- // + +XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc ) +{ +} + + +XMLComment::~XMLComment() +{ +} + + +char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) +{ + // Comment parses as text. + p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr ); + if ( p == 0 ) { + _document->SetError( XML_ERROR_PARSING_COMMENT, _parseLineNum, 0 ); + } + return p; +} + + +XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern? + return comment; +} + + +bool XMLComment::ShallowEqual( const XMLNode* compare ) const +{ + TIXMLASSERT( compare ); + const XMLComment* comment = compare->ToComment(); + return ( comment && XMLUtil::StringEqual( comment->Value(), Value() )); +} + + +bool XMLComment::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + return visitor->Visit( *this ); +} + + +// --------- XMLDeclaration ---------- // + +XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc ) +{ +} + + +XMLDeclaration::~XMLDeclaration() +{ + //printf( "~XMLDeclaration\n" ); +} + + +char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) +{ + // Declaration parses as text. + p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr ); + if ( p == 0 ) { + _document->SetError( XML_ERROR_PARSING_DECLARATION, _parseLineNum, 0 ); + } + return p; +} + + +XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern? + return dec; +} + + +bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const +{ + TIXMLASSERT( compare ); + const XMLDeclaration* declaration = compare->ToDeclaration(); + return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() )); +} + + + +bool XMLDeclaration::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + return visitor->Visit( *this ); +} + +// --------- XMLUnknown ---------- // + +XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc ) +{ +} + + +XMLUnknown::~XMLUnknown() +{ +} + + +char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) +{ + // Unknown parses as text. + p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr ); + if ( !p ) { + _document->SetError( XML_ERROR_PARSING_UNKNOWN, _parseLineNum, 0 ); + } + return p; +} + + +XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern? + return text; +} + + +bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const +{ + TIXMLASSERT( compare ); + const XMLUnknown* unknown = compare->ToUnknown(); + return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() )); +} + + +bool XMLUnknown::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + return visitor->Visit( *this ); +} + +// --------- XMLAttribute ---------- // + +const char* XMLAttribute::Name() const +{ + return _name.GetStr(); +} + +const char* XMLAttribute::Value() const +{ + return _value.GetStr(); +} + +char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr ) +{ + // Parse using the name rules: bug fix, was using ParseText before + p = _name.ParseName( p ); + if ( !p || !*p ) { + return 0; + } + + // Skip white space before = + p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); + if ( *p != '=' ) { + return 0; + } + + ++p; // move up to opening quote + p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); + if ( *p != '\"' && *p != '\'' ) { + return 0; + } + + const char endTag[2] = { *p, 0 }; + ++p; // move past opening quote + + p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr ); + return p; +} + + +void XMLAttribute::SetName( const char* n ) +{ + _name.SetStr( n ); +} + + +XMLError XMLAttribute::QueryIntValue( int* value ) const +{ + if ( XMLUtil::ToInt( Value(), value )) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const +{ + if ( XMLUtil::ToUnsigned( Value(), value )) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryInt64Value(int64_t* value) const +{ + if (XMLUtil::ToInt64(Value(), value)) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryUnsigned64Value(uint64_t* value) const +{ + if(XMLUtil::ToUnsigned64(Value(), value)) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryBoolValue( bool* value ) const +{ + if ( XMLUtil::ToBool( Value(), value )) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryFloatValue( float* value ) const +{ + if ( XMLUtil::ToFloat( Value(), value )) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +XMLError XMLAttribute::QueryDoubleValue( double* value ) const +{ + if ( XMLUtil::ToDouble( Value(), value )) { + return XML_SUCCESS; + } + return XML_WRONG_ATTRIBUTE_TYPE; +} + + +void XMLAttribute::SetAttribute( const char* v ) +{ + _value.SetStr( v ); +} + + +void XMLAttribute::SetAttribute( int v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + + +void XMLAttribute::SetAttribute( unsigned v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + + +void XMLAttribute::SetAttribute(int64_t v) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + _value.SetStr(buf); +} + +void XMLAttribute::SetAttribute(uint64_t v) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + _value.SetStr(buf); +} + + +void XMLAttribute::SetAttribute( bool v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + +void XMLAttribute::SetAttribute( double v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + +void XMLAttribute::SetAttribute( float v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + _value.SetStr( buf ); +} + + +// --------- XMLElement ---------- // +XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ), + _closingType( OPEN ), + _rootAttribute( 0 ) +{ +} + + +XMLElement::~XMLElement() +{ + while( _rootAttribute ) { + XMLAttribute* next = _rootAttribute->_next; + DeleteAttribute( _rootAttribute ); + _rootAttribute = next; + } +} + + +const XMLAttribute* XMLElement::FindAttribute( const char* name ) const +{ + for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) { + if ( XMLUtil::StringEqual( a->Name(), name ) ) { + return a; + } + } + return 0; +} + + +const char* XMLElement::Attribute( const char* name, const char* value ) const +{ + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return 0; + } + if ( !value || XMLUtil::StringEqual( a->Value(), value )) { + return a->Value(); + } + return 0; +} + +int XMLElement::IntAttribute(const char* name, int defaultValue) const +{ + int i = defaultValue; + QueryIntAttribute(name, &i); + return i; +} + +unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const +{ + unsigned i = defaultValue; + QueryUnsignedAttribute(name, &i); + return i; +} + +int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const +{ + int64_t i = defaultValue; + QueryInt64Attribute(name, &i); + return i; +} + +uint64_t XMLElement::Unsigned64Attribute(const char* name, uint64_t defaultValue) const +{ + uint64_t i = defaultValue; + QueryUnsigned64Attribute(name, &i); + return i; +} + +bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const +{ + bool b = defaultValue; + QueryBoolAttribute(name, &b); + return b; +} + +double XMLElement::DoubleAttribute(const char* name, double defaultValue) const +{ + double d = defaultValue; + QueryDoubleAttribute(name, &d); + return d; +} + +float XMLElement::FloatAttribute(const char* name, float defaultValue) const +{ + float f = defaultValue; + QueryFloatAttribute(name, &f); + return f; +} + +const char* XMLElement::GetText() const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + return FirstChild()->Value(); + } + return 0; +} + + +void XMLElement::SetText( const char* inText ) +{ + if ( FirstChild() && FirstChild()->ToText() ) + FirstChild()->SetValue( inText ); + else { + XMLText* theText = GetDocument()->NewText( inText ); + InsertFirstChild( theText ); + } +} + + +void XMLElement::SetText( int v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + SetText( buf ); +} + + +void XMLElement::SetText( unsigned v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + SetText( buf ); +} + + +void XMLElement::SetText(int64_t v) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + SetText(buf); +} + +void XMLElement::SetText(uint64_t v) { + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + SetText(buf); +} + + +void XMLElement::SetText( bool v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + SetText( buf ); +} + + +void XMLElement::SetText( float v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + SetText( buf ); +} + + +void XMLElement::SetText( double v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + SetText( buf ); +} + + +XMLError XMLElement::QueryIntText( int* ival ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->Value(); + if ( XMLUtil::ToInt( t, ival ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->Value(); + if ( XMLUtil::ToUnsigned( t, uval ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryInt64Text(int64_t* ival) const +{ + if (FirstChild() && FirstChild()->ToText()) { + const char* t = FirstChild()->Value(); + if (XMLUtil::ToInt64(t, ival)) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryUnsigned64Text(uint64_t* ival) const +{ + if(FirstChild() && FirstChild()->ToText()) { + const char* t = FirstChild()->Value(); + if(XMLUtil::ToUnsigned64(t, ival)) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryBoolText( bool* bval ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->Value(); + if ( XMLUtil::ToBool( t, bval ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryDoubleText( double* dval ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->Value(); + if ( XMLUtil::ToDouble( t, dval ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + + +XMLError XMLElement::QueryFloatText( float* fval ) const +{ + if ( FirstChild() && FirstChild()->ToText() ) { + const char* t = FirstChild()->Value(); + if ( XMLUtil::ToFloat( t, fval ) ) { + return XML_SUCCESS; + } + return XML_CAN_NOT_CONVERT_TEXT; + } + return XML_NO_TEXT_NODE; +} + +int XMLElement::IntText(int defaultValue) const +{ + int i = defaultValue; + QueryIntText(&i); + return i; +} + +unsigned XMLElement::UnsignedText(unsigned defaultValue) const +{ + unsigned i = defaultValue; + QueryUnsignedText(&i); + return i; +} + +int64_t XMLElement::Int64Text(int64_t defaultValue) const +{ + int64_t i = defaultValue; + QueryInt64Text(&i); + return i; +} + +uint64_t XMLElement::Unsigned64Text(uint64_t defaultValue) const +{ + uint64_t i = defaultValue; + QueryUnsigned64Text(&i); + return i; +} + +bool XMLElement::BoolText(bool defaultValue) const +{ + bool b = defaultValue; + QueryBoolText(&b); + return b; +} + +double XMLElement::DoubleText(double defaultValue) const +{ + double d = defaultValue; + QueryDoubleText(&d); + return d; +} + +float XMLElement::FloatText(float defaultValue) const +{ + float f = defaultValue; + QueryFloatText(&f); + return f; +} + + +XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name ) +{ + XMLAttribute* last = 0; + XMLAttribute* attrib = 0; + for( attrib = _rootAttribute; + attrib; + last = attrib, attrib = attrib->_next ) { + if ( XMLUtil::StringEqual( attrib->Name(), name ) ) { + break; + } + } + if ( !attrib ) { + attrib = CreateAttribute(); + TIXMLASSERT( attrib ); + if ( last ) { + TIXMLASSERT( last->_next == 0 ); + last->_next = attrib; + } + else { + TIXMLASSERT( _rootAttribute == 0 ); + _rootAttribute = attrib; + } + attrib->SetName( name ); + } + return attrib; +} + + +void XMLElement::DeleteAttribute( const char* name ) +{ + XMLAttribute* prev = 0; + for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) { + if ( XMLUtil::StringEqual( name, a->Name() ) ) { + if ( prev ) { + prev->_next = a->_next; + } + else { + _rootAttribute = a->_next; + } + DeleteAttribute( a ); + break; + } + prev = a; + } +} + + +char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr ) +{ + XMLAttribute* prevAttribute = 0; + + // Read the attributes. + while( p ) { + p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); + if ( !(*p) ) { + _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, "XMLElement name=%s", Name() ); + return 0; + } + + // attribute. + if (XMLUtil::IsNameStartChar( (unsigned char) *p ) ) { + XMLAttribute* attrib = CreateAttribute(); + TIXMLASSERT( attrib ); + attrib->_parseLineNum = _document->_parseCurLineNum; + + const int attrLineNum = attrib->_parseLineNum; + + p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr ); + if ( !p || Attribute( attrib->Name() ) ) { + DeleteAttribute( attrib ); + _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, attrLineNum, "XMLElement name=%s", Name() ); + return 0; + } + // There is a minor bug here: if the attribute in the source xml + // document is duplicated, it will not be detected and the + // attribute will be doubly added. However, tracking the 'prevAttribute' + // avoids re-scanning the attribute list. Preferring performance for + // now, may reconsider in the future. + if ( prevAttribute ) { + TIXMLASSERT( prevAttribute->_next == 0 ); + prevAttribute->_next = attrib; + } + else { + TIXMLASSERT( _rootAttribute == 0 ); + _rootAttribute = attrib; + } + prevAttribute = attrib; + } + // end of the tag + else if ( *p == '>' ) { + ++p; + break; + } + // end of the tag + else if ( *p == '/' && *(p+1) == '>' ) { + _closingType = CLOSED; + return p+2; // done; sealed element. + } + else { + _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, 0 ); + return 0; + } + } + return p; +} + +void XMLElement::DeleteAttribute( XMLAttribute* attribute ) +{ + if ( attribute == 0 ) { + return; + } + MemPool* pool = attribute->_memPool; + attribute->~XMLAttribute(); + pool->Free( attribute ); +} + +XMLAttribute* XMLElement::CreateAttribute() +{ + TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() ); + XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute(); + TIXMLASSERT( attrib ); + attrib->_memPool = &_document->_attributePool; + attrib->_memPool->SetTracked(); + return attrib; +} + + +XMLElement* XMLElement::InsertNewChildElement(const char* name) +{ + XMLElement* node = _document->NewElement(name); + return InsertEndChild(node) ? node : 0; +} + +XMLComment* XMLElement::InsertNewComment(const char* comment) +{ + XMLComment* node = _document->NewComment(comment); + return InsertEndChild(node) ? node : 0; +} + +XMLText* XMLElement::InsertNewText(const char* text) +{ + XMLText* node = _document->NewText(text); + return InsertEndChild(node) ? node : 0; +} + +XMLDeclaration* XMLElement::InsertNewDeclaration(const char* text) +{ + XMLDeclaration* node = _document->NewDeclaration(text); + return InsertEndChild(node) ? node : 0; +} + +XMLUnknown* XMLElement::InsertNewUnknown(const char* text) +{ + XMLUnknown* node = _document->NewUnknown(text); + return InsertEndChild(node) ? node : 0; +} + + + +// +// +// foobar +// +char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) +{ + // Read the element name. + p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); + + // The closing element is the form. It is + // parsed just like a regular element then deleted from + // the DOM. + if ( *p == '/' ) { + _closingType = CLOSING; + ++p; + } + + p = _value.ParseName( p ); + if ( _value.Empty() ) { + return 0; + } + + p = ParseAttributes( p, curLineNumPtr ); + if ( !p || !*p || _closingType != OPEN ) { + return p; + } + + p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr ); + return p; +} + + + +XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const +{ + if ( !doc ) { + doc = _document; + } + XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern? + for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) { + element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern? + } + return element; +} + + +bool XMLElement::ShallowEqual( const XMLNode* compare ) const +{ + TIXMLASSERT( compare ); + const XMLElement* other = compare->ToElement(); + if ( other && XMLUtil::StringEqual( other->Name(), Name() )) { + + const XMLAttribute* a=FirstAttribute(); + const XMLAttribute* b=other->FirstAttribute(); + + while ( a && b ) { + if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) { + return false; + } + a = a->Next(); + b = b->Next(); + } + if ( a || b ) { + // different count + return false; + } + return true; + } + return false; +} + + +bool XMLElement::Accept( XMLVisitor* visitor ) const +{ + TIXMLASSERT( visitor ); + if ( visitor->VisitEnter( *this, _rootAttribute ) ) { + for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) { + if ( !node->Accept( visitor ) ) { + break; + } + } + } + return visitor->VisitExit( *this ); +} + + +// --------- XMLDocument ----------- // + +// Warning: List must match 'enum XMLError' +const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = { + "XML_SUCCESS", + "XML_NO_ATTRIBUTE", + "XML_WRONG_ATTRIBUTE_TYPE", + "XML_ERROR_FILE_NOT_FOUND", + "XML_ERROR_FILE_COULD_NOT_BE_OPENED", + "XML_ERROR_FILE_READ_ERROR", + "XML_ERROR_PARSING_ELEMENT", + "XML_ERROR_PARSING_ATTRIBUTE", + "XML_ERROR_PARSING_TEXT", + "XML_ERROR_PARSING_CDATA", + "XML_ERROR_PARSING_COMMENT", + "XML_ERROR_PARSING_DECLARATION", + "XML_ERROR_PARSING_UNKNOWN", + "XML_ERROR_EMPTY_DOCUMENT", + "XML_ERROR_MISMATCHED_ELEMENT", + "XML_ERROR_PARSING", + "XML_CAN_NOT_CONVERT_TEXT", + "XML_NO_TEXT_NODE", + "XML_ELEMENT_DEPTH_EXCEEDED" +}; + + +XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) : + XMLNode( 0 ), + _writeBOM( false ), + _processEntities( processEntities ), + _errorID(XML_SUCCESS), + _whitespaceMode( whitespaceMode ), + _errorStr(), + _errorLineNum( 0 ), + _charBuffer( 0 ), + _parseCurLineNum( 0 ), + _parsingDepth(0), + _unlinked(), + _elementPool(), + _attributePool(), + _textPool(), + _commentPool() +{ + // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+) + _document = this; +} + + +XMLDocument::~XMLDocument() +{ + Clear(); +} + + +void XMLDocument::MarkInUse(const XMLNode* const node) +{ + TIXMLASSERT(node); + TIXMLASSERT(node->_parent == 0); + + for (int i = 0; i < _unlinked.Size(); ++i) { + if (node == _unlinked[i]) { + _unlinked.SwapRemove(i); + break; + } + } +} + +void XMLDocument::Clear() +{ + DeleteChildren(); + while( _unlinked.Size()) { + DeleteNode(_unlinked[0]); // Will remove from _unlinked as part of delete. + } + +#ifdef TINYXML2_DEBUG + const bool hadError = Error(); +#endif + ClearError(); + + delete [] _charBuffer; + _charBuffer = 0; + _parsingDepth = 0; + +#if 0 + _textPool.Trace( "text" ); + _elementPool.Trace( "element" ); + _commentPool.Trace( "comment" ); + _attributePool.Trace( "attribute" ); +#endif + +#ifdef TINYXML2_DEBUG + if ( !hadError ) { + TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() ); + TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() ); + TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() ); + TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() ); + } +#endif +} + + +void XMLDocument::DeepCopy(XMLDocument* target) const +{ + TIXMLASSERT(target); + if (target == this) { + return; // technically success - a no-op. + } + + target->Clear(); + for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) { + target->InsertEndChild(node->DeepClone(target)); + } +} + +XMLElement* XMLDocument::NewElement( const char* name ) +{ + XMLElement* ele = CreateUnlinkedNode( _elementPool ); + ele->SetName( name ); + return ele; +} + + +XMLComment* XMLDocument::NewComment( const char* str ) +{ + XMLComment* comment = CreateUnlinkedNode( _commentPool ); + comment->SetValue( str ); + return comment; +} + + +XMLText* XMLDocument::NewText( const char* str ) +{ + XMLText* text = CreateUnlinkedNode( _textPool ); + text->SetValue( str ); + return text; +} + + +XMLDeclaration* XMLDocument::NewDeclaration( const char* str ) +{ + XMLDeclaration* dec = CreateUnlinkedNode( _commentPool ); + dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" ); + return dec; +} + + +XMLUnknown* XMLDocument::NewUnknown( const char* str ) +{ + XMLUnknown* unk = CreateUnlinkedNode( _commentPool ); + unk->SetValue( str ); + return unk; +} + +static FILE* callfopen( const char* filepath, const char* mode ) +{ + TIXMLASSERT( filepath ); + TIXMLASSERT( mode ); +#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE) + FILE* fp = 0; + const errno_t err = fopen_s( &fp, filepath, mode ); + if ( err ) { + return 0; + } +#else + FILE* fp = fopen( filepath, mode ); +#endif + return fp; +} + +void XMLDocument::DeleteNode( XMLNode* node ) { + TIXMLASSERT( node ); + TIXMLASSERT(node->_document == this ); + if (node->_parent) { + node->_parent->DeleteChild( node ); + } + else { + // Isn't in the tree. + // Use the parent delete. + // Also, we need to mark it tracked: we 'know' + // it was never used. + node->_memPool->SetTracked(); + // Call the static XMLNode version: + XMLNode::DeleteNode(node); + } +} + + +XMLError XMLDocument::LoadFile( const char* filename ) +{ + if ( !filename ) { + TIXMLASSERT( false ); + SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=" ); + return _errorID; + } + + Clear(); + FILE* fp = callfopen( filename, "rb" ); + if ( !fp ) { + SetError( XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename ); + return _errorID; + } + LoadFile( fp ); + fclose( fp ); + return _errorID; +} + +XMLError XMLDocument::LoadFile( FILE* fp ) +{ + Clear(); + + TIXML_FSEEK( fp, 0, SEEK_SET ); + if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) { + SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); + return _errorID; + } + + TIXML_FSEEK( fp, 0, SEEK_END ); + + unsigned long long filelength; + { + const long long fileLengthSigned = TIXML_FTELL( fp ); + TIXML_FSEEK( fp, 0, SEEK_SET ); + if ( fileLengthSigned == -1L ) { + SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); + return _errorID; + } + TIXMLASSERT( fileLengthSigned >= 0 ); + filelength = static_cast(fileLengthSigned); + } + + const size_t maxSizeT = static_cast(-1); + // We'll do the comparison as an unsigned long long, because that's guaranteed to be at + // least 8 bytes, even on a 32-bit platform. + if ( filelength >= static_cast(maxSizeT) ) { + // Cannot handle files which won't fit in buffer together with null terminator + SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); + return _errorID; + } + + if ( filelength == 0 ) { + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); + return _errorID; + } + + const size_t size = static_cast(filelength); + TIXMLASSERT( _charBuffer == 0 ); + _charBuffer = new char[size+1]; + const size_t read = fread( _charBuffer, 1, size, fp ); + if ( read != size ) { + SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); + return _errorID; + } + + _charBuffer[size] = 0; + + Parse(); + return _errorID; +} + + +XMLError XMLDocument::SaveFile( const char* filename, bool compact ) +{ + if ( !filename ) { + TIXMLASSERT( false ); + SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=" ); + return _errorID; + } + + FILE* fp = callfopen( filename, "w" ); + if ( !fp ) { + SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=%s", filename ); + return _errorID; + } + SaveFile(fp, compact); + fclose( fp ); + return _errorID; +} + + +XMLError XMLDocument::SaveFile( FILE* fp, bool compact ) +{ + // Clear any error from the last save, otherwise it will get reported + // for *this* call. + ClearError(); + XMLPrinter stream( fp, compact ); + Print( &stream ); + return _errorID; +} + + +XMLError XMLDocument::Parse( const char* p, size_t len ) +{ + Clear(); + + if ( len == 0 || !p || !*p ) { + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); + return _errorID; + } + if ( len == static_cast(-1) ) { + len = strlen( p ); + } + TIXMLASSERT( _charBuffer == 0 ); + _charBuffer = new char[ len+1 ]; + memcpy( _charBuffer, p, len ); + _charBuffer[len] = 0; + + Parse(); + if ( Error() ) { + // clean up now essentially dangling memory. + // and the parse fail can put objects in the + // pools that are dead and inaccessible. + DeleteChildren(); + _elementPool.Clear(); + _attributePool.Clear(); + _textPool.Clear(); + _commentPool.Clear(); + } + return _errorID; +} + + +void XMLDocument::Print( XMLPrinter* streamer ) const +{ + if ( streamer ) { + Accept( streamer ); + } + else { + XMLPrinter stdoutStreamer( stdout ); + Accept( &stdoutStreamer ); + } +} + + +void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... ) +{ + TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT ); + _errorID = error; + _errorLineNum = lineNum; + _errorStr.Reset(); + + const size_t BUFFER_SIZE = 1000; + char* buffer = new char[BUFFER_SIZE]; + + TIXMLASSERT(sizeof(error) <= sizeof(int)); + TIXML_SNPRINTF(buffer, BUFFER_SIZE, "Error=%s ErrorID=%d (0x%x) Line number=%d", ErrorIDToName(error), int(error), int(error), lineNum); + + if (format) { + size_t len = strlen(buffer); + TIXML_SNPRINTF(buffer + len, BUFFER_SIZE - len, ": "); + len = strlen(buffer); + + va_list va; + va_start(va, format); + TIXML_VSNPRINTF(buffer + len, BUFFER_SIZE - len, format, va); + va_end(va); + } + _errorStr.SetStr(buffer); + delete[] buffer; +} + + +/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID) +{ + TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT ); + const char* errorName = _errorNames[errorID]; + TIXMLASSERT( errorName && errorName[0] ); + return errorName; +} + +const char* XMLDocument::ErrorStr() const +{ + return _errorStr.Empty() ? "" : _errorStr.GetStr(); +} + + +void XMLDocument::PrintError() const +{ + printf("%s\n", ErrorStr()); +} + +const char* XMLDocument::ErrorName() const +{ + return ErrorIDToName(_errorID); +} + +void XMLDocument::Parse() +{ + TIXMLASSERT( NoChildren() ); // Clear() must have been called previously + TIXMLASSERT( _charBuffer ); + _parseCurLineNum = 1; + _parseLineNum = 1; + char* p = _charBuffer; + p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum ); + p = const_cast( XMLUtil::ReadBOM( p, &_writeBOM ) ); + if ( !*p ) { + SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); + return; + } + ParseDeep(p, 0, &_parseCurLineNum ); +} + +void XMLDocument::PushDepth() +{ + _parsingDepth++; + if (_parsingDepth == TINYXML2_MAX_ELEMENT_DEPTH) { + SetError(XML_ELEMENT_DEPTH_EXCEEDED, _parseCurLineNum, "Element nesting is too deep." ); + } +} + +void XMLDocument::PopDepth() +{ + TIXMLASSERT(_parsingDepth > 0); + --_parsingDepth; +} + +XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) : + _elementJustOpened( false ), + _stack(), + _firstElement( true ), + _fp( file ), + _depth( depth ), + _textDepth( -1 ), + _processEntities( true ), + _compactMode( compact ), + _buffer() +{ + for( int i=0; i(entityValue); + TIXMLASSERT( flagIndex < ENTITY_RANGE ); + _entityFlag[flagIndex] = true; + } + _restrictedEntityFlag[static_cast('&')] = true; + _restrictedEntityFlag[static_cast('<')] = true; + _restrictedEntityFlag[static_cast('>')] = true; // not required, but consistency is nice + _buffer.Push( 0 ); +} + + +void XMLPrinter::Print( const char* format, ... ) +{ + va_list va; + va_start( va, format ); + + if ( _fp ) { + vfprintf( _fp, format, va ); + } + else { + const int len = TIXML_VSCPRINTF( format, va ); + // Close out and re-start the va-args + va_end( va ); + TIXMLASSERT( len >= 0 ); + va_start( va, format ); + TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 ); + char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator. + TIXML_VSNPRINTF( p, len+1, format, va ); + } + va_end( va ); +} + + +void XMLPrinter::Write( const char* data, size_t size ) +{ + if ( _fp ) { + fwrite ( data , sizeof(char), size, _fp); + } + else { + char* p = _buffer.PushArr( static_cast(size) ) - 1; // back up over the null terminator. + memcpy( p, data, size ); + p[size] = 0; + } +} + + +void XMLPrinter::Putc( char ch ) +{ + if ( _fp ) { + fputc ( ch, _fp); + } + else { + char* p = _buffer.PushArr( sizeof(char) ) - 1; // back up over the null terminator. + p[0] = ch; + p[1] = 0; + } +} + + +void XMLPrinter::PrintSpace( int depth ) +{ + for( int i=0; i 0 && *q < ENTITY_RANGE ) { + // Check for entities. If one is found, flush + // the stream up until the entity, write the + // entity, and keep looking. + if ( flag[static_cast(*q)] ) { + while ( p < q ) { + const size_t delta = q - p; + const int toPrint = ( INT_MAX < delta ) ? INT_MAX : static_cast(delta); + Write( p, toPrint ); + p += toPrint; + } + bool entityPatternPrinted = false; + for( int i=0; i(delta); + Write( p, toPrint ); + } + } + else { + Write( p ); + } +} + + +void XMLPrinter::PushHeader( bool writeBOM, bool writeDec ) +{ + if ( writeBOM ) { + static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 }; + Write( reinterpret_cast< const char* >( bom ) ); + } + if ( writeDec ) { + PushDeclaration( "xml version=\"1.0\"" ); + } +} + +void XMLPrinter::PrepareForNewNode( bool compactMode ) +{ + SealElementIfJustOpened(); + + if ( compactMode ) { + return; + } + + if ( _firstElement ) { + PrintSpace (_depth); + } else if ( _textDepth < 0) { + Putc( '\n' ); + PrintSpace( _depth ); + } + + _firstElement = false; +} + +void XMLPrinter::OpenElement( const char* name, bool compactMode ) +{ + PrepareForNewNode( compactMode ); + _stack.Push( name ); + + Write ( "<" ); + Write ( name ); + + _elementJustOpened = true; + ++_depth; +} + + +void XMLPrinter::PushAttribute( const char* name, const char* value ) +{ + TIXMLASSERT( _elementJustOpened ); + Putc ( ' ' ); + Write( name ); + Write( "=\"" ); + PrintString( value, false ); + Putc ( '\"' ); +} + + +void XMLPrinter::PushAttribute( const char* name, int v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + PushAttribute( name, buf ); +} + + +void XMLPrinter::PushAttribute( const char* name, unsigned v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + PushAttribute( name, buf ); +} + + +void XMLPrinter::PushAttribute(const char* name, int64_t v) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + PushAttribute(name, buf); +} + + +void XMLPrinter::PushAttribute(const char* name, uint64_t v) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr(v, buf, BUF_SIZE); + PushAttribute(name, buf); +} + + +void XMLPrinter::PushAttribute( const char* name, bool v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + PushAttribute( name, buf ); +} + + +void XMLPrinter::PushAttribute( const char* name, double v ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( v, buf, BUF_SIZE ); + PushAttribute( name, buf ); +} + + +void XMLPrinter::CloseElement( bool compactMode ) +{ + --_depth; + const char* name = _stack.Pop(); + + if ( _elementJustOpened ) { + Write( "/>" ); + } + else { + if ( _textDepth < 0 && !compactMode) { + Putc( '\n' ); + PrintSpace( _depth ); + } + Write ( "" ); + } + + if ( _textDepth == _depth ) { + _textDepth = -1; + } + if ( _depth == 0 && !compactMode) { + Putc( '\n' ); + } + _elementJustOpened = false; +} + + +void XMLPrinter::SealElementIfJustOpened() +{ + if ( !_elementJustOpened ) { + return; + } + _elementJustOpened = false; + Putc( '>' ); +} + + +void XMLPrinter::PushText( const char* text, bool cdata ) +{ + _textDepth = _depth-1; + + SealElementIfJustOpened(); + if ( cdata ) { + Write( "" ); + } + else { + PrintString( text, true ); + } +} + + +void XMLPrinter::PushText( int64_t value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushText( uint64_t value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr(value, buf, BUF_SIZE); + PushText(buf, false); +} + + +void XMLPrinter::PushText( int value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushText( unsigned value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushText( bool value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushText( float value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushText( double value ) +{ + char buf[BUF_SIZE]; + XMLUtil::ToStr( value, buf, BUF_SIZE ); + PushText( buf, false ); +} + + +void XMLPrinter::PushComment( const char* comment ) +{ + PrepareForNewNode( _compactMode ); + + Write( "" ); +} + + +void XMLPrinter::PushDeclaration( const char* value ) +{ + PrepareForNewNode( _compactMode ); + + Write( "" ); +} + + +void XMLPrinter::PushUnknown( const char* value ) +{ + PrepareForNewNode( _compactMode ); + + Write( "' ); +} + + +bool XMLPrinter::VisitEnter( const XMLDocument& doc ) +{ + _processEntities = doc.ProcessEntities(); + if ( doc.HasBOM() ) { + PushHeader( true, false ); + } + return true; +} + + +bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute ) +{ + const XMLElement* parentElem = 0; + if ( element.Parent() ) { + parentElem = element.Parent()->ToElement(); + } + const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode; + OpenElement( element.Name(), compactMode ); + while ( attribute ) { + PushAttribute( attribute->Name(), attribute->Value() ); + attribute = attribute->Next(); + } + return true; +} + + +bool XMLPrinter::VisitExit( const XMLElement& element ) +{ + CloseElement( CompactMode(element) ); + return true; +} + + +bool XMLPrinter::Visit( const XMLText& text ) +{ + PushText( text.Value(), text.CData() ); + return true; +} + + +bool XMLPrinter::Visit( const XMLComment& comment ) +{ + PushComment( comment.Value() ); + return true; +} + +bool XMLPrinter::Visit( const XMLDeclaration& declaration ) +{ + PushDeclaration( declaration.Value() ); + return true; +} + + +bool XMLPrinter::Visit( const XMLUnknown& unknown ) +{ + PushUnknown( unknown.Value() ); + return true; +} + +} // namespace tinyxml2 diff --git a/general/tinyxml2.h b/general/tinyxml2.h new file mode 100644 index 0000000000..003ef43eaf --- /dev/null +++ b/general/tinyxml2.h @@ -0,0 +1,2380 @@ +/* +Original code by Lee Thomason (www.grinninglizard.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#ifndef TINYXML2_INCLUDED +#define TINYXML2_INCLUDED + +#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__) +# include +# include +# include +# include +# include +# if defined(__PS3__) +# include +# endif +#else +# include +# include +# include +# include +# include +#endif +#include + +/* + TODO: intern strings instead of allocation. +*/ +/* + gcc: + g++ -Wall -DTINYXML2_DEBUG tinyxml2.cpp xmltest.cpp -o gccxmltest.exe + + Formatting, Artistic Style: + AStyle.exe --style=1tbs --indent-switches --break-closing-brackets --indent-preprocessor tinyxml2.cpp tinyxml2.h +*/ + +#if defined( _DEBUG ) || defined (__DEBUG__) +# ifndef TINYXML2_DEBUG +# define TINYXML2_DEBUG +# endif +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4251) +#endif + +#ifdef _WIN32 +# ifdef TINYXML2_EXPORT +# define TINYXML2_LIB __declspec(dllexport) +# elif defined(TINYXML2_IMPORT) +# define TINYXML2_LIB __declspec(dllimport) +# else +# define TINYXML2_LIB +# endif +#elif __GNUC__ >= 4 +# define TINYXML2_LIB __attribute__((visibility("default"))) +#else +# define TINYXML2_LIB +#endif + + +#if defined(TINYXML2_DEBUG) +# if defined(_MSC_VER) +# // "(void)0," is for suppressing C4127 warning in "assert(false)", "assert(true)" and the like +# define TIXMLASSERT( x ) if ( !((void)0,(x))) { __debugbreak(); } +# elif defined (ANDROID_NDK) +# include +# define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); } +# else +# include +# define TIXMLASSERT assert +# endif +#else +# define TIXMLASSERT( x ) {} +#endif + + +/* Versioning, past 1.0.14: + http://semver.org/ +*/ +static const int TIXML2_MAJOR_VERSION = 8; +static const int TIXML2_MINOR_VERSION = 0; +static const int TIXML2_PATCH_VERSION = 0; + +#define TINYXML2_MAJOR_VERSION 8 +#define TINYXML2_MINOR_VERSION 0 +#define TINYXML2_PATCH_VERSION 0 + +// A fixed element depth limit is problematic. There needs to be a +// limit to avoid a stack overflow. However, that limit varies per +// system, and the capacity of the stack. On the other hand, it's a trivial +// attack that can result from ill, malicious, or even correctly formed XML, +// so there needs to be a limit in place. +static const int TINYXML2_MAX_ELEMENT_DEPTH = 100; + +namespace tinyxml2 +{ +class XMLDocument; +class XMLElement; +class XMLAttribute; +class XMLComment; +class XMLText; +class XMLDeclaration; +class XMLUnknown; +class XMLPrinter; + +/* + A class that wraps strings. Normally stores the start and end + pointers into the XML file itself, and will apply normalization + and entity translation if actually read. Can also store (and memory + manage) a traditional char[] + + Isn't clear why TINYXML2_LIB is needed; but seems to fix #719 +*/ +class TINYXML2_LIB StrPair +{ +public: + enum { + NEEDS_ENTITY_PROCESSING = 0x01, + NEEDS_NEWLINE_NORMALIZATION = 0x02, + NEEDS_WHITESPACE_COLLAPSING = 0x04, + + TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, + TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, + ATTRIBUTE_NAME = 0, + ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, + ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, + COMMENT = NEEDS_NEWLINE_NORMALIZATION + }; + + StrPair() : _flags( 0 ), _start( 0 ), _end( 0 ) {} + ~StrPair(); + + void Set( char* start, char* end, int flags ) { + TIXMLASSERT( start ); + TIXMLASSERT( end ); + Reset(); + _start = start; + _end = end; + _flags = flags | NEEDS_FLUSH; + } + + const char* GetStr(); + + bool Empty() const { + return _start == _end; + } + + void SetInternedStr( const char* str ) { + Reset(); + _start = const_cast(str); + } + + void SetStr( const char* str, int flags=0 ); + + char* ParseText( char* in, const char* endTag, int strFlags, int* curLineNumPtr ); + char* ParseName( char* in ); + + void TransferTo( StrPair* other ); + void Reset(); + +private: + void CollapseWhitespace(); + + enum { + NEEDS_FLUSH = 0x100, + NEEDS_DELETE = 0x200 + }; + + int _flags; + char* _start; + char* _end; + + StrPair( const StrPair& other ); // not supported + void operator=( const StrPair& other ); // not supported, use TransferTo() +}; + + +/* + A dynamic array of Plain Old Data. Doesn't support constructors, etc. + Has a small initial memory pool, so that low or no usage will not + cause a call to new/delete +*/ +template +class DynArray +{ +public: + DynArray() : + _mem( _pool ), + _allocated( INITIAL_SIZE ), + _size( 0 ) + { + } + + ~DynArray() { + if ( _mem != _pool ) { + delete [] _mem; + } + } + + void Clear() { + _size = 0; + } + + void Push( T t ) { + TIXMLASSERT( _size < INT_MAX ); + EnsureCapacity( _size+1 ); + _mem[_size] = t; + ++_size; + } + + T* PushArr( int count ) { + TIXMLASSERT( count >= 0 ); + TIXMLASSERT( _size <= INT_MAX - count ); + EnsureCapacity( _size+count ); + T* ret = &_mem[_size]; + _size += count; + return ret; + } + + T Pop() { + TIXMLASSERT( _size > 0 ); + --_size; + return _mem[_size]; + } + + void PopArr( int count ) { + TIXMLASSERT( _size >= count ); + _size -= count; + } + + bool Empty() const { + return _size == 0; + } + + T& operator[](int i) { + TIXMLASSERT( i>= 0 && i < _size ); + return _mem[i]; + } + + const T& operator[](int i) const { + TIXMLASSERT( i>= 0 && i < _size ); + return _mem[i]; + } + + const T& PeekTop() const { + TIXMLASSERT( _size > 0 ); + return _mem[ _size - 1]; + } + + int Size() const { + TIXMLASSERT( _size >= 0 ); + return _size; + } + + int Capacity() const { + TIXMLASSERT( _allocated >= INITIAL_SIZE ); + return _allocated; + } + + void SwapRemove(int i) { + TIXMLASSERT(i >= 0 && i < _size); + TIXMLASSERT(_size > 0); + _mem[i] = _mem[_size - 1]; + --_size; + } + + const T* Mem() const { + TIXMLASSERT( _mem ); + return _mem; + } + + T* Mem() { + TIXMLASSERT( _mem ); + return _mem; + } + +private: + DynArray( const DynArray& ); // not supported + void operator=( const DynArray& ); // not supported + + void EnsureCapacity( int cap ) { + TIXMLASSERT( cap > 0 ); + if ( cap > _allocated ) { + TIXMLASSERT( cap <= INT_MAX / 2 ); + const int newAllocated = cap * 2; + T* newMem = new T[newAllocated]; + TIXMLASSERT( newAllocated >= _size ); + memcpy( newMem, _mem, sizeof(T)*_size ); // warning: not using constructors, only works for PODs + if ( _mem != _pool ) { + delete [] _mem; + } + _mem = newMem; + _allocated = newAllocated; + } + } + + T* _mem; + T _pool[INITIAL_SIZE]; + int _allocated; // objects allocated + int _size; // number objects in use +}; + + +/* + Parent virtual class of a pool for fast allocation + and deallocation of objects. +*/ +class MemPool +{ +public: + MemPool() {} + virtual ~MemPool() {} + + virtual int ItemSize() const = 0; + virtual void* Alloc() = 0; + virtual void Free( void* ) = 0; + virtual void SetTracked() = 0; +}; + + +/* + Template child class to create pools of the correct type. +*/ +template< int ITEM_SIZE > +class MemPoolT : public MemPool +{ +public: + MemPoolT() : _blockPtrs(), _root(0), _currentAllocs(0), _nAllocs(0), _maxAllocs(0), _nUntracked(0) {} + ~MemPoolT() { + MemPoolT< ITEM_SIZE >::Clear(); + } + + void Clear() { + // Delete the blocks. + while( !_blockPtrs.Empty()) { + Block* lastBlock = _blockPtrs.Pop(); + delete lastBlock; + } + _root = 0; + _currentAllocs = 0; + _nAllocs = 0; + _maxAllocs = 0; + _nUntracked = 0; + } + + virtual int ItemSize() const { + return ITEM_SIZE; + } + int CurrentAllocs() const { + return _currentAllocs; + } + + virtual void* Alloc() { + if ( !_root ) { + // Need a new block. + Block* block = new Block(); + _blockPtrs.Push( block ); + + Item* blockItems = block->items; + for( int i = 0; i < ITEMS_PER_BLOCK - 1; ++i ) { + blockItems[i].next = &(blockItems[i + 1]); + } + blockItems[ITEMS_PER_BLOCK - 1].next = 0; + _root = blockItems; + } + Item* const result = _root; + TIXMLASSERT( result != 0 ); + _root = _root->next; + + ++_currentAllocs; + if ( _currentAllocs > _maxAllocs ) { + _maxAllocs = _currentAllocs; + } + ++_nAllocs; + ++_nUntracked; + return result; + } + + virtual void Free( void* mem ) { + if ( !mem ) { + return; + } + --_currentAllocs; + Item* item = static_cast( mem ); +#ifdef TINYXML2_DEBUG + memset( item, 0xfe, sizeof( *item ) ); +#endif + item->next = _root; + _root = item; + } + void Trace( const char* name ) { + printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n", + name, _maxAllocs, _maxAllocs * ITEM_SIZE / 1024, _currentAllocs, + ITEM_SIZE, _nAllocs, _blockPtrs.Size() ); + } + + void SetTracked() { + --_nUntracked; + } + + int Untracked() const { + return _nUntracked; + } + + // This number is perf sensitive. 4k seems like a good tradeoff on my machine. + // The test file is large, 170k. + // Release: VS2010 gcc(no opt) + // 1k: 4000 + // 2k: 4000 + // 4k: 3900 21000 + // 16k: 5200 + // 32k: 4300 + // 64k: 4000 21000 + // Declared public because some compilers do not accept to use ITEMS_PER_BLOCK + // in private part if ITEMS_PER_BLOCK is private + enum { ITEMS_PER_BLOCK = (4 * 1024) / ITEM_SIZE }; + +private: + MemPoolT( const MemPoolT& ); // not supported + void operator=( const MemPoolT& ); // not supported + + union Item { + Item* next; + char itemData[ITEM_SIZE]; + }; + struct Block { + Item items[ITEMS_PER_BLOCK]; + }; + DynArray< Block*, 10 > _blockPtrs; + Item* _root; + + int _currentAllocs; + int _nAllocs; + int _maxAllocs; + int _nUntracked; +}; + + + +/** + Implements the interface to the "Visitor pattern" (see the Accept() method.) + If you call the Accept() method, it requires being passed a XMLVisitor + class to handle callbacks. For nodes that contain other nodes (Document, Element) + you will get called with a VisitEnter/VisitExit pair. Nodes that are always leafs + are simply called with Visit(). + + If you return 'true' from a Visit method, recursive parsing will continue. If you return + false, no children of this node or its siblings will be visited. + + All flavors of Visit methods have a default implementation that returns 'true' (continue + visiting). You need to only override methods that are interesting to you. + + Generally Accept() is called on the XMLDocument, although all nodes support visiting. + + You should never change the document from a callback. + + @sa XMLNode::Accept() +*/ +class TINYXML2_LIB XMLVisitor +{ +public: + virtual ~XMLVisitor() {} + + /// Visit a document. + virtual bool VisitEnter( const XMLDocument& /*doc*/ ) { + return true; + } + /// Visit a document. + virtual bool VisitExit( const XMLDocument& /*doc*/ ) { + return true; + } + + /// Visit an element. + virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ ) { + return true; + } + /// Visit an element. + virtual bool VisitExit( const XMLElement& /*element*/ ) { + return true; + } + + /// Visit a declaration. + virtual bool Visit( const XMLDeclaration& /*declaration*/ ) { + return true; + } + /// Visit a text node. + virtual bool Visit( const XMLText& /*text*/ ) { + return true; + } + /// Visit a comment node. + virtual bool Visit( const XMLComment& /*comment*/ ) { + return true; + } + /// Visit an unknown node. + virtual bool Visit( const XMLUnknown& /*unknown*/ ) { + return true; + } +}; + +// WARNING: must match XMLDocument::_errorNames[] +enum XMLError { + XML_SUCCESS = 0, + XML_NO_ATTRIBUTE, + XML_WRONG_ATTRIBUTE_TYPE, + XML_ERROR_FILE_NOT_FOUND, + XML_ERROR_FILE_COULD_NOT_BE_OPENED, + XML_ERROR_FILE_READ_ERROR, + XML_ERROR_PARSING_ELEMENT, + XML_ERROR_PARSING_ATTRIBUTE, + XML_ERROR_PARSING_TEXT, + XML_ERROR_PARSING_CDATA, + XML_ERROR_PARSING_COMMENT, + XML_ERROR_PARSING_DECLARATION, + XML_ERROR_PARSING_UNKNOWN, + XML_ERROR_EMPTY_DOCUMENT, + XML_ERROR_MISMATCHED_ELEMENT, + XML_ERROR_PARSING, + XML_CAN_NOT_CONVERT_TEXT, + XML_NO_TEXT_NODE, + XML_ELEMENT_DEPTH_EXCEEDED, + + XML_ERROR_COUNT +}; + + +/* + Utility functionality. +*/ +class TINYXML2_LIB XMLUtil +{ +public: + static const char* SkipWhiteSpace( const char* p, int* curLineNumPtr ) { + TIXMLASSERT( p ); + + while( IsWhiteSpace(*p) ) { + if (curLineNumPtr && *p == '\n') { + ++(*curLineNumPtr); + } + ++p; + } + TIXMLASSERT( p ); + return p; + } + static char* SkipWhiteSpace( char* const p, int* curLineNumPtr ) { + return const_cast( SkipWhiteSpace( const_cast(p), curLineNumPtr ) ); + } + + // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't + // correct, but simple, and usually works. + static bool IsWhiteSpace( char p ) { + return !IsUTF8Continuation(p) && isspace( static_cast(p) ); + } + + inline static bool IsNameStartChar( unsigned char ch ) { + if ( ch >= 128 ) { + // This is a heuristic guess in attempt to not implement Unicode-aware isalpha() + return true; + } + if ( isalpha( ch ) ) { + return true; + } + return ch == ':' || ch == '_'; + } + + inline static bool IsNameChar( unsigned char ch ) { + return IsNameStartChar( ch ) + || isdigit( ch ) + || ch == '.' + || ch == '-'; + } + + inline static bool IsPrefixHex( const char* p) { + p = SkipWhiteSpace(p, 0); + return p && *p == '0' && ( *(p + 1) == 'x' || *(p + 1) == 'X'); + } + + inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) { + if ( p == q ) { + return true; + } + TIXMLASSERT( p ); + TIXMLASSERT( q ); + TIXMLASSERT( nChar >= 0 ); + return strncmp( p, q, nChar ) == 0; + } + + inline static bool IsUTF8Continuation( const char p ) { + return ( p & 0x80 ) != 0; + } + + static const char* ReadBOM( const char* p, bool* hasBOM ); + // p is the starting location, + // the UTF-8 value of the entity will be placed in value, and length filled in. + static const char* GetCharacterRef( const char* p, char* value, int* length ); + static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ); + + // converts primitive types to strings + static void ToStr( int v, char* buffer, int bufferSize ); + static void ToStr( unsigned v, char* buffer, int bufferSize ); + static void ToStr( bool v, char* buffer, int bufferSize ); + static void ToStr( float v, char* buffer, int bufferSize ); + static void ToStr( double v, char* buffer, int bufferSize ); + static void ToStr(int64_t v, char* buffer, int bufferSize); + static void ToStr(uint64_t v, char* buffer, int bufferSize); + + // converts strings to primitive types + static bool ToInt( const char* str, int* value ); + static bool ToUnsigned( const char* str, unsigned* value ); + static bool ToBool( const char* str, bool* value ); + static bool ToFloat( const char* str, float* value ); + static bool ToDouble( const char* str, double* value ); + static bool ToInt64(const char* str, int64_t* value); + static bool ToUnsigned64(const char* str, uint64_t* value); + // Changes what is serialized for a boolean value. + // Default to "true" and "false". Shouldn't be changed + // unless you have a special testing or compatibility need. + // Be careful: static, global, & not thread safe. + // Be sure to set static const memory as parameters. + static void SetBoolSerialization(const char* writeTrue, const char* writeFalse); + +private: + static const char* writeBoolTrue; + static const char* writeBoolFalse; +}; + + +/** XMLNode is a base class for every object that is in the + XML Document Object Model (DOM), except XMLAttributes. + Nodes have siblings, a parent, and children which can + be navigated. A node is always in a XMLDocument. + The type of a XMLNode can be queried, and it can + be cast to its more defined type. + + A XMLDocument allocates memory for all its Nodes. + When the XMLDocument gets deleted, all its Nodes + will also be deleted. + + @verbatim + A Document can contain: Element (container or leaf) + Comment (leaf) + Unknown (leaf) + Declaration( leaf ) + + An Element can contain: Element (container or leaf) + Text (leaf) + Attributes (not on tree) + Comment (leaf) + Unknown (leaf) + + @endverbatim +*/ +class TINYXML2_LIB XMLNode +{ + friend class XMLDocument; + friend class XMLElement; +public: + + /// Get the XMLDocument that owns this XMLNode. + const XMLDocument* GetDocument() const { + TIXMLASSERT( _document ); + return _document; + } + /// Get the XMLDocument that owns this XMLNode. + XMLDocument* GetDocument() { + TIXMLASSERT( _document ); + return _document; + } + + /// Safely cast to an Element, or null. + virtual XMLElement* ToElement() { + return 0; + } + /// Safely cast to Text, or null. + virtual XMLText* ToText() { + return 0; + } + /// Safely cast to a Comment, or null. + virtual XMLComment* ToComment() { + return 0; + } + /// Safely cast to a Document, or null. + virtual XMLDocument* ToDocument() { + return 0; + } + /// Safely cast to a Declaration, or null. + virtual XMLDeclaration* ToDeclaration() { + return 0; + } + /// Safely cast to an Unknown, or null. + virtual XMLUnknown* ToUnknown() { + return 0; + } + + virtual const XMLElement* ToElement() const { + return 0; + } + virtual const XMLText* ToText() const { + return 0; + } + virtual const XMLComment* ToComment() const { + return 0; + } + virtual const XMLDocument* ToDocument() const { + return 0; + } + virtual const XMLDeclaration* ToDeclaration() const { + return 0; + } + virtual const XMLUnknown* ToUnknown() const { + return 0; + } + + /** The meaning of 'value' changes for the specific type. + @verbatim + Document: empty (NULL is returned, not an empty string) + Element: name of the element + Comment: the comment text + Unknown: the tag contents + Text: the text string + @endverbatim + */ + const char* Value() const; + + /** Set the Value of an XML node. + @sa Value() + */ + void SetValue( const char* val, bool staticMem=false ); + + /// Gets the line number the node is in, if the document was parsed from a file. + int GetLineNum() const { return _parseLineNum; } + + /// Get the parent of this node on the DOM. + const XMLNode* Parent() const { + return _parent; + } + + XMLNode* Parent() { + return _parent; + } + + /// Returns true if this node has no children. + bool NoChildren() const { + return !_firstChild; + } + + /// Get the first child node, or null if none exists. + const XMLNode* FirstChild() const { + return _firstChild; + } + + XMLNode* FirstChild() { + return _firstChild; + } + + /** Get the first child element, or optionally the first child + element with the specified name. + */ + const XMLElement* FirstChildElement( const char* name = 0 ) const; + + XMLElement* FirstChildElement( const char* name = 0 ) { + return const_cast(const_cast(this)->FirstChildElement( name )); + } + + /// Get the last child node, or null if none exists. + const XMLNode* LastChild() const { + return _lastChild; + } + + XMLNode* LastChild() { + return _lastChild; + } + + /** Get the last child element or optionally the last child + element with the specified name. + */ + const XMLElement* LastChildElement( const char* name = 0 ) const; + + XMLElement* LastChildElement( const char* name = 0 ) { + return const_cast(const_cast(this)->LastChildElement(name) ); + } + + /// Get the previous (left) sibling node of this node. + const XMLNode* PreviousSibling() const { + return _prev; + } + + XMLNode* PreviousSibling() { + return _prev; + } + + /// Get the previous (left) sibling element of this node, with an optionally supplied name. + const XMLElement* PreviousSiblingElement( const char* name = 0 ) const ; + + XMLElement* PreviousSiblingElement( const char* name = 0 ) { + return const_cast(const_cast(this)->PreviousSiblingElement( name ) ); + } + + /// Get the next (right) sibling node of this node. + const XMLNode* NextSibling() const { + return _next; + } + + XMLNode* NextSibling() { + return _next; + } + + /// Get the next (right) sibling element of this node, with an optionally supplied name. + const XMLElement* NextSiblingElement( const char* name = 0 ) const; + + XMLElement* NextSiblingElement( const char* name = 0 ) { + return const_cast(const_cast(this)->NextSiblingElement( name ) ); + } + + /** + Add a child node as the last (right) child. + If the child node is already part of the document, + it is moved from its old location to the new location. + Returns the addThis argument or 0 if the node does not + belong to the same document. + */ + XMLNode* InsertEndChild( XMLNode* addThis ); + + XMLNode* LinkEndChild( XMLNode* addThis ) { + return InsertEndChild( addThis ); + } + /** + Add a child node as the first (left) child. + If the child node is already part of the document, + it is moved from its old location to the new location. + Returns the addThis argument or 0 if the node does not + belong to the same document. + */ + XMLNode* InsertFirstChild( XMLNode* addThis ); + /** + Add a node after the specified child node. + If the child node is already part of the document, + it is moved from its old location to the new location. + Returns the addThis argument or 0 if the afterThis node + is not a child of this node, or if the node does not + belong to the same document. + */ + XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ); + + /** + Delete all the children of this node. + */ + void DeleteChildren(); + + /** + Delete a child of this node. + */ + void DeleteChild( XMLNode* node ); + + /** + Make a copy of this node, but not its children. + You may pass in a Document pointer that will be + the owner of the new Node. If the 'document' is + null, then the node returned will be allocated + from the current Document. (this->GetDocument()) + + Note: if called on a XMLDocument, this will return null. + */ + virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0; + + /** + Make a copy of this node and all its children. + + If the 'target' is null, then the nodes will + be allocated in the current document. If 'target' + is specified, the memory will be allocated is the + specified XMLDocument. + + NOTE: This is probably not the correct tool to + copy a document, since XMLDocuments can have multiple + top level XMLNodes. You probably want to use + XMLDocument::DeepCopy() + */ + XMLNode* DeepClone( XMLDocument* target ) const; + + /** + Test if 2 nodes are the same, but don't test children. + The 2 nodes do not need to be in the same Document. + + Note: if called on a XMLDocument, this will return false. + */ + virtual bool ShallowEqual( const XMLNode* compare ) const = 0; + + /** Accept a hierarchical visit of the nodes in the TinyXML-2 DOM. Every node in the + XML tree will be conditionally visited and the host will be called back + via the XMLVisitor interface. + + This is essentially a SAX interface for TinyXML-2. (Note however it doesn't re-parse + the XML for the callbacks, so the performance of TinyXML-2 is unchanged by using this + interface versus any other.) + + The interface has been based on ideas from: + + - http://www.saxproject.org/ + - http://c2.com/cgi/wiki?HierarchicalVisitorPattern + + Which are both good references for "visiting". + + An example of using Accept(): + @verbatim + XMLPrinter printer; + tinyxmlDoc.Accept( &printer ); + const char* xmlcstr = printer.CStr(); + @endverbatim + */ + virtual bool Accept( XMLVisitor* visitor ) const = 0; + + /** + Set user data into the XMLNode. TinyXML-2 in + no way processes or interprets user data. + It is initially 0. + */ + void SetUserData(void* userData) { _userData = userData; } + + /** + Get user data set into the XMLNode. TinyXML-2 in + no way processes or interprets user data. + It is initially 0. + */ + void* GetUserData() const { return _userData; } + +protected: + explicit XMLNode( XMLDocument* ); + virtual ~XMLNode(); + + virtual char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr); + + XMLDocument* _document; + XMLNode* _parent; + mutable StrPair _value; + int _parseLineNum; + + XMLNode* _firstChild; + XMLNode* _lastChild; + + XMLNode* _prev; + XMLNode* _next; + + void* _userData; + +private: + MemPool* _memPool; + void Unlink( XMLNode* child ); + static void DeleteNode( XMLNode* node ); + void InsertChildPreamble( XMLNode* insertThis ) const; + const XMLElement* ToElementWithName( const char* name ) const; + + XMLNode( const XMLNode& ); // not supported + XMLNode& operator=( const XMLNode& ); // not supported +}; + + +/** XML text. + + Note that a text node can have child element nodes, for example: + @verbatim + This is bold + @endverbatim + + A text node can have 2 ways to output the next. "normal" output + and CDATA. It will default to the mode it was parsed from the XML file and + you generally want to leave it alone, but you can change the output mode with + SetCData() and query it with CData(). +*/ +class TINYXML2_LIB XMLText : public XMLNode +{ + friend class XMLDocument; +public: + virtual bool Accept( XMLVisitor* visitor ) const; + + virtual XMLText* ToText() { + return this; + } + virtual const XMLText* ToText() const { + return this; + } + + /// Declare whether this should be CDATA or standard text. + void SetCData( bool isCData ) { + _isCData = isCData; + } + /// Returns true if this is a CDATA text element. + bool CData() const { + return _isCData; + } + + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + explicit XMLText( XMLDocument* doc ) : XMLNode( doc ), _isCData( false ) {} + virtual ~XMLText() {} + + char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ); + +private: + bool _isCData; + + XMLText( const XMLText& ); // not supported + XMLText& operator=( const XMLText& ); // not supported +}; + + +/** An XML Comment. */ +class TINYXML2_LIB XMLComment : public XMLNode +{ + friend class XMLDocument; +public: + virtual XMLComment* ToComment() { + return this; + } + virtual const XMLComment* ToComment() const { + return this; + } + + virtual bool Accept( XMLVisitor* visitor ) const; + + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + explicit XMLComment( XMLDocument* doc ); + virtual ~XMLComment(); + + char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr); + +private: + XMLComment( const XMLComment& ); // not supported + XMLComment& operator=( const XMLComment& ); // not supported +}; + + +/** In correct XML the declaration is the first entry in the file. + @verbatim + + @endverbatim + + TinyXML-2 will happily read or write files without a declaration, + however. + + The text of the declaration isn't interpreted. It is parsed + and written as a string. +*/ +class TINYXML2_LIB XMLDeclaration : public XMLNode +{ + friend class XMLDocument; +public: + virtual XMLDeclaration* ToDeclaration() { + return this; + } + virtual const XMLDeclaration* ToDeclaration() const { + return this; + } + + virtual bool Accept( XMLVisitor* visitor ) const; + + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + explicit XMLDeclaration( XMLDocument* doc ); + virtual ~XMLDeclaration(); + + char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ); + +private: + XMLDeclaration( const XMLDeclaration& ); // not supported + XMLDeclaration& operator=( const XMLDeclaration& ); // not supported +}; + + +/** Any tag that TinyXML-2 doesn't recognize is saved as an + unknown. It is a tag of text, but should not be modified. + It will be written back to the XML, unchanged, when the file + is saved. + + DTD tags get thrown into XMLUnknowns. +*/ +class TINYXML2_LIB XMLUnknown : public XMLNode +{ + friend class XMLDocument; +public: + virtual XMLUnknown* ToUnknown() { + return this; + } + virtual const XMLUnknown* ToUnknown() const { + return this; + } + + virtual bool Accept( XMLVisitor* visitor ) const; + + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + explicit XMLUnknown( XMLDocument* doc ); + virtual ~XMLUnknown(); + + char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ); + +private: + XMLUnknown( const XMLUnknown& ); // not supported + XMLUnknown& operator=( const XMLUnknown& ); // not supported +}; + + + +/** An attribute is a name-value pair. Elements have an arbitrary + number of attributes, each with a unique name. + + @note The attributes are not XMLNodes. You may only query the + Next() attribute in a list. +*/ +class TINYXML2_LIB XMLAttribute +{ + friend class XMLElement; +public: + /// The name of the attribute. + const char* Name() const; + + /// The value of the attribute. + const char* Value() const; + + /// Gets the line number the attribute is in, if the document was parsed from a file. + int GetLineNum() const { return _parseLineNum; } + + /// The next attribute in the list. + const XMLAttribute* Next() const { + return _next; + } + + /** IntValue interprets the attribute as an integer, and returns the value. + If the value isn't an integer, 0 will be returned. There is no error checking; + use QueryIntValue() if you need error checking. + */ + int IntValue() const { + int i = 0; + QueryIntValue(&i); + return i; + } + + int64_t Int64Value() const { + int64_t i = 0; + QueryInt64Value(&i); + return i; + } + + uint64_t Unsigned64Value() const { + uint64_t i = 0; + QueryUnsigned64Value(&i); + return i; + } + + /// Query as an unsigned integer. See IntValue() + unsigned UnsignedValue() const { + unsigned i=0; + QueryUnsignedValue( &i ); + return i; + } + /// Query as a boolean. See IntValue() + bool BoolValue() const { + bool b=false; + QueryBoolValue( &b ); + return b; + } + /// Query as a double. See IntValue() + double DoubleValue() const { + double d=0; + QueryDoubleValue( &d ); + return d; + } + /// Query as a float. See IntValue() + float FloatValue() const { + float f=0; + QueryFloatValue( &f ); + return f; + } + + /** QueryIntValue interprets the attribute as an integer, and returns the value + in the provided parameter. The function will return XML_SUCCESS on success, + and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful. + */ + XMLError QueryIntValue( int* value ) const; + /// See QueryIntValue + XMLError QueryUnsignedValue( unsigned int* value ) const; + /// See QueryIntValue + XMLError QueryInt64Value(int64_t* value) const; + /// See QueryIntValue + XMLError QueryUnsigned64Value(uint64_t* value) const; + /// See QueryIntValue + XMLError QueryBoolValue( bool* value ) const; + /// See QueryIntValue + XMLError QueryDoubleValue( double* value ) const; + /// See QueryIntValue + XMLError QueryFloatValue( float* value ) const; + + /// Set the attribute to a string value. + void SetAttribute( const char* value ); + /// Set the attribute to value. + void SetAttribute( int value ); + /// Set the attribute to value. + void SetAttribute( unsigned value ); + /// Set the attribute to value. + void SetAttribute(int64_t value); + /// Set the attribute to value. + void SetAttribute(uint64_t value); + /// Set the attribute to value. + void SetAttribute( bool value ); + /// Set the attribute to value. + void SetAttribute( double value ); + /// Set the attribute to value. + void SetAttribute( float value ); + +private: + enum { BUF_SIZE = 200 }; + + XMLAttribute() : _name(), _value(),_parseLineNum( 0 ), _next( 0 ), _memPool( 0 ) {} + virtual ~XMLAttribute() {} + + XMLAttribute( const XMLAttribute& ); // not supported + void operator=( const XMLAttribute& ); // not supported + void SetName( const char* name ); + + char* ParseDeep( char* p, bool processEntities, int* curLineNumPtr ); + + mutable StrPair _name; + mutable StrPair _value; + int _parseLineNum; + XMLAttribute* _next; + MemPool* _memPool; +}; + + +/** The element is a container class. It has a value, the element name, + and can contain other elements, text, comments, and unknowns. + Elements also contain an arbitrary number of attributes. +*/ +class TINYXML2_LIB XMLElement : public XMLNode +{ + friend class XMLDocument; +public: + /// Get the name of an element (which is the Value() of the node.) + const char* Name() const { + return Value(); + } + /// Set the name of the element. + void SetName( const char* str, bool staticMem=false ) { + SetValue( str, staticMem ); + } + + virtual XMLElement* ToElement() { + return this; + } + virtual const XMLElement* ToElement() const { + return this; + } + virtual bool Accept( XMLVisitor* visitor ) const; + + /** Given an attribute name, Attribute() returns the value + for the attribute of that name, or null if none + exists. For example: + + @verbatim + const char* value = ele->Attribute( "foo" ); + @endverbatim + + The 'value' parameter is normally null. However, if specified, + the attribute will only be returned if the 'name' and 'value' + match. This allow you to write code: + + @verbatim + if ( ele->Attribute( "foo", "bar" ) ) callFooIsBar(); + @endverbatim + + rather than: + @verbatim + if ( ele->Attribute( "foo" ) ) { + if ( strcmp( ele->Attribute( "foo" ), "bar" ) == 0 ) callFooIsBar(); + } + @endverbatim + */ + const char* Attribute( const char* name, const char* value=0 ) const; + + /** Given an attribute name, IntAttribute() returns the value + of the attribute interpreted as an integer. The default + value will be returned if the attribute isn't present, + or if there is an error. (For a method with error + checking, see QueryIntAttribute()). + */ + int IntAttribute(const char* name, int defaultValue = 0) const; + /// See IntAttribute() + unsigned UnsignedAttribute(const char* name, unsigned defaultValue = 0) const; + /// See IntAttribute() + int64_t Int64Attribute(const char* name, int64_t defaultValue = 0) const; + /// See IntAttribute() + uint64_t Unsigned64Attribute(const char* name, uint64_t defaultValue = 0) const; + /// See IntAttribute() + bool BoolAttribute(const char* name, bool defaultValue = false) const; + /// See IntAttribute() + double DoubleAttribute(const char* name, double defaultValue = 0) const; + /// See IntAttribute() + float FloatAttribute(const char* name, float defaultValue = 0) const; + + /** Given an attribute name, QueryIntAttribute() returns + XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion + can't be performed, or XML_NO_ATTRIBUTE if the attribute + doesn't exist. If successful, the result of the conversion + will be written to 'value'. If not successful, nothing will + be written to 'value'. This allows you to provide default + value: + + @verbatim + int value = 10; + QueryIntAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10 + @endverbatim + */ + XMLError QueryIntAttribute( const char* name, int* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryIntValue( value ); + } + + /// See QueryIntAttribute() + XMLError QueryUnsignedAttribute( const char* name, unsigned int* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryUnsignedValue( value ); + } + + /// See QueryIntAttribute() + XMLError QueryInt64Attribute(const char* name, int64_t* value) const { + const XMLAttribute* a = FindAttribute(name); + if (!a) { + return XML_NO_ATTRIBUTE; + } + return a->QueryInt64Value(value); + } + + /// See QueryIntAttribute() + XMLError QueryUnsigned64Attribute(const char* name, uint64_t* value) const { + const XMLAttribute* a = FindAttribute(name); + if(!a) { + return XML_NO_ATTRIBUTE; + } + return a->QueryUnsigned64Value(value); + } + + /// See QueryIntAttribute() + XMLError QueryBoolAttribute( const char* name, bool* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryBoolValue( value ); + } + /// See QueryIntAttribute() + XMLError QueryDoubleAttribute( const char* name, double* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryDoubleValue( value ); + } + /// See QueryIntAttribute() + XMLError QueryFloatAttribute( const char* name, float* value ) const { + const XMLAttribute* a = FindAttribute( name ); + if ( !a ) { + return XML_NO_ATTRIBUTE; + } + return a->QueryFloatValue( value ); + } + + /// See QueryIntAttribute() + XMLError QueryStringAttribute(const char* name, const char** value) const { + const XMLAttribute* a = FindAttribute(name); + if (!a) { + return XML_NO_ATTRIBUTE; + } + *value = a->Value(); + return XML_SUCCESS; + } + + + + /** Given an attribute name, QueryAttribute() returns + XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion + can't be performed, or XML_NO_ATTRIBUTE if the attribute + doesn't exist. It is overloaded for the primitive types, + and is a generally more convenient replacement of + QueryIntAttribute() and related functions. + + If successful, the result of the conversion + will be written to 'value'. If not successful, nothing will + be written to 'value'. This allows you to provide default + value: + + @verbatim + int value = 10; + QueryAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10 + @endverbatim + */ + XMLError QueryAttribute( const char* name, int* value ) const { + return QueryIntAttribute( name, value ); + } + + XMLError QueryAttribute( const char* name, unsigned int* value ) const { + return QueryUnsignedAttribute( name, value ); + } + + XMLError QueryAttribute(const char* name, int64_t* value) const { + return QueryInt64Attribute(name, value); + } + + XMLError QueryAttribute(const char* name, uint64_t* value) const { + return QueryUnsigned64Attribute(name, value); + } + + XMLError QueryAttribute( const char* name, bool* value ) const { + return QueryBoolAttribute( name, value ); + } + + XMLError QueryAttribute( const char* name, double* value ) const { + return QueryDoubleAttribute( name, value ); + } + + XMLError QueryAttribute( const char* name, float* value ) const { + return QueryFloatAttribute( name, value ); + } + + XMLError QueryAttribute(const char* name, const char** value) const { + return QueryStringAttribute(name, value); + } + + /// Sets the named attribute to value. + void SetAttribute( const char* name, const char* value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, int value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, unsigned value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + + /// Sets the named attribute to value. + void SetAttribute(const char* name, int64_t value) { + XMLAttribute* a = FindOrCreateAttribute(name); + a->SetAttribute(value); + } + + /// Sets the named attribute to value. + void SetAttribute(const char* name, uint64_t value) { + XMLAttribute* a = FindOrCreateAttribute(name); + a->SetAttribute(value); + } + + /// Sets the named attribute to value. + void SetAttribute( const char* name, bool value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, double value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + /// Sets the named attribute to value. + void SetAttribute( const char* name, float value ) { + XMLAttribute* a = FindOrCreateAttribute( name ); + a->SetAttribute( value ); + } + + /** + Delete an attribute. + */ + void DeleteAttribute( const char* name ); + + /// Return the first attribute in the list. + const XMLAttribute* FirstAttribute() const { + return _rootAttribute; + } + /// Query a specific attribute in the list. + const XMLAttribute* FindAttribute( const char* name ) const; + + /** Convenience function for easy access to the text inside an element. Although easy + and concise, GetText() is limited compared to getting the XMLText child + and accessing it directly. + + If the first child of 'this' is a XMLText, the GetText() + returns the character string of the Text node, else null is returned. + + This is a convenient method for getting the text of simple contained text: + @verbatim + This is text + const char* str = fooElement->GetText(); + @endverbatim + + 'str' will be a pointer to "This is text". + + Note that this function can be misleading. If the element foo was created from + this XML: + @verbatim + This is text + @endverbatim + + then the value of str would be null. The first child node isn't a text node, it is + another element. From this XML: + @verbatim + This is text + @endverbatim + GetText() will return "This is ". + */ + const char* GetText() const; + + /** Convenience function for easy access to the text inside an element. Although easy + and concise, SetText() is limited compared to creating an XMLText child + and mutating it directly. + + If the first child of 'this' is a XMLText, SetText() sets its value to + the given string, otherwise it will create a first child that is an XMLText. + + This is a convenient method for setting the text of simple contained text: + @verbatim + This is text + fooElement->SetText( "Hullaballoo!" ); + Hullaballoo! + @endverbatim + + Note that this function can be misleading. If the element foo was created from + this XML: + @verbatim + This is text + @endverbatim + + then it will not change "This is text", but rather prefix it with a text element: + @verbatim + Hullaballoo!This is text + @endverbatim + + For this XML: + @verbatim + + @endverbatim + SetText() will generate + @verbatim + Hullaballoo! + @endverbatim + */ + void SetText( const char* inText ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( int value ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( unsigned value ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText(int64_t value); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText(uint64_t value); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( bool value ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( double value ); + /// Convenience method for setting text inside an element. See SetText() for important limitations. + void SetText( float value ); + + /** + Convenience method to query the value of a child text node. This is probably best + shown by example. Given you have a document is this form: + @verbatim + + 1 + 1.4 + + @endverbatim + + The QueryIntText() and similar functions provide a safe and easier way to get to the + "value" of x and y. + + @verbatim + int x = 0; + float y = 0; // types of x and y are contrived for example + const XMLElement* xElement = pointElement->FirstChildElement( "x" ); + const XMLElement* yElement = pointElement->FirstChildElement( "y" ); + xElement->QueryIntText( &x ); + yElement->QueryFloatText( &y ); + @endverbatim + + @returns XML_SUCCESS (0) on success, XML_CAN_NOT_CONVERT_TEXT if the text cannot be converted + to the requested type, and XML_NO_TEXT_NODE if there is no child text to query. + + */ + XMLError QueryIntText( int* ival ) const; + /// See QueryIntText() + XMLError QueryUnsignedText( unsigned* uval ) const; + /// See QueryIntText() + XMLError QueryInt64Text(int64_t* uval) const; + /// See QueryIntText() + XMLError QueryUnsigned64Text(uint64_t* uval) const; + /// See QueryIntText() + XMLError QueryBoolText( bool* bval ) const; + /// See QueryIntText() + XMLError QueryDoubleText( double* dval ) const; + /// See QueryIntText() + XMLError QueryFloatText( float* fval ) const; + + int IntText(int defaultValue = 0) const; + + /// See QueryIntText() + unsigned UnsignedText(unsigned defaultValue = 0) const; + /// See QueryIntText() + int64_t Int64Text(int64_t defaultValue = 0) const; + /// See QueryIntText() + uint64_t Unsigned64Text(uint64_t defaultValue = 0) const; + /// See QueryIntText() + bool BoolText(bool defaultValue = false) const; + /// See QueryIntText() + double DoubleText(double defaultValue = 0) const; + /// See QueryIntText() + float FloatText(float defaultValue = 0) const; + + /** + Convenience method to create a new XMLElement and add it as last (right) + child of this node. Returns the created and inserted element. + */ + XMLElement* InsertNewChildElement(const char* name); + /// See InsertNewChildElement() + XMLComment* InsertNewComment(const char* comment); + /// See InsertNewChildElement() + XMLText* InsertNewText(const char* text); + /// See InsertNewChildElement() + XMLDeclaration* InsertNewDeclaration(const char* text); + /// See InsertNewChildElement() + XMLUnknown* InsertNewUnknown(const char* text); + + + // internal: + enum ElementClosingType { + OPEN, // + CLOSED, // + CLOSING // + }; + ElementClosingType ClosingType() const { + return _closingType; + } + virtual XMLNode* ShallowClone( XMLDocument* document ) const; + virtual bool ShallowEqual( const XMLNode* compare ) const; + +protected: + char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ); + +private: + XMLElement( XMLDocument* doc ); + virtual ~XMLElement(); + XMLElement( const XMLElement& ); // not supported + void operator=( const XMLElement& ); // not supported + + XMLAttribute* FindOrCreateAttribute( const char* name ); + char* ParseAttributes( char* p, int* curLineNumPtr ); + static void DeleteAttribute( XMLAttribute* attribute ); + XMLAttribute* CreateAttribute(); + + enum { BUF_SIZE = 200 }; + ElementClosingType _closingType; + // The attribute list is ordered; there is no 'lastAttribute' + // because the list needs to be scanned for dupes before adding + // a new attribute. + XMLAttribute* _rootAttribute; +}; + + +enum Whitespace { + PRESERVE_WHITESPACE, + COLLAPSE_WHITESPACE +}; + + +/** A Document binds together all the functionality. + It can be saved, loaded, and printed to the screen. + All Nodes are connected and allocated to a Document. + If the Document is deleted, all its Nodes are also deleted. +*/ +class TINYXML2_LIB XMLDocument : public XMLNode +{ + friend class XMLElement; + // Gives access to SetError and Push/PopDepth, but over-access for everything else. + // Wishing C++ had "internal" scope. + friend class XMLNode; + friend class XMLText; + friend class XMLComment; + friend class XMLDeclaration; + friend class XMLUnknown; +public: + /// constructor + XMLDocument( bool processEntities = true, Whitespace whitespaceMode = PRESERVE_WHITESPACE ); + ~XMLDocument(); + + virtual XMLDocument* ToDocument() { + TIXMLASSERT( this == _document ); + return this; + } + virtual const XMLDocument* ToDocument() const { + TIXMLASSERT( this == _document ); + return this; + } + + /** + Parse an XML file from a character string. + Returns XML_SUCCESS (0) on success, or + an errorID. + + You may optionally pass in the 'nBytes', which is + the number of bytes which will be parsed. If not + specified, TinyXML-2 will assume 'xml' points to a + null terminated string. + */ + XMLError Parse( const char* xml, size_t nBytes=static_cast(-1) ); + + /** + Load an XML file from disk. + Returns XML_SUCCESS (0) on success, or + an errorID. + */ + XMLError LoadFile( const char* filename ); + + /** + Load an XML file from disk. You are responsible + for providing and closing the FILE*. + + NOTE: The file should be opened as binary ("rb") + not text in order for TinyXML-2 to correctly + do newline normalization. + + Returns XML_SUCCESS (0) on success, or + an errorID. + */ + XMLError LoadFile( FILE* ); + + /** + Save the XML file to disk. + Returns XML_SUCCESS (0) on success, or + an errorID. + */ + XMLError SaveFile( const char* filename, bool compact = false ); + + /** + Save the XML file to disk. You are responsible + for providing and closing the FILE*. + + Returns XML_SUCCESS (0) on success, or + an errorID. + */ + XMLError SaveFile( FILE* fp, bool compact = false ); + + bool ProcessEntities() const { + return _processEntities; + } + Whitespace WhitespaceMode() const { + return _whitespaceMode; + } + + /** + Returns true if this document has a leading Byte Order Mark of UTF8. + */ + bool HasBOM() const { + return _writeBOM; + } + /** Sets whether to write the BOM when writing the file. + */ + void SetBOM( bool useBOM ) { + _writeBOM = useBOM; + } + + /** Return the root element of DOM. Equivalent to FirstChildElement(). + To get the first node, use FirstChild(). + */ + XMLElement* RootElement() { + return FirstChildElement(); + } + const XMLElement* RootElement() const { + return FirstChildElement(); + } + + /** Print the Document. If the Printer is not provided, it will + print to stdout. If you provide Printer, this can print to a file: + @verbatim + XMLPrinter printer( fp ); + doc.Print( &printer ); + @endverbatim + + Or you can use a printer to print to memory: + @verbatim + XMLPrinter printer; + doc.Print( &printer ); + // printer.CStr() has a const char* to the XML + @endverbatim + */ + void Print( XMLPrinter* streamer=0 ) const; + virtual bool Accept( XMLVisitor* visitor ) const; + + /** + Create a new Element associated with + this Document. The memory for the Element + is managed by the Document. + */ + XMLElement* NewElement( const char* name ); + /** + Create a new Comment associated with + this Document. The memory for the Comment + is managed by the Document. + */ + XMLComment* NewComment( const char* comment ); + /** + Create a new Text associated with + this Document. The memory for the Text + is managed by the Document. + */ + XMLText* NewText( const char* text ); + /** + Create a new Declaration associated with + this Document. The memory for the object + is managed by the Document. + + If the 'text' param is null, the standard + declaration is used.: + @verbatim + + @endverbatim + */ + XMLDeclaration* NewDeclaration( const char* text=0 ); + /** + Create a new Unknown associated with + this Document. The memory for the object + is managed by the Document. + */ + XMLUnknown* NewUnknown( const char* text ); + + /** + Delete a node associated with this document. + It will be unlinked from the DOM. + */ + void DeleteNode( XMLNode* node ); + + void ClearError() { + SetError(XML_SUCCESS, 0, 0); + } + + /// Return true if there was an error parsing the document. + bool Error() const { + return _errorID != XML_SUCCESS; + } + /// Return the errorID. + XMLError ErrorID() const { + return _errorID; + } + const char* ErrorName() const; + static const char* ErrorIDToName(XMLError errorID); + + /** Returns a "long form" error description. A hopefully helpful + diagnostic with location, line number, and/or additional info. + */ + const char* ErrorStr() const; + + /// A (trivial) utility function that prints the ErrorStr() to stdout. + void PrintError() const; + + /// Return the line where the error occurred, or zero if unknown. + int ErrorLineNum() const + { + return _errorLineNum; + } + + /// Clear the document, resetting it to the initial state. + void Clear(); + + /** + Copies this document to a target document. + The target will be completely cleared before the copy. + If you want to copy a sub-tree, see XMLNode::DeepClone(). + + NOTE: that the 'target' must be non-null. + */ + void DeepCopy(XMLDocument* target) const; + + // internal + char* Identify( char* p, XMLNode** node ); + + // internal + void MarkInUse(const XMLNode* const); + + virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const { + return 0; + } + virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const { + return false; + } + +private: + XMLDocument( const XMLDocument& ); // not supported + void operator=( const XMLDocument& ); // not supported + + bool _writeBOM; + bool _processEntities; + XMLError _errorID; + Whitespace _whitespaceMode; + mutable StrPair _errorStr; + int _errorLineNum; + char* _charBuffer; + int _parseCurLineNum; + int _parsingDepth; + // Memory tracking does add some overhead. + // However, the code assumes that you don't + // have a bunch of unlinked nodes around. + // Therefore it takes less memory to track + // in the document vs. a linked list in the XMLNode, + // and the performance is the same. + DynArray _unlinked; + + MemPoolT< sizeof(XMLElement) > _elementPool; + MemPoolT< sizeof(XMLAttribute) > _attributePool; + MemPoolT< sizeof(XMLText) > _textPool; + MemPoolT< sizeof(XMLComment) > _commentPool; + + static const char* _errorNames[XML_ERROR_COUNT]; + + void Parse(); + + void SetError( XMLError error, int lineNum, const char* format, ... ); + + // Something of an obvious security hole, once it was discovered. + // Either an ill-formed XML or an excessively deep one can overflow + // the stack. Track stack depth, and error out if needed. + class DepthTracker { + public: + explicit DepthTracker(XMLDocument * document) { + this->_document = document; + document->PushDepth(); + } + ~DepthTracker() { + _document->PopDepth(); + } + private: + XMLDocument * _document; + }; + void PushDepth(); + void PopDepth(); + + template + NodeType* CreateUnlinkedNode( MemPoolT& pool ); +}; + +template +inline NodeType* XMLDocument::CreateUnlinkedNode( MemPoolT& pool ) +{ + TIXMLASSERT( sizeof( NodeType ) == PoolElementSize ); + TIXMLASSERT( sizeof( NodeType ) == pool.ItemSize() ); + NodeType* returnNode = new (pool.Alloc()) NodeType( this ); + TIXMLASSERT( returnNode ); + returnNode->_memPool = &pool; + + _unlinked.Push(returnNode); + return returnNode; +} + +/** + A XMLHandle is a class that wraps a node pointer with null checks; this is + an incredibly useful thing. Note that XMLHandle is not part of the TinyXML-2 + DOM structure. It is a separate utility class. + + Take an example: + @verbatim + + + + + + + @endverbatim + + Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very + easy to write a *lot* of code that looks like: + + @verbatim + XMLElement* root = document.FirstChildElement( "Document" ); + if ( root ) + { + XMLElement* element = root->FirstChildElement( "Element" ); + if ( element ) + { + XMLElement* child = element->FirstChildElement( "Child" ); + if ( child ) + { + XMLElement* child2 = child->NextSiblingElement( "Child" ); + if ( child2 ) + { + // Finally do something useful. + @endverbatim + + And that doesn't even cover "else" cases. XMLHandle addresses the verbosity + of such code. A XMLHandle checks for null pointers so it is perfectly safe + and correct to use: + + @verbatim + XMLHandle docHandle( &document ); + XMLElement* child2 = docHandle.FirstChildElement( "Document" ).FirstChildElement( "Element" ).FirstChildElement().NextSiblingElement(); + if ( child2 ) + { + // do something useful + @endverbatim + + Which is MUCH more concise and useful. + + It is also safe to copy handles - internally they are nothing more than node pointers. + @verbatim + XMLHandle handleCopy = handle; + @endverbatim + + See also XMLConstHandle, which is the same as XMLHandle, but operates on const objects. +*/ +class TINYXML2_LIB XMLHandle +{ +public: + /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. + explicit XMLHandle( XMLNode* node ) : _node( node ) { + } + /// Create a handle from a node. + explicit XMLHandle( XMLNode& node ) : _node( &node ) { + } + /// Copy constructor + XMLHandle( const XMLHandle& ref ) : _node( ref._node ) { + } + /// Assignment + XMLHandle& operator=( const XMLHandle& ref ) { + _node = ref._node; + return *this; + } + + /// Get the first child of this handle. + XMLHandle FirstChild() { + return XMLHandle( _node ? _node->FirstChild() : 0 ); + } + /// Get the first child element of this handle. + XMLHandle FirstChildElement( const char* name = 0 ) { + return XMLHandle( _node ? _node->FirstChildElement( name ) : 0 ); + } + /// Get the last child of this handle. + XMLHandle LastChild() { + return XMLHandle( _node ? _node->LastChild() : 0 ); + } + /// Get the last child element of this handle. + XMLHandle LastChildElement( const char* name = 0 ) { + return XMLHandle( _node ? _node->LastChildElement( name ) : 0 ); + } + /// Get the previous sibling of this handle. + XMLHandle PreviousSibling() { + return XMLHandle( _node ? _node->PreviousSibling() : 0 ); + } + /// Get the previous sibling element of this handle. + XMLHandle PreviousSiblingElement( const char* name = 0 ) { + return XMLHandle( _node ? _node->PreviousSiblingElement( name ) : 0 ); + } + /// Get the next sibling of this handle. + XMLHandle NextSibling() { + return XMLHandle( _node ? _node->NextSibling() : 0 ); + } + /// Get the next sibling element of this handle. + XMLHandle NextSiblingElement( const char* name = 0 ) { + return XMLHandle( _node ? _node->NextSiblingElement( name ) : 0 ); + } + + /// Safe cast to XMLNode. This can return null. + XMLNode* ToNode() { + return _node; + } + /// Safe cast to XMLElement. This can return null. + XMLElement* ToElement() { + return ( _node ? _node->ToElement() : 0 ); + } + /// Safe cast to XMLText. This can return null. + XMLText* ToText() { + return ( _node ? _node->ToText() : 0 ); + } + /// Safe cast to XMLUnknown. This can return null. + XMLUnknown* ToUnknown() { + return ( _node ? _node->ToUnknown() : 0 ); + } + /// Safe cast to XMLDeclaration. This can return null. + XMLDeclaration* ToDeclaration() { + return ( _node ? _node->ToDeclaration() : 0 ); + } + +private: + XMLNode* _node; +}; + + +/** + A variant of the XMLHandle class for working with const XMLNodes and Documents. It is the + same in all regards, except for the 'const' qualifiers. See XMLHandle for API. +*/ +class TINYXML2_LIB XMLConstHandle +{ +public: + explicit XMLConstHandle( const XMLNode* node ) : _node( node ) { + } + explicit XMLConstHandle( const XMLNode& node ) : _node( &node ) { + } + XMLConstHandle( const XMLConstHandle& ref ) : _node( ref._node ) { + } + + XMLConstHandle& operator=( const XMLConstHandle& ref ) { + _node = ref._node; + return *this; + } + + const XMLConstHandle FirstChild() const { + return XMLConstHandle( _node ? _node->FirstChild() : 0 ); + } + const XMLConstHandle FirstChildElement( const char* name = 0 ) const { + return XMLConstHandle( _node ? _node->FirstChildElement( name ) : 0 ); + } + const XMLConstHandle LastChild() const { + return XMLConstHandle( _node ? _node->LastChild() : 0 ); + } + const XMLConstHandle LastChildElement( const char* name = 0 ) const { + return XMLConstHandle( _node ? _node->LastChildElement( name ) : 0 ); + } + const XMLConstHandle PreviousSibling() const { + return XMLConstHandle( _node ? _node->PreviousSibling() : 0 ); + } + const XMLConstHandle PreviousSiblingElement( const char* name = 0 ) const { + return XMLConstHandle( _node ? _node->PreviousSiblingElement( name ) : 0 ); + } + const XMLConstHandle NextSibling() const { + return XMLConstHandle( _node ? _node->NextSibling() : 0 ); + } + const XMLConstHandle NextSiblingElement( const char* name = 0 ) const { + return XMLConstHandle( _node ? _node->NextSiblingElement( name ) : 0 ); + } + + + const XMLNode* ToNode() const { + return _node; + } + const XMLElement* ToElement() const { + return ( _node ? _node->ToElement() : 0 ); + } + const XMLText* ToText() const { + return ( _node ? _node->ToText() : 0 ); + } + const XMLUnknown* ToUnknown() const { + return ( _node ? _node->ToUnknown() : 0 ); + } + const XMLDeclaration* ToDeclaration() const { + return ( _node ? _node->ToDeclaration() : 0 ); + } + +private: + const XMLNode* _node; +}; + + +/** + Printing functionality. The XMLPrinter gives you more + options than the XMLDocument::Print() method. + + It can: + -# Print to memory. + -# Print to a file you provide. + -# Print XML without a XMLDocument. + + Print to Memory + + @verbatim + XMLPrinter printer; + doc.Print( &printer ); + SomeFunction( printer.CStr() ); + @endverbatim + + Print to a File + + You provide the file pointer. + @verbatim + XMLPrinter printer( fp ); + doc.Print( &printer ); + @endverbatim + + Print without a XMLDocument + + When loading, an XML parser is very useful. However, sometimes + when saving, it just gets in the way. The code is often set up + for streaming, and constructing the DOM is just overhead. + + The Printer supports the streaming case. The following code + prints out a trivially simple XML file without ever creating + an XML document. + + @verbatim + XMLPrinter printer( fp ); + printer.OpenElement( "foo" ); + printer.PushAttribute( "foo", "bar" ); + printer.CloseElement(); + @endverbatim +*/ +class TINYXML2_LIB XMLPrinter : public XMLVisitor +{ +public: + /** Construct the printer. If the FILE* is specified, + this will print to the FILE. Else it will print + to memory, and the result is available in CStr(). + If 'compact' is set to true, then output is created + with only required whitespace and newlines. + */ + XMLPrinter( FILE* file=0, bool compact = false, int depth = 0 ); + virtual ~XMLPrinter() {} + + /** If streaming, write the BOM and declaration. */ + void PushHeader( bool writeBOM, bool writeDeclaration ); + /** If streaming, start writing an element. + The element must be closed with CloseElement() + */ + void OpenElement( const char* name, bool compactMode=false ); + /// If streaming, add an attribute to an open element. + void PushAttribute( const char* name, const char* value ); + void PushAttribute( const char* name, int value ); + void PushAttribute( const char* name, unsigned value ); + void PushAttribute( const char* name, int64_t value ); + void PushAttribute( const char* name, uint64_t value ); + void PushAttribute( const char* name, bool value ); + void PushAttribute( const char* name, double value ); + /// If streaming, close the Element. + virtual void CloseElement( bool compactMode=false ); + + /// Add a text node. + void PushText( const char* text, bool cdata=false ); + /// Add a text node from an integer. + void PushText( int value ); + /// Add a text node from an unsigned. + void PushText( unsigned value ); + /// Add a text node from a signed 64bit integer. + void PushText( int64_t value ); + /// Add a text node from an unsigned 64bit integer. + void PushText( uint64_t value ); + /// Add a text node from a bool. + void PushText( bool value ); + /// Add a text node from a float. + void PushText( float value ); + /// Add a text node from a double. + void PushText( double value ); + + /// Add a comment + void PushComment( const char* comment ); + + void PushDeclaration( const char* value ); + void PushUnknown( const char* value ); + + virtual bool VisitEnter( const XMLDocument& /*doc*/ ); + virtual bool VisitExit( const XMLDocument& /*doc*/ ) { + return true; + } + + virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute ); + virtual bool VisitExit( const XMLElement& element ); + + virtual bool Visit( const XMLText& text ); + virtual bool Visit( const XMLComment& comment ); + virtual bool Visit( const XMLDeclaration& declaration ); + virtual bool Visit( const XMLUnknown& unknown ); + + /** + If in print to memory mode, return a pointer to + the XML file in memory. + */ + const char* CStr() const { + return _buffer.Mem(); + } + /** + If in print to memory mode, return the size + of the XML file in memory. (Note the size returned + includes the terminating null.) + */ + int CStrSize() const { + return _buffer.Size(); + } + /** + If in print to memory mode, reset the buffer to the + beginning. + */ + void ClearBuffer( bool resetToFirstElement = true ) { + _buffer.Clear(); + _buffer.Push(0); + _firstElement = resetToFirstElement; + } + +protected: + virtual bool CompactMode( const XMLElement& ) { return _compactMode; } + + /** Prints out the space before an element. You may override to change + the space and tabs used. A PrintSpace() override should call Print(). + */ + virtual void PrintSpace( int depth ); + virtual void Print( const char* format, ... ); + virtual void Write( const char* data, size_t size ); + virtual void Putc( char ch ); + + inline void Write(const char* data) { Write(data, strlen(data)); } + + void SealElementIfJustOpened(); + bool _elementJustOpened; + DynArray< const char*, 10 > _stack; + +private: + /** + Prepares to write a new node. This includes sealing an element that was + just opened, and writing any whitespace necessary if not in compact mode. + */ + void PrepareForNewNode( bool compactMode ); + void PrintString( const char*, bool restrictedEntitySet ); // prints out, after detecting entities. + + bool _firstElement; + FILE* _fp; + int _depth; + int _textDepth; + bool _processEntities; + bool _compactMode; + + enum { + ENTITY_RANGE = 64, + BUF_SIZE = 200 + }; + bool _entityFlag[ENTITY_RANGE]; + bool _restrictedEntityFlag[ENTITY_RANGE]; + + DynArray< char, 20 > _buffer; + + // Prohibit cloning, intentionally not implemented + XMLPrinter( const XMLPrinter& ); + XMLPrinter& operator=( const XMLPrinter& ); +}; + + +} // tinyxml2 + +#if defined(_MSC_VER) +# pragma warning(pop) +#endif + +#endif // TINYXML2_INCLUDED diff --git a/general/version.cpp b/general/version.cpp index 4156c4ee52..bf238be048 100644 --- a/general/version.cpp +++ b/general/version.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/version.hpp b/general/version.hpp index 85905e4531..12f117e2f9 100644 --- a/general/version.hpp +++ b/general/version.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/general/zstr.hpp b/general/zstr.hpp index 47fd98f9fd..e9d74668f0 100644 --- a/general/zstr.hpp +++ b/general/zstr.hpp @@ -71,7 +71,7 @@ static std::string strerror() } #elif (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE || \ defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \ - defined(__NetBSD__) || defined(__DragonFly__) + defined(__NetBSD__) || defined(__DragonFly__) || defined(__EMSCRIPTEN__) // XSI-compliant strerror_r() if (strerror_r(errno, &buff[0], buff.size()) != 0) { diff --git a/linalg/CMakeLists.txt b/linalg/CMakeLists.txt index 0a2994b527..268bf7c740 100644 --- a/linalg/CMakeLists.txt +++ b/linalg/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # @@ -15,6 +15,7 @@ list(APPEND SRCS blockvector.cpp complex_operator.cpp densemat.cpp + symmat.cpp handle.cpp matrix.cpp ode.cpp @@ -31,6 +32,7 @@ list(APPEND HDRS blockvector.hpp complex_operator.hpp densemat.hpp + symmat.hpp dtensor.hpp handle.hpp invariants.hpp diff --git a/linalg/amgxsolver.cpp b/linalg/amgxsolver.cpp index 3596c0ab6b..59a581909b 100644 --- a/linalg/amgxsolver.cpp +++ b/linalg/amgxsolver.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -30,10 +30,16 @@ int AmgXSolver::count = 0; AMGX_resources_handle AmgXSolver::rsrc = nullptr; +AmgXSolver::AmgXSolver() + : ConvergenceCheck(false) {}; + AmgXSolver::AmgXSolver(const AMGX_MODE amgxMode_, const bool verbose) { amgxMode = amgxMode_; + if (amgxMode == AmgXSolver::SOLVER) { ConvergenceCheck = true;} + else { ConvergenceCheck = false;} + DefaultParameters(amgxMode, verbose); InitSerial(); @@ -47,6 +53,9 @@ AmgXSolver::AmgXSolver(const MPI_Comm &comm, std::string config; amgxMode = amgxMode_; + if (amgxMode == AmgXSolver::SOLVER) { ConvergenceCheck = true;} + else { ConvergenceCheck = false;} + DefaultParameters(amgxMode, verbose); InitExclusiveGPU(comm); @@ -58,6 +67,9 @@ AmgXSolver::AmgXSolver(const MPI_Comm &comm, const int nDevs, std::string config; amgxMode = amgxMode_; + if (amgxMode == AmgXSolver::SOLVER) { ConvergenceCheck = true;} + else { ConvergenceCheck = false;} + DefaultParameters(amgxMode_, verbose); InitMPITeams(comm, nDevs); @@ -178,6 +190,11 @@ void AmgXSolver::ReadParameters(const std::string config, configSrc = source; } +void AmgXSolver::SetConvergenceCheck(bool setConvergenceCheck_) +{ + ConvergenceCheck = setConvergenceCheck_; +} + void AmgXSolver::DefaultParameters(const AMGX_MODE amgxMode_, const bool verbose) { @@ -201,8 +218,8 @@ void AmgXSolver::DefaultParameters(const AMGX_MODE amgxMode_, { amgx_config = amgx_config + ",\n" " \"obtain_timings\": 1, \n" - " \"monitor_residual\": 1, \n" " \"print_grid_stats\": 1, \n" + " \"monitor_residual\": 1, \n" " \"print_solve_stats\": 1 \n"; } else @@ -238,12 +255,12 @@ void AmgXSolver::DefaultParameters(const AMGX_MODE amgxMode_, " \"convergence\": \"RELATIVE_MAX\", \n" " \"scope\": \"main\", \n" " \"tolerance\": 1e-12, \n" + " \"monitor_residual\": 1, \n" " \"norm\": \"L2\" "; if (verbose) { amgx_config = amgx_config + ", \n" " \"obtain_timings\": 1, \n" - " \"monitor_residual\": 1, \n" " \"print_grid_stats\": 1, \n" " \"print_solve_stats\": 1 \n"; } @@ -884,7 +901,7 @@ void AmgXSolver::Mult(const Vector& B, Vector& X) const AMGX_SOLVE_STATUS status; AMGX_solver_get_status(solver, &status); - if (status != AMGX_SOLVE_SUCCESS && amgxMode == SOLVER) + if (status != AMGX_SOLVE_SUCCESS && ConvergenceCheck) { if (status == AMGX_SOLVE_DIVERGED) { diff --git a/linalg/amgxsolver.hpp b/linalg/amgxsolver.hpp index 1cbefc7cf7..2e17367342 100644 --- a/linalg/amgxsolver.hpp +++ b/linalg/amgxsolver.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -73,13 +73,16 @@ public: /// Flags to configure AmgXSolver as a solver or preconditioner enum AMGX_MODE {SOLVER, PRECONDITIONER}; + /// Flag to check for convergence + bool ConvergenceCheck; + /** Flags to determine whether user solver settings are defined internally in the source code or will be read through an external JSON file. */ enum CONFIG_SRC {INTERNAL, EXTERNAL, UNDEFINED}; - AmgXSolver() = default; + AmgXSolver(); /** Configures AmgX with a default configuration based on the AmgX mode, and @@ -162,6 +165,9 @@ public: */ void DefaultParameters(const AMGX_MODE amgxMode_, const bool verbose); + /// Add a check for convergence after applying Mult. + void SetConvergenceCheck(bool setConvergenceCheck_=true); + ~AmgXSolver(); void Finalize(); diff --git a/linalg/blockmatrix.cpp b/linalg/blockmatrix.cpp index 7da006530b..25f8482c32 100644 --- a/linalg/blockmatrix.cpp +++ b/linalg/blockmatrix.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/blockmatrix.hpp b/linalg/blockmatrix.hpp index 15efe7c689..9f0fb41e61 100644 --- a/linalg/blockmatrix.hpp +++ b/linalg/blockmatrix.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/blockoperator.cpp b/linalg/blockoperator.cpp index 4829d1f8a5..e072791014 100644 --- a/linalg/blockoperator.cpp +++ b/linalg/blockoperator.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/blockoperator.hpp b/linalg/blockoperator.hpp index d65827cfca..d16fe6861f 100644 --- a/linalg/blockoperator.hpp +++ b/linalg/blockoperator.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/blockvector.cpp b/linalg/blockvector.cpp index 01b9fa3c39..bad5097ec3 100644 --- a/linalg/blockvector.cpp +++ b/linalg/blockvector.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -101,6 +101,7 @@ void BlockVector::Update(Vector & data, const Array & bOffsets) { blocks[i].MakeRef(data, blockOffsets[i], BlockSize(i)); } + MakeRef(data, 0, blockOffsets[numBlocks]); } void BlockVector::Update(const Array &bOffsets) diff --git a/linalg/blockvector.hpp b/linalg/blockvector.hpp index 8d89fb76b7..9bcbe54473 100644 --- a/linalg/blockvector.hpp +++ b/linalg/blockvector.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/complex_operator.cpp b/linalg/complex_operator.cpp index 9475c0b7e3..c17c2575a4 100644 --- a/linalg/complex_operator.cpp +++ b/linalg/complex_operator.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -287,10 +287,7 @@ void ComplexUMFPackSolver::Init() void ComplexUMFPackSolver::SetOperator(const Operator &op) { - int *Ap, *Ai; void *Symbolic; - double *Ax; - double *Az; if (Numeric) { @@ -322,10 +319,11 @@ void ComplexUMFPackSolver::SetOperator(const Operator &op) width = mat->real().Width(); MFEM_VERIFY(width == height, "not a square matrix"); - Ap = mat->real().GetI(); // assuming real and imag have the same sparsity - Ai = mat->real().GetJ(); - Ax = mat->real().GetData(); - Az = mat->imag().GetData(); + const int * Ap = + mat->real().HostReadI(); // assuming real and imag have the same sparsity + const int * Ai = mat->real().HostReadJ(); + const double * Ax = mat->real().HostReadData(); + const double * Az = mat->imag().HostReadData(); if (!use_long_ints) { @@ -395,6 +393,10 @@ void ComplexUMFPackSolver::Mult(const Vector &b, Vector &x) const if (mat == NULL) mfem_error("ComplexUMFPackSolver::Mult : matrix is not set!" " Call SetOperator first!"); + + b.HostRead(); + x.HostReadWrite(); + int n = b.Size()/2; double * datax = x.GetData(); double * datab = b.GetData(); @@ -413,8 +415,8 @@ void ComplexUMFPackSolver::Mult(const Vector &b, Vector &x) const if (!use_long_ints) { int status = - umfpack_zi_solve(UMFPACK_Aat, mat->real().GetI(), mat->real().GetJ(), - mat->real().GetData(), mat->imag().GetData(), + umfpack_zi_solve(UMFPACK_Aat, mat->real().HostReadI(), mat->real().HostReadJ(), + mat->real().HostReadData(), mat->imag().HostReadData(), datax, &datax[n], datab, &datab[n], Numeric, Control, Info); umfpack_zi_report_info(Control, Info); if (status < 0) @@ -426,8 +428,8 @@ void ComplexUMFPackSolver::Mult(const Vector &b, Vector &x) const else { SuiteSparse_long status = - umfpack_zl_solve(UMFPACK_Aat,AI,AJ,mat->real().GetData(), - mat->imag().GetData(), + umfpack_zl_solve(UMFPACK_Aat,AI,AJ,mat->real().HostReadData(), + mat->imag().HostReadData(), datax,&datax[n],datab,&datab[n],Numeric,Control,Info); umfpack_zl_report_info(Control, Info); @@ -448,6 +450,8 @@ void ComplexUMFPackSolver::MultTranspose(const Vector &b, Vector &x) const if (mat == NULL) mfem_error("ComplexUMFPackSolver::Mult : matrix is not set!" " Call SetOperator first!"); + b.HostRead(); + x.HostReadWrite(); int n = b.Size()/2; double * datax = x.GetData(); double * datab = b.GetData(); @@ -467,8 +471,8 @@ void ComplexUMFPackSolver::MultTranspose(const Vector &b, Vector &x) const if (!use_long_ints) { int status = - umfpack_zi_solve(UMFPACK_A, mat->real().GetI(), mat->real().GetJ(), - mat->real().GetData(), mat->imag().GetData(), + umfpack_zi_solve(UMFPACK_A, mat->real().HostReadI(), mat->real().HostReadJ(), + mat->real().HostReadData(), mat->imag().HostReadData(), datax, &datax[n], datab, &datab[n], Numeric, Control, Info); umfpack_zi_report_info(Control, Info); if (status < 0) @@ -480,8 +484,8 @@ void ComplexUMFPackSolver::MultTranspose(const Vector &b, Vector &x) const else { SuiteSparse_long status = - umfpack_zl_solve(UMFPACK_A,AI,AJ,mat->real().GetData(), - mat->imag().GetData(), + umfpack_zl_solve(UMFPACK_A,AI,AJ,mat->real().HostReadData(), + mat->imag().HostReadData(), datax,&datax[n],datab,&datab[n],Numeric,Control,Info); umfpack_zl_report_info(Control, Info); diff --git a/linalg/complex_operator.hpp b/linalg/complex_operator.hpp index 2c1ae3acba..faf53febd0 100644 --- a/linalg/complex_operator.hpp +++ b/linalg/complex_operator.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/cpardiso.hpp b/linalg/cpardiso.hpp index ac3fbc03e5..be01e2bddb 100644 --- a/linalg/cpardiso.hpp +++ b/linalg/cpardiso.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/densemat.cpp b/linalg/densemat.cpp index 5e532ce6c8..e5785178a7 100644 --- a/linalg/densemat.cpp +++ b/linalg/densemat.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/densemat.hpp b/linalg/densemat.hpp index 4bd65ca8c4..42c551a5f1 100644 --- a/linalg/densemat.hpp +++ b/linalg/densemat.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/dtensor.hpp b/linalg/dtensor.hpp index 2ab5509a10..db90fb6e58 100644 --- a/linalg/dtensor.hpp +++ b/linalg/dtensor.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/ginkgo.cpp b/linalg/ginkgo.cpp index 2f858faf66..16c00a90f2 100644 --- a/linalg/ginkgo.cpp +++ b/linalg/ginkgo.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/ginkgo.hpp b/linalg/ginkgo.hpp index 819cc52ea5..c474564262 100644 --- a/linalg/ginkgo.hpp +++ b/linalg/ginkgo.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/handle.cpp b/linalg/handle.cpp index 686ff314ba..e4091678de 100644 --- a/linalg/handle.cpp +++ b/linalg/handle.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/handle.hpp b/linalg/handle.hpp index 03a9a134fa..376d2956ed 100644 --- a/linalg/handle.hpp +++ b/linalg/handle.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/hiop.cpp b/linalg/hiop.cpp index c8b42b06c3..06b021622f 100644 --- a/linalg/hiop.cpp +++ b/linalg/hiop.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/hiop.hpp b/linalg/hiop.hpp index cfc3c6b602..3806804a96 100644 --- a/linalg/hiop.hpp +++ b/linalg/hiop.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/hypre.cpp b/linalg/hypre.cpp index 27ca05ae9a..e0d18fcc43 100644 --- a/linalg/hypre.cpp +++ b/linalg/hypre.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -128,6 +128,15 @@ HypreParVector::HypreParVector(ParFiniteElementSpace *pfes) own_ParVector = 1; } +void HypreParVector::WrapHypreParVector(hypre_ParVector *y, bool owner) +{ + if (own_ParVector) { hypre_ParVectorDestroy(x); } + Destroy(); + x = y; + _SetDataAndSize_(); + own_ParVector = owner; +} + Vector * HypreParVector::GlobalVector() const { hypre_Vector *hv = hypre_ParVectorToVectorAll(*this); @@ -926,6 +935,15 @@ void HypreParMatrix::GetOffd(SparseMatrix &offd, HYPRE_Int* &cmap) const cmap = A->col_map_offd; } +void HypreParMatrix::MergeDiagAndOffd(SparseMatrix &merged) +{ + SparseMatrix tmp_wrapper; + hypre_CSRMatrix *hypre_merged = hypre_MergeDiagAndOffd(A); + MakeWrapper(hypre_merged, tmp_wrapper); + merged = tmp_wrapper; + hypre_CSRMatrixDestroy(hypre_merged); +} + void HypreParMatrix::GetBlocks(Array2D &blocks, bool interleaved_rows, bool interleaved_cols) const @@ -966,6 +984,46 @@ HypreParMatrix * HypreParMatrix::Transpose() const return new HypreParMatrix(At); } +#if MFEM_HYPRE_VERSION >= 21800 +HypreParMatrix *HypreParMatrix::ExtractSubmatrix(const Array &indices, + double threshhold) const +{ + if (!(A->comm)) + { + hypre_MatvecCommPkgCreate(A); + } + + hypre_ParCSRMatrix *submat; + + // Get number of rows stored on this processor + int local_num_vars = hypre_CSRMatrixNumRows(hypre_ParCSRMatrixDiag(A)); + + // Form hypre CF-splitting array designating submatrix as F-points (-1) + Array CF_marker(local_num_vars); + CF_marker = 1; + for (int j=0; j local_num_vars) + { + MFEM_WARNING("WARNING : " << indices[j] << " > " << local_num_vars); + } + CF_marker[indices[j]] = -1; + } + + // Construct cpts_global array on hypre matrix structure + HYPRE_BigInt *cpts_global; + hypre_BoomerAMGCoarseParms(MPI_COMM_WORLD, local_num_vars, 1, NULL, + CF_marker, NULL, &cpts_global); + + // Extract submatrix into *submat + hypre_ParCSRMatrixExtractSubmatrixFC(A, CF_marker, cpts_global, + "FF", &submat, threshhold); + + mfem_hypre_TFree(cpts_global); + return new HypreParMatrix(submat); +} +#endif + HYPRE_Int HypreParMatrix::Mult(HypreParVector &x, HypreParVector &y, double a, double b) { @@ -1279,6 +1337,7 @@ void HypreParMatrix::operator*=(double s) static void get_sorted_rows_cols(const Array &rows_cols, Array &hypre_sorted) { + rows_cols.HostRead(); hypre_sorted.SetSize(rows_cols.Size()); bool sorted = true; for (int i = 0; i < rows_cols.Size(); i++) @@ -1365,6 +1424,49 @@ void HypreParMatrix::Threshold(double threshold) width = GetNumCols(); } +void HypreParMatrix::DropSmallEntries(double tol) +{ + HYPRE_Int err = 0; + +#if MFEM_HYPRE_VERSION < 21400 + + double threshold = 0.0; + if (tol > 0.0) + { + HYPRE_Int *diag_I = A->diag->i, *offd_I = A->offd->i; + double *diag_d = A->diag->data, *offd_d = A->offd->data; + HYPRE_Int local_num_rows = A->diag->num_rows; + double max_l2_row_norm = 0.0; + Vector row; + for (HYPRE_Int r = 0; r < local_num_rows; r++) + { + row.SetDataAndSize(diag_d + diag_I[r], diag_I[r+1]-diag_I[r]); + double l2_row_norm = row.Norml2(); + row.SetDataAndSize(offd_d + offd_I[r], offd_I[r+1]-offd_I[r]); + l2_row_norm = std::hypot(l2_row_norm, row.Norml2()); + max_l2_row_norm = std::max(max_l2_row_norm, l2_row_norm); + } + double loc_max_l2_row_norm = max_l2_row_norm; + MPI_Allreduce(&loc_max_l2_row_norm, &max_l2_row_norm, 1, MPI_DOUBLE, + MPI_MAX, A->comm); + threshold = tol * max_l2_row_norm; + } + + Threshold(threshold); + +#elif MFEM_HYPRE_VERSION < 21800 + + err = hypre_ParCSRMatrixDropSmallEntries(A, tol); + +#else + + err = hypre_ParCSRMatrixDropSmallEntries(A, tol, 2); + +#endif + + MFEM_VERIFY(!err, "error encountered: error code = " << err); +} + void HypreParMatrix::EliminateRowsCols(const Array &rows_cols, const HypreParVector &X, HypreParVector &B) @@ -1568,6 +1670,36 @@ void HypreParMatrix::Destroy() } } +#if MFEM_HYPRE_VERSION >= 21800 + +void BlockInverseScale(const HypreParMatrix *A, HypreParMatrix *C, + const Vector *b, HypreParVector *d, + int blocksize, BlockInverseScaleJob job) +{ + if (job == BlockInverseScaleJob::MATRIX_ONLY || + job == BlockInverseScaleJob::MATRIX_AND_RHS) + { + hypre_ParCSRMatrix *C_hypre; + hypre_ParcsrBdiagInvScal(*A, blocksize, &C_hypre); + hypre_ParCSRMatrixDropSmallEntries(C_hypre, 1e-15, 1); + C->WrapHypreParCSRMatrix(C_hypre); + } + + if (job == BlockInverseScaleJob::RHS_ONLY || + job == BlockInverseScaleJob::MATRIX_AND_RHS) + { + HypreParVector b_Hypre(A->GetComm(), + A->GetGlobalNumRows(), + b->GetData(), A->GetRowStarts()); + hypre_ParVector *d_hypre; + hypre_ParvecBdiagInvScal(b_Hypre, blocksize, &d_hypre, *A); + + d->WrapHypreParVector(d_hypre, true); + } +} + +#endif + #if MFEM_HYPRE_VERSION < 21400 HypreParMatrix *Add(double alpha, const HypreParMatrix &A, @@ -1995,6 +2127,8 @@ void EliminateBC(HypreParMatrix &A, HypreParMatrix &Ae, double *data_offd = hypre_CSRMatrixData(A_offd); #endif + ess_dof_list.HostRead(); + for (int i = 0; i < ess_dof_list.Size(); i++) { int r = ess_dof_list[i]; @@ -2161,6 +2295,7 @@ HypreSmoother::HypreSmoother() : Solver() B = X = V = Z = NULL; X0 = X1 = NULL; fir_coeffs = NULL; + A_is_symmetric = false; } HypreSmoother::HypreSmoother(HypreParMatrix &_A, int _type, @@ -2180,6 +2315,7 @@ HypreSmoother::HypreSmoother(HypreParMatrix &_A, int _type, B = X = V = Z = NULL; X0 = X1 = NULL; fir_coeffs = NULL; + A_is_symmetric = false; SetOperator(_A); } @@ -2467,6 +2603,16 @@ void HypreSmoother::Mult(const Vector &b, Vector &x) const Mult(*B, *X); } +void HypreSmoother::MultTranspose(const Vector &b, Vector &x) const +{ + if (A_is_symmetric || type == 0 || type == 1 || type == 5) + { + Mult(b, x); + return; + } + mfem_error("HypreSmoother::MultTranspose (...) : undefined!\n"); +} + HypreSmoother::~HypreSmoother() { if (B) { delete B; } @@ -2517,10 +2663,10 @@ void HypreSolver::Mult(const HypreParVector &b, HypreParVector &x) const x = 0.0; } + b.HostRead(); + x.HostReadWrite(); if (!setup_called) { - b.HostRead(); - x.HostReadWrite(); err = SetupFcn()(*this, *A, b, x); if (error_mode == WARN_HYPRE_ERRORS) { @@ -2534,8 +2680,6 @@ void HypreSolver::Mult(const HypreParVector &b, HypreParVector &x) const setup_called = 1; } - b.HostRead(); - x.HostReadWrite(); err = SolveFcn()(*this, *A, b, x); if (error_mode == WARN_HYPRE_ERRORS) { @@ -2804,6 +2948,11 @@ void HypreGMRES::SetTol(double tol) HYPRE_GMRESSetTol(gmres_solver, tol); } +void HypreGMRES::SetAbsTol(double tol) +{ + HYPRE_GMRESSetAbsoluteTol(gmres_solver, tol); +} + void HypreGMRES::SetMaxIter(int max_iter) { HYPRE_GMRESSetMaxIter(gmres_solver, max_iter); @@ -3607,6 +3756,116 @@ void HypreBoomerAMG::SetElasticityOptions(ParFiniteElementSpace *fespace) error_mode = IGNORE_HYPRE_ERRORS; } +#if MFEM_HYPRE_VERSION >= 21800 + +void HypreBoomerAMG::SetAdvectiveOptions(int distanceR, + const std::string &prerelax, + const std::string &postrelax) +{ + // Hypre parameters + int Sabs = 0; + int interp_type = 100; + int relax_type = 10; + int coarsen_type = 6; + double strength_tolC = 0.1; + double strength_tolR = 0.01; + double filter_tolR = 0.0; + double filterA_tol = 0.0; + + // Set relaxation on specified grid points + int ns_down, ns_up, ns_coarse; + if (distanceR > 0) + { + ns_down = prerelax.length(); + ns_up = postrelax.length(); + ns_coarse = 1; + + // Array to store relaxation scheme and pass to Hypre + HYPRE_Int **grid_relax_points = mfem_hypre_TAlloc(HYPRE_Int*, 4); + grid_relax_points[0] = NULL; + grid_relax_points[1] = mfem_hypre_TAlloc(HYPRE_Int, ns_down); + grid_relax_points[2] = mfem_hypre_TAlloc(HYPRE_Int, ns_up); + grid_relax_points[3] = mfem_hypre_TAlloc(HYPRE_Int, 1); + grid_relax_points[3][0] = 0; + + // set down relax scheme + for (int i = 0; i 0) + { + HYPRE_BoomerAMGSetStrongThresholdR(amg_precond, strength_tolR); + HYPRE_BoomerAMGSetFilterThresholdR(amg_precond, filter_tolR); + } + + if (relax_type > -1) + { + HYPRE_BoomerAMGSetRelaxType(amg_precond, relax_type); + } + + if (distanceR > 0) + { + HYPRE_BoomerAMGSetCycleNumSweeps(amg_precond, ns_coarse, 3); + HYPRE_BoomerAMGSetCycleNumSweeps(amg_precond, ns_down, 1); + HYPRE_BoomerAMGSetCycleNumSweeps(amg_precond, ns_up, 2); + + HYPRE_BoomerAMGSetADropTol(amg_precond, filterA_tol); + // type = -1: drop based on row inf-norm + HYPRE_BoomerAMGSetADropType(amg_precond, -1); + } +} + +#endif + HypreBoomerAMG::~HypreBoomerAMG() { for (int i = 0; i < rbms.Size(); i++) @@ -3695,7 +3954,7 @@ void HypreAMS::Init(ParFiniteElementSpace *edge_fespace) vert_fec); // generate and set the vertex coordinates - if (p == 1) + if (p == 1 && pmesh->GetNodes() == NULL) { ParGridFunction x_coord(vert_fespace); ParGridFunction y_coord(vert_fespace); @@ -3751,7 +4010,7 @@ void HypreAMS::Init(ParFiniteElementSpace *edge_fespace) // generate and set the Nedelec interpolation matrices Pi = Pix = Piy = Piz = NULL; - if (p > 1) + if (p > 1 || pmesh->GetNodes() != NULL) { ParFiniteElementSpace *vert_fespace_d = new ParFiniteElementSpace(pmesh, vert_fec, sdim, Ordering::byVDIM); @@ -3921,7 +4180,7 @@ void HypreADS::Init(ParFiniteElementSpace *face_fespace) edge_fec); // generate and set the vertex coordinates - if (p == 1) + if (p == 1 && pmesh->GetNodes() == NULL) { ParGridFunction x_coord(vert_fespace); ParGridFunction y_coord(vert_fespace); @@ -3986,7 +4245,7 @@ void HypreADS::Init(ParFiniteElementSpace *face_fespace) // generate and set the Nedelec and Raviart-Thomas interpolation matrices RT_Pi = RT_Pix = RT_Piy = RT_Piz = NULL; ND_Pi = ND_Pix = ND_Piy = ND_Piz = NULL; - if (p > 1) + if (p > 1 || pmesh->GetNodes() != NULL) { ParFiniteElementSpace *vert_fespace_d = new ParFiniteElementSpace(pmesh, vert_fec, 3, Ordering::byVDIM); diff --git a/linalg/hypre.hpp b/linalg/hypre.hpp index f14cababca..4f4358bc48 100644 --- a/linalg/hypre.hpp +++ b/linalg/hypre.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -81,6 +81,14 @@ private: inline void _SetDataAndSize_(); public: + + /// Default constructor, no underlying @a hypre_ParVector is created. + HypreParVector() + { + own_ParVector = false; + x = NULL; + } + /** @brief Creates vector with given global size and parallel partitioning of the rows/columns given by @a col. */ /** @anchor hypre_partitioning_descr @@ -113,6 +121,9 @@ public: /// MPI communicator MPI_Comm GetComm() { return x->comm; } + /// Converts hypre's format to HypreParVector + void WrapHypreParVector(hypre_ParVector *y, bool owner=true); + /// Returns the parallel row/column partitioning /** See @ref hypre_partitioning_descr "here" for a description of the partitioning array. */ @@ -228,15 +239,24 @@ public: /// An empty matrix to be used as a reference to an existing matrix HypreParMatrix(); + /// Converts hypre's format to HypreParMatrix + /** If @a owner is false, ownership of @a a is not transferred */ + void WrapHypreParCSRMatrix(hypre_ParCSRMatrix *a, bool owner = true) + { + Destroy(); + Init(); + A = a; + ParCSROwner = owner; + height = GetNumRows(); + width = GetNumCols(); + } + /// Converts hypre's format to HypreParMatrix /** If @a owner is false, ownership of @a a is not transferred */ explicit HypreParMatrix(hypre_ParCSRMatrix *a, bool owner = true) { Init(); - A = a; - if (!owner) { ParCSROwner = 0; } - height = GetNumRows(); - width = GetNumCols(); + WrapHypreParCSRMatrix(a, owner); } /// Creates block-diagonal square parallel matrix. @@ -387,6 +407,13 @@ public: void GetDiag(SparseMatrix &diag) const; /// Get the local off-diagonal block. NOTE: 'offd' will not own any data. void GetOffd(SparseMatrix &offd, HYPRE_Int* &cmap) const; + /** @brief Get a single SparseMatrix containing all rows from this processor, + merged from the diagonal and off-diagonal blocks stored by the + HypreParMatrix. */ + /** @note The number of columns in the SparseMatrix will be the global number + of columns in the parallel matrix, so using this method may result in an + integer overflow in the column indices. */ + void MergeDiagAndOffd(SparseMatrix &merged); /** Split the matrix into M x N equally sized blocks of parallel matrices. The size of 'blocks' must already be set to M x N. */ @@ -397,6 +424,13 @@ public: /// Returns the transpose of *this HypreParMatrix * Transpose() const; + /** Returns principle submatrix given by array of indices of connections + with relative size > @a threshold in *this. */ +#if MFEM_HYPRE_VERSION >= 21800 + HypreParMatrix *ExtractSubmatrix(const Array &indices, + double threshhold=0.0) const; +#endif + /// Returns the number of rows in the diagonal block of the ParCSRMatrix int GetNumRows() const { @@ -512,6 +546,13 @@ public: /// Remove values smaller in absolute value than some threshold void Threshold(double threshold = 0.0); + /** @brief Wrapper for hypre_ParCSRMatrixDropSmallEntries in different + versions of hypre. Drop off-diagonal entries that are smaller than + tol * l2 norm of its row */ + /** For HYPRE versions < 2.14, this method just calls Threshold() with + threshold = tol * max(l2 row norm). */ + void DropSmallEntries(double tol); + /// If a row contains only zeros, set its diagonal to 1. void EliminateZeroRows() { hypre_ParCSRMatrixFixZeroRows(A); } @@ -549,6 +590,23 @@ public: Type GetType() const { return Hypre_ParCSR; } }; +#if MFEM_HYPRE_VERSION >= 21800 + +enum class BlockInverseScaleJob +{ + MATRIX_ONLY, + RHS_ONLY, + MATRIX_AND_RHS +}; + +/** Constructs and applies block diagonal inverse of HypreParMatrix. + The enum @a job specifies whether the matrix or the RHS should be + scaled (or both). */ +void BlockInverseScale(const HypreParMatrix *A, HypreParMatrix *C, + const Vector *b, HypreParVector *d, + int blocksize, BlockInverseScaleJob job); +#endif + /** @brief Return a new matrix `C = alpha*A + beta*B`, assuming that both `A` and `B` use the same row and column partitions and the same `col_map_offd` arrays. */ @@ -638,6 +696,9 @@ protected: /// Combined coefficients for windowing and Chebyshev polynomials. double* fir_coeffs; + /// A flag that indicates whether the linear system matrix A is symmetric + bool A_is_symmetric; + public: /** Hypre smoother types: 0 = Jacobi @@ -646,11 +707,12 @@ public: 4 = truncated l1-scaled block Gauss-Seidel/SSOR 5 = lumped Jacobi 6 = Gauss-Seidel + 10 = On-processor forward solve for matrix w/ triangular structure 16 = Chebyshev 1001 = Taubin polynomial smoother 1002 = FIR polynomial smoother. */ enum Type { Jacobi = 0, l1Jacobi = 1, l1GS = 2, l1GStr = 4, lumpedJacobi = 5, - GS = 6, Chebyshev = 16, Taubin = 1001, FIR = 1002 + GS = 6, OPFS = 10, Chebyshev = 16, Taubin = 1001, FIR = 1002 }; HypreSmoother(); @@ -684,6 +746,12 @@ public: entries in the associated matrix. */ void SetPositiveDiagonal(bool pos = true) { pos_l1_norms = pos; } + /** Explicitly indicate whether the linear system matrix A is symmetric. If A + is symmetric, the smoother will also be symmetric. In this case, calling + MultTranspose will be redirected to Mult. (This is also done if the + smoother is diagonal.) By default, A is assumed to be nonsymmetric. */ + void SetOperatorSymmetry(bool is_sym) { A_is_symmetric = is_sym; } + /** Set/update the associated operator. Must be called after setting the HypreSmoother type and options. */ virtual void SetOperator(const Operator &op); @@ -692,6 +760,9 @@ public: virtual void Mult(const HypreParVector &b, HypreParVector &x) const; virtual void Mult(const Vector &b, Vector &x) const; + /// Apply transpose of the smoother to relax the linear system Ax=b + virtual void MultTranspose(const Vector &b, Vector &x) const; + virtual ~HypreSmoother(); }; @@ -755,6 +826,28 @@ public: virtual ~HypreSolver(); }; + +#if MFEM_HYPRE_VERSION >= 21800 +/** Preconditioner for HypreParMatrices that are triangular in some ordering. + Finds correct ordering and performs forward substitution on processor + as approximate inverse. Exact on one processor. */ +class HypreTriSolve : public HypreSolver +{ +public: + HypreTriSolve() : HypreSolver() { } + explicit HypreTriSolve(HypreParMatrix &A) : HypreSolver(&A) { } + virtual operator HYPRE_Solver() const { return NULL; } + + virtual HYPRE_PtrToParSolverFcn SetupFcn() const + { return (HYPRE_PtrToParSolverFcn) HYPRE_ParCSROnProcTriSetup; } + virtual HYPRE_PtrToParSolverFcn SolveFcn() const + { return (HYPRE_PtrToParSolverFcn) HYPRE_ParCSROnProcTriSolve; } + + HypreParMatrix* GetData() { return A; } + virtual ~HypreTriSolve() { } +}; +#endif + /// PCG solver in hypre class HyprePCG : public HypreSolver { @@ -832,6 +925,7 @@ public: virtual void SetOperator(const Operator &op); void SetTol(double tol); + void SetAbsTol(double tol); void SetMaxIter(int max_iter); void SetKDim(int dim); void SetLogging(int logging); @@ -1116,9 +1210,98 @@ public: construct A. */ void SetElasticityOptions(ParFiniteElementSpace *fespace); +#if MFEM_HYPRE_VERSION >= 21800 + /** Hypre parameters to use AIR AMG solve for advection-dominated problems. + See "Nonsymmetric Algebraic Multigrid Based on Local Approximate Ideal + Restriction (AIR)," Manteuffel, Ruge, Southworth, SISC (2018), + DOI:/10.1137/17M1144350. Options: "distanceR" -> distance of neighbor + DOFs to buld restriction operator; options include 1, 2, and 15 (1.5). + Strings "prerelax" and "postrelax" indicate points to relax on: + F = F-points, C = C-points, A = all points. E.g., FFC -> relax on + F-points, relax again on F-points, then relax on C-points. */ + void SetAdvectiveOptions(int distance=15, const std::string &prerelax="", + const std::string &postrelax="FFC"); + + /// Expert option - consult hypre documentation/team + void SetStrongThresholdR(double strengthR) + { HYPRE_BoomerAMGSetStrongThresholdR(amg_precond, strengthR); } + + /// Expert option - consult hypre documentation/team + void SetFilterThresholdR(double filterR) + { HYPRE_BoomerAMGSetFilterThresholdR(amg_precond, filterR); } + + /// Expert option - consult hypre documentation/team + void SetRestriction(int restrict_type) + { HYPRE_BoomerAMGSetRestriction(amg_precond, restrict_type); } + + /// Expert option - consult hypre documentation/team + void SetIsTriangular() + { HYPRE_BoomerAMGSetIsTriangular(amg_precond, 1); } + + /// Expert option - consult hypre documentation/team + void SetGMRESSwitchR(int gmres_switch) + { HYPRE_BoomerAMGSetGMRESSwitchR(amg_precond, gmres_switch); } + + /// Expert option - consult hypre documentation/team + void SetCycleNumSweeps(int prerelax, int postrelax) + { + HYPRE_BoomerAMGSetCycleNumSweeps(amg_precond, prerelax, 1); + HYPRE_BoomerAMGSetCycleNumSweeps(amg_precond, postrelax, 2); + } +#endif + void SetPrintLevel(int print_level) { HYPRE_BoomerAMGSetPrintLevel(amg_precond, print_level); } + void SetMaxIter(int max_iter) + { HYPRE_BoomerAMGSetMaxIter(amg_precond, max_iter); } + + /// Expert option - consult hypre documentation/team + void SetMaxLevels(int max_levels) + { HYPRE_BoomerAMGSetMaxLevels(amg_precond, max_levels); } + + /// Expert option - consult hypre documentation/team + void SetTol(double tol) + { HYPRE_BoomerAMGSetTol(amg_precond, tol); } + + /// Expert option - consult hypre documentation/team + void SetStrengthThresh(double strength) + { HYPRE_BoomerAMGSetStrongThreshold(amg_precond, strength); } + + /// Expert option - consult hypre documentation/team + void SetInterpolation(int interp_type) + { HYPRE_BoomerAMGSetInterpType(amg_precond, interp_type); } + + /// Expert option - consult hypre documentation/team + void SetCoarsening(int coarsen_type) + { HYPRE_BoomerAMGSetCoarsenType(amg_precond, coarsen_type); } + + /// Expert option - consult hypre documentation/team + void SetRelaxType(int relax_type) + { HYPRE_BoomerAMGSetRelaxType(amg_precond, relax_type); } + + /// Expert option - consult hypre documentation/team + void SetCycleType(int cycle_type) + { HYPRE_BoomerAMGSetCycleType(amg_precond, cycle_type); } + + void GetNumIterations(int &num_iterations) + { + HYPRE_Int num_it; + HYPRE_BoomerAMGGetNumIterations(amg_precond, &num_it); + num_iterations = internal::to_int(num_it); + } + + /// Expert option - consult hypre documentation/team + void SetNodal(int blocksize) + { + HYPRE_BoomerAMGSetNumFunctions(amg_precond, blocksize); + HYPRE_BoomerAMGSetNodal(amg_precond, 1); + } + + /// Expert option - consult hypre documentation/team + void SetAggressiveCoarsening(int num_levels) + { HYPRE_BoomerAMGSetAggNumLevels(amg_precond, num_levels); } + /// The typecast to HYPRE_Solver returns the internal amg_precond virtual operator HYPRE_Solver() const { return amg_precond; } @@ -1127,6 +1310,8 @@ public: virtual HYPRE_PtrToParSolverFcn SolveFcn() const { return (HYPRE_PtrToParSolverFcn) HYPRE_BoomerAMGSolve; } + using HypreSolver::Mult; + virtual ~HypreBoomerAMG(); }; diff --git a/linalg/hypre_parcsr.cpp b/linalg/hypre_parcsr.cpp index efdc035340..e4cf7e3f54 100644 --- a/linalg/hypre_parcsr.cpp +++ b/linalg/hypre_parcsr.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/hypre_parcsr.hpp b/linalg/hypre_parcsr.hpp index 81567afc9f..2d10c21885 100644 --- a/linalg/hypre_parcsr.hpp +++ b/linalg/hypre_parcsr.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/invariants.hpp b/linalg/invariants.hpp index 4280ceda13..aa851dee78 100644 --- a/linalg/invariants.hpp +++ b/linalg/invariants.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -62,8 +62,6 @@ protected: const scalar_t *D; // Always points to external data or is empty scalar_t *DaJ, *DJt, *DXt, *DYt; - scalar_t sign_detJ; - enum EvalMasks { HAVE_I1 = 1, @@ -96,8 +94,7 @@ protected: { eval_state |= HAVE_I2b; const scalar_t det = J[0]*J[3] - J[1]*J[2]; - sign_detJ = scalar_ops::sign(det); - I2b = sign_detJ*det; + I2b = det; } void Eval_dI1() { @@ -136,10 +133,10 @@ protected: // I2b = det(J) // dI2b = adj(J)^T Get_I2b(); - dI2b[0] = sign_detJ*J[3]; - dI2b[1] = -sign_detJ*J[2]; - dI2b[2] = -sign_detJ*J[1]; - dI2b[3] = sign_detJ*J[0]; + dI2b[0] = J[3]; + dI2b[1] = -J[2]; + dI2b[2] = -J[1]; + dI2b[3] = J[0]; } void Eval_DaJ() // D adj(J) = D dI2b^t { @@ -516,8 +513,6 @@ protected: const scalar_t *D; // Always points to external data or is empty scalar_t *DaJ, *DJt, *DdI2t, *DXt, *DYt; - scalar_t sign_detJ; - enum EvalMasks { HAVE_I1 = 1, @@ -585,8 +580,6 @@ protected: eval_state |= HAVE_I3b; I3b = J[0]*(J[4]*J[8] - J[7]*J[5]) - J[1]*(J[3]*J[8] - J[5]*J[6]) + J[2]*(J[3]*J[7] - J[4]*J[6]); - sign_detJ = scalar_ops::sign(I3b); - I3b = sign_detJ*I3b; } scalar_t Get_I3b_p() // I3b^{-2/3} { @@ -594,7 +587,7 @@ protected: { eval_state |= HAVE_I3b_p; const scalar_t i3b = Get_I3b(); - I3b_p = sign_detJ*scalar_ops::pow(i3b, -2, 3); + I3b_p = scalar_ops::pow(i3b, -2, 3); } return I3b_p; } @@ -680,15 +673,15 @@ protected: eval_state |= HAVE_dI3b; // I3b = det(J) // dI3b = adj(J)^T - dI3b[0] = sign_detJ*(J[4]*J[8] - J[5]*J[7]); // 0 3 6 - dI3b[1] = sign_detJ*(J[5]*J[6] - J[3]*J[8]); // 1 4 7 - dI3b[2] = sign_detJ*(J[3]*J[7] - J[4]*J[6]); // 2 5 8 - dI3b[3] = sign_detJ*(J[2]*J[7] - J[1]*J[8]); - dI3b[4] = sign_detJ*(J[0]*J[8] - J[2]*J[6]); - dI3b[5] = sign_detJ*(J[1]*J[6] - J[0]*J[7]); - dI3b[6] = sign_detJ*(J[1]*J[5] - J[2]*J[4]); - dI3b[7] = sign_detJ*(J[2]*J[3] - J[0]*J[5]); - dI3b[8] = sign_detJ*(J[0]*J[4] - J[1]*J[3]); + dI3b[0] = J[4]*J[8] - J[5]*J[7]; // 0 3 6 + dI3b[1] = J[5]*J[6] - J[3]*J[8]; // 1 4 7 + dI3b[2] = J[3]*J[7] - J[4]*J[6]; // 2 5 8 + dI3b[3] = J[2]*J[7] - J[1]*J[8]; + dI3b[4] = J[0]*J[8] - J[2]*J[6]; + dI3b[5] = J[1]*J[6] - J[0]*J[7]; + dI3b[6] = J[1]*J[5] - J[2]*J[4]; + dI3b[7] = J[2]*J[3] - J[0]*J[5]; + dI3b[8] = J[0]*J[4] - J[1]*J[3]; } void Eval_DZt(const scalar_t *Z, scalar_t **DZt_ptr) { diff --git a/linalg/kernels.hpp b/linalg/kernels.hpp index 02c629f981..59aa7b44eb 100644 --- a/linalg/kernels.hpp +++ b/linalg/kernels.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/linalg.hpp b/linalg/linalg.hpp index e740328fcd..659c2ca1fd 100644 --- a/linalg/linalg.hpp +++ b/linalg/linalg.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -24,6 +24,7 @@ #include "blockoperator.hpp" #include "sparsesmoothers.hpp" #include "densemat.hpp" +#include "symmat.hpp" #include "ode.hpp" #include "solvers.hpp" #include "handle.hpp" diff --git a/linalg/matrix.cpp b/linalg/matrix.cpp index 46cde93da0..fdb64d2939 100644 --- a/linalg/matrix.cpp +++ b/linalg/matrix.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/matrix.hpp b/linalg/matrix.hpp index 1134d47285..5eea273822 100644 --- a/linalg/matrix.hpp +++ b/linalg/matrix.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/mumps.cpp b/linalg/mumps.cpp index 8c5ee6a42e..9cafcffd78 100644 --- a/linalg/mumps.cpp +++ b/linalg/mumps.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -196,6 +196,8 @@ void MUMPSSolver::SetOperator(const Operator &op) void MUMPSSolver::Mult(const Vector &x, Vector &y) const { + x.HostRead(); + y.HostReadWrite(); #if MFEM_MUMPS_VERSION >= 530 id->nloc_rhs = x.Size(); diff --git a/linalg/mumps.hpp b/linalg/mumps.hpp index d7911ee743..787d17894f 100644 --- a/linalg/mumps.hpp +++ b/linalg/mumps.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/ode.cpp b/linalg/ode.cpp index 10086c2da0..7849d31023 100644 --- a/linalg/ode.cpp +++ b/linalg/ode.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/ode.hpp b/linalg/ode.hpp index e36d06b931..36b320446a 100644 --- a/linalg/ode.hpp +++ b/linalg/ode.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/operator.cpp b/linalg/operator.cpp index 7c8e8321b9..f78b8c32c7 100644 --- a/linalg/operator.cpp +++ b/linalg/operator.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/operator.hpp b/linalg/operator.hpp index 978a39f46c..9bf3787b66 100644 --- a/linalg/operator.hpp +++ b/linalg/operator.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -37,7 +37,8 @@ protected: const Array &test_tdof_list, RectangularConstrainedOperator* &Aout); - /// Returns RAP Operator of this, taking in input/output Prolongation matrices + /** @brief Returns RAP Operator of this, using input/output Prolongation matrices + @a Pi corresponds to "P", @a Po corresponds to "Rt" */ Operator *SetupRAP(const Operator *Pi, const Operator *Po); public: @@ -112,6 +113,11 @@ public: { return GetProlongation(); // Assume square unless specialized } + /** @brief Transpose of GetOutputRestriction, directly available in this + form to facilitate matrix-free RAP-type operators. + + `NULL` means identity. */ + virtual const Operator *GetOutputRestrictionTranspose() const { return NULL; } /** @brief Restriction operator from output vectors for the operator to linear algebra (linear system) vectors. `NULL` means identity. */ virtual const Operator *GetOutputRestriction() const diff --git a/linalg/petsc.cpp b/linalg/petsc.cpp index fcfdd325fe..6ad9c99e47 100644 --- a/linalg/petsc.cpp +++ b/linalg/petsc.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/petsc.hpp b/linalg/petsc.hpp index 8346f0722b..35ccac8973 100644 --- a/linalg/petsc.hpp +++ b/linalg/petsc.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/petscinternals.hpp b/linalg/petscinternals.hpp index 974fc53b4e..3e1e3e0cb6 100644 --- a/linalg/petscinternals.hpp +++ b/linalg/petscinternals.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/simd.hpp b/linalg/simd.hpp index 26df56f0da..39e418521b 100644 --- a/linalg/simd.hpp +++ b/linalg/simd.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/simd/auto.hpp b/linalg/simd/auto.hpp index 7e8f3a3e02..e52fde7583 100644 --- a/linalg/simd/auto.hpp +++ b/linalg/simd/auto.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/simd/m128.hpp b/linalg/simd/m128.hpp index eb3dbc0692..e8b1b370af 100644 --- a/linalg/simd/m128.hpp +++ b/linalg/simd/m128.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/simd/m256.hpp b/linalg/simd/m256.hpp index 6bc8c42ef0..4b24f561bf 100644 --- a/linalg/simd/m256.hpp +++ b/linalg/simd/m256.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/simd/m512.hpp b/linalg/simd/m512.hpp index dec27db24e..0eb3aa4472 100644 --- a/linalg/simd/m512.hpp +++ b/linalg/simd/m512.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/simd/qpx.hpp b/linalg/simd/qpx.hpp index b0c37f9d40..b194f30eb2 100644 --- a/linalg/simd/qpx.hpp +++ b/linalg/simd/qpx.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/simd/qpx256.hpp b/linalg/simd/qpx256.hpp index 7705fa7f83..f283785db8 100644 --- a/linalg/simd/qpx256.hpp +++ b/linalg/simd/qpx256.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/simd/vsx.hpp b/linalg/simd/vsx.hpp index 638da44dcf..00793af712 100644 --- a/linalg/simd/vsx.hpp +++ b/linalg/simd/vsx.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/simd/vsx128.hpp b/linalg/simd/vsx128.hpp index 175884edfc..cf52e2f515 100644 --- a/linalg/simd/vsx128.hpp +++ b/linalg/simd/vsx128.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/simd/x86.hpp b/linalg/simd/x86.hpp index c13e67db59..f185229d13 100644 --- a/linalg/simd/x86.hpp +++ b/linalg/simd/x86.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/slepc.cpp b/linalg/slepc.cpp index 0f3b3d899f..65a534c3a2 100644 --- a/linalg/slepc.cpp +++ b/linalg/slepc.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/slepc.hpp b/linalg/slepc.hpp index 7f8911ba21..6a192fd9de 100644 --- a/linalg/slepc.hpp +++ b/linalg/slepc.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/solvers.cpp b/linalg/solvers.cpp index cbefb74a12..29603d889a 100644 --- a/linalg/solvers.cpp +++ b/linalg/solvers.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -1556,6 +1556,7 @@ void NewtonSolver::SetOperator(const Operator &op) width = op.Width(); MFEM_ASSERT(height == width, "square Operator is required."); + xcur.SetSize(width); r.SetSize(width); c.SetSize(width); } @@ -1615,9 +1616,20 @@ void NewtonSolver::Mult(const Vector &b, Vector &x) const break; } - prec->SetOperator(oper->GetGradient(x)); + grad = &oper->GetGradient(x); + prec->SetOperator(*grad); - prec->Mult(r, c); // c = [DF(x_i)]^{-1} [F(x_i)-b] + if (lin_rtol_type) + { + AdaptiveLinRtolPreSolve(x, it, norm); + } + + prec->Mult(r, c); // c = [DF(x_i)]^{-1} [F(x_i)-b] + + if (lin_rtol_type) + { + AdaptiveLinRtolPostSolve(c, r, it, norm); + } const double c_scale = ComputeScalingFactor(x, b); if (c_scale == 0.0) @@ -1641,6 +1653,86 @@ void NewtonSolver::Mult(const Vector &b, Vector &x) const final_norm = norm; } +void NewtonSolver::SetAdaptiveLinRtol(const int type, + const double rtol0, + const double rtol_max, + const double alpha, + const double gamma) +{ + lin_rtol_type = type; + lin_rtol0 = rtol0; + lin_rtol_max = rtol_max; + this->alpha = alpha; + this->gamma = gamma; +} + +void NewtonSolver::AdaptiveLinRtolPreSolve(const Vector &x, + const int it, + const double fnorm) const +{ + // Assume that when adaptive linear solver relative tolerance is activated, + // we are working with an iterative solver. + auto iterative_solver = static_cast(prec); + // Adaptive linear solver relative tolerance + double eta; + // Safeguard threshold + double sg_threshold = 0.1; + + if (it == 0) + { + eta = lin_rtol0; + } + else + { + if (lin_rtol_type == 1) + { + // eta = gamma * abs(||F(x1)|| - ||F(x0) + DF(x0) s0||) / ||F(x0)|| + eta = gamma * abs(fnorm - lnorm_last) / fnorm_last; + } + else if (lin_rtol_type == 2) + { + // eta = gamma * (||F(x1)|| / ||F(x0)||)^alpha + eta = gamma * pow(fnorm / fnorm_last, alpha); + } + else + { + MFEM_ABORT("Unknown adaptive linear solver rtol version"); + } + + // Safeguard rtol from "oversolving" ?! + const double sg_eta = gamma * pow(eta_last, alpha); + if (sg_eta > sg_threshold) { eta = std::max(eta, sg_eta); } + } + + eta = std::min(eta, lin_rtol_max); + iterative_solver->SetRelTol(eta); + eta_last = eta; + if (print_level >= 0) + { + mfem::out << "Eisenstat-Walker rtol = " << eta << "\n"; + } +} + +void NewtonSolver::AdaptiveLinRtolPostSolve(const Vector &x, + const Vector &b, + const int it, + const double fnorm) const +{ + fnorm_last = fnorm; + + // If version 1 is chosen, the true linear residual norm has to be computed + // and in most cases we can only retrieve the preconditioned linear residual + // norm. + if (lin_rtol_type == 1) + { + // lnorm_last = ||F(x0) + DF(x0) s0|| + Vector linres(x.Size()); + grad->Mult(x, linres); + linres -= b; + lnorm_last = Norm(linres); + } +} + void LBFGSSolver::Mult(const Vector &b, Vector &x) const { MFEM_VERIFY(oper != NULL, "the Operator is not set (use SetOperator)."); @@ -2720,9 +2812,7 @@ void UMFPackSolver::Init() void UMFPackSolver::SetOperator(const Operator &op) { - int *Ap, *Ai; void *Symbolic; - double *Ax; if (Numeric) { @@ -2748,9 +2838,9 @@ void UMFPackSolver::SetOperator(const Operator &op) width = mat->Width(); MFEM_VERIFY(width == height, "not a square matrix"); - Ap = mat->GetI(); - Ai = mat->GetJ(); - Ax = mat->GetData(); + const int * Ap = mat->HostReadI(); + const int * Ai = mat->HostReadJ(); + const double * Ax = mat->HostReadData(); if (!use_long_ints) { @@ -2820,12 +2910,13 @@ void UMFPackSolver::Mult(const Vector &b, Vector &x) const if (mat == NULL) mfem_error("UMFPackSolver::Mult : matrix is not set!" " Call SetOperator first!"); - + b.HostRead(); + x.HostReadWrite(); if (!use_long_ints) { int status = - umfpack_di_solve(UMFPACK_At, mat->GetI(), mat->GetJ(), - mat->GetData(), x, b, Numeric, Control, Info); + umfpack_di_solve(UMFPACK_At, mat->HostReadI(), mat->HostReadJ(), + mat->HostReadData(), x, b, Numeric, Control, Info); umfpack_di_report_info(Control, Info); if (status < 0) { @@ -2836,7 +2927,7 @@ void UMFPackSolver::Mult(const Vector &b, Vector &x) const else { SuiteSparse_long status = - umfpack_dl_solve(UMFPACK_At, AI, AJ, mat->GetData(), x, b, + umfpack_dl_solve(UMFPACK_At, AI, AJ, mat->HostReadData(), x, b, Numeric, Control, Info); umfpack_dl_report_info(Control, Info); if (status < 0) @@ -2852,12 +2943,13 @@ void UMFPackSolver::MultTranspose(const Vector &b, Vector &x) const if (mat == NULL) mfem_error("UMFPackSolver::MultTranspose : matrix is not set!" " Call SetOperator first!"); - + b.HostRead(); + x.HostReadWrite(); if (!use_long_ints) { int status = - umfpack_di_solve(UMFPACK_A, mat->GetI(), mat->GetJ(), - mat->GetData(), x, b, Numeric, Control, Info); + umfpack_di_solve(UMFPACK_A, mat->HostReadI(), mat->HostReadJ(), + mat->HostReadData(), x, b, Numeric, Control, Info); umfpack_di_report_info(Control, Info); if (status < 0) { @@ -2869,7 +2961,7 @@ void UMFPackSolver::MultTranspose(const Vector &b, Vector &x) const else { SuiteSparse_long status = - umfpack_dl_solve(UMFPACK_A, AI, AJ, mat->GetData(), x, b, + umfpack_dl_solve(UMFPACK_A, AI, AJ, mat->HostReadData(), x, b, Numeric, Control, Info); umfpack_dl_report_info(Control, Info); if (status < 0) @@ -2972,4 +3064,101 @@ KLUSolver::~KLUSolver() #endif // MFEM_USE_SUITESPARSE +DirectSubBlockSolver::DirectSubBlockSolver(const SparseMatrix &A, + const SparseMatrix &block_dof_) + : Solver(A.NumRows()), block_dof(const_cast(block_dof_)), + block_solvers(block_dof.NumRows()) +{ + DenseMatrix sub_A; + for (int i = 0; i < block_dof.NumRows(); ++i) + { + local_dofs.MakeRef(block_dof.GetRowColumns(i), block_dof.RowSize(i)); + sub_A.SetSize(local_dofs.Size()); + A.GetSubMatrix(local_dofs, local_dofs, sub_A); + block_solvers[i].SetOperator(sub_A); + } +} + +void DirectSubBlockSolver::Mult(const Vector &x, Vector &y) const +{ + y.SetSize(x.Size()); + y = 0.0; + + for (int i = 0; i < block_dof.NumRows(); ++i) + { + local_dofs.MakeRef(block_dof.GetRowColumns(i), block_dof.RowSize(i)); + x.GetSubVector(local_dofs, sub_rhs); + sub_sol.SetSize(local_dofs.Size()); + block_solvers[i].Mult(sub_rhs, sub_sol); + y.AddElementVector(local_dofs, sub_sol); + } +} + +void ProductSolver::Mult(const Vector & x, Vector & y) const +{ + y.SetSize(x.Size()); + y = 0.0; + S0->Mult(x, y); + + Vector z(x.Size()); + z = 0.0; + A->Mult(y, z); + add(-1.0, z, 1.0, x, z); // z = (I - A * S0) x + + Vector S1z(x.Size()); + S1z = 0.0; + S1->Mult(z, S1z); + y += S1z; +} + +void ProductSolver::MultTranspose(const Vector & x, Vector & y) const +{ + y.SetSize(x.Size()); + y = 0.0; + S1->MultTranspose(x, y); + + Vector z(x.Size()); + z = 0.0; + A->MultTranspose(y, z); + add(-1.0, z, 1.0, x, z); // z = (I - A^T * S1^T) x + + Vector S0Tz(x.Size()); + S0Tz = 0.0; + S0->MultTranspose(z, S0Tz); + y += S0Tz; +} + +#ifdef MFEM_USE_MPI +AuxSpaceSmoother::AuxSpaceSmoother(const HypreParMatrix &op, + HypreParMatrix *aux_map, + bool op_is_symmetric, + bool own_aux_map) + : Solver(op.NumRows()), aux_map_(aux_map, own_aux_map) +{ + aux_system_.Reset(RAP(&op, aux_map)); + aux_system_.As()->EliminateZeroRows(); + aux_smoother_.Reset(new HypreSmoother(*aux_system_.As())); + aux_smoother_.As()->SetOperatorSymmetry(op_is_symmetric); +} + +void AuxSpaceSmoother::Mult(const Vector &x, Vector &y, bool transpose) const +{ + Vector aux_rhs(aux_map_->NumCols()); + aux_map_->MultTranspose(x, aux_rhs); + + Vector aux_sol(aux_rhs.Size()); + if (transpose) + { + aux_smoother_->MultTranspose(aux_rhs, aux_sol); + } + else + { + aux_smoother_->Mult(aux_rhs, aux_sol); + } + + y.SetSize(aux_map_->NumRows()); + aux_map_->Mult(aux_sol, y); +} +#endif // MFEM_USE_MPI + } diff --git a/linalg/solvers.hpp b/linalg/solvers.hpp index d657d919ac..8297a9903c 100644 --- a/linalg/solvers.hpp +++ b/linalg/solvers.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -14,6 +14,7 @@ #include "../config/config.hpp" #include "densemat.hpp" +#include "handle.hpp" #ifdef MFEM_USE_MPI #include @@ -406,7 +407,40 @@ void MINRES(const Operator &A, Solver &B, const Vector &b, Vector &x, class NewtonSolver : public IterativeSolver { protected: - mutable Vector r, c; + mutable Vector xcur, r, c; + mutable Operator *grad; + + // Adaptive linear solver rtol variables + + // Method to determine rtol, 0 means the adaptive algorithm is deactivated. + int lin_rtol_type = 0; + // rtol to use in first iteration + double lin_rtol0; + // Maximum rtol + double lin_rtol_max; + // Function norm ||F(x)|| of the previous iterate + mutable double fnorm_last = 0.0; + // Linear residual norm of the previous iterate + mutable double lnorm_last = 0.0; + // Forcing term (linear residual rtol) from the previous iterate + mutable double eta_last = 0.0; + // Eisenstat-Walker factor gamma + double gamma; + // Eisenstat-Walker factor alpha + double alpha; + + /** @brief Method for the adaptive linear solver rtol invoked before the + linear solve. */ + void AdaptiveLinRtolPreSolve(const Vector &x, + const int it, + const double fnorm) const; + + /** @brief Method for the adaptive linear solver rtol invoked after the + linear solve. */ + void AdaptiveLinRtolPostSolve(const Vector &x, + const Vector &b, + const int it, + const double fnorm) const; public: NewtonSolver() { } @@ -434,6 +468,26 @@ public: /** @brief This method can be overloaded in derived classes to perform computations that need knowledge of the newest Newton state. */ virtual void ProcessNewState(const Vector &x) const { } + + const Vector &GetCurrentResidual() const { return r; } + const Vector &GetCurrentIterate() const { return xcur; } + + /// Enable adaptive linear solver relative tolerance algorithm. + /** Compute a relative tolerance for the Krylov method after each nonlinear + iteration, based on the algorithm presented in [1]. + + The maximum linear solver relative tolerance @a rtol_max should be < 1. For + @a type 1 the parameters @a alpha and @a gamma are ignored. For @a type 2 + @a alpha has to be between 0 and 1 and @a gamma between 1 and 2. + + [1] Eisenstat, Stanley C., and Homer F. Walker. "Choosing the forcing terms + in an inexact Newton method." + */ + void SetAdaptiveLinRtol(const int type = 2, + const double rtol0 = 0.5, + const double rtol_max = 0.9, + const double alpha = 0.5 * (1.0 + sqrt(5.0)), + const double gamma = 1.0); }; /** L-BFGS method for solving F(x)=b for a given operator F, by minimizing @@ -799,6 +853,61 @@ public: #endif // MFEM_USE_SUITESPARSE +/// Block diagonal solver for A, each block is inverted by direct solver +class DirectSubBlockSolver : public Solver +{ + SparseMatrix& block_dof; + mutable Array local_dofs; + mutable Vector sub_rhs; + mutable Vector sub_sol; + Array block_solvers; +public: + /// block_dof is a boolean matrix, block_dof(i, j) = 1 if j-th dof belongs to + /// i-th block, block_dof(i, j) = 0 otherwise. + DirectSubBlockSolver(const SparseMatrix& A, const SparseMatrix& block_dof); + virtual void Mult(const Vector &x, Vector &y) const; + virtual void SetOperator(const Operator &op) { } +}; + +/// Solver S such that I - A * S = (I - A * S1) * (I - A * S0). +/// That is, S = S0 + S1 - S1 * A * S0. +class ProductSolver : public Solver +{ + OperatorPtr A; + OperatorPtr S0; + OperatorPtr S1; +public: + ProductSolver(Operator* A_, Solver* S0_, Solver* S1_, + bool ownA, bool ownS0, bool ownS1) + : Solver(A_->NumRows()), A(A_, ownA), S0(S0_, ownS0), S1(S1_, ownS1) { } + virtual void Mult(const Vector &x, Vector &y) const; + virtual void MultTranspose(const Vector &x, Vector &y) const; + virtual void SetOperator(const Operator &op) { } +}; + +#ifdef MFEM_USE_MPI +/** This smoother does relaxations on an auxiliary space (determined by a map + from the original space to the auxiliary space provided by the user). + The smoother on the auxiliary space is a HypreSmoother. Its options can be + modified through GetSmoother. + For example, the space can be the nullspace of div/curl, in which case the + smoother can be used to construct a Hiptmair smoother. */ +class AuxSpaceSmoother : public Solver +{ + OperatorPtr aux_map_; + OperatorPtr aux_system_; + OperatorPtr aux_smoother_; + void Mult(const Vector &x, Vector &y, bool transpose) const; +public: + AuxSpaceSmoother(const HypreParMatrix &op, HypreParMatrix *aux_map, + bool op_is_symmetric = true, bool own_aux_map = false); + virtual void Mult(const Vector &x, Vector &y) const { Mult(x, y, false); } + virtual void MultTranspose(const Vector &x, Vector &y) const { Mult(x, y, true); } + virtual void SetOperator(const Operator &op) { } + HypreSmoother& GetSmoother() { return *aux_smoother_.As(); } +}; +#endif // MFEM_USE_MPI + } #endif // MFEM_SOLVERS diff --git a/linalg/sparsemat.cpp b/linalg/sparsemat.cpp index 611becf08b..eb85651b0a 100644 --- a/linalg/sparsemat.cpp +++ b/linalg/sparsemat.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -47,6 +47,19 @@ void SparseMatrix::InitCuSparse() #endif } +void SparseMatrix::ClearCuSparse() +{ +#ifdef MFEM_USE_CUDA + if (initBuffers) + { + cusparseDestroySpMat(matA_descr); + cusparseDestroyDnVec(vecX_descr); + cusparseDestroyDnVec(vecY_descr); + initBuffers = false; + } +#endif +} + SparseMatrix::SparseMatrix(int nrows, int ncols) : AbstractSparseMatrix(nrows, (ncols >= 0) ? ncols : nrows), Rows(new RowNode *[nrows]), @@ -282,15 +295,7 @@ void SparseMatrix::SetEmpty() #endif isSorted = false; -#ifdef MFEM_USE_CUDA - if (initBuffers) - { - cusparseDestroySpMat(matA_descr); - cusparseDestroyDnVec(vecX_descr); - cusparseDestroyDnVec(vecY_descr); - initBuffers = false; - } -#endif + ClearCuSparse(); } int SparseMatrix::RowSize(const int i) const @@ -415,10 +420,14 @@ void SparseMatrix::SortColumnIndices() return; } + const int * Ip=HostReadI(); + HostReadWriteJ(); + HostReadWriteData(); + Array > row; for (int j = 0, i = 0; i < height; i++) { - int end = I[i+1]; + int end = Ip[i+1]; row.SetSize(end - j); for (int k = 0; k < row.Size(); k++) { @@ -3156,13 +3165,7 @@ void SparseMatrix::Destroy() delete At; #ifdef MFEM_USE_CUDA - if (initBuffers) - { - cusparseDestroySpMat(matA_descr); - cusparseDestroyDnVec(vecX_descr); - cusparseDestroyDnVec(vecY_descr); - initBuffers = false; - } + ClearCuSparse(); #endif } diff --git a/linalg/sparsemat.hpp b/linalg/sparsemat.hpp index ca9a7f57b9..c354baeb0f 100644 --- a/linalg/sparsemat.hpp +++ b/linalg/sparsemat.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -166,6 +166,10 @@ public: /// Clear the contents of the SparseMatrix. void Clear() { Destroy(); SetEmpty(); } + /** @brief Clear the CuSparse descriptors. + This must be called after releasing the device memory of A. */ + void ClearCuSparse(); + /// Check if the SparseMatrix is empty. bool Empty() const { return (A == NULL) && (Rows == NULL); } diff --git a/linalg/sparsesmoothers.cpp b/linalg/sparsesmoothers.cpp index 0cc2bc2122..3c14616fed 100644 --- a/linalg/sparsesmoothers.cpp +++ b/linalg/sparsesmoothers.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/sparsesmoothers.hpp b/linalg/sparsesmoothers.hpp index 4daf31cc0b..9cfc3adea3 100644 --- a/linalg/sparsesmoothers.hpp +++ b/linalg/sparsesmoothers.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/strumpack.cpp b/linalg/strumpack.cpp index 791400679a..ac69842290 100644 --- a/linalg/strumpack.cpp +++ b/linalg/strumpack.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/strumpack.hpp b/linalg/strumpack.hpp index b6eaba2a78..17a9945ad6 100644 --- a/linalg/strumpack.hpp +++ b/linalg/strumpack.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/sundials.cpp b/linalg/sundials.cpp index 0ba85a7691..9d4b1ee1ae 100644 --- a/linalg/sundials.cpp +++ b/linalg/sundials.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/sundials.hpp b/linalg/sundials.hpp index 663f4d609d..ff28439b74 100644 --- a/linalg/sundials.hpp +++ b/linalg/sundials.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/superlu.cpp b/linalg/superlu.cpp index a0a30c94b2..9003bf9bb3 100644 --- a/linalg/superlu.cpp +++ b/linalg/superlu.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -523,9 +523,10 @@ void SuperLUSolver::Mult( const Vector & x, Vector & y ) const // SuperLU overwrites x with y, so copy x to y and pass that to the solve // routine. - y = x; + const double *xPtr = x.HostRead(); + y = xPtr; + double * yPtr = y.HostReadWrite(); - double* yPtr = (double*)y; int info = -1, locSize = y.Size(); // Solve the system diff --git a/linalg/superlu.hpp b/linalg/superlu.hpp index db8def84c8..d75d32b6eb 100644 --- a/linalg/superlu.hpp +++ b/linalg/superlu.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/symmat.cpp b/linalg/symmat.cpp new file mode 100644 index 0000000000..448016982c --- /dev/null +++ b/linalg/symmat.cpp @@ -0,0 +1,109 @@ +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-806117. +// +// This file is part of the MFEM library. For more information and source code +// availability visit https://mfem.org. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. + + +// Implementation of data type DenseSymmetricMatrix + +#include "symmat.hpp" + +namespace mfem +{ + +DenseSymmetricMatrix::DenseSymmetricMatrix() : Matrix(0) +{ + data.Reset(); +} + +DenseSymmetricMatrix::DenseSymmetricMatrix(int s) : Matrix(s) +{ + MFEM_ASSERT(s >= 0, "invalid DenseSymmetricMatrix size: " << s); + if (s > 0) + { + data.New((s*(s+1))/2); + *this = 0.0; // init with zeroes + } + else + { + data.Reset(); + } +} + +void DenseSymmetricMatrix::SetSize(int s) +{ + MFEM_ASSERT(s >= 0, + "invalid DenseSymmetricMatrix size: " << s); + if (Height() == s) + { + return; + } + height = s; + width = s; + const int s2 = (s*(s+1))/2; + if (s2 > data.Capacity()) + { + data.Delete(); + data.New(s2); + *this = 0.0; // init with zeroes + } +} + +DenseSymmetricMatrix &DenseSymmetricMatrix::operator=(double c) +{ + const int s = (Height()*(Height()+1))/2; + for (int i = 0; i < s; i++) + { + data[i] = c; + } + return *this; +} + +double &DenseSymmetricMatrix::Elem(int i, int j) +{ + return (*this)(i,j); +} + +const double &DenseSymmetricMatrix::Elem(int i, int j) const +{ + return (*this)(i,j); +} + +DenseSymmetricMatrix &DenseSymmetricMatrix::operator*=(double c) +{ + int s = Height()*(Height()+1)/2; + for (int i = 0; i < s; i++) + { + data[i] *= c; + } + return *this; +} + +void DenseSymmetricMatrix::Mult(const Vector &x, Vector &y) const +{ + mfem_error("DenseSymmetricMatrix::Mult() not implemented!"); +} + +MatrixInverse *DenseSymmetricMatrix::Inverse() const +{ + mfem_error("DenseSymmetricMatrix::Inverse() not implemented!"); + return nullptr; +} + +void DenseSymmetricMatrix::Print (std::ostream & out, int width_) const +{ + mfem_error("DenseSymmetricMatrix::Print() not implemented!"); +} + +DenseSymmetricMatrix::~DenseSymmetricMatrix() +{ + data.Delete(); +} + +} diff --git a/linalg/symmat.hpp b/linalg/symmat.hpp new file mode 100644 index 0000000000..34960636fc --- /dev/null +++ b/linalg/symmat.hpp @@ -0,0 +1,175 @@ +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-806117. +// +// This file is part of the MFEM library. For more information and source code +// availability visit https://mfem.org. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. + +#ifndef MFEM_SYMMETRICMAT +#define MFEM_SYMMETRICMAT + +#include "../config/config.hpp" +#include "../general/globals.hpp" +#include "matrix.hpp" + +namespace mfem +{ + +/// Dense symmetric matrix storing the upper triangular part. This class so far +/// has little functionality beyond storage. +class DenseSymmetricMatrix : public Matrix +{ +private: + Memory data; + +public: + + /** Default constructor for DenseSymmetricMatrix. + Sets data = NULL and height = width = 0. */ + DenseSymmetricMatrix(); + + /// Creates square matrix of size s. + explicit DenseSymmetricMatrix(int s); + + /// Construct a DenseSymmetricMatrix using an existing data array. + /** The DenseSymmetricMatrix does not assume ownership of the data array, i.e. it will + not delete the array. */ + DenseSymmetricMatrix(double *d, int s) + : Matrix(s, s) { UseExternalData(d, s); } + + /// Change the data array and the size of the DenseSymmetricMatrix. + /** The DenseSymmetricMatrix does not assume ownership of the data array, i.e. it will + not delete the data array @a d. This method should not be used with + DenseSymmetricMatrix that owns its current data array. */ + void UseExternalData(double *d, int s) + { + data.Wrap(d, (s*(s+1))/2, false); + height = s; width = s; + } + + /// Change the data array and the size of the DenseSymmetricMatrix. + /** The DenseSymmetricMatrix does not assume ownership of the data array, i.e. it will + not delete the new array @a d. This method will delete the current data + array, if owned. */ + void Reset(double *d, int s) + { if (OwnsData()) { data.Delete(); } UseExternalData(d, s); } + + /** Clear the data array and the dimensions of the DenseSymmetricMatrix. This method + should not be used with DenseSymmetricMatrix that owns its current data array. */ + void ClearExternalData() { data.Reset(); height = width = 0; } + + /// Delete the matrix data array (if owned) and reset the matrix state. + void Clear() + { if (OwnsData()) { data.Delete(); } ClearExternalData(); } + + /// Change the size of the DenseSymmetricMatrix to s x s. + void SetSize(int s); + + /// Returns the matrix data array. + inline double *Data() const + { return const_cast((const double*)data);} + + /// Returns the matrix data array. + inline double *GetData() const { return Data(); } + + Memory &GetMemory() { return data; } + const Memory &GetMemory() const { return data; } + + /// Return the DenseSymmetricMatrix data (host pointer) ownership flag. + inline bool OwnsData() const { return data.OwnsHostPtr(); } + + /// Returns reference to a_{ij}. + inline double &operator()(int i, int j); + + /// Returns constant reference to a_{ij}. + inline const double &operator()(int i, int j) const; + + /// Returns reference to a_{ij}. + virtual double &Elem(int i, int j); + + /// Returns constant reference to a_{ij}. + virtual const double &Elem(int i, int j) const; + + /// Sets the matrix elements equal to constant c + DenseSymmetricMatrix &operator=(double c); + + DenseSymmetricMatrix &operator*=(double c); + + long MemoryUsage() const { return data.Capacity() * sizeof(double); } + + /// Shortcut for mfem::Read( GetMemory(), TotalSize(), on_dev). + const double *Read(bool on_dev = true) const + { return mfem::Read(data, Height()*Width(), on_dev); } + + /// Shortcut for mfem::Read(GetMemory(), TotalSize(), false). + const double *HostRead() const + { return mfem::Read(data, Height()*Width(), false); } + + /// Shortcut for mfem::Write(GetMemory(), TotalSize(), on_dev). + double *Write(bool on_dev = true) + { return mfem::Write(data, Height()*Width(), on_dev); } + + /// Shortcut for mfem::Write(GetMemory(), TotalSize(), false). + double *HostWrite() + { return mfem::Write(data, Height()*Width(), false); } + + /// Shortcut for mfem::ReadWrite(GetMemory(), TotalSize(), on_dev). + double *ReadWrite(bool on_dev = true) + { return mfem::ReadWrite(data, Height()*Width(), on_dev); } + + /// Shortcut for mfem::ReadWrite(GetMemory(), TotalSize(), false). + double *HostReadWrite() + { return mfem::ReadWrite(data, Height()*Width(), false); } + + /// Matrix vector multiplication. + virtual void Mult(const Vector &x, Vector &y) const; + + /// Returns a pointer to (an approximation) of the matrix inverse. + virtual MatrixInverse *Inverse() const; + + /// Prints matrix to stream out. + virtual void Print (std::ostream & out = mfem::out, int width_ = 4) const; + + /// Destroys the symmetric matrix. + virtual ~DenseSymmetricMatrix(); +}; + +// Inline methods + +// The number of entries stored in rows 1,...,k is +// n + n-1 + n-2 + ... + n-k+1, where there are k terms. This equals +// kn - sum_{i=1}^{k-1} i = kn - (k-1)k/2 +// This formula is used for the offset for each row. +inline double &DenseSymmetricMatrix::operator()(int i, int j) +{ + MFEM_ASSERT(data && i >= 0 && i < height && j >= 0 && j < width, ""); + if (i > j) // reverse i and j + { + return data[(j*height) - (((j-1)*j)/2) + i - j]; + } + else + { + return data[(i*height) - (((i-1)*i)/2) + j - i]; + } +} + +inline const double &DenseSymmetricMatrix::operator()(int i, int j) const +{ + MFEM_ASSERT(data && i >= 0 && i < height && j >= 0 && j < width, ""); + if (i > j) // reverse i and j + { + return data[(j*height) - (((j-1)*j)/2) + i - j]; + } + else + { + return data[(i*height) - (((i-1)*i)/2) + j - i]; + } +} + +} // namespace mfem + +#endif diff --git a/linalg/tlayout.hpp b/linalg/tlayout.hpp index c42d29aa7c..398710387f 100644 --- a/linalg/tlayout.hpp +++ b/linalg/tlayout.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/tmatrix.hpp b/linalg/tmatrix.hpp index 0c1ee62b34..d5e35d0211 100644 --- a/linalg/tmatrix.hpp +++ b/linalg/tmatrix.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/ttensor.hpp b/linalg/ttensor.hpp index 325efba9e3..e5d9cc8810 100644 --- a/linalg/ttensor.hpp +++ b/linalg/ttensor.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/vector.cpp b/linalg/vector.cpp index cc749e9fee..79aabc5e15 100644 --- a/linalg/vector.cpp +++ b/linalg/vector.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/linalg/vector.hpp b/linalg/vector.hpp index 3f52944734..6daa07bab2 100644 --- a/linalg/vector.hpp +++ b/linalg/vector.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/makefile b/makefile index 04034375b3..aa80947a88 100644 --- a/makefile +++ b/makefile @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # @@ -117,7 +117,7 @@ EXAMPLE_SUBDIRS = amgx ginkgo hiop petsc pumi sundials superlu EXAMPLE_DIRS := examples $(addprefix examples/,$(EXAMPLE_SUBDIRS)) EXAMPLE_TEST_DIRS := examples -MINIAPP_SUBDIRS = common electromagnetics meshing navier performance tools toys nurbs gslib adjoint +MINIAPP_SUBDIRS = common electromagnetics meshing navier performance tools toys nurbs gslib adjoint solvers MINIAPP_DIRS := $(addprefix miniapps/,$(MINIAPP_SUBDIRS)) MINIAPP_TEST_DIRS := $(filter-out %/common,$(MINIAPP_DIRS)) MINIAPP_USE_COMMON := $(addprefix miniapps/,electromagnetics meshing tools toys) @@ -536,7 +536,7 @@ clean: $(addsuffix /clean,$(EM_DIRS) $(TEST_DIRS)) distclean: clean config/clean doc/clean rm -rf mfem/ -INSTALL_SHARED_LIB = $(MFEM_CXX) $(MFEM_BUILD_FLAGS) $(INSTALL_SOFLAGS)\ +INSTALL_SHARED_LIB = $(MFEM_CXX) $(MFEM_LINK_FLAGS) $(INSTALL_SOFLAGS)\ $(OBJECT_FILES) $(EXT_LIBS) -o $(PREFIX_LIB)/libmfem.$(SO_VER) && \ cd $(PREFIX_LIB) && ln -sf libmfem.$(SO_VER) libmfem.$(SO_EXT) @@ -684,9 +684,10 @@ status info: ASTYLE_BIN = astyle ASTYLE = $(ASTYLE_BIN) --options=$(SRC)config/mfem.astylerc ASTYLE_VER = "Artistic Style Version 2.05.1" -FORMAT_FILES = $(foreach dir,$(DIRS) $(EM_DIRS) config,"$(dir)/*.?pp") -FORMAT_FILES += "tests/unit/*.cpp" -FORMAT_FILES += $(foreach dir,general linalg mesh fem,"tests/unit/$(dir)/*.?pp") +FORMAT_FILES := $(foreach dir,$(DIRS) $(EM_DIRS) config,$(dir)/*.?pp) +FORMAT_FILES += tests/unit/*.cpp +FORMAT_FILES += $(foreach dir,general linalg mesh fem,tests/unit/$(dir)/*.?pp) +FORMAT_FILES := $(filter-out general/tinyxml2.cpp,$(wildcard $(FORMAT_FILES))) COUT_CERR_FILES = $(foreach dir,$(DIRS),$(dir)/*.[ch]pp) COUT_CERR_EXCLUDE = '^general/error\.cpp' '^general/globals\.[ch]pp' diff --git a/mesh/CMakeLists.txt b/mesh/CMakeLists.txt index 65af32bdb6..fdca87f725 100644 --- a/mesh/CMakeLists.txt +++ b/mesh/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/mesh/element.cpp b/mesh/element.cpp index 81cd633707..4c95f876bd 100644 --- a/mesh/element.cpp +++ b/mesh/element.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/mesh/element.hpp b/mesh/element.hpp index 24b8706f09..497805b586 100644 --- a/mesh/element.hpp +++ b/mesh/element.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/mesh/gmsh.cpp b/mesh/gmsh.cpp index 31360cc19a..ac420407da 100644 --- a/mesh/gmsh.cpp +++ b/mesh/gmsh.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/mesh/gmsh.hpp b/mesh/gmsh.hpp index 34f193d3e8..4e09ee111c 100644 --- a/mesh/gmsh.hpp +++ b/mesh/gmsh.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/mesh/hexahedron.cpp b/mesh/hexahedron.cpp index 3d806d1f3f..17186afd9b 100644 --- a/mesh/hexahedron.cpp +++ b/mesh/hexahedron.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/mesh/hexahedron.hpp b/mesh/hexahedron.hpp index a85d0345dd..64ffb37b15 100644 --- a/mesh/hexahedron.hpp +++ b/mesh/hexahedron.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/mesh/mesh.cpp b/mesh/mesh.cpp index e1a976e88d..fdba4ba881 100644 --- a/mesh/mesh.cpp +++ b/mesh/mesh.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -471,10 +471,11 @@ void Mesh::GetBdrElementTransformation(int i, IsoparametricTransformation* ElTr) FaceElemTr.Loc1.Transf, face_info); // NOTE: FaceElemTr.Loc1 is overwritten here -- used as a temporary + Geometry::Type face_geom = GetBdrElementBaseGeometry(i); const FiniteElement *face_el = - Nodes->FESpace()->GetTraceElement(elem_id, - GetBdrElementBaseGeometry(i)); - + Nodes->FESpace()->GetTraceElement(elem_id, face_geom); + MFEM_VERIFY(dynamic_cast(face_el), + "Mesh requires nodal Finite Element."); IntegrationRule eir(face_el->GetDof()); FaceElemTr.Loc1.Transf.ElementNo = elem_id; FaceElemTr.Loc1.Transf.ElementType = ElementTransformation::ELEMENT; @@ -541,6 +542,8 @@ void Mesh::GetFaceTransformation(int FaceNo, IsoparametricTransformation *FTr) face_el = Nodes->FESpace()->GetTraceElement(face_info.Elem1No, face_geom); + MFEM_VERIFY(dynamic_cast(face_el), + "Mesh requires nodal Finite Element."); IntegrationRule eir(face_el->GetDof()); FaceElemTr.Loc1.Transf.ElementNo = face_info.Elem1No; @@ -1049,6 +1052,13 @@ void Mesh::GetFaceInfos(int Face, int *Inf1, int *Inf2) const *Inf2 = faces_info[Face].Elem2Inf; } +void Mesh::GetFaceInfos(int Face, int *Inf1, int *Inf2, int *NCFace) const +{ + *Inf1 = faces_info[Face].Elem1Inf; + *Inf2 = faces_info[Face].Elem2Inf; + *NCFace = faces_info[Face].NCFace; +} + Geometry::Type Mesh::GetFaceGeometryType(int Face) const { switch (Dim) @@ -2499,6 +2509,25 @@ void Mesh::FinalizeTopology(bool generate_bdr) if (spaceDim == 0) { spaceDim = Dim; } if (ncmesh) { ncmesh->spaceDim = spaceDim; } + // if the user defined any hanging nodes (see AddVertexParent), + // we're initializing a non-conforming mesh + if (tmp_vertex_parents.Size()) + { + MFEM_VERIFY(ncmesh == NULL, ""); + ncmesh = new NCMesh(this); + + // we need to recreate the Mesh because NCMesh reorders the vertices + // (see NCMesh::UpdateVertices()) + InitFromNCMesh(*ncmesh); + ncmesh->OnMeshUpdated(this); + GenerateNCFaceInfo(); + + SetAttributes(); + + tmp_vertex_parents.DeleteAll(); + return; + } + // set the mesh type: 'meshgen', ... SetMeshGen(); @@ -2554,15 +2583,6 @@ void Mesh::FinalizeTopology(bool generate_bdr) // generate the arrays 'attributes' and 'bdr_attributes' SetAttributes(); - - // if the user defined any hanging nodes (see AddVertexParent), - // initialize the NC mesh now - if (tmp_vertex_parents.Size()) - { - MFEM_VERIFY(ncmesh == NULL, ""); - EnsureNCMesh(true); - tmp_vertex_parents.DeleteAll(); - } } void Mesh::Finalize(bool refine, bool fix_orientation) @@ -2633,7 +2653,8 @@ void Mesh::Finalize(bool refine, bool fix_orientation) for (int i = 0; i < num_faces; i++) { MFEM_VERIFY(faces_info[i].Elem2No < 0 || - faces_info[i].Elem2Inf%2 != 0, "invalid mesh topology"); + faces_info[i].Elem2Inf%2 != 0, "Invalid mesh topology." + " Interior face with incompatible orientations."); } } #endif @@ -3441,26 +3462,55 @@ void Mesh::Loader(std::istream &input, int generate_edges, Clear(); + istream::pos_type beginning_pos = input.tellg(); string mesh_type; input >> ws; getline(input, mesh_type); filter_dos(mesh_type); - // MFEM's native mesh formats - bool mfem_v10 = (mesh_type == "MFEM mesh v1.0"); - bool mfem_v11 = (mesh_type == "MFEM mesh v1.1"); - bool mfem_v12 = (mesh_type == "MFEM mesh v1.2"); - if (mfem_v10 || mfem_v11 || mfem_v12) // MFEM's own mesh formats + // MFEM's conforming mesh formats + int mfem_version = 0; + if (mesh_type == "MFEM mesh v1.0") { mfem_version = 10; } // serial + else if (mesh_type == "MFEM mesh v1.2") { mfem_version = 12; } // parallel + + // MFEM nonconforming mesh format + // (NOTE: previous v1.1 is now under this branch for backward compatibility) + int mfem_nc_version = 0; + if (mesh_type == "MFEM NC mesh v1.0") { mfem_nc_version = 10; } + else if (mesh_type == "MFEM mesh v1.1") { mfem_nc_version = 1 /*legacy*/; } + + if (mfem_version) { // Formats mfem_v12 and newer have a tag indicating the end of the mesh // section in the stream. A user provided parse tag can also be provided // via the arguments. For example, if this is called from parallel mesh // object, it can indicate to read until parallel mesh section begins. - if ( mfem_v12 && parse_tag.empty() ) + if (mfem_version == 12 && parse_tag.empty()) { parse_tag = "mfem_mesh_end"; } - ReadMFEMMesh(input, mfem_v11, curved); + ReadMFEMMesh(input, mfem_version, curved); + } + else if (mfem_nc_version) + { + MFEM_ASSERT(ncmesh == NULL, "internal error"); +#ifdef MFEM_USE_MPI + ParMesh *pmesh = dynamic_cast(this); + if (pmesh) + { + MFEM_VERIFY(mfem_nc_version >= 10, + "Legacy nonconforming format (MFEM mesh v1.1) cannot be " + "used to load a parallel nonconforming mesh, sorry."); + + ncmesh = new ParNCMesh(pmesh->GetComm(), + input, mfem_nc_version, curved); + } + else +#endif + { + ncmesh = new NCMesh(input, mfem_nc_version, curved); + } + InitFromNCMesh(*ncmesh); } else if (mesh_type == "linemesh") // 1D mesh { @@ -3482,11 +3532,20 @@ void Mesh::Loader(std::istream &input, int generate_edges, { ReadTrueGridMesh(input); } - else if (mesh_type == "# vtk DataFile Version 3.0" || - mesh_type == "# vtk DataFile Version 2.0") // VTK + else if (mesh_type.rfind("# vtk DataFile Version") == 0) { + int major_vtk_version = mesh_type[mesh_type.length()-3] - '0'; + // int minor_vtk_version = mesh_type[mesh_type.length()-1] - '0'; + MFEM_VERIFY(major_vtk_version >= 2 && major_vtk_version <= 4, + "Unsupported VTK format"); ReadVTKMesh(input, curved, read_gf, finalize_topo); } + else if (mesh_type.rfind("VectorDim(); if (ncmesh) { ncmesh->spaceDim = spaceDim; } - // Set the 'vertices' from the 'Nodes' - for (int i = 0; i < spaceDim; i++) - { - Vector vert_val; - Nodes->GetNodalValues(vert_val, i+1); - for (int j = 0; j < NumOfVertices; j++) - { - vertices[j](i) = vert_val(j); - } - } + + // Set vertex coordinates from the 'Nodes' + SetVerticesFromNodes(Nodes); } // If a parse tag was supplied, keep reading the stream until the tag is // encountered. - if (mfem_v12) + if (mfem_version == 12) { string line; do @@ -3591,6 +3647,14 @@ void Mesh::Loader(std::istream &input, int generate_edges, } while (line != parse_tag); } + else if (mfem_nc_version >= 10) + { + string ident; + skip_comment_lines(input, '#'); + input >> ident; + MFEM_VERIFY(ident == "mfem_mesh_end", + "invalid mesh: end of file tag not found"); + } // Finalize(...) should be called after this, if needed. } @@ -4203,6 +4267,20 @@ void Mesh::SetCurvature(int order, bool discont, int space_dim, int ordering) Nodes->MakeOwner(nfec); } +void Mesh::SetVerticesFromNodes(const GridFunction *nodes) +{ + MFEM_ASSERT(nodes != NULL, ""); + for (int i = 0; i < spaceDim; i++) + { + Vector vert_val; + nodes->GetNodalValues(vert_val, i+1); + for (int j = 0; j < NumOfVertices; j++) + { + vertices[j](i) = vert_val(j); + } + } +} + int Mesh::GetNumFaces() const { switch (Dim) @@ -5260,6 +5338,21 @@ void Mesh::AddPointFaceElement(int lf, int gf, int el) } else // this will be elem2 { + /* WARNING: Without the following check the mesh faces_info data structure + may contain unreliable data. Normally, the order in which elements are + processed could swap which elements appear as Elem1No and Elem2No. In + branched meshes, where more than two elements can meet at a given node, + the indices stored in Elem1No and Elem2No will be the first and last, + respectively, elements found which touch a given node. This can lead to + inconsistencies in any algorithms which rely on this data structure. To + properly support branched meshes this data structure should be extended + to support multiple elements per face. */ + /* + MFEM_VERIFY(faces_info[gf].Elem2No < 0, "Invalid mesh topology. " + "Interior point found connecting 1D elements " + << faces_info[gf].Elem1No << ", " << faces_info[gf].Elem2No + << " and " << el << "."); + */ faces_info[gf].Elem2No = el; faces_info[gf].Elem2Inf = 64 * lf + 1; } @@ -5277,6 +5370,10 @@ void Mesh::AddSegmentFaceElement(int lf, int gf, int el, int v0, int v1) } else // this will be elem2 { + MFEM_VERIFY(faces_info[gf].Elem2No < 0, "Invalid mesh topology. " + "Interior edge found between 2D elements " + << faces_info[gf].Elem1No << ", " << faces_info[gf].Elem2No + << " and " << el << "."); int *v = faces[gf]->GetVertices(); faces_info[gf].Elem2No = el; if ( v[1] == v0 && v[0] == v1 ) @@ -5311,6 +5408,10 @@ void Mesh::AddTriangleFaceElement(int lf, int gf, int el, } else // this will be elem2 { + MFEM_VERIFY(faces_info[gf].Elem2No < 0, "Invalid mesh topology. " + "Interior triangular face found connecting elements " + << faces_info[gf].Elem1No << ", " << faces_info[gf].Elem2No + << " and " << el << "."); int orientation, vv[3] = { v0, v1, v2 }; orientation = GetTriOrientation(faces[gf]->GetVertices(), vv); // In a valid mesh, we should have (orientation % 2 != 0), however, if @@ -5335,6 +5436,10 @@ void Mesh::AddQuadFaceElement(int lf, int gf, int el, } else // this will be elem2 { + MFEM_VERIFY(faces_info[gf].Elem2No < 0, "Invalid mesh topology. " + "Interior quadrilateral face found connecting elements " + << faces_info[gf].Elem1No << ", " << faces_info[gf].Elem2No + << " and " << el << "."); int vv[4] = { v0, v1, v2, v3 }; int oo = GetQuadOrientation(faces[gf]->GetVertices(), vv); // Temporarily allow even face orientations: see the remark in @@ -5990,6 +6095,7 @@ int *Mesh::GeneratePartitioning(int nparts, int part_method) el_to_el = NULL; // Check for empty partitionings (a "feature" in METIS) + if (nparts > 1 && NumOfElements > nparts) { Array< Pair > psize(nparts); int empty_parts; @@ -6659,6 +6765,11 @@ void Mesh::NewNodes(GridFunction &nodes, bool make_owner) delete NURBSext; NURBSext = nodes.FESpace()->StealNURBSext(); } + + if (ncmesh) + { + ncmesh->MakeTopologyOnly(); + } } void Mesh::SwapNodes(GridFunction *&nodes, int &own_nodes_) @@ -6698,6 +6809,9 @@ void Mesh::UpdateNodes() { Nodes->FESpace()->Update(); Nodes->Update(); + + // update vertex coordinates for compatibility (e.g., GetVertex()) + SetVerticesFromNodes(Nodes); } } @@ -8068,7 +8182,13 @@ void Mesh::GeneralRefinement(const Array &el_to_refine, int nonconforming, void Mesh::EnsureNCMesh(bool simplices_nonconforming) { MFEM_VERIFY(!NURBSext, "Cannot convert a NURBS mesh to an NC mesh. " - "Project the NURBS to Nodes first."); + "Please project the NURBS to Nodes first, with SetCurvature()."); + +#ifdef MFEM_USE_MPI + MFEM_VERIFY(ncmesh != NULL || dynamic_cast(this) == NULL, + "Sorry, converting a conforming ParMesh to an NC mesh is " + "not possible."); +#endif if (!ncmesh) { @@ -8759,9 +8879,25 @@ void Mesh::Printer(std::ostream &out, std::string section_delimiter) const return; } - out << (ncmesh ? "MFEM mesh v1.1\n" : - section_delimiter.empty() ? "MFEM mesh v1.0\n" : - "MFEM mesh v1.2\n"); + if (Nonconforming()) + { + // nonconforming mesh format + ncmesh->Print(out); + + if (Nodes) + { + out << "\n# mesh curvature GridFunction"; + out << "\nnodes\n"; + Nodes->Save(out); + } + + out << "\nmfem_mesh_end" << endl; + return; + } + + // serial/parallel conforming mesh format + out << (section_delimiter.empty() + ? "MFEM mesh v1.0\n" : "MFEM mesh v1.2\n"); // optional out << @@ -8775,8 +8911,9 @@ void Mesh::Printer(std::ostream &out, std::string section_delimiter) const "# PRISM = 6\n" "#\n"; - out << "\ndimension\n" << Dim - << "\n\nelements\n" << NumOfElements << '\n'; + out << "\ndimension\n" << Dim; + + out << "\n\nelements\n" << NumOfElements << '\n'; for (i = 0; i < NumOfElements; i++) { PrintElement(elements[i], out); @@ -8788,15 +8925,6 @@ void Mesh::Printer(std::ostream &out, std::string section_delimiter) const PrintElement(boundary[i], out); } - if (ncmesh) - { - out << "\nvertex_parents\n"; - ncmesh->PrintVertexParents(out); - - out << "\ncoarse_elements\n"; - ncmesh->PrintCoarseElements(out); - } - out << "\nvertices\n" << NumOfVertices << '\n'; if (Nodes == NULL) { @@ -8818,7 +8946,7 @@ void Mesh::Printer(std::ostream &out, std::string section_delimiter) const Nodes->Save(out); } - if (!ncmesh && !section_delimiter.empty()) + if (!section_delimiter.empty()) { out << section_delimiter << endl; // only with format v1.2 } @@ -8937,7 +9065,7 @@ void Mesh::PrintVTK(std::ostream &out) const int nv = elements[i]->GetNVertices(); out << nv; Geometry::Type geom = elements[i]->GetGeometryType(); - const int *perm = (geom == Geometry::PRISM) ? vtk_prism_perm : NULL; + const int *perm = VTKGeometry::VertexPermutation[geom]; for (int j = 0; j < nv; j++) { out << ' ' << v[perm ? perm[j] : j]; @@ -9022,35 +9150,9 @@ void Mesh::PrintVTK(std::ostream &out) for (int i = 0; i < NumOfElements; i++) { int vtk_cell_type = 5; - Geometry::Type geom_type = GetElement(i)->GetGeometryType(); - if (order == 1) - { - switch (geom_type) - { - case Geometry::POINT: vtk_cell_type = 1; break; - case Geometry::SEGMENT: vtk_cell_type = 3; break; - case Geometry::TRIANGLE: vtk_cell_type = 5; break; - case Geometry::SQUARE: vtk_cell_type = 9; break; - case Geometry::TETRAHEDRON: vtk_cell_type = 10; break; - case Geometry::CUBE: vtk_cell_type = 12; break; - case Geometry::PRISM: vtk_cell_type = 13; break; - default: break; - } - } - else if (order == 2) - { - switch (geom_type) - { - case Geometry::SEGMENT: vtk_cell_type = 21; break; - case Geometry::TRIANGLE: vtk_cell_type = 22; break; - case Geometry::SQUARE: vtk_cell_type = 28; break; - case Geometry::TETRAHEDRON: vtk_cell_type = 24; break; - case Geometry::CUBE: vtk_cell_type = 29; break; - case Geometry::PRISM: vtk_cell_type = 32; break; - default: break; - } - } - + Geometry::Type geom = GetElement(i)->GetGeometryType(); + if (order == 1) { vtk_cell_type = VTKGeometry::Map[geom]; } + else if (order == 2) { vtk_cell_type = VTKGeometry::QuadraticMap[geom]; } out << vtk_cell_type << '\n'; } @@ -9268,7 +9370,7 @@ void Mesh::PrintVTU(std::ostream &out, int ref, VTKFormat format, { coff = coff+nv; offset.push_back(coff); - const int *p = (geom == Geometry::PRISM) ? vtk_prism_perm : NULL; + const int *p = VTKGeometry::VertexPermutation[geom]; for (int k = 0; k < nv; k++, j++) { WriteBinaryOrASCII(out, buf, np + RG[p ? p[j] : j], " ", format); @@ -9299,39 +9401,14 @@ void Mesh::PrintVTU(std::ostream &out, int ref, VTKFormat format, out << "" << std::endl; // cell types + const int *vtk_geom_map = + high_order_output ? VTKGeometry::HighOrderMap : VTKGeometry::Map; for (int i = 0; i < ne; i++) { Geometry::Type geom = get_geom(i); uint8_t vtk_cell_type = 5; - // VTK element types defined at: https://git.io/JvZLm - switch (geom) - { - case Geometry::POINT: - vtk_cell_type = 1; - break; - case Geometry::SEGMENT: - vtk_cell_type = high_order_output ? 68 : 3; - break; - case Geometry::TRIANGLE: - vtk_cell_type = high_order_output ? 69 : 5; - break; - case Geometry::SQUARE: - vtk_cell_type = high_order_output ? 70 : 9; - break; - case Geometry::TETRAHEDRON: - vtk_cell_type = high_order_output ? 71 : 10; - break; - case Geometry::CUBE: - vtk_cell_type = high_order_output ? 72 : 12; - break; - case Geometry::PRISM: - vtk_cell_type = high_order_output ? 73 : 13; - break; - default: - MFEM_ABORT("Unrecognized VTK element type \"" << geom << "\""); - break; - } + vtk_cell_type = vtk_geom_map[geom]; if (high_order_output) { @@ -9480,21 +9557,7 @@ void Mesh::PrintVTK(std::ostream &out, int ref, int field_data) int nv = Geometries.GetVertices(geom)->GetNPoints(); RefG = GlobGeometryRefiner.Refine(geom, ref, 1); Array &RG = RefG->RefGeoms; - int vtk_cell_type = 5; - - switch (geom) - { - case Geometry::POINT: vtk_cell_type = 1; break; - case Geometry::SEGMENT: vtk_cell_type = 3; break; - case Geometry::TRIANGLE: vtk_cell_type = 5; break; - case Geometry::SQUARE: vtk_cell_type = 9; break; - case Geometry::TETRAHEDRON: vtk_cell_type = 10; break; - case Geometry::CUBE: vtk_cell_type = 12; break; - case Geometry::PRISM: vtk_cell_type = 13; break; - default: - MFEM_ABORT("Unrecognized VTK element type \"" << geom << "\""); - break; - } + int vtk_cell_type = VTKGeometry::Map[geom]; for (int j = 0; j < RG.Size(); j += nv) { diff --git a/mesh/mesh.hpp b/mesh/mesh.hpp index 29a8420ed0..f3a01bc3dc 100644 --- a/mesh/mesh.hpp +++ b/mesh/mesh.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -185,6 +185,9 @@ protected: MemAlloc TetMemory; #endif + // used during NC mesh initialization only + Array > tmp_vertex_parents; + public: typedef Geometry::Constants seg_t; typedef Geometry::Constants tri_t; @@ -206,9 +209,6 @@ public: Array face_geom_factors; ///< Optional face geometric factors. - /// Used during initialization only. - Array > tmp_vertex_parents; - // Global parameter that can be used to control the removal of unused // vertices performed when reading a mesh in MFEM format. The default value // (true) is set in mesh_readers.cpp. @@ -234,13 +234,20 @@ protected: // Readers for different mesh formats, used in the Load() method. // The implementations of these methods are in mesh_readers.cpp. - void ReadMFEMMesh(std::istream &input, bool mfem_v11, int &curved); + void ReadMFEMMesh(std::istream &input, int version, int &curved); void ReadLineMesh(std::istream &input); void ReadNetgen2DMesh(std::istream &input, int &curved); void ReadNetgen3DMesh(std::istream &input); void ReadTrueGridMesh(std::istream &input); + void CreateVTKMesh(const Vector &points, const Array &cell_data, + const Array &cell_offsets, + const Array &cell_types, + const Array &cell_attributes, + int &curved, int &read_gf, bool &finalize_topo); void ReadVTKMesh(std::istream &input, int &curved, int &read_gf, bool &finalize_topo); + void ReadXML_VTKMesh(std::istream &input, int &curved, int &read_gf, + bool &finalize_topo); void ReadNURBSMesh(std::istream &input, int &curved, int &read_gf); void ReadInlineMesh(std::istream &input, bool generate_edges = false); void ReadGmshMesh(std::istream &input, int &curved, int &read_gf); @@ -310,6 +317,9 @@ protected: /// Update the nodes of a curved mesh after refinement void UpdateNodes(); + /// Helper to set vertex coordinates given a high-order curvature function. + void SetVerticesFromNodes(const GridFunction *nodes); + void UniformRefinement2D_base(bool update_nodes = true); /// Refine a mixed 2D mesh uniformly. @@ -1036,6 +1046,7 @@ public: } void GetFaceElements (int Face, int *Elem1, int *Elem2) const; void GetFaceInfos (int Face, int *Inf1, int *Inf2) const; + void GetFaceInfos (int Face, int *Inf1, int *Inf2, int *NCFace) const; Geometry::Type GetFaceGeometryType(int Face) const; Element::Type GetFaceElementType(int Face) const; diff --git a/mesh/mesh_headers.hpp b/mesh/mesh_headers.hpp index 38e658cb19..eced12797e 100644 --- a/mesh/mesh_headers.hpp +++ b/mesh/mesh_headers.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/mesh/mesh_operators.cpp b/mesh/mesh_operators.cpp index d94961fe20..403b5ceec8 100644 --- a/mesh/mesh_operators.cpp +++ b/mesh/mesh_operators.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/mesh/mesh_operators.hpp b/mesh/mesh_operators.hpp index 3b822dd312..6bc2d449c8 100644 --- a/mesh/mesh_operators.hpp +++ b/mesh/mesh_operators.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/mesh/mesh_readers.cpp b/mesh/mesh_readers.cpp index d1d2c0568a..3be63f40d9 100644 --- a/mesh/mesh_readers.cpp +++ b/mesh/mesh_readers.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -12,10 +12,13 @@ #include "mesh_headers.hpp" #include "../fem/fem.hpp" #include "../general/text.hpp" +#include "../general/tinyxml2.h" #include "gmsh.hpp" #include #include +#include +#include #ifdef MFEM_USE_NETCDF #include "netcdf.h" @@ -28,9 +31,12 @@ namespace mfem bool Mesh::remove_unused_vertices = true; -void Mesh::ReadMFEMMesh(std::istream &input, bool mfem_v11, int &curved) +void Mesh::ReadMFEMMesh(std::istream &input, int version, int &curved) { - // Read MFEM mesh v1.0 format + // Read MFEM mesh v1.0 or v1.2 format + MFEM_VERIFY(version == 10 || version == 12, + "unknown MFEM mesh version"); + string ident; // read lines beginning with '#' (comments) @@ -63,24 +69,7 @@ void Mesh::ReadMFEMMesh(std::istream &input, bool mfem_v11, int &curved) } skip_comment_lines(input, '#'); - input >> ident; - - if (mfem_v11 && ident == "vertex_parents") - { - ncmesh = new NCMesh(this, &input); - // NOTE: the constructor above will call LoadVertexParents - - skip_comment_lines(input, '#'); - input >> ident; - - if (ident == "coarse_elements") - { - ncmesh->LoadCoarseElements(input); - - skip_comment_lines(input, '#'); - input >> ident; - } - } + input >> ident; // 'vertices' MFEM_VERIFY(ident == "vertices", "invalid mesh file"); input >> NumOfVertices; @@ -98,9 +87,6 @@ void Mesh::ReadMFEMMesh(std::istream &input, bool mfem_v11, int &curved) input >> vertices[j](i); } } - - // initialize vertex positions in NCMesh - if (ncmesh) { ncmesh->SetVertexPositions(vertices); } } else { @@ -373,6 +359,398 @@ const int Mesh::vtk_quadratic_hex[27] = 24, 22, 21, 23, 20, 25, 26 }; +void Mesh::CreateVTKMesh(const Vector &points, const Array &cell_data, + const Array &cell_offsets, + const Array &cell_types, + const Array &cell_attributes, + int &curved, int &read_gf, bool &finalize_topo) +{ + int np = points.Size()/3; + Dim = -1; + NumOfElements = cell_types.Size(); + elements.SetSize(NumOfElements); + + int order = -1; + bool legacy_elem = false, lagrange_elem = false; + + int j = 0; + for (int i = 0; i < NumOfElements; i++) + { + int ct = cell_types[i]; + Geometry::Type geom = VTKGeometry::GetMFEMGeometry(ct); + elements[i] = NewElement(geom); + if (cell_attributes.Size() > 0) + { + elements[i]->SetAttribute(cell_attributes[i]); + } + // VTK ordering of vertices is the same as MFEM ordering of vertices + // for all element types *except* prisms, which require a permutation + if (geom == Geometry::PRISM && ct != VTKGeometry::LAGRANGE_PRISM) + { + int prism_vertices[6]; + for (int k=0; k<6; ++k) + { + prism_vertices[k] = cell_data[j+VTKGeometry::PrismMap[k]]; + } + elements[i]->SetVertices(prism_vertices); + } + else + { + elements[i]->SetVertices(&cell_data[j]); + } + + int elem_dim = Geometry::Dimension[geom]; + int elem_order = VTKGeometry::GetOrder(ct, cell_offsets[i] - j); + + if (VTKGeometry::IsLagrange(ct)) { lagrange_elem = true; } + else { legacy_elem = true; } + + MFEM_VERIFY(Dim == -1 || Dim == elem_dim, + "Elements with different dimensions are not supported"); + MFEM_VERIFY(order == -1 || order == elem_order, + "Elements with different orders are not supported"); + MFEM_VERIFY(legacy_elem != lagrange_elem, + "Mixing of legacy and Lagrange cell types is not supported"); + Dim = elem_dim; + order = elem_order; + j = cell_offsets[i]; + } + + if (order == 1 && !lagrange_elem) + { + NumOfVertices = np; + vertices.SetSize(np); + for (int i = 0; i < np; i++) + { + vertices[i](0) = points(3*i+0); + vertices[i](1) = points(3*i+1); + vertices[i](2) = points(3*i+2); + } + // No boundary is defined in a VTK mesh + NumOfBdrElements = 0; + FinalizeTopology(); + CheckElementOrientation(true); + } + else + { + // The following section of code is shared for legacy quadratic and the + // Lagrange high order elements + curved = 1; + + // generate new enumeration for the vertices + Array pts_dof(np); + pts_dof = -1; + // mark vertex points + for (int i = 0; i < NumOfElements; i++) + { + int *v = elements[i]->GetVertices(); + int nv = elements[i]->GetNVertices(); + for (int j = 0; j < nv; j++) + { + if (pts_dof[v[j]] == -1) { pts_dof[v[j]] = 0; } + } + } + + // The following loop reorders pts_dofs so vertices are visited in + // canonical order + + // Keep the original ordering of the vertices + int i, n; + for (n = i = 0; i < np; i++) + { + if (pts_dof[i] != -1) + { + pts_dof[i] = n++; + } + } + // update the element vertices + for (int i = 0; i < NumOfElements; i++) + { + int *v = elements[i]->GetVertices(); + int nv = elements[i]->GetNVertices(); + for (int j = 0; j < nv; j++) + { + v[j] = pts_dof[v[j]]; + } + } + // Define the 'vertices' from the 'points' through the 'pts_dof' map + NumOfVertices = n; + vertices.SetSize(n); + for (int i = 0; i < np; i++) + { + int j = pts_dof[i]; + if (j != -1) + { + vertices[j](0) = points(3*i+0); + vertices[j](1) = points(3*i+1); + vertices[j](2) = points(3*i+2); + } + } + + // No boundary is defined in a VTK mesh + NumOfBdrElements = 0; + + // determine spaceDim based on min/max differences detected each dimension + if (vertices.Size() > 0) + { + double min_value, max_value; + for (int d=0; d<3; ++d) + { + min_value = max_value = vertices[0](d); + for (int i = 1; i < vertices.Size(); i++) + { + min_value = std::min(min_value,vertices[i](d)); + max_value = std::max(max_value,vertices[i](d)); + if (min_value != max_value) + { + spaceDim++; + break; + } + } + } + } + // Generate faces and edges so that we can define + // FE space on the mesh + FinalizeTopology(); + + FiniteElementCollection *fec; + FiniteElementSpace *fes; + if (legacy_elem) + { + // Define quadratic FE space + fec = new QuadraticFECollection; + fes = new FiniteElementSpace(this, fec, spaceDim); + Nodes = new GridFunction(fes); + Nodes->MakeOwner(fec); // Nodes will destroy 'fec' and 'fes' + own_nodes = 1; + + // Map vtk points to edge/face/element dofs + Array dofs; + for (int i = 0; i < NumOfElements; i++) + { + fes->GetElementDofs(i, dofs); + const int *vtk_mfem; + switch (elements[i]->GetGeometryType()) + { + case Geometry::TRIANGLE: + case Geometry::SQUARE: + vtk_mfem = vtk_quadratic_hex; break; // identity map + case Geometry::TETRAHEDRON: + vtk_mfem = vtk_quadratic_tet; break; + case Geometry::CUBE: + vtk_mfem = vtk_quadratic_hex; break; + case Geometry::PRISM: + vtk_mfem = vtk_quadratic_wedge; break; + default: + vtk_mfem = NULL; // suppress a warning + break; + } + + int offset = (i == 0) ? 0 : cell_offsets[i-1]; + for (int j = 0; j < dofs.Size(); j++) + { + if (pts_dof[cell_data[offset+j]] == -1) + { + pts_dof[cell_data[offset+j]] = dofs[vtk_mfem[j]]; + } + else + { + if (pts_dof[cell_data[offset+j]] != dofs[vtk_mfem[j]]) + { + MFEM_ABORT("VTK mesh: inconsistent quadratic mesh!"); + } + } + } + } + } + else + { + // Define H1 FE space + fec = new H1_FECollection(order,Dim,BasisType::ClosedUniform); + fes = new FiniteElementSpace(this, fec, spaceDim); + Nodes = new GridFunction(fes); + Nodes->MakeOwner(fec); // Nodes will destroy 'fec' and 'fes' + own_nodes = 1; + Array dofs; + + std::map> vtk_inv_maps; + std::map*> lex_orderings; + + int i, n; + for (n = i = 0; i < NumOfElements; i++) + { + Geometry::Type geom = GetElementBaseGeometry(i); + fes->GetElementDofs(i, dofs); + + Array &vtk_inv_map = vtk_inv_maps[geom]; + if (vtk_inv_map.Size() == 0) + { + Array vtk_map; + CreateVTKElementConnectivity(vtk_map, geom, order); + vtk_inv_map.SetSize(vtk_map.Size()); + for (int j=0; j *&lex_ordering = lex_orderings[geom]; + if (!lex_ordering) + { + const FiniteElement *fe = fes->GetFE(i); + const NodalFiniteElement *nodal_fe = + dynamic_cast(fe); + MFEM_ASSERT(nodal_fe != NULL, "Unsupported element type"); + lex_ordering = &nodal_fe->GetLexicographicOrdering(); + } + + for (int lex_idx = 0; lex_idx < dofs.Size(); lex_idx++) + { + int mfem_idx = (*lex_ordering)[lex_idx]; + int vtk_idx = vtk_inv_map[lex_idx]; + int pt_idx = cell_data[n + vtk_idx]; + if (pts_dof[pt_idx] == -1) + { + pts_dof[pt_idx] = dofs[mfem_idx]; + } + else + { + if (pts_dof[pt_idx] != dofs[mfem_idx]) + { + MFEM_ABORT("VTK mesh: inconsistent Lagrange mesh!"); + } + } + } + n += dofs.Size(); + } + } + // Define the 'Nodes' from the 'points' through the 'pts_dof' map + Array dofs; + for (int i = 0; i < np; i++) + { + dofs.SetSize(1); + if (pts_dof[i] != -1) + { + dofs[0] = pts_dof[i]; + fes->DofsToVDofs(dofs); + for (int d = 0; d < dofs.Size(); d++) + { + (*Nodes)(dofs[d]) = points(3*i+d); + } + } + } + read_gf = 0; + } +} + +void Mesh::ReadXML_VTKMesh(std::istream &input, int &curved, int &read_gf, + bool &finalize_topo) +{ + using namespace tinyxml2; + + const char *erstr = "XML parsing error"; + + // Read entire stream into buffer + std::istreambuf_iterator eos; + std::vector buf(std::istreambuf_iterator(input), eos); + buf.push_back('\0'); // null-terminate buffer + + XMLDocument xml; + xml.Parse(buf.data()); + MFEM_VERIFY(xml.ErrorID() == XML_SUCCESS, erstr); + + const XMLElement *vtkfile = xml.FirstChildElement(); + MFEM_VERIFY(vtkfile, erstr); + MFEM_VERIFY(std::string(vtkfile->Name()) == "VTKFile", erstr); + const XMLElement *vtu = vtkfile->FirstChildElement(); + MFEM_VERIFY(vtu, erstr); + MFEM_VERIFY(std::string(vtu->Name()) == "UnstructuredGrid", erstr); + + // Count the number of points and cells + const XMLElement *piece = vtu->FirstChildElement(); + MFEM_VERIFY(std::string(piece->Name()) == "Piece", erstr); + MFEM_VERIFY(piece->NextSiblingElement() == NULL, + "XML VTK meshes with more than one Piece are not supported"); + int npts = piece->IntAttribute("NumberOfPoints"); + int ncells = piece->IntAttribute("NumberOfCells"); + + // Read the points + Vector points(3*npts); + const XMLElement *pts_xml; + for (pts_xml = piece->FirstChildElement(); + pts_xml != NULL; + pts_xml = pts_xml->NextSiblingElement()) + { + if (std::string(pts_xml->Name()) == "Points") + { + const XMLElement *pts_data = pts_xml->FirstChildElement(); + MFEM_VERIFY(std::string(pts_data->Name()) == "DataArray", erstr); + MFEM_VERIFY(std::string(pts_data->Attribute("Name")) == "Points", + erstr); + MFEM_VERIFY(pts_data->IntAttribute("NumberOfComponents") == 3, + "XML VTK Points DataArray must have 3 components"); + const char *pts_txt = pts_data->GetText(); + MFEM_VERIFY(pts_txt != NULL, erstr); + std::istringstream pts_stream(pts_txt); + points.Load(pts_stream, 3*npts); + break; + } + } + if (pts_xml == NULL) { MFEM_ABORT(erstr); } + + // Read the cells + Array cell_data, cell_offsets, cell_types; + const XMLElement *cells_xml; + for (cells_xml = piece->FirstChildElement(); + cells_xml != NULL; + cells_xml = cells_xml->NextSiblingElement()) + { + if (std::string(cells_xml->Name()) == "Cells") + { + const char *cell_data_txt = NULL; + for (const XMLElement *data_xml = cells_xml->FirstChildElement(); + data_xml != NULL; + data_xml = data_xml->NextSiblingElement()) + { + MFEM_VERIFY(std::string(data_xml->Name()) == "DataArray", erstr); + std::string data_name(data_xml->Attribute("Name")); + const char *data_txt = data_xml->GetText(); + MFEM_VERIFY(data_txt != NULL, erstr); + if (data_name == "offsets") + { + std::istringstream data_stream(data_txt); + cell_offsets.Load(ncells, data_stream); + } + else if (data_name == "types") + { + std::istringstream data_stream(data_txt); + cell_types.Load(ncells, data_stream); + } + else if (data_name == "connectivity") + { + // Have to read the connectivity after the offsets, because we + // don't know how many points to read until we have the offsets + // (size of connectivity array is equal to the last offset), so + // store the data pointer and read this array later. + cell_data_txt = data_txt; + } + } + MFEM_VERIFY(cell_offsets.Size() == ncells, erstr); + MFEM_VERIFY(cell_types.Size() == ncells, erstr); + MFEM_VERIFY(cell_data_txt != NULL, erstr); + int cell_data_size = cell_offsets.Last(); + std::istringstream cell_data_stream(cell_data_txt); + cell_data.Load(cell_data_size, cell_data_stream); + break; + } + } + if (cells_xml == NULL) { MFEM_ABORT(erstr); } + + // Currently don't support reading cell attributes from VTK mesh + Array cell_attributes; + CreateVTKMesh(points, cell_data, cell_offsets, cell_types, cell_attributes, + curved, read_gf, finalize_topo); +} + void Mesh::ReadVTKMesh(std::istream &input, int &curved, int &read_gf, bool &finalize_topo) { @@ -382,8 +760,6 @@ void Mesh::ReadVTKMesh(std::istream &input, int &curved, int &read_gf, // * https://lorensen.github.io/VTKExamples/site/VTKFileFormats // * https://www.kitware.com/products/books/VTKUsersGuide.pdf - int i, j, n, attr; - string buff; getline(input, buff); // comment line getline(input, buff); @@ -412,141 +788,78 @@ void Mesh::ReadVTKMesh(std::istream &input, int &curved, int &read_gf, } } while (buff != "POINTS"); - int np = 0; + Vector points; + int np; + input >> np >> ws; + getline(input, buff); // "double" + points.Load(input, 3*np); + + //skip metadata + // Looks like: + // METADATA + //INFORMATION 2 + //NAME L2_NORM_RANGE LOCATION vtkDataArray + //DATA 2 0 5.19615 + //NAME L2_NORM_FINITE_RANGE LOCATION vtkDataArray + //DATA 2 0 5.19615 + do { - input >> np >> ws; - points.SetSize(3*np); - getline(input, buff); // "double" - for (i = 0; i < points.Size(); i++) + input >> buff; + if (!input.good()) { - input >> points(i); + MFEM_ABORT("VTK mesh does not have CELLS data!"); } } + while (buff != "CELLS"); // Read the cells - NumOfElements = n = 0; - Array cells_data; - input >> ws >> buff; + Array cell_data, cell_offsets; if (buff == "CELLS") { - input >> NumOfElements >> n >> ws; - cells_data.SetSize(n); - for (i = 0; i < n; i++) + int ncells, n; + input >> ncells >> n >> ws; + cell_offsets.SetSize(ncells); + cell_data.SetSize(n - ncells); + int offset = 0; + for (int i=0; i> cells_data[i]; + int nv; + input >> nv; + cell_offsets[i] = offset + nv; + for (int j=0; j> cell_data[offset + j]; + } + offset += nv; } } // Read the cell types - Dim = -1; - int order = -1; input >> ws >> buff; + Array cell_types; + int ncells; if (buff == "CELL_TYPES") { - input >> NumOfElements; - elements.SetSize(NumOfElements); - for (j = i = 0; i < NumOfElements; i++) - { - int ct, elem_dim, elem_order = 1; - input >> ct; - switch (ct) - { - case 5: // triangle - elem_dim = 2; - elements[i] = new Triangle(&cells_data[j+1]); - break; - case 9: // quadrilateral - elem_dim = 2; - elements[i] = new Quadrilateral(&cells_data[j+1]); - break; - case 10: // tetrahedron - elem_dim = 3; -#ifdef MFEM_USE_MEMALLOC - elements[i] = TetMemory.Alloc(); - elements[i]->SetVertices(&cells_data[j+1]); -#else - elements[i] = new Tetrahedron(&cells_data[j+1]); -#endif - break; - case 12: // hexahedron - elem_dim = 3; - elements[i] = new Hexahedron(&cells_data[j+1]); - break; - case 13: // wedge - elem_dim = 3; - // switch between vtk vertex ordering and mfem vertex ordering: - // swap vertices (1,2) and (4,5) - elements[i] = - new Wedge(cells_data[j+1], cells_data[j+3], cells_data[j+2], - cells_data[j+4], cells_data[j+6], cells_data[j+5]); - break; - - case 22: // quadratic triangle - elem_dim = 2; - elem_order = 2; - elements[i] = new Triangle(&cells_data[j+1]); - break; - case 28: // biquadratic quadrilateral - elem_dim = 2; - elem_order = 2; - elements[i] = new Quadrilateral(&cells_data[j+1]); - break; - case 24: // quadratic tetrahedron - elem_dim = 3; - elem_order = 2; -#ifdef MFEM_USE_MEMALLOC - elements[i] = TetMemory.Alloc(); - elements[i]->SetVertices(&cells_data[j+1]); -#else - elements[i] = new Tetrahedron(&cells_data[j+1]); -#endif - break; - case 32: // biquadratic-quadratic wedge - elem_dim = 3; - elem_order = 2; - // switch between vtk vertex ordering and mfem vertex ordering: - // swap vertices (1,2) and (4,5) - elements[i] = - new Wedge(cells_data[j+1], cells_data[j+3], cells_data[j+2], - cells_data[j+4], cells_data[j+6], cells_data[j+5]); - break; - case 29: // triquadratic hexahedron - elem_dim = 3; - elem_order = 2; - elements[i] = new Hexahedron(&cells_data[j+1]); - break; - default: - MFEM_ABORT("VTK mesh : cell type " << ct << " is not supported!"); - return; - } - MFEM_VERIFY(Dim == -1 || Dim == elem_dim, - "elements with different dimensions are not supported"); - MFEM_VERIFY(order == -1 || order == elem_order, - "elements with different orders are not supported"); - Dim = elem_dim; - order = elem_order; - j += cells_data[j] + 1; - } + input >> ncells; + cell_types.Load(ncells, input); } - // Read attributes + // Read cell attributes streampos sp = input.tellg(); input >> ws >> buff; + Array cell_attributes; if (buff == "CELL_DATA") { + int n; input >> n >> ws; getline(input, buff); filter_dos(buff); // "SCALARS material dataType numComp" - if (!strncmp(buff.c_str(), "SCALARS material", 16)) + if (buff.rfind("SCALARS material") == 0) { getline(input, buff); // "LOOKUP_TABLE default" - for (i = 0; i < NumOfElements; i++) - { - input >> attr; - elements[i]->SetAttribute(attr); - } + cell_attributes.Load(ncells, input); } else { @@ -558,138 +871,9 @@ void Mesh::ReadVTKMesh(std::istream &input, int &curved, int &read_gf, input.seekg(sp); } - if (order == 1) - { - cells_data.DeleteAll(); - NumOfVertices = np; - vertices.SetSize(np); - for (i = 0; i < np; i++) - { - vertices[i](0) = points(3*i+0); - vertices[i](1) = points(3*i+1); - vertices[i](2) = points(3*i+2); - } - points.Destroy(); - - // No boundary is defined in a VTK mesh - NumOfBdrElements = 0; - } - else if (order == 2) - { - curved = 1; - - // generate new enumeration for the vertices - Array pts_dof(np); - pts_dof = -1; - for (n = i = 0; i < NumOfElements; i++) - { - int *v = elements[i]->GetVertices(); - int nv = elements[i]->GetNVertices(); - for (j = 0; j < nv; j++) - if (pts_dof[v[j]] == -1) - { - pts_dof[v[j]] = n++; - } - } - // keep the original ordering of the vertices - for (n = i = 0; i < np; i++) - if (pts_dof[i] != -1) - { - pts_dof[i] = n++; - } - // update the element vertices - for (i = 0; i < NumOfElements; i++) - { - int *v = elements[i]->GetVertices(); - int nv = elements[i]->GetNVertices(); - for (j = 0; j < nv; j++) - { - v[j] = pts_dof[v[j]]; - } - } - // Define the 'vertices' from the 'points' through the 'pts_dof' map - NumOfVertices = n; - vertices.SetSize(n); - for (i = 0; i < np; i++) - { - if ((j = pts_dof[i]) != -1) - { - vertices[j](0) = points(3*i+0); - vertices[j](1) = points(3*i+1); - vertices[j](2) = points(3*i+2); - } - } - - // No boundary is defined in a VTK mesh - NumOfBdrElements = 0; - - // Generate faces and edges so that we can define quadratic - // FE space on the mesh - FinalizeTopology(); - finalize_topo = false; - - // Define quadratic FE space - FiniteElementCollection *fec = new QuadraticFECollection; - FiniteElementSpace *fes = new FiniteElementSpace(this, fec, Dim); - Nodes = new GridFunction(fes); - Nodes->MakeOwner(fec); // Nodes will destroy 'fec' and 'fes' - own_nodes = 1; - - // Map vtk points to edge/face/element dofs - Array dofs; - for (n = i = 0; i < NumOfElements; i++) - { - fes->GetElementDofs(i, dofs); - const int *vtk_mfem; - switch (elements[i]->GetGeometryType()) - { - case Geometry::TRIANGLE: - case Geometry::SQUARE: - vtk_mfem = vtk_quadratic_hex; break; // identity map - case Geometry::TETRAHEDRON: - vtk_mfem = vtk_quadratic_tet; break; - case Geometry::CUBE: - vtk_mfem = vtk_quadratic_hex; break; - case Geometry::PRISM: - vtk_mfem = vtk_quadratic_wedge; break; - default: - vtk_mfem = NULL; // suppress a warning - break; - } - - for (n++, j = 0; j < dofs.Size(); j++, n++) - { - if (pts_dof[cells_data[n]] == -1) - { - pts_dof[cells_data[n]] = dofs[vtk_mfem[j]]; - } - else - { - if (pts_dof[cells_data[n]] != dofs[vtk_mfem[j]]) - { - MFEM_ABORT("VTK mesh : inconsistent quadratic mesh!"); - } - } - } - } - - // Define the 'Nodes' from the 'points' through the 'pts_dof' map - for (i = 0; i < np; i++) - { - dofs.SetSize(1); - if ((dofs[0] = pts_dof[i]) != -1) - { - fes->DofsToVDofs(dofs); - for (j = 0; j < dofs.Size(); j++) - { - (*Nodes)(dofs[j]) = points(3*i+j); - } - } - } - - read_gf = 0; - } -} + CreateVTKMesh(points, cell_data, cell_offsets, cell_types, cell_attributes, + curved, read_gf, finalize_topo); +} // end ReadVTKMesh void Mesh::ReadNURBSMesh(std::istream &input, int &curved, int &read_gf) { @@ -715,8 +899,8 @@ void Mesh::ReadNURBSMesh(std::istream &input, int &curved, int &read_gf) NURBSext->SetCoordsFromPatches(*Nodes); own_nodes = 1; read_gf = 0; - int vd = Nodes->VectorDim(); - for (int i = 0; i < vd; i++) + spaceDim = Nodes->VectorDim(); + for (int i = 0; i < spaceDim; i++) { Vector vert_val; Nodes->GetNodalValues(vert_val, i+1); @@ -2019,9 +2203,15 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf) for (int i = 0; i < num_per_ent; i++) { getline(input, buff); // Read and ignore entity dimension and tags - getline(input, buff); // Read and ignore affine mapping - // Read master/slave vertex pairs - input >> num_nodes; + getline(input, buff); // If affine mapping exist, read and ignore + if (!strncmp(buff.c_str(), "Affine", 6)) + { + input >> num_nodes; + } + else + { + num_nodes = atoi(buff.c_str()); + } for (int j=0; j> slave >> master; @@ -2030,6 +2220,34 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf) getline(input, buff); // Read end-of-line } + // Follow existing long chains of slave->master in v2v array. + // Upon completion of this loop, each v2v[slave] will point to a true + // master vertex. This algorithm is useful for periodicity defined in + // multiple directions. + for (int slave = 0; slave < v2v.Size(); slave++) + { + int master = v2v[slave]; + if (master != slave) + { + // This loop will end if it finds a circular dependency. + while (v2v[master] != master && master != slave) + { + master = v2v[master]; + } + if (master == slave) + { + // if master and slave are the same vertex, circular dependency + // exists. We need to fix the problem, we choose slave. + v2v[slave] = slave; + } + else + { + // the long chain has ended on the true master vertex. + v2v[slave] = master; + } + } + } + // Convert nodes to discontinuous GridFunction (if they aren't already) if (mesh_order == 1) { diff --git a/mesh/mesquite.cpp b/mesh/mesquite.cpp index 55589f2849..cb52b91930 100644 --- a/mesh/mesquite.cpp +++ b/mesh/mesquite.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/mesh/mesquite.hpp b/mesh/mesquite.hpp index 46668ca0f2..5b0bf8661d 100644 --- a/mesh/mesquite.hpp +++ b/mesh/mesquite.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/mesh/ncmesh.cpp b/mesh/ncmesh.cpp index 2e40109516..f5c22e5719 100644 --- a/mesh/ncmesh.cpp +++ b/mesh/ncmesh.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -10,16 +10,13 @@ // CONTRIBUTING.md for details. #include "mesh_headers.hpp" -#include "../fem/fem.hpp" #include "../general/sort_pairs.hpp" +#include "../general/text.hpp" #include #include -#include // INT_MAX #include -#include // debug - #include "ncmesh_tables.hpp" namespace mfem @@ -27,10 +24,21 @@ namespace mfem NCMesh::GeomInfo NCMesh::GI[Geometry::NumGeom]; -void NCMesh::GeomInfo::Initialize(const mfem::Element* elem) +void NCMesh::GeomInfo::InitGeom(Geometry::Type geom) { if (initialized) { return; } + mfem::Element *elem = NULL; + switch (geom) + { + case Geometry::CUBE: elem = new Hexahedron; break; + case Geometry::PRISM: elem = new Wedge; break; + case Geometry::SQUARE: elem = new Quadrilateral; break; + case Geometry::TRIANGLE: elem = new Triangle; break; + case Geometry::TETRAHEDRON: elem = new Tetrahedron; break; + default: MFEM_ABORT("unsupported geometry " << geom); + } + nv = elem->GetNVertices(); ne = elem->GetNEdges(); nf = elem->GetNFaces(); @@ -61,66 +69,31 @@ void NCMesh::GeomInfo::Initialize(const mfem::Element* elem) // make a degenerate face faces[i][0] = faces[i][1] = edges[i][0]; faces[i][2] = faces[i][3] = edges[i][1]; + nfv[i] = 2; } nf = ne; } + delete elem; initialized = true; } +static void CheckSupportedGeom(Geometry::Type geom) +{ + MFEM_VERIFY(geom == Geometry::TRIANGLE || geom == Geometry::SQUARE || + geom == Geometry::CUBE || geom == Geometry::PRISM || + geom == Geometry::TETRAHEDRON, + "Element type " << geom << " is not supported by NCMesh."); +} -NCMesh::NCMesh(const Mesh *mesh, std::istream *vertex_parents) +NCMesh::NCMesh(const Mesh *mesh) : shadow(1024, 2048) { Dim = mesh->Dimension(); spaceDim = mesh->SpaceDimension(); - - // assume the mesh is anisotropic if we're loading a file - Iso = vertex_parents ? false : true; - - // examine elements and reserve the first node IDs for vertices - // (note: 'mesh' may not have vertices defined yet, e.g., on load) - int max_id = -1; - for (int i = 0; i < mesh->GetNE(); i++) - { - const mfem::Element *elem = mesh->GetElement(i); - const int *v = elem->GetVertices(), nv = elem->GetNVertices(); - for (int j = 0; j < nv; j++) - { - max_id = std::max(max_id, v[j]); - } - } - for (int id = 0; id <= max_id; id++) - { - // top-level nodes are special: id == p1 == p2 == orig. vertex id - int node = nodes.GetId(id, id); - MFEM_CONTRACT_VAR(node); - MFEM_ASSERT(node == id, ""); - } - - // if a mesh file is being read, load the vertex hierarchy now; - // 'vertex_parents' must be at the appropriate section in the mesh file - if (vertex_parents) - { - LoadVertexParents(*vertex_parents); - } - // alternatively, the user might have initialized hanging nodes with - // Mesh::AddVertexParents; copy the hierarchy now - else if (mesh->tmp_vertex_parents.Size()) - { - for (const auto &triple : mesh->tmp_vertex_parents) - { - nodes.Reparent(triple.one, triple.two, triple.three); - } - } - else // otherwise we just assume a standard conforming coarse mesh - { - top_vertex_pos.SetSize(3*mesh->GetNV()); - for (int i = 0; i < mesh->GetNV(); i++) - { - std::memcpy(&top_vertex_pos[3*i], mesh->GetVertex(i), 3*sizeof(double)); - } - } + MyRank = 0; + Iso = true; + Legacy = false; // create the NCMesh::Element struct for each Mesh element for (int i = 0; i < mesh->GetNE(); i++) @@ -128,15 +101,10 @@ NCMesh::NCMesh(const Mesh *mesh, std::istream *vertex_parents) const mfem::Element *elem = mesh->GetElement(i); Geometry::Type geom = elem->GetGeometryType(); - MFEM_VERIFY(geom == Geometry::TRIANGLE || geom == Geometry::SQUARE || - geom == Geometry::CUBE || geom == Geometry::PRISM || - geom == Geometry::TETRAHEDRON, - "Element type " << geom << " not supported by NCMesh."); + CheckSupportedGeom(geom); + GI[geom].InitGeom(geom); - // initialize edge/face tables for this type of element - GI[geom].Initialize(elem); - - // create our Element struct for this element + // create NCMesh::Element for this mfem::Element int root_id = AddElement(Element(geom, elem->GetAttribute())); MFEM_ASSERT(root_id == i, ""); Element &root_elem = elements[root_id]; @@ -144,15 +112,33 @@ NCMesh::NCMesh(const Mesh *mesh, std::istream *vertex_parents) const int *v = elem->GetVertices(); for (int j = 0; j < GI[geom].nv; j++) { - root_elem.node[j] = v[j]; + int id = v[j]; + root_elem.node[j] = id; + nodes.Alloc(id, id, id); + // NOTE: top-level nodes are special: id == p1 == p2 == orig. vertex id } + } + // if the user initialized any hanging nodes with Mesh::AddVertexParents, + // copy the hierarchy now + if (mesh->tmp_vertex_parents.Size()) + { + for (const auto &triple : mesh->tmp_vertex_parents) + { + nodes.Reparent(triple.one, triple.two, triple.three); + } + } + + // create edge nodes and faces + nodes.UpdateUnused(); + for (int i = 0; i < elements.Size(); i++) + { // increase reference count of all nodes the element is using // (NOTE: this will also create and reference all edge nodes and faces) - ReferenceElement(root_id); + ReferenceElement(i); // make links from faces back to the element - RegisterFaces(root_id); + RegisterFaces(i); } // store boundary element attributes @@ -185,10 +171,17 @@ NCMesh::NCMesh(const Mesh *mesh, std::istream *vertex_parents) } } - if (!vertex_parents) // i.e., not loading mesh from a file + // copy top-level vertex coordinates (leave empty if the mesh is curved) + if (!mesh->Nodes) { - InitRootState(mesh->GetNE()); + coordinates.SetSize(3*mesh->GetNV()); + for (int i = 0; i < mesh->GetNV(); i++) + { + std::memcpy(&coordinates[3*i], mesh->GetVertex(i), 3*sizeof(double)); + } } + + InitRootState(mesh->GetNE()); InitGeomFlags(); Update(); @@ -197,8 +190,10 @@ NCMesh::NCMesh(const Mesh *mesh, std::istream *vertex_parents) NCMesh::NCMesh(const NCMesh &other) : Dim(other.Dim) , spaceDim(other.spaceDim) + , MyRank(other.MyRank) , Iso(other.Iso) , Geoms(other.Geoms) + , Legacy(other.Legacy) , nodes(other.nodes) , faces(other.faces) , elements(other.elements) @@ -206,7 +201,7 @@ NCMesh::NCMesh(const NCMesh &other) { other.free_element_ids.Copy(free_element_ids); other.root_state.Copy(root_state); - other.top_vertex_pos.Copy(top_vertex_pos); + other.coordinates.Copy(coordinates); Update(); } @@ -234,22 +229,16 @@ void NCMesh::Update() NCMesh::~NCMesh() { #ifdef MFEM_DEBUG -#ifdef MFEM_USE_MPI - // in parallel, update 'leaf_elements' - for (int i = 0; i < elements.Size(); i++) - { - elements[i].rank = 0; // make sure all leaves are in leaf_elements - } - UpdateLeafElements(); -#endif - // sign off of all faces and nodes Array elemFaces; - for (int i = 0; i < leaf_elements.Size(); i++) + for (int i = 0; i < elements.Size(); i++) { - elemFaces.SetSize(0); - UnreferenceElement(leaf_elements[i], elemFaces); - DeleteUnusedFaces(elemFaces); + if (elements[i].IsLeaf()) + { + elemFaces.SetSize(0); + UnreferenceElement(i, elemFaces); + DeleteUnusedFaces(elemFaces); + } } // NOTE: in release mode, we just throw away all faces and nodes at once #endif @@ -257,7 +246,7 @@ NCMesh::~NCMesh() NCMesh::Node::~Node() { - MFEM_ASSERT(!vert_refc && !edge_refc, "node was not unreffed properly, " + MFEM_ASSERT(!vert_refc && !edge_refc, "node was not unreferenced properly, " "vert_refc: " << (int) vert_refc << ", edge_refc: " << (int) edge_refc); } @@ -1687,7 +1676,7 @@ void NCMesh::DerefineElement(int elem) childFaces.SetSize(0); // delete children, determine rank - el.rank = INT_MAX; + el.rank = std::numeric_limits::max(); for (int i = 0; i < 8 && child[i] >= 0; i++) { el.rank = std::min(el.rank, elements[child[i]].rank); @@ -1853,44 +1842,50 @@ void NCMesh::SetDerefMatrixCodes(int parent, Array &fine_coarse) //// Mesh Interface //////////////////////////////////////////////////////////// -void NCMesh::UpdateVertices() -{ - // (overridden in ParNCMesh to assign special indices to ghost vertices) - NVertices = 0; - for (node_iterator node = nodes.begin(); node != nodes.end(); ++node) - { - if (node->HasVertex()) { node->vert_index = NVertices++; } - } - - vertex_nodeId.SetSize(NVertices); - - NVertices = 0; - for (node_iterator node = nodes.begin(); node != nodes.end(); ++node) - { - if (node->HasVertex()) { vertex_nodeId[NVertices++] = node.index(); } - } -} - -void NCMesh::CollectLeafElements(int elem, int state) +void NCMesh::CollectLeafElements(int elem, int state, Array &ghosts, + int &counter) { Element &el = elements[elem]; if (!el.ref_type) { - if (el.rank >= 0) // skip elements beyond ghost layer in parallel + if (el.rank >= 0) // skip elements beyond the ghost layer in parallel { - leaf_elements.Append(elem); + if (el.rank == MyRank) + { + leaf_elements.Append(elem); + } + else + { + // in parallel (or in serial loading a parallel file), collect + // elements of neighboring ranks in a separate array + ghosts.Append(elem); + } + + // assign the SFC index (temporarily, will be replaced by Mesh index) + el.index = counter++; + } + else + { + // elements beyond the ghost layer are invalid and don't appear in + // 'leaf_elements' (also for performance reasons) + el.index = -1; } } else { - // try to order elements along a space-filling curve + // in non-leaf elements, the 'rank' and 'index' members have no meaning + el.rank = -1; + el.index = -1; + + // recurse to subtrees; try to order leaf elements along a space-filling + // curve by changing the order the children are visited at each level if (el.Geom() == Geometry::SQUARE && el.ref_type == 3) { for (int i = 0; i < 4; i++) { int ch = quad_hilbert_child_order[state][i]; int st = quad_hilbert_child_state[state][i]; - CollectLeafElements(el.child[ch], st); + CollectLeafElements(el.child[ch], st, ghosts, counter); } } else if (el.Geom() == Geometry::CUBE && el.ref_type == 7) @@ -1899,40 +1894,229 @@ void NCMesh::CollectLeafElements(int elem, int state) { int ch = hex_hilbert_child_order[state][i]; int st = hex_hilbert_child_state[state][i]; - CollectLeafElements(el.child[ch], st); + CollectLeafElements(el.child[ch], st, ghosts, counter); } } - else + else // no SFC tables yet for remaining cases { for (int i = 0; i < 8; i++) { - if (el.child[i] >= 0) { CollectLeafElements(el.child[i], state); } + if (el.child[i] >= 0) + { + CollectLeafElements(el.child[i], state, ghosts, counter); + } } } } - el.index = -1; } void NCMesh::UpdateLeafElements() { + Array ghosts; + // collect leaf elements from all roots leaf_elements.SetSize(0); - for (int i = 0; i < root_state.Size(); i++) + for (int i = 0, counter = 0; i < root_state.Size(); i++) { - CollectLeafElements(i, root_state[i]); + CollectLeafElements(i, root_state[i], ghosts, counter); } - AssignLeafIndices(); -} -void NCMesh::AssignLeafIndices() -{ - // (overridden in ParNCMesh to handle ghost elements) + NElements = leaf_elements.Size(); + NGhostElements = ghosts.Size(); + + // append ghost elements at the end of 'leaf_element' (if any) + // and assign the final (Mesh) indices of leaves + leaf_elements.Append(ghosts); + leaf_sfc_index.SetSize(leaf_elements.Size()); + for (int i = 0; i < leaf_elements.Size(); i++) { - elements[leaf_elements[i]].index = i; + Element &el = elements[leaf_elements[i]]; + leaf_sfc_index[i] = el.index; + el.index = i; } } +void NCMesh::UpdateVertices() +{ +#ifndef MFEM_NCMESH_OLD_VERTEX_ORDERING + // This method assigns indices to vertices (Node::vert_index) that will + // be seen by the Mesh class and the rest of MFEM. We must be careful to: + // + // 1. Stay compatible with the conforming code, which expects top-level + // (original) vertices to be indexed first, otherwise GridFunctions + // defined on a conforming mesh would no longer be valid when the + // mesh is converted to an NC mesh. + // + // 2. Make sure serial NCMesh is compatible with the parallel ParNCMesh, + // so it is possible to read parallel partial solutions in serial code + // (e.g., serial GLVis). This means handling ghost elements, if present. + // + // 3. Assign vertices in a globally consistent order for parallel meshes: + // if two vertices i,j are shared by two ranks r1,r2, and ivert_index = -4; // assume beyond ghost layer + } + + for (int i = 0; i < leaf_elements.Size(); i++) + { + Element &el = elements[leaf_elements[i]]; + for (int j = 0; j < GI[el.Geom()].nv; j++) + { + Node &nd = nodes[el.node[j]]; + if (el.rank == MyRank) + { + if (nd.p1 == nd.p2) // local top-level vertex + { + if (nd.vert_index < -1) { nd.vert_index = -1; } + } + else // local non-top-level vertex + { + if (nd.vert_index < -2) { nd.vert_index = -2; } + } + } + else // ghost vertex + { + if (nd.vert_index < -3) { nd.vert_index = -3; } + } + } + } + + // STEP 2: assign indices of top-level local vertices, in original order + + NVertices = 0; + for (auto node = nodes.begin(); node != nodes.end(); ++node) + { + if (node->vert_index == -1) + { + node->vert_index = NVertices++; + } + } + + // STEP 3: go over all elements (local and ghost) in SFC order and assign + // remaining local vertices in that order. + + Array sfc_order(leaf_elements.Size()); + for (int i = 0; i < sfc_order.Size(); i++) + { + sfc_order[leaf_sfc_index[i]] = leaf_elements[i]; + } + + for (int i = 0; i < sfc_order.Size(); i++) + { + const Element &el = elements[sfc_order[i]]; + for (int j = 0; j < GI[el.Geom()].nv; j++) + { + Node &nd = nodes[el.node[j]]; + if (nd.vert_index == -2) { nd.vert_index = NVertices++; } + } + } + + // STEP 4: create the mapping from Mesh vertex index to NCMesh node index + + vertex_nodeId.SetSize(NVertices); + for (auto node = nodes.begin(); node != nodes.end(); ++node) + { + if (node->HasVertex() && node->vert_index >= 0) + { + MFEM_ASSERT(node->vert_index < vertex_nodeId.Size(), ""); + vertex_nodeId[node->vert_index] = node.index(); + } + } + + // STEP 5: assign remaining ghost vertices, ignore vertices beyond the + // ghost layer + + NGhostVertices = 0; + for (int i = 0; i < sfc_order.Size(); i++) + { + const Element &el = elements[sfc_order[i]]; + for (int j = 0; j < GI[el.Geom()].nv; j++) + { + Node &nd = nodes[el.node[j]]; + if (nd.vert_index == -3) + { + nd.vert_index = NVertices + NGhostVertices++; + } + } + } + +#else // old ordering for debugging/testing only + bool parallel = false; +#ifdef MFEM_USE_MPI + if (dynamic_cast(this)) { parallel = true; } +#endif + + if (!parallel) + { + NVertices = 0; + for (auto node = nodes.begin(); node != nodes.end(); ++node) + { + if (node->HasVertex()) { node->vert_index = NVertices++; } + } + + vertex_nodeId.SetSize(NVertices); + + NVertices = 0; + for (auto node = nodes.begin(); node != nodes.end(); ++node) + { + if (node->HasVertex()) { vertex_nodeId[NVertices++] = node.index(); } + } + } + else + { + for (auto node = nodes.begin(); node != nodes.end(); ++node) + { + if (node->HasVertex()) { node->vert_index = -1; } + } + + NVertices = 0; + for (int i = 0; i < leaf_elements.Size(); i++) + { + Element &el = elements[leaf_elements[i]]; + if (el.rank == MyRank) + { + for (int j = 0; j < GI[el.Geom()].nv; j++) + { + int &vindex = nodes[el.node[j]].vert_index; + if (vindex < 0) { vindex = NVertices++; } + } + } + } + + vertex_nodeId.SetSize(NVertices); + for (auto node = nodes.begin(); node != nodes.end(); ++node) + { + if (node->HasVertex() && node->vert_index >= 0) + { + vertex_nodeId[node->vert_index] = node.index(); + } + } + + NGhostVertices = 0; + for (auto node = nodes.begin(); node != nodes.end(); ++node) + { + if (node->HasVertex() && node->vert_index < 0) + { + node->vert_index = NVertices + (NGhostVertices++); + } + } + } +#endif +} + void NCMesh::InitRootState(int root_count) { root_state.SetSize(root_count); @@ -2015,14 +2199,10 @@ const double* NCMesh::CalcVertexPos(int node) const const Node &nd = nodes[node]; if (nd.p1 == nd.p2) // top-level vertex { - return &top_vertex_pos[3*nd.p1]; + return &coordinates[3*nd.p1]; } -#ifdef MFEM_DEBUG - TmpVertex &tv = tmp_vertex[node]; // to make DebugDump work -#else - TmpVertex &tv = tmp_vertex[nd.vert_index]; -#endif + TmpVertex &tv = tmp_vertex[node]; if (tv.valid) { return tv.pos; } MFEM_VERIFY(tv.visited == false, "cyclic vertex dependencies."); @@ -2042,7 +2222,7 @@ const double* NCMesh::CalcVertexPos(int node) const void NCMesh::GetMeshComponents(Mesh &mesh) const { mesh.vertices.SetSize(vertex_nodeId.Size()); - if (top_vertex_pos.Size()) + if (coordinates.Size()) { // calculate vertex positions from stored top-level vertex coordinates tmp_vertex = new TmpVertex[nodes.NumIds()]; @@ -2052,20 +2232,19 @@ void NCMesh::GetMeshComponents(Mesh &mesh) const } delete [] tmp_vertex; } - // NOTE: if the mesh is curved (top_vertex_pos is empty), mesh.vertices are + // NOTE: if the mesh is curved ('coordinates' is empty), mesh.vertices are // left uninitialized here; they will be initialized later by the Mesh from // Nodes -- here we just make sure mesh.vertices has the correct size. - mesh.elements.SetSize(leaf_elements.Size() - GetNumGhostElements()); + mesh.elements.SetSize(NElements); mesh.elements.SetSize(0); mesh.boundary.SetSize(0); // create an mfem::Element for each leaf Element - for (int i = 0; i < leaf_elements.Size(); i++) + for (int i = 0; i < NElements; i++) { const Element &nc_elem = elements[leaf_elements[i]]; - if (IsGhost(nc_elem)) { continue; } // ParNCMesh const int* node = nc_elem.node; GeomInfo& gi = GI[(int) nc_elem.geom]; @@ -2129,12 +2308,23 @@ void NCMesh::GetMeshComponents(Mesh &mesh) const void NCMesh::OnMeshUpdated(Mesh *mesh) { + //// PART 1: pull indices of regular edges/faces from the Mesh + NEdges = mesh->GetNEdges(); NFaces = mesh->GetNumFaces(); - Table *edge_vertex = mesh->GetEdgeVertexTable(); + // clear Node::edge_index and Face::index + for (auto node = nodes.begin(); node != nodes.end(); ++node) + { + if (node->HasEdge()) { node->edge_index = -1; } + } + for (auto face = faces.begin(); face != faces.end(); ++face) + { + face->index = -1; + } // get edge enumeration from the Mesh + Table *edge_vertex = mesh->GetEdgeVertexTable(); for (int i = 0; i < edge_vertex->Size(); i++) { const int *ev = edge_vertex->GetRow(i); @@ -2185,9 +2375,76 @@ void NCMesh::OnMeshUpdated(Mesh *mesh) (ev[1] == fv[0] && ev[0] == fv[1]), ""); #endif } + MFEM_VERIFY(face, "face not found."); face->index = i; } + + //// PART 2: assign indices of ghost edges/faces, if any + + // count ghost edges and assign their indices + NGhostEdges = 0; + for (auto node = nodes.begin(); node != nodes.end(); ++node) + { + if (node->HasEdge() && node->edge_index < 0) + { + node->edge_index = NEdges + (NGhostEdges++); + } + } + + // count ghost faces + NGhostFaces = 0; + for (auto face = faces.begin(); face != faces.end(); ++face) + { + if (face->index < 0) { NGhostFaces++; } + } + + if (Dim == 2) + { + // in 2D we have fake faces because of DG + MFEM_ASSERT(NFaces == NEdges, ""); + MFEM_ASSERT(NGhostFaces == NGhostEdges, ""); + } + + // resize face_geom (default_geom is for slave faces beyond the ghost layer) + Geometry::Type default_geom = Geometry::SQUARE; + face_geom.SetSize(NFaces + NGhostFaces, default_geom); + + // update 'face_geom' for ghost faces, assign ghost face indices + int nghosts = 0; + for (int i = 0; i < NGhostElements; i++) + { + Element &el = elements[leaf_elements[NElements + i]]; // ghost element + GeomInfo &gi = GI[el.Geom()]; + + for (int j = 0; j < gi.nf; j++) + { + const int *fv = gi.faces[j]; + Face* face = faces.Find(el.node[fv[0]], el.node[fv[1]], + el.node[fv[2]], el.node[fv[3]]); + MFEM_ASSERT(face, "face not found!"); + + if (face->index < 0) + { + face->index = NFaces + (nghosts++); + + // store the face geometry + static const Geometry::Type types[5] = + { + Geometry::INVALID, Geometry::INVALID, + Geometry::SEGMENT, Geometry::TRIANGLE, Geometry::SQUARE + }; + face_geom[face->index] = types[gi.nfv[j]]; + } + } + } + + // assign valid indices also to faces beyond the ghost layer + for (auto face = faces.begin(); face != faces.end(); ++face) + { + if (face->index < 0) { face->index = NFaces + (nghosts++); } + } + MFEM_ASSERT(nghosts == NGhostFaces, ""); } @@ -2742,10 +2999,7 @@ void NCMesh::TraverseEdge(int vn0, int vn1, double t0, double t1, int flags, void NCMesh::BuildEdgeList() { edge_list.Clear(); - if (Dim <= 2) - { - boundary_faces.SetSize(0); - } + if (Dim < 3) { boundary_faces.SetSize(0); } Array processed_edges(nodes.NumIds()); processed_edges = 0; @@ -2847,7 +3101,7 @@ void NCMesh::BuildEdgeList() void NCMesh::BuildVertexList() { - int total = NVertices + GetNumGhostVertices(); + int total = NVertices + NGhostVertices; vertex_list.Clear(); vertex_list.conforming.Reserve(total); @@ -3385,14 +3639,6 @@ void NCMesh::NeighborExpand(const Array &elems, } } -void RefTrf::Apply(const RefCoord src[3], RefCoord dst[3]) const -{ - for (int i = 0; i < 3; i++) - { - dst[i] = (src[i]*s[i] >> 1) + t[i]; - } -} - int NCMesh::GetVertexRootCoord(int elem, RefCoord coord[3]) const { while (1) @@ -4917,7 +5163,7 @@ void NCMesh::GetLimitRefinements(Array &refinements, int max_level) { for (int i = 0; i < leaf_elements.Size(); i++) { - if (IsGhost(elements[leaf_elements[i]])) { break; } + if (IsGhost(elements[leaf_elements[i]])) { break; } // TODO: NElements int splits[3]; CountSplits(leaf_elements[i], splits); @@ -4958,30 +5204,35 @@ void NCMesh::LimitNCLevel(int max_nc_level) } } -void NCMesh::PrintVertexParents(std::ostream &out) const + +//// I/O //////////////////////////////////////////////////////////////////////// + +int NCMesh::PrintVertexParents(std::ostream *out) const { - // count vertices with parents - int nv = 0; - for (node_const_iterator node = nodes.cbegin(); node != nodes.cend(); ++node) + if (!out) { - if (node->HasVertex() && node->p1 != node->p2) { nv++; } - } - out << nv << "\n"; - - // print the relations - for (node_const_iterator node = nodes.cbegin(); node != nodes.cend(); ++node) - { - if (node->HasVertex() && node->p1 != node->p2) + // count vertex nodes with parents + int nv = 0; + for (auto node = nodes.cbegin(); node != nodes.cend(); ++node) { - const Node &p1 = nodes[node->p1]; - const Node &p2 = nodes[node->p2]; - - MFEM_ASSERT(p1.HasVertex(), ""); - MFEM_ASSERT(p2.HasVertex(), ""); - - out << node->vert_index << " " - << p1.vert_index << " " << p2.vert_index << "\n"; + if (node->HasVertex() && node->p1 != node->p2) { nv++; } } + return nv; + } + else + { + // print the relations + for (auto node = nodes.cbegin(); node != nodes.cend(); ++node) + { + if (node->HasVertex() && node->p1 != node->p2) + { + MFEM_ASSERT(nodes[node->p1].HasVertex(), ""); + MFEM_ASSERT(nodes[node->p2].HasVertex(), ""); + + (*out) << node.index() << " " << node->p1 << " " << node->p2 << "\n"; + } + } + return 0; } } @@ -4999,78 +5250,438 @@ void NCMesh::LoadVertexParents(std::istream &input) MFEM_VERIFY(nodes.IdExists(p1), "parent " << p1 << " not found."); MFEM_VERIFY(nodes.IdExists(p2), "parent " << p2 << " not found."); + int check = nodes.FindId(p1, p2); + MFEM_VERIFY(check < 0, "parents (" << p1 << ", " << p2 << ") already " + "assigned to node " << check); + // assign new parents for the node nodes.Reparent(id, p1, p2); - - // NOTE: when loading an AMR mesh, node indices are guaranteed to have - // the same indices as vertices, see NCMesh::NCMesh. } } -void NCMesh::SetVertexPositions(const Array &mvertices) +int NCMesh::PrintBoundary(std::ostream *out) const { - int num_top_level = 0; - for (node_iterator node = nodes.begin(); node != nodes.end(); ++node) + static const int nfv2geom[5] = { - if (node->p1 == node->p2) // see NCMesh::NCMesh + Geometry::INVALID, Geometry::POINT, Geometry::SEGMENT, + Geometry::TRIANGLE, Geometry::SQUARE + }; + int deg = (Dim == 2) ? 2 : 1; // for degenerate faces in 2D + + int count = 0; + for (int i = 0; i < elements.Size(); i++) + { + const Element &el = elements[i]; + if (!el.IsLeaf()) { continue; } + + GeomInfo& gi = GI[el.Geom()]; + for (int k = 0; k < gi.nf; k++) { - MFEM_VERIFY(node.index() == node->p1, "invalid top-level vertex."); - MFEM_VERIFY(node->HasVertex(), "top-level vertex not found."); - MFEM_VERIFY(node->vert_index == node->p1, "bad top-level vertex index"); - num_top_level = std::max(num_top_level, node->p1 + 1); + const int* fv = gi.faces[k]; + const int nfv = gi.nfv[k]; + const Face* face = faces.Find(el.node[fv[0]], el.node[fv[1]], + el.node[fv[2]], el.node[fv[3]]); + MFEM_ASSERT(face != NULL, "face not found"); + if (face->Boundary()) + { + if (!out) { count++; continue; } + + (*out) << face->attribute << " " << nfv2geom[nfv]; + for (int j = 0; j < nfv; j++) + { + (*out) << " " << el.node[fv[j*deg]]; + } + (*out) << "\n"; + } } } + return count; +} - top_vertex_pos.SetSize(3*num_top_level); - for (int i = 0; i < num_top_level; i++) +void NCMesh::LoadBoundary(std::istream &input) +{ + int nb, attr, geom; + input >> nb; + for (int i = 0; i < nb; i++) { - std::memcpy(&top_vertex_pos[3*i], mvertices[i](), 3*sizeof(double)); + input >> attr >> geom; + + int v1, v2, v3, v4; + if (geom == Geometry::SQUARE) + { + input >> v1 >> v2 >> v3 >> v4; + Face* face = faces.Get(v1, v2, v3, v4); + face->attribute = attr; + } + else if (geom == Geometry::TRIANGLE) + { + input >> v1 >> v2 >> v3; + Face* face = faces.Get(v1, v2, v3); + face->attribute = attr; + } + else if (geom == Geometry::SEGMENT) + { + input >> v1 >> v2; + Face* face = faces.Get(v1, v1, v2, v2); + face->attribute = attr; + } + else + { + MFEM_ABORT("unsupported boundary element geometry: " << geom); + } } } -int NCMesh::PrintElements(std::ostream &out, int elem, int &coarse_id) const +void NCMesh::PrintCoordinates(std::ostream &out) const { - const Element &el = elements[elem]; - if (el.ref_type) - { - int child_id[8], nch = 0; - for (int i = 0; i < 8 && el.child[i] >= 0; i++) - { - child_id[nch++] = PrintElements(out, el.child[i], coarse_id); - } - MFEM_ASSERT(nch == ref_type_num_children[(int) el.ref_type], ""); + int nv = coordinates.Size()/3; + out << nv << "\n"; + if (!nv) { return; } - out << (int) el.ref_type; - for (int i = 0; i < nch; i++) + out << spaceDim << "\n"; + for (int i = 0; i < nv; i++) + { + out << coordinates[3*i]; + for (int j = 1; j < spaceDim; j++) { - out << " " << child_id[i]; + out << " " << coordinates[3*i + j]; } out << "\n"; - return coarse_id++; // return new id for this coarse element + } +} + +void NCMesh::LoadCoordinates(std::istream &input) +{ + int nv; + input >> nv; + if (!nv) { return; } + + input >> spaceDim; + + coordinates.SetSize(nv * 3); + coordinates = 0.0; + + for (int i = 0; i < nv; i++) + { + for (int j = 0; j < spaceDim; j++) + { + input >> coordinates[3*i + j]; + MFEM_VERIFY(input.good(), "unexpected EOF"); + } + } +} + +bool NCMesh::ZeroRootStates() const +{ + for (int i = 0; i < root_state.Size(); i++) + { + if (root_state[i]) { return false; } + } + return true; +} + +void NCMesh::Print(std::ostream &out) const +{ + out << "MFEM NC mesh v1.0\n\n" + "# NCMesh supported geometry types:\n" + "# TRIANGLE = 2\n" + "# SQUARE = 3\n" + "# TETRAHEDRON = 4\n" + "# CUBE = 5\n" + "# PRISM = 6\n"; + + out << "\ndimension\n" << Dim << "\n"; + +#ifndef MFEM_USE_MPI + if (MyRank != 0) // don't print this section in serial: default rank is 0 +#endif + { + out << "\nrank\n" << MyRank << "\n"; + } + + out << "\n# rank attr geom ref_type nodes/children"; + out << "\nelements\n" << elements.Size() << "\n"; + + for (int i = 0; i < elements.Size(); i++) + { + const Element &el = elements[i]; + out << el.rank << " " << el.attribute << " "; + if (el.parent == -2) { out << "-1\n"; continue; } // unused element + + out << int(el.geom) << " " << int(el.ref_type); + for (int j = 0; j < 8 && el.node[j] >= 0; j++) + { + out << " " << el.node[j]; + } + out << "\n"; + } + + int nb = PrintBoundary(NULL); + if (nb) + { + out << "\n# attr geom nodes"; + out << "\nboundary\n" << nb << "\n"; + + PrintBoundary(&out); + } + + int nvp = PrintVertexParents(NULL); + if (nvp) + { + out << "\n# vert_id p1 p2"; + out << "\nvertex_parents\n" << nvp << "\n"; + + PrintVertexParents(&out); + } + + if (!ZeroRootStates()) // root_state section is optional + { + out << "\n# root element orientation"; + out << "\nroot_state\n" << root_state.Size() << "\n"; + + for (int i = 0; i < root_state.Size(); i++) + { + out << root_state[i] << "\n"; + } + } + + if (coordinates.Size()) + { + out << "\n# top-level node coordinates"; + out << "\ncoordinates\n"; + + PrintCoordinates(out); } else { - return el.index; + // 'nodes' will be printed one level up by Mesh::Printer() } } -void NCMesh::PrintCoarseElements(std::ostream &out) const +void NCMesh::InitRootElements() { - // print the number of non-leaf elements - out << (elements.Size() - free_element_ids.Size() - leaf_elements.Size()) - << "\n"; - - // print the hierarchy recursively - int coarse_id = leaf_elements.Size(); - for (int i = 0; i < root_state.Size(); i++) + // initialize Element::parent + for (int i = 0; i < elements.Size(); i++) { - PrintElements(out, i, coarse_id); + Element &el = elements[i]; + if (el.ref_type) + { + for (int j = 0; j < 8 && el.child[j] >= 0; j++) + { + int child = el.child[j]; + MFEM_VERIFY(child < elements.Size(), "invalid mesh file: " + "element " << i << " references invalid child " << child); + elements[child].parent = i; + } + } } + + // count the root elements + int nroots = 0; + while (nroots < elements.Size() && + elements[nroots].parent == -1) + { + nroots++; + } + MFEM_VERIFY(nroots, "invalid mesh file: no root elements found."); + + // check that only the first 'nroot' elements are roots (have no parent) + for (int i = nroots; i < elements.Size(); i++) + { + MFEM_VERIFY(elements[i].parent != -1, + "invalid mesh file: only the first M elements can be roots. " + "Found element " << i << " with no parent."); + } + + // default root state is zero + root_state.SetSize(nroots); + root_state = 0; +} + +int NCMesh::CountTopLevelNodes() const +{ + int ntop = 0; + for (auto node = nodes.cbegin(); node != nodes.cend(); ++node) + { + if (node->p1 == node->p2) { ntop = node.index() + 1; } + } + return ntop; +} + +NCMesh::NCMesh(std::istream &input, int version, int &curved) + : spaceDim(0), MyRank(0), Iso(true), Legacy(false) +{ + if (version == 1) // old MFEM mesh v1.1 format + { + LoadLegacyFormat(input, curved); + Legacy = true; + return; + } + + MFEM_ASSERT(version == 10, ""); + std::string ident; + int count; + + // load dimension + skip_comment_lines(input, '#'); + input >> ident; + MFEM_VERIFY(ident == "dimension", "Invalid mesh file: " << ident); + input >> Dim; + + // load rank, if present + skip_comment_lines(input, '#'); + input >> ident; + if (ident == "rank") + { + input >> MyRank; + MFEM_VERIFY(MyRank >= 0, "Invalid rank"); + + skip_comment_lines(input, '#'); + input >> ident; + } + + // load file SFC version, if present (for future changes to SFC ordering) + if (ident == "sfc_version") + { + int sfc_version; // TODO future: store as class member + input >> sfc_version; + MFEM_VERIFY(sfc_version == 0, + "Unsupported mesh file SFC version (" << sfc_version << "). " + "Please update MFEM."); + + skip_comment_lines(input, '#'); + input >> ident; + } + + // load elements + MFEM_VERIFY(ident == "elements", "Invalid mesh file: " << ident); + input >> count; + for (int i = 0; i < count; i++) + { + int rank, attr, geom, ref_type; + input >> rank >> attr >> geom; + + Geometry::Type type = Geometry::Type(geom); + elements.Append(Element(type, attr)); + + MFEM_ASSERT(elements.Size() == i+1, ""); + Element &el = elements[i]; + el.rank = rank; + + if (geom >= 0) + { + CheckSupportedGeom(type); + GI[geom].InitGeom(type); + + input >> ref_type; + MFEM_VERIFY(ref_type >= 0 && ref_type < 8, ""); + el.ref_type = ref_type; + + if (ref_type) // refined element + { + for (int j = 0; j < ref_type_num_children[ref_type]; j++) + { + input >> el.child[j]; + } + if (Dim == 3 && ref_type != 7) { Iso = false; } + } + else // leaf element + { + for (int j = 0; j < GI[geom].nv; j++) + { + int id; + input >> id; + el.node[j] = id; + nodes.Alloc(id, id, id); + // NOTE: nodes that won't get parents assigned will + // stay hashed with p1 == p2 == id (top-level nodes) + } + } + } + else + { + el.parent = -2; // mark as unused + free_element_ids.Append(i); + } + } + + InitRootElements(); + InitGeomFlags(); + + skip_comment_lines(input, '#'); + input >> ident; + + // load boundary + if (ident == "boundary") + { + LoadBoundary(input); + + skip_comment_lines(input, '#'); + input >> ident; + } + + // load vertex hierarchy + if (ident == "vertex_parents") + { + LoadVertexParents(input); + + skip_comment_lines(input, '#'); + input >> ident; + } + + // load root states + if (ident == "root_state") + { + input >> count; + MFEM_VERIFY(count <= root_state.Size(), "Too many root states"); + for (int i = 0; i < count; i++) + { + input >> root_state[i]; + } + + skip_comment_lines(input, '#'); + input >> ident; + } + + // load coordinates or nodes + if (ident == "coordinates") + { + LoadCoordinates(input); + + MFEM_VERIFY(coordinates.Size()/3 >= CountTopLevelNodes(), + "Invalid mesh file: not all top-level nodes are covered by " + "the 'coordinates' section of the mesh file."); + } + else if (ident == "nodes") + { + coordinates.SetSize(0); // this means the mesh is curved + + // prepare to read the nodes + input >> std::ws; + curved = 1; + } + else + { + MFEM_ABORT("Invalid mesh file: either 'coordinates' or " + "'nodes' must be present"); + } + + // create edge nodes and faces + nodes.UpdateUnused(); + for (int i = 0; i < elements.Size(); i++) + { + if (elements[i].IsLeaf()) + { + ReferenceElement(i); + RegisterFaces(i); + } + } + + Update(); } void NCMesh::CopyElements(int elem, - const BlockArray &tmp_elements, - Array &index_map) + const BlockArray &tmp_elements) { Element &el = elements[elem]; if (el.ref_type) @@ -5078,12 +5689,11 @@ void NCMesh::CopyElements(int elem, for (int i = 0; i < 8 && el.child[i] >= 0; i++) { int old_id = el.child[i]; - // here, we do not use the content of 'free_element_ids', if any + // here we know 'free_element_ids' is empty int new_id = elements.Append(tmp_elements[old_id]); - index_map[old_id] = new_id; el.child[i] = new_id; elements[new_id].parent = elem; - CopyElements(new_id, tmp_elements, index_map); + CopyElements(new_id, tmp_elements); } } } @@ -5113,8 +5723,7 @@ void NCMesh::LoadCoarseElements(std::istream &input) { input >> id; MFEM_VERIFY(id >= 0, ""); - MFEM_VERIFY(id < leaf_elements.Size() || - id < elements.Size()-free_element_ids.Size(), + MFEM_VERIFY(id < elements.Size(), "coarse element cannot be referenced before it is " "defined (id=" << id << ")."); @@ -5136,19 +5745,14 @@ void NCMesh::LoadCoarseElements(std::istream &input) // prepare for reordering the elements BlockArray tmp_elements; elements.Swap(tmp_elements); - free_element_ids.SetSize(0); - - Array index_map(tmp_elements.Size()); - index_map = -1; // copy roots, they need to be at the beginning of 'elements' int root_count = 0; - for (elem_iterator el = tmp_elements.begin(); el != tmp_elements.end(); ++el) + for (auto el = tmp_elements.begin(); el != tmp_elements.end(); ++el) { if (el->parent == -1) { - int new_id = elements.Append(*el); // same as AddElement() - index_map[el.index()] = new_id; + elements.Append(*el); // same as AddElement() root_count++; } } @@ -5156,31 +5760,182 @@ void NCMesh::LoadCoarseElements(std::istream &input) // copy the rest of the hierarchy for (int i = 0; i < root_count; i++) { - CopyElements(i, tmp_elements, index_map); - } - - // we also need to renumber element links in Face::elem[] - for (face_iterator face = faces.begin(); face != faces.end(); ++face) - { - for (int i = 0; i < 2; i++) - { - if (face->elem[i] >= 0) - { - face->elem[i] = index_map[face->elem[i]]; - MFEM_ASSERT(face->elem[i] >= 0, ""); - } - } + CopyElements(i, tmp_elements); } // set the Iso flag (must be false if there are 3D aniso refinements) Iso = iso; InitRootState(root_count); +} + +void NCMesh::LoadLegacyFormat(std::istream &input, int &curved) +{ + MFEM_ASSERT(elements.Size() == 0, ""); + MFEM_ASSERT(nodes.Size() == 0, ""); + MFEM_ASSERT(free_element_ids.Size() == 0, ""); + + std::string ident; + int count, attr, geom; + + // load dimension + skip_comment_lines(input, '#'); + input >> ident; + MFEM_VERIFY(ident == "dimension", "invalid mesh file"); + input >> Dim; + + // load elements + skip_comment_lines(input, '#'); + input >> ident; + MFEM_VERIFY(ident == "elements", "invalid mesh file"); + + input >> count; + for (int i = 0; i < count; i++) + { + input >> attr >> geom; + + Geometry::Type type = Geometry::Type(geom); + CheckSupportedGeom(type); + GI[geom].InitGeom(type); + + int id = AddElement(Element(type, attr)); + MFEM_ASSERT(id == i, ""); + + Element &el = elements[id]; + for (int j = 0; j < GI[geom].nv; j++) + { + int id; + input >> id; + el.node[j] = id; + nodes.Alloc(id, id, id); // see comment in NCMesh::NCMesh + } + el.index = i; // needed for file leaf order below + } + + // load boundary + skip_comment_lines(input, '#'); + input >> ident; + MFEM_VERIFY(ident == "boundary", "invalid mesh file"); + + LoadBoundary(input); + + // load vertex hierarchy + skip_comment_lines(input, '#'); + input >> ident; + if (ident == "vertex_parents") + { + LoadVertexParents(input); + + skip_comment_lines(input, '#'); + input >> ident; + } + + // load element hierarchy + if (ident == "coarse_elements") + { + LoadCoarseElements(input); + + skip_comment_lines(input, '#'); + input >> ident; + } + else + { + // no element hierarchy -> all elements are roots + InitRootState(elements.Size()); + } InitGeomFlags(); + // load vertices + MFEM_VERIFY(ident == "vertices", "invalid mesh file"); + input >> count; + input >> std::ws >> ident; + if (ident != "nodes") + { + spaceDim = atoi(ident.c_str()); + + coordinates.SetSize(3*count); + coordinates = 0.0; + + for (int i = 0; i < count; i++) + { + for (int j = 0; j < spaceDim; j++) + { + input >> coordinates[3*i + j]; + MFEM_VERIFY(input.good(), "unexpected EOF"); + } + } + + // truncate extra coordinates (legacy vertices section is longer) + int ntop = CountTopLevelNodes(); + if (3*ntop < coordinates.Size()) + { + coordinates.SetSize(3*ntop); + } + } + else + { + coordinates.SetSize(0); + + // prepare to read the nodes + input >> std::ws; + curved = 1; + } + + // create edge nodes and faces + nodes.UpdateUnused(); + int leaf_count = 0; + for (int i = 0; i < elements.Size(); i++) + { + if (elements[i].IsLeaf()) + { + ReferenceElement(i); + RegisterFaces(i); + leaf_count++; + } + } + + // v1.1 honors file leaf order on load, prepare legacy 'leaf_elements' + Array file_leaf_elements(leaf_count); + file_leaf_elements = -1; + for (int i = 0; i < elements.Size(); i++) + { + if (elements[i].IsLeaf()) + { + file_leaf_elements[elements[i].index] = i; + } + } + MFEM_ASSERT(file_leaf_elements.Min() >= 0, ""); + Update(); + + // force file leaf order + Swap(leaf_elements, file_leaf_elements); } +void NCMesh::LegacyToNewVertexOrdering(Array &order) const +{ + order.SetSize(NVertices); + order = -1; + + int count = 0; + for (auto node = nodes.cbegin(); node != nodes.cend(); ++node) + { + if (node->HasVertex()) + { + MFEM_ASSERT(node.index() >= 0, ""); + MFEM_ASSERT(node.index() < order.Size(), ""); + MFEM_ASSERT(order[node.index()] == -1, ""); + + order[node.index()] = node->vert_index; + count++; + } + } + MFEM_ASSERT(count == order.Size(), ""); +} + + +//////////////////////////////////////////////////////////////////////////////// + void NCMesh::Trim() { vertex_list.Clear(); @@ -5191,6 +5946,9 @@ void NCMesh::Trim() element_vertex.Clear(); ClearTransforms(); + + // TODO future: consider trimming unused blocks at the end of 'elements' and + // maybe also of 'nodes' and 'faces'. } long NCMesh::NCList::MemoryUsage() const @@ -5228,8 +5986,9 @@ long NCMesh::MemoryUsage() const elements.MemoryUsage() + free_element_ids.MemoryUsage() + root_state.MemoryUsage() + - top_vertex_pos.MemoryUsage() + + coordinates.MemoryUsage() + leaf_elements.MemoryUsage() + + leaf_sfc_index.MemoryUsage() + vertex_nodeId.MemoryUsage() + face_list.MemoryUsage() + edge_list.MemoryUsage() + @@ -5251,8 +6010,9 @@ int NCMesh::PrintMemoryDetail() const mfem::out << elements.MemoryUsage() << " elements\n" << free_element_ids.MemoryUsage() << " free_element_ids\n" << root_state.MemoryUsage() << " root_state\n" - << top_vertex_pos.MemoryUsage() << " top_vertex_pos\n" + << coordinates.MemoryUsage() << " top_vertex_pos\n" << leaf_elements.MemoryUsage() << " leaf_elements\n" + << leaf_sfc_index.MemoryUsage() << " leaf_sfc_index\n" << vertex_nodeId.MemoryUsage() << " vertex_nodeId\n" << face_list.MemoryUsage() << " face_list\n" << edge_list.MemoryUsage() << " edge_list\n" @@ -5269,59 +6029,6 @@ int NCMesh::PrintMemoryDetail() const return elements.Size() - free_element_ids.Size(); } -void NCMesh::PrintStats(std::ostream &out) const -{ - static const double MiB = 1024.*1024.; - out << - "NCMesh statistics:\n" - "------------------\n" - " mesh and space dimensions : " << Dim << ", " << spaceDim << "\n" - " isotropic only : " << (Iso ? "yes" : "no") << "\n" - " number of Nodes : " << std::setw(9) - << nodes.Size() << " + [ " << std::setw(9) - << nodes.MemoryUsage()/MiB << " MiB ]\n" - " free " << std::setw(9) - << nodes.NumFreeIds() << "\n" - " number of Faces : " << std::setw(9) - << faces.Size() << " + [ " << std::setw(9) - << faces.MemoryUsage()/MiB << " MiB ]\n" - " free " << std::setw(9) - << faces.NumFreeIds() << "\n" - " number of Elements : " << std::setw(9) - << elements.Size()-free_element_ids.Size() << " + [ " << std::setw(9) - << (elements.MemoryUsage() + - free_element_ids.MemoryUsage())/MiB << " MiB ]\n" - " free " << std::setw(9) - << free_element_ids.Size() << "\n" - " number of root elements : " << std::setw(9) - << root_state.Size() << "\n" - " number of leaf elements : " << std::setw(9) - << leaf_elements.Size() << "\n" - " number of vertices : " << std::setw(9) - << vertex_nodeId.Size() << "\n" - " number of faces : " << std::setw(9) - << face_list.TotalSize() << " = [ " << std::setw(9) - << face_list.MemoryUsage()/MiB << " MiB ]\n" - " conforming " << std::setw(9) - << face_list.conforming.Size() << " +\n" - " master " << std::setw(9) - << face_list.masters.Size() << " +\n" - " slave " << std::setw(9) - << face_list.slaves.Size() << "\n" - " number of edges : " << std::setw(9) - << edge_list.TotalSize() << " = [ " << std::setw(9) - << edge_list.MemoryUsage()/MiB << " MiB ]\n" - " conforming " << std::setw(9) - << edge_list.conforming.Size() << " +\n" - " master " << std::setw(9) - << edge_list.masters.Size() << " +\n" - " slave " << std::setw(9) - << edge_list.slaves.Size() << "\n" - " total memory : " << std::setw(17) - << "[ " << std::setw(9) << MemoryUsage()/MiB << " MiB ]\n" - ; -} - #ifdef MFEM_DEBUG void NCMesh::DebugLeafOrder(std::ostream &out) const { @@ -5353,7 +6060,7 @@ void NCMesh::DebugDump(std::ostream &out) const // dump nodes tmp_vertex = new TmpVertex[nodes.NumIds()]; out << nodes.Size() << "\n"; - for (node_const_iterator node = nodes.cbegin(); node != nodes.cend(); ++node) + for (auto node = nodes.cbegin(); node != nodes.cend(); ++node) { const double *pos = CalcVertexPos(node.index()); out << node.index() << " " @@ -5369,27 +6076,28 @@ void NCMesh::DebugDump(std::ostream &out) const int nleaves = 0; for (int i = 0; i < elements.Size(); i++) { - const Element &el = elements[i]; - if (!el.ref_type && el.parent != -2 /*freed*/) { nleaves++; } + if (elements[i].IsLeaf()) { nleaves++; } } out << nleaves << "\n"; for (int i = 0; i < elements.Size(); i++) { const Element &el = elements[i]; - if (el.ref_type || el.parent == -2) { continue; } - const GeomInfo& gi = GI[el.Geom()]; - out << gi.nv << " "; - for (int j = 0; j < gi.nv; j++) + if (el.IsLeaf()) { - out << el.node[j] << " "; + const GeomInfo& gi = GI[el.Geom()]; + out << gi.nv << " "; + for (int j = 0; j < gi.nv; j++) + { + out << el.node[j] << " "; + } + out << el.attribute << " " << el.rank << " " << i << "\n"; } - out << el.attribute << " " << el.rank << " " << i << "\n"; } out << "\n"; // dump faces out << faces.Size() << "\n"; - for (face_const_iterator face = faces.cbegin(); face != faces.cend(); ++face) + for (auto face = faces.cbegin(); face != faces.cend(); ++face) { int elem = face->elem[0]; if (elem < 0) { elem = face->elem[1]; } diff --git a/mesh/ncmesh.hpp b/mesh/ncmesh.hpp index 67f853b490..beaa840456 100644 --- a/mesh/ncmesh.hpp +++ b/mesh/ncmesh.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -102,12 +102,14 @@ struct MatrixMap; // for internal use class NCMesh { public: - /** Initialize with elements from 'mesh'. If an already nonconforming mesh - is being loaded, 'vertex_parents' must point to a stream at the appropriate - section of the mesh file which contains the vertex hierarchy. */ - explicit NCMesh(const Mesh *mesh, std::istream *vertex_parents = NULL); + //// Initialize with elements from an existing 'mesh'. + explicit NCMesh(const Mesh *mesh); - NCMesh(const NCMesh &other); // deep copy + /// Load from a stream. The id header is assumed to have been read already. + NCMesh(std::istream &input, int version, int &curved); + + /// Deep copy of another instance. + NCMesh(const NCMesh &other); virtual ~NCMesh(); @@ -342,21 +344,14 @@ public: Array &fattr) const; - /// I/O: Print the "vertex_parents" section of the mesh file (ver. >= 1.1). - void PrintVertexParents(std::ostream &out) const; + /// I/O: Print the mesh in "MFEM NC mesh v1.0" format. + void Print(std::ostream &out) const; - /// I/O: Print the "coarse_elements" section of the mesh file (ver. >= 1.1). - void PrintCoarseElements(std::ostream &out) const; + /// I/O: Return true if the mesh was loaded from the legacy v1.1 format. + bool IsLegacyLoaded() const { return Legacy; } - /** I/O: Load the vertex parent hierarchy from a mesh file. NOTE: called - indirectly through the constructor. */ - void LoadVertexParents(std::istream &input); - - /// I/O: Load the element refinement hierarchy from a mesh file. - void LoadCoarseElements(std::istream &input); - - /// I/O: Set positions of all vertices (used by mesh loader). - void SetVertexPositions(const Array &vertices); + /// I/O: Return a map from old (v1.1) vertex indices to new vertex indices. + void LegacyToNewVertexOrdering(Array &order) const; /// Save memory by releasing all non-essential and cached data. virtual void Trim(); @@ -366,12 +361,10 @@ public: int PrintMemoryDetail() const; - void PrintStats(std::ostream &out = mfem::out) const; - - typedef int64_t RefCoord; + typedef std::int64_t RefCoord; -protected: // interface for Mesh to be able to construct itself from NCMesh +protected: // non-public interface for the Mesh class friend class Mesh; @@ -380,14 +373,20 @@ protected: // interface for Mesh to be able to construct itself from NCMesh /** Get edge and face numbering from 'mesh' (i.e., set all Edge::index and Face::index) after a new mesh was created from us. */ - virtual void OnMeshUpdated(Mesh *mesh); + void OnMeshUpdated(Mesh *mesh); + + /** Delete top-level vertex coordinates if the Mesh became curved, e.g., + by calling Mesh::SetCurvature or otherwise setting the Nodes. */ + void MakeTopologyOnly() { coordinates.DeleteAll(); } protected: // implementation int Dim, spaceDim; ///< dimensions of the elements and the vertex coordinates + int MyRank; ///< used in parallel, or when loading a parallel file in serial bool Iso; ///< true if the mesh only contains isotropic refinements int Geoms; ///< bit mask of element geometries present, see InitGeomFlags() + bool Legacy; ///< true if the mesh was loaded from the legacy v1.1 format /** A Node can hold a vertex, an edge, or both. Elements directly point to their corner nodes, but edge nodes also exist and can be accessed using @@ -453,13 +452,15 @@ protected: // implementation int node[8]; ///< element corners (if ref_type == 0) int child[8]; ///< 2-8 children (if ref_type != 0) }; - int parent; ///< parent element, -1 if this is a root element, -2 if free + int parent; ///< parent element, -1 if this is a root element, -2 if free'd Element(Geometry::Type geom, int attr); Geometry::Type Geom() const { return Geometry::Type(geom); } + bool IsLeaf() const { return !ref_type && (parent != -2); } }; + // primary data HashTable nodes; // associative container holding all Nodes @@ -473,14 +474,9 @@ protected: // implementation NOTE: the first M items of 'elements' is the coarse mesh. */ Array root_state; - /// coordinates of top-level vertices (organized as triples) - Array top_vertex_pos; - - typedef HashTable::iterator node_iterator; - typedef HashTable::iterator face_iterator; - typedef HashTable::const_iterator node_const_iterator; - typedef HashTable::const_iterator face_const_iterator; - typedef BlockArray::iterator elem_iterator; + /** Coordinates of top-level vertices (organized as triples). If empty, + the Mesh is curved (Nodes != NULL) and NCMesh is topology-only. */ + Array coordinates; // secondary data @@ -488,15 +484,20 @@ protected: // implementation /** Apart from the primary data structure, which is the element/node/face hierarchy, there is secondary data that is derived from the primary data and needs to be updated when the primary data changes. Update() - takes care of that and needs to be called after refinement and + takes care of that and needs to be called after each refinement and derefinement. */ virtual void Update(); - int NVertices; // set by UpdateVertices - int NEdges, NFaces; // set by OnMeshUpdated + // set by UpdateLeafElements, UpdateVertices and OnMeshUpdated + int NElements, NVertices, NEdges, NFaces; - Array leaf_elements; // finest level, calculated by UpdateLeafElements - Array vertex_nodeId; // vertex-index to node-id map, see UpdateVertices + // NOTE: the serial code understands the bare minimum about ghost elements and + // other ghost entities in order to be able to load parallel partial meshes + int NGhostElements, NGhostVertices, NGhostEdges, NGhostFaces; + + Array leaf_elements; ///< finest elements, in Mesh ordering (+ ghosts) + Array leaf_sfc_index; ///< natural tree ordering of leaf elements + Array vertex_nodeId; ///< vertex-index to node-id map, see UpdateVertices NCList face_list; ///< lazy-initialized list of faces, see GetFaceList NCList edge_list; ///< lazy-initialized list of edges, see GetEdgeList @@ -508,12 +509,10 @@ protected: // implementation Table element_vertex; ///< leaf-element to vertex table, see FindSetNeighbors - virtual void UpdateVertices(); ///< update Vertex::index and vertex_nodeId - - void CollectLeafElements(int elem, int state); void UpdateLeafElements(); - - virtual void AssignLeafIndices(); + void UpdateVertices(); ///< update Vertex::index and vertex_nodeId + void CollectLeafElements(int elem, int state, Array &ghosts, + int &counter); /** Try to find a space-filling curve friendly orientation of the root elements: set 'root_state' based on the ordering of coarse elements. @@ -521,15 +520,13 @@ protected: // implementation Mesh::GetGeckoElementOrdering. */ void InitRootState(int root_count); - virtual bool IsGhost(const Element &el) const { return false; } - virtual int GetNumGhostElements() const { return 0; } - virtual int GetNumGhostVertices() const { return 0; } - void InitGeomFlags(); bool HavePrisms() const { return Geoms & (1 << Geometry::PRISM); } bool HaveTets() const { return Geoms & (1 << Geometry::TETRAHEDRON); } + bool IsGhost(const Element &el) const { return el.rank != MyRank; } + // refinement/derefinement @@ -556,6 +553,7 @@ protected: // implementation void FreeElement(int id) { free_element_ids.Append(id); + elements[id].ref_type = 0; elements[id].parent = -2; // mark the element as free } @@ -846,9 +844,38 @@ protected: // implementation void CountSplits(int elem, int splits[3]) const; void GetLimitRefinements(Array &refinements, int max_level); - int PrintElements(std::ostream &out, int elem, int &coarse_id) const; - void CopyElements(int elem, const BlockArray &tmp_elements, - Array &index_map); + + // I/O + + /// Print the "vertex_parents" section of the mesh file. + int PrintVertexParents(std::ostream *out) const; + /// Load the vertex parent hierarchy from a mesh file. + void LoadVertexParents(std::istream &input); + + /** Print the "boundary" section of the mesh file. + If out == NULL, only return the number of boundary elements. */ + int PrintBoundary(std::ostream *out) const; + /// Load the "boundary" section of the mesh file. + void LoadBoundary(std::istream &input); + + /// Print the "coordinates" section of the mesh file. + void PrintCoordinates(std::ostream &out) const; + /// Load the "coordinates" section of the mesh file. + void LoadCoordinates(std::istream &input); + + /// Count root elements and initialize root_state. + void InitRootElements(); + /// Return the index of the last top-level node plus one. + int CountTopLevelNodes() const; + /// Return true if all root_states are zero. + bool ZeroRootStates() const; + + /// Load the element refinement hierarchy from a legacy mesh file. + void LoadCoarseElements(std::istream &input); + void CopyElements(int elem, const BlockArray &tmp_elements); + /// Load the deprecated MFEM mesh v1.1 format for backward compatibility. + void LoadLegacyFormat(std::istream &input, int &curved); + // geometry @@ -863,7 +890,7 @@ protected: // implementation bool initialized; GeomInfo() : initialized(false) {} - void Initialize(const mfem::Element* elem); + void InitGeom(Geometry::Type geom); }; static GeomInfo GI[Geometry::NumGeom]; diff --git a/mesh/ncmesh_tables.hpp b/mesh/ncmesh_tables.hpp index 98bdc035ba..7e817f7af0 100644 --- a/mesh/ncmesh_tables.hpp +++ b/mesh/ncmesh_tables.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -12,19 +12,22 @@ namespace mfem { -static int ref_type_num_children[8] = { 0, 2, 2, 4, 2, 4, 4, 8 }; +namespace // make everything static +{ + +const int ref_type_num_children[8] = { 0, 2, 2, 4, 2, 4, 4, 8 }; // derefinement tables -static int quad_deref_table[3][4 + 4] = +const int quad_deref_table[3][4 + 4] = { { 0, 1, 1, 0, /**/ 1, 1, 0, 0 }, // 1 - X { 0, 0, 1, 1, /**/ 0, 0, 1, 1 }, // 2 - Y { 0, 1, 2, 3, /**/ 1, 1, 3, 3 } // 3 - iso }; -static int hex_deref_table[7][8 + 6] = +const int hex_deref_table[7][8 + 6] = { { 0, 1, 1, 0, 0, 1, 1, 0, /**/ 1, 1, 1, 0, 0, 0 }, // 1 - X { 0, 0, 1, 1, 0, 0, 1, 1, /**/ 0, 0, 0, 1, 1, 1 }, // 2 - Y @@ -35,7 +38,7 @@ static int hex_deref_table[7][8 + 6] = { 0, 1, 2, 3, 4, 5, 6, 7, /**/ 1, 1, 1, 7, 7, 7 } // 7 - iso }; -static int prism_deref_table[7][6 + 5] = +const int prism_deref_table[7][6 + 5] = { {-1,-1,-1,-1,-1,-1, /**/ -1,-1,-1,-1,-1 }, // 1 {-1,-1,-1,-1,-1,-1, /**/ -1,-1,-1,-1,-1 }, // 2 @@ -49,19 +52,19 @@ static int prism_deref_table[7][6 + 5] = // child ordering tables -static char quad_hilbert_child_order[8][4] = +const char quad_hilbert_child_order[8][4] = { {0,1,2,3}, {0,3,2,1}, {1,2,3,0}, {1,0,3,2}, {2,3,0,1}, {2,1,0,3}, {3,0,1,2}, {3,2,1,0} }; -static char quad_hilbert_child_state[8][4] = +const char quad_hilbert_child_state[8][4] = { {1,0,0,5}, {0,1,1,4}, {3,2,2,7}, {2,3,3,6}, {5,4,4,1}, {4,5,5,0}, {7,6,6,3}, {6,7,7,2} }; -static char hex_hilbert_child_order[24][8] = +const char hex_hilbert_child_order[24][8] = { {0,1,2,3,7,6,5,4}, {0,3,7,4,5,6,2,1}, {0,4,5,1,2,6,7,3}, {1,0,3,2,6,7,4,5}, {1,2,6,5,4,7,3,0}, {1,5,4,0,3,7,6,2}, @@ -73,7 +76,7 @@ static char hex_hilbert_child_order[24][8] = {7,3,2,6,5,1,0,4}, {7,4,0,3,2,1,5,6}, {7,6,5,4,0,1,2,3} }; -static char hex_hilbert_child_state[24][8] = +const char hex_hilbert_child_state[24][8] = { {1,2,2,7,7,21,21,17}, {2,0,0,22,22,16,16,8}, {0,1,1,15,15,6,6,23}, {4,5,5,10,10,18,18,14}, {5,3,3,19,19,13,13,11}, {3,4,4,12,12,9,9,20}, @@ -100,14 +103,14 @@ const RefCoord S_HALF = 1; const RefCoord S_ONE = 2; const RefCoord S_TWO = 4; -static RefCoord tri_corners[3][3] = +const RefCoord tri_corners[3][3] = { { 0, 0, 0}, {T_ONE, 0, 0}, { 0, T_ONE, 0} }; -static RefCoord quad_corners[4][3] = +const RefCoord quad_corners[4][3] = { { 0, 0, 0}, {T_ONE, 0, 0}, @@ -115,7 +118,7 @@ static RefCoord quad_corners[4][3] = { 0, T_ONE, 0} }; -static RefCoord hex_corners[8][3] = +const RefCoord hex_corners[8][3] = { { 0, 0, 0}, {T_ONE, 0, 0}, @@ -127,7 +130,7 @@ static RefCoord hex_corners[8][3] = { 0, T_ONE, T_ONE} }; -static RefCoord prism_corners[6][3] = +const RefCoord prism_corners[6][3] = { { 0, 0, 0}, {T_ONE, 0, 0}, @@ -138,7 +141,7 @@ static RefCoord prism_corners[6][3] = }; typedef RefCoord RefPoint[3]; -static RefPoint* geom_corners[7] = +const RefPoint* geom_corners[7] = { NULL, // point NULL, // segment @@ -154,34 +157,40 @@ struct RefTrf { RefCoord s[3], t[3]; - void Apply(const RefCoord src[3], RefCoord dst[3]) const; + void Apply(const RefCoord src[3], RefCoord dst[3]) const + { + for (int i = 0; i < 3; i++) + { + dst[i] = (src[i]*s[i] >> 1) + t[i]; + } + } }; -static RefTrf quad_parent_rt1[2] = +const RefTrf quad_parent_rt1[2] = { { {S_HALF, S_ONE, 0}, { 0, 0, 0} }, { {S_HALF, S_ONE, 0}, {T_HALF, 0, 0} } }; -static RefTrf quad_child_rt1[2] = +const RefTrf quad_child_rt1[2] = { { {S_TWO, S_ONE, 0}, { 0, 0, 0} }, { {S_TWO, S_ONE, 0}, {-T_ONE, 0, 0} } }; -static RefTrf quad_parent_rt2[2] = +const RefTrf quad_parent_rt2[2] = { { {S_ONE, S_HALF, 0}, {0, 0, 0} }, { {S_ONE, S_HALF, 0}, {0, T_HALF, 0} } }; -static RefTrf quad_child_rt2[2] = +const RefTrf quad_child_rt2[2] = { { {S_ONE, S_TWO, 0}, {0, 0, 0} }, { {S_ONE, S_TWO, 0}, {0, -T_ONE, 0} } }; -static RefTrf quad_parent_rt3[4] = +const RefTrf quad_parent_rt3[4] = { { {S_HALF, S_HALF, 0}, { 0, 0, 0} }, { {S_HALF, S_HALF, 0}, {T_HALF, 0, 0} }, @@ -189,7 +198,7 @@ static RefTrf quad_parent_rt3[4] = { {S_HALF, S_HALF, 0}, { 0, T_HALF, 0} } }; -static RefTrf quad_child_rt3[4] = +const RefTrf quad_child_rt3[4] = { { {S_TWO, S_TWO, 0}, { 0, 0, 0} }, { {S_TWO, S_TWO, 0}, {-T_ONE, 0, 0} }, @@ -197,7 +206,7 @@ static RefTrf quad_child_rt3[4] = { {S_TWO, S_TWO, 0}, { 0, -T_ONE, 0} } }; -static RefTrf* quad_parent[4] = +const RefTrf* quad_parent[4] = { NULL, quad_parent_rt1, @@ -205,7 +214,7 @@ static RefTrf* quad_parent[4] = quad_parent_rt3 }; -static RefTrf* quad_child[4] = +const RefTrf* quad_child[4] = { NULL, quad_child_rt1, @@ -213,31 +222,31 @@ static RefTrf* quad_child[4] = quad_child_rt3 }; -static RefTrf hex_parent_rt1[2] = +const RefTrf hex_parent_rt1[2] = { { {S_HALF, S_ONE, S_ONE}, { 0, 0, 0} }, { {S_HALF, S_ONE, S_ONE}, {T_HALF, 0, 0} } }; -static RefTrf hex_child_rt1[2] = +const RefTrf hex_child_rt1[2] = { { {S_TWO, S_ONE, S_ONE}, { 0, 0, 0} }, { {S_TWO, S_ONE, S_ONE}, {-T_ONE, 0, 0} } }; -static RefTrf hex_parent_rt2[2] = +const RefTrf hex_parent_rt2[2] = { { {S_ONE, S_HALF, S_ONE}, {0, 0, 0} }, { {S_ONE, S_HALF, S_ONE}, {0, T_HALF, 0} } }; -static RefTrf hex_child_rt2[2] = +const RefTrf hex_child_rt2[2] = { { {S_ONE, S_TWO, S_ONE}, {0, 0, 0} }, { {S_ONE, S_TWO, S_ONE}, {0, -T_ONE, 0} } }; -static RefTrf hex_parent_rt3[4] = +const RefTrf hex_parent_rt3[4] = { { {S_HALF, S_HALF, S_ONE}, { 0, 0, 0} }, { {S_HALF, S_HALF, S_ONE}, {T_HALF, 0, 0} }, @@ -245,7 +254,7 @@ static RefTrf hex_parent_rt3[4] = { {S_HALF, S_HALF, S_ONE}, { 0, T_HALF, 0} } }; -static RefTrf hex_child_rt3[4] = +const RefTrf hex_child_rt3[4] = { { {S_TWO, S_TWO, S_ONE}, { 0, 0, 0} }, { {S_TWO, S_TWO, S_ONE}, {-T_ONE, 0, 0} }, @@ -253,19 +262,19 @@ static RefTrf hex_child_rt3[4] = { {S_TWO, S_TWO, S_ONE}, { 0, -T_ONE, 0} } }; -static RefTrf hex_parent_rt4[2] = +const RefTrf hex_parent_rt4[2] = { { {S_ONE, S_ONE, S_HALF}, {0, 0, 0} }, { {S_ONE, S_ONE, S_HALF}, {0, 0, T_HALF} } }; -static RefTrf hex_child_rt4[2] = +const RefTrf hex_child_rt4[2] = { { {S_ONE, S_ONE, S_TWO}, {0, 0, 0} }, { {S_ONE, S_ONE, S_TWO}, {0, 0, -T_ONE} } }; -static RefTrf hex_parent_rt5[4] = +const RefTrf hex_parent_rt5[4] = { { {S_HALF, S_ONE, S_HALF}, { 0, 0, 0} }, { {S_HALF, S_ONE, S_HALF}, {T_HALF, 0, 0} }, @@ -273,7 +282,7 @@ static RefTrf hex_parent_rt5[4] = { {S_HALF, S_ONE, S_HALF}, { 0, 0, T_HALF} } }; -static RefTrf hex_child_rt5[4] = +const RefTrf hex_child_rt5[4] = { { {S_TWO, S_ONE, S_TWO}, { 0, 0, 0} }, { {S_TWO, S_ONE, S_TWO}, {-T_ONE, 0, 0} }, @@ -281,7 +290,7 @@ static RefTrf hex_child_rt5[4] = { {S_TWO, S_ONE, S_TWO}, { 0, 0, -T_ONE} } }; -static RefTrf hex_parent_rt6[4] = +const RefTrf hex_parent_rt6[4] = { { {S_ONE, S_HALF, S_HALF}, {0, 0, 0} }, { {S_ONE, S_HALF, S_HALF}, {0, T_HALF, 0} }, @@ -289,7 +298,7 @@ static RefTrf hex_parent_rt6[4] = { {S_ONE, S_HALF, S_HALF}, {0, T_HALF, T_HALF} } }; -static RefTrf hex_child_rt6[4] = +const RefTrf hex_child_rt6[4] = { { {S_ONE, S_TWO, S_TWO}, {0, 0, 0} }, { {S_ONE, S_TWO, S_TWO}, {0, -T_ONE, 0} }, @@ -297,7 +306,7 @@ static RefTrf hex_child_rt6[4] = { {S_ONE, S_TWO, S_TWO}, {0, -T_ONE, -T_ONE} } }; -static RefTrf hex_parent_rt7[8] = +const RefTrf hex_parent_rt7[8] = { { {S_HALF, S_HALF, S_HALF}, { 0, 0, 0} }, { {S_HALF, S_HALF, S_HALF}, {T_HALF, 0, 0} }, @@ -309,7 +318,7 @@ static RefTrf hex_parent_rt7[8] = { {S_HALF, S_HALF, S_HALF}, { 0, T_HALF, T_HALF} } }; -static RefTrf hex_child_rt7[8] = +const RefTrf hex_child_rt7[8] = { { {S_TWO, S_TWO, S_TWO}, { 0, 0, 0} }, { {S_TWO, S_TWO, S_TWO}, {-T_ONE, 0, 0} }, @@ -321,7 +330,7 @@ static RefTrf hex_child_rt7[8] = { {S_TWO, S_TWO, S_TWO}, { 0, -T_ONE, -T_ONE} } }; -static RefTrf* hex_parent[8] = +const RefTrf* hex_parent[8] = { NULL, hex_parent_rt1, @@ -333,7 +342,7 @@ static RefTrf* hex_parent[8] = hex_parent_rt7 }; -static RefTrf* hex_child[8] = +const RefTrf* hex_child[8] = { NULL, hex_child_rt1, @@ -345,7 +354,7 @@ static RefTrf* hex_child[8] = hex_child_rt7 }; -static RefTrf tri_parent_rt3[4] = +const RefTrf tri_parent_rt3[4] = { { { S_HALF, S_HALF, 0}, { 0, 0, 0} }, { { S_HALF, S_HALF, 0}, {T_HALF, 0, 0} }, @@ -353,7 +362,7 @@ static RefTrf tri_parent_rt3[4] = { {-S_HALF, -S_HALF, 0}, {T_HALF, T_HALF, 0} } }; -static RefTrf tri_child_rt3[4] = +const RefTrf tri_child_rt3[4] = { { { S_TWO, S_TWO, 0}, { 0, 0, 0} }, { { S_TWO, S_TWO, 0}, {-T_ONE, 0, 0} }, @@ -361,19 +370,19 @@ static RefTrf tri_child_rt3[4] = { {-S_TWO, -S_TWO, 0}, { T_ONE, T_ONE, 0} } }; -static RefTrf* tri_parent[4] = +const RefTrf* tri_parent[4] = { NULL, NULL, NULL, tri_parent_rt3 }; -static RefTrf* tri_child[4] = +const RefTrf* tri_child[4] = { NULL, NULL, NULL, tri_child_rt3 }; -static RefTrf prism_parent_rt3[4] = +const RefTrf prism_parent_rt3[4] = { { { S_HALF, S_HALF, S_ONE}, { 0, 0, 0} }, { { S_HALF, S_HALF, S_ONE}, {T_HALF, 0, 0} }, @@ -381,7 +390,7 @@ static RefTrf prism_parent_rt3[4] = { {-S_HALF, -S_HALF, S_ONE}, {T_HALF, T_HALF, 0} } }; -static RefTrf prism_child_rt3[4] = +const RefTrf prism_child_rt3[4] = { { { S_TWO, S_TWO, S_ONE}, { 0, 0, 0} }, { { S_TWO, S_TWO, S_ONE}, {-T_ONE, 0, 0} }, @@ -389,19 +398,19 @@ static RefTrf prism_child_rt3[4] = { {-S_TWO, -S_TWO, S_ONE}, { T_ONE, T_ONE, 0} } }; -static RefTrf prism_parent_rt4[2] = +const RefTrf prism_parent_rt4[2] = { { {S_ONE, S_ONE, S_HALF}, {0, 0, 0} }, { {S_ONE, S_ONE, S_HALF}, {0, 0, T_HALF} } }; -static RefTrf prism_child_rt4[2] = +const RefTrf prism_child_rt4[2] = { { {S_ONE, S_ONE, S_TWO}, {0, 0, 0} }, { {S_ONE, S_ONE, S_TWO}, {0, 0, -T_ONE} } }; -static RefTrf prism_parent_rt7[8] = +const RefTrf prism_parent_rt7[8] = { { { S_HALF, S_HALF, S_HALF}, { 0, 0, 0} }, { { S_HALF, S_HALF, S_HALF}, {T_HALF, 0, 0} }, @@ -413,7 +422,7 @@ static RefTrf prism_parent_rt7[8] = { {-S_HALF, -S_HALF, S_HALF}, {T_HALF, T_HALF, T_HALF} } }; -static RefTrf prism_child_rt7[8] = +const RefTrf prism_child_rt7[8] = { { { S_TWO, S_TWO, S_TWO}, { 0, 0, 0} }, { { S_TWO, S_TWO, S_TWO}, {-T_ONE, 0, 0} }, @@ -425,7 +434,7 @@ static RefTrf prism_child_rt7[8] = { {-S_TWO, -S_TWO, S_TWO}, { T_ONE, T_ONE, -T_ONE} } }; -static RefTrf* prism_parent[8] = +const RefTrf* prism_parent[8] = { NULL, NULL, NULL, prism_parent_rt3, @@ -434,7 +443,7 @@ static RefTrf* prism_parent[8] = prism_parent_rt7 }; -static RefTrf* prism_child[8] = +const RefTrf* prism_child[8] = { NULL, NULL, NULL, prism_child_rt3, @@ -443,7 +452,7 @@ static RefTrf* prism_child[8] = prism_child_rt7 }; -static RefTrf** geom_parent[7] = +const RefTrf** geom_parent[7] = { NULL, NULL, @@ -454,7 +463,7 @@ static RefTrf** geom_parent[7] = prism_parent }; -static RefTrf** geom_child[7] = +const RefTrf** geom_child[7] = { NULL, NULL, @@ -466,4 +475,6 @@ static RefTrf** geom_child[7] = }; +} // namespace + } // namespace mfem diff --git a/mesh/nurbs.cpp b/mesh/nurbs.cpp index 9a985bcddc..e384c2cf9b 100644 --- a/mesh/nurbs.cpp +++ b/mesh/nurbs.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/mesh/nurbs.hpp b/mesh/nurbs.hpp index c5ce0e393a..e6316f2772 100644 --- a/mesh/nurbs.hpp +++ b/mesh/nurbs.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/mesh/pmesh.cpp b/mesh/pmesh.cpp index f774c0c739..c4223ef3b2 100644 --- a/mesh/pmesh.cpp +++ b/mesh/pmesh.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -273,6 +273,10 @@ ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_, element_counter++; } } + + // set meaningful values to 'vertices' even though we have Nodes, + // for compatibility (e.g., Mesh::GetVertex()) + SetVerticesFromNodes(Nodes); } if (partitioning != partitioning_) @@ -918,18 +922,50 @@ ParMesh::ParMesh(MPI_Comm comm, istream &input, bool refine) have_face_nbr_data = false; pncmesh = NULL; - string ident; - - // read the serial part of the mesh const int gen_edges = 1; + Load(input, gen_edges, refine, true); +} + +void ParMesh::Load(istream &input, int generate_edges, int refine, + bool fix_orientation) +{ + ParMesh::Destroy(); + // Tell Loader() to read up to 'mfem_serial_mesh_end' instead of // 'mfem_mesh_end', as we have additional parallel mesh data to load in from // the stream. - Loader(input, gen_edges, "mfem_serial_mesh_end"); + Loader(input, generate_edges, "mfem_serial_mesh_end"); ReduceMeshGen(); // determine the global 'meshgen' + if (Conforming()) + { + LoadSharedEntities(input); + } + else + { + // the ParNCMesh instance was already constructed in 'Loader' + pncmesh = dynamic_cast(ncmesh); + MFEM_ASSERT(pncmesh, "internal error"); + + // in the NC case we don't need to load extra data from the file, + // as the shared entities can be constructed from the ghost layer + pncmesh->GetConformingSharedStructures(*this); + } + + Finalize(refine, fix_orientation); + + EnsureParNodes(); + + // note: attributes and bdr_attributes are local lists + + // TODO: NURBS meshes? +} + +void ParMesh::LoadSharedEntities(istream &input) +{ + string ident; skip_comment_lines(input, '#'); // read the group topology @@ -943,7 +979,8 @@ ParMesh::ParMesh(MPI_Comm comm, istream &input, bool refine) // read and set the sizes of svert_lvert, group_svert { int num_sverts; - input >> ident >> num_sverts; // total_shared_vertices + input >> ident >> num_sverts; + MFEM_VERIFY(ident == "total_shared_vertices", "invalid mesh file"); svert_lvert.SetSize(num_sverts); group_svert.SetDims(GetNGroups()-1, num_sverts); } @@ -952,7 +989,8 @@ ParMesh::ParMesh(MPI_Comm comm, istream &input, bool refine) { skip_comment_lines(input, '#'); int num_sedges; - input >> ident >> num_sedges; // total_shared_edges + input >> ident >> num_sedges; + MFEM_VERIFY(ident == "total_shared_edges", "invalid mesh file"); sedge_ledge.SetSize(num_sedges); shared_edges.SetSize(num_sedges); group_sedge.SetDims(GetNGroups()-1, num_sedges); @@ -966,7 +1004,8 @@ ParMesh::ParMesh(MPI_Comm comm, istream &input, bool refine) { skip_comment_lines(input, '#'); int num_sface; - input >> ident >> num_sface; // total_shared_faces + input >> ident >> num_sface; + MFEM_VERIFY(ident == "total_shared_faces", "invalid mesh file"); sface_lface.SetSize(num_sface); group_stria.MakeI(GetNGroups()-1); group_squad.MakeI(GetNGroups()-1); @@ -994,10 +1033,10 @@ ParMesh::ParMesh(MPI_Comm comm, istream &input, bool refine) mfem_error(); } #endif - { int nv; input >> ident >> nv; // shared_vertices (in this group) + MFEM_VERIFY(ident == "shared_vertices", "invalid mesh file"); nv += svert_counter; MFEM_VERIFY(nv <= group_svert.Size_of_connections(), "incorrect number of total_shared_vertices"); @@ -1012,6 +1051,7 @@ ParMesh::ParMesh(MPI_Comm comm, istream &input, bool refine) { int ne, v[2]; input >> ident >> ne; // shared_edges (in this group) + MFEM_VERIFY(ident == "shared_edges", "invalid mesh file"); ne += sedge_counter; MFEM_VERIFY(ne <= group_sedge.Size_of_connections(), "incorrect number of total_shared_edges"); @@ -1070,15 +1110,6 @@ ParMesh::ParMesh(MPI_Comm comm, istream &input, bool refine) group_squad.GetJ()[i] = i; } } - - const bool fix_orientation = false; - Finalize(refine, fix_orientation); - - // If the mesh has Nodes, convert them from GridFunction to ParGridFunction? - - // note: attributes and bdr_attributes are local lists - - // TODO: AMR meshes, NURBS meshes? } ParMesh::ParMesh(ParMesh *orig_mesh, int ref_factor, int ref_type) @@ -1343,19 +1374,19 @@ long ParMesh::GetGlobalElementNum(int local_element_num) const void ParMesh::DistributeAttributes(Array &attr) { // Determine the largest attribute number across all processors - int max_attr = attr.Max(); + int max_attr = attr.Size() ? attr.Max() : 1 /*allow empty ranks*/; int glb_max_attr = -1; MPI_Allreduce(&max_attr, &glb_max_attr, 1, MPI_INT, MPI_MAX, MyComm); // Create marker arrays to indicate which attributes are present // assuming attribute numbers are in the range [1,glb_max_attr]. - bool * attr_marker = new bool[glb_max_attr]; - bool * glb_attr_marker = new bool[glb_max_attr]; - for (int i=0; i &attr) delete [] attr_marker; // Translate from the marker array to a unique, sorted list of attributes - Array glb_attr; - glb_attr.SetSize(glb_max_attr); - glb_attr = glb_max_attr; - int o = 0; - for (int i=0; iMakeOwner(nfec); } +void ParMesh::EnsureParNodes() +{ + if (Nodes && dynamic_cast(Nodes->FESpace()) == NULL) + { + ParFiniteElementSpace *pfes = + new ParFiniteElementSpace(*Nodes->FESpace(), *this); + ParGridFunction *new_nodes = new ParGridFunction(pfes); + + *new_nodes = *Nodes; + + if (Nodes->OwnFEC()) + { + new_nodes->MakeOwner(Nodes->OwnFEC()); + Nodes->MakeOwner(NULL); // takes away ownership of 'fec' and 'fes' + delete Nodes->FESpace(); + } + + delete Nodes; + Nodes = new_nodes; + } +} + void ParMesh::ExchangeFaceNbrData() { if (have_face_nbr_data) @@ -2625,6 +2672,8 @@ void ParMesh::GetGhostFaceTransformation( { const FiniteElement* face_el = Nodes->FESpace()->GetTraceElement(FETr->Elem1No, face_geom); + MFEM_VERIFY(dynamic_cast(face_el), + "Mesh requires nodal Finite Element."); #if 0 // TODO: handle the case of non-interpolatory Nodes DenseMatrix I; @@ -3516,8 +3565,8 @@ void ParMesh::NonconformingRefinement(const Array &refinements, { if (NURBSext) { - MFEM_ABORT("ParMesh::NonconformingRefinement: NURBS meshes are not " - "supported. Project the NURBS to Nodes first."); + MFEM_ABORT("NURBS meshes are not supported. Please project the " + "NURBS to Nodes first with SetCurvature()."); } if (!pncmesh) @@ -3639,21 +3688,11 @@ void ParMesh::RebalanceImpl(const Array *partition) " meshes."); } - // Make sure the Nodes use a ParFiniteElementSpace - if (Nodes && dynamic_cast(Nodes->FESpace()) == NULL) + if (Nodes) { - ParFiniteElementSpace *pfes = - new ParFiniteElementSpace(*Nodes->FESpace(), *this); - ParGridFunction *new_nodes = new ParGridFunction(pfes); - *new_nodes = *Nodes; - if (Nodes->OwnFEC()) - { - new_nodes->MakeOwner(Nodes->OwnFEC()); - Nodes->MakeOwner(NULL); // takes away ownership of 'fec' and 'fes' - delete Nodes->FESpace(); - } - delete Nodes; - Nodes = new_nodes; + // check that Nodes use a parallel FE space, so we can call UpdateNodes() + MFEM_VERIFY(dynamic_cast(Nodes->FESpace()) + != NULL, "internal error"); } DeleteFaceNbrData(); @@ -5536,10 +5575,17 @@ long ParMesh::ReduceInt(int value) const void ParMesh::ParPrint(ostream &out) const { - if (NURBSext || pncmesh) + if (NURBSext) { - // TODO: AMR meshes, NURBS meshes. - Print(out); + // TODO: NURBS meshes. + Print(out); // use the serial MFEM v1.0 format for now + return; + } + + if (Nonconforming()) + { + // the NC mesh format works both in serial and in parallel + Printer(out); return; } @@ -5813,7 +5859,87 @@ void ParMesh::PrintSharedEntities(const char *fname_prefix) const } } -ParMesh::~ParMesh() +void ParMesh::GetGlobalVertexIndices(Array &gi) const +{ + H1_FECollection fec(1, Dim); // Order 1, mesh dimension (not spatial dimension). + ParMesh *pm = const_cast(this); + ParFiniteElementSpace fespace(pm, &fec); + + gi.SetSize(GetNV()); + + Array dofs; + for (int i=0; i &gi) const +{ + if (Dim == 1) + { + GetGlobalVertexIndices(gi); + return; + } + + ND_FECollection fec(1, Dim); // Order 1, mesh dimension (not spatial dimension). + ParMesh *pm = const_cast(this); + ParFiniteElementSpace fespace(pm, &fec); + + gi.SetSize(GetNEdges()); + + Array dofs; + for (int i=0; i= 0) ? dofs[0] : -1 - dofs[0]; + gi[i] = fespace.GetGlobalTDofNumber(ldof); + } +} + +void ParMesh::GetGlobalFaceIndices(Array &gi) const +{ + if (Dim == 2) + { + GetGlobalEdgeIndices(gi); + return; + } + else if (Dim == 1) + { + GetGlobalVertexIndices(gi); + return; + } + + RT_FECollection fec(0, Dim); // Order 0, mesh dimension (not spatial dimension). + ParMesh *pm = const_cast(this); + ParFiniteElementSpace fespace(pm, &fec); + + gi.SetSize(GetNFaces()); + + Array dofs; + for (int i=0; i= 0) ? dofs[0] : -1 - dofs[0]; + gi[i] = fespace.GetGlobalTDofNumber(ldof); + } +} + +void ParMesh::GetGlobalElementIndices(Array &gi) const +{ + ComputeGlobalElementOffset(); + + const HYPRE_Int offset = glob_elem_offset; // Cast from long to HYPRE_Int + + gi.SetSize(GetNE()); + for (int i=0; i &attr); + void LoadSharedEntities(std::istream &input); + + /// If the mesh is curved, make sure 'Nodes' is ParGridFunction. + /** Note that this method is not related to the public 'Mesh::EnsureNodes`.*/ + void EnsureParNodes(); + + void Destroy(); + public: + /// Create a parallel mesh by partitioning a serial Mesh. + /** The mesh is partitioned automatically or using external partitioning + data (the optional parameter 'partitioning_[i]' contains the desired MPI + rank for element 'i'). Automatic partitioning uses METIS for conforming + meshes and quick space-filling curve equipartitioning for nonconforming + meshes (elements of nonconforming meshes should ideally be ordered as a + sequence of face-neighbors). */ + ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_ = NULL, + int part_method = 1); + /** Copy constructor. Performs a deep copy of (almost) all data, so that the source mesh can be modified (e.g. deleted, refined) without affecting the new mesh. If 'copy_nodes' is false, use a shallow (pointer) copy for the nodes, if present. */ explicit ParMesh(const ParMesh &pmesh, bool copy_nodes = true); - ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_ = NULL, - int part_method = 1); - /// Read a parallel mesh, each MPI rank from its own file/stream. /** The @a refine parameter is passed to the method Mesh::Finalize(). */ ParMesh(MPI_Comm comm, std::istream &input, bool refine = true); @@ -253,6 +268,19 @@ public: /// Map a local element number to a global element number. long GetGlobalElementNum(int local_element_num) const; + /** The following functions define global indices for all local vertices, + edges, faces, or elements. The global indices have no meaning or + significance for ParMesh, but can be used for purposes beyond this class. + */ + /// AMR meshes are not supported. + void GetGlobalVertexIndices(Array &gi) const; + /// AMR meshes are not supported. + void GetGlobalEdgeIndices(Array &gi) const; + /// AMR meshes are not supported. + void GetGlobalFaceIndices(Array &gi) const; + /// AMR meshes are supported. + void GetGlobalElementIndices(Array &gi) const; + GroupTopology gtopo; // Face-neighbor elements and vertices @@ -293,6 +321,7 @@ public: int ordering = 1); int GetNFaceNeighbors() const { return face_nbr_group.Size(); } + int GetNFaceNeighborElements() const { return face_nbr_elements.Size(); } int GetFaceNbrGroup(int fn) const { return face_nbr_group[fn]; } int GetFaceNbrRank(int fn) const; @@ -342,6 +371,9 @@ public: for 0 <= i < GetNE(). */ void Rebalance(const Array &partition); + /// Save the mesh in a parallel mesh format. + void ParPrint(std::ostream &out) const; + /** Print the part of the mesh in the calling processor adding the interface as boundary (for visualization purposes) using the mfem v1.0 format. */ virtual void Print(std::ostream &out = mfem::out) const; @@ -365,6 +397,19 @@ public: /// Old mesh format (Netgen/Truegrid) version of 'PrintAsOne' void PrintAsOneXG(std::ostream &out = mfem::out); + /** Print the mesh in parallel PVTU format. The PVTU and VTU files will be + stored in the directory specified by @a pathname. If the directory does + not exist, it will be created. */ + virtual void PrintVTU(std::string pathname, + VTKFormat format=VTKFormat::ASCII, + bool high_order_output=false, + int compression_level=0, + bool bdr=false); + + /// Parallel version of Mesh::Load(). + virtual void Load(std::istream &input, int generate_edges = 0, + int refine = 1, bool fix_orientation = true); + /// Returns the minimum and maximum corners of the mesh bounding box. For /// high-order meshes, the geometry is refined first "ref" times. void GetBoundingBox(Vector &p_min, Vector &p_max, int ref = 2); @@ -375,18 +420,6 @@ public: /// Print various parallel mesh stats virtual void PrintInfo(std::ostream &out = mfem::out); - /// Save the mesh in a parallel mesh format. - void ParPrint(std::ostream &out) const; - - /** Print the mesh in parallel PVTU format. The PVTU and VTU files will be - stored in the directory specified by @a pathname. If the directory does - not exist, it will be created. */ - virtual void PrintVTU(std::string pathname, - VTKFormat format=VTKFormat::ASCII, - bool high_order_output=false, - int compression_level=0, - bool bdr=false); - virtual int FindPoints(DenseMatrix& point_mat, Array& elem_ids, Array& ips, bool warn = true, InverseElementTransformation *inv_trans = NULL); @@ -400,7 +433,6 @@ public: #ifdef MFEM_USE_PUMI friend class ParPumiMesh; #endif - #ifdef MFEM_USE_ADIOS2 friend class adios2stream; #endif diff --git a/mesh/pncmesh.cpp b/mesh/pncmesh.cpp index 624c48d200..a6e5d5a312 100644 --- a/mesh/pncmesh.cpp +++ b/mesh/pncmesh.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -46,12 +46,38 @@ ParNCMesh::ParNCMesh(MPI_Comm comm, const NCMesh &ncmesh, int *part) // branches that only contain someone else's leaves (see Prune()) } +ParNCMesh::ParNCMesh(MPI_Comm comm, std::istream &input, int version, + int &curved) + : NCMesh(input, version, curved) +{ + MyComm = comm; + MPI_Comm_size(MyComm, &NRanks); + + int my_rank; + MPI_Comm_rank(MyComm, &my_rank); + + int max_rank = 0; + for (int i = 0; i < leaf_elements.Size(); i++) + { + max_rank = std::max(elements[leaf_elements[i]].rank, max_rank); + } + + MFEM_VERIFY((my_rank == MyRank) && (max_rank < NRanks), + "Parallel mesh file doesn't seem to match current MPI setup. " + "Loading a parallel NC mesh with a non-matching communicator " + "size is not supported."); + + bool iso = Iso; + MPI_Allreduce(&iso, &Iso, 1, MPI_C_BOOL, MPI_LAND, MyComm); + + Update(); +} + ParNCMesh::ParNCMesh(const ParNCMesh &other) // copy primary data only : NCMesh(other) , MyComm(other.MyComm) , NRanks(other.NRanks) - , MyRank(other.MyRank) { Update(); // mark all secondary stuff for recalculation } @@ -89,186 +115,6 @@ void ParNCMesh::Update() boundary_layer.SetSize(0); } -void ParNCMesh::AssignLeafIndices() -{ - // This is an override of NCMesh::AssignLeafIndices(). The difference is - // that we shift all elements we own to the beginning of the array - // 'leaf_elements' and assign all ghost elements indices >= NElements. - - // Also note that the ordering of ghosts and non-ghosts is preserved here, - // which is important for ParNCMesh::GetFaceNeighbors. - - // We store the original leaf ordering in 'leaf_glob_order'. This is later - // used (and deleted) in GetConformingSharedStructures - - NCMesh::AssignLeafIndices(); // original numbering, for 'leaf_glob_order' - - int nleafs = leaf_elements.Size(); - - Array ghosts; - ghosts.Reserve(nleafs); - - NElements = 0; - for (int i = 0; i < nleafs; i++) - { - int elem = leaf_elements[i]; - if (elements[elem].rank == MyRank) - { - leaf_elements[NElements++] = elem; - } - else - { - ghosts.Append(elem); - } - } - NGhostElements = ghosts.Size(); - - leaf_elements.SetSize(NElements); - leaf_elements.Append(ghosts); - - // store original (globally consistent) numbering in 'leaf_glob_order' - leaf_glob_order.SetSize(nleafs); - for (int i = 0; i < nleafs; i++) - { - leaf_glob_order[i] = elements[leaf_elements[i]].index; - } - - // new numbering with ghost shifted to the back - NCMesh::AssignLeafIndices(); -} - -void ParNCMesh::UpdateVertices() -{ - // This is an override of NCMesh::UpdateVertices. This version first - // assigns vert_index to vertices of elements of our rank. Only these - // vertices then make it to the Mesh in NCMesh::GetMeshComponents. - // The remaining (ghost) vertices are assigned indices greater or equal to - // Mesh::GetNV(). - - for (node_iterator node = nodes.begin(); node != nodes.end(); ++node) - { - if (node->HasVertex()) { node->vert_index = -1; } - } - - NVertices = 0; - for (int i = 0; i < leaf_elements.Size(); i++) - { - Element &el = elements[leaf_elements[i]]; - if (el.rank == MyRank) - { - for (int j = 0; j < GI[el.Geom()].nv; j++) - { - int &vindex = nodes[el.node[j]].vert_index; - if (vindex < 0) { vindex = NVertices++; } - } - } - } - - vertex_nodeId.SetSize(NVertices); - for (node_iterator node = nodes.begin(); node != nodes.end(); ++node) - { - if (node->HasVertex() && node->vert_index >= 0) - { - vertex_nodeId[node->vert_index] = node.index(); - } - } - - NGhostVertices = 0; - for (node_iterator node = nodes.begin(); node != nodes.end(); ++node) - { - if (node->HasVertex() && node->vert_index < 0) - { - node->vert_index = NVertices + (NGhostVertices++); - } - } -} - -void ParNCMesh::OnMeshUpdated(Mesh *mesh) -{ - // This is an override (or extension of) NCMesh::OnMeshUpdated(). - // In addition to getting edge/face indices from 'mesh', we also - // assign indices to ghost edges/faces that don't exist in the 'mesh'. - - // clear edge_index and Face::index - for (node_iterator node = nodes.begin(); node != nodes.end(); ++node) - { - if (node->HasEdge()) { node->edge_index = -1; } - } - for (face_iterator face = faces.begin(); face != faces.end(); ++face) - { - face->index = -1; - } - - // go assign existing edge/face indices - NCMesh::OnMeshUpdated(mesh); - - // count ghost edges and assign their indices - NEdges = mesh->GetNEdges(); - NGhostEdges = 0; - for (node_iterator node = nodes.begin(); node != nodes.end(); ++node) - { - if (node->HasEdge() && node->edge_index < 0) - { - node->edge_index = NEdges + (NGhostEdges++); - } - } - - // count ghost faces - NFaces = mesh->GetNumFaces(); - NGhostFaces = 0; - for (face_iterator face = faces.begin(); face != faces.end(); ++face) - { - if (face->index < 0) { NGhostFaces++; } - } - - if (Dim == 2) - { - // in 2D we have fake faces because of DG - MFEM_ASSERT(NFaces == NEdges, ""); - MFEM_ASSERT(NGhostFaces == NGhostEdges, ""); - } - - // resize face_geom (default_geom is for slave faces beyond the ghost layer) - Geometry::Type default_geom = Geometry::SQUARE; - face_geom.SetSize(NFaces + NGhostFaces, default_geom); - - // update 'face_geom' for ghost faces, assign ghost face indices - int nghosts = 0; - for (int i = 0; i < NGhostElements; i++) - { - Element &el = elements[leaf_elements[NElements + i]]; // ghost element - GeomInfo &gi = GI[el.Geom()]; - - for (int j = 0; j < gi.nf; j++) - { - const int *fv = gi.faces[j]; - Face* face = faces.Find(el.node[fv[0]], el.node[fv[1]], - el.node[fv[2]], el.node[fv[3]]); - MFEM_ASSERT(face, "face not found!"); - - if (face->index < 0) - { - face->index = NFaces + (nghosts++); - - // store the face geometry - static const Geometry::Type types[5] = - { - Geometry::INVALID, Geometry::INVALID, - Geometry::SEGMENT, Geometry::TRIANGLE, Geometry::SQUARE - }; - face_geom[face->index] = types[gi.nfv[j]]; - } - } - } - - // assign valid indices also to faces beyond the ghost layer - for (face_iterator face = faces.begin(); face != faces.end(); ++face) - { - if (face->index < 0) { face->index = NFaces + (nghosts++); } - } - MFEM_ASSERT(nghosts == NGhostFaces, ""); -} - void ParNCMesh::ElementSharesFace(int elem, int local, int face) { // Analogous to ElementSharesEdge. @@ -286,7 +132,7 @@ void ParNCMesh::ElementSharesFace(int elem, int local, int face) // derive globally consistent face ID from the global element sequence int &el_loc = entity_elem_local[2][f_index]; - if (el_loc < 0 || leaf_glob_order[el.index] < leaf_glob_order[(el_loc >> 4)]) + if (el_loc < 0 || leaf_sfc_index[el.index] < leaf_sfc_index[(el_loc >> 4)]) { el_loc = (el.index << 4) | local; } @@ -294,11 +140,16 @@ void ParNCMesh::ElementSharesFace(int elem, int local, int face) void ParNCMesh::BuildFaceList() { + if (HaveTets()) { GetEdgeList(); } // needed by TraverseTetEdge() + // This is an extension of NCMesh::BuildFaceList() which also determines // face ownership and prepares face processor groups. face_list.Clear(); - if (Dim < 3) { return; } + shared_faces.Clear(); + boundary_faces.SetSize(0); + + if (Dim < 3 || !leaf_elements.Size()) { return; } int nfaces = NFaces + NGhostFaces; @@ -348,7 +199,7 @@ void ParNCMesh::ElementSharesEdge(int elem, int local, int enode) // derive globally consistent edge ID from the global element sequence int &el_loc = entity_elem_local[1][e_index]; - if (el_loc < 0 || leaf_glob_order[el.index] < leaf_glob_order[(el_loc >> 4)]) + if (el_loc < 0 || leaf_sfc_index[el.index] < leaf_sfc_index[(el_loc >> 4)]) { el_loc = (el.index << 4) | local; } @@ -359,6 +210,12 @@ void ParNCMesh::BuildEdgeList() // This is an extension of NCMesh::BuildEdgeList() which also determines // edge ownership and prepares edge processor groups. + edge_list.Clear(); + shared_edges.Clear(); + if (Dim < 3) { boundary_faces.SetSize(0); } + + if (!leaf_elements.Size()) { return; } + int nedges = NEdges + NGhostEdges; tmp_owner.SetSize(nedges); @@ -403,7 +260,7 @@ void ParNCMesh::ElementSharesVertex(int elem, int local, int vnode) // derive globally consistent vertex ID from the global element sequence int &el_loc = entity_elem_local[0][v_index]; - if (el_loc < 0 || leaf_glob_order[el.index] < leaf_glob_order[(el_loc >> 4)]) + if (el_loc < 0 || leaf_sfc_index[el.index] < leaf_sfc_index[(el_loc >> 4)]) { el_loc = (el.index << 4) | local; } @@ -723,7 +580,7 @@ void ParNCMesh::CalcFaceOrientations() face_orient.SetSize(NFaces); face_orient = 0; - for (face_iterator face = faces.begin(); face != faces.end(); ++face) + for (auto face = faces.begin(); face != faces.end(); ++face) { if (face->elem[0] >= 0 && face->elem[1] >= 0 && face->index < NFaces) { @@ -917,10 +774,10 @@ void ParNCMesh::MakeSharedTable(int ngroups, int ent, Array &shared_local, int el_loc_a = entity_elem_local[ent][shared_local[a]]; int el_loc_b = entity_elem_local[ent][shared_local[b]]; - int lgo_a = leaf_glob_order[el_loc_a >> 4]; - int lgo_b = leaf_glob_order[el_loc_b >> 4]; + int lsi_a = leaf_sfc_index[el_loc_a >> 4]; + int lsi_b = leaf_sfc_index[el_loc_b >> 4]; - if (lgo_a != lgo_b) { return lgo_a < lgo_b; } + if (lsi_a != lsi_b) { return lsi_a < lsi_b; } return (el_loc_a & 0xf) < (el_loc_b & 0xf); }); @@ -929,16 +786,15 @@ void ParNCMesh::MakeSharedTable(int ngroups, int ent, Array &shared_local, void ParNCMesh::GetConformingSharedStructures(ParMesh &pmesh) { - // make sure we have entity_conf_group[x] and the ordering arrays if (leaf_elements.Size()) { + // make sure we have entity_conf_group[x] and the ordering arrays for (int ent = 0; ent < Dim; ent++) { GetSharedList(ent); MFEM_VERIFY(entity_conf_group[ent].Size(), "internal error"); MFEM_VERIFY(entity_elem_local[ent].Size(), "internal error"); } - MFEM_VERIFY(leaf_glob_order.Size(), "internal error"); } // create ParMesh groups, and the map (ncmesh_group -> pmesh_group) @@ -1025,7 +881,6 @@ void ParNCMesh::GetConformingSharedStructures(ParMesh &pmesh) entity_conf_group[ent].DeleteAll(); entity_elem_local[ent].DeleteAll(); } - leaf_glob_order.DeleteAll(); } void ParNCMesh::GetFaceNeighbors(ParMesh &pmesh) @@ -1143,15 +998,16 @@ void ParNCMesh::GetFaceNeighbors(ParMesh &pmesh) // create vertices in 'face_nbr_vertices' { pmesh.face_nbr_vertices.SetSize(vert_map.size()); - tmp_vertex = new TmpVertex[nodes.NumIds()]; // TODO: something cheaper? - - std::map::iterator it; - for (it = vert_map.begin(); it != vert_map.end(); ++it) + if (coordinates.Size()) { - pmesh.face_nbr_vertices[it->second-1].SetCoords( - spaceDim, CalcVertexPos(it->first)); + tmp_vertex = new TmpVertex[nodes.NumIds()]; // TODO: something cheaper? + for (auto it = vert_map.begin(); it != vert_map.end(); ++it) + { + pmesh.face_nbr_vertices[it->second-1].SetCoords( + spaceDim, CalcVertexPos(it->first)); + } + delete [] tmp_vertex; } - delete [] tmp_vertex; } // make the 'send_face_nbr_elements' table @@ -1836,7 +1692,6 @@ void ParNCMesh::Rebalance(const Array *custom_partition) Array new_ranks; custom_partition->Copy(new_ranks); - new_ranks.SetSize(leaf_elements.Size(), -1); // make room for ghosts RedistributeElements(new_ranks, -1, true); @@ -2925,7 +2780,6 @@ long ParNCMesh::MemoryUsage(bool with_base) const arrays_memory_usage(entity_owner) + arrays_memory_usage(entity_pmat_group) + arrays_memory_usage(entity_conf_group) + - leaf_glob_order.MemoryUsage() + arrays_memory_usage(entity_elem_local) + shared_vertices.MemoryUsage() + shared_edges.MemoryUsage() + @@ -2953,7 +2807,6 @@ int ParNCMesh::PrintMemoryDetail(bool with_base) const << arrays_memory_usage(entity_owner) << " entity_owner\n" << arrays_memory_usage(entity_pmat_group) << " entity_pmat_group\n" << arrays_memory_usage(entity_conf_group) << " entity_conf_group\n" - << leaf_glob_order.MemoryUsage() << " leaf_glob_order\n" << arrays_memory_usage(entity_elem_local) << " entity_elem_local\n" << shared_vertices.MemoryUsage() << " shared_vertices\n" << shared_edges.MemoryUsage() << " shared_edges\n" diff --git a/mesh/pncmesh.hpp b/mesh/pncmesh.hpp index 5a7df99895..028b87f3af 100644 --- a/mesh/pncmesh.hpp +++ b/mesh/pncmesh.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -64,8 +64,15 @@ class FiniteElementSpace; class ParNCMesh : public NCMesh { public: + /// Construct by partitioning a serial NCMesh. + /** SFC partitioning is used by default. A user-specified partition can be + passed in 'part', where part[i] is the desired MPI rank for element i. */ ParNCMesh(MPI_Comm comm, const NCMesh& ncmesh, int* part = NULL); + /// Load from a stream. The id header is assumed to have been read already. + ParNCMesh(MPI_Comm comm, std::istream &input, int version, int &curved); + + /// Deep copy of another instance. ParNCMesh(const ParNCMesh &other); virtual ~ParNCMesh(); @@ -252,10 +259,7 @@ protected: // interface for ParMesh protected: // implementation MPI_Comm MyComm; - int NRanks, MyRank; - - int NGhostVertices, NGhostEdges, NGhostFaces; - int NElements, NGhostElements; + int NRanks; typedef std::vector GroupList; typedef std::map GroupMap; @@ -271,7 +275,7 @@ protected: // implementation // ParMesh-compatible (conforming) groups for each vertex/edge/face (0/1/2) Array entity_conf_group[3]; // ParMesh compatibility helper arrays to order groups, also temporary - Array leaf_glob_order, entity_elem_local[3]; + Array entity_elem_local[3]; // lists of vertices/edges/faces shared by us and at least one more processor NCList shared_vertices, shared_edges, shared_faces; @@ -291,9 +295,6 @@ protected: // implementation virtual void Update(); - virtual bool IsGhost(const Element& el) const - { return el.rank != MyRank; } - virtual int GetNumGhostElements() const { return NGhostElements; } virtual int GetNumGhostVertices() const { return NGhostVertices; } @@ -309,10 +310,6 @@ protected: // implementation long PartitionFirstIndex(int rank, long total_elements) const { return (rank * total_elements + NRanks-1) / NRanks; } - virtual void UpdateVertices(); - virtual void AssignLeafIndices(); - virtual void OnMeshUpdated(Mesh *mesh); - virtual void BuildFaceList(); virtual void BuildEdgeList(); virtual void BuildVertexList(); diff --git a/mesh/point.cpp b/mesh/point.cpp index af76196cd9..1472b7e377 100644 --- a/mesh/point.cpp +++ b/mesh/point.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/mesh/point.hpp b/mesh/point.hpp index 5374104bd5..4990911b5d 100644 --- a/mesh/point.hpp +++ b/mesh/point.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/mesh/pumi.cpp b/mesh/pumi.cpp index 106699e499..9a972294b6 100644 --- a/mesh/pumi.cpp +++ b/mesh/pumi.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/mesh/pumi.hpp b/mesh/pumi.hpp index 2cd831457d..b661fbf114 100644 --- a/mesh/pumi.hpp +++ b/mesh/pumi.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/mesh/quadrilateral.cpp b/mesh/quadrilateral.cpp index 765709357d..e0665495a8 100644 --- a/mesh/quadrilateral.cpp +++ b/mesh/quadrilateral.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/mesh/quadrilateral.hpp b/mesh/quadrilateral.hpp index 33dc6d70b7..6ea060b442 100644 --- a/mesh/quadrilateral.hpp +++ b/mesh/quadrilateral.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/mesh/segment.cpp b/mesh/segment.cpp index c27793aa31..ae4129a474 100644 --- a/mesh/segment.cpp +++ b/mesh/segment.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/mesh/segment.hpp b/mesh/segment.hpp index f3af100ac2..d6af294c4c 100644 --- a/mesh/segment.hpp +++ b/mesh/segment.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/mesh/tetrahedron.cpp b/mesh/tetrahedron.cpp index 1894a36e63..6f51250438 100644 --- a/mesh/tetrahedron.cpp +++ b/mesh/tetrahedron.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/mesh/tetrahedron.hpp b/mesh/tetrahedron.hpp index 52d12f019c..de82045180 100644 --- a/mesh/tetrahedron.hpp +++ b/mesh/tetrahedron.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/mesh/tmesh.hpp b/mesh/tmesh.hpp index 3f9ae59f9f..09c50c15cb 100644 --- a/mesh/tmesh.hpp +++ b/mesh/tmesh.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/mesh/triangle.cpp b/mesh/triangle.cpp index ed0c401412..5d37f2f328 100644 --- a/mesh/triangle.cpp +++ b/mesh/triangle.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/mesh/triangle.hpp b/mesh/triangle.hpp index ab65d33e13..2cf4327b83 100644 --- a/mesh/triangle.hpp +++ b/mesh/triangle.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/mesh/vertex.cpp b/mesh/vertex.cpp index b41ef13417..eac8770b3f 100644 --- a/mesh/vertex.cpp +++ b/mesh/vertex.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/mesh/vertex.hpp b/mesh/vertex.hpp index db9791b9ec..f44bfc2fa8 100644 --- a/mesh/vertex.hpp +++ b/mesh/vertex.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/mesh/vtk.cpp b/mesh/vtk.cpp index c57bfe5162..8ce50c0b68 100644 --- a/mesh/vtk.cpp +++ b/mesh/vtk.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -18,7 +18,137 @@ namespace mfem { -const int vtk_prism_perm[6] = {0, 2, 1, 3, 5, 4}; +const int VTKGeometry::Map[Geometry::NUM_GEOMETRIES] = +{ + POINT, SEGMENT, TRIANGLE, SQUARE, TETRAHEDRON, CUBE, PRISM +}; + +const int VTKGeometry::QuadraticMap[Geometry::NUM_GEOMETRIES] = +{ + POINT, QUADRATIC_SEGMENT, QUADRATIC_TRIANGLE, BIQUADRATIC_SQUARE, + QUADRATIC_TETRAHEDRON, TRIQUADRATIC_CUBE, BIQUADRATIC_QUADRATIC_PRISM +}; + +const int VTKGeometry::HighOrderMap[Geometry::NUM_GEOMETRIES] = +{ + POINT, LAGRANGE_SEGMENT, LAGRANGE_TRIANGLE, LAGRANGE_SQUARE, + LAGRANGE_TETRAHEDRON, LAGRANGE_CUBE, LAGRANGE_PRISM +}; + +const int VTKGeometry::PrismMap[6] = {0, 2, 1, 3, 5, 4}; + +const int *VTKGeometry::VertexPermutation[Geometry::NUM_GEOMETRIES] = +{ + NULL, NULL, NULL, NULL, NULL, NULL, VTKGeometry::PrismMap +}; + +Geometry::Type VTKGeometry::GetMFEMGeometry(int vtk_geom) +{ + switch (vtk_geom) + { + case POINT: + return Geometry::POINT; + case SEGMENT: + case QUADRATIC_SEGMENT: + case LAGRANGE_SEGMENT: + return Geometry::SEGMENT; + case TRIANGLE: + case QUADRATIC_TRIANGLE: + case LAGRANGE_TRIANGLE: + return Geometry::TRIANGLE; + case SQUARE: + case BIQUADRATIC_SQUARE: + case LAGRANGE_SQUARE: + return Geometry::SQUARE; + case TETRAHEDRON: + case QUADRATIC_TETRAHEDRON: + case LAGRANGE_TETRAHEDRON: + return Geometry::TETRAHEDRON; + case CUBE: + case TRIQUADRATIC_CUBE: + case LAGRANGE_CUBE: + return Geometry::CUBE; + case PRISM: + case BIQUADRATIC_QUADRATIC_PRISM: + case LAGRANGE_PRISM: + return Geometry::PRISM; + default: + return Geometry::INVALID; + } +} + +bool VTKGeometry::IsLagrange(int vtk_geom) +{ + return vtk_geom >= LAGRANGE_SEGMENT && vtk_geom <= LAGRANGE_PRISM; +} + +bool VTKGeometry::IsQuadratic(int vtk_geom) +{ + return vtk_geom >= QUADRATIC_SEGMENT + && vtk_geom <= BIQUADRATIC_QUADRATIC_PRISM; +} + +int VTKGeometry::GetOrder(int vtk_geom, int npoints) +{ + if (IsQuadratic(vtk_geom)) + { + return 2; + } + else if (IsLagrange(vtk_geom)) + { + switch (vtk_geom) + { + case LAGRANGE_SEGMENT: + return npoints - 1; + case LAGRANGE_TRIANGLE: + return (std::sqrt(8*npoints + 1) - 3)/2; + case LAGRANGE_SQUARE: + return std::round(std::sqrt(npoints)) - 1; + case LAGRANGE_TETRAHEDRON: + switch (npoints) + { + // Note that for given order, npoints is given by + // npoints_order = (order + 1)*(order + 2)*(order + 3)/6, + case 4: return 1; + case 10: return 2; + case 20: return 3; + case 35: return 4; + case 56: return 5; + case 84: return 6; + case 120: return 7; + case 165: return 8; + case 220: return 9; + case 286: return 10; + default: + { + constexpr int max_order = 20; + int order = 11, npoints_order; + for (; order &con, Geometry::Type geom, int ref) { int idx = 0; int b[4]; - for (int k=0; k<=ref; k++) + for (b[2]=0; b[2]<=ref; b[2]++) { - for (int j=0; j<=k; j++) + for (b[1]=0; b[1]<=ref-b[2]; b[1]++) { - for (int i=0; i<=j; i++) + for (b[0]=0; b[0]<=ref-b[1]-b[2]; b[0]++) { - b[0] = k-j; - b[1] = i; - b[2] = j-i; b[3] = ref-b[0]-b[1]-b[2]; con[BarycentricToVTKTetra(b, ref)] = idx++; } diff --git a/mesh/vtk.hpp b/mesh/vtk.hpp index 771f521748..7b425f68b6 100644 --- a/mesh/vtk.hpp +++ b/mesh/vtk.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -17,7 +17,46 @@ namespace mfem { -// Helpers for writing to the VTK format +// Helpers for reading and writing VTK format + +// VTK element types defined at: https://git.io/JvZLm +struct VTKGeometry +{ + static const int POINT = 1; + static const int SEGMENT = 3; + static const int TRIANGLE = 5; + static const int SQUARE = 9; + static const int TETRAHEDRON = 10; + static const int CUBE = 12; + static const int PRISM = 13; + + static const int QUADRATIC_SEGMENT = 21; + static const int QUADRATIC_TRIANGLE = 22; + static const int BIQUADRATIC_SQUARE = 28; + static const int QUADRATIC_TETRAHEDRON = 24; + static const int TRIQUADRATIC_CUBE = 29; + static const int QUADRATIC_PRISM = 26; + static const int BIQUADRATIC_QUADRATIC_PRISM = 32; + + static const int LAGRANGE_SEGMENT = 68; + static const int LAGRANGE_TRIANGLE = 69; + static const int LAGRANGE_SQUARE = 70; + static const int LAGRANGE_TETRAHEDRON = 71; + static const int LAGRANGE_CUBE = 72; + static const int LAGRANGE_PRISM = 73; + + static const int PrismMap[6]; + static const int *VertexPermutation[Geometry::NUM_GEOMETRIES]; + + static const int Map[Geometry::NUM_GEOMETRIES]; + static const int QuadraticMap[Geometry::NUM_GEOMETRIES]; + static const int HighOrderMap[Geometry::NUM_GEOMETRIES]; + + static Geometry::Type GetMFEMGeometry(int vtk_geom); + static bool IsLagrange(int vtk_geom); + static bool IsQuadratic(int vtk_geom); + static int GetOrder(int vtk_geom, int npoints); +}; enum class VTKFormat { @@ -26,8 +65,6 @@ enum class VTKFormat BINARY32 }; -extern const int vtk_prism_perm[6]; - /// Create the VTK element connectivity array for a given element geometry and /// refinement level. Converts node numbers from MFEM to VTK ordering. void CreateVTKElementConnectivity(Array &con, Geometry::Type geom, diff --git a/mesh/wedge.cpp b/mesh/wedge.cpp index b0f8a3c6e0..f77e6cace2 100644 --- a/mesh/wedge.cpp +++ b/mesh/wedge.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/mesh/wedge.hpp b/mesh/wedge.hpp index 93b94639ef..cf3a0e29d6 100644 --- a/mesh/wedge.hpp +++ b/mesh/wedge.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/mfem-performance.hpp b/mfem-performance.hpp index e41d747c2c..f2bfc2960a 100644 --- a/mfem-performance.hpp +++ b/mfem-performance.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/mfem.hpp b/mfem.hpp index 0e68ce6a05..fbf33d6483 100644 --- a/mfem.hpp +++ b/mfem.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/CMakeLists.txt b/miniapps/CMakeLists.txt index 2f3c3172ff..9c5e5d8f5e 100644 --- a/miniapps/CMakeLists.txt +++ b/miniapps/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # @@ -26,3 +26,4 @@ add_subdirectory(tools) add_subdirectory(toys) add_subdirectory(nurbs) add_subdirectory(gslib) +add_subdirectory(solvers) diff --git a/miniapps/adjoint/CMakeLists.txt b/miniapps/adjoint/CMakeLists.txt index fefcb63bcd..c08cee7b73 100644 --- a/miniapps/adjoint/CMakeLists.txt +++ b/miniapps/adjoint/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/miniapps/adjoint/adjoint_advection_diffusion.cpp b/miniapps/adjoint/adjoint_advection_diffusion.cpp index 88580edddc..a603826f98 100644 --- a/miniapps/adjoint/adjoint_advection_diffusion.cpp +++ b/miniapps/adjoint/adjoint_advection_diffusion.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/adjoint/cvsRoberts_ASAi_dns.cpp b/miniapps/adjoint/cvsRoberts_ASAi_dns.cpp index 07a5650b11..a1c9dafcb2 100644 --- a/miniapps/adjoint/cvsRoberts_ASAi_dns.cpp +++ b/miniapps/adjoint/cvsRoberts_ASAi_dns.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/adjoint/makefile b/miniapps/adjoint/makefile index 3de6dce8ca..df514be511 100644 --- a/miniapps/adjoint/makefile +++ b/miniapps/adjoint/makefile @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/miniapps/common/CMakeLists.txt b/miniapps/common/CMakeLists.txt index 105049a427..361d6542ec 100644 --- a/miniapps/common/CMakeLists.txt +++ b/miniapps/common/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # @@ -29,6 +29,9 @@ endif() if (MFEM_USE_CUDA) set_property(SOURCE ${SRCS} PROPERTY LANGUAGE CUDA) endif() +if (MFEM_USE_HIP) + set_property(SOURCE ${SRCS} PROPERTY HIP_SOURCE_PROPERTY_FORMAT TRUE) +endif() convert_filenames_to_full_paths(SRCS) convert_filenames_to_full_paths(HDRS) @@ -36,5 +39,5 @@ convert_filenames_to_full_paths(HDRS) set(MINIAPPS_COMMON_SOURCES ${MINIAPPS_COMMON_SOURCES} ${SRCS} PARENT_SCOPE) set(MINIAPPS_COMMON_HEADERS ${MINIAPPS_COMMON_HEADERS} ${HDRS} PARENT_SCOPE) -add_library(mfem-common ${SRCS} ${HDRS}) +mfem_add_library(mfem-common ${SRCS} ${HDRS}) target_link_libraries(mfem-common mfem) diff --git a/miniapps/common/fem_extras.cpp b/miniapps/common/fem_extras.cpp index 4ec3cddcc2..fddab6b54d 100644 --- a/miniapps/common/fem_extras.cpp +++ b/miniapps/common/fem_extras.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/common/fem_extras.hpp b/miniapps/common/fem_extras.hpp index d2e1897285..7fa0a95341 100644 --- a/miniapps/common/fem_extras.hpp +++ b/miniapps/common/fem_extras.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/common/makefile b/miniapps/common/makefile index be9c4edebe..7d949e5dcc 100644 --- a/miniapps/common/makefile +++ b/miniapps/common/makefile @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/miniapps/common/mesh_extras.cpp b/miniapps/common/mesh_extras.cpp index 1f4214684f..c38ef596fc 100644 --- a/miniapps/common/mesh_extras.cpp +++ b/miniapps/common/mesh_extras.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/common/mesh_extras.hpp b/miniapps/common/mesh_extras.hpp index 786d7e4eb2..050ecbfff2 100644 --- a/miniapps/common/mesh_extras.hpp +++ b/miniapps/common/mesh_extras.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/common/mfem-common.hpp b/miniapps/common/mfem-common.hpp index dfaf3f7581..f064a9c48e 100644 --- a/miniapps/common/mfem-common.hpp +++ b/miniapps/common/mfem-common.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/common/pfem_extras.cpp b/miniapps/common/pfem_extras.cpp index 2cca1a2470..10f8987da5 100644 --- a/miniapps/common/pfem_extras.cpp +++ b/miniapps/common/pfem_extras.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/common/pfem_extras.hpp b/miniapps/common/pfem_extras.hpp index 5cbb687b75..fc40d0790b 100644 --- a/miniapps/common/pfem_extras.hpp +++ b/miniapps/common/pfem_extras.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/electromagnetics/CMakeLists.txt b/miniapps/electromagnetics/CMakeLists.txt index 8beab290fc..0f431f8ff8 100644 --- a/miniapps/electromagnetics/CMakeLists.txt +++ b/miniapps/electromagnetics/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/miniapps/electromagnetics/cylinder-hex.mesh b/miniapps/electromagnetics/cylinder-hex.mesh index 39aaef38eb..af7e13fdbe 100644 --- a/miniapps/electromagnetics/cylinder-hex.mesh +++ b/miniapps/electromagnetics/cylinder-hex.mesh @@ -1,845 +1,845 @@ -MFEM mesh v1.1 - -# -# MFEM Geometry Types (see mesh/geom.hpp): -# -# POINT = 0 -# SEGMENT = 1 -# TRIANGLE = 2 -# SQUARE = 3 -# TETRAHEDRON = 4 -# CUBE = 5 -# - -dimension -3 - -elements -252 -1 5 0 1 2 3 4 5 6 7 -1 5 8 9 1 0 10 11 5 4 -1 5 12 8 0 3 13 10 4 7 -1 5 14 3 2 15 16 7 6 17 -1 5 18 12 3 14 19 13 7 16 -1 5 20 18 14 15 21 19 16 17 -1 5 22 15 2 23 24 17 6 25 -1 5 26 20 15 22 27 21 17 24 -1 5 28 26 22 23 29 27 24 25 -1 5 30 23 2 1 31 25 6 5 -1 5 32 28 23 30 33 29 25 31 -1 5 9 32 30 1 11 33 31 5 -1 5 34 35 36 37 0 1 2 3 -1 5 38 39 35 34 8 9 1 0 -1 5 40 38 34 37 12 8 0 3 -1 5 41 37 36 42 14 3 2 15 -1 5 43 40 37 41 18 12 3 14 -1 5 44 43 41 42 20 18 14 15 -1 5 45 42 36 46 22 15 2 23 -1 5 47 44 42 45 26 20 15 22 -1 5 48 47 45 46 28 26 22 23 -1 5 49 46 36 35 30 23 2 1 -1 5 50 48 46 49 32 28 23 30 -1 5 39 50 49 35 9 32 30 1 -1 5 51 52 53 54 34 35 36 37 -1 5 55 56 52 51 38 39 35 34 -1 5 57 55 51 54 40 38 34 37 -1 5 58 54 53 59 41 37 36 42 -1 5 60 57 54 58 43 40 37 41 -1 5 61 60 58 59 44 43 41 42 -1 5 62 59 53 63 45 42 36 46 -1 5 64 61 59 62 47 44 42 45 -1 5 65 64 62 63 48 47 45 46 -1 5 66 63 53 52 49 46 36 35 -1 5 67 65 63 66 50 48 46 49 -1 5 56 67 66 52 39 50 49 35 -1 5 68 69 70 71 72 73 74 75 -1 5 28 76 69 68 29 77 73 72 -1 5 26 28 68 71 27 29 72 75 -1 5 78 71 70 79 80 75 74 81 -1 5 20 26 71 78 21 27 75 80 -1 5 82 20 78 79 83 21 80 81 -1 5 84 79 70 85 86 81 74 87 -1 5 88 82 79 84 89 83 81 86 -1 5 90 88 84 85 91 89 86 87 -1 5 92 85 70 69 93 87 74 73 -1 5 94 90 85 92 95 91 87 93 -1 5 76 94 92 69 77 95 93 73 -1 5 96 97 98 99 68 69 70 71 -1 5 48 100 97 96 28 76 69 68 -1 5 47 48 96 99 26 28 68 71 -1 5 101 99 98 102 78 71 70 79 -1 5 44 47 99 101 20 26 71 78 -1 5 103 44 101 102 82 20 78 79 -1 5 104 102 98 105 84 79 70 85 -1 5 106 103 102 104 88 82 79 84 -1 5 107 106 104 105 90 88 84 85 -1 5 108 105 98 97 92 85 70 69 -1 5 109 107 105 108 94 90 85 92 -1 5 100 109 108 97 76 94 92 69 -1 5 110 111 112 113 96 97 98 99 -1 5 65 114 111 110 48 100 97 96 -1 5 64 65 110 113 47 48 96 99 -1 5 115 113 112 116 101 99 98 102 -1 5 61 64 113 115 44 47 99 101 -1 5 117 61 115 116 103 44 101 102 -1 5 118 116 112 119 104 102 98 105 -1 5 120 117 116 118 106 103 102 104 -1 5 121 120 118 119 107 106 104 105 -1 5 122 119 112 111 108 105 98 97 -1 5 123 121 119 122 109 107 105 108 -1 5 114 123 122 111 100 109 108 97 -1 5 124 125 126 127 128 129 130 131 -1 5 90 94 125 124 91 95 129 128 -1 5 132 90 124 127 133 91 128 131 -1 5 134 127 126 135 136 131 130 137 -1 5 138 132 127 134 139 133 131 136 -1 5 140 138 134 135 141 139 136 137 -1 5 142 135 126 143 144 137 130 145 -1 5 146 140 135 142 147 141 137 144 -1 5 28 146 142 143 29 147 144 145 -1 5 148 143 126 125 149 145 130 129 -1 5 76 28 143 148 77 29 145 149 -1 5 94 76 148 125 95 77 149 129 -1 5 150 151 152 153 124 125 126 127 -1 5 107 109 151 150 90 94 125 124 -1 5 154 107 150 153 132 90 124 127 -1 5 155 153 152 156 134 127 126 135 -1 5 157 154 153 155 138 132 127 134 -1 5 158 157 155 156 140 138 134 135 -1 5 159 156 152 160 142 135 126 143 -1 5 161 158 156 159 146 140 135 142 -1 5 48 161 159 160 28 146 142 143 -1 5 162 160 152 151 148 143 126 125 -1 5 100 48 160 162 76 28 143 148 -1 5 109 100 162 151 94 76 148 125 -1 5 163 164 165 166 150 151 152 153 -1 5 121 123 164 163 107 109 151 150 -1 5 167 121 163 166 154 107 150 153 -1 5 168 166 165 169 155 153 152 156 -1 5 170 167 166 168 157 154 153 155 -1 5 171 170 168 169 158 157 155 156 -1 5 172 169 165 173 159 156 152 160 -1 5 174 171 169 172 161 158 156 159 -1 5 65 174 172 173 48 161 159 160 -1 5 175 173 165 164 162 160 152 151 -1 5 114 65 173 175 100 48 160 162 -1 5 123 114 175 164 109 100 162 151 -1 5 176 177 178 179 180 181 182 183 -1 5 28 32 177 176 29 33 181 180 -1 5 146 28 176 179 147 29 180 183 -1 5 184 179 178 185 186 183 182 187 -1 5 140 146 179 184 141 147 183 186 -1 5 188 140 184 185 189 141 186 187 -1 5 190 185 178 191 192 187 182 193 -1 5 194 188 185 190 195 189 187 192 -1 5 8 194 190 191 10 195 192 193 -1 5 196 191 178 177 197 193 182 181 -1 5 9 8 191 196 11 10 193 197 -1 5 32 9 196 177 33 11 197 181 -1 5 198 199 200 201 176 177 178 179 -1 5 48 50 199 198 28 32 177 176 -1 5 161 48 198 201 146 28 176 179 -1 5 202 201 200 203 184 179 178 185 -1 5 158 161 201 202 140 146 179 184 -1 5 204 158 202 203 188 140 184 185 -1 5 205 203 200 206 190 185 178 191 -1 5 207 204 203 205 194 188 185 190 -1 5 38 207 205 206 8 194 190 191 -1 5 208 206 200 199 196 191 178 177 -1 5 39 38 206 208 9 8 191 196 -1 5 50 39 208 199 32 9 196 177 -1 5 209 210 211 212 198 199 200 201 -1 5 65 67 210 209 48 50 199 198 -1 5 174 65 209 212 161 48 198 201 -1 5 213 212 211 214 202 201 200 203 -1 5 171 174 212 213 158 161 201 202 -1 5 215 171 213 214 204 158 202 203 -1 5 216 214 211 217 205 203 200 206 -1 5 218 215 214 216 207 204 203 205 -1 5 55 218 216 217 38 207 205 206 -1 5 219 217 211 210 208 206 200 199 -1 5 56 55 217 219 39 38 206 208 -1 5 67 56 219 210 50 39 208 199 -2 5 220 90 91 221 222 88 89 223 -2 5 224 220 221 225 226 222 223 227 -2 5 228 224 225 229 230 226 227 231 -2 5 232 107 90 220 233 106 88 222 -2 5 234 232 220 224 235 233 222 226 -2 5 236 234 224 228 237 235 226 230 -2 5 238 121 107 232 239 120 106 233 -2 5 240 238 232 234 241 239 233 235 -2 5 242 240 234 236 243 241 235 237 -2 5 222 88 89 223 244 82 83 245 -2 5 226 222 223 227 246 244 245 247 -2 5 230 226 227 231 248 246 247 249 -2 5 233 106 88 222 250 103 82 244 -2 5 235 233 222 226 251 250 244 246 -2 5 237 235 226 230 252 251 246 248 -2 5 239 120 106 233 253 117 103 250 -2 5 241 239 233 235 254 253 250 251 -2 5 243 241 235 237 255 254 251 252 -2 5 244 82 83 245 256 20 21 257 -2 5 246 244 245 247 258 256 257 259 -2 5 248 246 247 249 260 258 259 261 -2 5 250 103 82 244 262 44 20 256 -2 5 251 250 244 246 263 262 256 258 -2 5 252 251 246 248 264 263 258 260 -2 5 253 117 103 250 265 61 44 262 -2 5 254 253 250 251 266 265 262 263 -2 5 255 254 251 252 267 266 263 264 -2 5 268 132 133 269 220 90 91 221 -2 5 270 268 269 271 224 220 221 225 -2 5 272 270 271 273 228 224 225 229 -2 5 274 154 132 268 232 107 90 220 -2 5 275 274 268 270 234 232 220 224 -2 5 276 275 270 272 236 234 224 228 -2 5 277 167 154 274 238 121 107 232 -2 5 278 277 274 275 240 238 232 234 -2 5 279 278 275 276 242 240 234 236 -2 5 280 138 139 281 268 132 133 269 -2 5 282 280 281 283 270 268 269 271 -2 5 284 282 283 285 272 270 271 273 -2 5 286 157 138 280 274 154 132 268 -2 5 287 286 280 282 275 274 268 270 -2 5 288 287 282 284 276 275 270 272 -2 5 289 170 157 286 277 167 154 274 -2 5 290 289 286 287 278 277 274 275 -2 5 291 290 287 288 279 278 275 276 -2 5 292 140 141 293 280 138 139 281 -2 5 294 292 293 295 282 280 281 283 -2 5 296 294 295 297 284 282 283 285 -2 5 298 158 140 292 286 157 138 280 -2 5 299 298 292 294 287 286 280 282 -2 5 300 299 294 296 288 287 282 284 -2 5 301 171 158 298 289 170 157 286 -2 5 302 301 298 299 290 289 286 287 -2 5 303 302 299 300 291 290 287 288 -2 5 302 303 300 299 304 305 306 307 -2 5 301 302 299 298 308 304 307 309 -2 5 171 301 298 158 215 308 309 204 -2 5 299 300 296 294 307 306 310 311 -2 5 298 299 294 292 309 307 311 312 -2 5 158 298 292 140 204 309 312 188 -2 5 294 296 297 295 311 310 313 314 -2 5 292 294 295 293 312 311 314 315 -2 5 140 292 293 141 188 312 315 189 -2 5 304 305 306 307 316 317 318 319 -2 5 308 304 307 309 320 316 319 321 -2 5 215 308 309 204 218 320 321 207 -2 5 307 306 310 311 319 318 322 323 -2 5 309 307 311 312 321 319 323 324 -2 5 204 309 312 188 207 321 324 194 -2 5 311 310 313 314 323 322 325 326 -2 5 312 311 314 315 324 323 326 327 -2 5 188 312 315 189 194 324 327 195 -2 5 316 317 318 319 328 329 330 331 -2 5 320 316 319 321 332 328 331 333 -2 5 218 320 321 207 55 332 333 38 -2 5 319 318 322 323 331 330 334 335 -2 5 321 319 323 324 333 331 335 336 -2 5 207 321 324 194 38 333 336 8 -2 5 323 322 325 326 335 334 337 338 -2 5 324 323 326 327 336 335 338 339 -2 5 194 324 327 195 8 336 339 10 -2 5 8 336 339 10 12 340 341 13 -2 5 336 335 338 339 340 342 343 341 -2 5 335 334 337 338 342 344 345 343 -2 5 38 333 336 8 40 346 340 12 -2 5 333 331 335 336 346 347 342 340 -2 5 331 330 334 335 347 348 344 342 -2 5 55 332 333 38 57 349 346 40 -2 5 332 328 331 333 349 350 347 346 -2 5 328 329 330 331 350 351 348 347 -2 5 12 340 341 13 18 352 353 19 -2 5 340 342 343 341 352 354 355 353 -2 5 342 344 345 343 354 356 357 355 -2 5 40 346 340 12 43 358 352 18 -2 5 346 347 342 340 358 359 354 352 -2 5 347 348 344 342 359 360 356 354 -2 5 57 349 346 40 60 361 358 43 -2 5 349 350 347 346 361 362 359 358 -2 5 350 351 348 347 362 363 360 359 -2 5 18 352 353 19 20 256 257 21 -2 5 352 354 355 353 256 258 259 257 -2 5 354 356 357 355 258 260 261 259 -2 5 43 358 352 18 44 262 256 20 -2 5 358 359 354 352 262 263 258 256 -2 5 359 360 356 354 263 264 260 258 -2 5 60 361 358 43 61 265 262 44 -2 5 361 362 359 358 265 266 263 262 -2 5 362 363 360 359 266 267 264 263 - -boundary -204 -1 3 11 33 31 5 -1 3 33 29 25 31 -1 3 31 25 6 5 -1 3 29 27 24 25 -1 3 27 21 17 24 -1 3 24 17 6 25 -1 3 21 19 16 17 -1 3 19 13 7 16 -1 3 16 7 6 17 -1 3 13 10 4 7 -1 3 10 11 5 4 -1 3 4 5 6 7 -1 3 77 95 93 73 -1 3 95 91 87 93 -1 3 93 87 74 73 -1 3 91 89 86 87 -1 3 89 83 81 86 -1 3 86 81 74 87 -1 3 83 21 80 81 -1 3 21 27 75 80 -1 3 80 75 74 81 -1 3 27 29 72 75 -1 3 29 77 73 72 -1 3 72 73 74 75 -1 3 95 77 149 129 -1 3 77 29 145 149 -1 3 149 145 130 129 -1 3 29 147 144 145 -1 3 147 141 137 144 -1 3 144 137 130 145 -1 3 141 139 136 137 -1 3 139 133 131 136 -1 3 136 131 130 137 -1 3 133 91 128 131 -1 3 91 95 129 128 -1 3 128 129 130 131 -1 3 33 11 197 181 -1 3 11 10 193 197 -1 3 197 193 182 181 -1 3 10 195 192 193 -1 3 195 189 187 192 -1 3 192 187 182 193 -1 3 189 141 186 187 -1 3 141 147 183 186 -1 3 186 183 182 187 -1 3 147 29 180 183 -1 3 29 33 181 180 -1 3 180 181 182 183 -1 3 337 338 343 345 -1 3 338 339 341 343 -1 3 339 10 13 341 -1 3 345 343 355 357 -1 3 343 341 353 355 -1 3 341 13 19 353 -1 3 357 355 259 261 -1 3 355 353 257 259 -1 3 353 19 21 257 -1 3 91 221 223 89 -1 3 221 225 227 223 -1 3 225 229 231 227 -1 3 89 223 245 83 -1 3 223 227 247 245 -1 3 227 231 249 247 -1 3 83 245 257 21 -1 3 245 247 259 257 -1 3 247 249 261 259 -1 3 271 273 229 225 -1 3 269 271 225 221 -1 3 133 269 221 91 -1 3 283 285 273 271 -1 3 281 283 271 269 -1 3 139 281 269 133 -1 3 295 297 285 283 -1 3 293 295 283 281 -1 3 141 293 281 139 -1 3 327 195 10 339 -1 3 326 327 339 338 -1 3 325 326 338 337 -1 3 315 189 195 327 -1 3 314 315 327 326 -1 3 313 314 326 325 -1 3 293 141 189 315 -1 3 295 293 315 314 -1 3 297 295 314 313 -2 3 110 113 112 111 -2 3 65 110 111 114 -2 3 64 113 110 65 -2 3 115 116 112 113 -2 3 61 115 113 64 -2 3 117 116 115 61 -2 3 118 119 112 116 -2 3 120 118 116 117 -2 3 121 119 118 120 -2 3 122 111 112 119 -2 3 123 122 119 121 -2 3 114 111 122 123 -2 3 51 54 53 52 -2 3 55 51 52 56 -2 3 57 54 51 55 -2 3 58 59 53 54 -2 3 60 58 54 57 -2 3 61 59 58 60 -2 3 62 63 53 59 -2 3 64 62 59 61 -2 3 65 63 62 64 -2 3 66 52 53 63 -2 3 67 66 63 65 -2 3 56 52 66 67 -2 3 209 212 211 210 -2 3 65 209 210 67 -2 3 174 212 209 65 -2 3 213 214 211 212 -2 3 171 213 212 174 -2 3 215 214 213 171 -2 3 216 217 211 214 -2 3 218 216 214 215 -2 3 55 217 216 218 -2 3 219 210 211 217 -2 3 56 219 217 55 -2 3 67 210 219 56 -2 3 163 166 165 164 -2 3 121 163 164 123 -2 3 167 166 163 121 -2 3 168 169 165 166 -2 3 170 168 166 167 -2 3 171 169 168 170 -2 3 172 173 165 169 -2 3 174 172 169 171 -2 3 65 173 172 174 -2 3 175 164 165 173 -2 3 114 175 173 65 -2 3 123 164 175 114 -2 3 242 240 241 243 -2 3 240 238 239 241 -2 3 238 121 120 239 -2 3 243 241 254 255 -2 3 241 239 253 254 -2 3 239 120 117 253 -2 3 255 254 266 267 -2 3 254 253 265 266 -2 3 253 117 61 265 -2 3 55 332 349 57 -2 3 332 328 350 349 -2 3 328 329 351 350 -2 3 57 349 361 60 -2 3 349 350 362 361 -2 3 350 351 363 362 -2 3 60 361 265 61 -2 3 361 362 266 265 -2 3 362 363 267 266 -2 3 316 317 329 328 -2 3 320 316 328 332 -2 3 218 320 332 55 -2 3 304 305 317 316 -2 3 308 304 316 320 -2 3 215 308 320 218 -2 3 302 303 305 304 -2 3 301 302 304 308 -2 3 171 301 308 215 -2 3 277 167 121 238 -2 3 278 277 238 240 -2 3 279 278 240 242 -2 3 289 170 167 277 -2 3 290 289 277 278 -2 3 291 290 278 279 -2 3 301 171 170 289 -2 3 302 301 289 290 -2 3 303 302 290 291 -3 3 279 242 236 276 -3 3 276 236 228 272 -3 3 272 228 229 273 -3 3 291 279 276 288 -3 3 288 276 272 284 -3 3 284 272 273 285 -3 3 303 291 288 300 -3 3 300 288 284 296 -3 3 296 284 285 297 -3 3 228 230 231 229 -3 3 236 237 230 228 -3 3 242 243 237 236 -3 3 230 248 249 231 -3 3 237 252 248 230 -3 3 243 255 252 237 -3 3 248 260 261 249 -3 3 252 264 260 248 -3 3 255 267 264 252 -3 3 329 330 348 351 -3 3 330 334 344 348 -3 3 334 337 345 344 -3 3 351 348 360 363 -3 3 348 344 356 360 -3 3 344 345 357 356 -3 3 363 360 264 267 -3 3 360 356 260 264 -3 3 356 357 261 260 -3 3 322 325 337 334 -3 3 318 322 334 330 -3 3 317 318 330 329 -3 3 310 313 325 322 -3 3 306 310 322 318 -3 3 305 306 318 317 -3 3 296 297 313 310 -3 3 300 296 310 306 -3 3 303 300 306 305 - -vertices -364 -3 --0.39999999999999997 0.10000000000000002 0.16666666666666663 --0.29166666666666663 0.125 0.16666666666666663 --0.2499999999999999 0.25 0.16666666666666663 --0.3415063509461096 0.24999999999999994 0.16666666666666663 --0.39999999999999997 0.1 0.5 --0.29166666666666663 0.125 0.5 --0.24999999999999997 0.25 0.5 --0.3415063509461097 0.24999999999999992 0.5 --0.5 0. 0.16666666666666663 --0.33333333333333337 0. 0.16666666666666663 --0.5 0. 0.5 --0.3333333333333333 0. 0.5 --0.4330127018922194 0.24999999999999983 0.16666666666666663 --0.4330127018922194 0.24999999999999983 0.5 --0.24999999999999994 0.35980762113533155 0.16666666666666663 --0.12499999999999985 0.37500000000000006 0.16666666666666663 --0.2500000000000001 0.3598076211353315 0.5 --0.12499999999999999 0.375 0.5 --0.24999999999999978 0.4330127018922194 0.16666666666666663 --0.2500000000000002 0.4330127018922192 0.5 -0. 0.5 0.16666666666666663 -0. 0.5 0.5 --0.09999999999999998 0.25 0.16666666666666663 --0.12500000000000006 0.12499999999999997 0.16666666666666663 --0.1 0.25 0.5 --0.12499999999999999 0.125 0.5 -0. 0.24999999999999978 0.16666666666666663 -0. 0.25 0.5 -0. 0. 0.16666666666666663 -0. 0. 0.5 --0.2 0.09999999999999999 0.16666666666666663 --0.19999999999999996 0.1 0.5 --0.16666666666666696 0. 0.1666666666666666 --0.16666666666666663 0. 0.5 --0.3999999999999999 0.1 -0.16666666666666669 --0.2916666666666666 0.125 -0.16666666666666669 --0.24999999999999983 0.25000000000000006 -0.1666666666666667 --0.3415063509461095 0.24999999999999994 -0.1666666666666667 --0.5 0. -0.16666666666666669 --0.33333333333333337 0. -0.1666666666666666 --0.4330127018922194 0.24999999999999983 -0.16666666666666677 --0.24999999999999992 0.3598076211353316 -0.1666666666666667 --0.12499999999999982 0.3750000000000001 -0.1666666666666667 --0.24999999999999978 0.4330127018922194 -0.16666666666666674 -0. 0.5 -0.16666666666666669 --0.09999999999999995 0.25 -0.16666666666666669 --0.12499999999999999 0.125 -0.16666666666666666 -0. 0.25 -0.16666666666666663 -0. 0. -0.16666666666666669 --0.19999999999999996 0.1 -0.16666666666666666 --0.16666666666666674 0. -0.16666666666666663 --0.39999999999999986 0.10000000000000006 -0.5 --0.2916666666666666 0.12500000000000003 -0.5 --0.24999999999999983 0.25000000000000006 -0.5 --0.3415063509461095 0.25 -0.5 --0.5 0. -0.5 --0.33333333333333337 0. -0.5 --0.4330127018922192 0.2500000000000001 -0.5 --0.24999999999999992 0.3598076211353316 -0.5 --0.12499999999999985 0.3750000000000001 -0.5 --0.2499999999999999 0.4330127018922193 -0.5 -0. 0.5 -0.5 --0.09999999999999996 0.25 -0.5 --0.125 0.12499999999999997 -0.5 -0. 0.25 -0.5 -0. 0. -0.5 --0.19999999999999996 0.09999999999999999 -0.5 --0.16666666666666669 0. -0.5 -0.1 0.09999999999999998 0.16666666666666663 -0.20833333333333337 0.125 0.16666666666666663 -0.25 0.24999999999999994 0.16666666666666663 -0.12500000000000003 0.24999999999999994 0.16666666666666663 -0.1 0.1 0.5 -0.20833333333333337 0.125 0.5 -0.25 0.25 0.5 -0.125 0.25 0.5 -0.16666666666666674 0. 0.16666666666666669 -0.16666666666666674 0. 0.5 -0.10000000000000006 0.3999999999999999 0.16666666666666663 -0.25 0.3415063509461096 0.16666666666666663 -0.1 0.4 0.5 -0.25 0.34150635094610965 0.5 -0.2500000000000001 0.4330127018922192 0.16666666666666663 -0.25 0.4330127018922193 0.5 -0.3598076211353316 0.24999999999999994 0.16666666666666663 -0.375 0.125 0.16666666666666663 -0.3598076211353316 0.24999999999999997 0.5 -0.375 0.125 0.5 -0.4330127018922193 0.2499999999999999 0.1666666666666666 -0.4330127018922193 0.24999999999999994 0.5 -0.5 0. 0.16666666666666663 -0.5 0. 0.5 -0.30000000000000004 0.10000000000000003 0.16666666666666663 -0.30000000000000004 0.1 0.5 -0.33333333333333326 0. 0.16666666666666663 -0.33333333333333337 0. 0.5 -0.1 0.10000000000000003 -0.16666666666666666 -0.20833333333333337 0.125 -0.16666666666666666 -0.25 0.25 -0.16666666666666666 -0.12500000000000003 0.25 -0.16666666666666666 -0.1666666666666663 0. -0.16666666666666669 -0.10000000000000007 0.4 -0.16666666666666663 -0.25 0.3415063509461096 -0.16666666666666666 -0.25 0.4330127018922193 -0.1666666666666666 -0.3598076211353316 0.24999999999999994 -0.16666666666666666 -0.375 0.125 -0.16666666666666666 -0.4330127018922193 0.24999999999999994 -0.16666666666666674 -0.5 0. -0.16666666666666669 -0.30000000000000004 0.10000000000000003 -0.16666666666666666 -0.3333333333333335 0. -0.16666666666666666 -0.1 0.1 -0.5 -0.20833333333333337 0.125 -0.5 -0.25 0.25 -0.5 -0.12500000000000003 0.24999999999999997 -0.5 -0.16666666666666663 0. -0.5 -0.10000000000000005 0.4 -0.5 -0.25 0.3415063509461096 -0.5 -0.24999999999999994 0.4330127018922193 -0.5 -0.3598076211353316 0.24999999999999997 -0.5 -0.375 0.12500000000000003 -0.5 -0.4330127018922193 0.25 -0.5 -0.5 0. -0.5 -0.30000000000000004 0.10000000000000003 -0.5 -0.33333333333333326 0. -0.5 -0.4 -0.10000000000000006 0.16666666666666663 -0.2916666666666667 -0.12500000000000003 0.16666666666666663 -0.25 -0.24999999999999997 0.16666666666666663 -0.34150635094610965 -0.25 0.16666666666666663 -0.4 -0.1 0.5 -0.2916666666666667 -0.125 0.5 -0.25 -0.25 0.5 -0.34150635094610965 -0.25 0.5 -0.4330127018922193 -0.2499999999999999 0.16666666666666669 -0.4330127018922193 -0.25 0.5 -0.25 -0.3598076211353316 0.16666666666666663 -0.12500000000000006 -0.3749999999999999 0.16666666666666663 -0.24999999999999997 -0.3598076211353316 0.5 -0.125 -0.375 0.5 -0.25 -0.4330127018922193 0.1666666666666666 -0.24999999999999994 -0.4330127018922193 0.5 -0. -0.5 0.16666666666666669 -0. -0.5 0.5 -0.10000000000000003 -0.24999999999999994 0.16666666666666663 -0.125 -0.125 0.16666666666666663 -0.1 -0.25 0.5 -0.125 -0.125 0.5 -0. -0.24999999999999978 0.16666666666666663 -0. -0.25 0.5 -0.20000000000000004 -0.10000000000000003 0.16666666666666663 -0.20000000000000004 -0.1 0.5 -0.4 -0.10000000000000002 -0.16666666666666669 -0.29166666666666663 -0.125 -0.16666666666666669 -0.25 -0.24999999999999994 -0.16666666666666669 -0.3415063509461097 -0.24999999999999994 -0.16666666666666669 -0.4330127018922193 -0.2499999999999999 -0.16666666666666666 -0.25000000000000006 -0.3598076211353315 -0.16666666666666666 -0.12500000000000008 -0.37499999999999994 -0.16666666666666666 -0.2500000000000001 -0.4330127018922192 -0.16666666666666663 -0. -0.5 -0.16666666666666663 -0.10000000000000003 -0.25 -0.16666666666666669 -0.12499999999999997 -0.12500000000000003 -0.16666666666666669 -0. -0.2500000000000001 -0.16666666666666669 -0.19999999999999998 -0.10000000000000005 -0.16666666666666669 -0.4 -0.10000000000000002 -0.5 -0.2916666666666667 -0.125 -0.5 -0.25 -0.25 -0.5 -0.3415063509461097 -0.25 -0.5 -0.4330127018922193 -0.24999999999999994 -0.5 -0.25 -0.3598076211353316 -0.5 -0.12500000000000006 -0.375 -0.5 -0.25 -0.4330127018922193 -0.5 -0. -0.5 -0.5 -0.10000000000000002 -0.25 -0.5 -0.12499999999999999 -0.125 -0.5 -0. -0.25 -0.5 -0.2 -0.10000000000000002 -0.5 --0.10000000000000006 -0.09999999999999998 0.1666666666666666 --0.20833333333333337 -0.12499999999999997 0.16666666666666663 --0.25000000000000006 -0.25 0.16666666666666663 --0.12500000000000006 -0.24999999999999994 0.16666666666666663 --0.1 -0.1 0.5 --0.20833333333333331 -0.12499999999999999 0.5 --0.25 -0.24999999999999997 0.5 --0.125 -0.25 0.5 --0.10000000000000006 -0.3999999999999999 0.16666666666666666 --0.25 -0.34150635094610965 0.16666666666666666 --0.1 -0.39999999999999997 0.5 --0.24999999999999994 -0.34150635094610965 0.5 --0.2500000000000001 -0.4330127018922193 0.16666666666666674 --0.2499999999999999 -0.4330127018922193 0.5 --0.35980762113533155 -0.2500000000000001 0.16666666666666666 --0.375 -0.12500000000000006 0.16666666666666663 --0.3598076211353315 -0.25000000000000006 0.5 --0.375 -0.12499999999999999 0.5 --0.4330127018922191 -0.25000000000000033 0.16666666666666663 --0.4330127018922192 -0.2500000000000001 0.5 --0.30000000000000004 -0.10000000000000003 0.16666666666666663 --0.3 -0.1 0.5 --0.09999999999999996 -0.10000000000000005 -0.16666666666666666 --0.20833333333333331 -0.12499999999999997 -0.16666666666666666 --0.25 -0.24999999999999992 -0.16666666666666666 --0.12499999999999999 -0.25 -0.16666666666666666 --0.09999999999999999 -0.3999999999999999 -0.16666666666666666 --0.24999999999999994 -0.3415063509461096 -0.16666666666666666 --0.2499999999999999 -0.4330127018922193 -0.16666666666666669 --0.3598076211353316 -0.24999999999999994 -0.16666666666666666 --0.375 -0.1249999999999999 -0.16666666666666666 --0.4330127018922194 -0.24999999999999978 -0.16666666666666663 --0.3 -0.09999999999999995 -0.16666666666666666 --0.09999999999999995 -0.1 -0.5 --0.20833333333333334 -0.12499999999999994 -0.5 --0.2500000000000001 -0.2499999999999999 -0.5 --0.12500000000000006 -0.24999999999999994 -0.5 --0.1000000000000001 -0.3999999999999999 -0.5 --0.2500000000000001 -0.3415063509461096 -0.5 --0.2500000000000002 -0.4330127018922192 -0.5 --0.3598076211353317 -0.24999999999999994 -0.5 --0.3750000000000001 -0.12499999999999989 -0.5 --0.4330127018922194 -0.24999999999999983 -0.5 --0.30000000000000004 -0.09999999999999994 -0.5 -0.666666666666667 0. 0.16666666666666663 -0.6666666666666667 0. 0.5 -0.5773502691896261 0.3333333333333335 0.16666666666666663 -0.5773502691896258 0.33333333333333337 0.5 -0.8333333333333326 0. 0.16666666666666663 -0.8333333333333333 0. 0.5 -0.7216878364870316 0.4166666666666663 0.16666666666666663 -0.721687836487032 0.4166666666666665 0.5 -1. 0. 0.16666666666666663 -1. 0. 0.5 -0.8660254037844386 0.4999999999999998 0.1666666666666666 -0.8660254037844386 0.4999999999999999 0.5 -0.6666666666666672 0. -0.16666666666666666 -0.5773502691896263 0.3333333333333336 -0.16666666666666666 -0.8333333333333337 0. -0.16666666666666663 -0.7216878364870325 0.41666666666666685 -0.16666666666666663 -1. 0. -0.16666666666666669 -0.8660254037844386 0.4999999999999999 -0.16666666666666674 -0.6666666666666667 0. -0.5 -0.5773502691896258 0.33333333333333337 -0.5 -0.8333333333333333 0. -0.5 -0.721687836487032 0.4166666666666666 -0.5 -1. 0. -0.5 -0.8660254037844386 0.5 -0.5 -0.3333333333333335 0.5773502691896261 0.16666666666666666 -0.3333333333333333 0.577350269189626 0.5 -0.4166666666666663 0.7216878364870316 0.16666666666666666 -0.41666666666666663 0.7216878364870322 0.5 -0.5000000000000002 0.8660254037844384 0.16666666666666663 -0.5 0.8660254037844386 0.5 -0.3333333333333336 0.5773502691896263 -0.16666666666666663 -0.41666666666666685 0.7216878364870325 -0.1666666666666666 -0.5 0.8660254037844386 -0.1666666666666666 -0.3333333333333333 0.577350269189626 -0.5 -0.4166666666666665 0.7216878364870322 -0.5 -0.4999999999999999 0.8660254037844386 -0.5 -0. 0.666666666666667 0.16666666666666663 -0. 0.6666666666666667 0.5 -0. 0.8333333333333326 0.16666666666666663 -0. 0.8333333333333333 0.5 -0. 1. 0.16666666666666663 -0. 1. 0.5 -0. 0.6666666666666672 -0.16666666666666666 -0. 0.8333333333333337 -0.16666666666666663 -0. 1. -0.16666666666666669 -0. 0.6666666666666667 -0.5 -0. 0.8333333333333333 -0.5 -0. 1. -0.5 -0.5773502691896261 -0.3333333333333335 0.16666666666666663 -0.5773502691896258 -0.33333333333333337 0.5 -0.7216878364870316 -0.41666666666666624 0.16666666666666663 -0.721687836487032 -0.4166666666666666 0.5 -0.8660254037844386 -0.4999999999999998 0.16666666666666669 -0.8660254037844386 -0.5 0.5 -0.5773502691896263 -0.33333333333333354 -0.16666666666666669 -0.7216878364870325 -0.41666666666666674 -0.16666666666666663 -0.8660254037844386 -0.4999999999999998 -0.16666666666666666 -0.5773502691896258 -0.33333333333333337 -0.5 -0.721687836487032 -0.4166666666666666 -0.5 -0.8660254037844386 -0.4999999999999999 -0.5 -0.3333333333333335 -0.577350269189626 0.16666666666666666 -0.3333333333333333 -0.5773502691896257 0.5 -0.4166666666666663 -0.7216878364870315 0.16666666666666666 -0.4166666666666665 -0.7216878364870322 0.5 -0.5 -0.8660254037844386 0.1666666666666666 -0.4999999999999999 -0.8660254037844386 0.5 -0.3333333333333336 -0.5773502691896261 -0.16666666666666663 -0.41666666666666685 -0.7216878364870324 -0.1666666666666666 -0.5000000000000002 -0.8660254037844384 -0.16666666666666663 -0.3333333333333333 -0.577350269189626 -0.5 -0.41666666666666663 -0.721687836487032 -0.5 -0.5 -0.8660254037844386 -0.5 -0. -0.666666666666667 0.16666666666666669 -0. -0.6666666666666666 0.5 -0. -0.8333333333333326 0.16666666666666669 -0. -0.8333333333333333 0.5 -0. -1. 0.16666666666666669 -0. -1. 0.5 -0. -0.6666666666666672 -0.1666666666666666 -0. -0.8333333333333337 -0.16666666666666657 -0. -1. -0.16666666666666663 -0. -0.6666666666666667 -0.5 -0. -0.8333333333333334 -0.5 -0. -1. -0.5 --0.41666666666666663 -0.7216878364870322 -0.5 --0.4999999999999998 -0.8660254037844386 -0.5 --0.5000000000000002 -0.8660254037844386 -0.16666666666666663 --0.416666666666667 -0.7216878364870323 -0.16666666666666657 --0.3333333333333335 -0.5773502691896257 -0.5 --0.3333333333333337 -0.577350269189626 -0.16666666666666657 --0.5000000000000002 -0.8660254037844386 0.16666666666666666 --0.4166666666666665 -0.7216878364870314 0.16666666666666669 --0.33333333333333365 -0.5773502691896257 0.16666666666666669 --0.5000000000000004 -0.8660254037844384 0.5 --0.4166666666666669 -0.721687836487032 0.5 --0.33333333333333337 -0.5773502691896256 0.5 --0.7216878364870322 -0.41666666666666685 -0.5 --0.8660254037844384 -0.5000000000000002 -0.5 --0.8660254037844382 -0.5000000000000007 -0.16666666666666663 --0.7216878364870325 -0.41666666666666696 -0.1666666666666666 --0.5773502691896258 -0.33333333333333337 -0.5 --0.5773502691896262 -0.3333333333333336 -0.16666666666666663 --0.8660254037844388 -0.49999999999999956 0.16666666666666663 --0.7216878364870316 -0.4166666666666663 0.16666666666666666 --0.5773502691896261 -0.3333333333333334 0.16666666666666666 --0.8660254037844388 -0.49999999999999967 0.5 --0.721687836487032 -0.4166666666666665 0.5 --0.5773502691896257 -0.3333333333333333 0.5 --0.8333333333333334 0. -0.5 --1. 0. -0.5 --1. 0. -0.16666666666666663 --0.8333333333333337 0. -0.1666666666666666 --0.6666666666666667 0. -0.5 --0.6666666666666672 0. -0.16666666666666663 --1. 0. 0.16666666666666669 --0.8333333333333326 0. 0.16666666666666666 --0.666666666666667 0. 0.16666666666666666 --1. 0. 0.5 --0.8333333333333333 0. 0.5 --0.6666666666666666 0. 0.5 --0.577350269189626 0.33333333333333337 0.16666666666666666 --0.5773502691896256 0.33333333333333326 0.5 --0.7216878364870316 0.4166666666666662 0.16666666666666666 --0.7216878364870322 0.41666666666666663 0.5 --0.8660254037844388 0.49999999999999967 0.16666666666666677 --0.8660254037844384 0.5000000000000002 0.5 --0.5773502691896263 0.3333333333333334 -0.16666666666666669 --0.7216878364870327 0.4166666666666667 -0.16666666666666666 --0.8660254037844388 0.49999999999999967 -0.16666666666666669 --0.577350269189626 0.3333333333333333 -0.5 --0.7216878364870325 0.41666666666666646 -0.5 --0.8660254037844388 0.49999999999999967 -0.5 --0.3333333333333333 0.577350269189626 0.16666666666666666 --0.3333333333333335 0.5773502691896255 0.5 --0.4166666666666661 0.7216878364870315 0.16666666666666666 --0.4166666666666665 0.7216878364870323 0.5 --0.4999999999999988 0.8660254037844393 0.16666666666666663 --0.4999999999999998 0.8660254037844386 0.5 --0.3333333333333335 0.5773502691896261 -0.16666666666666663 --0.4166666666666667 0.7216878364870324 -0.1666666666666666 --0.49999999999999956 0.8660254037844388 -0.16666666666666666 --0.3333333333333334 0.5773502691896257 -0.5 --0.41666666666666696 0.7216878364870317 -0.5 --0.5000000000000004 0.8660254037844384 -0.5 +MFEM mesh v1.0 + +# +# MFEM Geometry Types (see mesh/geom.hpp): +# +# POINT = 0 +# SEGMENT = 1 +# TRIANGLE = 2 +# SQUARE = 3 +# TETRAHEDRON = 4 +# CUBE = 5 +# + +dimension +3 + +elements +252 +1 5 0 1 2 3 4 5 6 7 +1 5 8 9 1 0 10 11 5 4 +1 5 12 8 0 3 13 10 4 7 +1 5 14 3 2 15 16 7 6 17 +1 5 18 12 3 14 19 13 7 16 +1 5 20 18 14 15 21 19 16 17 +1 5 22 15 2 23 24 17 6 25 +1 5 26 20 15 22 27 21 17 24 +1 5 28 26 22 23 29 27 24 25 +1 5 30 23 2 1 31 25 6 5 +1 5 32 28 23 30 33 29 25 31 +1 5 9 32 30 1 11 33 31 5 +1 5 34 35 36 37 0 1 2 3 +1 5 38 39 35 34 8 9 1 0 +1 5 40 38 34 37 12 8 0 3 +1 5 41 37 36 42 14 3 2 15 +1 5 43 40 37 41 18 12 3 14 +1 5 44 43 41 42 20 18 14 15 +1 5 45 42 36 46 22 15 2 23 +1 5 47 44 42 45 26 20 15 22 +1 5 48 47 45 46 28 26 22 23 +1 5 49 46 36 35 30 23 2 1 +1 5 50 48 46 49 32 28 23 30 +1 5 39 50 49 35 9 32 30 1 +1 5 51 52 53 54 34 35 36 37 +1 5 55 56 52 51 38 39 35 34 +1 5 57 55 51 54 40 38 34 37 +1 5 58 54 53 59 41 37 36 42 +1 5 60 57 54 58 43 40 37 41 +1 5 61 60 58 59 44 43 41 42 +1 5 62 59 53 63 45 42 36 46 +1 5 64 61 59 62 47 44 42 45 +1 5 65 64 62 63 48 47 45 46 +1 5 66 63 53 52 49 46 36 35 +1 5 67 65 63 66 50 48 46 49 +1 5 56 67 66 52 39 50 49 35 +1 5 68 69 70 71 72 73 74 75 +1 5 28 76 69 68 29 77 73 72 +1 5 26 28 68 71 27 29 72 75 +1 5 78 71 70 79 80 75 74 81 +1 5 20 26 71 78 21 27 75 80 +1 5 82 20 78 79 83 21 80 81 +1 5 84 79 70 85 86 81 74 87 +1 5 88 82 79 84 89 83 81 86 +1 5 90 88 84 85 91 89 86 87 +1 5 92 85 70 69 93 87 74 73 +1 5 94 90 85 92 95 91 87 93 +1 5 76 94 92 69 77 95 93 73 +1 5 96 97 98 99 68 69 70 71 +1 5 48 100 97 96 28 76 69 68 +1 5 47 48 96 99 26 28 68 71 +1 5 101 99 98 102 78 71 70 79 +1 5 44 47 99 101 20 26 71 78 +1 5 103 44 101 102 82 20 78 79 +1 5 104 102 98 105 84 79 70 85 +1 5 106 103 102 104 88 82 79 84 +1 5 107 106 104 105 90 88 84 85 +1 5 108 105 98 97 92 85 70 69 +1 5 109 107 105 108 94 90 85 92 +1 5 100 109 108 97 76 94 92 69 +1 5 110 111 112 113 96 97 98 99 +1 5 65 114 111 110 48 100 97 96 +1 5 64 65 110 113 47 48 96 99 +1 5 115 113 112 116 101 99 98 102 +1 5 61 64 113 115 44 47 99 101 +1 5 117 61 115 116 103 44 101 102 +1 5 118 116 112 119 104 102 98 105 +1 5 120 117 116 118 106 103 102 104 +1 5 121 120 118 119 107 106 104 105 +1 5 122 119 112 111 108 105 98 97 +1 5 123 121 119 122 109 107 105 108 +1 5 114 123 122 111 100 109 108 97 +1 5 124 125 126 127 128 129 130 131 +1 5 90 94 125 124 91 95 129 128 +1 5 132 90 124 127 133 91 128 131 +1 5 134 127 126 135 136 131 130 137 +1 5 138 132 127 134 139 133 131 136 +1 5 140 138 134 135 141 139 136 137 +1 5 142 135 126 143 144 137 130 145 +1 5 146 140 135 142 147 141 137 144 +1 5 28 146 142 143 29 147 144 145 +1 5 148 143 126 125 149 145 130 129 +1 5 76 28 143 148 77 29 145 149 +1 5 94 76 148 125 95 77 149 129 +1 5 150 151 152 153 124 125 126 127 +1 5 107 109 151 150 90 94 125 124 +1 5 154 107 150 153 132 90 124 127 +1 5 155 153 152 156 134 127 126 135 +1 5 157 154 153 155 138 132 127 134 +1 5 158 157 155 156 140 138 134 135 +1 5 159 156 152 160 142 135 126 143 +1 5 161 158 156 159 146 140 135 142 +1 5 48 161 159 160 28 146 142 143 +1 5 162 160 152 151 148 143 126 125 +1 5 100 48 160 162 76 28 143 148 +1 5 109 100 162 151 94 76 148 125 +1 5 163 164 165 166 150 151 152 153 +1 5 121 123 164 163 107 109 151 150 +1 5 167 121 163 166 154 107 150 153 +1 5 168 166 165 169 155 153 152 156 +1 5 170 167 166 168 157 154 153 155 +1 5 171 170 168 169 158 157 155 156 +1 5 172 169 165 173 159 156 152 160 +1 5 174 171 169 172 161 158 156 159 +1 5 65 174 172 173 48 161 159 160 +1 5 175 173 165 164 162 160 152 151 +1 5 114 65 173 175 100 48 160 162 +1 5 123 114 175 164 109 100 162 151 +1 5 176 177 178 179 180 181 182 183 +1 5 28 32 177 176 29 33 181 180 +1 5 146 28 176 179 147 29 180 183 +1 5 184 179 178 185 186 183 182 187 +1 5 140 146 179 184 141 147 183 186 +1 5 188 140 184 185 189 141 186 187 +1 5 190 185 178 191 192 187 182 193 +1 5 194 188 185 190 195 189 187 192 +1 5 8 194 190 191 10 195 192 193 +1 5 196 191 178 177 197 193 182 181 +1 5 9 8 191 196 11 10 193 197 +1 5 32 9 196 177 33 11 197 181 +1 5 198 199 200 201 176 177 178 179 +1 5 48 50 199 198 28 32 177 176 +1 5 161 48 198 201 146 28 176 179 +1 5 202 201 200 203 184 179 178 185 +1 5 158 161 201 202 140 146 179 184 +1 5 204 158 202 203 188 140 184 185 +1 5 205 203 200 206 190 185 178 191 +1 5 207 204 203 205 194 188 185 190 +1 5 38 207 205 206 8 194 190 191 +1 5 208 206 200 199 196 191 178 177 +1 5 39 38 206 208 9 8 191 196 +1 5 50 39 208 199 32 9 196 177 +1 5 209 210 211 212 198 199 200 201 +1 5 65 67 210 209 48 50 199 198 +1 5 174 65 209 212 161 48 198 201 +1 5 213 212 211 214 202 201 200 203 +1 5 171 174 212 213 158 161 201 202 +1 5 215 171 213 214 204 158 202 203 +1 5 216 214 211 217 205 203 200 206 +1 5 218 215 214 216 207 204 203 205 +1 5 55 218 216 217 38 207 205 206 +1 5 219 217 211 210 208 206 200 199 +1 5 56 55 217 219 39 38 206 208 +1 5 67 56 219 210 50 39 208 199 +2 5 220 90 91 221 222 88 89 223 +2 5 224 220 221 225 226 222 223 227 +2 5 228 224 225 229 230 226 227 231 +2 5 232 107 90 220 233 106 88 222 +2 5 234 232 220 224 235 233 222 226 +2 5 236 234 224 228 237 235 226 230 +2 5 238 121 107 232 239 120 106 233 +2 5 240 238 232 234 241 239 233 235 +2 5 242 240 234 236 243 241 235 237 +2 5 222 88 89 223 244 82 83 245 +2 5 226 222 223 227 246 244 245 247 +2 5 230 226 227 231 248 246 247 249 +2 5 233 106 88 222 250 103 82 244 +2 5 235 233 222 226 251 250 244 246 +2 5 237 235 226 230 252 251 246 248 +2 5 239 120 106 233 253 117 103 250 +2 5 241 239 233 235 254 253 250 251 +2 5 243 241 235 237 255 254 251 252 +2 5 244 82 83 245 256 20 21 257 +2 5 246 244 245 247 258 256 257 259 +2 5 248 246 247 249 260 258 259 261 +2 5 250 103 82 244 262 44 20 256 +2 5 251 250 244 246 263 262 256 258 +2 5 252 251 246 248 264 263 258 260 +2 5 253 117 103 250 265 61 44 262 +2 5 254 253 250 251 266 265 262 263 +2 5 255 254 251 252 267 266 263 264 +2 5 268 132 133 269 220 90 91 221 +2 5 270 268 269 271 224 220 221 225 +2 5 272 270 271 273 228 224 225 229 +2 5 274 154 132 268 232 107 90 220 +2 5 275 274 268 270 234 232 220 224 +2 5 276 275 270 272 236 234 224 228 +2 5 277 167 154 274 238 121 107 232 +2 5 278 277 274 275 240 238 232 234 +2 5 279 278 275 276 242 240 234 236 +2 5 280 138 139 281 268 132 133 269 +2 5 282 280 281 283 270 268 269 271 +2 5 284 282 283 285 272 270 271 273 +2 5 286 157 138 280 274 154 132 268 +2 5 287 286 280 282 275 274 268 270 +2 5 288 287 282 284 276 275 270 272 +2 5 289 170 157 286 277 167 154 274 +2 5 290 289 286 287 278 277 274 275 +2 5 291 290 287 288 279 278 275 276 +2 5 292 140 141 293 280 138 139 281 +2 5 294 292 293 295 282 280 281 283 +2 5 296 294 295 297 284 282 283 285 +2 5 298 158 140 292 286 157 138 280 +2 5 299 298 292 294 287 286 280 282 +2 5 300 299 294 296 288 287 282 284 +2 5 301 171 158 298 289 170 157 286 +2 5 302 301 298 299 290 289 286 287 +2 5 303 302 299 300 291 290 287 288 +2 5 302 303 300 299 304 305 306 307 +2 5 301 302 299 298 308 304 307 309 +2 5 171 301 298 158 215 308 309 204 +2 5 299 300 296 294 307 306 310 311 +2 5 298 299 294 292 309 307 311 312 +2 5 158 298 292 140 204 309 312 188 +2 5 294 296 297 295 311 310 313 314 +2 5 292 294 295 293 312 311 314 315 +2 5 140 292 293 141 188 312 315 189 +2 5 304 305 306 307 316 317 318 319 +2 5 308 304 307 309 320 316 319 321 +2 5 215 308 309 204 218 320 321 207 +2 5 307 306 310 311 319 318 322 323 +2 5 309 307 311 312 321 319 323 324 +2 5 204 309 312 188 207 321 324 194 +2 5 311 310 313 314 323 322 325 326 +2 5 312 311 314 315 324 323 326 327 +2 5 188 312 315 189 194 324 327 195 +2 5 316 317 318 319 328 329 330 331 +2 5 320 316 319 321 332 328 331 333 +2 5 218 320 321 207 55 332 333 38 +2 5 319 318 322 323 331 330 334 335 +2 5 321 319 323 324 333 331 335 336 +2 5 207 321 324 194 38 333 336 8 +2 5 323 322 325 326 335 334 337 338 +2 5 324 323 326 327 336 335 338 339 +2 5 194 324 327 195 8 336 339 10 +2 5 8 336 339 10 12 340 341 13 +2 5 336 335 338 339 340 342 343 341 +2 5 335 334 337 338 342 344 345 343 +2 5 38 333 336 8 40 346 340 12 +2 5 333 331 335 336 346 347 342 340 +2 5 331 330 334 335 347 348 344 342 +2 5 55 332 333 38 57 349 346 40 +2 5 332 328 331 333 349 350 347 346 +2 5 328 329 330 331 350 351 348 347 +2 5 12 340 341 13 18 352 353 19 +2 5 340 342 343 341 352 354 355 353 +2 5 342 344 345 343 354 356 357 355 +2 5 40 346 340 12 43 358 352 18 +2 5 346 347 342 340 358 359 354 352 +2 5 347 348 344 342 359 360 356 354 +2 5 57 349 346 40 60 361 358 43 +2 5 349 350 347 346 361 362 359 358 +2 5 350 351 348 347 362 363 360 359 +2 5 18 352 353 19 20 256 257 21 +2 5 352 354 355 353 256 258 259 257 +2 5 354 356 357 355 258 260 261 259 +2 5 43 358 352 18 44 262 256 20 +2 5 358 359 354 352 262 263 258 256 +2 5 359 360 356 354 263 264 260 258 +2 5 60 361 358 43 61 265 262 44 +2 5 361 362 359 358 265 266 263 262 +2 5 362 363 360 359 266 267 264 263 + +boundary +204 +1 3 11 33 31 5 +1 3 33 29 25 31 +1 3 31 25 6 5 +1 3 29 27 24 25 +1 3 27 21 17 24 +1 3 24 17 6 25 +1 3 21 19 16 17 +1 3 19 13 7 16 +1 3 16 7 6 17 +1 3 13 10 4 7 +1 3 10 11 5 4 +1 3 4 5 6 7 +1 3 77 95 93 73 +1 3 95 91 87 93 +1 3 93 87 74 73 +1 3 91 89 86 87 +1 3 89 83 81 86 +1 3 86 81 74 87 +1 3 83 21 80 81 +1 3 21 27 75 80 +1 3 80 75 74 81 +1 3 27 29 72 75 +1 3 29 77 73 72 +1 3 72 73 74 75 +1 3 95 77 149 129 +1 3 77 29 145 149 +1 3 149 145 130 129 +1 3 29 147 144 145 +1 3 147 141 137 144 +1 3 144 137 130 145 +1 3 141 139 136 137 +1 3 139 133 131 136 +1 3 136 131 130 137 +1 3 133 91 128 131 +1 3 91 95 129 128 +1 3 128 129 130 131 +1 3 33 11 197 181 +1 3 11 10 193 197 +1 3 197 193 182 181 +1 3 10 195 192 193 +1 3 195 189 187 192 +1 3 192 187 182 193 +1 3 189 141 186 187 +1 3 141 147 183 186 +1 3 186 183 182 187 +1 3 147 29 180 183 +1 3 29 33 181 180 +1 3 180 181 182 183 +1 3 337 338 343 345 +1 3 338 339 341 343 +1 3 339 10 13 341 +1 3 345 343 355 357 +1 3 343 341 353 355 +1 3 341 13 19 353 +1 3 357 355 259 261 +1 3 355 353 257 259 +1 3 353 19 21 257 +1 3 91 221 223 89 +1 3 221 225 227 223 +1 3 225 229 231 227 +1 3 89 223 245 83 +1 3 223 227 247 245 +1 3 227 231 249 247 +1 3 83 245 257 21 +1 3 245 247 259 257 +1 3 247 249 261 259 +1 3 271 273 229 225 +1 3 269 271 225 221 +1 3 133 269 221 91 +1 3 283 285 273 271 +1 3 281 283 271 269 +1 3 139 281 269 133 +1 3 295 297 285 283 +1 3 293 295 283 281 +1 3 141 293 281 139 +1 3 327 195 10 339 +1 3 326 327 339 338 +1 3 325 326 338 337 +1 3 315 189 195 327 +1 3 314 315 327 326 +1 3 313 314 326 325 +1 3 293 141 189 315 +1 3 295 293 315 314 +1 3 297 295 314 313 +2 3 110 113 112 111 +2 3 65 110 111 114 +2 3 64 113 110 65 +2 3 115 116 112 113 +2 3 61 115 113 64 +2 3 117 116 115 61 +2 3 118 119 112 116 +2 3 120 118 116 117 +2 3 121 119 118 120 +2 3 122 111 112 119 +2 3 123 122 119 121 +2 3 114 111 122 123 +2 3 51 54 53 52 +2 3 55 51 52 56 +2 3 57 54 51 55 +2 3 58 59 53 54 +2 3 60 58 54 57 +2 3 61 59 58 60 +2 3 62 63 53 59 +2 3 64 62 59 61 +2 3 65 63 62 64 +2 3 66 52 53 63 +2 3 67 66 63 65 +2 3 56 52 66 67 +2 3 209 212 211 210 +2 3 65 209 210 67 +2 3 174 212 209 65 +2 3 213 214 211 212 +2 3 171 213 212 174 +2 3 215 214 213 171 +2 3 216 217 211 214 +2 3 218 216 214 215 +2 3 55 217 216 218 +2 3 219 210 211 217 +2 3 56 219 217 55 +2 3 67 210 219 56 +2 3 163 166 165 164 +2 3 121 163 164 123 +2 3 167 166 163 121 +2 3 168 169 165 166 +2 3 170 168 166 167 +2 3 171 169 168 170 +2 3 172 173 165 169 +2 3 174 172 169 171 +2 3 65 173 172 174 +2 3 175 164 165 173 +2 3 114 175 173 65 +2 3 123 164 175 114 +2 3 242 240 241 243 +2 3 240 238 239 241 +2 3 238 121 120 239 +2 3 243 241 254 255 +2 3 241 239 253 254 +2 3 239 120 117 253 +2 3 255 254 266 267 +2 3 254 253 265 266 +2 3 253 117 61 265 +2 3 55 332 349 57 +2 3 332 328 350 349 +2 3 328 329 351 350 +2 3 57 349 361 60 +2 3 349 350 362 361 +2 3 350 351 363 362 +2 3 60 361 265 61 +2 3 361 362 266 265 +2 3 362 363 267 266 +2 3 316 317 329 328 +2 3 320 316 328 332 +2 3 218 320 332 55 +2 3 304 305 317 316 +2 3 308 304 316 320 +2 3 215 308 320 218 +2 3 302 303 305 304 +2 3 301 302 304 308 +2 3 171 301 308 215 +2 3 277 167 121 238 +2 3 278 277 238 240 +2 3 279 278 240 242 +2 3 289 170 167 277 +2 3 290 289 277 278 +2 3 291 290 278 279 +2 3 301 171 170 289 +2 3 302 301 289 290 +2 3 303 302 290 291 +3 3 279 242 236 276 +3 3 276 236 228 272 +3 3 272 228 229 273 +3 3 291 279 276 288 +3 3 288 276 272 284 +3 3 284 272 273 285 +3 3 303 291 288 300 +3 3 300 288 284 296 +3 3 296 284 285 297 +3 3 228 230 231 229 +3 3 236 237 230 228 +3 3 242 243 237 236 +3 3 230 248 249 231 +3 3 237 252 248 230 +3 3 243 255 252 237 +3 3 248 260 261 249 +3 3 252 264 260 248 +3 3 255 267 264 252 +3 3 329 330 348 351 +3 3 330 334 344 348 +3 3 334 337 345 344 +3 3 351 348 360 363 +3 3 348 344 356 360 +3 3 344 345 357 356 +3 3 363 360 264 267 +3 3 360 356 260 264 +3 3 356 357 261 260 +3 3 322 325 337 334 +3 3 318 322 334 330 +3 3 317 318 330 329 +3 3 310 313 325 322 +3 3 306 310 322 318 +3 3 305 306 318 317 +3 3 296 297 313 310 +3 3 300 296 310 306 +3 3 303 300 306 305 + +vertices +364 +3 +-0.39999999999999997 0.10000000000000002 0.16666666666666663 +-0.29166666666666663 0.125 0.16666666666666663 +-0.2499999999999999 0.25 0.16666666666666663 +-0.3415063509461096 0.24999999999999994 0.16666666666666663 +-0.39999999999999997 0.1 0.5 +-0.29166666666666663 0.125 0.5 +-0.24999999999999997 0.25 0.5 +-0.3415063509461097 0.24999999999999992 0.5 +-0.5 0. 0.16666666666666663 +-0.33333333333333337 0. 0.16666666666666663 +-0.5 0. 0.5 +-0.3333333333333333 0. 0.5 +-0.4330127018922194 0.24999999999999983 0.16666666666666663 +-0.4330127018922194 0.24999999999999983 0.5 +-0.24999999999999994 0.35980762113533155 0.16666666666666663 +-0.12499999999999985 0.37500000000000006 0.16666666666666663 +-0.2500000000000001 0.3598076211353315 0.5 +-0.12499999999999999 0.375 0.5 +-0.24999999999999978 0.4330127018922194 0.16666666666666663 +-0.2500000000000002 0.4330127018922192 0.5 +0. 0.5 0.16666666666666663 +0. 0.5 0.5 +-0.09999999999999998 0.25 0.16666666666666663 +-0.12500000000000006 0.12499999999999997 0.16666666666666663 +-0.1 0.25 0.5 +-0.12499999999999999 0.125 0.5 +0. 0.24999999999999978 0.16666666666666663 +0. 0.25 0.5 +0. 0. 0.16666666666666663 +0. 0. 0.5 +-0.2 0.09999999999999999 0.16666666666666663 +-0.19999999999999996 0.1 0.5 +-0.16666666666666696 0. 0.1666666666666666 +-0.16666666666666663 0. 0.5 +-0.3999999999999999 0.1 -0.16666666666666669 +-0.2916666666666666 0.125 -0.16666666666666669 +-0.24999999999999983 0.25000000000000006 -0.1666666666666667 +-0.3415063509461095 0.24999999999999994 -0.1666666666666667 +-0.5 0. -0.16666666666666669 +-0.33333333333333337 0. -0.1666666666666666 +-0.4330127018922194 0.24999999999999983 -0.16666666666666677 +-0.24999999999999992 0.3598076211353316 -0.1666666666666667 +-0.12499999999999982 0.3750000000000001 -0.1666666666666667 +-0.24999999999999978 0.4330127018922194 -0.16666666666666674 +0. 0.5 -0.16666666666666669 +-0.09999999999999995 0.25 -0.16666666666666669 +-0.12499999999999999 0.125 -0.16666666666666666 +0. 0.25 -0.16666666666666663 +0. 0. -0.16666666666666669 +-0.19999999999999996 0.1 -0.16666666666666666 +-0.16666666666666674 0. -0.16666666666666663 +-0.39999999999999986 0.10000000000000006 -0.5 +-0.2916666666666666 0.12500000000000003 -0.5 +-0.24999999999999983 0.25000000000000006 -0.5 +-0.3415063509461095 0.25 -0.5 +-0.5 0. -0.5 +-0.33333333333333337 0. -0.5 +-0.4330127018922192 0.2500000000000001 -0.5 +-0.24999999999999992 0.3598076211353316 -0.5 +-0.12499999999999985 0.3750000000000001 -0.5 +-0.2499999999999999 0.4330127018922193 -0.5 +0. 0.5 -0.5 +-0.09999999999999996 0.25 -0.5 +-0.125 0.12499999999999997 -0.5 +0. 0.25 -0.5 +0. 0. -0.5 +-0.19999999999999996 0.09999999999999999 -0.5 +-0.16666666666666669 0. -0.5 +0.1 0.09999999999999998 0.16666666666666663 +0.20833333333333337 0.125 0.16666666666666663 +0.25 0.24999999999999994 0.16666666666666663 +0.12500000000000003 0.24999999999999994 0.16666666666666663 +0.1 0.1 0.5 +0.20833333333333337 0.125 0.5 +0.25 0.25 0.5 +0.125 0.25 0.5 +0.16666666666666674 0. 0.16666666666666669 +0.16666666666666674 0. 0.5 +0.10000000000000006 0.3999999999999999 0.16666666666666663 +0.25 0.3415063509461096 0.16666666666666663 +0.1 0.4 0.5 +0.25 0.34150635094610965 0.5 +0.2500000000000001 0.4330127018922192 0.16666666666666663 +0.25 0.4330127018922193 0.5 +0.3598076211353316 0.24999999999999994 0.16666666666666663 +0.375 0.125 0.16666666666666663 +0.3598076211353316 0.24999999999999997 0.5 +0.375 0.125 0.5 +0.4330127018922193 0.2499999999999999 0.1666666666666666 +0.4330127018922193 0.24999999999999994 0.5 +0.5 0. 0.16666666666666663 +0.5 0. 0.5 +0.30000000000000004 0.10000000000000003 0.16666666666666663 +0.30000000000000004 0.1 0.5 +0.33333333333333326 0. 0.16666666666666663 +0.33333333333333337 0. 0.5 +0.1 0.10000000000000003 -0.16666666666666666 +0.20833333333333337 0.125 -0.16666666666666666 +0.25 0.25 -0.16666666666666666 +0.12500000000000003 0.25 -0.16666666666666666 +0.1666666666666663 0. -0.16666666666666669 +0.10000000000000007 0.4 -0.16666666666666663 +0.25 0.3415063509461096 -0.16666666666666666 +0.25 0.4330127018922193 -0.1666666666666666 +0.3598076211353316 0.24999999999999994 -0.16666666666666666 +0.375 0.125 -0.16666666666666666 +0.4330127018922193 0.24999999999999994 -0.16666666666666674 +0.5 0. -0.16666666666666669 +0.30000000000000004 0.10000000000000003 -0.16666666666666666 +0.3333333333333335 0. -0.16666666666666666 +0.1 0.1 -0.5 +0.20833333333333337 0.125 -0.5 +0.25 0.25 -0.5 +0.12500000000000003 0.24999999999999997 -0.5 +0.16666666666666663 0. -0.5 +0.10000000000000005 0.4 -0.5 +0.25 0.3415063509461096 -0.5 +0.24999999999999994 0.4330127018922193 -0.5 +0.3598076211353316 0.24999999999999997 -0.5 +0.375 0.12500000000000003 -0.5 +0.4330127018922193 0.25 -0.5 +0.5 0. -0.5 +0.30000000000000004 0.10000000000000003 -0.5 +0.33333333333333326 0. -0.5 +0.4 -0.10000000000000006 0.16666666666666663 +0.2916666666666667 -0.12500000000000003 0.16666666666666663 +0.25 -0.24999999999999997 0.16666666666666663 +0.34150635094610965 -0.25 0.16666666666666663 +0.4 -0.1 0.5 +0.2916666666666667 -0.125 0.5 +0.25 -0.25 0.5 +0.34150635094610965 -0.25 0.5 +0.4330127018922193 -0.2499999999999999 0.16666666666666669 +0.4330127018922193 -0.25 0.5 +0.25 -0.3598076211353316 0.16666666666666663 +0.12500000000000006 -0.3749999999999999 0.16666666666666663 +0.24999999999999997 -0.3598076211353316 0.5 +0.125 -0.375 0.5 +0.25 -0.4330127018922193 0.1666666666666666 +0.24999999999999994 -0.4330127018922193 0.5 +0. -0.5 0.16666666666666669 +0. -0.5 0.5 +0.10000000000000003 -0.24999999999999994 0.16666666666666663 +0.125 -0.125 0.16666666666666663 +0.1 -0.25 0.5 +0.125 -0.125 0.5 +0. -0.24999999999999978 0.16666666666666663 +0. -0.25 0.5 +0.20000000000000004 -0.10000000000000003 0.16666666666666663 +0.20000000000000004 -0.1 0.5 +0.4 -0.10000000000000002 -0.16666666666666669 +0.29166666666666663 -0.125 -0.16666666666666669 +0.25 -0.24999999999999994 -0.16666666666666669 +0.3415063509461097 -0.24999999999999994 -0.16666666666666669 +0.4330127018922193 -0.2499999999999999 -0.16666666666666666 +0.25000000000000006 -0.3598076211353315 -0.16666666666666666 +0.12500000000000008 -0.37499999999999994 -0.16666666666666666 +0.2500000000000001 -0.4330127018922192 -0.16666666666666663 +0. -0.5 -0.16666666666666663 +0.10000000000000003 -0.25 -0.16666666666666669 +0.12499999999999997 -0.12500000000000003 -0.16666666666666669 +0. -0.2500000000000001 -0.16666666666666669 +0.19999999999999998 -0.10000000000000005 -0.16666666666666669 +0.4 -0.10000000000000002 -0.5 +0.2916666666666667 -0.125 -0.5 +0.25 -0.25 -0.5 +0.3415063509461097 -0.25 -0.5 +0.4330127018922193 -0.24999999999999994 -0.5 +0.25 -0.3598076211353316 -0.5 +0.12500000000000006 -0.375 -0.5 +0.25 -0.4330127018922193 -0.5 +0. -0.5 -0.5 +0.10000000000000002 -0.25 -0.5 +0.12499999999999999 -0.125 -0.5 +0. -0.25 -0.5 +0.2 -0.10000000000000002 -0.5 +-0.10000000000000006 -0.09999999999999998 0.1666666666666666 +-0.20833333333333337 -0.12499999999999997 0.16666666666666663 +-0.25000000000000006 -0.25 0.16666666666666663 +-0.12500000000000006 -0.24999999999999994 0.16666666666666663 +-0.1 -0.1 0.5 +-0.20833333333333331 -0.12499999999999999 0.5 +-0.25 -0.24999999999999997 0.5 +-0.125 -0.25 0.5 +-0.10000000000000006 -0.3999999999999999 0.16666666666666666 +-0.25 -0.34150635094610965 0.16666666666666666 +-0.1 -0.39999999999999997 0.5 +-0.24999999999999994 -0.34150635094610965 0.5 +-0.2500000000000001 -0.4330127018922193 0.16666666666666674 +-0.2499999999999999 -0.4330127018922193 0.5 +-0.35980762113533155 -0.2500000000000001 0.16666666666666666 +-0.375 -0.12500000000000006 0.16666666666666663 +-0.3598076211353315 -0.25000000000000006 0.5 +-0.375 -0.12499999999999999 0.5 +-0.4330127018922191 -0.25000000000000033 0.16666666666666663 +-0.4330127018922192 -0.2500000000000001 0.5 +-0.30000000000000004 -0.10000000000000003 0.16666666666666663 +-0.3 -0.1 0.5 +-0.09999999999999996 -0.10000000000000005 -0.16666666666666666 +-0.20833333333333331 -0.12499999999999997 -0.16666666666666666 +-0.25 -0.24999999999999992 -0.16666666666666666 +-0.12499999999999999 -0.25 -0.16666666666666666 +-0.09999999999999999 -0.3999999999999999 -0.16666666666666666 +-0.24999999999999994 -0.3415063509461096 -0.16666666666666666 +-0.2499999999999999 -0.4330127018922193 -0.16666666666666669 +-0.3598076211353316 -0.24999999999999994 -0.16666666666666666 +-0.375 -0.1249999999999999 -0.16666666666666666 +-0.4330127018922194 -0.24999999999999978 -0.16666666666666663 +-0.3 -0.09999999999999995 -0.16666666666666666 +-0.09999999999999995 -0.1 -0.5 +-0.20833333333333334 -0.12499999999999994 -0.5 +-0.2500000000000001 -0.2499999999999999 -0.5 +-0.12500000000000006 -0.24999999999999994 -0.5 +-0.1000000000000001 -0.3999999999999999 -0.5 +-0.2500000000000001 -0.3415063509461096 -0.5 +-0.2500000000000002 -0.4330127018922192 -0.5 +-0.3598076211353317 -0.24999999999999994 -0.5 +-0.3750000000000001 -0.12499999999999989 -0.5 +-0.4330127018922194 -0.24999999999999983 -0.5 +-0.30000000000000004 -0.09999999999999994 -0.5 +0.666666666666667 0. 0.16666666666666663 +0.6666666666666667 0. 0.5 +0.5773502691896261 0.3333333333333335 0.16666666666666663 +0.5773502691896258 0.33333333333333337 0.5 +0.8333333333333326 0. 0.16666666666666663 +0.8333333333333333 0. 0.5 +0.7216878364870316 0.4166666666666663 0.16666666666666663 +0.721687836487032 0.4166666666666665 0.5 +1. 0. 0.16666666666666663 +1. 0. 0.5 +0.8660254037844386 0.4999999999999998 0.1666666666666666 +0.8660254037844386 0.4999999999999999 0.5 +0.6666666666666672 0. -0.16666666666666666 +0.5773502691896263 0.3333333333333336 -0.16666666666666666 +0.8333333333333337 0. -0.16666666666666663 +0.7216878364870325 0.41666666666666685 -0.16666666666666663 +1. 0. -0.16666666666666669 +0.8660254037844386 0.4999999999999999 -0.16666666666666674 +0.6666666666666667 0. -0.5 +0.5773502691896258 0.33333333333333337 -0.5 +0.8333333333333333 0. -0.5 +0.721687836487032 0.4166666666666666 -0.5 +1. 0. -0.5 +0.8660254037844386 0.5 -0.5 +0.3333333333333335 0.5773502691896261 0.16666666666666666 +0.3333333333333333 0.577350269189626 0.5 +0.4166666666666663 0.7216878364870316 0.16666666666666666 +0.41666666666666663 0.7216878364870322 0.5 +0.5000000000000002 0.8660254037844384 0.16666666666666663 +0.5 0.8660254037844386 0.5 +0.3333333333333336 0.5773502691896263 -0.16666666666666663 +0.41666666666666685 0.7216878364870325 -0.1666666666666666 +0.5 0.8660254037844386 -0.1666666666666666 +0.3333333333333333 0.577350269189626 -0.5 +0.4166666666666665 0.7216878364870322 -0.5 +0.4999999999999999 0.8660254037844386 -0.5 +0. 0.666666666666667 0.16666666666666663 +0. 0.6666666666666667 0.5 +0. 0.8333333333333326 0.16666666666666663 +0. 0.8333333333333333 0.5 +0. 1. 0.16666666666666663 +0. 1. 0.5 +0. 0.6666666666666672 -0.16666666666666666 +0. 0.8333333333333337 -0.16666666666666663 +0. 1. -0.16666666666666669 +0. 0.6666666666666667 -0.5 +0. 0.8333333333333333 -0.5 +0. 1. -0.5 +0.5773502691896261 -0.3333333333333335 0.16666666666666663 +0.5773502691896258 -0.33333333333333337 0.5 +0.7216878364870316 -0.41666666666666624 0.16666666666666663 +0.721687836487032 -0.4166666666666666 0.5 +0.8660254037844386 -0.4999999999999998 0.16666666666666669 +0.8660254037844386 -0.5 0.5 +0.5773502691896263 -0.33333333333333354 -0.16666666666666669 +0.7216878364870325 -0.41666666666666674 -0.16666666666666663 +0.8660254037844386 -0.4999999999999998 -0.16666666666666666 +0.5773502691896258 -0.33333333333333337 -0.5 +0.721687836487032 -0.4166666666666666 -0.5 +0.8660254037844386 -0.4999999999999999 -0.5 +0.3333333333333335 -0.577350269189626 0.16666666666666666 +0.3333333333333333 -0.5773502691896257 0.5 +0.4166666666666663 -0.7216878364870315 0.16666666666666666 +0.4166666666666665 -0.7216878364870322 0.5 +0.5 -0.8660254037844386 0.1666666666666666 +0.4999999999999999 -0.8660254037844386 0.5 +0.3333333333333336 -0.5773502691896261 -0.16666666666666663 +0.41666666666666685 -0.7216878364870324 -0.1666666666666666 +0.5000000000000002 -0.8660254037844384 -0.16666666666666663 +0.3333333333333333 -0.577350269189626 -0.5 +0.41666666666666663 -0.721687836487032 -0.5 +0.5 -0.8660254037844386 -0.5 +0. -0.666666666666667 0.16666666666666669 +0. -0.6666666666666666 0.5 +0. -0.8333333333333326 0.16666666666666669 +0. -0.8333333333333333 0.5 +0. -1. 0.16666666666666669 +0. -1. 0.5 +0. -0.6666666666666672 -0.1666666666666666 +0. -0.8333333333333337 -0.16666666666666657 +0. -1. -0.16666666666666663 +0. -0.6666666666666667 -0.5 +0. -0.8333333333333334 -0.5 +0. -1. -0.5 +-0.41666666666666663 -0.7216878364870322 -0.5 +-0.4999999999999998 -0.8660254037844386 -0.5 +-0.5000000000000002 -0.8660254037844386 -0.16666666666666663 +-0.416666666666667 -0.7216878364870323 -0.16666666666666657 +-0.3333333333333335 -0.5773502691896257 -0.5 +-0.3333333333333337 -0.577350269189626 -0.16666666666666657 +-0.5000000000000002 -0.8660254037844386 0.16666666666666666 +-0.4166666666666665 -0.7216878364870314 0.16666666666666669 +-0.33333333333333365 -0.5773502691896257 0.16666666666666669 +-0.5000000000000004 -0.8660254037844384 0.5 +-0.4166666666666669 -0.721687836487032 0.5 +-0.33333333333333337 -0.5773502691896256 0.5 +-0.7216878364870322 -0.41666666666666685 -0.5 +-0.8660254037844384 -0.5000000000000002 -0.5 +-0.8660254037844382 -0.5000000000000007 -0.16666666666666663 +-0.7216878364870325 -0.41666666666666696 -0.1666666666666666 +-0.5773502691896258 -0.33333333333333337 -0.5 +-0.5773502691896262 -0.3333333333333336 -0.16666666666666663 +-0.8660254037844388 -0.49999999999999956 0.16666666666666663 +-0.7216878364870316 -0.4166666666666663 0.16666666666666666 +-0.5773502691896261 -0.3333333333333334 0.16666666666666666 +-0.8660254037844388 -0.49999999999999967 0.5 +-0.721687836487032 -0.4166666666666665 0.5 +-0.5773502691896257 -0.3333333333333333 0.5 +-0.8333333333333334 0. -0.5 +-1. 0. -0.5 +-1. 0. -0.16666666666666663 +-0.8333333333333337 0. -0.1666666666666666 +-0.6666666666666667 0. -0.5 +-0.6666666666666672 0. -0.16666666666666663 +-1. 0. 0.16666666666666669 +-0.8333333333333326 0. 0.16666666666666666 +-0.666666666666667 0. 0.16666666666666666 +-1. 0. 0.5 +-0.8333333333333333 0. 0.5 +-0.6666666666666666 0. 0.5 +-0.577350269189626 0.33333333333333337 0.16666666666666666 +-0.5773502691896256 0.33333333333333326 0.5 +-0.7216878364870316 0.4166666666666662 0.16666666666666666 +-0.7216878364870322 0.41666666666666663 0.5 +-0.8660254037844388 0.49999999999999967 0.16666666666666677 +-0.8660254037844384 0.5000000000000002 0.5 +-0.5773502691896263 0.3333333333333334 -0.16666666666666669 +-0.7216878364870327 0.4166666666666667 -0.16666666666666666 +-0.8660254037844388 0.49999999999999967 -0.16666666666666669 +-0.577350269189626 0.3333333333333333 -0.5 +-0.7216878364870325 0.41666666666666646 -0.5 +-0.8660254037844388 0.49999999999999967 -0.5 +-0.3333333333333333 0.577350269189626 0.16666666666666666 +-0.3333333333333335 0.5773502691896255 0.5 +-0.4166666666666661 0.7216878364870315 0.16666666666666666 +-0.4166666666666665 0.7216878364870323 0.5 +-0.4999999999999988 0.8660254037844393 0.16666666666666663 +-0.4999999999999998 0.8660254037844386 0.5 +-0.3333333333333335 0.5773502691896261 -0.16666666666666663 +-0.4166666666666667 0.7216878364870324 -0.1666666666666666 +-0.49999999999999956 0.8660254037844388 -0.16666666666666666 +-0.3333333333333334 0.5773502691896257 -0.5 +-0.41666666666666696 0.7216878364870317 -0.5 +-0.5000000000000004 0.8660254037844384 -0.5 diff --git a/miniapps/electromagnetics/cylinder-tet.mesh b/miniapps/electromagnetics/cylinder-tet.mesh index 76ff5f1b84..66129b614d 100644 --- a/miniapps/electromagnetics/cylinder-tet.mesh +++ b/miniapps/electromagnetics/cylinder-tet.mesh @@ -1,1216 +1,1216 @@ -MFEM mesh v1.1 - -# -# MFEM Geometry Types (see mesh/geom.hpp): -# -# POINT = 0 -# SEGMENT = 1 -# TRIANGLE = 2 -# SQUARE = 3 -# TETRAHEDRON = 4 -# CUBE = 5 -# - -dimension -3 - -elements -789 -1 4 0 1 2 3 -1 4 4 2 5 3 -1 4 6 7 8 3 -1 4 4 5 7 3 -1 4 9 10 11 7 -1 4 12 11 13 6 -1 4 10 14 15 16 -1 4 17 14 8 16 -1 4 10 6 8 16 -1 4 18 17 8 16 -1 4 11 6 10 16 -1 4 19 17 14 8 -1 4 20 21 22 1 -1 4 23 24 25 8 -1 4 26 14 1 8 -1 4 26 27 24 8 -1 4 25 24 27 8 -1 4 28 7 6 3 -1 4 29 30 31 32 -1 4 33 11 10 16 -1 4 11 10 6 7 -1 4 34 10 5 35 -1 4 36 37 38 39 -1 4 34 10 9 7 -1 4 28 4 7 3 -1 4 34 4 5 7 -1 4 1 40 8 3 -1 4 34 41 9 10 -1 4 34 5 4 35 -1 4 42 43 30 15 -1 4 4 5 43 35 -1 4 41 44 45 35 -1 4 44 43 45 35 -1 4 34 41 10 35 -1 4 26 30 1 14 -1 4 39 17 15 14 -1 4 15 14 17 16 -1 4 46 47 17 16 -1 4 5 1 14 8 -1 4 48 25 6 8 -1 4 46 18 6 16 -1 4 37 19 38 39 -1 4 37 49 38 19 -1 4 47 15 17 16 -1 4 50 15 39 17 -1 4 22 51 52 26 -1 4 50 47 15 17 -1 4 33 10 15 16 -1 4 21 22 1 40 -1 4 26 40 27 8 -1 4 53 54 42 43 -1 4 10 8 14 16 -1 4 5 10 7 8 -1 4 55 25 56 27 -1 4 48 25 57 6 -1 4 23 18 24 8 -1 4 55 57 25 58 -1 4 28 57 59 3 -1 4 25 8 40 3 -1 4 0 40 1 3 -1 4 60 26 40 27 -1 4 61 30 39 15 -1 4 19 17 39 14 -1 4 49 18 46 17 -1 4 36 37 39 32 -1 4 38 39 19 17 -1 4 62 55 56 27 -1 4 26 32 30 14 -1 4 0 63 40 58 -1 4 23 56 25 24 -1 4 48 6 18 8 -1 4 60 27 64 24 -1 4 62 56 64 27 -1 4 55 25 40 58 -1 4 22 51 26 40 -1 4 63 55 65 27 -1 4 46 66 6 18 -1 4 23 48 18 8 -1 4 60 67 26 24 -1 4 62 65 55 27 -1 4 68 55 63 58 -1 4 63 55 40 58 -1 4 57 25 58 3 -1 4 68 0 69 58 -1 4 59 57 69 58 -1 4 49 38 19 17 -1 4 61 30 70 39 -1 4 71 33 10 15 -1 4 49 46 47 17 -1 4 5 30 1 43 -1 4 42 43 15 35 -1 4 50 72 61 15 -1 4 73 61 72 15 -1 4 33 15 47 16 -1 4 28 6 57 3 -1 4 25 40 58 3 -1 4 46 6 11 16 -1 4 74 48 13 6 -1 4 28 75 57 6 -1 4 75 13 57 6 -1 4 41 15 10 35 -1 4 76 2 1 43 -1 4 10 30 43 15 -1 4 44 77 53 43 -1 4 4 5 2 43 -1 4 44 4 43 35 -1 4 41 71 10 15 -1 4 78 79 26 32 -1 4 36 80 81 39 -1 4 78 19 37 32 -1 4 60 64 67 24 -1 4 26 31 30 32 -1 4 80 70 81 39 -1 4 54 29 30 31 -1 4 82 59 28 57 -1 4 83 50 47 15 -1 4 30 32 39 14 -1 4 78 67 19 26 -1 4 78 26 19 32 -1 4 22 26 1 40 -1 4 23 25 48 8 -1 4 19 32 26 14 -1 4 52 26 79 31 -1 4 22 26 52 31 -1 4 30 39 15 14 -1 4 19 18 17 8 -1 4 49 19 84 18 -1 4 78 51 67 26 -1 4 2 5 1 43 -1 4 55 40 25 27 -1 4 0 58 40 3 -1 4 5 1 30 14 -1 4 5 1 8 3 -1 4 60 51 85 40 -1 4 1 43 30 31 -1 4 20 76 1 31 -1 4 2 1 5 3 -1 4 20 1 22 31 -1 4 49 47 38 17 -1 4 5 10 30 43 -1 4 5 14 10 8 -1 4 67 19 26 24 -1 4 49 19 18 17 -1 4 86 70 29 32 -1 4 78 36 87 32 -1 4 50 61 39 15 -1 4 46 17 18 16 -1 4 71 88 73 15 -1 4 10 15 43 35 -1 4 49 89 66 18 -1 4 66 48 74 6 -1 4 66 48 6 18 -1 4 6 18 8 16 -1 4 49 84 89 18 -1 4 56 27 25 24 -1 4 59 57 58 3 -1 4 28 12 6 7 -1 4 20 76 21 1 -1 4 19 26 24 8 -1 4 90 76 54 43 -1 4 46 11 33 16 -1 4 84 19 67 24 -1 4 77 4 2 43 -1 4 76 54 43 31 -1 4 77 2 76 43 -1 4 46 33 47 16 -1 4 55 57 48 25 -1 4 13 48 57 6 -1 4 69 57 55 58 -1 4 41 45 42 35 -1 4 52 51 79 26 -1 4 91 52 86 31 -1 4 28 12 75 6 -1 4 60 40 85 27 -1 4 63 85 40 27 -1 4 54 30 43 31 -1 4 9 33 11 10 -1 4 87 70 86 32 -1 4 9 71 33 10 -1 4 42 30 61 15 -1 4 20 52 91 31 -1 4 49 66 46 18 -1 4 25 27 40 8 -1 4 64 84 67 24 -1 4 62 60 85 27 -1 4 66 23 48 18 -1 4 82 28 75 57 -1 4 42 54 30 43 -1 4 63 22 21 40 -1 4 0 21 1 40 -1 4 92 90 76 54 -1 4 20 22 52 31 -1 4 63 85 22 40 -1 4 63 40 55 27 -1 4 0 63 21 40 -1 4 42 70 61 30 -1 4 64 27 56 24 -1 4 84 24 23 18 -1 4 71 73 83 15 -1 4 83 72 50 15 -1 4 80 61 70 39 -1 4 0 21 2 1 -1 4 20 92 76 31 -1 4 34 5 10 7 -1 4 62 85 65 27 -1 4 73 88 42 15 -1 4 12 11 6 7 -1 4 68 69 55 58 -1 4 25 6 8 3 -1 4 46 74 11 6 -1 4 84 93 23 24 -1 4 87 81 70 32 -1 4 84 19 24 18 -1 4 84 93 89 23 -1 4 26 1 40 8 -1 4 84 23 89 18 -1 4 82 69 59 57 -1 4 64 56 23 24 -1 4 23 56 48 25 -1 4 22 1 26 31 -1 4 9 11 12 7 -1 4 10 30 15 14 -1 4 71 83 33 15 -1 4 26 1 30 31 -1 4 41 45 88 42 -1 4 5 8 7 3 -1 4 21 76 2 1 -1 4 90 54 53 43 -1 4 28 34 12 7 -1 4 9 41 71 10 -1 4 34 4 44 35 -1 4 22 85 51 40 -1 4 70 39 30 32 -1 4 45 53 42 43 -1 4 41 42 88 15 -1 4 19 39 32 14 -1 4 44 53 45 43 -1 4 28 4 34 7 -1 4 37 67 84 19 -1 4 59 69 0 58 -1 4 92 91 54 31 -1 4 91 86 29 31 -1 4 42 54 29 30 -1 4 64 93 84 24 -1 4 73 42 61 15 -1 4 60 26 51 40 -1 4 91 29 54 31 -1 4 80 50 72 61 -1 4 78 87 79 32 -1 4 19 24 18 8 -1 4 36 39 81 32 -1 4 52 79 86 31 -1 4 19 14 26 8 -1 4 78 79 51 26 -1 4 50 38 47 17 -1 4 46 66 74 6 -1 4 64 23 93 24 -1 4 76 43 1 31 -1 4 10 6 7 8 -1 4 63 65 85 27 -1 4 5 30 10 14 -1 4 20 91 92 31 -1 4 36 38 80 39 -1 4 79 31 26 32 -1 4 5 10 43 35 -1 4 74 13 11 6 -1 4 45 43 42 35 -1 4 83 73 72 15 -1 4 83 47 33 15 -1 4 78 37 36 32 -1 4 37 19 39 32 -1 4 78 67 37 19 -1 4 75 12 13 6 -1 4 77 76 90 43 -1 4 86 29 31 32 -1 4 60 26 27 24 -1 4 80 38 50 39 -1 4 81 39 70 32 -1 4 62 64 60 27 -1 4 42 29 70 30 -1 4 86 31 79 32 -1 4 44 4 77 43 -1 4 55 48 56 25 -1 4 77 90 53 43 -1 4 92 54 76 31 -1 4 68 63 0 58 -1 4 41 88 71 15 -1 4 37 84 49 19 -1 4 41 42 15 35 -1 4 50 39 38 17 -1 4 29 70 30 32 -1 4 68 65 63 55 -1 4 60 67 51 26 -1 4 87 86 79 32 -1 4 36 81 87 32 -1 4 66 89 23 18 -1 4 59 0 2 3 -1 4 59 58 0 3 -1 4 59 2 4 3 -1 4 34 9 12 7 -1 4 80 50 61 39 -1 4 57 6 25 3 -1 4 28 59 4 3 -1 4 34 44 41 35 -2 4 33 94 95 96 -2 4 74 11 97 96 -2 4 33 95 11 96 -2 4 46 11 74 96 -2 4 98 99 100 101 -2 4 102 100 103 101 -2 4 104 102 103 101 -2 4 102 100 105 103 -2 4 106 107 108 109 -2 4 77 110 111 109 -2 4 59 108 107 109 -2 4 59 107 4 109 -2 4 77 4 112 109 -2 4 93 100 99 101 -2 4 104 113 98 101 -2 4 67 114 104 101 -2 4 37 84 67 101 -2 4 113 115 116 117 -2 4 64 116 60 117 -2 4 64 84 93 117 -2 4 64 93 99 117 -2 4 60 116 115 117 -2 4 47 118 94 119 -2 4 120 121 110 111 -2 4 38 119 103 122 -2 4 123 118 124 119 -2 4 125 119 126 122 -2 4 127 125 103 119 -2 4 124 118 126 119 -2 4 128 129 130 131 -2 4 21 132 129 133 -2 4 20 21 132 129 -2 4 91 134 52 129 -2 4 79 51 131 135 -2 4 22 133 129 130 -2 4 128 129 133 130 -2 4 22 51 130 131 -2 4 136 130 115 131 -2 4 128 136 137 131 -2 4 138 139 112 109 -2 4 4 140 112 107 -2 4 104 102 127 103 -2 4 141 112 140 107 -2 4 141 142 138 107 -2 4 141 143 142 107 -2 4 75 143 144 140 -2 4 12 75 144 140 -2 4 106 138 107 109 -2 4 145 146 147 148 -2 4 21 132 148 149 -2 4 21 148 132 133 -2 4 0 68 150 148 -2 4 69 150 108 149 -2 4 139 111 110 109 -2 4 106 146 151 149 -2 4 21 149 2 111 -2 4 21 132 149 111 -2 4 63 22 85 133 -2 4 146 150 148 149 -2 4 63 65 152 133 -2 4 145 149 132 111 -2 4 83 94 47 118 -2 4 81 153 80 122 -2 4 46 94 33 96 -2 4 83 154 94 118 -2 4 123 94 118 119 -2 4 123 94 155 118 -2 4 106 149 151 109 -2 4 76 77 90 111 -2 4 145 132 120 111 -2 4 145 151 149 111 -2 4 0 21 148 149 -2 4 21 76 132 111 -2 4 60 130 51 115 -2 4 136 131 115 135 -2 4 22 85 133 130 -2 4 127 124 125 119 -2 4 151 149 111 109 -2 4 156 157 141 112 -2 4 141 138 112 107 -2 4 34 140 157 112 -2 4 4 107 112 109 -2 4 34 157 44 112 -2 4 158 130 116 115 -2 4 159 160 128 133 -2 4 91 161 134 129 -2 4 128 137 129 131 -2 4 162 152 159 133 -2 4 162 132 148 133 -2 4 156 163 164 157 -2 4 162 128 129 133 -2 4 113 158 116 115 -2 4 64 60 67 117 -2 4 78 114 115 135 -2 4 78 79 87 135 -2 4 62 116 165 130 -2 4 136 130 158 115 -2 4 141 164 166 157 -2 4 166 167 168 157 -2 4 41 9 168 157 -2 4 138 151 139 109 -2 4 141 157 140 112 -2 4 9 11 95 169 -2 4 141 170 143 140 -2 4 9 34 12 140 -2 4 9 95 168 169 -2 4 166 171 144 169 -2 4 172 168 95 169 -2 4 173 155 95 154 -2 4 174 95 155 94 -2 4 174 172 95 96 -2 4 11 169 97 96 -2 4 175 94 176 177 -2 4 36 78 87 178 -2 4 179 172 174 96 -2 4 179 97 172 96 -2 4 46 33 11 96 -2 4 125 103 119 122 -2 4 102 103 105 177 -2 4 0 148 150 149 -2 4 49 47 177 119 -2 4 49 103 38 119 -2 4 37 49 84 103 -2 4 127 103 177 119 -2 4 36 103 104 122 -2 4 180 155 181 118 -2 4 83 72 181 118 -2 4 49 177 103 119 -2 4 83 154 33 94 -2 4 174 173 155 95 -2 4 155 94 154 118 -2 4 47 94 177 119 -2 4 182 181 155 154 -2 4 182 180 155 181 -2 4 173 183 182 154 -2 4 72 126 181 118 -2 4 73 181 183 154 -2 4 71 83 73 154 -2 4 83 181 154 118 -2 4 160 133 165 130 -2 4 52 134 86 131 -2 4 51 115 131 135 -2 4 184 185 186 135 -2 4 136 186 131 135 -2 4 186 185 131 135 -2 4 87 185 178 135 -2 4 78 67 51 115 -2 4 87 79 185 135 -2 4 37 104 36 103 -2 4 77 112 110 109 -2 4 187 104 125 122 -2 4 36 178 81 122 -2 4 36 81 80 122 -2 4 125 126 153 122 -2 4 80 126 119 122 -2 4 80 126 50 119 -2 4 33 168 95 154 -2 4 166 167 188 168 -2 4 173 168 183 154 -2 4 71 183 88 168 -2 4 188 167 183 168 -2 4 88 183 167 168 -2 4 123 177 94 119 -2 4 189 100 102 101 -2 4 46 47 33 94 -2 4 175 174 94 96 -2 4 176 94 123 177 -2 4 127 177 123 119 -2 4 102 190 176 177 -2 4 63 0 21 148 -2 4 191 162 161 132 -2 4 92 76 121 132 -2 4 139 110 112 109 -2 4 145 148 132 149 -2 4 34 4 140 112 -2 4 21 129 22 133 -2 4 162 129 132 133 -2 4 63 148 21 133 -2 4 44 53 77 112 -2 4 59 108 82 107 -2 4 28 143 140 107 -2 4 28 140 4 107 -2 4 166 169 144 140 -2 4 142 143 108 107 -2 4 76 121 132 111 -2 4 59 4 2 109 -2 4 106 108 146 149 -2 4 76 2 77 111 -2 4 21 2 76 111 -2 4 59 2 0 149 -2 4 159 152 165 133 -2 4 63 152 148 133 -2 4 166 173 172 168 -2 4 164 163 167 157 -2 4 45 163 44 157 -2 4 164 188 166 167 -2 4 156 164 141 157 -2 4 120 132 121 111 -2 4 80 153 126 122 -2 4 76 90 121 111 -2 4 123 180 124 118 -2 4 83 47 50 118 -2 4 73 83 72 181 -2 4 83 50 72 118 -2 4 173 95 168 154 -2 4 73 83 181 154 -2 4 59 149 108 109 -2 4 90 77 53 110 -2 4 151 120 139 111 -2 4 156 139 110 112 -2 4 44 77 4 112 -2 4 192 137 134 129 -2 4 92 121 161 132 -2 4 92 76 90 121 -2 4 78 104 67 114 -2 4 53 163 110 112 -2 4 92 20 76 132 -2 4 0 150 69 149 -2 4 0 68 69 150 -2 4 81 178 153 122 -2 4 104 114 113 101 -2 4 83 33 47 94 -2 4 175 190 193 177 -2 4 66 193 105 177 -2 4 172 97 169 96 -2 4 127 123 124 119 -2 4 50 118 47 119 -2 4 66 46 74 193 -2 4 41 71 88 168 -2 4 188 183 173 168 -2 4 41 34 9 157 -2 4 173 182 155 154 -2 4 41 88 167 168 -2 4 49 89 100 105 -2 4 104 127 125 103 -2 4 187 125 153 122 -2 4 86 134 185 131 -2 4 191 161 121 132 -2 4 44 163 53 112 -2 4 156 141 138 112 -2 4 45 167 163 157 -2 4 9 166 157 140 -2 4 52 79 51 131 -2 4 22 52 51 131 -2 4 162 128 192 129 -2 4 52 86 79 131 -2 4 91 86 52 134 -2 4 91 52 20 129 -2 4 84 117 67 101 -2 4 84 103 100 101 -2 4 189 102 100 105 -2 4 84 49 100 103 -2 4 79 131 185 135 -2 4 142 106 138 107 -2 4 162 147 152 148 -2 4 162 159 128 133 -2 4 68 152 150 148 -2 4 106 151 138 109 -2 4 63 68 0 148 -2 4 22 130 129 131 -2 4 191 162 192 161 -2 4 192 134 161 129 -2 4 173 95 172 168 -2 4 9 95 33 168 -2 4 160 165 116 130 -2 4 86 185 79 131 -2 4 162 147 159 152 -2 4 20 52 22 129 -2 4 62 65 85 165 -2 4 128 160 136 130 -2 4 65 85 165 133 -2 4 60 51 67 115 -2 4 114 136 115 135 -2 4 22 51 85 130 -2 4 137 186 185 131 -2 4 52 129 134 131 -2 4 71 168 33 154 -2 4 9 168 166 169 -2 4 174 155 176 94 -2 4 84 93 117 101 -2 4 71 33 83 154 -2 4 37 104 103 101 -2 4 104 103 125 122 -2 4 84 49 89 100 -2 4 49 66 105 177 -2 4 49 47 46 177 -2 4 102 176 127 177 -2 4 102 127 103 177 -2 4 67 115 114 117 -2 4 37 103 84 101 -2 4 64 99 116 117 -2 4 113 114 117 101 -2 4 85 165 133 130 -2 4 37 67 104 101 -2 4 66 46 193 177 -2 4 9 33 71 168 -2 4 174 95 94 96 -2 4 182 183 181 154 -2 4 71 183 168 154 -2 4 176 155 123 94 -2 4 91 20 161 129 -2 4 63 21 22 133 -2 4 128 130 136 131 -2 4 63 85 65 133 -2 4 2 111 149 109 -2 4 20 22 21 129 -2 4 145 162 132 148 -2 4 174 172 173 95 -2 4 124 181 126 118 -2 4 180 181 124 118 -2 4 46 47 94 177 -2 4 176 123 127 177 -2 4 50 126 118 119 -2 4 190 105 193 177 -2 4 80 50 38 119 -2 4 59 69 108 149 -2 4 63 152 68 148 -2 4 147 150 152 148 -2 4 59 69 82 108 -2 4 63 65 68 152 -2 4 0 2 21 149 -2 4 175 176 190 177 -2 4 106 108 149 109 -2 4 160 158 136 130 -2 4 65 165 152 133 -2 4 60 85 51 130 -2 4 141 140 143 107 -2 4 28 82 143 107 -2 4 59 0 69 149 -2 4 146 150 147 148 -2 4 82 108 143 107 -2 4 142 108 106 107 -2 4 162 161 132 129 -2 4 92 161 20 132 -2 4 50 126 72 118 -2 4 172 169 95 96 -2 4 11 13 97 169 -2 4 12 13 11 169 -2 4 141 157 166 140 -2 4 28 75 12 140 -2 4 12 75 13 144 -2 4 9 12 11 169 -2 4 9 11 33 95 -2 4 179 174 175 96 -2 4 46 74 193 96 -2 4 41 45 44 157 -2 4 41 168 167 157 -2 4 41 88 45 167 -2 4 41 9 71 168 -2 4 9 157 34 140 -2 4 12 144 13 169 -2 4 155 95 154 94 -2 4 45 53 44 163 -2 4 90 77 110 111 -2 4 9 169 166 140 -2 4 41 44 34 157 -2 4 114 136 158 115 -2 4 78 115 51 135 -2 4 160 116 158 130 -2 4 113 116 99 117 -2 4 164 167 166 157 -2 4 191 121 120 132 -2 4 166 168 172 169 -2 4 12 144 169 140 -2 4 67 117 114 101 -2 4 49 105 100 103 -2 4 13 144 97 169 -2 4 151 111 139 109 -2 4 156 110 163 112 -2 4 71 73 88 183 -2 4 71 73 183 154 -2 4 33 154 95 94 -2 4 141 166 170 140 -2 4 28 82 75 143 -2 4 171 97 144 169 -2 4 74 11 13 97 -2 4 145 151 146 149 -2 4 172 97 171 169 -2 4 60 116 62 130 -2 4 62 165 85 130 -2 4 145 146 148 149 -2 4 128 133 160 130 -2 4 22 129 52 131 -2 4 187 178 104 122 -2 4 166 172 171 169 -2 4 44 157 163 112 -2 4 11 95 169 96 -2 4 28 34 4 140 -2 4 175 174 176 94 -2 4 175 94 193 96 -2 4 155 154 181 118 -2 4 114 186 136 135 -2 4 184 114 104 178 -2 4 184 114 178 135 -2 4 64 62 60 116 -2 4 78 178 114 135 -2 4 162 192 161 129 -2 4 20 21 76 132 -2 4 145 162 191 132 -2 4 91 20 92 161 -2 4 77 2 4 109 -2 4 139 120 110 111 -2 4 137 134 129 131 -2 4 90 110 121 111 -2 4 34 44 4 112 -2 4 77 111 2 109 -2 4 145 191 120 132 -2 4 59 28 4 107 -2 4 137 185 134 131 -2 4 41 167 45 157 -2 4 98 113 99 101 -2 4 104 189 102 101 -2 4 113 114 115 117 -2 4 159 165 160 133 -2 4 145 120 151 111 -2 4 60 116 130 115 -2 4 49 66 89 105 -2 4 170 166 144 140 -2 4 113 117 99 101 -2 4 36 104 78 178 -2 4 37 78 36 104 -2 4 78 51 79 135 -2 4 59 2 149 109 -2 4 184 178 185 135 -2 4 51 115 130 131 -2 4 78 87 178 135 -2 4 60 115 67 117 -2 4 137 136 186 131 -2 4 36 87 81 178 -2 4 49 105 103 177 -2 4 179 193 97 96 -2 4 175 193 94 177 -2 4 49 46 66 177 -2 4 156 138 139 112 -2 4 46 94 193 177 -2 4 36 80 38 122 -2 4 59 82 28 107 -2 4 28 143 75 140 -2 4 162 148 152 133 -2 4 145 147 162 148 -2 4 46 193 94 96 -2 4 179 175 193 96 -2 4 74 97 193 96 -2 4 125 124 126 119 -2 4 38 50 47 119 -2 4 170 144 143 140 -2 4 104 98 189 101 -2 4 80 119 38 122 -2 4 60 62 85 130 -2 4 141 170 142 143 -2 4 102 105 190 177 -2 4 84 89 93 100 -2 4 80 72 50 126 -2 4 49 38 47 119 -2 4 20 132 161 129 -2 4 64 67 84 117 -2 4 37 67 78 104 -2 4 184 186 114 135 -2 4 37 38 49 103 -2 4 187 153 178 122 -2 4 36 104 178 122 -2 4 87 79 86 185 -2 4 189 98 100 101 -2 4 189 190 102 105 -2 4 9 166 168 157 -2 4 9 12 169 140 -2 4 138 112 107 109 -2 4 188 182 173 183 -2 4 93 99 117 101 -2 4 78 114 67 115 -2 4 156 163 157 112 -2 4 78 104 114 178 -2 4 184 104 187 178 -2 4 36 38 103 122 -2 4 166 188 173 168 -2 4 123 155 180 118 -2 4 37 36 38 103 -2 4 28 12 34 140 -2 4 77 53 110 112 -2 4 179 171 172 97 -2 4 128 137 192 129 -2 4 146 108 150 149 -2 4 84 100 93 101 -2 4 170 166 171 144 -2 4 113 114 158 115 - -boundary -208 -1 2 68 55 69 -1 2 93 89 23 -1 2 55 56 48 -1 2 62 56 55 -1 2 62 55 65 -1 2 66 23 89 -1 2 55 48 57 -1 2 66 48 23 -1 2 66 74 48 -1 2 68 65 55 -1 2 64 93 23 -1 2 74 13 48 -1 2 82 57 75 -1 2 64 23 56 -1 2 23 48 56 -1 2 69 55 57 -1 2 62 64 56 -1 2 82 69 57 -1 2 75 57 13 -1 2 13 57 48 -1 2 146 147 150 -1 2 89 93 100 -1 2 82 75 143 -1 2 64 99 93 -1 2 65 68 152 -1 2 170 144 171 -1 2 175 193 190 -1 2 142 108 143 -1 2 189 190 105 -1 2 74 97 13 -1 2 189 100 98 -1 2 179 171 97 -1 2 66 193 74 -1 2 62 65 165 -1 2 64 62 116 -1 2 142 106 108 -1 2 113 99 116 -1 2 68 150 152 -1 2 189 105 100 -1 2 89 100 105 -1 2 62 165 116 -1 2 69 82 108 -1 2 66 105 193 -1 2 190 193 105 -1 2 13 97 144 -1 2 147 159 152 -1 2 75 144 143 -1 2 66 89 105 -1 2 160 158 116 -1 2 147 152 150 -1 2 98 99 113 -1 2 68 69 150 -1 2 159 160 165 -1 2 113 116 158 -1 2 64 116 99 -1 2 170 142 143 -1 2 171 144 97 -1 2 170 143 144 -1 2 82 143 108 -1 2 69 108 150 -1 2 146 150 108 -1 2 106 146 108 -1 2 160 116 165 -1 2 159 165 152 -1 2 65 152 165 -1 2 98 100 99 -1 2 93 99 100 -1 2 74 193 97 -1 2 179 97 193 -1 2 179 193 175 -1 2 75 13 144 -2 2 73 61 42 -2 2 92 90 54 -2 2 91 54 29 -2 2 91 29 86 -2 2 80 61 72 -2 2 42 70 29 -2 2 90 53 54 -2 2 92 54 91 -2 2 73 72 61 -2 2 73 42 88 -2 2 42 61 70 -2 2 87 70 81 -2 2 80 70 61 -2 2 45 88 42 -2 2 45 42 53 -2 2 80 81 70 -2 2 42 29 54 -2 2 53 42 54 -2 2 86 29 70 -2 2 87 86 70 -2 2 191 161 192 -2 2 91 86 134 -2 2 164 188 167 -2 2 81 153 178 -2 2 73 181 72 -2 2 191 121 161 -2 2 191 120 121 -2 2 124 126 181 -2 2 87 81 178 -2 2 187 153 125 -2 2 188 182 183 -2 2 182 181 183 -2 2 92 121 90 -2 2 73 88 183 -2 2 87 178 185 -2 2 184 185 178 -2 2 90 110 53 -2 2 180 124 181 -2 2 90 121 110 -2 2 80 126 153 -2 2 87 185 86 -2 2 156 164 163 -2 2 88 45 167 -2 2 120 110 121 -2 2 125 153 126 -2 2 125 126 124 -2 2 156 163 110 -2 2 184 178 187 -2 2 91 161 92 -2 2 139 110 120 -2 2 91 134 161 -2 2 192 161 134 -2 2 192 134 137 -2 2 187 178 153 -2 2 73 183 181 -2 2 81 80 153 -2 2 182 180 181 -2 2 184 186 185 -2 2 92 161 121 -2 2 164 167 163 -2 2 45 163 167 -2 2 72 181 126 -2 2 80 72 126 -2 2 188 183 167 -2 2 88 167 183 -2 2 86 185 134 -2 2 137 134 185 -2 2 137 185 186 -2 2 156 110 139 -2 2 53 110 163 -2 2 45 53 163 -3 2 156 141 164 -3 2 141 142 170 -3 2 141 170 166 -3 2 145 191 162 -3 2 142 138 106 -3 2 184 187 104 -3 2 179 175 174 -3 2 104 189 98 -3 2 141 138 142 -3 2 159 128 160 -3 2 104 102 189 -3 2 128 192 137 -3 2 104 113 114 -3 2 145 146 151 -3 2 128 137 136 -3 2 156 139 138 -3 2 191 192 162 -3 2 145 162 147 -3 2 114 158 136 -3 2 184 114 186 -3 2 113 158 114 -3 2 176 127 123 -3 2 114 136 186 -3 2 187 125 104 -3 2 188 173 182 -3 2 166 172 173 -3 2 145 120 191 -3 2 104 98 113 -3 2 175 190 176 -3 2 175 176 174 -3 2 145 147 146 -3 2 179 172 171 -3 2 184 104 114 -3 2 137 186 136 -3 2 123 124 180 -3 2 106 138 151 -3 2 164 166 188 -3 2 106 151 146 -3 2 156 138 141 -3 2 141 166 164 -3 2 170 171 166 -3 2 166 173 188 -3 2 127 124 123 -3 2 189 102 190 -3 2 127 125 124 -3 2 162 128 159 -3 2 162 159 147 -3 2 138 139 151 -3 2 162 192 128 -3 2 160 136 158 -3 2 128 136 160 -3 2 151 139 120 -3 2 145 151 120 -3 2 102 176 190 -3 2 102 127 176 -3 2 104 125 127 -3 2 179 174 172 -3 2 166 171 172 -3 2 104 127 102 -3 2 182 155 180 -3 2 174 155 173 -3 2 173 155 182 -3 2 174 176 155 -3 2 176 123 155 -3 2 123 180 155 -3 2 174 173 172 - -vertices -194 -3 -0.11997195419097467 0.4853933767652775 0.2589180265268235 --0.010856803953973863 0.2425986392131464 -0.045413175647737614 -0.24306361668476772 0.4369440218656393 0.011464146250920404 -0.195818038071797 0.19789489642820537 0.17574910149909653 -0.4305958145480755 0.25414020636978973 0.010746350155629525 -0.18229432719890853 0.07154978461418435 0.005062844481944168 -0.20769078479683284 -0.1571614601395298 0.28916242978821277 -0.32848943413138754 -0.019071715998760914 0.11736316170436412 --0.021402334112599706 -0.09259164894757581 0.15723466079732742 -0.43582468446400036 -0.24506497997848342 -0.02188920206883055 -0.2206887347224819 -0.16740800818239635 -0.06475294639611945 -0.3576769918926359 -0.3493811235179073 0.2424738257434117 -0.4839265893768 -0.12575792656583507 0.24561453497006613 -0.43570968158023893 -0.2452693894012189 0.5 --0.06423753222010928 -0.08605471001342942 -0.052661201124829644 -0.12720304400812915 -0.2461219629292447 -0.3025522296563212 -0.11774212462954714 -0.28232447080304335 0.08470256603437014 --0.08958804437514946 -0.2866337526069329 0.010437254676599773 --0.11496003101039974 -0.2985337767151035 0.2777821697704855 --0.25742782564276834 -0.15887963248015538 0.07513322528612679 --0.14281309612062965 0.4791705537451564 -0.25655100411141574 --0.012023804698077074 0.4998554072135085 0.0008614304225812441 --0.26684255708862437 0.4228416366991361 0.004482075618457149 --0.19299604913517243 -0.20850229152545607 0.5 --0.28753677648407766 -0.07490310980313035 0.3169952001087608 --0.018192735296978593 0.039011950068369716 0.3312349340292917 --0.26953856745406424 0.05015274282835383 -0.007962456263327627 --0.2844994169434064 0.12927746826595696 0.31344932852845453 -0.4821087845581751 0.1325561007718586 0.2569062863349316 --0.14185684682876676 0.1565765244854318 -0.5 --0.03097886037265596 0.02928927839536998 -0.2676678538677485 --0.13769473423097411 0.2823346616652343 -0.30639228132844604 --0.28545292479556433 -0.057433337349894205 -0.2950439673729821 -0.2563359009870937 -0.42929233147720547 -0.026369197771376196 -0.4999858937711994 0.0037557994907759405 -0.00965060064717771 -0.35118834836766993 0.04605894350994181 -0.20880364537256635 --0.4187640200210708 -0.27319717336713456 -0.25 --0.4187640200210708 -0.27319717336713456 0. --0.2424136429356089 -0.4373049573451998 -0.14551444974248584 --0.176204707843803 -0.23760502140817893 -0.2897640092465014 --0.18811590295640457 0.224892084945821 0.15244216005169509 -0.4839934858438879 -0.12550022175551007 -0.2673506407688206 -0.16838400115940544 -0.045924516981502295 -0.5 -0.20730292969498612 0.1738990170372628 -0.2817604241829639 -0.4820910967508869 0.13262041484449877 -0.2567597289483131 -0.5 0. -0.5 -0.1270937202256388 -0.4835774873577212 0.23554234371594152 -0.004418815902774915 -0.4999804736847404 -0.05070109889922947 -0.06837845462111625 -0.15923796826127656 0.5 --0.1916008699591294 -0.46183233606029017 0.19248160419362736 --0.07157516625208954 -0.4948504779991485 -0.2904779710022272 --0.4564687867662406 0.2040496182504548 -0.006634770328774742 --0.36563815718436776 0.3410406691449269 -0.25970314261549454 -0.4310548235089896 0.2533608871346045 -0.5 -0.06840717137580687 0.27638589652485523 -0.5 --0.057368963778421156 0.2163557126213268 0.5 --0.2217889047167344 0.022030596613689224 0.5 -0.24824944094770662 0.07320012596009529 0.5 -0.05685687885736833 0.32301508538961726 0.378781099742994 -0.3492790100702384 0.35777670847101584 0.2650962067529058 --0.4786017412950019 0.1447078893128917 0.2756273490734399 --0.007270303983100357 -0.289982370357868 -0.5 --0.4423870584187638 0.23301006532678636 0.5 --0.142577496442851 0.479240709360222 0.25772629014882886 --0.4994578200390527 -0.023278445004707576 0.5 --0.2633220852606578 0.4250429147909407 0.5 -0.0163333763864498 -0.49973314960668613 0.5 --0.49743692488507296 -0.05056190028946966 0.1403935154754995 --0.011642379062566481 0.4998644366323368 0.5 -0.24324787311167112 0.43684147264957374 0.5 --0.22445532844900007 -0.09294413234398197 -0.5 -0.3595374815863839 -0.3474662563969638 -0.26985871138525586 -0.01633337672466685 -0.49973314959563175 -0.5 -0.2593717083715156 -0.4274649890885117 -0.5 -0.2593717079375579 -0.427464989351823 0.5 -0.5 0. 0.5 -0.11991911395363408 0.4854064339381744 -0.253131027048679 -0.3492243725499189 0.35783004012675546 -0.24892964340400275 --0.49728640869735186 -0.05202141602157956 -0.14992090460258778 --0.47860683828403505 0.14469103064032524 -0.2848272238244989 --0.23090526683537305 -0.4434892983462906 -0.5 --0.4187640200210708 -0.27319717336713456 -0.5 -0.4310590653573789 0.25335367013963483 0.5 -0.14596475359601946 -0.47821991876923453 -0.27469985351789106 --0.4187640200210708 -0.27319717336713456 0.25 --0.36475057815959055 0.34198978892979304 0.25876925855510313 --0.4424067176124312 0.2329727370560653 -0.5 --0.49945545791813406 -0.023329071044236163 -0.5 -0.4357096819122347 -0.24526938881144378 -0.5 --0.2309052669854515 -0.4434892982681514 0.5 -0.2432330449597631 0.436849729128452 -0.5 --0.26335074192012187 0.42502516011422353 -0.5 --0.011667713608086727 0.49986384592122646 -0.5 --0.4187640216620042 -0.27319717085186734 0.5 -0.1648092893260417 -0.698068472966144 0.01916480754979703 -0.49709773263551466 -0.5401644000750928 0.04685316334548395 -0.42923512816169396 -0.6200930575066769 0.28298192414755896 -0.5320971013969822 -0.44659715402945566 0.5 --0.8375280400421417 -0.5463943467342689 0.5 --0.6740374295910203 -0.2252897395303871 0.5 --0.4796886364253098 -0.5017756675750862 0.5 --0.6602148360204885 -0.42178475287936923 0.2738391654718595 --0.3743508885844845 -0.9272871250136101 0.1923014057089899 --0.3905463446030323 -0.5551470119858855 0.03028345229970595 --0.8375280400421417 -0.5463943467342691 0.0009050798851157893 --0.18388834997344516 -0.681726959426476 0.5 -0.6859084487184781 0.7276878451483237 0.5 -0.6908106003736185 0.3550173154374946 0.2365373453977786 -0.4963988652856184 0.5187144973091835 0.5 -0.4657982288202733 0.48926257925240496 -0.009066410328528141 -0.4972040079404958 0.5243373750500604 -0.5 -0.24595148858546906 0.6780839192636712 -0.16488678407288926 -0.6772703026987079 0.32970649744744135 -0.2085290091661496 --0.9868505920553636 -0.1616351105421665 0.5 --0.9999287545525191 0.0119367423968243 -0.02458037533056029 --0.6630818776079881 0.16130527090179975 0.13548961787098063 --0.6966957541845799 0.16853738083515957 0.5 --0.6808490402696524 -0.159003652416135 0.34002596081083414 -0.05598441718564498 -0.6858538317724099 -0.31631709529301594 --0.1933153032328007 -0.664775472160721 -0.2455951141007966 -0.3302750773609795 0.9438847245687361 -0.5 -0.14746101245794252 0.6952908100719171 -0.5 --0.44168803230554016 -0.4819714143630655 -0.3383847310733504 -0.07330668998626741 -0.9973094450586824 -0.2250937448115864 --0.13695776082997474 -0.9905768883577082 -0.5 --0.5322171407364256 -0.8466078874581453 -0.5 --0.1993178652507288 -0.6633324317723606 -0.5 --0.3179327565441217 -0.9481132644975789 -0.14660514943439706 --0.6476451030423191 0.7619421372422606 0.016891788312369038 --0.35841529411874334 0.5935814632694921 -0.14693224629347293 --0.628658619059129 0.3796275581847179 0.2273159046651026 --0.6230886408886086 0.37239930181553016 -0.22627696623588464 -0.016205952149959003 0.7447772580991381 -0.17397560473675172 --0.3356955256781739 0.6067970362626528 0.19891011219938176 --0.5073526820047336 0.5013325409139204 -0.5 --0.6948961904704768 0.14588809860205015 -0.20514122624342637 --0.9007476690444871 0.4343427640826112 -0.01750096847478627 --0.7926823329666097 0.6096349063190303 -0.5 -0.8171909034829123 0.5763670941897892 0.017944593391836405 -0.6787438518189246 0.7343750973569363 -0.5 -0.669488503042687 0.0031878968753018835 0.1702458759976271 -0.9805018388312463 0.19650990827066372 0.013536077514493927 -0.9182887744162915 0.3959112612455288 0.5 -0.6956629052588639 0.1782837817729419 0.5 -0.6850606674990449 -0.15838298131204254 0.5 -0.13171896645825493 0.9912870996210781 0.01830864398258303 -0.33824080956541 0.9410595914948936 0.5 --0.0724755357331037 0.9973701904108623 0.5 --0.002415753634857049 0.7195104385534825 0.21207969145156405 -0.2660217023032155 0.6834321682468841 0.1889190627097833 -0.13013064483278836 0.675116320748556 0.5 -0.5185029454428911 0.8550758419970981 -0.0074662502613973 --0.1931213680983992 0.6601075670586916 0.5 --0.4835020902397924 -0.507738076955535 -0.5 -0.3696205762810363 -0.574659819443879 -0.21512573409565364 -0.4244126174375137 -0.9054689007137895 -0.17431739988440909 -0.9156551973630727 0.40196462473953154 -0.5 -0.7365711616695659 0.01554100836707668 -0.19536686682078142 --0.9688711879158358 0.24756538777978826 0.5 --0.47469814077992056 0.8801486664990674 0.5 --0.7901445551701427 0.6129205347636653 0.5 --0.19849274312997123 0.6646631834803811 -0.5 --0.2823536740873904 0.9593103787249211 0.023788514094556845 -0.6879307326827979 0.1796265808006876 -0.5 -1. 0. -0.5 --0.47219520355646416 0.498124673656299 0.5 -0.9621751248435289 -0.27243169626961483 -0.010210963130078077 -0.6791029100539356 -0.1515269232248766 -0.5 -0.5594933951579955 -0.3895199068872477 -0.12946432153365675 -0.6537530365115155 -0.33853885454630034 0.28158249775901134 -1. 0. 0.5 -0.909834738941556 -0.41497077947145955 0.5 -0.7940206713300018 -0.6078907578674422 0.1933036221834642 -0.7565263027173401 -0.6539632660148667 -0.1423234797999447 -0.5227836879567489 -0.852465375019033 0.16491704436541454 -0.28615413094601594 -0.9581836010611589 0.5 -0.07573678522231944 -0.9971278450450514 0.12448119766402888 --0.07125657497927042 -0.7161407287443025 0.18384182894018675 --0.653904449844533 -0.2295408927481397 -0.5 -0.6581889353823536 -0.7528527912814322 0.5 -0.2861753463146679 -0.9581772649993736 -0.5 -0.2060810039115023 -0.6921883270417896 -0.5 -0.6576794891307078 -0.7532978757283011 -0.5 -0.5287160986484637 -0.44402576695056395 -0.5 --0.9867503230983625 -0.16224610893724706 -0.5 --0.7009790534683309 0.16657462196315853 -0.5 --0.969523404503658 0.244998710444843 -0.5 --0.8375280400421417 -0.5463943467342691 -0.5 -0.9091328560011489 -0.4165062426173154 -0.5 --0.5330361537343615 -0.8460924646940651 0.5 --0.1375575329186719 -0.9904937784445333 0.5 --0.08006786563001286 0.9967894145171556 -0.5 --0.48000710661746904 0.8772645995346704 -0.5 -0.20641653965789786 -0.6862744051412235 0.5 +MFEM mesh v1.0 + +# +# MFEM Geometry Types (see mesh/geom.hpp): +# +# POINT = 0 +# SEGMENT = 1 +# TRIANGLE = 2 +# SQUARE = 3 +# TETRAHEDRON = 4 +# CUBE = 5 +# + +dimension +3 + +elements +789 +1 4 0 1 2 3 +1 4 4 2 5 3 +1 4 6 7 8 3 +1 4 4 5 7 3 +1 4 9 10 11 7 +1 4 12 11 13 6 +1 4 10 14 15 16 +1 4 17 14 8 16 +1 4 10 6 8 16 +1 4 18 17 8 16 +1 4 11 6 10 16 +1 4 19 17 14 8 +1 4 20 21 22 1 +1 4 23 24 25 8 +1 4 26 14 1 8 +1 4 26 27 24 8 +1 4 25 24 27 8 +1 4 28 7 6 3 +1 4 29 30 31 32 +1 4 33 11 10 16 +1 4 11 10 6 7 +1 4 34 10 5 35 +1 4 36 37 38 39 +1 4 34 10 9 7 +1 4 28 4 7 3 +1 4 34 4 5 7 +1 4 1 40 8 3 +1 4 34 41 9 10 +1 4 34 5 4 35 +1 4 42 43 30 15 +1 4 4 5 43 35 +1 4 41 44 45 35 +1 4 44 43 45 35 +1 4 34 41 10 35 +1 4 26 30 1 14 +1 4 39 17 15 14 +1 4 15 14 17 16 +1 4 46 47 17 16 +1 4 5 1 14 8 +1 4 48 25 6 8 +1 4 46 18 6 16 +1 4 37 19 38 39 +1 4 37 49 38 19 +1 4 47 15 17 16 +1 4 50 15 39 17 +1 4 22 51 52 26 +1 4 50 47 15 17 +1 4 33 10 15 16 +1 4 21 22 1 40 +1 4 26 40 27 8 +1 4 53 54 42 43 +1 4 10 8 14 16 +1 4 5 10 7 8 +1 4 55 25 56 27 +1 4 48 25 57 6 +1 4 23 18 24 8 +1 4 55 57 25 58 +1 4 28 57 59 3 +1 4 25 8 40 3 +1 4 0 40 1 3 +1 4 60 26 40 27 +1 4 61 30 39 15 +1 4 19 17 39 14 +1 4 49 18 46 17 +1 4 36 37 39 32 +1 4 38 39 19 17 +1 4 62 55 56 27 +1 4 26 32 30 14 +1 4 0 63 40 58 +1 4 23 56 25 24 +1 4 48 6 18 8 +1 4 60 27 64 24 +1 4 62 56 64 27 +1 4 55 25 40 58 +1 4 22 51 26 40 +1 4 63 55 65 27 +1 4 46 66 6 18 +1 4 23 48 18 8 +1 4 60 67 26 24 +1 4 62 65 55 27 +1 4 68 55 63 58 +1 4 63 55 40 58 +1 4 57 25 58 3 +1 4 68 0 69 58 +1 4 59 57 69 58 +1 4 49 38 19 17 +1 4 61 30 70 39 +1 4 71 33 10 15 +1 4 49 46 47 17 +1 4 5 30 1 43 +1 4 42 43 15 35 +1 4 50 72 61 15 +1 4 73 61 72 15 +1 4 33 15 47 16 +1 4 28 6 57 3 +1 4 25 40 58 3 +1 4 46 6 11 16 +1 4 74 48 13 6 +1 4 28 75 57 6 +1 4 75 13 57 6 +1 4 41 15 10 35 +1 4 76 2 1 43 +1 4 10 30 43 15 +1 4 44 77 53 43 +1 4 4 5 2 43 +1 4 44 4 43 35 +1 4 41 71 10 15 +1 4 78 79 26 32 +1 4 36 80 81 39 +1 4 78 19 37 32 +1 4 60 64 67 24 +1 4 26 31 30 32 +1 4 80 70 81 39 +1 4 54 29 30 31 +1 4 82 59 28 57 +1 4 83 50 47 15 +1 4 30 32 39 14 +1 4 78 67 19 26 +1 4 78 26 19 32 +1 4 22 26 1 40 +1 4 23 25 48 8 +1 4 19 32 26 14 +1 4 52 26 79 31 +1 4 22 26 52 31 +1 4 30 39 15 14 +1 4 19 18 17 8 +1 4 49 19 84 18 +1 4 78 51 67 26 +1 4 2 5 1 43 +1 4 55 40 25 27 +1 4 0 58 40 3 +1 4 5 1 30 14 +1 4 5 1 8 3 +1 4 60 51 85 40 +1 4 1 43 30 31 +1 4 20 76 1 31 +1 4 2 1 5 3 +1 4 20 1 22 31 +1 4 49 47 38 17 +1 4 5 10 30 43 +1 4 5 14 10 8 +1 4 67 19 26 24 +1 4 49 19 18 17 +1 4 86 70 29 32 +1 4 78 36 87 32 +1 4 50 61 39 15 +1 4 46 17 18 16 +1 4 71 88 73 15 +1 4 10 15 43 35 +1 4 49 89 66 18 +1 4 66 48 74 6 +1 4 66 48 6 18 +1 4 6 18 8 16 +1 4 49 84 89 18 +1 4 56 27 25 24 +1 4 59 57 58 3 +1 4 28 12 6 7 +1 4 20 76 21 1 +1 4 19 26 24 8 +1 4 90 76 54 43 +1 4 46 11 33 16 +1 4 84 19 67 24 +1 4 77 4 2 43 +1 4 76 54 43 31 +1 4 77 2 76 43 +1 4 46 33 47 16 +1 4 55 57 48 25 +1 4 13 48 57 6 +1 4 69 57 55 58 +1 4 41 45 42 35 +1 4 52 51 79 26 +1 4 91 52 86 31 +1 4 28 12 75 6 +1 4 60 40 85 27 +1 4 63 85 40 27 +1 4 54 30 43 31 +1 4 9 33 11 10 +1 4 87 70 86 32 +1 4 9 71 33 10 +1 4 42 30 61 15 +1 4 20 52 91 31 +1 4 49 66 46 18 +1 4 25 27 40 8 +1 4 64 84 67 24 +1 4 62 60 85 27 +1 4 66 23 48 18 +1 4 82 28 75 57 +1 4 42 54 30 43 +1 4 63 22 21 40 +1 4 0 21 1 40 +1 4 92 90 76 54 +1 4 20 22 52 31 +1 4 63 85 22 40 +1 4 63 40 55 27 +1 4 0 63 21 40 +1 4 42 70 61 30 +1 4 64 27 56 24 +1 4 84 24 23 18 +1 4 71 73 83 15 +1 4 83 72 50 15 +1 4 80 61 70 39 +1 4 0 21 2 1 +1 4 20 92 76 31 +1 4 34 5 10 7 +1 4 62 85 65 27 +1 4 73 88 42 15 +1 4 12 11 6 7 +1 4 68 69 55 58 +1 4 25 6 8 3 +1 4 46 74 11 6 +1 4 84 93 23 24 +1 4 87 81 70 32 +1 4 84 19 24 18 +1 4 84 93 89 23 +1 4 26 1 40 8 +1 4 84 23 89 18 +1 4 82 69 59 57 +1 4 64 56 23 24 +1 4 23 56 48 25 +1 4 22 1 26 31 +1 4 9 11 12 7 +1 4 10 30 15 14 +1 4 71 83 33 15 +1 4 26 1 30 31 +1 4 41 45 88 42 +1 4 5 8 7 3 +1 4 21 76 2 1 +1 4 90 54 53 43 +1 4 28 34 12 7 +1 4 9 41 71 10 +1 4 34 4 44 35 +1 4 22 85 51 40 +1 4 70 39 30 32 +1 4 45 53 42 43 +1 4 41 42 88 15 +1 4 19 39 32 14 +1 4 44 53 45 43 +1 4 28 4 34 7 +1 4 37 67 84 19 +1 4 59 69 0 58 +1 4 92 91 54 31 +1 4 91 86 29 31 +1 4 42 54 29 30 +1 4 64 93 84 24 +1 4 73 42 61 15 +1 4 60 26 51 40 +1 4 91 29 54 31 +1 4 80 50 72 61 +1 4 78 87 79 32 +1 4 19 24 18 8 +1 4 36 39 81 32 +1 4 52 79 86 31 +1 4 19 14 26 8 +1 4 78 79 51 26 +1 4 50 38 47 17 +1 4 46 66 74 6 +1 4 64 23 93 24 +1 4 76 43 1 31 +1 4 10 6 7 8 +1 4 63 65 85 27 +1 4 5 30 10 14 +1 4 20 91 92 31 +1 4 36 38 80 39 +1 4 79 31 26 32 +1 4 5 10 43 35 +1 4 74 13 11 6 +1 4 45 43 42 35 +1 4 83 73 72 15 +1 4 83 47 33 15 +1 4 78 37 36 32 +1 4 37 19 39 32 +1 4 78 67 37 19 +1 4 75 12 13 6 +1 4 77 76 90 43 +1 4 86 29 31 32 +1 4 60 26 27 24 +1 4 80 38 50 39 +1 4 81 39 70 32 +1 4 62 64 60 27 +1 4 42 29 70 30 +1 4 86 31 79 32 +1 4 44 4 77 43 +1 4 55 48 56 25 +1 4 77 90 53 43 +1 4 92 54 76 31 +1 4 68 63 0 58 +1 4 41 88 71 15 +1 4 37 84 49 19 +1 4 41 42 15 35 +1 4 50 39 38 17 +1 4 29 70 30 32 +1 4 68 65 63 55 +1 4 60 67 51 26 +1 4 87 86 79 32 +1 4 36 81 87 32 +1 4 66 89 23 18 +1 4 59 0 2 3 +1 4 59 58 0 3 +1 4 59 2 4 3 +1 4 34 9 12 7 +1 4 80 50 61 39 +1 4 57 6 25 3 +1 4 28 59 4 3 +1 4 34 44 41 35 +2 4 33 94 95 96 +2 4 74 11 97 96 +2 4 33 95 11 96 +2 4 46 11 74 96 +2 4 98 99 100 101 +2 4 102 100 103 101 +2 4 104 102 103 101 +2 4 102 100 105 103 +2 4 106 107 108 109 +2 4 77 110 111 109 +2 4 59 108 107 109 +2 4 59 107 4 109 +2 4 77 4 112 109 +2 4 93 100 99 101 +2 4 104 113 98 101 +2 4 67 114 104 101 +2 4 37 84 67 101 +2 4 113 115 116 117 +2 4 64 116 60 117 +2 4 64 84 93 117 +2 4 64 93 99 117 +2 4 60 116 115 117 +2 4 47 118 94 119 +2 4 120 121 110 111 +2 4 38 119 103 122 +2 4 123 118 124 119 +2 4 125 119 126 122 +2 4 127 125 103 119 +2 4 124 118 126 119 +2 4 128 129 130 131 +2 4 21 132 129 133 +2 4 20 21 132 129 +2 4 91 134 52 129 +2 4 79 51 131 135 +2 4 22 133 129 130 +2 4 128 129 133 130 +2 4 22 51 130 131 +2 4 136 130 115 131 +2 4 128 136 137 131 +2 4 138 139 112 109 +2 4 4 140 112 107 +2 4 104 102 127 103 +2 4 141 112 140 107 +2 4 141 142 138 107 +2 4 141 143 142 107 +2 4 75 143 144 140 +2 4 12 75 144 140 +2 4 106 138 107 109 +2 4 145 146 147 148 +2 4 21 132 148 149 +2 4 21 148 132 133 +2 4 0 68 150 148 +2 4 69 150 108 149 +2 4 139 111 110 109 +2 4 106 146 151 149 +2 4 21 149 2 111 +2 4 21 132 149 111 +2 4 63 22 85 133 +2 4 146 150 148 149 +2 4 63 65 152 133 +2 4 145 149 132 111 +2 4 83 94 47 118 +2 4 81 153 80 122 +2 4 46 94 33 96 +2 4 83 154 94 118 +2 4 123 94 118 119 +2 4 123 94 155 118 +2 4 106 149 151 109 +2 4 76 77 90 111 +2 4 145 132 120 111 +2 4 145 151 149 111 +2 4 0 21 148 149 +2 4 21 76 132 111 +2 4 60 130 51 115 +2 4 136 131 115 135 +2 4 22 85 133 130 +2 4 127 124 125 119 +2 4 151 149 111 109 +2 4 156 157 141 112 +2 4 141 138 112 107 +2 4 34 140 157 112 +2 4 4 107 112 109 +2 4 34 157 44 112 +2 4 158 130 116 115 +2 4 159 160 128 133 +2 4 91 161 134 129 +2 4 128 137 129 131 +2 4 162 152 159 133 +2 4 162 132 148 133 +2 4 156 163 164 157 +2 4 162 128 129 133 +2 4 113 158 116 115 +2 4 64 60 67 117 +2 4 78 114 115 135 +2 4 78 79 87 135 +2 4 62 116 165 130 +2 4 136 130 158 115 +2 4 141 164 166 157 +2 4 166 167 168 157 +2 4 41 9 168 157 +2 4 138 151 139 109 +2 4 141 157 140 112 +2 4 9 11 95 169 +2 4 141 170 143 140 +2 4 9 34 12 140 +2 4 9 95 168 169 +2 4 166 171 144 169 +2 4 172 168 95 169 +2 4 173 155 95 154 +2 4 174 95 155 94 +2 4 174 172 95 96 +2 4 11 169 97 96 +2 4 175 94 176 177 +2 4 36 78 87 178 +2 4 179 172 174 96 +2 4 179 97 172 96 +2 4 46 33 11 96 +2 4 125 103 119 122 +2 4 102 103 105 177 +2 4 0 148 150 149 +2 4 49 47 177 119 +2 4 49 103 38 119 +2 4 37 49 84 103 +2 4 127 103 177 119 +2 4 36 103 104 122 +2 4 180 155 181 118 +2 4 83 72 181 118 +2 4 49 177 103 119 +2 4 83 154 33 94 +2 4 174 173 155 95 +2 4 155 94 154 118 +2 4 47 94 177 119 +2 4 182 181 155 154 +2 4 182 180 155 181 +2 4 173 183 182 154 +2 4 72 126 181 118 +2 4 73 181 183 154 +2 4 71 83 73 154 +2 4 83 181 154 118 +2 4 160 133 165 130 +2 4 52 134 86 131 +2 4 51 115 131 135 +2 4 184 185 186 135 +2 4 136 186 131 135 +2 4 186 185 131 135 +2 4 87 185 178 135 +2 4 78 67 51 115 +2 4 87 79 185 135 +2 4 37 104 36 103 +2 4 77 112 110 109 +2 4 187 104 125 122 +2 4 36 178 81 122 +2 4 36 81 80 122 +2 4 125 126 153 122 +2 4 80 126 119 122 +2 4 80 126 50 119 +2 4 33 168 95 154 +2 4 166 167 188 168 +2 4 173 168 183 154 +2 4 71 183 88 168 +2 4 188 167 183 168 +2 4 88 183 167 168 +2 4 123 177 94 119 +2 4 189 100 102 101 +2 4 46 47 33 94 +2 4 175 174 94 96 +2 4 176 94 123 177 +2 4 127 177 123 119 +2 4 102 190 176 177 +2 4 63 0 21 148 +2 4 191 162 161 132 +2 4 92 76 121 132 +2 4 139 110 112 109 +2 4 145 148 132 149 +2 4 34 4 140 112 +2 4 21 129 22 133 +2 4 162 129 132 133 +2 4 63 148 21 133 +2 4 44 53 77 112 +2 4 59 108 82 107 +2 4 28 143 140 107 +2 4 28 140 4 107 +2 4 166 169 144 140 +2 4 142 143 108 107 +2 4 76 121 132 111 +2 4 59 4 2 109 +2 4 106 108 146 149 +2 4 76 2 77 111 +2 4 21 2 76 111 +2 4 59 2 0 149 +2 4 159 152 165 133 +2 4 63 152 148 133 +2 4 166 173 172 168 +2 4 164 163 167 157 +2 4 45 163 44 157 +2 4 164 188 166 167 +2 4 156 164 141 157 +2 4 120 132 121 111 +2 4 80 153 126 122 +2 4 76 90 121 111 +2 4 123 180 124 118 +2 4 83 47 50 118 +2 4 73 83 72 181 +2 4 83 50 72 118 +2 4 173 95 168 154 +2 4 73 83 181 154 +2 4 59 149 108 109 +2 4 90 77 53 110 +2 4 151 120 139 111 +2 4 156 139 110 112 +2 4 44 77 4 112 +2 4 192 137 134 129 +2 4 92 121 161 132 +2 4 92 76 90 121 +2 4 78 104 67 114 +2 4 53 163 110 112 +2 4 92 20 76 132 +2 4 0 150 69 149 +2 4 0 68 69 150 +2 4 81 178 153 122 +2 4 104 114 113 101 +2 4 83 33 47 94 +2 4 175 190 193 177 +2 4 66 193 105 177 +2 4 172 97 169 96 +2 4 127 123 124 119 +2 4 50 118 47 119 +2 4 66 46 74 193 +2 4 41 71 88 168 +2 4 188 183 173 168 +2 4 41 34 9 157 +2 4 173 182 155 154 +2 4 41 88 167 168 +2 4 49 89 100 105 +2 4 104 127 125 103 +2 4 187 125 153 122 +2 4 86 134 185 131 +2 4 191 161 121 132 +2 4 44 163 53 112 +2 4 156 141 138 112 +2 4 45 167 163 157 +2 4 9 166 157 140 +2 4 52 79 51 131 +2 4 22 52 51 131 +2 4 162 128 192 129 +2 4 52 86 79 131 +2 4 91 86 52 134 +2 4 91 52 20 129 +2 4 84 117 67 101 +2 4 84 103 100 101 +2 4 189 102 100 105 +2 4 84 49 100 103 +2 4 79 131 185 135 +2 4 142 106 138 107 +2 4 162 147 152 148 +2 4 162 159 128 133 +2 4 68 152 150 148 +2 4 106 151 138 109 +2 4 63 68 0 148 +2 4 22 130 129 131 +2 4 191 162 192 161 +2 4 192 134 161 129 +2 4 173 95 172 168 +2 4 9 95 33 168 +2 4 160 165 116 130 +2 4 86 185 79 131 +2 4 162 147 159 152 +2 4 20 52 22 129 +2 4 62 65 85 165 +2 4 128 160 136 130 +2 4 65 85 165 133 +2 4 60 51 67 115 +2 4 114 136 115 135 +2 4 22 51 85 130 +2 4 137 186 185 131 +2 4 52 129 134 131 +2 4 71 168 33 154 +2 4 9 168 166 169 +2 4 174 155 176 94 +2 4 84 93 117 101 +2 4 71 33 83 154 +2 4 37 104 103 101 +2 4 104 103 125 122 +2 4 84 49 89 100 +2 4 49 66 105 177 +2 4 49 47 46 177 +2 4 102 176 127 177 +2 4 102 127 103 177 +2 4 67 115 114 117 +2 4 37 103 84 101 +2 4 64 99 116 117 +2 4 113 114 117 101 +2 4 85 165 133 130 +2 4 37 67 104 101 +2 4 66 46 193 177 +2 4 9 33 71 168 +2 4 174 95 94 96 +2 4 182 183 181 154 +2 4 71 183 168 154 +2 4 176 155 123 94 +2 4 91 20 161 129 +2 4 63 21 22 133 +2 4 128 130 136 131 +2 4 63 85 65 133 +2 4 2 111 149 109 +2 4 20 22 21 129 +2 4 145 162 132 148 +2 4 174 172 173 95 +2 4 124 181 126 118 +2 4 180 181 124 118 +2 4 46 47 94 177 +2 4 176 123 127 177 +2 4 50 126 118 119 +2 4 190 105 193 177 +2 4 80 50 38 119 +2 4 59 69 108 149 +2 4 63 152 68 148 +2 4 147 150 152 148 +2 4 59 69 82 108 +2 4 63 65 68 152 +2 4 0 2 21 149 +2 4 175 176 190 177 +2 4 106 108 149 109 +2 4 160 158 136 130 +2 4 65 165 152 133 +2 4 60 85 51 130 +2 4 141 140 143 107 +2 4 28 82 143 107 +2 4 59 0 69 149 +2 4 146 150 147 148 +2 4 82 108 143 107 +2 4 142 108 106 107 +2 4 162 161 132 129 +2 4 92 161 20 132 +2 4 50 126 72 118 +2 4 172 169 95 96 +2 4 11 13 97 169 +2 4 12 13 11 169 +2 4 141 157 166 140 +2 4 28 75 12 140 +2 4 12 75 13 144 +2 4 9 12 11 169 +2 4 9 11 33 95 +2 4 179 174 175 96 +2 4 46 74 193 96 +2 4 41 45 44 157 +2 4 41 168 167 157 +2 4 41 88 45 167 +2 4 41 9 71 168 +2 4 9 157 34 140 +2 4 12 144 13 169 +2 4 155 95 154 94 +2 4 45 53 44 163 +2 4 90 77 110 111 +2 4 9 169 166 140 +2 4 41 44 34 157 +2 4 114 136 158 115 +2 4 78 115 51 135 +2 4 160 116 158 130 +2 4 113 116 99 117 +2 4 164 167 166 157 +2 4 191 121 120 132 +2 4 166 168 172 169 +2 4 12 144 169 140 +2 4 67 117 114 101 +2 4 49 105 100 103 +2 4 13 144 97 169 +2 4 151 111 139 109 +2 4 156 110 163 112 +2 4 71 73 88 183 +2 4 71 73 183 154 +2 4 33 154 95 94 +2 4 141 166 170 140 +2 4 28 82 75 143 +2 4 171 97 144 169 +2 4 74 11 13 97 +2 4 145 151 146 149 +2 4 172 97 171 169 +2 4 60 116 62 130 +2 4 62 165 85 130 +2 4 145 146 148 149 +2 4 128 133 160 130 +2 4 22 129 52 131 +2 4 187 178 104 122 +2 4 166 172 171 169 +2 4 44 157 163 112 +2 4 11 95 169 96 +2 4 28 34 4 140 +2 4 175 174 176 94 +2 4 175 94 193 96 +2 4 155 154 181 118 +2 4 114 186 136 135 +2 4 184 114 104 178 +2 4 184 114 178 135 +2 4 64 62 60 116 +2 4 78 178 114 135 +2 4 162 192 161 129 +2 4 20 21 76 132 +2 4 145 162 191 132 +2 4 91 20 92 161 +2 4 77 2 4 109 +2 4 139 120 110 111 +2 4 137 134 129 131 +2 4 90 110 121 111 +2 4 34 44 4 112 +2 4 77 111 2 109 +2 4 145 191 120 132 +2 4 59 28 4 107 +2 4 137 185 134 131 +2 4 41 167 45 157 +2 4 98 113 99 101 +2 4 104 189 102 101 +2 4 113 114 115 117 +2 4 159 165 160 133 +2 4 145 120 151 111 +2 4 60 116 130 115 +2 4 49 66 89 105 +2 4 170 166 144 140 +2 4 113 117 99 101 +2 4 36 104 78 178 +2 4 37 78 36 104 +2 4 78 51 79 135 +2 4 59 2 149 109 +2 4 184 178 185 135 +2 4 51 115 130 131 +2 4 78 87 178 135 +2 4 60 115 67 117 +2 4 137 136 186 131 +2 4 36 87 81 178 +2 4 49 105 103 177 +2 4 179 193 97 96 +2 4 175 193 94 177 +2 4 49 46 66 177 +2 4 156 138 139 112 +2 4 46 94 193 177 +2 4 36 80 38 122 +2 4 59 82 28 107 +2 4 28 143 75 140 +2 4 162 148 152 133 +2 4 145 147 162 148 +2 4 46 193 94 96 +2 4 179 175 193 96 +2 4 74 97 193 96 +2 4 125 124 126 119 +2 4 38 50 47 119 +2 4 170 144 143 140 +2 4 104 98 189 101 +2 4 80 119 38 122 +2 4 60 62 85 130 +2 4 141 170 142 143 +2 4 102 105 190 177 +2 4 84 89 93 100 +2 4 80 72 50 126 +2 4 49 38 47 119 +2 4 20 132 161 129 +2 4 64 67 84 117 +2 4 37 67 78 104 +2 4 184 186 114 135 +2 4 37 38 49 103 +2 4 187 153 178 122 +2 4 36 104 178 122 +2 4 87 79 86 185 +2 4 189 98 100 101 +2 4 189 190 102 105 +2 4 9 166 168 157 +2 4 9 12 169 140 +2 4 138 112 107 109 +2 4 188 182 173 183 +2 4 93 99 117 101 +2 4 78 114 67 115 +2 4 156 163 157 112 +2 4 78 104 114 178 +2 4 184 104 187 178 +2 4 36 38 103 122 +2 4 166 188 173 168 +2 4 123 155 180 118 +2 4 37 36 38 103 +2 4 28 12 34 140 +2 4 77 53 110 112 +2 4 179 171 172 97 +2 4 128 137 192 129 +2 4 146 108 150 149 +2 4 84 100 93 101 +2 4 170 166 171 144 +2 4 113 114 158 115 + +boundary +208 +1 2 68 55 69 +1 2 93 89 23 +1 2 55 56 48 +1 2 62 56 55 +1 2 62 55 65 +1 2 66 23 89 +1 2 55 48 57 +1 2 66 48 23 +1 2 66 74 48 +1 2 68 65 55 +1 2 64 93 23 +1 2 74 13 48 +1 2 82 57 75 +1 2 64 23 56 +1 2 23 48 56 +1 2 69 55 57 +1 2 62 64 56 +1 2 82 69 57 +1 2 75 57 13 +1 2 13 57 48 +1 2 146 147 150 +1 2 89 93 100 +1 2 82 75 143 +1 2 64 99 93 +1 2 65 68 152 +1 2 170 144 171 +1 2 175 193 190 +1 2 142 108 143 +1 2 189 190 105 +1 2 74 97 13 +1 2 189 100 98 +1 2 179 171 97 +1 2 66 193 74 +1 2 62 65 165 +1 2 64 62 116 +1 2 142 106 108 +1 2 113 99 116 +1 2 68 150 152 +1 2 189 105 100 +1 2 89 100 105 +1 2 62 165 116 +1 2 69 82 108 +1 2 66 105 193 +1 2 190 193 105 +1 2 13 97 144 +1 2 147 159 152 +1 2 75 144 143 +1 2 66 89 105 +1 2 160 158 116 +1 2 147 152 150 +1 2 98 99 113 +1 2 68 69 150 +1 2 159 160 165 +1 2 113 116 158 +1 2 64 116 99 +1 2 170 142 143 +1 2 171 144 97 +1 2 170 143 144 +1 2 82 143 108 +1 2 69 108 150 +1 2 146 150 108 +1 2 106 146 108 +1 2 160 116 165 +1 2 159 165 152 +1 2 65 152 165 +1 2 98 100 99 +1 2 93 99 100 +1 2 74 193 97 +1 2 179 97 193 +1 2 179 193 175 +1 2 75 13 144 +2 2 73 61 42 +2 2 92 90 54 +2 2 91 54 29 +2 2 91 29 86 +2 2 80 61 72 +2 2 42 70 29 +2 2 90 53 54 +2 2 92 54 91 +2 2 73 72 61 +2 2 73 42 88 +2 2 42 61 70 +2 2 87 70 81 +2 2 80 70 61 +2 2 45 88 42 +2 2 45 42 53 +2 2 80 81 70 +2 2 42 29 54 +2 2 53 42 54 +2 2 86 29 70 +2 2 87 86 70 +2 2 191 161 192 +2 2 91 86 134 +2 2 164 188 167 +2 2 81 153 178 +2 2 73 181 72 +2 2 191 121 161 +2 2 191 120 121 +2 2 124 126 181 +2 2 87 81 178 +2 2 187 153 125 +2 2 188 182 183 +2 2 182 181 183 +2 2 92 121 90 +2 2 73 88 183 +2 2 87 178 185 +2 2 184 185 178 +2 2 90 110 53 +2 2 180 124 181 +2 2 90 121 110 +2 2 80 126 153 +2 2 87 185 86 +2 2 156 164 163 +2 2 88 45 167 +2 2 120 110 121 +2 2 125 153 126 +2 2 125 126 124 +2 2 156 163 110 +2 2 184 178 187 +2 2 91 161 92 +2 2 139 110 120 +2 2 91 134 161 +2 2 192 161 134 +2 2 192 134 137 +2 2 187 178 153 +2 2 73 183 181 +2 2 81 80 153 +2 2 182 180 181 +2 2 184 186 185 +2 2 92 161 121 +2 2 164 167 163 +2 2 45 163 167 +2 2 72 181 126 +2 2 80 72 126 +2 2 188 183 167 +2 2 88 167 183 +2 2 86 185 134 +2 2 137 134 185 +2 2 137 185 186 +2 2 156 110 139 +2 2 53 110 163 +2 2 45 53 163 +3 2 156 141 164 +3 2 141 142 170 +3 2 141 170 166 +3 2 145 191 162 +3 2 142 138 106 +3 2 184 187 104 +3 2 179 175 174 +3 2 104 189 98 +3 2 141 138 142 +3 2 159 128 160 +3 2 104 102 189 +3 2 128 192 137 +3 2 104 113 114 +3 2 145 146 151 +3 2 128 137 136 +3 2 156 139 138 +3 2 191 192 162 +3 2 145 162 147 +3 2 114 158 136 +3 2 184 114 186 +3 2 113 158 114 +3 2 176 127 123 +3 2 114 136 186 +3 2 187 125 104 +3 2 188 173 182 +3 2 166 172 173 +3 2 145 120 191 +3 2 104 98 113 +3 2 175 190 176 +3 2 175 176 174 +3 2 145 147 146 +3 2 179 172 171 +3 2 184 104 114 +3 2 137 186 136 +3 2 123 124 180 +3 2 106 138 151 +3 2 164 166 188 +3 2 106 151 146 +3 2 156 138 141 +3 2 141 166 164 +3 2 170 171 166 +3 2 166 173 188 +3 2 127 124 123 +3 2 189 102 190 +3 2 127 125 124 +3 2 162 128 159 +3 2 162 159 147 +3 2 138 139 151 +3 2 162 192 128 +3 2 160 136 158 +3 2 128 136 160 +3 2 151 139 120 +3 2 145 151 120 +3 2 102 176 190 +3 2 102 127 176 +3 2 104 125 127 +3 2 179 174 172 +3 2 166 171 172 +3 2 104 127 102 +3 2 182 155 180 +3 2 174 155 173 +3 2 173 155 182 +3 2 174 176 155 +3 2 176 123 155 +3 2 123 180 155 +3 2 174 173 172 + +vertices +194 +3 +0.11997195419097467 0.4853933767652775 0.2589180265268235 +-0.010856803953973863 0.2425986392131464 -0.045413175647737614 +0.24306361668476772 0.4369440218656393 0.011464146250920404 +0.195818038071797 0.19789489642820537 0.17574910149909653 +0.4305958145480755 0.25414020636978973 0.010746350155629525 +0.18229432719890853 0.07154978461418435 0.005062844481944168 +0.20769078479683284 -0.1571614601395298 0.28916242978821277 +0.32848943413138754 -0.019071715998760914 0.11736316170436412 +-0.021402334112599706 -0.09259164894757581 0.15723466079732742 +0.43582468446400036 -0.24506497997848342 -0.02188920206883055 +0.2206887347224819 -0.16740800818239635 -0.06475294639611945 +0.3576769918926359 -0.3493811235179073 0.2424738257434117 +0.4839265893768 -0.12575792656583507 0.24561453497006613 +0.43570968158023893 -0.2452693894012189 0.5 +-0.06423753222010928 -0.08605471001342942 -0.052661201124829644 +0.12720304400812915 -0.2461219629292447 -0.3025522296563212 +0.11774212462954714 -0.28232447080304335 0.08470256603437014 +-0.08958804437514946 -0.2866337526069329 0.010437254676599773 +-0.11496003101039974 -0.2985337767151035 0.2777821697704855 +-0.25742782564276834 -0.15887963248015538 0.07513322528612679 +-0.14281309612062965 0.4791705537451564 -0.25655100411141574 +-0.012023804698077074 0.4998554072135085 0.0008614304225812441 +-0.26684255708862437 0.4228416366991361 0.004482075618457149 +-0.19299604913517243 -0.20850229152545607 0.5 +-0.28753677648407766 -0.07490310980313035 0.3169952001087608 +-0.018192735296978593 0.039011950068369716 0.3312349340292917 +-0.26953856745406424 0.05015274282835383 -0.007962456263327627 +-0.2844994169434064 0.12927746826595696 0.31344932852845453 +0.4821087845581751 0.1325561007718586 0.2569062863349316 +-0.14185684682876676 0.1565765244854318 -0.5 +-0.03097886037265596 0.02928927839536998 -0.2676678538677485 +-0.13769473423097411 0.2823346616652343 -0.30639228132844604 +-0.28545292479556433 -0.057433337349894205 -0.2950439673729821 +0.2563359009870937 -0.42929233147720547 -0.026369197771376196 +0.4999858937711994 0.0037557994907759405 -0.00965060064717771 +0.35118834836766993 0.04605894350994181 -0.20880364537256635 +-0.4187640200210708 -0.27319717336713456 -0.25 +-0.4187640200210708 -0.27319717336713456 0. +-0.2424136429356089 -0.4373049573451998 -0.14551444974248584 +-0.176204707843803 -0.23760502140817893 -0.2897640092465014 +-0.18811590295640457 0.224892084945821 0.15244216005169509 +0.4839934858438879 -0.12550022175551007 -0.2673506407688206 +0.16838400115940544 -0.045924516981502295 -0.5 +0.20730292969498612 0.1738990170372628 -0.2817604241829639 +0.4820910967508869 0.13262041484449877 -0.2567597289483131 +0.5 0. -0.5 +0.1270937202256388 -0.4835774873577212 0.23554234371594152 +0.004418815902774915 -0.4999804736847404 -0.05070109889922947 +0.06837845462111625 -0.15923796826127656 0.5 +-0.1916008699591294 -0.46183233606029017 0.19248160419362736 +-0.07157516625208954 -0.4948504779991485 -0.2904779710022272 +-0.4564687867662406 0.2040496182504548 -0.006634770328774742 +-0.36563815718436776 0.3410406691449269 -0.25970314261549454 +0.4310548235089896 0.2533608871346045 -0.5 +0.06840717137580687 0.27638589652485523 -0.5 +-0.057368963778421156 0.2163557126213268 0.5 +-0.2217889047167344 0.022030596613689224 0.5 +0.24824944094770662 0.07320012596009529 0.5 +0.05685687885736833 0.32301508538961726 0.378781099742994 +0.3492790100702384 0.35777670847101584 0.2650962067529058 +-0.4786017412950019 0.1447078893128917 0.2756273490734399 +-0.007270303983100357 -0.289982370357868 -0.5 +-0.4423870584187638 0.23301006532678636 0.5 +-0.142577496442851 0.479240709360222 0.25772629014882886 +-0.4994578200390527 -0.023278445004707576 0.5 +-0.2633220852606578 0.4250429147909407 0.5 +0.0163333763864498 -0.49973314960668613 0.5 +-0.49743692488507296 -0.05056190028946966 0.1403935154754995 +-0.011642379062566481 0.4998644366323368 0.5 +0.24324787311167112 0.43684147264957374 0.5 +-0.22445532844900007 -0.09294413234398197 -0.5 +0.3595374815863839 -0.3474662563969638 -0.26985871138525586 +0.01633337672466685 -0.49973314959563175 -0.5 +0.2593717083715156 -0.4274649890885117 -0.5 +0.2593717079375579 -0.427464989351823 0.5 +0.5 0. 0.5 +0.11991911395363408 0.4854064339381744 -0.253131027048679 +0.3492243725499189 0.35783004012675546 -0.24892964340400275 +-0.49728640869735186 -0.05202141602157956 -0.14992090460258778 +-0.47860683828403505 0.14469103064032524 -0.2848272238244989 +-0.23090526683537305 -0.4434892983462906 -0.5 +-0.4187640200210708 -0.27319717336713456 -0.5 +0.4310590653573789 0.25335367013963483 0.5 +0.14596475359601946 -0.47821991876923453 -0.27469985351789106 +-0.4187640200210708 -0.27319717336713456 0.25 +-0.36475057815959055 0.34198978892979304 0.25876925855510313 +-0.4424067176124312 0.2329727370560653 -0.5 +-0.49945545791813406 -0.023329071044236163 -0.5 +0.4357096819122347 -0.24526938881144378 -0.5 +-0.2309052669854515 -0.4434892982681514 0.5 +0.2432330449597631 0.436849729128452 -0.5 +-0.26335074192012187 0.42502516011422353 -0.5 +-0.011667713608086727 0.49986384592122646 -0.5 +-0.4187640216620042 -0.27319717085186734 0.5 +0.1648092893260417 -0.698068472966144 0.01916480754979703 +0.49709773263551466 -0.5401644000750928 0.04685316334548395 +0.42923512816169396 -0.6200930575066769 0.28298192414755896 +0.5320971013969822 -0.44659715402945566 0.5 +-0.8375280400421417 -0.5463943467342689 0.5 +-0.6740374295910203 -0.2252897395303871 0.5 +-0.4796886364253098 -0.5017756675750862 0.5 +-0.6602148360204885 -0.42178475287936923 0.2738391654718595 +-0.3743508885844845 -0.9272871250136101 0.1923014057089899 +-0.3905463446030323 -0.5551470119858855 0.03028345229970595 +-0.8375280400421417 -0.5463943467342691 0.0009050798851157893 +-0.18388834997344516 -0.681726959426476 0.5 +0.6859084487184781 0.7276878451483237 0.5 +0.6908106003736185 0.3550173154374946 0.2365373453977786 +0.4963988652856184 0.5187144973091835 0.5 +0.4657982288202733 0.48926257925240496 -0.009066410328528141 +0.4972040079404958 0.5243373750500604 -0.5 +0.24595148858546906 0.6780839192636712 -0.16488678407288926 +0.6772703026987079 0.32970649744744135 -0.2085290091661496 +-0.9868505920553636 -0.1616351105421665 0.5 +-0.9999287545525191 0.0119367423968243 -0.02458037533056029 +-0.6630818776079881 0.16130527090179975 0.13548961787098063 +-0.6966957541845799 0.16853738083515957 0.5 +-0.6808490402696524 -0.159003652416135 0.34002596081083414 +0.05598441718564498 -0.6858538317724099 -0.31631709529301594 +-0.1933153032328007 -0.664775472160721 -0.2455951141007966 +0.3302750773609795 0.9438847245687361 -0.5 +0.14746101245794252 0.6952908100719171 -0.5 +-0.44168803230554016 -0.4819714143630655 -0.3383847310733504 +0.07330668998626741 -0.9973094450586824 -0.2250937448115864 +-0.13695776082997474 -0.9905768883577082 -0.5 +-0.5322171407364256 -0.8466078874581453 -0.5 +-0.1993178652507288 -0.6633324317723606 -0.5 +-0.3179327565441217 -0.9481132644975789 -0.14660514943439706 +-0.6476451030423191 0.7619421372422606 0.016891788312369038 +-0.35841529411874334 0.5935814632694921 -0.14693224629347293 +-0.628658619059129 0.3796275581847179 0.2273159046651026 +-0.6230886408886086 0.37239930181553016 -0.22627696623588464 +0.016205952149959003 0.7447772580991381 -0.17397560473675172 +-0.3356955256781739 0.6067970362626528 0.19891011219938176 +-0.5073526820047336 0.5013325409139204 -0.5 +-0.6948961904704768 0.14588809860205015 -0.20514122624342637 +-0.9007476690444871 0.4343427640826112 -0.01750096847478627 +-0.7926823329666097 0.6096349063190303 -0.5 +0.8171909034829123 0.5763670941897892 0.017944593391836405 +0.6787438518189246 0.7343750973569363 -0.5 +0.669488503042687 0.0031878968753018835 0.1702458759976271 +0.9805018388312463 0.19650990827066372 0.013536077514493927 +0.9182887744162915 0.3959112612455288 0.5 +0.6956629052588639 0.1782837817729419 0.5 +0.6850606674990449 -0.15838298131204254 0.5 +0.13171896645825493 0.9912870996210781 0.01830864398258303 +0.33824080956541 0.9410595914948936 0.5 +-0.0724755357331037 0.9973701904108623 0.5 +-0.002415753634857049 0.7195104385534825 0.21207969145156405 +0.2660217023032155 0.6834321682468841 0.1889190627097833 +0.13013064483278836 0.675116320748556 0.5 +0.5185029454428911 0.8550758419970981 -0.0074662502613973 +-0.1931213680983992 0.6601075670586916 0.5 +-0.4835020902397924 -0.507738076955535 -0.5 +0.3696205762810363 -0.574659819443879 -0.21512573409565364 +0.4244126174375137 -0.9054689007137895 -0.17431739988440909 +0.9156551973630727 0.40196462473953154 -0.5 +0.7365711616695659 0.01554100836707668 -0.19536686682078142 +-0.9688711879158358 0.24756538777978826 0.5 +-0.47469814077992056 0.8801486664990674 0.5 +-0.7901445551701427 0.6129205347636653 0.5 +-0.19849274312997123 0.6646631834803811 -0.5 +-0.2823536740873904 0.9593103787249211 0.023788514094556845 +0.6879307326827979 0.1796265808006876 -0.5 +1. 0. -0.5 +-0.47219520355646416 0.498124673656299 0.5 +0.9621751248435289 -0.27243169626961483 -0.010210963130078077 +0.6791029100539356 -0.1515269232248766 -0.5 +0.5594933951579955 -0.3895199068872477 -0.12946432153365675 +0.6537530365115155 -0.33853885454630034 0.28158249775901134 +1. 0. 0.5 +0.909834738941556 -0.41497077947145955 0.5 +0.7940206713300018 -0.6078907578674422 0.1933036221834642 +0.7565263027173401 -0.6539632660148667 -0.1423234797999447 +0.5227836879567489 -0.852465375019033 0.16491704436541454 +0.28615413094601594 -0.9581836010611589 0.5 +0.07573678522231944 -0.9971278450450514 0.12448119766402888 +-0.07125657497927042 -0.7161407287443025 0.18384182894018675 +-0.653904449844533 -0.2295408927481397 -0.5 +0.6581889353823536 -0.7528527912814322 0.5 +0.2861753463146679 -0.9581772649993736 -0.5 +0.2060810039115023 -0.6921883270417896 -0.5 +0.6576794891307078 -0.7532978757283011 -0.5 +0.5287160986484637 -0.44402576695056395 -0.5 +-0.9867503230983625 -0.16224610893724706 -0.5 +-0.7009790534683309 0.16657462196315853 -0.5 +-0.969523404503658 0.244998710444843 -0.5 +-0.8375280400421417 -0.5463943467342691 -0.5 +0.9091328560011489 -0.4165062426173154 -0.5 +-0.5330361537343615 -0.8460924646940651 0.5 +-0.1375575329186719 -0.9904937784445333 0.5 +-0.08006786563001286 0.9967894145171556 -0.5 +-0.48000710661746904 0.8772645995346704 -0.5 +0.20641653965789786 -0.6862744051412235 0.5 diff --git a/miniapps/electromagnetics/electromagnetics.hpp b/miniapps/electromagnetics/electromagnetics.hpp index 4ad58f20d0..6d0a7dbf79 100644 --- a/miniapps/electromagnetics/electromagnetics.hpp +++ b/miniapps/electromagnetics/electromagnetics.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/electromagnetics/joule.cpp b/miniapps/electromagnetics/joule.cpp index 2110d7c4d5..1f12f90907 100644 --- a/miniapps/electromagnetics/joule.cpp +++ b/miniapps/electromagnetics/joule.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/electromagnetics/joule_solver.cpp b/miniapps/electromagnetics/joule_solver.cpp index 90d4c1b8c9..697e43f2b2 100644 --- a/miniapps/electromagnetics/joule_solver.cpp +++ b/miniapps/electromagnetics/joule_solver.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/electromagnetics/joule_solver.hpp b/miniapps/electromagnetics/joule_solver.hpp index 77a10ded88..92338867fe 100644 --- a/miniapps/electromagnetics/joule_solver.hpp +++ b/miniapps/electromagnetics/joule_solver.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/electromagnetics/makefile b/miniapps/electromagnetics/makefile index 2bf149c7b9..91591e0465 100644 --- a/miniapps/electromagnetics/makefile +++ b/miniapps/electromagnetics/makefile @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/miniapps/electromagnetics/maxwell.cpp b/miniapps/electromagnetics/maxwell.cpp index aca89a1cf7..ac567a43c2 100644 --- a/miniapps/electromagnetics/maxwell.cpp +++ b/miniapps/electromagnetics/maxwell.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/electromagnetics/maxwell_solver.cpp b/miniapps/electromagnetics/maxwell_solver.cpp index 12917b8fdf..8e1995e3dd 100644 --- a/miniapps/electromagnetics/maxwell_solver.cpp +++ b/miniapps/electromagnetics/maxwell_solver.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/electromagnetics/maxwell_solver.hpp b/miniapps/electromagnetics/maxwell_solver.hpp index 51a6c78615..91ae34f6d0 100644 --- a/miniapps/electromagnetics/maxwell_solver.hpp +++ b/miniapps/electromagnetics/maxwell_solver.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/electromagnetics/tesla.cpp b/miniapps/electromagnetics/tesla.cpp index e66f659e48..d152bd58c7 100644 --- a/miniapps/electromagnetics/tesla.cpp +++ b/miniapps/electromagnetics/tesla.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/electromagnetics/tesla_solver.cpp b/miniapps/electromagnetics/tesla_solver.cpp index 8a647071df..84bc4bfcce 100644 --- a/miniapps/electromagnetics/tesla_solver.cpp +++ b/miniapps/electromagnetics/tesla_solver.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/electromagnetics/tesla_solver.hpp b/miniapps/electromagnetics/tesla_solver.hpp index 0d6b86c630..485a8c5c25 100644 --- a/miniapps/electromagnetics/tesla_solver.hpp +++ b/miniapps/electromagnetics/tesla_solver.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/electromagnetics/volta.cpp b/miniapps/electromagnetics/volta.cpp index 9a623f7328..af30c91b3a 100644 --- a/miniapps/electromagnetics/volta.cpp +++ b/miniapps/electromagnetics/volta.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/electromagnetics/volta_solver.cpp b/miniapps/electromagnetics/volta_solver.cpp index 151cbdfecc..b14514d885 100644 --- a/miniapps/electromagnetics/volta_solver.cpp +++ b/miniapps/electromagnetics/volta_solver.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/electromagnetics/volta_solver.hpp b/miniapps/electromagnetics/volta_solver.hpp index e55bef790d..e378244fde 100644 --- a/miniapps/electromagnetics/volta_solver.hpp +++ b/miniapps/electromagnetics/volta_solver.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/gslib/CMakeLists.txt b/miniapps/gslib/CMakeLists.txt index 39660c35c7..b5ecadf24c 100644 --- a/miniapps/gslib/CMakeLists.txt +++ b/miniapps/gslib/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/miniapps/gslib/field-diff.cpp b/miniapps/gslib/field-diff.cpp index 77e84b2af2..5a9cb76973 100644 --- a/miniapps/gslib/field-diff.cpp +++ b/miniapps/gslib/field-diff.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/gslib/field-interp.cpp b/miniapps/gslib/field-interp.cpp index 4ba9e87579..65599ec2b4 100644 --- a/miniapps/gslib/field-interp.cpp +++ b/miniapps/gslib/field-interp.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/gslib/findpts.cpp b/miniapps/gslib/findpts.cpp index 03dce76576..09752e2a11 100644 --- a/miniapps/gslib/findpts.cpp +++ b/miniapps/gslib/findpts.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/gslib/makefile b/miniapps/gslib/makefile index 5ace88aedf..192d53514f 100644 --- a/miniapps/gslib/makefile +++ b/miniapps/gslib/makefile @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/miniapps/gslib/pfindpts.cpp b/miniapps/gslib/pfindpts.cpp index d58448ee25..a6570432d9 100644 --- a/miniapps/gslib/pfindpts.cpp +++ b/miniapps/gslib/pfindpts.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/meshing/CMakeLists.txt b/miniapps/meshing/CMakeLists.txt index dae9ae677d..dfbb74f1c5 100644 --- a/miniapps/meshing/CMakeLists.txt +++ b/miniapps/meshing/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/miniapps/meshing/amr-quad-q2.mesh b/miniapps/meshing/amr-quad-q2.mesh index 75101310f5..cb72262043 100644 --- a/miniapps/meshing/amr-quad-q2.mesh +++ b/miniapps/meshing/amr-quad-q2.mesh @@ -1,57 +1,63 @@ -MFEM mesh v1.1 +MFEM NC mesh v1.0 -# -# MFEM Geometry Types (see mesh/geom.hpp): -# -# POINT = 0 -# SEGMENT = 1 +# NCMesh supported geometry types: # TRIANGLE = 2 # SQUARE = 3 # TETRAHEDRON = 4 # CUBE = 5 # PRISM = 6 -# dimension 2 +# rank attr geom ref_type nodes/children elements -28 -1 3 0 9 21 12 -1 3 12 21 11 7 -1 3 21 22 37 25 -1 3 25 37 24 11 -1 3 37 23 8 24 -1 3 22 10 23 37 -1 3 9 4 10 21 -1 3 4 13 26 10 -1 3 13 1 14 26 -1 3 26 14 5 15 -1 3 38 28 15 29 -1 3 27 26 28 38 -1 3 10 27 38 23 -1 3 23 38 29 8 -1 3 8 29 39 33 -1 3 33 39 32 18 -1 3 39 31 30 32 -1 3 29 15 31 39 -1 3 15 5 16 30 -1 3 30 16 3 17 -1 3 18 30 17 6 -1 3 34 18 6 19 -1 3 40 33 18 36 -1 3 24 8 33 40 -1 3 11 24 40 35 -1 3 35 40 36 34 -1 3 7 11 34 20 -1 3 20 34 19 2 +37 +-1 1 3 3 1 10 19 28 +-1 1 3 3 2 3 4 9 +0 1 3 0 0 9 21 12 +0 1 3 0 9 4 10 21 +-1 1 3 3 5 6 7 8 +0 1 3 0 21 22 37 25 +0 1 3 0 22 10 23 37 +0 1 3 0 37 23 8 24 +0 1 3 0 25 37 24 11 +0 1 3 0 12 21 11 7 +-1 1 3 3 11 12 13 14 +0 1 3 0 4 13 26 10 +0 1 3 0 13 1 14 26 +0 1 3 0 26 14 5 15 +-1 1 3 3 15 16 17 18 +0 1 3 0 10 27 38 23 +0 1 3 0 27 26 28 38 +0 1 3 0 38 28 15 29 +0 1 3 0 23 38 29 8 +-1 1 3 3 20 25 26 27 +-1 1 3 3 21 22 23 24 +0 1 3 0 8 29 39 33 +0 1 3 0 29 15 31 39 +0 1 3 0 39 31 30 32 +0 1 3 0 33 39 32 18 +0 1 3 0 15 5 16 30 +0 1 3 0 30 16 3 17 +0 1 3 0 18 30 17 6 +-1 1 3 3 29 30 35 36 +0 1 3 0 7 11 34 20 +-1 1 3 3 31 32 33 34 +0 1 3 0 11 24 40 35 +0 1 3 0 24 8 33 40 +0 1 3 0 40 33 18 36 +0 1 3 0 35 40 36 34 +0 1 3 0 34 18 6 19 +0 1 3 0 20 34 19 2 +# attr geom nodes boundary 16 2 1 0 9 1 1 12 0 -1 1 7 12 2 1 9 4 +1 1 7 12 2 1 4 13 2 1 13 1 1 1 1 14 @@ -60,11 +66,12 @@ boundary 1 1 16 3 2 1 3 17 2 1 17 6 -2 1 6 19 1 1 20 7 +2 1 6 19 2 1 19 2 1 1 2 20 +# vert_id p1 p2 vertex_parents 37 4 0 1 @@ -105,21 +112,7 @@ vertex_parents 39 29 32 40 24 36 -coarse_elements -9 -3 2 5 4 3 -3 0 6 28 1 -3 12 11 10 13 -3 7 8 9 30 -3 14 17 16 15 -3 32 18 19 20 -3 24 23 22 25 -3 26 34 21 27 -3 29 31 33 35 - -vertices -41 - +# mesh curvature GridFunction nodes FiniteElementSpace FiniteElementCollection: H1_2D_P2 @@ -130,43 +123,43 @@ Ordering: 0 1 0 1 -0.5 -1 -0.5 -0 -0.490917 0.25 -0.481659 +0.230224 +0 0.229025 0 +0.361824 +0.365809 +0.256374 +0.358947 +0.498798 +0.490917 +0.481659 +0.5 0.75 +0.75627 +1 1 0.75002 -1 -0.75 -0.497731 -0.25 -0 -0.230224 -0.361824 -0.498798 -0.358947 -0.256374 -0.75627 -0.609156 +0.616315 0.760931 0.614878 -0.754468 -0.729327 -0.597212 -0.479497 -0.255854 -0.252575 -0.374701 -0.365809 -0.616315 +0.609156 0.620005 +0.479497 +0.597212 +0.497731 +0.729327 +0.754468 +1 +0.75 +0.5 +0.255854 +0.25 0.354453 +0.374701 +0.252575 +0 0.125 0.241186 0.113998 @@ -276,42 +269,42 @@ Ordering: 0 1 1 0 -0.5 -1 -0.5 -0.500169 -0 -0.230361 -0.506286 -0.25 -0 -0.25 -0.501817 -0.75 -1 -0.751223 -1 -0.75 0.245442 +0.25 +0.506286 +0.5 0.249774 -0.359053 -0.482625 +0.380657 0.339768 +0.482625 +0.359053 +0.500169 +0.230361 +0 +0 0.25622 -0.246257 +0.25 +0.5 +0.501817 +0.367339 0.342759 0.493736 -0.737081 -0.598044 -0.732223 -0.628407 -0.755429 -0.618147 -0.736346 -0.380657 -0.367339 +0.246257 0.619478 +0.628407 +0.732223 +0.751223 +0.598044 +0.737081 +0.75 +1 +1 +0.755429 +1 0.619469 +0.736346 +0.618147 +0.75 0 0.112152 0.214709 @@ -416,3 +409,5 @@ Ordering: 0 0.679016 0.617255 0.87398 + +mfem_mesh_end diff --git a/miniapps/meshing/extruder.cpp b/miniapps/meshing/extruder.cpp index e3e502fe02..799a3fda05 100644 --- a/miniapps/meshing/extruder.cpp +++ b/miniapps/meshing/extruder.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/meshing/jagged.mesh b/miniapps/meshing/jagged.mesh new file mode 100644 index 0000000000..1d10e0e2f4 --- /dev/null +++ b/miniapps/meshing/jagged.mesh @@ -0,0 +1,717 @@ +MFEM mesh v1.0 + +# +# MFEM Geometry Types (see mesh/geom.hpp): +# +# POINT = 0 +# SEGMENT = 1 +# TRIANGLE = 2 +# SQUARE = 3 +# TETRAHEDRON = 4 +# CUBE = 5 +# + +dimension +2 + +elements +18 +1 3 0 1 8 7 +1 3 1 2 9 8 +1 3 2 3 10 9 +1 3 3 4 11 10 +1 3 4 5 12 11 +1 3 5 6 13 12 +1 3 7 8 15 14 +1 3 8 9 16 15 +1 3 9 10 17 16 +1 3 10 11 18 17 +1 3 11 12 19 18 +1 3 12 13 20 19 +1 3 14 15 22 21 +1 3 15 16 23 22 +1 3 16 17 24 23 +1 3 17 18 25 24 +1 3 18 19 26 25 +1 3 19 20 27 26 + +boundary +18 +4 1 0 1 +4 1 1 2 +4 1 2 3 +4 1 3 4 +4 1 4 5 +4 1 5 6 +2 1 22 21 +2 1 23 22 +2 1 24 23 +2 1 25 24 +2 1 26 25 +2 1 27 26 +4 1 7 0 +4 1 14 7 +4 1 21 14 +4 1 6 13 +4 1 13 20 +4 1 20 27 + +vertices +28 + +nodes +FiniteElementSpace +FiniteElementCollection: H1_2D_P4 +VDim: 2 +Ordering: 0 + +0 +1 +2 +3 +3.1666667 +3.3333333 +3.5 +-0.33333333 +0.61111111 +1.5555556 +2.5 +2.8888889 +3.2777778 +3.6666667 +-0.66666667 +0.22222222 +1.1111111 +2 +2.6111111 +3.2222222 +3.8333333 +-1 +-0.16666667 +0.66666667 +1.5 +2.3333333 +3.1666667 +4 +0.17267316 +0.5 +0.82732684 +0.93284932 +0.80555556 +0.67826179 +-0.17025312 +0.13888889 +0.4480309 +-0.057557722 +-0.16666667 +-0.27577561 +1.1726732 +1.5 +1.8273268 +1.9232564 +1.7777778 +1.6322992 +0.77419132 +1.0833333 +1.3924753 +2.1726732 +2.5 +2.8273268 +2.9136634 +2.75 +2.5863366 +1.7186358 +2.0277778 +2.3369198 +3.0287789 +3.0833333 +3.1378878 +3.1187019 +3.0277778 +2.9368537 +2.5671507 +2.6944444 +2.8217382 +3.1954455 +3.25 +3.3045545 +3.3237404 +3.3055556 +3.2873707 +2.9560396 +3.0833333 +3.2106271 +3.3621122 +3.4166667 +3.4712211 +3.5287789 +3.5833333 +3.6378878 +3.3449285 +3.4722222 +3.599516 +0.54396044 +0.41666667 +0.2893729 +-0.51317941 +-0.22222222 +0.068734965 +-0.39089105 +-0.5 +-0.60910895 +1.4788119 +1.3333333 +1.1878547 +0.37570948 +0.66666667 +0.95762385 +2.4136634 +2.25 +2.0863366 +1.2645984 +1.5555556 +1.8465127 +2.8409241 +2.75 +2.6590759 +2.1055225 +2.3055556 +2.5055886 +3.2681848 +3.25 +3.2318152 +2.7166336 +2.9166667 +3.1166997 +3.6954455 +3.75 +3.8045545 +3.3277447 +3.5277778 +3.7278108 +0.15507155 +0.027777778 +-0.099515992 +-0.8561057 +-0.58333333 +-0.31056097 +-0.72422439 +-0.83333333 +-0.94244228 +1.0343675 +0.88888889 +0.7434103 +-0.022772363 +0.25 +0.52277236 +1.9136634 +1.75 +1.5863366 +0.81056097 +1.0833333 +1.3561057 +2.5631463 +2.4722222 +2.3812981 +1.6438943 +1.9166667 +2.189439 +3.2126293 +3.1944444 +3.1762596 +2.4772276 +2.75 +3.0227724 +3.8621122 +3.9166667 +3.9712211 +3.310561 +3.5833333 +3.8561057 +0.113459 +0.4376458 +0.76183261 +0.0012100212 +0.31944444 +0.63767887 +-0.11103896 +0.20124309 +0.51352513 +1.103866 +1.4280528 +1.7522397 +0.97343224 +1.2916667 +1.6099011 +0.84299844 +1.1552805 +1.4675625 +2.0942731 +2.4184599 +2.7426467 +1.9456545 +2.2638889 +2.5821233 +1.7970358 +2.1093179 +2.4215999 +2.9490681 +3.0161827 +3.0832973 +2.7979648 +2.8888889 +2.979813 +2.6468615 +2.7615951 +2.8763288 +3.1541065 +3.2212211 +3.2883357 +3.0757425 +3.1666667 +3.2575908 +2.9973785 +3.1121122 +3.2268458 +3.359145 +3.4262596 +3.4933742 +3.3535203 +3.4444444 +3.5353686 +3.3478956 +3.4626293 +3.5773629 +-0.22946729 +0.076534691 +0.38253667 +-0.34171627 +-0.041666667 +0.25838293 +-0.45396524 +-0.15986802 +0.13422919 +0.7053842 +1.0113862 +1.3173882 +0.5749504 +0.875 +1.1750496 +0.4445166 +0.73861382 +1.032711 +1.6402357 +1.9462377 +2.2522397 +1.4916171 +1.7916667 +2.0917163 +1.3429984 +1.6370957 +1.9311929 +2.4874399 +2.6272938 +2.7671477 +2.3363366 +2.5 +2.6636634 +2.1852333 +2.3727062 +2.5601792 +2.9147006 +3.0545545 +3.1944084 +2.8363366 +3 +3.1636634 +2.7579726 +2.9454455 +3.1329185 +3.3419613 +3.4818152 +3.6216691 +3.3363366 +3.5 +3.6636634 +3.3307119 +3.5181848 +3.7056578 +-0.57239358 +-0.28457642 +0.0032407353 +-0.68464255 +-0.40277778 +-0.120913 +-0.79689153 +-0.52097913 +-0.24506674 +0.30690236 +0.59471951 +0.88253667 +0.17646856 +0.45833333 +0.74019811 +0.046034758 +0.32194715 +0.59785955 +1.1861983 +1.4740155 +1.7618326 +1.0375797 +1.3194444 +1.6013092 +0.88896104 +1.1648734 +1.4407858 +2.0258117 +2.2384049 +2.4509981 +1.8747084 +2.1111111 +2.3475138 +1.7236051 +1.9838173 +2.2440296 +2.6752946 +2.8878878 +3.100481 +2.5969306 +2.8333333 +3.069736 +2.5185666 +2.7787789 +3.0389911 +3.3247775 +3.5373707 +3.7499639 +3.3191528 +3.5555556 +3.7919583 +3.3135281 +3.5737404 +3.8339526 +0 +0.5 +1 +1.5 +1 +0.5 +0 +0.66666667 +1 +1.3333333 +1.6666667 +1.3333333 +1 +0.66666667 +1.3333333 +1.5 +1.6666667 +1.8333333 +1.6666667 +1.5 +1.3333333 +2 +2 +2 +2 +2 +2 +2 +0.086336582 +0.25 +0.41366342 +0.58633658 +0.75 +0.91366342 +0.72422439 +0.83333333 +0.94244228 +0.11511544 +0.33333333 +0.55155122 +0.58633658 +0.75 +0.91366342 +1.0575577 +1.1666667 +1.2757756 +1.0575577 +1.1666667 +1.2757756 +1.0863366 +1.25 +1.4136634 +1.5287789 +1.5833333 +1.6378878 +1.3908911 +1.5 +1.6091089 +1.4136634 +1.25 +1.0863366 +1.0575577 +1.1666667 +1.2757756 +1.6091089 +1.5 +1.3908911 +0.91366342 +0.75 +0.58633658 +0.58633658 +0.75 +0.91366342 +1.2757756 +1.1666667 +1.0575577 +0.41366342 +0.25 +0.086336582 +0.11511544 +0.33333333 +0.55155122 +0.94244228 +0.83333333 +0.72422439 +1.0863366 +1.25 +1.4136634 +1.3621122 +1.4166667 +1.4712211 +0.78178211 +1 +1.2182179 +1.3908911 +1.5 +1.6091089 +1.5287789 +1.5833333 +1.6378878 +1.6954455 +1.75 +1.8045545 +1.6954455 +1.75 +1.8045545 +1.3908911 +1.5 +1.6091089 +1.8045545 +1.75 +1.6954455 +1.0863366 +1.25 +1.4136634 +1.6378878 +1.5833333 +1.5287789 +0.78178211 +1 +1.2182179 +1.4712211 +1.4166667 +1.3621122 +1.5863366 +1.75 +1.9136634 +2 +2 +2 +1.4484488 +1.6666667 +1.8848846 +1.7242244 +1.8333333 +1.9424423 +2 +2 +2 +1.8621122 +1.9166667 +1.9712211 +2 +2 +2 +1.7242244 +1.8333333 +1.9424423 +2 +2 +2 +1.5863366 +1.75 +1.9136634 +2 +2 +2 +1.4484488 +1.6666667 +1.8848846 +2 +2 +2 +0.19648269 +0.35072601 +0.50496934 +0.40528049 +0.54166667 +0.67805285 +0.61407828 +0.73260732 +0.85113636 +0.66770383 +0.82194715 +0.97619048 +0.82194715 +0.95833333 +1.0947195 +0.97619048 +1.0947195 +1.2132486 +1.138925 +1.2931683 +1.4474116 +1.2386138 +1.375 +1.5113862 +1.3383027 +1.4568317 +1.5753607 +1.4474116 +1.2931683 +1.138925 +1.5113862 +1.375 +1.2386138 +1.5753607 +1.4568317 +1.3383027 +0.97619048 +0.82194715 +0.66770383 +1.0947195 +0.95833333 +0.82194715 +1.2132486 +1.0947195 +0.97619048 +0.50496934 +0.35072601 +0.19648269 +0.67805285 +0.54166667 +0.40528049 +0.85113636 +0.73260732 +0.61407828 +0.83437049 +0.93405935 +1.0337482 +1.0431683 +1.125 +1.2068317 +1.2519661 +1.3159407 +1.3799152 +1.138925 +1.2386138 +1.3383027 +1.2931683 +1.375 +1.4568317 +1.4474116 +1.5113862 +1.5753607 +1.4434794 +1.5431683 +1.6428571 +1.5431683 +1.625 +1.7068317 +1.6428571 +1.7068317 +1.7708063 +1.6428571 +1.5431683 +1.4434794 +1.7068317 +1.625 +1.5431683 +1.7708063 +1.7068317 +1.6428571 +1.3383027 +1.2386138 +1.138925 +1.4568317 +1.375 +1.2931683 +1.5753607 +1.5113862 +1.4474116 +1.0337482 +0.93405935 +0.83437049 +1.2068317 +1.125 +1.0431683 +1.3799152 +1.3159407 +1.2519661 +1.4722583 +1.5173927 +1.5625271 +1.6810561 +1.7083333 +1.7356106 +1.8898539 +1.899274 +1.9086941 +1.6101461 +1.6552805 +1.7004149 +1.7643894 +1.7916667 +1.8189439 +1.9186328 +1.9280528 +1.9374729 +1.7480339 +1.7931683 +1.8383027 +1.8477228 +1.875 +1.9022772 +1.9474116 +1.9568317 +1.9662518 +1.8383027 +1.7931683 +1.7480339 +1.9022772 +1.875 +1.8477228 +1.9662518 +1.9568317 +1.9474116 +1.7004149 +1.6552805 +1.6101461 +1.8189439 +1.7916667 +1.7643894 +1.9374729 +1.9280528 +1.9186328 +1.5625271 +1.5173927 +1.4722583 +1.7356106 +1.7083333 +1.6810561 +1.9086941 +1.899274 +1.8898539 diff --git a/miniapps/meshing/klein-bottle.cpp b/miniapps/meshing/klein-bottle.cpp index 7b6a7585ac..ff08088604 100644 --- a/miniapps/meshing/klein-bottle.cpp +++ b/miniapps/meshing/klein-bottle.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/meshing/makefile b/miniapps/meshing/makefile index e08ac8b004..fbb2ebae55 100644 --- a/miniapps/meshing/makefile +++ b/miniapps/meshing/makefile @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/miniapps/meshing/mesh-explorer.cpp b/miniapps/meshing/mesh-explorer.cpp index c969cb30a5..ee10504eee 100644 --- a/miniapps/meshing/mesh-explorer.cpp +++ b/miniapps/meshing/mesh-explorer.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/meshing/mesh-optimizer.cpp b/miniapps/meshing/mesh-optimizer.cpp index 7f7d5cfc6b..393ae01170 100644 --- a/miniapps/meshing/mesh-optimizer.cpp +++ b/miniapps/meshing/mesh-optimizer.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -33,11 +33,11 @@ // // Sample runs: // Adapted analytic shape: -// mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 2 -tid 4 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 +// mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 2 -tid 4 -ni 200 -bnd -qt 1 -qo 8 // Adapted analytic size+orientation: -// mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 14 -tid 4 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd +// mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 14 -tid 4 -ni 100 -bnd -qt 1 -qo 8 -fd // Adapted analytic shape+orientation: -// mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 85 -tid 4 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd +// mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 85 -tid 4 -ni 100 -bnd -qt 1 -qo 8 -fd // // Adapted discrete size: // mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 80 -tid 5 -ni 50 -qo 4 -nor @@ -49,9 +49,9 @@ // Adapted discrete size+orientation (requires GSLIB): // * mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 36 -tid 8 -qo 4 -fd -ae 1 -nor // Adapted discrete aspect-ratio+orientation (requires GSLIB): -// * mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 85 -tid 8 -ni 10 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd -ae 1 +// * mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 85 -tid 8 -ni 10 -bnd -qt 1 -qo 8 -fd -ae 1 // Adapted discrete aspect ratio (3D): -// mesh-optimizer -m cube.mesh -o 2 -rs 2 -mid 302 -tid 7 -ni 20 -ls 2 -li 100 -bnd -qt 1 -qo 8 +// mesh-optimizer -m cube.mesh -o 2 -rs 2 -mid 302 -tid 7 -ni 20 -bnd -qt 1 -qo 8 // // Adaptive limiting: // mesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -alc 0.5 @@ -61,28 +61,33 @@ // * mesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -alc 0.5 -fd -ae 1 // // Blade shape: -// mesh-optimizer -m blade.mesh -o 4 -rs 0 -mid 2 -tid 1 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 +// mesh-optimizer -m blade.mesh -o 4 -mid 2 -tid 1 -ni 30 -ls 3 -art 1 -bnd -qt 1 -qo 8 // Blade shape with FD-based solver: -// mesh-optimizer -m blade.mesh -o 4 -rs 0 -mid 2 -tid 1 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd +// mesh-optimizer -m blade.mesh -o 4 -mid 2 -tid 1 -ni 30 -ls 4 -bnd -qt 1 -qo 8 -fd // Blade limited shape: -// mesh-optimizer -m blade.mesh -o 4 -rs 0 -mid 2 -tid 1 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -lc 5000 +// mesh-optimizer -m blade.mesh -o 4 -mid 2 -tid 1 -bnd -qt 1 -qo 8 -lc 5000 // ICF shape and equal size: -// mesh-optimizer -o 3 -rs 0 -mid 9 -tid 2 -ni 25 -ls 3 -qo 5 +// mesh-optimizer -o 3 -mid 9 -tid 2 -ni 25 -ls 3 -art 2 -qo 5 // ICF shape and initial size: -// mesh-optimizer -o 3 -rs 0 -mid 9 -tid 3 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 +// mesh-optimizer -o 3 -mid 9 -tid 3 -ni 30 -ls 3 -bnd -qt 1 -qo 8 // ICF shape: -// mesh-optimizer -o 3 -rs 0 -mid 1 -tid 1 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 +// mesh-optimizer -o 3 -mid 1 -tid 1 -ni 100 -bnd -qt 1 -qo 8 // ICF limited shape: -// mesh-optimizer -o 3 -rs 0 -mid 1 -tid 1 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -lc 10 +// mesh-optimizer -o 3 -mid 1 -tid 1 -ni 100 -bnd -qt 1 -qo 8 -lc 10 // ICF combo shape + size (rings, slow convergence): -// mesh-optimizer -o 3 -rs 0 -mid 1 -tid 1 -ni 1000 -ls 2 -li 100 -bnd -qt 1 -qo 8 -cmb 1 +// mesh-optimizer -o 3 -mid 1 -tid 1 -ni 1000 -bnd -qt 1 -qo 8 -cmb 1 // Mixed tet / cube / hex mesh with limiting: // mesh-optimizer -m ../../data/fichera-mixed-p2.mesh -o 4 -rs 1 -mid 301 -tid 1 -fix-bnd -qo 6 -nor -lc 0.25 // 3D pinched sphere shape (the mesh is in the mfem/data GitHub repository): -// * mesh-optimizer -m ../../../mfem_data/ball-pert.mesh -o 4 -rs 0 -mid 303 -tid 1 -ni 20 -ls 2 -li 500 -fix-bnd +// * mesh-optimizer -m ../../../mfem_data/ball-pert.mesh -o 4 -mid 303 -tid 1 -ni 20 -li 500 -fix-bnd // 2D non-conforming shape and equal size: -// mesh-optimizer -m ./amr-quad-q2.mesh -o 2 -rs 1 -mid 9 -tid 2 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 - +// mesh-optimizer -m ./amr-quad-q2.mesh -o 2 -rs 1 -mid 9 -tid 2 -ni 200 -bnd -qt 1 -qo 8 +// +// 2D untangling: +// mesh-optimizer -m jagged.mesh -o 2 -mid 22 -tid 1 -ni 50 -li 50 -qo 4 -fd -vl 1 +// 3D untangling (the mesh is in the mfem/data GitHub repository): +// * mesh-optimizer -m ../../../mfem_data/cube-holes-inv.mesh -o 3 -mid 313 -tid 1 -rtol 1e-5 -li 50 -qo 4 -fd -vl 1 +// #include "mfem.hpp" #include "../common/mfem-common.hpp" @@ -109,6 +114,7 @@ int main(int argc, char *argv[]) int solver_type = 0; int solver_iter = 20; double solver_rtol = 1e-10; + int solver_art_type = 0; int lin_solver = 2; int max_lin_iter = 100; bool move_bnd = true; @@ -147,15 +153,17 @@ int main(int argc, char *argv[]) "80 : (1-gamma)mu_2 + gamma mu_77 -- 2D shape+size\n\t" "85 : |T-|T|/sqrt(2)I|^2 -- 2D shape+orientation\n\t" "98 : (1/tau)|T-I|^2 -- 2D shape+size+orientation\n\t" - "211: (tau-1)^2-tau+sqrt(tau^2) -- 2D untangling\n\t" - "252: 0.5(tau-1)^2/(tau-tau_0) -- 2D untangling\n\t" + // "211: (tau-1)^2-tau+sqrt(tau^2) -- 2D untangling\n\t" + // "252: 0.5(tau-1)^2/(tau-tau_0) -- 2D untangling\n\t" "301: (|T||T^-1|)/3-1 -- 3D shape\n\t" "302: (|T|^2|T^-1|^2)/9-1 -- 3D shape\n\t" "303: (|T|^2)/3*tau^(2/3)-1 -- 3D shape\n\t" + //"311: (tau-1)^2-tau+sqrt(tau^2+eps)-- 3D untangling\n\t" + "313: (|T|^2)(tau-tau0)^(-2/3)/3 -- 3D untangling\n\t" "315: (tau-1)^2 -- 3D size\n\t" "316: 0.5(sqrt(tau)-1/sqrt(tau))^2 -- 3D size\n\t" "321: |T-T^-t|^2 -- 3D shape+size\n\t" - "352: 0.5(tau-1)^2/(tau-tau_0) -- 3D untangling\n\t" + // "352: 0.5(tau-1)^2/(tau-tau_0) -- 3D untangling\n\t" "A-metrics\n\t" "11 : (1/4*alpha)|A-(adjA)^T(W^TW)/omega|^2 -- 2D shape\n\t" "36 : (1/alpha)|A-W|^2 -- 2D shape+size+orientation\n\t" @@ -185,12 +193,17 @@ int main(int argc, char *argv[]) "Maximum number of Newton iterations."); args.AddOption(&solver_rtol, "-rtol", "--newton-rel-tolerance", "Relative tolerance for the Newton solver."); + args.AddOption(&solver_art_type, "-art", "--adaptive-rel-tol", + "Type of adaptive relative linear solver tolerance:\n\t" + "0: None (default)\n\t" + "1: Eisenstat-Walker type 1\n\t" + "2: Eisenstat-Walker type 2"); args.AddOption(&lin_solver, "-ls", "--lin-solver", "Linear solver:\n\t" "0: l1-Jacobi\n\t" "1: CG\n\t" "2: MINRES\n\t" - "3: MINRES + Jacobi preconditioner" + "3: MINRES + Jacobi preconditioner\n\t" "4: MINRES + l1-Jacobi preconditioner"); args.AddOption(&max_lin_iter, "-li", "--lin-iter", "Maximum number of iterations in the linear solve."); @@ -198,7 +211,7 @@ int main(int argc, char *argv[]) "--fix-boundary", "Enable motion along horizontal and vertical boundaries."); args.AddOption(&combomet, "-cmb", "--combo-type", - "Combination of metrics options:" + "Combination of metrics options:\n\t" "0: Use single metric\n\t" "1: Shape + space-dependent size given analytically\n\t" "2: Shape + adapted size given discretely; shared target"); @@ -345,15 +358,17 @@ int main(int argc, char *argv[]) case 80: metric = new TMOP_Metric_080(0.5); break; case 85: metric = new TMOP_Metric_085; break; case 98: metric = new TMOP_Metric_098; break; - case 211: metric = new TMOP_Metric_211; break; - case 252: metric = new TMOP_Metric_252(tauval); break; + // case 211: metric = new TMOP_Metric_211; break; + // case 252: metric = new TMOP_Metric_252(tauval); break; case 301: metric = new TMOP_Metric_301; break; case 302: metric = new TMOP_Metric_302; break; case 303: metric = new TMOP_Metric_303; break; + // case 311: metric = new TMOP_Metric_311; break; + case 313: metric = new TMOP_Metric_313(tauval); break; case 315: metric = new TMOP_Metric_315; break; case 316: metric = new TMOP_Metric_316; break; case 321: metric = new TMOP_Metric_321; break; - case 352: metric = new TMOP_Metric_352(tauval); break; + // case 352: metric = new TMOP_Metric_352(tauval); break; // A-metrics case 11: metric = new TMOP_AMetric_011; break; case 36: metric = new TMOP_AMetric_036; break; @@ -370,7 +385,7 @@ int main(int argc, char *argv[]) FiniteElementSpace ind_fes(mesh, &ind_fec); FiniteElementSpace ind_fesv(mesh, &ind_fec, dim); GridFunction size(&ind_fes), aspr(&ind_fes), disc(&ind_fes), ori(&ind_fes); - GridFunction aspr3d(&ind_fesv), size3d(&ind_fesv); + GridFunction aspr3d(&ind_fesv); switch (target_id) { case 1: target_t = TargetConstructor::IDEAL_SHAPE_UNIT_SIZE; break; @@ -428,14 +443,14 @@ int main(int argc, char *argv[]) #endif } - //Diffuse the interface + // Diffuse the interface DiffuseField(disc,2); - //Get partials with respect to x and y of the grid function + // Get partials with respect to x and y of the grid function disc.GetDerivative(1,0,d_x); disc.GetDerivative(1,1,d_y); - //Compute the squared magnitude of the gradient + // Compute the squared magnitude of the gradient for (int i = 0; i < size.Size(); i++) { size(i) = std::pow(d_x(i),2)+std::pow(d_y(i),2); @@ -687,6 +702,40 @@ int main(int argc, char *argv[]) } else { a.AddDomainIntegrator(he_nlf_integ); } + // Compute the minimum det(J) of the starting mesh. + tauval = infinity(); + const int NE = mesh->GetNE(); + for (int i = 0; i < NE; i++) + { + const IntegrationRule &ir = + irules->Get(fespace->GetFE(i)->GetGeomType(), quad_order); + ElementTransformation *transf = mesh->GetElementTransformation(i); + for (int j = 0; j < ir.GetNPoints(); j++) + { + transf->SetIntPoint(&ir.IntPoint(j)); + tauval = min(tauval, transf->Jacobian().Det()); + } + } + cout << "Minimum det(J) of the original mesh is " << tauval << endl; + + if (tauval < 0.0 && metric_id != 22 && metric_id != 211 && metric_id != 252 + && metric_id != 311 && metric_id != 313 && metric_id != 352) + { + MFEM_ABORT("The input mesh is inverted! Try an untangling metric."); + } + if (tauval < 0.0) + { + MFEM_VERIFY(target_t == TargetConstructor::IDEAL_SHAPE_UNIT_SIZE, + "Untangling is supported only for ideal targets."); + + const DenseMatrix &Wideal = + Geometries.GetGeomToPerfGeomJac(fespace->GetFE(0)->GetGeomType()); + tauval /= Wideal.Det(); + + // Slightly below minJ0 to avoid div by 0. + tauval -= 0.01 * h0.Min(); + } + const double init_energy = a.GetGridFunctionEnergy(x); // Visualize the starting mesh and metric values. @@ -786,23 +835,6 @@ int main(int argc, char *argv[]) S = minres; } - // Compute the minimum det(J) of the starting mesh. - tauval = infinity(); - const int NE = mesh->GetNE(); - for (int i = 0; i < NE; i++) - { - const IntegrationRule &ir = - irules->Get(fespace->GetFE(i)->GetGeomType(), quad_order); - ElementTransformation *transf = mesh->GetElementTransformation(i); - for (int j = 0; j < ir.GetNPoints(); j++) - { - transf->SetIntPoint(&ir.IntPoint(j)); - tauval = min(tauval, transf->Jacobian().Det()); - } - } - cout << "Minimum det(J) of the original mesh is " << tauval << endl; - tauval -= 0.01 * h0.Min(); // Slightly below minJ0 to avoid div by 0. - // Perform the nonlinear optimization. const IntegrationRule &ir = irules->Get(fespace->GetFE(0)->GetGeomType(), quad_order); @@ -814,9 +846,15 @@ int main(int argc, char *argv[]) // Specify linear solver when we use a Newton-based solver. solver.SetPreconditioner(*S); } + // For untangling, the solver will update the min det(T) values. + if (tauval < 0.0) { solver.SetMinDetPtr(&tauval); } solver.SetMaxIter(solver_iter); solver.SetRelTol(solver_rtol); solver.SetAbsTol(0.0); + if (solver_art_type > 0) + { + solver.SetAdaptiveLinRtol(solver_art_type, 0.5, 0.9); + } solver.SetPrintLevel(verbosity_level >= 1 ? 1 : -1); solver.SetOperator(a); solver.Mult(b, x.GetTrueVector()); diff --git a/miniapps/meshing/mesh-optimizer.hpp b/miniapps/meshing/mesh-optimizer.hpp index 649daf73d7..617d905616 100644 --- a/miniapps/meshing/mesh-optimizer.hpp +++ b/miniapps/meshing/mesh-optimizer.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/meshing/minimal-surface.cpp b/miniapps/meshing/minimal-surface.cpp index 925ceccc99..0967d5b5a4 100644 --- a/miniapps/meshing/minimal-surface.cpp +++ b/miniapps/meshing/minimal-surface.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/meshing/mobius-strip.cpp b/miniapps/meshing/mobius-strip.cpp index 5bf0dbff56..0a6e36fa98 100644 --- a/miniapps/meshing/mobius-strip.cpp +++ b/miniapps/meshing/mobius-strip.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/meshing/pmesh-optimizer.cpp b/miniapps/meshing/pmesh-optimizer.cpp index 5bae2ca352..fd0443f8ab 100644 --- a/miniapps/meshing/pmesh-optimizer.cpp +++ b/miniapps/meshing/pmesh-optimizer.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -33,11 +33,11 @@ // // Sample runs: // Adapted analytic shape: -// mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 2 -tid 4 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 +// mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 2 -tid 4 -ni 200 -bnd -qt 1 -qo 8 // Adapted analytic size+orientation: -// mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 14 -tid 4 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd +// mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 14 -tid 4 -ni 200 -bnd -qt 1 -qo 8 -fd // Adapted analytic shape+orientation: -// mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 85 -tid 4 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd +// mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 85 -tid 4 -ni 100 -bnd -qt 1 -qo 8 -fd // // Adapted discrete size: // mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 80 -tid 5 -ni 50 -qo 4 -nor @@ -49,9 +49,9 @@ // Adapted discrete size+orientation (requires GSLIB): // * mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 36 -tid 8 -qo 4 -fd -ae 1 -nor // Adapted discrete aspect_ratio+orientation (requires GSLIB): -// * mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 85 -tid 8 -ni 10 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd -ae 1 +// * mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 85 -tid 8 -ni 10 -bnd -qt 1 -qo 8 -fd -ae 1 // Adapted discrete aspect ratio (3D): -// mpirun -np 4 pmesh-optimizer -m cube.mesh -o 2 -rs 2 -mid 302 -tid 7 -ni 20 -ls 2 -li 100 -bnd -qt 1 -qo 8 +// mpirun -np 4 pmesh-optimizer -m cube.mesh -o 2 -rs 2 -mid 302 -tid 7 -ni 20 -bnd -qt 1 -qo 8 // // Adaptive limiting: // mpirun -np 4 pmesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -alc 0.5 @@ -61,27 +61,33 @@ // * mpirun -np 4 pmesh-optimizer -m stretched2D.mesh -o 2 -mid 2 -tid 1 -ni 50 -qo 5 -nor -vl 1 -alc 0.5 -fd -ae 1 // // Blade shape: -// mpirun -np 4 pmesh-optimizer -m blade.mesh -o 4 -rs 0 -mid 2 -tid 1 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 +// mpirun -np 4 pmesh-optimizer -m blade.mesh -o 4 -mid 2 -tid 1 -ni 30 -ls 3 -art 1 -bnd -qt 1 -qo 8 // Blade shape with FD-based solver: -// mpirun -np 4 pmesh-optimizer -m blade.mesh -o 4 -rs 0 -mid 2 -tid 1 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -fd +// mpirun -np 4 pmesh-optimizer -m blade.mesh -o 4 -mid 2 -tid 1 -ni 30 -ls 4 -bnd -qt 1 -qo 8 -fd // Blade limited shape: -// mpirun -np 4 pmesh-optimizer -m blade.mesh -o 4 -rs 0 -mid 2 -tid 1 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -lc 5000 +// mpirun -np 4 pmesh-optimizer -m blade.mesh -o 4 -mid 2 -tid 1 -bnd -qt 1 -qo 8 -lc 5000 // ICF shape and equal size: -// mpirun -np 4 pmesh-optimizer -o 3 -rs 0 -mid 9 -tid 2 -ni 25 -ls 3 -qo 5 +// mpirun -np 4 pmesh-optimizer -o 3 -mid 9 -tid 2 -ni 25 -ls 3 -art 2 -qo 5 // ICF shape and initial size: -// mpirun -np 4 pmesh-optimizer -o 3 -rs 0 -mid 9 -tid 3 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 +// mpirun -np 4 pmesh-optimizer -o 3 -mid 9 -tid 3 -ni 30 -ls 3 -bnd -qt 1 -qo 8 // ICF shape: -// mpirun -np 4 pmesh-optimizer -o 3 -rs 0 -mid 1 -tid 1 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 +// mpirun -np 4 pmesh-optimizer -o 3 -mid 1 -tid 1 -ni 100 -bnd -qt 1 -qo 8 // ICF limited shape: -// mpirun -np 4 pmesh-optimizer -o 3 -rs 0 -mid 1 -tid 1 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -lc 10 +// mpirun -np 4 pmesh-optimizer -o 3 -mid 1 -tid 1 -ni 100 -bnd -qt 1 -qo 8 -lc 10 // ICF combo shape + size (rings, slow convergence): -// mpirun -np 4 pmesh-optimizer -o 3 -rs 0 -mid 1 -tid 1 -ni 1000 -ls 2 -li 100 -bnd -qt 1 -qo 8 -cmb 1 +// mpirun -np 4 pmesh-optimizer -o 3 -mid 1 -tid 1 -ni 1000 -bnd -qt 1 -qo 8 -cmb 1 // Mixed tet / cube / hex mesh with limiting: // mpirun -np 4 pmesh-optimizer -m ../../data/fichera-mixed-p2.mesh -o 4 -rs 1 -mid 301 -tid 1 -fix-bnd -qo 6 -nor -lc 0.25 // 3D pinched sphere shape (the mesh is in the mfem/data GitHub repository): -// * mpirun -np 4 pmesh-optimizer -m ../../../mfem_data/ball-pert.mesh -o 4 -rs 0 -mid 303 -tid 1 -ni 20 -ls 2 -li 500 -fix-bnd +// * mpirun -np 4 pmesh-optimizer -m ../../../mfem_data/ball-pert.mesh -o 4 -mid 303 -tid 1 -ni 20 -li 500 -fix-bnd // 2D non-conforming shape and equal size: -// mpirun -np 4 pmesh-optimizer -m ./amr-quad-q2.mesh -o 2 -rs 1 -mid 9 -tid 2 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 +// mpirun -np 4 pmesh-optimizer -m ./amr-quad-q2.mesh -o 2 -rs 1 -mid 9 -tid 2 -ni 200 -bnd -qt 1 -qo 8 +// +// 2D untangling: +// mpirun -np 4 pmesh-optimizer -m jagged.mesh -o 2 -mid 22 -tid 1 -ni 50 -li 50 -qo 4 -fd -vl 1 +// 3D untangling (the mesh is in the mfem/data GitHub repository): +// * mpirun -np 4 pmesh-optimizer -m ../../../mfem_data/cube-holes-inv.mesh -o 3 -mid 313 -tid 1 -rtol 1e-5 -li 50 -qo 4 -fd -vl 1 +// #include "mfem.hpp" #include "../common/mfem-common.hpp" @@ -115,6 +121,7 @@ int main (int argc, char *argv[]) int solver_type = 0; int solver_iter = 20; double solver_rtol = 1e-10; + int solver_art_type = 0; int lin_solver = 2; int max_lin_iter = 100; bool move_bnd = true; @@ -155,15 +162,17 @@ int main (int argc, char *argv[]) "80 : (1-gamma)mu_2 + gamma mu_77 -- 2D shape+size\n\t" "85 : |T-|T|/sqrt(2)I|^2 -- 2D shape+orientation\n\t" "98 : (1/tau)|T-I|^2 -- 2D shape+size+orientation\n\t" - "211: (tau-1)^2-tau+sqrt(tau^2) -- 2D untangling\n\t" - "252: 0.5(tau-1)^2/(tau-tau_0) -- 2D untangling\n\t" + // "211: (tau-1)^2-tau+sqrt(tau^2+eps) -- 2D untangling\n\t" + // "252: 0.5(tau-1)^2/(tau-tau_0) -- 2D untangling\n\t" "301: (|T||T^-1|)/3-1 -- 3D shape\n\t" "302: (|T|^2|T^-1|^2)/9-1 -- 3D shape\n\t" "303: (|T|^2)/3*tau^(2/3)-1 -- 3D shape\n\t" + // "311: (tau-1)^2-tau+sqrt(tau^2+eps)-- 3D untangling\n\t" + "313: (|T|^2)(tau-tau0)^(-2/3)/3 -- 3D untangling\n\t" "315: (tau-1)^2 -- 3D size\n\t" "316: 0.5(sqrt(tau)-1/sqrt(tau))^2 -- 3D size\n\t" "321: |T-T^-t|^2 -- 3D shape+size\n\t" - "352: 0.5(tau-1)^2/(tau-tau_0) -- 3D untangling\n\t" + // "352: 0.5(tau-1)^2/(tau-tau_0) -- 3D untangling\n\t" "A-metrics\n\t" "11 : (1/4*alpha)|A-(adjA)^T(W^TW)/omega|^2 -- 2D shape\n\t" "36 : (1/alpha)|A-W|^2 -- 2D shape+size+orientation\n\t" @@ -193,12 +202,17 @@ int main (int argc, char *argv[]) "Maximum number of Newton iterations."); args.AddOption(&solver_rtol, "-rtol", "--newton-rel-tolerance", "Relative tolerance for the Newton solver."); + args.AddOption(&solver_art_type, "-art", "--adaptive-rel-tol", + "Type of adaptive relative linear solver tolerance:\n\t" + "0: None (default)\n\t" + "1: Eisenstat-Walker type 1\n\t" + "2: Eisenstat-Walker type 2"); args.AddOption(&lin_solver, "-ls", "--lin-solver", "Linear solver:\n\t" "0: l1-Jacobi\n\t" "1: CG\n\t" "2: MINRES\n\t" - "3: MINRES + Jacobi preconditioner" + "3: MINRES + Jacobi preconditioner\n\t" "4: MINRES + l1-Jacobi preconditioner"); args.AddOption(&max_lin_iter, "-li", "--lin-iter", "Maximum number of iterations in the linear solve."); @@ -206,7 +220,7 @@ int main (int argc, char *argv[]) "--fix-boundary", "Enable motion along horizontal and vertical boundaries."); args.AddOption(&combomet, "-cmb", "--combo-type", - "Combination of metrics options:" + "Combination of metrics options:\n\t" "0: Use single metric\n\t" "1: Shape + space-dependent size given analytically\n\t" "2: Shape + adapted size given discretely; shared target"); @@ -374,15 +388,17 @@ int main (int argc, char *argv[]) case 80: metric = new TMOP_Metric_080(0.5); break; case 85: metric = new TMOP_Metric_085; break; case 98: metric = new TMOP_Metric_098; break; - case 211: metric = new TMOP_Metric_211; break; - case 252: metric = new TMOP_Metric_252(tauval); break; + // case 211: metric = new TMOP_Metric_211; break; + // case 252: metric = new TMOP_Metric_252(tauval); break; case 301: metric = new TMOP_Metric_301; break; case 302: metric = new TMOP_Metric_302; break; case 303: metric = new TMOP_Metric_303; break; + // case 311: metric = new TMOP_Metric_311; break; + case 313: metric = new TMOP_Metric_313(tauval); break; case 315: metric = new TMOP_Metric_315; break; case 316: metric = new TMOP_Metric_316; break; case 321: metric = new TMOP_Metric_321; break; - case 352: metric = new TMOP_Metric_352(tauval); break; + // case 352: metric = new TMOP_Metric_352(tauval); break; // A-metrics case 11: metric = new TMOP_AMetric_011; break; case 36: metric = new TMOP_AMetric_036; break; @@ -399,7 +415,7 @@ int main (int argc, char *argv[]) ParFiniteElementSpace ind_fes(pmesh, &ind_fec); ParFiniteElementSpace ind_fesv(pmesh, &ind_fec, dim); ParGridFunction size(&ind_fes), aspr(&ind_fes), disc(&ind_fes), ori(&ind_fes); - ParGridFunction aspr3d(&ind_fesv), size3d(&ind_fesv); + ParGridFunction aspr3d(&ind_fesv); switch (target_id) { @@ -437,7 +453,7 @@ int main (int argc, char *argv[]) target_c = tc; break; } - case 6: //material indicator 2D + case 6: // material indicator 2D { ParGridFunction d_x(&ind_fes), d_y(&ind_fes); @@ -457,14 +473,14 @@ int main (int argc, char *argv[]) MFEM_ABORT("MFEM is not built with GSLIB."); #endif } - //Diffuse the interface + // Diffuse the interface DiffuseField(disc,2); - //Get partials with respect to x and y of the grid function + // Get partials with respect to x and y of the grid function disc.GetDerivative(1,0,d_x); disc.GetDerivative(1,1,d_y); - //Compute the squared magnitude of the gradient + // Compute the squared magnitude of the gradient for (int i = 0; i < size.Size(); i++) { size(i) = std::pow(d_x(i),2)+std::pow(d_y(i),2); @@ -727,6 +743,46 @@ int main (int argc, char *argv[]) } else { a.AddDomainIntegrator(he_nlf_integ); } + // Compute the minimum det(J) of the starting mesh. + tauval = infinity(); + const int NE = pmesh->GetNE(); + for (int i = 0; i < NE; i++) + { + const IntegrationRule &ir = + irules->Get(pfespace->GetFE(i)->GetGeomType(), quad_order); + ElementTransformation *transf = pmesh->GetElementTransformation(i); + for (int j = 0; j < ir.GetNPoints(); j++) + { + transf->SetIntPoint(&ir.IntPoint(j)); + tauval = min(tauval, transf->Jacobian().Det()); + } + } + double minJ0; + MPI_Allreduce(&tauval, &minJ0, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD); + tauval = minJ0; + if (myid == 0) + { cout << "Minimum det(J) of the original mesh is " << tauval << endl; } + + if (tauval < 0.0 && metric_id != 22 && metric_id != 211 && metric_id != 252 + && metric_id != 311 && metric_id != 313 && metric_id != 352) + { + MFEM_ABORT("The input mesh is inverted! Try an untangling metric."); + } + if (tauval < 0.0) + { + MFEM_VERIFY(target_t == TargetConstructor::IDEAL_SHAPE_UNIT_SIZE, + "Untangling is supported only for ideal targets."); + + const DenseMatrix &Wideal = + Geometries.GetGeomToPerfGeomJac(pfespace->GetFE(0)->GetGeomType()); + tauval /= Wideal.Det(); + + double h0min = h0.Min(), h0min_all; + MPI_Allreduce(&h0min, &h0min_all, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD); + // Slightly below minJ0 to avoid div by 0. + tauval -= 0.01 * h0min_all; + } + const double init_energy = a.GetParGridFunctionEnergy(x); // Visualize the starting mesh and metric values. @@ -829,29 +885,6 @@ int main (int argc, char *argv[]) S = minres; } - // Compute the minimum det(J) of the starting mesh. - tauval = infinity(); - const int NE = pmesh->GetNE(); - for (int i = 0; i < NE; i++) - { - const IntegrationRule &ir = - irules->Get(pfespace->GetFE(i)->GetGeomType(), quad_order); - ElementTransformation *transf = pmesh->GetElementTransformation(i); - for (int j = 0; j < ir.GetNPoints(); j++) - { - transf->SetIntPoint(&ir.IntPoint(j)); - tauval = min(tauval, transf->Jacobian().Det()); - } - } - double minJ0; - MPI_Allreduce(&tauval, &minJ0, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD); - tauval = minJ0; - if (myid == 0) - { cout << "Minimum det(J) of the original mesh is " << tauval << endl; } - double h0min = h0.Min(), h0min_all; - MPI_Allreduce(&h0min, &h0min_all, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD); - tauval -= 0.01 * h0min_all; // Slightly below minJ0 to avoid div by 0. - // Perform the nonlinear optimization. const IntegrationRule &ir = irules->Get(pfespace->GetFE(0)->GetGeomType(), quad_order); @@ -863,9 +896,15 @@ int main (int argc, char *argv[]) // Specify linear solver when we use a Newton-based solver. solver.SetPreconditioner(*S); } + // For untangling, the solver will update the min det(T) values. + if (tauval < 0.0) { solver.SetMinDetPtr(&tauval); } solver.SetMaxIter(solver_iter); solver.SetRelTol(solver_rtol); solver.SetAbsTol(0.0); + if (solver_art_type > 0) + { + solver.SetAdaptiveLinRtol(solver_art_type, 0.5, 0.9); + } solver.SetPrintLevel(verbosity_level >= 1 ? 1 : -1); solver.SetOperator(a); solver.Mult(b, x.GetTrueVector()); diff --git a/miniapps/meshing/pminimal-surface.cpp b/miniapps/meshing/pminimal-surface.cpp index 28d398dffe..339faeb8b6 100644 --- a/miniapps/meshing/pminimal-surface.cpp +++ b/miniapps/meshing/pminimal-surface.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/meshing/polar-nc.cpp b/miniapps/meshing/polar-nc.cpp index eed6b18a05..c7685c0571 100644 --- a/miniapps/meshing/polar-nc.cpp +++ b/miniapps/meshing/polar-nc.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -199,6 +199,8 @@ Mesh* Make2D(int nsteps, double rstep, double phi, double aspect, int order, mfem::Swap(params, new_params); } + mesh->FinalizeMesh(); + // create high-order curvature if (order > 1) { @@ -240,8 +242,6 @@ Mesh* Make2D(int nsteps, double rstep, double phi, double aspect, int order, nodes->RestrictConforming(); } - mesh->FinalizeMesh(); - return mesh; } diff --git a/miniapps/meshing/shaper.cpp b/miniapps/meshing/shaper.cpp index 0ce19ff4f4..d361580a6a 100644 --- a/miniapps/meshing/shaper.cpp +++ b/miniapps/meshing/shaper.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/meshing/toroid.cpp b/miniapps/meshing/toroid.cpp index a3707c09a2..8a576e481b 100644 --- a/miniapps/meshing/toroid.cpp +++ b/miniapps/meshing/toroid.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/meshing/trimmer.cpp b/miniapps/meshing/trimmer.cpp index 929dea2541..12d02367eb 100644 --- a/miniapps/meshing/trimmer.cpp +++ b/miniapps/meshing/trimmer.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/meshing/twist.cpp b/miniapps/meshing/twist.cpp index 53f389f3d8..e555c59d73 100644 --- a/miniapps/meshing/twist.cpp +++ b/miniapps/meshing/twist.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/navier/CMakeLists.txt b/miniapps/navier/CMakeLists.txt index eff158caf9..b91a024189 100644 --- a/miniapps/navier/CMakeLists.txt +++ b/miniapps/navier/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/miniapps/navier/makefile b/miniapps/navier/makefile index dc94a4b644..9db95ae98e 100644 --- a/miniapps/navier/makefile +++ b/miniapps/navier/makefile @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/miniapps/navier/navier_3dfoc.cpp b/miniapps/navier/navier_3dfoc.cpp index 3983136462..2485218234 100644 --- a/miniapps/navier/navier_3dfoc.cpp +++ b/miniapps/navier/navier_3dfoc.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/navier/navier_kovasznay.cpp b/miniapps/navier/navier_kovasznay.cpp index 4bfc0e8e70..d7b33e3744 100644 --- a/miniapps/navier/navier_kovasznay.cpp +++ b/miniapps/navier/navier_kovasznay.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/navier/navier_kovasznay_vs.cpp b/miniapps/navier/navier_kovasznay_vs.cpp index 526ea23001..82d5f1ad74 100644 --- a/miniapps/navier/navier_kovasznay_vs.cpp +++ b/miniapps/navier/navier_kovasznay_vs.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/navier/navier_mms.cpp b/miniapps/navier/navier_mms.cpp index b3d0ca2612..1313d612b8 100644 --- a/miniapps/navier/navier_mms.cpp +++ b/miniapps/navier/navier_mms.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/navier/navier_shear.cpp b/miniapps/navier/navier_shear.cpp index b82407e5e2..f2c3da6e3c 100644 --- a/miniapps/navier/navier_shear.cpp +++ b/miniapps/navier/navier_shear.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/navier/navier_solver.cpp b/miniapps/navier/navier_solver.cpp index b1f9ec60bf..380b48dd01 100644 --- a/miniapps/navier/navier_solver.cpp +++ b/miniapps/navier/navier_solver.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/navier/navier_solver.hpp b/miniapps/navier/navier_solver.hpp index 5908dd79b0..fed334b3ec 100644 --- a/miniapps/navier/navier_solver.hpp +++ b/miniapps/navier/navier_solver.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/navier/navier_tgv.cpp b/miniapps/navier/navier_tgv.cpp index 9d30dbf255..e0c8d395bd 100644 --- a/miniapps/navier/navier_tgv.cpp +++ b/miniapps/navier/navier_tgv.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/navier/ortho_solver.cpp b/miniapps/navier/ortho_solver.cpp index c5ef79773d..4e0bb724ed 100644 --- a/miniapps/navier/ortho_solver.cpp +++ b/miniapps/navier/ortho_solver.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/navier/ortho_solver.hpp b/miniapps/navier/ortho_solver.hpp index 3445f282eb..66ef135f4e 100644 --- a/miniapps/navier/ortho_solver.hpp +++ b/miniapps/navier/ortho_solver.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/nurbs/CMakeLists.txt b/miniapps/nurbs/CMakeLists.txt index db10809e60..13d3b877b6 100644 --- a/miniapps/nurbs/CMakeLists.txt +++ b/miniapps/nurbs/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/miniapps/nurbs/makefile b/miniapps/nurbs/makefile index 6df631a913..d624f22d7b 100644 --- a/miniapps/nurbs/makefile +++ b/miniapps/nurbs/makefile @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/miniapps/performance/CMakeLists.txt b/miniapps/performance/CMakeLists.txt index 375e6874c5..1d2276591a 100644 --- a/miniapps/performance/CMakeLists.txt +++ b/miniapps/performance/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/miniapps/performance/makefile b/miniapps/performance/makefile index a98d303a6e..c6a2cff0ed 100644 --- a/miniapps/performance/makefile +++ b/miniapps/performance/makefile @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/miniapps/solvers/CMakeLists.txt b/miniapps/solvers/CMakeLists.txt new file mode 100644 index 0000000000..29db4a03fa --- /dev/null +++ b/miniapps/solvers/CMakeLists.txt @@ -0,0 +1,34 @@ +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced +# at the Lawrence Livermore National Laboratory. All Rights reserved. See files +# LICENSE and NOTICE for details. LLNL-CODE-806117. +# +# This file is part of the MFEM library. For more information and source code +# availability visit https://mfem.org. +# +# MFEM is free software; you can redistribute it and/or modify it under the +# terms of the BSD-3 license. We welcome feedback and contributions, see file +# CONTRIBUTING.md for details. + +if (MFEM_USE_MPI) + add_mfem_miniapp(block-solvers + MAIN block-solvers.cpp + EXTRA_SOURCES div_free_solver.cpp + EXTRA_HEADERS div_free_solver.hpp + LIBRARIES mfem) + + # Add the corresponding tests to the "test" target + add_test(NAME block-solvers-constant + COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP} + ${MPIEXEC_PREFLAGS} + $ -r 2 + ${MPIEXEC_POSTFLAGS}) + + add_test(NAME block-solvers-anisotropic + COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP} + ${MPIEXEC_PREFLAGS} + $ -r 2 + -m ${CMAKE_CURRENT_SOURCE_DIR}/anisotropic.mesh + -c ${CMAKE_CURRENT_SOURCE_DIR}/anisotropic.coeff + -eb ${CMAKE_CURRENT_SOURCE_DIR}/anisotropic.brd + ${MPIEXEC_POSTFLAGS}) +endif() diff --git a/miniapps/solvers/README b/miniapps/solvers/README new file mode 100644 index 0000000000..89d4a43b9b --- /dev/null +++ b/miniapps/solvers/README @@ -0,0 +1,63 @@ + Finite Element Discretization Library + __ + _ __ ___ / _| ___ _ __ ___ + | '_ ` _ \ | |_ / _ \| '_ ` _ \ + | | | | | || _|| __/| | | | | | + |_| |_| |_||_| \___||_| |_| |_| + + https://mfem.org + +This directory contains some sophisticated solvers for discrete problems +generated by MFEM. + +# Block Solvers + +The miniapp block-solvers compares the relative performance of some solvers for +the discrete saddle point problems arising from the mixed finite element +discretization of the second order scalar elliptic problem + -div(K grad p) = r.h.s. +The user can customize the problem settings by providing the mesh, the +coefficient K, and the essential/natural boundary assignment. + +The discrete saddle point problem has a block structure of the form + + [ M B^T ] [u] = [g] + [ B 0 ] [p] = [f] + +The solvers for the above block system include: + +1. The divergence free solver (both coupled and decoupled modes). + + The idea of the solver is to exploit a multilevel decomposition of the + Raviart-Thomas finite element space to find a particular flux solution + satisfying the divergence constraint B u_p = f, and then solve the remaining + divergence-free component of the flux u in the kernel space of the discrete + divergence operator B. In our implementation, these two flux components and + the pressure p can be solved one by one, or altogether simultaneously by + switching the flag DFSParameters::coupled_solve (see div_free_solver.hpp). + + The multilevel decompositions of the Raviart-Thomas and discrete L2 space are + given by DFSData, see the documentation in div_free_solver.hpp for more + details. In block-solvers.cpp, the data are generated geometrically through + mesh refinement and collection of "TransferOperators" of the spaces, This + process is done in DFSSpaces. In general, the multilevel decompositions can + also be obtained via element agglomeration (e.g., use ParElag). + + For more details see + + [1] Vassilevski, Multilevel Block Factorization Preconditioners (Appendix F.3), + Springer, 2008. + [2] Voronin, Lee, Neumuller, Sepulveda, Vassilevski, Space-time discretizations + using constrained first-order system least squares (CFOSLS). + J. Comput. Phys. 373: 863-876, 2018. + +2. MINRES preconditioned by a block diagonal preconditioner. + + This solver is the one used in examples/ex5p.cpp. + + First, define the approximate Schur complement S = B diag(M)^{-1} B^T. Then, + BoomerAMG is used as a preconditioner for S, denoted by AMG(S). Lastly, the + block diagonal preconditioner is defined as + + P^{-1} = [ diag(M)^{-1} 0 ] + [ 0 AMG(S) ] diff --git a/miniapps/solvers/anisotropic.bdr b/miniapps/solvers/anisotropic.bdr new file mode 100644 index 0000000000..c33203f592 --- /dev/null +++ b/miniapps/solvers/anisotropic.bdr @@ -0,0 +1,6 @@ +1 +0 +0 +0 +0 +0 diff --git a/miniapps/solvers/anisotropic.coeff b/miniapps/solvers/anisotropic.coeff new file mode 100644 index 0000000000..f4427b6b9b --- /dev/null +++ b/miniapps/solvers/anisotropic.coeff @@ -0,0 +1,792 @@ +0.53954445 +0.22549194 +0.17554043 +0.6232961 +3.9474903 +1.1763994 +0.15953608 +0.5346474 +0.071946426 +0.27618319 +0.038794516 +0.017720945 +0.19547625 +0.018190876 +0.021858425 +0.161226 +0.048233452 +0.01233314 +0.22336696 +0.03152973 +0.021232131 +0.35002676 +0.042366675 +0.078446145 +0.36620758 +0.27147758 +0.19418627 +0.73965438 +0.54985188 +0.27074627 +1.3862306 +0.88329477 +0.31936074 +2.939068 +2.0953586 +2.7368568 +2.7196851 +3.5258893 +2.4651934 +2.2427343 +2.7182976 +2.4672844 +2.2825311 +2.3145863 +3.5044815 +1.7006244 +2.2728067 +2.9676209 +1.7263386 +1.6462535 +2.6058082 +1.6365185 +1.7139727 +2.0046933 +2.5237373 +0.84184899 +2.0749918 +2.2474833 +0.95478537 +2.2096613 +2.3227044 +1.645756 +1.1308406 +2.4515956 +0.97820338 +0.99361217 +7.8678373 +3.1214309 +5.2644737 +7.0903641 +2.7940164 +4.9682181 +5.0132344 +3.8190848 +6.0428335 +4.5215501 +5.3877717 +6.9237266 +4.5631432 +7.3344965 +8.462099 +3.2977914 +5.2426195 +7.2704055 +4.0367975 +7.3312697 +4.9674207 +4.8237107 +6.5163739 +5.4707154 +4.1281359 +4.7580322 +6.1769918 +7.2189443 +6.7831436 +4.9782971 +8.1194053 +8.1574352 +4.8431305 +3.7883644 +6.3571902 +9.7484291 +6.9858721 +3.6616675 +7.2037676 +7.4467355 +2.7823033 +8.0763336 +5.9955004 +2.068472 +8.6997547 +6.4947084 +1.9626231 +4.7956748 +6.9883741 +2.832308 +4.3139989 +9.4575043 +3.4930932 +3.5119429 +9.5733924 +3.6507549 +3.6460211 +11.090327 +5.8209888 +4.1140307 +12.497609 +8.3156252 +2.5856916 +7.8455832 +4.3452395 +2.7036047 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 diff --git a/miniapps/solvers/anisotropic.mesh b/miniapps/solvers/anisotropic.mesh new file mode 100644 index 0000000000..1901104560 --- /dev/null +++ b/miniapps/solvers/anisotropic.mesh @@ -0,0 +1,1414 @@ +MFEM mesh v1.0 + +# +# MFEM Geometry Types (see mesh/geom.hpp): +# +# POINT = 0 +# SEGMENT = 1 +# TRIANGLE = 2 +# SQUARE = 3 +# TETRAHEDRON = 4 +# CUBE = 5 +# PRISM = 6 +# + +dimension +3 + +elements +792 +1 4 53 0 5 1 +1 4 53 0 1 49 +1 4 53 0 49 48 +1 4 53 0 4 5 +1 4 53 0 52 4 +1 4 53 0 48 52 +2 4 54 1 6 2 +2 4 54 1 2 50 +2 4 54 1 50 49 +2 4 54 1 5 6 +2 4 54 1 53 5 +2 4 54 1 49 53 +3 4 55 2 7 3 +3 4 55 2 3 51 +3 4 55 2 51 50 +3 4 55 2 6 7 +3 4 55 2 54 6 +3 4 55 2 50 54 +4 4 57 4 9 5 +4 4 57 4 5 53 +4 4 57 4 53 52 +4 4 57 4 8 9 +4 4 57 4 56 8 +4 4 57 4 52 56 +5 4 58 5 10 6 +5 4 58 5 6 54 +5 4 58 5 54 53 +5 4 58 5 9 10 +5 4 58 5 57 9 +5 4 58 5 53 57 +6 4 59 6 11 7 +6 4 59 6 7 55 +6 4 59 6 55 54 +6 4 59 6 10 11 +6 4 59 6 58 10 +6 4 59 6 54 58 +7 4 61 8 13 9 +7 4 61 8 9 57 +7 4 61 8 57 56 +7 4 61 8 12 13 +7 4 61 8 60 12 +7 4 61 8 56 60 +8 4 62 9 14 10 +8 4 62 9 10 58 +8 4 62 9 58 57 +8 4 62 9 13 14 +8 4 62 9 61 13 +8 4 62 9 57 61 +9 4 63 10 15 11 +9 4 63 10 11 59 +9 4 63 10 59 58 +9 4 63 10 14 15 +9 4 63 10 62 14 +9 4 63 10 58 62 +10 4 65 12 17 13 +10 4 65 12 13 61 +10 4 65 12 61 60 +10 4 65 12 16 17 +10 4 65 12 64 16 +10 4 65 12 60 64 +11 4 66 13 18 14 +11 4 66 13 14 62 +11 4 66 13 62 61 +11 4 66 13 17 18 +11 4 66 13 65 17 +11 4 66 13 61 65 +12 4 67 14 19 15 +12 4 67 14 15 63 +12 4 67 14 63 62 +12 4 67 14 18 19 +12 4 67 14 66 18 +12 4 67 14 62 66 +13 4 69 16 21 17 +13 4 69 16 17 65 +13 4 69 16 65 64 +13 4 69 16 20 21 +13 4 69 16 68 20 +13 4 69 16 64 68 +14 4 70 17 22 18 +14 4 70 17 18 66 +14 4 70 17 66 65 +14 4 70 17 21 22 +14 4 70 17 69 21 +14 4 70 17 65 69 +15 4 71 18 23 19 +15 4 71 18 19 67 +15 4 71 18 67 66 +15 4 71 18 22 23 +15 4 71 18 70 22 +15 4 71 18 66 70 +16 4 73 20 25 21 +16 4 73 20 21 69 +16 4 73 20 69 68 +16 4 73 20 24 25 +16 4 73 20 72 24 +16 4 73 20 68 72 +17 4 74 21 26 22 +17 4 74 21 22 70 +17 4 74 21 70 69 +17 4 74 21 25 26 +17 4 74 21 73 25 +17 4 74 21 69 73 +18 4 75 22 27 23 +18 4 75 22 23 71 +18 4 75 22 71 70 +18 4 75 22 26 27 +18 4 75 22 74 26 +18 4 75 22 70 74 +19 4 77 24 29 25 +19 4 77 24 25 73 +19 4 77 24 73 72 +19 4 77 24 28 29 +19 4 77 24 76 28 +19 4 77 24 72 76 +20 4 78 25 30 26 +20 4 78 25 26 74 +20 4 78 25 74 73 +20 4 78 25 29 30 +20 4 78 25 77 29 +20 4 78 25 73 77 +21 4 79 26 31 27 +21 4 79 26 27 75 +21 4 79 26 75 74 +21 4 79 26 30 31 +21 4 79 26 78 30 +21 4 79 26 74 78 +22 4 81 28 33 29 +22 4 81 28 29 77 +22 4 81 28 77 76 +22 4 81 28 32 33 +22 4 81 28 80 32 +22 4 81 28 76 80 +23 4 82 29 34 30 +23 4 82 29 30 78 +23 4 82 29 78 77 +23 4 82 29 33 34 +23 4 82 29 81 33 +23 4 82 29 77 81 +24 4 83 30 35 31 +24 4 83 30 31 79 +24 4 83 30 79 78 +24 4 83 30 34 35 +24 4 83 30 82 34 +24 4 83 30 78 82 +25 4 85 32 37 33 +25 4 85 32 33 81 +25 4 85 32 81 80 +25 4 85 32 36 37 +25 4 85 32 84 36 +25 4 85 32 80 84 +26 4 86 33 38 34 +26 4 86 33 34 82 +26 4 86 33 82 81 +26 4 86 33 37 38 +26 4 86 33 85 37 +26 4 86 33 81 85 +27 4 87 34 39 35 +27 4 87 34 35 83 +27 4 87 34 83 82 +27 4 87 34 38 39 +27 4 87 34 86 38 +27 4 87 34 82 86 +28 4 89 36 41 37 +28 4 89 36 37 85 +28 4 89 36 85 84 +28 4 89 36 40 41 +28 4 89 36 88 40 +28 4 89 36 84 88 +29 4 90 37 42 38 +29 4 90 37 38 86 +29 4 90 37 86 85 +29 4 90 37 41 42 +29 4 90 37 89 41 +29 4 90 37 85 89 +30 4 91 38 43 39 +30 4 91 38 39 87 +30 4 91 38 87 86 +30 4 91 38 42 43 +30 4 91 38 90 42 +30 4 91 38 86 90 +31 4 93 40 45 41 +31 4 93 40 41 89 +31 4 93 40 89 88 +31 4 93 40 44 45 +31 4 93 40 92 44 +31 4 93 40 88 92 +32 4 94 41 46 42 +32 4 94 41 42 90 +32 4 94 41 90 89 +32 4 94 41 45 46 +32 4 94 41 93 45 +32 4 94 41 89 93 +33 4 95 42 47 43 +33 4 95 42 43 91 +33 4 95 42 91 90 +33 4 95 42 46 47 +33 4 95 42 94 46 +33 4 95 42 90 94 +34 4 101 48 53 49 +34 4 101 48 49 97 +34 4 101 48 97 96 +34 4 101 48 52 53 +34 4 101 48 100 52 +34 4 101 48 96 100 +35 4 102 49 54 50 +35 4 102 49 50 98 +35 4 102 49 98 97 +35 4 102 49 53 54 +35 4 102 49 101 53 +35 4 102 49 97 101 +36 4 103 50 55 51 +36 4 103 50 51 99 +36 4 103 50 99 98 +36 4 103 50 54 55 +36 4 103 50 102 54 +36 4 103 50 98 102 +37 4 105 52 57 53 +37 4 105 52 53 101 +37 4 105 52 101 100 +37 4 105 52 56 57 +37 4 105 52 104 56 +37 4 105 52 100 104 +38 4 106 53 58 54 +38 4 106 53 54 102 +38 4 106 53 102 101 +38 4 106 53 57 58 +38 4 106 53 105 57 +38 4 106 53 101 105 +39 4 107 54 59 55 +39 4 107 54 55 103 +39 4 107 54 103 102 +39 4 107 54 58 59 +39 4 107 54 106 58 +39 4 107 54 102 106 +40 4 109 56 61 57 +40 4 109 56 57 105 +40 4 109 56 105 104 +40 4 109 56 60 61 +40 4 109 56 108 60 +40 4 109 56 104 108 +41 4 110 57 62 58 +41 4 110 57 58 106 +41 4 110 57 106 105 +41 4 110 57 61 62 +41 4 110 57 109 61 +41 4 110 57 105 109 +42 4 111 58 63 59 +42 4 111 58 59 107 +42 4 111 58 107 106 +42 4 111 58 62 63 +42 4 111 58 110 62 +42 4 111 58 106 110 +43 4 113 60 65 61 +43 4 113 60 61 109 +43 4 113 60 109 108 +43 4 113 60 64 65 +43 4 113 60 112 64 +43 4 113 60 108 112 +44 4 114 61 66 62 +44 4 114 61 62 110 +44 4 114 61 110 109 +44 4 114 61 65 66 +44 4 114 61 113 65 +44 4 114 61 109 113 +45 4 115 62 67 63 +45 4 115 62 63 111 +45 4 115 62 111 110 +45 4 115 62 66 67 +45 4 115 62 114 66 +45 4 115 62 110 114 +46 4 117 64 69 65 +46 4 117 64 65 113 +46 4 117 64 113 112 +46 4 117 64 68 69 +46 4 117 64 116 68 +46 4 117 64 112 116 +47 4 118 65 70 66 +47 4 118 65 66 114 +47 4 118 65 114 113 +47 4 118 65 69 70 +47 4 118 65 117 69 +47 4 118 65 113 117 +48 4 119 66 71 67 +48 4 119 66 67 115 +48 4 119 66 115 114 +48 4 119 66 70 71 +48 4 119 66 118 70 +48 4 119 66 114 118 +49 4 121 68 73 69 +49 4 121 68 69 117 +49 4 121 68 117 116 +49 4 121 68 72 73 +49 4 121 68 120 72 +49 4 121 68 116 120 +50 4 122 69 74 70 +50 4 122 69 70 118 +50 4 122 69 118 117 +50 4 122 69 73 74 +50 4 122 69 121 73 +50 4 122 69 117 121 +51 4 123 70 75 71 +51 4 123 70 71 119 +51 4 123 70 119 118 +51 4 123 70 74 75 +51 4 123 70 122 74 +51 4 123 70 118 122 +52 4 125 72 77 73 +52 4 125 72 73 121 +52 4 125 72 121 120 +52 4 125 72 76 77 +52 4 125 72 124 76 +52 4 125 72 120 124 +53 4 126 73 78 74 +53 4 126 73 74 122 +53 4 126 73 122 121 +53 4 126 73 77 78 +53 4 126 73 125 77 +53 4 126 73 121 125 +54 4 127 74 79 75 +54 4 127 74 75 123 +54 4 127 74 123 122 +54 4 127 74 78 79 +54 4 127 74 126 78 +54 4 127 74 122 126 +55 4 129 76 81 77 +55 4 129 76 77 125 +55 4 129 76 125 124 +55 4 129 76 80 81 +55 4 129 76 128 80 +55 4 129 76 124 128 +56 4 130 77 82 78 +56 4 130 77 78 126 +56 4 130 77 126 125 +56 4 130 77 81 82 +56 4 130 77 129 81 +56 4 130 77 125 129 +57 4 131 78 83 79 +57 4 131 78 79 127 +57 4 131 78 127 126 +57 4 131 78 82 83 +57 4 131 78 130 82 +57 4 131 78 126 130 +58 4 133 80 85 81 +58 4 133 80 81 129 +58 4 133 80 129 128 +58 4 133 80 84 85 +58 4 133 80 132 84 +58 4 133 80 128 132 +59 4 134 81 86 82 +59 4 134 81 82 130 +59 4 134 81 130 129 +59 4 134 81 85 86 +59 4 134 81 133 85 +59 4 134 81 129 133 +60 4 135 82 87 83 +60 4 135 82 83 131 +60 4 135 82 131 130 +60 4 135 82 86 87 +60 4 135 82 134 86 +60 4 135 82 130 134 +61 4 137 84 89 85 +61 4 137 84 85 133 +61 4 137 84 133 132 +61 4 137 84 88 89 +61 4 137 84 136 88 +61 4 137 84 132 136 +62 4 138 85 90 86 +62 4 138 85 86 134 +62 4 138 85 134 133 +62 4 138 85 89 90 +62 4 138 85 137 89 +62 4 138 85 133 137 +63 4 139 86 91 87 +63 4 139 86 87 135 +63 4 139 86 135 134 +63 4 139 86 90 91 +63 4 139 86 138 90 +63 4 139 86 134 138 +64 4 141 88 93 89 +64 4 141 88 89 137 +64 4 141 88 137 136 +64 4 141 88 92 93 +64 4 141 88 140 92 +64 4 141 88 136 140 +65 4 142 89 94 90 +65 4 142 89 90 138 +65 4 142 89 138 137 +65 4 142 89 93 94 +65 4 142 89 141 93 +65 4 142 89 137 141 +66 4 143 90 95 91 +66 4 143 90 91 139 +66 4 143 90 139 138 +66 4 143 90 94 95 +66 4 143 90 142 94 +66 4 143 90 138 142 +67 4 149 96 101 97 +67 4 149 96 97 145 +67 4 149 96 145 144 +67 4 149 96 100 101 +67 4 149 96 148 100 +67 4 149 96 144 148 +68 4 150 97 102 98 +68 4 150 97 98 146 +68 4 150 97 146 145 +68 4 150 97 101 102 +68 4 150 97 149 101 +68 4 150 97 145 149 +69 4 151 98 103 99 +69 4 151 98 99 147 +69 4 151 98 147 146 +69 4 151 98 102 103 +69 4 151 98 150 102 +69 4 151 98 146 150 +70 4 153 100 105 101 +70 4 153 100 101 149 +70 4 153 100 149 148 +70 4 153 100 104 105 +70 4 153 100 152 104 +70 4 153 100 148 152 +71 4 154 101 106 102 +71 4 154 101 102 150 +71 4 154 101 150 149 +71 4 154 101 105 106 +71 4 154 101 153 105 +71 4 154 101 149 153 +72 4 155 102 107 103 +72 4 155 102 103 151 +72 4 155 102 151 150 +72 4 155 102 106 107 +72 4 155 102 154 106 +72 4 155 102 150 154 +73 4 157 104 109 105 +73 4 157 104 105 153 +73 4 157 104 153 152 +73 4 157 104 108 109 +73 4 157 104 156 108 +73 4 157 104 152 156 +74 4 158 105 110 106 +74 4 158 105 106 154 +74 4 158 105 154 153 +74 4 158 105 109 110 +74 4 158 105 157 109 +74 4 158 105 153 157 +75 4 159 106 111 107 +75 4 159 106 107 155 +75 4 159 106 155 154 +75 4 159 106 110 111 +75 4 159 106 158 110 +75 4 159 106 154 158 +76 4 161 108 113 109 +76 4 161 108 109 157 +76 4 161 108 157 156 +76 4 161 108 112 113 +76 4 161 108 160 112 +76 4 161 108 156 160 +77 4 162 109 114 110 +77 4 162 109 110 158 +77 4 162 109 158 157 +77 4 162 109 113 114 +77 4 162 109 161 113 +77 4 162 109 157 161 +78 4 163 110 115 111 +78 4 163 110 111 159 +78 4 163 110 159 158 +78 4 163 110 114 115 +78 4 163 110 162 114 +78 4 163 110 158 162 +79 4 165 112 117 113 +79 4 165 112 113 161 +79 4 165 112 161 160 +79 4 165 112 116 117 +79 4 165 112 164 116 +79 4 165 112 160 164 +80 4 166 113 118 114 +80 4 166 113 114 162 +80 4 166 113 162 161 +80 4 166 113 117 118 +80 4 166 113 165 117 +80 4 166 113 161 165 +81 4 167 114 119 115 +81 4 167 114 115 163 +81 4 167 114 163 162 +81 4 167 114 118 119 +81 4 167 114 166 118 +81 4 167 114 162 166 +82 4 169 116 121 117 +82 4 169 116 117 165 +82 4 169 116 165 164 +82 4 169 116 120 121 +82 4 169 116 168 120 +82 4 169 116 164 168 +83 4 170 117 122 118 +83 4 170 117 118 166 +83 4 170 117 166 165 +83 4 170 117 121 122 +83 4 170 117 169 121 +83 4 170 117 165 169 +84 4 171 118 123 119 +84 4 171 118 119 167 +84 4 171 118 167 166 +84 4 171 118 122 123 +84 4 171 118 170 122 +84 4 171 118 166 170 +85 4 173 120 125 121 +85 4 173 120 121 169 +85 4 173 120 169 168 +85 4 173 120 124 125 +85 4 173 120 172 124 +85 4 173 120 168 172 +86 4 174 121 126 122 +86 4 174 121 122 170 +86 4 174 121 170 169 +86 4 174 121 125 126 +86 4 174 121 173 125 +86 4 174 121 169 173 +87 4 175 122 127 123 +87 4 175 122 123 171 +87 4 175 122 171 170 +87 4 175 122 126 127 +87 4 175 122 174 126 +87 4 175 122 170 174 +88 4 177 124 129 125 +88 4 177 124 125 173 +88 4 177 124 173 172 +88 4 177 124 128 129 +88 4 177 124 176 128 +88 4 177 124 172 176 +89 4 178 125 130 126 +89 4 178 125 126 174 +89 4 178 125 174 173 +89 4 178 125 129 130 +89 4 178 125 177 129 +89 4 178 125 173 177 +90 4 179 126 131 127 +90 4 179 126 127 175 +90 4 179 126 175 174 +90 4 179 126 130 131 +90 4 179 126 178 130 +90 4 179 126 174 178 +91 4 181 128 133 129 +91 4 181 128 129 177 +91 4 181 128 177 176 +91 4 181 128 132 133 +91 4 181 128 180 132 +91 4 181 128 176 180 +92 4 182 129 134 130 +92 4 182 129 130 178 +92 4 182 129 178 177 +92 4 182 129 133 134 +92 4 182 129 181 133 +92 4 182 129 177 181 +93 4 183 130 135 131 +93 4 183 130 131 179 +93 4 183 130 179 178 +93 4 183 130 134 135 +93 4 183 130 182 134 +93 4 183 130 178 182 +94 4 185 132 137 133 +94 4 185 132 133 181 +94 4 185 132 181 180 +94 4 185 132 136 137 +94 4 185 132 184 136 +94 4 185 132 180 184 +95 4 186 133 138 134 +95 4 186 133 134 182 +95 4 186 133 182 181 +95 4 186 133 137 138 +95 4 186 133 185 137 +95 4 186 133 181 185 +96 4 187 134 139 135 +96 4 187 134 135 183 +96 4 187 134 183 182 +96 4 187 134 138 139 +96 4 187 134 186 138 +96 4 187 134 182 186 +97 4 189 136 141 137 +97 4 189 136 137 185 +97 4 189 136 185 184 +97 4 189 136 140 141 +97 4 189 136 188 140 +97 4 189 136 184 188 +98 4 190 137 142 138 +98 4 190 137 138 186 +98 4 190 137 186 185 +98 4 190 137 141 142 +98 4 190 137 189 141 +98 4 190 137 185 189 +99 4 191 138 143 139 +99 4 191 138 139 187 +99 4 191 138 187 186 +99 4 191 138 142 143 +99 4 191 138 190 142 +99 4 191 138 186 190 +100 4 197 144 149 145 +100 4 197 144 145 193 +100 4 197 144 193 192 +100 4 197 144 148 149 +100 4 197 144 196 148 +100 4 197 144 192 196 +101 4 198 145 150 146 +101 4 198 145 146 194 +101 4 198 145 194 193 +101 4 198 145 149 150 +101 4 198 145 197 149 +101 4 198 145 193 197 +102 4 199 146 151 147 +102 4 199 146 147 195 +102 4 199 146 195 194 +102 4 199 146 150 151 +102 4 199 146 198 150 +102 4 199 146 194 198 +103 4 201 148 153 149 +103 4 201 148 149 197 +103 4 201 148 197 196 +103 4 201 148 152 153 +103 4 201 148 200 152 +103 4 201 148 196 200 +104 4 202 149 154 150 +104 4 202 149 150 198 +104 4 202 149 198 197 +104 4 202 149 153 154 +104 4 202 149 201 153 +104 4 202 149 197 201 +105 4 203 150 155 151 +105 4 203 150 151 199 +105 4 203 150 199 198 +105 4 203 150 154 155 +105 4 203 150 202 154 +105 4 203 150 198 202 +106 4 205 152 157 153 +106 4 205 152 153 201 +106 4 205 152 201 200 +106 4 205 152 156 157 +106 4 205 152 204 156 +106 4 205 152 200 204 +107 4 206 153 158 154 +107 4 206 153 154 202 +107 4 206 153 202 201 +107 4 206 153 157 158 +107 4 206 153 205 157 +107 4 206 153 201 205 +108 4 207 154 159 155 +108 4 207 154 155 203 +108 4 207 154 203 202 +108 4 207 154 158 159 +108 4 207 154 206 158 +108 4 207 154 202 206 +109 4 209 156 161 157 +109 4 209 156 157 205 +109 4 209 156 205 204 +109 4 209 156 160 161 +109 4 209 156 208 160 +109 4 209 156 204 208 +110 4 210 157 162 158 +110 4 210 157 158 206 +110 4 210 157 206 205 +110 4 210 157 161 162 +110 4 210 157 209 161 +110 4 210 157 205 209 +111 4 211 158 163 159 +111 4 211 158 159 207 +111 4 211 158 207 206 +111 4 211 158 162 163 +111 4 211 158 210 162 +111 4 211 158 206 210 +112 4 213 160 165 161 +112 4 213 160 161 209 +112 4 213 160 209 208 +112 4 213 160 164 165 +112 4 213 160 212 164 +112 4 213 160 208 212 +113 4 214 161 166 162 +113 4 214 161 162 210 +113 4 214 161 210 209 +113 4 214 161 165 166 +113 4 214 161 213 165 +113 4 214 161 209 213 +114 4 215 162 167 163 +114 4 215 162 163 211 +114 4 215 162 211 210 +114 4 215 162 166 167 +114 4 215 162 214 166 +114 4 215 162 210 214 +115 4 217 164 169 165 +115 4 217 164 165 213 +115 4 217 164 213 212 +115 4 217 164 168 169 +115 4 217 164 216 168 +115 4 217 164 212 216 +116 4 218 165 170 166 +116 4 218 165 166 214 +116 4 218 165 214 213 +116 4 218 165 169 170 +116 4 218 165 217 169 +116 4 218 165 213 217 +117 4 219 166 171 167 +117 4 219 166 167 215 +117 4 219 166 215 214 +117 4 219 166 170 171 +117 4 219 166 218 170 +117 4 219 166 214 218 +118 4 221 168 173 169 +118 4 221 168 169 217 +118 4 221 168 217 216 +118 4 221 168 172 173 +118 4 221 168 220 172 +118 4 221 168 216 220 +119 4 222 169 174 170 +119 4 222 169 170 218 +119 4 222 169 218 217 +119 4 222 169 173 174 +119 4 222 169 221 173 +119 4 222 169 217 221 +120 4 223 170 175 171 +120 4 223 170 171 219 +120 4 223 170 219 218 +120 4 223 170 174 175 +120 4 223 170 222 174 +120 4 223 170 218 222 +121 4 225 172 177 173 +121 4 225 172 173 221 +121 4 225 172 221 220 +121 4 225 172 176 177 +121 4 225 172 224 176 +121 4 225 172 220 224 +122 4 226 173 178 174 +122 4 226 173 174 222 +122 4 226 173 222 221 +122 4 226 173 177 178 +122 4 226 173 225 177 +122 4 226 173 221 225 +123 4 227 174 179 175 +123 4 227 174 175 223 +123 4 227 174 223 222 +123 4 227 174 178 179 +123 4 227 174 226 178 +123 4 227 174 222 226 +124 4 229 176 181 177 +124 4 229 176 177 225 +124 4 229 176 225 224 +124 4 229 176 180 181 +124 4 229 176 228 180 +124 4 229 176 224 228 +125 4 230 177 182 178 +125 4 230 177 178 226 +125 4 230 177 226 225 +125 4 230 177 181 182 +125 4 230 177 229 181 +125 4 230 177 225 229 +126 4 231 178 183 179 +126 4 231 178 179 227 +126 4 231 178 227 226 +126 4 231 178 182 183 +126 4 231 178 230 182 +126 4 231 178 226 230 +127 4 233 180 185 181 +127 4 233 180 181 229 +127 4 233 180 229 228 +127 4 233 180 184 185 +127 4 233 180 232 184 +127 4 233 180 228 232 +128 4 234 181 186 182 +128 4 234 181 182 230 +128 4 234 181 230 229 +128 4 234 181 185 186 +128 4 234 181 233 185 +128 4 234 181 229 233 +129 4 235 182 187 183 +129 4 235 182 183 231 +129 4 235 182 231 230 +129 4 235 182 186 187 +129 4 235 182 234 186 +129 4 235 182 230 234 +130 4 237 184 189 185 +130 4 237 184 185 233 +130 4 237 184 233 232 +130 4 237 184 188 189 +130 4 237 184 236 188 +130 4 237 184 232 236 +131 4 238 185 190 186 +131 4 238 185 186 234 +131 4 238 185 234 233 +131 4 238 185 189 190 +131 4 238 185 237 189 +131 4 238 185 233 237 +132 4 239 186 191 187 +132 4 239 186 187 235 +132 4 239 186 235 234 +132 4 239 186 190 191 +132 4 239 186 238 190 +132 4 239 186 234 238 + +boundary +356 +1 2 5 0 4 +1 2 0 5 1 +1 2 6 1 5 +1 2 1 6 2 +1 2 7 2 6 +1 2 2 7 3 +1 2 9 4 8 +1 2 4 9 5 +1 2 10 5 9 +1 2 5 10 6 +1 2 11 6 10 +1 2 6 11 7 +1 2 13 8 12 +1 2 8 13 9 +1 2 14 9 13 +1 2 9 14 10 +1 2 15 10 14 +1 2 10 15 11 +1 2 17 12 16 +1 2 12 17 13 +1 2 18 13 17 +1 2 13 18 14 +1 2 19 14 18 +1 2 14 19 15 +1 2 21 16 20 +1 2 16 21 17 +1 2 22 17 21 +1 2 17 22 18 +1 2 23 18 22 +1 2 18 23 19 +1 2 25 20 24 +1 2 20 25 21 +1 2 26 21 25 +1 2 21 26 22 +1 2 27 22 26 +1 2 22 27 23 +1 2 29 24 28 +1 2 24 29 25 +1 2 30 25 29 +1 2 25 30 26 +1 2 31 26 30 +1 2 26 31 27 +1 2 33 28 32 +1 2 28 33 29 +1 2 34 29 33 +1 2 29 34 30 +1 2 35 30 34 +1 2 30 35 31 +1 2 37 32 36 +1 2 32 37 33 +1 2 38 33 37 +1 2 33 38 34 +1 2 39 34 38 +1 2 34 39 35 +1 2 41 36 40 +1 2 36 41 37 +1 2 42 37 41 +1 2 37 42 38 +1 2 43 38 42 +1 2 38 43 39 +1 2 45 40 44 +1 2 40 45 41 +1 2 46 41 45 +1 2 41 46 42 +1 2 47 42 46 +1 2 42 47 43 +6 2 197 192 193 +6 2 192 197 196 +6 2 198 193 194 +6 2 193 198 197 +6 2 199 194 195 +6 2 194 199 198 +6 2 201 196 197 +6 2 196 201 200 +6 2 202 197 198 +6 2 197 202 201 +6 2 203 198 199 +6 2 198 203 202 +6 2 205 200 201 +6 2 200 205 204 +6 2 206 201 202 +6 2 201 206 205 +6 2 207 202 203 +6 2 202 207 206 +6 2 209 204 205 +6 2 204 209 208 +6 2 210 205 206 +6 2 205 210 209 +6 2 211 206 207 +6 2 206 211 210 +6 2 213 208 209 +6 2 208 213 212 +6 2 214 209 210 +6 2 209 214 213 +6 2 215 210 211 +6 2 210 215 214 +6 2 217 212 213 +6 2 212 217 216 +6 2 218 213 214 +6 2 213 218 217 +6 2 219 214 215 +6 2 214 219 218 +6 2 221 216 217 +6 2 216 221 220 +6 2 222 217 218 +6 2 217 222 221 +6 2 223 218 219 +6 2 218 223 222 +6 2 225 220 221 +6 2 220 225 224 +6 2 226 221 222 +6 2 221 226 225 +6 2 227 222 223 +6 2 222 227 226 +6 2 229 224 225 +6 2 224 229 228 +6 2 230 225 226 +6 2 225 230 229 +6 2 231 226 227 +6 2 226 231 230 +6 2 233 228 229 +6 2 228 233 232 +6 2 234 229 230 +6 2 229 234 233 +6 2 235 230 231 +6 2 230 235 234 +6 2 237 232 233 +6 2 232 237 236 +6 2 238 233 234 +6 2 233 238 237 +6 2 239 234 235 +6 2 234 239 238 +5 2 52 0 48 +5 2 0 52 4 +5 2 56 4 52 +5 2 4 56 8 +5 2 60 8 56 +5 2 8 60 12 +5 2 64 12 60 +5 2 12 64 16 +5 2 68 16 64 +5 2 16 68 20 +5 2 72 20 68 +5 2 20 72 24 +5 2 76 24 72 +5 2 24 76 28 +5 2 80 28 76 +5 2 28 80 32 +5 2 84 32 80 +5 2 32 84 36 +5 2 88 36 84 +5 2 36 88 40 +5 2 92 40 88 +5 2 40 92 44 +5 2 100 48 96 +5 2 48 100 52 +5 2 104 52 100 +5 2 52 104 56 +5 2 108 56 104 +5 2 56 108 60 +5 2 112 60 108 +5 2 60 112 64 +5 2 116 64 112 +5 2 64 116 68 +5 2 120 68 116 +5 2 68 120 72 +5 2 124 72 120 +5 2 72 124 76 +5 2 128 76 124 +5 2 76 128 80 +5 2 132 80 128 +5 2 80 132 84 +5 2 136 84 132 +5 2 84 136 88 +5 2 140 88 136 +5 2 88 140 92 +5 2 148 96 144 +5 2 96 148 100 +5 2 152 100 148 +5 2 100 152 104 +5 2 156 104 152 +5 2 104 156 108 +5 2 160 108 156 +5 2 108 160 112 +5 2 164 112 160 +5 2 112 164 116 +5 2 168 116 164 +5 2 116 168 120 +5 2 172 120 168 +5 2 120 172 124 +5 2 176 124 172 +5 2 124 176 128 +5 2 180 128 176 +5 2 128 180 132 +5 2 184 132 180 +5 2 132 184 136 +5 2 188 136 184 +5 2 136 188 140 +5 2 196 144 192 +5 2 144 196 148 +5 2 200 148 196 +5 2 148 200 152 +5 2 204 152 200 +5 2 152 204 156 +5 2 208 156 204 +5 2 156 208 160 +5 2 212 160 208 +5 2 160 212 164 +5 2 216 164 212 +5 2 164 216 168 +5 2 220 168 216 +5 2 168 220 172 +5 2 224 172 220 +5 2 172 224 176 +5 2 228 176 224 +5 2 176 228 180 +5 2 232 180 228 +5 2 180 232 184 +5 2 236 184 232 +5 2 184 236 188 +3 2 55 3 7 +3 2 3 55 51 +3 2 59 7 11 +3 2 7 59 55 +3 2 63 11 15 +3 2 11 63 59 +3 2 67 15 19 +3 2 15 67 63 +3 2 71 19 23 +3 2 19 71 67 +3 2 75 23 27 +3 2 23 75 71 +3 2 79 27 31 +3 2 27 79 75 +3 2 83 31 35 +3 2 31 83 79 +3 2 87 35 39 +3 2 35 87 83 +3 2 91 39 43 +3 2 39 91 87 +3 2 95 43 47 +3 2 43 95 91 +3 2 103 51 55 +3 2 51 103 99 +3 2 107 55 59 +3 2 55 107 103 +3 2 111 59 63 +3 2 59 111 107 +3 2 115 63 67 +3 2 63 115 111 +3 2 119 67 71 +3 2 67 119 115 +3 2 123 71 75 +3 2 71 123 119 +3 2 127 75 79 +3 2 75 127 123 +3 2 131 79 83 +3 2 79 131 127 +3 2 135 83 87 +3 2 83 135 131 +3 2 139 87 91 +3 2 87 139 135 +3 2 143 91 95 +3 2 91 143 139 +3 2 151 99 103 +3 2 99 151 147 +3 2 155 103 107 +3 2 103 155 151 +3 2 159 107 111 +3 2 107 159 155 +3 2 163 111 115 +3 2 111 163 159 +3 2 167 115 119 +3 2 115 167 163 +3 2 171 119 123 +3 2 119 171 167 +3 2 175 123 127 +3 2 123 175 171 +3 2 179 127 131 +3 2 127 179 175 +3 2 183 131 135 +3 2 131 183 179 +3 2 187 135 139 +3 2 135 187 183 +3 2 191 139 143 +3 2 139 191 187 +3 2 199 147 151 +3 2 147 199 195 +3 2 203 151 155 +3 2 151 203 199 +3 2 207 155 159 +3 2 155 207 203 +3 2 211 159 163 +3 2 159 211 207 +3 2 215 163 167 +3 2 163 215 211 +3 2 219 167 171 +3 2 167 219 215 +3 2 223 171 175 +3 2 171 223 219 +3 2 227 175 179 +3 2 175 227 223 +3 2 231 179 183 +3 2 179 231 227 +3 2 235 183 187 +3 2 183 235 231 +3 2 239 187 191 +3 2 187 239 235 +2 2 49 0 1 +2 2 0 49 48 +2 2 97 48 49 +2 2 48 97 96 +2 2 145 96 97 +2 2 96 145 144 +2 2 193 144 145 +2 2 144 193 192 +2 2 50 1 2 +2 2 1 50 49 +2 2 98 49 50 +2 2 49 98 97 +2 2 146 97 98 +2 2 97 146 145 +2 2 194 145 146 +2 2 145 194 193 +2 2 51 2 3 +2 2 2 51 50 +2 2 99 50 51 +2 2 50 99 98 +2 2 147 98 99 +2 2 98 147 146 +2 2 195 146 147 +2 2 146 195 194 +4 2 93 44 92 +4 2 44 93 45 +4 2 141 92 140 +4 2 92 141 93 +4 2 189 140 188 +4 2 140 189 141 +4 2 237 188 236 +4 2 188 237 189 +4 2 94 45 93 +4 2 45 94 46 +4 2 142 93 141 +4 2 93 142 94 +4 2 190 141 189 +4 2 141 190 142 +4 2 238 189 237 +4 2 189 238 190 +4 2 95 46 94 +4 2 46 95 47 +4 2 143 94 142 +4 2 94 143 95 +4 2 191 142 190 +4 2 142 191 143 +4 2 239 190 238 +4 2 190 239 191 + +vertices +240 +3 +0 0 0 +0.4 0 0 +0.8 0 0 +1.2 0 0 +0 0.2 0 +0.4 0.2 0 +0.8 0.2 0 +1.2 0.2 0 +0 0.4 0 +0.4 0.4 0 +0.8 0.4 0 +1.2 0.4 0 +0 0.6 0 +0.4 0.6 0 +0.8 0.6 0 +1.2 0.6 0 +0 0.8 0 +0.4 0.8 0 +0.8 0.8 0 +1.2 0.8 0 +0 1 0 +0.4 1 0 +0.8 1 0 +1.2 1 0 +0 1.2 0 +0.4 1.2 0 +0.8 1.2 0 +1.2 1.2 0 +0 1.4 0 +0.4 1.4 0 +0.8 1.4 0 +1.2 1.4 0 +0 1.6 0 +0.4 1.6 0 +0.8 1.6 0 +1.2 1.6 0 +0 1.8 0 +0.4 1.8 0 +0.8 1.8 0 +1.2 1.8 0 +0 2 0 +0.4 2 0 +0.8 2 0 +1.2 2 0 +0 2.2 0 +0.4 2.2 0 +0.8 2.2 0 +1.2 2.2 0 +0 0 0.04 +0.4 0 0.04 +0.8 0 0.04 +1.2 0 0.04 +0 0.2 0.04 +0.4 0.2 0.04 +0.8 0.2 0.04 +1.2 0.2 0.04 +0 0.4 0.04 +0.4 0.4 0.04 +0.8 0.4 0.04 +1.2 0.4 0.04 +0 0.6 0.04 +0.4 0.6 0.04 +0.8 0.6 0.04 +1.2 0.6 0.04 +0 0.8 0.04 +0.4 0.8 0.04 +0.8 0.8 0.04 +1.2 0.8 0.04 +0 1 0.04 +0.4 1 0.04 +0.8 1 0.04 +1.2 1 0.04 +0 1.2 0.04 +0.4 1.2 0.04 +0.8 1.2 0.04 +1.2 1.2 0.04 +0 1.4 0.04 +0.4 1.4 0.04 +0.8 1.4 0.04 +1.2 1.4 0.04 +0 1.6 0.04 +0.4 1.6 0.04 +0.8 1.6 0.04 +1.2 1.6 0.04 +0 1.8 0.04 +0.4 1.8 0.04 +0.8 1.8 0.04 +1.2 1.8 0.04 +0 2 0.04 +0.4 2 0.04 +0.8 2 0.04 +1.2 2 0.04 +0 2.2 0.04 +0.4 2.2 0.04 +0.8 2.2 0.04 +1.2 2.2 0.04 +0 0 0.08 +0.4 0 0.08 +0.8 0 0.08 +1.2 0 0.08 +0 0.2 0.08 +0.4 0.2 0.08 +0.8 0.2 0.08 +1.2 0.2 0.08 +0 0.4 0.08 +0.4 0.4 0.08 +0.8 0.4 0.08 +1.2 0.4 0.08 +0 0.6 0.08 +0.4 0.6 0.08 +0.8 0.6 0.08 +1.2 0.6 0.08 +0 0.8 0.08 +0.4 0.8 0.08 +0.8 0.8 0.08 +1.2 0.8 0.08 +0 1 0.08 +0.4 1 0.08 +0.8 1 0.08 +1.2 1 0.08 +0 1.2 0.08 +0.4 1.2 0.08 +0.8 1.2 0.08 +1.2 1.2 0.08 +0 1.4 0.08 +0.4 1.4 0.08 +0.8 1.4 0.08 +1.2 1.4 0.08 +0 1.6 0.08 +0.4 1.6 0.08 +0.8 1.6 0.08 +1.2 1.6 0.08 +0 1.8 0.08 +0.4 1.8 0.08 +0.8 1.8 0.08 +1.2 1.8 0.08 +0 2 0.08 +0.4 2 0.08 +0.8 2 0.08 +1.2 2 0.08 +0 2.2 0.08 +0.4 2.2 0.08 +0.8 2.2 0.08 +1.2 2.2 0.08 +0 0 0.12 +0.4 0 0.12 +0.8 0 0.12 +1.2 0 0.12 +0 0.2 0.12 +0.4 0.2 0.12 +0.8 0.2 0.12 +1.2 0.2 0.12 +0 0.4 0.12 +0.4 0.4 0.12 +0.8 0.4 0.12 +1.2 0.4 0.12 +0 0.6 0.12 +0.4 0.6 0.12 +0.8 0.6 0.12 +1.2 0.6 0.12 +0 0.8 0.12 +0.4 0.8 0.12 +0.8 0.8 0.12 +1.2 0.8 0.12 +0 1 0.12 +0.4 1 0.12 +0.8 1 0.12 +1.2 1 0.12 +0 1.2 0.12 +0.4 1.2 0.12 +0.8 1.2 0.12 +1.2 1.2 0.12 +0 1.4 0.12 +0.4 1.4 0.12 +0.8 1.4 0.12 +1.2 1.4 0.12 +0 1.6 0.12 +0.4 1.6 0.12 +0.8 1.6 0.12 +1.2 1.6 0.12 +0 1.8 0.12 +0.4 1.8 0.12 +0.8 1.8 0.12 +1.2 1.8 0.12 +0 2 0.12 +0.4 2 0.12 +0.8 2 0.12 +1.2 2 0.12 +0 2.2 0.12 +0.4 2.2 0.12 +0.8 2.2 0.12 +1.2 2.2 0.12 +0 0 0.16 +0.4 0 0.16 +0.8 0 0.16 +1.2 0 0.16 +0 0.2 0.16 +0.4 0.2 0.16 +0.8 0.2 0.16 +1.2 0.2 0.16 +0 0.4 0.16 +0.4 0.4 0.16 +0.8 0.4 0.16 +1.2 0.4 0.16 +0 0.6 0.16 +0.4 0.6 0.16 +0.8 0.6 0.16 +1.2 0.6 0.16 +0 0.8 0.16 +0.4 0.8 0.16 +0.8 0.8 0.16 +1.2 0.8 0.16 +0 1 0.16 +0.4 1 0.16 +0.8 1 0.16 +1.2 1 0.16 +0 1.2 0.16 +0.4 1.2 0.16 +0.8 1.2 0.16 +1.2 1.2 0.16 +0 1.4 0.16 +0.4 1.4 0.16 +0.8 1.4 0.16 +1.2 1.4 0.16 +0 1.6 0.16 +0.4 1.6 0.16 +0.8 1.6 0.16 +1.2 1.6 0.16 +0 1.8 0.16 +0.4 1.8 0.16 +0.8 1.8 0.16 +1.2 1.8 0.16 +0 2 0.16 +0.4 2 0.16 +0.8 2 0.16 +1.2 2 0.16 +0 2.2 0.16 +0.4 2.2 0.16 +0.8 2.2 0.16 +1.2 2.2 0.16 diff --git a/miniapps/solvers/block-solvers.cpp b/miniapps/solvers/block-solvers.cpp new file mode 100644 index 0000000000..db0cdd8a7d --- /dev/null +++ b/miniapps/solvers/block-solvers.cpp @@ -0,0 +1,418 @@ +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-806117. +// +// This file is part of the MFEM library. For more information and source code +// availability visit https://mfem.org. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. +// +// ---------------------------------------------------------- +// Block Solvers Miniapp: Compare Saddle Point System Solvers +// ---------------------------------------------------------- +// +// This miniapp compares various linear solvers for the saddle point system +// obtained from mixed finite element discretization of the simple mixed Darcy +// problem in ex5p +// +// k*u + grad p = f +// - div u = g +// +// with natural boundary condition -p = . We use a given exact +// solution (u,p) and compute the corresponding r.h.s. (f,g). We discretize +// with Raviart-Thomas finite elements (velocity u) and piecewise discontinuous +// polynomials (pressure p). +// +// The solvers being compared include: +// 1. The divergence free solver (couple and decoupled modes) +// 2. MINRES preconditioned by a block diagonal preconditioner +// +// We recommend viewing example 5 before viewing this miniapp. +// +// Sample runs: +// +// mpirun -np 8 block-solvers-compare -r 2 -o 0 +// mpirun -np 8 block-solvers-compare -m anisotropic.mesh -c anisotropic.coeff -be anisotropic.bdr +// +// +// NOTE: The coefficient file (provided through -c) defines a piecewise constant +// scalar coefficient k. The number of entries in this file should equal +// to the number of "element attributes" in the mesh file. The value of +// the coefficient in elements with the i-th attribute is given by the +// i-th entry of the coefficient file. +// +// +// NOTE: The essential boundary attribute file (provided through -eb) defines +// which attributes to impose essential boundary condition (on u). The +// number of entries in this file should equal to the number of "boundary +// attributes" in the mesh file. If the i-th entry of the file is nonzero +// (respectively 0), essential (respectively natural) boundary condition +// will be imposed on boundary with the i-th attribute. + +#include "mfem.hpp" +#include "div_free_solver.hpp" +#include +#include +#include + +using namespace std; +using namespace mfem; +using namespace blocksolvers; + +// Exact solution, u and p, and r.h.s., f and g. +void u_exact(const Vector & x, Vector & u); +double p_exact(const Vector & x); +void f_exact(const Vector & x, Vector & f); +double g_exact(const Vector & x); +double natural_bc(const Vector & x); + +/** Wrapper for assembling the discrete Darcy problem (ex5p) + [ M B^T ] [u] = [f] + [ B 0 ] [p] = [g] + where: + M = \int_\Omega (k u_h) \cdot v_h dx, + B = -\int_\Omega (div_h u_h) q_h dx, + f = \int_\Omega f_exact v_h dx + \int_D natural_bc v_h dS, + g = \int_\Omega g_exact q_h dx, + u_h, v_h \in R_h (Raviart-Thomas finite element space), + q_h \in W_h (piecewise discontinuous polynomials), + D: subset of the boundary where natural boundary condition is imposed. */ +class DarcyProblem +{ + OperatorPtr M_; + OperatorPtr B_; + Vector rhs_; + Vector ess_data_; + ParGridFunction u_; + ParGridFunction p_; + ParMesh mesh_; + VectorFunctionCoefficient ucoeff_; + FunctionCoefficient pcoeff_; + DFSSpaces dfs_spaces_; + const IntegrationRule *irs_[Geometry::NumGeom]; +public: + DarcyProblem(Mesh &mesh, int num_refines, int order, const char *coef_file, + Array &ess_bdr, DFSParameters param); + + HypreParMatrix& GetM() { return *M_.As(); } + HypreParMatrix& GetB() { return *B_.As(); } + const Vector& GetRHS() { return rhs_; } + const Vector& GetEssentialBC() { return ess_data_; } + const DFSData& GetDFSData() const { return dfs_spaces_.GetDFSData(); } + void ShowError(const Vector &sol, bool verbose); + void VisualizeSolution(const Vector &sol, string tag); +}; + +DarcyProblem::DarcyProblem(Mesh &mesh, int num_refs, int order, + const char *coef_file, Array &ess_bdr, + DFSParameters dfs_param) + : mesh_(MPI_COMM_WORLD, mesh), ucoeff_(mesh.Dimension(), u_exact), + pcoeff_(p_exact), dfs_spaces_(order, num_refs, &mesh_, ess_bdr, dfs_param) +{ + for (int l = 0; l < num_refs; l++) + { + mesh_.UniformRefinement(); + dfs_spaces_.CollectDFSData(); + } + + Vector coef_vector(mesh.GetNE()); + coef_vector = 1.0; + if (std::strcmp(coef_file, "")) + { + ifstream coef_str(coef_file); + coef_vector.Load(coef_str, mesh.GetNE()); + } + PWConstCoefficient mass_coeff(coef_vector); + VectorFunctionCoefficient fcoeff(mesh_.Dimension(), f_exact); + FunctionCoefficient natcoeff(natural_bc); + FunctionCoefficient gcoeff(g_exact); + + u_.SetSpace(dfs_spaces_.GetHdivFES()); + p_.SetSpace(dfs_spaces_.GetL2FES()); + p_ = 0.0; + u_ = 0.0; + u_.ProjectBdrCoefficientNormal(ucoeff_, ess_bdr); + + ParLinearForm fform(dfs_spaces_.GetHdivFES()); + fform.AddDomainIntegrator(new VectorFEDomainLFIntegrator(fcoeff)); + fform.AddBoundaryIntegrator(new VectorFEBoundaryFluxLFIntegrator(natcoeff)); + fform.Assemble(); + + ParLinearForm gform(dfs_spaces_.GetL2FES()); + gform.AddDomainIntegrator(new DomainLFIntegrator(gcoeff)); + gform.Assemble(); + + ParBilinearForm mVarf(dfs_spaces_.GetHdivFES()); + ParMixedBilinearForm bVarf(dfs_spaces_.GetHdivFES(), dfs_spaces_.GetL2FES()); + + mVarf.AddDomainIntegrator(new VectorFEMassIntegrator(mass_coeff)); + mVarf.Assemble(); + mVarf.EliminateEssentialBC(ess_bdr, u_, fform); + mVarf.Finalize(); + M_.Reset(mVarf.ParallelAssemble()); + + bVarf.AddDomainIntegrator(new VectorFEDivergenceIntegrator); + bVarf.Assemble(); + bVarf.SpMat() *= -1.0; + bVarf.EliminateTrialDofs(ess_bdr, u_, gform); + bVarf.Finalize(); + B_.Reset(bVarf.ParallelAssemble()); + + rhs_.SetSize(M_->NumRows() + B_->NumRows()); + Vector rhs_block0(rhs_.GetData(), M_->NumRows()); + Vector rhs_block1(rhs_.GetData()+M_->NumRows(), B_->NumRows()); + fform.ParallelAssemble(rhs_block0); + gform.ParallelAssemble(rhs_block1); + + ess_data_.SetSize(M_->NumRows() + B_->NumRows()); + ess_data_ = 0.0; + Vector ess_data_block0(ess_data_.GetData(), M_->NumRows()); + u_.ParallelProject(ess_data_block0); + + int order_quad = max(2, 2*order+1); + for (int i=0; i < Geometry::NumGeom; ++i) + { + irs_[i] = &(IntRules.Get(i, order_quad)); + } +} + +void DarcyProblem::ShowError(const Vector& sol, bool verbose) +{ + u_.Distribute(Vector(sol.GetData(), M_->NumRows())); + p_.Distribute(Vector(sol.GetData()+M_->NumRows(), B_->NumRows())); + + double err_u = u_.ComputeL2Error(ucoeff_, irs_); + double norm_u = ComputeGlobalLpNorm(2, ucoeff_, mesh_, irs_); + double err_p = p_.ComputeL2Error(pcoeff_, irs_); + double norm_p = ComputeGlobalLpNorm(2, pcoeff_, mesh_, irs_); + + if (!verbose) { return; } + cout << "|| u_h - u_ex || / || u_ex || = " << err_u / norm_u << "\n"; + cout << "|| p_h - p_ex || / || p_ex || = " << err_p / norm_p << "\n"; +} + +void DarcyProblem::VisualizeSolution(const Vector& sol, string tag) +{ + int num_procs, myid; + MPI_Comm_size(mesh_.GetComm(), &num_procs); + MPI_Comm_rank(mesh_.GetComm(), &myid); + + u_.Distribute(Vector(sol.GetData(), M_->NumRows())); + p_.Distribute(Vector(sol.GetData()+M_->NumRows(), B_->NumRows())); + + const char vishost[] = "localhost"; + const int visport = 19916; + socketstream u_sock(vishost, visport); + u_sock << "parallel " << num_procs << " " << myid << "\n"; + u_sock.precision(8); + u_sock << "solution\n" << mesh_ << u_ << "window_title 'Velocity (" + << tag << " solver)'" << endl; + MPI_Barrier(mesh_.GetComm()); + socketstream p_sock(vishost, visport); + p_sock << "parallel " << num_procs << " " << myid << "\n"; + p_sock.precision(8); + p_sock << "solution\n" << mesh_ << p_ << "window_title 'Pressure (" + << tag << " solver)'" << endl; +} + +bool IsAllNeumannBoundary(const Array& ess_bdr_attr) +{ + for (int attr : ess_bdr_attr) { if (attr == 0) { return false; } } + return true; +} + +int main(int argc, char *argv[]) +{ + // Initialize MPI. + MPI_Session mpi(argc, argv); + + StopWatch chrono; + auto ResetTimer = [&chrono]() { chrono.Clear(); chrono.Start(); }; + + // Parse command-line options. + const char *mesh_file = "../../data/beam-hex.mesh"; + const char *coef_file = ""; + const char *ess_bdr_attr_file = ""; + int order = 0; + int par_ref_levels = 2; + bool show_error = false; + bool visualization = false; + DFSParameters param; + OptionsParser args(argc, argv); + args.AddOption(&mesh_file, "-m", "--mesh", + "Mesh file to use."); + args.AddOption(&order, "-o", "--order", + "Finite element order (polynomial degree)."); + args.AddOption(&par_ref_levels, "-r", "--ref", + "Number of parallel refinement steps."); + args.AddOption(&coef_file, "-c", "--coef", + "Coefficient file to use."); + args.AddOption(&ess_bdr_attr_file, "-eb", "--ess-bdr", + "Essential boundary attribute file to use."); + args.AddOption(&show_error, "-se", "--show-error", "-no-se", + "--no-show-error", + "Show or not show approximation error."); + args.AddOption(&visualization, "-vis", "--visualization", "-no-vis", + "--no-visualization", + "Enable or disable GLVis visualization."); + args.Parse(); + if (!args.Good()) + { + if (mpi.Root()) { args.PrintUsage(cout); } + return 1; + } + if (mpi.Root()) { args.PrintOptions(cout); } + + if (mpi.Root() && par_ref_levels == 0) + { + std::cout << "WARNING: DivFree solver is equivalent to BDPMinresSolver " + << "when par_ref_levels == 0.\n"; + } + + // Initialize the mesh, boundary attributes, and solver parameters + Mesh *mesh = new Mesh(mesh_file, 1, 1); + int dim = mesh->Dimension(); + int ser_ref_lvls = (int)ceil(log(mpi.WorldSize()/mesh->GetNE())/log(2.)/dim); + for (int i = 0; i < ser_ref_lvls; ++i) + { + mesh->UniformRefinement(); + } + + Array ess_bdr(mesh->bdr_attributes.Max()); + ess_bdr = 0; + if (std::strcmp(ess_bdr_attr_file, "")) + { + ifstream ess_bdr_attr_str(ess_bdr_attr_file); + ess_bdr.Load(mesh->bdr_attributes.Max(), ess_bdr_attr_str); + } + if (IsAllNeumannBoundary(ess_bdr)) + { + if (mpi.Root()) + { + cout << "\nSolution is not unique when Neumann boundary condition is " + << "imposed on the entire boundary. \nPlease provide a different " + << "boundary condition.\n"; + } + delete mesh; + return 0; + } + + string line = "**********************************************************\n"; + + ResetTimer(); + + // Generate components of the saddle point problem + DarcyProblem darcy(*mesh, par_ref_levels, order, coef_file, ess_bdr, param); + HypreParMatrix& M = darcy.GetM(); + HypreParMatrix& B = darcy.GetB(); + const DFSData& DFS_data = darcy.GetDFSData(); + delete mesh; + + if (mpi.Root()) + { + cout << line << "System assembled in " << chrono.RealTime() << "s.\n"; + cout << "Dimension of the physical space: " << dim << "\n"; + cout << "Size of the discrete Darcy system: " << M.M() + B.M() << "\n"; + if (par_ref_levels > 0) + { + cout << "Dimension of the divergence free subspace: " + << DFS_data.C.Last().Ptr()->NumCols() << "\n\n"; + } + } + + // Setup various solvers for the discrete problem + std::map setup_time; + ResetTimer(); + BDPMinresSolver bdp(M, B, param); + setup_time[&bdp] = chrono.RealTime(); + + ResetTimer(); + DivFreeSolver dfs_dm(M, B, DFS_data); + setup_time[&dfs_dm] = chrono.RealTime(); + + ResetTimer(); + const_cast(DFS_data.param.coupled_solve) = true; + DivFreeSolver dfs_cm(M, B, DFS_data); + setup_time[&dfs_cm] = chrono.RealTime(); + + std::map solver_to_name; + solver_to_name[&bdp] = "Block-diagonal-preconditioned MINRES"; + solver_to_name[&dfs_dm] = "Divergence free (decoupled mode)"; + solver_to_name[&dfs_cm] = "Divergence free (coupled mode)"; + + // Solve the problem using all solvers + for (const auto& solver_pair : solver_to_name) + { + auto& solver = solver_pair.first; + auto& name = solver_pair.second; + + Vector sol = darcy.GetEssentialBC(); + + ResetTimer(); + solver->Mult(darcy.GetRHS(), sol); + chrono.Stop(); + + if (mpi.Root()) + { + cout << line << name << " solver:\n Setup time: " + << setup_time[solver] << "s.\n Solve time: " + << chrono.RealTime() << "s.\n Total time: " + << setup_time[solver] + chrono.RealTime() << "s.\n" + << " Iteration count: " << solver->GetNumIterations() <<"\n\n"; + } + if (show_error && std::strcmp(coef_file, "") == 0) + { + darcy.ShowError(sol, mpi.Root()); + } + else if (show_error && mpi.Root()) + { + cout << "Exact solution is unknown for coefficient '" << coef_file + << "'.\nApproximation error is computed in this case!\n\n"; + } + + if (visualization) { darcy.VisualizeSolution(sol, name); } + + } + + return 0; +} + +void u_exact(const Vector & x, Vector & u) +{ + double xi(x(0)); + double yi(x(1)); + double zi(x.Size() == 3 ? x(2) : 0.0); + + u(0) = - exp(xi)*sin(yi)*cos(zi); + u(1) = - exp(xi)*cos(yi)*cos(zi); + if (x.Size() == 3) + { + u(2) = exp(xi)*sin(yi)*sin(zi); + } +} + +double p_exact(const Vector & x) +{ + double xi(x(0)); + double yi(x(1)); + double zi(x.Size() == 3 ? x(2) : 0.0); + return exp(xi)*sin(yi)*cos(zi); +} + +void f_exact(const Vector & x, Vector & f) +{ + f = 0.0; +} + +double g_exact(const Vector & x) +{ + if (x.Size() == 3) { return -p_exact(x); } + return 0; +} + +double natural_bc(const Vector & x) +{ + return (-p_exact(x)); +} diff --git a/miniapps/solvers/div_free_solver.cpp b/miniapps/solvers/div_free_solver.cpp new file mode 100644 index 0000000000..8f60ab0c00 --- /dev/null +++ b/miniapps/solvers/div_free_solver.cpp @@ -0,0 +1,603 @@ +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-806117. +// +// This file is part of the MFEM library. For more information and source code +// availability visit https://mfem.org. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. + +#include "div_free_solver.hpp" + +using namespace std; +using namespace mfem; +using namespace blocksolvers; + +void SetOptions(IterativeSolver& solver, const IterSolveParameters& param) +{ + solver.SetPrintLevel(param.print_level); + solver.SetMaxIter(param.max_iter); + solver.SetAbsTol(param.abs_tol); + solver.SetRelTol(param.rel_tol); +} + +HypreParMatrix* TwoStepsRAP(const HypreParMatrix& Rt, const HypreParMatrix& A, + const HypreParMatrix& P) +{ + OperatorPtr R(Rt.Transpose()); + OperatorPtr RA(ParMult(R.As(), &A)); + return ParMult(RA.As(), &P, true); +} + +void GetRowColumnsRef(const SparseMatrix& A, int row, Array& cols) +{ + cols.MakeRef(const_cast(A.GetRowColumns(row)), A.RowSize(row)); +} + +SparseMatrix ElemToDof(const ParFiniteElementSpace& fes) +{ + int* I = new int[fes.GetNE()+1]; + copy_n(fes.GetElementToDofTable().GetI(), fes.GetNE()+1, I); + Array J(new int[I[fes.GetNE()]], I[fes.GetNE()]); + copy_n(fes.GetElementToDofTable().GetJ(), J.Size(), J.begin()); + fes.AdjustVDofs(J); + double* D = new double[J.Size()]; + fill_n(D, J.Size(), 1.0); + return SparseMatrix(I, J, D, fes.GetNE(), fes.GetVSize()); +} + +DFSSpaces::DFSSpaces(int order, int num_refine, ParMesh *mesh, + const Array& ess_attr, const DFSParameters& param) + : hdiv_fec_(order, mesh->Dimension()), l2_fec_(order, mesh->Dimension()), + l2_0_fec_(0, mesh->Dimension()), ess_bdr_attr_(ess_attr), level_(0) +{ + if (mesh->GetElement(0)->GetType() == Element::TETRAHEDRON && order) + { + mfem_error("DFSDataCollector: High order spaces on tetrahedra are not supported"); + } + + data_.param = param; + + if (mesh->Dimension() == 3) + { + hcurl_fec_.reset(new ND_FECollection(order+1, mesh->Dimension())); + } + else + { + hcurl_fec_.reset(new H1_FECollection(order+1, mesh->Dimension())); + } + + all_bdr_attr_.SetSize(ess_attr.Size(), 1); + hdiv_fes_.reset(new ParFiniteElementSpace(mesh, &hdiv_fec_)); + l2_fes_.reset(new ParFiniteElementSpace(mesh, &l2_fec_)); + coarse_hdiv_fes_.reset(new ParFiniteElementSpace(*hdiv_fes_)); + coarse_l2_fes_.reset(new ParFiniteElementSpace(*l2_fes_)); + l2_0_fes_.reset(new ParFiniteElementSpace(mesh, &l2_0_fec_)); + l2_0_fes_->SetUpdateOperatorType(Operator::MFEM_SPARSEMAT); + el_l2dof_.reserve(num_refine+1); + el_l2dof_.push_back(ElemToDof(*coarse_l2_fes_)); + + data_.agg_hdivdof.SetSize(num_refine); + data_.agg_l2dof.SetSize(num_refine); + data_.P_hdiv.SetSize(num_refine, OperatorPtr(Operator::Hypre_ParCSR)); + data_.P_l2.SetSize(num_refine, OperatorPtr(Operator::Hypre_ParCSR)); + data_.Q_l2.SetSize(num_refine); + hdiv_fes_->GetEssentialTrueDofs(ess_attr, data_.coarsest_ess_hdivdofs); + data_.C.SetSize(num_refine+1); + + hcurl_fes_.reset(new ParFiniteElementSpace(mesh, hcurl_fec_.get())); + coarse_hcurl_fes_.reset(new ParFiniteElementSpace(*hcurl_fes_)); + data_.P_hcurl.SetSize(num_refine, OperatorPtr(Operator::Hypre_ParCSR)); +} + +SparseMatrix* AggToInteriorDof(const Array& bdr_truedofs, + const SparseMatrix& agg_elem, + const SparseMatrix& elem_dof, + const HypreParMatrix& dof_truedof, + Array& agg_starts) +{ + OperatorPtr agg_dof(Mult(agg_elem, elem_dof)); + SparseMatrix& agg_dof_ref = *agg_dof.As(); + OperatorPtr agg_tdof(dof_truedof.LeftDiagMult(agg_dof_ref, agg_starts)); + OperatorPtr agg_tdof_T(agg_tdof.As()->Transpose()); + SparseMatrix tdof_agg, is_shared; + HYPRE_Int* trash; + agg_tdof_T.As()->GetDiag(tdof_agg); + agg_tdof_T.As()->GetOffd(is_shared, trash); + + int * I = new int [tdof_agg.NumRows()+1](); + int * J = new int[tdof_agg.NumNonZeroElems()]; + + Array is_bdr; + FiniteElementSpace::ListToMarker(bdr_truedofs, tdof_agg.NumRows(), is_bdr); + + int counter = 0; + for (int i = 0; i < tdof_agg.NumRows(); ++i) + { + bool agg_bdr = is_bdr[i] || is_shared.RowSize(i) || tdof_agg.RowSize(i)>1; + if (agg_bdr) { I[i+1] = I[i]; continue; } + I[i+1] = I[i] + 1; + J[counter++] = tdof_agg.GetRowColumns(i)[0]; + } + + double * D = new double[I[tdof_agg.NumRows()]]; + std::fill_n(D, I[tdof_agg.NumRows()], 1.0); + + SparseMatrix intdof_agg(I, J, D, tdof_agg.NumRows(), tdof_agg.NumCols()); + return Transpose(intdof_agg); +} + +void DFSSpaces::MakeDofRelationTables(int level) +{ + Array agg_starts(Array(l2_0_fes_->GetDofOffsets(), 2)); + auto& elem_agg = (const SparseMatrix&)*l2_0_fes_->GetUpdateOperator(); + OperatorPtr agg_elem(Transpose(elem_agg)); + SparseMatrix& agg_el = *agg_elem.As(); + + el_l2dof_.push_back(ElemToDof(*l2_fes_)); + data_.agg_l2dof[level].Reset(Mult(agg_el, el_l2dof_[level+1])); + + Array bdr_tdofs; + hdiv_fes_->GetEssentialTrueDofs(all_bdr_attr_, bdr_tdofs); + auto tmp = AggToInteriorDof(bdr_tdofs, agg_el, ElemToDof(*hdiv_fes_), + *hdiv_fes_->Dof_TrueDof_Matrix(), agg_starts); + data_.agg_hdivdof[level].Reset(tmp); +} + +void DFSSpaces::CollectDFSData() +{ + auto GetP = [this](OperatorPtr& P, unique_ptr& cfes, + ParFiniteElementSpace& fes, bool remove_zero) + { + fes.Update(); + fes.GetTrueTransferOperator(*cfes, P); + if (remove_zero) + { + P.As()->DropSmallEntries(1e-16); + } + (level_ < data_.P_l2.Size()-1) ? cfes->Update() : cfes.reset(); + }; + + GetP(data_.P_hdiv[level_], coarse_hdiv_fes_, *hdiv_fes_, true); + GetP(data_.P_l2[level_], coarse_l2_fes_, *l2_fes_, false); + MakeDofRelationTables(level_); + + GetP(data_.P_hcurl[level_], coarse_hcurl_fes_, *hcurl_fes_, true); + + Vector trash1(hcurl_fes_->GetVSize()), trash2(hdiv_fes_->GetVSize()); + ParDiscreteLinearOperator curl(hcurl_fes_.get(), hdiv_fes_.get()); + curl.AddDomainInterpolator(new CurlInterpolator); + curl.Assemble(); + curl.EliminateTrialDofs(ess_bdr_attr_, trash1, trash2); + curl.Finalize(); + data_.C[level_+1].Reset(curl.ParallelAssemble()); + + ++level_; + + if (level_ == data_.P_l2.Size()) { DataFinalize(); } +} + +void DFSSpaces::DataFinalize() +{ + ParBilinearForm mass(l2_fes_.get()); + mass.AddDomainIntegrator(new MassIntegrator()); + mass.Assemble(); + mass.Finalize(); + OperatorPtr W(mass.LoseMat()); + + SparseMatrix P_l2; + for (int l = data_.P_l2.Size()-1; l >= 0; --l) + { + data_.P_l2[l].As()->GetDiag(P_l2); + OperatorPtr PT_l2(Transpose(P_l2)); + auto PTW = Mult(*PT_l2.As(), *W.As()); + auto cW = Mult(*PTW, P_l2); + auto cW_inv = new SymDirectSubBlockSolver(*cW, el_l2dof_[l]); + data_.Q_l2[l].Reset(new ProductOperator(cW_inv, PTW, true, true)); + W.Reset(cW); + } + + l2_0_fes_.reset(); +} + +BBTSolver::BBTSolver(const HypreParMatrix& B, IterSolveParameters param) + : Solver(B.NumRows()), BBT_solver_(B.GetComm()) +{ + OperatorPtr BT(B.Transpose()); + BBT_.Reset(ParMult(&B, BT.As())); + BBT_.As()->CopyColStarts(); + + BBT_prec_.Reset(new HypreBoomerAMG(*BBT_.As())); + BBT_prec_.As()->SetPrintLevel(0); + + SetOptions(BBT_solver_, param); + BBT_solver_.SetOperator(*BBT_); + BBT_solver_.SetPreconditioner(*BBT_prec_.As()); +} + +LocalSolver::LocalSolver(const DenseMatrix& M, const DenseMatrix& B) + : Solver(M.NumRows()+B.NumRows()), local_system_(height), offset_(M.NumRows()) +{ + local_system_.CopyMN(M, 0, 0); + local_system_.CopyMN(B, offset_, 0); + local_system_.CopyMNt(B, 0, offset_); + + local_system_.SetRow(offset_, 0.0); + local_system_.SetCol(offset_, 0.0); + local_system_(offset_, offset_) = -1.0; + local_solver_.SetOperator(local_system_); +} + +void LocalSolver::Mult(const Vector &x, Vector &y) const +{ + const double x0 = x[offset_]; + const_cast(x)[offset_] = 0.0; + + y.SetSize(local_system_.NumRows()); + local_solver_.Mult(x, y); + + const_cast(x)[offset_] = x0; +} + +SaddleSchwarzSmoother::SaddleSchwarzSmoother(const HypreParMatrix& M, + const HypreParMatrix& B, + const SparseMatrix& agg_hdivdof, + const SparseMatrix& agg_l2dof, + const HypreParMatrix& P_l2, + const HypreParMatrix& Q_l2) + : Solver(M.NumRows() + B.NumRows()), agg_hdivdof_(agg_hdivdof), + agg_l2dof_(agg_l2dof), solvers_loc_(agg_l2dof.NumRows()) +{ + coarse_l2_projector_.Reset(new ProductOperator(&P_l2, &Q_l2, false, false)); + + offsets_loc_.SetSize(3, 0); + offsets_.SetSize(3, 0); + offsets_[1] = M.NumRows(); + offsets_[2] = M.NumRows() + B.NumRows(); + + SparseMatrix M_diag, B_diag; + M.GetDiag(M_diag); + B.GetDiag(B_diag); + + DenseMatrix B_loc, M_loc; + + for (int agg = 0; agg < solvers_loc_.Size(); agg++) + { + GetRowColumnsRef(agg_hdivdof_, agg, hdivdofs_loc_); + GetRowColumnsRef(agg_l2dof_, agg, l2dofs_loc_); + M_loc.SetSize(hdivdofs_loc_.Size(), hdivdofs_loc_.Size()); + B_loc.SetSize(l2dofs_loc_.Size(), hdivdofs_loc_.Size()); + M_diag.GetSubMatrix(hdivdofs_loc_, hdivdofs_loc_, M_loc); + B_diag.GetSubMatrix(l2dofs_loc_, hdivdofs_loc_, B_loc); + solvers_loc_[agg].Reset(new LocalSolver(M_loc, B_loc)); + } +} + +void SaddleSchwarzSmoother::Mult(const Vector & x, Vector & y) const +{ + y.SetSize(offsets_[2]); + y = 0.0; + + BlockVector blk_y(y.GetData(), offsets_); + BlockVector Pi_x(offsets_); // aggregate-wise average free projection of x + static_cast(Pi_x) = x; + + // Right hand side: F_l = F - W_l P_l2[l] (W_{l+1})^{-1} P_l2[l]^T F + // This ensures the existence of solutions to the local problems + Vector coarse_l2_projection(Pi_x.BlockSize(1)); + coarse_l2_projector_->MultTranspose(Pi_x.GetBlock(1), coarse_l2_projection); + + Pi_x.GetBlock(1) -= coarse_l2_projection; + + for (int agg = 0; agg < solvers_loc_.Size(); agg++) + { + GetRowColumnsRef(agg_hdivdof_, agg, hdivdofs_loc_); + GetRowColumnsRef(agg_l2dof_, agg, l2dofs_loc_); + + offsets_loc_[1] = hdivdofs_loc_.Size(); + offsets_loc_[2] = offsets_loc_[1]+l2dofs_loc_.Size(); + + BlockVector rhs_loc(offsets_loc_), sol_loc(offsets_loc_); + Pi_x.GetBlock(0).GetSubVector(hdivdofs_loc_, rhs_loc.GetBlock(0)); + Pi_x.GetBlock(1).GetSubVector(l2dofs_loc_, rhs_loc.GetBlock(1)); + + solvers_loc_[agg]->Mult(rhs_loc, sol_loc); + + blk_y.GetBlock(0).AddElementVector(hdivdofs_loc_, sol_loc.GetBlock(0)); + blk_y.GetBlock(1).AddElementVector(l2dofs_loc_, sol_loc.GetBlock(1)); + } + + coarse_l2_projector_->Mult(blk_y.GetBlock(1), coarse_l2_projection); + blk_y.GetBlock(1) -= coarse_l2_projection; +} + +BDPMinresSolver::BDPMinresSolver(HypreParMatrix& M, HypreParMatrix& B, + IterSolveParameters param) + : DarcySolver(M.NumRows(), B.NumRows()), op_(offsets_), prec_(offsets_), + BT_(B.Transpose()), solver_(M.GetComm()) +{ + op_.SetBlock(0,0, &M); + op_.SetBlock(0,1, BT_.As()); + op_.SetBlock(1,0, &B); + + Vector Md; + M.GetDiag(Md); + BT_.As()->InvScaleRows(Md); + S_.Reset(ParMult(&B, BT_.As())); + BT_.As()->ScaleRows(Md); + + prec_.SetDiagonalBlock(0, new HypreDiagScale(M)); + prec_.SetDiagonalBlock(1, new HypreBoomerAMG(*S_.As())); + static_cast(prec_.GetDiagonalBlock(1)).SetPrintLevel(0); + prec_.owns_blocks = true; + + SetOptions(solver_, param); + solver_.SetOperator(op_); + solver_.SetPreconditioner(prec_); +} + +void BDPMinresSolver::Mult(const Vector & x, Vector & y) const +{ + solver_.Mult(x, y); + for (int dof : ess_zero_dofs_) { y[dof] = 0.0; } +} + +DivFreeSolver::DivFreeSolver(const HypreParMatrix &M, const HypreParMatrix& B, + const DFSData& data) + : DarcySolver(M.NumRows(), B.NumRows()), data_(data), param_(data.param), + BT_(B.Transpose()), BBT_solver_(B, param_.BBT_solve_param), + ops_offsets_(data.P_l2.Size()+1), ops_(ops_offsets_.Size()), + blk_Ps_(ops_.Size()-1), smoothers_(ops_.Size()) +{ + ops_offsets_.Last().MakeRef(DarcySolver::offsets_); + ops_.Last() = new BlockOperator(ops_offsets_.Last()); + ops_.Last()->SetBlock(0, 0, const_cast(&M)); + ops_.Last()->SetBlock(1, 0, const_cast(&B)); + ops_.Last()->SetBlock(0, 1, BT_.Ptr()); + + for (int l = data.P_l2.Size(); l >= 0; --l) + { + auto& M_f = static_cast(ops_[l]->GetBlock(0, 0)); + auto& B_f = static_cast(ops_[l]->GetBlock(1, 0)); + + if (l == 0) + { + SparseMatrix M_f_diag, B_f_diag; + M_f.GetDiag(M_f_diag); + B_f.GetDiag(B_f_diag); + for (int dof : data.coarsest_ess_hdivdofs) + { + M_f_diag.EliminateRowCol(dof); + B_f_diag.EliminateCol(dof); + } + + const IterSolveParameters& param = param_.coarse_solve_param; + auto coarse_solver = new BDPMinresSolver(M_f, B_f, param); + if (ops_.Size() > 1) + { + coarse_solver->SetEssZeroDofs(data.coarsest_ess_hdivdofs); + } + smoothers_[l] = coarse_solver; + continue; + } + + HypreParMatrix& P_hdiv_l = *data.P_hdiv[l-1].As(); + HypreParMatrix& P_l2_l = *data.P_l2[l-1].As(); + SparseMatrix& agg_hdivdof_l = *data.agg_hdivdof[l-1].As(); + SparseMatrix& agg_l2dof_l = *data.agg_l2dof[l-1].As(); + HypreParMatrix& Q_l2_l = *data.Q_l2[l-1].As(); + HypreParMatrix* C_l = data.C[l].As(); + + auto S0 = new SaddleSchwarzSmoother(M_f, B_f, agg_hdivdof_l, + agg_l2dof_l, P_l2_l, Q_l2_l); + if (param_.coupled_solve) + { + auto S1 = new BlockDiagonalPreconditioner(ops_offsets_[l]); + S1->SetDiagonalBlock(0, new AuxSpaceSmoother(M_f, C_l)); + S1->owns_blocks = true; + smoothers_[l] = new ProductSolver(ops_[l], S0, S1, false, true, true); + } + else + { + smoothers_[l] = S0; + } + + HypreParMatrix* M_c = TwoStepsRAP(P_hdiv_l, M_f, P_hdiv_l); + HypreParMatrix* B_c = TwoStepsRAP(P_l2_l, B_f, P_hdiv_l); + + ops_offsets_[l-1].SetSize(3, 0); + ops_offsets_[l-1][1] = M_c->NumRows(); + ops_offsets_[l-1][2] = M_c->NumRows() + B_c->NumRows(); + + blk_Ps_[l-1] = new BlockOperator(ops_offsets_[l], ops_offsets_[l-1]); + blk_Ps_[l-1]->SetBlock(0, 0, &P_hdiv_l); + blk_Ps_[l-1]->SetBlock(1, 1, &P_l2_l); + + ops_[l-1] = new BlockOperator(ops_offsets_[l-1]); + ops_[l-1]->SetBlock(0, 0, M_c); + ops_[l-1]->SetBlock(1, 0, B_c); + ops_[l-1]->SetBlock(0, 1, B_c->Transpose()); + ops_[l-1]->owns_blocks = true; + } + + Array own_ops(ops_.Size()); + Array own_smoothers(smoothers_.Size()); + Array own_Ps(blk_Ps_.Size()); + own_ops = true; + own_smoothers = true; + own_Ps = true; + + if (data_.P_l2.Size() == 0) { return; } + + if (param_.coupled_solve) + { + solver_.Reset(new GMRESSolver(B.GetComm())); + solver_.As()->SetOperator(*(ops_.Last())); + prec_.Reset(new Multigrid(ops_, smoothers_, blk_Ps_, + own_ops, own_smoothers, own_Ps)); + } + else + { + Array ops(data_.P_hcurl.Size()+1); + Array smoothers(ops.Size()); + Array Ps(data_.P_hcurl.Size()); + own_Ps = false; + + HypreParMatrix& C_finest = *data.C.Last().As(); + ops.Last() = TwoStepsRAP(C_finest, M, C_finest); + ops.Last()->EliminateZeroRows(); + ops.Last()->DropSmallEntries(1e-14); + + solver_.Reset(new CGSolver(B.GetComm())); + solver_.As()->SetOperator(*ops.Last()); + smoothers.Last() = new HypreSmoother(*ops.Last()); + static_cast(smoothers.Last())->SetOperatorSymmetry(true); + + for (int l = Ps.Size()-1; l >= 0; --l) + { + Ps[l] = data_.P_hcurl[l].As(); + ops[l] = TwoStepsRAP(*Ps[l], *ops[l+1], *Ps[l]); + ops[l]->DropSmallEntries(1e-14); + smoothers[l] = new HypreSmoother(*ops[l]); + static_cast(smoothers[l])->SetOperatorSymmetry(true); + } + + prec_.Reset(new Multigrid(ops, smoothers, Ps, own_ops, own_smoothers, own_Ps)); + } + + solver_.As()->SetPreconditioner(*prec_.As()); + SetOptions(*solver_.As(), param_); +} + +DivFreeSolver::~DivFreeSolver() +{ + if (param_.coupled_solve) { return; } + for (int i = 0; i < ops_.Size(); ++i) + { + delete ops_[i]; + delete smoothers_[i]; + if (i == ops_.Size() - 1) { break; } + delete blk_Ps_[i]; + } +} + +void DivFreeSolver::SolveParticular(const Vector& rhs, Vector& sol) const +{ + Array rhss(smoothers_.Size()); + Array sols(smoothers_.Size()); + + rhss.Last().SetDataAndSize(const_cast(rhs), rhs.Size()); + sols.Last().SetDataAndSize(sol, sol.Size()); + + for (int l = blk_Ps_.Size()-1; l >= 0; --l) + { + rhss[l].SetSize(blk_Ps_[l]->NumCols()); + sols[l].SetSize(blk_Ps_[l]->NumCols()); + blk_Ps_[l]->MultTranspose(rhss[l+1], rhss[l]); + } + + for (int l = 0; l < smoothers_.Size(); ++l) + { + smoothers_[l]->Mult(rhss[l], sols[l]); + } + + for (int l = 0; l < blk_Ps_.Size(); ++l) + { + Vector P_sol(blk_Ps_[l]->NumRows()); + blk_Ps_[l]->Mult(sols[l], P_sol); + sols[l+1] += P_sol; + } +} + +void DivFreeSolver::SolveDivFree(const Vector &rhs, Vector& sol) const +{ + Vector rhs_divfree(data_.C.Last()->NumCols()); + data_.C.Last()->MultTranspose(rhs, rhs_divfree); + + Vector potential_divfree(rhs_divfree.Size()); + potential_divfree = 0.0; + solver_->Mult(rhs_divfree, potential_divfree); + + data_.C.Last()->Mult(potential_divfree, sol); +} + +void DivFreeSolver::SolvePotential(const Vector& rhs, Vector& sol) const +{ + Vector rhs_p(BT_->NumCols()); + BT_->MultTranspose(rhs, rhs_p); + BBT_solver_.Mult(rhs_p, sol); +} + +void DivFreeSolver::Mult(const Vector & x, Vector & y) const +{ + MFEM_VERIFY(x.Size() == offsets_[2], "MLDivFreeSolver: x size is invalid"); + MFEM_VERIFY(y.Size() == offsets_[2], "MLDivFreeSolver: y size is invalid"); + + if (ops_.Size() == 1) { smoothers_[0]->Mult(x, y); return; } + + BlockVector blk_y(y, offsets_); + + BlockVector resid(offsets_); + ops_.Last()->Mult(y, resid); + add(1.0, x, -1.0, resid, resid); + + BlockVector correction(offsets_); + correction = 0.0; + + if (param_.coupled_solve) + { + solver_->Mult(resid, correction); + y += correction; + } + else + { + StopWatch ch; + ch.Start(); + + SolveParticular(resid, correction); + blk_y += correction; + + if (param_.verbose) + { + cout << "Particular solution found in " << ch.RealTime() << "s.\n"; + } + + ch.Clear(); + ch.Start(); + + ops_.Last()->Mult(y, resid); + add(1.0, x, -1.0, resid, resid); + + SolveDivFree(resid.GetBlock(0), correction.GetBlock(0)); + blk_y.GetBlock(0) += correction.GetBlock(0); + + if (param_.verbose) + { + cout << "Divergence free solution found in " << ch.RealTime() << "s.\n"; + } + + ch.Clear(); + ch.Start(); + + auto M = dynamic_cast(ops_.Last()->GetBlock(0, 0)); + M.Mult(-1.0, correction.GetBlock(0), 1.0, resid.GetBlock(0)); + SolvePotential(resid.GetBlock(0), correction.GetBlock(1)); + blk_y.GetBlock(1) += correction.GetBlock(1); + + if (param_.verbose) + { + cout << "Scalar potential found in " << ch.RealTime() << "s.\n"; + } + } +} + +int DivFreeSolver::GetNumIterations() const +{ + if (ops_.Size() == 1) + { + return static_cast(smoothers_[0])->GetNumIterations(); + } + return solver_.As()->GetNumIterations(); +} diff --git a/miniapps/solvers/div_free_solver.hpp b/miniapps/solvers/div_free_solver.hpp new file mode 100644 index 0000000000..d018686cc2 --- /dev/null +++ b/miniapps/solvers/div_free_solver.hpp @@ -0,0 +1,239 @@ +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-806117. +// +// This file is part of the MFEM library. For more information and source code +// availability visit https://mfem.org. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. + +#ifndef MFEM_DIVFREE_SOLVER_HPP +#define MFEM_DIVFREE_SOLVER_HPP + +#include "mfem.hpp" +#include + +namespace mfem +{ +namespace blocksolvers +{ + +/// Parameters for iterative solver +struct IterSolveParameters +{ + int print_level = 0; + int max_iter = 500; + double abs_tol = 1e-12; + double rel_tol = 1e-9; +}; + +/// Parameters for the divergence free solver +struct DFSParameters : IterSolveParameters +{ + /** There are three components in the solver: a particular solution + satisfying the divergence constraint, the remaining div-free component of + the flux, and the pressure. When coupled_solve == false, the three + components will be solved one by one in the aforementioned order. + Otherwise, they will be solved at the same time. */ + bool coupled_solve = false; + bool verbose = false; + IterSolveParameters coarse_solve_param; + IterSolveParameters BBT_solve_param; +}; + +/// Data for the divergence free solver +struct DFSData +{ + Array agg_hdivdof; // agglomerates to H(div) dofs table + Array agg_l2dof; // agglomerates to L2 dofs table + Array P_hdiv; // Interpolation matrix for H(div) space + Array P_l2; // Interpolation matrix for L2 space + Array P_hcurl; // Interpolation for kernel space of div + Array Q_l2; // Q_l2[l] = (W_{l+1})^{-1} P_l2[l]^T W_l + Array coarsest_ess_hdivdofs; // coarsest level essential H(div) dofs + Array C; // discrete curl: ND -> RT, map to Null(B) + DFSParameters param; +}; + +/// Finite element spaces concerning divergence free solver. +/// The main usage of this class is to collect data needed for the solver. +class DFSSpaces +{ + RT_FECollection hdiv_fec_; + L2_FECollection l2_fec_; + std::unique_ptr hcurl_fec_; + L2_FECollection l2_0_fec_; + + std::unique_ptr coarse_hdiv_fes_; + std::unique_ptr coarse_l2_fes_; + std::unique_ptr coarse_hcurl_fes_; + std::unique_ptr l2_0_fes_; + + std::unique_ptr hdiv_fes_; + std::unique_ptr l2_fes_; + std::unique_ptr hcurl_fes_; + + std::vector el_l2dof_; + const Array& ess_bdr_attr_; + Array all_bdr_attr_; + + int level_; + DFSData data_; + + void MakeDofRelationTables(int level); + void DataFinalize(); +public: + DFSSpaces(int order, int num_refine, ParMesh *mesh, + const Array& ess_attr, const DFSParameters& param); + + /** This should be called each time when the mesh (where the FE spaces are + defined) is refined. The spaces will be updated, and the prolongation for + the spaces and other data needed for the div-free solver are stored. */ + void CollectDFSData(); + + const DFSData& GetDFSData() const { return data_; } + ParFiniteElementSpace* GetHdivFES() const { return hdiv_fes_.get(); } + ParFiniteElementSpace* GetL2FES() const { return l2_fes_.get(); } +}; + +/// Abstract solver class for Darcy's flow +class DarcySolver : public Solver +{ +protected: + Array offsets_; +public: + DarcySolver(int size0, int size1) : Solver(size0 + size1), offsets_(3) + { offsets_[0] = 0; offsets_[1] = size0; offsets_[2] = height; } + virtual int GetNumIterations() const = 0; +}; + +/// Solver for B * B^T +/// Compute the product B * B^T and solve it with CG preconditioned by BoomerAMG +class BBTSolver : public Solver +{ + OperatorPtr BBT_; + OperatorPtr BBT_prec_; + CGSolver BBT_solver_; +public: + BBTSolver(const HypreParMatrix &B, IterSolveParameters param); + virtual void Mult(const Vector &x, Vector &y) const { BBT_solver_.Mult(x, y); } + virtual void SetOperator(const Operator &op) { } +}; + +/// Block diagonal solver for symmetric A, each block is inverted by direct solver +class SymDirectSubBlockSolver : public DirectSubBlockSolver +{ +public: + SymDirectSubBlockSolver(const SparseMatrix& A, const SparseMatrix& block_dof) + : DirectSubBlockSolver(A, block_dof) { } + virtual void MultTranspose(const Vector &x, Vector &y) const { Mult(x, y); } +}; + +/// non-overlapping additive Schwarz smoother for saddle point systems +/// [ M B^T ] +/// [ B 0 ] +class SaddleSchwarzSmoother : public Solver +{ + const SparseMatrix& agg_hdivdof_; + const SparseMatrix& agg_l2dof_; + OperatorPtr coarse_l2_projector_; + + Array offsets_; + mutable Array offsets_loc_; + mutable Array hdivdofs_loc_; + mutable Array l2dofs_loc_; + Array solvers_loc_; +public: + /** SaddleSchwarzSmoother solves local saddle point problems defined on a + list of non-overlapping aggregates (of elements). + @param agg_hdivdof aggregate to H(div) dofs relation table (boolean matrix) + @param agg_l2dof aggregate to L2 dofs relation table (boolean matrix) + @param P_l2 prolongation matrix of the discrete L2 space + @param Q_l2 projection matrix of the discrete L2 space: + Q_l2 := (P_l2 W P_l2)^{-1} * P_l2 * W, + where W is the mass matrix of the discrete L2 space. */ + SaddleSchwarzSmoother(const HypreParMatrix& M, + const HypreParMatrix& B, + const SparseMatrix& agg_hdivdof, + const SparseMatrix& agg_l2dof, + const HypreParMatrix& P_l2, + const HypreParMatrix& Q_l2); + virtual void Mult(const Vector &x, Vector &y) const; + virtual void MultTranspose(const Vector &x, Vector &y) const { Mult(x, y); } + virtual void SetOperator(const Operator &op) { } +}; + +/// Solver for local problems in SaddleSchwarzSmoother +class LocalSolver : public Solver +{ + DenseMatrix local_system_; + DenseMatrixInverse local_solver_; + const int offset_; +public: + LocalSolver(const DenseMatrix &M, const DenseMatrix &B); + virtual void Mult(const Vector &x, Vector &y) const; + virtual void SetOperator(const Operator &op) { } +}; + +/// Wrapper for the block-diagonal-preconditioned MINRES defined in ex5p.cpp +class BDPMinresSolver : public DarcySolver +{ + BlockOperator op_; + BlockDiagonalPreconditioner prec_; + OperatorPtr BT_; + OperatorPtr S_; // S_ = B diag(M)^{-1} B^T + MINRESSolver solver_; + Array ess_zero_dofs_; +public: + BDPMinresSolver(HypreParMatrix& M, HypreParMatrix& B, + IterSolveParameters param); + virtual void Mult(const Vector & x, Vector & y) const; + virtual void SetOperator(const Operator &op) { } + void SetEssZeroDofs(const Array& dofs) { dofs.Copy(ess_zero_dofs_); } + virtual int GetNumIterations() const { return solver_.GetNumIterations(); } +}; + +/** Divergence free solver. + The basic idea of the solver is to exploit a multilevel decomposition of + Raviart-Thomas space to find a particular solution satisfying the divergence + constraint, and then solve the remaining (divergence-free) component in the + kernel space of the discrete divergence operator. + + For more details see + 1. Vassilevski, Multilevel Block Factorization Preconditioners (Appendix F.3), + Springer, 2008. + 2. Voronin, Lee, Neumuller, Sepulveda, Vassilevski, Space-time discretizations + using constrained first-order system least squares (CFOSLS). + J. Comput. Phys. 373: 863-876, 2018. */ +class DivFreeSolver : public DarcySolver +{ + const DFSData& data_; + DFSParameters param_; + OperatorPtr BT_; + BBTSolver BBT_solver_; + Array> ops_offsets_; + Array ops_; + Array blk_Ps_; + Array smoothers_; + OperatorPtr prec_; + OperatorPtr solver_; + + void SolveParticular(const Vector& rhs, Vector& sol) const; + void SolveDivFree(const Vector& rhs, Vector& sol) const; + void SolvePotential(const Vector &rhs, Vector& sol) const; +public: + DivFreeSolver(const HypreParMatrix& M, const HypreParMatrix &B, + const DFSData& data); + ~DivFreeSolver(); + virtual void Mult(const Vector &x, Vector &y) const; + virtual void SetOperator(const Operator &op) { } + virtual int GetNumIterations() const; +}; + +} // namespace blocksolvers + +} // namespace mfem + +#endif // MFEM_DIVFREE_SOLVER_HPP diff --git a/miniapps/solvers/makefile b/miniapps/solvers/makefile new file mode 100644 index 0000000000..e7f15c76d0 --- /dev/null +++ b/miniapps/solvers/makefile @@ -0,0 +1,74 @@ +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced +# at the Lawrence Livermore National Laboratory. All Rights reserved. See files +# LICENSE and NOTICE for details. LLNL-CODE-806117. +# +# This file is part of the MFEM library. For more information and source code +# availability visit https://mfem.org. +# +# MFEM is free software; you can redistribute it and/or modify it under the +# terms of the BSD-3 license. We welcome feedback and contributions, see file +# CONTRIBUTING.md for details. + +# Use the MFEM build directory +MFEM_DIR ?= ../.. +MFEM_BUILD_DIR ?= ../.. +SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/miniapps/solvers/,) +CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk +# Use the MFEM install directory +# MFEM_INSTALL_DIR = ../../mfem +# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk + +MFEM_LIB_FILE = mfem_is_not_built +-include $(CONFIG_MK) + +BLOCK_COMMON_SRC = div_free_solver.cpp +BLOCK_COMMON_OBJ = $(BLOCK_COMMON_SRC:.cpp=.o) + +PAR_MINIAPPS = block-solvers + +ifeq ($(MFEM_USE_MPI),NO) + MINIAPPS = +else + MINIAPPS = $(PAR_MINIAPPS) +endif + +.SUFFIXES: +.SUFFIXES: .o .cpp .mk +.PHONY: all clean clean-build clean-exec + +# Remove built-in rules +%: %.cpp +%.o: %.cpp + +%: %.cpp $(BLOCK_COMMON_OBJ) + $(MFEM_CXX) $(MFEM_LINK_FLAGS) $< -o $@ $(BLOCK_COMMON_OBJ) $(MFEM_LIBS) + +%.o: %.cpp $(MFEM_LIB_FILE) $(CONFIG_MK) + $(MFEM_CXX) $(MFEM_FLAGS) -c $< -o $@ + +all: $(MINIAPPS) + +MFEM_TESTS = MINIAPPS +include $(MFEM_TEST_MK) + +# Testing: Specific execution options +RUN_MPI = $(MFEM_MPIEXEC) $(MFEM_MPIEXEC_NP) $(MFEM_MPI_NP) +block-solvers-test-par: block-solvers-constant block-solvers-anisotropic +block-solvers-constant: block-solvers + @$(call mfem-test,$<, $(RUN_MPI), BlockSolver miniapp,-r 2) +block-solvers-anisotropic: block-solvers + @$(call mfem-test,$<, $(RUN_MPI), BlockSolver miniapp,-r 2\ + -m anisotropic.mesh -c anisotropic.coeff -eb anisotropic.bdr) + +# Generate an error message if the MFEM library is not built and exit +$(MFEM_LIB_FILE): + $(error The MFEM library is not built) + +clean: clean-build clean-exec + +clean-build: + rm -f *.o *~ $(PAR_MINIAPPS) + rm -rf *.dSYM *.TVD.*breakpoints + +clean-exec: + @rm -rf block-solvers diff --git a/miniapps/tools/CMakeLists.txt b/miniapps/tools/CMakeLists.txt index 961b4e7408..d3c06a3e23 100644 --- a/miniapps/tools/CMakeLists.txt +++ b/miniapps/tools/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/miniapps/tools/convert-dc.cpp b/miniapps/tools/convert-dc.cpp index 4ff4558e40..35f7e3486b 100644 --- a/miniapps/tools/convert-dc.cpp +++ b/miniapps/tools/convert-dc.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/tools/display-basis.cpp b/miniapps/tools/display-basis.cpp index 52008c5b91..d3297fa251 100644 --- a/miniapps/tools/display-basis.cpp +++ b/miniapps/tools/display-basis.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/tools/get-values.cpp b/miniapps/tools/get-values.cpp index 060b67454d..956e4e4547 100644 --- a/miniapps/tools/get-values.cpp +++ b/miniapps/tools/get-values.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/tools/load-dc.cpp b/miniapps/tools/load-dc.cpp index 0540097091..d9c4d4dd8e 100644 --- a/miniapps/tools/load-dc.cpp +++ b/miniapps/tools/load-dc.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/tools/lor-transfer.cpp b/miniapps/tools/lor-transfer.cpp index dfa690dfba..df94d8802e 100644 --- a/miniapps/tools/lor-transfer.cpp +++ b/miniapps/tools/lor-transfer.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/tools/makefile b/miniapps/tools/makefile index 3b003e97ef..cddd0ca809 100644 --- a/miniapps/tools/makefile +++ b/miniapps/tools/makefile @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/miniapps/toys/CMakeLists.txt b/miniapps/toys/CMakeLists.txt index 86c5c5e672..397cd1d7fd 100644 --- a/miniapps/toys/CMakeLists.txt +++ b/miniapps/toys/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/miniapps/toys/automata.cpp b/miniapps/toys/automata.cpp index fc9e46f9f1..38a81bba3e 100644 --- a/miniapps/toys/automata.cpp +++ b/miniapps/toys/automata.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/toys/life.cpp b/miniapps/toys/life.cpp index 7f0fbf374a..69ee78639f 100644 --- a/miniapps/toys/life.cpp +++ b/miniapps/toys/life.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/toys/lissajous.cpp b/miniapps/toys/lissajous.cpp index 65d4e8324a..8581027f0f 100644 --- a/miniapps/toys/lissajous.cpp +++ b/miniapps/toys/lissajous.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/toys/makefile b/miniapps/toys/makefile index b5975a4b8a..1f7bf5392d 100644 --- a/miniapps/toys/makefile +++ b/miniapps/toys/makefile @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/miniapps/toys/mandel.cpp b/miniapps/toys/mandel.cpp index 189719e168..cb36721fa1 100644 --- a/miniapps/toys/mandel.cpp +++ b/miniapps/toys/mandel.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/toys/mondrian.cpp b/miniapps/toys/mondrian.cpp index 8263d4d3db..7d133b8b71 100644 --- a/miniapps/toys/mondrian.cpp +++ b/miniapps/toys/mondrian.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/toys/rubik.cpp b/miniapps/toys/rubik.cpp index a6d37d5a15..720fc98e0a 100644 --- a/miniapps/toys/rubik.cpp +++ b/miniapps/toys/rubik.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/miniapps/toys/snake.cpp b/miniapps/toys/snake.cpp index 915a8a0ba1..2ca0e885fa 100644 --- a/miniapps/toys/snake.cpp +++ b/miniapps/toys/snake.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6870eed54d..fde4045cb3 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/tests/convergence/makefile b/tests/convergence/makefile index ead634e016..17341c28b2 100644 --- a/tests/convergence/makefile +++ b/tests/convergence/makefile @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/tests/convergence/prates.cpp b/tests/convergence/prates.cpp index f66731e0b2..5a78e34142 100644 --- a/tests/convergence/prates.cpp +++ b/tests/convergence/prates.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/convergence/rates.cpp b/tests/convergence/rates.cpp index 08dcd3862b..3e45cbf9d0 100644 --- a/tests/convergence/rates.cpp +++ b/tests/convergence/rates.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/par-mesh-format/makefile b/tests/par-mesh-format/makefile index 0151f6115f..d8ec467d19 100644 --- a/tests/par-mesh-format/makefile +++ b/tests/par-mesh-format/makefile @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/tests/scripts/branch-history b/tests/scripts/branch-history index df2a2f9aa4..cce7f22354 100755 --- a/tests/scripts/branch-history +++ b/tests/scripts/branch-history @@ -1,6 +1,6 @@ #!/usr/bin/env perl -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/tests/scripts/code-style b/tests/scripts/code-style index 0a64f53f56..d3943e508e 100755 --- a/tests/scripts/code-style +++ b/tests/scripts/code-style @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/tests/scripts/documentation b/tests/scripts/documentation index 21ad54a055..8e2e674c69 100755 --- a/tests/scripts/documentation +++ b/tests/scripts/documentation @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/tests/scripts/gitignore b/tests/scripts/gitignore index a82941b41a..a45655c3c4 100755 --- a/tests/scripts/gitignore +++ b/tests/scripts/gitignore @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/tests/scripts/runtest b/tests/scripts/runtest index 7e9c6da7c2..5921c5b105 100755 --- a/tests/scripts/runtest +++ b/tests/scripts/runtest @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index 76c3229de8..5818ad065e 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # @@ -22,6 +22,7 @@ set(UNIT_TESTS_SRCS general/test_text.cpp general/test_zlib.cpp linalg/test_complex_operator.cpp + linalg/test_direct_solvers.cpp linalg/test_hypre_ilu.cpp linalg/test_ilu.cpp linalg/test_matrix_block.cpp @@ -37,38 +38,47 @@ set(UNIT_TESTS_SRCS linalg/test_vector.cpp mesh/test_mesh.cpp mesh/test_ncmesh.cpp + mesh/test_pmesh.cpp fem/test_1d_bilininteg.cpp fem/test_2d_bilininteg.cpp fem/test_3d_bilininteg.cpp fem/test_assemblediagonalpa.cpp + fem/test_blocknonlinearform.cpp fem/test_calcshape.cpp fem/test_calcvshape.cpp fem/test_calcdshape.cpp fem/test_calccurlshape.cpp fem/test_calcdivshape.cpp fem/test_datacollection.cpp + fem/test_estimator.cpp fem/test_face_permutation.cpp fem/test_fe.cpp fem/test_intrules.cpp fem/test_intruletypes.cpp fem/test_inversetransform.cpp + fem/test_lexicographic_ordering.cpp fem/test_lin_interp.cpp fem/test_linear_fes.cpp fem/test_operatorjacobismoother.cpp fem/test_pa_coeff.cpp fem/test_pa_kernels.cpp + fem/test_pa_grad.cpp + fem/test_pa_idinterp.cpp fem/test_quadf_coef.cpp fem/test_quadraturefunc.cpp - fem/test_blocknonlinearform.cpp + fem/test_sum_bilin.cpp miniapps/test_sedov.cpp ) if (MFEM_USE_CUDA) set_property(SOURCE ${UNIT_TESTS_SRCS} PROPERTY LANGUAGE CUDA) endif() +if (MFEM_USE_HIP) + set_property(SOURCE unit_test_main.cpp ${UNIT_TESTS_SRCS} PROPERTY HIP_SOURCE_PROPERTY_FORMAT TRUE) +endif() # All serial non-device unit tests are built into a single executable 'unit_tests'. -add_executable(unit_tests unit_test_main.cpp ${UNIT_TESTS_SRCS}) +mfem_add_executable(unit_tests unit_test_main.cpp ${UNIT_TESTS_SRCS}) # Unit tests need the ../../data directory. add_dependencies(unit_tests copy_data) target_link_libraries(unit_tests mfem) @@ -102,13 +112,16 @@ set(SEDOV_TESTS_SRCS if (MFEM_USE_CUDA) set_property(SOURCE ${SEDOV_TESTS_SRCS} PROPERTY LANGUAGE CUDA) endif() +if (MFEM_USE_HIP) + set_property(SOURCE ${SEDOV_TESTS_SRCS} PROPERTY HIP_SOURCE_PROPERTY_FORMAT TRUE) +endif() -add_executable(sedov_tests_cpu ${SEDOV_TESTS_SRCS}) +mfem_add_executable(sedov_tests_cpu ${SEDOV_TESTS_SRCS}) target_compile_definitions(sedov_tests_cpu PUBLIC MFEM_SEDOV_TESTS=1) target_compile_definitions(sedov_tests_cpu PUBLIC MFEM_SEDOV_DEVICE="cpu") target_link_libraries(sedov_tests_cpu mfem) -add_executable(sedov_tests_debug ${SEDOV_TESTS_SRCS}) +mfem_add_executable(sedov_tests_debug ${SEDOV_TESTS_SRCS}) target_compile_definitions(sedov_tests_debug PUBLIC MFEM_SEDOV_TESTS=1) target_compile_definitions(sedov_tests_debug PUBLIC MFEM_SEDOV_DEVICE="debug") target_link_libraries(sedov_tests_debug mfem) @@ -206,6 +219,13 @@ if (MFEM_USE_MPI) target_compile_definitions(psedov_tests_cuda_uvm PUBLIC MFEM_SEDOV_TESTS=1) target_compile_definitions(psedov_tests_cuda_uvm PUBLIC MFEM_SEDOV_DEVICE="cuda:uvm") target_link_libraries(psedov_tests_cuda_uvm mfem) + + set(PCUNIT_TESTS_SRCS pcunit_test_main.cpp) + set_property(SOURCE ${PCUNIT_TESTS_SRCS} PROPERTY LANGUAGE CUDA) + add_executable(pcunit_tests ${PCUNIT_TESTS_SRCS}) + add_dependencies(pcunit_tests copy_data) + target_link_libraries(pcunit_tests mfem) + add_dependencies(${MFEM_ALL_TESTS_TARGET_NAME} pcunit_tests) endif() add_dependencies(${MFEM_ALL_TESTS_TARGET_NAME} punit_tests psedov_tests_cpu psedov_tests_debug) diff --git a/tests/unit/ceed/test_ceed.cpp b/tests/unit/ceed/test_ceed.cpp index 799c4661f4..c108b13e38 100644 --- a/tests/unit/ceed/test_ceed.cpp +++ b/tests/unit/ceed/test_ceed.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/ceed/test_ceed_main.cpp b/tests/unit/ceed/test_ceed_main.cpp index 84bf67b526..774cfe095b 100644 --- a/tests/unit/ceed/test_ceed_main.cpp +++ b/tests/unit/ceed/test_ceed_main.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/cunit_test_main.cpp b/tests/unit/cunit_test_main.cpp index 61dc2f9a66..8fa71a7cd3 100644 --- a/tests/unit/cunit_test_main.cpp +++ b/tests/unit/cunit_test_main.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/fem/test_1d_bilininteg.cpp b/tests/unit/fem/test_1d_bilininteg.cpp index 9f6e36f7a3..8a8fa6b7be 100644 --- a/tests/unit/fem/test_1d_bilininteg.cpp +++ b/tests/unit/fem/test_1d_bilininteg.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/fem/test_2d_bilininteg.cpp b/tests/unit/fem/test_2d_bilininteg.cpp index 4f13c398bb..f5b9a5e1cd 100644 --- a/tests/unit/fem/test_2d_bilininteg.cpp +++ b/tests/unit/fem/test_2d_bilininteg.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/fem/test_3d_bilininteg.cpp b/tests/unit/fem/test_3d_bilininteg.cpp index 8ae67fc57a..962cf96343 100644 --- a/tests/unit/fem/test_3d_bilininteg.cpp +++ b/tests/unit/fem/test_3d_bilininteg.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/fem/test_assemblediagonalpa.cpp b/tests/unit/fem/test_assemblediagonalpa.cpp index 68b42e51c6..85742887d5 100644 --- a/tests/unit/fem/test_assemblediagonalpa.cpp +++ b/tests/unit/fem/test_assemblediagonalpa.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -95,23 +95,23 @@ void fullSymmetricMatrixCoeffFunction(const Vector & x, DenseMatrix & f) } } -void symmetricMatrixCoeffFunction(const Vector & x, Vector & f) +void symmetricMatrixCoeffFunction(const Vector & x, DenseSymmetricMatrix & f) { f = 0.0; if (dimension == 2) { - f[0] = 1.1 + sin(M_PI * x[1]); // 1,1 - f[1] = cos(2.5 * M_PI * x[0]); // 1,2 - f[2] = 1.1 + sin(4.9 * M_PI * x[0]); // 2,2 + f(0,0) = 1.1 + sin(M_PI * x[1]); // 1,1 + f(0,1) = cos(2.5 * M_PI * x[0]); // 1,2 + f(1,1) = 1.1 + sin(4.9 * M_PI * x[0]); // 2,2 } else if (dimension == 3) { - f[0] = sin(M_PI * x[1]); // 1,1 - f[1] = cos(2.5 * M_PI * x[0]); // 1,2 - f[2] = sin(4.9 * M_PI * x[2]); // 1,3 - f[3] = sin(6.1 * M_PI * x[1]); // 2,2 - f[4] = cos(6.1 * M_PI * x[2]); // 2,3 - f[5] = sin(6.1 * M_PI * x[2]); // 3,3 + f(0,0) = sin(M_PI * x[1]); // 1,1 + f(0,1) = cos(2.5 * M_PI * x[0]); // 1,2 + f(0,2) = sin(4.9 * M_PI * x[2]); // 1,3 + f(1,1) = sin(6.1 * M_PI * x[1]); // 2,2 + f(1,2) = cos(6.1 * M_PI * x[2]); // 2,3 + f(2,2) = sin(6.1 * M_PI * x[2]); // 3,3 } } @@ -191,7 +191,7 @@ TEST_CASE("diffusiondiag") Coefficient* coeff = nullptr; VectorCoefficient* vcoeff = nullptr; MatrixCoefficient* mcoeff = nullptr; - MatrixCoefficient* smcoeff = nullptr; + SymmetricMatrixCoefficient* smcoeff = nullptr; if (coeffType == 0) { coeff = new ConstantCoefficient(12.34); @@ -208,22 +208,25 @@ TEST_CASE("diffusiondiag") { mcoeff = new MatrixFunctionCoefficient(dimension, &fullSymmetricMatrixCoeffFunction); - smcoeff = new MatrixFunctionCoefficient(dimension, - &symmetricMatrixCoeffFunction); + smcoeff = new SymmetricMatrixFunctionCoefficient(dimension, + &symmetricMatrixCoeffFunction); } else if (coeffType == 4) { mcoeff = new MatrixFunctionCoefficient(dimension, &asymmetricMatrixCoeffFunction); - smcoeff = new MatrixFunctionCoefficient(dimension, - &asymmetricMatrixCoeffFunction); } BilinearForm paform(&h1_fespace); paform.SetAssemblyLevel(AssemblyLevel::PARTIAL); BilinearForm faform(&h1_fespace); - if (coeffType >= 3) + if (coeffType >= 4) + { + paform.AddDomainIntegrator(new DiffusionIntegrator(*mcoeff)); + faform.AddDomainIntegrator(new DiffusionIntegrator(*mcoeff)); + } + else if (coeffType == 3) { paform.AddDomainIntegrator(new DiffusionIntegrator(*smcoeff)); faform.AddDomainIntegrator(new DiffusionIntegrator(*mcoeff)); @@ -360,9 +363,9 @@ TEST_CASE("Hcurl/Hdiv diagonal PA", const int numSpaces = (coeffType == 0) ? 2 : 1; Coefficient* coeff = nullptr; - VectorCoefficient* vcoeff = nullptr; + DiagonalMatrixCoefficient* dcoeff = nullptr; MatrixCoefficient* mcoeff = nullptr; - MatrixCoefficient* smcoeff = nullptr; + SymmetricMatrixCoefficient* smcoeff = nullptr; if (coeffType == 0) { coeff = new ConstantCoefficient(12.34); @@ -373,21 +376,19 @@ TEST_CASE("Hcurl/Hdiv diagonal PA", } else if (coeffType == 2) { - vcoeff = new VectorFunctionCoefficient(dimension, &vectorCoeffFunction); + dcoeff = new VectorFunctionCoefficient(dimension, &vectorCoeffFunction); } else if (coeffType == 3) { mcoeff = new MatrixFunctionCoefficient(dimension, &fullSymmetricMatrixCoeffFunction); - smcoeff = new MatrixFunctionCoefficient(dimension, - &symmetricMatrixCoeffFunction); + smcoeff = new SymmetricMatrixFunctionCoefficient(dimension, + &symmetricMatrixCoeffFunction); } else if (coeffType == 4) { mcoeff = new MatrixFunctionCoefficient(dimension, &asymmetricMatrixCoeffFunction); - smcoeff = new MatrixFunctionCoefficient(dimension, - &asymmetricMatrixCoeffFunction); } enum Spaces {Hcurl, Hdiv}; @@ -432,15 +433,20 @@ TEST_CASE("Hcurl/Hdiv diagonal PA", paform.SetAssemblyLevel(AssemblyLevel::PARTIAL); if (integrator == 0) { - if (coeffType >= 3) + if (coeffType >= 4) + { + paform.AddDomainIntegrator(new VectorFEMassIntegrator(*mcoeff)); + faform.AddDomainIntegrator(new VectorFEMassIntegrator(*mcoeff)); + } + else if (coeffType == 3) { paform.AddDomainIntegrator(new VectorFEMassIntegrator(*smcoeff)); faform.AddDomainIntegrator(new VectorFEMassIntegrator(*mcoeff)); } else if (coeffType == 2) { - paform.AddDomainIntegrator(new VectorFEMassIntegrator(*vcoeff)); - faform.AddDomainIntegrator(new VectorFEMassIntegrator(*vcoeff)); + paform.AddDomainIntegrator(new VectorFEMassIntegrator(*dcoeff)); + faform.AddDomainIntegrator(new VectorFEMassIntegrator(*dcoeff)); } else { @@ -456,15 +462,20 @@ TEST_CASE("Hcurl/Hdiv diagonal PA", const IntegrationRule *intRule = &MassIntegrator::GetRule(*fel, *fel, *mesh->GetElementTransformation(0)); - if (coeffType >= 3) + if (coeffType >= 4) + { + paform.AddDomainIntegrator(new CurlCurlIntegrator(*mcoeff, intRule)); + faform.AddDomainIntegrator(new CurlCurlIntegrator(*mcoeff, intRule)); + } + else if (coeffType == 3) { paform.AddDomainIntegrator(new CurlCurlIntegrator(*smcoeff, intRule)); faform.AddDomainIntegrator(new CurlCurlIntegrator(*mcoeff, intRule)); } else if (coeffType == 2) { - paform.AddDomainIntegrator(new CurlCurlIntegrator(*vcoeff, intRule)); - faform.AddDomainIntegrator(new CurlCurlIntegrator(*vcoeff, intRule)); + paform.AddDomainIntegrator(new CurlCurlIntegrator(*dcoeff, intRule)); + faform.AddDomainIntegrator(new CurlCurlIntegrator(*dcoeff, intRule)); } else { @@ -500,7 +511,7 @@ TEST_CASE("Hcurl/Hdiv diagonal PA", } // spaceType delete coeff; - delete vcoeff; + delete dcoeff; delete mcoeff; delete smcoeff; } // coeffType diff --git a/tests/unit/fem/test_assembly_levels.cpp b/tests/unit/fem/test_assembly_levels.cpp index b7fc17bad2..4b5cdd7fe3 100644 --- a/tests/unit/fem/test_assembly_levels.cpp +++ b/tests/unit/fem/test_assembly_levels.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/fem/test_bilinearform.cpp b/tests/unit/fem/test_bilinearform.cpp index 59aef4e6f9..5678d81805 100644 --- a/tests/unit/fem/test_bilinearform.cpp +++ b/tests/unit/fem/test_bilinearform.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/fem/test_blocknonlinearform.cpp b/tests/unit/fem/test_blocknonlinearform.cpp index 3a4cff2804..8794d1d7d8 100644 --- a/tests/unit/fem/test_blocknonlinearform.cpp +++ b/tests/unit/fem/test_blocknonlinearform.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/fem/test_calcshape.cpp b/tests/unit/fem/test_calcshape.cpp index 5bd1e407ed..32b5d29f5d 100644 --- a/tests/unit/fem/test_calcshape.cpp +++ b/tests/unit/fem/test_calcshape.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/fem/test_datacollection.cpp b/tests/unit/fem/test_datacollection.cpp index 5dcfa1712e..f8db56428e 100644 --- a/tests/unit/fem/test_datacollection.cpp +++ b/tests/unit/fem/test_datacollection.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/fem/test_derefine.cpp b/tests/unit/fem/test_derefine.cpp index 9203a1511a..ce7a6f12b5 100644 --- a/tests/unit/fem/test_derefine.cpp +++ b/tests/unit/fem/test_derefine.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/fem/test_eigs.cpp b/tests/unit/fem/test_eigs.cpp index 5e11753e76..58593f71c9 100644 --- a/tests/unit/fem/test_eigs.cpp +++ b/tests/unit/fem/test_eigs.cpp @@ -51,6 +51,8 @@ int eigs[21] = 7,10,13,15,16,19,21 }; +#ifdef MFEM_USE_LAPACK +# TEST_CASE("Laplacian Eigenvalues", "[H1_FECollection]" "[GridFunction]" @@ -154,6 +156,8 @@ TEST_CASE("Laplacian Eigenvalues", } } +#endif // MFEM_USE_LAPACK + #ifdef MFEM_USE_MPI # TEST_CASE("Laplacian Eigenvalues in Parallel", diff --git a/tests/unit/fem/test_estimator.cpp b/tests/unit/fem/test_estimator.cpp new file mode 100644 index 0000000000..b4cb6729b1 --- /dev/null +++ b/tests/unit/fem/test_estimator.cpp @@ -0,0 +1,438 @@ +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-806117. +// +// This file is part of the MFEM library. For more information and source code +// availability visit https://mfem.org. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. + +#include "mfem.hpp" +#include "unit_tests.hpp" + +#include +#include + +using namespace mfem; + +#if defined(MFEM_USE_MPI) + +namespace testhelper +{ +double SmoothSolutionX(const mfem::Vector& x) +{ + return x(0); +} + +double SmoothSolutionY(const mfem::Vector& x) +{ + return x(1); +} + +double SmoothSolutionZ(const mfem::Vector& x) +{ + return x(2); +} + +double NonsmoothSolutionX(const mfem::Vector& x) +{ + return std::abs(x(0)-0.5); +} + +double NonsmoothSolutionY(const mfem::Vector& x) +{ + return std::abs(x(1)-0.5); +} + +double NonsmoothSolutionZ(const mfem::Vector& x) +{ + return std::abs(x(2)-0.5); +} +} + +TEST_CASE("Kelly Error Estimator on 2D NCMesh", + "[NCMesh], [Parallel]") +{ + // Setup + const auto order = GENERATE(1, 3, 5); + auto mesh = new Mesh(2, 2, Element::QUADRILATERAL); + + // Make the mesh NC + mesh->EnsureNCMesh(); + { + Array elements_to_refine(1); + elements_to_refine[0] = 1; + mesh->GeneralRefinement(elements_to_refine, 1, 0); + } + + auto pmesh = new ParMesh(MPI_COMM_WORLD, *mesh); + delete mesh; + + H1_FECollection fe_coll(order, pmesh->Dimension()); + ParFiniteElementSpace fespace(pmesh, &fe_coll); + + SECTION("Perfect Approximation X") + { + FunctionCoefficient u_analytic(testhelper::SmoothSolutionX); + ParGridFunction u_gf(&fespace); + u_gf.ProjectCoefficient(u_analytic); + + L2_FECollection flux_fec(order, pmesh->Dimension()); + ParFiniteElementSpace flux_fes(pmesh, &flux_fec, pmesh->SpaceDimension()); + DiffusionIntegrator di; + KellyErrorEstimator estimator(di, u_gf, flux_fes); + + auto &local_errors = estimator.GetLocalErrors(); + for (int i=0; iDimension()); + ParFiniteElementSpace flux_fes(pmesh, &flux_fec, pmesh->SpaceDimension()); + DiffusionIntegrator di; + KellyErrorEstimator estimator(di, u_gf, flux_fes); + + auto &local_errors = estimator.GetLocalErrors(); + for (int i=0; iDimension()); + ParFiniteElementSpace flux_fes(pmesh, &flux_fec, pmesh->SpaceDimension()); + DiffusionIntegrator di; + KellyErrorEstimator estimator(di, u_gf, flux_fes); + + auto &local_errors = estimator.GetLocalErrors(); + for (int i=0; i= 0.0); + } + REQUIRE(estimator.GetTotalError() > 0.0); + } + + SECTION("Nonsmooth Approximation Y") + { + FunctionCoefficient u_analytic(testhelper::NonsmoothSolutionY); + ParGridFunction u_gf(&fespace); + u_gf.ProjectCoefficient(u_analytic); + + L2_FECollection flux_fec(order, pmesh->Dimension()); + ParFiniteElementSpace flux_fes(pmesh, &flux_fec, pmesh->SpaceDimension()); + DiffusionIntegrator di; + KellyErrorEstimator estimator(di, u_gf, flux_fes); + + auto &local_errors = estimator.GetLocalErrors(); + for (int i=0; i= MFEM_Approx(0.0)); + } + REQUIRE(estimator.GetTotalError() > 0.0); + } + + delete pmesh; +} + +TEST_CASE("Kelly Error Estimator on 2D NCMesh embedded in 3D", + "[NCMesh], [Parallel]") +{ + // Setup + const auto order = GENERATE(1, 3, 5); + + // Manually construct embedded mesh + std::array vertices = + { + 0.0,0.0,0.0, + 0.0,1.0,0.0, + 1.0,1.0,0.0, + 1.0,0.0,0.0 + }; + + std::array element_indices = + { + 0,1,2,3 + }; + + std::array element_attributes = + { + 1 + }; + + std::array boundary_indices = + { + 0,1, + 1,2, + 2,3, + 3,0 + }; + + std::array boundary_attributes = + { + 1, + 1, + 1, + 1 + }; + + auto mesh = new Mesh( + vertices.data(), 4, + element_indices.data(), Geometry::SQUARE, + element_attributes.data(), 1, + boundary_indices.data(), Geometry::SEGMENT, + boundary_attributes.data(), 4, + 2, 3 + ); + mesh->UniformRefinement(); + mesh->Finalize(); + + // Make the mesh NC + mesh->EnsureNCMesh(); + { + Array elements_to_refine(1); + elements_to_refine[0] = 1; + mesh->GeneralRefinement(elements_to_refine, 1, 0); + } + + auto pmesh = new ParMesh(MPI_COMM_WORLD, *mesh); + delete mesh; + + H1_FECollection fe_coll(order, pmesh->Dimension()); + ParFiniteElementSpace fespace(pmesh, &fe_coll); + + SECTION("Perfect Approximation X") + { + FunctionCoefficient u_analytic(testhelper::SmoothSolutionX); + ParGridFunction u_gf(&fespace); + u_gf.ProjectCoefficient(u_analytic); + + L2_FECollection flux_fec(order, pmesh->Dimension()); + ParFiniteElementSpace flux_fes(pmesh, &flux_fec, pmesh->SpaceDimension()); + DiffusionIntegrator di; + KellyErrorEstimator estimator(di, u_gf, flux_fes); + + auto &local_errors = estimator.GetLocalErrors(); + for (int i=0; iDimension()); + ParFiniteElementSpace flux_fes(pmesh, &flux_fec, pmesh->SpaceDimension()); + DiffusionIntegrator di; + KellyErrorEstimator estimator(di, u_gf, flux_fes); + + auto &local_errors = estimator.GetLocalErrors(); + for (int i=0; iDimension()); + ParFiniteElementSpace flux_fes(pmesh, &flux_fec, pmesh->SpaceDimension()); + DiffusionIntegrator di; + KellyErrorEstimator estimator(di, u_gf, flux_fes); + + auto &local_errors = estimator.GetLocalErrors(); + for (int i=0; i= 0.0); + } + REQUIRE(estimator.GetTotalError() > 0.0); + } + + SECTION("Nonsmooth Approximation Y") + { + FunctionCoefficient u_analytic(testhelper::NonsmoothSolutionY); + ParGridFunction u_gf(&fespace); + u_gf.ProjectCoefficient(u_analytic); + + L2_FECollection flux_fec(order, pmesh->Dimension()); + ParFiniteElementSpace flux_fes(pmesh, &flux_fec, pmesh->SpaceDimension()); + DiffusionIntegrator di; + KellyErrorEstimator estimator(di, u_gf, flux_fes); + + auto &local_errors = estimator.GetLocalErrors(); + for (int i=0; i= MFEM_Approx(0.0)); + } + REQUIRE(estimator.GetTotalError() > 0.0); + } + + delete pmesh; +} + +TEST_CASE("Kelly Error Estimator on 3D NCMesh", + "[NCMesh], [Parallel]") +{ + // Setup + const auto order = GENERATE(1, 3, 5); + auto mesh = new Mesh(2, 2, 2, Element::HEXAHEDRON); + + // Make the mesh NC + mesh->EnsureNCMesh(); + { + Array elements_to_refine(1); + elements_to_refine[0] = 1; + mesh->GeneralRefinement(elements_to_refine, 1, 0); + } + + auto pmesh = new ParMesh(MPI_COMM_WORLD, *mesh); + delete mesh; + + H1_FECollection fe_coll(order, pmesh->Dimension()); + ParFiniteElementSpace fespace(pmesh, &fe_coll); + + SECTION("Perfect Approximation X") + { + FunctionCoefficient u_analytic(testhelper::SmoothSolutionX); + ParGridFunction u_gf(&fespace); + u_gf.ProjectCoefficient(u_analytic); + + L2_FECollection flux_fec(order, pmesh->Dimension()); + ParFiniteElementSpace flux_fes(pmesh, &flux_fec, pmesh->SpaceDimension()); + DiffusionIntegrator di; + KellyErrorEstimator estimator(di, u_gf, flux_fes); + + auto &local_errors = estimator.GetLocalErrors(); + for (int i=0; iDimension()); + ParFiniteElementSpace flux_fes(pmesh, &flux_fec, pmesh->SpaceDimension()); + DiffusionIntegrator di; + KellyErrorEstimator estimator(di, u_gf, flux_fes); + + auto &local_errors = estimator.GetLocalErrors(); + for (int i=0; iDimension()); + ParFiniteElementSpace flux_fes(pmesh, &flux_fec, pmesh->SpaceDimension()); + DiffusionIntegrator di; + KellyErrorEstimator estimator(di, u_gf, flux_fes); + + auto &local_errors = estimator.GetLocalErrors(); + for (int i=0; iDimension()); + ParFiniteElementSpace flux_fes(pmesh, &flux_fec, pmesh->SpaceDimension()); + DiffusionIntegrator di; + KellyErrorEstimator estimator(di, u_gf, flux_fes); + + auto &local_errors = estimator.GetLocalErrors(); + for (int i=0; i= 0.0); + } + REQUIRE(estimator.GetTotalError() > 0.0); + } + + SECTION("Nonsmooth Approximation Y") + { + FunctionCoefficient u_analytic(testhelper::NonsmoothSolutionY); + ParGridFunction u_gf(&fespace); + u_gf.ProjectCoefficient(u_analytic); + + L2_FECollection flux_fec(order, pmesh->Dimension()); + ParFiniteElementSpace flux_fes(pmesh, &flux_fec, pmesh->SpaceDimension()); + DiffusionIntegrator di; + KellyErrorEstimator estimator(di, u_gf, flux_fes); + + auto &local_errors = estimator.GetLocalErrors(); + for (int i=0; i= MFEM_Approx(0.0)); + } + REQUIRE(estimator.GetTotalError() > 0.0); + } + + SECTION("Nonsmooth Approximation Z") + { + FunctionCoefficient u_analytic(testhelper::NonsmoothSolutionZ); + ParGridFunction u_gf(&fespace); + u_gf.ProjectCoefficient(u_analytic); + + L2_FECollection flux_fec(order, pmesh->Dimension()); + ParFiniteElementSpace flux_fes(pmesh, &flux_fec, pmesh->SpaceDimension()); + DiffusionIntegrator di; + KellyErrorEstimator estimator(di, u_gf, flux_fes); + + auto &local_errors = estimator.GetLocalErrors(); + for (int i=0; i= 0.0); + } + REQUIRE(estimator.GetTotalError() > 0.0); + } + + delete pmesh; +} + +#endif diff --git a/tests/unit/fem/test_face_elem_trans.cpp b/tests/unit/fem/test_face_elem_trans.cpp index b940e45671..01d70236e3 100644 --- a/tests/unit/fem/test_face_elem_trans.cpp +++ b/tests/unit/fem/test_face_elem_trans.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/fem/test_face_permutation.cpp b/tests/unit/fem/test_face_permutation.cpp index 9abdd6794c..3b3be7c170 100644 --- a/tests/unit/fem/test_face_permutation.cpp +++ b/tests/unit/fem/test_face_permutation.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/fem/test_fe.cpp b/tests/unit/fem/test_fe.cpp index 9a92ddeef9..32097d6dd4 100644 --- a/tests/unit/fem/test_fe.cpp +++ b/tests/unit/fem/test_fe.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/fem/test_get_value.cpp b/tests/unit/fem/test_get_value.cpp index 615003381e..c3f77da50f 100644 --- a/tests/unit/fem/test_get_value.cpp +++ b/tests/unit/fem/test_get_value.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/fem/test_intrules.cpp b/tests/unit/fem/test_intrules.cpp index 60686735f8..048fcf025c 100644 --- a/tests/unit/fem/test_intrules.cpp +++ b/tests/unit/fem/test_intrules.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/fem/test_intruletypes.cpp b/tests/unit/fem/test_intruletypes.cpp index 86fb4e5d24..cb85272bc2 100644 --- a/tests/unit/fem/test_intruletypes.cpp +++ b/tests/unit/fem/test_intruletypes.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/fem/test_inversetransform.cpp b/tests/unit/fem/test_inversetransform.cpp index 498d8494a1..2a86d7c039 100644 --- a/tests/unit/fem/test_inversetransform.cpp +++ b/tests/unit/fem/test_inversetransform.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/fem/test_lexicographic_ordering.cpp b/tests/unit/fem/test_lexicographic_ordering.cpp new file mode 100644 index 0000000000..a265faecf8 --- /dev/null +++ b/tests/unit/fem/test_lexicographic_ordering.cpp @@ -0,0 +1,64 @@ +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-806117. +// +// This file is part of the MFEM library. For more information and source code +// availability visit https://mfem.org. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. + +#include "mfem.hpp" +#include "unit_tests.hpp" + +using namespace mfem; + +void VerifyOrdering(NodalFiniteElement &el) +{ + int order = el.GetOrder(); + Geometry::Type geom = el.GetGeomType(); + const Array &p = el.GetLexicographicOrdering(); + + GeometryRefiner refiner; + refiner.SetType(BasisType::GaussLobatto); + RefinedGeometry *ref_geom = refiner.Refine(geom, order); + + double error = 0.0; + + for (int i=0; i 0) ? p[i] : i; + error += std::fabs(el.GetNodes()[pi].x - ref_geom->RefPts[i].x); + error += std::fabs(el.GetNodes()[pi].y - ref_geom->RefPts[i].y); + error += std::fabs(el.GetNodes()[pi].z - ref_geom->RefPts[i].z); + } + + REQUIRE(error == MFEM_Approx(0.0)); +} + +template void VerifyOrdering(int order) +{ + T el(order, BasisType::GaussLobatto); + Geometry::Type geom = el.GetGeomType(); + INFO("order " << order << " " << Geometry::Name[geom]); + VerifyOrdering(el); +} + +TEST_CASE("Lexicographic Ordering", "[FiniteElement,Geometry]") +{ + auto order = GENERATE(1, 2, 3, 4, 5, 6); + VerifyOrdering(order); + VerifyOrdering(order); + VerifyOrdering(order); + VerifyOrdering(order); + VerifyOrdering(order); + VerifyOrdering(order); + + VerifyOrdering(order); + VerifyOrdering(order); + VerifyOrdering(order); + VerifyOrdering(order); + VerifyOrdering(order); + VerifyOrdering(order); +} diff --git a/tests/unit/fem/test_lin_interp.cpp b/tests/unit/fem/test_lin_interp.cpp index de50e2c4e3..dc5d19cb35 100644 --- a/tests/unit/fem/test_lin_interp.cpp +++ b/tests/unit/fem/test_lin_interp.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -17,6 +17,36 @@ using namespace mfem; namespace lin_interp { +double f1(const Vector & x) { return 2.345 * x[0]; } +double grad_f1(const Vector & x) { return 2.345; } +void Grad_f1(const Vector & x, Vector & df) +{ + df.SetSize(1); + df[0] = grad_f1(x); +} + +double f2(const Vector & x) { return 2.345 * x[0] + 3.579 * x[1]; } +void F2(const Vector & x, Vector & v) +{ + v.SetSize(2); + v[0] = 1.234 * x[0] - 2.357 * x[1]; + v[1] = 3.572 * x[0] + 4.321 * x[1]; +} + +void Grad_f2(const Vector & x, Vector & df) +{ + df.SetSize(2); + df[0] = 2.345; + df[1] = 3.579; +} +double curlF2(const Vector & x) { return 3.572 + 2.357; } +void CurlF2(const Vector & x, Vector & v) +{ + v.SetSize(1); + v[0] = curlF2(x); +} +double DivF2(const Vector & x) { return 1.234 + 4.321; } + double f3(const Vector & x) { return 2.345 * x[0] + 3.579 * x[1] + 4.680 * x[2]; } void F3(const Vector & x, Vector & v) @@ -27,9 +57,34 @@ void F3(const Vector & x, Vector & v) v[2] = -2.572 * x[0] + 1.321 * x[1] + 3.234 * x[2]; } +void Grad_f3(const Vector & x, Vector & df) +{ + df.SetSize(3); + df[0] = 2.345; + df[1] = 3.579; + df[2] = 4.680; +} +void CurlF3(const Vector & x, Vector & df) +{ + df.SetSize(3); + df[0] = 1.321 + 1.234; + df[1] = 3.572 + 2.572; + df[2] = 2.537 + 2.357; +} +double DivF3(const Vector & x) +{ return 1.234 + 4.321 + 3.234; } + +double g1(const Vector & x) { return 4.234 * x[0]; } +double g2(const Vector & x) { return 4.234 * x[0] + 3.357 * x[1]; } double g3(const Vector & x) { return 4.234 * x[0] + 3.357 * x[1] + 1.572 * x[2]; } +void G2(const Vector & x, Vector & v) +{ + v.SetSize(2); + v[0] = 4.234 * x[0] + 3.357 * x[1]; + v[1] = 4.537 * x[0] + 1.321 * x[1]; +} void G3(const Vector & x, Vector & v) { v.SetSize(3); @@ -38,6 +93,27 @@ void G3(const Vector & x, Vector & v) v[2] = 1.572 * x[0] + 2.321 * x[1] + 3.234 * x[2]; } +double fg1(const Vector & x) { return f1(x) * g1(x); } + +double fg2(const Vector & x) { return f2(x) * g2(x); } +void fG2(const Vector & x, Vector & v) { G2(x, v); v *= f2(x); } +void Fg2(const Vector & x, Vector & v) { F2(x, v); v *= g2(x); } + +void FcrossG2(const Vector & x, Vector & FxG) +{ + Vector F; F2(x, F); + Vector G; G2(x, G); + FxG.SetSize(1); + FxG(0) = F(0) * G(1) - F(1) * G(0); +} + +double FdotG2(const Vector & x) +{ + Vector F; F2(x, F); + Vector G; G2(x, G); + return F * G; +} + double fg3(const Vector & x) { return f3(x) * g3(x); } void fG3(const Vector & x, Vector & v) { G3(x, v); v *= f3(x); } void Fg3(const Vector & x, Vector & v) { F3(x, v); v *= g3(x); } @@ -59,164 +135,805 @@ double FdotG3(const Vector & x) return F * G; } -TEST_CASE("Linear Interpolators") +TEST_CASE("Identity Linear Interpolators", + "[IdentityInterpolator]") { - int order_h1 = 1, order_nd = 2, order_rt = 2, n = 3, dim = 3; + int order_h1 = 1, order_nd = 2, order_rt = 1, order_l2 = 1, n = 3, dim = -1; double tol = 1e-9; - Mesh mesh(n, n, n, Element::HEXAHEDRON, 1, 2.0, 3.0, 5.0); - - FunctionCoefficient fCoef(f3); - VectorFunctionCoefficient FCoef(dim, F3); - - FunctionCoefficient gCoef(g3); - VectorFunctionCoefficient GCoef(dim, G3); - - FunctionCoefficient fgCoef(fg3); - FunctionCoefficient FGCoef(FdotG3); - VectorFunctionCoefficient fGCoef(dim, fG3); - VectorFunctionCoefficient FgCoef(dim, Fg3); - VectorFunctionCoefficient FxGCoef(dim, FcrossG3); - - SECTION("Operators on H1") + for (int type = (int)Element::SEGMENT; + type <= (int)Element::HEXAHEDRON; type++) { - H1_FECollection fec_h1(order_h1, dim); - FiniteElementSpace fespace_h1(&mesh, &fec_h1); + Mesh *mesh = NULL; - GridFunction g0(&fespace_h1); - g0.ProjectCoefficient(gCoef); - - SECTION("Mapping H1 to H1") + if (type < (int)Element::TRIANGLE) { - GridFunction f0(&fespace_h1); - f0.ProjectCoefficient(fCoef); + dim = 1; + mesh = new Mesh(n, (Element::Type)type, 1, 2.0); - H1_FECollection fec_h1p(2*order_h1, dim); - FiniteElementSpace fespace_h1p(&mesh, &fec_h1p); - - DiscreteLinearOperator Opf0(&fespace_h1,&fespace_h1p); - Opf0.AddDomainInterpolator(new ScalarProductInterpolator(fCoef)); - Opf0.Assemble(); - - GridFunction fg0(&fespace_h1p); - Opf0.Mult(g0,fg0); - - REQUIRE( fg0.ComputeL2Error(fgCoef) < tol ); } - SECTION("Mapping to HCurl") + else if (type < (int)Element::TETRAHEDRON) { - ND_FECollection fec_nd(order_nd, dim); - FiniteElementSpace fespace_nd(&mesh, &fec_nd); - - GridFunction F1(&fespace_nd); - F1.ProjectCoefficient(FCoef); - - ND_FECollection fec_ndp(order_h1+order_nd, dim); - FiniteElementSpace fespace_ndp(&mesh, &fec_ndp); - - DiscreteLinearOperator OpF1(&fespace_h1,&fespace_ndp); - OpF1.AddDomainInterpolator(new VectorScalarProductInterpolator(FCoef)); - OpF1.Assemble(); - - GridFunction Fg1(&fespace_ndp); - OpF1.Mult(g0,Fg1); - - REQUIRE( Fg1.ComputeL2Error(FgCoef) < tol ); + dim = 2; + mesh = new Mesh(n, n, (Element::Type)type, 1, 2.0, 3.0); + } + else + { + dim = 3; + mesh = new Mesh(n, n, n, (Element::Type)type, 1, 2.0, 3.0, 5.0); } - } - SECTION("Operators on HCurl") - { - ND_FECollection fec_nd(order_nd, dim); - FiniteElementSpace fespace_nd(&mesh, &fec_nd); - GridFunction G1(&fespace_nd); - G1.ProjectCoefficient(GCoef); + FunctionCoefficient fCoef((dim==1) ? f1 : + ((dim==2) ? f2 : f3)); + VectorFunctionCoefficient dfCoef(dim, + (dim==1) ? Grad_f1 : + ((dim==2)? Grad_f2 : Grad_f3)); - SECTION("Mapping HCurl to HCurl") + SECTION("Operators on H1 for element type " + std::to_string(type)) { H1_FECollection fec_h1(order_h1, dim); - FiniteElementSpace fespace_h1(&mesh, &fec_h1); + FiniteElementSpace fespace_h1(mesh, &fec_h1); GridFunction f0(&fespace_h1); f0.ProjectCoefficient(fCoef); - ND_FECollection fec_ndp(order_nd+order_h1, dim); - FiniteElementSpace fespace_ndp(&mesh, &fec_ndp); + SECTION("Mapping to H1") + { + H1_FECollection fec_h1p(order_h1+1, dim); + FiniteElementSpace fespace_h1p(mesh, &fec_h1p); - DiscreteLinearOperator Opf0(&fespace_nd,&fespace_ndp); - Opf0.AddDomainInterpolator(new ScalarVectorProductInterpolator(fCoef)); - Opf0.Assemble(); + GridFunction f0p(&fespace_h1p); - GridFunction fG1(&fespace_ndp); - Opf0.Mult(G1,fG1); + DiscreteLinearOperator Op(&fespace_h1,&fespace_h1p); + Op.AddDomainInterpolator(new IdentityInterpolator()); + Op.Assemble(); - REQUIRE( fG1.ComputeL2Error(fGCoef) < tol ); + Op.Mult(f0,f0p); + + REQUIRE( f0p.ComputeH1Error(&fCoef, &dfCoef) < tol ); + } + SECTION("Mapping to L2") + { + L2_FECollection fec_l2(order_l2, dim); + FiniteElementSpace fespace_l2(mesh, &fec_l2); + + GridFunction f1(&fespace_l2); + + DiscreteLinearOperator Op(&fespace_h1,&fespace_l2); + Op.AddDomainInterpolator(new IdentityInterpolator()); + Op.Assemble(); + + Op.Mult(f0,f1); + + REQUIRE( f1.ComputeL2Error(fCoef) < tol ); + } + SECTION("Mapping to L2 (INTEGRAL)") + { + L2_FECollection fec_l2(order_l2, dim, + BasisType::GaussLegendre, + FiniteElement::INTEGRAL); + FiniteElementSpace fespace_l2(mesh, &fec_l2); + + GridFunction f1(&fespace_l2); + + DiscreteLinearOperator Op(&fespace_h1,&fespace_l2); + Op.AddDomainInterpolator(new IdentityInterpolator()); + Op.Assemble(); + + Op.Mult(f0,f1); + + REQUIRE( f1.ComputeL2Error(fCoef) < tol ); + } } - SECTION("Mapping to HDiv") + SECTION("Operators on L2 for element type " + std::to_string(type)) { - GridFunction F1(&fespace_nd); - F1.ProjectCoefficient(FCoef); + L2_FECollection fec_l2(order_l2, dim); + FiniteElementSpace fespace_l2(mesh, &fec_l2); - RT_FECollection fec_rtp(2*order_nd, dim); - FiniteElementSpace fespace_rtp(&mesh, &fec_rtp); + GridFunction f0(&fespace_l2); + f0.ProjectCoefficient(fCoef); - DiscreteLinearOperator OpF1(&fespace_nd,&fespace_rtp); - OpF1.AddDomainInterpolator(new VectorCrossProductInterpolator(FCoef)); - OpF1.Assemble(); + SECTION("Mapping to L2") + { + L2_FECollection fec_l2p(order_l2+1, dim); + FiniteElementSpace fespace_l2p(mesh, &fec_l2p); - GridFunction FxG2(&fespace_rtp); - OpF1.Mult(G1,FxG2); + GridFunction f1(&fespace_l2p); - REQUIRE( FxG2.ComputeL2Error(FxGCoef) < tol ); + DiscreteLinearOperator Op(&fespace_l2,&fespace_l2p); + Op.AddDomainInterpolator(new IdentityInterpolator()); + Op.Assemble(); + + Op.Mult(f0,f1); + + REQUIRE( f1.ComputeL2Error(fCoef) < tol ); + } + SECTION("Mapping to L2 (INTEGRAL)") + { + L2_FECollection fec_l2p(order_l2+1, dim, + BasisType::GaussLegendre, + FiniteElement::INTEGRAL); + FiniteElementSpace fespace_l2p(mesh, &fec_l2p); + + GridFunction f1(&fespace_l2p); + + DiscreteLinearOperator Op(&fespace_l2,&fespace_l2p); + Op.AddDomainInterpolator(new IdentityInterpolator()); + Op.Assemble(); + + Op.Mult(f0,f1); + + REQUIRE( f1.ComputeL2Error(fCoef) < tol ); + } } - SECTION("Mapping to L2") + SECTION("Operators on L2 (INTEGRAL) for element type " + + std::to_string(type)) { - RT_FECollection fec_rt(order_rt, dim); - FiniteElementSpace fespace_rt(&mesh, &fec_rt); + L2_FECollection fec_l2(order_l2, dim, + BasisType::GaussLegendre, + FiniteElement::INTEGRAL); + FiniteElementSpace fespace_l2(mesh, &fec_l2); - GridFunction F2(&fespace_rt); - F2.ProjectCoefficient(FCoef); + GridFunction f0(&fespace_l2); + f0.ProjectCoefficient(fCoef); - L2_FECollection fec_l2p(order_nd+order_rt, dim); - FiniteElementSpace fespace_l2p(&mesh, &fec_l2p); + SECTION("Mapping to L2") + { + L2_FECollection fec_l2p(order_l2+1, dim); + FiniteElementSpace fespace_l2p(mesh, &fec_l2p); - DiscreteLinearOperator OpF2(&fespace_nd,&fespace_l2p); - OpF2.AddDomainInterpolator(new VectorInnerProductInterpolator(FCoef)); - OpF2.Assemble(); + GridFunction f1(&fespace_l2p); - GridFunction FG3(&fespace_l2p); - OpF2.Mult(G1,FG3); + DiscreteLinearOperator Op(&fespace_l2,&fespace_l2p); + Op.AddDomainInterpolator(new IdentityInterpolator()); + Op.Assemble(); - REQUIRE( FG3.ComputeL2Error(FGCoef) < tol ); + Op.Mult(f0,f1); + + REQUIRE( f1.ComputeL2Error(fCoef) < tol ); + } + SECTION("Mapping to L2 (INTEGRAL)") + { + L2_FECollection fec_l2p(order_l2+1, dim, + BasisType::GaussLegendre, + FiniteElement::INTEGRAL); + FiniteElementSpace fespace_l2p(mesh, &fec_l2p); + + GridFunction f1(&fespace_l2p); + + DiscreteLinearOperator Op(&fespace_l2,&fespace_l2p); + Op.AddDomainInterpolator(new IdentityInterpolator()); + Op.Assemble(); + + Op.Mult(f0,f1); + + REQUIRE( f1.ComputeL2Error(fCoef) < tol ); + } } + if (dim > 1) + { + VectorFunctionCoefficient FCoef(dim, + (dim==2) ? F2 : F3); + VectorFunctionCoefficient curlFCoef(dim, + (dim==2) ? CurlF2 : CurlF3); + FunctionCoefficient divFCoef((dim==2) ? DivF2 : DivF3); + + SECTION("Operators on HCurl for element type " + std::to_string(type)) + { + ND_FECollection fec_nd(order_nd, dim); + FiniteElementSpace fespace_nd(mesh, &fec_nd); + + GridFunction f1(&fespace_nd); + f1.ProjectCoefficient(FCoef); + + SECTION("Mapping to HCurl") + { + ND_FECollection fec_ndp(order_nd+1, dim); + FiniteElementSpace fespace_ndp(mesh, &fec_ndp); + + GridFunction f1p(&fespace_ndp); + + DiscreteLinearOperator Op(&fespace_nd,&fespace_ndp); + Op.AddDomainInterpolator(new IdentityInterpolator()); + Op.Assemble(); + + Op.Mult(f1,f1p); + + REQUIRE( f1p.ComputeHCurlError(&FCoef, &curlFCoef) < tol ); + } + SECTION("Mapping to L2^d") + { + L2_FECollection fec_l2(order_l2, dim); + FiniteElementSpace fespace_l2(mesh, &fec_l2, dim); + + GridFunction f2d(&fespace_l2); + + DiscreteLinearOperator Op(&fespace_nd,&fespace_l2); + Op.AddDomainInterpolator(new IdentityInterpolator()); + Op.Assemble(); + + Op.Mult(f1,f2d); + + REQUIRE( f2d.ComputeL2Error(FCoef) < tol ); + } + SECTION("Mapping to L2^d (INTEGRAL)") + { + L2_FECollection fec_l2(order_l2, dim, + BasisType::GaussLegendre, + FiniteElement::INTEGRAL); + FiniteElementSpace fespace_l2(mesh, &fec_l2, dim); + + GridFunction f2d(&fespace_l2); + + DiscreteLinearOperator Op(&fespace_nd,&fespace_l2); + Op.AddDomainInterpolator(new IdentityInterpolator()); + Op.Assemble(); + + Op.Mult(f1,f2d); + + REQUIRE( f2d.ComputeL2Error(FCoef) < tol ); + } + } + SECTION("Operators on HDiv for element type " + std::to_string(type)) + { + RT_FECollection fec_rt(order_rt, dim); + FiniteElementSpace fespace_rt(mesh, &fec_rt); + + GridFunction f2(&fespace_rt); + f2.ProjectCoefficient(FCoef); + + SECTION("Mapping to HDiv") + { + RT_FECollection fec_rtp(order_rt+1, dim); + FiniteElementSpace fespace_rtp(mesh, &fec_rtp); + + GridFunction f2p(&fespace_rtp); + + DiscreteLinearOperator Op(&fespace_rt,&fespace_rtp); + Op.AddDomainInterpolator(new IdentityInterpolator()); + Op.Assemble(); + + Op.Mult(f2,f2p); + + REQUIRE( f2p.ComputeHDivError(&FCoef, &divFCoef) < tol ); + } + SECTION("Mapping to L2^d") + { + L2_FECollection fec_l2(order_l2, dim); + FiniteElementSpace fespace_l2(mesh, &fec_l2, dim); + + GridFunction f2d(&fespace_l2); + + DiscreteLinearOperator Op(&fespace_rt,&fespace_l2); + Op.AddDomainInterpolator(new IdentityInterpolator()); + Op.Assemble(); + + Op.Mult(f2,f2d); + + REQUIRE( f2d.ComputeL2Error(FCoef) < tol ); + } + SECTION("Mapping to L2^d (INTEGRAL)") + { + L2_FECollection fec_l2(order_l2, dim, + BasisType::GaussLegendre, + FiniteElement::INTEGRAL); + FiniteElementSpace fespace_l2(mesh, &fec_l2, dim); + + GridFunction f2d(&fespace_l2); + + DiscreteLinearOperator Op(&fespace_rt,&fespace_l2); + Op.AddDomainInterpolator(new IdentityInterpolator()); + Op.Assemble(); + + Op.Mult(f2,f2d); + + REQUIRE( f2d.ComputeL2Error(FCoef) < tol ); + } + } + SECTION("Operators on H1^d for element type " + std::to_string(type)) + { + H1_FECollection fec_h1(order_h1, dim); + FiniteElementSpace fespace_h1(mesh, &fec_h1, dim); + + GridFunction f0(&fespace_h1); + f0.ProjectCoefficient(FCoef); + + SECTION("Mapping to HCurl") + { + ND_FECollection fec_ndp(order_nd, dim); + FiniteElementSpace fespace_ndp(mesh, &fec_ndp); + + GridFunction f1(&fespace_ndp); + + DiscreteLinearOperator Op(&fespace_h1,&fespace_ndp); + Op.AddDomainInterpolator(new IdentityInterpolator()); + Op.Assemble(); + + Op.Mult(f0,f1); + + REQUIRE( f1.ComputeHCurlError(&FCoef, &curlFCoef) < tol ); + } + SECTION("Mapping to HDiv") + { + RT_FECollection fec_rtp(order_rt, dim); + FiniteElementSpace fespace_rtp(mesh, &fec_rtp); + + GridFunction f2(&fespace_rtp); + + DiscreteLinearOperator Op(&fespace_h1,&fespace_rtp); + Op.AddDomainInterpolator(new IdentityInterpolator()); + Op.Assemble(); + + Op.Mult(f0,f2); + + REQUIRE( f2.ComputeHDivError(&FCoef, &divFCoef) < tol ); + } + } + /// The following tests would fail. The reason for the failure would + /// not be obvious from the user's point of view. I recommend keeping + /// these tests here as a reminder that we should consider supporting + /// this, or a very similar, usage. + /* + SECTION("Mapping to L2^d") + { + L2_FECollection fec_l2(order_l2, dim); + FiniteElementSpace fespace_l2(&mesh, &fec_l2, dim); + + GridFunction f2d(&fespace_l2); + + DiscreteLinearOperator Op(&fespace_h1,&fespace_l2); + Op.AddDomainInterpolator(new IdentityInterpolator()); + Op.Assemble(); + + Op.Mult(f0,f2d); + + REQUIRE( f2d.ComputeL2Error(FCoef) < tol ); + } + SECTION("Mapping to L2^d (INTEGRAL)") + { + L2_FECollection fec_l2(order_l2, dim, + BasisType::GaussLegendre, + FiniteElement::INTEGRAL); + FiniteElementSpace fespace_l2(&mesh, &fec_l2, dim); + + GridFunction f2d(&fespace_l2); + + DiscreteLinearOperator Op(&fespace_h1,&fespace_l2); + Op.AddDomainInterpolator(new IdentityInterpolator()); + Op.Assemble(); + + Op.Mult(f0,f2d); + + REQUIRE( f2d.ComputeL2Error(FCoef) < tol ); + } + */ + } + delete mesh; } - SECTION("Operators on HDiv") +} + +TEST_CASE("Derivative Linear Interpolators", + "[GradientInterpolator]" + "[CurlInterpolator]" + "[DivergenceInterpolator]") +{ + int order_h1 = 1, order_nd = 1, order_rt = 0, order_l2 = 0, n = 3, dim = -1; + double tol = 1e-9; + + for (int type = (int)Element::SEGMENT; + type <= (int)Element::HEXAHEDRON; type++) { - RT_FECollection fec_rt(order_rt, dim); - FiniteElementSpace fespace_rt(&mesh, &fec_rt); + Mesh *mesh = NULL; - GridFunction G2(&fespace_rt); - G2.ProjectCoefficient(GCoef); - - SECTION("Mapping to L2") + if (type < (int)Element::TRIANGLE) { - ND_FECollection fec_nd(order_nd, dim); - FiniteElementSpace fespace_nd(&mesh, &fec_nd); + dim = 1; + mesh = new Mesh(n, (Element::Type)type, 1, 2.0); - GridFunction F1(&fespace_nd); - F1.ProjectCoefficient(FCoef); + } + else if (type < (int)Element::TETRAHEDRON) + { + dim = 2; + mesh = new Mesh(n, n, (Element::Type)type, 1, 2.0, 3.0); + } + else + { + dim = 3; + mesh = new Mesh(n, n, n, (Element::Type)type, 1, 2.0, 3.0, 5.0); + } - L2_FECollection fec_l2p(order_nd+order_rt, dim); - FiniteElementSpace fespace_l2p(&mesh, &fec_l2p); + FunctionCoefficient fCoef((dim==1) ? f1 : + ((dim==2) ? f2 : f3)); + FunctionCoefficient gradfCoef(grad_f1); + VectorFunctionCoefficient GradfCoef(dim, + (dim==1) ? Grad_f1 : + ((dim==2)? Grad_f2 : Grad_f3)); - DiscreteLinearOperator OpF1(&fespace_rt,&fespace_l2p); - OpF1.AddDomainInterpolator(new VectorInnerProductInterpolator(FCoef)); - OpF1.Assemble(); + SECTION("Operators on H1 for element type " + std::to_string(type)) + { + H1_FECollection fec_h1(order_h1, dim); + FiniteElementSpace fespace_h1(mesh, &fec_h1); - GridFunction FG3(&fespace_l2p); - OpF1.Mult(G2,FG3); + GridFunction f0(&fespace_h1); + f0.ProjectCoefficient(fCoef); - REQUIRE( FG3.ComputeL2Error(FGCoef) < tol ); + if (dim ==1) + { + SECTION("Mapping to L2") + { + L2_FECollection fec_l2(order_l2, dim); + FiniteElementSpace fespace_l2(mesh, &fec_l2); + + GridFunction df0(&fespace_l2); + + DiscreteLinearOperator Op(&fespace_h1,&fespace_l2); + Op.AddDomainInterpolator(new GradientInterpolator()); + Op.Assemble(); + + Op.Mult(f0,df0); + + REQUIRE( df0.ComputeL2Error(gradfCoef) < tol ); + } + SECTION("Mapping to L2 (INTEGRAL)") + { + L2_FECollection fec_l2(order_l2, dim, + BasisType::GaussLegendre, + FiniteElement::INTEGRAL); + FiniteElementSpace fespace_l2(mesh, &fec_l2); + + GridFunction df0(&fespace_l2); + + DiscreteLinearOperator Op(&fespace_h1,&fespace_l2); + Op.AddDomainInterpolator(new GradientInterpolator()); + Op.Assemble(); + + Op.Mult(f0,df0); + + REQUIRE( df0.ComputeL2Error(gradfCoef) < tol ); + } + + } + else + { + SECTION("Mapping to HCurl") + { + ND_FECollection fec_nd(order_nd, dim); + FiniteElementSpace fespace_nd(mesh, &fec_nd); + + GridFunction df0(&fespace_nd); + + DiscreteLinearOperator Op(&fespace_h1,&fespace_nd); + Op.AddDomainInterpolator(new GradientInterpolator()); + Op.Assemble(); + + Op.Mult(f0,df0); + + REQUIRE( df0.ComputeL2Error(GradfCoef) < tol ); + } + } + } + if (dim > 1) + { + VectorFunctionCoefficient FCoef(dim, + (dim==2) ? F2 : F3); + FunctionCoefficient curlFCoef(curlF2); + VectorFunctionCoefficient CurlFCoef(dim, + (dim==2) ? CurlF2 : CurlF3); + FunctionCoefficient DivFCoef((dim==2) ? DivF2 : DivF3); + + SECTION("Operators on HCurl for element type " + std::to_string(type)) + { + ND_FECollection fec_nd(order_nd, dim); + FiniteElementSpace fespace_nd(mesh, &fec_nd); + + GridFunction F1(&fespace_nd); + F1.ProjectCoefficient(FCoef); + + if (dim == 2) + { + SECTION("Mapping to L2") + { + L2_FECollection fec_l2(order_l2, dim); + FiniteElementSpace fespace_l2(mesh, &fec_l2); + + GridFunction dF1(&fespace_l2); + + DiscreteLinearOperator Op(&fespace_nd,&fespace_l2); + Op.AddDomainInterpolator(new CurlInterpolator()); + Op.Assemble(); + + Op.Mult(F1,dF1); + + REQUIRE( dF1.ComputeL2Error(curlFCoef) < tol ); + } + SECTION("Mapping to L2 (INTEGRAL)") + { + L2_FECollection fec_l2(order_l2, dim, + BasisType::GaussLegendre, + FiniteElement::INTEGRAL); + FiniteElementSpace fespace_l2(mesh, &fec_l2); + + GridFunction dF1(&fespace_l2); + + DiscreteLinearOperator Op(&fespace_nd,&fespace_l2); + Op.AddDomainInterpolator(new CurlInterpolator()); + Op.Assemble(); + + Op.Mult(F1,dF1); + + REQUIRE( dF1.ComputeL2Error(curlFCoef) < tol ); + } + } + else + { + SECTION("Mapping to HDiv") + { + RT_FECollection fec_rt(order_rt, dim); + FiniteElementSpace fespace_rt(mesh, &fec_rt); + + GridFunction dF1(&fespace_rt); + + DiscreteLinearOperator Op(&fespace_nd,&fespace_rt); + Op.AddDomainInterpolator(new CurlInterpolator()); + Op.Assemble(); + + Op.Mult(F1,dF1); + + REQUIRE( dF1.ComputeL2Error(CurlFCoef) < tol ); + } + } + } + SECTION("Operators on HDiv for element type " + std::to_string(type)) + { + RT_FECollection fec_rt(order_rt, dim); + FiniteElementSpace fespace_rt(mesh, &fec_rt); + + GridFunction F2(&fespace_rt); + F2.ProjectCoefficient(FCoef); + + SECTION("Mapping to L2") + { + L2_FECollection fec_l2(order_l2, dim); + FiniteElementSpace fespace_l2(mesh, &fec_l2); + + GridFunction dF2(&fespace_l2); + + DiscreteLinearOperator Op(&fespace_rt,&fespace_l2); + Op.AddDomainInterpolator(new DivergenceInterpolator()); + Op.Assemble(); + + Op.Mult(F2,dF2); + + REQUIRE( dF2.ComputeL2Error(DivFCoef) < tol ); + } + SECTION("Mapping to L2 (INTEGRAL)") + { + L2_FECollection fec_l2(order_l2, dim, + BasisType::GaussLegendre, + FiniteElement::INTEGRAL); + FiniteElementSpace fespace_l2(mesh, &fec_l2); + + GridFunction dF2(&fespace_l2); + + DiscreteLinearOperator Op(&fespace_rt,&fespace_l2); + Op.AddDomainInterpolator(new DivergenceInterpolator()); + Op.Assemble(); + + Op.Mult(F2,dF2); + + REQUIRE( dF2.ComputeL2Error(DivFCoef) < tol ); + } + } + } + delete mesh; + } +} + +TEST_CASE("Product Linear Interpolators", + "[ScalarProductInterpolator]" + "[VectorScalarProductInterpolator]" + "[ScalarVectorProductInterpolator]" + "[ScalarCrossProductInterpolator]" + "[VectorCrossProductInterpolator]" + "[VectorInnerProductInterpolator]") +{ + int order_h1 = 1, order_nd = 2, order_rt = 2, n = 3, dim = -1; + double tol = 1e-9; + + for (int type = (int)Element::SEGMENT; + type <= (int)Element::HEXAHEDRON; type++) + { + Mesh *mesh = NULL; + + if (type < (int)Element::TRIANGLE) + { + dim = 1; + mesh = new Mesh(n, (Element::Type)type, 1, 2.0); + + } + else if (type < (int)Element::TETRAHEDRON) + { + dim = 2; + mesh = new Mesh(n, n, (Element::Type)type, 1, 2.0, 3.0); + } + else + { + dim = 3; + mesh = new Mesh(n, n, n, (Element::Type)type, 1, 2.0, 3.0, 5.0); + } + + FunctionCoefficient fCoef((dim==1) ? f1 : + ((dim==2) ? f2 : f3)); + FunctionCoefficient gCoef((dim==1) ? g1 : + ((dim==2) ? g2 : g3)); + FunctionCoefficient fgCoef((dim==1) ? fg1 : + ((dim==2) ? fg2 : fg3)); + + VectorFunctionCoefficient FCoef(dim, + (dim==2) ? F2 : F3); + VectorFunctionCoefficient GCoef(dim, + (dim==2) ? G2 : G3); + + FunctionCoefficient FGCoef((dim==2) ? FdotG2 : FdotG3); + VectorFunctionCoefficient fGCoef(dim, (dim==2) ? fG2 : fG3); + VectorFunctionCoefficient FgCoef(dim, (dim==2) ? Fg2 : Fg3); + VectorFunctionCoefficient FxGCoef(dim, (dim==2) ? FcrossG2 : FcrossG3); + + SECTION("Operators on H1 for element type " + std::to_string(type)) + { + H1_FECollection fec_h1(order_h1, dim); + FiniteElementSpace fespace_h1(mesh, &fec_h1); + + GridFunction g0(&fespace_h1); + g0.ProjectCoefficient(gCoef); + + SECTION("Mapping H1 to H1") + { + H1_FECollection fec_h1p(2*order_h1, dim); + FiniteElementSpace fespace_h1p(mesh, &fec_h1p); + + DiscreteLinearOperator Opf0(&fespace_h1,&fespace_h1p); + Opf0.AddDomainInterpolator( + new ScalarProductInterpolator(fCoef)); + Opf0.Assemble(); + + GridFunction fg0(&fespace_h1p); + Opf0.Mult(g0,fg0); + + REQUIRE( fg0.ComputeL2Error(fgCoef) < tol ); + } + if (dim > 1) + { + SECTION("Mapping to HCurl") + { + ND_FECollection fec_nd(order_nd, dim); + FiniteElementSpace fespace_nd(mesh, &fec_nd); + + ND_FECollection fec_ndp(order_h1+order_nd, dim); + FiniteElementSpace fespace_ndp(mesh, &fec_ndp); + + DiscreteLinearOperator OpF1(&fespace_h1,&fespace_ndp); + OpF1.AddDomainInterpolator( + new VectorScalarProductInterpolator(FCoef)); + OpF1.Assemble(); + + GridFunction Fg1(&fespace_ndp); + OpF1.Mult(g0,Fg1); + + REQUIRE( Fg1.ComputeL2Error(FgCoef) < tol ); + } + } + } + if (dim > 1) + { + SECTION("Operators on HCurl for element type " + std::to_string(type)) + { + ND_FECollection fec_nd(order_nd, dim); + FiniteElementSpace fespace_nd(mesh, &fec_nd); + + GridFunction G1(&fespace_nd); + G1.ProjectCoefficient(GCoef); + + SECTION("Mapping HCurl to HCurl") + { + H1_FECollection fec_h1(order_h1, dim); + FiniteElementSpace fespace_h1(mesh, &fec_h1); + + ND_FECollection fec_ndp(order_nd+order_h1, dim); + FiniteElementSpace fespace_ndp(mesh, &fec_ndp); + + DiscreteLinearOperator Opf0(&fespace_nd,&fespace_ndp); + Opf0.AddDomainInterpolator( + new ScalarVectorProductInterpolator(fCoef)); + Opf0.Assemble(); + + GridFunction fG1(&fespace_ndp); + Opf0.Mult(G1,fG1); + + REQUIRE( fG1.ComputeL2Error(fGCoef) < tol ); + } + if (dim == 2) + { + SECTION("Mapping to L2") + { + L2_FECollection fec_l2p(2*order_nd-1, dim); + FiniteElementSpace fespace_l2p(mesh, &fec_l2p); + + DiscreteLinearOperator OpF1(&fespace_nd,&fespace_l2p); + OpF1.AddDomainInterpolator( + new ScalarCrossProductInterpolator(FCoef)); + OpF1.Assemble(); + + GridFunction FxG2(&fespace_l2p); + OpF1.Mult(G1,FxG2); + + REQUIRE( FxG2.ComputeL2Error(FxGCoef) < tol ); + } + } + else + { + SECTION("Mapping to HDiv") + { + RT_FECollection fec_rtp(2*order_nd-1, dim); + FiniteElementSpace fespace_rtp(mesh, &fec_rtp); + + DiscreteLinearOperator OpF1(&fespace_nd,&fespace_rtp); + OpF1.AddDomainInterpolator( + new VectorCrossProductInterpolator(FCoef)); + OpF1.Assemble(); + + GridFunction FxG2(&fespace_rtp); + OpF1.Mult(G1,FxG2); + + REQUIRE( FxG2.ComputeL2Error(FxGCoef) < tol ); + } + } + SECTION("Mapping to L2") + { + RT_FECollection fec_rt(order_rt, dim); + FiniteElementSpace fespace_rt(mesh, &fec_rt); + + L2_FECollection fec_l2p(order_nd+order_rt, dim); + FiniteElementSpace fespace_l2p(mesh, &fec_l2p); + + DiscreteLinearOperator OpF2(&fespace_nd,&fespace_l2p); + OpF2.AddDomainInterpolator( + new VectorInnerProductInterpolator(FCoef)); + OpF2.Assemble(); + + GridFunction FG3(&fespace_l2p); + OpF2.Mult(G1,FG3); + + REQUIRE( FG3.ComputeL2Error(FGCoef) < tol ); + } + } + SECTION("Operators on HDiv for element type " + std::to_string(type)) + { + RT_FECollection fec_rt(order_rt, dim); + FiniteElementSpace fespace_rt(mesh, &fec_rt); + + GridFunction G2(&fespace_rt); + G2.ProjectCoefficient(GCoef); + + SECTION("Mapping to L2") + { + ND_FECollection fec_nd(order_nd, dim); + FiniteElementSpace fespace_nd(mesh, &fec_nd); + + L2_FECollection fec_l2p(order_nd+order_rt, dim); + FiniteElementSpace fespace_l2p(mesh, &fec_l2p); + + DiscreteLinearOperator OpF1(&fespace_rt,&fespace_l2p); + OpF1.AddDomainInterpolator( + new VectorInnerProductInterpolator(FCoef)); + OpF1.Assemble(); + + GridFunction FG3(&fespace_l2p); + OpF1.Mult(G2,FG3); + + REQUIRE( FG3.ComputeL2Error(FGCoef) < tol ); + } + } } } } diff --git a/tests/unit/fem/test_linear_fes.cpp b/tests/unit/fem/test_linear_fes.cpp index c2134db5e5..2af7398fa3 100644 --- a/tests/unit/fem/test_linear_fes.cpp +++ b/tests/unit/fem/test_linear_fes.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/fem/test_operatorjacobismoother.cpp b/tests/unit/fem/test_operatorjacobismoother.cpp index 4ca9b5b518..761011779d 100644 --- a/tests/unit/fem/test_operatorjacobismoother.cpp +++ b/tests/unit/fem/test_operatorjacobismoother.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/fem/test_pa_coeff.cpp b/tests/unit/fem/test_pa_coeff.cpp index 02414b9c7e..f9081a1745 100644 --- a/tests/unit/fem/test_pa_coeff.cpp +++ b/tests/unit/fem/test_pa_coeff.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // @@ -107,23 +107,23 @@ void fullSymmetricMatrixCoeffFunction(const Vector & x, DenseMatrix & f) } } -void symmetricMatrixCoeffFunction(const Vector & x, Vector & f) +void symmetricMatrixCoeffFunction(const Vector & x, DenseSymmetricMatrix & f) { f = 0.0; if (dimension == 2) { - f[0] = 1.1 + sin(M_PI * x[1]); // 1,1 - f[1] = cos(2.5 * M_PI * x[0]); // 1,2 - f[2] = 1.1 + sin(4.9 * M_PI * x[0]); // 2,2 + f(0,0) = 1.1 + sin(M_PI * x[1]); // 1,1 + f(0,1) = cos(2.5 * M_PI * x[0]); // 1,2 + f(1,1) = 1.1 + sin(4.9 * M_PI * x[0]); // 2,2 } else if (dimension == 3) { - f[0] = sin(M_PI * x[1]); // 1,1 - f[1] = cos(2.5 * M_PI * x[0]); // 1,2 - f[2] = sin(4.9 * M_PI * x[2]); // 1,3 - f[3] = sin(6.1 * M_PI * x[1]); // 2,2 - f[4] = cos(6.1 * M_PI * x[2]); // 2,3 - f[5] = sin(6.1 * M_PI * x[2]); // 3,3 + f(0,0) = sin(M_PI * x[1]); // 1,1 + f(0,1) = cos(2.5 * M_PI * x[0]); // 1,2 + f(0,2) = sin(4.9 * M_PI * x[2]); // 1,3 + f(1,1) = sin(6.1 * M_PI * x[1]); // 2,2 + f(1,2) = cos(6.1 * M_PI * x[2]); // 2,3 + f(2,2) = sin(6.1 * M_PI * x[2]); // 3,3 } } @@ -161,7 +161,7 @@ TEST_CASE("H1 pa_coeff") Coefficient* coeff = nullptr; VectorCoefficient* vcoeff = nullptr; MatrixCoefficient* mcoeff = nullptr; - MatrixCoefficient* smcoeff = nullptr; + SymmetricMatrixCoefficient* smcoeff = nullptr; if (coeffType == 0) { coeff = new ConstantCoefficient(1.0); @@ -186,15 +186,13 @@ TEST_CASE("H1 pa_coeff") { mcoeff = new MatrixFunctionCoefficient(dimension, &fullSymmetricMatrixCoeffFunction); - smcoeff = new MatrixFunctionCoefficient(dimension, - &symmetricMatrixCoeffFunction); + smcoeff = new SymmetricMatrixFunctionCoefficient(dimension, + &symmetricMatrixCoeffFunction); } else if (coeffType == 5) { mcoeff = new MatrixFunctionCoefficient(dimension, &asymmetricMatrixCoeffFunction); - smcoeff = new MatrixFunctionCoefficient(dimension, - &asymmetricMatrixCoeffFunction); } paform.SetAssemblyLevel(AssemblyLevel::PARTIAL); @@ -204,10 +202,14 @@ TEST_CASE("H1 pa_coeff") { paform.AddDomainIntegrator(new DiffusionIntegrator(*vcoeff)); } - else if (coeffType >= 4) + else if (coeffType == 4) { paform.AddDomainIntegrator(new DiffusionIntegrator(*smcoeff)); } + else if (coeffType == 5) + { + paform.AddDomainIntegrator(new DiffusionIntegrator(*mcoeff)); + } else { paform.AddDomainIntegrator(new DiffusionIntegrator(*coeff)); @@ -301,13 +303,13 @@ TEST_CASE("Hcurl/Hdiv pa_coeff", mesh = new Mesh(ne, ne, ne, Element::HEXAHEDRON, 1, 1.0, 1.0, 1.0); } - for (int coeffType = 0; coeffType < 5; ++coeffType) + for (int coeffType = 3; coeffType < 5; ++coeffType) { Coefficient* coeff = nullptr; Coefficient* coeff2 = nullptr; VectorCoefficient* vcoeff = nullptr; MatrixCoefficient* mcoeff = nullptr; - MatrixCoefficient* smcoeff = nullptr; + SymmetricMatrixCoefficient* smcoeff = nullptr; if (coeffType == 0) { coeff = new ConstantCoefficient(12.34); @@ -327,22 +329,20 @@ TEST_CASE("Hcurl/Hdiv pa_coeff", { mcoeff = new MatrixFunctionCoefficient(dimension, &fullSymmetricMatrixCoeffFunction); - smcoeff = new MatrixFunctionCoefficient(dimension, - &symmetricMatrixCoeffFunction); + smcoeff = new SymmetricMatrixFunctionCoefficient(dimension, + &symmetricMatrixCoeffFunction); coeff2 = new FunctionCoefficient(&linearFunction); } else if (coeffType == 4) { mcoeff = new MatrixFunctionCoefficient(dimension, &asymmetricMatrixCoeffFunction); - smcoeff = new MatrixFunctionCoefficient(dimension, - &asymmetricMatrixCoeffFunction); coeff2 = new FunctionCoefficient(&linearFunction); } enum MixedSpaces {Hcurl, Hdiv, HcurlHdiv, HdivHcurl, NumSpaceTypes}; - for (int spaceType = 0; spaceType < NumSpaceTypes; ++spaceType) + for (int spaceType = 2; spaceType < NumSpaceTypes; ++spaceType) { if (spaceType == Hdiv && coeffType >= 2) { @@ -459,7 +459,12 @@ TEST_CASE("Hcurl/Hdiv pa_coeff", y_pa.SetSize(testSize); y_pa = 0.0; - if (coeffType >= 3) + if (coeffType >= 4) + { + paform->AddDomainIntegrator(new VectorFEMassIntegrator(*mcoeff)); + assemblyform->AddDomainIntegrator(new VectorFEMassIntegrator(*mcoeff)); + } + else if (coeffType == 3) { paform->AddDomainIntegrator(new VectorFEMassIntegrator(*smcoeff)); assemblyform->AddDomainIntegrator(new VectorFEMassIntegrator(*mcoeff)); @@ -522,7 +527,12 @@ TEST_CASE("Hcurl/Hdiv pa_coeff", if (integrator < 2) { - if (coeffType >= 3) + if (coeffType >= 4) + { + paform->AddDomainIntegrator(new VectorFEMassIntegrator(*mcoeff)); + assemblyform->AddDomainIntegrator(new VectorFEMassIntegrator(*mcoeff)); + } + else if (coeffType == 3) { paform->AddDomainIntegrator(new VectorFEMassIntegrator(*smcoeff)); assemblyform->AddDomainIntegrator(new VectorFEMassIntegrator(*mcoeff)); @@ -547,7 +557,12 @@ TEST_CASE("Hcurl/Hdiv pa_coeff", const IntegrationRule *intRule = &MassIntegrator::GetRule(*fel, *fel, *mesh->GetElementTransformation(0)); - if (coeffType >= 3 && dimension == 3) + if (coeffType >= 4 && dimension == 3) + { + paform->AddDomainIntegrator(new CurlCurlIntegrator(*mcoeff, intRule)); + assemblyform->AddDomainIntegrator(new CurlCurlIntegrator(*mcoeff, intRule)); + } + else if (coeffType == 3 && dimension == 3) { paform->AddDomainIntegrator(new CurlCurlIntegrator(*smcoeff, intRule)); assemblyform->AddDomainIntegrator(new CurlCurlIntegrator(*mcoeff, intRule)); @@ -634,7 +649,7 @@ TEST_CASE("Hcurl/Hdiv mixed pa_coeff", for (int coeffType = 0; coeffType < 3; ++coeffType) { Coefficient* coeff = nullptr; - VectorCoefficient* vcoeff = nullptr; + DiagonalMatrixCoefficient* dcoeff = nullptr; if (coeffType == 0) { coeff = new ConstantCoefficient(12.34); @@ -645,7 +660,7 @@ TEST_CASE("Hcurl/Hdiv mixed pa_coeff", } else if (coeffType == 2) { - vcoeff = new VectorFunctionCoefficient(dimension, &vectorCoeffFunction); + dcoeff = new VectorFunctionCoefficient(dimension, &vectorCoeffFunction); } enum MixedSpaces {HcurlH1, HcurlL2, HdivL2, NumSpaceTypes}; @@ -716,13 +731,13 @@ TEST_CASE("Hcurl/Hdiv mixed pa_coeff", { if (integrator == 0) { - paform->AddDomainIntegrator(new MixedVectorCurlIntegrator(*vcoeff)); - assemblyform->AddDomainIntegrator(new MixedVectorCurlIntegrator(*vcoeff)); + paform->AddDomainIntegrator(new MixedVectorCurlIntegrator(*dcoeff)); + assemblyform->AddDomainIntegrator(new MixedVectorCurlIntegrator(*dcoeff)); } else { - paform->AddDomainIntegrator(new MixedVectorWeakCurlIntegrator(*vcoeff)); - assemblyform->AddDomainIntegrator(new MixedVectorWeakCurlIntegrator(*vcoeff)); + paform->AddDomainIntegrator(new MixedVectorWeakCurlIntegrator(*dcoeff)); + assemblyform->AddDomainIntegrator(new MixedVectorWeakCurlIntegrator(*dcoeff)); } } else @@ -827,7 +842,7 @@ TEST_CASE("Hcurl/Hdiv mixed pa_coeff", } delete coeff; - delete vcoeff; + delete dcoeff; } delete mesh; diff --git a/tests/unit/fem/test_pa_grad.cpp b/tests/unit/fem/test_pa_grad.cpp new file mode 100644 index 0000000000..adff0f1a64 --- /dev/null +++ b/tests/unit/fem/test_pa_grad.cpp @@ -0,0 +1,219 @@ +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-806117. +// +// This file is part of the MFEM library. For more information and source code +// availability visit https://mfem.org. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. + +#include "catch.hpp" +#include "mfem.hpp" +#include "unit_tests.hpp" + +using namespace mfem; + +double compare_pa_assembly(int dim, int num_elements, int order, bool transpose) +{ + Mesh * mesh; + if (num_elements == 0) + { + if (dim == 2) + { + mesh = new Mesh("../../data/star.mesh", order); + } + else + { + mesh = new Mesh("../../data/beam-hex.mesh", order); + } + } + else + { + if (dim == 2) + { + mesh = new Mesh(num_elements, num_elements, Element::QUADRILATERAL, true); + } + else + { + mesh = new Mesh(num_elements, num_elements, num_elements, + Element::HEXAHEDRON, true); + } + } + FiniteElementCollection *h1_fec = new H1_FECollection(order, dim); + FiniteElementCollection *nd_fec = new ND_FECollection(order, dim); + FiniteElementSpace h1_fespace(mesh, h1_fec); + FiniteElementSpace nd_fespace(mesh, nd_fec); + + DiscreteLinearOperator assembled_grad(&h1_fespace, &nd_fespace); + assembled_grad.AddDomainInterpolator(new GradientInterpolator); + const int skip_zeros = 1; + assembled_grad.Assemble(skip_zeros); + assembled_grad.Finalize(skip_zeros); + const SparseMatrix& assembled_grad_mat = assembled_grad.SpMat(); + + DiscreteLinearOperator pa_grad(&h1_fespace, &nd_fespace); + pa_grad.SetAssemblyLevel(AssemblyLevel::PARTIAL); + pa_grad.AddDomainInterpolator(new GradientInterpolator); + pa_grad.Assemble(); + pa_grad.Finalize(); + + int insize, outsize; + if (transpose) + { + insize = nd_fespace.GetVSize(); + outsize = h1_fespace.GetVSize(); + } + else + { + insize = h1_fespace.GetVSize(); + outsize = nd_fespace.GetVSize(); + } + Vector xv(insize); + Vector assembled_y(outsize); + Vector pa_y(outsize); + + xv.Randomize(); + if (transpose) + { + assembled_grad_mat.BuildTranspose(); + assembled_grad_mat.MultTranspose(xv, assembled_y); + pa_grad.MultTranspose(xv, pa_y); + } + else + { + assembled_grad_mat.Mult(xv, assembled_y); + pa_grad.Mult(xv, pa_y); + } + + pa_y -= assembled_y; + double error = pa_y.Norml2() / assembled_y.Norml2(); + INFO("dim " << dim << " ne " << num_elements << " order " << order + << (transpose ? " T:" : ":") << " error in PA gradient: " << error); + + delete h1_fec; + delete nd_fec; + delete mesh; + + return error; +} + +TEST_CASE("PAGradient", "[CUDA]") +{ + auto transpose = GENERATE(true, false); + auto order = GENERATE(1, 2, 3, 4); + auto dim = GENERATE(2, 3); + auto num_elements = GENERATE(0, 1, 2, 3, 4); + + double error = compare_pa_assembly(dim, num_elements, order, transpose); + REQUIRE(error == MFEM_Approx(0.0, 1.0e-14)); +} + +#ifdef MFEM_USE_MPI + +double par_compare_pa_assembly(int dim, int num_elements, int order, + bool transpose) +{ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + int size; + MPI_Comm_size(MPI_COMM_WORLD, &size); + + Mesh * smesh; + if (dim == 2) + { + smesh = new Mesh(num_elements, num_elements, Element::QUADRILATERAL, true); + } + else + { + smesh = new Mesh(num_elements, num_elements, num_elements, + Element::HEXAHEDRON, true); + } + ParMesh * mesh = new ParMesh(MPI_COMM_WORLD, *smesh); + delete smesh; + FiniteElementCollection *h1_fec = new H1_FECollection(order, dim); + FiniteElementCollection *nd_fec = new ND_FECollection(order, dim); + ParFiniteElementSpace h1_fespace(mesh, h1_fec); + ParFiniteElementSpace nd_fespace(mesh, nd_fec); + + ParDiscreteLinearOperator assembled_grad(&h1_fespace, &nd_fespace); + assembled_grad.AddDomainInterpolator(new GradientInterpolator); + const int skip_zeros = 1; + assembled_grad.Assemble(skip_zeros); + assembled_grad.Finalize(skip_zeros); + HypreParMatrix * assembled_grad_mat = assembled_grad.ParallelAssemble(); + + ParDiscreteLinearOperator pa_grad(&h1_fespace, &nd_fespace); + pa_grad.SetAssemblyLevel(AssemblyLevel::PARTIAL); + pa_grad.AddDomainInterpolator(new GradientInterpolator); + pa_grad.Assemble(); + OperatorPtr pa_grad_oper; + pa_grad.FormRectangularSystemMatrix(pa_grad_oper); + + int insize, outsize; + if (transpose) + { + insize = assembled_grad_mat->Height(); + outsize = assembled_grad_mat->Width(); + } + else + { + insize = assembled_grad_mat->Width(); + outsize = assembled_grad_mat->Height(); + } + Vector xv(insize); + Vector assembled_y(outsize); + Vector pa_y(outsize); + assembled_y = 0.0; + pa_y = 0.0; + + xv.Randomize(); + if (transpose) + { + assembled_grad_mat->MultTranspose(xv, assembled_y); + pa_grad_oper->MultTranspose(xv, pa_y); + } + else + { + assembled_grad_mat->Mult(xv, assembled_y); + pa_grad_oper->Mult(xv, pa_y); + } + + Vector error_vec(pa_y); + error_vec -= assembled_y; + // serial norms and serial error; we are enforcing equality on each processor + // in the test + double error = error_vec.Norml2() / assembled_y.Norml2(); + + for (int p = 0; p < size; ++p) + { + if (rank == p) + { + INFO("[" << rank << "][par] dim " << dim << " ne " << num_elements + << " order " << order << (transpose ? " T:" : ":") + << " error in PA gradient: " << error); + } + MPI_Barrier(MPI_COMM_WORLD); + } + + delete h1_fec; + delete nd_fec; + delete assembled_grad_mat; + delete mesh; + + return error; +} + +TEST_CASE("ParallelPAGradient", "[Parallel], [ParallelPAGradient]") +{ + auto transpose = GENERATE(true, false); + auto order = GENERATE(1, 2, 3, 4); + auto dim = GENERATE(2, 3); + auto num_elements = GENERATE(4, 5); + + double error = par_compare_pa_assembly(dim, num_elements, order, transpose); + REQUIRE(error == MFEM_Approx(0.0, 1.0e-14)); +} + +#endif diff --git a/tests/unit/fem/test_pa_idinterp.cpp b/tests/unit/fem/test_pa_idinterp.cpp new file mode 100644 index 0000000000..2b803bd6c4 --- /dev/null +++ b/tests/unit/fem/test_pa_idinterp.cpp @@ -0,0 +1,123 @@ +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-806117. +// +// This file is part of the MFEM library. For more information and source code +// availability visit https://mfem.org. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. + +#include "catch.hpp" +#include "mfem.hpp" +#include "unit_tests.hpp" + +using namespace mfem; + +double compare_pa_id_assembly(int dim, int num_elements, int order, + bool transpose) +{ + Mesh * mesh; + if (num_elements == 0) + { + if (dim == 2) + { + mesh = new Mesh("../../data/star.mesh", order); + } + else + { + mesh = new Mesh("../../data/beam-hex.mesh", order); + + // Transform mesh vertices to test without alignment with coordinate axes. + for (int i=0; iGetNV(); ++i) + { + double *v = mesh->GetVertex(i); + const double yscale = 1.0 + v[1]; + const double zscale = 1.0 + v[2]; + v[0] *= zscale; + v[1] *= zscale; + v[2] *= yscale; + } + } + } + else + { + if (dim == 2) + { + mesh = new Mesh(num_elements, num_elements, Element::QUADRILATERAL, true); + } + else + { + mesh = new Mesh(num_elements, num_elements, num_elements, + Element::HEXAHEDRON, true); + } + } + FiniteElementCollection *h1_fec = new H1_FECollection(order, dim); + FiniteElementCollection *nd_fec = new ND_FECollection(order, dim); + FiniteElementSpace h1_fespace(mesh, h1_fec, dim); + FiniteElementSpace nd_fespace(mesh, nd_fec); + + DiscreteLinearOperator assembled_id(&h1_fespace, &nd_fespace); + assembled_id.AddDomainInterpolator(new IdentityInterpolator); + const int skip_zeros = 1; + assembled_id.Assemble(skip_zeros); + assembled_id.Finalize(skip_zeros); + const SparseMatrix& assembled_id_mat = assembled_id.SpMat(); + + DiscreteLinearOperator pa_id(&h1_fespace, &nd_fespace); + pa_id.SetAssemblyLevel(AssemblyLevel::PARTIAL); + pa_id.AddDomainInterpolator(new IdentityInterpolator); + pa_id.Assemble(); + pa_id.Finalize(); + + int insize, outsize; + if (transpose) + { + insize = nd_fespace.GetVSize(); + outsize = h1_fespace.GetVSize(); + } + else + { + insize = h1_fespace.GetVSize(); + outsize = nd_fespace.GetVSize(); + } + Vector x(insize); + Vector assembled_y(outsize); + Vector pa_y(outsize); + + x.Randomize(); + if (transpose) + { + assembled_id_mat.BuildTranspose(); + assembled_id_mat.MultTranspose(x, assembled_y); + pa_id.MultTranspose(x, pa_y); + } + else + { + assembled_id.Mult(x, assembled_y); + pa_id.Mult(x, pa_y); + } + + pa_y -= assembled_y; + double error = pa_y.Norml2() / assembled_y.Norml2(); + INFO("dim " << dim << " ne " << num_elements << " order " << order + << (transpose ? " T:" : ":") << " error in PA identity: " << error); + + delete h1_fec; + delete nd_fec; + delete mesh; + + return error; +} + +TEST_CASE("PAIdentityInterp", "[CUDA]") +{ + auto transpose = GENERATE(true, false); + auto order = GENERATE(1, 2, 3, 4); + auto dim = GENERATE(2, 3); + auto num_elements = GENERATE(0, 1, 2, 3, 4); + + double error = compare_pa_id_assembly(dim, num_elements, order, transpose); + REQUIRE(error == MFEM_Approx(0.0, 1.0e-14)); +} diff --git a/tests/unit/fem/test_pa_kernels.cpp b/tests/unit/fem/test_pa_kernels.cpp index 9a0bbe444d..ab1494b5be 100644 --- a/tests/unit/fem/test_pa_kernels.cpp +++ b/tests/unit/fem/test_pa_kernels.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/fem/test_quadf_coef.cpp b/tests/unit/fem/test_quadf_coef.cpp index c51f95f85b..0d69433489 100644 --- a/tests/unit/fem/test_quadf_coef.cpp +++ b/tests/unit/fem/test_quadf_coef.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/fem/test_quadraturefunc.cpp b/tests/unit/fem/test_quadraturefunc.cpp index e79282cd41..6017f64dd8 100644 --- a/tests/unit/fem/test_quadraturefunc.cpp +++ b/tests/unit/fem/test_quadraturefunc.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/fem/test_sparse_matrix.cpp b/tests/unit/fem/test_sparse_matrix.cpp new file mode 100644 index 0000000000..36222dec1a --- /dev/null +++ b/tests/unit/fem/test_sparse_matrix.cpp @@ -0,0 +1,204 @@ +// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-806117. +// +// This file is part of the MFEM library. For more information and source code +// availability visit https://mfem.org. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. + +#include "catch.hpp" +#include "mfem.hpp" +#include +#include + +using namespace mfem; + +#ifdef MFEM_USE_MPI + +namespace sparse_matrix_test +{ + +double coeff_function(const Vector &x) +{ + return 1.0 + x[0]*x[0]; +} + +void velocity_function(const Vector &x, Vector &v) +{ + int dim = x.Size(); + switch (dim) + { + case 1: v(0) = 1.0; break; + case 2: v(0) = x(1); v(1) = -x(0); break; + case 3: v(0) = x(1); v(1) = -x(0); v(2) = x(0); break; + } +} + +enum class Coeff {Const, Grid, Quad}; + +static std::string getString(Coeff coeff_type) +{ + switch (coeff_type) + { + case Coeff::Const: + return "Const"; + break; + case Coeff::Grid: + return "Grid"; + break; + case Coeff::Quad: + return "Quad"; + break; + } + mfem_error("Unknown CeedCoeff."); + return ""; +} + +enum class Problem {Mass, Convection, Diffusion}; + +static std::string getString(Problem pb) +{ + switch (pb) + { + case Problem::Mass: + return "Mass"; + break; + case Problem::Convection: + return "Convection"; + break; + case Problem::Diffusion: + return "Diffusion"; + break; + } + mfem_error("Unknown Problem."); + return ""; +} + +void test_sparse_matrix(const char* input, int order, const Coeff coeff_type, + const Problem pb, const bool keep_nbr_block, + int basis) +{ + std::string knb = keep_nbr_block ? "ON" : "OFF"; + std::string section = "keep_nbr_block: " + knb + "\n" + + "coeff_type: " + getString(coeff_type) + "\n" + + "pb: " + getString(pb) + "\n" + + "order: " + std::to_string(order) + "\n" + + "mesh: " + input; + INFO(section); + Mesh mesh(input, 1, 1); + mesh.EnsureNodes(); + mesh.UniformRefinement(); + ParMesh pmesh(MPI_COMM_WORLD, mesh); + int dim = mesh.Dimension(); + + FiniteElementCollection *fec; + if (pb == Problem::Convection) + { + fec = new L2_FECollection(order, dim, basis); + } + else + { + fec = new H1_FECollection(order, dim, basis); + } + ParFiniteElementSpace fes(&pmesh, fec); + + ParBilinearForm k_test(&fes); + ParBilinearForm k_ref(&fes); + + ParFiniteElementSpace coeff_fes(&pmesh, fec); + ParGridFunction gf(&coeff_fes); + + Coefficient *coeff = nullptr; + ConstantCoefficient rho(1.0); + VectorFunctionCoefficient velocity(dim, velocity_function); + switch (coeff_type) + { + case Coeff::Const: + coeff = new ConstantCoefficient(1.0); + break; + case Coeff::Grid: + { + FunctionCoefficient f_coeff(coeff_function); + gf.ProjectCoefficient(f_coeff); + coeff = new GridFunctionCoefficient(&gf); + break; + } + case Coeff::Quad: + coeff = new FunctionCoefficient(coeff_function); + break; + } + + switch (pb) + { + case Problem::Mass: + k_ref.AddDomainIntegrator(new MassIntegrator(*coeff)); + k_test.AddDomainIntegrator(new MassIntegrator(*coeff)); + break; + case Problem::Convection: + k_ref.AddDomainIntegrator(new ConvectionIntegrator(velocity, -1.0)); + k_ref.AddInteriorFaceIntegrator( + new TransposeIntegrator(new DGTraceIntegrator(rho, velocity, 1.0, -0.5))); + k_ref.AddBdrFaceIntegrator( + new TransposeIntegrator(new DGTraceIntegrator(rho, velocity, 1.0, -0.5))); + k_test.AddDomainIntegrator(new ConvectionIntegrator(velocity, -1.0)); + k_test.AddInteriorFaceIntegrator( + new TransposeIntegrator(new DGTraceIntegrator(rho, velocity, 1.0, -0.5))); + k_test.AddBdrFaceIntegrator( + new TransposeIntegrator(new DGTraceIntegrator(rho, velocity, 1.0, -0.5))); + break; + case Problem::Diffusion: + k_ref.AddDomainIntegrator(new DiffusionIntegrator(*coeff)); + k_test.AddDomainIntegrator(new DiffusionIntegrator(*coeff)); + break; + } + + if (keep_nbr_block) { k_ref.KeepNbrBlock(); } + k_ref.Assemble(); + k_ref.Finalize(); + + k_test.SetAssemblyLevel(AssemblyLevel::FULL); + if (keep_nbr_block) { k_test.KeepNbrBlock(); } + k_test.Assemble(); + + const int sizeIn = pb == Problem::Convection ? + fes.GetVSize() + fes.GetFaceNbrVSize() : + fes.GetVSize(); + const int sizeOut = (pb == Problem::Convection && keep_nbr_block)? + fes.GetVSize() + fes.GetFaceNbrVSize() : + fes.GetVSize(); + const int sizeEnd = fes.GetVSize(); + Vector x(sizeIn), y_test(sizeOut), y_ref(sizeOut); + x.Randomize(1); + + k_test.SpMat().Mult(x,y_test); + k_ref.SpMat().Mult(x,y_ref); + + y_test -= y_ref; + + Vector result(y_test.HostReadWrite(), sizeEnd); + + REQUIRE(result.Norml2() < 1.e-12); + delete coeff; + delete fec; +} + +TEST_CASE("Sparse Matrix", "[Parallel]") +{ + auto basis = GENERATE(BasisType::GaussLobatto,BasisType::Positive); + auto keep_nbr_block = GENERATE(false); + auto coeff_type = GENERATE(Coeff::Const,Coeff::Grid,Coeff::Quad); + auto pb = GENERATE(Problem::Mass,Problem::Convection,Problem::Diffusion); + auto order = GENERATE(1,2,3); + auto mesh = GENERATE("../../data/inline-quad.mesh", + "../../data/inline-hex.mesh", + "../../data/star-q2.mesh", + "../../data/fichera-q2.mesh"); + test_sparse_matrix(mesh, order, coeff_type, pb, keep_nbr_block, basis); +} // test case + +} // namespace sparse_matrix_test + +#endif // MFEM_USE_MPI diff --git a/tests/unit/fem/test_sum_bilin.cpp b/tests/unit/fem/test_sum_bilin.cpp new file mode 100644 index 0000000000..770f380f52 --- /dev/null +++ b/tests/unit/fem/test_sum_bilin.cpp @@ -0,0 +1,231 @@ +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-806117. +// +// This file is part of the MFEM library. For more information and source code +// availability visit https://mfem.org. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. + +#include "unit_tests.hpp" +#include "mfem.hpp" +#include +#include + +using namespace mfem; + +namespace pa_kernels +{ + +TEST_CASE("H1 SumIntegrator", "[SumIntegrator][PartialAssembly]") +{ + Mesh mesh(1, 1, 1, Element::HEXAHEDRON); + H1_FECollection fec(2, mesh.Dimension()); + FiniteElementSpace fes(&mesh, &fec); + + MassIntegrator integ1; + DiffusionIntegrator integ2; + + SumIntegrator integ_sum(true); + integ_sum.AddIntegrator(new MassIntegrator); + integ_sum.AddIntegrator(new DiffusionIntegrator); + + const FiniteElement &el = *fes.GetFE(0); + ElementTransformation &T = *mesh.GetElementTransformation(0); + DenseMatrix m1, m_tmp, m2; + + // AssembleElementMatrix + integ1.AssembleElementMatrix(el, T, m1); + integ2.AssembleElementMatrix(el, T, m_tmp); + m1 += m_tmp; + integ_sum.AssembleElementMatrix(el, T, m2); + m1 -= m2; + REQUIRE(m1.MaxMaxNorm() == MFEM_Approx(0.0)); + + // AssembleElementMatrix2 + integ1.AssembleElementMatrix2(el, el, T, m1); + integ2.AssembleElementMatrix2(el, el, T, m_tmp); + m1 += m_tmp; + integ_sum.AssembleElementMatrix2(el, el, T, m2); + m1 -= m2; + REQUIRE(m1.MaxMaxNorm() == MFEM_Approx(0.0)); + + // PA + integ1.AssemblePA(fes); + integ2.AssemblePA(fes); + integ_sum.AssemblePA(fes); + + int n = fes.GetTrueVSize(); + Vector x(n), y1(n), y2(n); + Vector diag1(n), diag_tmp(n), diag2(n); + x.Randomize(1); + + // AddMultPA + y1 = 0.0; + y2 = 0.0; + integ1.AddMultPA(x, y1); + integ2.AddMultPA(x, y1); + integ_sum.AddMultPA(x, y2); + y1 -= y2; + REQUIRE(y1.Normlinf() == MFEM_Approx(0.0)); + + // AddMultTransposePA + y1 = 0.0; + y2 = 0.0; + integ1.AddMultTransposePA(x, y1); + integ2.AddMultTransposePA(x, y1); + integ_sum.AddMultTransposePA(x, y2); + y1 -= y2; + REQUIRE(y1.Normlinf() == MFEM_Approx(0.0)); + + // AssembleDiagonalPA + diag1 = 0.0; + diag_tmp = 0.0; + diag2 = 0.0; + integ1.AssembleDiagonalPA(diag1); + integ2.AssembleDiagonalPA(diag_tmp); + diag1 += diag_tmp; + integ_sum.AssembleDiagonalPA(diag2); + diag1 -= diag2; + REQUIRE(diag1.Normlinf() == MFEM_Approx(0.0)); + + // MF +#ifdef MFEM_USE_CEED + if (DeviceCanUseCeed()) + { + integ1.AssembleMF(fes); + integ2.AssembleMF(fes); + integ_sum.AssembleMF(fes); + + // AddMultMF + y1 = 0.0; + y2 = 0.0; + integ1.AddMultMF(x, y1); + integ2.AddMultMF(x, y1); + integ_sum.AddMultMF(x, y2); + y1 -= y2; + REQUIRE(y1.Normlinf() == MFEM_Approx(0.0)); + + // AddMultTransposeMF + y1 = 0.0; + y2 = 0.0; + integ1.AddMultTransposeMF(x, y1); + integ2.AddMultTransposeMF(x, y1); + integ_sum.AddMultTransposeMF(x, y2); + y1 -= y2; + REQUIRE(y1.Normlinf() == MFEM_Approx(0.0)); + + // AssembleDiagonalMF + integ1.AssembleDiagonalMF(diag1); + integ2.AssembleDiagonalMF(diag_tmp); + diag1 += diag_tmp; + integ_sum.AssembleDiagonalMF(diag2); + diag1 -= diag2; + REQUIRE(diag1.Normlinf() == MFEM_Approx(0.0)); + } +#endif +} + +TEST_CASE("DG SumIntegrator", "[SumIntegrator][PartialAssembly]") +{ + Mesh mesh(2, 1, 1, Element::HEXAHEDRON); + DG_FECollection fec(2, mesh.Dimension(), BasisType::GaussLobatto); + FiniteElementSpace fes(&mesh, &fec); + + Vector v(mesh.Dimension()); + v = 1.0; + VectorConstantCoefficient v_coeff(v); + + DGTraceIntegrator integ1(v_coeff, 1.0, 2.0); + DGTraceIntegrator integ2(v_coeff, 3.0, 4.0); + + SumIntegrator integ_sum(true); + integ_sum.AddIntegrator(new DGTraceIntegrator(v_coeff, 1.0, 2.0)); + integ_sum.AddIntegrator(new DGTraceIntegrator(v_coeff, 3.0, 4.0)); + + DenseMatrix m1, m_tmp, m2; + + // AssembleFaceMatrix + int nfaces = mesh.GetNumFaces(); + for (int i = 0; i < nfaces; i++) + { + FaceElementTransformations *tr = mesh.GetFaceElementTransformations(i); + const FiniteElement &el0 = *fes.GetFE(tr->Elem1No); + const FiniteElement &el1 = (tr->Elem2No >= 0) ? *fes.GetFE(tr->Elem2No) : el0; + integ1.AssembleFaceMatrix(el0, el1, *tr, m1); + integ2.AssembleFaceMatrix(el0, el1, *tr, m_tmp); + m1 += m_tmp; + integ_sum.AssembleFaceMatrix(el0, el1, *tr, m2); + m1 -= m2; + REQUIRE(m1.MaxMaxNorm() == MFEM_Approx(0.0)); + } + + // PA interior + integ1.AssemblePAInteriorFaces(fes); + integ2.AssemblePAInteriorFaces(fes); + integ_sum.AssemblePAInteriorFaces(fes); + + const Operator *R_int = fes.GetFaceRestriction( + ElementDofOrdering::LEXICOGRAPHIC, + FaceType::Interior); + + int n_int = R_int->Height(); + Vector x(n_int), y1(n_int), y2(n_int); + x.Randomize(1); + + // AddMultPA + y1 = 0.0; + y2 = 0.0; + integ1.AddMultPA(x, y1); + integ2.AddMultPA(x, y1); + integ_sum.AddMultPA(x, y2); + y1 -= y2; + REQUIRE(y1.Normlinf() == MFEM_Approx(0.0)); + + // AddMultTransposePA + y1 = 0.0; + y2 = 0.0; + integ1.AddMultTransposePA(x, y1); + integ2.AddMultTransposePA(x, y1); + integ_sum.AddMultTransposePA(x, y2); + y1 -= y2; + REQUIRE(y1.Normlinf() == MFEM_Approx(0.0)); + + // PA boundary + integ1.AssemblePABoundaryFaces(fes); + integ2.AssemblePABoundaryFaces(fes); + integ_sum.AssemblePABoundaryFaces(fes); + + const Operator *R_bdr = fes.GetFaceRestriction( + ElementDofOrdering::LEXICOGRAPHIC, + FaceType::Boundary, + L2FaceValues::DoubleValued); + + int n_bdr = R_bdr->Height(); + x.SetSize(n_bdr); + y1.SetSize(n_bdr); + y2.SetSize(n_bdr); + x.Randomize(1); + + // AddMultPA + y1 = 0.0; + y2 = 0.0; + integ1.AddMultPA(x, y1); + integ2.AddMultPA(x, y1); + integ_sum.AddMultPA(x, y2); + y1 -= y2; + REQUIRE(y1.Normlinf() == MFEM_Approx(0.0)); + + // AddMultTransposePA + y1 = 0.0; + y2 = 0.0; + integ1.AddMultTransposePA(x, y1); + integ2.AddMultTransposePA(x, y1); + integ_sum.AddMultTransposePA(x, y2); + y1 -= y2; + REQUIRE(y1.Normlinf() == MFEM_Approx(0.0)); +} + +} // namespace pa_kernels diff --git a/tests/unit/fem/test_tet_reorder.cpp b/tests/unit/fem/test_tet_reorder.cpp index c7401b2797..aa7ff86a04 100644 --- a/tests/unit/fem/test_tet_reorder.cpp +++ b/tests/unit/fem/test_tet_reorder.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/fem/test_transfer.cpp b/tests/unit/fem/test_transfer.cpp index 6b05e1a924..13521da4e2 100644 --- a/tests/unit/fem/test_transfer.cpp +++ b/tests/unit/fem/test_transfer.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/general/test_mem.cpp b/tests/unit/general/test_mem.cpp index bc7228f330..9191f11f8a 100644 --- a/tests/unit/general/test_mem.cpp +++ b/tests/unit/general/test_mem.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/general/test_text.cpp b/tests/unit/general/test_text.cpp index e681841702..17e7322735 100644 --- a/tests/unit/general/test_text.cpp +++ b/tests/unit/general/test_text.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/general/test_zlib.cpp b/tests/unit/general/test_zlib.cpp index 628eada493..0e71bb297b 100644 --- a/tests/unit/general/test_zlib.cpp +++ b/tests/unit/general/test_zlib.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/linalg/test_cg_indefinite.cpp b/tests/unit/linalg/test_cg_indefinite.cpp index b4fcea70ff..78f2cafa74 100644 --- a/tests/unit/linalg/test_cg_indefinite.cpp +++ b/tests/unit/linalg/test_cg_indefinite.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/linalg/test_chebyshev.cpp b/tests/unit/linalg/test_chebyshev.cpp index 16e3424119..976da31cc9 100644 --- a/tests/unit/linalg/test_chebyshev.cpp +++ b/tests/unit/linalg/test_chebyshev.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/linalg/test_complex_operator.cpp b/tests/unit/linalg/test_complex_operator.cpp index 33c03104dc..1e3ffe553e 100644 --- a/tests/unit/linalg/test_complex_operator.cpp +++ b/tests/unit/linalg/test_complex_operator.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/linalg/test_direct_solvers.cpp b/tests/unit/linalg/test_direct_solvers.cpp new file mode 100644 index 0000000000..d7fde2cd80 --- /dev/null +++ b/tests/unit/linalg/test_direct_solvers.cpp @@ -0,0 +1,261 @@ +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-806117. +// +// This file is part of the MFEM library. For more information and source code +// availability visit https://mfem.org. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. + +#include "unit_tests.hpp" +#include "mfem.hpp" + +using namespace mfem; + +#ifdef MFEM_USE_SUITESPARSE +#define DIRECT_SOLVE_SERIAL +#endif +#ifdef MFEM_USE_MUMPS +#define DIRECT_SOLVE_PARALLEL +#endif +#ifdef MFEM_USE_SUPERLU +#define DIRECT_SOLVE_PARALLEL +#endif + +#if defined(DIRECT_SOLVE_SERIAL) || defined(DIRECT_SOLVE_PARALLEL) + +int dim; +double uexact(const Vector& x) +{ + double u; + switch (dim) + { + case 1: + u = 3.0 + 2.0 * x(0) - 0.5 * x(0) * x(0); + break; + case 2: + u = 1.0 + 0.2 * x(0) - 0.9 * x(0) * x(1) + x(1) * x(1) * x(0); + break; + default: + u = x(2) * x(2) * x(2) - 5.0 * x(0) * x(0) * x(1) * x(2); + break; + } + return u; +} + +void gradexact(const Vector& x, Vector & grad) +{ + grad.SetSize(dim); + switch (dim) + { + case 1: + grad[0] = 2.0 - x(0); + break; + case 2: + grad[0] = 0.2 - 0.9 * x(1) + x(1) * x (1); + grad[1] = - 0.9 * x(0) + 2.0 * x(0) * x(1); + break; + default: + grad[0] = -10.0 * x(0) * x(1) * x(2); + grad[1] = - 5.0 * x(0) * x(0) * x(2); + grad[2] = 3.0 * x(2) * x(2) - 5.0 * x(0) * x(0) * x(1); + break; + } +} + +double d2uexact(const Vector& x) // retuns \Delta u +{ + double d2u; + switch (dim) + { + case 1: + d2u = -1.0; + break; + case 2: + d2u = 2.0 * x(0); + break; + default: + d2u = -10.0 * x(1) * x(2) + 6.0 * x(2); + break; + } + return d2u; +} + +double fexact(const Vector& x) // retuns -\Delta u +{ + double d2u = d2uexact(x); + return -d2u; +} + +#endif + +#ifdef DIRECT_SOLVE_SERIAL + +TEST_CASE("direct-serial","[CUDA]") +{ + const int ne = 2; + for (dim = 1; dim < 4; ++dim) + { + Mesh* mesh; + if (dim == 1) + { + mesh = new Mesh(ne, 1.0); + } + else if (dim == 2) + { + mesh = new Mesh(ne, ne, Element::QUADRILATERAL, 1, 1.0, 1.0); + } + else + { + mesh = new Mesh(ne, ne, ne, Element::HEXAHEDRON, 1, 1.0, 1.0, + 1.0); + } + int order = 3; + FiniteElementCollection* fec = new H1_FECollection(order, dim); + FiniteElementSpace fespace(mesh, fec); + Array ess_tdof_list; + Array ess_bdr(mesh->bdr_attributes.Max()); + ess_bdr = 1; + fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list); + + FunctionCoefficient f(fexact); + LinearForm b(&fespace); + b.AddDomainIntegrator(new DomainLFIntegrator(f)); + b.Assemble(); + + BilinearForm a(&fespace); + ConstantCoefficient one(1.0); + a.AddDomainIntegrator(new DiffusionIntegrator(one)); + a.Assemble(); + + GridFunction x(&fespace); + FunctionCoefficient uex(uexact); + x = 0.0; + x.ProjectBdrCoefficient(uex,ess_bdr); + + OperatorPtr A; + Vector B, X; + a.FormLinearSystem(ess_tdof_list, x, b, A, X, B); + + UMFPackSolver umf_solver; + umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS; + umf_solver.SetOperator(*A); + umf_solver.Mult(B, X); + + Vector Y(X.Size()); + A->Mult(X,Y); + Y-=B; + REQUIRE(Y.Norml2() < 1.e-12); + + a.RecoverFEMSolution(X, b, x); + VectorFunctionCoefficient grad(dim,gradexact); + double err = x.ComputeH1Error(&uex,&grad); + REQUIRE(err < 1.e-12); + delete fec; + delete mesh; + } +} + +#endif + +#ifdef DIRECT_SOLVE_PARALLEL + +TEST_CASE("direct-parallel", "[Parallel], [CUDA]") +{ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + const int ne = 2; + for (dim = 1; dim < 4; ++dim) + { + Mesh* mesh; + if (dim == 1) + { + mesh = new Mesh(ne, 1.0); + } + else if (dim == 2) + { + mesh = new Mesh(ne, ne, Element::QUADRILATERAL, 1, 1.0, 1.0); + } + else + { + mesh = new Mesh(ne, ne, ne, Element::HEXAHEDRON, 1, 1.0, 1.0, + 1.0); + } + + ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh); + delete mesh; + int order = 3; + FiniteElementCollection* fec = new H1_FECollection(order, dim); + ParFiniteElementSpace fespace(pmesh, fec); + Array ess_tdof_list; + Array ess_bdr; + if (pmesh->bdr_attributes.Size()) + { + ess_bdr.SetSize(pmesh->bdr_attributes.Max()); + ess_bdr = 1; + fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list); + } + FunctionCoefficient f(fexact); + ParLinearForm b(&fespace); + b.AddDomainIntegrator(new DomainLFIntegrator(f)); + b.Assemble(); + + ParBilinearForm a(&fespace); + ConstantCoefficient one(1.0); + a.AddDomainIntegrator(new DiffusionIntegrator(one)); + a.Assemble(); + + ParGridFunction x(&fespace); + FunctionCoefficient uex(uexact); + x = 0.0; + x.ProjectBdrCoefficient(uex,ess_bdr); + + OperatorPtr A; + Vector B, X; + a.FormLinearSystem(ess_tdof_list, x, b, A, X, B); + +#ifdef MFEM_USE_MUMPS + { + MUMPSSolver mumps; + mumps.SetPrintLevel(0); + mumps.SetOperator(*A.As()); + mumps.Mult(B,X); + Vector Y(X.Size()); + A->Mult(X,Y); + Y-=B; + REQUIRE(Y.Norml2() < 1.e-12); + + a.RecoverFEMSolution(X, b, x); + VectorFunctionCoefficient grad(dim,gradexact); + double err = x.ComputeH1Error(&uex,&grad); + REQUIRE(err < 1.e-12); + } +#endif +#ifdef MFEM_USE_SUPERLU + // Transform to monolithic HypreParMatrix + { + SuperLURowLocMatrix SA(*A.As()); + SuperLUSolver superlu(MPI_COMM_WORLD); + superlu.SetPrintStatistics(false); + superlu.SetSymmetricPattern(false); + superlu.SetColumnPermutation(superlu::METIS_AT_PLUS_A); + superlu.SetOperator(SA); + superlu.Mult(B, X); + Vector Y(X.Size()); + A->Mult(X,Y); + Y-=B; + REQUIRE(Y.Norml2() < 1.e-12); + a.RecoverFEMSolution(X, b, x); + VectorFunctionCoefficient grad(dim,gradexact); + double err = x.ComputeH1Error(&uex,&grad); + REQUIRE(err < 1.e-12); + } +#endif + delete fec; + delete pmesh; + } +} + +#endif diff --git a/tests/unit/linalg/test_hypre_ilu.cpp b/tests/unit/linalg/test_hypre_ilu.cpp index 5da14a5caa..c0db73ecb3 100644 --- a/tests/unit/linalg/test_hypre_ilu.cpp +++ b/tests/unit/linalg/test_hypre_ilu.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/linalg/test_ilu.cpp b/tests/unit/linalg/test_ilu.cpp index 873645d020..90296e2260 100644 --- a/tests/unit/linalg/test_ilu.cpp +++ b/tests/unit/linalg/test_ilu.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/linalg/test_matrix_block.cpp b/tests/unit/linalg/test_matrix_block.cpp index e0a1cc5bb2..b5f2542394 100644 --- a/tests/unit/linalg/test_matrix_block.cpp +++ b/tests/unit/linalg/test_matrix_block.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/linalg/test_matrix_dense.cpp b/tests/unit/linalg/test_matrix_dense.cpp index 93085aaa3d..a49ab1b4f9 100644 --- a/tests/unit/linalg/test_matrix_dense.cpp +++ b/tests/unit/linalg/test_matrix_dense.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/linalg/test_matrix_hypre.cpp b/tests/unit/linalg/test_matrix_hypre.cpp index f59cd62785..c360144bf2 100644 --- a/tests/unit/linalg/test_matrix_hypre.cpp +++ b/tests/unit/linalg/test_matrix_hypre.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/linalg/test_matrix_rectangular.cpp b/tests/unit/linalg/test_matrix_rectangular.cpp index 7e7c0e6fdd..b083778cc0 100644 --- a/tests/unit/linalg/test_matrix_rectangular.cpp +++ b/tests/unit/linalg/test_matrix_rectangular.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/linalg/test_matrix_sparse.cpp b/tests/unit/linalg/test_matrix_sparse.cpp index f01384cceb..fbece97392 100644 --- a/tests/unit/linalg/test_matrix_sparse.cpp +++ b/tests/unit/linalg/test_matrix_sparse.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/linalg/test_matrix_square.cpp b/tests/unit/linalg/test_matrix_square.cpp index 256ddab19f..33531dc444 100644 --- a/tests/unit/linalg/test_matrix_square.cpp +++ b/tests/unit/linalg/test_matrix_square.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/linalg/test_ode.cpp b/tests/unit/linalg/test_ode.cpp index b71ae78b25..b379147c01 100644 --- a/tests/unit/linalg/test_ode.cpp +++ b/tests/unit/linalg/test_ode.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/linalg/test_ode2.cpp b/tests/unit/linalg/test_ode2.cpp index a3581a77d6..e0dcea9396 100644 --- a/tests/unit/linalg/test_ode2.cpp +++ b/tests/unit/linalg/test_ode2.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/linalg/test_operator.cpp b/tests/unit/linalg/test_operator.cpp index 78ff43b5d0..b3c9c63e2f 100644 --- a/tests/unit/linalg/test_operator.cpp +++ b/tests/unit/linalg/test_operator.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/linalg/test_vector.cpp b/tests/unit/linalg/test_vector.cpp index 5f9e2fdda9..278a45a6f1 100644 --- a/tests/unit/linalg/test_vector.cpp +++ b/tests/unit/linalg/test_vector.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/makefile b/tests/unit/makefile index 2b280a0062..2a1178519e 100644 --- a/tests/unit/makefile +++ b/tests/unit/makefile @@ -1,4 +1,4 @@ -# Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +# Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced # at the Lawrence Livermore National Laboratory. All Rights reserved. See files # LICENSE and NOTICE for details. LLNL-CODE-806117. # @@ -34,6 +34,7 @@ DATA_DIR = data SEQ_MAIN_OBJ = unit_test_main.o PAR_MAIN_OBJ = punit_test_main.o CUDA_MAIN_OBJ = cunit_test_main.o +PCUDA_MAIN_OBJ = pcunit_test_main.o # Sedov numerical seq/par files and tests SEDOV_FILES = $(SRC)miniapps/test_sedov.cpp @@ -57,6 +58,7 @@ PAR_SEDOV_CUDA_UVM_OBJ_FILES = $(if $(USE_CUDA),$(SEDOV_FILES:$(SRC)%.cpp=%.pcud SEQ_UNIT_TESTS = unit_tests $(SEQ_SEDOV_TESTS) SEQ_UNIT_TESTS += $(if $(USE_CUDA),cunit_tests) PAR_UNIT_TESTS = punit_tests $(PAR_SEDOV_TESTS) +PAR_UNIT_TESTS += $(if $(USE_CUDA),pcunit_tests) # Ceed tests USE_CEED := $(MFEM_USE_CEED:NO=) @@ -84,12 +86,15 @@ punit_tests: $(PAR_MAIN_OBJ) $(OBJECT_FILES) $(MFEM_LIB_FILE) $(CONFIG_MK) $(DAT cunit_tests: $(CUDA_MAIN_OBJ) $(OBJECT_FILES) $(MFEM_LIB_FILE) $(CONFIG_MK) $(DATA_DIR) $(CCC) $(CUDA_MAIN_OBJ) $(OBJECT_FILES) $(MFEM_LINK_FLAGS) $(MFEM_LIBS) -o $(@) +pcunit_tests: $(PCUDA_MAIN_OBJ) $(OBJECT_FILES) $(MFEM_LIB_FILE) $(CONFIG_MK) $(DATA_DIR) + $(CCC) $(PCUDA_MAIN_OBJ) $(OBJECT_FILES) $(MFEM_LINK_FLAGS) $(MFEM_LIBS) -o $(@) + ceed_tests: $(CEED_OBJ) $(MFEM_LIB_FILE) $(CONFIG_MK) $(DATA_DIR) $(CCC) $(CEED_OBJ) $(MFEM_LINK_FLAGS) $(MFEM_LIBS) -o $(@) # Note: in this rule, we always use the full path to the source file as a # workaround for an issue with coveralls. -$(OBJECT_FILES) $(SEQ_MAIN_OBJ) $(PAR_MAIN_OBJ) $(CUDA_MAIN_OBJ): %.o: $(SRC)%.cpp \ +$(OBJECT_FILES) $(SEQ_MAIN_OBJ) $(PAR_MAIN_OBJ) $(CUDA_MAIN_OBJ) $(PCUDA_MAIN_OBJ): %.o: $(SRC)%.cpp \ $(HEADER_FILES) $(CONFIG_MK) @mkdir -p $(@D) $(CCC) -c $(abspath $(<)) $(MFEM_FLAGS) $(INCLUDES) -o $(@) diff --git a/tests/unit/mesh/test_mesh.cpp b/tests/unit/mesh/test_mesh.cpp index 7e2278694a..2ea9426df5 100644 --- a/tests/unit/mesh/test_mesh.cpp +++ b/tests/unit/mesh/test_mesh.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/mesh/test_ncmesh.cpp b/tests/unit/mesh/test_ncmesh.cpp index 4163f9f74f..d97b2dcf0e 100644 --- a/tests/unit/mesh/test_ncmesh.cpp +++ b/tests/unit/mesh/test_ncmesh.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/mesh/test_pmesh.cpp b/tests/unit/mesh/test_pmesh.cpp new file mode 100644 index 0000000000..a051aa9bf4 --- /dev/null +++ b/tests/unit/mesh/test_pmesh.cpp @@ -0,0 +1,123 @@ +// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// at the Lawrence Livermore National Laboratory. All Rights reserved. See files +// LICENSE and NOTICE for details. LLNL-CODE-806117. +// +// This file is part of the MFEM library. For more information and source code +// availability visit https://mfem.org. +// +// MFEM is free software; you can redistribute it and/or modify it under the +// terms of the BSD-3 license. We welcome feedback and contributions, see file +// CONTRIBUTING.md for details. + +#include "mfem.hpp" +#include "unit_tests.hpp" + +namespace mfem +{ +#ifdef MFEM_USE_MPI + +TEST_CASE("ParMeshGlobalIndices", "[Parallel], [ParMesh]") +{ + const int ne = 5; + + for (int dimension = 1; dimension < 4; ++dimension) + { + for (int amr=0; amr < 1 + (dimension > 1); ++amr) + { + Mesh* mesh; + if (dimension == 1) + { + mesh = new Mesh(ne, 1.0); + } + else if (dimension == 2) + { + if (amr) + { + const char *mesh_file = "../../data/amr-quad.mesh"; + mesh = new Mesh(mesh_file, 1, 1); + } + else + { + mesh = new Mesh(ne, ne, Element::QUADRILATERAL, 1, 1.0, 1.0); + } + } + else + { + if (amr) + { + const char *mesh_file = "../../data/amr-hex.mesh"; + mesh = new Mesh(mesh_file, 1, 1); + } + else + { + mesh = new Mesh(ne, ne, ne, Element::HEXAHEDRON, 1, 1.0, 1.0, 1.0); + } + } + + ParMesh pmesh(MPI_COMM_WORLD, *mesh); + + int globalN = 0; + + enum EntityType { VERTEX, EDGE, FACE, ELEMENT }; + // Loop over all types of mesh entities + for (int e=EntityType::VERTEX; e<=EntityType::ELEMENT; ++e) + { + if (amr && dimension > 1 && e != EntityType::ELEMENT) + { + continue; + } + + Array gi; + + switch (e) + { + case EntityType::VERTEX: + globalN = mesh->GetNV(); + pmesh.GetGlobalVertexIndices(gi); + break; + case EntityType::EDGE: + globalN = dimension == 1 ? mesh->GetNV() : mesh->GetNEdges(); + pmesh.GetGlobalEdgeIndices(gi); + break; + case EntityType::FACE: + globalN = mesh->GetNumFaces(); + pmesh.GetGlobalFaceIndices(gi); + break; + case EntityType::ELEMENT: + globalN = mesh->GetNE(); + pmesh.GetGlobalElementIndices(gi); + break; + } + + // Verify that the local entities do not share a global index. + { + std::set localGI; + for (int i=0; i::precision = 8; + Catch::StringMaker::precision = 16; + + // Apply provided command line arguments. + int r = session.applyCommandLine(argc, argv); + if (r != 0) + { + return r; + } + +#ifdef MFEM_USE_MPI + mfem::MPI_Session mpi; + GlobalMPISession = &mpi; + + // Exclude all tests that are not labeled with Parallel and CUDA. + auto cfg = session.configData(); + cfg.testsOrTags.push_back("[Parallel]"); + cfg.testsOrTags.push_back("[CUDA]"); + + session.useConfigData(cfg); + + if (mpi.Root()) + { + mfem::out + << "WARNING: Only running the [Parallel] [CUDA] label." + << std::endl; + } +#endif + + int result = session.run(); + + return result; +} diff --git a/tests/unit/punit_test_main.cpp b/tests/unit/punit_test_main.cpp index 827eeaea68..dd5b2213b3 100644 --- a/tests/unit/punit_test_main.cpp +++ b/tests/unit/punit_test_main.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/unit_test_main.cpp b/tests/unit/unit_test_main.cpp index dbe054f0b3..f8185473cb 100644 --- a/tests/unit/unit_test_main.cpp +++ b/tests/unit/unit_test_main.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // diff --git a/tests/unit/unit_tests.hpp b/tests/unit/unit_tests.hpp index 1edc396496..1752d2ce28 100644 --- a/tests/unit/unit_tests.hpp +++ b/tests/unit/unit_tests.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced +// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. //